mysqlのalter tableについて少々€¦ · ( ´-`).oo(...

78
MySQLALTER TABLEについて少々 ほんの1時間ばかり(少々とは) 2020/05/11 yoku0825 GMOテクノロジーブートキャンプ 2020

Upload: others

Post on 14-Jul-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

MySQLのALTER TABLEについて少々ほんの1時間ばかり(少々とは)

2020/05/11

yoku0825GMOテクノロジーブートキャンプ 2020

Page 2: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ここまでのあらすじ(?)

web基礎コーディング基礎プログラミング基礎オブジェクト指向DB設計SQLMySQL <- イマココ

1/77

Page 3: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

( ´-`).oO(

初めて具体的な製品名が出て来たぞDB設計できてSQLが書ければ特定のRDBMSに対する更なるインプット要る?

2/77

Page 4: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

よし3/77

Page 5: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ここでしか聞けないような話をしよう

( ・ㅂ・)̑̑و 4/77

Page 6: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ここでしか 聞け 耳にする機会がないような話をしよう( ・ㅂ・)̑̑و

5/77

Page 7: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

具体的に言うと ORDER BY のはなしをしたい

6/77

Page 8: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

???7/77

Page 9: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

詳細は終わりごろに出てきます

8/77

Page 10: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

いいわけ

最初は「MySQLと正規化」みたいな話をしようと思っていたでもそういう話、昔やったから またやるのめんどくさい どうせなら世に出てない情報の方が 面白い 有益かなって思った

-

MySQLと正規形のはなし-設計段階から正規化できてればいいけど、そうでない場合は運用中に直さないといけないあるいは完全に正規化されていようと、仕様が変わればスキーマは変わるもの-

となると必要なものは何だ? ALTER TABLEだ!ってなった多少反省はしている

9/77

Page 11: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

\こんにちは/

yoku0825@GMOメディア株式会社オラクれない-ポスグれない-マイエスキューエる-

生息域Twitter: @yoku0825-Blog: 日々の覚書-日本MySQLユーザ会-MySQL Casual-

10/77

Page 12: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

MySQLの尻に敷かれる毎日

(c)tomo

11/77

Page 13: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

おことわり

この時間のレベル感はデザイナーも駆け出しエンジニアも等しく「ちょっと何言ってるかわからない」を目指していますたかだか1時間MySQLの話を聞いたところでMySQLができるようになるわけもありませんし、何一つ記憶しなければならないことはありませんいつかALTER TABLEで障害を起こした時に「そういえばなんか聞いたような…」と思い出してくれたりすれば幸いですがこれデザイナーさんも聞いてるんですよね

12/77

Page 14: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

はい13/77

Page 15: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ALTER TABLE

テーブルの定義変更に使うステートメントRDBMSによってバリエーションがあるので飽くまでMySQLのはなしMySQL :: MySQL 8.0 Reference Manual :: 13.1.9 ALTER TABLE Statement

14/77

Page 16: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

基本構文

ALTER TABLE tbl_name [alter_option [, alter_option] ...] [partition_options]

alter_option は特定の組み合わせを除いて列挙可能インデックスとかまとめて複数張った方がI/Oのインプット側的に有利追加したカラムにそのままインデックス張るとか、新しいインデックス張るついでに古いインデックスを消すとか

-

15/77

Page 17: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

table_option(抜粋)

table_option: { AUTO_INCREMENT [=] value | [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'} | {DATA | INDEX} DIRECTORY [=] 'absolute path to directory' | ENCRYPTION [=] {'Y' | 'N'} | ENGINE [=] engine_name | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT} | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1} | STATS_PERSISTENT [=] {DEFAULT | 0 | 1} | STATS_SAMPLE_PAGES [=] value | TABLESPACE tablespace_name [STORAGE {DISK | MEMORY}]}

16/77

Page 18: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

alter_option(1)

alter_option: { | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST | AFTER col_name] | ALTER [COLUMN] col_name {SET DEFAULT {literal | (expr)} | DROP DEFAULT} | DROP [COLUMN] col_name | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] | RENAME COLUMN old_col_name TO new_col_name

17/77

Page 19: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

カラム操作系

データ型の変更を する場合だけ ALTER TABLE中の書き込みがブロックされるそれ以外は書き込みしながらテーブルの定義変更ができるのでメンテに入れなくても全然いけるカラムの追加(変更じゃない)-カラムの削除(変更じゃない)-カラムの並べ替え(データ型は変更されない)-カラムのリネーム(データ型は変更されない)-

18/77

Page 20: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ただし

この3つはテーブル全体が再構築されるのでコストは高いカラムの追加(変更じゃない)-カラムの削除(変更じゃない)-カラムの並べ替え(データ型は変更されない)-

19/77

Page 21: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

たとえば

こんなテーブルがあるじゃろ?num は PRIMARY KEY-

mysql80 66> SELECT * FROM t1;+------+-------+| num | val |+------+-------+| 1 | one || 2 | two || 3 | three |+------+-------+3 rows in set (0.00 sec)

20/77

Page 22: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

その時

ibd ファイルの中身はこんなんなってるじゃろ?0200200 \0 \0 001 \0 \0 \0 * Z 232 201 \0 \0 001 \v 001 0200200220 o n e 003 \0 \0 \0 030 \0 033 200 \0 \0 002 \0 \0 <-- one0200240 \0 * Z 232 201 \0 \0 001 \v 001 035 t w o 005 \0 <-- two0200260 \0 \0 377 273 200 \0 \0 003 \0 \0 \0 * Z 232 2010200300 \0 \0 001 \v 001 * t h r e e \0 \0 \0 \0 \0 <-- three

21/77

Page 23: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

カラムを足すじゃろ?

mysql80 68> ALTER TABLE t1 ADD COLUMN val_j varchar(32) DEFAULT 'hoge', ALGORITHM= INPLACE;Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Warnings: 0

mysql80 68> SELECT * FROM t1;+------+-------+-------+| num | val | val_j |+------+-------+-------+| 1 | one | hoge || 2 | two | hoge || 3 | three | hoge |+------+-------+-------+3 rows in set (0.00 sec)

22/77

Page 24: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

こうなるんじゃよ

0240200 200 \0 \0 001 \0 \0 \0 * Z 232 201 \0 \0 001 \v 0010240220 020 o n e h o g e 004 003 \0 \0 \0 030 \0 <-- onehoge0240240 200 \0 \0 002 \0 \0 \0 * Z 232 201 \0 \0 001 \v 0010240260 035 t w o h o g e 004 005 \0 \0 \0 377 260 <-- twohoge0240300 200 \0 \0 003 \0 \0 \0 * Z 232 201 \0 \0 001 \v 0010240320 * t h r e e h o g e \0 \0 \0 \0 \0 \0 <-- threehoge

23/77

Page 25: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

行指向(row-oriented)

24/77

Page 26: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

行指向(row-oriented)

25/77

Page 27: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

行指向(row-oriented)

26/77

Page 28: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

なんじゃよ27/77

Page 29: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

そこに颯爽と現れるINSTANT ADD COLUMN

しかしそこに考える若者(かどうかは知らんけど)がおったのじゃ「行指向で格納されたデータはそのままにして、『追加した列が見当たらなかった時だけデフォルト値返せばいいんじゃね?』『UPDATEやINSERTが走ったやつはその列もデータに格納すればいいんじゃね?』」頭いいんだこれが

28/77

Page 30: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

INSTANT ADD COLUMN

カラムを足す前のt1と同じ構造のt2にALTER TABLEするじゃろmysql80 69> ALTER TABLE t2 ADD COLUMN val_j varchar(32) DEFAULT 'hoge', ALGORITHM= INSTANT;Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Warnings: 0

mysql80 70> SELECT * FROM t2;+------+-------+-------+| num | val | val_j |+------+-------+-------+| 1 | one | hoge || 2 | two | hoge || 3 | three | hoge |+------+-------+-------+3 rows in set (0.00 sec)

29/77

Page 31: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

INSTANT ADD COLUMN

ないんじゃよ0200200 \0 \0 001 \0 \0 \0 * Z 301 202 \0 \0 \0 216 001 0200200220 o n e 003 \0 \0 \0 030 \0 033 200 \0 \0 002 \0 \0 <-- one0200240 \0 * Z 301 202 \0 \0 \0 216 001 035 t w o 005 \0 <-- two0200260 \0 \0 377 273 200 \0 \0 003 \0 \0 \0 * Z 301 2020200300 \0 \0 \0 216 001 * t h r e e \0 \0 \0 \0 \0 <-- three

30/77

Page 32: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

INSTANT ADD COLUMN

INSERTした時に初めてmysql80 76> INSERT INTO t2 VALUES (4, 'four', 'yon');Query OK, 1 row affected (0.01 sec)

mysql80 76> SELECT * FROM t2;+-----+-------+-------+| num | val | val_j |+-----+-------+-------+| 1 | one | hoge || 2 | two | hoge || 3 | three | hoge || 4 | four | yon |+-----+-------+-------+4 rows in set (0.00 sec)

31/77

Page 33: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

INSTANT ADD COLUMN

出てくる0200200 \0 \0 001 \0 \0 \0 * Z 353 202 \0 \0 \0 235 001 0200200220 o n e 003 \0 \0 \0 030 \0 033 200 \0 \0 002 \0 \0 <-- one0200240 \0 * Z 353 202 \0 \0 \0 235 001 035 t w o 005 \0 <-- two0200260 \0 \0 \0 037 200 \0 \0 003 \0 \0 \0 * Z 353 2020200300 \0 \0 \0 235 001 * t h r e e 003 004 \0 005 200 <-- three0200320 \0 ( 377 234 200 \0 \0 004 \0 \0 \0 * [ \0 201 \00200340 \0 \0 242 001 020 f o u r y o n \0 \0 \0 \0 <-- four, yon

32/77

Page 34: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

INSTANT ADD COLUMN

33/77

Page 35: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

INSTANT ADD COLUMN

34/77

Page 36: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

あったまいいなー…

35/77

Page 37: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

カラム操作系

データ型の変更を する場合だけ ALTER TABLE中の書き込みがブロックされるそれ以外は書き込みしながらテーブルの定義変更ができるのでメンテに入れなくても全然いけるカラムの追加(変更じゃない)-カラムの削除(変更じゃない)-カラムの並べ替え(データ型は変更されない)-カラムのリネーム(データ型は変更されない)-

36/77

Page 38: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

カラム操作系

カラムを増やす、減らすは当然ある当然あるんだから、そのために書き込みブロックをしなくても良いようにMySQLは進化してきた

-

「スキーマレス」をフル活用するつもりでなければ、「ブロックレススキーマ」は十分良いとこ取りができる

-

アプリケーション側でカラムの増減に弱い構造にしてはいけないINSERT INTO のカラムリストを省略する-SELECT * でselect_listの順番に依存している-などなど-

37/77

Page 39: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

はい次38/77

Page 40: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

alter_option(2)

alter_option: { | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY] [index_name] [index_type] (key_part,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (col_name,...) reference_definition | ADD {INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option] ... | ALTER INDEX index_name {VISIBLE | INVISIBLE} | DROP {INDEX | KEY} index_name | DROP PRIMARY KEY | DROP FOREIGN KEY fk_symbol | RENAME {INDEX | KEY} old_index_name TO new_index_name

39/77

Page 41: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

インデックス操作系

InnoDBのファイル構造レコード < ページ < インデックス < テーブル-

40/77

Page 42: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

インデックス操作系

1つのテーブルスペースファイルの中にインデックスはどんな順番で並んでいてもいい効率のためにある程度連続した領域を取ろうとはするけど、それはその時のファイルの中身の状況で決まるだけでルールではない

-

ということは、「新しいインデックスだけ空いているスペースで構築して、最後に「この領域は新しいインデックスが使っている」とマークしなおせばいい」

fast index creationと呼ばれる手法-

41/77

Page 43: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

インデックス操作系

fast index creationから更に発展して、「ALTER TABLEが始まった時点のデータ(これはMVCCで保証できる)をfast index creationして」「ALTER TABLEが始まってから終わるまでの間の更新差分だけ新しいインデックスに反映させればいいんじゃ?」後者を記録するための領域を「(ALTER)オンラインログ」と呼ぶ-ALTER TABLEが「始まった時点のデータを保証する」のと「最後の差分のマージ」はロックで保護する

-

InnoDBは行のデータもインデックスの一種なので「カラム操作系」もこのテクニックを使っている「別の領域にクラスターインデックスを新しく作ってそれをすり替え」ている-

42/77

Page 44: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

インデックス操作系

カラムの増減(= 行データを管理するインデックスの改変)よりも更にお手軽足りなければ足す、を当たり前に-

InnoDBのネクストキーロックは名前の通り「インデックスに対するロック+α」なので、インデックスが効かないと UPDATE や DELETE のロック範囲が異常に広くなる

InnoDBのロック競合は基本は「適切なインデックスを足して」やればほとんどの場合上手くいく

-

43/77

Page 45: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

インデックス操作系

MySQLの「ユニーク制約」「外部キー制約」はインデックスに基づいて制約される制約をかける ≒ インデックスを作る-

制約の追加、修正も比較的楽。そう、マイエスキューエル(5.6とそれ以降)ならね

44/77

Page 46: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

alter_option(2.5)

alter_option: { | ADD {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...) [index_option] ... | ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED] | DROP {CHECK | CONSTRAINT} symbol | ALTER {CHECK | CONSTRAINT} symbol [NOT] ENFORCED

45/77

Page 47: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

インデックス操作系?

FULLTEXT(全文検索用)インデックス、SPATIAL(空間)インデックスはちょっと別口コイツらはB+Treeの形をしていないのでフツーのインデックスと同じ扱いが出来ない-

CONSTRAINT のキーワード (だけ) は一緒だけど、CHECK制約もインデックスに基づかないテーブル内の全データが制約に沿うかどうか確認しないといけない関係上、テーブルへの書き込みをブロックするしテーブルコピーする

-

46/77

Page 48: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

alter_option(3)

alter_option: { | ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY} | {DISCARD | IMPORT} TABLESPACE | FORCE | LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE} | ORDER BY col_name [, col_name] ... | RENAME [TO | AS] new_tbl_name | {WITHOUT | WITH} VALIDATION}

47/77

Page 49: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

(つд⊂)ゴシゴシ

48/77

Page 50: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

alter_option(3)

alter_option: { | ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY} | {DISCARD | IMPORT} TABLESPACE | FORCE | LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE} | ORDER BY col_name [, col_name] ... | RENAME [TO | AS] new_tbl_name | {WITHOUT | WITH} VALIDATION}

49/77

Page 51: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ORDER BY50/77

Page 52: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

alter_option(3)

alter_option: { | ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY} | {DISCARD | IMPORT} TABLESPACE | FORCE | LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE} | ORDER BY col_name [, col_name] ... | RENAME [TO | AS] new_tbl_name | {WITHOUT | WITH} VALIDATION}

