这个问题不是关于处决的顺序。这只是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”效率不高。
请保留与我的问题相关的答案,而不是像购买中的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语句,不会扫描Purchases表,即使它是一个清晰可见的SELECT / FROM语句:
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)
将产生除以零误差。
答案 0 :(得分:5)
首先,你所谓的“陈述”不是这样的。它们是ORDER BY(主要)条款的子条款。区别很重要,因为“Statement”意味着可分离,有序和程序化的东西,而SQL子句则不属于这些。
具体来说,SQL子子句(即SQL主要子句(SELECT,FROM,WHERE,ORDER BY等)的各个项)没有自己的隐式(也没有显式)执行顺序。 SQL会以方便的方式对它们进行重新排序,如果执行其中任何一个,它们几乎总是会执行 所有 。简而言之,SQL Server不会进行那种“短路”优化,因为它们非常有效并严重妨碍它所做的非常不同的优化(即统计数据访问/运算符优化)。
因此,对原始问题(您不应该更改)的正确答案是否定的,不可靠。您不能依赖SQL Server不使用ORDER BY的某些子子句,只是因为它看起来不需要。
唯一常见的例外是CASE函数可以(在大多数情况下)用于短路执行路径(在 CASE函数中,但不在其外部),但仅限于因为它是专门为此而设计的。我无法想到你可以依赖的任何其他SQL行为。
答案 1 :(得分:0)
DECLARE @MyTable TABLE
(
Data varchar(30)
)
INSERT INTO @MyTable (Data) SELECT 'One'
INSERT INTO @MyTable (Data) SELECT 'Two'
INSERT INTO @MyTable (Data) SELECT 'Three'
--SELECT *
--FROM @MyTable
--ORDER BY LEN(Data), LEN(Data)/0
-- Divide by zero error encountered.
SELECT *
FROM @MyTable
ORDER BY LEN(Data), CASE WHEN Data is null THEN LEN(Data)/0 ELSE 1 END
-- no problem
同样使用SET STATISTICS IO ON
我看到了这些结果:
SELECT *
FROM @MyTable
ORDER BY LEN(Data)
--(3 row(s) affected)
--Table '#4F2895A9'. Scan count 1, logical reads 1
SELECT *
FROM @MyTable
ORDER BY LEN(Data), CASE WHEN Data = 'One' THEN (SELECT MAX(t2.Data) FROM @MyTable t2) ELSE Data END
--(3 row(s) affected)
--Table '#4F2895A9'. Scan count 2, logical reads 2
SELECT *
FROM @MyTable
ORDER BY LEN(Data), CASE WHEN Data = 'Zero' THEN (SELECT MAX(t2.Data) FROM @MyTable t2) ELSE Data END
--(3 row(s) affected)
--Table 'Worktable'. Scan count 0, logical reads 0
--Table '#4F2895A9'. Scan count 1, logical reads 1
答案 2 :(得分:0)
我猜你已经回答了你的问题。但是,为什么要对 firstname , lastname 上的数据进行排序,如果这两个相同,那么购买订单,否则你将在DOB上进行?
逻辑上,它应该是名字,姓氏, DOB 。如果这三者相同,那么您才应该评估 purchaseorderdate 。有许多人具有相同的名称,但很少有相同的名称和DOB。这将减少您查询购买表的时间。