OLTP 的な、1件更新について書きます。
sys.internal_partitions と sys.column_store_row_groups で見ると更新処理の動きが見えてきます。
以降このクエリで情報を見ていきます。
-- <tablename> は適宜読み替えてください。 -- internal_partition select object_name(object_id), internal_object_type, internal_object_type_desc, row_group_id, rows from sys.internal_partitions where object_name(object_id) = '<tablename>' order by object_id, internal_object_type -- column_store_row_gourps select object_name(object_id), row_group_id, state, state_description, total_rows, deleted_rows, size_in_bytes from sys.column_store_row_groups where object_name(object_id) = '<tablename>' order by object_id, row_group_id
クラスター化列ストアインデックス Clustered Columnstore Index (CCI) について
2014 から変わったという記述を見つけれなかったので、多分 2014 と同じ。
クラスター化列ストア インデックスの使用
ざっくりとした動きはこちら
- INSERT
- デルタストアに INSERT
- DELETE
- 削除ビットマップ を立てる
- UPDATE
- 列ストアにデータがあるときは、上の DELETE、INSERT の操作
- デルタストアにデータがあるときは、UPDATE
実際に試してみましょう。
まず更新前の状態です。200万行が列ストアとして圧縮済です。
INSERT
insert into cci (c1) values (-1)
internal_partitions には、COLUMN_STORE_DELTA_STORE が追加されていますね。
column_store_row_gourps には、OPEN な新しい行グループが増えて、そこに1行追加されたのがわかります。
DELETE
delete from cci where c1 = 1000000
COLUMN_STORE_DELETE_BITMAP の rows が 1になり、
データがいたと思われる行グループは、deleted_rows が 1 になりました。
UPDATE
update cci set c2 = 100 where c1 = 1000
DELETE と INSERT の動きを合わせた結果になってますね。
最後に、デルタストアにある行を DELETE してみます。
delete from cci where c1 = -1
これは、デルタストアの行が減ってることが確認出来ます。
非クラスター化列ストアインデックス Nonclustered Columnstore Index (NCCI) について
- INSERT
- デルタストアに INSERT
- DELETE
- 削除バッファに INSERT
- UPDATE
- DELETE、INSERT の操作(デルタストアにあっても UPDATEしない。*1 )
NCCI の場合は、削除ビットマップ ではなく、削除バッファーに行くのが違いですね。
削除バッファーから削除ビットマップへの変換は、バックグランドで定期的に行われるか、インデックスのメンテナンスのタイミングになります。
こちらも実際に試してみましょう。
まず更新前の状態です。200万行が列ストアとして圧縮済です。
CCI との違いは、COLUMN_STORE_DELETE_BUFFER があることですね。
INSERT
insert into ncci (c1) values (-1)
CCI と同様の動きですね。
DELETE
delete from ncci where c1 = 1000000
CCI とは異なり、COLUMN_STORE_DELETE_BUFFER の rows が 1になり、DELETE_BITMAP の方は変化なしです。
行グループも、deleted_rows が増えていません。
UPDATE
update ncci set c2 = 100 where c1 = 1000
CCI と同様、DELETE と INSERT の動きを合わせた結果になってますね。
CCI と違うのは、DELETE が DELETE_BUFFER に入るとこです。
デルタストアにある行を DELETE してみます。
delete from ncci where c1 = -1
CCI と同様の動きですね。
最後は インデックスのメンテナンスをしてみましょう。
alter index ncci_index ON ncci REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON);
DELETE_BUFFER から DELETE_BITMAP に変換されてますね。
DELETE_BITMAP に変換されたので、deleted_rows の値が増えてます。
あとは OPEN だった行グループが圧縮されて、新しい行グループになり、圧縮前のデルタストア(行グループ)は廃棄(TOMBSTONE)状態になりました。
TOMBSTONE の行グループはしばらくすると消えてなくなります。
フィルター付き NCCI
NCCI は、フィルター条件を付けれるので、フィルターの条件にマッチする行の追加/更新/削除 は上と同じ動きをしますが、
フィルターの条件外の行の場合は、列ストアインデックスでは無いので列ストアとしての更新処理は行われません。
*1:解釈間違ってたらゴメン原文:There is no in place update even when the row is found in delta rowgroup.