51/77

Page 53: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

制御系のオプション

ORDER BY を指定すると、データ本体の並び順を ORDER BY オプションで指定した通りに並べ替えてくれる「は?」って思ったでしょ。俺も8年位前にそう思った。-

ただしプライマリーキー(厳密にはクラスターインデックス)がない場合に限るというかこういうのを真似してはいけない-

52/77

Page 54: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ORDER BY

PRIMARY KEYなしで作るmysql80 8> CREATE TABLE t3 (num int, val varchar(32));Query OK, 0 rows affected (0.02 sec)

mysql80 8> INSERT INTO t3 VALUES (1, 'one'), (2, 'two'), (3, 'three');Query OK, 3 rows affected (0.00 sec)Records: 3 Duplicates: 0 Warnings: 0

mysql80 8> SELECT * FROM t3; -- ORDER BYがないSELECTは行が見つかった順に返す+------+-------+| num | val |+------+-------+| 1 | one || 2 | two || 3 | three |+------+-------+3 rows in set (0.00 sec)

53/77

Page 55: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ORDER BY

とすると、内部的に6バイトの「暗黙の行ID」が作られてその通りに並ぶ0200220 001 020 200 \0 \0 001 o n e 003 \0 \0 \0 030 \0 ! <-- one0200240 \0 \0 \0 002 302 001 \0 \0 \0 J h N 201 \0 \0 \00200260 215 001 037 200 \0 \0 002 t w o 005 \0 \0 \0 377 <-- two0200300 257 \0 \0 \0 002 302 002 \0 \0 \0 J h N 201 \0 \00200320 \0 215 001 . 200 \0 \0 003 t h r e e \0 \0 \0 <-- three

