Setup
For this demo, I'm using the 2013 version of the Stack Overflow database, and SQL Server 2022 CTP2, but it is valid going back through SQL Server 2017 which is as far back as I care to check.
Function One
For this function, SQL Server tracks execution time spent in the function:
CREATE OR ALTER FUNCTION
dbo.ScoreStats
(
@UserId int
)
RETURNS
@out table
(
TotalScore bigint
)
WITH SCHEMABINDING
AS
BEGIN
INSERT
@out
(
TotalScore
)
SELECT
TotalScore =
SUM(x.Score)
FROM
(
SELECT
Score =
SUM(p.Score)
FROM dbo.Posts AS p
WHERE p.OwnerUserId = @UserId
UNION ALL
SELECT
Score =
SUM(c.Score)
FROM dbo.Comments AS c
WHERE c.UserId = @UserId
) AS x;
RETURN;
END;
Here's the query and execution plan:
SELECT
u.DisplayName,
TotalScore =
(
SELECT
ss.TotalScore
FROM dbo.ScoreStats(u.Id) AS ss
)
FROM dbo.Users AS u
WHERE u.Reputation >= 1000000;
You can see that both in the query plan and in the Query Time Stats property, time is tracked accurately.
Function Two
Here's the second function, where that doesn't happen:
CREATE OR ALTER FUNCTION
dbo.VoteStats()
RETURNS
@out table
(
PostId int,
UpVotes int,
DownVotes int,
UpMultipier AS
UpVotes * 2
)
WITH SCHEMABINDING
AS
BEGIN
INSERT
@out
(
PostId,
UpVotes,
DownVotes
)
SELECT
v.PostId,
UpVotes =
SUM
(
CASE v.VoteTypeId
WHEN 2
THEN 1
ELSE 0
END
),
DownVotes =
SUM
(
CASE v.VoteTypeId
WHEN 3
THEN 1
ELSE 0
END
)
FROM dbo.Votes AS v
GROUP BY
v.PostId;
RETURN;
END;
Here's the query and execution plan:
SELECT TOP (100)
p.Id,
vs.UpVotes,
vs.DownVotes
FROM dbo.VoteStats() AS vs
JOIN dbo.Posts AS p
ON vs.PostId = p.Id
WHERE vs.DownVotes > vs.UpMultipier
AND p.CommunityOwnedDate IS NULL
AND p.ClosedDate IS NULL
ORDER BY vs.UpVotes DESC;
In this query, time is not accurately tracked in the graphical execution plan, but is tracked in the Query Time Stats property.
Function Two At MAXDOP 1
Even when forced serial, the time is not accurately tracked:
SELECT TOP (100)
p.Id,
vs.UpVotes,
vs.DownVotes
FROM dbo.VoteStats() AS vs
JOIN dbo.Posts AS p
ON vs.PostId = p.Id
WHERE vs.DownVotes > vs.UpMultipier
AND p.CommunityOwnedDate IS NULL
AND p.ClosedDate IS NULL
ORDER BY vs.UpVotes DESC
OPTION(MAXDOP 1);
El Problemo
Back to the question at hand: Why is time tracked in one query plan accurately, but not in the other?