如何减少子查询的范围?

时间:2013-06-07 23:37:04

标签: sql sql-server query-optimization

我在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有点生疏)。

2 个答案:

答案 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行之外还可以执行任何操作。