クエリの実行中にSQL Serverがいくつかの行を返すのはなぜですか?


33

「実行」を押すと、いくつかの行が表示され、成長し続けるクエリがありますが、クエリはまだ終了していません。ただし、クエリが終了するまで待機する場合があります。

なぜこれが起こるのですか?これを制御する方法はありますか?

回答:


43

答えは、いつものように(大抵の場合)、実行計画にあります。

これらの行の処理を開始して下流に渡す前に、すべての行が到着することを必要とする特定の演算子があります。次に例を示します。

  • ハッシュ結合(ハッシュテーブルの構築時)
  • ハッシュマッチ
  • 並べ替え(ハッシュフローを除く)

これらは、ブロッキングと呼ばれるか、またはこのためストップアンドゴーオペレーターのいずれかであり、多くのデータを処理してデータを見つける必要があるとオプティマイザーが考える場合にしばしば選択されます。

ストリーミングを開始できる、または見つかった行をすぐに渡すことができる他の演算子があります

  • 入れ子ループ
  • インデックスでサポートされているマージ結合
  • ストリーム集約

クエリがすぐにデータを返し始めてもすぐに終了しない場合は、通常、オプティマイザが起動コストの低い演算子を使用していくつかの行をすばやく見つけて返す計画を選択したことを示しています。

これは、ユーザーまたはオプティマイザーによって行の目標が導入されたために発生する可能性があります。

何らかの理由(SARGabilityの欠如、パラメータスニッフィング、不十分な統計など)で悪い計画が選択された場合にも発生する可能性がありますが、それを見つけるにはさらに掘り下げる必要があります。

詳細については、Rob Farleyのブログをご覧ください。

そして、ポール・ホワイトのシリーズ行の目標にここここここ、とここに

また、SSMSについて話している場合、行が表示されるのは、意志だけではなく、バッファ全体がいっぱいになると表示されることにも注意してください。


14

あなたが観察していることを理解すると、これがManagement Studioが行をレンダリングする方法であり、SQL Server 行を返す方法とはほとんど関係ありません。実際、SSMSに大きな結果を返してグリッドにレンダリングしようとすると、SSMSが追いつかず、SQL Serverがアプリがより多くの行を処理するのを待つことになります。この場合、SQL ServerがASYNC_NETWORK_IO待機を蓄積していることがわかります。

SSMSはグリッドを描画するよりも高速にテキストを描画できるため、Results to Gridの代わりにResults to Textを使用することでいくらか制御できますが、列の数と関連するデータ型によっては読みやすさに影響する可能性があります。どちらも、SSMSがそのペインに結果を実際に書き出すことを決定するときの影響を受けます。これは、出力バッファーがどれだけいっぱいになっているかによって異なります。

あなたが持っている場合は、複数の文を、あなたがメッセージペインに出力結果をレンダリングするために、バッファを強制したい、あなたは文の間に少し印刷トリックを使用することができます。

RAISERROR('', 0, 1) WITH NOWAIT;

ただし、すべての出力が単一のステートメントから来ているときに、SSMSで行をより速くレンダリングしようとする場合、これは役に立ちません。

より直接的に、SSMSでレンダリングする結果の数を制限することで、それを制御できます。グリッドに100万行を返すのにかかる時間について人々が不満を言うのをよく見ます。一体誰もがSSMSグリッドの100万行で何をするのか、私にはわかりません。

のようないくつかのハックがありますOPTION (FAST 100)。これは、最初の100行(またはouterがない場合は100行)を取得するために最適化されORDER BYますが、残りの行とより多くの計画の取得が非常に遅くなります全体的に非効率的であるため、実際に行くべきオプションではありません。


1

あなたの質問は、SQLServer自体に関するものではありませんが、次のとおりです。

  • SQLサーバー
  • ネットワーク
  • クライアントアプリケーションとしてのSSMS

これを制御する方法はありますか?

短い答え

  1. または-modeのsqlcmd代わりに試してくださいssmssqlcmdssms
  2. 接続とセッションの設定を確認してください

長い答え

もちろん!しかし、1つではありません-問題

  1. ssms sqlcmdsqlcmd-modeを使用して、または-modeでクエリを実行します。
  2. ネットワークの役割を除外する場合-共有メモリ接続のあるサーバーでクエリを実行します。
  3. 共有メモリ接続でもクエリのパフォーマンスが満足できない場合-実行計画を分析します。ネットワーク経由でクエリのパフォーマンスが悪い場合-ネットワークのネットワーク管理者に連絡してください。SSMSでのみクエリのパフォーマンスが悪い場合-さらに読みます。
  4. これで、問題がクライアント側(この場合はssms)にあることが確実になりました。SSMSの接続とセッションの設定を見てください。ssmsインターフェイス信じないで、SQLプロファイラーで確認してください。接続を見つけてspid、セッション設定の完全なリストを取得します。sqlcmdセッションの設定と比較します。何もクリックしない場合-すべてのセッション設定をプロファイラーからクエリスクリプトにコピーし、sqlcmd-mode で実行し、徐々に原因を見つけて設定を切り替えます。

がんばろう!


-2

sp_BlitzErikの回答に追加するにNOT IN ()は、サブ選択でa を使用した例を取り上げます。アイテムがネストされたクエリの結果に含まれているかどうかを判断するには、(通常)結果全体を取得する必要があります。

したがって、このようなクエリのパフォーマンスを向上させるために見つけた簡単な方法の1つはLEFT OUTER JOINRIGHTsideの条件がnull であるように書き換えることです(もちろん、誰でも使用できRIGHT OUTER JOINSます)。これにより、結果がすぐに返され始めます。


そうは思いません。比較される列がNULL可能でない場合、3つのバージョンのアンチジョイン(NOT IN、NOT EXISTS、LEFT JOIN / IS NULL)の結果は同じであり、計画-通常は同じである必要があります。結果全体を取得する必要はありません。
ypercubeᵀᴹ

副選択が本当に複雑なものである場合、生成されたクエリがNOT IN条件、WHERE t.x IN (<complex SELECT subquery>)等価LEFT JOIN、をチェックする前に副選択全体を評価する必要がある場合、副問い合わせも評価する必要がLEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULLあります(そのため、NOT INバージョン)。
ypercubeᵀᴹ

@ypercubeᵀᴹ過去に私のために働いていました。クエリが数分かかってから1秒未満に戻るのを見てきました。
ジミージェームズ

@ypercubeᵀᴹ私はOracleで簡単な例をまとめました(現時点ではSQLServerにアクセスできません)、彼らは間違いなく異なる説明計画を持っていました。おそらく、それらは意味のある違いではありませんでしたが、かなり異なって見えます。
ジミージェームズ

@JimmyJames:安定したパフォーマンスが必要な場合、これは簡単な方法ではなく、そのような「最適化」はSQLServerバージョンに対して非常に敏感です。そして、Oracleにアピールするミスをしないでください(どのバージョンですか?)。歴史的にはSQLServerが好まれましたNOT EXISTSNOT IN、クエリではOracle が好まれました。しかし、今日それは計画ジェネレーターのエラーと見なされる必要があります
アレックスユ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.