SlideShare a Scribd company logo
1 of 142
Download to read offline
MySQLのパフォーマンスチューニン
グについて少々
2016/01/20
yoku0825の中の⼈
GMOアドパートナーズグループ勉強会
\こんにちは/
yoku0825@とある企業のDBA の中の⼈
オラクれない-
ポスグれない-
マイエスキューエる-
Twitter: @yoku0825
Blog: ⽇々の覚書
Oracle ACE Details
MySQL 5.7 Community Contributor Award
1/141
このスライド書いた中の⼈です
2/141
ちなみに
3/141
というわけで安⼼
して 地雷友達 5.7
使っていいです
よ :)
4/141
クエリーのライフサイクル
client
connection_handling parser optimizer executor
handler storage_engine
application
mysqld
5/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
6/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
7/141
Connection Handling
ソケット, ポートからの接続を待ち受ける
接続があったらclone(またはスレッドキャッシュから取り
出してディスパッチ)
⼀次認証
8/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
9/141
Parser
MySQLプロトコルのパース
SQL構⽂のパース
⼆次認証(データベース, テーブル単位のアクセス権限チ
ェック)
クエリーキャッシュ処理
ジェネラルログ
10/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
11/141
Optimizer
統計情報の取得(Storage Engine APIを叩いてるっぽい)
クエリーの書き換えを含めた実⾏計画の決定
12/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
13/141
Executor
オプティマイザーから渡された実⾏計画の通りにHandlerを
叩く
Handlerから戻ってきた結果を使って実⾏計画の残りを実⾏
Using where; Using filesort; Using temporary; はコ
イツが頑張ってる証拠
-
スローログ, バイナリーログ
14/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
15/141
Handler
ストレージエンジンの抽象化レイヤー
あんまり意識することはない
16/141
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
17/141
Storage Engine
実際にデータを格納するレイヤー
プラガブルアーキテクチャーなので、ほとんどの機能はこの
レイヤーで実装されている
ストレージエンジンごとにトランザクション対応が違う
とか
-
ストレージエンジンごとにロック粒度が違うとか-
ストレージエンジンごとにバッファが違うとか-
18/141
クエリーのライフサイクル
client
connection_handling parser optimizer executor
handler storage_engine
application
mysqld
19/141
どこが 遅
い︖
20/141
どこが遅い︖
connection_handling parser optimizer executor
handler storage_engine
mysqld
だいたいExecutor
たまにStorage Engine
21/141
Executorが遅い理由
MySQLの不得意なことをやろうとしている
⾊々パターンはあるけど、⼀⾔で⾔うならこれにあたる-
Executorに仕事をさせたら負け
22/141
MySQLの不得意なこと
複数のインデックスを使いこなす
相関サブクエリー
23/141
複数のインデックスに弱い理由
MySQLは原則1クエリー内で1つのテーブルあたり1つのイ
ンデックスしか使わない
インデックスマージという例外が⼀応あるにはあるが、
後付け
-
そもそもこういう設計思想なんだと思う-
テーブルスキャンに強い/弱いはストレージエンジンのレイ
ヤー
MyISAMはスキャンに強く、InnoDBは弱い-
関数演算、(インデックスで解決できない)フィルター、
(インデックスで解決できない)ソートはExecutorのお仕
事(= 遅い)
24/141
EXPLAIN
mysql> EXPLAIN SELECT * FROM table_1 a JOIN `table_2` s ON a.user_id=s.`user_id` AND s.site_i
d=120 WHERE app_id=8250G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: a
type: ref
possible_keys: PRIMARY,ix_table_1,ix2_table_2,ix3_table_1,idx_table_1_06,idx_table_1_07,idx_t
able_1_09
key: idx_table_1_06
key_len: 4
ref: const
rows: 13496
Extra:
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: s
type: ref
possible_keys: idx_table_2_02,idx_table_2_03
key: idx_table_2_02
key_len: 4
ref: xxx.a.user_id
rows: 1
Extra: Using where
2 rows in set (0.00 sec)
25/141
いくつかのルール
Extra列はExecutorの都合
それ以外はオプティマイザー、ハンドラー(= ストレージエ
ンジン)の都合
key_len, rowsがヒントになる
26/141
type
ALLがダメなんて良く⾔う
ALL .. テーブルスキャン-
ref .. 非ユニークキーによる選択-
range .. レンジスキャン-
27/141
type
どの⽅法でアクセスさせるのが最速だと オプティマイザー
が ⾒積もった結果
特にInnoDBはクラスターインデックスなので、下⼿にセ
カンダリーインデックスを使うよりも本当に速いケース
もある
-
MyISAMもスキャンに強いので、本当に速いケースがあ
る
-
ダメなのはALLじゃなく、本当の最適なアクセスと違う時
rows, key_lenが判断の助けになる-
28/141
オプティマイザーが⾒誤る理由
InnoDBの統計情報がサンプリング1.
オプティマイザーはLIMIT句を正しくハンドリングできない2.
29/141
InnoDBの統計情報
InnoDBの統計情報は テーブル全体から⼀部の情報をランダ
ムに選び出し、全体を推測する サンプリング統計
5.5とそれ以前では1インデックスあたり8ページ(=
16kB * 8ページで128kB)でハードコード
-
5.6とそれ以降では1インデックスあたりデフォルト20ペ
ージ(innodb_stats_persistent_sample_pages)
CREATE TABLE, ALTER TABLEでテーブル単位でページ数
を指定することも可能
-
30/141
InnoDBの統計情報
サンプリングなので
統計情報の再計算はそこまで(MyISAMと⽐べれば)⼤
きくない
-
統計情報が間違っている(著しく実際のデータの分布と
乖離している)可能性が⾼い
-
31/141
LIMIT句のハンドリング
LIMIT句はORDER BY句の処理が終わってから実⾏される
ORDER BY句の処理は最終的にExecutorで終端するので-
つまりLIMIT句もExecutorの処理の範疇-
オプティマイザーは⾃分より後のExecutorの動作を正しく
⾒積もれない
なので、ORDER BY .. LIMIT ..で効率的にORDER BY狙い
のキーが使える場合でも、選んでくれないケースがある
-
5.7でLIMITありの場合のオプティマイズが効くようにな
っている
-
32/141
Extra: Using where; Using filesort;
ExecutorがWHEREをフィルターしている、ExecutorがORDER
BYのソートをしている
インデックスを使って⾼速化できるのは WHERE, ORDER BY,
GROUP BY, select_list
どうすればいいかと⾔われると、「インデックス使う」とし
か⾔いようがない
33/141
トランプの
話をします
34/141
Query As A Card
100枚のトランプが裏返して積まれた⼭があります
何組かのトランプを混ぜたもので何が何枚⼊ってるかはわか
りません
35/141
この⼭の中から
スペードのAを
探してください
36/141
どうするかというと
⼭の⼀番上のトランプをめくる1.
スートと番号を⾒る2.
スペードのAだったら⼿元に残す3.
スペードのAじゃなかったらどっかに置いておく4.
⼭の全てのカードに対して2, 3, 4を繰り返す
⼭にスペードのAが何枚あるかに関わらず、⼭の全てのカー
ドに対して繰り返す
5.
37/141
これがtype: ALLかつExtra: Using where
トランプをめくる .. ⾏をフェッチする
スートと番号を⾒る .. Executorでのフィルター処理
38/141
この⼭の中からス
ペードを全て探し
出して、K〜Aの順
で並べてください
39/141
どうするかというと
右⼿で ⼭の⼀番上のトランプをめくる1.
スートと番号を⾒る2.
スペードだったらそのカードを 左⼿に 残しておく3.
スペードじゃなかったらどっかに置いておく4.
⼭の全てのカードに対して2, 3, 4を繰り返す5.
⼭から全てのスペードが出揃ったら、⼿元のカードをK〜A
まで順番に並べる
6.
40/141
これがtype: ALLかつExtra: Using where; Using
filesort
トランプをめくる .. ⾏をフェッチする
トランプをめくった 右⼿ .. リードバッファー
スートを⾒る .. Executorでのフィルター処理
スートが⼀致した時にカードを⼊れた 左⼿ .. ソートバッフ
ァー
⼿元のカードを並べ替える .. Executorによるクイックソー
ト
41/141
KEY(suit)
suit 上から
club 3,5,13,14,16,18,19,20,37,44,45,55,57,
63,66,81,86,87,91,92,98,99,100
diamond 1,4,15,17,21,22,25,27,31,34,39,50,56,
58,60,65,68,70,72,73,78,97
heart 6,7,10,12,24,26,32,36,38,40,41,43,48,
51,52,61,62,67,74,75,84,85,88,89,90,9
3,95
spade 2,8,9,11,23,28,29,30,33,35,42,46,47,4
9,53,54,59,64,69,71,76,77,79,80,82,8
3,94,96
42/141
ここからスペードのAを探す
suit 上から
club 3,5,13,14,16,18,19,20,37,44,45,55,57,
63,66,81,86,87,91,92,98,99,100
diamond 1,4,15,17,21,22,25,27,31,34,39,50,56,
58,60,65,68,70,72,73,78,97
heart 6,7,10,12,24,26,32,36,38,40,41,43,48,
51,52,61,62,67,74,75,84,85,88,89,90,9
3,95
spade 2,8,9,11,23,28,29,30,33,35,42,46,47,4
9,53,54,59,64,69,71,76,77,79,80,82,8
3,94,96
43/141
スペードのAを探す
トランプの上から2, 8, 9, .. 枚目を順番にめくり1.
番号を⾒る(スペードのものだけめくってるんだから、スー
トは⾒る必要がない)
2.
Aだったらそのカードを残しておく3.
Aじゃなかったらどっかに置いておく4.
44/141
これがtype: ref, ref: const, Extra: Using where
インデックス上からスペードを探して「上から2番目」の情
報を得る
1.
上から2番目のカードをめくる .. ここまでha̲index̲read2.
Aかどうかを判定する .. Executorによるフィルター3.
インデックス上の全てのリーフをさらうまで繰り返す ..
ha̲index̲nextがHA̲ERR̲END̲OF̲FILEを返すまでルー
プ
4.
45/141
ここからスペードを全て探し出して、K〜Aの順で並べる
suit 上から
club 3,5,13,14,16,18,19,20,37,44,45,55,57,
63,66,81,86,87,91,92,98,99,100
diamond 1,4,15,17,21,22,25,27,31,34,39,50,56,
58,60,65,68,70,72,73,78,97
heart 6,7,10,12,24,26,32,36,38,40,41,43,48,
51,52,61,62,67,74,75,84,85,88,89,90,9
3,95
spade 2,8,9,11,23,28,29,30,33,35,42,46,47,4
9,53,54,59,64,69,71,76,77,79,80,82,8
3,94,96
46/141
スペードを全て探し出して、K〜Aの順で並べる
トランプの上から2, 8, 9, .. 枚目を順番にめくり 左⼿ に取
る
1.
番号を⾒て、並べ替える2.
47/141
type: ref, ref: const, Extra: Using filesort
インデックス上からスペードを探して「上から2番目」の情
報を得る
1.
上から2番目のカードを 左⼿ に .. ha̲index̲readしてソー
トバッファーに詰める
2.
番号を⾒て並べ替える .. Executorによるクイックソート3.
48/141
KEY(suit, number)
suit number 上から
club 2 13,20
club 3 18,45
.. .. ..
heart 13 85
spade 1 2,23,47,76
spade 2 77
spade 3 83
.. .. ..
spade 11 11,33,35,96
spade 12 49,59,80
49/141
ここからスペードのAを探す
suit number 上から
club 2 13,20
club 3 18,45
.. .. ..
heart 13 85
spade 1 2,23,47,76
spade 2 77
spade 3 83
.. .. ..
spade 11 11,33,35,96
spade 12 49,59,80
50/141
スペードのAを探す
トランプの上から2, 23, 47, 76枚目を順番にめくる(おし
まい︕)
インデックスの情報だけで完結するため、⼭を全て⼿繰
る(不要なものをフェッチする)必要がない
1.
51/141
type: ref, ref: const, const
インデックス上から(スペード, 1)を探して「上から2番目」
の情報を得る
1.
上から2番目のカードを取る .. ha̲index̲read2.
インデックス上の全てのリーフをさらうまで繰り返す ..
ha̲index̲nextがHA̲ERR̲END̲OF̲FILEを返すまでルー
プ
3.
52/141
スペードを全て探し出して、K〜Aの順で並べる
suit number 上から
club 2 13,20
club 3 18,45
.. .. ..
heart 13 85
spade 1 2,23,47,76
spade 2 77
spade 3 83
.. .. ..
spade 11 11,33,35,96
spade 12 49,59,80
Kなかった。。
53/141
スペードを全て探し出して、K〜Aの順で並べる
トランプの上から49, 59, 80枚目を⼿に取る1.
トランプの上から11, 33, 35, 96枚目を⼿に取る2.
全てのスペードのカードぶん1, 2を繰り返す3.
54/141
type: ref, ref: const, const, Extra: Using index
インデックス上から(スペード, 最後のノード)を探して「上
から49番目」の情報を得る
1.
上から49番目のカードを取る .. ha̲index̲read2.
インデックス上の全てのリーフをさらうまで繰り返す ..
ha̲index̲prevがHA̲ERR̲END̲OF̲FILEを返すまでルー
プ
3.
55/141
:(;゙゚ʼω゚ʼ): Extra: Using whereが消えなかった
たまに消えない
たぶんオプティマイザーのバグ(ORDER BYと混じると
Executorが仕事してなくてもUsing whereが消えない)
56/141
KEY(number)
number 上から
1 2,22,23,26,47,76,93
2 4,13,20,25,75,77
.. ..
12 16,31,41,49,59,68,73,80,91
13 19,58,85
57/141
ここからスペードのAを探す
インデックスからAを探して、「2, 22, 23, ..枚目」の情報
を得て
1.
ひっくり返してスペードかどうかを判定する2.
Aのリーフが全部終わったら終わり3.
type: ref, ref: const, Extra: Using where
58/141
スペードを全て探し出して、K〜Aの順で並べる
インデックスからKを探して19, 58, 85枚目を⼿に取る1.
スペードなら⼿元に、そうでなければよける2.
カードの⼭全てに対して1, 2を繰り返す3.
59/141
type: index, Extra: Using where
ただしこれはLIMITがない場合はテーブルスキャンを選んで
た
5.6の場合、LIMITがあってもテーブルスキャンを選ぶ-
そりゃ、結局全部のカードを裏返してるから、頭から全部ひ
っくり返した⽅が速い
LIMITがある= 「枚数が揃ったらそこでそれ以降の結果セ
ットは考慮する必要がない」
-
この条件にマッチした場合、フェッチする⾏数を⼤幅に
減らせる
-
60/141
インデックスのイメージ
インデックスは ソート済みのデータの部分複製 (異論は認め
る)
root club
spade
2
3
2
13
20
18
45
77
B+Treeじゃないけど取り敢えずそこまで気にしない
61/141
インデックスのリーフ
root club
spade
2
3
2
13
20
18
45
77
MyISAMの場合はMYDファイルの先頭からのオフセットバイト
数
InnoDBの場合はクラスターインデックスの値 62/141
InnoDBのクラスターインデックスイメージ
root club
spade
3
5
13
14
2
23
root p3
p5
p13
p14
p2
p23
Club-A
Club-4
Club-2
Club-5
Spade-A
Spade-A
Secondary Index Clustered Index
63/141
InnoDBでWHERE狙いのキー
SELECT * FROM card USING(idx_suit) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
3
5
13
14
2
23
root p3
p5
p13
p14
p2
p23
Club-A
Club-4
Club-2
Club-5
Spade-A
Spade-A
Secondary Index Clustered Index
64/141
InnoDBでWHERE狙いのキー
SELECT * FROM card USING(idx_suit) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
3
5
13
14
2
23
root p3
p5
p13
p14
p2
p23
Club-A
Club-4
Club-2
Club-5
Spade-A
Spade-A
Secondary Index Clustered Index
65/141
InnoDBでWHERE狙いのキー
SELECT * FROM card USING(idx_suit) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
3
5
13
14
2
23
root p3
p5
p13
p14
p2
p23
Club-A
1
Club-4
Club-2
Club-5
Spade-A
Spade-A
Secondary Index Clustered Index
66/141
InnoDBでWHERE狙いのキー
SELECT * FROM card USING(idx_suit) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
3
5
13
14
2
23
root p3
p5
p13
p14
p2
p23
Club-A
1
Club-4
Club-2
Club-5
Spade-A
Spade-A
Secondary Index Clustered Index
67/141
InnoDBでWHERE狙いのキー
SELECT * FROM card USING(idx_suit) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
3
5
13
14
2
23
root p3
p5
p13
p14
p2
p23
Club-A
1
Club-4
2
Club-2
Club-5
Spade-A
Spade-A
Secondary Index Clustered Index
68/141
InnoDBでWHERE狙いのキー
SELECT * FROM card USING(idx_suit) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
3
5
13
14
2
23
root p3
p5
p2
p23
p13
p14
Club-A
1
Club-4
2
Club-2
3
Club-5
4
Spade-A
Spade-A
Secondary Index Clustered Index
フェッチした⾏をクイックソートしてからLIMITを評価
69/141
InnoDBでORDER BY狙いのキー
SELECT * FROM card USING(idx_number) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root A
2
2
22
23
26
4
13
root p2
p22
p23
p26
p4
p13
Spade-A
Diamond-A
Spade-A
Heart-A
Diamond-2
Club-2
Secondary Index Clustered Index
70/141
InnoDBでORDER BY狙いのキー
SELECT * FROM card USING(idx_number) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root A
2
2
22
23
26
4
13
root p2
p22
p23
p26
p4
p13
Spade-A
1
Diamond-A
2
Spade-A
3
Heart-A
4
Diamond-2
5
Club-2
6
Secondary Index Clustered Index
LIMIT件数が早めに⾒つかれば勝ち、そうでなければ負け。
ところでこれ、 何かに似てると思いません︖
71/141
InnoDBでcovering index
SELECT * FROM card USING(idx_number) WHERE suit= 'club'
ORDER BY number LIMIT 1;
root club
spade
2
3
A
13
20
18
45
2
23
root p13
p20
p18
p45
p2
p23
Club-2
1
Club-2
Club-3
Club-3
Spade-A
Spade-A
Secondary Index Clustered Index
72/141
WHERE狙いのキー, ORDER BY狙いのキー
WHEREとORDER BY .. LIMITを同時にカバーできるインデック
スが作成できない時に
WHEREをストレージエンジンに任せてフェッチする⾏を減
らしてファイルソートをExecutorにやらせるか
-
ORDER BY .. LIMITをストレージエンジンに任せて
ExecutorにフィルターさせつつLIMITでループを抜けるの
を期待するか
-
73/141
WHERE狙いのキー, ORDER BY狙いのキー
「JOINが遅い」はJOINが遅いんじゃなくてJOINの参照表で
ソートしようとしてExecutorがソートしちゃってるケース
あとはオプティマイザーにバグがあって、駆動表を
Executorがフィルターして参照表の参照回数が減る可能
性を考慮していない。
-
See also, http://www.slideshare.net/yoku0825/
whereorder-by
74/141
Executorに仕
事をさせたら
負け
75/141
Executorが必要以上の仕事をしていないか
GROUP BYのケースを除いて、Rows_sent= Rows_examinedが⼀
番良い
MySQLにはヒストグラム統計がないので、WHERE狙いと
ORDER BY狙いのどちらが本当に速いのかMySQLは知らない
(憶えてない)
76/141
Executorが必要以上の仕事をしていないか
⼈間は得てして 正しい 統計情報を知っているケースがある
サービスの特性(⼥性は少ないからWHERE gender= 'F'
ORDER BY birthdayはWHEREで狙った⽅がいいだろうし、
WHERE gender= 'M' ORDER BY birthdayはORDER BY狙いの
⽅が良いだろう、とか)
-
サンプリングでない実際の分布(InnoDBの統計情報は飽
くまでサンプリングなのでたまに踏み外す)
-
LIMITの考慮(5.6とそれ以前のMySQLはORDER BY ..
LIMITの時でも積極的にWHEREを狙う)
-
77/141
オプティマイザーの強化
MySQL 5.6
Multi-Range Read, Batched Key Access(デフォルトOFF),
Semi-JOIN, Materialized
MySQL 5.7
ORDER BY .. LIMIT Optimization, Configurable cost
Model, JOIN optimization
78/141
迷ったら最新(オ
プティマイザーに
関しては)
79/141
クエリーの最適化(5.5)
mysql55> EXPLAIN SELECT * FROM Country WHERE Continent = 'Asia' AND Code IN
io
n / 2);
+----+--------------------+---------+----------------+---------------+------
-------+---------+------+------+-------------+
e
y | key_len | ref | rows | Extra |
+----+--------------------+---------+----------------+---------------+------
-------+---------+------+------+-------------+
| 1 | PRIMARY | Country | ALL | NULL | NUL
L | NULL | NULL | 226 | Using where |
| 2 | DEPENDENT SUBQUERY | City | index_subquery | CountryCode | Count
ryCode | 3 | func | 7 | Using where |
+----+--------------------+---------+----------------+---------------+------
-------+---------+------+------+-------------+
2 rows in set (0.02 sec)
80/141
クエリーの最適化(5.7)
mysql57> EXPLAIN SELECT * FROM Country WHERE Continent = 'Asia' AND Code IN
-> (SELECT CountryCode FROM City WHERE Population > Country.Population / 2);
+----+-------------+---------+------------+------+---------------+-------------+
---------+-----------------+------+----------+----------------------------------
+
| id | select_type | table | partitions | type | possible_keys | key
| key_len | ref | rows | filtered | Extr
a |
+----+-------------+---------+------------+------+---------------+-------------+
---------+-----------------+------+----------+----------------------------------
+
| 1 | SIMPLE | Country | NULL | ALL | PRIMARY | NULL
| NULL | NULL | 239 | 14.29 | Using wher
e |
| 1 | SIMPLE | City | NULL | ref | CountryCode | CountryCode
| 3 | d1.Country.Code | 18 | 33.33 | Using where; FirstMatch(Country
) |
+----+-------------+---------+------------+------+---------------+-------------+
---------+-----------------+------+----------+----------------------------------
+
2 rows in set, 2 warnings (0.00 sec)
81/141
古いMySQLに慣れていると、⼾惑うことも
「MySQLはこう 間違うだろう」という予測と 違う間違え⽅
をする
EXPLAIN EXTENDED, SHOW WARNINGSでオプティマイザーがクエ
リーをどう書き換えたか表⽰できる
mysql57> show warningsG
*************************** 2. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select `d1`.`Country`.`Code` AS `Code`,`d1`.`Country`.`Name` AS `Name
`,`d1`.`Country`.`Continent` AS `Continent`,`d1`.`Country`.`Region` AS `Region`,`d1`.`Country
`.`SurfaceArea` AS `SurfaceArea`,`d1`.`Country`.`IndepYear` AS `IndepYear`,`d1`.`Country`.`Po
pulation` AS `Population`,`d1`.`Country`.`LifeExpectancy` AS `LifeExpectancy`,`d1`.`Country`.
`GNP` AS `GNP`,`d1`.`Country`.`GNPOld` AS `GNPOld`,`d1`.`Country`.`LocalName` AS `LocalName`,
`d1`.`Country`.`GovernmentForm` AS `GovernmentForm`,`d1`.`Country`.`HeadOfState` AS `HeadOfSt
ate`,`d1`.`Country`.`Capital` AS `Capital`,`d1`.`Country`.`Code2` AS `Code2` from `d1`.`Count
ry` semi join (`d1`.`City`) where ((`d1`.`City`.`CountryCode` = `d1`.`Country`.`Code`) and (`
d1`.`Country`.`Continent` = 'Asia') and (`d1`.`City`.`Population` > (`d1`.`Country`.`Populati
on` / 2)))
2 rows in set (0.00 sec)
82/141
sysスキーマ
performance̲schema, information̲schemaのビューと、
performance̲schema関連の設定をゴニョるプロシージャ
の詰め合わせ
なのでperformance_schema= ONが⼤前提-
合わせて使いたいinnodb_monitor_enable= all-
5.6の場合はgitリポジトリーからcloneしてsqlスクリプト
実⾏
-
83/141
sys.statement̲analysis
query
full̲scanしてれば*
exec̲count
err̲count, warn̲count
*̲latency
rows̲sent̲avg, rows̲examined̲avg
tmp̲tables, sort̲merge̲passes
84/141
Percona Server + log_slow_verbosity = query_plan
# Time: 130601 8:01:06.058915
# User@Host: root[root] @ localhost [] Id: 42
# Schema: imdb Last_errno: 0 Killed: 0
# Query_time: 7.725616 Lock_time: 0.000328 Rows_sent: 4 Rows_e
xamined: 1543720 Rows_affected: 0
# Bytes_sent: 272 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_s
izes: 0
# QC_Hit: No Full_scan: Yes Full_join: No Tmp_table: No Tmp_t
able_on_disk: No
# Filesort: No Filesort_on_disk: No Merge_passes: 0
85/141
Anemometer
86/141
相関サブクエリー
外側のクエリーが内側のサブクエリーの条件になっているケ
ース
内側のサブクエリーが外側の条件になるケースはMySQL
⽤語では単にサブクエリーと呼ぶ(個⼈的には明確に区
別するために「キャッシャブルなサブクエリー」と呼ん
でる)
-
しかしWHERE INはキャッシャブルなサブクエリーのはず
でも相関サブクエリーになるというダメ仕様が5.5とそれ
以前にあってだな。。
-
87/141
シンプルな話、外側のクエリーに1⾏マッチするたびに内
側のクエリーを実⾏してしまう
⾏のフェッチのみならず、クエリーまるごと実⾏する。
外側テーブルのサイズが⼤きくなると加速度的に遅くな
るのはこのせい。
-
mysql> SHOW PROFILE;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000023 |
| .. | .. |
| executing | 0.000006 |
| Sending data | 0.000006 |
| .. | .. |
| executing | 0.000005 |
| Sending data | 0.000014 |
| executing | 0.000005 |
| Sending data | 0.000047 |
| end | 0.000010 |
| .. | .. |
+--------------------------------+----------+
2000025 rows in set (4.78 sec)
88/141
相関サブクエリーの書き換え⽅
7割⽅JOINに書き換えられる
JOINに落とし込んでUSE INDEXまでつければ5.5とそれ以
前でも戦える
-
どうしてもロジックとしてJOINに書き換えられないケース
もある
CREATE TEMPORARY TABLEを使って落とし込むのがいい
テンポラリーテーブルはクラッシュアンセーフ( 更新
ステートメントには使わない︕ )
そもそもクラッシュアンセーフだから迷わずMyISAM
を選んでいい
⼤した量でなくてもインデックス張る。劇的に違う
-
のがいい、というか、SQLだけでやるにはそれしかない- 89/141
書き換える時に必要なもの
再帰テスト
無いと死ぬ-
ポジション上、返す結果が変わらないことの担保をしな
いといけない
パラメーター渡して、新旧クエリーの2パターン投げて
結果を⽐較するだけでも取り敢えずいいんだ
最近はコマンドラインクライアントで
REPEATABLE-READでトランザクション内でやればオ
ブジェクト⽐較するだけで済む
分布に極端な偏りがあるパラメーターはいくつかバリ
エーションを⽤意した⽅がいい(同じ形をしていても
パラメーターで実⾏計画は変わる)
-
90/141
ひとやす
み
91/141
Storage Engineが遅い理由
リソースが⾜りていない1.
パラメーターが適切でない2.
キャッシュミスヒット3.
ロックやmutexの競合(並列度が⾼すぎる)4.
バルク操作5.
92/141
リソースが⾜りていない
ホットデータが100GBあるのにInnoDBバッファプールが
16GBしかなかったら︖
物理メモリーが64GBしかないのに
innodb_buffer_pool_size= 128Gにしたら︖
50並列でクエリーを実⾏するのに8コアしかなかったら︖
秒間1000コミットあるのにIOPSが200しかなかったら︖
93/141
パラメーターが適切でない
innodb_buffer_pool_size
innodb_log_file_size * innodb_log_files_in_group
innodb_flush_method
innodb_log_buffer_size
innodb_flush_log_at_trx_commit
innodb_io_capacity, innodb_io_capacity_max
94/141
innodb̲buffer̲pool̲size
InnoDBの動作の要
個⼈的にはキャッシュじゃなくて データの本体-
⾜りてないとSELECTだけじゃなく全ての動作が遅い
ただしDROP TABLEとTRUNCATE TABLEはバッファプールが⼤き
ければ⼤きいほど遅くなる
95/141
InnoDBの動作の要
SELECTのとき
バッファプールを⾒る
あればそれを使う
なければテーブルスペースファイルを読んでバッファ
プールに載せる
バッファプールがいっぱいだったら⼀番古いのを追い
出してバッファプールに載せる
追い出そうとしたページがダーティーページだったら
フラッシュしてから追い出す
-
96/141
InnoDBの動作の要
INSERT, UPDATE, DELETEのとき
UNDOとログはちょっと省略
-
UPDATE, DELETEの時にPRIMARY KEY以外の属性で絞り込
む場合は、SELECTと同様にバッファプールを使って検索
する
-
97/141
InnoDBの動作の要
INSERT, UPDATE, DELETEのとき
データそのものの追加, 更新, 削除は最終的にクラスター
インデックスの値から、書き込むページ番号を特定する
バッファプールはCOMMIT前に更新される(COMMIT
されてるかどうかのフラグがある)
READ-UNCOMMITTEDはバッファプールから読んで
COMMITされてるかどうかのフラグを⾒ない
COMMITされてるかどうかに関わらず、古いファイル
はUNDOセグメントに移されて、そのページ番号がペ
ージに書き込まれる
-
98/141
対象のページがバッファプールに載っていれば
バッファプール上のデータを書き換える
InnoDBのDELETEは論理削除-
バッファプールのページに「delete mark」を付ける-
まだテーブルスペースファイルに反映されてないページ
のことを「ダーティーページ」と呼ぶ
ダーティーページはバッファプールから押し出される
時にテーブルスペースファイルにフラッシュされなけ
ればいけない
-
99/141
対象のページがバッファプールに載っていなければ
テーブルスペースファイルを読んでバッファプールに載せて
から書く
バッファプールに載せてからINSERT-
バッファプールに載せてからUPDATE-
バッファプールに載せてからDELETE-
Replication Booster for MySQLやinnodb̲fake̲changes
はこの仕組みを利⽤したもの
100/141
DROP TABLE, TRUNCATEのとき
TRUNCATEは内部的にDROP TABLE, CREATE TABLE
ディクショナリーから参照を切る
バッファプール上の全てのページをチェックし、そのテーブ
ルのページがあれば破棄する
「バッファプールに載せてdelete mark」はしない-
101/141
ROW̲FORMAT= Compressed
InnoDB圧縮
圧縮はページ単位、圧縮したままでは読むことも書くことも
できない
バッファプールに 圧縮状態のまま 読み込むa.
バッファプール上で 解凍してコピーするb.
解凍済みのページに対する操作をするc.
解凍済みのページがフラッシュされる時に再圧縮されて
圧縮状態のページ が更新される(再圧縮)
d.
圧縮状態のページはバッファプールにもう少し残るe.
ただでさえ重いディスクアクセスのタイミングで圧縮/解凍
処理が加わる。
102/141
InnoDB圧縮のワーストケース
SELECTクエリーがやってきて1.
バッファプールミスヒット2.
バッファプールの空きが無い3.
⼀番古いページを押し出す4.
⼀番古いページがダーティーページだったら︖5.
再圧縮してフラッシュ6.
空けたページに圧縮状態のページを持ってきて7.
解凍してコピー8.
103/141
InnoDB圧縮は
バッファプール効率とCPU効率を犠牲にして容量を稼いでい
る
IO回数が減らせるという側⾯もあるけれど、余程の場合でな
い限り⽀払う代償は⼤きい
バッファプールにミスヒットした時だけやたら重い
(20ms => 400msオーバーとか)
-
しかも実際にSELECTするとバッファプールに載るから、
スローログ⾒てSELECTした時は全然遅くないとか
-
104/141
innodb̲buffer̲pool̲sizeだいじ
⼩さすぎると(ほぼ)全てのクエリーが遅くなる
特にInnoDB圧縮を使うならデータサイズの1.5倍以上あっ
てもいい
105/141
innodb̲log̲file̲size *
innodb̲log̲files̲in̲group
バッファプールが更新されてからテーブルスペースファイル
に反映されるまでの中間状態がInnoDBログ
テーブルスペースに即時反映されなくともログファイル
に即時反映を保証することでデータの永続性を担保する
-
ログファイルに即時反映を保証できなくなると、データ
の保護のためInnoDBはトランザクション処理を中断する
(シャープチェックポイント)
-
106/141
innodb̲log̲file̲size *
innodb̲log̲files̲in̲group
⾜りているか , ⾜りていないか の⼆軸なので、⾜りていれ
ば⼤きすぎる必要もないし、⾜りていなければどんどん⼤き
くしないといけない
⼤きすぎるとクラッシュリカバリー終わらないって話が
あるけど、MySQL 5.5以降でログファイルサイズによる
クラッシュリカバリーが終わらないって話はそうそうな
い(⻑くて数分程度)
-
innodb_flush_method= O_DIRECTでもページキャッシュさ
れる(O̲DIRECTで開くのはテーブルスペースファイル
だけ)ので、ページキャッシュと相談
-
107/141
innodb̲log̲file̲size *
innodb̲log̲files̲in̲group
InnoDBログの性能は innodb_log_file_size と
innodb_log_files_in_group の積にほぼ⽐例
64M * 3 と96M * 2 はほぼ同等の性能-
⾜りてるか⾜りてないかだから-
5.5とそれ以前はinnodb_log_files_in_groupのみを増やす場
合のみ再作成不要
5.6とそれ以降は増やす時でも減らす時でもmy.cnfを書
き換えて再起動するだけでいい。楽ちん。
-
108/141
InnoDBのデータ永続化
InnoDBはテーブルスペースファイル + ログファイルで初め
て完全なデータ
バッファプールは (テーブルスペースファイル + ログフ
ァイル) の部分集合
-
ある意味「フルバックアップ」と「バイナリーログ」か
らポイントインタイムリカバリーをするのに似ている
-
バッファプール上にあってテーブルスペースファイルに
ないデータ(ダーティページ)が⼀定割合を超えると強制
チェックポイント
-
109/141
innodb̲flush̲method
テーブルスペースファイル(ibdata1, .ibd)のopenフラグを
変更できる
暗黙のデフォルトは実質fsync
ファイルシステムキャッシュを併⽤しつつfsyncする
-
使うとしてもO̲DIRECTくらいしかぱっと思いつかない
ファイルシステムキャッシュを通さずにfsyncする
ページキャッシュで節約したぶんをバッファプールに
回せる
ブロックデバイスが対応している場合は、DMA転送が
有効になるらしい(ioDriveがちょっぱやなのはこれが
効いているらしい)
-
nosync, O_DIRECT_NO_FSYNCとか…わかるな︖- 110/141
innodb̲log̲buffer̲size
InnoDBログのバッファ
ログファイルがwriteされるまでの間、ログに書き込まれる
べきデータはここにいる
1トランザクションが⼤きすぎてログバッファに⼊りきら
ないと途中でフラッシュ
-
innodb_flush_log_at_trx_commit = 0のときはここにあ
りったけ詰め込まれる
-
⼼当たりがあれば⼤きくすれば良いけどせいぜいMB単位
なので⼤きくしてもいい
-
111/141
innodb̲flush̲log̲at̲trx̲commit
InnoDBログをsyncする頻度
デフォルトは1。RDBMSとしては1であるべき。
innodb̲flush̲log̲at̲trx̲co
mmit
write fsync
0 InnoDBまかせ InnoDBまかせ
1 COMMITごと COMMITごと
2 COMMITごと 1秒に1回
112/141
InnoDBログとクラッシュ
problem commit write sync detail
mysqldクラッ
シュ
OK OK OK データの⽋損な
し
OSクラッシュ OK OK OK データの⽋損な
し
mysqldクラッ
シュ
OK OK Not yet データの⽋損な
し
OSクラッシュ OK OK Not yet データ⽋損
mysqldクラッ
シュ
OK Not yet Not yet データ⽋損
OSクラッシュ OK Not yet Not yet データ⽋損
mysqldクラッ
シュ
Not yet Not yet Not yet データの⽋損な
し
OSクラッシュ Not yet Not yet Not yet データの⽋損な
し
113/141
innodb̲flush̲log̲at̲trx̲commit= 1
problem commit write sync detail
mysqldクラッ
シュ
OK OK OK データの⽋損な
し
OSクラッシュ OK OK OK データの⽋損な
し
mysqldクラッ
シュ
OK OK Not yet データの⽋損な
し
OSクラッシュ OK OK Not yet データ⽋損
mysqldクラッ
シュ
OK Not yet Not yet データ⽋損
OSクラッシュ OK Not yet Not yet データ⽋損
mysqldクラッ
シュ
Not yet Not yet Not yet データの⽋損な
し
OSクラッシュ Not yet Not yet Not yet データの⽋損な
し
114/141
innodb̲flush̲log̲at̲trx̲commit= 2
problem commit write sync detail
mysqldクラッ
シュ
OK OK OK データの⽋損な
し
OSクラッシュ OK OK OK データの⽋損な
し
mysqldクラッ
シュ
OK OK Not yet データの⽋損な
し
OSクラッシュ OK OK Not yet データ⽋損
mysqldクラッ
シュ
OK Not yet Not yet データ⽋損
OSクラッシュ OK Not yet Not yet データ⽋損
mysqldクラッ
シュ
Not yet Not yet Not yet データの⽋損な
し
OSクラッシュ Not yet Not yet Not yet データの⽋損な
し
115/141
innodb̲flush̲log̲at̲trx̲commit= 0
problem commit write sync detail
mysqldクラッ
シュ
OK OK OK データの⽋損な
し
OSクラッシュ OK OK OK データの⽋損な
し
mysqldクラッ
シュ
OK OK Not yet データの⽋損な
し
OSクラッシュ OK OK Not yet データ⽋損
mysqldクラッ
シュ
OK Not yet Not yet データ⽋損
OSクラッシュ OK Not yet Not yet データ⽋損
mysqldクラッ
シュ
Not yet Not yet Not yet データの⽋損な
し
OSクラッシュ Not yet Not yet Not yet データの⽋損な
し
116/141
独断と偏⾒
MySQLが単体でダウンするよりはH/W障害で軒並みごっそ
りいかれる⽅が回数が多い気がする
ということはinnodb_flush_log_at_trx_commitは1か0( ク
ラッシュしたら必ず毎回作り直す )が効率がいいと思う
毎回作り直す ことを前提に設計すれば、
innodb_log_group_home_dir= /dev/shm も可能
/dev/shmだとページキャッシュ⾷わないし
更にはskip_innodb_doublewriteも使える
-
117/141
innodb̲io̲capacity, innodb̲io̲capacity̲max
ダーティーページのアダプティブフラッシュに使うIO回数を
制限する
5.6で⼤幅に動作が変わっていて、5.5とそれ以前より⼤幅に
下げないとバックグラウンドスレッドがIOを⾷い切る
innodb_adaptive_flushing_lwmを上げるのもいいかも知れな
い
118/141
キャッシュミスヒット
InnoDBの圧縮はミスヒットのコストがヒット時に⽐べて異
様に⾼い
テーブルキャッシュミスヒットは統計情報を再計算するので
インデックスの数が多いと重い
APサーバーを再起動したタイミングで⼀⻫にSHOW FIELDS
を取りに来るようなORMは「⼀⻫に」と相まって⼀瞬で
テーブルキャッシュを⾷い尽くすことがある
-
クエリーキャッシュはヒット/ミスヒットに関わらずジャイ
アントロックがでかすぎ
119/141
ロックの競合(並列度が⾼いだけとは限らない)
あるいは単にInnoDBが⾏ロックだと 思い込んで ロック粒
度が適切でない
InnoDBのロックはネクストキーロック-
つまり インデックスロック-
ネクストキーロックは インデックス間のギャップもロッ
ク
ギャップロックが避けたい場合はREAD-COMMITTED
にするとまあまあ良くなる
-
sys.innodb̲lock̲waitsがロック解析を助けてくれる
InnoDBは基本的に参照ロックフリー
120/141
Too many connectionsは⼤概並列度⾼すぎではない
単にクエリーが遅い
単にロックが競合してる
単に性能限界を超えたmax_connectionsを設定してしまって
る
Connection Handlerをcloneして認証までしてから”Too
many connections”の判定をするから、cloneの負荷はか
かる
-
稼げる時間は⼗数分、それもエラーを減らすために他の
クエリーの速度を犠牲にする
-
ただしホントにmutexが変に刺さってもこれは出る(けど、
頻度は少ない)
mutexが刺さったならmysqldの再起動⼀択- 121/141
mutexの競合(並列度が⾼すぎる)
ガチでmutexが詰まってる場合は%sysが跳ねあがることが
多い
InnoDBのmutexの詰まりはSHOW ENGINE INNODB STATUSで
SEMAPHORESセクションにいっぱい吐く
こうなると正直⼿の打ちようがほぼない-
多少IO処理を軽くしたりスレッドの数減らして再起動し
ても焼け⽯に⽔
-
スケールアウト検討どき-
⾼負荷状況下で新機能を使うと刺さって残ることがたまにあ
る
というか先週InnoDB Online DDLで変に刺さって再起動
した
-
122/141
バルク操作
最初の戦略
トランザクションの粒度をできるだけ(アトミック性を担保
できるだけ)⼩さくする
トランザクションが⼤きいと
ロックを取る時間が⻑くなる
5.5とそれ以前のスレーブSQLスレッドは同時に1つの
クエリーしかさばけないためレプリケーションが遅延
する
5.6でもスキーマが違わないとパラレルに動かない
5.7でテーブル単位もイケるらしいが未検証
-
123/141
バルク操作
トランザクションが⼩さいと
InnoDBログにフラッシュする回数が多くなる-
ダブルライトの回数が多くなる(ライトコンバインドが
効きにくくなる)
-
バイナリーログエントリーが増えるのでI/Oと帯域に注意-
124/141
バルク操作
新しいインスタンスをスレーブで⽴てて、そっち側でバルク
更新
skip_innodb_doublewrite,
innodb_flush_log_at_trx_commit= 0, skip_log_bin,
skip_slow_query_log
-
バルク操作を分割して並列化-
切り替え時に ショートメンテが必要 (テーブルごとデー
タの転送)
他のスレーブがあった場合、そっちにも転送しないと
いけない
5.6とそれ以降ならFLUSH TABLE FOR EXPORTを使ってテ
ーブル単位でファイルコピーできる
-
125/141
バルク操作
pt-online-schema-changeを流⽤してしのぐ
pt-online-schema-changeは5.5とそれ以前のバージョン
でもオンラインでALTER TABLEを実現できるように作られ
たハックの粋が詰まったスクリプト
-
要はトリガーとREAD-COMMITTEDを使って上⼿いこと
新しいテーブルにデータを移す
-
126/141
pt-oscの仕組み
オリジナルテーブルの定義をコピーしてクローンテーブルを
作る
クローンに対して定義の操作をする
オリジナルにトリガーをかけ、オリジナルに対する更新をク
ローンに伝播させる
READ-COMMITTEDでオリジナルからクローンに少しずつ
データをコピー
データがコピーし終わったらRENAME TABLEでオリジナルとク
ローンを⼊れ替える
127/141
pt-oscの流⽤でバルク操作
トリガーを⼿で(か、pt-oscを中途半端に終わらせてトリガ
ーを残す)張ってpt-archiverとか使うとレプリケーション
遅延とかもチェックしてくれて便利
スレーブを使う⽅法に⽐べてショートメンテは要らない
pt-oscと同じデメリットがある
最⼤でテーブルサイズの2倍以上の空き容量が必要
デッドロック発⽣の可能性
トリガー処理分のレスポンスタイムのオーバーヘッド
数回のメタデータロック
-
128/141
バルクデリートが遅い
InnoDBのDELETEは論理削除、だが
クラスターインデックスだけは再編成する-
5.5とそれ以降ならセカンダリーインデックスはチェンジ
バッファが効いて非同期にマージ
それ以前の場合、⾏を消すということは必ず全てのセ
カンダリーインデックスに更新が⾛るので超重い
-
DELETEの場合、クラスターインデックスのリーフを削除す
るので場合によっては再編成が⾛る
B+Treeはツリーの再編成が重い-
129/141
容量との戦い
DELETEは⼀度拡張したテーブルスペースを縮⼩させない
空き領域が再利⽤されるので、テーブルスペースのサイ
ズがそこで頭打ちになる、程度。
-
テーブルスペースを⼩さくするにはOPTIMIZE TABLEが必
要。
ただしInnoDBでinnodb_file_per_table= 0の場合は
OPTIMIZE TABLEでも⼩さくならない。
この設定だとDROP TABLEやTRUNCATEでも決して⼩さく
ならないので結構⾯倒。
-
130/141
容量との戦い
オンラインでOPTIMIZE TABLE
pt-oscなら5.5や5.6.16とそれ以前でもオンラインででき
る
ただしオリジナルテーブルを残したままクローンテー
ブルに⾏をコピーするので、(容量的な意味での)最
⼤瞬間風速に注意。
-
InnoDBネイティブのオンラインALTER TABLEができる
ようになるのは5.6.17とそれ以降
-
更新がそこまで多くないテーブルなら(秒間数千叩かれ
続けるようなのは⾟かった)5.6.17以降を使うのが簡単
でいい
-
131/141
容量との戦い
タイトになるのがわかってる時はパーティショニングしてる
削除条件が設計段階できれいに決まっているなら、それ
に合わせてパーティショニングすることでALTER TABLE
TRUNCATE PARTITIONが使える。
-
12か⽉保存のためにPARTITION BY LIST ((YEAR
(register_date) MOD 2)* 100 + MONTH(register_date))
で24パーティション確保して13か⽉目にTRUNCATE
PARTITIONするとか
-
132/141
容量との戦い
int型かsmallint型か、timestamp型かdatetime型かは多く
の場合どうでもいい
2バイトの差= 10億⾏でやっと2GB-
インデックスの数に⽐例するけど、それでも⽂字列型に
⽐べれば全然⼤したことない
-
テーブルのサイズは基本的にvarcharに⽀配される
EUC, SJISは2バイト、UTF-8は3バイト(utf8mb4の場
合は最⼤で4バイト⽂字も⼊る)
-
とはいえユーザーコンテンツはどうしようもないんだよ
なぁ。。
垂直シャードするのがギリギリのライン。。
-
133/141
論理削除
個⼈的には好きじゃない
やるなら、これは守っておいた⽅がいい
整数型かENUM型(でないとc.が守りにくい)a.
全てのセカンダリーインデックス の先頭に削除フラグの
カラムが存在しなければならない
b.
決して”=”以外の演算⼦を使わない(NOTとかダメ、絶
対)
c.
”=”演算⼦で等価⽐較するものを全てのWHERE句の先頭に
つける
d.
これ以外で迂闊に使うと、あっという間にExecutorさんが
頑張る世界線に突⼊する
134/141
Questions
and/or
Suggestions?
135/141
Question
MySQL 5.5からそれ以降にアップグレードするにあたって注意
事項はある︖
5.6ではInnoDBのバックグラウンドスレッドが活発になってい
るのでinnodb̲io̲capacityを減らす、メモリーを⼤⾷いにな
ったので「物理メモリーの75%」よりも減らしておくと良い。
SQL的な非互換はほぼない。
5.7はsql̲modeのデフォルト値に変更があったので明⽰的に
sql_mode= ''をコンフィグに記載しないとSQLが非互換。
sql̲modeが同じでも多少の非互換があり、古いRailsだと
migrationに失敗する。いくつか古いオプションが削除になっ
ている。
136/141
Question
オプティマイザーだけアップグレードとかできない︖
できません><
137/141
Question
Using whereとUsing filesort、どっちが悪いっていう指標はあ
るの︖
フェッチするのが2⾏だったらUsing whereでもUsing filesort
でも構わないけどフェッチするのが1000万⾏だったらダメだ
よね、という感じなので、Rows_sentとRows_examinedの⽐率で
⽐べるのがいいんじゃ。
138/141
Question
InnoDBの統計情報をサンプリングではなく全ページをスキャン
にはできないの︖
グローバル変数またはテーブル単位でページ数を指定できるの
で、それを⼗分⼤きくすれば全ページをスキャンした統計情報
は可能。ただ、5.5で知⼈が試した限り遅かったらしい。
139/141
Question
MyISAMならALTER TABLE .. ORDER BY ..で降順のインデック
スを作れる︖
インデックス上は必ず昇順。ALTER TABLE .. ORDER BY ..で並
べ替えられるのはデータファイル上の並び順。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.1.7
ALTER TABLE 構⽂
140/141
Question
MySQLからMariaDBに移⾏したら性能があがった。考えられる
要因は︖
MariaDBのオプティマイザーは性能が良い。MariaDBの
InnoDBはPerconaが開発しているXtraDBなのでちょっとだけ
いい。バイナリーログのグループコミットが性能が良く、スレ
ーブの遅延が起きにくい。
メディアではMariaDBは使っている︖
スレッドプールプラグインが使いたくて導⼊したことがあった
が、ワークロード的にMySQLより遅くなったので、より
MySQLに近いPercona Serverに移⾏した。
141/141

