34. Extra: Using where; Using filesort;
ExecutorがWHEREをフィルターしている、ExecutorがORDER
BYのソートをしている
インデックスを使って⾼速化できるのは WHERE, ORDER BY,
GROUP BY, select_list
どうすればいいかと⾔われると、「インデックス使う」とし
か⾔いようがない
33/141
65. 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
66. 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
67. 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
68. 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
69. 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
70. 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
71. 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
72. 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
73. 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
74. WHERE狙いのキー, ORDER BY狙いのキー
WHEREとORDER BY .. LIMITを同時にカバーできるインデック
スが作成できない時に
WHEREをストレージエンジンに任せてフェッチする⾏を減
らしてファイルソートをExecutorにやらせるか
-
ORDER BY .. LIMITをストレージエンジンに任せて
ExecutorにフィルターさせつつLIMITでループを抜けるの
を期待するか
-
73/141
78. 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
79. オプティマイザーの強化
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
81. クエリーの最適化(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
82. クエリーの最適化(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
83. 古い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
114. 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
115. 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
116. 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
117. 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
141. Question
MyISAMならALTER TABLE .. ORDER BY ..で降順のインデック
スを作れる︖
インデックス上は必ず昇順。ALTER TABLE .. ORDER BY ..で並
べ替えられるのはデータファイル上の並び順。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.1.7
ALTER TABLE 構⽂
140/141