SET NOCOUNT ONの使用法


341

SET NOCOUNTについて異なる見解があるこの質問に触発され ...

SQL ServerにはSET NOCOUNT ONを使用する必要がありますか?そうでない場合、なぜそうではないのですか?

何それがない 2011年7月22日に、編集6

DMLの後に「影響を受けるxx行」メッセージを抑制します。これは結果セットであり、送信時にクライアントはそれを処理する必要があります。小さいですが、測定可能です(以下の回答を参照)

トリガーなどの場合、クライアントは複数の「影響を受けるxx行」を受け取ります。これにより、一部のORM、MS Access、JPAなどであらゆる種類のエラーが発生します(以下の編集を参照)。

バックグラウンド:

一般的に受け入れられているベストプラクティス(この質問までは考えていました)はSET NOCOUNT ON、SQL Serverのトリガーとストアドプロシージャで使用することです。私たちはどこでもそれを使用し、簡単なグーグルは多くのSQL Server MVPも同意することを示しています。

MSDNは、これが.net SQLDataAdapterを破壊する可能性があると述べています。

これは、SQLDataAdapterが「影響を受ける行数n」のメッセージが一致することを期待しているため、まったく単純なCRUD処理に限定されていることを意味します。だから、私は使用できません:

  • 重複を避けるために存在する場合(行はメッセージに影響しません)注:注意して使用してください
  • 存在しない場所(予想される行が少ない場合)
  • ささいな更新を除外する(たとえば、実際に変更されるデータはない)
  • 前にテーブルへのアクセスを行う(ロギングなど)
  • 複雑さや正規化を隠す

marc_s(彼のSQLを知っている人)の質問では、これを使用しないでください。これは私が思うこととは異なります(私もSQLである程度有能であると私は考えています)。

何か不足している可能性があります(明らかなことを自由に指摘してください)が、そこにいる人々はどう思いますか?

注:SQLDataAdapterを最近使用していないため、このエラーが発生してから数年が経ちました。

コメントと質問の後の編集:

編集:その他の考え...

複数のクライアントがあります。1つはC#SQLDataAdaptorを使用し、もう1つはJavaのnHibernateを使用します。これらは、によってさまざまな方法で影響を受ける可能性がありますSET NOCOUNT ON

ストアドプロシージャをメソッドと見なす場合、内部処理の一部が独自の目的で特定の方法で機能すると想定することは不適切な形式(アンチパターン)です。

編集2:nHibernateの質問を破るトリガーSET NOCOUNT ON設定できない場所

(そして、それはこれの複製ではありません)

編集3:私のMVPの同僚のおかげで、さらに詳しい情報

編集4:2011年5月13日

指定されていない場合、Linq 2 SQLも壊れますか?

編集5:2011年6月14日

JPA、テーブル変数を含むストアドプロシージャを壊す:JPA 2.0はSQL Serverテーブル変数をサポートしていますか?

編集6:2011年8月15日

SSMSの「行の編集」データグリッドにはSET NOCOUNT ONが必要です:GROUP BYでトリガーを更新

編集7:2013年3月7日

@RemusRusanuからの詳細:SET NOCOUNT ONは本当にパフォーマンスに大きな違いをもたらします


@AlexKuznetsov:「スレッドセーフ」アプローチとは何でしょうか?EXISTSで実行された読み取りには、未処理のトランザクションが含まれますか?
AnthonyWJones

2
@ジェレミー・セギ:返信が遅くなってすみません。(影響を受ける#rows)メッセージは、SSMSなどによって解釈されるクライアントツールのものです。ただし、この情報とともに送信されるパケットがあります。もちろん、@@ rowcountなどがどのように機能するかは承知していますが、これは問題ではありません...
gbn

1
心配ない。個人的に私はあなたの立場に同意します。IF / WHERE EXISTS構文の結果とSET NOCOUNTの結果の間に直接的な相関関係はないというコメントをしました。NOCOUNTに関係なく、これらのコンストラクトから一貫した結果が得られます。他に何か言うことがあれば、私の方法で送ってください。
Jeremy S

1
@Jeremy Seghi:正解です。SETNOCOUNT ON は、クライアントに返されるデータの余分なパケットのみを抑制します。IF、@@ ROWCOUNTなどは影響を受けません。ああ、それはSQLDataAdaptersを壊します... :-)
gbn

1
@Kieren Johnstone:振り返ってみると、これは不適切な言葉で書かれた質問です。これが私の質問ではなかった場合は、終了するよう投票します...
gbn

