如何改善 SQL 哈希匹配右外连接的服务器性能问题

How to improve SQL Server performance issue with hash match right outer join

我不熟悉性能问题。所以我不确定我的方法应该是什么。

这是 运行 花费 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      

执行计划指出有一个

Hash Match Right Outer Join that Cost 89%

查询。

查询中没有右外连接,所以我看不出问题出在哪里。

如何提高查询效率?

这是散列映射的详细信息:

我会根据减少每个连接返回的记录数的能力对连接重新排序。无论哪种连接可以减少返回的数量或记录,都会提高效率。然后执行外连接。此外,table 锁定始终是一个问题,因此添加 with(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
                )
            )

为了详细说明我的评论,您可以尝试将其分成两个查询,第一个匹配 GuarantorID,第二个匹配 InsuranceSubscriber 中的 NULL,以及在 Guarantor 中,或者如果 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
        );