More Related Content

What's hot

Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugMasatoshi Tada
 
MySQL 8.0で憶えておいてほしいこと
MySQL 8.0で憶えておいてほしいことMySQL 8.0で憶えておいてほしいこと
MySQL 8.0で憶えておいてほしいことyoku0825
 
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装infinite_loop
 
MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法yoku0825
 
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
MySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っているMySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っているyoku0825
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Taku Miyakawa
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界Yoshinori Nakanishi
 
やってはいけない空振りDelete
やってはいけない空振りDeleteやってはいけない空振りDelete
やってはいけない空振りDeleteYu Yamada
 
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)NTT DATA Technology & Innovation
 
Cassandraのしくみ データの読み書き編
Cassandraのしくみ データの読み書き編Cassandraのしくみ データの読み書き編
Cassandraのしくみ データの読み書き編Yuki Morishita
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
トランザクションの設計と進化
トランザクションの設計と進化トランザクションの設計と進化
トランザクションの設計と進化Kumazaki Hiroki
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較Akihiro Suda
 

What's hot (20)

Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
MySQL 8.0で憶えておいてほしいこと
MySQL 8.0で憶えておいてほしいことMySQL 8.0で憶えておいてほしいこと
MySQL 8.0で憶えておいてほしいこと
 
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装
 
MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法
 
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
MySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っているMySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っている
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
Vacuum徹底解説
Vacuum徹底解説Vacuum徹底解説
Vacuum徹底解説
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界
 
やってはいけない空振りDelete
やってはいけない空振りDeleteやってはいけない空振りDelete
やってはいけない空振りDelete
 
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
 
Cassandraのしくみ データの読み書き編
Cassandraのしくみ データの読み書き編Cassandraのしくみ データの読み書き編
Cassandraのしくみ データの読み書き編
 
分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
トランザクションの設計と進化
トランザクションの設計と進化トランザクションの設計と進化
トランザクションの設計と進化
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較
 

More from yoku0825

逝くぞ最新版、罠の貯蔵は十分か
逝くぞ最新版、罠の貯蔵は十分か逝くぞ最新版、罠の貯蔵は十分か
逝くぞ最新版、罠の貯蔵は十分かyoku0825
 
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技yoku0825
 
片手間MySQLチューニング戦略
片手間MySQLチューニング戦略片手間MySQLチューニング戦略
片手間MySQLチューニング戦略yoku0825
 
MySQLを割と一人で300台管理する技術
MySQLを割と一人で300台管理する技術MySQLを割と一人で300台管理する技術
MySQLを割と一人で300台管理する技術yoku0825
 
