2017-08-08 331 views
2

爲了獲得實體的「描述」列,我需要連接多個表。內部連接在開始時已經足夠了,但現在需求已經改變了,我需要從包含「Description」列的表中獲取多行,所以我創建了一個Table-Valued函數。如何提高使用OUTER APPLY的查詢的性能

問題是,查詢執行更糟糕。當使用內連接時,需要1秒鐘,現在需要30秒。

如何優化性能?

我知道使用outer apply會比內連接返回更多的行。

我試着在AGREEMENT_LINE表中添加AGR_LINE_NO和Meta_IsCurrent作爲聚集索引,但這隻改進了原始查詢的性能。

下面是原始查詢,新的一個,函數和執行計劃。

原始查詢:

SELECT TOP 10000 
OBJECT_TYPE, 
SEQ_NO, 
O.AGR_LINE_NO, 
SHORT_DESC, 
C02, 
C03, 
C04, 
C05, 
C07, 
C10, 
C52, 
N05, 
N04, 
N02, 
N19, 
N01, 
X.[Description]  AS CarConcept, 
O.[Timestamp]  AS OBJ_TIMESTAMP, 
O.Record_Timestamp AS OBJ_RECORD_TIMESTAMP, 
X.RECORD_TIMESTAMP AS X_RECORD_TIMESTAMP 

    FROM [Archive].[TIA_TIA_OBJECT] O 

    INNER JOIN [Archive].[TIA_TIA_AGREEMENT_LINE] A 
    ON A.AGR_LINE_NO = O.Agr_Line_No 

    INNER JOIN [Archive].[TIA_TIA_PRODUCT_LINE] PL 
    ON PL.PRODUCT_LINE_ID = A.PRODUCT_LINE_ID AND PL.PRODUCT_LINE_VER_NO = A.PRODUCT_LINE_VER_NO 

    INNER JOIN [Archive].[TIA_TIA_TARIFF_STRUCTURE] TS 
    ON PL.TARIFF_TYPE_LIST_VER = TS.[VERSION] AND PL.PRODUCT_LINE_ID = TS.PRODUCT_LINE_ID 

    INNER JOIN [Archive].[TIA_TIA_TARIFF_CODES] TC 
    ON TC.PRODUCT_LINE_ID = PL.PRODUCT_LINE_ID AND TC.[TYPE] = TS.[TYPE] AND TC.[VERSION] = TS.TYPE_VERSION 

    INNER JOIN [Archive].[TIA_TIA_XLA_PE_REFERENCE] X 
    ON TC.[TYPE] = X.Table_Name AND PL.PRODUCT_LINE_ID = X.ID AND TC.[VERSION] = X.[VERSION] AND TC.CODE = X.[CODE] 

    WHERE O.OBJECT_TYPE = 'BIO01' 

    AND 
    TC.[TYPE] =  
    CASE WHEN O.C52 IS NOT NULL 
     THEN 'XTARIFTYPE' 
     ELSE 'ART' 
    END 

    AND X.[Language] = 'DK' 

    AND 
    X.Code = 
    CASE WHEN O.C52 IS NOT NULL 
     THEN O.C52 
     ELSE O.C02 
    END 

    AND O.Meta_IsCurrent = 1 
    AND A.Meta_IsCurrent = 1 
    AND PL.Meta_IsCurrent = 1 
    AND TS.Meta_IsCurrent = 1 
    AND TC.Meta_IsCurrent = 1 
    AND X.Meta_IsCurrent = 1 

新建查詢:

SELECT TOP 10000 
OBJECT_TYPE, 
SEQ_NO, 
O.AGR_LINE_NO, 
SHORT_DESC, 
C02, 
C03, 
C04, 
C05, 
C07, 
C10, 
C52, 
N05, 
N04, 
N02, 
N19, 
N01, 
carConcept.CodeDescription  AS CarConcept, 
O.[Timestamp]  AS OBJ_TIMESTAMP, 
O.Record_Timestamp AS OBJ_RECORD_TIMESTAMP, 
carConcept.RECORD_TIMESTAMP AS X_RECORD_TIMESTAMP 

    FROM [Archive].[TIA_TIA_OBJECT] O 

    INNER JOIN [Archive].[TIA_TIA_AGREEMENT_LINE] A 
    ON A.AGR_LINE_NO = O.Agr_Line_No 

    INNER JOIN [Archive].[TIA_TIA_PRODUCT_LINE] PL 
    ON PL.PRODUCT_LINE_ID = A.PRODUCT_LINE_ID AND PL.PRODUCT_LINE_VER_NO = A.PRODUCT_LINE_VER_NO 

    OUTER APPLY Staging.ufnGetCodeDescription(PL.PRODUCT_LINE_ID, PL.PRODUCT_LINE_VER_NO, PL.TARIFF_TYPE_LIST_VER, 
    CASE WHEN O.C52 IS NOT NULL 
     THEN 'XTARIFTYPE' 
     ELSE 'ART' 
    END, 
    CASE WHEN O.C52 IS NOT NULL 
     THEN O.C52 
     ELSE O.C02 
    END) carConcept 

    WHERE O.OBJECT_TYPE = 'BIO01' 

    AND O.Meta_IsCurrent = 1 
    AND A.Meta_IsCurrent = 1 
    AND PL.Meta_IsCurrent = 1 

