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

データベース【サイボウズ新人研修2025】

Avatar for Cybozu Cybozu
July 06, 2025
1.7k

 データベース【サイボウズ新人研修2025】

Avatar for Cybozu

Cybozu

July 06, 2025
Tweet

More Decks by Cybozu

Transcript

  1. \こんにちは/ yoku0825@とある企業のDBAだったもの オラクれない ‐ ポスグれない ‐ マイエスキューエる ‐ 生息域 Twitterだったもの:

    @yoku0825 ‐ Blog: 日々の覚書 ‐ 日本MySQLユーザ会副代表 ‐ MySQL Casual ‐ bozumanではだいたいGaroonのShare Customer Support板にいます 余裕がある時は “MySQL” で全件検索して勝手にコメントをつけたり ‐ 1/77
  2. はじめてのMySQL root@% がパスワードなしなので手元で試すくらいで… docker run -d --restart=on-failure \ -e MYSQL_ALLOW_EMPTY_PASSWORD=1

    \ -e MYSQL_ROOT_PASSWORD="""" \ -e MYSQL_ROOT_HOST=""%"" \ container-registry.oracle.com/mysql/community-server:8.4.5 \ --gtid-mode=ON --enforce-gtid-consistency=ON 5/77
  3. はじめてのMySQL 10秒くらい待つ docker logs コンテナID [Entrypoint] MySQL Docker Image 8.4.5-1.2.21-server

    [Entrypoint] Initializing database 2025-04-21T04:21:50.528592Z 0 [System] [MY-015017] [Server] MySQL Server I nitialization - start. 2025-04-21T04:21:50.530156Z 0 [System] [MY-013169] [Server] /usr/sbin/mys qld (mysqld 8.4.5) initializing of server in progress as process 17 .. [Entrypoint] MySQL init process done. Ready for start up. .. 2025-04-21T04:21:59.400336Z 0 [System] [MY-010931] [Server] /usr/sbin/mys qld: ready for connections. Version: '8.4.5' socket: '/var/lib/mysql/mys ql.sock' port: 3306 MySQL Community Server - GPL. 6/77
  4. はじめてのMySQL docker inspect コンテナID | jq -r '.[0].NetworkSettings.Networks[].IPAddres s' 172.17.0.2

    mysql -h IPアドレス -uroot SELECT @@version; +-----------+ | @@version | +-----------+ | 8.4.5 | +-----------+ 1 row in set (0.00 sec) 7/77
  5. はじめてのMySQL CREATE DATABASE d1; use d1 CREATE TABLE t1 (num

    INT PRIMARY KEY, val VARCHAR(32) NOT NULL, UNIQUE KE Y uidx_val(val)); INSERT INTO t1 (num, val) VALUES (1, 'one'); INSERT INTO t1 (num, val) VALUES (2, 'two'); INSERT INTO t1 (num, val) VALUES (3, 'three'); 8/77
  6. はじめてのMySQL SELECT * FROM t1; +-----+-------+ | num | val

    | +-----+-------+ | 1 | one | | 3 | three | <--- threeが先? | 2 | two | +-----+-------+ 9/77
  7. はじめてのMySQL SELECT * FROM t1 ORDER BY num; +-----+-------+ |

    num | val | +-----+-------+ | 1 | one | | 2 | two | | 3 | three | +-----+-------+ 10/77
  8. はじめてのMySQL mysql> help CREATE DATABASE Name: 'CREATE DATABASE' Description: Syntax:

    CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_option] ... create_option: [DEFAULT] { CHARACTER SET [=] charset_name | COLLATE [=] collation_name | ENCRYPTION [=] {'Y' | 'N'} } CREATE DATABASE creates a database with the given name. To use this statement, you need the CREATE privilege for the database. CREATE SCHEMA is a synonym for CREATE DATABASE. 12/77
  9. いわゆるCRUD Create: INSERT INTO .. Read: SELECT .. FROM ..

    Update: UPDATE .. SET .. Delete: DELETE FROM .. 14/77
  10. いわゆるCRUD よくドキュメントを見てみると <snip> Single-table syntax: UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET

    assignment_list [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] <snip> Multiple-table syntax: 15/77
  11. いわゆるCRUD たとえば UPDATE の直後にくるキーワードは table_reference 単一のテーブルである必要はない ‐ UPDATE t1 AS

    normal_t1 JOIN t1 AS another_t1 ON normal_t1.num = another_t 1.num SET normal_t1.num = normal_t1.num + another_t1.num WHERE another_t1. num = 3; SELECT * FROM t1 ORDER BY num; +-----+-------+ | num | val | +-----+-------+ | 1 | one | | 2 | two | | 6 | three | +-----+-------+ 16/77
  12. いわゆるCRUD DELETE はもっとクセがある <snip> Single-Table Syntax DELETE [LOW_PRIORITY] [QUICK] [IGNORE]

    FROM tbl_name [[AS] tbl_alias] [PARTITION (partition_name [, partition_name] ...)] [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] <snip> Multiple-Table Syntax DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... 17/77
  13. いわゆるCRUD SELECT .. FROM テーブル名 とかよく言われるやつの「テーブル名」は「テーブル名」じゃない ことがある MySQL用語的には「テーブルリファレンス」 ‐ INSERT

    INTO .. の後ろ側も「テーブルリファレンス」であって VALUES (..) が「テーブルリ ファレンスのコンストラクタ」 なので INSERT INTO .. から VALUES の「代わりに」 SELECT が来ても成立する ‐ なので INSERT INTO .. SELECT .. の時は VALUES が「ない」 SELECT 自体がテーブルリファレンスを返すから ‐ 18/77
  14. テーブルとテーブルリファレンス このあたりの考え方を拡張していくと インデックスを強制するDELETE文 とかちょっとした小ネ タが広がる EXPLAIN DELETE t1 FROM t1

    WHERE num = 6; +----+-------------+-------+------------+-------+---------------+--------- +---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+--------- +---------+-------+------+----------+-------+ | 1 | DELETE | t1 | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL | +----+-------------+-------+------------+-------+---------------+--------- +---------+-------+------+----------+-------+ 19/77
  15. テーブルとテーブルリファレンス EXPLAIN DELETE FROM t1 IGNORE INDEX(PRIMARY) WHERE num =

    6; ### DELETE FROMの あとはテーブル名が来ないといけないのでシンタックスエラー ERROR 1064 (42000): You have an error in your SQL syntax; check the manual th at corresponds to your MySQL server version for the right syntax to use near ' IGNORE INDEX(PRIMARY) WHERE num = 6' at line 1 EXPLAIN DELETE t1 FROM t1 IGNORE INDEX(PRIMARY) WHERE num = 6; ### インデック スヒントを含んだテーブル指定は「テーブルリファレンス」 +----+-------------+-------+------------+------+---------------+------+------- --+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_l en | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+------- --+------+------+----------+-------------+ | 1 | DELETE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 50.00 | Using where | +----+-------------+-------+------------+------+---------------+------+------- --+------+------+----------+-------------+ 20/77
  16. 余談 なお、今日日 インデックスを強制するDELETE文 を書くならオプティマイザヒントの方が楽 {USE|FORCE|IGNORE} INDEX はMySQL方言で非推奨の流れだし ‐ 今はできるんですよ、って昔から使ってる人に言いたいだけ ‐

    EXPLAIN DELETE /*+ NO_INDEX(t1 PRIMARY) */ t1 FROM t1 WHERE num = 6; +----+-------------+-------+------------+------+---------------+------+--- ------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | ke y_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+--- ------+------+------+----------+-------------+ | 1 | DELETE | t1 | NULL | ALL | NULL | NULL | NU LL | NULL | 3 | 50.00 | Using where | +----+-------------+-------+------------+------+---------------+------+--- ------+------+------+----------+-------------+ 21/77
  17. いわゆるCRUD 特定のケースを除いて SELECT はロックフリー SELECT .. FOR SHARE, SELECT ..

    FOR UPDATE a. transaction_isolation = SERIALIZABLE b. INSERT は対応するユニークキーとPrimary Keyの値をロック UPDATE / DELETE は「WHERE句の解決に使ったインデックス」と対応するPrimary Keyの 値をロック ### ターミナル1 BEGIN; INSERT INTO t1 VALUES (3, 'three'), (4, 'four'), (5, 'five'); ### COMMITせずに次へ 23/77
  18. いわゆるCRUD 特定のケースを除いて SELECT はロックフリー SELECT .. FOR SHARE, SELECT ..

    FOR UPDATE a. transaction_isolation = SERIALIZABLE b. INSERT は対応するユニークキーとPrimary Keyの値をロック UPDATE / DELETE は「WHERE句の解決に使ったインデックス」と対応するPrimary Keyの 値をロック ### ターミナル2 BEGIN; SELECT * FROM t1 ORDER BY num; ### 何もつけないSELECTはロックフリー +-----+-----+ | num | val | +-----+-----+ 24/77
  19. いわゆるCRUD 特定のケースを除いて SELECT はロックフリー SELECT .. FOR SHARE, SELECT ..

    FOR UPDATE a. transaction_isolation = SERIALIZABLE b. INSERT は対応するユニークキーとPrimary Keyの値をロック UPDATE / DELETE は「WHERE句の解決に使ったインデックス」と対応するPrimary Keyの 値をロック ### ターミナル2 SET SESSION innodb_lock_wait_timeout = 1; SELECT * FROM t1 WHERE num = 3 FOR UPDATE; ### num = 3はINSERTにロックされて いる INSERT INTO t1 VALUES (3, 'drei'); ### ↑同様 INSERT INTO t1 VALUES (6, 'six'); ### num = 6はロックされてないので 25/77
  20. いわゆるCRUD 特定のケースを除いて SELECT はロックフリー SELECT .. FOR SHARE, SELECT ..

    FOR UPDATE a. transaction_isolation = SERIALIZABLE b. INSERT は対応するユニークキーとPrimary Keyの値をロック UPDATE / DELETE は「WHERE句の解決に使ったインデックス」と対応するPrimary Keyの 値をロック ### ターミナル2 DELETE FROM t1 WHERE val = 'five'; ### val = 'five' に紐づく num = 5 がINSERTにロックされている UPDATE t1 SET val = 'five' WHERE num = 1; ### num = 1はロックされていないが v al = 'five' がロックされている UPDATE t1 SET val = 'eins' WHERE num = 1; ### num = 1もval = 'eins' もロッ クされていないので成功 ### ちなみにvalがユニークキーでない場合は2つ目のUPDATEが成功する 26/77
  21. transaction_isolation = SERIALIZABLE トランザクション分離レベルというやつ MySQL :: MySQL 8.4 Reference Manual

    :: 15.3.7 SET TRANSACTION Statement ‐ 同時実行されるトランザクション同士が「単一スレッドで逐次実行された時と同じ結果になる (Serializabilityを持つ)」ことを保証したいのが SERIALIZABLE なお transaction_isolation = SERIALIZABLE は(規格上)必ずしも常に「単一スレッドで逐次 実行された時と同じ結果になる」わけではないらしい Isolation Levelの階層 #ポエム \- Qiita 一人トランザクション技術 \- Qiita Advent Calendar 2016 \- Qiita ‐ 28/77
  22. transaction_isolation = SERIALIZABLE transaction_isolation = SERIALIZABLE だけがSerializabilityを保つとは限らな い 相手のトランザクションのパターンによる ‐

    どんなトランザクションでもSerializabilityに近付けるフレームワークだと考えると良さそう ‐ SELECT が暗黙に共有ロックを取るようになる kintoneは transaction_isolation = SERIALIZABLE と transaction_isolation = READ_COMMITTED を使い分けていたはず 興味がない人は「SELECT(だけじゃないけど)の時のロックの動作を変えるアノテーション」とでも思っておいてOK ‐ Garoonは transaction_isolation = READ_COMMITTED と、 SELECT .. FOR {SHARE|UPDATE} で直列化したいところだけ直列化する方式だったはず 76/77