MySQLステータスモニタリング
MySQLステータスモニタリングMySQLステータスモニタリング
MySQLステータスモニタリングyoku0825
 
わかった気になるMySQL
わかった気になるMySQLわかった気になるMySQL
わかった気になるMySQLyoku0825
 
わたしを支える技術
わたしを支える技術わたしを支える技術
わたしを支える技術yoku0825
 
MySQL 5.7の次のMySQL 8.0はどんなものになるだろう
MySQL 5.7の次のMySQL 8.0はどんなものになるだろうMySQL 5.7の次のMySQL 8.0はどんなものになるだろう
MySQL 5.7の次のMySQL 8.0はどんなものになるだろうyoku0825
 
Dockerイメージで誰でも気軽にMroonga体験
Dockerイメージで誰でも気軽にMroonga体験Dockerイメージで誰でも気軽にMroonga体験
Dockerイメージで誰でも気軽にMroonga体験yoku0825
 
MySQLアンチパターン
MySQLアンチパターンMySQLアンチパターン
MySQLアンチパターンyoku0825
 
MySQLerの7つ道具 plus
MySQLerの7つ道具 plusMySQLerの7つ道具 plus
MySQLerの7つ道具 plusyoku0825
 
MySQL 5.7の次のMySQLは
MySQL 5.7の次のMySQLはMySQL 5.7の次のMySQLは
MySQL 5.7の次のMySQLはyoku0825
 
