Если в вашем коде TSQL много вложенных вызовов stored procedures, вы можете наглядно построить стек вызовов с помощью "flame chart" - стандартным представлением для профилирования вызовов.

Опишем по шагам всю процедуру.
Создание трейса
Запустите SQL profiler и выберете события:

SP:Starting
SP:Completed
Выберите следующие колонки:
ObjectName
NestLevel
StartTime
EndTime
Spid
В фильтрах укажите условие по Spid на равенство - это важно. Анализируется только один поток выполнения. Записав достаточно событий, сохраните трейс в базу данных. В базе данных создайте следующую процедуру:
Скрытый текст
create procedure flame
@trname sysname, @spname sysname, @start int=0
as
-- Trace must contain Sp:Start, Sp:Completed, StartTime, EndTime, Nestlevel, ObjectName
-- 1 SPID should be recorded
set nocount on
declare @r int, @b int, @e int, @t datetime, @class int, @lev int, @obj varchar(255), @prevt datetime,
@stack varchar(max)='', @prevstack varchar(max)='', @sql varchar(1000)
create table #trace (RowNumber int, EventClass int, StartTime datetime, EndTime datetime, NestLevel int, ObjectName nvarchar(255))
set @sql = 'insert into #trace select RowNumber,EventClass,StartTime,EndTime,Nestlevel,ObjectName from '+@trname+' where EventClass in (42,43)'
exec (@sql)
select (select max(RowNumber) from #trace I where I.EventClass=42 and I.ObjectName=@spname and I.Nestlevel=1 and I.RowNumber<O.RowNumber) as [Start],
O.RowNumber as [End], StartTime, EndTime, datediff(ms, StartTime, endTime) as DurationMs
from #trace O where EventClass=43 and ObjectName=@spname and Nestlevel=1
order by 1
select @b=min(RowNumber) from #trace where EventClass=42 and ObjectName=@spname and NestLevel=1 and RowNumber>=@start
if @b is null begin print 'procedure: start not found' return end
select @e=min(RowNumber) from #trace where EventClass=43 and ObjectName=@spname and RowNumber>@b and Nestlevel=1
if @e is null begin print 'procedure: end not found' return end
select 'Selected', @b as [Start], @e as [End]
DECLARE my_cur CURSOR FOR SELECT RowNumber,EventClass,isnull(EndTime,StartTime),NestLevel,ObjectName
from #trace where RowNumber>=@b and RowNumber<=@e order by RowNumber
OPEN my_cur
FETCH NEXT FROM my_cur INTO @r, @class, @t, @lev, @obj
WHILE @@FETCH_STATUS = 0
BEGIN
if @class=42 set @stack = @stack + ';' + @obj
else set @stack=reverse(substring(reverse(@stack),charindex(';', reverse(@stack))+1,100000))
if @prevt is not null print substring(@prevstack,2,100000)+' '+convert(varchar,datediff(ms,@prevt,@t))
set @prevt=@t
set @prevstack=@stack
FETCH NEXT FROM my_cur INTO @r, @class, @t, @lev, @obj
END
CLOSE my_cur
DEALLOCATE my_cur
GO
Генерация данных
Запустите процедуру flame указав параметры:
имя таблицы с трейсом
имя процедуры для построения диаграммы. Процедура должны быть на самом верхнем уровне вызова (NestLevel=1). Имя указывается без скобок и схемы, то есть вместо [dbo].[myProc] указываем myProc
третий параметр опционален, по умолчанию 0. Позволяет выбрать конкретное выполнение, если их много
Пример:

Первая табличка показывает все найденные выполнения данной функции, диапазон RowNumber, диапазон времен и длительность в миллисекундах
Если нас интересует не самое первое выполнение, то указываем в третьем параметре Start нужного нам. Во втором результате указывается выполнение, выбранное к анализу. Например, для 9го исполнения указываем значение 10574
Построение диаграммы
Убедившись, что все в порядке, заглянем во вкладку Messages и скопируем результат в текстовый файл, удалив в самом конце ненужное вместе с пустой строкой:

Далее идем на сайт https://www.speedscope.app и загружаем созданный нами файл. Готово.
