の私のクエリの1つは、リリース後にシリアル実行モードで実行されていました。アプリケーションから生成されたLINQ to SQLクエリで参照されるビューで2つの新しい関数が使用されていることに気付きました。したがって、これらのSCALAR関数をTVF関数に変換しましたが、クエリはシリアルモードで実行されています。
以前、他のいくつかのクエリでスカラーからTVFへの変換を実行し、強制的なシリアル実行の問題を解決しました。
これがスカラー関数です:
CREATE FUNCTION [dbo].[FindEventReviewDueDate]
(
@EventNumber VARCHAR(20),
@EventID VARCHAR(25),
@EventIDDate BIT
)
RETURNS DateTime
AS
BEGIN
DECLARE @CurrentEventStatus VARCHAR(20)
DECLARE @EventDateTime DateTime
DECLARE @ReviewDueDate DateTime
SELECT @CurrentEventStatus = (SELECT cis.EventStatus
FROM CurrentEventStatus cis
INNER JOIN Event1 r WITH (NOLOCK) ON (cis.Event1Id = r.Id)
WHERE (r.EventNumber = @EventNumber) AND r.EventID = @EventID)
SELECT @EventDateTime = (SELECT EventDateTime FROM Event1 r
WHERE (r.EventNumber = @EventNumber) AND r.EventID = @EventID)
IF @CurrentEventStatus IN ('0','6') AND EventIDDate = 1
BEGIN
SET @ReviewDueDate = DATEADD(DAY, 30, @EventDateTime)
WHILE @ReviewDueDate < getdate()
SET @ReviewDueDate = DATEADD(DAY, 30, @ReviewDueDate)
DECLARE @EventDateJournalDate DateTime
SELECT @EventDateJournalDate = (SELECT TOP 1 ij.Date
FROM EventPage_EventJournal ij
INNER JOIN EventJournalPages p ON ij.PageId = p.Id
INNER JOIN Journal f ON p.FormId = f.Id
INNER JOIN Event1 r WITH (NOLOCK) ON (f.Event1Id = r.Id)
WHERE (r.EventNumber = @EventNumber AND r.EventID = @EventID) AND ij.ReviewType = 'Supervisor Monthly Review' ORDER BY ij.Date DESC)
IF(DATEADD(DAY, 30, @EventDateTime) < getdate() AND
(@EventDateJournalDate is null OR DATEADD(DAY, 30, @EventDateJournalDate) < getdate()) AND
DATEADD(DAY, 14, @ReviewDueDate) > DATEADD(DAY, 30, getdate()))
SET @ReviewDueDate = DATEADD(DAY, -30, @ReviewDueDate)
ELSE IF((@EventDateJournalDate is not null ) AND (DATEADD(DAY, 30, @EventDateJournalDate) >= @ReviewDueDate))
SET @ReviewDueDate = DATEADD(DAY, 30, @ReviewDueDate)
END
RETURN @ReviewDueDate
END
これは変換されたTVF関数です。
CREATE FUNCTION [dbo].[FindEventReviewDueDate_test]
(
@EventNumber VARCHAR(20),
@EventID VARCHAR(25),
@EventIDDate BIT
)
RETURNS @FunctionResultTableVairable TABLE (
CurrentEventStatus varchar(20),
Event1DateTime DateTime,
ReviewDueDate DateTime
)
AS
BEGIN
DECLARE @CurrentEventStatus VARCHAR(20)
DECLARE @EventDateTime DateTime
DECLARE @ReviewDueDate DateTime
SELECT @CurrentEventStatus = (SELECT cis.EventStatus
FROM CurrentEventStatus cis
INNER JOIN Event1 r WITH (NOLOCK) ON (cis.Event1Id = r.Id)
WHERE (r.EventNumber = @EventNumber) AND r.EventID = @EventID)
SELECT @EventDateTime = (SELECT EventDateTime FROM Event1 r
WHERE (r.EventNumber = @EventNumber) AND r.EventID = @EventID)
IF @CurrentEventStatus IN ('0','6') AND EventIDDate = 1
BEGIN
SET @ReviewDueDate = DATEADD(DAY, 30, @EventDateTime)
WHILE @ReviewDueDate < getdate()
SET @ReviewDueDate = DATEADD(DAY, 30, @ReviewDueDate)
DECLARE @EventDateJournalDate DateTime
SELECT @EventDateJournalDate = (SELECT TOP 1 ij.Date
FROM EventPage_EventJournal ij
INNER JOIN EventJournalPages p ON ij.PageId = p.Id
INNER JOIN Journal f ON p.FormId = f.Id
INNER JOIN Event1 r WITH (NOLOCK) ON (f.Event1Id = r.Id)
WHERE (r.EventNumber = @EventNumber AND r.EventID = @EventID) AND ij.ReviewType = 'Supervisor Monthly Review' ORDER BY ij.Date DESC)
IF(DATEADD(DAY, 30, @EventDateTime) < getdate() AND
(@EventDateJournalDate is null OR DATEADD(DAY, 30, @EventDateJournalDate) < getdate()) AND
DATEADD(DAY, 14, @ReviewDueDate) > DATEADD(DAY, 30, getdate()))
SET @ReviewDueDate = DATEADD(DAY, -30, @ReviewDueDate)
ELSE IF((@EventDateJournalDate is not null ) AND (DATEADD(DAY, 30, @EventDateJournalDate) >= @ReviewDueDate))
SET @ReviewDueDate = DATEADD(DAY, 30, @ReviewDueDate)
insert into @FunctionResultTableVairable
select @CurrentEventStatus,@EventDateTime,@ReviewDueDate
END
return;
END
GO
クエリが並列モードで実行されないようにするTVF関数の実装に問題がありますか?.
以下のように、クエリでTVF関数を使用します。
select ReviewDueDate from dbo.FunctionResultTableVairable('a','b','c')
ビューを使用する実際のクエリは非常に複雑であり、ビューの関数部分をコメントアウトしてを実行すると、クエリは並列で実行されます。したがって、クエリを並列で実行する必要があるのは関数です。
私の実際のクエリは以下の形式です。
select
dv.column1,
dv.column2,
---------
---------
--------
(select ReviewDueDate from dbo.FunctionResultTableVairable('a','b','c')) AS 'Columnx'
from
DemoView dv
Where
condition1
conditon 2
どんな助けでもありがたいです。
スカラー関数をインラインTVFに変換できますか?
はい。以下のようなものがそれを行います。
それはまだかなり高額であり、相関実行を行うとおそらく非常に非効率になります。 Aaronがコメントで指摘しているように、定数値でこれを呼び出していますが、うまくいけば、クエリプランはこれを反映し、一度だけ実行します。
CREATE FUNCTION [dbo].[FindEventReviewDueDateInline] (@EventNumber VARCHAR(20),
@EventID VARCHAR(25),
@EventIDDate BIT)
RETURNS TABLE
AS
RETURN
WITH X
AS (SELECT cis.EventStatus AS CurrentEventStatus,
r.EventDateTime
FROM CurrentEventStatus cis
INNER JOIN Event1 r
ON cis.Event1Id = r.Id
WHERE r.EventNumber = @EventNumber
AND r.EventID = @EventID
AND cis.EventStatus IN ( '0', '6' )
AND @EventIDDate = 1)
SELECT X.CurrentEventStatus,
X.EventDateTime,
CA4.ReviewDueDate
FROM X
--SET @ReviewDueDate = DATEADD(DAY, 30, @EventDateTime)
CROSS APPLY(VALUES(DATEADD(DAY, 30, X.EventDateTime))) CA1(ReviewDueDate)
-- WHILE @ReviewDueDate < getdate()
-- SET @ReviewDueDate = DATEADD(DAY, 30, @ReviewDueDate)
CROSS APPLY(VALUES( IIF(CA1.ReviewDueDate >= GETDATE(), CA1.ReviewDueDate, DATEADD(DAY, 30 * CEILING(( IIF(CAST(GETDATE() AS TIME) > CAST(CA1.ReviewDueDate AS TIME), 1, 0)
+ DATEDIFF(DAY, CA1.ReviewDueDate, GETDATE()) ) / 30.0), CA1.ReviewDueDate)))) CA2(ReviewDueDate)
--SELECT @EventDateJournalDate = ....
CROSS APPLY(SELECT TOP 1 ij.Date
FROM EventPage_EventJournal ij
INNER JOIN EventJournalPages p
ON ij.PageId = p.Id
INNER JOIN Journal f
ON p.FormId = f.Id
INNER JOIN Event1 r WITH (NOLOCK)
ON ( f.Event1Id = r.Id )
WHERE ( r.EventNumber = @EventNumber
AND r.EventID = @EventID )
AND ij.ReviewType = 'Supervisor Monthly Review'
ORDER BY ij.Date DESC) CA3(EventDateJournalDate)
-- IF(DATEADD(DAY, 30, @EventDateTime) < getdate()
CROSS APPLY(VALUES ( CASE
WHEN ( DATEADD(DAY, 30, X.EventDateTime) < GETDATE()
AND ( CA3.EventDateJournalDate IS NULL
OR DATEADD(DAY, 30, CA3.EventDateJournalDate) < GETDATE() )
AND DATEADD(DAY, 14, CA2.ReviewDueDate) > DATEADD(DAY, 30, GETDATE()) )
THEN DATEADD(DAY, -30, CA2.ReviewDueDate)
WHEN( ( CA3.EventDateJournalDate IS NOT NULL )
AND ( DATEADD(DAY, 30, CA3.EventDateJournalDate) >= CA2.ReviewDueDate ) )
THEN DATEADD(DAY, 30, CA2.ReviewDueDate)
ELSE CA2.ReviewDueDate
END )) CA4(ReviewDueDate);
フォレストはほぼ正しいですが、より詳細は次のとおりです。
SQL Serverは、関数が使用するテーブル変数への変更を並列化できません。
SQL Server 2017の Interleaved Execution より前のバージョンでは、マルチステートメントテーブル値関数からの行推定は非常に低かった。
このことの副作用の1つは、ローエンドでのプランのコストが非常に低く、並列処理のコストしきい値を超えないことが多いことです。
SQL Serverは、マルチステートメントTVFを並列化できません。並列化できるのはインラインTVFのみです。