2017-08-08 330 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