Sql-Server
將標量函式轉換為 TVF 函式以進行並行執行 - 仍在串列模式下執行
我的一個查詢在發布後以串列執行模式執行,我注意到在從應用程序生成的 LINQ to SQL 查詢中引用的視圖中使用了兩個新函式。所以我將這些 SCALAR 函式轉換為 TVF 函式,但查詢仍然以串列模式執行。
早些時候,我在其他一些查詢中進行了 Scalar 到 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);