有很多"为什么我的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>
答案 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%的差异(虽然如果这么大,我会感到惊讶)。