1 GBのデータを含む1000万行のテーブルで、同じ更新クエリを頻繁に実行するサードパーティソフトウェアがあります。
(@P1 bigint,@P2 bigint,@P3 bigint,@P4 bigint,@P5 bigint)
UPDATE top(1000) hsi.hspendingitems
SET status = @P1
WHERE handlertype = @P2
AND status in (@P3,@P4,@P5)
クエリ1プラン:
https://www.brentozar.com/pastetheplan/?id=Syv7OxRHW
クエリIO統計
Table 'hspendingitems'. Scan count 9, logical reads 1686, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
次に、インデックスを追加しました。
CREATE NONCLUSTERED INDEX [ix_test_dba] ON [hsi].[hspendingitems]
(
[handlertype] ASC,
[status] ASC
)
WITH
(
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
)
ON [DBSpace8]
クエリ2プラン:https://www.brentozar.com/pastetheplan/?id=S1yjulAS-
クエリ統計:
Table 'hspendingitems'. Scan count 1, logical reads 10253, physical reads 20, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Serverが行うスキャンは少ないが、論理的な読み取りは多い方が良いですか?
コストプランも異なることに気づきました。
初期コスト102.937 vsインデックスあり0.0232853?
ベンダーはそのインデックスを追加することを認識していますが、そのインデックスを追加するためにベンダーに何をプッシュすればよいと思いますか?
IOクエリの統計情報を比較する場合、コンテキストは重要です。まず、クエリがプランに基づいて何を実行するかを説明することから始めましょう。
最初のクエリは、更新が必要な1000行が見つかるまでヒープを並行してスキャンします。次に、テーブルに対して更新が実行されます。パフォーマンスの最悪のシナリオでは、テーブル全体をスキャンする必要があります。
2番目のクエリは、更新が必要な1000行が見つかるまでインデックスシークを実行します。インデックスの列を変更しているため、テーブルデータとインデックスの両方を更新する必要があります。クエリのコストが非常に低いため、並列処理の対象にはなりません。
ここで、IO統計に戻って、それらがより意味があるかどうかを確認します。最初のクエリの場合:
テーブル 'hspendingitems'。スキャンカウント9、論理読み取り1686、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
スキャンカウント9は、クエリがDOP 8で実行されたことを意味します。論理読み取りカウントは、最初の1000行を見つけるために必要な読み取り数と、テーブルのデータを更新するために必要なアクティビティを表します。 UPDATEクエリは1000行しか更新しないため、ループで実行されると想定しています。クエリを実行すると、SQL Serverが更新する次の1000行を見つけるためにテーブルをさらにスキャンする必要があるため、論理読み取り数が増える可能性があります。
2番目のクエリの場合:
テーブル 'hspendingitems'。スキャンカウント1、論理読み取り10253、物理読み取り20、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
クエリは並行して実行されないため、スキャンカウントは1です。作成した非クラスター化インデックスは別のオブジェクトとして保存されるため、テーブルとインデックスのデータの両方を更新する必要があります。クエリがループで実行されるとき、このクエリのパフォーマンスはほぼ一定のままであると期待します。
インデックスを作成する必要がありますか?場合によります。現在のコードでパフォーマンスの問題はありますか?インデックスはパフォーマンスの問題を最善の方法で解決しますか?インデックスの恩恵を受けることができる他のクエリはありますか?インデックスにより、テーブルの他のDMLの処理速度が低下しすぎますか?これらの質問にお答えすることはできませんが、ループ内のインデックス付けされていないヒープに対して1000行を更新することは、パフォーマンスの点で適切な戦略ではない場合が多いと言います。