Python 为什么同一个SQLite查询在只获取两倍的结果时会慢30倍?
我已经花了一个星期的时间来加速一个查询,并在这里问了几个问题(,) 在那里给出的答案的非常有用的帮助下,我成功地获得了sqlite查询的时间Python 为什么同一个SQLite查询在只获取两倍的结果时会慢30倍?,python,performance,sqlite,fetchall,Python,Performance,Sqlite,Fetchall,我已经花了一个星期的时间来加速一个查询,并在这里问了几个问题(,) 在那里给出的答案的非常有用的帮助下,我成功地获得了sqlite查询的时间100.95秒,并获取了所有的时间:1485.43。这仍然不够,所以在尝试了一些不同的索引之后,我设法将一个样本的查询时间缩短到0.08秒,将fetchall时间缩短到54.97秒。所以我想我终于设法加快了速度 然后,查询将运行下一个示例,时间为0.58秒,fetchall时间为3952.80秒。对于第三个示例,查询用了1.01秒和1970.67秒来获取全部
100.95
秒,并获取了所有的时间:1485.43
。这仍然不够,所以在尝试了一些不同的索引之后,我设法将一个样本的查询时间缩短到0.08
秒,将fetchall时间缩短到54.97
秒。所以我想我终于设法加快了速度
然后,查询将运行下一个示例,时间为0.58
秒,fetchall时间为3952.80
秒。对于第三个示例,查询用了1.01
秒和1970.67
秒来获取全部
第一个样本获取了12951行,第二个样本获取了24972行,第三个样本获取了6470行。
我很好奇为什么第一个示例获取行的速度要快得多,而第二个示例的获取量只有第一个示例的一半
代码(
spectrumFeature_inputValues
是使用的3个样本中的(1,)、(2,)和(3,):
结果是:
EXPLAIN QUERY PLAN:
[(0, 0, 2, u'SCAN TABLE feature (~100000 rows)'), (0, 1, 1, u'SEARCH TABLE spectrum USING INDEX fk_spectrum_scahn_start_time_1 (scan_start_time>? AND scan_start_time<?) (~3125 rows)'), (0, 2, 0, u'SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~5 rows)')]
query took: 0.0754859447479 seconds
it fetched: 12951 rows
fetchall took 54.2855291367 seconds
inserting took 0.602859973907 seconds
It took 54.9704811573 seconds
EXPLAIN QUERY PLAN:
[(0, 0, 2, u'SCAN TABLE feature (~100000 rows)'), (0, 1, 1, u'SEARCH TABLE spectrum USING INDEX fk_spectrum_scahn_start_time_1 (scan_start_time>? AND scan_start_time<?) (~3125 rows)'), (0, 2, 0, u'SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~5 rows)')]
query took: 0.579694032669 seconds
it fetched: 24972 rows
fetchall took 3950.08093309 seconds
inserting took 2.11575508118 seconds
It took 3952.80745602 seconds
EXPLAIN QUERY PLAN:
[(0, 0, 2, u'SCAN TABLE feature (~100000 rows)'), (0, 1, 1, u'SEARCH TABLE spectrum USING INDEX fk_spectrum_scahn_start_time_1 (scan_start_time>? AND scan_start_time<?) (~3125 rows)'), (0, 2, 0, u'SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~5 rows)')]
query took: 1.01185703278 seconds
it fetched: 6470 rows
fetchall took 1970.622962 seconds
inserting took 0.673867940903 seconds
It took 1972.31343699 seconds
正如你们所看到的,我已经用频谱和特征中的mz
和rt
值建立了索引,因为我发现大部分时间都花在比较这些数字上
那么为什么第一个样本比第二个和第三个样本快那么多呢?查询时间与fetchall时间的关系如何?最重要的是,我有没有办法加快速度
更新1: 与同事交谈后,可能是因为将一个点与二维尺寸(rtMin、rtMax、mzMin、mzMax)进行比较需要n^2时间。这大致相当于第二个fetchall花费的时间略多于60^2秒(大约是第一个fetchall花费的时间),并且它检索到的行数略少于行数的两倍。但这并没有回答我的任何问题
更新2: 我试着按照评论中的建议使用R*tree。我做了一张新桌子:
CREATE VIRTUAL TABLE convexhull_edges USING rtree(
feature_feature_table_id,
rtMin, rtMax,
mzMin, mzMax,
);
并将我的查询更改为:
self.cursor.execute("SELECT precursor_id, feature_table_id "+
"FROM `MSMS_precursor` "+
"INNER JOIN `spectrum` ON spectrum.spectrum_id = MSMS_precursor.spectrum_spectrum_id "+
"INNER JOIN `feature` ON feature.msrun_msrun_id = spectrum.msrun_msrun_id "+
"INNER JOIN `convexhull_edges` ON convexhull_edges.feature_feature_table_id = feature.feature_table_id "
"WHERE spectrum.scan_start_time BETWEEN convexhull_edges.rtMin AND convexhull_edges.rtMax "+
"AND MSMS_precursor.ion_mz BETWEEN convexhull_edges.mzMin AND convexhull_edges.mzMax "+
"AND feature.msrun_msrun_id = ?", spectrumFeature_InputValues)
结果如下:
EXPLAIN QUERY PLAN:
[(0, 0, 3, u'SCAN TABLE convexhull_edges VIRTUAL TABLE INDEX 2: (~0 rows)'), (0, 1, 2, u'SEARCH TABLE feature USING INDEX sqlite_autoindex_feature_1 (feature_table_id=?) (~1 rows)'), (0, 2, 1, u'SEARCH TABLE spectrum USING INDEX fk_spectrum_scahn_start_time_1 (scan_start_time>? AND scan_start_time<?) (~3125 rows)'), (0, 3, 0, u'SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~5 rows)')]
query took: 0.0572800636292 seconds
it fetched: 13140 rows
fetchall took 34.4445540905 seconds
EXPLAIN QUERY PLAN:
[(0, 0, 3, u'SCAN TABLE convexhull_edges VIRTUAL TABLE INDEX 2: (~0 rows)'), (0, 1, 2, u'SEARCH TABLE feature USING INDEX sqlite_autoindex_feature_1 (feature_table_id=?) (~1 rows)'), (0, 2, 1, u'SEARCH TABLE spectrum USING INDEX fk_spectrum_scahn_start_time_1 (scan_start_time>? AND scan_start_time<?) (~3125 rows)'), (0, 3, 0, u'SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~5 rows)')]
query took: 0.819370031357 seconds
it fetched: 25402 rows
fetchall took 3625.72873998 seconds
EXPLAIN QUERY PLAN:
[(0, 0, 3, u'SCAN TABLE convexhull_edges VIRTUAL TABLE INDEX 2: (~0 rows)'), (0, 1, 2, u'SEARCH TABLE feature USING INDEX sqlite_autoindex_feature_1 (feature_table_id=?) (~1 rows)'), (0, 2, 1, u'SEARCH TABLE spectrum USING INDEX fk_spectrum_scahn_start_time_1 (scan_start_time>? AND scan_start_time<?) (~3125 rows)'), (0, 3, 0, u'SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~5 rows)')]
query took: 0.878498077393 seconds
it fetched: 6761 rows
fetchall took 1419.34246588 seconds
inserting took 0.340960025787 seconds
It took 1420.56637716 seconds
解释查询计划:
[(0,0,3,u'SCAN TABLE converxhull_edges VIRTUAL TABLE INDEX 2:(~0行),(0,1,2,u'SEARCH TABLE feature使用索引sqlite\u autoindex\u feature\u 1(feature\u TABLE\u id=?)(~1行),(0,2,1,u'SEARCH TABLE spectrum使用索引fk\u spectrum\u scahn\u start\u time\u 1(scan_start_time>?和scan_start_time执行时间与每个表中的行数成几何比例,而不是算术比例,例如
3 tables with 10 rows each => 1,000 comparision
3 tables with 10, 10 and 40 rows => 4,000 comparisons
3 tables with 20 rows each => 8,000 comparisons
您可能需要重新考虑查询以避免某些连接/游标-何时需要答案
你能这样做吗:
SELECT precursor_id, feature_table_id
FROM MSMS_precursor
INNER JOIN
(
SELECT mzMin, mzMax, rtMin, rtMax, spectrum_id, feature_table_id, msrun_msrun_id
FROM spectrum
INNER JOIN
(select feature_table_id, mzMin, mzMax, rtMin, rtMax, msrun_msrun_id
from feature
where feature.msrun_msrun_id = 'value'
) subquery
ON subquery.msrun_msrun_id = spectrum.msrun_msrun_id
WHERE
spectrum.scan_start_time BETWEEN subquery.rtMin AND subquery.rtMax
) subquery
ON subquery.spectrum_id = MSMS_precursor.spectrum_spectrum_id
WHERE
MSMS_precursor.ion_mz BETWEEN subquery.mzMin AND subquery.mzMax
使用子查询可以减少表之间的比较次数-可以快速过滤掉不需要的特征,然后在搜索合适的前体之前过滤掉不相关的光谱
我不使用SQLLite,但原则仍然适用。
更新:修复了SQL中的错误
注:
你不必担心ANDs,你只会得到:
- 功能,其中feature.msrun\u msrun\u id='value'
- 这些特征的光谱以及spectrum.scan\u开始时间之间的位置
subquery.rtMin和subquery.rtMax
- 这些光谱的前驱体,其中subquery.mzMin和
subquery.mzMax
5月18日更新:
这是索引!!!您在搜索字段上有索引,但在参与联接的字段上没有索引-外键索引确实提高了性能:
CREATE INDEX `fk_msrun_msrun_id_feature` ON `feature` (`msrun_msrun_id` ASC);
CREATE INDEX `fk_spectrum_spectrum_id_feature` ON `feature` (`msrun_msrun_id` ASC);
CREATE INDEX `fk_spectrum_spectrum_id_MSMS_precursor` ON `MSMS_precursor` (`spectrum_spectrum_id` ASC);
我建议您尝试使用,它们是为有效的范围查询而设计的
我实际上没有太多地使用R*树,只是阅读了文档,但我认为您可能没有正确地使用它。您可能希望尝试将查询更改为使用
WHERE convexhull_edges.rtMin <= spectrum.scan_start_time AND convexhull_edges.rtMax >= spectrum.scan_start_time AND
convexhull_edges.mzMin <= MSMS_precursor.ion_mz AND convexhull_edges.mzMax >= MSMS_precursor.ion_mz
其中convexhull\u edges.rtMin=spectrum.scan\u start\u time和
convexhull_edges.mzMin=MSMS_.ion_mz
这应该相当于您当前的查询,但我认为应该更快(您应该从R*树中选择一个范围,而不是将点与范围进行比较)考虑在查询中涉及的表上使用
在select
语句和相应的internal join
和where
子句中,您确实获取了数量有限的列。通过使用包含有序列的覆盖索引,您应该可以得到一个非常快速的查询,也就是说,您将删除扫描表
,以支持查询
尝试在表上使用这些索引:
CREATE INDEX `fk_covering_feature` ON `feature` (`msrun_msrun_id`,`mzMin`,`mzMax`,`rtMin`,`rtMax`,`feature_table_id`);
CREATE INDEX `fk_covering_spectrum` ON `spectrum` (`msrun_msrun_id`,`scan_start_time`,`spectrum_id`);
CREATE INDEX `fk_covering_MSMS_precursor` ON `MSMS_precursor` (`spectrum_spectrum_id`,`ion_mz`,`precursor_id`);
在追求速度时,您还应该提示查询计划员了解msrun\u msrun\u id是一个常量,用于检查功能
和频谱
表。在查询中添加常量测试,方法是将此附加测试放在查询末尾(并通过频谱功能(u InputValues
两次):
这些数字很可能取决于您机器的环境因素,例如:可用内存、硬盘驱动器速度、.sqlite数据库的大小等。在此处发布这些值可能会有所帮助。我将在明天发布这些值。但是,这些对我来说很奇怪的计时在同一台机器上。不确定这是否有帮助,但您是否我开始使用?它们是为有效的范围查询而设计的,看起来很有希望,我将在未来几天的某个地方试用它。谢谢!将严格的相等约束移到内部连接的ON
子句可能会有所帮助。我在PostgreSQL中遇到类似的问题,在花了很多时间之后,它就没有了无需完全重新设计模式即可解决。WHERE
子句中的多个不等式与非统一的数据集相冲突,这本质上是不确定的
CREATE INDEX `fk_msrun_msrun_id_feature` ON `feature` (`msrun_msrun_id` ASC);
CREATE INDEX `fk_spectrum_spectrum_id_feature` ON `feature` (`msrun_msrun_id` ASC);
CREATE INDEX `fk_spectrum_spectrum_id_MSMS_precursor` ON `MSMS_precursor` (`spectrum_spectrum_id` ASC);
WHERE convexhull_edges.rtMin <= spectrum.scan_start_time AND convexhull_edges.rtMax >= spectrum.scan_start_time AND
convexhull_edges.mzMin <= MSMS_precursor.ion_mz AND convexhull_edges.mzMax >= MSMS_precursor.ion_mz
CREATE INDEX `fk_covering_feature` ON `feature` (`msrun_msrun_id`,`mzMin`,`mzMax`,`rtMin`,`rtMax`,`feature_table_id`);
CREATE INDEX `fk_covering_spectrum` ON `spectrum` (`msrun_msrun_id`,`scan_start_time`,`spectrum_id`);
CREATE INDEX `fk_covering_MSMS_precursor` ON `MSMS_precursor` (`spectrum_spectrum_id`,`ion_mz`,`precursor_id`);
"AND spectrum.msrun_msrun_id = ?"