54/77

Page 56: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ORDER BY

ORDER BY val DESC にしてみるmysql80 8> ALTER TABLE t3 ORDER BY val DESC;Query OK, 3 rows affected (0.04 sec)Records: 3 Duplicates: 0 Warnings: 0

mysql80 8> SELECT * FROM t3; -- ORDER BYがないSELECTは行が見つかった順に返す+------+-------+| num | val |+------+-------+| 2 | two || 3 | three || 1 | one |+------+-------+3 rows in set (0.00 sec)

55/77

Page 57: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ORDER BY

ibdファイルの中身はこうなってる0200220 \0 \0 200 \0 \0 002 t w o 005 \0 \0 \0 030 \0 # <-- two0200240 \0 \0 \0 002 302 004 \0 \0 \0 J h Y 200 \0 \0 \00200260 \0 \0 \0 200 \0 \0 003 t h r e e 003 \0 \0 \0 <-- three0200300 377 255 \0 \0 \0 002 302 005 \0 \0 \0 J h Y 2000200320 \0 \0 \0 \0 \0 \0 200 \0 \0 001 o n e \0 \0 \0 <-- one

56/77

Page 58: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ORDER BY

古の時代、「1日1回くらい ALTER TABLE .. ORDER BY updated_at DESC ってやればSELECTに ORDER BY 書かなくても(=ソートのためのコストを払わなくても)それなりに最新のものが返ってくるんじゃ?」と思って作られたんではなかろうか当然ながらこんなものを使ってはいけない。 だがこのへんがMySQLっぽくて楽しい

