忘れかけのIT備忘録

今まで学んできた知識や小技、なるほど!と思ったことをメモするブログです。

Oracleの統計情報(クラスタ化係数編)

今回はOracleクラスタ化係数について調査しました。

Oracleの統計情報 - 忘れかけのIT備忘録で少しだけ触れましたが、クラスタ化係数は索引の列データと表の列データの分布度(データの格納順がどれくらい異なるかの指標)です。
索引の列データに格納されているデータ(キー値)と実際の表の列データに格納されているデータ(キー値)の順番がどれくらい揃っているか、バラツキがあるかを表します。
データの格納順がだいたい揃っている(比較的一致している)場合、クラスタ化係数は小さくなります
データの格納順がほとんど揃っていない(バラツキがある)場合、クラスタ化係数は大きくなります
係数の値によってデータアクセスのオペレーションが変わってきます(係数が小さい場合、TABLE ACCESS BY INDEX ROWIDが採用されやすくなりますが、係数が大きい場合、索引スキャンより全表スキャンの方が効率が良いと判断される可能性があります)
クラスタ化係数は、XXX_IND_STATISTICS、XXX_INDEXESのCLUSTERING_FACTOR列で確認できます。

クラスタ化係数の計算方法
リーフブロックの隣り合ったレコードが、異なる表ブロックの列データへのポインタを持つ場合、カウントアップします
極端に言うとリーフブロックに格納されている列データが異なる表ブロックに格納されている場合、カウントアップするイメージです
あくまで想定ですが参考資料を読むうちに法則みたいなものがあるのではと思いました。

(パターン①)隣接する列データが同じ索引ブロックにあり、同じ表ブロックにある   → カウントアップしない
(パターン②)隣接する列データが同じ索引ブロックにあるが、異なる表ブロックにある → カウントアップする
(パターン③)隣接する列データが異なる索引ブロックにあるが、同じ表ブロックにある → カウントアップしない
(パターン④)隣接する列データが異なる索引ブロックにあり、異なる表ブロックにある → カウントアップする

クラスタ化係数が小さい場合
たとえば下記の図で、EMPNO「1001~1004」の表データにアクセスする場合、合計3ブロックアクセスになります(索引ブロックアクセス:2ブロック、表ブロックアクセス:1ブロック)
クラスタ化係数は「4」になるはずです(トレース表を参照)
→索引スキャン(INDEX XXX SCAN、TABLE ACCESS BY INDEX ROWID)が採用されやすくなります

クラスタ化係数が大きい場合
たとえば下記の図で、EMPNO「1001~1004」の表データにアクセスする場合、合計6ブロックアクセスになります(索引ブロックアクセス:2ブロック、表ブロックアクセス:4ブロック)
クラスタ化係数は「15」になるはずです(トレース表を参照)
→全表スキャン(TABLE ACCESS FULL)が採用されやすくなります(表内の大半のデータにアクセスするため)

■参考資料
https://www.oracle.com/technetwork/jp/ondemand/branch/120328-cbo-1593994-ja.pdf
パフォーマンス改善と事前対策に役立つ Oracle SQLチューニング 本気で学ぶ実践的な考え方とテクニック

■おわりに
クラスタ化係数は小さい方が良いか、大きい方が良いかという疑問も出てきますが(関連資料が見つけられませんでした)、よくよく考えてみるとクラスタ化係数はあくまでオプティマイザが索引スキャンか全表スキャンかの指標にするものなので一概にどちらが良いとは言えないと思いました。(図を描く上では小さい方が助かりますが。。)