表值函數:

CREATE FUNCTION [Staging].[ufnGetCodeDescription] 
(
    @ProductLineId as nvarchar(20), 
    @ProductLineVersion as decimal(10,4), 
    @TariffTypeListVer as decimal(10,4), 
    @Type as nvarchar(20), 
    @Code as nvarchar(20) 
) 
RETURNS @returntable TABLE 
(
    CodeDescription nvarchar(100) NOT NULL, 
    Record_Timestamp datetime2 NOT NULL 
) 
AS 
BEGIN 

    DECLARE @CodeDescription as nvarchar(200) 
    DECLARE @Record_Timestamp as datetime2 

    SELECT 
    @CodeDescription = X.[Description], 
    @Record_Timestamp = X.RECORD_TIMESTAMP 

    FROM [Archive].[TIA_TIA_TARIFF_STRUCTURE] TS 

    INNER JOIN [Archive].[TIA_TIA_TARIFF_CODES] TC 
    ON TC.PRODUCT_LINE_ID = @ProductLineId AND TC.[TYPE] = TS.[TYPE] AND TC.[VERSION] = TS.TYPE_VERSION 

    INNER JOIN [Archive].[TIA_TIA_XLA_PE_REFERENCE] X 
    ON TC.[TYPE] = X.Table_Name AND @ProductLineId = X.ID AND TC.[VERSION] = X.[VERSION] AND TC.CODE = X.[CODE] 

    WHERE 

    TS.PRODUCT_LINE_ID = @ProductLineId 
    AND 
    TS.[VERSION] = @TariffTypeListVer 

    AND TS.CLASS = 'CODE' 

    AND TC.[TYPE] = @Type 
    AND TC.Code = @Code 

    AND X.[Language] = 'DK' 

    AND TS.Meta_IsCurrent = 1 
    AND TC.Meta_IsCurrent = 1 
    AND X.Meta_IsCurrent = 1 

    IF @CodeDescription IS NOT NULL AND @Record_Timestamp IS NOT NULL 
    BEGIN 
     INSERT @returntable 
     SELECT @CodeDescription, @Record_Timestamp 
    END; 
    RETURN; 
END 

執行計劃原來的查詢:

https://pastebin.com/3j9G1rSi

enter image description here

執行計劃新的查詢:

https://pastebin.com/uAADwuU6

enter image description here

回答

0

我在函數(TIA_TIA_TARIFF_STRUCTURE,TIA_TIA_TARIFF_CODES,TIA_TIA_XLA_PE_REFERENCE)中加入的表沒有正確的索引。

我認爲這是沒有必要的,因爲它們包含大約3K,17K和22K行。

在[Staging]。[ufnGetCodeDescription]正在將性能從30秒降低到5-6秒的表上放置聚簇索引。

2

使用OUTER APPLY您實際上爲每行執行函數(和函數中的SELECT)。

相反,我會建議將函數調用移出FROM/WHERE。只需檢索所有必要的列/

這個想法是首先選擇必要的列,然後將函數調用到所有過濾器已應用的相對較小的行集。

SELECT 
    sub.*, 
    carConcept.* 
FROM (the new query except the OUTER APPLY) sub 
    OUTER APPLY Staging.ufnGetCodeDescription(SUB.PRODUCT_LINE_ID, SUB.PRODUCT_LINE_VER_NO, SUB.TARIFF_TYPE_LIST_VER, 
    CASE WHEN SUB.C52 IS NOT NULL 
     THEN 'XTARIFTYPE' 
     ELSE 'ART' 
    END, 
    CASE WHEN SUB.C52 IS NOT NULL 
     THEN SUB.C52 
     ELSE SUB.C02 
    END) carConcept 

或者你仍然可以使用INNER JOIN。如果INNER JOIN返回多行,則添加GROUP BY邏輯以返回第一個值。

+0

感謝您的回覆。它沒有解決性能問題,但通常是有用的。 – Kenci