Exadata Hybrid Columnar Compression に関する検証 その4

投稿日: 2010年1月27日

<Exadata Hybrid Columnar Compression に関する検証 その4>
ペンネーム: ベロ

前回より引き続き、Hybrid Columnar Conpressionの検証を実施していきます。
前回、Columnarたる所以をダンプから発見することは出来ませんでした。

CU(Compression Unit)と呼ばれる圧縮単位はOracle Block単位ではなく、複数
のOracle Blockをまたがった単位であることは分かりました。

しかしながら、CUの中身がどのような構造になっているのか、検証することが
できません。あまり、ここにこだわっていても埒があかないので、物的証拠を
探すよりも状況証拠を集める方針に切り替えることにします。

1. カラム単位で圧縮することで、パフォーマンス(Query)がどう変わるのか?
カラム単位で圧縮と言うと、カラム単位で別領域(別Block)にデータを格納
して、Queryアクセスもカラム単位でアクセスするのではないか?
そうすると、SELECT句の書き方で、パフォーマンスが大きく異なるのでは?
と想像できます。

以下、全カラムを選択 vs. 単一カラムを選択で、パフォーマンスがどう
変化するのか検証してみます。

ここで、有意な変化があるのなら、CUの中の”カラム単位”のブロックへの
アクセスをしているのではないかと推察できます。

全カラムを選択)

SELECT * FROM ARCHIVE_HIGH_COMPRESS_TABLE;

単一カラムを選択)

SELECT CUST_EMAIL FROM ARCHIVE_HIGH_COMPRESS_TABLE;

先ず経過時間から

全カラムを選択)

経過: 00:08:01.96

単一カラムを選択)

経過: 00:03:56.84

なるほど、経過時間は、全カラム選択時と比較して、約半分に減少しました。
ということは、CUの内部ではカラム単位でデータアクセスしていると言える。
いやいや、それだけでは何とも言えません。
経過時間と共に統計情報を見てみます。

全カラムを選択)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
1211607 consistent gets
^^^^^^^ ^^^^^^^^^^^^^^^
204487 physical reads
^^^^^^ ^^^^^^^^^^^^^^
0 redo size
961889541 bytes sent via SQL*Net to client
^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13011128 bytes received via SQL*Net from client
1182794 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
17741894 rows processed

単一カラムを選択)

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
1199592 consistent gets
^^^^^^^ ^^^^^^^^^^^^^^^
342135 physical reads
^^^^^^ ^^^^^^^^^^^^^^
0 redo size
480834823 bytes sent via SQL*Net to client
^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13011128 bytes received via SQL*Net from client
1182794 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
17741894 rows processed

統計情報をみると、全カラム選択時も単一カラム選択時もconsistent gets
およびphysical readsに大きな変化は見られません。
唯一、bytes sent via SQL*Net toclientが、約半分になっています。
これは、経過時間が半分になったことと相関してます。

つまり、Columnarと言えども、内部的にカラム単位でアクセスするような動作
ではないのではないと思われます。それは、低レベルのブロックアクセスがカ
ラム単位の有無で変化がないことから想像できます。

では、なぜ、経過時間が約半分に減少したのでしょうか?
それは、上記で触れたbytes sent via SQL*Net to clientに関係します。
クライアントに返したデータ量が半分になったのです。それは、圧縮してある
データの展開量が半分になったと推定できます。

要は、Hybrid Columnar Compressionでは、データをクライアントに返す直前
に必要なデータの展開を行っているということです。

圧縮データの展開処理は、データをクライアントに返す直前に行う。となると
WHERE句の処理はどうなるのか?と疑問が湧いてきます。

2. WHERE句の有無でパフォーマンス(Query)に変化があるのか?
WHERE句の有無で、パフォーマンスが大きく異なる場合、データの展開処理の
場所と頻度が異なる可能性が高い。
以下、WHERE句の無いSQLと有るSQLでパフォーマンスを計測してみます。

WHERE句無し)

SELECT CUST_EMAIL FROM ARCHIVE_HIGH_COMPRESS_TABLE;

