2010-12-10 36 views
2

Voici un CTE qui ralentit toute la procédure stockée:SQL Server: INNER JOIN après UNION conduit à ralentir Hash Match (agrégat de)

select * 
from #finalResults 
where intervalEnd is not null 
union 
select    
    two.startTime, 
    two.endTime, 
    two.intervalEnd, 
    one.barcodeID, 
    one.id, 
    one.pairId, 
    one.bookingTypeID, 
    one.cardID, 
    one.factor, 
    two.openIntervals, 
    two.factorSumConcurrentJobs 
from #finalResults as one 
inner join #finalResults as two 
    on two.cardID = one.cardID 
    and two.startTime > one.startTime 
    and two.startTime < one.intervalEnd 

Le tableau #finalResults contient un peu plus de 600K lignes, la partie supérieure partie de l'UNION (where intervalEnd is not null) environ 580K lignes, la partie inférieure avec le #finalResults rejoint environ 300K lignes. Cependant, cette estimation de jointure interne se termine par 100 mio. les lignes qui pourraient être responsables de la longue course Hash Match ici: alt text

Maintenant, si je understand Hash Joins correctement, la plus petite table devrait être hachée première et la plus grande table insérée et si vous devinez les tailles de mal au début, vous obtenez des pénalités de performance en raison de l'inversion des rôles à mi-processus. Cela pourrait-il être responsable de la lenteur?
J'ai essayé explicitement inner merge join et inner loop join dans l'espoir d'améliorer l'estimation du nombre de lignes, mais en vain.
Une autre chose: le Spool Eager en bas à droite estime à 17K lignes, se termine par 300K lignes et effectue près d'un demi-million de réaffectations et réécritures. Est-ce normal?

Edit: La table temporaire #finalResults a un index sur elle:

create nonclustered index "finalResultsIDX_cardID_intervalEnd_startTime__REST" 
on #finalresults("cardID", "intervalEnd", "startTime") 
include(barcodeID, id, pairID, bookingTypeID, factor, 
     openIntervals, factorSumConcurrentJobs); 

Ai-je besoin de construire une statistique distincte aussi bien?

+0

Ce n'est pas une jointure de hachage, c'est un match de hachage. C'est la suppression des doublons pour l'opérateur UNION (notez qu'il n'a qu'une seule entrée) –

Répondre

1

J'ai rencontré des situations où UNION a fait une requête beaucoup plus lente que UNION ALL avec un DISTINCT ensuite. Ainsi, alors que je n'ai pas d'explication pour le mauvais plan de requête (? Les statistiques et les index sont d'accord), je suggère que vous procédez comme suit:

select distinct * from (
    select * 
    from #finalResults 
    where intervalEnd is not null 
    union all 
    select    
     two.startTime, 
     two.endTime, 
     two.intervalEnd, 
     one.barcodeID, 
     one.id, 
     one.pairId, 
     one.bookingTypeID, 
     one.cardID, 
     one.factor, 
     two.openIntervals, 
     two.factorSumConcurrentJobs 
    from #finalResults as one 
    inner join #finalResults as two 
     on two.cardID = one.cardID 
     and two.startTime > one.startTime 
     and two.startTime < one.intervalEnd 
) 
+0

Je l'ai déjà fait: il donne le même plan d'exécution que la sélection du CTE original avec une option (groupe de commande), c'est à dire qu'il prend le même Comme auparavant, il passe juste le tri au lieu de le hacher. –

+0

Oui, en regardant ce plan de requête, le Hash Match n'a qu'une seule entrée - donc c'est la suppression des doublons par UNION qui cause le problème (et aucune indication sur la jointure ne vous aidera) –

+0

Je vois. Peut-être qu'un 'UNION ALL' où vous vous assurez de ne pas ajouter d'enregistrements en double en utilisant' ÈXCEPT' pourrait vous aider, car cela éviterait de trier les 580K lignes de la première partie? – Lucero

0

Peut-être qu'il améliorera si vous créez des statistiques pour la colonne CARDID .