MySQL 5.7が魅せる新しい運⽤の形
What does 5.7 bring us?
2015/12/15
yoku0825
MySQL User Conference 2015
こんにちは、しゃべろう
としたことの9割以上を
@RDBMS と
@yyasamaki1 に潰さ
れたyoku0825です
1/104
あまりにアレなので軽
いネタからいきますが
このセッションは終始ゆるふわ
です
2/104
character̲set̲server=
latin1で幸せな⼈います
か?
3/104
よく訓練されたMySQLerはご存知の
4/104
騙されて 知ら
ずに作っち
ゃった⽅?
5/104
そのアカウントを有
効(かどうかわから
ないんですが)活⽤
してみませんか?
6/104
MySQL Bugs
これが押せるようになります 7/104
MySQL Bugs: #71659: Make UTF8 Default
Character Set
“Affects me”の数は中の⼈にしか⾒えないらしいけれど
このFRはあんまり流⾏ってないらしい
みんなで”Affects me”押したら、デフォルト変わったりし
ないかな?
いっぱい集まって変わったら不幸せになる⼈が減りそう
だし
-
いっぱい集まったのに変わらなかったら「これだから
○racleは!」ってdisればいいし
-
どっちに転んでも悪いことはないかなって-
8/104
騙されて アカウント作っ
ちゃった⽅で パスワード
まだ憶えてる⽅ はこの実
験やってみませんか?
9/104
みなさんのご参
加をお待ちして
おります :)
10/104
MySQL 5.7 has
been General
Availability at
2015/10/21
11/104
MySQL 5.7三部作
MySQL 5.7の罠があなたを狙っている
 
光のMySQL 5.7
 
MySQL 5.7が魅せる新しい運⽤の形
 
