为啥 Sqlite 不使用这个 ORDER BY 的索引?

Posted

技术标签:

【中文标题】为啥 Sqlite 不使用这个 ORDER BY 的索引?【英文标题】:why does Sqlite not use the index for this ORDER BY?为什么 Sqlite 不使用这个 ORDER BY 的索引? 【发布时间】:2013-03-07 16:55:12 【问题描述】:

我有这个问题:

SELECT * FROM Events e 
  INNER JOIN Telemetry ss ON ss.Id = e.TelemetryId 
  INNER JOIN Services s ON s.Id = ss.ServiceId 
  WHERE s.AssetId = @AssetId AND e.TimestampTicks >= @StartTime 
  ORDER BY e.TimestampTicks LIMIT 1000

我有这个索引:

CREATE INDEX [IX_Events_TelemetryId_TimestampTicks] ON [Events] ([TelemetryId],[TimestampTicks])

但是,索引不用于 ORDER BY 子句。我得到这个查询解释:

0|0|2|SCAN TABLE Services AS s (~44 rows)
0|1|1|SEARCH TABLE Telemetry AS ss USING AUTOMATIC COVERING INDEX (ServiceId=?) (~5 rows)
0|2|0|SEARCH TABLE Events AS e USING INDEX IX_Events_TelemetryId_TimestampTicks (TelemetryId=? AND TimestampTicks>?) (~1816 rows)
0|0|0|USE TEMP B-TREE FOR ORDER BY

为什么是 B-TREE?如果我反转索引,我实际上会得到更差的性能。这是查询计划:

0|0|0|SEARCH TABLE Events AS e USING INDEX IX_Events_TimestampTicks_TelemetryId (TimestampTicks>?) (~4031303 rows)
0|1|1|SEARCH TABLE Telemetry AS ss USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|2|2|SEARCH TABLE Services AS s USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)

我不知道为什么该排序不允许使用 TelemetryId。我真的需要这个查询更快。有什么帮助吗?

【问题讨论】:

第二个查询计划看起来更快。您测得的性能差多少? 第一次大约需要一秒钟,第二次大约需要三秒钟。 【参考方案1】: 指定的索引在 ([TelemetryId],[TimestampTicks]) 上,而不是 ([TimestampTicks]),并且 [TelemetryId] 上没有过滤条件。 如果测试数据库没有完整的工作数据卷,则测试中的执行计划可能无法反映生产中的执行计划。 在选择使用索引之前,数据库引擎会尝试对索引使用是否比表扫描更有效进行建模。如果预期数据量 > ~10% 的表,通常可能会忽略看起来有用的索引。 (但在这种情况下不太可能。) 追查想象中的性能问题会浪费很多时间。在这种情况下是否存在真正的性能问题?

【讨论】:

TelemetryId 上有过滤条件。它在 JOIN 中,据我了解,它被翻译为 Sqlite 中的 WHERE。 @Brannon:我认为这句话清楚地表明了索引的使用,只是不完全是你认为的方式和位置:“如果我反转索引,我实际上会得到更差的性能”。 短语“USE TEMP B-TREE”表示它没有使用 ORDER BY 子句的索引。

以上是关于为啥 Sqlite 不使用这个 ORDER BY 的索引?的主要内容,如果未能解决你的问题,请参考以下文章

在 SQLite 的 GROUP_CONCAT 函数中使用 ORDER BY 子句

为啥 ORDER BY 不对这个查询进行排序?

使用 ORDER BY 时出现数据类型不匹配错误

group_concat sqlite 和 order by

如何使用 SQLite 使用 UNION ALL 和 ORDER BY 进行排序

如何使用 SQL Order By 语句对结果进行排序,不区分大小写?