2013-03-01 2 views
-1

avez une question qui prend plus d'une minute pour exécuter
Le tableau a plus de 2 millions de lignes
[sID] est le PK
[textHash] est indexé et permet nulls
Les deux indices ont moins de 1 % fragmentation
Ce que je veux à est d'ajouter [textHash] correspond à la base où
Depuis [textHash] peut être nul besoin les deux conditions de jointureOptimize TSQL Rejoignez

en raison de la façon dont les autres conditions sont construites Union sur la La sélection principale n'est pas une option.
Dans la prochaine version majeure, la modification des méthodes de création de requêtes permet d'utiliser UNION.

En général, je veux rejoindre sur une propriété qui peut être nul
Si elle est nulle alors inclure la ligne sur la base PK

Select top 10001 [docFam].[sID] 
From [docSVsys] with (nolock) 
LEFT OUTER JOIN [docSVsys] as [docFam] with (nolock) 
    On [docSVsys].[sID] = [docFam].[sID] 
    Or [docSVsys].[textHash] = [docFam].[textHash] 
Where [docSVsys].[sID] <= '1000' 
Group By [docFam].[sID] 
Order By [docFam].[sID] Asc 

Si certains voudraient s'il vous plaît dire à ma façon de copier le plan de requête I l'incluera

J'ai essayé les astuces HASH, MERGE et LOOP.
Les deux premiers le compilateur a rejeté et la boucle était plus lente, puis aucun indice.

J'ai essayé

On ([docSVsys].[textHash] is null and [docSVsys].[sID] = [docFam].[sID]) 
Or [docSVsys].[textHash] = [docFam].[textHash] 

Et il était plus lent

Une requête similaire fonctionne en 2 secondes
Mais dans ce cas [sparidés] est non nul donc je ne ai besoin d'une condition de jointure

Select top 10001 [docFam].[sID] 
From [docSVsys] with (nolock) 
LEFT OUTER JOIN [docSVsys] as [docFam] with (nolock) 
    On [docSVsys].[sParID] = [docFam].[sParID] 
Where [docSVsys].[sID] <= '1000' 
Group By [docFam].[sID] 
Order By [docFam].[sID] Asc 

Pour les requêtes qui retournent un petit nombre de lignes APPLY fonctionne.
Cette syntaxe ci-dessous s'exécute en 1 seconde contre 1 minute pour la syntaxe ci-dessus (renvoie 1 022 lignes).

Vous rencontrez toujours un problème avec les deux formes de la requête pour les conditions qui retournent beaucoup de lignes mais je ne considère pas cela comme un problème SQL ou de syntaxe - beaucoup de lignes vont prendre plus de temps.

Select [docFam].[sID] 
From [docSVsys] with (nolock) 
OUTER APPLY -- cross apply 
    ( 
    Select [docSVsysHashNull].[sID] 
    From [docSVsys] as [docSVsysHashNull]with (nolock) 
    where [docSVsysHashNull].[sID] = [docSVsys].[sID] 
    union 
    Select [docSVsysHashNotNull].[sID] 
    From [docSVsys] as [docSVsysHashNotNull]with (nolock) 
    where [docSVsysHashNotNull].[sID] != [docSVsys].[sID] 
     and [docSVsysHashNotNull].[textHash] = [docSVsys].[textHash] 
) as docFam 
Where [docSVsys].[sID] <= '1000' 
Group By [docFam].[sID] 
Order By [docFam].[sID] Asc 
+0

Avez-vous essayé DISTINCT au lieu du GROUP BY? – chrisb

+0

@chrisb DISTINCT prend un peu plus de temps et la viande du plan de requête est identique. – Paparazzi

+0

Pourquoi le vote à la baisse? – Paparazzi

Répondre

0

La réponse a été fournie dans un commentaire de @ NikolaMarkovinović

select distinct isnull(docFam.sID, docSVsys.sID) as sID 
from docSVsys 
left join docSVsys as docFam 
    on docSVsys.textHash = docFam.textHash 
where ... 
1

Avez-vous pensé à écrire avec exists clause. quelque chose comme ça

select distinct top 10001 a.[sID] 
From [docSVsys] as a 
where exists 
(
select * 
From [docSVsys] as b 
where b.[sID]<='1000' 
and (a.[sID] = b.[sID] OR a.[textHash] = b.[textHash]) 
) 
+0

Pas plus rapide sur les requêtes qui retournent peu et plus lent à condition de revenir beaucoup. Encore +1 cela valait la peine d'essayer. – Paparazzi