我的理解是,在(My)SQL中,SELECT DISTINCT
应该对所有列的GROUP BY
做同样的事情,除了GROUP BY
进行隐式排序,所以这两个查询应该是一样的:
SELECT boardID,threadID FROM posts GROUP BY boardID,threadID ORDER BY NULL LIMIT 100;
SELECT DISTINCT boardID,threadID FROM posts LIMIT 100;
他们都给了我相同的结果,他们从EXPLAIN
得到相同的输出:
+----+-------------+-------+------+---------------+------+---------+------+---------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-----------------+
| 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1263320 | Using temporary |
+----+-------------+-------+------+---------------+------+---------+------+---------+-----------------+
1 row in set
但在我的桌面上,DISTINCT
的查询会立即返回,GROUP BY
的查询大约需要4秒。我已禁用查询缓存来测试它。
有25列,所以我也尝试创建一个单独的表,其中只包含 boardID和threadID列,但同样的问题和性能差异仍然存在。
我 使用GROUP BY
代替DISTINCT
,因此我可以添加其他列,而不会将它们包含在DISTINCT
的评估中。所以现在我不知道如何继续。为什么会有区别?
答案 0 :(得分:3)
首先,您的查询不完全相同 - GROUP BY具有ORDER BY,但DISTINCT没有。
请注意,在任何一种情况下,都不使用索引,这对性能不利。
我建议为(boardid, threadid)
创建复合索引 - 这应该让两个查询都能使用索引,并且两者都应该开始更快地工作
编辑:解释为什么SELECT DISTINCT ... LIMIT 100
在没有索引时比GROUP BY ... LIMIT 100
快。
要执行第一个语句(SELECT DISTINCT
),服务器只需要获取100个,可能稍微多一行,并且只要它有100个不同的行就可以停止 - 没有更多的工作要做。
这是因为原始SQL语句没有指定任何顺序,因此服务器可以随意提供任意100行,只要它们是不同的。但是,如果您要在ORDER BY
之前对此进行任何无索引LIMIT 100
,则此查询将立即变慢。
要执行第二个语句(SELECT ... GROUP BY ... LIMIT 100
),MySQL始终使用GROUP BY中使用的相同列进行隐式ORDER BY
。换句话说,它在获取前几个100多行之后不能快速停止,直到获取,分组和排序所有记录。在那之后,它会应用你添加的ORDER BY NULL
(我猜这不会做太多,但放弃它可能会加快速度),最后,它会获得前100行并抛弃剩余的结果。当然,这很慢。
当你有复合索引时,在任何一种情况下都可以非常快速地完成所有这些步骤。