達人に学ぶDB設計 徹底指南書 ch6 データベースとパフォーマンス
データベースのパフォーマンスを決める要因
インデックス
統計情報
- SQL: ユーザはデータを「how」ではなく「what」で指定する
- かつて: 「ルールベース」
- エンジニアがある程度「how」を指定
- 現在: 「コストベース」
- DBMS任せ
- 統計情報
- 最短経路を知るための「地図」にあたる
インデックス設計
- 特徴
- アプリケーション透過的
- インデックスを使用するかどうかはDBMSが自動的に判断
- アプリケーションプログラムの変更がない
- cf. 非正規化はアプリケーション大改修不可避
- データ透過的
- データが影響を受けることはない
- 論理設計に撥ねることもない
- 性能改善の効果が大きい
- 性能がデータ量に対して線形よりも緩やかにしか劣化しない
- とはいえ闇雲に作っても駄目
- アプリケーション透過的
まずはB-treeインデックスから
- インデックスにもいろいろ
- B-treeインデックス
- ビットマップインデックス
- ハッシュインデックス
- オールラウンダーB-tree
B-treeインデックスの長所
B-treeインデックスはオール4の秀才
- 均一性
- 各キー値の間で検索速度にバラツキが少ない
- 持続性
- データ量の増加に対してパフォーマンス低下が少ない
- 処理汎用性
- 検索、挿入、更新、削除のいずれの処理そこそこ速い
- 非等値性
- 等号(=)に限らず、不等号(< > <= >=)を使ってもそこそこ速い
- 親ソート性
- 暗黙のソートが発生する処理を高速化できる
- GROUP BY
- ORDER BY
- COUNT/MAX/MIN
- 暗黙のソートが発生する処理を高速化できる
B-treeインデックスの構造
- 均一性
- B-treeが平衡木だから
- 挿入、更新、削除等が繰り返されると非平衡木になっていくことがある
- B-treeが平衡木だから
- 持続性
O(log n)
- cf. フルスキャンは
O(n)
- 処理汎用性
- 挿入、更新、削除も
O(log n)
- cf. ビットマップインデックスは検索は速いが更新が遅い
- 挿入、更新、削除も
- 非等値性
- 検索木だから「右」とか「左」とかに絞れる
<>
とかは速くならない
- 親ソート性
- 木構造自体がソート済のようなもの
- ソートをスキップできる
- 特にファイルソートのI/Oコストは甚大なので効果大
B-treeインデックスの設計方針
B-treeインデックスはどの列に作れば良いか?
- 大規模テーブル
- カーディナリティの高い列
- WHERE句の選択条件、結合条件に使用されている列
B-treeインデックスとテーブルの規模
データ量が少ない場合はインデックスの効果はない
- 前述の通り、B-treeインデックスの性能劣化のオーダーはCRUDすべて
O(log n)
n
が小さいとO(n)
のフルスキャンのほうが早かったりする- どれくらい
- 1万件が目安
B-treeインデックスとカーディナリティ
カーディナリティが高い列ほどインデックスの効果が高い。ただし、値が平均的に分散しているのがベスト
- カーディナリティ
- 特定の列の値がどれくらいの種類の多さをもつか
- カーディナリティが低い例
- 性別(カーディナリティ3)
- 男性
- 女性
- 不詳
- 1/3=33%程度にしか絞れない
- 性別(カーディナリティ3)
- カーディナリティが高い例
- 営業日(カーディナリティ200くらい)
- 1/200=0.5%にまで絞れる
- 5%程度には絞れること
カーディナリティの注意点
- 順番
- 複合列(a,b,c)
- a,b,cそれぞれカーディナリティ2,5,10だとする
- 組み合わせると
1/(2*5*10)=1%
程度に絞りこめる
- データの分布
- 1-100の値をとるが、値の99%は100であるようなケース
- 検索性能は安定しない
B-treeインデックスとSQL
- 効かないケースに気をつける
- 演算NG
- NULLは可搬性失う
- 否定形NG
- ORはNG
- INはOK
- 前方一致以外のLIKE述語
- 暗黙の型変換
B-treeインデックスに関するその他の注意事項
- 自動で作成されるからわざわざ作成しなくていいケース
- 主キー
- 一意制約
- B-treeインデックスは更新性能を劣化させる
- 極力無駄に作らない
- 定期的なメンテナンスをすることが望ましい
- 木が崩れていく
- 崩れ具合の指標値(断片化率、木の高さ等)と調査方法はDBMSによる
- マニュアルで調べよ
統計情報
オプティマイザと実行計画
統計情報の設計指針
統計情報収集のタイミング
データが大きく更新された後、なるべく早く
統計情報収集は原則、夜間帯に実施する
- 更新: INSERT/UPDATE/DELETE
- レコード件数増減
- データ分布・偏りの変化
- 大規模更新の後は「地図が古い」状態になる
- 地図の更新が必要
- リソース大量消費
- 長時間かかる
- 日中はオンライン処理の性能を劣化させるので避けよ
統計情報収集の対象(範囲)
- 統計情報収集は高負荷
- なので不要なテーブルは含めない
- CRUD表などで整理する
- 一時テーブルに注意
- INSERT後に統計情報収集しないといけない
統計情報の凍結について
統計情報の凍結は、オプティマイザを信じない悲観的設計。
しかし現実に実施するのはかなり大変
- データ量の増加に伴って実行計画は変化する
- これによりパフォーマンスが劣化することは珍しくない
- 実行計画を現状のものから実行計画を変化させたくない場合に統計情報を凍結する
- システムのサービス終了時のデータを想定した状態での統計情報を用意
- 「サービス終了時のデータ」を想定して用意するのは大変なので断念することも多い