在按不同表中的列排序时避免使用临时表

don*_*onk 6 mysql optimization profiler temporary-tables

所以我在这里有这个 MySQL InnoDB 查询:

SELECT s.vid, s.body, s.timestamp, COUNT(v.id) AS votecnt
FROM stories s
LEFT JOIN votes v ON s.vid = v.vid
WHERE s.lv = 1
AND s.status = 1
GROUP BY s.vid
ORDER BY votecnt DESC
Run Code Online (Sandbox Code Playgroud)

分析显示,运行此查询所需时间的 93% 以上需要复制到结果临时表,以便通过votecnt 进一步排序。可以做些什么来使其更快?

解释输出:

| 1 | 简单 | | 参考 | 最新 | 最新 | 2 | 常量,常量 | 19873 | 使用哪里;使用临时;使用文件排序 |

| 1 | 简单 | v | 参考 | 投票 | 投票 | 4 | sikna_ci.s.vid | 1 | 使用索引 |

Rol*_*DBA 7

您可能还需要增加以下变量:

如果这些太小,tmptable 会很快进入磁盘。

如果这些太大,当超过限制时 tmp 表会很快进入,但由于在完成 tmptable 的使用之前将大内存 tmptable 移动到磁盘而造成间歇性。

因此,您需要对这些 tmp 表变量进行严格的平衡。这些变量也具有与此答案中提到的 @DTest 相同的每线程约束。

顺便说一句,理论上排序缓冲区本身就是一个 tmptable,尽管由不同的会话选项(sort_buffer_size)控制。由于您使用的是分组列而不是纯表建立的列进行排序,因此临时表在某种程度上是不可避免的。


Der*_*ney 6

按优化排序的手册页可能对您有所帮助,特别是文章末尾的建议摘要。在增加 sort_buffer_size 和 read_rnd_buffer_size 时要小心,因为我相信它们是“每个线程”的值,这意味着每个 mysql 连接线程将获得与每个值关联的内存。如果太大,您会发现您的服务器很快就会耗尽内存。