2008-12-09 8 views
20

Estoy tratando de depurar un evaluador de fórmulas bastante complicado escrito en T-SQL UDF (no pregunte) que recursivamente (pero indirectamente a través de una función intermedia) se llama a sí mismo, bla , bla.Cómo rastrear llamadas de función T-SQL

Y, por supuesto, tenemos un error.

Ahora, usando instrucciones PRINT (que luego se pueden leer en ADO.NET mediante la implementación de un controlador para el evento InfoMessage), puedo simular un seguimiento para los procedimientos almacenados.

Hacer lo mismo para los resultados de UDF en un mensaje de tiempo de compilación:

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

me sale el mensaje (IMPRIMIR hace algunas cosas como el restablecimiento @@ROWCOUNT la que definitivamente es un no-no en el UDF, pero ¿cómo puedo dejar rastro ? a través de las llamadas que desea tener esta traza imprime, para que pueda estudiarlo sin distraerse dando un paso a través de las llamadas en el depurador ...

EDIT: me han tratado de utilizar el Analizador de SQL (esto fue una primera vez para mí), pero no puedo averiguar qué rastrear: Alt Aunque puedo obtener el seguimiento para generar las consultas enviadas a la base de datos, son opacas en el sentido de que no puedo acceder a las UDF de Expresión llamadas: puedo rastrear el procedimiento almacenado invocado, pero las UDF llamadas por este el procedimiento no está en la lista. ¿Me estoy perdiendo de algo? Creo que no ...

editar # 2: Acabase la (auto) respuesta aceptada hace rastrear las llamadas de función - muy útil, gracias - no ayuda en saber cuáles eran los parámetros pasó a la función. Esto, por supuesto, es esencial en depurando funciones recursivas. Voy a publicar si encuentro alguna solución ...

+0

Sí, consulte la respuesta de Matthieu a continuación, que explica qué eventos necesita agregar en la configuración de su Analizador. De forma predeterminada, solo captura unos pocos eventos y no son los que necesita para su solución de problemas. –

Respuesta

26

¿Por qué no utilizar SQL Profiler con eventos de nivel de declaración agregados?

Editar: Añadir eventos para procedimientos almacenados: SP: a partir de Stmt o SP: sentencia completadas utilizar variables para depurar si es necesario, es decir, conjunto de depuración @ = 'Estoy aquí'; Los procedimientos UDF, aunque no se almacenan técnicamente, serán rastreados con los eventos de nivel de declaración.

+0

Claro, pero no se trata de procedimientos almacenados que me interesan, pero UDF. Estas son una bestia completamente diferente en T-SQL y tienen restricciones muy duras ... –

+3

SP: StmtStarting también maneja las funciones. Para un ejemplo, vea mi respuesta más abajo. –

0

En segundo lugar la sugerencia de SQL Profiler. Tómese su tiempo para configurarlo de modo que solo los eventos que le interesan se registren para reducir el tamaño de la salida. Puede generar la traza en un archivo: con frecuencia he cargado ese archivo nuevamente en una tabla para permitir el análisis. (muy útil para el análisis de rendimiento, aunque sin duda alguien me dirá que 2008 tiene todo esto incorporado en algún lugar ...)

A veces no tendrá permisos para ejecutar el Analizador de SQL ya que ralentiza el servidor - pregunte su DBA para otorgarle permiso en su servidor Dev. No deberían tener ningún problema con eso.

+0

He intentado esto, realmente no funciona: aunque el seguimiento muestra el procedimiento almacenado original que se llamó, las UDF (expresiones) reales no están enumeradas, por lo que solo estoy mirando una caja negra. –

+0

Hmm, no tengo SQL Profiler en frente mío (la función actual está basada en Oracle).Tal vez alguien que tiene puede encontrar los eventos correctos para obtener la información UDF (o decirle ua que no es posible). – kpollock

+0

Procedimiento almacenado: SP: StmtStarting o SP: StmtCompleted También puede agregar variables locales y hacer Set @ debug = 'estoy aquí' que se mostrará en el generador de perfiles – SqlACID

1

Use el Analizador de SQL, le recomiendo que vaya por la borda para agregar eventos la primera vez que le permita obtener una idea de lo que necesita. Sin pruebas, agregaría los eventos para SP: StmtStarted (o Completed o ambos), SQL: StmtStarted (otra vez Completed o Both).

0

Bueno, en el pasado tuve que tomar valores típicos que estarían en el UDF y luego ejecutar solo la parte udf en una ventana de consulta separada como SQL directo no un udf usando los valores típicos como variables establecidas con un declare y una declaración establecida.Si se ejecuta desde una tabla en lugar de tener solo un valor, configuraría una tabla temporal o variable de tabla con los valores de entrada y luego los ejecutaría a través del sql en el UDF (pero de nuevo como SQL directo no como UDF) a través de un cursor. Al ejecutar SQL directamente, puede tener instrucciones de impresión para ver lo que está sucediendo. Sé que esto es un dolor, pero funciona. (Realizo un proceso similar al crear/depurar desencadenantes, setup #inserted y #deleted con mis valores de prueba y luego pruebo el código que pretendo poner en el desencadenador, luego reemplazo global el # con nada y agrego el código de activación de creación.)

0

Tal vez usted puede utilizar SQL CLR para hacer el rastreo como se describe aquí How to log in T-SQL

4

This se parece a lo que necesita, pero sólo está disponible en las versiones del equipo/pro de Visual Studio.

0

Puede tomar su función, y hacer una segunda copia, pero devolver un tipo de tabla con una columna adicional para su información de depuración.

Por ejemplo, la función mySum continuación

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) 

se convertiría en

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) 

No es una solución ideal, pero útil sólo para regresar un poco de texto para ayudar a localizar a un error.

12

En el generador de perfiles SQL, necesita: SP: Inicio, SP: StmtStarting, SP: Completado, SQL: BatchStarting. Luego, obtiene todas las entradas, salga de las funciones/procedimientos almacenados.

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 

con esto, me sale:

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 

es suficiente para ti?

0

Uso SQL SPY, que hace lo que está buscando y más.

SQL SPY

SQL SPY Feature Documentation

de SQL SPY entrante SQL Sniffer muestra el código SQL de entrada de cada conexión (Incluye DDL y DML seguimiento declaración)

Esta característica está diseñada para MS SQL Server 2005 \ 2008 , pero funcionará con MS SQL Server 2000 en un alcance limitado. Tiene la capacidad de registrar e informar sobre SQL entrante. Cómo usar las funciones: Consulte

Divulgación: soy parte del equipo de SQL SPY.

+0

El sitio está muerto, tal vez se convirtió en: https: // sqlspy. codeplex.com/ - No creo que esto responda la pregunta sin embargo. –

Cuestiones relacionadas