WHERE句有り)

SELECT CUST_EMAIL FROM ARCHIVE_HIGH_COMPRESS_TABLE WHERE CUST_EMAIL like
'%@%';

以下、経過時間と統計情報です。

WHERE句無し)

経過: 00:03:56.84

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
1199592 consistent gets
342135 physical reads
0 redo size
480834823 bytes sent via SQL*Net to client
13011128 bytes received via SQL*Net from client
1182794 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
17741894 rows processed

WHERE句有り)

経過: 00:03:58.86

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
1199592 consistent gets
342135 physical reads
0 redo size
480834823 bytes sent via SQL*Net to client
13011128 bytes received via SQL*Net from client
1182794 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
17741894 rows processed

WHERE句の有無でパフォーマンスに有意な差は見られません。つまり、WHERE句
の処理は、通常(非圧縮データ)のように、データブロックを検索して結果を
得るのではなく、どこか別のメタデータ(一種のインデックス)を使用して
いるのではないかと推察されます。
このメタデータを経由して、実データへアクセスすることで展開処理がなく
ても(オーバーヘッドを最小化して)検索が実行できるものと思われます。

ではでは、メタデータにはどんなものがあるのでしょうか?
これは、現在のところ想像の域を出ませんが、きっと、圧縮前のデータと
それを使用しているROW、(もしくはカラム)へのポインタ情報ではないか?

ではでは、実データにアクセスしない(と思われる)方法、つまりメタデータ
のみアクセス出来そうなものは何か?
きっとCOUNT(*)系のアクセスだと、メタデータ+そのポインタのみのアクセス
で完了して、実データへはアクセスしなくて良い可能性が高い。

3. メタデータにはどんなデータを管理しているのか?
また、メタデータだけのアクセスが可能なのか?

以下のSQLを実行してみます。

SELECT COUNT(*) FROM ARCHIVE_HIGH_COMPRESS_TABLE;

メタデータが先程、筆者が想像したような構造になっている場合、実データ
へのアクセスは行わず、メタデータから必要なポインタ計算のみ実行すること
でアクセスは相当高速化されるはずです。

経過: 00:00:00.95

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
15927 consistent gets
^^^^^ ^^^^^^^^^^^^^^^
15898 physical reads
^^^^^ ^^^^^^^^^^^^^^
0 redo size
448 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

思った通りです。先程のCOUNT(*)でないSQLの場合、consistent gets +
physical reads で1416094となっていましたが、今回のCOUNT(*)では31825
と大幅に減少しています。また、経過時間も1秒未満となっています。

つまり、メタデータの大きさはこの31825 block(未満)程度の大きさでは
ないかと大まかに推測できます。

ちなみに、COUNT(*)ではなく、カラム名を入れてCOUNTを取得すると以下
のようになりました。

SELECT COUNT(CUST_EMAIL) FROM ARCHIVE_HIGH_COMPRESS_TABLE;

経過: 00:00:09.37

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
16842 consistent gets
^^^^^ ^^^^^^^^^^^^^^^
17738 physical reads
^^^^^ ^^^^^^^^^^^^^^
0 redo size
457 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

COUNT(*)と比較すると、consistent gets や physical readsに大きな変化は
ありませんが、経過時間が大きく異なります。

これは、メタデータから、COUNT(*)のようなカラム情報がないものを検索する
より、カラム情報を特定するオーバーヘッドがかなり高いと想像できます。

ということで、今回の検証はこの辺にしておきます。今回の検証は想像を含め
た状況証拠を見てみることに集中しました。その中で、以下のようなことが言
えると思われます。

1. Hybrid Columnar Compressionの最小アクセス単位はCUであり、Columnarと
言っても、Column単位でのアクセスではないと思われる
2. 圧縮データの展開はクライアントのデータを返す直前であり、圧縮データ
の検索はメタデータを使用しているに違いない
3. そのメタデータからカラムデータを特定するオーバーヘッドは、結構高い
と思われる

ちょっと春の兆しが感じられる 恵比寿より