3

当我在查询中添加 ORDER BY 语句时,它变得非常慢。

这是我没有 ORDER BY 的查询:

SELECT ClientIpAddress, Agentstring, Count(ClientIpAddress) AS Count FROM LogEntries
WHERE SiteIisId = 3 AND DateTime >= '13-09-2012 00:00:00'
GROUP BY ClientIpAddress, Agentstring
LIMIT 5

ET:1毫秒

现在使用 ORDER BY:

SELECT ClientIpAddress, Agentstring, Count(ClientIpAddress) AS Count FROM LogEntries
WHERE SiteIisId = 3 AND DateTime >= '13-09-2012 00:00:00'
GROUP BY ClientIpAddress, Agentstring
ORDER BY Count DESC
LIMIT 5

东部时间:294 毫秒

我正在查询的表包含 1.380.855 行。

这是我正在使用的索引:

CREATE INDEX "LogEntries_MostActiveClients" ON "LogEntries" ("ClientIpAddress" ASC, "Agentstring" ASC, "SiteIisId" ASC, "DateTime" DESC)

使用EXPLAIN QUERY PLANSqlite 告诉我它正在使用我的索引扫描表并TEMB B-TREE用于我的 Order By。

我该如何克服这个问题?显然我无法索引Count,那该怎么办?

太感谢了!

4

2 回答 2

1

当您单步执行结果集时,SQLite 会尝试即时计算尽可能多的值。

因此,在您的第一个查询中,SQLite 永远不需要对表中的所有地址/代理值进行分组;一旦它通过某个索引读取了前五个ClientIpAddress/Agentstring组合的记录,它就可以停止。

在您的第二个查询中,这是不可能的:必须完全计算所有地址/代理组,然后才能对其进行排序并选择前五个。

要排序的临时结果中的记录已经在缓存中,并且比原始表中的数据小,所以我猜大部分时间不是用于排序,而是用于分组。

如果排序是问题,并且如果您估计五个最大计数有多大,您可以尝试添加一个HAVING "Count" >= some_limit子句来减少要排序的记录数。

您无法采取任何措施来避免分组。您可以尝试的只是通过通用优化获得小的改进,例如:

  • 将 SQLite 的页面缓存增加到工作集的大小;和
  • 创建一个覆盖索引以避免在表本身中进行查找(您已经有了)。

另一种方法是预先计算此查询的值:与您的 有一个单独的表Count,并在您添加日志条目时更新它。这将使这些更新变慢,并且您必须确定时间戳使用的粒度。

于 2012-10-14T15:11:36.487 回答
0

使用此处的 SQLite 合并测试您的应用程序。

理查德·希普最近宣布:

我们最近对 SQLite 中的查询优化器进行了许多重大改进。特别是,最新的代码更好地识别何时可以通过仔细选择索引和扫描顺序来满足 ORDER BY 子句,而无需进行任何排序。这种优化可以显着提高具有大型结果集的查询的性能。

电子邮件线程在这里

于 2012-10-14T03:21:34.913 回答