MyISAMでできるのは知ってたけどまさかInnoDBにも対応しているとは思わなかった…-

57/77

Page 59: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

忘れましょう

58/77

Page 60: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

制御系のオプション

ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY}テーブルコピーまたはfast index creation型(=インプレース)またはINSTANT ADD COLUMN-

LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}読み書きを許可する(= NONE)、読み取りだけ許可する(= SHARED)-

59/77

Page 61: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

制御系のオプション

おまじない代わりに ALGORITHM = INPLACE, LOCK = NONE を付けておくと「オンラインでできないまたはテーブルコピーが必要なALTER TABLEはエラーになる」

mysql80 8> ALTER TABLE t1 ADD COLUMN c1 int, ALGORITHM= INPLACE, LOCK= NONE;Query OK, 0 rows affected (0.03 sec)Records: 0 Duplicates: 0 Warnings: 0

mysql80 8> ALTER TABLE t1 MODIFY c1 bigint, ALGORITHM= INPLACE, LOCK= NONE;ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

mysql80 8> ALTER TABLE t1 ADD FULLTEXT KEY(val), ALGORITHM= INPLACE, LOCK= NONE;ERROR 1846 (0A000): LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED.

60/77

Page 62: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ALTER TABLEのツボ

ALTER TABLEが「始まった時点のデータを保証する」のと「最後の差分のマージ」はロックで保護する