12/104
MySQL 5.7三部作
MySQL 5.7の罠があなたを狙っている
闇
光のMySQL 5.7
光
MySQL 5.7が魅せる新しい運⽤の形
夢
13/104
MySQL 5.7で
何ができるよ
うになるのか
14/104
繰り返しますが、しゃべ
ろうとしたことの9割以上
は @RDBMS と
@yyasamaki1 に⾷わ
れました
15/104
MySQLの最近のバージョンおさらい
date version description
2008/11/14 5.1.30 MySQL 5.1 GA
2010/12/03 5.5.8 MySQL 5.5 GA
2011/04/11 5.6.2-m15 MySQL 5.6最初のDMR
2013/02/05 5.6.10 MySQL 5.6 GA
2013/04/23 5.7.1-m11 MySQL 5.7最初のDMR
2013/12/03 5.1.73 MySQL 5.1 最後のリリース
2015/10/21 5.7.9 MySQL 5.7 GA
2015/12/07 5.5.47 MySQL 5.5 (たぶん)最後の
リリース
16/104
\こんにちは/
yoku0825@とある企業のDBA
オラクれない-
ポスグれない-
マイエスキューエる-
家に帰ると
妻の夫-
せがれの⽗-
ムスメの⽗-
Twitter: @yoku0825
Blog: ⽇々の覚書
MyNA ML: ⽇本MySQLユーザ会
17/104
最低限これだけは知ってほしい5.7(いつものやつ)
16桁ハッシュのパスワードの廃⽌
default̲password̲lifetime
sql̲modeのデフォルト値変更
log̲error̲verbosity vs. log̲warnings
テンポラリーテーブルがInnoDBに
18/104
⼀応知っておいてほしい5.7(いつものやつ)
mysql.user.passwordカラムの廃⽌
認証周りの構⽂の変更
secure̲file̲priv
log̲timestamps
mysql̲install̲db
mysqld –initialize
InnoDBバッファプールの暖気がデフォルトでONに
binlog̲formatのデフォルト変更
rpmパッケージではvalidate̲passwordプラグインがデフォ
ルトで有効
innodb̲default̲row̲formatの注意
19/104
これを知っているとちょっと得する5.7(いつものやつ)
sysスキーマ
GTIDのオンライン有効化がサポート
MySQLネイティブの全⽂検索が⽇本語対応
InnoDB UNDO logのシュリンク
サーバーサイドステートメントタイムアウト
generated columnで関数インデックス
SSL関連いろいろ
JSONデータ型
マルチスレッドスレーブの機能向上
20/104
知っておいても損はない5.7(いつものやつ)
innodb̲buffer̲pool̲sizeのオンライン変更がサポート
sync̲binlogのデフォルト変更
マルチソースレプリケーション
ダイナミックレプリケーションフィルター
InnoDBの新しい圧縮
1テーブルに複数トリガー設定可能
mysql p ump
log-syslog
オフラインモード
GET̲LOCK関数で複数のロックを取れる
Query Rewrite Plugin
21/104
ターゲットはこのへん
mysql p ump
sysスキーマ
GTIDのオンライン有効化がサポート
MySQLネイティブの全⽂検索が⽇本語対応
generated columnで関数インデックス
マルチソースレプリケーション
MySQL Router + MySQL Fabric
22/104
mysqlpump
⾺⿅にされてるのかな どんなジョークなんだろうって思っ
た
Oracle(DBの⽅)のdatapumpとparallel dumpをかけたの
かな
正直まだ使えるレベルではありません(MySQL 5.7.8現在)
23/104
mysqlpumpのオプション
--defer-table-indexes
CREATE TABLE, INSERT INTOの 後に ALTER TABLE ADD KEY
してくれる
-
Fast Index Creation以来、あとからADD KEYの⽅が全
体の時間が短縮できる。
MySQL 5.6における⼤量データロード時の考慮点 -
SH2の⽇記
-
24/104
mysqlpumpのオプション
--watch-progress
進捗どうですか-
Dump progress: 0/9 tables, 10/594278 rows
Dump progress: 6/9 tables, 543510/594278 rows
Dump completed in 1525 milliseconds
25/104
mysqlpumpのオプション
--compress-output
”| pbzip2 -c > ..”とかしなくても、直接出⼒を圧縮でき
る。
-
zlib, lz4に対応-
--user
mysql.userとかmysql.dbとか権限情報をGRANT
STATEMENTに加⼯してダンプに含めてくれる。
--events, --triggersのGRANT版
-
正直これは使い勝⼿がいい(MySQL 5.6とそれ以前向け
にも使える)
-
26/104
mysqlpumpのオプション
--default-parallelism
並列度を指定
デフォルトは2
ドキュメントに ダンプファイルの中⾝が交差するよ っ
て書いてあって、つまり別々に叩いたSELECTをそれ
ぞれ標準出⼒に独⽴して書き出す感じ。
-
1より⼤きい値を指定した時(つまりパラレルでダンプす
る時)、START TRANSACTIONはそれぞれのスレッドが
別々に叩くので、–single-transactionは意味を持たな
い。
よって、更新トラフィックのある状態で--default-
parallelism > 1だとバックアップとしてのデータの整
合性は保証されない
-
27/104
mysqlpumpにないもの
--lock-all-tables
ない。--default-parallelism > 1の時に欲しい機能なの
に。
-
--master-data他もろもろ
今まで通りのやり⽅でレプリケーションスレーブを作る
ような情報は⼀切取れなくなっている。
-
master̲info̲repository= TABLE,
relay̲log̲info̲repository= TABLE,
mysql.gtid̲executeあたりから取ってくることを想定し
ている
-
28/104
mysqlpumpはこれから
MySQL 5.7以降が前提
5.7でもすぐに全て置き換えられるものではない-
スレーブでSTOP SLAVEできるならバルクダンプツール
としては5.7以前でも使える
-
MyDumperで良くない? と⾔わないこと
mysqlpumpはパラレルダンプ、シリアルロード-
MyDumperはパラレルダンプ、パラレルロード-
遅延CREATE INDEXはいいと思う
--usersもいいと思う
mysqlpump先⽣の次回作にご期待ください
どんどん MySQL Bugs にFeature Request上げていけば
いいと思う
-
29/104
sysスキーマ
元 ps̲helper
リポジトリーの名前はdbahelper。。-
performance̲schema, information̲schemaのビューと、
performance̲schema関連の設定をゴニョるプロシージャ
の詰め合わせ
なのでperformance_schema= ONが⼤前提-
合わせて使いたいinnodb_monitor_enable= all-
実は5.6から使える(使ってる。便利)-
30/104
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 |
..
31/104
余計なところを気にしなくて良いとグラフ化も簡単
32/104
余計なところを気にしなくて良いとグラフ化も簡単
https://github.com/yoku0825/my̲script/blob/master/
my̲logstash.pl
foreach my $row (@{$mysql->{conn}->selectall_arrayref($status
_sql, {Slice => {}})})
{
my $name= $row->{name};
$mysql->{prev}->{$name}= $mysql->{new}->{$name};
$mysql->{new}->{$name} = $row->{value};
$current_status->{$name} = ($mysql->{new}->{$name} - $mysql->
{prev}->{$name}) / $interval
if defined($mysql->{prev}->{$name}
);
}
$fluent->post("mysql.status", {$mysql->{ident} => {%$current_
status}}) or die $fluent->strerr if $current_status;
33/104
sys.schema̲index̲statistics
どのインデックスを使ってどれだけハンドラーが呼ばれた
か、そのレイテンシーの合計は…というのが⾒られる。
あんまり使われてないインデックスをあぶりだすのは後述の
sys.schema_unused_indexesビューでもいける。
mysql> SELECT * FROM sys.schema_index_statistics;
+--------------+----------------------------------------+-----------------------
------------------------+---------------+-----
| table_schema | table_name | index_nam
e | rows_selected | sele
+--------------+----------------------------------------+-----------------------
------------------------+---------------+-----
| xxxxxxx | quiz_xxxxxxxx | idx_xxxxxxxxxxxxx_0
1 | 224188730866 | 1.20
| xxxxxxx | history_xxxxxxxx1 | idx_xxxxxxxxxxxxxxxxx_
01 | 13545050665 | 2.40
| xxxxxxx | history_xxxxxxxxxx2 | idx_xxxxxxxxxxxxxxxxxx
x_01 | 7937476199 | 1.15
..
34/104
sys.schema̲index̲statistics
mysql> DESC sys.schema_index_statistics;
+----------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+-------+
| table_schema | varchar(64) | YES | | NULL | |
| table_name | varchar(64) | YES | | NULL | |
| index_name | varchar(64) | YES | | NULL | |
| rows_selected | bigint(20) unsigned | NO | | NULL | |
| select_latency | text | YES | | NULL | |
| rows_inserted | bigint(20) unsigned | NO | | NULL | |
| insert_latency | text | YES | | NULL | |
| rows_updated | bigint(20) unsigned | NO | | NULL | |
| update_latency | text | YES | | NULL | |
| rows_deleted | bigint(20) unsigned | NO | | NULL | |
| delete_latency | text | YES | | NULL | |
+----------------+---------------------+------+-----+---------+-------+
35/104
sys.schema̲unused̲indexes
名前そのものズバリ、使われてない(統計開始から⼀度も使
われていない)インデックスを⼀覧してくれる。
ただし、performance_schema.setup_actors,
performance_schema.setup_objects,
performance_schema.setup_instruments= 'wait/io/table/
sql/handler'あたりの設定に依存する。吊るしで使ってるな
らフツーのテーブルではmysqldの起動時から全部統計が有効
になっている。
36/104
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_analysis;
+-------------------------------------------------------------------+--------------------+-----------+------------+-----------
| query | db | full_scan | exec_count | err_count
+-------------------------------------------------------------------+--------------------+-----------+------------+-----------
| COMMIT | xxxxxxx | | 479684679 | 0
| SELECT * FROM `history_xxxxxx_ ... tatus` = ? ORDER BY `id` DESC | xxxxxxx | | 802831874 | 0
| SELECT * FROM `quiz_xxxxxxxx` ... `level` = ? LIMIT ? OFFSET ? | xxxxxxx | | 37052227 | 0
| SELECT * FROM `history_xxxxxxx ... ? ORDER BY `id` DESC LIMIT ? | xxxxxxx | | 287513557 | 0
..
37/104
sys.statement̲analysis
mysql> DESC sys.statement_analysis;
+-------------------+---------------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------------------+-------+
| query | longtext | YES | | NULL | |
| db | varchar(64) | YES | | NULL | |
| full_scan | varchar(1) | NO | | | |
| exec_count | bigint(20) unsigned | NO | | NULL | |
| err_count | bigint(20) unsigned | NO | | NULL | |
| warn_count | bigint(20) unsigned | NO | | NULL | |
| total_latency | text | YES | | NULL | |
| max_latency | text | YES | | NULL | |
| avg_latency | text | YES | | NULL | |
| lock_latency | text | YES | | NULL | |
| rows_sent | bigint(20) unsigned | NO | | NULL | |
| rows_sent_avg | decimal(21,0) | NO | | 0 | |
| rows_examined | bigint(20) unsigned | NO | | NULL | |
| rows_examined_avg | decimal(21,0) | NO | | 0 | |
| rows_affected | bigint(20) unsigned | NO | | NULL | |
| rows_affected_avg | decimal(21,0) | NO | | 0 | |
| tmp_tables | bigint(20) unsigned | NO | | NULL | |
| tmp_disk_tables | bigint(20) unsigned | NO | | NULL | |
| rows_sorted | bigint(20) unsigned | NO | | NULL | |
| sort_merge_passes | bigint(20) unsigned | NO | | NULL | |
| digest | varchar(32) | YES | | NULL | |
| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | |
| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------------+---------------------+------+-----+---------------------+-------+
38/104
sys.statements̲with̲errors̲or̲warnings
カジュアルに桁切り詰めワーニングを無視してるステートメ
ントとか⼀網打尽にできる。
--gtid-enforce-consistency= WARNと組み合わせて使うと夢
が広がる。
39/104
sys.innodb̲lock̲waits
SH2さんのステートメントとの別離の時
MySQL InnoDBにおけるロック競合の解析⼿順 - SH2の
⽇記
-
KILLするためのステートメントも出⼒してくれるあたりがロ
ック
しかもKILL QUERYとKILLを両⽅出⼒する芸の細かさ-
40/104
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)
41/104
危険なヤツら
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でクエリーを殺すと突き刺さる率が俺の中
では⾼い
-
42/104
名前で判りそうなやつら
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
43/104
sysスキーマというかperformance̲schemaの特徴
コードの中に”instrument”と呼ばれる記録ポイントが埋め
込まれていて、そこを通るたびにメモリー上に記録する
本質的にプロファイラー-
ディスクに落とさない(オンメモリーストレージエンジン
)でhistoryを増やせば増やすだけメモリー⾷う
メモリーは起動時確保(5.6)
5.7で変わったっぽい。メモリー使⽤量が穏やかに。
-
44/104
sysスキーマというかperformance̲schemaの特徴
プロファイラーなので、テーブルにアクセスしても実⾏中の
処理には影響が出ない(実⾏済みの処理の統計が記録されて
いるだけ)
それに対してi̲sはテーブルアクセス時に各種情報をかき
集める
だからinnodb̲buffer̲pageはしこたま重い
-
デフォルトではプロファイラーっぽい表⽰をするための
instrumentは無効
45/104
sys(というかperformance̲schema)がもたらすもの
ジェネラルログやスローログ(あるいはlong_query_time)
が適切に設定されていないと尻尾を掴むことが難しかった
クソ ダメなクエリーが
p̲sはダイジェスト単位とはいえ 後追い で検索できる。-
テンポラリーテーブルになってるか、ソートした⾏数はいく
つだったかはSHOW GLOBAL STATUSしかなかった。
SQLダイジェスト単位 で検索可能。-
スローログにも記録されなかった情報がある。今までは
記録したかったらPercona ServerかMariaDBを選んで
た。
-
46/104
MySQL 5.6 performance̲schema= ON + sysスキー
マ
かなり良い
MySQL 5.6以降でp̲sが有効なら是非⼊れるべき。-
ただしS/N⽐が悪い(ノイズ多い)-
万能ではない
検索できるところまでは良くても
ノイズをノイズとして⾒分ける能⼒
そのクエリーをチューニングする能⼒
-
は相変わらず必要-
MySQL Workbenchはsysの結果を⾷ってグラフを作る機能
を提供したらもっと流⾏ると思う
47/104
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には感⼼した。
48/104
ひとやす
み
49/104
GTIDのオンライン有効化がサポート
Global Transaction ID
トランザクションを世界中で⼀意に識別するための値
トランザクションを実⾏したマスターのSERVER̲UUID
とマスター内のトランザクション連番をくっつけたもの
-
5.6では “レプリケーションクラスター全体でON”, “レプリ
ケーションクラスター全体でOFF”の2通りしかなかった
しかも再起動が必要なパラメーターだった。-
50/104
GTIDのローリング有効化
masterslave OFF OFF̲PERMISSIVE ON̲PERMISSIVE ON
OFF ○ ○ ○ ×
OFF̲PERMIS
SIVE
○ ○ ○ ×
ON̲PERMISS
IVE
× ○ ○ ○
ON × ○ ○ ○
51/104
gtid̲modeの値
OFF
マスターからGTIDがあるイベントが来ると⽂句を⾔う、⾃分
の更新にはGTIDを振らない
OFF̲PERMISSIVE
マスターからGTIDがあるイベント来ても⽂句は⾔わないけ
ど、⾃分の更新にはGTIDを振らない
ON̲PERMISSIVE
マスターからGTIDが ない イベントが来ても⽂句は⾔わないけ
ど、⾃分の更新にはGTIDを振る
ON
マスターからGTIDがないイベントが来ると⽂句を⾔う、⾃分
の更新にはもちろんGTIDを振る 52/104
GTIDのローリング有効化ステートメント
slave> SET GLOBAL gtid_mode= OFF_PERMISSIVE;
master> SET GLOBAL gtid_mode= OFF_PERMISSIVE;
slave> SET GLOBAL gtid_mode= ON_PERMISSIVE;
master> SET GLOBAL gtid_mode= ON_PERMISSIVE;
slave> SET GLOBAL enforce_gtid_consistency= ON;
master> SET GLOBAL enforce_gtid_consistency= ON;
slave> SET GLOBAL gtid_mode= ON;
master> SET GLOBAL gtid_mode= ON;
53/104
有効化する前にやること
enforce_gtid_consistencyを有効にしないといけない。
有効にすると、オートコミットでないMyISAMとInnoDB
のテーブルをまたがるトランザクションがエラーになっ
たりする。
-
enforce_gtid_consistencyの取りうる値がON, OFF, WARN
の3種類に。
enforce_gtid_consistency= WARNだと、ON̲PERMISSIVE
以上のgtid̲modeではエラーになるステートメントがワー
ニングで出⼒される。
sys.statements_with_errors_or_warningsで拾っていく
スタイル。
-
54/104
GTIDで得られるもの
CHANGE MASTER TO master_auto_position= 1はラク。
master̲log̲fileとmaster̲log̲posを⾃分で指定しなく
ていい。打ち間違える⼼配もない。
-
mysqldump --include-master-host-portをそのまま流し
込んでユーザー名とパスワードを指定しさえすればいい
(5.6同⼠の場合)
-
RESET SLAVE ALLではexecuted̲gtidの値は吹っ⾶ばない
ので注意(スレーブでRESET MASTERで吹っ⾶ぶ)
-
カスケード構成に強い
始祖マスターと中間マスターと末端のスレーブで同じ
GTIDが共有されるのでbinlogが追いやすい
-
55/104
GTIDで得られるもの
あとは
MySQL Fabricとか-
MySQL Fabricとか-
MySQL Fabricとか-
56/104
GTIDで失ったもの
SET GLOBAL sql_slave_skip_counter= 1
つまりpt-slave-restart-
とはいえ、MySQL 5.6からのクラッシュセーフスレーブ
でこれにお世話になる機会はほぼなくなった
relay_log_info_repository= TABLE
この前、「スレーブにrelay̲log.infoファイルがないこ
とってありえますかね…?」ってかなり深刻な顔で聞
かれた。
relay_log_recovery
ただしI/Oスレッドを頻繁に⽌める場合は注意。
InnoDB以外ではこのデメリットが⼤きいかも。
-
57/104
ひとやす
み
58/104
せずに
59/104
次
60/104
MySQLネイティブの全⽂検索が⽇本語対応
NgramパーサーとMeCabパーサーがバンドル
Ngramはやめといた⽅がいい
ngram_token_size=1じゃないと1⽂字のトークンが検索
できない
Unigramは死ぬほど遅い
Bigramでもファイルサイズでかい
結果セットを絞り込めないとUsing filesortで死ぬ
MySQLの全⽂検索に関するあれやこれや
-
61/104
MySQLネイティブの全⽂検索が⽇本語対応
MeCabはmy.cnfとかちょっといじる必要あり
とはいえMroongaさんとか⼊れるのに⽐べれば格段に”す
ぐ始められる”
-
MeCabパーサー使えるならmebab-ipadic-NEologdはシー
ドまで含めてApache License 2.0らしいので、積極的に使
っていきたい。
https://twitter.com/overlast/
status/659997069399080960
-
全然メリットないけど、InnoDBでなくてMyISAMでもイケ
る
62/104
MeCab FTパーサーの有効化
$ vim /etc/my.cnf
[mysqld]
loose-mecab-rc-file= /usr/lib64/mysql/mecab/etc/mecabrc
mysql57> INSTALL PLUGIN mecab SONAME 'libpluginmecab.so';
Query OK, 0 rows affected (0.02 sec)
63/104
わざわざMySQLで全⽂検索をする理由(外向き)
今までは(?) MySQL + “全⽂検索⽤の何か”
1つで済むようになる-
⼆相コミットなんて誰もしたくない-
枯れたレプリケーションが参照分散を助ける
InnoDB FTSならトランザクションによる保護が受けられる
トランザクションによる保護 ≒ クラッシュ耐性-
64/104
わざわざMySQLで全⽂検索をする理由(割と本⾳)
⾃前のフレームワークに組み込まれたORMっぽい⿊魔術が
MySQLにしか対応してnあれ誰か来たようだ
Mroongaが快適だからたぶん乗り換えない
MroongaはBigramでも1⽂字トークンを検索できる細⼯
がしてある
-
あとやっぱり圧倒的に速い
クラッシュしたら作り直すのがお約束だけど
-
ある程度以上規模が出てきたらMySQLから分離する前提で
ある程度以上になれなかったら、負債は踏み倒せる-
65/104
はい次
66/104
generated columnで関数インデックス
⽣成された列にNOT NULL制約、UNIQUE制約もかけられる
(疑似チェック制約が作れる)
直接値を投⼊することはできないが、「カラム」としては定
義されるのでSELECT *とかINSERT INTO .. VALUESに注意。
STOREDタイプは全⽂検索にも対応
STORED or VIRTUAL INDEXあり INDEXなし
VIRTUAL(デフォルト) ALTER TABLE時 SELECT時
STORED ALTER TABLE時 ALTER TABLE時
67/104
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)
68/104
generated columnで全⽂検索
mysql> ALTER TABLE t2 ADD v_text text AS (val->'$.text'), ADD FULLTEXT KEY (v_text) WITH PARSER MeCab;
ERROR 3106 (HY000): 'Fulltext index on virtual generated column' is not supported for generated columns.
mysql> ALTER TABLE t2 ADD v_text text AS (val->'$.text') STORED, ADD FULLTEXT KEY (v_text) WITH PARSER MeCab;
Query OK, 100 rows affected (0.37 sec)
Records: 100 Duplicates: 0 Warnings: 0
mysql> SELECT v_id, v_text, val->'$.created_at' FROM t2 WHERE match(v_text) 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)
69/104
逆パターン
# 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)
70/104
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)
71/104
挙句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"}
72/104
範囲検索で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)
73/104
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)
74/104
昇順と降順が混じったソートも
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)
75/104
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)
76/104
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)
77/104
似非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
78/104
⾊々できる
クエリーの書き換えは必要になる
カラム指定せずにINSERTしようとするお⾏儀の悪いクエ
リー
-
generatedなカラムとフツーのカラムを⾒分けるにはSHOW
FULL COLUMNSのExtra列をちゃんとパースしないとダメ
mysqldumpとの相性が悪い。。-
ORMとの相性も悪い。。
ActiveRecord!!1 @kamipo++ => ActiveRecord
とMySQL 5.7
-
開発者との相性も(今のところ)悪い。。
もっと広く知られるようになれば問題はなくなると思
う。
-
79/104
ひとやす
み
80/104
マルチソースレプリケーション
マルチスレッドスレーブ(MTS)とは別物。
1つのI/Oスレッドは相変わらず1つのマスターにしか接続し
ない。
MTSする場合「チャンネル単位でslave_parallel_workersス
レッドずつ」になるぽい
複数のMySQLから集約スレーブを作ってJOINJOIN。
⽔平シャーディングしたサーバーの集約。
81/104
シングルソース、シングルスレッドレプリケーション
Binary Log Binlog Dump Thread
Slave I/O Thread Relay Log Slave SQL Thread
master
slave
82/104
シングルソース、マルチスレッドレプリケーション
Binary Log Binlog Dump Thread
Slave I/O Thread relay Slave SQL Thread
Slave SQL Thread
Slave SQL Thread
master
slave
83/104
マルチソース、シングルスレッドレプリケーション
master1
master2
master3
Slave I/O Thread Relay Log Slave SQL Thread
Slave I/O Thread Relay Log Slave SQL Thread
Slave I/O Thread Relay Log Slave SQL Thread
slaveFOR CHANNEL master1
FOR CHANNEL master2
FOR CHANNEL master3
84/104
マルチソースレプリケーション
今までのレプリケーション関連コマンドの末尾にFOR
CHANNEL 'channel_name'をつけるだけでOK
mysql57> STOP SLAVE FOR CHANNEL 'node2';
mysql57> SHOW SLAVE STATUS FOR CHANNEL 'node2'G
mysql57> START SLAVE FOR CHANNEL 'node2';
85/104
マルチソースレプ
リケーション
with GTID の変
態ソリューション
86/104
循環レプリ
ケーション
87/104
( ゚д゚) えっ
MySQL1
1
MySQL2
2
MySQL3
3
CHANGE MASTER TO mast
er_host= 'MySQL1'
CHANGE MASTER TO mast
er_host= 'MySQL2'
CHANGE MASTER TO mast
er_host= 'MySQL3'
①に⼊った更新は②経由で③まで伝わる
②に⼊った更新は③ => ①と伝播する
88/104
循環レプリケーションの問題点
auto̲incrementがぶつかって死ぬ
①のテーブルと③のテーブルに同時にINSERTすると
Error: 1062で⽌まる
-
auto_increment_incrementを調整するといっても限度が
ある
特にリストアと相性が悪い
-
89/104
循環レプリケーションの問題点
ロストアップデート問題
server1> UPDATE t1 SET price = price * 1.08 WHERE item= 1;
server2> UPDATE t1 SET price = 108 WHERE item= 1;
server3> UPDATE t1 SET price = price + 8 WHERE item= 1;
更新が伝播して状態が収束する前にこの3つが流れてきたら
どうなる?
90/104
循環レプリケーションの問題点
auto̲increment, ロストアップデート問題は、サーバーを
またいで同じテーブルを更新させないようにするしかない
アプリケーション側で、「このテーブル」(あるいは、
「このスキーマ」)はこのサーバー、このサーバーが死
んでたらこのサーバー、と決め打つしかない
-
3台以上だと1台死ぬと全体として死ぬ
カスケードの中間がいなくなっちゃう-
⻑いクエリーがSQLスレッドを占有して死ぬ
3台構成でALTER TABLEが⼀巡するには、ALTER TABLEの実
⾏時間の3倍かかる
-
91/104
新しい循環レプリケーションの形
フルメッシュ
スタースキーマ
実際スタースキーマはOLTP向けには使わないと思うけれ
ど
-
92/104
どうかしている
MySQL1 MySQL2 MySQL3
server1> CHANGE MASTER TO master_host= 'MySQL2', .. FOR CHANNNEL 'serv
er2';
server1> CHANGE MASTER TO master_host= 'MySQL3', .. FOR CHANNNEL 'serv
er3';
server2> CHANGE MASTER TO master_host= 'MySQL1', .. FOR CHANNNEL 'serv
er1';
server2> CHANGE MASTER TO master_host= 'MySQL3', .. FOR CHANNNEL 'serv
er3';
server3> CHANGE MASTER TO master_host= 'MySQL1', .. FOR CHANNNEL 'serv
er1';
server3> CHANGE MASTER TO master_host= 'MySQL2', .. FOR CHANNNEL 'serv
er2';
93/104
5.7でフルメッシュレプリケーション
1台死ぬと全体が⽌まる問題の解決
MTSがALTER TABLE問題を(⼀応)解消
slave_parallel_type= LOGICAL_CLOCKにしておく-
auto̲increment, ロストアップデート問題は相変わら
ず。。
GTIDはそのサーバー内でのトランザクション順序を保証
できるけど、サーバーをまたいだトランザクションの順
番は保証できない。
-
94/104
5.7でフルメッシュレプリケーション
Percona XtraDB Cluster(Galera Cluster)でいいじゃんっ
て⾔わない
PXCに⽐べてノードの追加は楽そう
ISTになるようにリストアすればいいだけなんだけどそ
れが⾯倒
-
やっぱり仮想完全同期と非同期の間には性能の幅がある-
Group Replication? 知らない⼦ですね。
2台に絞ってMySQL Routerでmode=read-write,
destination= server1,server2ってやるだけならシンプルで
使えるかも
server1が転けたらserver2に、転けるまではserver1を
⾒続ける、ので。
-
95/104
MySQL Router + MySQL Fabric
レプリケーションの “構成管理” はMySQL Fabric
アプリケーションの “向き先管理” はMySQL Router
96/104
MySQL Fabric
レプリケーションの “構成管理” はMySQL Fabric
マスターが倒れたらスレーブをpromote-
他のスレーブを新しいmasterに向けなおす
だからGTIDが必要
5.6ではGTIDを有効にするまでに⼀苦労
-
バッキングストア(MySQL Fabricが構成情報を格納する
mysqld)は⾃前で冗⻑化
ごく⼩規模になるはずなので、MySQL ClusterのAct/
ActでもPercona XtraDB Clusterでも循環レプリケー
ションでも
循環レプリケーションなら管理ノード相当のやつが要
らないから最低2インスタンスで運⽤できる
-
97/104
Before MySQL Router
アプリケーションの “向き先管理” は MySQL Fabric対応コ
ネクターに全⾯依存
MySQL Connector/Python-
MySQL Connector/J-
MySQL Connector/.NET-
ねえ、PHPは? Rubyは? Perl ううんなんでもない-
MySQL Fabricサーバーが落ちてもクライアントがキャッシ
ュしてくれるから運⽤継続できる?
Connector/Cは再接続できなかったよ-
都度接続モデルだとキャッシュしてようが、インスタン
ス壊しちゃうので相性が悪い
-
98/104
After MySQL Router
アプリケーションの “向き先管理” は MySQL Router
コネクターが何であれMySQLプロトコルをしゃべれれば
それでOK
-
mysqlrouterデーモンが⽣き続けるからキャッシュが⽣き残
る
コンポーネントとしては1つ増える
各APサーバーに⽣やす形にするなら管理の⼿間は増える-
MySQL側の増減はMySQL Fabricで吸収できる-
CentOS 6.xは⾃分でビルドしないとパッケージがない。。
99/104
After MySQL Router
AP1 MySQL Router
AP2 MySQL Router
MySQL Fabric Server
mysqld(backingstore)
MySQL Master MySQL Slave
MySQL Slave
Connect to 1
27.0.0.1
Connect to 1
27.0.0.1
replication
replication
100/104
あまりにフツーに使えそうでびっくり
MySQL Fabric&Routerつらくない Advent Calendar
2015 - Qiita
101/104
まとめ
mysql p ump
エクスポート⽤途では使うと思う-
sysスキーマ
既に5.6で平常運⽤中。便利。-
GTIDのオンライン有効化がサポート
5.7導⼊次第やっていく(でも5.6マスターが残るんだよ
なぁ。。)
-
MySQLネイティブの全⽂検索が⽇本語対応
バックエンドがEC2⼀台な案件が降ってきたらやるか
も。
-
102/104
まとめ
generated columnで関数インデックス
特に似非CHECK制約はやる予定-
マルチソースレプリケーション
たぶん使う(今、 #どあきレプリケーション でやってる
とことか)
-
MySQL Router + MySQL Fabric
MySQL FabricはGTID依存なのでまだ完全導⼊は先-
MySQL RouterはまずLVSでスレーブのラウンドロビン
やってるとこから導⼊予定
-
103/104
Questions
and/or
Suggestions?
104/104

MySQL 5.7が魅せる新しい運用の形