我最近发现了一个奇怪的行为,当我提供简单的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;
有人有想法,为什么会这样?我是否需要通过将参数选择到临时表/表变量来利用这种效果?