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.
MySQLerの七つ道具
2016/11/26
yoku0825
第18回 中国地⽅DB勉強会 in 広島
\こんにちは/
yoku0825@GMOメディア株式会社
オラクれない-
ポスグれない-
マイエスキューエる-
⽣息域
Twitter: @yoku0825-
Blog: ⽇々の覚書-
MyNA ML: ⽇本MySQLユーザ会-
MySQL C...
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
2/79
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
3/79
pt-query-digest
みんなだいすきPercona Toolkitの⼈気No.1
スローログをまとめて⾒やすくしてくれる
⼤⽂字⼩⽂字、⽂字列定数と数値定数をノーマライズして「ダイジェ
スト」ごとに集約
-
4/79
先頭のセクション
$ pt-query-digest /path/to/slowlog
..
# Time range: 2016-03-16 17:29:32 to 2016-11-22 11:37:24
# Attribute total ...
先頭のセクション
まああんま⾒ない
6/79
ダイジェスト⼀覧
# Profile
# Rank Query ID Response time Calls R/Call V/M It
em
# ==== ================== ================ ===== =...
ダイジェスト⼀覧
デフォルトでは「トータルでかかった時間」の降順
--order-by で変えられるデフォルトは “Query̲time:sum”
書き⽅にちょっとクセがある
Query̲time:max
Query̲time:sum
Rows...
ダイジェストごと、前半
Query 1: 0.00 QPS, 0.01x concurrency, ID 0x15E7E7E2F486896A at byte 6304792
# This item is included in the rep...
ダイジェストごと、前半
1⾏目に ID 0x.. があるので、ダイジェスト⼀覧から検索で
⾶んでくるとよし
Time range を⾒ないと、実は半年前に撲滅されたクエリー
を⼀⽣懸命EXPLAINする⽻目に遭ったり
単発のクエリーが⼤きくて累...
ダイジェストごと、後半
# Query_time distribution
# 1us
# 10us
# 100us
# 1ms
# 10ms
# 100ms
# 1s
# 10s+ ##############################...
ダイジェストごと、後半
クエリーごとにバラつきがあるか︖
バラついているなら、カーディナリティーの悪戯か、それともキャッ
シュの具合か
特にInnoDB圧縮を使ってる場合、バッファプールミスヒットやテーブルキャッシュミ
スヒットのコストは⼤きい...
pt-query-digestと上⼿く付き合うコツ
--since オプションはほぼ必須
--since オプションでもログは舐めてしまうので、⼤きなログを⾷わ
すのであれば tail -50000 slow.log | pt-query-di...
with Anemometer
pt-query-digest の出⼒結果を可視化するツール
pt-query-digest の結果をMySQLに⼊れる機能(--history,
--review)をそのまま使ってる
box/Anemomete...
Anemometerの弱点
テーブル上UNIQUE KEY (hostname_max, checksum, ts_min,
ts_max)で、Anemometerはts_minでプロットするため、そ
のクエリーがts_minに集中したことにな...
Anemometerの弱点
⽇次で pt-query-digest を回している程度だと、⽇単位までし
か分解できない
16/79
anemo eat er
スローログをスプリットして pt-query-digest を呼びまくる
1分ぶんずつ pt-query-digest に⾷わせれば、ts_min と ts_max の差
は最⼤でも1分
-
AnemometerをDo...
with anemo eat er
1分単位でプロットできる
18/79
anemo eat er
リアルタイムでなくてもいい
スロークエリーのリアルタイム通知は別の⽅法でしてる-
グラフで⾒られれば数分前の情報であっても全然構わない-
リアルタイムを捨てて
保存期間を考えない
スローログが残っている限りの情報を、最...
anemo eat er
現在のところ docker と pt-query-digest はホストにインス
トールしておかないとダメ
$ git clone https://github.com/yoku0825/anemoeater
$ cd...
pt-query-digest
だいたいこんな感じでDailyの動きをメールで⾶ばしてる
気になったら anemo eat erで⾒る
$ pt-query-digest --since=$(date -d yesterday "+%Y-%m-...
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
22/79
EXPLAIN
今更なのでEXTENDEDの話しかしないよ
23/79
目XPLAIN
出来る⼈︖
24/79
Please 目XPLAIN Me
SELECT DISTINCT
T.c_month,
T.unique_id
FROM
(SELECT A.a_id, DATE_FORMAT(C.datetime, '%Y%m') AS c_month, ...
実はこれ、5.6
と5.7で実⾏計
画が違う
26/79
5.6
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
type: ref
...
5.7
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: C
partitions: NULL
typ...
5.6
mysql> SHOW WARNINGSG
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /...
5.7
> SHOW WARNINGSG
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* sel...
EXPLAIN EXTENDED
5.7からはデフォルトでEXTENDEDがついてくる
EXPLAIN直後に SHOW WARNINGS でオプティマイザーが最適化した後
のクエリーが⾒える
-
想像したのと違う遅くなり⽅ をしたらEXTEND...
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
32/79
PMP(Percona Monitoring Plugins) for Cacti
別に for Zabbixでもいいと思う
単にウチはもともとCactiを使っていたからというだけ
33/79
PMP for Cacti
rrdtoolだから容量効率は素晴らしい
rrdtoolだから丸め誤差は厳しい
CactiそのものがWEBからポチポチするインターフェースな
のつらい
ss̲get̲mysql̲stats.php ⾃体はPHPで、頑...
Data Input Methodのデフォルトを⼀気にSQLで書き換
えるとか
mysql> UPDATE data_input_fields JOIN data_input_data ON data_input_fields.id
= dat...
Device追加する時にポートを⼀⻫に変えるブックマーク
レットだとか
javascript:void((function(elems,port){for(var p in elems){elems[p
].value=port}})(docu...
みんなどうし
てるんだろう
37/79
PMP for Cacti
やっぱり視認性だいじ
絶対値に惑わされない
問題が起きていなくてもたまには⾒る
たまには⻑い期間で⾒る
使いづらいものはユーティリティー作っちゃえばいいと思う
38/79
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
39/79
innotop
みんな⼤好き、topライクに SHOW PROCESSLIST を表⽰して
くれるinnotop
地味に “M” (Replication Status) も便利
なんとMSR対応してるんだぜ
-
“L” (InnoDB Loc...
innotop
41/79
innotop
地味に機能は多いけど今のバージョンだと表⽰されない項目
がたまにある
旧バージョンのサポート切れば楽なんだけど…と思ったり思わなかっ
たり
-
ALTER TABLE や percona-toolkit で重いことやる時のおとも...
innotop
中⾝は結構スパゲティ
最近メンテナンス遅め
ちょっと⾊々事情が-
⽇々の覚書: innotopのその後 2016年6⽉-
43/79
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
44/79
SHOW PROFILE
MySQLの組み込みプロファイラー
「そのクエリーが実⾏されていた期間、どのStatus(SHOW
PROCESSLIST で “State” と表⽰されているもの)にどのくら
いの時間かかったか
使うのが超簡単
45...
SHOW PROFILE
mysql> SET @@profiling= 1;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> ..;
mysql> SHOW PROFILE;
+-...
SHOW PROFILE
組み込みだから使うのは超簡単
プロファイルを「どう解析するか」はまた別の問題
ざっと⾒てわかりやすいところに時間がかかってたらつぶせ
る…くらいのノリ
再現性がないとつらい
47/79
SHOW PROFILE S
mysql> SHOW PROFILES;
+----------+-------------+-----------------------------------------------------------...
SHOW PROFILE FOR QUERY ..
mysql> SHOW PROFILE FOR QUERY 4;
+------------------------------+-----------+
| Status | Duratio...
SHOW PROFILE
MySQL 5.6でdeprecated
代替として performance_schema.events_stages_* と
events_statements_* が案内されている…けど
-
@@profiling...
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
51/79
performance̲schema(p̲s)
パフォーマンスモニタリング専⽤のストレージエンジン
MySQL 5.6から真っ当に使えるようになってる
吊るしのデフォルトではONになってる-
計測する項目も「だいたい必要になりそうなところ」だけ...
p_s.setup_*
mysql> SHOW TABLES FROM performance_schema LIKE 'setup_%';
+-----------------------------------------+
| Table...
p_s.setup_consumers
mysql> SELECT * FROM setup_consumers;
+----------------------------------+---------+
| NAME | ENABLED ...
p_s.setup_instruments
mysql> SELECT SUBSTRING_INDEX(`name`, '/', 2) AS short_name, ANY_VALUE(name) AS example, SUM(ENABLED...
統計情報へのアクセス
mysql> SHOW TABLES;
..
| events_stages_summary_by_account_by_event_name |
| events_stages_summary_by_host_by_ev...
p̲s⾃体のモニタリング
mysql> SHOW ENGINE PERFORMANCE_SCHEMA STATUS;
+--------------------+-----------------------------------------...
sys
p̲sの情報を⾒やすくするためのビューやストアドファンク
ション、ストアドプロシージャ
名前空間として sys スキーマを使うのでそう呼ぶことも
performance_schema = OFF の状態ではほとんどからっぽ
MySQL ...
sysのインストール(5.6向け)
$ git clone https://github.com/mysql/mysql-sys.git
Initialized empty Git repository in /root/mysql-sys/....
sys.statement_analysis
p_s.events_statements_summary_by_digest のビュー
超⾒やすい
これのためだけに p̲s有効にする価値がある
60/79
sys.statement_analysis
mysql> SELECT * FROM statement_analysisG
..
*************************** 2. row ********************...
sys.innodb_lock_waits
いわゆるSH2さんの アレ とほぼ同等の機能
これは i̲s のビューなので、p̲sが無効でもフツーに⾒られ
る
バンドルされて便利になったという感じ
62/79
sys.innodb_lock_waits
mysql57> SELECT * FROM innodb_lock_waitsG
*************************** 1. row ***********************...
sys.ps_truncate_all_tables
ストアド
p̲s は起動時から統計情報を累積するが、それをリセットす
るにはp̲sの各テーブルに対してTRUNCATEが必要
それを全部まとめてやってくれる、ただそれだけなんだけど
便利なス...
sys.x$*
x$ で始まるビューは、 x$ のない他のビューと対になってい
る
フツーの⽅は、[kMG]B をまとめたり [num]s をまとめた
りしてくれるが、そうすると⽂字列になっちゃうのでソート
に不便
そんな時、 x$ のビューは...
MySQLer七つ道具
pt-query-digest1.
EXPLAIN2.
PMP for Cacti3.
innotop4.
SHOW PROFILE5.
performance̲schema & sys6.
???7.
66/79
Do you
know
“Dimitri”?
67/79
Dimitri KRAVTCHUK
68/79
Dimitriおじさん says
69/79
Dimitriおじさん says
70/79
Dimitriおじさん says
71/79
エコシステム
たとえば MariaDB, Percona Server
たとえば MHA for MySQL, HandlerSocket
たとえば ⽇本MySQLユーザ会, MySQL Casual
たとえば Oracle
72/79
USE YOUR
BRAIN
73/79
but/and
74/79
YOU are
not alone.
75/79
2年前
76/79
みなさんのご参加をお待ちしております :)
MyNA ML: ⽇本MySQLユーザ会
MySQL Casualʼs Slack: MySQL Casual
77/79
Advent Calendarのおさそい
まだまだお席に余裕がございます
具体的には 20 名様ほどお⼊りいただけます-
@soudai1025-
@kkkida̲twtr-
@kamipo-
MySQL Casual Advent Calen...
Questions
and/or
Suggestions?
79/79
Upcoming SlideShare
Loading in …5
×

MySQLerの7つ道具

4,944 views

Published on

2016/11/26 中国地方DB勉強会 in 広島

Published in: Technology
  • Be the first to comment

MySQLerの7つ道具

  1. 1. MySQLerの七つ道具 2016/11/26 yoku0825 第18回 中国地⽅DB勉強会 in 広島
  2. 2. \こんにちは/ yoku0825@GMOメディア株式会社 オラクれない- ポスグれない- マイエスキューエる- ⽣息域 Twitter: @yoku0825- Blog: ⽇々の覚書- MyNA ML: ⽇本MySQLユーザ会- MySQL Casualʼs Slack: MySQL Casual- 1/79
  3. 3. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 2/79
  4. 4. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 3/79
  5. 5. pt-query-digest みんなだいすきPercona Toolkitの⼈気No.1 スローログをまとめて⾒やすくしてくれる ⼤⽂字⼩⽂字、⽂字列定数と数値定数をノーマライズして「ダイジェ スト」ごとに集約 - 4/79
  6. 6. 先頭のセクション $ pt-query-digest /path/to/slowlog .. # Time range: 2016-03-16 17:29:32 to 2016-11-22 11:37:24 # Attribute total min max avg 95% stddev medi an # ============ ======= ======= ======= ======= ======= ======= ===== == # Exec time 45155s 500ms 117s 3s 7s 9s 640 ms # Lock time 2s 29us 14ms 110us 176us 136us 93 us # Rows sent 156.96M 0 5.85M 10.33k 54.03k 74.89k 0. 99 # Rows examine 36.18G 0 26.40M 2.38M 22.38M 5.41M 298.0 6k # Rows affecte 0 0 0 0 0 0 0 # Bytes sent 9.86G 0 362.91M 664.55k 4.26M 4.87M 1.0 9k # Query size 3.29M 25 24.47k 221.80 346.17 425.46 136. 99 .. 5/79
  7. 7. 先頭のセクション まああんま⾒ない 6/79
  8. 8. ダイジェスト⼀覧 # Profile # Rank Query ID Response time Calls R/Call V/M It em # ==== ================== ================ ===== ======= ===== == ========= # 1 0x15E7E7E2F486896A 16739.1308 37.1% 382 43.8197 0.76 SE LECT table1 table2 table3 # 2 0x223A9E1EC454F977 10883.7272 24.1% 270 40.3101 5.94 SE LECT table1 table3 # 3 0xAF335DE1A49E8218 2909.3875 6.4% 5542 0.5250 0.00 SE LECT table4 # 4 0x180720D51CB2E890 2044.8649 4.5% 1451 1.4093 0.07 SE LECT table5 .. 7/79
  9. 9. ダイジェスト⼀覧 デフォルトでは「トータルでかかった時間」の降順 --order-by で変えられるデフォルトは “Query̲time:sum” 書き⽅にちょっとクセがある Query̲time:max Query̲time:sum Rows̲examined:max bytes:sum とか - 8/79
  10. 10. ダイジェストごと、前半 Query 1: 0.00 QPS, 0.01x concurrency, ID 0x15E7E7E2F486896A at byte 6304792 # This item is included in the report because it matches --limit. # Scores: V/M = 0.76 # Time range: 2016-11-01 14:02:59 to 2016-11-22 11:37:24 # Attribute pct total min max avg 95% stddev median # ============ === ======= ======= ======= ======= ======= ======= ======= # Count 2 382 # Exec time 37 16739s 37s 100s 44s 52s 6s 40s # Lock time 2 50ms 70us 395us 131us 152us 25us 125us # Rows sent 0 1.87k 5 5 5 5 0 5 # Rows examine 27 9.78G 26.05M 26.40M 26.22M 25.91M 0 25.91M # Rows affecte 0 0 0 0 0 0 0 0 # Bytes sent 0 311.36k 825 840 834.63 833.10 7.50 833.10 # Query size 6 228.65k 611 614 612.93 592.07 0 592.07 9/79
  11. 11. ダイジェストごと、前半 1⾏目に ID 0x.. があるので、ダイジェスト⼀覧から検索で ⾶んでくるとよし Time range を⾒ないと、実は半年前に撲滅されたクエリー を⼀⽣懸命EXPLAINする⽻目に遭ったり 単発のクエリーが⼤きくて累計 Exec time が⼤きくなってる のか、満遍なく出続けているのか anemo eat erも便利だよ- Rows examine / Rows_sent GROUP BYを除くと、⽐率が1に近く低いほど理想- Lock time はInnoDBではアテにならないので注意 10/79
  12. 12. ダイジェストごと、後半 # Query_time distribution # 1us # 10us # 100us # 1ms # 10ms # 100ms # 1s # 10s+ ######################################################## ######## # Tables .. # EXPLAIN /*!50100 PARTITIONS*/ SELECT .. 11/79
  13. 13. ダイジェストごと、後半 クエリーごとにバラつきがあるか︖ バラついているなら、カーディナリティーの悪戯か、それともキャッ シュの具合か 特にInnoDB圧縮を使ってる場合、バッファプールミスヒットやテーブルキャッシュミ スヒットのコストは⼤きい - 均等に遅いなら、それはクソクエリーかな- ただし pt-query-digest がそもそも、スローログに載っているヤーツ しか⾒られない以上、まともな速度で応答を返しているヤーツは検出 されない - 最後の⾏はEXPLAIN⽤に1⾏、集約してないやつを引っこ抜 いてくれるだけ オプションによっては⾃動でEXPLAINまでかけてくれる- 12/79
  14. 14. pt-query-digestと上⼿く付き合うコツ --since オプションはほぼ必須 --since オプションでもログは舐めてしまうので、⼤きなログを⾷わ すのであれば tail -50000 slow.log | pt-query-digest とパイプで ⾷わせるのも⼿ - 「膨⼤で⾒にくいスローログの塊を、認識しやすいチャンク にまとめる」 --group-by=tables からの --group-by=fingerprint -- filter='$events->{fingerprint} =~ /sテーブル名s/' とか - 13/79
  15. 15. with Anemometer pt-query-digest の出⼒結果を可視化するツール pt-query-digest の結果をMySQLに⼊れる機能(--history, --review)をそのまま使ってる box/Anemometer: Box SQL Slow Query Monitor 14/79
  16. 16. Anemometerの弱点 テーブル上UNIQUE KEY (hostname_max, checksum, ts_min, ts_max)で、Anemometerはts_minでプロットするため、そ のクエリーがts_minに集中したことになってしまう。 mysql> SELECT * FROM global_query_review_history LIMIT 1G *************************** 1. row *************************** hostname_max: xxx db_max: xxx checksum: 1233945238822708500 sample: xxx ts_min: 2015-09-14 11:32:12 ts_max: 2015-10-28 15:51:01 ts_cnt: 31 Query_time_sum: 651.778 Query_time_min: 2.07993 Query_time_max: 197.678 15/79
  17. 17. Anemometerの弱点 ⽇次で pt-query-digest を回している程度だと、⽇単位までし か分解できない 16/79
  18. 18. anemo eat er スローログをスプリットして pt-query-digest を呼びまくる 1分ぶんずつ pt-query-digest に⾷わせれば、ts_min と ts_max の差 は最⼤でも1分 - AnemometerをDockerコンテナーとして起動する- 既存のAnemometerがあれば単にスローログを分割して⾷わせる pt- query-digest のラッパーとして呼べる - 17/79
  19. 19. with anemo eat er 1分単位でプロットできる 18/79
  20. 20. anemo eat er リアルタイムでなくてもいい スロークエリーのリアルタイム通知は別の⽅法でしてる- グラフで⾒られれば数分前の情報であっても全然構わない- リアルタイムを捨てて 保存期間を考えない スローログが残っている限りの情報を、最初から、最後まで⾒られる - ⾒るかどうかもわからないグラフのために常時リソースを割かなくて いい ⾒たく / ⾒せたく なったら起動、⾒終わったら停⽌ - 19/79
  21. 21. anemo eat er 現在のところ docker と pt-query-digest はホストにインス トールしておかないとダメ $ git clone https://github.com/yoku0825/anemoeater $ cd anemoeater $ ./anemoeater slow_log_file Docker container starts with 172.17.0.43. URL will be http://xxxx:32780/anemometer 20/79
  22. 22. pt-query-digest だいたいこんな感じでDailyの動きをメールで⾶ばしてる 気になったら anemo eat erで⾒る $ pt-query-digest --since=$(date -d yesterday "+%Y-%m-%d") /pat h/to/slowlog | awk '/^# Overall:/{print $3, $5}' 822 4 21/79
  23. 23. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 22/79
  24. 24. EXPLAIN 今更なのでEXTENDEDの話しかしないよ 23/79
  25. 25. 目XPLAIN 出来る⼈︖ 24/79
  26. 26. Please 目XPLAIN Me SELECT DISTINCT T.c_month, T.unique_id FROM (SELECT A.a_id, DATE_FORMAT(C.datetime, '%Y%m') AS c_month, C.u nique_id FROM table_2 AS C LEFT OUTER JOIN table_1 AS A ON (CAST(C.session_id AS CHAR) = A.another_id AND C.unique_id = A.unique_id) WHERE C.unique_id = 0x333132 AND C.unique_id <= 260006385 AND C.datetime < TIMESTAMPADD(DAY, -180, CURDATE()) ) AS T WHERE T.another_id IS NULL 25/79
  27. 27. 実はこれ、5.6 と5.7で実⾏計 画が違う 26/79
  28. 28. 5.6 *************************** 1. row *************************** id: 1 select_type: PRIMARY table: <derived2> type: ref possible_keys: <auto_key0> key: <auto_key0> key_len: 35 ref: const rows: 10 Extra: Using where; Using temporary *************************** 2. row *************************** id: 2 select_type: DERIVED table: C type: range possible_keys: PRIMARY,idx_xxx,idx_yyy_zzz key: PRIMARY key_len: 8 ref: NULL rows: 12130512 Extra: Using where *************************** 3. row *************************** id: 2 select_type: DERIVED table: A type: eq_ref possible_keys: PRIMARY,idx_xxx_yyy,idx_xxx_aaa_ccc,idx_xxx_ddd key: PRIMARY key_len: 68 ref: func,const rows: 1 Extra: Using where; Using index 27/79
  29. 29. 5.7 *************************** 1. row *************************** id: 1 select_type: SIMPLE table: C partitions: NULL type: range possible_keys: PRIMARY,idx_xxx,idx_yyy_zzz key: PRIMARY key_len: 8 ref: NULL rows: 12675660 filtered: 5.97 Extra: Using where; Using temporary *************************** 2. row *************************** id: 1 select_type: SIMPLE table: A partitions: NULL type: eq_ref possible_keys: PRIMARY,idx_xxx_yyy,idx_xxx_aaa_ccc,idx_xxx_ddd key: PRIMARY key_len: 68 ref: func,const rows: 1 filtered: 100.00 Extra: Using where; Not exists; Using index 28/79
  30. 30. 5.6 mysql> SHOW WARNINGSG *************************** 1. row *************************** Level: Note Code: 1003 Message: /* select#1 */ select distinct `t`.`c_month` AS `c_month `,`t`.`unique_id` AS `unique_id` from (/* select#2 */ select `sch ema`.`a`.`another_id` AS `another_id`,date_format(`schema`.`c`.`d atetime`,'%Y%m') AS `c_month`,`schema`.`c`.`unique_id` AS `unique _id` from `schema`.`table_2` `c` left join `schema`.`table_1` `a ` on(((`schema`.`a`.`unique_id` = 0x333132) and (cast(`schema`.`c `.`SESSION_ID` as char charset sjis) = `schema`.`a`.`another_id`) )) where ((`schema`.`c`.`unique_id` = 0x333132) and (`schema`.`c `.`UNIQUE_ID` <= 260006385) and (`schema`.`c`.`datetime` < <cache >((curdate() + interval -(180) day))))) `t` where isnull(`t`.`ano ther_id`) 1 row in set (0.00 sec) 29/79
  31. 31. 5.7 > SHOW WARNINGSG *************************** 1. row *************************** Level: Note Code: 1003 Message: /* select#1 */ select distinct date_format(`schema`.`c`. `OCCUR_DATE`,'%Y%m') AS `c_month`,`schema`.`c`.`unique_id` AS `un ique_id` from `schema`.`table_2` `c` left join `schema`.`table_1 ` `a` on(((`schema`.`a`.`unique_id` = 0x333132) and (cast(`schema `.`c`.`SESSION_ID` as char charset sjis) = `schema`.`a`.`another_ id`))) where ((`schema`.`c`.`unique_id` = 0x333132) and isnull(`s chema`.`a`.`another_id`) and (`schema`.`c`.`UNIQUE_ID` <= 2600063 85) and (`schema`.`c`.`OCCUR_DATE` < <cache>((curdate() + interva l -(180) day)))) 30/79
  32. 32. EXPLAIN EXTENDED 5.7からはデフォルトでEXTENDEDがついてくる EXPLAIN直後に SHOW WARNINGS でオプティマイザーが最適化した後 のクエリーが⾒える - 想像したのと違う遅くなり⽅ をしたらEXTENDED⾒た⽅が 良い 特に5.6の蝉ジョインとか蝉ジョインとか蝉ジョインとか- MySQL :: MySQL 5.6 リファレンスマニュアル :: 8.8.3 EXPLAIN EXTENDED 出⼒フォーマット 31/79
  33. 33. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 32/79
  34. 34. PMP(Percona Monitoring Plugins) for Cacti 別に for Zabbixでもいいと思う 単にウチはもともとCactiを使っていたからというだけ 33/79
  35. 35. PMP for Cacti rrdtoolだから容量効率は素晴らしい rrdtoolだから丸め誤差は厳しい CactiそのものがWEBからポチポチするインターフェースな のつらい ss̲get̲mysql̲stats.php ⾃体はPHPで、頑張って⾊々パー スしてるので、ホゲろうと思えばホゲれる けど、それならPerlで書きたい- 34/79
  36. 36. Data Input Methodのデフォルトを⼀気にSQLで書き換 えるとか mysql> UPDATE data_input_fields JOIN data_input_data ON data_input_fields.id = data_input_data.data_input_field_id JOIN data_input ON data_input_fields.d ata_input_id = data_input.id -> SET data_input_data.value = 'pmp' WHERE data_input.name LIKE 'Percon a %' AND data_input_fields.name = 'Username'; mysql> UPDATE data_input_fields JOIN data_input_data ON data_input_fields.id = data_input_data.data_input_field_id JOIN data_input ON data_input_fields.d ata_input_id = data_input.id -> SET data_input_data.value = 'pmp_pass' WHERE data_input.name LIKE 'Pe rcona %' AND data_input_fields.name = 'Password'; mysql> UPDATE data_input_fields JOIN data_input_data ON data_input_fields.id = data_input_data.data_input_field_id JOIN data_input ON data_input_fields.d ata_input_id = data_input.id -> SET data_input_data.value = '3306', data_input_data.t_value = 'on' WH ERE data_input.name LIKE 'Percona %' AND data_input_fields.name = 'Port'; 35/79
  37. 37. Device追加する時にポートを⼀⻫に変えるブックマーク レットだとか javascript:void((function(elems,port){for(var p in elems){elems[p ].value=port}})(document.querySelectorAll('input[type=text]'),pro mpt('port','3306'))) (c) irok 36/79
  38. 38. みんなどうし てるんだろう 37/79
  39. 39. PMP for Cacti やっぱり視認性だいじ 絶対値に惑わされない 問題が起きていなくてもたまには⾒る たまには⻑い期間で⾒る 使いづらいものはユーティリティー作っちゃえばいいと思う 38/79
  40. 40. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 39/79
  41. 41. innotop みんな⼤好き、topライクに SHOW PROCESSLIST を表⽰して くれるinnotop 地味に “M” (Replication Status) も便利 なんとMSR対応してるんだぜ - “L” (InnoDB Locks) とか- “T” (InnoDB Transaction) とか- pt-osc してる間だと “D” (InnoDB Deadlocks) を眺めることもある- tmuxでばっちんばっちんターミナル割って、 dstat とか流 しながら⾒るのが好き 40/79
  42. 42. innotop 41/79
  43. 43. innotop 地味に機能は多いけど今のバージョンだと表⽰されない項目 がたまにある 旧バージョンのサポート切れば楽なんだけど…と思ったり思わなかっ たり - ALTER TABLE や percona-toolkit で重いことやる時のおとも に最適 “d” で表⽰間隔の変更。0.1とかやるとたのしい- ただし万能感を期待しない- “Q” => “K” => “T” => “k” (killステートメント) のコンボで詰まっ てるのを殺すくらい - 42/79
  44. 44. innotop 中⾝は結構スパゲティ 最近メンテナンス遅め ちょっと⾊々事情が- ⽇々の覚書: innotopのその後 2016年6⽉- 43/79
  45. 45. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 44/79
  46. 46. SHOW PROFILE MySQLの組み込みプロファイラー 「そのクエリーが実⾏されていた期間、どのStatus(SHOW PROCESSLIST で “State” と表⽰されているもの)にどのくら いの時間かかったか 使うのが超簡単 45/79
  47. 47. SHOW PROFILE mysql> SET @@profiling= 1; Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> ..; mysql> SHOW PROFILE; +----------------------+----------+ | Status | Duration | +----------------------+----------+ | starting | 0.000206 | | checking permissions | 0.000024 | | Opening tables | 0.000039 | | init | 0.000089 | | System lock | 0.000027 | | optimizing | 0.000037 | | statistics | 0.000245 | | preparing | 0.000058 | | Creating tmp table | 0.000119 | | Sorting result | 0.000023 | | executing | 0.000019 | | Sending data | 2.619037 | | Creating sort index | 0.000821 | | end | 0.000014 | | removing tmp table | 0.000017 | | end | 0.000013 | | query end | 0.000015 | | closing tables | 0.000022 | | freeing items | 0.000028 | | logging slow query | 0.000109 | | cleaning up | 0.000013 | +----------------------+----------+ 21 rows in set (0.00 sec) 46/79
  48. 48. SHOW PROFILE 組み込みだから使うのは超簡単 プロファイルを「どう解析するか」はまた別の問題 ざっと⾒てわかりやすいところに時間がかかってたらつぶせ る…くらいのノリ 再現性がないとつらい 47/79
  49. 49. SHOW PROFILE S mysql> SHOW PROFILES; +----------+-------------+-------------------------------------------------------------------------------+ | Query_ID | Duration | Query | +----------+-------------+-------------------------------------------------------------------------------+ | 1 | 7.56061200 | SELECT * FROM t1 WHERE val IN (SELECT val FROM t2 WHERE num BETWEEN 1 AND 10) | | 2 | 8.00373925 | DELETE FROM t1 WHERE num > 1000 | | 3 | 1.05841250 | DELETE FROM t1 WHERE num > 100 | | 4 | 33.97938100 | DELETE FROM t2 WHERE num > 100 | | 5 | 1.09654200 | DELETE FROM t2 WHERE num > 40 | | 6 | 0.03032175 | DELETE FROM t1 WHERE num > 40 | | 7 | 0.00410725 | explain SELECT * FROM t2 JOIN t1 USING(val) WHERE t2.num = 1 | | 8 | 0.01773500 | SELECT * FROM t1 WHERE val IN (SELECT val FROM t2 WHERE num BETWEEN 1 AND 10) | | 9 | 0.02148750 | DELETE FROM t1 WHERE num > 30 | | 10 | 0.27967925 | DELETE FROM t2 WHERE num > 30 | | 11 | 0.00826075 | SELECT * FROM t1 WHERE val IN (SELECT val FROM t2 WHERE num BETWEEN 1 AND 10) | +----------+-------------+-------------------------------------------------------------------------------+ 11 rows in set (0.01 sec) 48/79
  50. 50. SHOW PROFILE FOR QUERY .. mysql> SHOW PROFILE FOR QUERY 4; +------------------------------+-----------+ | Status | Duration | +------------------------------+-----------+ | starting | 0.007228 | | checking permissions | 0.000302 | | Opening tables | 0.001042 | | System lock | 0.000030 | | init | 0.006702 | | updating | 33.930371 | | end | 0.000923 | | Waiting for query cache lock | 0.000013 | | end | 0.002784 | | query end | 0.024151 | | closing tables | 0.000430 | | freeing items | 0.000809 | | logging slow query | 0.000006 | | logging slow query | 0.004583 | | cleaning up | 0.000009 | +------------------------------+-----------+ 15 rows in set (0.01 sec) 49/79
  51. 51. SHOW PROFILE MySQL 5.6でdeprecated 代替として performance_schema.events_stages_* と events_statements_* が案内されている…けど - @@profiling はセッション単位に対して、p̲sはセッション単位の調 整がちょっと難しい - ⼀応、MySQL 8.0.0現在でもまだ使える 50/79
  52. 52. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 51/79
  53. 53. performance̲schema(p̲s) パフォーマンスモニタリング専⽤のストレージエンジン MySQL 5.6から真っ当に使えるようになってる 吊るしのデフォルトではONになってる- 計測する項目も「だいたい必要になりそうなところ」だけがONになっ てるので、必要になるまではそのまま使えばOK - メモリーを⾷うのは相変わらず デフォルトがautosizeなので、気になる場合は固定値を決め打つ- しかも5.7のデフォルトが auto re size になりやがった。。- 52/79
  54. 54. p_s.setup_* mysql> SHOW TABLES FROM performance_schema LIKE 'setup_%'; +-----------------------------------------+ | Tables_in_performance_schema (setup_%) | +-----------------------------------------+ | setup_actors | | setup_consumers | | setup_instruments | | setup_objects | | setup_timers | +-----------------------------------------+ 5 rows in set (0.00 sec) 53/79
  55. 55. p_s.setup_consumers mysql> SELECT * FROM setup_consumers; +----------------------------------+---------+ | NAME | ENABLED | +----------------------------------+---------+ | events_stages_current | NO | | events_stages_history | NO | | events_stages_history_long | NO | | events_statements_current | YES | | events_statements_history | YES | | events_statements_history_long | NO | | events_transactions_current | NO | | events_transactions_history | NO | | events_transactions_history_long | NO | | events_waits_current | NO | | events_waits_history | NO | | events_waits_history_long | NO | | global_instrumentation | YES | | thread_instrumentation | YES | | statements_digest | YES | +----------------------------------+---------+ 15 rows in set (0.00 sec) 54/79
  56. 56. p_s.setup_instruments mysql> SELECT SUBSTRING_INDEX(`name`, '/', 2) AS short_name, ANY_VALUE(name) AS example, SUM(ENABLED = 'YES') AS enabled, SUM(ENABLED = 'NO') AS disabled FROM setup_instruments GROUP BY short_name; +---------------------------+-----------------------------------------------------+---------+----------+ | short_name | example | enabled | disabled | +---------------------------+-----------------------------------------------------+---------+----------+ | idle | idle | 1 | 0 | | memory/archive | memory/archive/FRM | 0 | 2 | | memory/blackhole | memory/blackhole/blackhole_share | 0 | 1 | | memory/client | memory/client/mysql_options | 0 | 7 | | memory/csv | memory/csv/TINA_SHARE | 0 | 5 | | memory/federated | memory/federated/FEDERATED_SHARE | 0 | 1 | | memory/innodb | memory/innodb/adaptive hash index | 0 | 85 | | memory/keyring | memory/keyring/KEYRING | 0 | 1 | | memory/memory | memory/memory/HP_SHARE | 0 | 4 | | memory/myisam | memory/myisam/MYISAM_SHARE | 0 | 21 | | memory/myisammrg | memory/myisammrg/MYRG_INFO | 0 | 2 | | memory/mysys | memory/mysys/max_alloca | 0 | 21 | | memory/partition | memory/partition/ha_partition::file | 0 | 3 | | memory/performance_schema | memory/performance_schema/mutex_instances | 70 | 0 | | memory/sql | memory/sql/Locked_tables_list::m_locked_tables_root | 0 | 152 | | memory/vio | memory/vio/ssl_fd | 0 | 3 | | stage/innodb | stage/innodb/alter table (end) | 8 | 0 | | stage/mysys | stage/mysys/Waiting for table level lock | 0 | 1 | | stage/sql | stage/sql/After create | 1 | 119 | | statement/abstract | statement/abstract/Query | 3 | 0 | | statement/com | statement/com/Sleep | 32 | 0 | | statement/scheduler | statement/scheduler/event | 1 | 0 | | statement/sp | statement/sp/stmt | 16 | 0 | | statement/sql | statement/sql/select | 141 | 0 | | transaction | transaction | 0 | 1 | | wait/io | wait/io/file/sql/map | 55 | 3 | | wait/lock | wait/lock/table/sql/handler | 1 | 1 | | wait/synch | wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc | 0 | 257 | +---------------------------+-----------------------------------------------------+---------+----------+ 28 rows in set (0.01 sec) 55/79
  57. 57. 統計情報へのアクセス mysql> SHOW TABLES; .. | events_stages_summary_by_account_by_event_name | | events_stages_summary_by_host_by_event_name | .. | memory_summary_by_thread_by_event_name | | memory_summary_by_user_by_event_name | | memory_summary_global_by_event_name | .. | replication_applier_configuration | | replication_applier_status | .. 56/79
  58. 58. p̲s⾃体のモニタリング mysql> SHOW ENGINE PERFORMANCE_SCHEMA STATUS; +--------------------+---------------------------------------------------------- ---+----------+ | Type | Nam e | Status | +--------------------+---------------------------------------------------------- ---+----------+ | performance_schema | events_waits_current.siz e | 176 | | performance_schema | events_waits_current.coun t | 1536 | | performance_schema | events_waits_history.siz e | 176 | | performance_schema | events_waits_history.coun t | 2560 | | performance_schema | events_waits_history.memor y | 450560 | .. | performance_schema | performance_schema.memor y | 94739320 | +--------------------+---------------------------------------------------------- ---+----------+ 229 rows in set (0.00 sec) 57/79
  59. 59. sys p̲sの情報を⾒やすくするためのビューやストアドファンク ション、ストアドプロシージャ 名前空間として sys スキーマを使うのでそう呼ぶことも performance_schema = OFF の状態ではほとんどからっぽ MySQL 5.7では最初から導⼊済み MySQL 5.6にも対応 GitHubのmysql-sysリポジトリー からインストール- 58/79
  60. 60. sysのインストール(5.6向け) $ git clone https://github.com/mysql/mysql-sys.git Initialized empty Git repository in /root/mysql-sys/.git/ remote: Counting objects: 3009, done. remote: Total 3009 (delta 0), reused 0 (delta 0), pack-reused 3008 Receiving objects: 100% (3009/3009), 1.17 MiB | 466 KiB/s, done. Resolving deltas: 100% (1768/1768), done. $ cd mysql-sys $ mysql -uroot -p < sys_56.sql $ mysql -uroot -p mysql> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.01 sec) 59/79
  61. 61. sys.statement_analysis p_s.events_statements_summary_by_digest のビュー 超⾒やすい これのためだけに p̲s有効にする価値がある 60/79
  62. 62. sys.statement_analysis mysql> SELECT * FROM statement_analysisG .. *************************** 2. row *************************** query: SELECT `c` FROM `sbtest1` WHERE `id` = ? db: sbtest full_scan: exec_count: 23890 err_count: 0 warn_count: 0 total_latency: 2.36 s max_latency: 521.15 us avg_latency: 98.74 us lock_latency: 778.65 ms rows_sent: 23890 rows_sent_avg: 1 rows_examined: 23890 rows_examined_avg: 1 rows_affected: 0 rows_affected_avg: 0 tmp_tables: 0 tmp_disk_tables: 0 rows_sorted: 0 sort_merge_passes: 0 digest: 80295d1d2720d4515b05d648e8caa82f first_seen: 2016-07-12 17:04:40 last_seen: 2016-07-12 17:04:53 .. 61/79
  63. 63. sys.innodb_lock_waits いわゆるSH2さんの アレ とほぼ同等の機能 これは i̲s のビューなので、p̲sが無効でもフツーに⾒られ る バンドルされて便利になったという感じ 62/79
  64. 64. sys.innodb_lock_waits mysql57> SELECT * FROM innodb_lock_waitsG *************************** 1. row *************************** wait_started: 2016-07-12 17:49:06 wait_age: 00:00:13 wait_age_secs: 13 locked_table: `d1`.`user` locked_index: PRIMARY locked_type: RECORD waiting_trx_id: 8063 waiting_trx_started: 2016-07-12 17:49:06 waiting_trx_age: 00:00:13 waiting_trx_rows_locked: 1 waiting_trx_rows_modified: 0 waiting_pid: 320 waiting_query: SELECT * FROM user LIMIT 3 FOR UPDATE waiting_lock_id: 8063:146:3:2 waiting_lock_mode: X blocking_trx_id: 8062 blocking_pid: 321 blocking_query: NULL blocking_lock_id: 8062:146:3:2 blocking_lock_mode: X blocking_trx_started: 2016-07-12 17:49:06 blocking_trx_age: 00:00:13 blocking_trx_rows_locked: 3 blocking_trx_rows_modified: 0 sql_kill_blocking_query: KILL QUERY 321 sql_kill_blocking_connection: KILL 321 1 row in set (0.01 sec) 63/79
  65. 65. sys.ps_truncate_all_tables ストアド p̲s は起動時から統計情報を累積するが、それをリセットす るにはp̲sの各テーブルに対してTRUNCATEが必要 それを全部まとめてやってくれる、ただそれだけなんだけど 便利なストアド mysql> CALL sys.ps_truncate_all_tables(0); +---------------------+ | summary | +---------------------+ | Truncated 44 tables | +---------------------+ 1 row in set (0.01 sec) Query OK, 0 rows affected (0.01 sec) 64/79
  66. 66. sys.x$* x$ で始まるビューは、 x$ のない他のビューと対になってい る フツーの⽅は、[kMG]B をまとめたり [num]s をまとめた りしてくれるが、そうすると⽂字列になっちゃうのでソート に不便 そんな時、 x$ のビューは何の整形もしないので…ってこと だと思う でもナノ秒単位とか正直つらいので、ソートだけ x$ でやって digest カラムとかでフツーのビューとJOINした⽅がいいと思う - 65/79
  67. 67. MySQLer七つ道具 pt-query-digest1. EXPLAIN2. PMP for Cacti3. innotop4. SHOW PROFILE5. performance̲schema & sys6. ???7. 66/79
  68. 68. Do you know “Dimitri”? 67/79
  69. 69. Dimitri KRAVTCHUK 68/79
  70. 70. Dimitriおじさん says 69/79
  71. 71. Dimitriおじさん says 70/79
  72. 72. Dimitriおじさん says 71/79
  73. 73. エコシステム たとえば MariaDB, Percona Server たとえば MHA for MySQL, HandlerSocket たとえば ⽇本MySQLユーザ会, MySQL Casual たとえば Oracle 72/79
  74. 74. USE YOUR BRAIN 73/79
  75. 75. but/and 74/79
  76. 76. YOU are not alone. 75/79
  77. 77. 2年前 76/79
  78. 78. みなさんのご参加をお待ちしております :) MyNA ML: ⽇本MySQLユーザ会 MySQL Casualʼs Slack: MySQL Casual 77/79
  79. 79. Advent Calendarのおさそい まだまだお席に余裕がございます 具体的には 20 名様ほどお⼊りいただけます- @soudai1025- @kkkida̲twtr- @kamipo- MySQL Casual Advent Calendar 2016 - Qiita 78/79
  80. 80. Questions and/or Suggestions? 79/79

×