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チューニング戦略

15,508 views

Published on

2017/10/08 phpcon 2017
https://joind.in/event/japan-php-conference-2017/session05-mysql

Published in: Technology
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Nice !! Download 100 % Free Ebooks, PPts, Study Notes, Novels, etc @ https://www.ThesisScientist.com
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

片手間MySQLチューニング戦略

  1. 1. ⽚⼿間MySQLチューニング戦略 忙しいPHPer(とか)のための「最低限ここから、次のステップはこの へん」 2017/10/08 ⽇本MySQLユーザ会 yoku0825 phpcon 2017
  2. 2. TL;DR スローログを出しましょう InnoDBバッファプール (innodb_buffer_pool_size) は⼗分 ⼤きくしましょう インデックスを使いましょう 劇薬に⼿を出すのはやめましょう 1/77
  3. 3. まずはそ こから 2/77
  4. 4. \こんにちは/ yoku0825@とある企業のDBA オラクれない- ポスグれない- マイエスキューエる- ⽣息域 Twitter: @yoku0825- Blog: ⽇々の覚書- MyNA ML: ⽇本MySQLユーザ会- MySQL Casual: Slack- 3/77
  5. 5. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 4/77
  6. 6. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 5/77
  7. 7. スローログを出す スロークエリー(実⾏に⼀定時間以上時間がかかったクエリ ー)を出⼒させるログ これがないと「どのクエリーが遅かったのか」がそもそもわ からない performance_schema でもいいけどなかなかノイズが多いのでちょっと わかる⼈向け - 6/77
  8. 8. スローログ関連パラメーター name default recommend slow̲query̲log 0(OFF) 1(ON) long̲query̲time 10 0.2(?) log̲output FILE FILE 7/77
  9. 9. スローログを出す slow̲query̲log これをONにしないと始まらない long̲query̲time 応答時間目標と合わせて。MySQLで200msかかるってことは全体ではもっ とかかるはず log̲output FILE の場合テキストファイルに、 TABLE の場合 mysql.slow_log テーブル (CSVストレージエンジン)に出⼒。 FILE,TABLE で両出⼒も可能。テーブ ルに吐かせると並列性能ガタ落ち 8/77
  10. 10. ジェネラルログとは違うの︖ ジェネラルログ ( general_log )はクエリーをパースする 時点(=クエリー実⾏前)で吐き出すログ 実⾏に関する情報(何秒かかった、何⾏フェッチした、またはエラー になったかなど)は何も持っていない - あとジェネラルログはロックがはるかにでかい 9/77
  11. 11. スローログの中味 # Time: 2017-10-02T12:51:35.321319+09:00 # User@Host: root[root] @ localhost [] Id: 78 # Query_time: 0.000497 Lock_time: 0.000176 Rows_sent: 8 Rows_ex amined: 247 SET timestamp=1506916295; SELECT code FROM country WHERE continent = 'Asia' AND region = 'E astern Asia' ORDER BY population; 10/77
  12. 12. スローログの中味 Time そのクエリーが「終了した」時刻。直前のスロークエリーと同じTimeの場 合、この⾏は省略される(5.6とそれ以前でよく⾒る風景) User@Host そのクエリーを実⾏したユーザーと接続元ホスト Id クエリーを実⾏したスレッドのコネクションID(SHOW PROCESSLIST で⾒え るやつ) 11/77
  13. 13. スローログの中味 Query̲time クエリーの実⾏にかかった時間 Lock̲time ロックを取るまでに要した時間 Rows̲sent そのクエリーが返送した結果セットの⾏数(更新系だと0になる) Rows̲examined そのクエリーが結果セットを作成するためにスキャンした⾏数 12/77
  14. 14. スローログの中味 # Time: 2017-10-02T12:51:35.321319+09:00 # User@Host: root[root] @ localhost [] Id: 78 # Query_time: 0.000497 Lock_time: 0.000176 Rows_sent: 8 Rows_ex amined: 247 SET timestamp=1506916295; SELECT code FROM country WHERE continent = 'Asia' AND region = 'E astern Asia' ORDER BY population; 13/77
  15. 15. ポイント Time が短期間に集中している︖ 慢性的に遅いのか、何らかの要因があったのか 慢性的に遅い⽅がチューニングは楽なことが多い 再現しにくいスロークエリーのチューニングは⼿間がかかる - anemometerまたはそのラッパーのanemoeaterが便利- 14/77
  16. 16. 時間分布を把握するためのツール yoku0825/anemoeater 15/77
  17. 17. ポイント Rows_examined / Rows_sent が⼗分⼩さいか︖ GROUP BY を使⽤している場合を除いた SELECT ステートメントでは1 が最も良い - 返送するのに必要な⾏だけを綺麗にストレージから取り出していれば 1になる - これが⼤きいクエリーはインデックスでチューニングするのが楽- あとはそもそも Rows_sent が本当にアプリケーションで必要 とされているのか︖ 3万⾏くらい受け取ってるけど実際には100⾏くらいしか使ってなくて アプリ側で捨てられてたこととか(つらい) - 16/77
  18. 18. Rows_examined / Rows_sent 31くらい # Time: 2017-10-02T12:51:35.321319+09:00 # User@Host: root[root] @ localhost [] Id: 78 # Query_time: 0.000497 Lock_time: 0.000176 Rows_sent: 8 Rows_ex amined: 247 SET timestamp=1506916295; SELECT code FROM country WHERE continent = 'Asia' AND region = 'E astern Asia' ORDER BY population; 17/77
  19. 19. ポイント WHERE 句の値が特定のものに偏っていないか︖ WHERE user_id = 1000 の時だけ遅いとか- 全ての値が均等に分布しているわけではない- 特定の値に対して使うインデックスを使い分けるなどちょっとコツが いる - 18/77
  20. 20. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 19/77
  21. 21. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 20/77
  22. 22. バッファプールの使われ⽅を知る 「物理メモリーの75%」とかよく語られる InnoDBバッファプールはInnoDBの動作の核 なぜ⼤きくなければいけないのか ただのキャッシュではない動き 21/77
  23. 23. ⽤語 ⽤語 意味 ファイル名 主なパラメーター バッファプール メモリー上に確保さ れるヒープ領域 N/A(オンメモリー) innodb_buffer_pool _size ログファイル 更新履歴を記録する ファイル (*) ib_logfile innodb_log_file_si ze, innodb_log_files_i n_group テーブルスペースフ ァイル バッファプールの中 ⾝をストレージに写 し取ったもの ibdata1, *.ibd innodb_file_per_ta ble, innodb_data_home_d ir (*) バイナリーログファイルとは別物 22/77
  24. 24. バッファプールに載っている状態でのSELECT A B AA C B E D F A AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file 23/77
  25. 25. バッファプールに載っていない状態でのSELECT A B AA C B E D F A AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file 24/77
  26. 26. バッファプールに載っていない状態でのSELECT A B AA C B E D F B AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file 25/77
  27. 27. バッファプールに載っていない状態でのSELECT A B AA C B E D F B AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file 26/77
  28. 28. バッファプールの使われ⽅その1 データやインデックスをキャッシュする 単位はページ(デフォルト16kB) バッファプールにヒットした場合、ストレージアクセスはな い ミスヒットした場合のストレージアクセスはバックグラウンドスレッ ド - 27/77
  29. 29. バッファプールに載っている状態でのUPDATE A B AA C B E D F A AA D C UPDATE .. SET = 'X' InnoDB Buffer Pool tablespace file log file 28/77
  30. 30. バッファプールに載っている状態でのUPDATE A B AA C B E D F X AA D C UPDATE .. SET = 'X' InnoDB Buffer Pool tablespace file log file A => X 29/77
  31. 31. この状態でSELECTが⾛ると A B AA C B E D F X AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file A => X 30/77
  32. 32. テーブルスペースファイルへの反映は非同期 X B AA C B E D F X AA D C InnoDB Buffer Pool tablespace file log file A => X 31/77
  33. 33. バッファプールの使われ⽅その2 コミット時に同期的に更新されるのはバッファプールとログ ファイルのみ それでも読み出すデータは(当然)影響を受けない- バッファプール(メモリー)とログファイル(シーケンシャルライ ト)だけの書き込みで⾼速化 - テーブルスペースファイルへの反映は非同期 テーブルスペースファイルへの書き込みはランダムライトになるので やや遅い - コミット後、テーブルスペースファイルに未反映のページをダーテ ィーページと呼ぶ - 32/77
  34. 34. ダーティーページがある状態でSELECT⽤のページが⾜り なくなると A B AA C B E D F X AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file A => X 33/77
  35. 35. ダーティーページがある状態でSELECT⽤のページが⾜り なくなると A B AA C B E D F X AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file A => X 34/77
  36. 36. その時点でそのページに関するログをテーブルスペースフ ァイルに反映して X B AA C B E D F X AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file A => X 35/77
  37. 37. 空いたページにSELECTしたいページを載せてから X B AA C B E D F B AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file A => X 36/77
  38. 38. データを返す X B AA C B E D F B AA D C SELECT .. FROM .. WHERE InnoDB Buffer Pool tablespace file log file A => X 37/77
  39. 39. バッファプールの使われ⽅その3 SELECTしただけなのに 書き込みが⾛った バッファプールに余裕があって 空きページがあれば- 追い出すページがダーティーページでなければ 実際はもうちょっとインテリジェントに判定する - こんなことにはならない- 5.6とそれ以降はWrite on SELECTを避けるための Adaptive Flushingという仕組みがある 38/77
  40. 40. INSERTもほぼ同様 INSERT INTO VALUES ('N') A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file A 39/77
  41. 41. INSERTもほぼ同様 INSERT INTO VALUES ('N') A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file 40/77
  42. 42. INSERTもほぼ同様 A B AA C B E D F AA D C INSERT INTO VALUES ('N') InnoDB Buffer Pool tablespace file log file N 41/77
  43. 43. INSERTもほぼ同様 A B AA C B E D F AA D C INSERT INTO VALUES ('N') InnoDB Buffer Pool tablespace file log file N N/A => N 42/77
  44. 44. INSERTもほぼ同様 A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file N N/A => N 43/77
  45. 45. INSERTもほぼ同様 A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file N N/A => N N 44/77
  46. 46. DELETEだってバッファプールを使う DELETE FROM .. WHERE A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file A 45/77
  47. 47. DELETEだってバッファプールを使う DELETE FROM .. WHERE A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file 46/77
  48. 48. DELETEだってバッファプールを使う DELETE FROM .. WHERE A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file B 47/77
  49. 49. DELETEだってバッファプールを使う DELETE FROM .. WHERE A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file 48/77
  50. 50. DELETEだってバッファプールを使う DELETE FROM .. WHERE A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file B => N/A 49/77
  51. 51. DELETEだってバッファプールを使う A B AA C B E D F AA D C InnoDB Buffer Pool tablespace file log file B => N/A 50/77
  52. 52. まとめ 実はCRUD全ての動作にバッファプールが使われている ただのキャッシュだと思って当たると思わぬWrite on SELECTに遭遇 する - 余裕を持ったサイジングと「無駄遣いしない努⼒」 InnoDB圧縮 (ROW_FORMAT=COMPRESSED)は圧縮前と圧縮後の 両⽅ がバ ッファプールに載る ストレージを稼ぐためにメモリーを犠牲にするような戦略 - 次に続く話- 51/77
  53. 53. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 52/77
  54. 54. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 53/77
  55. 55. インデックスの概観図 セカンダリーインデックスは「ソート済みのデータの部分複製」 root club spade 2 3 2 13 20 18 45 77 54/77
  56. 56. インデックスの概観図 InnoDBはこのツリーを「右または下に だけ 移動できる」 root club spade 2 3 2 13 20 18 45 77 55/77
  57. 57. インデックスの概観図 セカンダリーインデックスのリーフノードには「PRIMARY KEY の値」 root club spade 2 3 2 13 20 18 45 77 56/77
  58. 58. InnoDBクラスターインデックスのイメージ root club spade 2 3 A 13 20 18 45 2 23 root p2 p13 p18 p20 p23 p45 Spade-A Club-2 1 Club-3 Club-2 Spade-A Club-3 Secondary Index Clustered Index 57/77
  59. 59. MySQLの(インデックスの)得意な操作 特定のキーの値を狙い撃ち( = 演算⼦と AND 演算⼦) 概観図でいうところの「右に進む」操作- IN 演算⼦なんかも効くっちゃ効くけど、 ORDER BY まで波及しないケ ースあり - リーフノードが並んでいる順番での ORDER BY 概観図でいうところの「下に進む」操作- EXPLAIN で Extra: Using filesort になっているケースの⾼速化- JOIN はこれを狙うのに慣れがいるので敬遠されがち- 58/77
  60. 60. 簡単な憶え⽅ インデックスは WHERE 句のカラムを列挙してから ORDER BY 句のカラムを列挙する = と AND しか使ってない場合はこれでいける SELECT .. FROM country WHERE continent = 'Asia' AND region = 'Eastern Asia' ORDER BY population; ↓ KEY(continent, region, population) 59/77
  61. 61. 簡単な憶え⽅(︖) こう︖ SELECT .. FROM country JOIN countrylanguage ON country.code= countrylanguage.countrycode WHERE country.continent = 'Asia' ORDER BY countrylanguage.percentage LIMIT 5; ↓ country: KEY(continent) countrylanguage: KEY(countrycode, percentage) 60/77
  62. 62. 簡単な憶え⽅(︖) *************************** 1. row *************************** id: 1 select_type: SIMPLE table: country partitions: NULL type: ref possible_keys: PRIMARY,idx_continent key: idx_continent key_len: 1 ref: const rows: 51 filtered: 100.00 Extra: Using temporary; Using filesort *************************** 2. row *************************** id: 1 select_type: SIMPLE table: countrylanguage partitions: NULL type: ref possible_keys: PRIMARY,CountryCode,idx_countrycode_percentage key: PRIMARY key_len: 3 ref: world.country.Code rows: 4 filtered: 100.00 Extra: NULL 61/77
  63. 63. 簡単じゃない憶え⽅ ⼀番速くなるのは実はこう SELECT .. FROM country JOIN countrylanguage ON country.code= countrylanguage.countrycode WHERE country.continent = 'Asia' ORDER BY countrylanguage.percentage LIMIT 5; ↓ country: KEY(code, continent) countrylanguage: KEY(percentage) 62/77
  64. 64. 簡単じゃない憶え⽅ *************************** 1. row *************************** id: 1 select_type: SIMPLE table: countrylanguage partitions: NULL type: index possible_keys: NULL key: idx_percentage key_len: 4 ref: NULL rows: 5 filtered: 100.00 Extra: NULL *************************** 2. row *************************** id: 1 select_type: SIMPLE table: country partitions: NULL type: ref possible_keys: idx_code_continent key: idx_code_continent key_len: 4 ref: world.countrylanguage.CountryCode,const rows: 1 filtered: 100.00 Extra: NULL 63/77
  65. 65. JOINだと簡単な憶え⽅が通⽤しにくい(´・ω・`) とはいえ平均的に⾏数が絞り込めるので、体感で遅くなるま ではこれで⼗分戦える 詳しく知りたい⽅は Where狙いのキー、order by狙いのキ ー のスライドをどうぞ 64/77
  66. 66. ポイント AND と = 以外の演算⼦を ORDER BY と混ぜて使わない 概観図でいうところの「左に⾏く」必要がありそうな動作- NOT, IN, <, >, OR などなど- 使っている場合、AND と = だけの形に落とし込めないか︖ 5.7とそれ以降はgenerated columnで式インデックスが使える - インデックスを張ってあるカラムに対する演算をしない ⾏から値を取り出して計算するまでWHERE句の評価ができない = 不 要な⾏までフェッチして評価してしまう - NG: WHERE price * 1.08 = 108- OK: WHERE price = 100- 65/77
  67. 67. インデックスを綺麗に使うと バッファプールを⼤事に使える テーブルデータよりもインデックスの⽅が⼩さい ミスヒット率が下がる - そもそもバッファプールに出⼊りするページの数が減る 非同期のダーティーページフラッシュで⼗分戦える - デフォルトのInnoDBのロックはネクストキーロック インデックスで絞り込めれば絞り込めるほど、ロックの粒度が⼩さく なっていく - 66/77
  68. 68. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 67/77
  69. 69. おしながき スローログを出す バッファプールの気持ちになる インデックスの基本戦略を理解する 劇薬に⼿を出さない 68/77
  70. 70. MySQLの劇薬 skip_innodb_doublewrite innodb_flush_log_at_trx_commit <> 1 sync_binlog <> 1 パラメーター名に unsafe とか⼊ってるやつ MyISAMストレージエンジン 69/77
  71. 71. MySQLの劇薬 今までやってきたのが何だったんだってくらい性能が上がる (こともある) ただし、これらの設定はだいたい「クラッシュ時のデータの 保全性」を犠牲にしている mysqld が落ちた後、データが壊れているかも知れない- 壊れているならまだしも、黙って抜け落ちているかも知れない- 70/77
  72. 72. ダメ、絶 対 71/77
  73. 73. まとめ スローログを出しましょう InnoDBバッファプール (innodb_buffer_pool_size) は⼗分 ⼤きくしましょう インデックスを使いましょう 劇薬に⼿を出すのはやめましょう 72/77
  74. 74. おまけ バージョンを上げるにつれ、オンラインで変更できるパラメ ーターが増えている バージョンはなるべく新しいものにした⽅がいくらでも取り返しがつ くように - MySQL 5.7だとついにオンラインでバッファプールのサイズが変更で きるようになったし - 73/77
  75. 75. And next… ダーティーページが溜まり続けるとログファイルを書ききっ てしまうかも SHOW PROCESSLIST, SHOW GLOBAL STATUS などで現状を可視化 していく SHOW ENGINE INNODB STATUS からトランザクションの様⼦に 目を配る 74/77
  76. 76. And next… information_schema.innodb_lock_waits から競合している ロックを探して更にインデックスを⾜す EXPLAIN と仲良くなって JOIN でもORDER BY狙いのキーを 狙っていく information_schema.innodb_buffer_page, ib_buffer_pool からどのテーブルがどの程度バッファプールを占めているの かを確認する memcachedにキャッシュさせる(ぁ 75/77
  77. 77. Further more… ⼀通りこの辺を調べてなお深く知りたくなったら、MySQL の英霊を召喚するといいと思うの ⽇本MySQLユーザ会 MySQL Mailing List- MySQL Casual MySQL CasualのSlackへの参加- 76/77
  78. 78. Questions and/or Suggestions? 77/77

×