我怎样才能摆脱这个 Lazy Spool,或者以其他方式提高这个查询的性能?

Jef*_*eff 3 sql-server execution-plan sql-server-2012

这是计划:https : //www.brentozar.com/pastetheplan/?id=rkM8d7ONS

我最感兴趣的是如何摆脱懒惰的线轴?

这是查询:

SELECT DISTINCT 
        SM.Security_ID 'Security_ID',  
        Leg.Leg_Type 'Leg_Type', 
        Leg.Leg_Side 'Leg_Side',
        Ct.Security_Type AS 'Swap_Type',
        Leg.CDX_Indicator AS 'CDS_CDX_Flag',
        SM.Currency AS 'Notional_Currency',
        Ct.Cross_Currency_Flag AS 'Cross_Currency_Flag',
        Ct.Custom_Overrides AS 'Special_Instructions',
        Leg.Protection_Indicator AS 'Buy_Sell_Protection',
        Leg.Commission_Direction AS 'Commission_Direction',
        Leg.Dividend_Payment_Indicator AS 'Undl_Asset_Dividend_Flag',
        SM.Issue_Date AS 'Effective_Date',
        SM.Maturity_Date AS 'Maturity_Date',
        Leg.Settlement_Frequency 'Settlement_Frequency',
        Leg.Reset_Frequency 'Reset_Frequency',
        Leg.Roll_Day AS 'Roll_Day',
        Leg.Reset_Business_Day_Convention AS 'Reset_Business_Day_Convn',
        Leg.Settlement_Business_Day_Convention AS 'Settlement_Business_Day_Convn',
        Leg.First_Payment_Date AS 'First_Period_End_Date',
        Leg.Day_Count AS 'Day_Count_Basis',
        Leg.Interest_Rate AS 'Interest_Rate',
        Leg.Spread AS 'Spread',
        Leg.CDX_Attachment AS 'CDX_Attachment',  
        Leg.CDX_Detachment AS 'CDX_Detachment',  
        Leg.Factor AS 'Factor',
        Leg.Commission AS 'Commission',  
        Leg.Reset_Lag AS 'Reset_Lag',  
        Leg.Initial_Index_Price AS 'Initial_Price',
        Ct.Principal_Exchange_Initial AS 'Principal_Exchange_Initial',
        Ct.Principal_Exchange_Final AS 'Principal_Exchange_Final',
        IsNull(Leg.Delay_Days, 0) AS 'Settlement_Delay_Days',
        Leg.Red_Code AS 'Red_Code',
        Leg.Referenced_Asset AS 'Referenced_Asset',
        SM.Short_Description AS 'Security_Description',
        Leg.Notional_Reset_Type AS 'Notional_Reset_Type',
        Leg.Reset_Arrears_Flag AS 'Reset_Arrears_Flag',
        SM.MIC AS 'Position_Market',
        SM.Currency AS 'Position_Currency',
        1,
        Ct.Security_Id,
        Txn.CLEARED_TRD_INDICATOR
    FROM 
        ##AssetAddSwap_Tbl S
        INNER JOIN Sch_Core_Data.Security_Master SM (NOLOCK) ON S.Security_ID = SM.Security_ID
        INNER JOIN Sch_Core_Data.Security_Detail_SwapLeg Leg (NOLOCK) ON SM.Security_Id = Leg.Security_Id
        INNER JOIN Sch_Core_Data.Security_Detail_SwapContract Ct (NOLOCK) ON Leg.Contract_Security_Id = Ct.Security_Id
        LEFT JOIN Sch_Core_Data.VW_TRANSACTIONS_Abbreviated Txn WITH (NOLOCK) ON Leg.Security_ID = Txn.Security_ID
        LEFT JOIN Sch_Core_Data.Security_Alt_Identifier SAI (NOLOCK) ON SAI.Security_Id = Leg.Security_Id 
            AND SAI.Identifier_Type = 'APXID' AND SAI.STATUS_FLAG = 'ACT'
    WHERE 
        S.Retransmit_Flag = 1 
        OR (--Txn.Transaction_ID IS NOT NULL
            --AND Txn.TRANSACTION_SOURCE_SYSTEM <> @TargetSystem
             Txn.TRANSACTION_SOURCE_SYSTEM NOT IN (SELECT svalue from SCH_CORE_DATA.DBL WHERE PROCESS = 'SYSTEMS' AND [FUNCTION] = 'LIST' AND DESCRIPTION3 = 'NON-TOM')
            AND Sch_Core_Code.Udf_Chk_BitValue(Txn.Account_Subscription, 3) = 1
            AND Sch_Core_Code.Udf_Chk_BitValue(Txn.Transmitted, 3) = 0      
            AND IsNull(SAI.Identifier, '') = '')
Run Code Online (Sandbox Code Playgroud)

使用此功能:

-- =============================================
-- Author:      Anuj Kalra
-- =============================================
CREATE FUNCTION [SCH_CORE_CODE].[UDF_CHK_BITVALUE]
(
@VALUE INT,
@FIND INT
)
RETURNS BIT
WITH EXECUTE AS 'USR_CORE'
AS
BEGIN
    DECLARE @CHECK BIT;
    SET @CHECK = 0; 
    IF ((POWER(2,@FIND) & @VALUE)<> 0) 
    BEGIN 
        SET @CHECK = 1; 
    END
    RETURN @CHECK;
Run Code Online (Sandbox Code Playgroud)

Jos*_*ell 7

使用标量用户定义函数会抑制此查询中的并行性,这在执行计划 XML 中有所暗示: NonParallelPlanReason="CouldNotGenerateValidParallelPlan"

一种选择是手动内联此函数的实现。所以这:

Sch_Core_Code.Udf_Chk_BitValue(Txn.Account_Subscription, 3) = 1
Run Code Online (Sandbox Code Playgroud)

变成这样:

CASE WHEN (POWER(2,3) & Txn.Account_Subscription)<> 0 THEN 1 ELSE 0 END = 1
Run Code Online (Sandbox Code Playgroud)

注意:您需要对函数的两个引用执行此操作

执行计划中有一些大的索引扫描(从ACCOUNT表中读取了 2200 万行)。如果查询真的需要处理这么多行,并行性会大有帮助。

如果DISTINCT不需要正确的结果,删除它也可以帮助提高性能(防止Sort (Distinct Sort)计划中的潜在成本。

就线轴而言,在这种情况下它实际上可能有所帮助。您可以通过添加到查询的末尾并查看计划/查询执行时间的不同来尝试抑制假脱机OPTION (QUERYTRACEON 8690)。在 SQL Server 2016 以后,查询提示NO_PEROFRMANCE_SPOOL可用。