クエリアナライザによるストアドプロシージャのデバッグテクニックはじめにSQLステートメントのデバッグは、Visual Studio .NET環境でやるよりもSQL Server 2000のクエリアナライザでやった方がよいことがあります。私自身、バグがSQLストアドプロシージャにあることがわかっているときは、デバッグにSQLクエリアナライザを使うことがほとんどです。問題の所在がSQLだとわかっているのに、わざわざVisual Studioのようなオーバーヘッドの大きなアプリケーション開発環境を使っても、メリットはありません。問題を手早く突き止めるためには、呼び出し側アプリケーションを省いてマシンに余計な負荷をかけないようにする、というのも有益なテクニックです。ただしそのためには、使用している権限を偽造もしくはバイパスできること――つまり、セキュリティコンテキストを呼び出し側アプリケーションの元の状態(バグのある状態)と同じにできること――が前提となります。 サーバー/クライアント/ネットワークのセットアップ使用するWindowsオペレーティングシステムやSQL Serverのバージョン、インストールしてあるサービスパックなどによっては、デバッグが一筋縄ではいかないこともあります。また、サーバー上でのデバッグなら1台のマシンをチェックするだけで済みますが、クライアント上でのデバッグだと、クライアントとサーバーの両方がインストールされ、正しく設定されていることを確認しなければなりません。さらに、単純なLAN以外のものを使用しているときは、PRC設定やファイアウォール設定も含め、ネットワーク問題のチェックも必要となります。こうした問題のトラブルシューティングには、Microsoftのサポート技術情報の文書番号280101『INF - Transact-SQL Debugger Limitations and Troubleshooting Tips for SQL Server 2000』が役に立ちます。 また、端末/リモートセッションを通じてのデバッグは当面できません。Microsoftによるバグの解決待ちです。これについては、文書番号280100『 BUG - Transact-SQL Debugger Is Not Available Through Terminal Server Session』を参照してください。 セキュリティ/権限ローカルマシンでデバッグするためには、クエリアナライザへのログオンに使用するユーザアカウントが、masterデータベースにあるsp_sdidebug拡張ストアドプロシージャの実行権限を持っている必要があります。その他のSQL権限や認証がすべて引き続き有効であることを確認し、そうでないときは、バグを生じたユーザアカウント以外のユーザアカウントをデバッグに使用してください。 とにかくやってみる上記の設定その他は、いかにも面倒そうに聞こえるかもしれません。Visual Studioからのデバッグでは、おそらく、そうした面倒な作業の全部またはほとんどが既に済んでいて、だからこそVisual Studioの内部からデバッグできるわけです。SQL Serverのデバッグ設定をまったくやっていない方は、まずストアドプロシージャのデバッグをやってみてください。それなら最初のトライから成功するかもしれません。 デバッガを探すSQL 2000のクエリアナライザには、「オブジェクトブラウザ」と呼ばれるツリー表示機能があり、接続先のSQL Serverにあるすべてのものを表示できます。オブジェクトブラウザをまだ使ったことがない方は、[Tools]→[Object Browser]→[Show/Hide]メニューオプションを選択して表示してください。 オブジェクトブラウザのツリー表示が現れたら、データベースからストアドプロシージャを選び、そのストアドプロシージャ名を右クリックします。右クリックメニューが現れ、一番下に[Debug]オプションがあります。 このメニューオプションが灰色になっているときは、現ユーザに付与されている権限に不備があります。 例1:単純なストアドプロシージャのデバッグデバッガ機能を試すために、まず次のストアドプロシージャを作成します。 CREATE procedure DebugA ( @IntIn int, @IntOut int OUTPUT ) as Set @IntOut = @IntIn + 10 Return これは、ある数を受け取り、それに10を加えて、新しい数を出力変数に返すという単純なストアドプロシージャです。このストアドプロシージャは、クエリアナライザを使って次のコードで実行できます。 Declare @NewInt int exec DebugA 5,@NewInt OUTPUT Select @NewInt この例では、ストアドプロシージャに値5を与えているため、それに10を加えた値15が返されます。 [Debug Procedure]ウィンドウオブジェクトブラウザのツリー表示でストアドプロシージャ名を右クリックし、[Debug]を選択すると、[Debug Procedure]ウィンドウが現れます。ここで各パラメータに初期値を指定できます。 ![]() 右下の[Value]ボックスに値を入れてください。[Set to null]チェックボックスをオンにすれば、値をNULLに設定できます。 ![]() 出力専用として扱いたいパラメータの場合は、必ず[Set to null]チェックボックスをオンにしてください。 デバッグセッションの結果をデータベースに反映させたくないときは、[Auto roll back]チェックボックスをオンにしておきます。これで、ストアドプロシージャのデバッグ中にデータベースに加えた変更がすべてロールバックされます。 初期値の設定が終わったら、[Execute]をクリックして、デバッガに入ります。デバッガは、実行すべき最初のコード行で停止しています。 ![]() 注
私は画面を広く使いたいため、デバッグ中はオブジェクトブラウザを閉じています。
デバッガウィンドウデバッガのメインウィンドウの上に、いくつかのツールアイコンが並んでいます。これらのツールアイコンを使用して、どのコード行で実行を一時停止するかや、どのコード部分を細かく分析するかを制御できます。ツールアイコンの下にあるのがメインウィンドウで、ここにストアドプロシージャのコードが表示されています。このコードウィンドウの下に、さらに2つのウィンドウセクションがあります。 中段のセクションは3つに分かれていて、それぞれにローカル変数、グローバル変数、コールスタックが表示されています。ローカル変数は、デバッグ内部で変更できます。グローバル変数は、デバッグ内部で追加もしくは除去できます。この例では 下段のセクションは結果ウィンドウで、クエリアナライザがデバッグモードにないときのウィンドウと同じです。つまり、結果セットや 再び例1へ ここまで説明どおりに操作してきた場合は、デバッグウィンドウのローカル変数セクションでは ![]() 例2:入れ子になったストアドプロシージャ今度は、[Callstack]ウィンドウの理解を深めるために、T-SQLコードは単純なままで、別のストアドプロシージャを追加することにします。次のコードを実行して、必要なストアドプロシージャを作成してください。 CREATE TABLE [Table1] ( [TestId] [int] IDENTITY (1, 1) NOT NULL , [A] [int] NOT NULL , [B] [int] NOT NULL , [Total] [int] NOT NULL ) ALTER procedure DebugA ( @IntIn int, @IntOut int OUTPUT ) as Declare @Id int exec DebugB @IntIn, 10, @IntOut OUTPUT, @Id OUTPUT return Create procedure DebugB ( @IntIn int, @IntConst int, @Total int OUTPUT, @Id int OUTPUT ) as Set @Total = @IntIn + @IntConst Insert into Table1 (A,B,Total) values (@IntIn,@IntConst,@Total) Select @Id = @@identity Return これで「Table1」テーブルが作成され、 コードの実行後、オブジェクトブラウザで ローカル変数ウィンドウとグローバル変数ウィンドウには、例1と同じ値が表示されるはずです。デバッグツールバーにある[Step Into]ツール( コードウィンドウに、 では、最初のステートメントをステップ実行し、 挿入・更新・削除のいずれかのステートメントにバグがある場合は、当該ステートメント実行後の 次の デバッグモードでローカル変数の値を変更することの意義は何でしょうか? ストアドプロシージャに含まれる問題がいつも1つとは限りません。1つを修正するたびに初めからやり直していたのでは、時間が無駄になります。最初の問題の所在がわかったら、影響を受けたローカル変数を変更して、すぐ次のバグに移動した方が便利です。 カーソルなどの複雑なコードコードが複雑になればなるほど、デバッグのありがたみがわかります。たとえば、カーソルでは実に多くのことが行われているため、デバッグは必須です。いくつものテーブルが関係する入れ子式のカーソルなどは、その最たるものでしょう。SQLクエリアナライザを使わずにデバッグをする場合は、カーソルや入れ子式プロシージャを完全に排除し、そういう複雑な作業を呼び出し側アプリケーションに任せ、そちらのデバッガ(たとえば、Visual Studio)を使いたくなる人もいるかもしれません。SQL Server 2000のデバッガは完璧には程遠い代物ですが、正しい方向への大きな1歩だとは言えるでしょう。このおかげで、T-SQLコードのロジックをあるべきところに置き、コードを強力に管理できるのです。 例3:カーソル次のコードでカーソルを作成してみましょう。 create procedure DebugCursor as DECLARE cursorDebug Cursor FOR Select TestId, A, B, Total From Table1 Open cursorDebug Declare @cursorTestId int Declare @cursorA int Declare @cursorB int Declare @cursorTotal int Declare @randomDifference int Fetch NEXT FROM cursorDebug INTO @cursorTestId, @cursorA, @cursorB, @cursorTotal While (@@FETCH_STATUS =0) BEGIN -- generate random number seeded by row id Set @randomDifference = Convert(int,Rand(@cursorTestId)) Update Table1 Set @cursorTotal = @cursorA + (@cursorB * @randomDifference) Where TestId = @cursorTestId END FETCH NEXT From cursorDebug INTO @cursorTestId, @cursorA, @cursorB, @cursorTotal CLOSE cursorDebug DEALLOCATE cursorDebug GO このカーソルは例2の変形です。データベースに挿入される合計値を、行ごとに、その行のIDに基づくランダムなパーセンテージで変更します。 オブジェクトブラウザで ![]() これでSQLクエリアナライザのデバッガが呼び出され、実行可能な最初のステートメントが示されます。 ![]() グローバル変数に カーソルループ内のステートメントを1つずつステップ実行していき、 次は このカーソルがさらに別のストアドプロシージャを呼び出したとしても、そのストアドプロシージャの中までコードと値を追いかけていくことは難しくありません。 まとめSQL Server 2000によるデバッグは、大きな前進です。たとえストアドプロシージャのコードが複雑で、入れ子になっていても、ステートメントごとにデータベースの状態がどう変化するかを確認しながら、テストを進めることができます。この方法ならば、SQL Serverの持つトランザクション能力と処理速度をフルに生かすことができ、同様の機能を呼び出し側のアプリケーションで作り直す必要はなくなります。 著者紹介Dina Fleet Berry(Dina Fleet Berry)
|