SQL Server 2012データベース(サイズが8GB)を、同じメモリとCPU構成で新しくセットアップされたSQL Server 2019仮想マシンに移動し、互換性レベルをSQL Server 2019に変更しました。
アプリケーション内のすべてが正常に機能しますが、2つのパラメーターを持つ1つの大きなSQLクエリで構成される1つのストアドプロシージャ(および特別なオプションはありません)を除きます。これがSP実行されると、SQL Serverプロセスのメモリが指定された最大レベルまで上がり、エラーが返されます。
「このクエリを実行するにはメモリが不足しています」
SSMSの別のクエリウィンドウで(ストアドプロシージャ内の)SQLクエリを実行すると、すぐに実行され、予想される300行が返されます。また、DBの互換性レベルを「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
_
以下は、テーブル定義(ドイツ語)です。
_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);
_
私はヒントを試しました:
OPTION(USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'))
OPTION(USE HINT('QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_140'))
...しかし、エラーを防ぐことはできませんでした。
2つのテーブル、テストデータ、および関数(GetWtmTime
は他の2つのスカラー関数に依存)を空のテストデータベースに挿入し、関数を2回実行することができました。その後、再びメモリエラーが発生しました。
SQL Serverは 関数のインライン化 を試みていますが、複雑なため失敗しました。
実行中に大量のメモリを使用することは予期せぬことであり、ほぼ間違いなくバグです。
ネストされた関数の定義dbo.IstFeiertag
完全な再現には必要です。
追加 WITH INLINE = OFF
を関数定義に追加します。この問題が解決されたら、そのオプションを削除して、関数のインライン展開によるパフォーマンス上のメリットを享受できるはずです。
report この問題をマイクロソフトに報告する必要があります。サポート契約がある場合は、そのルートに進んでください。または、バグレポートを ser Voice に投稿し、Intelligentqp @ Microsoft.comのIntelligent Query Processingチームにメールを送信してください。
Joe Sack (プリンシパルプログラムマネージャー、Microsoft SQL Server製品チーム)はコメントしました:
ご報告ありがとうございます。ポールホワイトは私にヘッドアップを与え、私は調査のために私たちのチームに報告しました。
この問題の修正 は SQL Server 2019の累積的な更新2 の一部としてリリースされました。