回答:


245

さて、私は私の研究を終えました、これが取引です:

TDSプロトコルでは、「SET NOCOUNT ON」というテキスト自体がなんと14バイトですが、クエリごとに9バイトSET NOCOUNT ONしか節約できません。以前はサーバーからプレーンテキストで別のネットワークパケットで返されたと思っていましたが、そうではありませんでした。実際には、応答に埋め込まれたと呼ばれる小さな構造です。これは個別のネットワークパケットではないため、無駄なラウンドトリップはありません。123 row(s) affectedDONE_IN_PROC

ほとんどの場合、パフォーマンスを気にすることなく、デフォルトのカウント動作を維持できます。ただし、前方スクロールカーソルなど、事前に行数を計算するとパフォーマンスに影響する場合もあります。その場合、NOCOUNTが必要になることがあります。それ以外は、「可能な限りNOCOUNTを使用する」というモットーに従う必要はまったくありません。

SET NOCOUNT設定の重要性についての非常に詳細な分析は次のとおりです。http//daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/


確かに。SET NOCOUNT ONを永久に使用してきましたが、他の質問でmarc_sがSQLDataAdapterの制限を指摘しました。
gbn 2009年

ありがとう。バイトやサイズは私には問題ではありませんが、クライアントがそれを処理する必要があります。それは...まだかかわらず、私をastoundsというSqlDataAdapterオブジェクトの依存関係だ
GBN

2
ご回答有難うございます。あなたの調査により、これを受け入れます。それにより、より多くの情報と私からの働きが引き起こされました。ただし、オーバーヘッドについては同意しません。他の回答が示すように、問題になる可能性があります。乾杯、GBN
GBN

13
それはバイト数ではなく、パフォーマンスキラーであるワイヤを介した往復遅延
レーシングスネイル2013

1
TDSメッセージストリームでの例は、値のみをテーブルに挿入する場合です。DONINPROC(RPC)またはDONE(バッチ)メッセージを用いてストリーミングされrowcountている間、影響を受けた行にセットdone_countフラグがtrue関係なく場合、NO_COUNTですON。クエリが選択を行うSELECTステートメントまたはRPC呼び出しを保持する場合、クライアントライブラリの実装に依存します。カウントを無効にする必要がある場合があります...無効にすると、selectステートメントの行は引き続きカウントされますが、フラグDONE_COUNTはに設定されfalseます。あなたの代わりにトークン(メッセージ)ストリームを解釈するため、クライアントライブラリが提案する内容を常に読んでください
Milan Jaric

86

NOCOUNTあたりの実際のベンチマークの数値を見つけるのに多くの掘り下げが必要だったので、簡単な要約を共有したいと思いました。

  • ストアドプロシージャがカーソルを使用して多くの非常に迅速な操作を実行し、結果が返されない場合、NOCOUNT OFFをオンにすると、約10倍の時間がかかります。1これは最悪のシナリオです。
  • ストアドプロシージャが単一のクイック操作のみを実行して結果が返されない場合、NOCOUNT ONを設定すると、パフォーマンスが約3%向上する可能性があります。2これは、通常の挿入または更新手順と一致します。(なぜこれが常に速いとは限らないのかについての議論については、この回答のコメントを参照してください。)
  • ストアドプロシージャが結果を返す(つまり、何かを選択する)場合、パフォーマンスの違いは結果セットのサイズに比例して減少します。

5
カーソルへの影響の+1、これは私の観察と一致しています
zvolkov

ポイント2は正確ではありません!それが言及しているブログを意味します。なかった!DONE、DONEPROC、およびDONEINPROCは、NO_COUNTがONまたはOFFに設定されているかどうかに関係なく、同じサイズで送信されます。RowCountはULONGLONG(64バイト)として存在し、フラグDONE_COUNTはまだ存在しますが、ビット値は0です。SQLサーバーは、DONEトークンから値を読み取る必要がない場合でも、行数をカウントします。@@ ROWCOUNTを読み取る場合は、returnvalueトークンの形式で、または別のcolmetadata +行トークンとして、トークンストリームにバイトを追加しました!
ミラノジャリック

@MilanJaric:声をかけてくれてありがとう。あなたは私が間違った記事をリンクしたことを理解するのを助けました。リンクが更新され、記事では、SET NOCOUNT ONを使用するとパフォーマンスがわずかに向上する可能性があることを示す説得力のある議論が行われます。使用されているベンチマーク手法に問題があると思いますか?
StriplingWarrior

