一意のインデックスの更新と統計行の変更カウンター


14

次の表、一意のクラスター化インデックス、および統計情報が与えられます。

CREATE TABLE dbo.Banana
(
    pk integer NOT NULL, 
    c1 char(1) NOT NULL, 
    c2 char(1) NOT NULL
);

CREATE UNIQUE CLUSTERED INDEX pk ON dbo.Banana (pk);

CREATE STATISTICS c1 ON dbo.Banana (c1);
CREATE STATISTICS c2 ON dbo.Banana (c2);

INSERT dbo.Banana 
    (pk, c1, c2) 
VALUES 
    (1, 'A', 'W'), 
    (2, 'B', 'X'), 
    (3, 'C', 'Y'), 
    (4, 'D', 'Z');

-- Populate statistics
UPDATE STATISTICS dbo.Banana;

サンプルデータ

統計行の変更カウンターは、更新前に明らかにゼロを示します。

-- Show statistics modification counters
SELECT
    stats_name = S.[name], 
    DDSP.stats_id,
    DDSP.[rows],
    DDSP.modification_counter
FROM sys.stats AS S
CROSS APPLY sys.dm_db_stats_properties(S.object_id, S.stats_id) AS DDSP
WHERE
    S.[object_id] = OBJECT_ID(N'dbo.Banana', N'U');

ゼロ修正カウンター

pk行ごとに各列の値を1 ずつ増やします。

-- Increment pk in every row
UPDATE dbo.Banana 
SET pk += 1;

実行計画を使用します。

分割ソート折りたたみ実行プラン

次の統計変更カウンターを生成します。

更新後の変更カウンター

ご質問

  1. Split、Sort、Collapse演算子は何をしますか?
  2. なぜpk統計が2つの修正を示すが、c1およびc25を表示?

回答:


15

SQL Serverは、複数の行に影響する(または影響する可能性のある)更新の一部として一意のインデックス維持する場合、常に演算子の分割、並べ替え、および折りたたみの組み合わせを使用します。

質問の例を使用して、存在する4行ごとに個別の単一行更新として更新を記述できます。

-- Per row updates
UPDATE dbo.Banana SET pk = 2 WHERE pk = 1;
UPDATE dbo.Banana SET pk = 3 WHERE pk = 2;
UPDATE dbo.Banana SET pk = 4 WHERE pk = 3;
UPDATE dbo.Banana SET pk = 5 WHERE pk = 4;

それは変化するので問題は、最初のステートメントが失敗することがあるpk1から2まで、及び行既に存在するpk= 2ザSQL Serverストレージエンジンは一意のインデックスがあっても、単一のステートメント内、処理の各段階で一意のままである必要が。これは、分割、並べ替え、および折りたたみによって解決される問題です。

スプリット スプリット

最初のステップは、各更新ステートメントを削除に続いて挿入に分割することです。

DELETE dbo.Banana WHERE pk = 1;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');

DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');

DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');

DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');

Splitオペレーターは、アクションコード列をストリームに追加します(ここではAct1007とラベル付けされています)。

分割プロパティ

アクションコードは、更新の場合は1、削除の場合は3、挿入の場合は4です。

ソート ソート

上記の分割ステートメントは依然として一時的な一意のキー違反を生成するため、次のステップは、更新される一意のインデックスのキー(pkこの場合)、アクションコードの順にステートメントを並べ替えることです。この例では、これは単に、同じキーの削除(3)が挿入(4)の前に順序付けられることを意味します。結果の順序は次のとおりです。

-- Sort (pk, action)
DELETE dbo.Banana WHERE pk = 1;
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');

プロパティを並べ替える

崩壊 崩壊

前の段階は、すべての場合において誤った一意性違反の回避を保証するのに十分です。最適化として、Collapseは同じキー値の隣接する削除と挿入更新に結合します

-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');

pk値2、3、および4 の削除/挿入ペアは更新に結合され、pk1 つの削除= 1、およびpk= 5の挿入を残しています。

Collapse演算子は、キー列で行をグループ化し、アクションコードを更新して、折りたたみの結果を反映します。

プロパティを折りたたむ

クラスター化インデックスの更新 クラスター化インデックスの更新

この演算子には「更新」というラベルが付いていますが、挿入、更新、削除が可能です。行ごとにクラスター化インデックス更新によって実行されるアクションは、その行のアクションコードの値によって決まります。オペレーターには、この操作モードを反映するActionプロパティがあります。

クラスター化インデックスの更新アクションのプロパティ


行修正カウンター

上記の3つの更新は、保持されている一意のインデックスのキーを変更しないことに注意してください。実際には、インデックス内のキー列の更新を、非キー列(c1およびc2)の更新に加えて、削除と挿入に変換しました。削除も挿入も、誤った一意キー違反を引き起こすことはありません。

挿入または削除は、行内のすべての列に影響を与えるため、すべての列に関連付けられた統計の修正カウンターは増分されます。更新の場合、(値が変更されていない場合でも)更新された列のいずれかが先行列である統計のみの変更カウンターが増分されます。

したがって、統計行変更カウンターは、に2つの変更を表示しpkc1c2

-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;                         -- All columns modified
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;  -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;  -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;  -- c1 and c2 modified
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');    -- All columns modified

注意:ベースオブジェクト(ヒープまたはクラスター化インデックス)に適用される変更のみが、統計行の変更カウンターに影響します。非クラスター化インデックスは、ベースオブジェクトに既に加えられた変更を反映する二次構造です。これらは統計行変更カウンターにはまったく影響しません。

オブジェクトに複数の一意のインデックスがある場合、個別の分割、並べ替え、折りたたみの組み合わせを使用して、それぞれの更新を整理します。SQL Serverは、スプリットの結果をEager Table Spoolに保存し、一意のインデックスごとにそのセットを再生することで、非クラスター化インデックスに対してこのケースを最適化します(インデックスキーによる独自の並べ替え+アクションコード、および折りたたみ)。

統計更新への影響

自動統計更新(有効な場合)クエリオプティマイザは、既存の統計があることを統計情報や通知を必要とするときに発生する日付のうち(またはスキーマの変更により無効。記録された変更の数がしきい値を超えると、統計は古くなったと見なされます。

Split / Sort / Collapseの配置により、予想とは異なる行の変更が記録されます。これは、統計の更新が遅かれ早かれトリガーされる可能性があることを意味します。

上記の例では、キー列の行の変更は、4(影響を受けるテーブル行ごとに1つ)または5(折りたたみによって作成された削除/更新/挿入ごとに1つ)ではなく2(正味の変更)ずつ増加します。

さらに、元のクエリによって論理的に変更さなかった非キー列は、更新されたテーブル行の2倍(削除ごとに1回、挿入ごとに1回)の行修正を蓄積します。


記録される変更の数は、古いキー列の値と新しいキー列の値との重なりの程度(したがって、個別の削除と挿入を折りたたむことができる程度)に依存します。各実行間でテーブルをリセットすると、次のクエリは、重複が異なる行変更カウンタへの影響を示します。

UPDATE dbo.Banana SET pk = pk + 0; -- Full overlap

pk = pk + 0

UPDATE dbo.Banana SET pk = pk + 1;

pk = pk + 1

UPDATE dbo.Banana SET pk = pk + 2;

pk = pk + 2

UPDATE dbo.Banana SET pk = pk + 3;

pk = pk + 3

UPDATE dbo.Banana SET pk = pk + 4; -- No overlap

pk = pk + 4

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