あんちぽくんさん「ネタは雑 + 5.7
がいいです︕」
いつのまにかあんちぽちゃんさんになっていたことに気付かなかっ
た
2016/02/22
yoku0825の中の⼈
Pepabo de MySQL
\こんにちは/
yoku0825@とある企業のDBA の中の⼈
オラクれない-
ポスグれない-
マイエスキューエる-
Twitter: @yoku0825
Blog: ⽇々の覚書
Oracle ACE Details
MySQL 5.7 Community Contributor Award
1/69
このスライド書いた中の⼈です
2/69
ちなみに
3/69
というわけで安⼼
して 地雷友達 5.7
使っていいです
よ :)
4/69
なお
ウチは明⽇ 5.7のカットオーバーがあります
明⽇からまた5.7についてぐちぐち呟いてたら痛い目⾒たん
だと思ってください
5/69
ざっくりMySQL 5.7
2013/02 MySQL 5.6.10 GA
2013/04 MySQL 5.7.1 DMR11
2015/03 MySQL 5.7.6 DMR16
2015/04 MySQL 5.7.7 RC
2015/08 MySQL 5.7.8 RC
2015/10 MySQL 5.7.9 GA
2015/12 MySQL 5.7.10 GA
2016/02 MySQL 5.7.11 GA
6/69
MySQL 5.7
2015/04 MySQL 5.7.7 RC
ここまではまあいい
2015/08 MySQL 5.7.8 RC
JSON型, virtual generated columnの拡張, InnoDB Page
Compression
2015/10 MySQL 5.7.9 GA
innodb_default_row_format, JSON -> operator,
innodb_numa_interleave
2015/12 MySQL 5.7.10 GA
Bug Fix
2016/02 MySQL 5.7.11 GA
InnoDB Tablespace Encryption 7/69
MySQL 5.7
2015/04 MySQL 5.7.7 RC
ここまではまあいい
2015/08 MySQL 5.7.8 RC
新機能!!
2015/10 MySQL 5.7.9 GA
新機能!!
2015/12 MySQL 5.7.10 GA
Bug Fix
2016/02 MySQL 5.7.11 GA
新機能!!
8/69
General
Available #
とは
9/69
MySQL 5.7について雑に⾔っておきたいこと
取り敢えず⼀通りなアレは slideshare と ブログ に置いて
きました
気に⼊ってる機能だけ伝えます
10/69
お気に⼊り
sysスキーマ を 5.6で 使うこと
generated column
GTIDのオンライン有効化
11/69
sysスキーマ
元 ps̲helper
リポジトリーの名前はdbahelper。。-
performance̲schema, information̲schemaのビューと、
performance̲schema関連の設定をゴニョるプロシージャ
の詰め合わせ
なのでperformance_schema= ONが⼤前提-
合わせて使いたいinnodb_monitor_enable= all-
実は5.6から使える(使ってる。便利)-
12/69
sys.metrics
監視に良さそうな項目の詰め合わせ。
もうSHOW ENGINE INNODB STATUSをパースしなくてもいい
んだ。。
-
mysql> SELECT * FROM sys.metrics;
+-----------------------------------------------+---------------------+--------------------------------------+---------+
| Variable_name | Variable_value | Type | Enabled |
+-----------------------------------------------+---------------------+--------------------------------------+---------+
| aborted_clients | 3288 | Global Status | YES |
| aborted_connects | 1533301 | Global Status | YES |
| binlog_cache_disk_use | 0 | Global Status | YES |
| binlog_cache_use | 6788464032 | Global Status | YES |
..
| buffer_flush_adaptive | 23215268 | InnoDB Metrics - buffer | YES |
| buffer_flush_adaptive_pages | 8 | InnoDB Metrics - buffer | YES |
| buffer_flush_adaptive_total_pages | 257407436 | InnoDB Metrics - buffer | YES |
| buffer_flush_avg_page_rate | 7 | InnoDB Metrics - buffer | YES |
| buffer_flush_background | 4894219 | InnoDB Metrics - buffer | YES |
..
| compression_pad_decrements | 9 | InnoDB Metrics - compression | YES |
| compression_pad_increments | 9 | InnoDB Metrics - compression | YES |
| compress_pages_compressed | 362107 | InnoDB Metrics - compression | YES |
| compress_pages_decompressed | 155406 | InnoDB Metrics - compression | YES |
..
13/69
sys.schema̲index̲statistics
どのインデックスを使ってどれだけハンドラーが呼ばれた
か、そのレイテンシーの合計は…というのが⾒られる。
あんまり使われてないインデックスをあぶりだすのは後述の
sys.schema_unused_indexesビューでもいける。
mysql> SELECT * FROM sys.schema_index_statisticsG
*************************** 1. row ***************************
table_schema: xxxxxxx
table_name: quiz_xxxxxxxx
index_name: idx_xxxxxxxxx
rows_selected: 352020501193
select_latency: 5.83 d
rows_inserted: 0
insert_latency: 0 ps
rows_updated: 0
update_latency: 0 ps
rows_deleted: 0
delete_latency: 0 ps
1 row in set (0.04 sec)
14/69
sys.schema̲unused̲indexes
名前そのものズバリ、使われてない(統計開始から⼀度も使
われていない)インデックスを⼀覧してくれる。
ただし、performance_schema.setup_actors,
performance_schema.setup_objects,
performance_schema.setup_instruments= 'wait/io/table/
sql/handler'あたりの設定に依存する。吊るしで使ってるな
らフツーのテーブルではmysqldの起動時から全部統計が有効
になっている。
アクセス具合によるので、マスターで使ってなくてスレーブ
で使ってるインデックスとかあるので注意。
15/69
sys.statement̲analysis
sys.format_statementというストアドファンクションを噛ん
でいるせいで、queryカラムが切り詰められる。
performance_schema.events_statements_summary_by_dig
est.digest_textに切り詰められていないステートメント
があるので、USING (digest)でJOINしてやるとpt-
query-digestっぽい出⼒が得られる。
-
sys.x$statement_analysisでもいいんだけど、queryカラ
ム以外も全部展開されちゃって⾒にくい。
-
mysql> SELECT * FROM sys.statement_analysisG
*************************** 2. row ***************************
query: SELECT `xxxx_REPORT` . `UNIQU ... S `PURE_TOTAL_xxxx` , SUM (
16/69
sys.statements̲with̲errors̲or̲warnings
カジュアルに桁切り詰めワーニングを無視してるステートメ
ントとか⼀網打尽にできる。
--gtid-enforce-consistency= WARNと組み合わせて使うと夢
が広がる。
17/69
sys.innodb̲lock̲waits
SH2さんのステートメントとの別離の時
MySQL InnoDBにおけるロック競合の解析⼿順 - SH2の
⽇記
-
KILLするためのステートメントも出⼒してくれるあたりがロ
ック
しかもKILL QUERYとKILLを両⽅出⼒する芸の細かさ-
18/69
sys.innodb̲lock̲waits
mysql> DESC sys.innodb_lock_waits;
+------------------------------+---------------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------------+---------------------+------+-----+---------------------+-------+
| wait_started | datetime | YES | | NULL | |
| wait_age | time | YES | | NULL | |
| wait_age_secs | bigint(21) | YES | | NULL | |
| locked_table | varchar(1024) | NO | | | |
| locked_index | varchar(1024) | YES | | NULL | |
| locked_type | varchar(32) | NO | | | |
| waiting_trx_id | varchar(18) | NO | | | |
| waiting_trx_started | datetime | NO | | 0000-00-00 00:00:00 | |
| waiting_trx_age | time | YES | | NULL | |
| waiting_trx_rows_locked | bigint(21) unsigned | NO | | 0 | |
| waiting_trx_rows_modified | bigint(21) unsigned | NO | | 0 | |
| waiting_pid | bigint(21) unsigned | NO | | 0 | |
| waiting_query | longtext | YES | | NULL | |
| waiting_lock_id | varchar(81) | NO | | | |
| waiting_lock_mode | varchar(32) | NO | | | |
| blocking_trx_id | varchar(18) | NO | | | |
| blocking_pid | bigint(21) unsigned | NO | | 0 | |
| blocking_query | longtext | YES | | NULL | |
| blocking_lock_id | varchar(81) | NO | | | |
| blocking_lock_mode | varchar(32) | NO | | | |
| blocking_trx_started | datetime | NO | | 0000-00-00 00:00:00 | |
| blocking_trx_age | time | YES | | NULL | |
| blocking_trx_rows_locked | bigint(21) unsigned | NO | | 0 | |
| blocking_trx_rows_modified | bigint(21) unsigned | NO | | 0 | |
| sql_kill_blocking_query | varchar(32) | YES | | NULL | |
| sql_kill_blocking_connection | varchar(26) | YES | | NULL | |
+------------------------------+---------------------+------+-----+---------------------+-------+
26 rows in set (0.01 sec)
19/69
危険なヤツら
sys.innodb̲buffer̲stats̲by̲schema
sys.innodb̲buffer̲stats̲by̲table
sys.schema̲table̲statistics̲with̲buffer
これ注意。 迂闊に触ると死ぬ ことがある。
内部的にinformaition̲schema.innodb̲buffer̲pageを⾒
ているので、でかいバッファプール(経験則だと20GB超)
でやるとたまに突き刺さる。
特にCtrl + Cでクエリーを殺すと突き刺さる率が俺の中
では⾼い
-
20/69
名前で判りそうなやつら
sys.statements̲with̲temp̲tables
sys.statements̲with̲full̲table̲scans
sys.statements̲with̲runtimes̲in̲95th̲percentile
sys.statements̲with̲sorting
sys.statements̲with̲temp̲tables
21/69
sysスキーマというかperformance̲schemaの特徴
コードの中に”instrument”と呼ばれる記録ポイントが埋め
込まれていて、そこを通るたびにメモリー上に記録する
本質的にプロファイラー-
ディスクに落とさない(オンメモリーストレージエンジン
)でhistoryを増やせば増やすだけメモリー⾷う
メモリーは起動時確保(5.6)
5.7で変わったっぽい。メモリー使⽤量が穏やかに。
-
22/69
sysスキーマというかperformance̲schemaの特徴
プロファイラーなので、テーブルにアクセスしても実⾏中の
処理には影響が出ない(実⾏済みの処理の統計が記録されて
いるだけ)
それに対してi̲sはテーブルアクセス時に各種情報をかき
集める
だからinnodb̲buffer̲pageはしこたま重い
-
デフォルトではプロファイラーっぽい表⽰をするための
instrumentは無効
23/69
sys(というかperformance̲schema)がもたらすもの
ジェネラルログやスローログ(あるいはlong_query_time)
が適切に設定されていないと尻尾を掴むことが難しかった
クソ ダメなクエリーが
p̲sはダイジェスト単位とはいえ 後追い で検索できる。-
テンポラリーテーブルになってるか、ソートした⾏数はいく
つだったかはSHOW GLOBAL STATUSしかなかった。
SQLダイジェスト単位 で検索可能。-
スローログにも記録されなかった情報がある。今までは
記録したかったらPercona ServerかMariaDBを選んで
た。
-
24/69
MySQL 5.6 performance̲schema= ON + sysスキー
マ
かなり良い
MySQL 5.6以降でp̲sが有効なら是非⼊れるべき。-
ただしS/N⽐が悪い(ノイズ多い)-
万能ではない
検索できるところまでは良くても
ノイズをノイズとして⾒分ける能⼒
そのクエリーをチューニングする能⼒
-
は相変わらず必要-
MySQL Workbenchはsysの結果を⾷ってグラフを作る機能
を提供したらもっと流⾏ると思う
25/69
sysスキーマのストアドプロシージャ/ファンクション
SELECT routine_name, routine_type FROM
information_schema.routines WHERE routine_schema=
'sys'で確認できる。
MySQL :: MySQL 5.7 Reference Manual :: 22.4.4
sys Schema Stored Procedures
-
⼀番お世話になるのは今までの統計情報の履歴を吹っ⾶ばし
てくれる sys.ps_truncate_all_tables
ある程度チューニングしたら履歴を吹っ⾶ばして状況を
確認しなおす
-
sys.create_synonym_dbには感⼼した。
26/69
sysスキーマ on 5.6
mysql/mysql-sys: The MySQL sys schema からcloneし
てきて突っ込むだけ。
sys作成時はbinlogオフにするので、マスターで実⾏して
もスレーブには作られない。
-
$ git clone https://github.com/mysql/mysql-sys
$ cd mysql-sys
$ mysql -uroot -pxxx < ./sys_56.sql
27/69
generated columnで関数インデックス
⽣成された列にNOT NULL制約、UNIQUE制約もかけられる
(疑似チェック制約が作れる)
直接値を投⼊することはできないが、「カラム」としては定
義されるのでSELECT *とかINSERT INTO .. VALUESに注意。
STOREDタイプは全⽂検索にも対応
STORED or VIRTUAL INDEXあり INDEXなし
VIRTUAL(デフォルト) ALTER TABLE時 SELECT時
STORED ALTER TABLE時 ALTER TABLE時
28/69
generated columnでcovering index
mysql> ALTER TABLE t2 ADD v_lang varchar(16) AS (val->'$.lang'), ADD KEY(v_lang
);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain SELECT v_lang, COUNT(*) AS c FROM t2 GROUP BY v_lang;
+----+-------------+-------+------------+-------+---------------+--------+------
---+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_l
en | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------+------
---+------+------+----------+-------------+
| 1 | SIMPLE | t2 | NULL | index | v_lang | v_lang | 1
9 | NULL | 74 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------+------
---+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
29/69
generated columnで全⽂検索
KEY (v_text) WITH PARSER MeCab;
t supported for generated columns.
ULLTEXT KEY (v_text) WITH PARSER MeCab;
Query OK, 100 rows affected (0.37 sec)
Records: 100 Duplicates: 0 Warnings: 0
ext) against ('MySQL') LIMIT 3G
*************************** 1. row ***************************
v_id: 654573993006010368
v_text: "RT @mysql_jp: MySQL 5.7 GAと同時にMySQL Fabricによる構成や各種レプリケーション構成
へのアクセスをシンプルにするMySQL RouterもGAとなっています https://t.co/u3e1E2OSoV #mysql_jp"
val->'$.created_at': "Mon Oct 19 14:17:58 +0000 2015"
*************************** 2. row ***************************
v_id: 654573993006010368
v_text: "RT @mysql_jp: MySQL 5.7 GAおよびMySQL Router GAなどの技術情報はMySQL 最新情報セミナ
ー2015秋にてご紹介い たします。ぜひご参加下さい。なお東京は11月9日にも第2回を開催予定です http://t.c
o/0Drp08uNbW #m…"
val->'$.created_at': "Mon Oct 19 14:22:05 +0000 2015"
*************************** 3. row ***************************
v_id: 654573993006010368
v_text: "RT @mysql_jp: MySQL 5.7の機能概要はこちらです http://t.co/FZ1Qa7HTfon新機能の一覧
はOracle ACE(MySQL)のyoku0825さんによるこちらの記事をご参照下さい https://t.co/WclCToU1Xrn#mysq…"
val->'$.created_at': "Tue Oct 20 02:00:03 +0000 2015"
3 rows in set (0.00 sec)
30/69
逆パターン
# wget http://downloads.mysql.com/docs/world.sql.gz
# mysqladmin create world
# zcat world.sql.gz | mysql world
mysql> SELECT * FROM world.City LIMIT 3;
+----+----------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+----+----------+-------------+----------+------------+
| 1 | Kabul | AFG | Kabol | 1780000 |
| 2 | Qandahar | AFG | Qandahar | 237500 |
| 3 | Herat | AFG | Herat | 186800 |
+----+----------+-------------+----------+------------+
3 rows in set (0.00 sec)
31/69
generated columnでJSONにしてしまう
mysql> ALTER TABLE City ADD v_json BLOB AS (json_object('name', N
ame, 'countrycode', CountryCode, 'district', District, 'populatio
n', Population)) STORED;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SELECT v_json FROM City LIMIT 3G
*************************** 1. row ***************************
v_json: {"name": "Kabul", "district": "Kabol", "population": 1780
000, "countrycode": "AFG"}
*************************** 2. row ***************************
v_json: {"name": "Qandahar", "district": "Qandahar", "population
": 237500, "countrycode": "AFG"}
*************************** 3. row ***************************
v_json: {"name": "Herat", "district": "Herat", "population": 1868
00, "countrycode": "AFG"}
3 rows in set (0.00 sec)
32/69
挙句InnoDB Memcached(JSON型だと結果がおかしく
なったのでBLOB型でSTORED)
# mysql < /usr/share/mysql/innodb_memcached_config.sql
mysql> INSTALL PLUGIN daemon_memcached SONAME "libmemcached.so";
mysql> ALTER TABLE world.City ADD c1 int DEFAULT 0, ADD c2 bigint DEFAUL
T 0, ADD c3 int DEFAULT 0;
Query OK, 0 rows affected (0.23 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> DELETE FROM innodb_memcache.containers;
mysql> INSERT INTO innodb_memcache.containers VALUES ('world_json', 'wor
ld', 'City', 'ID', 'v_json', 'c1', 'c2', 'c3', 'PRIMARY');
# service mysqld restart
# memcat --servers=127.0.0.1:11211 1
{"name": "Kabul", "district": "Kabol", "population": 1780000, "countryco
de": "AFG"}
33/69
範囲検索でORDER BYまでキーが使えないやつも
mysql> ALTER TABLE Country ADD KEY (population, gnp);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain SELECT Name FROM Country WHERE Population > 100000000 ORD
ER BY GNP DESC;
+----+-------------+---------+------------+-------+---------------+-----
-------+---------+------+------+----------+-----------------------------
----------+
| id | select_type | table | partitions | type | possible_keys | ke
y | key_len | ref | rows | filtered | Extr
a |
+----+-------------+---------+------------+-------+---------------+-----
-------+---------+------+------+----------+-----------------------------
----------+
| 1 | SIMPLE | Country | NULL | range | Population | Popu
lation | 4 | NULL | 10 | 100.00 | Using index condition; Usin
g filesort |
+----+-------------+---------+------------+-------+---------------+-----
-------+---------+------+------+----------+-----------------------------
----------+
1 row in set, 1 warning (0.00 sec)
34/69
generated columnならこの通り
mysql> ALTER TABLE Country ADD is_over_100mil tinyint AS (IF(Population > 100000
00, 1, 0)), ADD KEY (is_over_100mil, GNP);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain SELECT Name FROM Country WHERE is_over_100mil = 1 ORDER BY GNP DE
SC;
+----+-------------+---------+------------+------+----------------+-------------
---+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | ke
y | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+----------------+-------------
---+---------+-------+------+----------+-------------+
| 1 | SIMPLE | Country | NULL | ref | is_over_100mil | is_over_100m
il | 2 | const | 78 | 100.00 | Using where |
+----+-------------+---------+------------+------+----------------+-------------
---+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
35/69
昇順と降順が混じったソートも
mysql> ALTER TABLE Country ADD KEY (is_over_100mil, GNP, GNPOld);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain SELECT Name FROM Country USE INDEX(is_over_100mil_2) WHERE is_ove
r_100mil = 1 ORDER BY GNP ASC, GNPOld DESC LIMIT 1;
+----+-------------+---------+------------+------+------------------+-----------
-------+---------+-------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | ke
y | key_len | ref | rows | filtered | Extr
a |
+----+-------------+---------+------------+------+------------------+-----------
-------+---------+-------+------+----------+-----------------------------+
| 1 | SIMPLE | Country | NULL | ref | is_over_100mil_2 | is_over_10
0mil_2 | 2 | const | 78 | 100.00 | Using where; Using filesort |
+----+-------------+---------+------------+------+------------------+-----------
-------+---------+-------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)
36/69
generated columnならこの通り
mysql> ALTER TABLE Country ADD invert_gnpold float(10, 2) AS (0 - GNPOld), ADD K
EY (is_over_100mil, GNP, invert_gnpold);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain SELECT Name FROM Country WHERE is_over_100mil = 1 ORDER BY GNP AS
C, invert_gnpold ASC LIMIT 1;
+----+-------------+---------+------------+------+------------------------------
--------------------+------------------+---------+-------+------+----------+----
---------+
| id | select_type | table | partitions | type | possible_key
s | key | key_len | ref | row
s | filtered | Extra |
+----+-------------+---------+------------+------+------------------------------
--------------------+------------------+---------+-------+------+----------+----
---------+
| 1 | SIMPLE | Country | NULL | ref | is_over_100mil,is_over_100mil
_2,is_over_100mil_3 | is_over_100mil_3 | 2 | const | 78 | 100.00 | Usi
ng where |
+----+-------------+---------+------------+------+------------------------------
--------------------+------------------+---------+-------+------+----------+----
---------+
1 row in set, 1 warning (0.00 sec)
37/69
MySQLにないCHECK制約もgenerated columnならこ
の通り
mysql> ALTER TABLE Country ADD v_check tinyint AS (IF(GNPOld < 10
00, NULL, 1)) NOT NULL;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> INSERT INTO Country SET Name= 'Dummy', GNPOld= 0.01;
ERROR 1048 (23000): Column 'v_check' cannot be null
mysql> INSERT INTO Country SET Name= 'Dummy', GNPOld= 1000.01;
Query OK, 1 row affected (0.00 sec)
38/69
似非CHECK制約の仕様
VIRTUALかつセカンダリーインデックスなしだと実⾏時評
価になるので、「今までの似非CHECK制約違反は無視して
ALTER TABLE完了、その後の更新には似非CHECK制約適
⽤」
STOREDまたはセカンダリーインデックスありだとALTER
TABLE時に評価されるので「似非CHECK制約違反があると
ALTER TABLEがエラーになる」
mysql57> ALTER TABLE Country ADD v_check tinyint AS (IF(GNPOld < 1000, NULL, 1)) STORED NOT NULL;
ERROR 1048 (23000): Column 'v_check' cannot be null
mysql57> ALTER TABLE Country ADD v_check tinyint AS (IF(GNPOld < 1000, NULL, 1)) NOT NULL, ADD KE
Y (v_check);
ERROR 1048 (23000): Column 'v_check' cannot be null
mysql57> ALTER TABLE Country ADD v_check tinyint AS (IF(GNPOld < 1000, NULL, 1)) NOT NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
39/69
⾊々できる
クエリーの書き換えは必要になる
カラム指定せずにINSERTしようとするお⾏儀の悪いクエ
リー
-
generatedなカラムとフツーのカラムを⾒分けるにはSHOW
FULL COLUMNSのExtra列をちゃんとパースしないとダメ
mysqldumpとの相性が悪い。。-
ORMとの相性も悪い。。
ActiveRecord︕︕1 @kamipo++ => ActiveRecord
とMySQL 5.7
-
開発者との相性も(今のところ)悪い。。
もっと広く知られるようになれば問題はなくなると思
う。
-
40/69
GTIDのオンライン有効化
masterslave OFF OFF̲PERMISSIVE ON̲PERMISSIVE ON
OFF ○ ○ ○ ×
OFF̲PERMIS
SIVE
○ ○ ○ ×
ON̲PERMISS
IVE
× ○ ○ ○
ON × ○ ○ ○
41/69
GTIDのオンライン有効化
OFF
GTIDを振らない。GTIDの振られたイベントが来るとエラる
OFF̲PERMISSIVE (5.7から)
GTIDを振らないけど、GTIDの振られたイベントが来ても⽂句
を⾔わない
ON̲PERMISSIVE (5.7から)
GTIDを振るけど、GTIDの振られてないイベントが来ても⽂句
を⾔わない
ON
GTIDを振るし、GTIDの振られてないイベントが来るとエラる
42/69
GTIDのオンライン有効化
enforce_gtid_consistencyの取りうる値がON, OFF, WARN
の3種類 && SET GLOBALでオンライン変更可能になった
enforce_gtid_consistency= WARNだと、ON̲PERMISSIVE
以上のgtid̲modeではエラーになるステートメントがワー
ニングで出⼒される
sys.statements_with_errors_or_warningsで拾っていく
スタイル
-
43/69
GTIDで嬉しいこと
CHANGE MASTER TO master_auto_position= 1できるようにな
る
master_log_file, master_log_posはgtid_executedなどの
情報からマスターとスレーブが勝⼿にネゴってくれる
-
さっくり作る、さっくり切り替える、さっくり捨てる に
向いてる
データサイズ⼤きくなってくると、「さっくり作る」
がアレになってくるかな。。
Dockerと相性が良かった
Dockerはせいぜい開発環境⽤にくらいしか考えてない
けど
-
44/69
GTIDで嬉しいこと
MHAは5.6のクラッシュセーフスレーブ設定だと動かない、
他の選択肢が必要になってきた
松信さんには「いや動くでしょ︖」って⾔われたけど
relay_log_info_repository= TABLEだと動かない。。
-
mysqlfailover, mysqlrpladminはダメすぎてつらい
MySQL Fabricがいいな
コマンドラインにしては割とグラフィカルで楽しい-
Fabric対応コネクターとかMySQL Routerとかは夢-
master_ip_failover_script, report_scriptに相当するも
のはない
やるとしたらこんな感じのまた書く気がする Redis
Sentinelを運⽤してみたお話
-
45/69
続いて雑
なやつ
46/69
FAQ
あの資料雑なの︖
雑です
雑 #とは
Executorに仕事させないためにインデックス使ってね、だけ
で、肝⼼のインデックスの貼り⽅書いてないあたりが
書けよ
だってめんどくさいんだもん
47/69
前回のあ
らすじ
48/69
クエリーのライフサイクル
client
connection_handling parser optimizer executor
handler storage_engine
application
mysqld
49/69
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
50/69
どこが遅い︖
connection_handling parser optimizer executor
handler storage_engine
mysqld
51/69
Executorが遅い理由
MySQLの不得意なことをやろうとしている
⾊々パターンはあるけど、⼀⾔で⾔うならこれにあたる-
Executorに仕事をさせたら負け
52/69
MySQLの不得意なこと
複数のインデックスを使いこなす
相関サブクエリー
これらはExecutorのお仕事
53/69
複数のインデックスに弱い理由
MySQLは原則1クエリー内で1つのテーブルあたり1つのイ
ンデックスしか使わない
インデックスマージという例外が⼀応あるにはあるが、
後付け
-
そもそもこういう設計思想なんだと思う-
テーブルスキャンに強い/弱いはストレージエンジンのレイ
ヤー
MyISAMはスキャンに強く、InnoDBは弱い-
関数演算、(インデックスで解決できない)フィルター、
(インデックスで解決できない)ソートはExecutorのお仕
事(= 遅い)
54/69
みんな⼤好き
Excel⽅眼紙
55/69
ルール
右に動いていいです
左には動いてはいけません
下か上に動いていいですが
⼀度上か下に動くと右には進めなくなります
56/69
ざっくり
AND演算⼦は 右に進む
OR演算⼦, IN演算⼦, 不等号演算⼦は 下に進む
エグゼキューターが仕事するためには ⼀番右にいないとい
けない
57/69
JOIN︖
⽅眼紙作れなかった。。
58/69
MySQLでも⼈間でも最初に考える(であろう)こと
WHEREにインデックスを利かせる
下にしか進めなくなっても困らないくらいの範囲ならエ
グゼキューターでも戦える
-
59/69
MySQLでも⼈間でも次に考える(であろう)こと
WHEREにインデックスを利かせてORDER BYにインデックスを
利かせる
⼗分範囲を狭めてから、「上から下に順番になぞる」-
60/69
WHERE狙いのキー, ORDER BY狙いのキー
WHEREとORDER BY .. LIMITを同時にカバーできるインデック
スが作成できない時に
WHEREをストレージエンジンに任せてフェッチする⾏を減
らしてファイルソートをExecutorにやらせるか
-
ORDER BY .. LIMITをストレージエンジンに任せて
ExecutorにフィルターさせつつLIMITでループを抜けるの
を期待するか
-
61/69
WHERE狙いのキー, ORDER BY狙いのキー
「JOINが遅い」はJOINが遅いんじゃなくてJOINの参照表で
ソートしようとしてExecutorがソートしちゃってるケース
あとはオプティマイザーにバグがあって、駆動表を
Executorがフィルターして参照表の参照回数が減る可能
性を考慮していない。
-
MySQLにはヒストグラム統計がないので、WHERE狙いと
ORDER BY狙いのどちらが本当に速いのかMySQLは知らない
(憶えてない)
See also, http://www.slideshare.net/yoku0825/
whereorder-by
62/69
⼈間がAIに今のところ勝てること
⼈間は得てして 正しい 統計情報を知っているケースがある
サービスの特性(⼥性は少ないからWHERE gender= 'F'
ORDER BY birthdayはWHEREで狙った⽅がいいだろうし、
WHERE gender= 'M' ORDER BY birthdayはORDER BY狙いの
⽅が良いだろう、とか)
-
サンプリングでない実際の分布(InnoDBの統計情報は飽
くまでサンプリングなのでたまに踏み外す)
-
LIMITの考慮(5.6とそれ以前のMySQLはORDER BY ..
LIMITの時でも積極的にWHEREを狙う)
-
63/69
オプティマイザーの強化
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
ホントに賢くなってて、「ほらMySQLバカでしょ︖」って
デモがしづらくなった
64/69
相関サブクエリー
外側のクエリーが内側のサブクエリーの条件になっているケ
ース
内側のサブクエリーが外側の条件になるケースはMySQL
⽤語では単にサブクエリーと呼ぶ(個⼈的には明確に区
別するために「キャッシャブルなサブクエリー」と呼ん
でる)
-
しかしWHERE INはキャッシャブルなサブクエリーのはず
でも相関サブクエリーになるというダメ仕様が5.5とそれ
以前にあってだな。。
-
65/69
シンプルな話、外側のクエリーに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)
66/69
相関サブクエリーの書き換え⽅
7割⽅JOINに書き換えられる
JOINに落とし込んでUSE INDEXまでつければ5.5とそれ以
前でも戦える
-
どうしてもロジックとしてJOINに書き換えられないケース
もある
CREATE TEMPORARY TABLEを使って落とし込むのがいい
テンポラリーテーブルはクラッシュアンセーフ( 更新
ステートメントには使わない︕ )
そもそもクラッシュアンセーフだから迷わずMyISAM
を選んでいい
⼤した量でなくてもインデックス張る。劇的に違う
-
のがいい、というか、SQLだけでやるにはそれしかない- 67/69
書き換える時に必要なもの
再帰テスト
無いと死ぬ-
ポジション上、返す結果が変わらないことの担保をしな
いといけない
パラメーター渡して、新旧クエリーの2パターン投げて
結果を⽐較するだけでも取り敢えずいいんだ
最近はコマンドラインクライアントで
REPEATABLE-READでトランザクション内でやればオ
ブジェクト⽐較するだけで済む
分布に極端な偏りがあるパラメーターはいくつかバリ
エーションを⽤意した⽅がいい(同じ形をしていても
パラメーターで実⾏計画は変わる)
-
68/69
Questions
and/or
Suggestions?
69/69

ペパボ de MySQL