:) SET NOCOUNT OFF / ONについては依然として不正確です。エラーは、2番目のSPにないことでSET NOCOUNT OFF;あり、そのため、応答で余分なバイトを取得していないと考えています。正確なベンチマークを使用することですSET NOCOUNT ON左にし、SET NOCOUNT OFF右のストアドプロシージャで。あなたとTDSパッケージを取得します。この方法でDONEINPROC (SET NOCOUNT ...)再び10、DONEINPROC (INSERT statement)そして、そしてRETURNVALUE(@@ROWCOUNT)、その後、RETURNSTATUS 0SP用とfinaly DONPROC。2番目のspの本文にSET NOCOUNT OFFがないため、エラーが発生します!
ミラノジャリック

彼らが見つけたものを言い換えると、彼らが気づかなかったのは、1Kのフェッチカーソルリクエストがある場合、最初に1つのリクエストで接続に対してNOCOUNTをONまたはOFFに設定してから、同じ接続を使用してカーソルフェッチを1K回呼び出し、帯域幅を節約することです。NOCOUNT ONまたはOFFの実際の接続状態は帯域幅に影響しません。たとえば、ADO.netやODBCなどのクライアントライブラリを混乱させるだけです。したがって、「帯域幅を気にする場合は、SET NOCOUNT <WHATEVER>を使用しないでください」:)
Milan Jaric

77
  • SET NOCOUNTがONの場合、カウント(Transact-SQLステートメントの影響を受ける行の数を示す)は返されません。SET NOCOUNTがOFFの場合、カウントが返されます。SELECT、INSERT、UPDATE、DELETEステートメントで使用されます。

  • SET NOCOUNTの設定は、解析時ではなく、実行時または実行時に設定されます。

  • SET NOCOUNT ONは、ストアドプロシージャ(SP)のパフォーマンスを向上させます。

  • 構文:SET NOCOUNT {ON | オフ}

SET NOCOUNT ONの例:

ここに画像の説明を入力してください

SET NOCOUNT OFFの例:

ここに画像の説明を入力してください


7
スクリーンショットで簡単かつ迅速に理解できます。よくやった。:)
shaijut 2018

35

ある程度、それはDBA対開発者の問題だと思います。

開発者として、私は絶対に積極的にする必要がない限り使用しないでください。使用するとADO.NETコードが壊れる可能性があるためです(Microsoftによって文書化されています)。

そして、私はDBAとして、もう一方の側にいると思います。使用を実際に防ぐ必要がない限り、可能な限り使用してください。

また、開発者がADO.NETのExecuteNonQueryメソッド呼び出しによって返される「RecordsAffected」を使用するSET NOCOUNT ON場合、この場合、ExecuteNonQueryは常に0を返すため、誰もが使用すると問題が発生します。

Peter Brombergのブログ投稿も参照して、彼の立場を確認してください。

ですから、それは誰が基準を設定できるかということになります:-)

マーク


彼はかかわらについての簡単なCRUD上だ:彼は言及データグリッドは、往復などを避けるために、複数の行を送信するためにXMLを使用することができます
GBN

SqlDataAdaptersを使用したことがなく、ExecuteNonQueryによって返される「影響を受けるレコード」の数を確認して依存しない場合(たとえば、Linq-to-SQLやNHibernateのようなものを使用する場合)、おそらく問題はないと思いますすべてのストアドプロシージャでSET NOCOUNT ONを使用します。
marc_s

12

別のクライアントも使用している可能性がある場合、SET NOCOUNTがONに設定されていないと、従来のADOに問題が発生します。

私が定期的に経験するもの:ストアドプロシージャがいくつかのステートメントを実行する場合(したがって、「xxxの影響を受ける行」のメッセージが返される場合)、ADOはこれを処理せず、エラーをスローします 「レコードセットオブジェクトのActiveConnectionプロパティを変更できません」ますソースとしてコマンドオブジェクトを持っています。」

ですから、本当に本当に正当な理由がない限り、私はそれをONに設定することを推奨します。あなたは私が行ってさらに読む必要がある本当に本当に良い理由を見つけたかもしれません。


9

物事をより複雑にするリスクがあるので、私は上記のすべてのものとは少し異なるルールを推奨します。

  • 常にセットNOCOUNT ONあなたはprocの内いずれかの作業を行う前に、PROCの上部に、しかしまた、 常にSET NOCOUNT OFFストアドプロシージャから任意のレコードセットを返す前に、もう一度。

