奇怪的SQLite行为:将AND语句添加到已经没有结果的查询时增加了执行时间

时间:2014-04-22 03:20:26

标签: sqlite

在调试执行成千上万次查询的Python应用程序时发现了一些奇怪的东西,它看起来花了太长时间(半小时,现在它已经缩短到7秒)。

我有一个包含关系的本地表,rxcui1rxcui2是索引数字值,rela是索引字符串。当我有 rxcui2 rela 时,我希望得到所有 rxcui1 。现在我发现当我只搜索 rxcui2 时,我很快得到一个结果,在示例中为空集。当我向同一个查询添加AND rela = xy时,执行时间会上升,尽管搜索 rxcui2 已经空了。看到这个时间:

sqlite> SELECT rxcui1 from rxnrel where rxcui2=29186;
CPU Time: user 0.000068 sys 0.000033
sqlite> SELECT rxcui1 from rxnrel where rxcui2=29186 AND rela IS NOT NULL;
CPU Time: user 0.000054 sys 0.000029
sqlite> SELECT rxcui1 from rxnrel where rxcui2=29186 AND rela IS NOT NULL AND rela='tradename_of';
CPU Time: user 0.119211 sys 0.018329

为什么会这样?结果在第一次限制后返回空,为什么SQLite甚至懒得检查后续语句?我在OS X 10.9上使用SQLite 3.7.13


更新

哇!我刚刚删除了rela上的索引,现在它按预期工作了!任何人都可以解释为什么会这样吗?也许这是在最新的SQLite版本中修复的?

sqlite> SELECT rxcui1 from rxnrel where rxcui2=29186 AND rela IS NOT NULL AND rela='tradename_of';
CPU Time: user 0.000064 sys 0.000028

更新

我猜使用EXPLAIN QUERY PLAN解决了这个谜。

索引超过 rela

sqlite> EXPLAIN QUERY PLAN SELECT rxcui1 from rxnrel where rxcui2=29186 AND rela IS NOT NULL AND rela='tradename_of';
0|0|0|SEARCH TABLE rxnrel USING INDEX X_RXNREL_RELA (RELA=?) (~2 rows)

没有 rela 索引但 rxcui2 索引:

sqlite> EXPLAIN QUERY PLAN SELECT rxcui1 from rxnrel where rxcui2=29186 AND rela IS NOT NULL AND rela='tradename_of';
0|0|0|SEARCH TABLE rxnrel USING INDEX X_RXNREL_RXCUI2 (RXCUI2=?) (~2 rows)

1 个答案:

答案 0 :(得分:0)

查看查询计划,它现在清楚会发生什么。 SQLite每个查询只能使用一个索引(我不知道的第一件事),并不认为您的查询排序很重要(我不知道的第二件事)。回到MySQL时代,我过去通过"正确地优化查询"对语句进行排序,但SQLite不尊重这一点,而且大部分时间都可能是正确的。但不是在这种情况下,它决定使用 rela 索引,我知道该索引的效果不如 rxcui2 索引。

我使用 rxcui2 rela 的组合索引进行了一些测试,但它没有明显快于只有 rxcui2的索引。这是我的用例非常具体的,我的需要是我需要仔细查看每个具体的SQLite查询,如果我想确保它的速度快,那还不够确保第一个语句可以使用索引,然后随意添加更多语句。