在MySQL中SELECT DISTINCT或GROUP BY更快吗?
如果我有一张桌子
CREATE TABLE users ( id int(10) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL, profession varchar(255) NOT NULL, employer varchar(255) NOT NULL, PRIMARY KEY (id) )
我想获得profession
领域的所有独特价值,什么会更快(或推荐):
SELECT DISTINCT u.profession FROM users u
要么
SELECT u.profession FROM users u GROUP BY u.profession
?
它们本质上是相同的(事实上,这是一些数据库如何在DISTINCT
实现DISTINCT
)。
如果其中一个更快,这将是DISTINCT
。 这是因为,虽然两者是相同的,但是查询优化器必须知道你的GROUP BY
没有利用任何组成员,只是他们的关键。 DISTINCT
使得这个明确,所以你可以离开稍微优化的优化器。
如有疑问,testing!
如果你有一个profession
的指数,这两个是同义词。
如果你不这样做,那么使用DISTINCT
。
MySQL
GROUP BY
对结果进行sorting。 你甚至可以这样做:
SELECT u.profession FROM users u GROUP BY u.profession DESC
并按照DESC
顺序sorting你的职业。
DISTINCT
创build一个临时表并使用它来存储重复项。 GROUP BY
也是这样做的,但是之后对不同的结果进行sorting。
所以
SELECT DISTINCT u.profession FROM users u
如果你没有profession
的指数,速度会更快。
去尽可能最简单和最短的 – DISTINCT似乎更多的是你要找的只是因为它会给你正确的答案,你需要的只有这一点!
上面的所有答案都是正确的,对于单列上的DISTINCT与单列上的GROUP BY的情况。 每个数据库引擎都有自己的实现和优化,如果你关心的是很less的差别(在大多数情况下),那么你必须testing特定的服务器和特定的版本! 由于实现可能会改变…
但是,如果您在查询中select多个列,那么DISTINCT本质上是不同的! 因为在这种情况下,它将比较所有行的所有列,而不是仅一列。
所以如果你有这样的东西:
// This will NOT return unique by [id], but unique by (id,name) SELECT DISTINCT id, name FROM some_query_with_joins // This will select unique by [id]. SELECT id, name FROM some_query_with_joins GROUP BY id
认为DISTINCT关键字通过您指定的第一列来区分行是常见的错误,但DISTINCT是这种方式的一般关键字。
所以,你必须小心,不要把上面的答案作为正确的所有情况…你可能会感到困惑,并得到错误的结果,而你想要的只是优化!
在postgres的某些场合(不了解其他dbs),可能会比group更慢。
testing的例子:
postgres=# select count(*) from (select distinct i from g) a; count 10001 (1 row) Time: 1563,109 ms postgres=# select count(*) from (select i from g group by i) a; count 10001 (1 row) Time: 594,481 ms
http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I
所以要小心… 🙂
似乎查询不完全一样。 至less对于MySQL来说。
比较:
- 描述从northwind.products中select不同的产品名称
- 用产品名称描述northwind.products组中的产品名称
第二个查询在Extra中额外提供了“使用filesort”。
分组比由于分组不同而不同,并且明显地避免了分组。 但是,如果你想通过产生不同的结果作为不同的秩序由null ..
SELECT DISTINCT u.profession FROM users u
等于
SELECT u.profession FROM users u GROUP BY u.profession order by null
(更多function说明)
有些情况下,你必须使用GROUP BY,例如,如果你想获得每个雇主的雇员数量:
SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer
在这种情况下, DISTINCT u.employer
无法正常工作。 也许有办法,但我不知道。 (如果有人知道如何使用DISTINCT进行查询,请添加注释!)
在MySQL中 ,“ Group By
”使用额外的步骤: filesort
。 我意识到DISTINCT
比GROUP BY
快,这是一个惊喜。
经过严格的testing,我们得出GROUP BY更快的结论
SELECT sql_no_cache opnamegroep_intern FROM telwerken
WHERE opnemergroep
IN(7,8,9,10,11,12,13)group by opnamegroep_intern
635共计0.0944秒Weergave面包车logging0 – 29(635 totaal,查询duurde 0.0484秒)
SELECT sql_no_cache distinct(opnamegroep_intern)FROM telwerken
WHERE opnemergroep
IN(7,8,9,10,11,12,13)
635共0.2117秒(几乎100%慢)Weergave面包车logging0 – 29(635头,询问duurde 0.3468秒)
这不是一个规则
对于每个查询….尝试单独不同然后分组…比较时间来完成每个查询和使用更快….
在我的项目中,有时我会使用group和other
这是一个简单的方法,将打印每个查询的2个不同的时间。
DECLARE @t1 DATETIME; DECLARE @t2 DATETIME; SET @t1 = GETDATE(); SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT SET @t2 = GETDATE(); PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar); SET @t1 = GETDATE(); SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY SET @t2 = GETDATE(); PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);
或者尝试SET STATISTICS TIME(Transact-SQL)
SET STATISTICS TIME ON; SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY SET STATISTICS TIME OFF;
它只显示parsing,编译和执行每个语句所需的毫秒数,如下所示:
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 2 ms.
如果您不需要执行任何组函数(总和,平均值等等,以防将数字数据添加到表中),请使用SELECT DISTINCT。 我怀疑它更快,但我没有什么可以显示的。
无论如何,如果您担心速度,请在列上创build一个索引。
SELECT DISTINCT将始终与GROUP BY相同或更快。 在某些系统(如Oracle)上,对于大多数查询,它可能被优化为与DISTINCT相同。 在其他人(如SQL Server)上,速度可能会更快。
如果问题允许,请尝试使用EXISTS,因为它已经过优化,一旦find结果就立即结束(并且不要缓冲任何响应),所以,如果您只是想为这样的WHERE子句规范化数据
SELECT FROM SOMETHING S WHERE S.ID IN ( SELECT DISTINCT DCR.SOMETHING_ID FROM DIFF_CARDINALITY_RELATIONSHIP DCR ) -- to keep same cardinality
更快的反应是:
SELECT FROM SOMETHING S WHERE EXISTS ( SELECT 1 FROM DIFF_CARDINALITY_RELATIONSHIP DCR WHERE DCR.SOMETHING_ID = S.ID )
这并不总是可能的,但是如果可用,您将看到更快的响应。