したがって、「実際に結果セットを返す場合を除いて、通常は何もしないでおく」。これがクライアントコードを壊す可能性のある方法はわかりません。これは、クライアントコードがproc内部について何も知る必要がないことを意味し、特に面倒ではありません。


ありがとう。もちろん、DataSetまたは消費コンテナから行数を取得できますが、便利な場合があります。SELECTにトリガーを設定することはできないため、これは安全です。ほとんどのクライアントエラーは、データ変更時の偽のメッセージが原因です。
gbn

このルールの問題は、「プロシージャの先頭にSET NOCOUNT ONがあるか?」よりもテストが難しいことです。Sql EnlightのようなSQL分析ツールがそのようなことをテストできるかどうか疑問に思っています... SQLフォーマッタープロジェクトの長期的なToDoリストに追加します:)
Tao

5

NHibernateを破壊するトリガーに関して、私は直接その経験をしました。基本的に、NHがUPDATEを実行すると、特定の数の行が影響を受けることが予想されます。トリガーにSET NOCOUNT ONを追加することにより、行数をNHが予期したものに戻し、それによって問題を修正します。ですから、NHを使用する場合は、トリガーに対してオフにすることをお勧めします。

SPでの使用については、個人の好みの問題です。私は常に行カウントをオフにしていましたが、それでも、どちらの方法にも本当の強い議論はありません。

別の言い方をすれば、SPベースのアーキテクチャからの移行を検討する必要があります。そうすれば、この質問すらありません。


1
ストアドプロシージャからの移行に同意しません。つまり、2つの異なるクライアントコードベースで同じSQLを使用し、クライアントプログラマーを信頼する必要があります。私たちは開発者DBAです。そして、「SET NOCOUNT ON」を意味しませんか?
gbn 2009年

@CodeBlend:必要以上のことをGoogleに任せましょう。ただし... stackoverflow.com/a/4040466/27535
gbn

3

「SET NOCOUNT ON」がネットワークパケットも往復も保存しないことを自分で確認したかった

別のホストでテストSQLServer 2017を使用しました(VMを使用しました) create table ttable1 (n int); insert into ttable1 values (1),(2),(3),(4),(5),(6),(7) go create procedure procNoCount as begin set nocount on update ttable1 set n=10-n end create procedure procNormal as begin update ttable1 set n=10-n end 次に、ツール 'Wireshark'してポート1433でパケットをトレースしました: 'キャプチャフィルター'ボタン-> 'ポート1433'

exec procNoCount

これは応答パケットです: 0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00 0010 00 42 d0 ce 40 00 40 06 84 0d c0 a8 32 88 c0 a8 0020 32 01 05 99 fe a5 91 49 e5 9c be fb 85 01 50 18 0030 02 b4 e6 0e 00 00 04 01 00 1a 00 35 01 00 79 00 0040 00 00 00 fe 00 00 e0 00 00 00 00 00 00 00 00 00

exec procNormal

これは応答パケットです: 0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00 0010 00 4f d0 ea 40 00 40 06 83 e4 c0 a8 32 88 c0 a8 0020 32 01 05 99 fe a5 91 49 e8 b1 be fb 8a 35 50 18 0030 03 02 e6 1b 00 00 04 01 00 27 00 35 01 00 ff 11 0040 00 c5 00 07 00 00 00 00 00 00 00 79 00 00 00 00 0050 fe 00 00 e0 00 00 00 00 00 00 00 00 00

40行目で、「影響を受ける行」の数である「07」を確認できます。応答パケットに含まれています。余分なパケットはありません。

ただし、保存できる13バイトが余分にありますが、列名を減らすことよりも価値はありません(例: 'ManagingDepartment'から 'MD')。

だから、パフォーマンスのためにそれを使う理由はない

しかし、他の人が言及したように、それはADO.NETを破壊する可能性があり、私はpythonを使用した問題にも遭遇しました: MSSQL2008-Pyodbc-以前のSQLはクエリではありませんでした

だからおそらくまだ良い習慣...


1
SET NOCOUNT ON;

このコード行は、クエリの実行で影響を受けた行数を返さないようにSQLで使用されます。影響を受ける行数を必要としない場合は、これを使用して、メモリ使用量を節約し、クエリの実行速度を向上させることができます。


