Python 非常慢的select查询,如何加快速度?

Python 非常慢的select查询,如何加快速度?,python,sql,performance,sqlite,comparison,Python,Sql,Performance,Sqlite,Comparison,我问了两个相关的问题(和)。我已经改变了一些事情,并获得了一些加速,但select语句仍然需要一个多小时才能完成 我有一个表功能,其中包含rtMin、rtMax、mzMin和mzMax值。这些值一起是矩形的角(如果您阅读我以前的问题,我将分别保存这些值,而不是从convxhull表中获取min()和max(),这样工作速度更快)我得到了一个表spectrum,带有rt和mz值。我有一个表格,当光谱的rt和mz值位于特征的矩形中时,它将特征链接到光谱 为此,我使用以下sql和python代码检索频

我问了两个相关的问题(和)。我已经改变了一些事情,并获得了一些加速,但select语句仍然需要一个多小时才能完成

我有一个表
功能
,其中包含
rtMin
rtMax
mzMin
mzMax
值。这些值一起是矩形的角(如果您阅读我以前的问题,我将分别保存这些值,而不是从
convxhull
表中获取min()和max(),这样工作速度更快)
我得到了一个表
spectrum
,带有
rt
mz
值。我有一个表格,当光谱的
rt
mz
值位于特征的矩形中时,它将特征链接到光谱

为此,我使用以下sql和python代码检索频谱和功能的ID:

self.cursor.execute("SELECT spectrum_id, feature_table_id "+
                    "FROM `spectrum` "+
                    "INNER JOIN `feature` "+
                    "ON feature.msrun_msrun_id = spectrum.msrun_msrun_id "+
                    "WHERE spectrum.scan_start_time >= feature.rtMin "+
                    "AND spectrum.scan_start_time <= feature.rtMax "+
                    "AND spectrum.base_peak_mz >= feature.mzMin "+
                    "AND spectrum.base_peak_mz <= feature.mzMax")        
spectrumAndFeature_ids = self.cursor.fetchall()

for spectrumAndFeature_id in spectrumAndFeature_ids:
        spectrum_has_feature_inputValues = (spectrumAndFeature_id[0], spectrumAndFeature_id[1])
        self.cursor.execute("INSERT INTO `spectrum_has_feature` VALUES (?,?)",spectrum_has_feature_inputValues)
因此,此查询大约需要一个半小时,其中大部分时间用于执行fetchall()。我怎样才能加快速度?我应该在python代码中进行
rt
mz
比较吗


更新: 为了显示我得到的索引,以下是表的create语句:

