こんにちは。今日は、SQL Serverの列ストアインデックスで登場するColumn EliminationとRow Eliminationという概念について少し調べたので、分かったこと(というか翻訳メモ)を残しておこうと思います。
いずれも公式Docsでは明記されていないような気がしましたが、Microsoftのエンジニアによるブログで言及されていました。ので、今回はそれを読んでみました。
それではまいります。
Column Eliminationとは
Columnstore Index Performance: Column Elimination | Microsoft Docs
- 列ストアインデックスでは、データは列毎に圧縮されて保持されているため、各列へのアクセスは独立している。
- このため、例えば50列を持つテーブルから5列の情報を利用するクエリを発行するような場合、行ストアと異なり最初から5列にだけアクセスすることができる。
- これによって、I/Oや、メモリの大幅な節約ができ、クエリが高速に実行できる。
Row Group Eliminationとは
Columnstore Index Performance: Rowgroup Elimination – Microsoft Tech Community
- Column Eliminationによる工夫に加えて、どのように読み込む行を最小限に抑えるか、という課題もあった。
- 列ストアインデックスにはキーカラムがない。
- ので、範囲述語を使用するクエリで数十億行あるような列ストアインデックスのフルスキャンが必要であればパフォーマンスに大きな影響を与えてしまう。
- 例えば、Factテーブルに過去10年間の売上データがあり、現在の四半期の売上分析に関心があるとき、テーブル全体をスキャンするより最後の四半期のデータのみスキャンすれば、I/Oとクエリ効率が97.5%削減できる。
- 行ストアの場合、例えばSalesDate列にクラスタ化インデックスを作成すれば簡単に上記が実現できるが、列ストアの場合はどうすればよいだろう?
- 一つの案は、SalesDateをキーにテーブルをパーティション化して、パーティションへのアクセスに限定すること。ただ、パーティションが大きな場合、この中でさらに地域で絞る、となると問題が残る。(行ストアの場合、SalesDateでパーティション化した上で、地域でクラスタ化インデックスを作成することで解消できる)
- 上記例から分かるように、列ストアインデックスでは、データが適切にソートされていないと必要以上に多くの行をスキャンする必要があり、非効率。
- SQL Server 2016では、NCI(非クラスター化列ストアインデックス)を利用してこの問題に対処できる可能性があるが、対象行数が少ない場合に限られている。
- この問題を解決するのが、Row Group Elimination。
- 列ストアインデックスでは以下のように行グループ(最大100万行)の単位で行を区切り、その単位で列データを圧縮した列セグメントを保持しているが、SQL Serverではこの各列セグメントの最大・最小値をメタデータとして保持することで、クエリ時に必要な行グループに絞ったアクセスを可能にしている。(Row Group Elimination)
- 先ほどの売上データの例だと、行はSalesDate順に挿入され、列セグメント毎に最大値/最小値をもっているため、要求された日付範囲(現在の四半期)を含む行グループを簡単に特定でき、その行グループへのアクセスのみを行うことができる。
- さらに地域で絞り込みをかける必要がある場合は、列ストアインデックスをSalesDateで分割し、地域でソートした後に地域でパーティション化すればよい。
以上、簡単ですがRow Group EliminationとColumn Eliminationの概要まとめでした。
こうした工夫によって列ストアインデックスが効率的にクエリを処理することができるのですね。勉強になりました。
おしまい
コメントを残す