2
@@ ROWCOUNTがまだ設定されていることに注意してください。SET NOCOUNT ONは、SQL Serverがクライアントに送信する追加の応答を抑制します。上記の受け入れられた回答を参照してください
gbn '17

1

NOCOUNTをONに設定します。上記のコードは、DML / DDLコマンドの実行後に、SQLサーバーエンジンによって生成されたメッセージを前面の結果ウィンドウに停止します。

なぜそれを行うのですか?SQLサーバーエンジンは、ステータスを取得してメッセージを生成するためにリソースを使用するため、SQLサーバーエンジンへの過負荷と見なされます。したがって、noncountメッセージをオンに設定します。


1

SET NOCOUNT ON本当に役立つ1つの場所は、ループまたはカーソルでクエリを実行しているところです。これにより、ネットワークトラフィックが増加する可能性があります。

CREATE PROCEDURE NoCountOn
AS
set nocount on
    DECLARE @num INT = 10000
    while @num > 0
    begin
       update MyTable SET SomeColumn=SomeColumn
       set @num = @num - 1
    end
GO


CREATE PROCEDURE NoCountOff
AS
set nocount off
    DECLARE @num INT = 10000
    while @num > 0
    begin
       update MyTable SET SomeColumn=SomeColumn
       set @num = @num - 1
    end
GO

SSMSでクライアントの統計をオンにするEXEC NoCountOnEXEC NoCountOff、NoCountOffに390KBのトラフィックが追加されたことがわかります。

クライアント統計

おそらくループやカーソルでクエリを実行することは理想的ではありませんが、理想的な世界には住んでいません:)


0

私はそれがかなり古い質問であることを知っています。しかし、更新のためだけです。

「SET NOCOUNT ON」を使用する最良の方法は、SPの最初のステートメントとして設定し、最後のSELECTステートメントの直前にオフに設定することです。


-1

クライアントとSQLの間でSET NOCOUNT ONをテストする方法がわからないので、他のSETコマンド「SET TRANSACTION ISOLATION LEVEL READ UNCIMMITTED」に対して同様の動作をテストしました

SQLのデフォルトの動作(READ COMMITTED)を変更するコマンドを接続から送信しましたが、次のコマンド用に変更されました。ストアドプロシージャ内のISOLATIONレベルを変更しても、次のコマンドの接続動作は変更されませんでした。

現在の結論、

  1. ストアドプロシージャ内の設定を変更しても、接続のデフォルト設定は変更されません。
  2. ADOCOnnectionを使用してコマンドを送信して設定を変更すると、デフォルトの動作が変更されます。

これは、 "SET NOCOUNT ON"などの他のSETコマンドに関連していると思います


上記のポイント1は、グローバル環境に影響を与えないため、最後にNOCOUNT OFFを設定する必要がないことを意味しますか?
funkymushroom 14年

それが彼がポイント1で何を意味していたかはわかりませんが、私のテストではそうです、明らかに、グローバル環境はストアドプロシージャ内のSET NOCOUNT ONの影響を受けません。
Doug

分離レベルを明示的に特定の取引に関連しているので、これは、比較のお粗末な選択だったので、それはのような設定と一致するように期待する特別な理由はありませんNOCOUNT
IMSoP

-1

if(カウントを設定しない==オフ)

{次に、影響を受けるレコードの数のデータを保持するため、パフォーマンスが低下します}その他{変更のレコードを追跡しないため、パフォーマンスが向上します}}


-1

場合によっては、最も単純なものでも違いが生じることがあります。すべてのストアドプロシージャに含める必要があるこれらの単純なアイテムの1つはSET NOCOUNT ONです。ストアドプロシージャの先頭にあるこの1行のコードは、各T-SQLステートメントの実行後にSQL Serverがクライアントに返すメッセージをオフにします。これはすべてのために行われSELECTINSERTUPDATE、およびDELETEステートメント。この情報は、クエリウィンドウでT-SQLステートメントを実行するときに便利ですが、ストアドプロシージャを実行するときに、この情報をクライアントに返す必要はありません。

この余分なオーバーヘッドをネットワークから取り除くことにより、データベースとアプリケーションの全体的なパフォーマンスを大幅に向上させることができます。

それでも、実行中のT-SQLステートメントの影響を受ける行数を取得する必要がある場合は、この@@ROWCOUNTオプションを使用できます。SET NOCOUNT ONこの関数(@@ROWCOUNT)を発行しても機能し、ストアドプロシージャで使用して、ステートメントによって影響を受けた行数を特定できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.