不良的聚集索引寻求表现?

时间:2009-08-27 09:50:38

标签: sql-server performance indexing

我有两个问题:

SELECT SELECT NamesRecord.NameID, NamesRecord.FulfillmentAddressID NameFulfillmentAddressID, ContractRecord.FulfillmentAddressID, ContractRecord.BillingAddressId
FROM Magnet.dbo.ContractRecord ContractRecord
    INNER JOIN Magnet.dbo.NamesRecord NamesRecord
        ON NamesRecord.NameId = ContractRecord.DonorId
WHERE NameID > -1
AND (EXISTS (
        SELECT 1
        FROM Magnet.dbo.AddressRecord AddressRecord
        WHERE AddressRecord.AddressId = ContractRecord.FulfillmentAddressId
        AND BuildingFloor LIKE 'M%')
    OR  EXISTS (
        SELECT 1
        FROM Magnet.dbo.AddressRecord AddressRecord
        WHERE AddressRecord.AddressId = ContractRecord.BillingAddressId
        AND BuildingFloor LIKE 'M%'))


SELECT SELECT NamesRecord.NameID, NamesRecord.FulfillmentAddressID NameFulfillmentAddressID, ContractRecord.FulfillmentAddressID, ContractRecord.BillingAddressId
FROM Magnet.dbo.ContractRecord ContractRecord
    INNER JOIN Magnet.dbo.NamesRecord NamesRecord
        ON NamesRecord.NameId = ContractRecord.DonorId
WHERE NameID > -1
AND (EXISTS (SELECT 1
        FROM Magnet.dbo.AddressRecord AddressRecord
        WHERE AddressRecord.AddressId IN (ContractRecord.FulfillmentAddressId, ContractRecord.BillingAddressId)
        AND BuildingFloor LIKE 'M%'))

第一个查询运行速度比第二个快10多倍。根据执行计划,第一个查询使用两个Clustered Index Scans,其中“BuildingFloor LIKE'M%'”作为谓词,并在ContractRecord上使用WHERE子句中的每个子选项进行索引搜索(每个成本40%)子选择)。

第二个查询使用Clustered Index Seek,其中“BuildingFloor LIKE'M%'”作为谓词,并使用AddressId约束的搜索谓词(96%成本)。估计行数也完全没有(实际为250,估计为1)。

如何改善第二个查询的性能?我可以强制SQL Server选择替代策略,还是必须修改表上的索引?

1 个答案:

答案 0 :(得分:8)

每行子查询和分离(or)过滤条件一样慢。完全摆脱子查询,如果您在过滤器中使用or谓词,则可以考虑将其替换为union。在内部,in被转换为or

select
    NamesRecord.NameId
from (
    select
        ContractRecord.DonorId,
        ContractRecord.FulfillmentAddressId as AddressId
    from Magnet.dbo.ContractRecord ContractRecord
    union
    select
        ContractRecord.DonorId,
        ContractRecord.BillingAddressId as AddressId
    from Magnet.dbo.ContractRecord ContractRecord
) ContractRecordInfo
join Magnet.dbo.NamesRecord NamesRecord on 1=1
    and NamesRecord.NameId = ContractRecordInfo.DonorId
    and NamesRecord.NameId > -1
join Magnet.dbo.AddressRecord AddressRecord on 1=1
    and AddressRecord.AddressId = ContractRecordInfo.AddressId
    and AddressRecord.BuildingFloor like 'M%'