Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ぼくらが8.0に至ったみちのり(踏破)

 ぼくらが8.0に至ったみちのり(踏破)

2019/05/23 Middlewares Deep Talks
https://middlewaresdeeptalkstokyo20190.splashthat.com/

yoku0825

May 23, 2019
Tweet

More Decks by yoku0825

Other Decks in Technology

Transcript

  1. MySQL 8.0 mysql80 160> SELECT CURDATE() /* JST */; +------------+

    | CURDATE() | +------------+ | 2018-04-20 | +------------+ 1 row in set (0.00 sec) mysql80 160> SELECT @@version; +-----------+ | @@version | +-----------+ | 8.0.11 | +-----------+ 1 row in set (0.00 sec) 1/118
  2. MySQL 8.0 mysql80 101493> SELECT CURDATE() /* JST */; +------------+

    | CURDATE() | +------------+ | 2019-05-23 | +------------+ 1 row in set (0.00 sec) mysql80 101493> SELECT @@version; +-----------+ | @@version | +-----------+ | 8.0.16 | +-----------+ 1 row in set (0.00 sec) 2/118
  3. MySQL 8.0 ナッツシェル( What is New in MySQL 8.0 の章)が何故か

    どんどん増える $ curl -L -s https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshe ll.html | perl -nlE 'if ($_ =~ /(8\.0\.\d+)/) { say $1 }' | sort -t "." -k 3 -n | uniq -c 1 8.0.0 3 8.0.2 3 8.0.3 2 8.0.4 2 8.0.12 6 8.0.13 6 8.0.14 8 8.0.16 8.0.15はガチで8.0.14のリグレッションを1件だけ直した「メンテナンスリリース」だった。よってWhat is Newの中にはない 3/118
  4. MySQL 8.0 「メンテナンスリリース」 だと言い張る The MySQL 8.0.12 Maintenance Release is

    Generally Available | MySQL Server Blog ‐ The MySQL 8.0.13 Maintenance Release is Generally Available | MySQL Server Blog ‐ The MySQL 8.0.14 Maintenance Release is Generally Available | MySQL Server Blog ‐ The MySQL 8.0.16 Maintenance Release is Generally Available | MySQL Server Blog ‐ 8.0.15はガチで8.0.14のリグレッションを1件だけ直した「メンテナンスリリース」だった。よって公式ブログに記事は無い() 5/118
  5. インスタンスの特徴 2011年にMySQL 5.5でサービス開始 文字コードは (3バイト) UTF-8 ‐ 接続元アプリケーションはJava ‐ テーブルは

    ほぼ InnoDBストレージエンジン ‐ 2016年、MySQL 5.6バージョンアップ 2018年、アプリケーションのフルスクラッチリファクタリ ング(?)が決定 接続元アプリケーションはPHP(Laravel)に変更 ‐ MySQLも8.0にバージョンアップすることが決定 ‐ 14/118
  6. インスタンスの特徴 2011年にMySQL 5.5でサービス開始 文字コードは (3バイト) UTF-8 ‐ 接続元アプリケーションはJava ‐ テーブルは

    ほぼ InnoDBストレージエンジン ‐ 2016年、MySQL 5.6バージョンアップ 2018年、アプリケーションのフルスクラッチリファクタリ ング(?)が決定 接続元アプリケーションはPHP(Laravel)に変更 ‐ MySQLも8.0にバージョンアップすることが決定 ‐ 15/118
  7. インスタンスの特徴 2011年にMySQL 5.5でサービス開始 文字コードは (3バイト) UTF-8 ←救いだった ‐ 接続元アプリケーションはJava ‐

    テーブルは ほぼ InnoDBストレージエンジン ‐ 2016年、MySQL 5.6バージョンアップ 2018年、アプリケーションのフルスクラッチリファクタリ ング(?)が決定 接続元アプリケーションはPHP(Laravel)に変更 ‐ MySQLも8.0にバージョンアップすることが決定 ‐ 16/118
  8. インスタンスの特徴 2011年にMySQL 5.5でサービス開始 文字コードは (3バイト) UTF-8 ←救いだった ‐ 接続元アプリケーションはJava ‐

    テーブルは ほぼ InnoDBストレージエンジン ‐ 2016年、MySQL 5.6バージョンアップ 2018年、アプリケーションのフルスクラッチリファクタリ ング(?)が決定 接続元アプリケーションはPHP(Laravel)に変更 ‐ MySQLも8.0にバージョンアップすることが決定 ← 5.7どこ行っ た? ‐ 17/118
  9. インスタンスの特徴 2011年にMySQL 5.5でサービス開始 文字コードは (3バイト) UTF-8 ←救いだった ‐ 接続元アプリケーションはJava ‐

    テーブルは ほぼ InnoDBストレージエンジン ‐ 2016年、MySQL 5.6バージョンアップ 2018年、アプリケーションのフルスクラッチリファクタリ ング(?)が決定 接続元アプリケーションはPHP(Laravel)に変更 ‐ MySQLも8.0にバージョンアップすることが決定 ← 5.7どこ行っ た? データ作り直しだからいいんじゃね? ‐ 18/118
  10. インスタンスの特徴 2018年、アプリケーションのフルスクラッチリファクタリ ング(?)が決定 接続元アプリケーションはPHP(Laravel)に変更 ‐ MySQLも8.0にバージョンアップすることが決定 ← 5.7どこ行っ た? データ作り直しだからいいんじゃね?

    ‐ 2018年秋、既存のデータもアプリも捨てられないことが確 定 MySQL 5.6から8.0へのレプリケーションでのデータ移行 ‐ しかも2011年から継ぎ足され続けた秘伝のJavaがつなぎに来る ‐ 21/118
  11. 開発開始時 master(5.6) schema1 schema2 slave(5.6) schema1 schema2 slave(5.6) schema1 schema2

    slave(5.6) schema1 schema2 slave(8.0) schema1 schema2 schema3 30/118
  12. 上げて master(5.6) schema1 schema2 slave(5.7) schema1 schema2 slave(5.7) schema1 schema2

    slave(5.6) schema1 schema2 slave(8.0) schema1 schema2 schema3 32/118
  13. 上げて master(5.6) schema1 schema2 slave(5.7) schema1 schema2 slave(5.7) schema1 schema2

    slave(5.7) schema1 schema2 slave(8.0) schema1 schema2 schema3 33/118
  14. 開発が終わり master(5.6) schema1 schema2 slave(5.7) schema1 schema2 slave(5.7) schema1 schema2

    slave(5.7) schema1 schema2 slave(8.0) schema1 schema2 schema3 34/118
  15. カットーバー当日 master(5.6) schema1 schema2 slave(5.7) schema1 schema2 slave(5.7) schema1 schema2

    slave(5.7) schema1 schema2 slave(8.0) schema1 schema2 schema3 36/118
  16. ガシャッ master(5.7) schema1 schema2 slave(5.7) schema1 schema2 slave(5.7) schema1 schema2

    slave(5.7) schema1 schema2 slave(8.0) schema1 schema2 schema3 38/118
  17. SELECT .. FOR UPDATE SKIP LOCKED mysql80 28> SELECT *

    FROM t1 ORDER BY num LIMIT 1 FOR UPDATE; +-----+------+ | num | val | +-----+------+ | 1 | one | +-----+------+ 1 row in set (0.00 sec) mysql80 29> SELECT * FROM t1 ORDER BY num LIMIT 1 FOR UPDATE; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql80 29> SELECT * FROM t1 ORDER BY num LIMIT 1 FOR UPDATE SKIP LOCKED; +-----+------+ | num | val | +-----+------+ | 2 | two | +-----+------+ 1 row in set (0.00 sec) 49/118
  18. JSON_TABLE関数 SELECT DISTINCT tweet_id, LEFT(REPLACE(text, '\n', '\\n'), 16) AS text

    FROM t2, JSON_TABLE(t2.j, '$.statuses[*]' COLUMNS ( tweet_id NUMERIC(32) PATH '$.id', text VARCHAR(300) PATH '$.text' ) ) AS json; +---------------------+----------------------+ | tweet_id | text | +---------------------+----------------------+ | 1131026738492739584 | @ikaneko MySQLメイ | | 1131025041070497792 | LAMP環境\n\nLinux, | | 1131024962121281536 | RT @OracleDev_JP | | 1131026921276317697 | RT @sirius_gener | +---------------------+----------------------+ 4 rows in set (0.00 sec) 53/118
  19. Window関数 たくさんあるたまごパックの在庫から、賞味期限が古い方か ら順番に100個使う mysql80 51> SELECT * FROM t1 LIMIT

    3; +---------+------------+----------------+ | pack_id | egg_amount | expiration_day | +---------+------------+----------------+ | 1 | 4 | 2019-05-23 | | 2 | 1 | 2019-05-25 | | 3 | 4 | 2019-05-25 | +---------+------------+----------------+ 3 rows in set (0.00 sec) 57/118
  20. Window関数 たくさんあるたまごパックの在庫から、賞味期限が古い方か ら順番に100個使う mysql80 51> SELECT pack_id, egg_amount, expiration_day, SUM(egg_a

    mount) OVER (ORDER BY expiration_day, pack_id) AS egg_total FROM t1 LIMIT 3; +---------+------------+----------------+-----------+ | pack_id | egg_amount | expiration_day | egg_total | +---------+------------+----------------+-----------+ | 1 | 4 | 2019-05-23 | 4 | | 27 | 2 | 2019-05-23 | 6 | | 33 | 4 | 2019-05-23 | 10 | +---------+------------+----------------+-----------+ 3 rows in set (0.01 sec) 58/118
  21. Window関数 たくさんあるたまごパックの在庫から、賞味期限が古い方か ら順番に100個使う mysql80 51> WITH list AS (SELECT pack_id,

    egg_amount, expiration_day, SUM(egg_amoun t) OVER (ORDER BY expiration_day, pack_id) AS egg_total FROM t1), -> last_one AS (SELECT * FROM list WHERE egg_total >= 100 ORDER BY eg g_total LIMIT 1) -> SELECT * FROM list WHERE egg_total < 100 -> UNION ALL -> SELECT * FROM last_one; +---------+------------+----------------+-----------+ | pack_id | egg_amount | expiration_day | egg_total | +---------+------------+----------------+-----------+ | 1 | 4 | 2019-05-23 | 4 | | 27 | 2 | 2019-05-23 | 6 | | 33 | 4 | 2019-05-23 | 10 | .. | 489 | 3 | 2019-05-23 | 96 | | 491 | 5 | 2019-05-23 | 101 | +---------+------------+----------------+-----------+ 41 rows in set (0.04 sec) 59/118
  22. CTE(WITH句) FROM句にいっぱい書き連ねるようなクエリーを WITH で先 頭にくくりだせる SELECT MAX(txt), MIN(txt) FROM (

    SELECT concat(cte2.txt, cte3.txt) as txt FROM ( SELECT CONCAT(cte1.txt,'is a ') as txt FROM ( SELECT 'This ' as txt ) as cte1 ) as cte2, ( SELECT 'nice query' as txt UNION SELECT 'query that rocks' UNION SELECT 'query' ) as cte3 ) as cte4; 63/118
  23. CTE(WITH句) FROM句にいっぱい書き連ねるようなクエリーを WITH で先 頭にくくりだせる WITH cte1(txt) AS (SELECT "This

    "), cte2(txt) AS (SELECT CONCAT(cte1.txt,"is a ") FROM cte1), cte3(txt) AS (SELECT "nice query" UNION SELECT "query that rocks" UNION SELECT "query"), cte4(txt) AS (SELECT concat(cte2.txt, cte3.txt) FROM cte2, cte3) SELECT MAX(txt), MIN(txt) FROM cte4; 64/118
  24. 式インデックス 事前に計算できる(= NOW() とかはダメ)値に対して式を通し た値をインデックスにできる 5.7ではgenerated columnを作ってそれにインデックスを足してい たが、カラムなしでインデックスだけドスンと作れる ‐ mysql>

    ALTER TABLE t1 ADD KEY idx_exp ((age > 20)); mysql> EXPLAIN SELECT .. FROM t1 WHERE age > 20; +----+-------------+-------+------------+------+---------------+------+---------+------+-------+---- ------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | fil tered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+-------+---- ------+-------------+ | 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10195 | 33.33 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+-------+---- ------+-------------+ 1 row in set, 1 warning (0.00 sec) 68/118
  25. 式インデックス…? mysql> EXPLAIN SELECT .. FROM t1 WHERE age >

    20; +----+-------------+-------+------------+------+---------------+- -----+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+- -----+---------+------+-------+----------+-------------+ | 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10195 | 33.33 | Using where | +----+-------------+-------+------------+------+---------------+- -----+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) 70/118
  26. 新しいデータディクショナリー 全てのテーブルへのアクセスのベースになるので、 「新機 能 使わなければ 大丈夫」 といった五七五が効かない 何かあった時に回避が難しい ‐ ド新規で作ったテーブルはちゃんとテストされているだろう

    けど、特にMySQL 5.7未満からアップグレードを重ねてき たMySQLには㌧でもないテーブル定義が埋まっていたりす る 何故かテーブルコメントがSJISで書かれたテーブル ‐ lower_case_table_names= 1と相性が悪い… ‐ 76/118
  27. SQLパーザーのリファクタリング 地味に(?)リファクタしたらしい MySQL 8.0: Refactoring and Improving the Parser |

    MySQL Server Blog ‐ それはそれで良いんだけど、これも全アクセスの礎になって 回避しようがない部分… Window関数やCTEの追加でごりっと手を入れるからついで に(?)リファクタなのかなあ 5.7の時もパーザーのリファクタはやりたいって言ってたしなあ ‐ 79/118
  28. SET PERSIST SET GLOBAL は現在の設定値を更新するだけで mysqld を再起 動すると揮発する 永続化させたければ自分で my.cnf

    を更新しないといけない ‐ SET PERSIST は現在の設定値を更新した上で $datadir/ mysqld-auto.cnf に変更内容を記録する SQLインターフェイスだけで設定の永続化までやってくれる ‐ 83/118
  29. SET PERSIST /etc/my.cnf と $datadir/mysqld-auto.cnf に同じパラメー ターに対する設定があった場合、優先されるのはどっち? my.cnf 系が読み込まれた後に mysqld-auto.cnf

    が読まれる ‐ MySQLのパラメーター設定は 後勝ち ‐ つまり mysqld-auto.cnf の方が強い ‐ 「my.cnf編集して再起動したんですけど、 max_connections増えてない…」「それ、mysqld- auto.cnfから読んでるんじゃ?」みたいなことはありそう 84/118
  30. SET PERSIST MySQL開発チームの中の人とかは、「my.cnfを編集できな い、SQLインターフェイスしかないマネージドなMySQLで も設定変更を可能に」的なことを言っていたけど そもそも SET GLOBAL や SET

    PERSIST に必要なSuper権限を認めてい ないマネージドMySQLとか ‐ 提供している側からすれば「どっちが優先されるの問題」でエンド ユーザーに混乱を招く原因になりかねないとか ‐ 稼働中にいきなり着火する系ではないのが救い 85/118
  31. utf8mb4_0900_ai_ci character_set_server のデフォルトが latin1 から utf8mb4 に こっちはそのまま使ってる日本人は少ないと思うので別にいいと思う けど ‐

    character_set_server= utf8mb4 の時のデフォルトの照合順 序が変更になった utf8mb4_general_ci から utf8mb4_0900_ai_ci に ‐ 88/118
  32. utf8mb4_0900_ai_ci collation mysql = MySQL ハハ != パパ びょういん !

    = びようい ん != MySQL = M ySQL = != ≠ utf8mb4 _genera l_ci o o o x x o utf8mb4 _0900_ ai_ci o x x o o x utf8mb4 _ja_090 0_as_cs x o o o o o utf8mb4 _bin x o o o x o 89/118
  33. utf8mb4_0900_ai_ci kamipoのハハ=パパ問題 ActiveRecordでデフォルトの照合順序を変更する \- Qiita ‐ びょういん=びよういん問題 MySQL Bugs: #79977:

    utf8mb4_unicode_520_ci don’t make sense for Japanese FTS ‐ イコールイコールノットイコール問題 MySQL Bugs: #92899: Incorrect uniqueness determination with equality symbols ‐ 問題 https://twitter.com/tmtms/status/546925668424896512 ‐ MySQL Bugs: #76553: Sushi\-Beer issue of MySQL with utf8mb4 ‐ 90/118
  34. utf8mb4_0900_ai_ci 問題になりそうな場合は collation_server の変更を忘れず に 個人的には utf8mb4_bin, メールアドレスとかで大文字小文字を握り つぶしたいなら utf8mb4_general_ci

    かなぁ… ‐ これはMySQL 8.0の最初期から言ってきたことなので、み んな既に知っていることだといいな… 91/118
  35. Instant ADD COLUMN MySQL 5.6とそれ以降の「オンラインALTER TABLE」とは 違うもの オンラインで(= テーブルへの書き込みを許容しながら)実行できる 点は一緒

    ‐ 「既存の行の再構築を行わずにメタデータの調整だけでカラ ムを追加する」という超絶技術 99/118
  36. Instant ADD COLUMN 100万行, 100MBくらいのテーブルに対して mysql80 20> ALTER TABLE t1

    ADD c1 int, ALGORITHM= INSTANT; Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql80 20> ALTER TABLE t1 ADD c2 int, ALGORITHM= INPLACE; Query OK, 0 rows affected (3.43 sec) Records: 0 Duplicates: 0 Warnings: 0 100/118
  37. INSTANT ADD COLUMN ALGORITHM = INSTANT ----system---- ----total-cpu-usage---- -dsk/total- ---system--

    ------mem ory-usage----- --io/total- | time | usr sys idl wai hiq siq | read writ | int csw | used buff cach free | read writ | | 20-11 16:44:56 | 2 1 97 1 0 0 | 0 6409k | 877 996 | 692M 0 172M 127M | 0 222 | | 20-11 16:44:57 | 3 1 96 0 0 0 | 128k 394k | 1545 2509 | 692M 0 172M 127M | 8.00 63.0 | | 20-11 16:44:58 | 2 0 98 0 0 0 | 0 6410k | 901 982 | 692M 0 172M 127M | 0 225 | | 20-11 16:44:59 | 2 1 97 1 0 0 | 3260k 972k | 908 927 | 692M 0 175M 124M | 54.0 41.0 | | 20-11 16:45:00 | 2 0 98 0 0 0 | 0 0 | 641 772 | 692M 0 175M 124M | 0 0 | 17338 buffer_pages_written 2018-11-20 16:44:56 17347 buffer_pages_written 2018-11-20 16:44:57 17547 buffer_pages_written 2018-11-20 16:44:58 17577 buffer_pages_written 2018-11-20 16:44:59 17577 buffer_pages_written 2018-11-20 16:45:00 101/118
  38. INSTANT ADD COLUMN ALGORITHM = INPLACE ----system---- ----total-cpu-usage---- -dsk/total- ---system--

    ------memory-usage----- --io/total- | time | usr sys idl wai hiq siq | read writ | int csw | used buff ca ch free | read writ | | 20-11 16:45:00 | 2 0 98 0 0 0 | 0 0 | 641 772 | 692M 0 17 5M 124M | 0 0 | | 20-11 16:45:01 | 35 5 49 10 0 0 | 14M 78M | 14k 34k | 692M 0 17 5M 124M | 897 2150 | | 20-11 16:45:02 | 13 5 49 32 0 0 | 37M 51M | 9577 16k | 701M 0 20 5M 85.1M | 1213 3318 | | 20-11 16:45:03 | 19 8 49 23 0 0 | 14M 51M | 12k 18k | 693M 0 20 6M 91.7M | 245 5287 | | 20-11 16:45:04 | 3 2 85 10 0 0 | 6028k 31M | 6985 13k | 693M 0 21 1M 87.7M | 142 3098 | | 20-11 16:45:05 | 2 0 98 0 0 0 | 0 419k | 681 817 | 693M 0 21 1M 87.7M | 0 20.0 | 17577 buffer_pages_written 2018-11-20 16:45:00 18047 buffer_pages_written 2018-11-20 16:45:01 19139 buffer_pages_written 2018-11-20 16:45:02 21147 buffer_pages_written 2018-11-20 16:45:03 21591 buffer_pages_written 2018-11-20 16:45:04 21604 buffer_pages_written 2018-11-20 16:45:05 102/118
  39. INSTANT ADD COLUMN どういう黒魔術使ってるんだってくらい速い MySQL 8.0: InnoDB now supports Instant

    ADD COLUMN | MySQL Server Blog ‐ Tencent Gamesがパッチを寄贈したらしい ぼく「さすが自分たちで使い倒している企業は俺たちが欲しいものをよくわかって いる」 ‐ バッファプールも全然触らなくてすごい 楽しくて笑えてくるレベル ‐ ENUM型の定義変更も ALGORITHM = INSTANT でできるらしい ですよ!!!1 103/118
  40. ROLE IPアドレス単位でアカウント作ってる人にはわかってもらえ るかしらん MySQL側ではホスト部を指定せずに、セキュリティーグループとか で接続元を絞ってる場合はそんなに嬉しくないと思う ‐ mysql> CREATE USER apuser@apserver1;

    mysql> GRANT ALL ON ap_db.* TO apuser@apserver1; mysql> CREATE USER apuser@apserver2; mysql> GRANT ALL ON ap_db.* TO apuser@apserver2; mysql> CREATE USER apuser@apserver3; mysql> GRANT ALL ON ap_db.* TO apuser@apserver3; .. 106/118
  41. ROLE 「すいません、新機能はサーバーもわけることになりまし た。既存のアカウントは今まで通りap_dbだけ、新サーバー 用のアカウントはap_dbの読み取りとnew_dbの読み書き権 限を」 ( ゚д゚) えっえっ mysql> REVOKE

    ALL ON new_db.* FROM apuser@apserver1; mysql> REVOKE ALL ON new_db.* FROM apuser@apserver2; mysql> REVOKE ALL ON new_db.* FROM apuser@apserver3; .. mysql> CREATE USER apuser@apserver11; mysql> GRANT ALL ON new_db.* TO apuser@apserver11; mysql> GRANT SELECT ON ap_db.* TO apuser@apserver11; .. 108/118
  42. ROLE mysql> CREATE ROLE ap_rw; mysql> GRANT ALL ON ap_db.*

    TO ap_rw; mysql> CREATE USER apuser@apserver1 DEFAULT ROLE ap_rw; mysql> CREATE USER apuser@apserver2 DEFAULT ROLE ap_rw; mysql> CREATE USER apuser@apserver3 DEFAULT ROLE ap_rw; .. 110/118
  43. ROLE mysql> GRANT ALL ON new_db.* TO ap_rw; mysql> REVOKE

    ALL ON new_db.* FROM ap_rw; mysql> CREATE ROLE ap_ro; mysql> GRANT SELECT ON ap_db.* TO ap_ro; mysql> CREATE ROLE new_rw; mysql> GRANT ALL ON new_db.* TO new_rw; mysql> GRANT ap_ro TO new_rw; mysql> CREATE USER apuser@apserver11 DEFAULT ROLE new_rw; .. 111/118