Я проводил трассировку и нашел кое-что, чего не понимаю. У меня есть процедура с простым оператором выбора, который возвращает первое ненулевое значение из последовательности вызовов функций.
Я бы ожидал, что каждая функция будет вызываться только один раз. Поэтому при профилировании с помощью событий SP: STMTCOMPLETED я ожидал увидеть только один набор записей с операторами из этого одного вызова.
Однако то, что я вижу, - это набор записей несколько раз, что говорит о том, что функция вызывается несколько раз.
Действительно ли функция вызывается дважды? И почему?
Вот сценарий для создания функции и хранимой процедуры:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[FOO] (@v INT)
RETURNS bit AS
BEGIN
RETURN 0
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[POO]
@v int,
@p varchar(100)
AS
SELECT
@p as p,
CASE @p
WHEN 'x' THEN COALESCE(dbo.FOO(@v), 0)
ELSE 1
END as poo
GO
Вот вызов процедуры
exec dbo.POO @v = 13911, @p = 'x'
Вот выходные данные Profiler, показывающие две строки для функции FOO и одна строка для процедуры POO:
![enter image description here](https://i.stack.imgur.com/cRtx5.png)
Если я заменю вызов COALESCE таким оператором CASE:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[POO]
@v int,
@p varchar(100)
AS
SELECT
@p as p,
CASE @p
WHEN 'x' THEN CASE WHEN dbo.FOO(@v) = 1 THEN 1 ELSE 0 END
ELSE 1
END as poo
GO
Я получаю только одну строку для FOO в профилировщике:
![enter image description here](https://i.stack.imgur.com/is2YU.png)
Вот сценарий профилирования, созданный SQL Profiler (фильтрация по имени базы данных = dbTest):
/****************************************************/
/* Created by: SQL Server 2017 Profiler */
/* Date: 05/08/2020 12:06:04 AM */
/****************************************************/
-- Create a Queue
declare @rc int
declare @TraceID int
declare @maxfilesize bigint
set @maxfilesize = 5
-- Please replace the text InsertFileNameHere, with an appropriate
-- filename prefixed by a path, e.g., c:\MyFolder\MyTrace. The .trc extension
-- will be appended to the filename automatically. If you are writing from
-- remote server to local drive, please use UNC path and make sure server has
-- write access to your network share
exec @rc = sp_trace_create @TraceID output, 0, N'InsertFileNameHere', @maxfilesize, NULL
if (@rc != 0) goto error
-- Client side File and Table cannot be scripted
-- Set the events
declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 45, 1, @on
exec sp_trace_setevent @TraceID, 45, 9, @on
exec sp_trace_setevent @TraceID, 45, 3, @on
exec sp_trace_setevent @TraceID, 45, 4, @on
exec sp_trace_setevent @TraceID, 45, 5, @on
exec sp_trace_setevent @TraceID, 45, 6, @on
exec sp_trace_setevent @TraceID, 45, 7, @on
exec sp_trace_setevent @TraceID, 45, 8, @on
exec sp_trace_setevent @TraceID, 45, 10, @on
exec sp_trace_setevent @TraceID, 45, 11, @on
exec sp_trace_setevent @TraceID, 45, 12, @on
exec sp_trace_setevent @TraceID, 45, 13, @on
exec sp_trace_setevent @TraceID, 45, 14, @on
exec sp_trace_setevent @TraceID, 45, 15, @on
exec sp_trace_setevent @TraceID, 45, 16, @on
exec sp_trace_setevent @TraceID, 45, 17, @on
exec sp_trace_setevent @TraceID, 45, 18, @on
exec sp_trace_setevent @TraceID, 45, 22, @on
exec sp_trace_setevent @TraceID, 45, 25, @on
exec sp_trace_setevent @TraceID, 45, 26, @on
exec sp_trace_setevent @TraceID, 45, 28, @on
exec sp_trace_setevent @TraceID, 45, 29, @on
exec sp_trace_setevent @TraceID, 45, 34, @on
exec sp_trace_setevent @TraceID, 45, 35, @on
exec sp_trace_setevent @TraceID, 45, 41, @on
exec sp_trace_setevent @TraceID, 45, 48, @on
exec sp_trace_setevent @TraceID, 45, 49, @on
exec sp_trace_setevent @TraceID, 45, 50, @on
exec sp_trace_setevent @TraceID, 45, 51, @on
exec sp_trace_setevent @TraceID, 45, 55, @on
exec sp_trace_setevent @TraceID, 45, 60, @on
exec sp_trace_setevent @TraceID, 45, 61, @on
exec sp_trace_setevent @TraceID, 45, 62, @on
exec sp_trace_setevent @TraceID, 45, 64, @on
exec sp_trace_setevent @TraceID, 45, 66, @on
-- Set the Filters
declare @intfilter int
declare @bigintfilter bigint
exec sp_trace_setfilter @TraceID, 35, 0, 6, N'dbTest'
-- Set the trace status to start
exec sp_trace_setstatus @TraceID, 1
-- display trace id for future references
select TraceID=@TraceID
goto finish
error:
select ErrorCode=@rc
finish:
go