MySQL上的GROUP BY非常慢。与索引无关

时间:2017-04-16 11:36:40

标签: mysql performance group-by

有很多"为什么我的GROUP BY这么慢"关于SO的问题,其中大部分似乎都是用索引解决的。

我的情况不同。事实上,我对非索引数据进行了GROUP BY,但这是故意的,而且我不能改变它。

但是,当我将GROUP BY的性能与没有GROUP BY的类似查询(也没有使用索引)的性能进行比较时,GROUP BY查询的速度会慢一个数量级。

查询缓慢:

SELECT someFunc(col), COUNT(*) FROM tbl WHERE col2 = 42 GROUP BY someFunc(col)

结果是这样的:

someFunc(col)    COUNT(*)
=========================
a                100000
b                80000
c                20
d                10

快速(呃)查询:

SELECT 'a', COUNT(*) FROM tbl WHERE col2 = 42 AND someFunc(col) = 'a'
UNION
SELECT 'b', COUNT(*) FROM tbl WHERE col2 = 42 AND someFunc(col) = 'b'
UNION
SELECT 'c', COUNT(*) FROM tbl WHERE col2 = 42 AND someFunc(col) = 'c'
UNION
SELECT 'd', COUNT(*) FROM tbl WHERE col2 = 42 AND someFunc(col) = 'd'

尽管实际运行了多个单独的查询,但此查询会产生相同的结果并且大约快十倍

我发现从MySQL的角度来看它们并不相同,因为MySQL事先并不知道someFunc(col)只能产生四个不同的值,但看起来它们似乎差别太大了。

我认为这与GROUP BY在幕后做的一些工作有关(创建临时表和类似的东西)。

我是否可以调整配置参数以使GROUP BY更快?

有没有办法暗示MySQL在查询本身内做不同的事情? (例如,不要创建临时表)。

编辑: 实际上我上面提到的someFunc(col)实际上是JSON_EXTRACT()。我只是尝试将提取的特定数据复制到自己的(未编入索引的)列中,这使得GROUP BY非常快,而且确实比替代的UNIONed查询更快。

问题仍然存在:为什么? JSON_EXTRACT()可能很慢但是四个查询的速度应该一样慢(实际上速度较慢,因为扫描的行数较多)。另外,我读过MySQL JSON是为快速读取而设计的。

我看到的差异超过200秒(GROUP BY与JSON_EXTRACT())和1-2秒(实际未编制索引列上CONCAT()上的GROUP BY)。< / p>

1 个答案:

答案 0 :(得分:1)

首先,对于此查询:

SELECT someFunc(col), COUNT(*)
FROM tbl
WHERE col2 = 42
GROUP BY someFunc(col);

你应该在tbl(col2, col)上有一个索引。这是查询的覆盖索引,因此它应该提高性能。

小注意:第二个版本应使用UNION ALL而不是UNION。消除重复项的性能差异在4行中很小,但在这些情况下UNION是一个坏习惯。

我不确定什么会导致10倍性能减慢。我可以很容易地想到两件事会使第二版更快。

首先,此查询为每个正在处理的行调用someFunc()两次。如果这是一项昂贵的操作,那么这将占查询负载增加的一半。如果第一个版本在所有行上调用someFunc()而不是仅匹配行,则可能会大得多。

要查看这是否是一个问题,您可以尝试:

SELECT someFunc(col) as someFunc_col, COUNT(*)
FROM tbl
WHERE col2 = 42
GROUP BY someFunc_col;

其次,做4个较小的GROUP BY s会比做1个较大的GROUP BY快一点。这是因为closestEdge使用排序,排序为O(n log(n))。因此,排序100,000行和80,000行应该比排序180,000快。您的案例大约有两组数据的一半。这可能会导致高达50%的差异(虽然如果这么大,我会感到惊讶)。