mysql勉強会 インデックス編.2013 08-02
TRANSCRIPT
![Page 1: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/1.jpg)
MySQL社内講習 インデックス編
CROOZ Team Venus
![Page 2: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/2.jpg)
目次
• インデックスとは • EXPLAINとは • インデックスが使えない場合 • インデックスの種類 • インデックスの制限事項 • 複合インデックス • カバリングインデックス • まとめ • 参考資料
![Page 3: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/3.jpg)
『インデックスとは』
![Page 4: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/4.jpg)
インデックスとは 目次のことです
![Page 5: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/5.jpg)
目次が在るから目的のページが探せる
![Page 6: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/6.jpg)
目次がないと….。
![Page 7: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/7.jpg)
最初から全部 読まなければならない
![Page 8: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/8.jpg)
目次は万能じゃない
• ページがしょっちゅう増えるとその都度目次も作り直す
• 目次のページ数自体が大きすぎると本末転倒
• 適正に目次を作成して使用するのが大事
![Page 9: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/9.jpg)
事例に基づいて 考えて見ましょう
![Page 10: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/10.jpg)
アイテムの付与ミスったー
![Page 11: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/11.jpg)
取り消しバッチを作れー!
![Page 12: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/12.jpg)
付与したtimestampを 条件に論理削除すれば
良いよね
![Page 13: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/13.jpg)
付与したtimestampを 条件に論理削除すれば
良いよね 死亡フラグ
![Page 14: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/14.jpg)
demo
![Page 15: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/15.jpg)
対象テーブル
・贈り物テーブル ・ヒストリーデータ ・サンプルのデータは180万件
![Page 16: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/16.jpg)
mysql> UPDATE prize_history SET del_flg = 1 WHERE prize_id = 14 AND ctime BETWEEN '2013-05-18 00:00:00' AND '2013-05-24 00:00:00';
実行するSQL
イベント報酬ID
イベント開始日時
イベント終了日時
![Page 17: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/17.jpg)
どうすれば良かったのか?
![Page 18: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/18.jpg)
まずはEXPLAINを実行
![Page 19: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/19.jpg)
EXPLAINとは
![Page 20: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/20.jpg)
EXPLAINとは
• SQLの実行計画を見るクエリー
• インデックスの使用状況を確認できる
• 実行するSQLの先頭にEXPLAINをつける (※ DELETE文/UPDATE文の場合はSELECT文に置き換える) (※ WHERE句があるSQLはインデックスが使われる)
![Page 21: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/21.jpg)
mysql> EXPLAIN SELECT * FROM prize_history WHERE prize_id = 14 AND ctime BETWEEN '2013-05-18 00:00:00' AND '2013-05-24 00:00:00'\G;*************************** 1. row *************************** id: 1 select_type: SIMPLE table: prize_history type: ALLpossible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 2233733 Extra: Using where
【クエリーのタイプ】:全件検索
【使用されているインデックス】: インデックスが使われていない
【検索行数】:テーブル全行数
【追加情報(処理方法)】:Using temoraryと、 Using filesortは要注意、それぞれ、一時書き出し、ファイルソートが発生していてクエリーが遅くなる傾向がある
![Page 22: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/22.jpg)
SHOW INDEX FROM prize_history;+----------------------+------------+----------+--------------+-----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |+----------------------+------------+----------+--------------+-----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| prize_history | 0 | PRIMARY | 1 | prize_history_id | A | 2235476 | NULL | NULL | | BTREE | | || prize_history | 1 | user_id | 1 | user_id | A | 2235476 | NULL | NULL | | BTREE | | || prize_history | 1 | user_id | 2 | receive_flg | A | 2235476 | NULL | NULL | | BTREE | | |
| prize_history | 1 | user_id | 3 | prize_id | A | 2235476 | NULL | NULL | | BTREE | | |+----------------------+------------+----------+--------------+-----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (5.73 sec)
インデックスを確認する
ctimeのインデックスがない
インデックス名 インデックス種別 対象カラム
プライマリキー プライマリキー prize_history user_id インデックス user_id,receive_flg,prize_id
![Page 23: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/23.jpg)
ALTER TABLE prize_history ADD KEY prize_id (prize_id,ctime);EXPLAIN SELECT * FROM prize_history WHERE prize_id = 14 AND ctime BETWEEN '2013-05-18 00:00:00' AND '2013-05-24 00:00:00'\G;*************************** 1. row *************************** id: 1 select_type: SIMPLE table: prize_history type: rangepossible_keys: prize_id key: prize_id key_len: 12 ref: NULL rows: 186246 Extra: Using where;
インデックス追加
![Page 24: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/24.jpg)
■ BEFOREmysql> SELECT SQL_NO_CACHE count(*) FROM prize_history WHERE prize_id = 14 AND ctime BETWEEN '2013-05-18 00:00:00' AND '2013-05-24 00:00:00';+----------+| count(*) |+----------+| 86399 |+----------+1 row in set (3.62 sec)
■ AFTER
mysql> SELECT SQL_NO_CACHE count(*) FROM prize_history WHERE prize_id = 14 AND ctime BETWEEN '2013-05-18 00:00:00' AND '2013-05-24 00:00:00';+----------+| count(*) |+----------+| 86399 |+----------+1 row in set (0.06 sec)
BEFORE/AFTER
60x FAST
![Page 25: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/25.jpg)
インデックスが使えない場合
• テーブルの後ろから読みLIMITで制限をかける。ヒストリー系のテーブルで有効
• 使えるインデックスに変換する
![Page 26: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/26.jpg)
ctimeを プライマリキーに変換
イベント期間
2013/04/23
2013/05/18 2013/05/24 2013/05/30
× 最初からフルスキャンするにはデータが多すぎる
2181000
1
2008199 2094599
ctimeをプライマリキーに
変換 データの終わりから フルスキャン指定期間に達したらクエリ終了
![Page 27: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/27.jpg)
対象となる期間の プライマリキーのIDを検索
![Page 28: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/28.jpg)
SELECT prize_history_id FROM prize_history WHERE ctime < '2013-05-18 00:00:00' ORDER BY prize_history_id DESC LIMIT 1;+-----------------------+| prize_history_id |+-----------------------+| 2008199 |+-----------------------+
イベント開催日時 ※バックアップサーバーで実行
![Page 29: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/29.jpg)
SELECT prize_history_id FROM prize_history WHERE ctime < '2013-05-24 00:00:00' ORDER BY prize_history_id DESC LIMIT 1;+-----------------------+| prize_history_id |+-----------------------+| 2094599 |+-----------------------+
イベント終了日時 ※バックアップサーバーで実行
![Page 30: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/30.jpg)
mysql> EXPLAIN SELECT * FROM prize_history WHERE prize_id = 14 AND prize_history_id BETWEEN 2008199 AND 2094599\G;*************************** 1. row *************************** id: 1 select_type: SIMPLE table: prize_history type: rangepossible_keys: PRIMARY key: PRIMARY key_len: 8 ref: NULL rows: 174524 Extra: Using where
期間をプライマリキーに 置き換えてEXPLAIN
![Page 31: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/31.jpg)
UPDATE prize_history SET del_flg=1 WHERE prize_id = 14 AND prize_history_id BETWEEN 2008199 AND 2094599;
UPDATE文を作成
×
![Page 32: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/32.jpg)
1つのSQLでまとめて update/insert/delete しない
![Page 33: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/33.jpg)
詳しくは 次回『リプリケーション』編で
![Page 34: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/34.jpg)
1行更新する UPDATE文を作成する
• プログラムでselectした結果からforで回して、一行更新するのupdate文を実行するバッチを作る
• SELECTした結果をEXCELに貼ってマクロでUPDATE文を作成する
• SQLで1行更新するupdate文のSQLを作成
![Page 35: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/35.jpg)
SQLで1行更新する update文のSQLを作成
![Page 36: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/36.jpg)
SELECT CONCAT( 'UPDATE prize_history ', 'SET del_flg = 1 ', 'WHERE prize_history_id =', prize_history_id,';' ) FROM prize_history WHERE prize_id = 14 AND prize_history_id BETWEEN 2008199 AND 2094599;
UPDATE文作成 ※バックアップサーバーで実行
![Page 37: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/37.jpg)
バックアップ作成
SELECT CONCAT( 'UPDATE prize_history ', 'SET del_flg = ',del_flg,' ', 'WHERE prize_history_id =', prize_history_id,';' ) FROM prize_history WHERE prize_id = 14 AND prize_history_id BETWEEN 2008199 AND 2094599;
※バックアップサーバーで実行
![Page 38: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/38.jpg)
『インデックスの種類』
![Page 39: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/39.jpg)
インデックスの種類
• プライマリキー • ユニークキー • インデックス
![Page 40: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/40.jpg)
インデックスの制限事項
• !=、<>はインデックスが使用できない
• LIKE検索では前方一致のみ使用できる。
![Page 41: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/41.jpg)
『複合インデックスとは』
![Page 42: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/42.jpg)
複数のカラムに対する インデックス
複合インデックスとは
![Page 43: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/43.jpg)
複合インデックスは 先頭から順に部分インデックス
として使用できる。
![Page 44: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/44.jpg)
つまり
• index(user_id,category_id,del_flg) という複合インデックスがあった場合 ×index(user_id,category_id) ×index(user_id) のインデックスは作る必要がない
![Page 45: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/45.jpg)
テスト用テーブル
・サンプルのデータは10万件
カラム名 型
id unsinged int(11)
A unsinged int(11)
B varchar(255) C unsinged int(11)
インデックス名
インデックス種別
対象カラム
pkey プライマリキー Id
index_A インデックス A
index_B インデックス B
index_C インデックス C
index_A_B_C
インデックス A,B,C
![Page 46: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/46.jpg)
複合インデックス が使える場合
• SELECT * FROM test WHERE A=1 and B=2 and C=3
• SELECT * FROM test WHERE A=1 and B=2
• SELECT * FROM test WHERE A=1 ※ INDEX index_a_b_c(A,B,C)の場合
![Page 47: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/47.jpg)
複合インデックス が使えない場合
• SELECT * FROM test WHERE B=2 and C=3
• SELECT * FROM test WHERE A=1 and C=3
• SELECT * FROM test WHERE B=2
※ INDEX index_a_b_c(A,B,C)の場合
![Page 48: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/48.jpg)
複合インデックスは 順番が重要
![Page 49: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/49.jpg)
カバリング インデックスとは
![Page 50: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/50.jpg)
対象となるすべての 検索条件・検索項目を含んだ
複合インデックス
![Page 51: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/51.jpg)
カバリングインデックスの例
• SELECT A,B,C FROM test WHERE A=1 and B=2 and C=3
• SELECT A FROM test WHERE A=1 and B=2
• SELECT A,B,C FROM test WHERE A=1
※ INDEX index_a_b_c(A,B,C)の場合
![Page 52: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/52.jpg)
カバリングインデックス EXPLAIN
EXPLAIN SELECT A,B,C FROM test WHERE A=757 AND b='0.ZYc2FHB0kpo' \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: test type: ref possible_keys: index_A,index_B,index_A_B_C key: index_A_B_C key_len: 771 ref: const,const rows: 1 Extra: Using where; Using index
Indexを使っているという意味ではない。Index内のデータを使用しているという意味(カバリングインデックス)
![Page 53: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/53.jpg)
インデックススキャンだけで 完結しているので
非常に高速
![Page 54: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/54.jpg)
通常の場合
インデックス
データベース
クエリ
結果セット
インデックスを元にデータベース
を参照
![Page 55: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/55.jpg)
カバリングインデックスの場合
インデックス
クエリ
結果セット
InnoDBの場合、インデックスにデータが含まれる為、対象データがインデックスに存在すれば、データベース参照なしで結果セットを返す。
![Page 56: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/56.jpg)
だだし、サマリーテーブルを 作るようなものなので、 ディスク容量に注意
![Page 57: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/57.jpg)
まとめ
• ムダなインデックスは作らない。
• インデックスは出来るだけ1つの複合インデックスで複数カバー出来るように作る。カラムの順番が重要。
![Page 58: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/58.jpg)
次回予告
![Page 59: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/59.jpg)
インデックスが効かないとどうなるか
![Page 60: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/60.jpg)
MySQL社内講習 リプリケーション編
![Page 61: MySQL勉強会 インデックス編.2013 08-02](https://reader036.vdocuments.pub/reader036/viewer/2022062708/558aff76d8b42a86338b4571/html5/thumbnails/61.jpg)
『参考資料』 ・ソーシャルゲーム開発者なら知っておきたい MySQL INDEX + EXPLAIN入門 ・MySQL5からのインデックス結合で1テーブル複数インデックスを使う ・実践ハイパフォーマンスMySQL 第2版