2009-10-08 9 views
1

Lorsque j'utilise un calcul ou une sous-requête dans ma clause ORDER qui se trouve déjà dans ma clause SELECT, SQL sait-il juste commander par cette colonne? Ou recalcule-t-il tout pour chaque ligne lors du tri?Est-ce que la clause Order By recalcule la valeur dans SQL Server?

Par exemple, permet de dire que j'écris une terrible requête comme ceci:

SELECT EmployeeName, (SELECT COUNT(*) FROM Employee e2 WHERE MgrID = Employee.EmployeeID) 
FROM Employee 
ORDER BY (SELECT COUNT(*) FROM Employee e2 WHERE MgrID = Employee.EmployeeID) 

Ouais, je sais comment mieux écrire cette requête, et je sais comment utiliser ordinaux dans ma commande by-- mais si je ne le fais pas? Est-ce que SQL relance cette sous-requête pour chaque ligne, ou sait-elle qu'elle peut utiliser la valeur déjà dans la colonne 2?

Que diriez-vous de ORDERing sur une colonne qui utilise une fonction?

SELECT EmployeeName, LTRIM(RTRIM(BranchName)) FROM Employee 
ORDER BY LTRIM(RTRIM(BranchName)) 

Est-ce que ça rétrimne ma colonne BranchName pour faire le tri? J'ai regardé quelques plans d'exécution et il semble ne pas ajouter de calcul, mais j'ai pensé que je trouverais si cela est vrai comme une généralité au lieu de mes cas spécifiques.

La raison principale que je demande est que lorsque vous faites une opération fenêtrée, comme ROWNUMBER() OVER(ORDER BY EmployeeID), je ne peux pas utiliser une référence ordinale pour le ORDER BY. Donc, si l'une de mes colonnes est complexe, je discute parfois de la faire tomber dans une variable de table et ensuite de la trier à nouveau.

Répondre

1

la table du compte de sélection (*) sera numérisée deux fois. une fois pour la commande et une fois pour sélectionner. vous pouvez jouer plus avec dire en utilisant le top 100 sur les deux sous-requêtes etc pour voir ce qui se passe. Observer le nombre de lectures logiques produites par les requêtes.

vous pouvez le voir avec cette requête:

SET STATISTICS IO ON 

USE AdventureWorks 
GO 

SELECT (SELECT COUNT(*) FROM Sales.SalesOrderDetail WHERE SalesOrderID = SOH.SalesOrderID) AS c, * 
FROM Sales.SalesOrderHeader SOH 
ORDER by (SELECT COUNT(*) FROM Sales.SalesOrderDetail WHERE SalesOrderID = SOH.SalesOrderID) desc 
GO 

SELECT (SELECT COUNT(*) FROM Sales.SalesOrderDetail WHERE SalesOrderID = SOH.SalesOrderID) AS c, * 
FROM Sales.SalesOrderHeader SOH 
ORDER BY 1 desc 
+0

Oui, il semble que l'ajout à lui, mais si je alias le champ, il n'a pas besoin de re-scanner la table. MS doit ajouter un support d'alias dans le composant OVER windowed! –

1

Il seulement le genre une fois, le moteur lui-même peut trier par un nom d'alias vous donner la colonne

SELECT EmployeeName, (SELECT COUNT(*) FROM Employee e2 WHERE MgrID = Employee.EmployeeID) 
FROM Employee 
ORDER BY (SELECT COUNT(*) FROM Employee e2 WHERE MgrID = Employee.EmployeeID) 

pourrait aussi être exprimé comme

SELECT EmployeeName, (SELECT COUNT(*) FROM Employee e2 WHERE MgrID = Employee.EmployeeID) MyField 
FROM Employee 
ORDER BY myField 

Le moteur fera essentiellement la même chose, en donnant un nom temporaire à votre colonne à utiliser dans la clause order by.

+0

droit, mais je n'ai pas obtenu des alias pour travailler avec la clause OVER(). Vous ne pouvez pas faire quelque chose comme SELECT EmployeeName, (SELECT COUNT (*) de l'employé e2 OÙ MGRID = Employee.EmployeeID) MyField, ROW_NUMBER() OVER (ORDER BY MyField) comme rownumber de l'employé (je devrais avons choisi un vrai tableau auquel nous pouvons tous faire référence, mais les pubs supprimés par l'administrateur ici au travail) –

+0

Les alias dans une clause select ne sont pas disponibles dans cette clause select, pour toute utilisation. Logiquement, une clause select est tout à la fois. Vous pouvez utiliser des CTE ou des vues en ligne pour nommer le champ, puis l'utiliser ultérieurement. SELECT EmployeeName, MyField, ROW_NUMBER() OVER (ORDER BY MyField) en tant que numéro de client FROM (SELECT EmployeeName, (SELECT COUNT (*) FROM Employé e2 WHERE MgrID = Employee.EmployeeID) MyField FROM Employee) T –