この質問は、実行の順序に関するものではありません。それはちょうどORDER BYについてです。
標準的な実行では次のとおりです。
- から
- どこ
- グループ化
- 持っている
- 選択する
- オーダーバイ
- 上
編集: この質問は多かれ少なかれ「SQL Server は ORDER BY 式を実行するときに短絡評価を適用しますか?」という問題でした。答えは SOMETIMES です! 合理的な理由が見つからないだけです。編集#4を参照してください。
ここで、次のようなステートメントがあるとします。
DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
Customers.Name
FROM
Customers
WHERE
Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
Contacts.LastName ASC, --STATEMENT1
Contacts.FirstName ASC, --STATEMENT2
(
SELECT
MAX(PurchaseDateTime)
FROM
Purchases
WHERE
Purchases.CustomerID = Customers.CustomerID
) DESC --STATEMENT3
これは私が実行しようとしている実際のステートメントではなく、単なる例です。ORDER BY ステートメントは 3 つあります。3 番目のステートメントは、姓と名が一致するまれなケースにのみ使用されます。
姓が重複していない場合、SQL Server は ORDER BY ステートメント #2 と #3 を実行しませんか? また、論理的には、姓と名が重複していない場合、SQL Server はステートメント #3 を実行します。
これは本当に最適化のためです。Purchases テーブルからの読み取りは、最後の手段にすぎません。私のアプリケーションの場合、「CustomerID」でグループ化された「Purchases」からすべての「PurchaseDateTime」を読み取るのは効率的ではありません。
Purchases で CustomerID、PurchaseDateTime のインデックスを構築するような提案ではなく、私の質問に関連する回答を保持してください。問題は、SQL Server が不要な ORDER BY ステートメントをスキップするかどうかです。
編集: どうやら、SQL Server は、行が 1 つある限り、常にすべてのステートメントを実行します。1行であっても、これによりゼロ除算エラーが発生します。
DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
Customers.Name
FROM
Customers
WHERE
Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
Contacts.LastName ASC, --STATEMENT1
Contacts.FirstName ASC, --STATEMENT2
1/(Contacts.ContactID - Contacts.ContactID) --STATEMENT3
Edit2:どうやら、これはゼロ除算を与えません:
DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
Customers.Name
FROM
Customers
WHERE
Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
Contacts.LastName ASC, --STATEMENT1
Contacts.FirstName ASC, --STATEMENT2
CASE WHEN 1=0
THEN Contacts.ContactID
ELSE 1/(Contacts.ContactID - Contacts.ContactID)
END --STATEMENT3
ええと、私の質問に対する最初の答えは「はい」です。実行しますが、適切な CASE WHEN で実行を停止できるのは素晴らしいことです。
編集 3: 適切な CASE WHEN を使用して ORDER BY ステートメントの実行を停止できます。秘訣は、それを適切に使用する方法を理解することだと思います。CASE WHEN は、私が望むもの、つまり ORDER BY ステートメントでの短絡実行を提供します。SSMS で実行計画を比較したところ、CASE WHEN ステートメントによっては、明確に見える SELECT/FROM ステートメントであっても Purchases テーブルがまったくスキャンされません。
DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
Customers.Name
FROM
Customers
WHERE
Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
Contacts.LastName ASC, --STATEMENT1
Contacts.FirstName ASC, --STATEMENT2
CASE WHEN 1=0
THEN
(
SELECT
MAX(PurchaseDateTime)
FROM
Purchases
WHERE
Purchases.CustomerID = Customers.CustomerID
)
ELSE Customers.DateOfBirth
END DESC
編集 4: 今、私は完全に混乱しています。これは@Lievenによる例です
WITH Test (name, ID) AS
(SELECT 'Lieven1', 1 UNION ALL SELECT 'Lieven2', 2)
SELECT * FROM Test ORDER BY name, 1/ (ID - ID)
これによりゼロ除算は発生しません。つまり、SQL Server は実際に、WITH コマンドで作成されたいくつかのテーブルで短絡評価を行います。
TABLE変数でこれを試してみてください:
DECLARE @Test TABLE
(
NAME nvarchar(30),
ID int
);
INSERT INTO @Test (Name,ID) VALUES('Lieven1',1);
INSERT INTO @Test (Name,ID) VALUES('Lieven2',2);
SELECT * FROM @Test ORDER BY name, 1/ (ID - ID)
ゼロ除算エラーが発生します。