この2か所が詰まりがちALTER TABLE開始時のロックは「テーブルメタデータロック」本来時間は短いが「ロックの粒度」はかなりゴツい

-

シンプルな「接続してクエリー投げて切断」みたいなやつなら大体大丈夫なんだけど、トランザクションかけて他所のAPI叩いて戻りを待って…みたいな作りになっていると相性が悪いというか他所のAPIを叩くケース、失敗したように見えて応答が返ってきてないだけの可能性がたくさんあるのでシンプルなトランザクションじゃなくて「二度書き」のトランザクションにすると良い

-

あとは集計バッチとかかな…-

61/77

Page 63: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

テーブルメタデータロック

mysql80 9> BEGIN;Query OK, 0 rows affected (0.00 sec)

mysql80 9> SELECT * FROM t1; -- 単なるSELECTは行ロックは取らないがEmpty set (0.00 sec)

mysql80 10> ALTER TABLE t1 Engine = InnoDB; -- 9のトランザクションに阻まれてロック待ち

mysql80 11> SELECT * FROM t1; -- 10のALTER TABLEに阻まれてロック待ち

62/77

Page 64: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

テーブルメタデータロック

mysql80 9> SHOW PROCESSLIST;+----+-----------------+-----------+------+---------+-------+---------------------------------+--------------------------------+| Id | User | Host | db | Command | Time | State | Info |+----+-----------------+-----------+------+---------+-------+---------------------------------+--------------------------------+| 5 | event_scheduler | localhost | NULL | Daemon | 34966 | Waiting on empty queue | NULL || 9 | root | localhost | d1 | Query | 0 | starting | SHOW PROCESSLIST || 10 | root | localhost | d1 | Query | 16 | Waiting for table metadata lock | ALTER TABLE t1 Engine = InnoDB || 11 | root | localhost | d1 | Query | 4 | Waiting for table metadata lock | SELECT * FROM t1 |+----+-----------------+-----------+------+---------+-------+---------------------------------+--------------------------------+4 rows in set (0.00 sec)

