Transcript Document

アクセスパス
1
アクセスパス(Access Path)
• 属性値から,タプル識別子 TID(あるいは他の内
部アドレス表現)へ変換することは,一般に連想
アクセスなどと呼ばれる
• アクセスパスとは,連想アクセスのためのアルゴ
リズムやデータ構造のこと
• 提案されてきたアルゴリズムは多数
実装されたアルゴリズムは少数
2
アクセスパスの3つの機能
• 主キーアクセス
一致問い合わせ: キー属性=定数
範囲問い合わせ: 定数1≦キー属性≦定数2
• 2次キーアクセス
• マルチテーブル・アクセス
– 階層化,あるいは,ネットワーク化された複数のリレーショ
ンに関するアクセスパス.ここでは取り扱わない
3
アクセスパスの実装技術
• ハッシュ(hashing)
– 主キーを引数にして,タプルの記憶位置を返す関数を利用
– 理想的には,アクセス1回で取り出し可能
– 一致問い合わせのみサポート
• キー比較(key comparison)
–
–
–
–
木やリストなど,キー属性に基づいた動的な構造体を利用
通常は,数回以上のアクセスが必要
一致問い合わせのほか,範囲問い合わせもサポート可能
葉ノードのみにタプル(またはTID)を持つB +木(以後単に
B木)が最も重要
4
アクセスパスの実装技術
• ハッシュ(hashing)
– 主キーを引数にして,タプルの記憶位置を返す関数を利用
– 理想的には,アクセス1回で取り出し可能
– 一致問い合わせのみサポート
• キー比較(key comparison)
–
–
–
–
木やリストなど,キー属性に基づいた動的な構造体を利用
通常は,数回以上のアクセスが必要
一致問い合わせのほか,範囲問い合わせもサポート可能
葉ノードのみにタプル(またはTID)を持つB +木(以後単にB
木)が最も重要
5
ハッシュ
6
フォールディングとハッシュ
フォール
ディング
キー値
の範囲
(一様に
分布せず)
ハッシュ
整
数
タプルア
ドレス空
間
(一様に
分布)
(例:4バイト整数)
7
フォールディングの例
• 可変長文字列を4バイト整数にフォールディング
– 文字列を4バイト境界までパディング
– 4バイト単位で排他的論理和を取る
• 注意
– キー値のすべてのビットが結果に影響を与えること
– 結果に特定のパターンを生じないこと
• キー値がEBCDIC コードで表現された10進数の場合,各コー
ドは 0xFn のパターンを持ち,排他的論理和を取っても 0xFn か
0x0n のパターンが残る
– 結果が衝突しないこと
8
ハッシュ関数
PAGEID
hash (FILEID fileid, char *keyvalue, int keylength)
ファイル
キー値
キー長
• ページを返す.このページをバケツ(bucket)と呼ぶ
– タプルを見つけるには,さらにページ内検索が必要
• 4バイト整数へフォールディングした後ならば,ハッシュ関数 H
は,
H: { 0, …, 232-1 } → { 0, …, B-1 }
のマッピング (B: バケツ数)
• 検索時だけでなく,タプルの挿入時にもハッシュ関数を利用
9
ハッシュにおける制限事項
• 連続割り当て
– 連続したページを割り当てなければならない
• 固定長
– 全ページをあらかじめ割り当てなければならない.バ
ケツ数Bを変更するには,ハッシュ関数を変更し,全タ
プルについて再ハッシュしなければならない
10
さまざまなハッシュ関数
• 除算/剰余(合同ハッシュ)
←普通はこれ
H (kb) = kb mod B
•
•
•
•
•
N乗 (N乗した結果の中央付近のビット)
基数変換
多項式除算(CRC)
数値解析(ユーザ定義ハッシュ)
暗号化
11
合同方式でのバケツ数Bの決定
• B (バケツ数),T(推定タプル総数),F(1ページ
に格納できる平均タプル数)とする
• B = ┎ T/F ┒ではだめ
– Fが偶数だと,キー値の偶奇がハッシュ値に残る
• キー値と相関のあるBもだめ
– ハッシュ値の範囲が限られる場合がある
• 通常は次の式で決められる
B = 次に大きい素数(┎ T / (F*U) ┒)
Uはページの利用率を表し,多くの場合 U=0.8
12
衝突による
ページオーバフローの見積もり
あるページに t 個のタプルがマップされる確率 P(t) は,
であり,あるページの衝突(オーバフロー)確率 Pcoll は,
である.
オーバフローに関しては,バケツが大きいほど良く,1個の大きなバケツの場
合が最も良いことになるが,それではハッシュの意味がない.
13
一意でない属性に対するハッシュ
• 同じ属性値を持つタプルが複数存在するため,ペー
ジオーバフローが属性値の分布に依存する
• キーとする属性について,異なる値の数を V として
3つの場合がある
V ≈ T ほとんど一意なので問題なし
V ≥ B B を次の B’ に修正.n = └V/B┘として
B’ = 次に大きい素数(┎ V / n ┒)
V < B 問題 ⇒ (1) ハッシュを使わない
(2) 小さいBで済むようにする(ページを大きく
する,タプルでなくポインタを記憶するなどして
14
F を大きくする)
オーバフロー対策
• 内部衝突処理(内部戦略)
– オーバフロー時に,既存の他のバケツに記憶する
– 次式のように,i を増やしながら i のオフセット関数 O(K,i)
をハッシュ値に加えて,空きのあるバケツを探す
page-no(K,i) = H(K) + O(K, i) mod B
• 外部衝突処理(外部戦略)
– オーバフロー時には,「オーバフローページ」をバケツに
リンクし,そこに記憶する.そのページがオーバフローし
たら,さらにオーバフローページをリンクする.
– 簡単で適用範囲が広いが,オーバフローページが多くな
ると検索効率が落ちる
15
オーバフロー対策での注意と
バケツ内の管理
• 代替ページをどこまで検索すればよいのか
– 内部戦略の場合には,付加情報が必要(そうでないと
存在しないことを知るのに,全バケツを検索する必要
あり).
– 外部戦略の場合には,オーバフローページのリンクが
尽きるまで(一意属性の場合は,タプルが見つかった
時点で終了できる)
• バケツ内の管理
– ページディレクトリ(後を参照)を用いる方法
– バケツ内でもう1度ハッシュする方法
16
readkey操作の実装
1. 検索対象のキー値に対し共有ロック(7章)を獲得
2. ハッシュ関数で主バケツのアドレスを計算
3. バケツページに対して,共有セマフォ(8章)指定
で bufferfix(13章)
4. バケツページ内を検索
5. タプルが見つからなければ,オーバフローページ
へクラビング(8章)し検索 (セマフォを持ちながら入
出力処理をしないように注意が必要(略))
6. (セマフォ解放,bufferunfix)
17
insert操作の実装(1/2)
1. 挿入しようとしているキー属性の値を排他ロック
2. 属性値にハッシュ関数を適用
3. 一意属性の場合,readkey操作により値が存在
するかを調べ,存在するなら挿入を拒否
4. バケツページについて排他セマフォを獲得
5. 十分な空きがあれば,タプルの挿入について物
理論理ログレコード(10章)を書きこみ,タプル
を物理的にコピーし,insert操作を終了
6. 空きがなければ……
18
insert操作の実装(2/2)
7. バケツの LSN (9章)を記憶し,セマフォを解放
8. セマフォなしでオーバフローページに対し
bufferfix を要求
9. バケツページの排他セマフォを再獲得し,オー
バフローページへクラビング.挿入を試みる
10. (例外)セマフォなしの間にページ(LSN)が変更
されていたら,やりなおし
11. オーバフローページが尽きたときに,新規にリ
ンクする処理が必要
19
update操作の実装
1. 通常は,他のファイル型の場合と同じ
2. タプルが大きくなりページに領域が足りなくなる
と,オーバフロー処理が必要
3. ハッシュのキー属性値が変更される場合は,一
旦旧タプルを削除し,(別のバケツに)新しい値
で再挿入
20
delete操作の実装
削除しようとしているキー属性の値を排他ロック
ハッシュによりバケツページを決定
バケツページに対し排他セマフォを獲得
そのページにタプルがなければ,insert時と同様
にクラビングして調べる
5. タプルを削除
6. オーバフローチェインの短縮を試みる場合には,
関連する全ページの排他セマフォと再配置する
全タプルの排他ロックが必要
1.
2.
3.
4.
21
ハッシュのまとめ
• 利点
– 主キーを介したタプルを連想検索するのに,タプル当
たり1回を少し越える程度のページアクセスで済む
• 欠点
– ファイルサイズがあらかじめわかっている必要がある
•
•
•
•
連続ページの割り当てが必要
バケツ数変更には,全タプルの再ハッシュが必要
よって,大きめに見積もらざるを得ない.
サイズが劇的に変化するリレーションには向かない
– キー値のソート順が保存されない(範囲検索できず)
– 一意でない属性では,衝突問題が深刻
22
B木
23
B木とは
• 各ノード(=ページ)が多数の子供を持つ多分木
(multi-way tree)の1つ
• すべての探索パスで,ルートから葉にいたるノー
ド数が等しい(バランスしているから,あるいは,
Bayer らの論文だから,B木)
• データを葉ノードにだけ持つ(B+木)のみを扱う
ルート
インデクスノード
葉ノード
24
インデックスノードの構造
struct {
char*
K;
/* 分割点を表すキー値 */
PAGEID P;
/* 子ノードへのポインタ */
} index_node_structure[]; /* キー値・ポインタ対の配列 */
/* 0~F-1 の F 個の対 */
• 第 i 要素(0 ≤ i ≤ F-2)は,Ki ≤ Key < Ki+1 を満たすすべての
Key 値をカバーする. 第F-1要素は, KF-2 以上の全キー値
– K0 はなくて済むが,統一性のため含めるのが普通
• F を ファンアウト(Fan-out)と呼ぶ
25
葉ノードの構造
• <キー値,データ>対の配列
– K0が必要
• データは
– タプルへのポインタ(TIDなど),または,
– タプルそのもの
• 1つの葉ノードに収容可能なデータ数を C
(Capacity)で表す(一般に,インデクスノードに収
納可能なポインタ数 F とは異なる)
26
B木の例
イ
ン
デ
ク
ス
ノ
ー
ド
ルートノード
220
140
355
168
220
271
312
L1
120
140
136
220
151
168
225
L2
170
190
236
271
296
299
312
318
葉
ノ
ー
ド
303
L3
27
B木における探索(1/2)
Key = 299 の一致探索
299
220
355
299
140
168
220
271
312
L1
120
136
220
225
236
299
140
151
168
L2
170
190
271
296
299
312
318
303
L3
28
B木における探索(2/2)
299 ≤ Key ≤ 315 の範囲探索
299
220
355
299
140
168
220
271
312
L1
120
136
220
225
236
299
140
151
168
L2
170
190
271
296
299
312
318
303
L3
29
B木への挿入(1/2)
Key = 240 の挿入
240
220
355
240
220
F=5, C=4を仮定
220
225
271
236
271
312
240
296
299
312
318
303
30
B木への挿入(2/2)
Key = 280 の挿入
280
220
355
280
220
220
空きがない!
⇒ ノード分割
225
271
236
271
312
240
280
296
299
312
318
303
31
ノード分割
Key = 280 の挿入
220
271
312
220
225
236
280
271
296
240
299
220
271
312
299
312
220
225
236
240
303
271
296
280
299
296
303
1. タプルを分割
312
318
2.横方向リン
クを設定
3.上位ノード
へ伝達
299
303
新ページを割り当て
312
318
葉
ノ
ー
ド
B木の成長
高さ3の木
3. 空きなし
⇒分割
高さ4の木
5. ルートに
空きなし
⇒成長
ルートページ不変
新しい段
4. 新しい
インデクス
1. 空きなし 2.新しい葉
⇒分割
33
B木からの削除
• B木の(教科書的)原則
– ページ利用率を常に50%以上に保つ(平均ファンアウ
トを大きくし,木を低くする).平均利用率が69%になる
• 葉ページからのタプルの削除
– タプルを探索,タプルが存在すれば葉ページから削除
し,葉ページ内でタプルを順につめる
– タプルを削除しても,葉ページ利用率が50%以上なら
ば,それで終わり(そのタプルのキー値がインデクス
ノードで分割キーになっていてもそのままでよい)
– 50%未満に落ちる(アンダーフロー)場合は,他のノー
ドとやりとりして,50%を保つようにする
34
アンダーフロー処理
• 右ノードHから移動する方法
– HからこのノードNへタプルを移動
– その結果ぎりぎりの利用率だったノード H がアンダー
フローし,そのまた右とマージし,...と最悪右端まで
行く
• 右ノードとマージする方法
• 左ノード L,自ノード N,右ノード H の3ページの
タプルを集め,新たな2ページに再分配する方法
• しかし……(次頁へ)
35
マージを行なわない実装が多い
• マージはコストが高い(並列処理性を損なう)
• 分割とは違い,マージしなくても正しく動作する
• データベースが長期的には大きくなるのが普通だと
すると,マージしてもすぐ分割するはめになる
• そこで,アンダーフローしてもマージしない実装が多
い.完全に不要になったページのみ返却する
36
ページの返却
• 1段上のインデクスノードから,当該ページへの
ポインタを削除
• 左右の双方向リンクをショートカット
• インデクスノードが空になったら,インデクスノー
ドのページを同様に返却
• ルート内のポインタが1個になったら,木を1段縮
める
37
ページ返却の後回し
• 葉ページやインデクスページが空になっても,B
木は正しく動作する
• よって,コストの高いページの返却処理を,シス
テム負荷が小さい時に非同期に行なうことが可
能(実例あり)
• なお,ノードをマージしなくても,容量利用率がそ
れほど落ちず,性能(並列処理性)は高いという
解析結果あり
38
一意でない属性に対するB木(2次インデクス)
葉ページの3つのレイアウト
キー値
A
23
キー値
B
23
ポインタ
P1
23
P2
23
P3
28
P4
ポインタリスト
P1 P2 P3
キー値
C
23
28
P4
参照
R1
28
P1 P2 P3
R2
P4
39
一意でない属性に対する2つの立場
• 一意でない属性は存在しないとする立場
– 統一的な取り扱いを重視
• あたかも一意的な属性として取り扱う(A方式)
• あるいは,属性値とタプル識別子の組み合わせが一意であ
ると考える
• 一意でない属性を特別扱いすべきという立場
– 効率の向上を重視
• データ構造の最適化
• 同期化(並列処理性)の最適化
(どちらも,もっともな主張)
40
B木の性能
• 主要パラメタは,高さ H (探索ページ数)と,木に
必要な総ページ数 S
あるいは,
N:タプル総数
41
B木の高さ H とタプル総数 N
H
キー順ファイル(C*=43)
N (タプル総数)
2次インデクス(C*=300)
N (タプル総数)
2
12,900
90,000
3
3,870,000
27,000,000
4
1,161,000,000
8,100,000,000
5
348,300,000,000
2,430,000,000,000
(F*=300などを仮定,本文参照)
ディスク分割
42
B木の高さを低くする
• 葉の数を減らす(N一定で N/C* を小さくする)
– 葉ページを大きくする
– 葉ページのデータサイズを小さくする
• タプルそのものの代わりに,ポインタにする
– ただし,その分アクセス回数が1増えるため,アクセス回数から
計算すると,ポインタにしてサイズが 1/F* (F*: 平均ファンアウ
ト) 以下にならないとペイしない
• ファンアウトを増やす
– キー値を圧縮する
• サフィクス圧縮とプレフィクス圧縮
• 挿入や削除,あるいは(プレフィクス圧縮の場合は)検索のコ
ストが高くなる問題がある (トレードオフの見積もりが難し
43
い)
サフィクス圧縮
• インデクスノードにおける分割キーは,キーの先頭から分
割を判断するのに必要な最低限な文字(文字列キーの場
合)までで十分であり,それ以降のサフィクスを省略できる
Coppelleti
最大キー
Cooperativa
最小キー
Coppelleti
Cop
最大キー
Cooperativa
最小キー
Coppelleti
44
プレフィクス圧縮
• 下位ノードでは,隣接したキー値が途中まで共通なことが
多いため,プレフィクスを省略し,差分のみを記憶すること
ができる
<直前のキー値と共通の文字数(1バイト),残りの文字列>で記憶
Manino, Manna, Mannari, Mannarino, Mannella, Mannelli
(43B)
↓
Man に続いて <3, ino> <3, na> <5, ri> <7, no> <4, ella> <7, i> (20B)
葉に近い下位ノードでは,プレフィクス圧縮とサフィクス圧縮の両
方を組み合わせて利用可能.1エントリ当たり平均2バイト以下
にできることもある
コスト増えるのであまりやらない
45
B木の性能のまとめ
• 毎秒60回のトランザクションと,ファンアウト F=400 を仮定
• ルートは常に主記憶中にバッファされる
• 2段目のインデクスノードは,平均してそれぞれ 400/60 =
6.7秒に1回アクセスされる.5分間ルールによれば,これら
もバッファすべき
• 3段目以下のノードは,アクセス頻度が低いためバッファさ
れない
• 高さ H のB木では,ランダムな readkey 1回について,H-2
回の入出力が必要
• 実際には,ルートのエントリ数が小さい場合もあり,その場
合,H-3回に1回の入出力となる
46