GROUP BY和DISTINCT是否有区别?
有一天我学到了关于SQL的一些简单的东西:
SELECT c FROM myTbl GROUP BY C
具有与以下相同的结果:
SELECT DISTINCT C FROM myTble
我感到好奇的是,SQL引擎处理命令的方式有什么不同,还是真的是一回事?
我个人比较喜欢独特的语法,但我相信它比其他任何事都更习惯于习惯。
编辑:这不是一个关于聚合的问题。 了解使用GROUP BY
与聚合函数。
MusiGenesis的回答在function上是正确的,就你所说的问题而言; SQL Server足够聪明地认识到,如果你使用“Group By”而不使用任何聚合函数,那么你实际上的意思是“Distinct” – 因此它产生一个执行计划,就好像你只是使用“Distinct “。
不过,我认为重要的是要注意到汉克的反应 – 如果你不小心的话,“集体”和“不同”的骑士待遇可能会导致一些有害的瑕疵。 说这不是一个关于聚集的问题是不完全正确的,因为你在问两个SQL查询关键字之间的function差别,其中一个是用于聚合 ,另一个则不是。
有时锤子可以用螺丝刀驱动,但是如果你有方便的螺丝刀,为什么呢?
GROUP BY
允许您使用聚合函数,如AVG
, MAX
, MIN
, SUM
和COUNT
。 另一方面DISTINCT
只是删除重复。
例如,如果您有一堆购买logging,并且想要知道每个部门花了多less钱,则可以执行以下操作:
SELECT department, SUM(amount) FROM purchases GROUP BY department
这将为每个部门提供一行,包含部门名称以及该部门所有行中所有amount
值的总和。
没有区别 (在SQL Server中,至less)。 这两个查询使用相同的执行计划。
http://sqlmag.com/database-performance-tuning/distinct-vs-group
也许有区别,如果有涉及的子查询:
没有区别 (Oracle风格):
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212
如果您只想删除重复项,请使用DISTINCT
。 如果要应用聚合运算符( MAX
, SUM
, GROUP_CONCAT
,…或HAVING
子句),请使用GROUPY BY
。
我期望在执行过程中有细微差别的可能性。 我检查了Oracle 10g中这两行function相同的查询的执行计划:
core> select sta from zip group by sta; --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 58 | 174 | 44 (19)| 00:00:01 | | 1 | HASH GROUP BY | | 58 | 174 | 44 (19)| 00:00:01 | | 2 | TABLE ACCESS FULL| ZIP | 42303 | 123K| 38 (6)| 00:00:01 | --------------------------------------------------------------------------- core> select distinct sta from zip; --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 58 | 174 | 44 (19)| 00:00:01 | | 1 | HASH UNIQUE | | 58 | 174 | 44 (19)| 00:00:01 | | 2 | TABLE ACCESS FULL| ZIP | 42303 | 123K| 38 (6)| 00:00:01 | ---------------------------------------------------------------------------
中间操作略有不同:“HASH GROUP BY”和“HASH UNIQUE”,但估算的成本等是一致的。 然后我执行这些跟踪和两个实际操作计数是相同的(除了第二个由于caching不必做任何物理读取)。
但是我认为,因为操作名称是不同的,所以执行会遵循一些不同的代码path,从而打开更大的差异的可能性。
我认为你应该更喜欢这种用途的DISTINCT语法。 这不仅仅是习惯,更清楚地表明查询的目的。
对于您发布的查询,它们是相同的。 但对于其他查询,可能并非如此。
例如,它不是一样的:
SELECT C FROM myTbl GROUP BY C, D
如果对多列使用DISTINCT,那么结果集将不会像GROUP BY那样分组,您不能将集合函数与DISTINCT一起使用。
它们具有不同的语义,即使它们恰好在您的特定数据上具有相同的结果。
我读了所有上述评论,但没有看到任何人指出除了聚合位之外,组合之间的主要区别。
不同的是返回所有的行然后去重复它们,而Group By逐一删除重复的行。
这意味着他们可以产生不同的结果!
例如,下面的代码会产生不同的结果:
SELECT distinct ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable SELECT ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable GROUP BY Name
如果表中有10个名称,其中1个是另一个的副本,则第一个查询返回10行,而第二个查询返回9行。
原因是我上面所说的,所以他们可以有不同的performance!
与单纯的重复删除function的观点有什么不同?
除了与DISTINCT
不同的是, GROUP BY
允许汇总每个组的数据(这已经被许多其他答案提及),我认为最重要的差异是这两个操作“发生”在两个非常不同的步骤在SELECT
语句中执行的操作的逻辑顺序 。
这是最重要的操作:
-
FROM
(包括JOIN
,APPLY
等) -
WHERE
-
GROUP BY
(可以删除重复项) - 聚合
-
HAVING
- 窗口function
-
SELECT
-
DISTINCT
(可以删除重复项) -
UNION
,INTERSECT
,EXCEPT
(可以删除重复项) -
ORDER BY
-
OFFSET
-
LIMIT
正如你所看到的,每个操作的逻辑顺序影响着可以做什么以及它如何影响后续操作。 特别是, GROUP BY
操作“发生在” SELECT
操作(投影) 之前的事实意味着:
- 它不依赖于投影(这可能是一个优点)
- 它不能使用投影中的任何值(这可能是一个缺点)
1.它不依赖于投影
不依赖于投影的例子是有用的,如果你想计算不同值的窗口函数:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn FROM film GROUP BY rating
当对Sakila数据库运行时,这会产生:
rating rn ----------- G 1 NC-17 2 PG 3 PG-13 4 R 5
DISTINCT
很容易达不到:
SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn FROM film
该查询是“错误”,并产生如下所示:
rating rn ------------ G 1 G 2 G 3 ... G 178 NC-17 179 NC-17 180 ...
这不是我们想要的。 DISTINCT
操作“发生在”投影之后,所以我们不能再删除DISTINCT
等级,因为窗口函数已经被计算和投影了。 为了使用DISTINCT
,我们必须嵌套查询的那一部分:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn FROM ( SELECT DISTINCT rating FROM film ) f
附注: 在这种情况下,我们也可以使用DENSE_RANK()
SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn FROM film
2.它不能使用投影中的任何值
SQL的一个缺点就是它的冗长性。 出于和我们以前见过的一样的原因(即操作的逻辑顺序),我们不能“容易地”按照我们所预测的东西进行分组。
这是无效的SQL:
SELECT first_name || ' ' || last_name AS name FROM customer GROUP BY name
这是有效的(重复expression式)
SELECT first_name || ' ' || last_name AS name FROM customer GROUP BY first_name || ' ' || last_name
这也是有效的(嵌套expression式)
SELECT name FROM ( SELECT first_name || ' ' || last_name AS name FROM customer ) c GROUP BY name
我在博客文章中更深入地写了这个话题
GROUP BY具有与DISTINCT函数不同(heh)的非常具体的含义。
GROUP BY使查询结果使用选定的expression式进行分组,然后可以应用聚合函数,这些函数将作用于每个组,而不是整个结果集。
以下是一个可能有所帮助的例子:
给定一个如下所示的表格:
name ------ barry dave bill dave dave barry john
这个查询:
SELECT name, count(*) AS count FROM table GROUP BY name;
将会产生这样的输出:
name count ------------- barry 2 dave 3 bill 1 john 1
这与使用DISTINCT显然是非常不同的。 如果你想分组你的结果,使用GROUP BY,如果你只想要一个特定列的唯一列表,使用DISTINCT。 这将使您的数据库有机会针对您的需求优化查询。
如果您使用的是没有任何聚合函数的GROUP BY,那么在内部它将被视为DISTINCT,所以在这种情况下GROUP BY和DISTINCT没有区别。
但是,当您提供DISTINCT子句时更好地使用它来查找唯一的logging,因为GROUP BY的目标是实现聚合。
group by用于合计操作 – 就像当你想获得按列C细分的Bs数一样
select C, count(B) from myTbl group by C
不同的是它听起来像 – 你得到独特的行。
在sql server 2005中,它看起来像查询优化器能够优化我运行的简单例子中的差异。 不知道,如果你能在所有的情况下,依靠这一点,但。
当你的意思是DISTINCT时,请不要使用GROUP BY,即使它们碰巧是一样的。 我假设你正试图从查询中减less毫秒数,而且我必须指出,开发者的时间比计算机时间要贵得多。
在那个特定的查询中没有区别。 但是,当然,如果你添加任何聚合列,那么你将不得不使用group by。
从“SQL语言”的angular度来看,这两个结构是等价的,你select哪一个是我们必须做的那些“生活方式”select之一。 我认为DISTINCT是一个很好的例子,因为它更加明确(因此对于inheritance你的代码的人会更加考虑),但这并不意味着GROUP BY构造是无效的select。
我认为这个“GROUP BY是为了聚合”是错误的重点。 民间应该知道,设置函数(MAX,MIN,COUNT等)可以省略,这样他们就可以了解编码器的意图了。
理想的优化器将识别等效的SQL结构,并且总会相应地select理想的计划。 对于您select的真实生活SQL引擎,您必须testing:)
PS注意DISTINCT关键字在select子句中的位置可能会产生不同的结果,例如对比度:
SELECT COUNT(DISTINCT C) FROM myTbl; SELECT DISTINCT COUNT(C) FROM myTbl;
你只注意到,因为你正在select一个列。
尝试select两个字段,看看会发生什么。
Group By是为了像这样使用:
SELECT name, SUM(transaction) FROM myTbl GROUP BY name
这将显示每个人的所有交易的总和。
我知道这是一个旧的职位。 但是,碰巧有一个查询使用组,只是在蟾蜍中使用该查询时返回不同的值,而oracle报告一切正常,我的意思是一个很好的响应时间。 当我们从Oracle 9i迁移到11g时,蟾蜍的响应时间非常好,但是在报告中花了约35分钟完成报告,使用以前的版本花了大约5分钟。
解决方法是改变组,并使用DISTINCT,现在报告运行约30秒。
我希望这对于有相同情况的人有用。
我一直理解的方式是,使用不同的分组是按照您select的顺序select的每个字段进行分组。
即:
select distinct a, b, c from table;
是相同的:
select a, b, c from table group by a, b, c
我以前有这个问题,我需要从我的400万行表中追加三列(三列到新表的一个新列),但只有不同的列。
所以我用“group by”方法运行了包含这个查询的存储过程,花了32分钟。 然后我又跑了一遍,但用“明显”的方法,花了25分钟。
这是相同的结果,但用第二种方法要快一点
除了聚合函数的使用之外,group by和distinct clause之间没有显着的区别。 两者都可以用来区分价值,但是如果在性能上来看group by是更好的。 当使用distinct关键字时,内部使用可以在执行计划中查看的sorting操作。
试试简单的例子
声明@tmpresult表(Id tinyint)
插入@tmpresultselect5 Union allselect2 Union allselect3 Union allselect4
从@tmpresult中select不同的ID