2009-08-27 3 views
4

J'ai ces deux requêtes:Un mauvais index clusterisé recherche la 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%')) 

La première requête est exécutée plus de 10 fois plus rapide que la seconde. Selon le plan d'exécution, la première requête utilise deux scans d'index clusterisés avec "BuildingFloor LIKE 'M%'" comme prédicat et un index Seek sur le ContractRecord pour chacun des sous-sélections de la clause WHERE (40% du coût par sous-sélection).

La deuxième requête utilise un index clusterisé avec "BuildingFloor LIKE 'M%'" comme prédicat et un prédicat de recherche pour les contraintes AddressId (coût de 96%). Il est estimé que le nombre de lignes est complètement éliminé (250 effectifs contre 1 estimé).

Comment puis-je améliorer les performances de la deuxième requête? Puis-je forcer SQL Server à choisir une stratégie alternative ou dois-je modifier les index sur les tables?

Répondre

8

Les sous-requêtes par ligne sont lentes, tout comme les conditions de filtre disjonctif (or). Débarrassez-vous entièrement des sous-requêtes et, si vous utilisez un prédicat or dans un filtre, vous pouvez envisager de le remplacer par un union. En interne, le in est traduit en 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%' 
+0

Il semble y avoir une différence dans les ensembles de résultats renvoyés. Je ferai un peu plus d'enquête avant de poster un commentaire de suivi. – ilitirit

+0

OK, j'ai trouvé le problème et c'était de ma faute. Je n'ai pas inclus quelques colonnes obligatoires dans l'instruction select. – ilitirit

+0

Combien de fois est-ce plus rapide? – yfeldblum

Questions connexes