Desain Proses T-SQL dan Rencana Eksekusi (UDF Parameter Sniffing?)

Pada SQL Server 2005, saya memiliki proses alokasi multi-level yang kompleks yang terlihat seperti ini (pseudo-SQL):

FOR EACH @LVL_NUM < @MAX_LVL:
INSERT INTO ALLOCS
SELECT 'OUT', *
FROM BALANCES(@LVL_NUM)
INNER JOIN ALLOCN_SUMRY(@LVL_NUM)

INSERT INTO ALLOCS
SELECT 'IN', *
FROM BALANCES(@LVL_NUM)
INNER JOIN ALLOCNS(@LVL_NUM)
INNER JOIN ALLOCN_SUMRY(@LVL_NUM)

Dimana ALLOCS diunggulkan dengan alokasi langsung dan kemudian BALANCES(@LVL_NUM) didasarkan pada ALLOCS pada @LVL_NUM (yang mungkin merupakan beberapa alokasi langsung ditambah beberapa alokasi IN dari level sebelumnya) dan ALOCNS(@LVL_NUM) didasarkan pada BALANCES(@LVL_NUM) dan ALOCN_SUMRY(@LVL_NUM) hanya didasarkan pada ALOCNS(@LVL_NUM) - dengan banyak tabel konfigurasi yang menunjukkan driver yang mengeluarkan alokasi.

Ini disederhanakan, tapi sebenarnya ada empat atau lima pasangan seperti ini dalam loop karena ada berbagai logika yang tidak mungkin ditangani bersama-sama (dan beberapa kasus yang mungkin ditangani bersama-sama.)

Logika dasarnya adalah mengambil jumlah total di pusat biaya/lini produk/dll tertentu (yaitu BALANCES) dan kemudian mengalokasikannya ke pusat biaya/lini produk/dll lainnya berdasarkan bagiannya (yaitu ALLOCNS / ALLOCN_SUMRY persentase bagian) dari metrik tertentu.

Dengan begitu banyak logika yang diulang dalam pencatatan OUT dan IN, dan tentu saja SUMRY berdasarkan detail ALLOCN, saya akhirnya mengimplementasikan menggunakan fungsi nilai tabel sebaris, yang tampaknya berkinerja cukup baik (dan cocok dengan perilaku sistem yang ada di tes regresi, yang merupakan nilai tambah!). (Sistem yang ada adalah program monster C/C++/MFC/ODBC yang membaca semua data ke dalam array besar dan struktur data lainnya dan ditulis dengan sangat buruk.)

Masalahnya adalah ketika dijalankan dalam loop saya tampaknya mendapatkan masalah rencana eksekusi saat saya menaikkan level ketika tabel ALLOCS mulai berubah (dan semuanya berubah, karena level memiliki pusat biaya yang berbeda, jadi konfigurasi yang digunakan untuk menggerakkan ALLOCNS berubah). Saya kira saya memiliki hingga 99 level, tetapi level terendah dimulai 2, 4, 6. Tampaknya menjalankan @LVL_NUM = 6 dengan sendirinya di luar UDF berkinerja baik, tetapi kinerja UDF buruk - mungkin karena UDF memiliki rencana cache atau keseluruhan rencana sudah buruk karena ALLOCS ditambahkan dari langkah sebelumnya di @LVL_NUM IN (2, 4).

Sebelumnya dalam pengembangan, saya berhasil menjalankan 30 level dalam 30 menit, tetapi sekarang saya tidak bisa menyelesaikan 3 level pertama dalam 2 jam.

Saya sedang mempertimbangkan untuk menjalankan dua sisipan dalam SP lain dan menyebutnya DENGAN RECOMPILE, tetapi penasaran apakah RECOMPILE ini mengalir dengan benar ke UDF TVF? Saran lainnya juga akan dihargai.

Kode Sebenarnya:

/****** Object:  UserDefinedFunction [MISProcess].[udf_MR_BALANCES_STAT_UNI]    Script Date: 05/14/2009 22:16:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [MISProcess].[udf_MR_BALANCES_STAT_UNI] (
     @DATA_DT_ID int
    ,@LVL_NUM int
    )
RETURNS TABLE
--    WITH SCHEMABINDING
AS 
RETURN
    (
     SELECT AB.YYMM_ID
           ,AB.BUS_UNIT_ID
           ,AB.BUS_UNIT_PROD_LINE_CD
--                   ,AB.ALOCN_SRC_CD
           ,AB.ALOCN_SRC_PROD_LINE_CD
           ,CASE WHEN ORIG_ALSRC.ALOCN_TYPE_CD = 'C'
                      AND ORIG_ALSRC.RETN_IND = 'Y' THEN AB.ORIG_ALOCN_SRC_CD
                 ELSE AB.BUS_UNIT_ID
            END AS ORIG_ALOCN_SRC_CD
           ,CASE WHEN BUPALSRC.COLLAPSE_IND = 'Y'
                 THEN BUPLNTM.ALOCN_LINE_ITEM_NUM
                 ELSE AB.LINE_ITEM_NUM
            END AS ALOCN_LINE_ITEM_NUM
           ,SUM(BUPLNTM.ALOCN_SIGN_IND * AB.ANULZD_ACTL_BAL) AS ANULZD_ACTL_BAL
     FROM   MISWork.vwMR_BALANCES AS AB
     INNER JOIN MISProcess.LKP_BUPLNTM AS BUPLNTM
            ON BUPLNTM.DATA_DT_ID = @DATA_DT_ID
               AND BUPLNTM.LINE_ITEM_NUM = AB.LINE_ITEM_NUM
               AND BUPLNTM.ALOCN_LINE_ITEM_NUM <> 0
     INNER JOIN [MISProcess].[udf_MR_ALSRC](@DATA_DT_ID, @LVL_NUM) AS BUPALSRC
            ON BUPALSRC.ALOCN_SRC_CD = AB.BUS_UNIT_ID
     INNER JOIN [MISProcess].LKP_BUPALSRC AS ORIG_ALSRC
            ON ORIG_ALSRC.DATA_DT_ID = @DATA_DT_ID
               AND ORIG_ALSRC.ALOCN_SRC_CD = AB.ORIG_ALOCN_SRC_CD
     GROUP BY AB.YYMM_ID
           ,AB.BUS_UNIT_ID
           ,AB.BUS_UNIT_PROD_LINE_CD
--                   ,AB.ALOCN_SRC_CD
           ,AB.ALOCN_SRC_PROD_LINE_CD
           ,CASE WHEN ORIG_ALSRC.ALOCN_TYPE_CD = 'C'
                      AND ORIG_ALSRC.RETN_IND = 'Y' THEN AB.ORIG_ALOCN_SRC_CD
                 ELSE AB.BUS_UNIT_ID
            END
           ,CASE WHEN BUPALSRC.COLLAPSE_IND = 'Y'
                 THEN BUPLNTM.ALOCN_LINE_ITEM_NUM
                 ELSE AB.LINE_ITEM_NUM
            END
    )

/****** Object:  UserDefinedFunction [MISProcess].[udf_MR_ALOCNS_STAT_UNI]    Script Date: 05/14/2009 22:16:16 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [MISProcess].[udf_MR_ALOCNS_STAT_UNI] (
     @DATA_DT_ID int
    ,@LVL_NUM int
    )
RETURNS TABLE
--    WITH SCHEMABINDING
AS 
RETURN
    (
     SELECT BALANCES.YYMM_ID
           ,BS.ALOCN_SRC_CD AS BUS_UNIT_ID
           ,BS.PROD_LINE_CD AS BUS_UNIT_PROD_LINE_CD
           ,BALANCES.BUS_UNIT_ID AS ALOCN_SRC_CD
           ,BALANCES.BUS_UNIT_PROD_LINE_CD AS ALOCN_SRC_PROD_LINE_CD
           ,BALANCES.ORIG_ALOCN_SRC_CD
           ,BALANCES.ALOCN_LINE_ITEM_NUM
           ,SUM(BS.ACCT_STATS_CNT) AS ACCT_STATS_CNT
     FROM   [MISProcess].[udf_MR_BALANCES_STAT_UNI](@DATA_DT_ID, @LVL_NUM) AS BALANCES
     INNER JOIN [MISProcess].[udf_MR_ALSRC](@DATA_DT_ID, @LVL_NUM) AS BUPALSRC
            ON BUPALSRC.ALOCN_SRC_CD = BALANCES.BUS_UNIT_ID
     INNER JOIN MISProcess.LKP_PRODLINE AS PRODLINE
            ON PRODLINE.DATA_DT_ID = @DATA_DT_ID
               AND PRODLINE.PROD_LINE_CD = BALANCES.BUS_UNIT_PROD_LINE_CD
     INNER JOIN PUASFIN.FocusResults.BS AS BS
            ON BS.YYMM_ID = BALANCES.YYMM_ID
               AND BS.ALOCN_BASE_CD = BUPALSRC.ALOCN_BASE_CD
               AND BS.ALOCN_SRC_CD <> BALANCES.BUS_UNIT_ID
               AND (
                    PRODLINE.GENRC_PROD_LINE_IND = 'Y'
                    OR BS.PROD_LINE_CD = BALANCES.BUS_UNIT_PROD_LINE_CD
                   )
     INNER JOIN [MISProcess].[udf_MR_ALSRC](@DATA_DT_ID, 0) AS DEST_BUP_ALSRC
            ON DEST_BUP_ALSRC.ALOCN_SRC_CD = BS.ALOCN_SRC_CD
               AND DEST_BUP_ALSRC.ALOCN_LVL_NUM > @LVL_NUM
     LEFT JOIN [MISProcess].[udf_MR_BLOCK_STD_COST_PCT](@DATA_DT_ID) AS BLOCK_STD_COST_PCT
            ON BLOCK_STD_COST_PCT.FROM_ALOCN_SRC_CD = BALANCES.BUS_UNIT_ID
     LEFT JOIN [MISProcess].[udf_MR_BLOCK_NOT](@DATA_DT_ID) AS BLOCK_NOT
            ON BLOCK_NOT.ALOCN_SRC_CD = BALANCES.BUS_UNIT_ID
     LEFT JOIN [MISProcess].[udf_MR_BLOCK](@DATA_DT_ID) AS BLOCK
            ON BLOCK_NOT.ALOCN_SRC_CD IS NULL
               AND BLOCK.FROM_ALOCN_SRC_CD = BALANCES.BUS_UNIT_ID
               AND (
                    BLOCK.FROM_PROD_LINE_CD IS NULL
                    OR BLOCK.FROM_PROD_LINE_CD = BALANCES.BUS_UNIT_PROD_LINE_CD
                   )
     LEFT JOIN [MISProcess].[udf_MR_BLOCK_ALOCN_PAIRS](@DATA_DT_ID, @LVL_NUM)
            AS BLOCK_ALOCN_PAIRS
            ON BLOCK_NOT.ALOCN_SRC_CD IS NOT NULL
               AND BLOCK_ALOCN_PAIRS.FROM_ALOCN_SRC_CD = BALANCES.BUS_UNIT_ID
               AND BLOCK_ALOCN_PAIRS.TO_ALOCN_SRC_CD = BS.ALOCN_SRC_CD
     WHERE  BLOCK_ALOCN_PAIRS.TO_ALOCN_SRC_CD IS NULL
            AND BLOCK_STD_COST_PCT.FROM_ALOCN_SRC_CD IS NULL
            AND (
                 BLOCK.TO_ALOCN_SRC_CD IS NULL
                 OR BLOCK.TO_ALOCN_SRC_CD = BS.ALOCN_SRC_CD
                )
            AND (
                 BLOCK.TO_PROD_LINE_CD IS NULL
                 OR BLOCK.TO_PROD_LINE_CD = BS.PROD_LINE_CD
                )
            AND (
                 BLOCK.YEAR_NUM IS NULL
                 OR BLOCK.YEAR_NUM = BALANCES.YYMM_ID / 10000
                )
            AND (
                 BLOCK.MTH_NUM IS NULL
                 OR BLOCK.MTH_NUM = (BALANCES.YYMM_ID / 100) % 100
                )
            AND (
                 BLOCK.TO_DIV_NUM IS NULL
                 OR BLOCK.TO_DIV_NUM = DEST_BUP_ALSRC.DIV_NUM
                )
            AND (
                 BLOCK.TO_GRP_NUM IS NULL
                 OR BLOCK.TO_GRP_NUM = DEST_BUP_ALSRC.DIV_GRP
                )
            AND (
                 BLOCK.TO_REGN_GRP_NM IS NULL
                 OR BLOCK.TO_REGN_GRP_NM = DEST_BUP_ALSRC.REGN_GRP_NM
                )
            AND (
                 BLOCK.TO_REGN_NM IS NULL
                 OR BLOCK.TO_REGN_NM = DEST_BUP_ALSRC.REGN_NM
                )
            AND (
                 BLOCK.TO_ARENA_NM IS NULL
                 OR BLOCK.TO_ARENA_NM = DEST_BUP_ALSRC.ARENA_NM
                )
            AND (
                 BLOCK.TO_SUB_REGN_NM IS NULL
                 OR BLOCK.TO_SUB_REGN_NM = DEST_BUP_ALSRC.SUB_REGN_NM
                )
            AND (
                 BLOCK.TO_SUB_ARENA_NM IS NULL
                 OR BLOCK.TO_SUB_ARENA_NM = DEST_BUP_ALSRC.SUB_ARENA_NM
                )
     GROUP BY BALANCES.YYMM_ID
           ,BS.ALOCN_SRC_CD
           ,BS.PROD_LINE_CD
           ,BALANCES.BUS_UNIT_ID
           ,BALANCES.BUS_UNIT_PROD_LINE_CD
           ,BALANCES.ORIG_ALOCN_SRC_CD
           ,BALANCES.ALOCN_LINE_ITEM_NUM
    )

/****** Object:  UserDefinedFunction [MISProcess].[udf_MR_ALOCN_SUMRY_STAT_UNI]    Script Date: 05/14/2009 22:16:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [MISProcess].[udf_MR_ALOCN_SUMRY_STAT_UNI] (
     @DATA_DT_ID int
    ,@LVL_NUM int
    )
RETURNS TABLE
--    WITH SCHEMABINDING
AS 
RETURN
    (
     SELECT YYMM_ID
           ,ALOCN_SRC_CD
           ,ALOCN_SRC_PROD_LINE_CD
           ,ORIG_ALOCN_SRC_CD
           ,ALOCN_LINE_ITEM_NUM
           ,SUM(ACCT_STATS_CNT) AS ACCT_STATS_CNT
     FROM   [MISProcess].[udf_MR_ALOCNS_STAT_UNI](@DATA_DT_ID, @LVL_NUM) AS ALOCNS
     GROUP BY YYMM_ID
           ,ALOCN_SRC_CD
           ,ALOCN_SRC_PROD_LINE_CD
           ,ORIG_ALOCN_SRC_CD
           ,ALOCN_LINE_ITEM_NUM
    )

Ini adalah kumpulan pengujian saya yang pada akhirnya akan menjalankan seluruh proses dalam satu SP. Anda dapat melihat dari bagian yang dikomentari bahwa saya telah bermain-main dengan tabel sementara dan variabel tabel juga:

USE PCAPFIN

DECLARE @DATA_DT_ID_use AS int
DECLARE @MinLevel AS int
DECLARE @MaxLevel AS int
DECLARE @TestEveryLevel AS bit
DECLARE @TestFinal AS bit

SET @DATA_DT_ID_use = 20090331
SET @MinLevel = 6
SET @MaxLevel = 6
SET @TestEveryLevel = 0
SET @TestFinal = 1

--DECLARE @BALANCES TABLE (
--     METHOD_TXT varchar(12) NOT NULL
--    ,YYMM_ID int NOT NULL
--    ,BUS_UNIT_ID varchar(6) NOT NULL
--    ,BUS_UNIT_PROD_LINE_CD varchar(4) NOT NULL
--    ,ALOCN_SRC_PROD_LINE_CD varchar(4) NOT NULL
--    ,ORIG_ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_LINE_ITEM_NUM int NOT NULL
--    ,ANULZD_ACTL_BAL money
--    )
--
--DECLARE @ALOCNS TABLE (
--     METHOD_TXT varchar(12) NOT NULL
--    ,YYMM_ID int NOT NULL
--    ,BUS_UNIT_ID varchar(6) NOT NULL
--    ,BUS_UNIT_PROD_LINE_CD varchar(4) NOT NULL
--    ,ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_SRC_PROD_LINE_CD varchar(4) NOT NULL
--    ,ORIG_ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_LINE_ITEM_NUM int NOT NULL
--    ,ACCT_STATS_CNT money
--    )
--
--DECLARE @ALOCN_SUMRY TABLE (
--     METHOD_TXT varchar(12) NOT NULL
--    ,YYMM_ID int NOT NULL
--    ,ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_SRC_PROD_LINE_CD varchar(4) NOT NULL
--    ,ORIG_ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_LINE_ITEM_NUM int NOT NULL
--    ,ACCT_STATS_CNT money
--    )

--IF OBJECT_ID('tempdb..#BALANCES') IS NOT NULL 
--    DROP TABLE #BALANCES
--
--CREATE TABLE #BALANCES (
--     METHOD_TXT varchar(12) NOT NULL
--    ,YYMM_ID int NOT NULL
--    ,BUS_UNIT_ID varchar(6) NOT NULL
--    ,BUS_UNIT_PROD_LINE_CD varchar(4) NOT NULL
--    ,ALOCN_SRC_PROD_LINE_CD varchar(4) NOT NULL
--    ,ORIG_ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_LINE_ITEM_NUM int NOT NULL
--    ,ANULZD_ACTL_BAL money
--    ,CONSTRAINT [PK_BALANCES] PRIMARY KEY CLUSTERED ([METHOD_TXT] ASC, [YYMM_ID] ASC, [BUS_UNIT_ID] ASC, [BUS_UNIT_PROD_LINE_CD] ASC, [ALOCN_SRC_PROD_LINE_CD] ASC, [ORIG_ALOCN_SRC_CD] ASC, [ALOCN_LINE_ITEM_NUM] ASC)
--        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
--              IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
--              ALLOW_PAGE_LOCKS = ON)
--    )
--
--IF OBJECT_ID('tempdb..#ALOCN_SUMRY') IS NOT NULL 
--    DROP TABLE #ALOCNS
--
--CREATE TABLE #ALOCNS (
--     METHOD_TXT varchar(12) NOT NULL
--    ,YYMM_ID int NOT NULL
--    ,BUS_UNIT_ID varchar(6) NOT NULL
--    ,BUS_UNIT_PROD_LINE_CD varchar(4) NOT NULL
--    ,ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_SRC_PROD_LINE_CD varchar(4) NOT NULL
--    ,ORIG_ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_LINE_ITEM_NUM int NOT NULL
--    ,ACCT_STATS_CNT money
--    ,CONSTRAINT [PK_ALOCNS] PRIMARY KEY CLUSTERED ([METHOD_TXT] ASC, YYMM_ID ASC, BUS_UNIT_ID ASC, BUS_UNIT_PROD_LINE_CD ASC, ALOCN_SRC_CD ASC, ALOCN_SRC_PROD_LINE_CD ASC, ORIG_ALOCN_SRC_CD ASC, ALOCN_LINE_ITEM_NUM ASC)
--        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
--              IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
--              ALLOW_PAGE_LOCKS = ON)
--    )
--
--IF OBJECT_ID('tempdb..#ALOCN_SUMRY') IS NOT NULL 
--    DROP TABLE #ALOCN_SUMRY
--CREATE TABLE #ALOCN_SUMRY (
--     METHOD_TXT varchar(12) NOT NULL
--    ,YYMM_ID int NOT NULL
--    ,ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_SRC_PROD_LINE_CD varchar(4) NOT NULL
--    ,ORIG_ALOCN_SRC_CD varchar(6) NOT NULL
--    ,ALOCN_LINE_ITEM_NUM int NOT NULL
--    ,ACCT_STATS_CNT money
--    ,CONSTRAINT [PK_ALOCN_SUMRY] PRIMARY KEY CLUSTERED ([METHOD_TXT] ASC, YYMM_ID ASC, ALOCN_SRC_CD ASC, ALOCN_SRC_PROD_LINE_CD ASC, ORIG_ALOCN_SRC_CD ASC, ALOCN_LINE_ITEM_NUM ASC)
--        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
--              IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
--              ALLOW_PAGE_LOCKS = ON)
--    )

SET @MinLevel = (
                 SELECT MIN(BUPALSRC.ALOCN_LVL_NUM)
                 FROM   MISProcess.LKP_BUPALSRC AS BUPALSRC
                 WHERE  BUPALSRC.DATA_DT_ID = @DATA_DT_ID_use
                        AND BUPALSRC.ALOCN_LVL_NUM >= @MinLevel
                )

DECLARE @Restart AS bit
IF @MinLevel > (
                SELECT  MIN(BUPALSRC.ALOCN_LVL_NUM)
                FROM    MISProcess.LKP_BUPALSRC AS BUPALSRC
                WHERE   BUPALSRC.DATA_DT_ID = @DATA_DT_ID_use
               ) 
    SET @Restart = 0
ELSE 
    SET @Restart = 1

DECLARE @subset_criteria AS varchar(max)

SET NOCOUNT ON

IF @Restart = 1 
    BEGIN
        RAISERROR ('Restarting process', 10, 1) WITH NOWAIT
--        TRUNCATE TABLE MISWork.AB
        DELETE FROM MISWork.AB

        INSERT  INTO MISWork.AB (
                 YYMM_ID
                ,BUS_UNIT_ID
                ,BUS_UNIT_PROD_LINE_CD
                ,ALOCN_SRC_CD
                ,ALOCN_SRC_PROD_LINE_CD
                ,ORIG_ALOCN_SRC_CD
                ,LINE_ITEM_NUM
                ,BAL_ORIGTN_IND
                ,ANULZD_ACTL_BAL
                ,ACCT_STATS_CNT
                ,LVL_NUM
                ,METHOD_TXT
                )
                SELECT  YYMM_ID
                       ,ALOCN_SRC_CD AS BUS_UNIT_ID
                       ,PROD_LINE_CD AS BUS_UNIT_PROD_LINE_CD
                       ,ALOCN_SRC_CD
                       ,PROD_LINE_CD AS ALOCN_SRC_PROD_LINE_CD
                       ,ALOCN_SRC_CD AS ORIG_ALOCN_SRC_CD
                       ,LINE_ITEM_NUM
                       ,'D' AS BAL_ORIGTN_IND
                       ,FIN_ALOCN_AMT AS ANULZD_ACTL_BAL
                       ,0.0 AS ACCT_STATS_CNT
                       ,0 AS LVL_NUM
                       ,'D-INIT' AS METHOD_TXT
    --        FROM    MISProcess.FIN_FTP
                FROM    PUASFIN.FocusResults.BUPALLGE
    END
ELSE 
    BEGIN
        DELETE  FROM MISWork.AB
        WHERE   LVL_NUM >= @MinLevel
    END

DECLARE @LVL_NUM AS int
SET @LVL_NUM = @MinLevel
WHILE @LVL_NUM <= @MaxLevel
    BEGIN
        DECLARE @LevelStart AS varchar(50)
        SET @LevelStart = 'Level:' + CONVERT(varchar, @LVL_NUM)
        RAISERROR (@LevelStart, 10, 1) WITH NOWAIT

        RAISERROR ('STD_COST_PCT allocations - No D - B records', 10, 1) WITH NOWAIT
        -- STD_COST_PCT allocations - No D - B records
        INSERT  INTO MISWork.AB (
                 YYMM_ID
                ,BUS_UNIT_ID
                ,BUS_UNIT_PROD_LINE_CD
                ,ALOCN_SRC_CD
                ,ALOCN_SRC_PROD_LINE_CD
                ,ORIG_ALOCN_SRC_CD
                ,LINE_ITEM_NUM
                ,BAL_ORIGTN_IND
                ,ANULZD_ACTL_BAL
                ,ACCT_STATS_CNT
                ,LVL_NUM
                ,METHOD_TXT
                )
                SELECT  ALOCNS.YYMM_ID
                       ,ALOCNS.BUS_UNIT_ID
                       ,ALOCNS.BUS_UNIT_PROD_LINE_CD
                       ,ALOCNS.BUS_UNIT_ID AS ALOCN_SRC_CD
                       ,ALOCNS.BUS_UNIT_PROD_LINE_CD AS ALOCN_SRC_PROD_LINE_CD
                       ,ALOCNS.BUS_UNIT_ID AS ORIG_ALOCN_SRC_CD
                       ,ALOCNS.LINE_ITEM_NUM
                       ,'B' AS BAL_ORIGTN_IND
                       ,-1.0 * ROUND(ALOCNS.ANULZD_ACTL_BAL, 2) AS ANULZD_ACTL_BAL
                       ,ROUND(ALOCNS.ACCT_STATS_CNT, 2) AS ACCT_STATS_CNT
                       ,@LVL_NUM AS LVL_NUM
                       ,'NO-D-B' AS METHOD_TXT
                FROM    [MISProcess].[udf_MR_ALOCNS_STD_COST_PCT_NO_D](@DATA_DT_ID_use, @LVL_NUM)
                        AS ALOCNS

        RAISERROR ('STD_COST_PCT allocations - No D - A records', 10, 1) WITH NOWAIT
        -- STD_COST_PCT allocations - No D - A records
        INSERT  INTO MISWork.AB (
                 YYMM_ID
                ,BUS_UNIT_ID
                ,BUS_UNIT_PROD_LINE_CD
                ,ALOCN_SRC_CD
                ,ALOCN_SRC_PROD_LINE_CD
                ,ORIG_ALOCN_SRC_CD
                ,LINE_ITEM_NUM
                ,BAL_ORIGTN_IND
                ,ANULZD_ACTL_BAL
                ,ACCT_STATS_CNT
                ,LVL_NUM
                ,METHOD_TXT
                )
                SELECT  ALOCNS.YYMM_ID
                       ,BLOCK.TO_ALOCN_SRC_CD AS BUS_UNIT_ID
                       ,ALOCNS.ALOCN_SRC_PROD_LINE_CD AS BUS_UNIT_PROD_LINE_CD
                       ,ALOCNS.ALOCN_SRC_CD
                       ,ALOCNS.BUS_UNIT_PROD_LINE_CD AS ALOCN_SRC_PROD_LINE_CD
                       ,ALOCNS.ORIG_ALOCN_SRC_CD
                       ,ALOCNS.LINE_ITEM_NUM
                       ,'A' AS BAL_ORIGTN_IND
                       ,ROUND(ALOCNS.ANULZD_ACTL_BAL, 2) AS ANULZD_ACTL_BAL
                       ,ROUND(ALOCNS.ACCT_STATS_CNT, 2) AS ACCT_STATS_CNT
                       ,@LVL_NUM AS LVL_NUM
                       ,'NO-D-A' AS METHOD_TXT
                FROM    [MISProcess].[udf_MR_ALOCNS_STD_COST_PCT_NO_D](@DATA_DT_ID_use, @LVL_NUM)
                        AS ALOCNS
                INNER JOIN MISProcess.LKP_BLOCK AS BLOCK
                        -- TODO: Can this be moved into the udf above?
                            ON BLOCK.DATA_DT_ID = @DATA_DT_ID_use
                               AND BLOCK.FROM_ALOCN_SRC_CD = ALOCNS.BUS_UNIT_ID

        RAISERROR ('STD_COST_PCT allocations - B records', 10, 1) WITH NOWAIT

        -- STD_COST_PCT allocations - B records
        INSERT  INTO MISWork.AB (
                 YYMM_ID
                ,BUS_UNIT_ID
                ,BUS_UNIT_PROD_LINE_CD
                ,ALOCN_SRC_CD
                ,ALOCN_SRC_PROD_LINE_CD
                ,ORIG_ALOCN_SRC_CD
                ,LINE_ITEM_NUM
                ,BAL_ORIGTN_IND
                ,ANULZD_ACTL_BAL
                ,ACCT_STATS_CNT
                ,LVL_NUM
                ,METHOD_TXT
                )
                SELECT  ALOCNS.YYMM_ID
                       ,ALOCNS.BUS_UNIT_ID
                       ,ALOCNS.BUS_UNIT_PROD_LINE_CD
                       ,ALOCNS.ALOCN_SRC_CD
                       ,ALOCNS.BUS_UNIT_PROD_LINE_CD AS ALOCN_SRC_PROD_LINE_CD
                       ,ALOCNS.ORIG_ALOCN_SRC_CD
                       ,ALOCNS.LINE_ITEM_NUM
                       ,'B' AS BAL_ORIGTN_IND
                       ,-1.0 * ROUND(ALOCNS.ANULZD_ACTL_BAL * RATIOS.RATIO, 2) AS ANULZD_ACTL_BAL
                       ,ROUND(ALOCNS.ACCT_STATS_CNT, 2) AS ACCT_STATS_CNT
                       ,@LVL_NUM AS LVL_NUM
                       ,'STD-B' AS METHOD_TXT
                FROM    [MISProcess].[udf_MR_ALOCNS_STD_COST_PCT](@DATA_DT_ID_use, @LVL_NUM)
                        AS ALOCNS
                INNER JOIN [MISProcess].[udf_MR_RATIOS_STD_COST_PCT](@DATA_DT_ID_use, @LVL_NUM)
                        AS RATIOS
                        ON RATIOS.YYMM_ID = ALOCNS.YYMM_ID
                           AND RATIOS.BUS_UNIT_ID = ALOCNS.BUS_UNIT_ID
                           AND RATIOS.LINE_ITEM_NUM = ALOCNS.LINE_ITEM_NUM

        RAISERROR ('STD_COST_PCT allocations - A records', 10, 1) WITH NOWAIT

        -- STD_COST_PCT allocations - A records
        ;
        WITH    CORRECTED_ALOCNS
                  AS (
                      SELECT    ALOCNS.YYMM_ID
                               ,ALOCNS.BUS_UNIT_ID
                               ,ALOCNS.BUS_UNIT_PROD_LINE_CD
                               ,ALOCNS.ALOCN_SRC_CD
                               ,ALOCNS.ALOCN_SRC_PROD_LINE_CD
                               ,ALOCNS.ORIG_ALOCN_SRC_CD
                               ,ALOCNS.LINE_ITEM_NUM
                               ,ALOCNS.ANULZD_ACTL_BAL * RATIOS.RATIO AS ANULZD_ACTL_BAL
                               ,CASE WHEN RATIOS.RATIO <> 1.0
                                     THEN RATIOS.RATIO
                                     ELSE ALOCNS.ACCT_STATS_CNT
                                END AS ACCT_STATS_CNT
                      FROM      [MISProcess].[udf_MR_CORR_ALOCNS_STD_COST_PCT](@DATA_DT_ID_use, @LVL_NUM)
                                AS ALOCNS
                      INNER JOIN [MISProcess].[udf_MR_RATIOS_STD_COST_PCT](@DATA_DT_ID_use, @LVL_NUM)
                                AS RATIOS
                                ON RATIOS.YYMM_ID = ALOCNS.YYMM_ID
                                   AND RATIOS.BUS_UNIT_ID = ALOCNS.ALOCN_SRC_CD
                                   AND RATIOS.LINE_ITEM_NUM = ALOCNS.LINE_ITEM_NUM
                     ),
                ROUNDED_ALOCNS
                  AS (
                      SELECT    YYMM_ID
                               ,BUS_UNIT_ID
                               ,BUS_UNIT_PROD_LINE_CD
                               ,ALOCN_SRC_CD
                               ,ALOCN_SRC_PROD_LINE_CD
                               ,ORIG_ALOCN_SRC_CD
                               ,LINE_ITEM_NUM
                               ,CASE WHEN ABS(ANULZD_ACTL_BAL) < 0.05 THEN 0.0
                                     WHEN ABS(ANULZD_ACTL_BAL) > 0.05
                                          AND ABS(ANULZD_ACTL_BAL) < 0.10
                                     THEN 0.10 * SIGN(ANULZD_ACTL_BAL)
                                     ELSE ANULZD_ACTL_BAL
                                END AS ANULZD_ACTL_BAL
                               ,ACCT_STATS_CNT
                      FROM      CORRECTED_ALOCNS
                     )
            INSERT  INTO MISWork.AB (
                     YYMM_ID
                    ,BUS_UNIT_ID
                    ,BUS_UNIT_PROD_LINE_CD
                    ,ALOCN_SRC_CD
                    ,ALOCN_SRC_PROD_LINE_CD
                    ,ORIG_ALOCN_SRC_CD
                    ,LINE_ITEM_NUM
                    ,BAL_ORIGTN_IND
                    ,ANULZD_ACTL_BAL
                    ,ACCT_STATS_CNT
                    ,LVL_NUM
                    ,METHOD_TXT
                    )
                    SELECT  YYMM_ID
                           ,BUS_UNIT_ID
                           ,BUS_UNIT_PROD_LINE_CD
                           ,ALOCN_SRC_CD
                           ,ALOCN_SRC_PROD_LINE_CD
                           ,ORIG_ALOCN_SRC_CD
                           ,LINE_ITEM_NUM
                           ,'A' AS BAL_ORIGTN_IND
                           ,ROUND(ANULZD_ACTL_BAL, 2) AS ANULZD_ACTL_BAL
                           ,ROUND(ACCT_STATS_CNT, 2) AS ACCT_STATS_CNT
                           ,@LVL_NUM AS LVL_NUM
                           ,'STD-A' AS METHOD_TXT
                    FROM    ROUNDED_ALOCNS
                    WHERE   ANULZD_ACTL_BAL <> 0.0
                            OR ACCT_STATS_CNT <> 0.0

        RAISERROR ('COLLAPSE, BLOCK 100 ALOCN_PCT - B records', 10, 1) WITH NOWAIT

        -- COLLAPSE, BLOCK 100% ALOCN_PCT - B records
        INSERT  INTO MISWork.AB (
                 YYMM_ID
                ,BUS_UNIT_ID
                ,BUS_UNIT_PROD_LINE_CD
                ,ALOCN_SRC_CD
                ,ALOCN_SRC_PROD_LINE_CD
                ,ORIG_ALOCN_SRC_CD
                ,LINE_ITEM_NUM
                ,BAL_ORIGTN_IND
                ,ANULZD_ACTL_BAL
                ,ACCT_STATS_CNT
                ,LVL_NUM
                ,METHOD_TXT
                )
                SELECT  BALANCES.YYMM_ID
                       ,BALANCES.BUS_UNIT_ID
                       ,BALANCES.BUS_UNIT_PROD_LINE_CD
                       ,BALANCES.BUS_UNIT_ID AS ALOCN_SRC_CD
                       ,BALANCES.BUS_UNIT_PROD_LINE_CD AS ALOCN_SRC_PROD_LINE_CD
                       ,BALANCES.ORIG_ALOCN_SRC_CD
                       ,BALANCES.ALOCN_LINE_ITEM_NUM AS LINE_ITEM_NUM
                       ,'B' AS BAL_ORIGTN_IND
                       ,-1.0 * BALANCES.ANULZD_ACTL_BAL
                       ,ALOCN_SUMRY.ACCT_STATS_CNT
                       ,@LVL_NUM AS LVL_NUM
                       ,'BLOCK-100' AS METHOD_TXT
                FROM    [MISProcess].[udf_MR_BALANCES_BLOCK_100_PCT](@DATA_DT_ID_use, @LVL_NUM)
                        AS BALANCES
                INNER JOIN [MISProcess].[udf_MR_ALOCN_SUMRY_BLOCK_100_PCT](@DATA_DT_ID_use, @LVL_NUM)
                        AS ALOCN_SUMRY
                        ON ALOCN_SUMRY.YYMM_ID = BALANCES.YYMM_ID
                           AND ALOCN_SUMRY.BUS_UNIT_ID = BALANCES.BUS_UNIT_ID
                           AND ALOCN_SUMRY.BUS_UNIT_PROD_LINE_CD = BALANCES.BUS_UNIT_PROD_LINE_CD
                           AND ALOCN_SUMRY.ALOCN_SRC_CD = BALANCES.ALOCN_SRC_CD
                           AND ALOCN_SUMRY.ALOCN_SRC_PROD_LINE_CD = BALANCES.ALOCN_SRC_PROD_LINE_CD
                           AND ALOCN_SUMRY.ORIG_ALOCN_SRC_CD = BALANCES.ORIG_ALOCN_SRC_CD

        RAISERROR ('COLLAPSE, BLOCK 100 ALOCN_PCT - A records', 10, 1) WITH NOWAIT

        -- COLLAPSE, BLOCK 100% ALOCN_PCT - A records
        INSERT  INTO MISWork.AB (
                 YYMM_ID
                ,BUS_UNIT_ID
                ,BUS_UNIT_PROD_LINE_CD
                ,ALOCN_SRC_CD
                ,ALOCN_SRC_PROD_LINE_CD

person Cade Roux    schedule 15.05.2009    source sumber
comment
Sepertinya saya mengalami batasan ukuran pertanyaan di SO, jadi panggilan sebenarnya ke kumpulan UDF khusus yang saya berikan tidak ada, tetapi panggilan tersebut mirip dengan panggilan yang muncul.   -  person Cade Roux    schedule 15.05.2009


Jawaban (3)


Ya, kompilasi ulang harus diperluas ke UDFS TV.

Namun, saya akan menggunakan parameter masking bukan RECOMPILE.

  1. Dengan pertanyaan seperti ini, kompensasi akan menjadi mahal
  2. Jika UDF tidak disarangkan, penyembunyian parameter juga akan diterapkan. UDF TV tidak memiliki rencana seperti itu: mereka adalah bagian dari permintaan panggilan karena tidak bertingkat.

Bisakah Anda membagi beberapa panggilan UDF ke dalam tabel sementara dan kemudian bergabung di tabel sementara? Saya yakin ketika UDF tidak disarangkan, kueri menjadi terlalu rumit untuk dijalankan secara efisien. Pengoptimal memerlukan waktu seminggu untuk menemukan rencana ideal dengan sesuatu yang begitu kompleks. Dengan tabel temp (bukan variabel tabel), saya rasa Anda akan mendapatkan peningkatan yang lumayan.

Saya sendiri telah menggunakan teknik ini dalam beberapa pertanyaan yang lebih besar (menghasilkan pohon harga untuk instrumen keuangan)

Fakta bahwa Anda memiliki 150.000 baris dibayangi oleh kerumitannya menurut saya.

Edit:

TVF tidak memerlukan penyembunyian parameter karena hanya makro. Anda benar-benar dapat menggantinya dengan CTE atau tabel turunan.

Lihat jawaban saya di sini: Apakah pengoptimal rencana kueri berfungsi dengan baik dengan fungsi bernilai tabel yang digabungkan/difilter Dan Tony Rogerson di Tampilan

person gbn    schedule 15.05.2009
comment
Saya berasumsi yang Anda maksud adalah penyembunyian parameter di SP. Karena ketika saya pertama kali melihatnya, saya tidak dapat menemukan cara untuk melakukan penyembunyian parameter di TVF inline. Ya, saya melakukan itu untuk setiap SP. Saya berharap kami menggunakan tahun 2008 sehingga kami dapat menggunakan opsi OPTIMIZE FOR UNKNOWN. - person Cade Roux; 15.05.2009
comment
Anda tidak perlu menutupi TVF karena ini bukan objek terpisah. Ini diperluas ke dalam kueri yang memuatnya. Jawaban yang diperbarui - person gbn; 15.05.2009

Bisakah Anda memposting T-SQL yang sebenarnya dan bukan pseudo-SQL? Apa yang Anda gambarkan terdengar seperti pemindaian tabel pada kumpulan hasil yang semakin besar seiring bertambahnya @LVL_NUM dan mungkin RECOMPILE tidak akan membantu di sana. Namun, berdasarkan pseudo-SQL, sangat sulit untuk memberikan apa pun selain tebakan semu...

person Remus Rusanu    schedule 15.05.2009
comment
Tampaknya test case terpotong di postingan dan dari kodenya sendiri udf_MR_ALSRC hilang. Bisakah Anda juga memberikan perkiraan ukuran meja untuk meja peserta? - person Remus Rusanu; 15.05.2009
comment
Selain itu, saya melihat Anda mencoba menambahkan SCHEMABINDING, mengapa Anda menghapusnya? - person Remus Rusanu; 15.05.2009
comment
Sudahkah Anda membandingkan rencana eksekusi kueri yang sebenarnya saat Anda meningkatkan @LVL_NUM? Jika teori Anda benar maka rencananya akan berubah menggantikan jalur akses yang baik (mencari) dengan jalur akses yang buruk (scan). Jika teori saya benar maka rencananya akan tetap sama tetapi bobot eksekusi akan meningkat secara eksponensial dari eksekusi berulang pada @LVL_NUM yang lebih tinggi (Anda akan melihat elemen dengan 'jumlah eksekusi' yang terus meningkat dalam rencana). - person Remus Rusanu; 15.05.2009
comment
Rencana eksekusi sepertinya tidak akan berubah jika saya menjalankan satu level pada satu waktu. Hal ini membuat saya percaya bahwa UDF mempunyai semacam rencana yang disimpan dalam cache. Tentu saja, ketika dijalankan dalam satu lingkaran, rencana yang sama digunakan untuk setiap iterasi, jadi mungkin itulah penyebab utamanya. Saya memperhatikan perbedaan kinerja jika saya menghapus dan membuat ulang UDF, jadi sepertinya ada beberapa cache di sana. - person Cade Roux; 15.05.2009
comment
Jika Anda memulai langsung dengan @LVL_NUM tinggi pada cache dingin (DBCC FREESYTEMCACHE), apakah Anda mendapatkan paket yang lebih baik untuk itu? Juga, berapa waktu eksekusi dan berapa kompilasi, setelah Anda menghapus rencana dari cache? SET STATISTIK WAKTU AKTIF untuk mendapatkan waktu kompilasi. - person Remus Rusanu; 15.05.2009
comment
Tampaknya saat ini masalahnya berakar pada masalah LEFT JOIN. Saya pernah melihat ini sebelumnya dan harus mengubah LEFT JOIN WHERE right_key IS NULL menjadi WHERE NOT IN. Ada sesuatu yang aneh tentang instalasi ini dan DBA tidak mengenalinya. Itu tidak konsisten. - person Cade Roux; 18.05.2009
comment
Tidak konsisten? Mungkin pengoptimal kueri terpaksa memilih paket suboptimal berdasarkan kondisi memori. Yaitu. rencana optimal memerlukan gabungan hash, tetapi tidak cukup memori yang kosong, jadi Anda mendapatkan gabungan loop bersarang. Apakah ini Os 64 bit dan SQL 64 bit? Juga ATAU biasanya menghancurkan kemampuan SARG kueri. - person Remus Rusanu; 18.05.2009

Salah satu hal yang harus diperhatikan dengan fungsi bernilai tabel (terutama fungsi bernilai tabel multi-pernyataan) adalah bahwa tabel yang dihasilkan, seperti halnya variabel tabel, tidak memiliki statistik kolom dan tidak memiliki indeks.

Saya cenderung menggunakan TVF dengan hati-hati.

person Mitch Wheat    schedule 15.05.2009
comment
Bahkan di level 6, tabel yang dikembalikan oleh fungsi tersebut kecil - menurut saya 150.000 baris. - person Cade Roux; 15.05.2009
comment
Dan ini semua adalah fungsi bernilai tabel inline. - person Cade Roux; 15.05.2009
comment
Yang saya pahami pada dasarnya dianggap sebagai tampilan berparameter - yaitu pengoptimal dapat menciutkannya dan menyatukannya seperti jika ditulis secara inline. - person Cade Roux; 15.05.2009