CREATE  TABLE IF NOT EXISTS `feature` (
  `feature_table_id` INT PRIMARY KEY NOT NULL ,
  `feature_id` VARCHAR(40) NOT NULL ,
  `intensity` DOUBLE NOT NULL ,
  `overallquality` DOUBLE NOT NULL ,
  `charge` INT NOT NULL ,
  `content` VARCHAR(45) NOT NULL ,
  `intensity_cutoff` DOUBLE NOT NULL,
  `mzMin` DOUBLE NULL ,
  `mzMax` DOUBLE NULL ,
  `rtMin` DOUBLE NULL ,
  `rtMax` DOUBLE NULL ,
  `msrun_msrun_id` INT NOT NULL ,
  CONSTRAINT `fk_feature_msrun1`
    FOREIGN KEY (`msrun_msrun_id` )
    REFERENCES `msrun` (`msrun_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

  CREATE UNIQUE INDEX `id_UNIQUE` ON `feature` (`feature_table_id` ASC);
  CREATE INDEX `fk_feature_msrun1` ON `feature` (`msrun_msrun_id` ASC);



CREATE  TABLE IF NOT EXISTS `spectrum` (
  `spectrum_id` INT PRIMARY KEY NOT NULL ,
  `spectrum_index` INT NOT NULL ,
  `ms_level` INT NOT NULL ,
  `base_peak_mz` DOUBLE NOT NULL ,
  `base_peak_intensity` DOUBLE NOT NULL ,
  `total_ion_current` DOUBLE NOT NULL ,
  `lowest_observes_mz` DOUBLE NOT NULL ,
  `highest_observed_mz` DOUBLE NOT NULL ,
  `scan_start_time` DOUBLE NOT NULL ,
  `ion_injection_time` DOUBLE,
  `binary_data_mz` BLOB NOT NULL,
  `binaray_data_rt` BLOB NOT NULL,
  `msrun_msrun_id` INT NOT NULL ,
  CONSTRAINT `fk_spectrum_msrun1`
    FOREIGN KEY (`msrun_msrun_id` )
    REFERENCES `msrun` (`msrun_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

  CREATE INDEX `fk_spectrum_msrun1` ON `spectrum` (`msrun_msrun_id` ASC);



CREATE  TABLE IF NOT EXISTS `spectrum_has_feature` (
  `spectrum_spectrum_id` INT NOT NULL ,
  `feature_feature_table_id` INT NOT NULL ,
  CONSTRAINT `fk_spectrum_has_feature_spectrum1`
    FOREIGN KEY (`spectrum_spectrum_id` )
    REFERENCES `spectrum` (`spectrum_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_spectrum_has_feature_feature1`
    FOREIGN KEY (`feature_feature_table_id` )
    REFERENCES `feature` (`feature_table_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

  CREATE INDEX `fk_spectrum_has_feature_feature1` ON `spectrum_has_feature` (`feature_feature_table_id` ASC);
  CREATE INDEX `fk_spectrum_has_feature_spectrum1` ON `spectrum_has_feature` (`spectrum_spectrum_id` ASC);

更新2:
我有20938个光谱,305742个特征和2个msrun。结果是10822场比赛


更新3:
使用新索引(在
spectrum
上创建索引
fk_spectrum_msrun1_2
msrun_msrun_id
base_peak_mz
);可节省约20秒: 查询时间:76.4599349499秒 自fetchall后5864.15418601秒


更新4: 从解释查询计划打印:

(0, 0, 0, u'SCAN TABLE spectrum (~1000000 rows)'), (0, 1, 1, u'SEARCH TABLE feature USING INDEX fk_feature_msrun1 (msrun_msrun_id=?) (~2 rows)') 
0|0|0|SCAN TABLE spectrum (~20000 rows)
0|1|1|SEARCH TABLE feature USING COVERING INDEX idx1 (lnk_feature=? AND mzMin<?) (~7 rows)

使用between而不是>=和使sql部分的性能更好


总之,使用索引

在正常的RDBMS中,应该在
频谱
特征
表之间进行哈希连接。如果您可以强制它执行散列连接,那么查询应该可以运行

但是,您可以尝试执行单个查询吗

self.cursor.execute("INSERT INTO `spectrum_has_feature` " + 
                    "SELECT spectrum_id, feature_table_id "+
                    "FROM `spectrum` "+
                    "INNER JOIN `feature` "+
                    "ON feature.msrun_msrun_id = spectrum.msrun_msrun_id "+
                    "WHERE spectrum.scan_start_time >= feature.rtMin "+
                    "AND spectrum.scan_start_time <= feature.rtMax "+
                    "AND spectrum.base_peak_mz >= feature.mzMin "+
                    "AND spectrum.base_peak_mz <= feature.mzMax")  
self.cursor.execute(“插入到'spectrum\u has\u feature`'中””
“选择频谱\u id、特征\u表格\u id”+
“来自“光谱”+
“内部联接`feature`”+
“在feature.msrun\u msrun\u id=spectrum.msrun\u msrun\u id上”+
“其中spectrum.scan\u start\u time>=feature.rtMin”+
“和spectrum.scan\u start\u time=feature.mzMin”+
而spectrum.base_peak_mz改变了这一点

CREATE INDEX `fk_spectrum_msrun1` ON `spectrum` (`msrun_msrun_id` ASC);
其中一个(以更具选择性的为准)

第一个可以加快对
scan\u start\u time
的比较,第二个可以加快对
base\u peak\u mz
的比较。因为这是不等式比较,所以两列上的索引都没有用。

1.使用between而不是


2.在扫描开始时间和基准峰值mz上添加索引。您正在关联两个大表。一些快速数学:300k x 20k=60亿行。如果只是返回所有这些行,那么您肯定会受到I/O限制(但实际上仅限于(O)输出端).但是,where子句几乎过滤掉了所有内容,因为您只返回了10k行,所以您可以确定CPU绑定在这里

SQLite一次不能使用多个索引,但被称为“”的索引除外。此外,由于内部联接为“”,因此不会从中获得任何性能增益

归根结底,SQLite将无法像say
postgresql
等那样高效地执行您的查询

我对您的场景进行了研究,因为我很想知道您的查询可以优化多少。最终,似乎最好的优化是删除所有显式索引(!)。SQLite似乎在运行中找到了一些索引,这些索引比我尝试的不同方法具有更好的性能

作为一个演示,请考虑从您的派生出的模式:

CREATE TABLE feature ( -- 300k
    feature_id INTEGER PRIMARY KEY,
    mzMin DOUBLE,
    mzMax DOUBLE,
    rtMin DOUBLE,
    rtMax DOUBLE,
    lnk_feature INT);
CREATE TABLE spectrum ( -- 20k
    spectrum_id INTEGER PRIMARY KEY,
    mz DOUBLE,
    rt DOUBLE,
    lnk_spectrum INT);
feature
有300k行,而
spectrum
20k(执行此操作的python代码在下面的某个地方)。由于定义为
整数主键,因此没有指定明确的索引:

除整数主键列外,包括唯一主键列和主键列 通过在数据库中创建索引(在 与“CREATEUNIQUE INDEX”语句的方法相同) 索引与数据库中的任何其他索引一样用于优化 因此,通常没有优势(但意义重大) 开销)在一组已经存在的列上创建索引 共同受唯一或主键约束

使用上面的模式,SQLite提到它将在
lnk_feature
的查询期间创建索引:

sqlite> EXPLAIN QUERY PLAN SELECT feature_id, spectrum_id FROM spectrum, feature
   ...> WHERE lnk_feature = lnk_spectrum
   ...>     AND rt >= rtMin AND rt <= rtMax
   ...>     AND mz >= mzMin AND mz <= mzMax;
0|0|0|SCAN TABLE spectrum (~20000 rows)
0|1|1|SEARCH TABLE feature USING AUTOMATIC COVERING INDEX (lnk_feature=?) (~7 rows)
我得到的输出:

54626 rows; 1210.96 seconds

我运行了Ludo的脚本,它在我的系统上报告了1451秒。然后我添加了以下索引,将时间缩短到875秒(减少40%):

速度仍然不快,但更好。下面是解释查询计划的输出:

(0, 0, 0, u'SCAN TABLE spectrum (~1000000 rows)'), (0, 1, 1, u'SEARCH TABLE feature USING INDEX fk_feature_msrun1 (msrun_msrun_id=?) (~2 rows)') 
0|0|0|SCAN TABLE spectrum (~20000 rows)
0|1|1|SEARCH TABLE feature USING COVERING INDEX idx1 (lnk_feature=? AND mzMin<?) (~7 rows)
0 | 0 | 0 |扫描表光谱(~20000行)

0 | 1 | 1 |使用覆盖索引idx1搜索表特征(lnk_feature=?和MzMint这不会让它变得很快。查询优化器知道
=
查询优化器应该知道
=
现在尝试一下,需要一点时间来看看它会有多大的效果。它没有加快我的查询速度。你对那些表的哪些列进行了索引?我更新了我的问题要用Indexe显示我的create语句,我认为问题在于sqlite。它能在spectrum和features之间进行哈希连接吗?你有多少spectrum、features和MSRun?这两个范围相对于所有数据有多大?我有20938个spectrum、305742个features和2个msruns。最终它将是spectrum和features的150倍。我正在使用索引,我用我的create语句更新了我的问题。据我所知,Sqlite没有哈希连接,只有循环连接。这就解释了一切。你不能加速循环。他说
54626 rows; 1210.96 seconds
CREATE INDEX idx1 ON feature (lnk_feature, mzMin, mzMax, rtMin, rtMax);
0|0|0|SCAN TABLE spectrum (~20000 rows)
0|1|1|SEARCH TABLE feature USING COVERING INDEX idx1 (lnk_feature=? AND mzMin<?) (~7 rows)