lt・dbチューニング

22
DBチューニング MySQL編~ by po seed

Upload: pollseed

Post on 14-Apr-2017

133 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Lt・dbチューニング

DBチューニング~MySQL編~

by poll seed

Page 2: Lt・dbチューニング

まずは、テーブルを作る

商品テーブル

都道府県

商品

分類

Page 3: Lt・dbチューニング

インデックスなし1. 商品全体テーブルを作成

CREATE TABLE `item` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `pref_code` int(11) NOT NULL, `items_code` int(11) NOT NULL, `classify_code` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8

2. 各々のcodeに対して正規化しテーブルを生成→比較のためキーなどは設けない

Page 4: Lt・dbチューニング

クエリの実行計画1. Explainにより実行計画を調べる

explain SELECT * FROM item i inner join pref p on i.pref_code = p.pref_code WHERE p.pref_code = 1 ;

2. 実行計画結果

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 1, SIMPLE, p, const, PRIMARY, PRIMARY, 4, const, 1, 1, SIMPLE, i, ALL, , , , , 21, Using where

※「i」テーブルのtypeが「ALL」となっている

Page 5: Lt・dbチューニング

ALLとはそもそもtypeとはなんだろうか

結論から言えば、「結合型」

さらに言えば、ALLと言うのは「フルテーブルスキャン」のALLである。ただの爆遅結合ということ

要は、ALLなんて出してはいけない

Page 6: Lt・dbチューニング

改善しよう

typeで爆速なのがsystem, constである。

systemというのは1レコードのみなので「const」,

次に早い「eq_ref」を目指すというのがエンジニアの必須事項

Page 7: Lt・dbチューニング

手を加える11. indexの追加

ALTER TABLE `test`.`item` ADD INDEX `idx_item1` USING BTREE (`pref_code` ASC);

2. 実行計画

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 1, SIMPLE, p, const, PRIMARY, PRIMARY, 4, const, 1, 1, SIMPLE, i, ALL, idx_item1, , , , 21, Using where

※idx_item1がキーの候補として出てきた。ただし、まだALLである。

Page 8: Lt・dbチューニング

pref_codeにインデックスをつけることについて考える1

通常、B木インデックスをつける時は、カーディナリティの高い列を選ぶことが前提としてある

なぜならば、B木をより平坦にする必要があるからである。平坦というのはリーフが多い状態

具体的にはレコード全体の5%以下に抑えることができる場合、インデックスを張るのは有効と言われる

Page 9: Lt・dbチューニング

pref_codeにインデックスをつけることについて考える2

pref_codeというのは都道府県である。よって、47

件のデータが存在する。1件につき全体のデータを大体2.1%程度に絞る事が可能

先の前提を元にすれば充分インデックスを張るのが有効だと言えよう

Page 10: Lt・dbチューニング

手を加える21. 外部キーを付ける

ALTER TABLE `test`.`item` ADD CONSTRAINT `fk_item1` FOREIGN KEY (`pref_code`) REFERENCES `test`.`pref` (`pref_code`) ON DELETE NO ACTION ON UPDATE NO ACTION;

2. 実行計画

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 1, SIMPLE, p, const, PRIMARY, PRIMARY, 4, const, 1, 1, SIMPLE, i, ALL, idx_item1, , , , 21, Using where

Page 11: Lt・dbチューニング

変わっていない?

Page 12: Lt・dbチューニング

もう一度先ほどの話を見てみよう

Page 13: Lt・dbチューニング

pref_codeにインデックスをつけることについて考える1

通常、B木インデックスをつける時は、カーディナリティの高い列を選ぶことが前提としてある

なぜならば、B木をより平坦にする必要があるからである。平坦というのはリーフが多い状態

具体的にはレコード全体の5%以下に抑えることができる場合、インデックスを張るのは有効と言われる

Page 14: Lt・dbチューニング

どういうことか

言うなれば、概算としてレコードを2.1%におさえれるという想定で先のインデックスを張り、外部キーまで加えたのにALLのまま

現場では得てしてこういうことが起こる。

それでは、このカラクリを紐解いてみよう。

Page 15: Lt・dbチューニング

件数ベースで確認1. 件数を見てみよう

SELECT COUNT(*), COUNT(IF(pref_code = 1, 1, NULL)) FROM test.item;

2. 件数の結果

# count(*), count(if(pref_code=1,1,null)) 21, 16

※全体の76%以上がpref_code=1となっている。

想定では高いと思っていたが、データ的にはカーディナリティが低いのである。

Page 16: Lt・dbチューニング

データ確認1select * from item where pref_code <> 1;

# id, pref_code, items_code, classify_code 1, 3, 1, 1 18, 2, 1, 1 19, 2, 2, 1 20, 2, 3, 1 21, 2, 4, 1

※3のカーディナリティは4.7%と高いため、こいつで条件を見てみる

Page 17: Lt・dbチューニング

データ確認2

1. 実行計画をpref_code=3で見てみる

explain SELECT * FROM item i inner join pref p on i.pref_code = p.pref_code where p.pref_code = 3;

2. 結果

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 1, SIMPLE, p, const, PRIMARY, PRIMARY, 4, const, 1, 1, SIMPLE, i, ref, idx_item1, idx_item1, 4, const, 1,

※問題なくインデックスが使われている

Page 18: Lt・dbチューニング

まとめB木インデックスをつける時は、カーディナリティの高い列を選ぶ

レコード全体の5%以下に抑えることができる場合、インデックスを張るのは有効

ただし、データ件数によっては、インデックスが有効でない場合も実際の現場では多い

Page 19: Lt・dbチューニング

発展として複合インデックスについてはどうか?

カーディナリティの高い順に貼っていくのが妥当と思われる

現場でデータ件数を元に決めるのがよい

検索するときも、インデックスが効くようにWhere文で検索する順序に注意

Page 20: Lt・dbチューニング

余力があればハンズオン

以下のURLにアクセス

https://raw.githubusercontent.com/pollseed/linux_setup/master/src/hackathon/db/tuning_before.sql

Q1~Q3をできるところまで

Page 21: Lt・dbチューニング

資料

以下のドキュメントも参考にして下さい

https://raw.githubusercontent.com/pollseed/linux_setup/master/src/hackathon/db/doc.md

Page 22: Lt・dbチューニング

Fin