Comment tracer les appels de fonction T-SQL

j'essaie de déboguer un évaluateur de formule plutôt compliqué écrit en T-SQL UDFs (don't ask) que récursivement (mais indirectement à travers une fonction intermédiaire) se nomme, blah, blah.

Et, bien sûr, nous avons un bug.

maintenant, en utilisant des instructions D'impression (qui peuvent alors être lues à partir de ADO.NET en implémentant un handler pour L'événement InfoMessage), je peux simuler une trace pour les procédures stockées.

faire la même chose pour UDF se traduit par un message de compilation:

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

je reçois le message (imprimer fait quelques trucs comme réinitialiser @@ROWCOUNT qui est définitivement un non-non dans UDFs, mais comment puis-je tracer à travers les appels? Je veux que cette trace soit imprimée, pour que je puisse l'étudier sans me laisser distraire par les appels du débogueur...

EDIT: j'ai essayé D'utiliser le profileur SQL (c'était un une première fois pour moi), mais je ne sais pas pour quoi tracer: bien que je puisse obtenir la trace des requêtes envoyées à la base de données, elles sont opaques dans le sens où je ne peux pas aller jusqu'à L'Expression-UDFs appelée: je peux tracer la procédure stockée réelle invoquée, mais les UDFs appelées par cette procédure ne sont pas listées. Ai-je raté quelque chose? Je ne pense pas...

EDIT #2: bien que les (auto-)a accepté de répondre à n'trace les appels de fonction - très utile, Merci - il n'aide pas à trouver quels paramètres étaient passé à la fonction. Ceci, bien sûr, est essentiel dans débogage fonctions récursives. Je vais poster si je trouve un solution à tout...

21
demandé sur Daren Thomas 2008-12-09 15:45:16

9 réponses

pourquoi ne pas utiliser SQL Profiler avec les événements statement level ajoutés?

Edit : ajouter des événements pour les procédures stockées: SP: stmt Starting ou SP:Stmt Completed Utilisez des variables pour déboguer si nécessaire, c'est-à-dire set @debug='je suis ici'; les procédures UDF, bien qu'elles ne soient pas techniquement stockées, seront tracées avec les événements au niveau de la déclaration.

27
répondu SqlACID 2009-02-17 17:45:21

dans le profileur SQL, vous avez besoin de:SP:Starting, SP:StmtStarting, SP:Completed, SQL: BatchStarting. Ensuite, vous obtenez chaque entrée, sortie des fonctions / procédures stockées.

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

avec ceci, je reçois:

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

ça vous suffit?

12
répondu Matthew Farwell 2009-02-17 14:48:18

ce ressemble à ce dont vous avez besoin, mais il est seulement disponible dans les versions team/pro de Visual Studio.

4
répondu Rich Andrews 2009-02-16 11:21:36

utilisez SQL Profiler, je vous recommande d'aller trop loin sur l'ajout d'événements la première fois qui vous permettra d'avoir une idée de ce dont vous avez besoin. Sans tester, j'ajouterais les évènements pour SP:StmtStarted (ou Completed ou les deux), SQL: StmtStarted (à nouveau Completed ou les deux).

1
répondu JoshBerke 2008-12-09 14:02:06

j'appuie la suggestion du profileur SQL. Prenez le temps de le configurer de sorte que seuls les événements qui vous intéressent sont connecté pour couper la taille de sortie. Vous pouvez afficher la trace d'un fichier - j'ai souvent chargé ce fichier de nouveau dans une table pour permettre l'analyse. (extrêmement pratique pour l'analyse de performance, bien que nul doute que quelqu'un me dira que 2008 a tout cela construit dans Somwhere...)

parfois vous n'aurez pas les permissions D'exécuter le profileur SQL car il ralentit le serveur est en panne - demandez à votre DBA de vous accorder la permission sur votre serveur Dev. Ils ne devraient pas avoir de problème avec ça.

0
répondu kpollock 2008-12-09 12:56:51

Eh bien dans le passé j'ai dû prendre des valeurs typiques qui seraient dans L'UDF et puis exécuter juste la partie udf dans une fenêtre de requête séparée comme SQL droit pas un udf en utilisant les valeurs typiques comme variables définies avec un declare et une instruction set. Si elle est exécutée à partir d'une table au lieu d'avoir une seule valeur, je mettrais en place une table temp table ou une variable table avec les valeurs d'entrée et les lancerais ensuite à travers le sql dans L'UDF (mais encore une fois en tant que SQL droit pas un UDF) à travers un curseur. En exécutant vous pourriez avoir des instructions d'impression pour voir ce qui se passe. Je sais que c'est une douleur, mais il fonctionne. (Je passe par un processus simliar lors de la création/débogage des triggers, setup #insered et #deleted avec mes valeurs de test et ensuite tester le code que j'ai l'intention de mettre dans la trigger, puis global remplacer le # par rien et ajouter le code de Trigger create.)

0
répondu HLGEM 2008-12-10 16:50:15

peut-être Pouvez-vous utiliser SQL CLR pour faire le traçage comme décrit ici comment se connecter T-SQL

0
répondu Jonas Engman 2017-05-23 12:26:03

pouvez-vous prendre votre fonction, et en faire une deuxième copie, mais en retournant un type de table avec une colonne supplémentaire pour vos informations de débogage.

par exemple, la fonction mySum ci-dessous

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 transformerait 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)

ce n'est pas une solution idéale, mais il est utile de simplement renvoyer du texte pour aider à dépister un bogue.

0
répondu Robin Day 2009-02-16 15:31:54

J'utilise SQL SPY qui fait ce que vous cherchez et plus.

SQL SPY

SQL ESPION de la Documentation sur la Fonctionnalité

SQL SPY's Incoming SQL Sniffer affiche le code SQL entrant de chaque connexion (y compris le suivi des déclarations DDL et DML)

cette fonctionnalité est conçu pour MS SQL Server 2005 \ 2008, mais fonctionnera avec MS SQL Server 2000 en Limité portée. Il a la capacité d'enregistrer et de signaler sur SQL entrant. Comment utiliser les fonctionnalités: Voir

Divulgation: je suis partie de la SQL ESPION de l'équipe.

0
répondu IEnumerator 2009-02-19 04:14:49