Ali*_*imi 1 mysql performance join query-performance
我有两个表,其中一个包含下载 url 的历史记录,而另一个表包含有关每个 url 的详细信息。
以下查询按过去一小时内的重复次数对 URL 进行分组。
SELECT COUNT(history.url) as total, history.url
FROM history
WHERE history.time > UNIX_TIMESTAMP()-3600
GROUP BY history.url
ORDER BY COUNT(history.url) DESC
LIMIT 30
Run Code Online (Sandbox Code Playgroud)
上面的查询大约需要 800ms 执行,不够快,但可以接受,
但是,当与缓存表连接时,新查询大约需要25s才能执行,速度非常慢。
SELECT th.total, th.url, tc.url, tc.json
FROM (SELECT COUNT(history.url) as total, history.url
FROM history
WHERE history.time > UNIX_TIMESTAMP()-3600
GROUP BY history.url
ORDER BY COUNT(history.url) DESC
LIMIT 30
) th
INNER JOIN (SELECT cache.url, cache.json FROM cache) tc
ON th.url = tc.url
GROUP BY th.url
ORDER BY th.total DESC
LIMIT 30
Run Code Online (Sandbox Code Playgroud)
我认为这可能会发生,因为在“tc”中,正在加载整个缓存表,并且它包含超过 100 万个条目。
当我使用第一个查询,然后以编程方式迭代结果,然后从缓存中为每个结果运行 SELECT 查询时,速度要快得多。有什么办法可以加快我的第二次查询速度吗?
PS我使用的是InnoDB
通常最好对参与 JOIN 谓词或 WHERE 子句的列建立索引。一个常见的错误是创建多个单列索引而不是较少的多列索引。在这里,我们可以从历史记录中的 url 和时间中受益(查看针对这些表的所有查询,您可能会发现可以向这些索引添加其他列):
CREATE INDEX x01_history_url ON HISTORY (URL, TIME);
CREATE INDEX x01_cache_url ON CACHE (URL);
Run Code Online (Sandbox Code Playgroud)
其次,尝试解除查询的嵌套。MySQL 对它能够执行的查询重写类型有限制,因此嵌套可能会导致不必要的开销。
SELECT COUNT(th.url) as total, tc.url, tc.json
FROM history th
JOIN cache tc
ON th.url = tc.url
WHERE th.time > UNIX_TIMESTAMP()-3600
GROUP BY tc.url, tc.json
ORDER BY COUNT(th.url) DESC
LIMIT 30
Run Code Online (Sandbox Code Playgroud)
请注意,此查询在语义上与您的查询不同,因此您可能会得到不同的结果。如果这是一个问题,您可能需要像以前一样将 LIMIT 30 结构保留在子查询中。您还可以考虑是否可以为 CACHE 添加类似的限制,您必须调查多少 CACHE 行才能总共获得 30 行,是否有上限?
INNER JOIN (SELECT cache.url, cache.json
FROM cache
ORDER BY ? LIMIT ?) tc
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
23968 次 |
最近记录: |