はじめに
第2回はデータの位置を高速に特定するデータ構造で最もよく使用される索引について説明しました。索引はクエリーがアクセスするデータ量がごく少数の場合に効果の高いデータ構造です。しかし、クエリーがごく少数のデータにアクセスする場合と、大量のデータにアクセスする場合で最適なアルゴリズムとデータ構造は異なります。第3回は大量のデータにアクセスする場合に範囲を限定するデータ構造であるパーティショニングについて見ていきます。
なお、本連載で例として挙げるデータベースはオラクルが提供しているものが多いですが、オラクル製品を使っていない方にも参考にしていただけるように解説していきます。
対象読者
この連載では以下の読者を想定しています。
- データ資産を活用する、新しいアプリケーションの構想や設計を担われる方
- データ基盤の運用を担われている方や、今後検討される方
- 新たに開発するアプリケーションの、最適なデータベースをお探しの方
- 目的別データベースから、価値ある情報を素早く引き出す検討をされている方
データの位置を範囲で絞りこむ
索引はデータの値とデータ本体へのポインタの組をもちますが、索引を全件検索することなく値を特定することができます。索引経由のアクセスは全表走査よりもアクセスするブロック数を減らすことで1つのデータの位置を高速に特定することができます。しかし、集計や分析処理のような多数のデータにアクセスする場合、索引経由のアクセスよりも全表走査するほうが高速になるときがあります。全表走査する場合にアクセスするブロック数を減らす方法はないでしょうか。それがパーティショニングというデータ構造です。
パーティショニングは、ある列の値が満たす条件を設定し、その条件を満たす行データの集合(パーティション)をストレージ上で区分するというアイデアです。クエリーの検索条件が合致するパーティションにのみアクセスすることで、アクセスする範囲が表の全ブロックから特定パーティションの全ブロックに減ります。Oracle Databaseではパーティションのグループを定義するアルゴリズムはいくつかあります。主なものは次の3つです。
- レンジ:列の値の範囲(主に時刻)
- リスト:列の値の即値(文字列や離散的な値)
- ハッシュ:列の値をハッシュしたハッシュ・バケット(各パーティションに均等に分散させる)
一般的に、データベースに記録されるデータは時刻の情報を持っていることが多く、サイズが大きくなる表は主に「いつ、なにが行われた」の履歴データです。このようなデータは後で分析や集計処理にかけられます。分析や集計処理は「1か月ごとの売り上げ」のように時間の範囲を指定することが頻繁にあります。ここで、パーティショニングで区分する単位を頻繁に実行される分析や集計のクエリーのアクセス範囲に合わせておくと、クエリーがアクセスする範囲が特定のパーティションに限定されます。そのため、パーティショニングのグループを指定するアルゴリズムで最も使用されているのが列の値の範囲を定義するレンジ・パーティションです。
クエリーのSQL実行計画が特定のパーティションにしかアクセスしないことをパーティション・プルーニングといいます。
データ量が急速に拡大していく表はほとんどの場合、時刻の情報を持つ履歴データです。このような表を時刻の列でレンジ・パーティションしておくと、時刻の範囲を指定したクエリーのアクセス範囲が限定されます。これは単にクエリーが高速になるというだけでなく、処理時間が表全体のサイズ増加の影響を受けないという効果もあります。
パーティショニングの実装
パーティショニングを実現するための内部実装にはいくつか種類があります。その代表的なものを見ていきます。
- (1)複数の表を連結する
- (2)1つの表を分割する
これはパーティション表を定義するCREATE TABLE文の構文の話ではありません。データのパーティショニングをどうやって実現するかのデータ構造の実装の話です。
Oracle Databaseで初めてパーティション表が実装されたのはOracle8で、これは(2)1つの表を分割する実装です。実はその1つ前のOracle7では複数の表を使ってレンジ・パーティションを実現するパーティション・ビューという機能がありました。パーティション・ビューは(1)複数の表を連結する実装です。Oracle7の複数の表を連結する実装には問題があったのでOracle8で1つの表を分割する実装に作り直された[*1]のですが、何が問題だったのでしょうか。まずOracle7パーティション・ビューの実装を見ていきます。
[*1] パーティション・ビューを実装したOracle7.2は1995年、パーティション表を実装したOracle8は1997年です。