dsu*_*aro 11 sql-server functions sql-server-2019
我已将 SQL Server 2012 数据库(大小为 8GB)移至具有相同内存和 CPU 配置的新设置的 SQL Server 2019 虚拟机,并将兼容级别更改为 SQL Server 2019。
我的应用程序中的所有内容都运行良好,除了一个存储过程,它包含一个带有两个参数的大 SQL 查询(并且没有花哨的选项)。当这个 SP 执行时,它让 SQL Server 进程的内存上升到指定的最大级别,然后返回错误:
“内存不足,无法运行此查询”
当我在 SSMS 的单独查询窗口中执行 SQL 查询(在存储过程中)时,它会立即执行并返回预期的 300 行。此外,当我将数据库的兼容性级别更改为“SQL Server 2017”并执行存储过程时,一切正常。
我首先认为这可能是参数嗅探问题,但没有一种解决方法有帮助(例如OPTION (RECOMPILE)
)。
我已经将问题深入到标量值函数的调用中。每次调用这个函数,都会出现内存错误。
这是该函数的 DDL(抱歉,部分是德语):
CREATE FUNCTION [dbo].[GetWtmTime] (
@WorkTimeModelID uniqueidentifier,
@Date DATETIME,
@SequenceNo TINYINT)
RETURNS VARCHAR(5)
AS
BEGIN
-- SET DATEFIRST 7; has to be executed before calling this function
DECLARE @WtmTime VARCHAR(5)
DECLARE @WtmWeeks INT
DECLARE @WtmTakeHolidays BIT
DECLARE @WtmMaxMemberCount TINYINT
SELECT @WtmWeeks = AnzahlWochen
, @WtmTakeHolidays = ÜbernimmtFeiertage
, @WtmMaxMemberCount = MaxAnzahlMitglieder
FROM Arbeitszeitmodelle
WHERE ArbeitszeitmodellID = @WorkTimeModelID;
IF @WtmWeeks = 1
BEGIN
IF (dbo.IstFeiertag(@Date, 0) = 1 -- Holiday
AND @WtmMaxMemberCount = 1)
BEGIN
IF @WtmTakeHolidays = 0
BEGIN
IF @Date >= '20130901'
SET @WtmTime = 'KD'
ELSE
SET @WtmTime = 'ZA';
END ELSE
BEGIN
IF EXISTS ( SELECT *
FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo
AND AzmZeitMo IN ('KD','T')
AND AzmZeitDi IN ('KD','T')
AND AzmZeitMi IN ('KD','T')
AND AzmZeitDo IN ('KD','T')
AND AzmZeitFr IN ('KD','T')
AND AzmZeitSa IN ('KD','T')
AND AzmZeitSo IN ('KD','T') )
SET @WtmTime = 'T';
ELSE
SET @WtmTime = 'G';
END
END ELSE IF DATEPART(dw, @Date) = 1 -- Sunday
SELECT @WtmTime = AzmZeitSo FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
ELSE IF DATEPART(dw, @Date) = 2 -- Monday
SELECT @WtmTime = AzmZeitMo FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
ELSE IF DATEPART(dw, @Date) = 3 -- Tuesday
SELECT @WtmTime = AzmZeitDi FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
ELSE IF DATEPART(dw, @Date) = 4 -- Wednesday
SELECT @WtmTime = AzmZeitMi FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
ELSE IF DATEPART(dw, @Date) = 5 -- Thursday
SELECT @WtmTime = AzmZeitDo FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
ELSE IF DATEPART(dw, @Date) = 6 -- Friday
SELECT @WtmTime = AzmZeitFr FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
ELSE -- Saturday
SELECT @WtmTime = AzmZeitSa FROM AzmWochen
WHERE ArbeitszeitmodellID = @WorkTimeModelID
AND Folgenummer = @SequenceNo;
END ELSE
BEGIN
DECLARE @NUMWEEKS INT
SELECT @NUMWEEKS = DATEDIFF(week, CONVERT(CHAR(10), '01.01.2000', 104), @Date)
IF DATEPART(dw, @Date) = 1
SET @NUMWEEKS = @NUMWEEKS - 1;
DECLARE @WEEKNUMBER INT
IF @NUMWEEKS % 2 = 0
SET @WEEKNUMBER = 1
ELSE
SET @WEEKNUMBER = 2;
IF DATEPART(dw, @Date) = 1 -- Sunday
SELECT @WtmTime = AzmZeitSo FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
ELSE IF DATEPART(dw, @Date) = 2 -- Monday
SELECT @WtmTime = AzmZeitMo FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
ELSE IF DATEPART(dw, @Date) = 3 -- Tuedsay
SELECT @WtmTime = AzmZeitDi FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
ELSE IF DATEPART(dw, @Date) = 4 -- Wednesday
SELECT @WtmTime = AzmZeitMi FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
ELSE IF DATEPART(dw, @Date) = 5 -- Thursday
SELECT @WtmTime = AzmZeitDo FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
ELSE IF DATEPART(dw, @Date) = 6 -- Friday
SELECT @WtmTime = AzmZeitFr FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
ELSE -- Saturday
SELECT @WtmTime = AzmZeitSa FROM AzmWochen
WHERE Folgenummer = @SequenceNo AND Wochennummer = @WEEKNUMBER
AND ArbeitszeitmodellID = @WorkTimeModelID
END
IF @Date >= '20130901' AND @WtmTime = 'ZA'
SET @WtmTime = 'KD';
RETURN @WtmTime;
END
CREATE FUNCTION [dbo].[IstFeiertag] (
@Datum DATETIME,
@IstEvangelisch BIT)
RETURNS INT
AS
BEGIN
DECLARE @I INT
DECLARE @Y INT
DECLARE @A INT
DECLARE @B INT
SET @I = DATEPART(year, @Datum) / 100 - DATEPART(year, @Datum) / 400 + 4;
SET @Y = @I - DATEPART(year, @Datum) / 300 + 11;
SET @A = (((DATEPART(year, @Datum) % 19) * 19) + @Y) % 30;
SET @B = (((DATEPART(year, @Datum) % 4) * 2 + 4 * DATEPART(year, @Datum) + 6 * @A + @I) % 7) + @A - 9;
DECLARE @OstTag INT
DECLARE @OstMon INT
IF @B < 1
BEGIN
SET @OstTag = 31 + @B
SET @OstMon = 3
END ELSE
BEGIN
IF ((@B = 26) OR ((@A = 28) AND (@B = 25) AND ((11 * (@Y + 1) % 30) < 19)))
BEGIN
SET @B = @B - 7;
END
SET @OstTag = @B
SET @OstMon = 4
END
DECLARE @Ostersonntag DATETIME
SET @Ostersonntag = dbo.CreateDate(DATEPART(year, @Datum), @OstMon, @OstTag)
IF @Datum >= @Ostersonntag
BEGIN
DECLARE @TAGE INT
SET @TAGE = DATEDIFF(day, @Ostersonntag, @Datum)
IF @TAGE = 0 OR @TAGE = 1 OR @TAGE = 39 OR @TAGE = 50 OR @TAGE = 60
BEGIN
RETURN 1
END
END
DECLARE @TEMP INT
SET @TEMP = DATEPART(month, @Datum) * 100 + DATEPART(day, @Datum)
IF @TEMP = 101 OR @TEMP = 106 OR @TEMP = 501 OR @TEMP = 815 OR @TEMP = 1026
OR @TEMP = 1101 OR @TEMP = 1208 OR @TEMP = 1225 OR @TEMP = 1226
BEGIN
RETURN 1
END
RETURN 0
END
GO
CREATE FUNCTION [dbo].[CreateDate] (
@Year int,
@Month int,
@Day int)
RETURNS DATETIME
AS
BEGIN
declare @d datetime;
set @d = dateadd(year,(@Year - 1753),'1/1/1753');
set @d = dateadd(month,@Month - 1,@d);
return dateadd(day,@Day - 1,@d)
END
GO
Run Code Online (Sandbox Code Playgroud)
这些是表定义(德语):
CREATE TABLE [dbo].[Arbeitszeitmodelle]
(
[ArbeitszeitmodellID] uniqueidentifier ROWGUIDCOL NOT NULL
CONSTRAINT [DF_Arbeitszeitmodelle_ArbeitszeitmodellID] DEFAULT (newid())
CONSTRAINT [PK_Arbeitszeitmodelle_ArbeitszeitmodellID] PRIMARY KEY CLUSTERED,
[Name] nvarchar(25) NOT NULL,
[MaxAnzahlMitglieder] tinyint NOT NULL
CONSTRAINT [CK_Arbeitszeitmodelle_MaxAnzahlMitglieder] CHECK (([MaxAnzahlMitglieder] > 0) AND ([MaxAnzahlMitglieder] < 10)),
[AnzahlWochen] tinyint NOT NULL
CONSTRAINT [CK_Arbeitszeitmodelle_AnzahlWochen] CHECK (([AnzahlWochen] > 0) AND ([AnzahlWochen] < 5)),
[ÜbernimmtFeiertage] bit
);
CREATE TABLE [dbo].[AzmWochen]
(
[AzmWochenID] uniqueidentifier ROWGUIDCOL NOT NULL
CONSTRAINT [DF_AzmWochen_AzmWochenID] DEFAULT (newid())
CONSTRAINT [PK_AzmWochen_AzmWochenID] PRIMARY KEY CLUSTERED,
[Folgenummer] tinyint NOT NULL
CONSTRAINT [CK_AzmWochen_Folgenummer] CHECK (([Folgenummer] > 0) AND ([Folgenummer] < 10)),
[Wochennummer] tinyint NOT NULL
CONSTRAINT [CK_AzmWochen_Wochennummer] CHECK (([Wochennummer] > 0) AND ([Wochennummer] < 3)),
[ArbeitszeitmodellID] uniqueidentifier NOT NULL
CONSTRAINT [FK_AzmWochen_ArbeitszeitmodellID] FOREIGN KEY ([ArbeitszeitmodellID]) REFERENCES [dbo].[Arbeitszeitmodelle] ([ArbeitszeitmodellID]) ON UPDATE CASCADE ON DELETE CASCADE,
[AzmZeitMo] varchar(5) NOT NULL,
[AzmZeitDi] varchar(5) NOT NULL,
[AzmZeitMi] varchar(5) NOT NULL,
[AzmZeitDo] varchar(5) NOT NULL,
[AzmZeitFr] varchar(5) NOT NULL,
[AzmZeitSa] varchar(5) NOT NULL,
[AzmZeitSo] varchar(5) NOT NULL
);
ALTER TABLE AzmWochen ADD CONSTRAINT [UQ_AzmWochen_FolgeWochen] UNIQUE ([ArbeitszeitmodellID] ASC, [Folgenummer] ASC, [Wochennummer] ASC);
Run Code Online (Sandbox Code Playgroud)
我尝试了以下提示:
OPTION(USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'))
OPTION(USE HINT('QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_140'))
...但他们并没有阻止错误。
我将两个表、测试数据和函数(GetWtmTime
取决于其他两个标量函数)插入到一个空的测试数据库中,并且能够执行该函数两次。然后我又得到了内存错误。
Pau*_*ite 11
SQL Server 正在尝试内联该函数,但由于复杂性而失败。
这样做时使用如此多的内存是出乎意料的,几乎可以肯定是一个错误。
dbo.IstFeiertag
完整再现需要嵌套函数的定义。
添加WITH INLINE = OFF
到函数定义。解决此问题后,您应该能够删除该选项以获得函数内联的性能优势。
您应该将此问题报告给 Microsoft。如果您有支持协议,请走那条路。或者,在User Voice上发布错误报告,并通过智能查询处理团队发送电子邮件至 smartqp@microsoft.com。
Joe Sack(Microsoft SQL Server 产品团队首席项目经理)评论道:
感谢您的举报。保罗怀特提醒了我,我已向我们的团队报告以进行调查。
此问题的修复程序已作为SQL Server 2019 累积更新 2 的一部分发布。
归档时间: |
|
查看次数: |
958 次 |
最近记录: |