Sql server 如何使用哈希匹配右外部联接提高SQL Server性能问题

Sql server 如何使用哈希匹配右外部联接提高SQL Server性能问题,sql-server,sqlperformance,Sql Server,Sqlperformance,我不熟悉性能问题。因此,我不确定我的方法应该是什么 这是一个运行时间超过7分钟的查询 INSERT INTO SubscriberToEncounterMapping(PatientEncounterID, InsuranceSubscriberID) SELECT PV.PatientVisitId AS PatientEncounterID, InsSub.InsuranceSubscriberID FROM DB1.d

我不熟悉性能问题。因此,我不确定我的方法应该是什么

这是一个运行时间超过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%

查询的最后一步

查询中没有正确的外部联接,因此我看不出问题出在哪里

如何使查询更高效

以下是哈希映射的详细信息:

我会根据减少每个联接返回的记录数的能力对联接重新排序。无论哪种联接可以减少返回的数量或记录,都将提高效率。然后执行外部联接。此外,表锁定总是一个问题,因此添加withnolock以防止记录被锁定

也许像这样的东西需要稍微调整一下

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中为空时匹配,第二个查询在AssuranceSubscriber中匹配,或者如果Guaranter中的记录完全缺失:


首先:我在您的语句中没有看到任何表使用您在列的SELECT列表中使用的InsSub别名。。。。。另外:您真的需要连接所有这些表来获得这两条信息吗?您能显示哈希匹配的详细信息吗?什么是探头,什么是输出?从屏幕截图上看不清楚。我猜想这个谓词会导致你的问题--Sub.GuangthRoID.G.CuaAutoRID或SuS.CuavangRoID为null,G.CuaAutoRID为NULL,你可能希望考虑使用两个查询,并将结果联合在一起,通常当你有或这样的谓词导致一个次优的计划时,这两个独立的查询能够更好地利用索引。@GarethD可能在where子句中使用EXISTS,而不是在join中使用这两个谓词?是的。我需要那些连接。InsSub别名用于获取插入的保险订户ID。添加NOLOCK对执行计划中的哈希联接运算符有何影响?除非使用选项FORCEORDER,否则写入联接的顺序与执行联接的顺序无关,因此这没有任何区别。您可能还希望阅读,这不是一个神奇的性能修复程序,应该谨慎使用,通常是那些理解并意识到风险的人。我发现连接顺序确实很重要,如果您希望信任优化器为连接执行它的工作,那么这很好,或者您可以自己进行优化。同意无锁可能不需要或不理想,但如果某个东西正在锁定,它将通过防止等待锁来加快执行速度。如果它不能帮助移除它们。哈希匹配将始终存在,但在操作中减少记录集大小应该会有所帮助。这肯定会快很多!但返回的记录与原始查询不同。所以我得走了,但这绝对是我要走的路!。谢谢
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
        );