MySQLerの7つ道具
MySQLerの7つ道具MySQLerの7つ道具
MySQLerの7つ道具yoku0825
 
MHAの次を目指す mikasafabric for MySQL
MHAの次を目指す mikasafabric for MySQLMHAの次を目指す mikasafabric for MySQL
MHAの次を目指す mikasafabric for MySQLyoku0825
 
5.7の次のMySQL
5.7の次のMySQL5.7の次のMySQL
5.7の次のMySQLyoku0825
 
mikasafabric for MySQL
mikasafabric for MySQLmikasafabric for MySQL
mikasafabric for MySQLyoku0825
 
とあるイルカの近況報告
とあるイルカの近況報告とあるイルカの近況報告
とあるイルカの近況報告yoku0825
 
MySQL Fabricでぼっこぼこにされたはなし
MySQL FabricでぼっこぼこにされたはなしMySQL Fabricでぼっこぼこにされたはなし
MySQL Fabricでぼっこぼこにされたはなしyoku0825
 
MySQLと正規形のはなし
MySQLと正規形のはなしMySQLと正規形のはなし
MySQLと正規形のはなしyoku0825
 
MySQLおじさんの逆襲
MySQLおじさんの逆襲MySQLおじさんの逆襲
MySQLおじさんの逆襲yoku0825
 

