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

ili*_*rit 4 sql-server indexing performance

我有这两个问题:

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%'))
Run Code Online (Sandbox Code Playgroud)

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

第二个查询使用Clustered Index Seek,其中"BuildingFloor LIKE'M%'"作为谓词,而查询谓词用于AddressId约束(96%成本).估计行数也完全没有(250实际与1估计).

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

yfe*_*lum 8

每行子查询和disjunctive(or)过滤条件一样慢.完全摆脱子查询,如果你or在过滤器中使用谓词,你可能会考虑用a替换它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%'
Run Code Online (Sandbox Code Playgroud)