SQL Server 2014 では Clusterd Columnstore Index (CCI) が使用できるようになっています。
更新可能な列ストアインデックス (Updatable Columnstore Index) として PDW v2 で実装されていた機能が SQL Server 2014 でも使用できるようになります。
BOL では Columnstore Indexes で解説されています。
MS Resarch の資料も参考になりそうですね。
Enhancements to SQL Server Column Stores
SQL Server 2012 で 非クラスター化列ストアインデックス (Non Clustered Columnstore Index) が使用できるようになり、データの追加であればパーティションのスイッチで実施することができたのですが、それ以外の更新系の処理はできませんでした。
SQL Server 2014 で追加されたクラスター化列ストアインデックス (Clustered Columnstore Index) では、追加 / 更新 / 削除が可能となりました。
作成は新しいインデックスの作成で [Clustered Columnstore Index] から作成することができます。
仕組みとしては以下のようになっています。
基本的な構成は今までの列ストアインデックスと変わらないのですが新たに Deltastore という領域がもたれるようになりました。
この Deltastore を使用して変更があったデータの処理が行われます。
このあたりの考え方は Memory Optimized Table (Hekaton) でも似たような形になるかと。
更新系の処理は、
- INSERT
- UPDATE
- DELETE
になりますが、これらを Deltastore を使用して以下のように処理していきます。
- INSERT : Deltastore にデータをストア
- UPDATE : 元のデータは削除として論理的にマークし、更新後のデータを Deltastore にストア
- DELETE 😕 データを削除として論理的にマーク、Deltastore に存在している場合は削除
このあたりの動作は sys.column_store_row_groups (Transact-SQL) を使うとわかりやすいかと思います。
10,000 件のデータが入っている状態でクラスター化列ストアインデックスを設定した状態が以下になります。
COMPRESSED のデータとして 10,000 行格納されていることが確認できます。
ここに 10,000 行追加してみます。
OPEN な状態の行として 10,000 行追加されたことがわかります。
これが Deltastore に格納された状態となります。
Deltastore としてストアする行数ですが 1M 行 (1,048,576) 単位で管理されているようです。
# 複数セッションで同時に処理をした場合などは 1M 行に達しなくても複数の Deltastore ができるようですが。
ある程度の行数になると [CLOSED] となり、
バックグラウンドジョブにより COMPRESSED となります。
# Memory Optimized Table にも GC によるマージ処理等があったはずです。
次に UPDATE を見てみたいと思います。
以下の状態で全件 UPDATE をしてみます。
[COMPRESSED] の [deleted_rows] が [10,000] になり、Deltastore として [10,000] 追加されていることが確認できます。
既存のデータは論理削除としてマークし、更新後のデータを新規に追加されていることになります。
最後に DELETE を見てみたいと思います。こちらが初期の状態です。
全件削除を実施したところすべてのレコードが [deleted_row] となっていることが確認できます。
Deltastore のレコードに対して削除をした場合は、
Deltastore のレコードが削除されます。
Deltastore はバックグラウンドで適宜圧縮されますが、Deltastore の数が多くなってきた場合には、
再構築 (REBUILD) をすることで最適化できます。
# ONLINE REBUILD はできないようです。
ALTER INDEX [ClusteredColumnStoreIndex] ON [dbo].[MyDimTable] REBUILD PARTITION = ALL WITH (DATA_COMPRESSION = COLUMNSTORE) |
操作としては最構成 (REORGANIZE) もできるようですね。
# こちらは [CLOSED] のものに対しての最適化処理となるようですね。
ALTER INDEX [ClusteredColumnStoreIndex] ON [dbo].[MyDimTable] REORGANIZE WITH ( LOB_COMPACTION = ON ) |
Memory Optimized Tables とは似たような仕組みではありますが、列圧縮の仕組みやどのタイミングでメモリを消費するのかというの違いはあるのかと思います。
この辺のベストプラクティスもそのうち公開されたりしそうですね。