我在MS SQL Server上运行的SQL类似于以下内容:
SELECT
CustNum,
Name,
FROM
Cust
LEFT JOIN (
SELECT
CustNum, MAX(OrderDate) as LastOrderDate
FROM
Orders
GROUP BY
CustNum) as Orders
ON Orders.CustNum = Cust.CustNum
WHERE
Region = 1
它包含一个子查询,用于从子表中查找MAX记录。关注的是这些表具有非常多的行。看起来子查询将在子表的所有行上运行,即使由于外部查询上的WHERE子句而实际上只需要很少的子行
有没有办法减少内部查询的范围?像添加WHERE子句只包括外部查询中包含的记录?像
这样的东西WHERE CustomerOrders.CustomerNumber = Customers.CustomerNumber -- Customers from the outer query.
我怀疑这不是必需的,但是我从其他开发人员那里得到了一些推动,我想确定(我的SQL有点生疏)。
答案 0 :(得分:1)
如果您的统计信息等是最新的,通常没有必要。这是优化者的工作。你可以尝试使用CROSS APPLY操作符,如果你认为你错过了一些快捷方式,但通常如果你有所有约束和统计数据就可以了。
您建议的其他WHERE可能对您有意义,但由于它与您发布的实际查询中的任何内容都不相关,因此会更改结果(如果它可以正常工作)。如果你想要评论,你需要发表表格&关系等。
最好的方法是检查执行计划,看看它是否正在做任何愚蠢的事情。
答案 1 :(得分:1)
你对子查询是正确的。它必须总结所有数据。你可以像这样重写这个查询:
SELECT CustNum, Name, max(OrderDate) as LastOrderDate
FROM Cust LEFT JOIN
Orders
ON Orders.CustNum = Cust.CustNum
WHERE Region = 1
group by CustNum, Name
这将让SQL优化器选择最佳路径。
如果您知道匹配Region = 1
的客户非常少,并且CustNum, OrderDate
中的Orders
上有索引,那么您可以像这样编写查询:
select CustNum, Name,
(select top 1 OrderDate
from Orders o
where Cust.CustNum = o.CustNum
order by OrderDate desc
) as LastOrderDate
from Cust
Where Region = 1
我认为使用cross apply
可以获得非常相似的效果。
顺便说一下,我不喜欢为此目的重写查询。但是,我没有找到一个SQL优化器,除了在这种情况下汇总所有orders
行之外还可以执行任何操作。