More from yoku0825 (20)

逝くぞ最新版、罠の貯蔵は十分か
逝くぞ最新版、罠の貯蔵は十分か逝くぞ最新版、罠の貯蔵は十分か
逝くぞ最新版、罠の貯蔵は十分か
 
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技
サーバーが完膚なきまでに死んでもMySQLのデータを失わないための表技
 
片手間MySQLチューニング戦略
片手間MySQLチューニング戦略片手間MySQLチューニング戦略
片手間MySQLチューニング戦略
 
MySQLを割と一人で300台管理する技術
MySQLを割と一人で300台管理する技術MySQLを割と一人で300台管理する技術
MySQLを割と一人で300台管理する技術
 
MySQLステータスモニタリング
MySQLステータスモニタリングMySQLステータスモニタリング
MySQLステータスモニタリング
 
わかった気になるMySQL
わかった気になるMySQLわかった気になるMySQL
わかった気になるMySQL
 
わたしを支える技術
わたしを支える技術わたしを支える技術
わたしを支える技術
 
MySQL 5.7の次のMySQL 8.0はどんなものになるだろう
MySQL 5.7の次のMySQL 8.0はどんなものになるだろうMySQL 5.7の次のMySQL 8.0はどんなものになるだろう
MySQL 5.7の次のMySQL 8.0はどんなものになるだろう
 
