【问题标题】:SQLITE is extreme slow with ORDER BY使用 ORDER BY 时 SQLITE 非常慢
【发布时间】:2018-06-09 15:53:09
【问题描述】:

我有一个简单的查询,例如

SELECT * FROM "mytable" where col1="foo"

在大约 0.5 秒内解决(大约 100'000 行的 700 MB 数据库文件的大约 100 个结果)

但是,我添加 ORDER BY 后需要 120 秒。

SELECT * FROM "mytable" where col1="foo" ORDER BY col2

即使我像这样限制结果

SELECT * FROM (SELECT * FROM "mytable" where col1="foo" LIMIT 1) ORDER BY col2

这需要 120 秒,但实际上没有什么可排序的。

唯一的例外是如果我使用ORDER BY rowid(而不是ORDER BY col2)进行排序,或者当我这样做时(0.5 秒):

SELECT * FROM "mytable" WHERE rowid IN (SELECT rowid FROM "mytable"  WHERE col1="foo") ORDER BY col2

VACUUM'ed 数据库并检查了数据库的完整性(好的),这个问题仍然存在。 我正在使用 SQLite 版本:3.7.7.1,减速出现在 phpLITEadmin 和我的 PHP 代码中。

编辑

EXPLAIN QUERY PLAN SELECT * FROM "mytable" WHERE col1="foo" 
选择ID|订单|来自|详细信息 0| 0| 0|SCAN TABLE mytable(~11345 行)
EXPLAIN QUERY PLAN SELECT * FROM "mytable" WHERE col1="foo" ORDER BY col2
选择ID|订单|来自|详细信息 0| 0| 0|SEARCH TABLE mytable 使用自动覆盖索引 (col1=?) (~7 行) 0| 0| 0|使用 TEMP B-TREE 进行排序

解决方案

好的,我们似乎找到了解决方案:出于某种神秘原因需要CREATE INDEX col1_idx ON "mytable" (col1)。在 col2(要排序的列)上创建索引没有区别(使用或不使用 col2 的索引进行排序需要 120 秒)。对我来说似乎是一个 SQLite 错误,因为没有索引 col1 的查询结果很快(0.5 秒),并且对单个非索引行进行排序(= 根本不排序)不应该花费 120 秒。即使对整个表进行排序SELECT * FROM "mytable" ORDER BY col2 SQLite 也只需要 7 秒。

还很有趣:为 col1 和 col2 创建索引只用了 1.5 秒。因此,即使假设这种速度变慢的原因是 SQLite 自动为查询创建了一个临时索引,它仍然无法解释 SQLite 需要这么长时间来排序的原因。

【问题讨论】:

  • 你知道什么是索引吗?
  • EXPLAIN QUERY PLAN 的输出是什么?
  • @rustyx EXPLAIN QUERY PLAN SELECT * FROM "mytablename" WHERE col1="foo"selectid|order|from|detail 0|0|0|SCAN TABLE mytablename(~11345 行)EXPLAIN QUERY PLAN SELECT * FROM "mytablename" WHERE col1="foo" ORDER BY col2selectid|order|from|detail 0|0|0|使用自动覆盖索引 (col1=?) 搜索表 mytablename (~7 行) 0|0|0|使用 TEMP B-TREE FOR ORDER BY
  • 在 col2 上创建索引,这样可以避免创建临时 btree
  • @Peeyush col2 上已有索引。我在 col2 上运行了有无索引的测试,结果相同 = 120 秒。

标签: database performance sqlite sorting


【解决方案1】:

因此,SQLite 似乎错误地认为构建临时索引 (automatic covering index) 来运行查询而不是在内存中排序会更便宜。显然,为每个查询在 100,000 行上建立索引并不是最优的查询计划。

一个明显的解决方案是在要执行查询/排序的列上添加索引。

CREATE INDEX col1_idx ON mytable (col1);
CREATE INDEX col2_idx ON mytable (col2);

【讨论】:

  • 该索引已经存在并且没有任何区别。有无索引都需要 120 秒。
  • @Mike.M 也在col1?
  • 不,col1 没有任何索引,创建索引似乎解决了这个问题,或者我应该说,绕过了这个 SQLITE 错误。谢谢。
【解决方案2】:

我们遇到了类似的问题,添加了一个虚拟计算值并使用它进行排序解决了这个“错误”:

SELECT *, (col2+0) AS col2_forSort FROM "mytable" where col1="foo" ORDER BY col2_forSort

或者对于字符串(这不是我们的情况):

SELECT *, (col2 || "") AS col2_forSort FROM "mytable" where col1="foo" ORDER BY col2_forSort

YMMV...祝你好运!

【讨论】:

  • 你的 SQLite 版本是多少?
  • @Mike.M Vesion 3.22.0 在嵌入式设备上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 2013-04-30
  • 1970-01-01
相关资源
最近更新 更多