インデックス・格納方式と性能
インデックスの目的、B木・B+木とハッシュの違い、ハッシュ値の理想的な分布、ソートマージ結合、再編成の目的を区別して、科目Aの4択で正しい選択肢を選べるようになる。
DBは件数が増えると遅くなります。遅くなったときに「インデックスを足す」「インデックスの種類を選ぶ」「定期的に再編成する」の3つで性能を保つ考え方は、試験でも実務の性能トラブルの会話でも基本になります。
このレッスンで稽古する(用語チェック・過去問)結論:このレッスンの地図
DBの性能の話は、どう探すか(インデックス)、どう結合するか(結合方式)、**どう保つか(再編成)**の3つに分かれます。
| 悩み | 打ち手 | 試験のキーワード |
|---|---|---|
| 検索が遅い(全件を読んでいる) | 検索条件に合うインデックスを追加 | 格納位置へ効率的にアクセス |
| 範囲・前方一致で探したい | B+木インデックス | 深さが均一・log X |
| 「=」でピンポイントに探したい | ハッシュインデックス | 等価検索・衝突(シノニム) |
| 2つの表をつなぎたい | 結合方式を選ぶ | ソートマージ=並べ替えて先頭から突き合わせ |
| 更新を繰り返して遅くなった | 再編成 | アクセス効率の回復 |
インデックスの目的:本の索引と同じ
インデックス(索引)は、列の値から「そのデータがどこに格納されているか」へ直接たどるための仕組みです。目的は検索速度の向上で、全件を先頭から読む(全件走査)のを避けます。本の巻末索引で「正規化 → p.120」と引けば、全ページをめくらずに済むのと同じです。
検索のたびに全レコードを読んでいて遅いなら、検索条件に使っている列にインデックスを追加するのが最も効く対策です。領域を広げても、DBMSを入れ直しても、読む件数は減らないので速くなりません。
代わりに、データを追加・更新・削除するたびにインデックスも更新されるので、更新処理は少し重くなり、格納領域も増えます。
| 仕組み | 目的 | 混同しやすい点 |
|---|---|---|
| インデックス | 検索を速くする | 値の正しさは守らない |
| 外部キー制約 | 別の表の主キーに存在する値だけを許す | 「別の表と一致させる」はこちら |
| 一意制約(UNIQUE) | 列の値の重複を禁止する | 「重複させない」はこちら |
| 表の分割格納 | 大きな表を複数のディスクに分けて置く | 容量の節約が目的ではない |
B木・B+木:深さがそろった木
B木は、1つのノード(節)が多くの子を持つ木(多分木)で、すべての葉が同じ深さになるように、ノードの分割と併合を行う平衡木です。データが偏って増えても木が片側だけ深くならないので、どのキーを探してもかかる手間がほぼ同じになります。
B+木はB木の改良版で、データ(またはデータへの位置)を葉にだけ持ち、葉どうしを順につないでいます。そのため、1件を探すときは根から葉へ下り、範囲で探すときは葉を横にたどります。
1件を探すときのノードのアクセス回数は木の深さと同じで、データ件数Xに対して log X のオーダ(件数が10倍になっても回数は少し増えるだけ)です。全件走査は X のオーダです。
| ファイル編成・構造 | 特徴 | 試験での説明文 |
|---|---|---|
| B木 | 平衡な多分木 | 階層の深さが同じになるよう分割・併合 |
| ハッシュ法(直接編成) | 関数で格納位置を計算 | キー値から関数で格納位置を求める |
| 順編成ファイル | 先頭から順に並べる | 先頭からの順次アクセスだけ |
| 区分編成ファイル | 登録簿+メンバ | メンバは順編成ファイル |
ハッシュインデックスとB+木の使い分け
ハッシュインデックスは、キー値をハッシュ関数(値を決まった計算で番地に変える関数)に入れて格納位置を求めます。「=」で1つの値を探す等価検索に最も強いです。
一方、ハッシュ値は元の値の大小や並び順を保たないので、「1万円以上」「今月」のような範囲検索や、「'DB'で始まる」のような前方一致検索には使えません。これらは値が順に並んでいるB+木が向いています。
| 検索条件の形 | 例 | 向くインデックス |
|---|---|---|
| 等価(=) | 利用者ID = '1001' | ハッシュ(B+木でも可) |
| 範囲(以上・以下・期間) | 売上金額 >= 10000、今月 | B+木 |
| 前方一致 | 商品名 LIKE 'DB%' | B+木 |
| 並べ替えて取り出す | 日付順に表示 | B+木 |
ハッシュの衝突と理想の分布(一様分布)
ハッシュ関数は、異なるキー値を同じ格納位置に変換してしまうことがあります。これを衝突(コリジョン)といい、衝突したキーどうしをシノニム(同義語)と呼びます。4つのインデックス方式のうち、キー値から格納位置を計算するのはハッシュだけなので、衝突が起こりうるのもハッシュだけです。
衝突を減らすには、ハッシュ値が全番地に偏りなく散らばることが大切です。理想は一様分布(どの値も同じ確率で出る分布)で、このとき同じハッシュ値になる確率が最も低くなります。
下駄箱にたとえると、100人分の靴を100個の箱に入れるとき、誰がどの箱になるかが均等なら、1つの箱に何足も押し込まれにくくなります。正規分布・ポアソン分布・二項分布・幾何分布は、どれも特定の値に出やすさが集まる分布なので、ハッシュ値の理想にはなりません。
キー値をハッシュで番地に変えてレコードを置くファイルを直接編成ファイルといいます。ここでもハッシュ値の理想は一様分布です。
| インデックス方式 | 格納位置の求め方 | 衝突 |
|---|---|---|
| ハッシュ | キー値から関数で計算 | 起こりうる |
| B+木 | 木をたどる | 起こらない |
| 転置インデックス | 語 → その語を含む文書の一覧 | 起こらない |
| ビットマップインデックス | 値ごとに、各行が該当するかを0/1で持つ | 起こらない |
表の結合方式:主に4つあり、ソートマージは「並べ替えて突き合わせ」
RDBMSが2つの表を結合する方法は、主に4つあります。試験では「どの説明がソートマージ結合か」を問われます。
ソートマージ結合は、両方の表を結合する列の値で並べ替え、2つの表の先頭から順に突き合わせて結合します。名簿を2冊とも五十音順に並べてから、上から同時に見比べるやり方です。
| 結合方式 | やり方 | 試験の説明文のキーワード |
|---|---|---|
| ネストループ結合 | 一方の表の行を順に読み、行ごとにもう一方の表と照合する | 一方の表の値を順に読み出し、もう一方と結合 |
| インデックスを使う結合 | 一方の表の値で、もう一方の表のインデックスを引いて照合する | 結合列がインデックスに含まれている |
| ハッシュ結合 | 一方の表の結合列でハッシュ表を作り、もう一方の表の値で引く | ハッシュ表を作成 |
| ソートマージ結合 | 両方の表を結合列で並べ替え、先頭から順に突き合わせる | 並べ替えたそれぞれの表を先頭から順に |
データベース再編成:散らかった倉庫の片付け
データの追加・更新・削除を繰り返すと、削除後の空き領域が点在したり、収まりきらないデータがあふれ領域に飛ばされたりして、データの物理的な並びが乱れます。その結果、同じ検索でも読む場所が増え、アクセス効率が落ちます。
再編成は、データをいったん取り出して(アンロード)、詰め直して格納し直す(リロード)処理です。空き領域や乱れを解消し、アクセス効率を回復するために定期的に行います。
| 処理 | 目的 | 分類 |
|---|---|---|
| 再編成 | 乱れた格納状態を整え、アクセス効率を回復する | 性能維持 |
| バックアップ | 障害に備えて複製を取る | 障害対策 |
| データベースダンプ | DBの内容をファイルに書き出す(バックアップの手段) | 障害対策 |
| ロールバック | 失敗したトランザクションの更新を取り消す | 障害回復・整合性 |
ハッシュとB+木のどちらが適切かを見分ける
ア 売上金額が 1 万円以上の売上を検索する。<売上金額>
イ 売上年月日が今月の売上を検索する。<売上年月日>
ウ 商品名が ‘DB’ で始まる売上を検索する。<商品名>
エ 利用者 ID が ‘1001’ の売上を検索する。<利用者 ID>
解き方と答えを見る
- 手順1:各選択肢の検索条件が「=(等価)」「範囲」「前方一致」のどれかを判定する。
- 手順2:ア「売上金額が1万円以上」は「以上」なので範囲検索 → B+木向き。
- 手順3:イ「売上年月日が今月」は月初から月末までの期間なので範囲検索 → B+木向き。
- 手順4:ウ「商品名が'DB'で始まる」は前方一致 → 値の並び順が必要なのでB+木向き。
- 手順5:エ「利用者IDが'1001'」は1つの値と等しいかを見る等価検索 → ハッシュが最も適する。
答え:エ(等価検索だけがハッシュ向き。範囲・前方一致はB+木)
結合方式の説明文からソートマージ結合を選ぶ
ア 一方の表の結合する列がインデックスに含まれている場合,もう一方の表の結合する列とインデックスの値で結合する。
イ 一方の表の結合する列の値でハッシュ表を作成し,もう一方の表の結合する列と結合する。
ウ 一方の表の結合する列の値を順に読み出し,もう一方の表の結合する列と結合する。
エ 結合する列の値で並べ替えたそれぞれの表の行を,先頭から順に結合する。
解き方と答えを見る
- 手順1:選択肢の説明から、各方式の決め手になる語を探す。
- 手順2:ア「結合する列がインデックスに含まれている」→ インデックスを使う結合。
- 手順3:イ「ハッシュ表を作成」→ ハッシュ結合。
- 手順4:ウ「一方の表の値を順に読み出し、もう一方と結合」→ 並べ替えをしていないのでネストループ結合。
- 手順5:エ「並べ替えたそれぞれの表の行を、先頭から順に結合」→ 並べ替え(ソート)と突き合わせ(マージ)がそろうのでソートマージ結合。
答え:エ(「並べ替え」と「先頭から順に」の両方があるものがソートマージ結合)
要点(試験直前に読む)
- インデックスの目的は「格納位置へ効率的にアクセスして検索を速くする」。全件走査で遅いなら、検索条件に合うインデックスを追加する。
- B木は「階層の深さが同じになるよう分割・併合」。B+木の1件検索のアクセス回数は log X のオーダ。
- ハッシュは等価検索(=)向き。範囲・前方一致・並べ替えはB+木。
- 格納位置を計算するハッシュだけが衝突(シノニム)を起こす。ハッシュ値の理想は一様分布で、このとき衝突確率が最も低い。
- ソートマージ結合=結合列で両表を並べ替え、先頭から順に突き合わせる。
- 再編成=アクセス効率を落とさないための定期処理。バックアップ・ダンプ・ロールバックとは目的が違う。
ひっかけ
- インデックスの目的に「外部キーを一致させる」「重複をなくす」が並ぶ → それは外部キー制約・一意制約。インデックスは検索速度。
- 遅い検索の対策に「領域の拡張」「再インストール」が並ぶ → 読む件数が減らないので無効。インデックス追加を選ぶ。
- 「以上」「今月」「〜で始まる」の検索でハッシュを選ばせる → 範囲・前方一致はB+木。ハッシュは「=」だけ。
- ハッシュ値の分布で正規分布・ポアソン分布を選ばせる → 偏りのない一様分布が正解。
- 結合方式の選択肢で「順に読み出して結合」をソートマージと誤認させる → 「並べ替えた」がなければソートマージではない。
用語(17)
列の値からデータの格納位置へ直接たどれるようにし、検索を速くする仕組み。
⚠ 外部キー制約(別の表との値の一致)や一意制約(重複禁止)とは目的が違う。インデックスの目的は検索速度。
条件に合うデータを探すために、表の全レコードを先頭から順に読むこと。
⚠ インデックスを使えば読む件数を減らせる。領域の拡張では読む件数は減らない。
1つのノードが多くの子を持ち、ノードの分割と併合ですべての葉の深さをそろえる平衡木。
⚠ 「キー値から関数で格納位置を求める」はハッシュ法の説明。
データを葉にだけ持ち、葉どうしを順につないだB木の一種で、1件の検索も範囲検索も得意。
⚠ ハッシュは等価検索専用。範囲・前方一致・並べ替えはB+木。
どの葉までの深さもほぼ同じになるように保たれた木構造。
キー値をハッシュ関数で計算して格納位置を求めるインデックスで、「=」による等価検索に強い。
⚠ B+木と違い値の並び順を保たないので、範囲検索・前方一致には使えない。
キー値を決まった計算で格納番地などの値に変換する関数。
異なるキー値が同じハッシュ値になることで、同じ値になったキーどうしをシノニムと呼ぶ。
⚠ 衝突が起こりうるのは格納位置を計算するハッシュだけ。B+木・転置・ビットマップでは起こらない。
どの値も同じ確率で現れる分布で、ハッシュ値がこれに近いほど衝突が起きにくい。
⚠ 正規・ポアソン・二項・幾何分布は値が偏るので、ハッシュ値の理想ではない。
キー値をハッシュなどで番地に変換し、その位置にレコードを置くファイル編成。
⚠ 順編成は先頭から順に読むだけ。区分編成は登録簿とメンバ(順編成)で構成。
語ごとに、その語を含む文書や行の一覧を持つインデックスで、全文検索に使う。
⚠ 格納位置を計算しないので衝突は起こらない。
列の値ごとに、各行がその値に該当するかを0/1の並びで持つインデックスで、値の種類が少ない列に向く。
⚠ 格納位置を計算しないので衝突は起こらない。
結合する列で両方の表を並べ替え、先頭から順に突き合わせて結合する方式。
⚠ ハッシュ表を作るのはハッシュ結合。片方を順に読みもう片方と照合するのはネストループ結合。インデックスを引くのはインデックスを使う結合。
一方の表の行を1行ずつ読み、その行ごとにもう一方の表と照合して結合する方式。
⚠ 並べ替えをしない点でソートマージ結合と区別する。
一方の表の結合列でハッシュ表を作り、もう一方の表の値でそのハッシュ表を引いて結合する方式。
⚠ 「ハッシュ表を作成」という語があればこれ。
更新の繰返しで乱れた格納状態を、データを取り出して詰め直すことで整え、アクセス効率を回復する処理。
⚠ バックアップ・ダンプは障害対策、ロールバックはトランザクションの取消しで、性能回復ではない。
失敗したトランザクションの更新を取り消し、実行前の状態に戻すこと。
⚠ アクセス効率の維持とは無関係。性能維持は再編成。
このレッスンの過去問
- インデックスの目的平成24年度 秋期 基本情報技術者試験 午前 問27
- B木の定義(階層深さの均一化)基本情報技術者試験 科目A免除 修了試験 20171210 実施分 問27
- ハッシュインデックスとB+木インデックスの使い分け平成26年度 秋期 基本情報技術者試験 午前 問27
- ハッシュ値の分布と衝突確率(一様分布)平成27年度 秋期 基本情報技術者試験 午前 問26
- 表の結合方式(ソートマージ結合)平成29年度 春期 基本情報技術者試験 午前 問27
- データベース再編成の目的平成26年度 秋期 基本情報技術者試験 午前 問29