Dockerイメージで誰でも気軽にMroonga体験
Dockerイメージで誰でも気軽にMroonga体験Dockerイメージで誰でも気軽にMroonga体験
Dockerイメージで誰でも気軽にMroonga体験
 
MySQLアンチパターン
MySQLアンチパターンMySQLアンチパターン
MySQLアンチパターン
 
MySQLerの7つ道具 plus
MySQLerの7つ道具 plusMySQLerの7つ道具 plus
MySQLerの7つ道具 plus
 
MySQL 5.7の次のMySQLは
MySQL 5.7の次のMySQLはMySQL 5.7の次のMySQLは
MySQL 5.7の次のMySQLは
 
MySQLerの7つ道具
MySQLerの7つ道具MySQLerの7つ道具
MySQLerの7つ道具
 
MHAの次を目指す mikasafabric for MySQL
MHAの次を目指す mikasafabric for MySQLMHAの次を目指す mikasafabric for MySQL
MHAの次を目指す mikasafabric for MySQL
 
5.7の次のMySQL
5.7の次のMySQL5.7の次のMySQL
5.7の次のMySQL
 
mikasafabric for MySQL
mikasafabric for MySQLmikasafabric for MySQL
mikasafabric for MySQL
 
とあるイルカの近況報告
とあるイルカの近況報告とあるイルカの近況報告
とあるイルカの近況報告
 
MySQL Fabricでぼっこぼこにされたはなし
MySQL FabricでぼっこぼこにされたはなしMySQL Fabricでぼっこぼこにされたはなし
MySQL Fabricでぼっこぼこにされたはなし
 
MySQLと正規形のはなし
MySQLと正規形のはなしMySQLと正規形のはなし
MySQLと正規形のはなし
 
MySQLおじさんの逆襲
MySQLおじさんの逆襲MySQLおじさんの逆襲
MySQLおじさんの逆襲
 

Recently uploaded

SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 

Recently uploaded (10)

SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 

雑なMySQLパフォーマンスチューニング