SQL Serverクエリがメモリで実行されているかディスクに移動しているかを判断する方法はありますか?


13

今日、アプリケーションで一連のストアドプロシージャに出くわしました。これらは、長時間実行されるプロセス内で繰り返し呼び出されます。各プロシージャ内で、複数の異なるselectステートメントを見つけました。一部はループ内です。当然のことながら、現在使用されているこれらのルーチンの実行には数分かかりますが、直観では数秒で完了すると予想されます。

これらの手順が書かれたとき、パフォーマンスが考慮されなかったことはかなり明白であるように見えます。「良いアイデアではない」もののインスタンスが複数あります。

データのインポート時の各行の処理には1行あたり300ミリ秒かかるため、比較的小さなインポートの処理には数分かかります。

ただし、手順に含まれるテーブルの大部分は非常に小さいものです。これらのテーブルのすべてがメモリに完全に常駐している場合、おそらくこのいずれかを書き換えても得られるものはそれほど多くないと考えています。

私は決定しようとしている....この明らかに非効率的なコードのために、それはどれほどの本当の影響を与えているのか?修正する価値はありますか?

質問は次のとおり
です。-完全にメモリに固定されているテーブルを特定する方法はありますか?
-ネストされたストアドプロシージャを監視して特に高価な部分を見つけるために、トレースをオンにする方法はありますか?

注:これはSQL Server 2008 R2にあります

回答:


12

これら2つのクエリのいずれかを使用して、論理読み取りの合計と物理読み取りの合計を確認できます。

SELECT  DB_NAME(st.dbid) Db,
        OBJECT_NAME(st.objectid, st.dbid) Prc,
        qs.execution_count,
        qs.total_logical_reads,
        qs.total_physical_reads,
        qs.statement_start_offset,
        qs.statement_end_offset,
        st.text
FROM    sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st;

SELECT  DB_NAME(database_id) Db,
        OBJECT_NAME(object_id, database_id) Prc,
        execution_count,
        total_logical_reads,
        total_physical_reads
FROM    sys.dm_exec_procedure_stats ps;

最初のステートメントはこれをステートメントごとに分類し、2番目のステートメントは手順全体でカウントします。

物理読み取りはディスクに対する読み取りであり、論理読み取りはメモリに対する読み取りです。これを使用して、システムで最も高価なプロシージャまたはステートメントを特定し、それらを調整してみてください。

論理的な読み取りは物理的な読み取りよりもはるかに安価ですが、依然として高価なので、それらの数を減らす(たとえば、適切なインデックスを追加する)と、クエリの実行速度が大幅に向上します。

上記のDMVには、興味深いと思われる追加の列がたくさんあります。


インデックスは論理読み取りを減らすのにどのように役立ちますか?

SQL Serverでは、すべてのデータはサイズが8 KBのブロックに編成されます。これらのブロックは「ページ」と呼ばれます。

すべてのテーブルには、テーブルの構造とpataページに関する情報を含む「メタ」ページが含まれています。インデックスが存在せず、SELECT * FROM tbl WHERE Id = 7SQL Server などのクエリを実行する場合、テーブル全体でこの行またはこれらの行を検索する必要があります。そのため、一度に1ページずつ読み取り、各ページのすべての行をループして、WHERE句に適合する行を決定します。したがって、テーブルに1,000,000ページを保存する必要がある場合、このクエリの実行には1,000,000の論理読み取りが必要になります。

インデックスがある場合、SQL Serverはページ内でデータを論理的に並べ替え、ページ間のリンクリストを確立します。これによりORDER BY、高価なソート操作なしでクエリを実行できます。しかし、重要なことは、並べ替え、SQL ServerがテーブルにBツリーを追加することです。B + Treeは、本のインデックスに匹敵する構造です。特定のキーワードを探すと、そのキーワードを含むページに直接ジャンプできます。典型的な本には1つのインデックスレベルしかありませんが、B +ツリーには複数のインデックスレベルを設定できます。インデックス自体が複数ページの長さである大きな本を考えてください。そのような場合、ページでインデックスワードが始まることを示す追加のインデックスレイヤーを追加することは理にかなっていますS

