Python 非常慢的select查询,如何加快速度?
我问了两个相关的问题(和)。我已经改变了一些事情,并获得了一些加速,但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代码检索频
功能
,其中包含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将无法像saypostgresql
等那样高效地执行您的查询
我对您的场景进行了研究,因为我很想知道您的查询可以优化多少。最终,似乎最好的优化是删除所有显式索引(!)。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)