Подтвердить что ты не робот

Как отслеживать вызовы функций T-SQL

Я пытаюсь отлаживать довольно сложный оценщик формулы, написанный в UDF T-SQL (не спрашивайте), что рекурсивно (но косвенно через промежуточную функцию) вызывает себя, blah, blah.

И, конечно, у нас есть ошибка.

Теперь, используя инструкции PRINT (которые затем могут быть прочитаны из ADO.NET путем реализации обработчика события InfoMessage), я могу имитировать трассировку для хранимых процедур.

Выполнение этого же для UDF приводит к сообщению времени компиляции:

Invalid use of side-effecting or time-dependent operator in 'PRINT' within a function.

Я получаю сообщение (PRINT делает некоторые вещи, такие как сброс @@ROWCOUNT, который определенно не имеет значения в UDF, но как я могу отслеживать вызовы? Я хочу, чтобы этот трассировка была распечатана, поэтому я могу ее изучить не отвлекаясь, перейдя через вызовы в отладчике...

РЕДАКТИРОВАТЬ: Я попытался использовать SQL Profiler (это был первый раз для меня), но я не могу понять, что отслеживать: хотя я могу получить трассировку выводит запросы, отправленные в базу данных, они непрозрачны в том смысле, что я не могу перейти к вызываемым выражениям UDF: я могу отслеживать вызвавшуюся хранимую процедуру, но UDF, вызываемые этой процедурой, не указаны. Я что-то упускаю? Думаю, не...

РЕДАКТИРОВАТЬ № 2:. Несмотря на то, что принятый (автоматический) ответ проверяет вызовы функций - очень полезно, спасибо - это не помогает определить, какие параметры были переданы функции. Это, конечно, важно в рекурсивных функциях отладки. Я отправлю сообщение, если найду какое-нибудь решение...

4b9b3361

Ответ 1

Почему бы не использовать SQL Profiler с добавлением событий уровня инструкций?

Изменить. Добавить события для хранимых процедур: SP: запуск Stm или SP: Stmt Completed Используйте переменные для отладки при необходимости, т.е. Установите @debug = 'i am here'; UDF, а не технически хранимые процедуры, будут отслеживаться с событиями уровня инструкций.

Ответ 2

В профилировщике 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

достаточно для вас?

Ответ 4

Используйте SQL Profiler, я рекомендую вам переходить на добавление событий в первый раз, что позволит вам почувствовать, что вам нужно. Без тестирования я бы добавил события для SP: StmtStarted (или Completed или оба), SQL: StmtStarted (снова завершено или оба).

Ответ 5

Во-вторых, предложение SQL Profiler. Потратьте некоторое время, чтобы настроить его, чтобы только события, которые вас интересуют, регистрируются, чтобы сократить выходной размер. Вы можете вывести трассировку в файл - я часто загружал этот файл обратно в таблицу, чтобы включить анализ. (чрезвычайно удобный для анализа производительности, хотя, несомненно, кто-то скажет мне, что в 2008 году все это было построено в некотором роде...)

Иногда у вас не будет разрешений на запуск SQL Profiler, так как он замедляет работу сервера - попросите своего администратора базы данных предоставить вам разрешение на ваш сервер Dev. У них не должно быть проблем с этим.

Ответ 6

В прошлом мне приходилось принимать типичные значения, которые были бы в UDF, а затем запускать только часть udf в отдельном окне запроса, поскольку прямой SQL не является udf, используя типичные значения как переменные, заданные с объявлением, и set statement. Если он запускается из таблицы вместо того, чтобы иметь только одно значение, я бы установил временную таблицу или таблицу с входными значениями, а затем запустил их через sql в UDF (но опять же, как прямой SQL, а не UDF) через курсор. Запустив прямой SQL, вы можете иметь в нем инструкции печати, чтобы увидеть, что происходит. Я знаю, что это боль, но она работает. (Я запускаю процесс simliar при создании/отладке триггеров, устанавливаю #incerted и #deleted с моими тестовыми значениями, а затем тестирую код, который я намерен помещать в триггер, затем глобально заменяю # ничем и добавляем создающий триггер-код. )

Ответ 7

Возможно, вы можете использовать SQL CLR для выполнения трассировки, как описано здесь Как войти в T-SQL

Ответ 8

Можете ли вы взять свою функцию и сделать вторую ее копию, но верните тип таблицы с дополнительным столбцом для вашей информации об отладке.

Например, функция 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)

Не идеальное решение, но полезно просто вернуть некоторый текст, чтобы помочь отследить ошибку.

Ответ 9

Я использую SQL SPY, который делает то, что вы ищете, и многое другое.

SQL SPY

Документация по SQL SPY

SQL SPY Входящий SQL Sniffer показывает входящий SQL-код каждого соединения (включает отслеживание операторов DDL и DML)

Эта функция предназначена для MS SQL Server 2005\2008, но будет работать с MS SQL Server 2000 в ограниченной области. Он имеет возможность записывать и сообщать о входящем SQL. Как использовать функции: См.

Раскрытие информации: Я являюсь частью команды SQL SPY.