这个问题与执行顺序无关。这只是关于 ORDER BY。
在标准执行中是:
- 从
- 在哪里
- 通过...分组
- 拥有
- 选择
- 订购方式
- 最佳
编辑:这个问题或多或少是“ SQL Server 在执行 ORDER BY 表达式时应用短路评估吗? ” 答案是有时!我只是没有找到一个合理的理由。见编辑#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 语句。第三个语句仅用于姓氏和名字匹配的极少数情况。
如果没有重复的姓氏,SQL Server 是否不执行 ORDER BY 语句 #2 和 #3?而且,从逻辑上讲,如果没有重复的姓和名,SQL Server 是否会注意执行语句 #3。
这真的是为了优化。从采购表中读取应该只是最后的手段。在我的应用程序中,从按“CustomerID”分组的“Purchases”中读取每个“PurchaseDateTime”并不是很有效。
请保留与我的问题相关的答案,而不是像在 Purchases 中为 CustomerID、PurchaseDateTime 建立索引这样的建议。真正的问题是,SQL Server 会跳过不必要的 ORDER BY 语句吗?
编辑:显然,只要有一行,SQL Server 就会始终执行每条语句。即使只有一行,这也会给你一个除以零的错误:
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
好吧,我的问题的原始答案是肯定的,它确实执行了,但好的是我可以在适当的情况下停止执行
编辑 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)
将产生除以零错误。