当我向我的查询添加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:1ms
现在使用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
ET:294 ms
我查询的表包含1.380.855行。
这是我正在使用的索引:
CREATE INDEX "LogEntries_MostActiveClients" ON "LogEntries" ("ClientIpAddress" ASC, "Agentstring" ASC, "SiteIisId" ASC, "DateTime" DESC)
使用EXPLAIN QUERY PLAN
Sqlite告诉我它正在使用我的索引扫描表格并使用TEMB B-TREE
作为我的订单依据。
我该如何克服这个问题?显然我无法索引Count
,那该怎么办?
万分感谢!
答案 0 :(得分:1)
当您逐步执行结果集时,SQLite会尝试计算尽可能多的值动态。
因此,在您的第一个查询中,SQLite永远不需要对表中的所有地址/代理值进行分组;只要它通过某个索引读取了前五个ClientIpAddress
/ Agentstring
组合的记录,就可以停止。
在第二个查询中,这是不可能的:所有地址/代理组必须先完全计算,然后才能对它们进行排序,并选择前五个。
要排序的临时结果中的记录已经在缓存中,并且小于原始表中的数据,因此我猜大多数时间不用于排序,而是分组。
如果排序是问题,并且如果您估计了五个最大计数的大小,则可以尝试添加HAVING "Count" >= some_limit
子句以减少要排序的记录数。
您无法避免分组。 您可以尝试的是通过通用优化获得小的改进,例如:
另一种方法是预先计算此查询的值:拥有一个包含Count
的单独表,并在添加日志条目时更新它。这将使这些更新变慢,您将不得不确定用于时间戳的粒度。
答案 1 :(得分:0)