2017-08-08 244 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の行が含まれているので、必要ではないと思っていました。

[ステージング]。[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

関連する問題