1

Sur SQL Server 2005, j'ai un complexe processus d'allocation multi-niveaux qui ressemble à ceci (pseudo-SQL):Process Design T-SQL et plan d'exécution (UDF Paramètre reniflage?)

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) 

ALLOCSBALANCES(@LVL_NUM) est basé sur sur au @LVL_NUM (qui pourrait être quelques allocations directes plus quelques allocations IN d'un niveau précédent) et ALOCNS(@LVL_NUM) est basé sur BALANCES(@LVL_NUM) et ALOCN_SUMRY(@LVL_NUM) est simplement basé sur ALOCNS(@LVL_NUM) - avec beaucoup de configuration tables qui indiquent les pilotes qui génèrent les allocations.

C'est simplifié, mais il y a en fait quatre ou cinq paires comme celui-ci dans la boucle, car il existe une variété de logiques qui ne sont pas possibles pour gérer ensemble (et certains cas qui permettent de traiter ensemble.)

La logique de base consiste à prendre le montant total dans un centre de coûts/ligne de produits particulier (c.-à-d. BALANCES), puis de l'allouer à un autre centre de coûts/ligne de produits/etc en fonction de sa part (ALLOCNS/ALLOCN_SUMRY pourcentage) d'une métrique particulière.

Avec tant de logique répétée dans la tenue des dossiers OUT et IN, et bien sûr le SUMRY basé sur le ALLOCN détail, je fini par mettre en œuvre en utilisant des fonctions de valeur de table en ligne, qui semblent exécuter assez bien (et ils correspondent à l'existant comportement du système dans les tests de régression, ce qui est un plus!). (Le système existant est un programme monstre C/C++/MFC/ODBC qui lit toutes les données dans des tableaux massifs et autres structures de données et est assez atrocement écrit.)

Le problème semble être que lorsqu'il est exécuté dans la boucle I Les tables commencent à changer (et tout change, car les niveaux ont des centres de coûts différents, donc la configuration utilisée pour piloter le ALLOCNS est en train de changer). J'ai jusqu'à 99 niveaux, je pense, mais les niveaux les plus bas commencent 2, 4, 6. Il semble qu'exécuter @LVL_NUM = 6 par lui-même en dehors de l'UDF fonctionne bien, mais que l'UDF fonctionne mal - probablement parce que l'UDF a un plan en cache ou que le plan global est déjà mauvais en raison des ALLOCS ajoutés à partir des étapes précédentes au @LVL_NUM IN (2, 4).

Plus tôt dans le développement, j'ai réussi à obtenir 30 niveaux en 30 minutes, mais maintenant je n'arrive pas à terminer les 3 premiers niveaux en 2 heures.

Je songe à exécuter les deux insertions dans un autre SP et à l'appeler WITH RECOMPILE, mais je me demandais si ce RECOMPILE cascades correctement dans les UDF TVF? Tout autre conseil serait également apprécié.

Real Code:

/****** 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 
    ) 

Ceci est mon lot de test qui finira par exécuter l'ensemble du processus en un seul SP. Vous pouvez voir de commentaires des sections que je joue avec des tables temporaires et les variables de table ainsi:

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 
+0

On dirait que je suis tombé sur une limite de la taille de la question sur le SO, de sorte que les appels réels à l'ensemble apparié particulier de UDFs je donnai manquent, mais les appels sont similaires à ceux qui apparaissent. –

Répondre

1

Oui, la recompilation devrait s'étendre à la TV UDFS. Cependant, j'utiliserais le masquage de paramètres non RECOMPILE.

  1. Avec des requêtes comme celle-ci, complation sera cher
  2. Lorsque les UDFs sont non imbriquées, le masquage des paramètres appliquera aussi. Les fonctions UDF de télévision n'ont pas de plan en tant que tel: elles font partie de la requête d'appel car elles ne sont pas utilisées.

Pouvez-vous répartir certains appels UDF dans des tables temporaires, puis rejoindre les tables temporaires? Je parie que lorsque les UDF sont non-testés, la requête est simplement trop complexe pour fonctionner efficacement. L'optimiseur pourrait prendre une semaine pour trouver le plan idéal avec quelque chose de si complexe. Avec les tables temporaires (pas les variables de table), je suppose que vous obtiendrez des améliorations respectables.

Je l'ai utilisé moi-même dans la technique des requêtes plus grandes (générant des arbres de prix pour les instruments financiers)

Le fait que vous 150.000 lignes est éclipsée par la complexité même je pense.

Modifier:

TVFs ne ont pas besoin de masquage de paramètres, car ils ne sont que des macros. Vous pourriez littéralement le remplacer par un CTE ou une table dérivée.

Voir ma réponse ici: Does query plan optimizer works well with joined/filtered table-valued functions Et Tony Rogerson on Views

+0

Je suppose que vous voulez dire le masquage des paramètres dans le SP. Parce que quand je l'ai d'abord regardé, je ne pouvais pas trouver un moyen de masquer les paramètres dans un TVF en ligne. Oui, je le fais pour chaque SP. Je souhaite que nous utilisions 2008 afin que nous puissions utiliser l'option OPTIMISER POUR INCONNU. –

+0

Vous n'avez pas besoin de maska ​​TVF car ce n'est pas un objet discret. Il est développé dans la requête contenant. Réponse mise à jour – gbn

0

L'une des choses à surveiller avec des fonctions table (en particulier la table multi-instruction valorisée fonctions) est que la table résultante, tout comme une variable de table, n'a aucune statistique de colonne et aucun index.

J'ai tendance à utiliser les TVF avec prudence.

+0

Même au niveau 6, les tables retournées par la fonction sont minuscules - je pense 150 000 lignes. –

+0

Et ce sont toutes les fonctions de table en ligne. –

+0

Ce que je comprends être essentiellement traité comme des vues paramétrées - c'est-à-dire que l'optimiseur peut les réduire et les pousser ensemble comme si elles étaient écrites en ligne. –

0

Pouvez-vous poster le vrai T-SQL plutôt que le pseudo-SQL? Ce que vous décrivez ressemble à des analyses de tables sur des ensembles de résultats de plus en plus grands lorsque @LVL_NUM augmente et que RECOMPILE ne sera probablement pas utile. Mais, basé sur pseudo-SQL, est vraiment difficile de donner quelque chose de plus qu'une pseudo-conjecture ...

+0

Publié le code réel. –

+0

Il semble que le scénario de test ait été tronqué dans le message et que le code udf_MR_ALSRC soit manquant. Pouvez-vous également donner l'approximation des tailles de table pour les tables des participants? –

+0

Aussi, je vois que vous avez essayé d'ajouter SCHEMABINDING, pourquoi l'avez-vous retiré? –