Weitere ähnliche Inhalte Ähnlich wie データベースシステム論12 - 問い合わせ処理と最適化 (20) データベースシステム論12 - 問い合わせ処理と最適化2. 講義計画
• 関係データベースの歴史と基本概念
• SQLの基礎と応用(演習を含めつつ)
• データベースの設計と構成
• SQL問い合わせ処理とそれを支える技術
• 関係データモデル以外のデータベース
データベースシステム論 第 回2016 [ 10 ] 2p.
※現時点での予定です。進捗に応じて変更します。
27Apr.
20Apr.
13Apr.
25May
18May
11May
1June
8June
22June
15June
13July
6July
29July
20July
27July
4. インデクス
• インデクスとは?
• 主キーに自動的に付与される
• 明示的に特定のカラムへ付与する事もできる
データベースシステム論 第 回2016 [ 12 ] 4p.
データに付随して格納される情報で最も重要なRDBの機能が
インデックスは、データベースの性能を向上させ
るための一般的な方法です。データベースサーバで
インデックスを使用すると、インデックスを使用し
ない場合に比べてかなり速く、特定の行を検出し抽
出することができます。しかし、インデックスを使
用すると、データベースシステム全体にオーバー
ヘッドを追加することにもなるため、注意して使用
する必要があります。
(出典:PostgreSQL9.3.1公式ドキュメント)
5. インデクスの種類
• B-tree, B+tree
• ある順番でソート可能なデータに対する等価性や範
囲の問い合わせに対して効果を発揮する。
• Hash
• 単純な等価性比較を行う場合に効果を発揮する。
• 空間インデクス(R-Tree)
• 多次元空間中での範囲検索や近傍検索に効果を発揮
する。
データベースシステム論 第 回2016 [ 12 ] 5p.
7. 対象カラムによる分類
• ユニークインデクス
• キーの値が重複していないインデクスの事
• 主キーやUNIQUEが指定されたカラムへインデクス
が付与された場合、必然的にユニークインデクスと
なる
• ノンユニークインデクス
• キーの重複が許されているカラムに対するインデク
スの事
データベースシステム論 第 回2016 [ 12 ] 7p.
これらは暗黙的に決定されるので、利用者の立場からは気にす
る必要はありませんが、問い合わせ処理上、ユニークが保障さ
れていない場合の処理とそうでない場合の処理を切り分ける目
的で利用されます。
9. B+tree
• d次のB+treeの定義
• 値と中間ノード
• 1~2d個の整列された値を持つ
• 値数+1個のポインタ(最大2d+1)を持つ
• 値xの左にあるポインタはx未満の値を持つノードを指す
• 値xの右にあるポインタはx以上の値を持つノードを指す
• 葉
• d~2d個の整列された値を持つ
• 次の葉へのリンクを持つ(B木に比べ順次アクセスで利点)
• 一般的に葉の値はタプルを指すポインタ
• タプルの値が入って居る場合がクラスタードインデクス
データベースシステム論 第 回2016 [ 12 ] 9p.
35
10 25 65
1 3 10 16 25 30 35 40 65 74
索引部
データ部
X<35 35≦X
X<6510 ≦X<25
次
64≦X
次 次 次
12. Postgresで試して見よう
• 使用テーブル
• zipcode (インストール時に作成したテーブル)
• 準備
• zipcodeはインデクスが貼られていない
• zipcodeと同じスキーマのzipcode2を作成
• zipcode2に対してインデクスを付与
• zip(なぜか整数型です)にbtree
• addr3にhash
• 両方のテーブルで性能差を確認
• zipの範囲検索はどうか?
• addr3の等価検索はどうか?
データベースシステム論 第 回2016 [ 12 ] 12p.
13. 準備
• SQLは講義HPにもあります。
• テーブルの作成
• zipcode作成時と同じCREATE TABLE 文
• データのコピー
• INSERT INTO ~ SELECT ~文
データベースシステム論 第 回2016 [ 12 ] 13p.
INSERT INTO zipcode2
SELECT * FROM zipcode;
※INSERT 0 123423と出たら成功
14. CREATE INDEX文
• インデクス名
• 任意の名前で良いがテーブル名・カラム名から連想できる名
前にした方が識別しやすい
• 例: wine.wid→idx_wine_wid
• メソッド
• btree / hash / gist / spgist / ginのどれか
• UNIQUE
• ユニークインデクスなら明示する
データベースシステム論 第 回2016 [ 12 ] 14p.
CREATE [UNIQUE] INDEX インデクス名
ON テーブル名
USING メソッド (カラム名);
17. 効果測定1 btree & 等価検索
データベースシステム論 第 回2016 [ 12 ] 17p.
QUERY PLAN
------------------------------------------------------------
Seq Scan on zipcode (cost=0.00..3566.79 rows=1 width=100)
Filter: (zip = 4328011)
(2 行)
QUERY PLAN
------------------------------------------------------------
-----------------------
Index Scan using idx_zipcode2_zip on zipcode2 (cost=0.42..8.44 rows=1
width=100)
Index Cond: (zip = 4328011)
(2 行)
3566.79 8.44vs無し 有り
EXPLAIN SELECT * FROM zipcode WHERE zip = 4328011;
EXPLAIN SELECT * FROM zipcode2 WHERE zip = 4328011;
Win!
18. 効果測定2 btree&範囲検索
データベースシステム論 第 回2016 [ 12 ] 18p.
QUERY PLAN
------------------------------------------------------------
Seq Scan on zipcode (cost=0.00..3875.35 rows=1 width=100)
Filter: ((zip >= 4328011) AND (zip <= 4328066))
(2 行)
QUERY PLAN
------------------------------------------------------------
-----------------------
Index Scan using idx_zipcode2_zip on zipcode2 (cost=0.42..8.44 rows=1
width=100)
Index Cond: ((zip >= 4328011) AND (zip <= 4328066))
(2 行)
3875.35 8.44vs無し 有り
EXPLAIN SELECT * FROM zipcode WHERE zip >= 4328011 AND zip <= 4328066 ;
EXPLAIN SELECT * FROM zipcode2 WHERE zip >= 4328011 AND zip <= 4328066 ;
Win!
19. 効果測定3 hash &完全一致検索
データベースシステム論 第 回2016 [ 12 ] 19p.
QUERY PLAN
------------------------------------------------------------
Seq Scan on zipcode (cost=0.00..3566.79 rows=2 width=100)
Filter: ((addr3)::text = '城北'::text)
(2 行)
QUERY PLAN
------------------------------------------------------------
Bitmap Heap Scan on zipcode2 (cost=4.02..11.85 rows=2 width=100)
Recheck Cond: ((addr3)::text = '城北'::text)
-> Bitmap Index Scan on idx_zipcode2_addr3 (cost=0.00..4.01 rows=2
width=0)
Index Cond: ((addr3)::text = '城北'::text)
(4 行)
3566.79 11.85vs無し 有り
EXPLAIN SELECT * FROM zipcode WHERE addr3 = '城北';
EXPLAIN SELECT * FROM zipcode2 WHERE addr3 = '城北';
Win!
20. 効果測定4 hash &部分一致検索
データベースシステム論 第 回2016 [ 12 ] 20p.
QUERY PLAN
------------------------------------------------------------
Seq Scan on zipcode (cost=0.00..3566.79 rows=2317 width=100)
Filter: ((addr3)::text ~~ '%城%'::text)
(2 行)
QUERY PLAN
------------------------------------------------------------
Seq Scan on zipcode (cost=0.00..3566.79 rows=2317 width=100)
Filter: ((addr3)::text ~~ '%城%'::text)
(2 行)
3566.79 3566.79vs無し 有り
※等価(完全一致)検索以外ではhashインデクスは働かない
EXPLAIN SELECT * FROM zipcode WHERE addr3 LIKE '%城%';
EXPLAIN SELECT * FROM zipcode2 WHERE addr3 LIKE '%城%';
引き分け!
21. 実行時間の計測
• ANALIZEを付けて実行時間を見る
• マシンスペックに依存する値です
• 他のプロセスによるCUP負荷にも依存します
→毎回違う結果が出てくる
データベースシステム論 第 回2016 [ 12 ] 21p.
インデックス無し インデックス有り
btree&等価 15.373ms 0.041ms
btree&範囲 28.147ms 0.066ms
hash&完全一致 28.485ms 0.070ms
hash&部分一致 36.720ms 32.708ms
※それに対してコストの値はマシンスペックや環境に依存しない
→同じスキーマ・データに対する同じSQL文は必ず同じ結果を得る
→値そのものには意味が無いが、値同士の比較により効率的なクエリが分かる
27. リライト
• クエリツリー内のビューを展開
データベースシステム論 第 回2016 [ 12 ] 27p.
wine_list
SELECT wid, name, district, price
FROM wine JOIN vineyard
ON wine.did = vineyard.did;
πwid,name,district,price
⨝wine.did=vineyard.did
wine
vineyard
書き換え
28. オプティマイズ
• クエリツリーを解析
• プランツリーを生成
• 実際の処理をノードとしたツリー
• 処理の例:table scan、index scan等
• 効率的なプランツリーを求める
• 最適化
データベースシステム論 第 回2016 [ 12 ] 28p.
π*
σwid=1
πwid,name,district,price
⨝wine.did=vineyard.did
wine
vineyard クエリツリー 候補実行プラン 実行計画
プランツリー
29. 「効率的な」とは?
• 例:結合(JOIN)
• 複数の処理方法がある
• ネスティドループ結合
• ソートマージ結合
• シングルループ結合(講義では省略)
• ハッシュ結合
• オプティマイズにより最適な結合処理が選ばれる
• それぞれ長所や制約があり、結合対象となるテーブルの
性質(行数やインデクスの有無・種類)によって、効率的な
結合処理は異なる。
• コスト計算により定量的に評価する
• 前回講義のEXPLAIN文で出てきたコストを思い出して!
データベースシステム論 第 回2016 [ 12 ] 29p.
30. ネスティドループ結合
• 入れ子のループで全組み合わせを求める
• テーブルAとテーブルBの結合
• AのカラムxとBのカラムyを条件とした等結合
データベースシステム論 第 回2016 [ 12 ] 30p.
for(var a = 0; a < |A|; a++){
for (var b = 0; b < |B|; b++){
if(A[a].x = A[b].y){
JoinTuples(A[a],B[b]);
}
}
}
最も単純でいかなる条件下でも実行できるが、行数が多いテーブ
ル同時の結合は計算量が膨大になる。
31. ソートマージ結合
• 予めソートする事により計算量を削減
データベースシステム論 第 回2016 [ 12 ] 31p.
var n = 0;
sort(A); sort(B);
for(var a = 0; a < |A|; a++){
for (var b = n; b < |B|; b++){
if(A[a].x = B[b].y){
JoinTuples(A[a],B[b]);
}else{
n = b++; break;
}
}
}
ソートのコストがオーバヘッドとして掛かるが、結合のための
ループ回数はネスティドループに比べ大幅な削減が期待できる。
32. ハッシュ結合
• 同値に対するハッシュキーの等価性を利用する
データベースシステム論 第 回2016 [ 12 ] 32p.
var hashtable= {};
for(var b=0; b<|B|; b++){
var key = hash(B[b].y);
hashtable[key] = B[b];
}
for(var a=0; a<|A|; a++){
var key = hash(A.x);
if(key in hashtable){
JoinTuples(A[a], hashtable[key]);
}
}
ハッシュのオーバヘッドが許容でき、かつ行数に対して十分なメ
モリを有する場合、高速に結合が行えるため高効率が期待できる。
33. 試してみよう
• どの結合方法が選ばれた?
データベースシステム論 第 回2016 [ 12 ] 33p.
EXPLAIN
SELECT * FROM wine_list WHERE wid = 1;
dbsys-# SELECT * FROM wine_list WHERE wid = 1;
QUERY PLAN
-------------------------------------------------------------------
Nested Loop (cost=0.30..16.35 rows=1 width=244)
-> Index Scan using wine_pkey on wine (cost=0.15..8.17 rows=1 width=134)
Index Cond: (wid = 1)
-> Index Scan using vineyard_pkey on vineyard (cost=0.15..8.17 rows=1 width=126)
Index Cond: (did = wine.did)
(5 行)
34. 試してみよう2
• ネスティドループ結合を無理矢理無効に
データベースシステム論 第 回2016 [ 12 ] 34p.
set ENABLE_NESTLOOP to off;
EXPLAIN
SELECT * FROM wine_list WHERE wid = 1;
Hash Join (cost=8.18..25.34 rows=1 width=244)
Hash Cond: (vineyard.did = wine.did)
-> Seq Scan on vineyard (cost=0.00..15.20 rows=520 width=126)
-> Hash (cost=8.17..8.17 rows=1 width=134)
-> Index Scan using wine_pkey on wine (cost=0.15..8.17 rows=1 width=134)
Index Cond: (wid = 1)
35. 試してみよう3
• ハッシュ結合も無効に
データベースシステム論 第 回2016 [ 12 ] 35p.
set ENABLE_HASHJOIN to off;
EXPLAIN
SELECT * FROM wine_list WHERE wid = 1;
Merge Join (cost=46.83..49.45 rows=1 width=244)
Merge Cond: (wine.did = vineyard.did)
-> Sort (cost=8.18..8.18 rows=1 width=134)
Sort Key: wine.did
-> Index Scan using wine_pkey on wine (cost=0.15..8.17 rows=1 width=134)
Index Cond: (wid = 1)
-> Sort (cost=38.66..39.96 rows=520 width=126)
Sort Key: vineyard.did
-> Seq Scan on vineyard (cost=0.00..15.20 rows=520 width=126)
36. 比べてみよう
• 一位: Nested Loop
• 二位: Hash Join
• 三位: Merge
→ネスティド結合が最適な実行計画
データベースシステム論 第 回2016 [ 12 ] 36p.
Nested Loop (cost=0.30..16.35 rows=1 width=244)
Hash Join (cost=8.18..25.34 rows=1 width=244)
Merge Join (cost=46.83..49.45 rows=1 width=244)
set ENABLE_NESTLOOP to on;
set ENABLE_HASHJOIN to on;
※ちゃんと設定を戻しておこう!
• DBMSはNested Loopが最適である事を事前予想して、デフォルトで実行した
• どのアルゴリズムが最適かはデータ量やJoinのキーに依存する
37. オプティマイズ - 別の例
• おバカなSQL文も直してくれます。
• 二度の全行スキャンを一度に最適化している
• このように冗長なクエリを効率化する事もオプ
ティマイズの重要な役目である。
データベースシステム論 第 回2016 [ 12 ] 37p.
EXPLAIN
SELECT *
FROM (SELECT * FROM zipcode) AS a;
QUERY PLAN
-----------------------------------------------------------------
Seq Scan on zipcode (cost=0.00..3258.23 rows=123423 width=100)
(1 行)
39. 式変換による最適化 - 例
• 選択率による最適な実行計画の立案を例に
• wine_listはwineとvineyardを等結合したビュー
• ビューは問い合わせ時にSQL文に書き換えられる
• この問い合わせは結合処理結果に対する選択演算
• 選択の条件は「3000円より高いワイン」
データベースシステム論 第 回2016 [ 12 ] 39p.
SELECT *
FROM wine_list
WHERE price > 3000;
40. 式変換による最適化 - 例つづき1
• まず、WHERE句無しでコストを考える
データベースシステム論 第 回2016 [ 12 ] 40p.
EXPLAIN
SELECT *
FROM wine_list;
Hash Join (cost=21.70..43.34 rows=490 width=244)
Hash Cond: (wine.did = vineyard.did)
-> Seq Scan on wine (cost=0.00..14.90 rows=490 width=134)
-> Hash (cost=15.20..15.20 rows=520 width=126)
-> Seq Scan on vineyard (cost=0.00..15.20 rows=520 width=126)
41. 式変換による最適化 - 例つづき2
• 次に、結合無し(wineテーブル)でコストを求める
• 予想
• 結合結果に対して選択演算を適用するため、コスト
は両コストを足し合わせたものになるだろう・・・
データベースシステム論 第 回2016 [ 12 ] 41p.
EXPLAIN
SELECT *
FROM wine WHERE price > 3000;
Seq Scan on wine (cost=0.00..16.13 rows=163 width=134)
Filter: (price > 3000)
Hash Join (cost=21.70..43.34 rows=490 width=244)
42. 式変換による最適化 - 例つづき3
• ではやってみよう!
データベースシステム論 第 回2016 [ 12 ] 42p.
EXPLAIN
SELECT *
FROM wine_list
WHERE price > 3000;
Hash Join (cost=21.70..40.07 rows=163 width=244)
Hash Cond: (wine.did = vineyard.did)
-> Seq Scan on wine (cost=0.00..16.13 rows=163 width=134)
Filter: (price > 3000)
-> Hash (cost=15.20..15.20 rows=520 width=126)
-> Seq Scan on vineyard (cost=0.00..15.20 rows=520 width=126)
SELECT *
FROM wine_list
よりも低コスト!
43. 式変換による最適化 - 例つづき4
• 結合前のwineに対して選択演算を実行
• 高速なハッシュ結合とはいえ行数にコストは依存
• 結合前に行数を減らすと結合が高速化できる
• |wine|=7行 だが |σprice>3000(wine)|=2行
• 最適化前:σprice>3000(wine⨝vineyard)
• 最適化後:σprice>3000(wine)⨝vineyard
データベースシステム論 第 回2016 [ 12 ] 43p.
Hash Join (cost=21.70..40.07 rows=163 width=244)
Hash Cond: (wine.did = vineyard.did)
-> Seq Scan on wine (cost=0.00..16.13 rows=163 width=134)
Filter: (price > 3000)
-> Hash (cost=15.20..15.20 rows=520 width=126)
-> Seq Scan on vineyard (cost=0.00..15.20 rows=520 width=126)
45. ヒストグラム統計
• 選択率の統計はどのように保持されるか?
• 例:price>3000の時に何行返されるか?
• 全ての選択条件での選択率を保持しておくのは
現実的では無い
• そこでヒストグラムとして保持する
データベースシステム論 第 回2016 [ 12 ] 45p.
ワインID 名前 産地ID 価格
1 シャブリ A 2400
2 ジュヴレシャンベルタン A 3000
3 サンテミリオン B 5800
4 オーメドック B 2200
5 サンセール C 2800
6 シャンパン D 4000
1000 コンチャ・イ・トロ E 980
価格帯 度数(行)
[ 0 – 1000] 1
[1001 – 2000] 0
[2001 – 3000] 4
[3001 – 4000] 1
[4001 – 5000] 0
[5001 – 6000] 1
価格帯 度数(行)
[ 0 – 2200] 2
[2201 – 2800] 2
[2801 – 4000] 2
[4001 – 5800] 1
幅一定方式 奥行一定方式