2016-11-09 6 views
0

성능 문제가 생겼습니다. 그래서 나는 나의 접근 방식이 무엇인지 확신 할 수 없다.해시 일치 오른쪽 외부 조인을 사용하여 SQL Server 성능 문제를 개선하는 방법

7 분 이상 걸리는 쿼리입니다.

INSERT INTO SubscriberToEncounterMapping(PatientEncounterID, InsuranceSubscriberID) 
    SELECT 
     PV.PatientVisitId AS PatientEncounterID, 
     InsSub.InsuranceSubscriberID 
    FROM 
     DB1.dbo.PatientVisit PV 
    JOIN 
     DB1.dbo.PatientVisitInsurance PVI ON PV.PatientVisitId = PVI.PatientVisitId 
    JOIN 
     DB1.dbo.PatientInsurance PatIns on PatIns.PatientInsuranceId = PVI.PatientInsuranceId 
    JOIN 
     DB1.dbo.PatientProfile PP On PP.PatientProfileId = PatIns.PatientProfileId 
    LEFT OUTER JOIN 
     DB1.dbo.Guarantor G ON PatIns.PatientProfileId = G.PatientProfileId 
    JOIN 
     Warehouse.dbo.InsuranceSubscriber InsSub ON InsSub.InsuranceCarriersID = PatIns.InsuranceCarriersId 
         AND InsSub.OrderForClaims = PatIns.OrderForClaims 
         AND ((InsSub.GuarantorID = G.GuarantorId) OR (InsSub.GuarantorID IS NULL AND G.GuarantorId IS NULL)) 
    JOIN 
     Warehouse.dbo.Encounter E ON E.PatientEncounterID = PV.PatientVisitId  

실행 계획은

해시 일치 오른쪽 외부 그 비용 89 % 쿼리의

에게 가입이 있음을 주장한다. 오른쪽 외부 없다

enter image description here

문제가 어디 내가 볼 수 없습니다 쿼리에 가입 할 수 있습니다.

어떻게 쿼리를보다 효율적으로 만들 수 있습니까? enter image description here

+0

첫째 : Guarantor에서 나는 당신이 ..... 또한 열 당신의'SELECT' 목록에서 사용하는'InsSub' 별칭을 사용 명세서에있는 테이블을 참조하지 않습니다 당신을 * 정말로이 두 가지 정보를 얻기 위해 모든 테이블에 가입해야합니까? –

+0

해시 일치의 세부 정보를 표시 할 수 있습니까? 프로브 란 무엇이며 출력은 무엇입니까? 스크린 샷에서 분명하지 않습니다. 나는이 술어가 당신의 이슈를 일으킨다 고 생각할 것이다 -'(InsSub.GuarantorID = G.GuarantorId) 또는 (InsSub.GuarantorID IS NULL과 G.GuarantorId가 NULL이다)', 당신은 두 개의 질의를 사용하고 결과를 결합하는 것을 고려할 수있다. 이처럼 OR 연산자를 사용하면 하위 최적화 계획이 생기고 두 개의 개별 쿼리가 인덱스를 더 잘 활용할 수 있습니다. – GarethD

+0

@ GarethD 아마도 join에서 두 술어를 사용하는 대신 where 절에서 EXISTS를 사용합니까? – dfundako

답변

1

은 당신이 InsuranceSubscriber에서 NULL 경우에 맞게, 첫 번째 GuarantorID와 두 번째에 일치하는 두 개의 쿼리로 분할 시도 할 수 내 댓글에 정교하고 Guarantor에서, 또는 기록이 완전히 누락 된 경우하려면 모든

INSERT INTO SubscriberToEncounterMapping(PatientEncounterID, InsuranceSubscriberID) 
SELECT PV.PatientVisitId AS PatientEncounterID, InsSub.InsuranceSubscriberID 
FROM DB1.dbo.PatientVisit PV 
     JOIN DB1.dbo.PatientVisitInsurance PVI 
      ON PV.PatientVisitId = PVI.PatientVisitId 
     JOIN DB1.dbo.PatientInsurance PatIns 
      ON PatIns.PatientInsuranceId = PVI.PatientInsuranceId 
     JOIN DB1.dbo.PatientProfile PP 
      ON PP.PatientProfileId = PatIns.PatientProfileId 
     JOIN DB1.dbo.Guarantor G 
      ON PatIns.PatientProfileId = G.PatientProfileId 
     JOIN Warehouse.dbo.InsuranceSubscriber InsSub 
      ON InsSub.InsuranceCarriersID = PatIns.InsuranceCarriersId 
      AND InsSub.OrderForClaims = PatIns.OrderForClaims 
      AND InsSub.GuarantorID = G.GuarantorId 
     JOIN Warehouse.dbo.Encounter E 
      ON E.PatientEncounterID = PV.PatientVisitId 
