Как отслеживать вызовы функций T-SQL
Я пытаюсь отладить довольно сложный вычислитель формул, написанный в T-SQL UDFs (не спрашивайте), что рекурсивно (но косвенно через промежуточную функцию) называет себя, бла-бла.
и, конечно, у нас есть ошибка.
теперь, используя операторы печати (которые затем можно прочитать из ADO.NET реализуя обработчик для события InfoMessage), я могу имитировать трассировку для хранимых процедур.
делать то же самое для UDF приводит к сообщение времени компиляции:
Invalid use of side-effecting or time-dependent operator in 'PRINT' within a function.
Я получаю сообщение (печать делает некоторые вещи, такие как сброс @@ROWCOUNT
который определенно является no-no в UDFs, но как я могу проследить через вызовы? Я хочу, чтобы эта трассировка была распечатана, чтобы я мог изучить ее, не отвлекаясь на вызовы в отладчике...
EDIT: Я попытался использовать SQL Profiler (это был первый раз для меня), но я не могу понять, что отслеживать: хотя я могу получить трассировка для вывода запросов, отправленных в базу данных, они непрозрачны в том смысле, что я не могу перейти к выражению-UDFs: я могу отслеживать фактическую вызванную хранимую процедуру, но UDFs, вызванные этой процедурой, не перечислены. Я что-то упускаю? Думаю, нет...
редактировать #2: хотя (авто-)принятый ответ отслеживает вызовы функций-очень полезно, спасибо - это не помогает в выяснении, какие параметры были принят к функция. Это, конечно, существенно в отладка рекурсивные функции. Я отправлю сообщение, если найду какое-либо решение...
9 ответов
Почему бы не использовать SQL Profiler с добавлением событий уровня оператора?
редактировать: добавление событий для хранимых процедур:запуск SP: Stmt или завершение SP:Stmt Используйте переменные для отладки, если это необходимо, т. е. set @debug= 'i am here'; UDF, хотя и не технически хранимые процедуры, будут отслеживаться с событиями уровня оператора.
в профилировщике SQL вам нужно: SP:Starting, SP:StmtStarting, SP:Completed, SQL: BatchStarting. Затем вы получаете каждую запись, выход из функций / хранимых процедур.
alter FUNCTION [dbo].[ufn_mjf](@i numeric(10))
RETURNS numeric(20)
AS
BEGIN
declare @datapoint varchar(10)
set @datapoint = 'hello world'
return @i
END
go
drop table foo
go
create table dbo.foo ( foo_id numeric(10))
go
delete from foo
insert into foo ( foo_id ) values ( 1 )
insert into foo ( foo_id ) values ( 2 )
select foo_id, dbo.ufn_mjf(foo_id) from foo
С этим, я получаю:
SQL:BatchStarting alter FUNCTION [dbo].[ufn_mjf](@i numeric(10))
SQL:BatchStarting drop table foo
SQL:BatchStarting create table dbo.foo ( foo_id numeric(10))
SQL:BatchStarting delete from foo
insert into foo ( foo_id ) values ( 1 )
insert into foo ( foo_id ) values ( 2 )
select foo_id, dbo.ufn_mjf(foo_id) from foo
SP:Starting select foo_id, dbo.ufn_mjf(foo_id) from foo
SP:StmtStarting set @datapoint = 'hello world'
SP:StmtStarting return @i
SP:Completed select foo_id, dbo.ufn_mjf(foo_id) from foo
SP:Starting select foo_id, dbo.ufn_mjf(foo_id) from foo
SP:StmtStarting set @datapoint = 'hello world'
SP:StmtStarting return @i
SP:Completed select foo_id, dbo.ufn_mjf(foo_id) from foo
этого достаточно для вас?
этой похоже, что вам нужно, но оно доступно только в версиях team / pro Visual Studio.
используйте SQL Profiler, я рекомендую вам пойти за борт на добавление событий в первый раз, который позволит вам почувствовать, что вам нужно. Без тестирования я бы добавил события для SP:StmtStarted (или завершено или оба), SQL: StmtStarted (снова завершено или оба).
Я поддерживаю предложение SQL Profiler. Потратьте некоторое время, чтобы настроить его так, чтобы только события, которые вас интересуют, регистрировались для сокращения размера вывода. Вы можете вывести трассировку в файл - я часто загружал этот файл обратно в таблицу, чтобы включить анализ. (очень удобно для анализа производительности, хотя, без сомнения, кто-то скажет мне, что 2008 все это построено в somwehere...)
иногда у вас не будет разрешений на запуск SQL Profiler, поскольку он замедляет работу сервера down-попросите DBA предоставить вам разрешение на вашем Dev-сервере. У них не должно быть никаких проблем с этим.
Ну, в прошлом мне приходилось принимать типичные значения, которые были бы в UDF, а затем запускать только часть udf в отдельном окне запроса как прямой SQL, а не udf, используя типичные значения в качестве переменных, заданных с помощью оператора declare и set. Если он запускается из таблицы вместо того, чтобы иметь только одно значение, я бы настроил временную таблицу или переменную таблицы с входными значениями, а затем запустил их через sql в UDF (но снова как прямой SQL не UDF) через курсор. Запустив прямо SQL вы можете иметь инструкции печати в нем, чтобы увидеть, что происходит. Я знаю, это больно, но это работает. (Я прохожу через процесс simliar при создании / отладке триггеров, установке #inserted и #deleted с моими тестовыми значениями, А затем тестирую код, который я намерен поместить в триггер, затем глобальный замените # ничем и добавьте код create trigger.)
возможно, вы можете использовать SQL CLR для выполнения трассировки, как описано здесь Как войти в T-SQL
можете ли вы взять свою функцию и сделать ее вторую копию, но возвращая тип таблицы с дополнительным столбцом для отладочной информации.
например, функция mySum ниже
CREATE FUNCTION mySum
(
@param1 int,
@param2 int
)
RETURNS INT AS
BEGIN
DECLARE @mySum int
SET @mySum = @param1
SET @mySum = @mySum + @param2
RETURN @mySum
END
GO
SELECT dbo.mySum(1, 2)
станет
CREATE FUNCTION mySumDebug
(
@param1 int,
@param2 int
)
RETURNS @myTable TABLE
(
[mySum] int,
[debug] nvarchar(max)
)
AS
BEGIN
DECLARE @debug nvarchar(max)
SET @debug = 'Declare @mySum variable. '
DECLARE @mySum int
SET @debug = @debug + 'Set @mySum = @param1(' + CONVERT(nvarchar(50), @param1) + ') '
SET @mySum = @param1
SET @debug = @debug + 'Add @param2(' + CONVERT(nvarchar(50), @param2) + ') to @mySum(' + CONVERT(nvarchar(50), @mySum) + ') '
SET @mySum = @mySum + @param2
SET @debug = @debug + 'Return @mySum variable. '
INSERT @myTable (mySum, debug) VALUES (@mySum, @debug)
RETURN
END
GO
SELECT mySum, debug FROM dbo.mySumDebug(1, 2)
не идеальное решение, но полезно просто вернуть текст, чтобы помочь отследить ошибку.
Я использую SQL SPY, который делает то, что вы ищете, и многое другое.
SQL SPY'S Incoming SQL Sniffer показывает входящий SQL-код каждого соединения (включая отслеживание инструкций DDL и DML)
эта функция предназначена для MS SQL Server 2005\2008, но будет работать с MS SQL Server 2000 в ограниченной области. Он имеет возможность записывать и сообщать о входящих SQL. Как использовать функции: см
раскрытие информации: я являюсь частью команды SQL SPY.