ときどき、コメントがパフォーマンスに影響を与えるかどうかを人々が確信する会話が生まれます。
一般的に言って、いいえ、コメントはパフォーマンスに影響を与えません 、しかし「それは依存する」免責事項の余地は常にあります。サンプルデータベースとジャンクでいっぱいのテーブルを作成しましょう:
CREATE DATABASE CommentTesting; GO USE CommentTesting; GO SELECT TOP (1000) n = NEWID(), * INTO dbo.SampleTable FROM sys.all_columns ORDER BY NEWID(); GO CREATE UNIQUE CLUSTERED INDEX x ON dbo.SampleTable(n); GO
ここで、4つのストアドプロシージャを作成します。1つは20文字のコメント、1つは2000、1つは20,000、もう1つは200,000です。そして、コメントが独立しているのではなく、プロシージャ内のクエリステートメント内に埋め込まれている場合にもう一度やりたいと思います(これはプランのXMLに影響します)。最後に、OPTION (RECOMPILE)を追加するプロセスを繰り返しました。 クエリに。
DECLARE @comments nvarchar(max) = N'',
@basesql nvarchar(max),
@sql nvarchar(max);
SELECT TOP (5000) -- * 40 character strings
@comments += N'--' + RTRIM(NEWID()) + CHAR(13) + CHAR(10)
FROM sys.all_columns;
SET @basesql = N'CREATE PROCEDURE dbo.$name$
AS
BEGIN
SET NOCOUNT ON;
/* $comments1$ */
DECLARE @x int;
SELECT @x = COUNT(*) /* $comments2$ */ FROM dbo.SampleTable OPTION (RECOMPILE);
END';
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Small_Separate'), N'$comments1$', LEFT(@comments, 20));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Medium_Separate'), N'$comments1$', LEFT(@comments, 2000));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Large_Separate'), N'$comments1$', LEFT(@comments, 20000));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'ExtraLarge_Separate'), N'$comments1$', LEFT(@comments, 200000));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Small_Embedded'), N'$comments2$', LEFT(@comments, 20));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Medium_Embedded'), N'$comments2$', LEFT(@comments, 2000));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Large_Embedded'), N'$comments2$', LEFT(@comments, 20000));
EXEC sys.sp_executesql @sql;
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'ExtraLarge_Embedded'), N'$comments2$', LEFT(@comments, 200000));
EXEC sys.sp_executesql @sql;>
ここで、各プロシージャを100,000回実行するコードを生成し、sys.dm_exec_procedure_statsから期間を測定する必要がありました。 、キャッシュ内のプランのサイズも確認してください。
DECLARE @hammer nvarchar(max) = N''; SELECT @hammer += N' DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; GO EXEC dbo.' + [name] + N'; GO 100000 SELECT [size of ' + [name] + ' (b)] = DATALENGTH(definition) FROM sys.sql_modules WHERE [object_id] = ' + CONVERT(varchar(32),([object_id])) + N'; SELECT [size of ' + [name] + ' (b)] = size_in_bytes FROM sys.dm_exec_cached_plans AS p CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t WHERE t.objectid = ' + CONVERT(varchar(32),([object_id])) + N'; SELECT N''' + [name] + N''', avg_dur = total_elapsed_time*1.0/execution_count FROM sys.dm_exec_procedure_stats WHERE [object_id] = ' + CONVERT(varchar(32),([object_id])) + N';' FROM sys.procedures WHERE [name] LIKE N'%[_]Separate' OR [name] LIKE N'%[_]Embedded'; PRINT @hammer;
まず、プロシージャボディのサイズを見てみましょう。ここで驚くことはありません。上記の構築コードが各手順で予想されるサイズのコメントを生成したことを確認するだけです。
| 手順 | サイズ(バイト) |
|---|---|
| Small_Separate / Small_Embedded | 378 |
| Medium_Separate / Medium_Embedded | 4,340 |
| Large_Separate / Large_Separate | 40,338 |
| ExtraLarge_Separate / ExtraLarge_Separate | 400,348 |
次に、キャッシュ内のプランの大きさはどれくらいでしたか?
| 手順 | サイズ(バイト) |
|---|---|
| Small_Separate / Small_Embedded | 40,360 |
| Medium_Separate / Medium_Embedded | 40,360 |
| Large_Separate / Large_Separate | 40,360 |
| ExtraLarge_Separate / ExtraLarge_Separate | 40,360 |
最後に、パフォーマンスはどうでしたか? OPTION (RECOMPILE)なし 、これがミリ秒単位の平均実行時間です。すべての手順でかなり一貫しています:
平均継続時間(ミリ秒)–オプションなし(再コンパイル)
ステートメントレベルのOPTION (RECOMPILE)を使用 、再コンパイルなしと比較して、全体の平均期間で約50%のヒットが見られますが、それでもかなり均一です:
平均継続時間(ミリ秒)–オプション付き(再コンパイル)
どちらの場合も、OPTION (RECOMPILE) バージョンは一般的に遅くなり、事実上ゼロでした プロシージャ本体のコメントサイズに関係なく、実行時の違い。
コンパイルコストが高くなるのはどうですか?
次に、これらの大きなコメントがコンパイルコストに大きな影響を与えるかどうかを確認したいと思いました。たとえば、プロシージャがWITH RECOMPILEで作成された場合などです。 。上記の構築コードは、これを説明するために簡単に変更できました。しかし、この場合、私はsys.dm_exec_procedure_statsに頼ることができませんでした 、これはプロシージャWITH RECOMPILEでは機能しないためです。 。したがって、平均期間を手動で追跡する必要があるため、テストの生成コードは少し異なります。
DECLARE @hammer nvarchar(max) = N''; SELECT @hammer += N' DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; SELECT SYSDATETIME(); GO EXEC dbo.' + [name] + N'; GO 100000 SELECT SYSDATETIME();'; PRINT @hammer;
この場合、キャッシュ内のプランのサイズを確認できませんでしたが、プロシージャの平均実行時間を決定でき、コメントサイズ(または、おそらくプロシージャ本体のサイズ)に基づいて違いがありました:
平均期間(ミリ秒)–プロシージャレベルでの再コンパイルあり
それらをすべてグラフにまとめると、WITH RECOMPILEがどれほど高価であるかは明らかです。 使用法は次のとおりです。
平均期間(ミリ秒)–3つの方法すべてを比較>
後でこれを詳しく調べて、そのホッケースティックがどこで機能するかを正確に確認します。10,000文字単位でテストすることを想定しています。しかし今のところ、私は質問に答えたことにかなり満足しています。
概要
コメントは、プロシージャがWITH RECOMPILEで定義されている場合を除いて、実際の監視可能なストアドプロシージャのパフォーマンスとはまったく関係がないようです。 。個人的には、これが実際に使用されているとは思いませんが、YMMVです。このオプションとステートメントレベルのOPTION (RECOMPILE)の微妙な違いについて 、Paul Whiteの記事「パラメータのスニッフィング、埋め込み、およびRECOMPILEオプション」を参照してください。
個人的には、コメントは、コードを確認、保守、またはトラブルシューティングする必要がある人にとって非常に価値があると思います。これには将来のあなたも含まれます。妥当な量のコメントがパフォーマンスに与える影響を心配するのではなく、コメントが提供するコンテキストの有用性を優先することに重点を置くことを強くお勧めします。 Twitterの誰かが言ったように、限界があります。コメントがWarandPeaceの簡略版に相当する場合は、コードをドキュメントから切り離すリスクを冒して、そのドキュメントを別の場所に配置し、手順の本文のコメントにあるリンクを参照することを検討してください。
デカップリングのリスクを最小限に抑えるため、またはドキュメントとコードが時間の経過とともに同期しなくなるリスクを最小限に抑えるために、接尾辞_documentationを付けて2番目のプロシージャを作成できます。 または_comments 、コメント(またはコメント付きバージョンのコード)をそこに配置します。たぶん、それを別のスキーマに入れて、メインのソートリストから除外します。少なくともドキュメントはどこに行ってもデータベースに残りますが、それが維持されることを保証するものではありません。 WITH SCHEMABINDINGを使用して通常のプロシージャを作成できないのは残念です 、この場合、コメントプロシージャをソースに明示的に関連付けることができます。