2017-08-18 5 views
0

L'application que je travaille sur génère une requête SQL peu comme ceci:lente requête de deux tables dans SQL Server

Select 
    VISIT_VIEW.VISIT_ID, VISIT_VIEW.PATIENT_ID, VISIT_VIEW.MRN_ID, 
    VISIT_VIEW.BILL_NO, INSURANCE.INS_PAYOR' 
FROM 
    'VISIT_VIEW 
LEFT JOIN 
    INSURANCE ON VISIT_VIEW.visit_id = INSURANCE._fk_visit ' 
WHERE 
    'VISIT_VIEW.VISIT_ID IN (1002, 1003, 1005, 1006, 1007, 1008, 1010, 1011, <...>, 1193, 1194, 1195, 1196, 1197, 1198, 1199)' 

Le <...> représente une longue liste de ids. La taille de la liste dépend des résultats d'une requête précédente et, à son tour, des paramètres sélectionnés pour générer cette requête.

La liste des ID peut varier de 100 articles ci-dessus à long 2000.

Le tableau INSURANCE est grande, plus de 9 millions de lignes. La table de visite est également grande, mais pas tout à fait aussi grande.

Comme le nombre d'ID monte, il y a une augmentation assez forte d'une durée de moins d'une seconde à plus de 15 minutes. L'augmentation commence quelque part autour de 175 ids. Si les paramètres utilisés pour générer la requête sont modifiés de sorte que la colonne INS_PAYOR n'est pas sélectionnée, et donc il n'y a pas de jointure à gauche, la requête s'exécute en moins d'une seconde, même avec plus de 2000 éléments dans la liste des ID .

Le plan d'exécution montre que 97% du temps de recherche est consacré à une recherche en cluster sur la table INSURANCE.

Comment puis-je retravailler cette requête pour obtenir les mêmes résultats avec un retard moins horrible?

Rappelez-vous que le SQL est généré par le code, et non à la main. Il est généré à partir d'une liste de champs (avec la connaissance de quel champ appartient à quelle table) et d'une liste d'ID dans la table primaire à vérifier. Je n'ai accès au code qui fait la génération de requête, et peut le modifier à condition que les résultats finaux de la requête sont exactement même.

Merci

+1

Il est beaucoup plus susceptible d'être cette condition 'IN()' qui est plutôt lent que de se joindre les deux tables. –

+0

Cela peut être, mais quand il est essayé avec la condition IN, mais sans la jointure, le temps de résultat passe de plus de 15 minutes à moins de 1 seconde. Ceci est par mesure réelle sur le site. Je ne peux pas essayer facilement avec le rejoindre, mais sans, donc je pense qu'il est à la fois ensemble qui ralentissent cette baisse –

Répondre

0

Le < ...> représente une longue liste de ids. La taille de la liste dépend des résultats d'une requête précédente

Ne pas faire.

Pour ce faire:

SELECT <...> 
FROM VISIT_VIEW 
INNER JOIN (
    <previous query goes here> 
) t on VISIT_VIEW.VISIT_ID = t.<ID?> 
LEFT JOIN INSURANCE ON VISIT_VIEW.visit_id=INSURANCE._fk_visit 
+0

Ce sera un problème. Je ne dirai pas que c'est impossible, mais le résultat de la requête précédente est actuellement traité de plusieurs façons (principalement pour exclure des éléments) avant qu'il ne soit utilisé pour générer la requête finale. Il y a aussi une confirmation de l'utilisateur entre les deux. Mais merci pour la suggestion. –

0

Voyez si vous voyez des améliorations en utilisant ce qui suit ...

IF OBJECT_ID('tempdb..#VisitList', 'U') IS NOT NULL 
DROP TABLE #VisitList; 

CREATE TABLE #VisitList (
    VISIT_ID INT NOT NULL PRIMARY KEY 
    ); 

INSERT #VisitList (VISIT_ID) VALUES (1002),(1003),(1005),(1006),(1007),(1008),(1010),(1011),(<...>),(1193),(1194),(1195),(1196),(1197),(1198),(1199); 

SELECT 
    vv.VISIT_ID, 
    vv.PATIENT_ID, 
    vv.MRN_ID, 
    vv.BILL_NO, 
    ix.INS_PAYOR 
FROM 
    VISIT_VIEW vv 
    JOIN #VisitList vl 
     ON vv.VISIT_ID = vl.VISIT_ID 
    CROSS APPLY (
       SELECT TOP 1 
        i.INS_PAYOR 
       FROM 
        INSURANCE i 
       WHERE 
        vv.visit_id=i._fk_visit 
       ) ix; 
+0

Merci. Cela semble plausible. Je vais essayer et voir quels sont les résultats. –