UNION ALL 
SELECT PV.PatientVisitId AS PatientEncounterID, InsSub.InsuranceSubscriberID 
FROM DB1.dbo.PatientVisit PV 
     JOIN DB1.dbo.PatientVisitInsurance PVI 
      ON PV.PatientVisitId = PVI.PatientVisitId 
     JOIN DB1.dbo.PatientInsurance PatIns 
      ON PatIns.PatientInsuranceId = PVI.PatientInsuranceId 
     JOIN DB1.dbo.PatientProfile PP 
      ON PP.PatientProfileId = PatIns.PatientProfileId 
     JOIN Warehouse.dbo.InsuranceSubscriber InsSub 
      ON InsSub.InsuranceCarriersID = PatIns.InsuranceCarriersId 
      AND InsSub.OrderForClaims = PatIns.OrderForClaims 
      AND InsSub.GuarantorID IS NULL 
     JOIN Warehouse.dbo.Encounter E 
      ON E.PatientEncounterID = PV.PatientVisitId 
WHERE NOT EXISTS 
     ( SELECT 1 
      FROM DB1.dbo.Guarantor G 
      WHERE PatIns.PatientProfileId = G.PatientProfileId 
      AND  InsSub.GuarantorID IS NOT NULL 
     ); 
+0

이것은 훨씬 빠릅니다. 그러나 반환 된 레코드는 원래 쿼리와 다릅니다. 그래서 나는 tweek해야 할 것이다. 그러나 이것은 명확히가는 길이다!. 다스! –

-2

가 결합 각에 의해 반환 된 레코드의 수를 줄일 수있는 능력을 기반으로 조인 나는 것 다시 순서 : 여기

는 해시지도 상세이다. 어느 쪽이든 조인하면 리턴되는 수 또는 레코드를 줄일 수있어 효율성이 높아집니다. 그런 다음 외부 조인을 수행하십시오. 또한 테이블 잠금은 항상 문제가 될 수 있으므로 잠겨있는 레코드를 방지하기 위해 (nolock)을 추가하십시오.

아마도 이와 같이 약간의 조정이 필요할 것입니다.

INSERT INTO SubscriberToEncounterMapping (
    PatientEncounterID 
    , InsuranceSubscriberID 
    ) 
SELECT PV.PatientVisitId AS PatientEncounterID 
    , InsSub.InsuranceSubscriberID 
FROM DB1.dbo.PatientVisit PV WITH (NOLOCK) 
INNER JOIN Warehouse.dbo.Encounter E WITH (NOLOCK) 
    ON E.PatientEncounterID = PV.PatientVisitId 
INNER JOIN DB1.dbo.PatientVisitInsurance PVI WITH (NOLOCK) 
    ON PV.PatientVisitId = PVI.PatientVisitId 
INNER JOIN DB1.dbo.PatientInsurance PatIns WITH (NOLOCK) 
    ON PatIns.PatientInsuranceId = PVI.PatientInsuranceId 
INNER JOIN DB1.dbo.PatientProfile PP WITH (NOLOCK) 
    ON PP.PatientProfileId = PatIns.PatientProfileId 
INNER JOIN Warehouse.dbo.InsuranceSubscriber InsSub WITH (NOLOCK) 
    ON InsSub.InsuranceCarriersID = PatIns.InsuranceCarriersId 
     AND InsSub.OrderForClaims = PatIns.OrderForClaims 
LEFT JOIN DB1.dbo.Guarantor G WITH (NOLOCK) 
    ON PatIns.PatientProfileId = G.PatientProfileId 
     AND (
      (InsSub.GuarantorID = G.GuarantorId) 
      OR (
       InsSub.GuarantorID IS NULL 
       AND G.GuarantorId IS NULL 
       ) 
      ) 
+1

NOLOCK을 추가하면 실행 계획에서 해시 조인 연산자에 어떤 영향을 미칩니 까? – dfundako

+1

조인이 쓰여지는 순서는 (OPTION (FORCEORDER)를 사용하지 않는 한) 실행되는 순서와 관계가 없으므로 아무런 차이가 없습니다. [나쁜 습관 : 모든 곳에서 NOLOCK하기] (https://blogs.sentryone.com/aaronbertrand/bad-habits-nolock-everywhere/)를 읽고 싶을 수도 있습니다. 이것은 마술 성능 수정이 아니므로주의해서 사용해야합니다 일반적으로 이해하는 사람들이 위험을인지하고 있습니다. – GarethD

+0

조인 순서가 중요하다는 것을 알았고 옵티마이 저가 조인에 대한 작업을 할 수 있도록 트러스트를 원한다면 괜찮습니다. 아니면 직접 최적화하십시오 Joins.동의하지 않는 잠금은 필요하지 않거나 이상적 일 수 있지만 잠금 기능이있는 경우 잠금 대기를 방지하여 실행 속도를 높입니다. 그들을 제거하는 데 도움이되지 않으면. 해시 일치는 항상 존재하지만 작업의 레코드 세트 크기를 줄이면 도움이됩니다. – KH1229