22

T-SQL UDF で記述されたかなり複雑な式エバリュエーターをデバッグしようとしています (質問しないでください) 。

そしてもちろん、バグがあります。

ここで、PRINT ステートメント (InfoMessage イベントのハンドラーを実装することで ADO.NET から読み取ることができます) を使用して、ストアド プロシージャのトレースをシミュレートできます。

UDF に対して同じことを行うと、コンパイル時に次のメッセージが表示されます。

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

メッセージが表示されます (PRINT はリセットのようなものを行います@@ROWCOUNTが、これは明らかに UDF では禁止されていますが、呼び出しをトレースするにはどうすればよいでしょうか?デバッガーでの呼び出し...

編集: SQL プロファイラーを使用しようとしましたが (これは私にとって初めてのことでした)、何をトレースするのかわかりません: データベースに送信されたクエリを出力するトレースを取得できますが、それらは呼び出された式-UDF にドリルダウンできないという意味で不透明です。呼び出された実際のストアド プロシージャを追跡できますが、このプロシージャによって呼び出された UDF は一覧表示されません。何か不足していますか?私はそうではないと思います...

編集#2:(自動)受け入れられた回答は関数呼び出しをトレースしますが、非常に役立ちます-ありがとうございます-関数に渡されたパラメーターを見つけるのには役立ちません。もちろん、これは再帰関数のデバッグに不可欠です。解決策が見つかったら投稿します...

4

9 に答える 9

28

ステートメント レベルのイベントが追加された SQL プロファイラーを使用してみませんか?

編集: ストアド プロシージャのイベントを追加: SP:Stmt Starting または SP:Stmt Completed 必要に応じて変数を使用してデバッグします。UDF は、技術的にはストアド プロシージャではありませんが、ステートメント レベルのイベントでトレースされます。

于 2008-12-09T12:50:56.137 に答える
12

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

それで十分ですか?

于 2009-02-17T14:48:18.760 に答える
1

SQL プロファイラーを使用してください。初めてイベントを追加することをお勧めします。これにより、必要なものを感じ取ることができます。テストを行わずに、SP:StmtStarted (または Completed または両方)、SQL:StmtStarted (再び Completed または両方) のイベントを追加します。

于 2008-12-09T14:02:06.993 に答える
0

私はあなたが探していることなどを行うSQLSPYを使用しています。

SQL SPY

SQLSPY機能のドキュメント

SQLSPYの着信SQLスニファは、各接続の着信SQLコードを表示します(DDLおよびDMLステートメントの追跡を含む)

この機能はMSSQLServer 2005 \ 2008用に設計されていますが、限られた範囲でMS SQLServer2000で動作します。着信SQLを記録およびレポートする機能があります。機能の使用方法:を参照してください

開示:私はSQLSPYチームの一員です。

于 2009-02-19T04:14:49.873 に答える
0

関数を取得して、その 2 番目のコピーを作成できますが、デバッグ情報用に追加の列を含むテーブル型を返します。

たとえば、以下の 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)

理想的な解決策ではありませんが、バグを追跡するのに役立つテキストを返すだけで役立ちます。

于 2009-02-16T15:31:54.793 に答える
0

以前は、UDF に含まれる典型的な値を取得し、別のクエリ ウィンドウで udf 部分だけを実行しなければなりませんでした。典型的な値を変数として使用して、UDF ではなく、declare および set ステートメントで設定します。値を 1 つだけ持つのではなくテーブルから実行する場合は、入力値を使用して一時テーブルまたはテーブル変数を設定し、それらを UDF の SQL で実行します (ただし、UDF ではなくストレート SQL として)。カーソル。直接 SQL を実行すると、その中に print ステートメントを入れて、何が起こっているかを確認できます。私はこれが苦痛であることを知っていますが、うまくいきます。(トリガーの作成/デバッグ時に同様のプロセスを実行し、#inserted と #deleted をテスト値でセットアップしてから、トリガーに入れる予定のコードをテストし、グローバルで # を何も置き換えずに作成トリガー コードを追加します。 )

于 2008-12-10T16:50:15.250 に答える
0

SQL Profiler の提案に賛成です。関心のあるイベントのみがログに記録され、出力サイズが削減されるように、時間をかけて設定してください。トレースをファイルに出力できます。その後、分析を可能にするために、そのファイルをテーブルに頻繁にロードしました。(パフォーマンス分析には非常に便利ですが、2008年にはこれがすべて組み込まれていると誰かが言うことは間違いありません...)

サーバーの速度が低下するため、SQL プロファイラーを実行する権限がない場合があります。開発サーバーで権限を付与するよう DBA に依頼してください。彼らはそれで何の問題もないはずです。

于 2008-12-09T12:56:51.743 に答える
0

ここで説明されているように、SQL CLR を使用してトレースを行うことができるかもしれません T-SQL にログインする方法

于 2009-02-13T13:33:29.810 に答える