B + Treeは、インデックスレベルごとに1ページを読み取ることでインデックス内のレコードを検索できるというプロパティを提供しながら、できるだけ少ないレベルを持つように最適化されます。したがって、でWHERE Id = 7ソートされたインデックスがある場合、上記のクエリを想定してくださいId。インデックスには5つのレベルがあるとしましょう。ここで、このクエリに一致するすべてのレコードを検索するには、インデックスレベルごとに1ページ(つまり5ページ)を読み取る必要があります。これは「インデックスシーク」と呼ばれます。法案に適合する複数のレコードがある場合、それらのすべてを取得するために、しばらくの間、ソートされたインデックスに従う必要があります。しかし、レコードが1つしかないと仮定しましょう。

したがって、インデックスを実行せずにクエリを実行すると1,000,000回の読み取りが必要でしたが、実際には5回の読み取りが必要でした。論理読み取りはインメモリ操作ですが、かなりのコストがかかります。実際、上記のような単純なクエリで最も高価な操作です。したがって、必要な論理読み取りの量を200,000分の1に減らすと、同様の要因でクエリが高速化されます。

したがって、論理読み取りはテーブルスキャンと同等ではありませんが、テーブルスキャンはインデックスシークよりもはるかに多くの論理読み取りを引き起こします。


>「...適切なインデックスを追加するなどしてそれらの数を減らすと、クエリの実行速度が大幅に向上します。」インデックスを追加すると、論理読み取りがどのように削減されるのか説明できますか?論理読み取りはテーブルスキャンと同義ですか?

1
上記の私の答えに説明を追加しました。
セバスチャンマイネ

ありがとう。関係するすべてのテーブルに適切なインデックスがあると仮定しても...メモリに固定されているテーブルとディスクから読み取られているテーブルのパフォーマンスには大きな違いがあると思います(両方のシナリオで同じインデックスを想定)...または他のつまり、インデックスを追加すると、メモリの少ないマシンよりもRAMの多いマシンの方がパフォーマンスの向上が少なくなります。

1
物理ディスクアクセスは明らかに、メモリアクセスよりも桁違いに高価です。そのため、それを回避するための対策を講じることで、あなたは非常に遠くに行けます。クエリのチューニング時には、最初に論理読み取りの数を最初に確認する必要があります。それらを低く保つと、物理的な読み取りが低くなります。また、ページをキャッシュから削除する必要がない可能性が高く、必要な物理読み取りをさらに削減できます。
セバスチャンマイネ

2
マイナーなピック-ページは8kbだと思います:-)。いい答えです。
-onupdatecascade

3
  • ネストされたストアドプロシージャを監視して特に高価な部分を見つけるために、トレースをオンにする方法はありますか?

SQLプロファイラーを使用できます。トレースを開始するとき、RPC Completed、SP Starting、SP StmtStarting、およびSP StmtCompletedを選択する必要があります(下の画像を参照)

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

これにより、ストアドプロシージャ内で実行されるすべてのクエリを確認できます。ネストされたストアドプロシージャが何回呼び出されるかを確認できます。トレースが終了したら、保存する必要があります。次に、それを再度開きます。その後、([列フィルター]ボタンを使用して)フィルター処理して、問題の原因となっているクエリを見つけることができます。(例:読み取りがx回以上かかったクエリ、またはx秒以上続いたクエリ(期間)...)

私がお見せしたプロファイラーのオプションには、実行計画も表示されますが、これも非常に役立ちます。


1

一般的なクエリ最適化の質問のようです。あなたの説明から:

  1. コードを見て、行ごとの処理を行うかどうかを確認します。その場合、セット(同時に処理される複数の行)を使用して同じロジックを実装することにより、桁違いの改善を行うことができます。つまり、「各行をループする」ように動作する場合は、「すべての行を処理する」ように変更します。SQLは、オプティマイザーがより多くの可能なメソッドから選択できるため、潜在的に並列処理を使用し、一度に1行から生じる多くのオーバーヘッドを。
  2. 次に、作業をサポートするインデックスがあることを確認します。繰り返しになりますが、多くの場合、正しいインデックスを使用した場合と使用しない場合で、桁違いに改善される場合があります。これは、メモリおよびディスクアクセスに当てはまります。大規模なデータセットに適切なインデックスがない場合、プロセスはRAM内のすべてのもので数時間かかることがあります。
  3. 次に、設定されたロジックとインデックスを使用して、影響を受けるデータページがメモリに収まるかどうかを調べます。この時点で、まだ多くのディスクアクセスがある場合、物理読み取りとディスクアクティビティを確認することは理にかなっています。最適化による大きなメリットはすべて最初の2つのステップで行われるためです。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.