普通参数比创建表参数慢

时间:2016-02-22 08:40:58

标签: sql sql-server parameters table-valued-parameters

我最近发现了一个奇怪的行为,当我提供简单的NCHAR参数而不是表值参数时,一个函数(可能也是程序)运行速度明显变慢。在尝试了一下之后我还发现,如果我将NCHAR参数选择为表变量,那么具有NCHAR参数的函数的运行速度与表值参数函数一样快。这是我用这个创建的一些代码。

带参数的功能:

ALTER FUNCTION [rpt].[ReportMaterial]
(
            @dateto NCHAR(8),
            @mfrnr NVARCHAR(10),
            @vkorg NVARCHAR(4)
)

RETURNS @ReturnValue TABLE 
( 
            MANDT NVARCHAR(3),
            MATNR NVARCHAR(18),
            MFRPN NVARCHAR(40),
            MAKTX NVARCHAR(40),
            WERKS NVARCHAR(4),
            MTART NVARCHAR(4),
            KBETR DECIMAL(11, 2),
            KONWA NVARCHAR(5)
)

AS 

BEGIN

            -- FILL UP
            SELECT @mfrnr = REPLICATE('0', 10 - LEN(@mfrnr)) + @mfrnr;

            -- OUTPUT
            WITH mat AS
            (
                        -- direct assignment
                        SELECT 
                                   ma.MANDT,
                                   ma.MATNR,
                                   ma.MFRPN,
                                   mc.WERKS,
                                   ma.MTART
                        FROM sap.MARA ma
                        INNER JOIN sap.MARC mc ON ma.MATNR = mc.MATNR AND ma.MANDT = mc.MANDT AND mc.CDCDELETED = 0
                        INNER JOIN
                        (
                                   -- better to use in subselect here
                                   SELECT DISTINCT
                                               WERKS
                                   FROM [sap].[Werks] w
                                   WHERE w.WERKSTYPE = 'D' AND w.VKORG = @vkorg
                        ) w ON w.WERKS = mc.WERKS
                        WHERE ma.MANDT = N'100' AND ma.CDCDELETED = 0 AND ma.MFRNR = @mfrnr
            )

            INSERT INTO @ReturnValue (MANDT, MATNR, MFRPN, MAKTX, WERKS, MTART, KBETR, KONWA)
            SELECT
                        t.MANDT,
                        t.MATNR,
                        t.MFRPN,
                        mk.MAKTX,
                        t.WERKS,
                        t.MTART,
                        COALESCE(pp.KBETR, 0) KBETR,
                        pp.KONWA
            FROM
            (
                        SELECT
                                   m.MANDT,
                                   m.MATNR,
                                   m.MFRPN,
                                   m.WERKS,
                                   m.MTART
                        FROM mat m

                        UNION ALL

                        -- material selection (part of a hardbundle)
                        SELECT 
                                   ma.MANDT,
                                   ma.MATNR,
                                   ma.MFRPN,
                                   ms.WERKS,
                                   ma.MTART
                        FROM sap.MARA ma
                        INNER JOIN sap.MAST ms ON ms.MATNR = ma.MATNR AND ms.STLAN = N'3' AND ms.MANDT = ma.MANDT
                        INNER JOIN sap.STKO ko ON ko.STLNR = ms.STLNR AND ko.STLAL = ms.STLAL AND ko.MANDT = ms.MANDT
                        INNER JOIN sap.STPO po ON po.STLNR = ms.STLNR AND po.MANDT = ms.MANDT
                        INNER JOIN mat mr ON po.IDNRK = mr.MATNR AND mr.MANDT = po.MANDT -- use only relevant items...
                        INNER JOIN
                        (
                                   -- better to use as subselect
                                   SELECT DISTINCT
                                               WERKS
                                   FROM [sap].[Werks] w
                                   WHERE w.WERKSTYPE = 'D' AND w.VKORG = @vkorg
                        ) w ON w.WERKS = ms.WERKS
                        WHERE ma.MTART = N'ZFER' AND ma.MFRNR = N'0080001373'  -- we use only dummy hard bundles (sign for mixed manufacturer bundles)
            ) t
            INNER JOIN sap.MAKT mk ON mk.MATNR = t.MATNR AND mk.SPRAS = N'E' AND mk.MANDT = t.MANDT
            LEFT JOIN sap.PurchasePrice pp ON pp.MATNR = t.MATNR AND pp.WERKS = t.WERKS AND pp.FLIFN = N'X' AND @dateto BETWEEN pp.VDATU AND pp.BDATU AND @dateto BETWEEN pp.DATAB AND pp.DATBI;

            RETURN 

END; 

首先在表变量中选择参数的功能:

