Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

MySQL勉強会 インデックス編.2013 08-02

4,445 views

Published on

Published in: Technology
  • Be the first to comment

MySQL勉強会 インデックス編.2013 08-02

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

×