2010-10-14 12 views
4

Je suis confronté à un problème très étrange que je n'ai pas encore trouvé d'explication. Avec SQL Server 2008 et en utilisant le GROUP BY il commande mes colonnes sans ORDER BY spécifié. Voici un script qui illustre la situation.Pourquoi SQL Server 2008 commande-t-il lorsque vous utilisez un GROUP BY et qu'aucune commande n'a été spécifiée?

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 

Le premier SELECT retournera

4 
3 
2 
1 

Le second SELECT retournera

1 
2 
3 
4 

Selon le MSDN Documentation il est écrit: "La clause GROUP BY ne commande pas le jeu de résultats "

+2

Les documents MSDN ont l'air d'être mal formulés. Il * peut * ordonner le jeu de résultats, mais il vaut mieux ne pas faire de * suppositions * à propos de cette commande. Cela pourrait changer dans une future version. Ou, comme indiqué dans les réponses, il pourrait même changer si vous mettez plus de données dans votre tableau. –

Répondre

13

Pour répondre à cette question, regardez les plans de requête produits par les deux.

Le premier SELECT est un simple balayage de table, ce qui signifie qu'il produit des lignes dans l'ordre d'allocation. Comme il s'agit d'une nouvelle table, elle correspond à l'ordre dans lequel vous avez inséré les enregistrements.

Le deuxième SELECT ajoute un GROUP BY, que SQL Server implémente via un tri distinct puisque le nombre de lignes estimé est si bas. Si vous deviez avoir plus de lignes ou ajouter un agrégat à votre SELECT, cet opérateur pourrait changer.

Par exemple, essayez:

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 

En raison du nombre de lignes, cela se transforme en un agrégat de hachage, et maintenant il n'y a pas de tri dans le plan de requête. En l'absence de ORDER BY, SQL Server peut renvoyer les résultats dans n'importe quel ordre, et l'ordre dans lequel il revient est un effet secondaire de la façon dont il pense pouvoir renvoyer le plus rapidement les données.

+0

Le plan d'exécution affiche en effet un TRI DISTINCT lors du regroupement. –

+0

Bonne réponse! Merci pour la modification supplémentaire pour montrer la différence. –

6

Si vous ne spécifiez pas de clause order by, SQLServer est libre de renvoyer les résultats dans n'importe quel ordre.

Peut-être dans votre requête spécifique, il retournera les résultats commandés, mais cela ne signifie pas qu'il toujours resltsets de tri lors de l'utilisation d'une clause group by.

Peut-être (juste peut-être) il fait un certain agrégat de hachage pour calculer le groupe par et la table de hachage se trouve être triée par 1,2,3,4. Et puis retour des lignes dans l'ordre de hachage ...

1

Il s'agit d'une facette d'optimisation DB. Le moteur SQL doit généralement analyser les données dans l'ordre de la colonne groupée. Plutôt que de perdre du temps après, il laisse l'ensemble de données dans n'importe quel ordre analysé.

Il y a des situations où cela ne sera pas le cas (surtout si vous utilisez des fonctions d'agrégation). L'utilisation de la commande ORDER BY annule évidemment cette fonctionnalité (et par conséquent implique une charge un tout petit peu supplémentaire, pas assez pour s'inquiéter dans tous les cas sauf les plus extrêmes).

1

Vous pouvez également nettoyer vos instructions d'insertion ici. SQL Server 2008 a ajouté une nouvelle fonctionnalité pour les insertions.Exemple:

dans Inert TBL (CLMN) Valeurs (1), (2), (3) Chaque enregistrement n'a pas besoin de son propre instruction d'insertion et chacun est séparé par le coma.