Построение Flame Chart для MSSQL

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

bd3c0b84c4a78a25aead9b3b15fca4b5.png

Опишем по шагам всю процедуру.

Создание трейса

Запустите 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=@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. Позволяет выбрать конкретное выполнение, если их много

Пример:

9309d9f0f8e54358e3ebf54805c1dfe7.png

Первая табличка показывает все найденные выполнения данной функции, диапазон RowNumber, диапазон времен и длительность в миллисекундах

Если нас интересует не самое первое выполнение, то указываем в третьем параметре Start нужного нам. Во втором результате указывается выполнение, выбранное к анализу. Например, для 9 го исполнения указываем значение 10574

Построение диаграммы

Убедившись, что все в порядке, заглянем во вкладку Messages и скопируем результат в текстовый файл, удалив в самом конце ненужное вместе с пустой строкой:

e9a69b1c1b1ea8f70e8534bea2312615.png

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

f0d3ddfc7cbcefd5d1509f5cd05e5d7a.png

© Habrahabr.ru