63/77

Page 65: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ALTER TABLEのツボ

少なくともALTER TABLE開始時と終了時は innotop とかで監視をinnotop/innotop: A realtime terminal-based top-like monitor for MySQL-万一ブロッキングALTER TABLEになっても早期発見が可能なので-

開始時に詰まったら止められるけど、終了時に詰まっても「止めてはいけない」(し、だいたいCtrl+Cくらいじゃ「止まらない」)最後の差分マージはロックで詰まるわけではなくて単に負荷が異様に高くなるだけだけ(InnoDBログにぐわっと書き込むから)

-

64/77

Page 66: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ALTER TABLEのツボ

「書き込みながらALTER TABLEできる」のはマスターの話で、スレーブはまた別の制約を受けるレプリケーションスレーブは(原則)同時にそんなに複数の更新を捌かない-ALTER TABLEのリプレイ中はスレーブはどんづまるマスターで1時間かかったALTER TABLEはスレーブでもおそらく1時間かかる

-

65/77

Page 67: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

ALTER TABLEのツボ

「レプリケーションを介してALTER TABLEを流すとどんづまる」「じゃあレプリケーションを介さずにALTER TABLEすればいいんでは? 」「えっ」「えっ」

66/77

Page 68: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションの基本的な仕組み

67/77

Page 69: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションの基本的な仕組み

68/77

Page 70: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションの基本的な仕組み

69/77

Page 71: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションの基本的な仕組み

70/77

Page 72: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションの基本的な仕組み

71/77

Page 73: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションが構成されていない3台の別のサーバーでも

72/77

Page 74: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

レプリケーションの基本的な仕組み

ふしぎなちからではない本質的には「マスターに適用された更新のSQLをバイナリログで伝達し、スレーブでリプレイする」

-

MySQLには接続単位でバイナリログをOFFにする特権(Super権限が必要)があるバイナリログ経由で二重にALTER TABLEを適用すると名前が衝突して死んじゃうことがあるから

-

73/77

Page 75: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

Rolling Schema Upgrade

Rollingとはいうけど順番じゃなくて一斉にやっても別に良いとはいえ先にスレーブやって様子を見てからマスターに流すよね-

mysql> SET sql_log_bin = OFF;mysql> ALTER TABLE t1 ADD KEY idx_test(val);

74/77

Page 76: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

Rolling Schema Upgrade

カラムの増減でこれをやると往々にして死ぬこれはアプリケーションが吐くSQLがカラムの増減に強く && binlog_format = STATEMENTでなくてはならないから

-

後者を設定すると大体別のところで死ぬので、binlog_format= ROWが推奨される世の中-上手く使いきれる人はニンジャ-

だからこそINSTANT ADD COLUMNが生まれたとも考えられる

75/77

Page 77: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

まとめ

MySQLはサービスを止めなくてもALTER TABLEができるように進化してきたサービス側でそれを享受するにはアプリケーションでのSQLの書き方もだいじ定石はググれば案外出てくるので上手く使い分ける

76/77

Page 78: MySQLのALTER TABLEについて少々€¦ · ( ´-`).oo( 初めて具体的な製品名が出て来たぞ db設計できてsqlが書ければ特定のrdbmsに対する更なるインプット要る?

Any Questions and/or

Suggestions?77/77