L'une de mes requêtes s'exécutait en mode d'exécution série après une version et j'ai remarqué que deux nouvelles fonctions étaient utilisées dans une vue référencée dans la requête LINQ to SQL générée à partir de l'application. J'ai donc converti ces fonctions SCALAIRES en fonctions TVF, mais la requête s'exécute toujours en mode série.
Plus tôt, j'ai fait la conversion de Scalar en TVF dans certaines autres requêtes et cela a résolu le problème de l'exécution forcée en série.
Voici la fonction scalaire:
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
Voici la fonction TVF convertie.
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
Y a-t-il un problème avec mon implémentation de la fonction TVF qui empêche la requête de s'exécuter en mode parallèle.
J'utilise la fonction TVF dans la requête comme ci-dessous;
select ReviewDueDate from dbo.FunctionResultTableVairable('a','b','c')
Ma requête réelle qui utilise la vue est assez complexe et si je commente la partie fonction dans la vue et lors de l'exécution, la requête s'exécute en parallèle. C'est donc la fonction qui oblige la requête à s'exécuter en parallèle.
Ma requête réelle est dans le format ci-dessous.
select
dv.column1,
dv.column2,
---------
---------
--------
(select ReviewDueDate from dbo.FunctionResultTableVairable('a','b','c')) AS 'Columnx'
from
DemoView dv
Where
condition1
conditon 2
Toute aide est appréciée.
Réponses:
Oui. Quelque chose comme ci-dessous le ferait.
Il est encore assez lourd et s'il était corrélé, il serait probablement assez inefficace. Comme Aaron le souligne dans les commentaires, vous appelez cela avec des valeurs constantes, alors espérons que le plan de requête reflète cela et ne l'exécute qu'une seule fois.
la source
Forrest a généralement raison, mais les détails les plus fins sont les suivants:
SQL Server ne peut pas paralléliser les modifications apportées aux variables de table, que votre fonction utilise.
Avant l' exécution entrelacée de SQL Server 2017 , les estimations de ligne des fonctions de valeur de table à instructions multiples étaient très faibles.
Un effet secondaire de cela est que les plans ont été très mal évalués sur le bas de gamme, et souvent ne dépassaient pas le seuil de coût pour le parallélisme.
la source
SQL Server ne peut pas paralléliser les TVF multi-instructions, ce qui est le vôtre. Seuls les TVF en ligne peuvent être parallélisés.
la source