ALTER FUNCTION [rpt].[ReportMaterial]
(
            @dateto NCHAR(8),
            @mfrnr NVARCHAR(10),
            @vkorg NVARCHAR(4)
)

RETURNS @ReturnValue TABLE 
( 
            MANDT NVARCHAR(3),
            MATNR NVARCHAR(18),
            MFRPN NVARCHAR(40),
            MAKTX NVARCHAR(40),
            WERKS NVARCHAR(4),
            MTART NVARCHAR(4),
            KBETR DECIMAL(11, 2),
            KONWA NVARCHAR(5)
)

AS 

BEGIN

            -- FILL UP
            SELECT @mfrnr = REPLICATE('0', 10 - LEN(@mfrnr)) + @mfrnr;

            --> Better performance if using a table to join instead of directly using of parameters

            -- CREATE TABLE
            DECLARE @keyValue TABLE
            (
                        MFRNR NVARCHAR(10),
                        VKORG NVARCHAR(4)
            );

            INSERT INTO @keyValue (MFRNR, VKORG) VALUES (@mfrnr, @vkorg);

            -- OUTPUT
            WITH mat AS
            (
                        -- direct assignment
                        SELECT 
                                   ma.MANDT,
                                   ma.MATNR,
                                   ma.MFRPN,
                                   mc.WERKS,
                                   ma.MTART
                        FROM sap.MARA ma
                        INNER JOIN sap.MARC mc ON ma.MATNR = mc.MATNR AND ma.MANDT = mc.MANDT AND mc.CDCDELETED = 0
                        INNER JOIN
                        (
                                   -- better to use in subselect here
                                   SELECT DISTINCT
                                               WERKS
                                   FROM [sap].[Werks] w
                                   INNER JOIN @keyValue kv1 ON kv1.VKORG = w.VKORG
                                   WHERE w.WERKSTYPE = 'D'
                        ) w ON w.WERKS = mc.WERKS
                        INNER JOIN @keyValue kv2 ON kv2.MFRNR = ma.MFRNR
                        WHERE ma.MANDT = N'100' AND ma.CDCDELETED = 0
            )

            INSERT INTO @ReturnValue (MANDT, MATNR, MFRPN, MAKTX, WERKS, MTART, KBETR, KONWA)
            SELECT
                        t.MANDT,
                        t.MATNR,
                        t.MFRPN,
                        mk.MAKTX,
                        t.WERKS,
                        t.MTART,
                        COALESCE(pp.KBETR, 0) KBETR,
                        pp.KONWA
            FROM
            (
                        SELECT
                                   m.MANDT,
                                   m.MATNR,
                                   m.MFRPN,
                                   m.WERKS,
                                   m.MTART
                        FROM mat m

                        UNION ALL

                        -- material selection (part of a hardbundle)
                        SELECT 
                                   ma.MANDT,
                                   ma.MATNR,
                                   ma.MFRPN,
                                   ms.WERKS,
                                   ma.MTART
                        FROM sap.MARA ma
                        INNER JOIN sap.MAST ms ON ms.MATNR = ma.MATNR AND ms.STLAN = N'3' AND ms.MANDT = ma.MANDT
                        INNER JOIN sap.STKO ko ON ko.STLNR = ms.STLNR AND ko.STLAL = ms.STLAL AND ko.MANDT = ms.MANDT
                        INNER JOIN sap.STPO po ON po.STLNR = ms.STLNR AND po.MANDT = ms.MANDT
                        INNER JOIN mat mr ON po.IDNRK = mr.MATNR AND mr.MANDT = po.MANDT -- use only relevant items...
                        INNER JOIN
                        (
                                   -- better to use as subselect
                                   SELECT DISTINCT
                                               WERKS
                                   FROM [sap].[Werks] w
                                   INNER JOIN @keyValue kv1 ON kv1.VKORG = w.VKORG
                                   WHERE w.WERKSTYPE = 'D'
                        ) w ON w.WERKS = ms.WERKS
                        WHERE ma.MTART = N'ZFER' AND ma.MFRNR = N'00000000'
            ) t
            INNER JOIN sap.MAKT mk ON mk.MATNR = t.MATNR AND mk.SPRAS = N'E' AND mk.MANDT = t.MANDT
            LEFT JOIN sap.PurchasePrice pp ON pp.MATNR = t.MATNR AND pp.WERKS = t.WERKS AND pp.FLIFN = N'X' AND @dateto BETWEEN pp.VDATU AND pp.BDATU AND @dateto BETWEEN pp.DATAB AND pp.DATBI;

            RETURN  

END;

有人有想法,为什么会这样?我是否需要通过将参数选择到临时表/表变量来利用这种效果?

0 个答案:

没有答案