Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么同一个SQLite查询在只获取两倍的结果时会慢30倍?_Python_Performance_Sqlite_Fetchall - Fatal编程技术网

Python 为什么同一个SQLite查询在只获取两倍的结果时会慢30倍?

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秒来获取全部

我已经花了一个星期的时间来加速一个查询,并在这里问了几个问题(,)

在那里给出的答案的非常有用的帮助下,我成功地获得了sqlite查询的时间
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 = ?"