2010-10-14 37 views
4

我遇到了一个很奇怪的问题,我还没有找到任何解释。使用SQL Server 2008并使用GROUP BY,它会在没有指定任何ORDER BY的情况下对我的列进行排序。这是一个演示情况的脚本。为什么SQL Server 2008在使用GROUP BY时没有指定顺序?

CREATE TABLE #Values (FieldValue varchar(50)) 

;WITH FieldValues AS 
(
    SELECT '4' FieldValue UNION ALL 
    SELECT '3' FieldValue UNION ALL 
    SELECT '2' FieldValue UNION ALL 
    SELECT '1' FieldValue 
) 
INSERT INTO #Values (FieldValue) 
SELECT 
    FieldValue 
FROM FieldValues 

-- First SELECT demonstrating they are ordered DESCENDING 
SELECT 
    FieldValue 
FROM #Values 

-- Second SELECT demonstrating they are ordered ASCENDING 
SELECT 
    FieldValue 
FROM #Values 
GROUP BY 
    FieldValue 

DROP TABLE #Values 

第一个SELECT返回

4 
3 
2 
1 

第二个SELECT将返回

1 
2 
3 
4 

根据它指出了MSDN Documentation:“GROUP BY子句不下令结果集

+2

MSDN文档听起来像他们措辞不佳。它*可能会对结果集进行排序,但您最好不要对该排序做出任何*假设*。它可能在未来的版本中发生变化。或者,如答案中所述,如果您在表格中添加更多数据,甚至可能会改变。 – 2010-10-14 23:10:00

回答

13

要回答此问题,请查看两者生成的查询计划。

第一个SELECT是一个简单的表扫描,这意味着它会按分配顺序生成行。由于这是一张新表,它与您插入记录的顺序相符。

第二个SELECT添加了一个GROUP BY,SQL Server通过不同的排序实现,因为估计的行数非常少。如果您有更多的行或将聚合添加到您的SELECT,此操作符可能会更改。

例如,尝试:

CREATE TABLE #Values (FieldValue varchar(50)) 

;WITH FieldValues AS 
(
    SELECT '4' FieldValue UNION ALL 
    SELECT '3' FieldValue UNION ALL 
    SELECT '2' FieldValue UNION ALL 
    SELECT '1' FieldValue 
) 
INSERT INTO #Values (FieldValue) 
SELECT 
    A.FieldValue 
FROM FieldValues A 
CROSS JOIN FieldValues B 
CROSS JOIN FieldValues C 
CROSS JOIN FieldValues D 
CROSS JOIN FieldValues E 
CROSS JOIN FieldValues F 

SELECT 
    FieldValue 
FROM #Values 
GROUP BY 
    FieldValue 

DROP TABLE #Values 

由于行数,这变成一个哈希聚集,现在有查询计划没有排序。

没有ORDER BY,SQL Server可以以任何顺序返回结果,它返回的顺序是它认为它能够最快速地返回数据的副作用。

+0

执行计划确实在分组时显示DISTINCT SORT。 – 2010-10-14 23:14:43

+0

很好的回应!感谢您的额外修改,以显示不同之处。 – 2010-10-14 23:16:28

6

如果您未指定order by子句,则SQLServer可以按任意顺序自由返回结果。

也许在您的具体查询中,它会返回结果排序,但这并不意味着它会总是使用group by子句时排序resltsets。

也许(也许)它正在做一些哈希聚合来计算组,并且哈希表碰巧按1,2,3,4排序。然后按散列顺序返回行...

1

这是一个数据库优化方面。 SQL引擎通常必须按照分组列的顺序解析数据。而不是浪费时间,它会以任何分析的顺序离开数据集。

有些情况下不会出现这种情况(尤其是使用聚合函数时)。使用ORDER BY命令显然会覆盖这个功能(因此意味着稍微有点额外的负载,但是除了最极端的情况外,还不足以担心)。

1

你也可以在这里清理你的insert语句。 SQL Server 2008为插入添加了一项新功能。例如:

惰性成TBL(clmn) 值(1), (2), (3) 每个记录并不需要它自己的INSERT语句,每一方都昏迷分开。

相关问题