Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.
わかった 気になる MySQL
〜SELECTステートメント編〜
2017/06/23
yoku0825の中の⼈
GMOテクノロジーブートキャンプ
おことわり
この資料で述べられる⾒解はyoku0825の中の⼈のノリによ
るものであり、所属する組織または所属しない組織の意⾒を
代表するわけがありません
この資料を読んだりセッションを聞いたりしてもたぶんSQL
を書けるようにはなりません
1...
つまり
2/105
テキトーに聞
いといてくだ
さい
3/105
MySQL触った
ことある⼈︖
4/105
MySQL で
きる ⼈︖
5/105
MySQL知
らない⼈︖
6/105
MySQLより
年下の⼈︖
7/105
MySQL 1.0は1995年
リリースらしい
Past, Present and future of
MySQL and variants Part
1: Ghosts of MySQL Past |
Ramblings
8/105
こんな画⾯触ったことある⼈︖
9/105
こういうやつの⽅が好きな⼈︖
10/105
MySQL好
きな⼈︖
11/105
三度の飯より
MySQLが好き
な⼈︖
12/105
MySQLやめる
か煙草やめるか
って⾔われたら
13/105
⼈間やめ
る⼈︖
14/105
\こんにちは/
yoku0825の中の⼈@GMOメディア
オラクれない-
ポスグれない-
マイエスキューエる-
⽣息域
Twitter: @yoku0825-
Blog: ⽇々の覚書-
MyNA ML: ⽇本MySQLユーザ会-
MySQL C...
普段やってること
障害対応
社内サポートデスク
DBに特化した運⽤, 設計, ショット作業
教育, 啓蒙活動
技術研究
16/105
障害対応
開発陣はDBサーバーにSSHログインできない
AP起因でMySQLがぶん回ったりするものを含む
HWの交換はお任せ、OSを再セットアップしてもらってから
が出番
17/105
社内サポートデスク
新しい開発環境のDBが欲しいんですけど
APサーバーが追加されたからGRANTしてほしいんだけど
クエリー遅いんですけど
このサーバー撤去するんでDBどかして欲しいんですけど
DBサーバー増やす︖ 減らす︖
18/105
DBに特化した運⽤, 設計, ショット作業
DBレイヤーのグランドデザイン
バックアップの記録, 保管-
シャーディング-
mikasafabric for MySQL + MySQL Router-
必要リソースの⾒積もり-
MySQL, P...
DBに特化した運⽤, 設計, ショット作業
フツーの ALTER TABLE でないオンラインスキーマ変更
pt-osc-
SET SESSION sql_log_bin= 0 からの ALTER TABLE .. ADD KEY ..
ALG...
教育, 啓蒙活動
新⼊社員研修
社内勉強会
おもむろにPRやIssueに出現してマサカリを投げて去る
21/105
技術研究
MySQL 8.0
エコシステム各種の検証
⼿抜き監査ログクライアント
mikasafabric for MySQL
何故かDocker全般
22/105
MySQL #とは
世界でもっとも普及している、オープン ソース データ
ベース
https://www.mysql.com/jp/
23/105
MySQL #とは
永続化可能な
サーバーまたいでアクセスできる
排他・共有ロック機能付きの
グローバル変数のすごいやつ
異論は認める
MySQLおじさんの逆襲
24/105
置いとい
て
25/105
今⽇は基礎として
SELECTステート
メントの話(だけ)
をします
26/105
簡素化したSELECTステートメント
SELECT
column1, column2, ..
FROM
table1
WHERE
column1 = '..'
ORDER BY
column2;
27/105
肩慣らし
28/105
肩慣らし
何のエラーが出る︖
SEECT -- Invalid Syntax
nonexistent_column_in_select_list
FROM
nonexistent_table
WHERE
nonexistent_column_i...
答え
MySQL error code 1064 (ER̲PARSE̲ERROR): %s near
ʻ%-.80sʼ at line %d
ERROR 1064 (42000): You have an error in your SQL s...
肩慣らし
何のエラーが出る︖
SELECT
nonexistent_column_in_select_list
FROM
nonexistent_table
WHERE
nonexistent_column_in_where_clause = ...
答え
MySQL error code 1146 (ER̲NO̲SUCH̲TABLE): Table
ʻ%-.192s.%-.192sʼ doesnʼt exist
ERROR 1146 (42S02): Table 'test.nonexis...
肩慣らし
何のエラーが出る︖
SELECT
nonexistent_column_in_select_list
FROM
table1
WHERE
nonexistent_column_in_where_clause = '..'
ORDER ...
答え
MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR):
Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ
ERROR 1054 (42S22): Unknown column 'n...
肩慣らし
何のエラーが出る︖
SELECT
column1
FROM
table1
WHERE
nonexistent_column_in_where_clause = '..'
ORDER BY
nonexistent_column_in_o...
答え
MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR):
Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ
ERROR 1054 (42S22): Unknown column 'n...
肩慣らし
何のエラーが出る︖
SELECT
column1
FROM
table1
WHERE
column1 = '..'
ORDER BY
nonexistent_column_in_orderby_clause;
37/105
答え
MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR):
Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ
ERROR 1054 (42S22): Unknown column 'n...
ER̲BAD̲FIELD̲ERROR
MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR):
Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ
ERROR 1054 (42S22): U...
取り敢えずわかること
シンタックスエラーが⼀番強い
パースできないとどれがオブジェクトでどれがキーワードかわからな
い
-
FROM句だけ特別っぽい
たぶん、対象オブジェクトを確定してアクセス権限のチェックしない
といけないから
-
他は頭から...
シンプルな
SELECTにも
⾊々ある
41/105
ストアドファンク
ションとか使った
複雑なSELECTには
もっと⾊々(ry
42/105
SELECTステートメント
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [...
シンタックス
このへんはフツーに使うだろうからやらない
DISTINCT-
STRAIGHT̲JOIN-
LIMIT-
INTO OUTFILE-
[FOR UPDATE | LOCK IN SHARE MODE]-
44/105
シンタックス(1)
select_expr
select̲listとも-
雑に⾔うと「カラム名を列挙するとこ」-
exprの名が⽰すように、式も記述できる-
最低1つ必要-
45/105
MySQLのbool評価式
真なら1, 偽なら0, UNKNOWNならNULLが返る
mysql80 5> SELECT DAYOFWEEK('2017/06/23') = 6;
+-----------------------------+
...
こんな結果セットがあった時に
mysql80 5> WITH RECURSIVE june AS (
-> SELECT CAST('2017/06/01' AS DATE) AS dt
-> UNION ALL
-> SELECT DATE_...
こんな キモい こともできる
1または0だからSUMがきく
mysql80 5> WITH RECURSIVE june AS (
-> SELECT CAST('2017/06/01' AS DATE) AS dt
-> UNION ALL
...
SELECTステートメント
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [...
シンタックス(2)
table_references
テーブルじゃなくてテーブルリファレンス、なのが楽しいところ-
JOINした結果やサブクエリーなど、割とあらゆるSELECTの出⼒結果
がそのままテーブルリファレンスになれる
-
特別なキーワ...
こんな⼊れ⼦も
mysql80 5> SELECT * FROM (
-> SELECT * FROM (
-> SELECT * FROM (
-> SELECT * FROM (
-> SELECT * FROM (
-> SELECT N...
SELECTステートメント
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [...
シンタックス(3)
where_condition
WHEREとHAVINGで指定する-
真偽値(ところによりNULL)を返す式-
実は定数でもイケる-
MySQLでは0が偽、0以外が真、NULLがUNKNOWN
ただしFALSEは0のシノニム...
知ってると⾯⽩い
mysql80 5> SELECT * FROM t1;
+-----+------+
| num | val |
+-----+------+
| 1 | one |
| 2 | two |
+-----+------+
2...
知ってると⾯⽩い
mysql80 5> SELECT * FROM t1 WHERE num = TRUE;
+-----+------+
| num | val |
+-----+------+
| 1 | one | <-- TRUEは1だ...
NULLに対する演算(1)
NULL + 1
NULL - 1
NULL * 1
NULL / 1
CONCAT(NULL, 'ぽ', 'ガッ')
56/105
NULLに対する演算(1)
mysql80 25> SELECT NULL + 1, NULL - 1, NULL * 1, NULL / 1, CONCAT
(NULL, 'ぽ', 'ガッ')G
**********************...
NULLに対する演算(2)
NULL AND NULL
NULL AND TRUE
NULL AND FALSE
NULL OR NULL
NULL OR TRUE
NULL OR FALSE
58/105
NULLに対する演算(2)
mysql80 25> SELECT NULL AND NULL, NULL AND TRUE, NULL AND FALS
E, NULL OR NULL, NULL OR TRUE, NULL OR FALSEG...
NOT NULL推奨
ある整数Aは
A = 1 または A <> 1-
A == 1のテストとA == 0のテストを書けば境界値テストでカバーで
きる
-
ある整数型のNULLABLEなカラムに格納された値Bは
B = 1 または B <> 1...
テストケースの増⼤
WHERE句にカラムを並べたとして
カラムの数 NOT NULL 境界値の数
1 o 2^1=2
2 o 2^2=4
3 o 2^3=8
1 x 3^1=3
2 x 3^2=9
3 x 3^3=27
61/105
NOT
NULL推奨
62/105
(余談) NULLABLEは伝播する
NULLに対する演算をしてもNULLが返らない演算をNULLセ
ーフな演算と呼ぶ
たとえば IS NULL 演算⼦はNULLセーフ演算⼦-
NULLに対する非NULLセーフな演算の結果はNULL
いくつかの...
閑話休題
64/105
SELECTステートメント
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [...
シンタックス(4)
col_name | expr | position
GROUP BY や ORDER BY で指定するやつ-
カラム名、評価式、select̲list内のオフセット(1オリジン)で指定で
きる
-
ORDER BY RAN...
⾶び道具っぽいORDER BY指定
mysql80 5> SELECT * FROM t1;
+-----+-------+
| num | val |
+-----+-------+
| 1 | one |
| 2 | two |
| 3 |...
⾶び道具ORDER BYその2
mysql80 23> SELECT * FROM t1 ORDER BY FIELD (num, 1, 4, 5, 3, 2);
+-----+-------+
| num | val |
+-----+---...
NULLABLEなカラムのソート
mysql80 24> SELECT * FROM t1 ORDER BY num;
+------+------+
| num | val |
+------+------+
| NULL | NULL |
...
SELECTステートメント
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [...
クエリーキャッシュ関連
[SQL̲CACHE|SQL̲NO̲CACHE]
クエリー単位でクエリーキャッシュの有効/無効を切り替え
られる
query̲cache̲type 指定なし SQL̲CACHE SQL̲NO̲CACHE
0(DISABL...
笑えるコード
653 static bool has_no_cache_directive(const char *sql, uint offset,
654 size_t query_length)
655 {
..
671 if (my_t...
過去の遺物
[HIGH̲PRIORITY]
[SQL̲SMALL̲RESULT]
[SQL̲BIG̲RESULT]
[SQL̲BUFFER̲RESULT]
[PROCEDURE analyse()]
73/105
闇なやつ
[SQL̲CALC̲FOUND̲ROWS]
ORDER BY .. LIMIT .. のbreakを無効にする代わりに、
COUNT(*) も⼀緒に取得する
取得した COUNT(*) は SELECT FOUND_ROWS() でア...
闇なやつ
mysql80 7397205> SELECT * FROM city ORDER BY population DESC LIMIT 10;
..
10 rows in set (0.01 sec)
mysql80 7397205> ...
5.6とそれ以降ではパーティションがテーブルリファレン
スに指定できる
FROM t1 PARTITION (p1, p2)
特定のパーティションだけをあたかもテーブルのようにアク
セスできる
上⼿く使うとWHERE句をいっこかっ⾶ばせたり、不...
パーティション指定アクセス
mysql80 22> SHOW CREATE TABLE t2G
*************************** 1. row ***************************
Table: t2
C...
パーティション指定アクセス
mysql80 22> EXPLAIN SELECT * FROM t2 WHERE dt BETWEEN '2017/06/01' AND '2017/06/30';
+----+-------------+---...
SELECT処理のイメージ
イメージなのでちょくちょく 嘘
79/105
SELECT処理のイメージ(1)
まず結果セットのベースになるFROM句の要素全体に注目
ただし相関サブクエリー以外のサブクエリーはこれに先⽴って解決される-
Whole Table
80/105
SELECT処理のイメージ(2)
WHERE句に従ってフィルタリング
Whole Table
Filtered Set
81/105
SELECT処理のイメージ(3)
ソートしたり集約したり
Whole Table
Filtered Set
Sorted Set
82/105
SELECT処理のイメージ(4)
結果セットに必要な列だけをバッファに詰めてできあがり
Whole Table
Filtered Set
Sorted Set
83/105
GROUP BY, HAVING, ORDER BY, LIMIT
WHEREで件数を絞り込んだあとに
GROUP BYで集約した後に
HAVINGでフィルターして
ORDER BYで並べ替えてから
LIMITで指定した⾏数だけ返す
84/105
もうちょっ
と細かく︖
85/105
よく使う図
InnoDB API
Handler API
Executor
Optimizer
Parser
MySQL Protocol HS Protocol
HS Plugin
memcached Protocol
InnoDB Memc...
クエリーのライフサイクル
Connection Handling
Parser
Optimizer
Executor
Handler
Storage Engine
87/105
Connection Handling
ソケット, ポートからの接続を待ち受ける
接続があったらclone(またはスレッドキャッシュから取り
出してディスパッチ)
⼀次認証
88/105
Parser
MySQLプロトコルのパース
SQL構⽂のパース
⼆次認証(データベース, テーブル単位のアクセス権限チ
ェック)
クエリーキャッシュ処理
ジェネラルログ
89/105
Optimizer
統計情報の取得(Storage Engine APIを叩いてるっぽい)
クエリーの書き換えを含めた実⾏計画の決定
90/105
Executor
オプティマイザーから渡された実⾏計画の通りにHandlerを
叩く
Handlerから戻ってきた結果を使って実⾏計画の残りを実⾏
Using where; Using filesort; Using temporary; はコ...
Handler
ストレージエンジンの抽象化レイヤー
あんまり意識することはない
92/105
Storage Engine
実際にデータを格納するレイヤー
プラガブルアーキテクチャーなので、ほとんどの機能はこの
レイヤーで実装されている
ストレージエンジンごとにトランザクション対応が違うとか-
ストレージエンジンごとにロック粒度が違うと...
え︖ もっ
と細かく︖
94/105
SELECTステートメントの⼀⽣(1)
3306ポートへのアクセスがmysqld̲mainによって捕捉さ
れ、⼦スレッドが割り当てられる
handle̲connectionからdo̲commandを経て
dispatch̲commandへ、ここ...
SELECTステートメントの⼀⽣(2)
read̲onlyオプションの判定が⼊ったりしたあと
lex->sql̲commandで振り分け処理がされつつ
select̲precheckが呼ばれてアカウントの権限が評価され
execute̲sqlc...
SELECTステートメントの⼀⽣(3)
可能であればOUTER JOIN ⇒ INNER JOINの書き換えとか
結合条件をWHERE句に移動する処理とか
SEMIJOINならここでビットマップインデックスを作る
sql̲mode=ONLY̲F...
SELECTステートメントの⼀⽣(4)
⾏のフェッチが終わったらソートしたりフィルタリングした
り⾊々してから
close̲thread̲tablesでテンポラリーテーブル消したり
close̲thread̲tableでテーブル閉じてテーブルキ...
諸元
SQLパーサー
sql/sql̲yacc.yy, sql/sql̲yacc.cc
エグゼキューター
sql/sql̲executor.cc, sql/sql̲select.cc
汎⽤ユーティリティー
sql/sql̲class.cc
In...
え、まだまだ
⾜りない︖
100/105
↑やら↑
101/105
↓ない↓
102/105
まとめ︖
普段何気なく使っているMySQLもアプリケーション
⾊んな内部実装があって、得意なことがあったり苦⼿なこと
があったり
それをユーザーに意識させないためにSQLというレイヤーが
あるので
それより下を勉強するのはなかなか⼤変
世界は広...
まとめ︖
困った時はいつでもどうぞ
MyNA ML: ⽇本MySQLユーザ会-
MySQL Casual: Slack-
おじさんズ welcome you!
104/105
Questions
and/or
Suggestions?
105/105
Próxima SlideShare
Cargando en…5
×

わかった気になるMySQL

9.034 visualizaciones

Publicado el

2017/06/23 GMOテクノロジーブートキャンプ

Publicado en: Tecnología
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí
  • Download this 3-step guide to generating insane amounts of media coverage for your from LinkedIn: http://bit.ly/linkedin3stepguide
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí

わかった気になるMySQL

  1. 1. わかった 気になる MySQL 〜SELECTステートメント編〜 2017/06/23 yoku0825の中の⼈ GMOテクノロジーブートキャンプ
  2. 2. おことわり この資料で述べられる⾒解はyoku0825の中の⼈のノリによ るものであり、所属する組織または所属しない組織の意⾒を 代表するわけがありません この資料を読んだりセッションを聞いたりしてもたぶんSQL を書けるようにはなりません 1/105
  3. 3. つまり 2/105
  4. 4. テキトーに聞 いといてくだ さい 3/105
  5. 5. MySQL触った ことある⼈︖ 4/105
  6. 6. MySQL で きる ⼈︖ 5/105
  7. 7. MySQL知 らない⼈︖ 6/105
  8. 8. MySQLより 年下の⼈︖ 7/105
  9. 9. MySQL 1.0は1995年 リリースらしい Past, Present and future of MySQL and variants Part 1: Ghosts of MySQL Past | Ramblings 8/105
  10. 10. こんな画⾯触ったことある⼈︖ 9/105
  11. 11. こういうやつの⽅が好きな⼈︖ 10/105
  12. 12. MySQL好 きな⼈︖ 11/105
  13. 13. 三度の飯より MySQLが好き な⼈︖ 12/105
  14. 14. MySQLやめる か煙草やめるか って⾔われたら 13/105
  15. 15. ⼈間やめ る⼈︖ 14/105
  16. 16. \こんにちは/ yoku0825の中の⼈@GMOメディア オラクれない- ポスグれない- マイエスキューエる- ⽣息域 Twitter: @yoku0825- Blog: ⽇々の覚書- MyNA ML: ⽇本MySQLユーザ会- MySQL Casual: Slack- 15/105
  17. 17. 普段やってること 障害対応 社内サポートデスク DBに特化した運⽤, 設計, ショット作業 教育, 啓蒙活動 技術研究 16/105
  18. 18. 障害対応 開発陣はDBサーバーにSSHログインできない AP起因でMySQLがぶん回ったりするものを含む HWの交換はお任せ、OSを再セットアップしてもらってから が出番 17/105
  19. 19. 社内サポートデスク 新しい開発環境のDBが欲しいんですけど APサーバーが追加されたからGRANTしてほしいんだけど クエリー遅いんですけど このサーバー撤去するんでDBどかして欲しいんですけど DBサーバー増やす︖ 減らす︖ 18/105
  20. 20. DBに特化した運⽤, 設計, ショット作業 DBレイヤーのグランドデザイン バックアップの記録, 保管- シャーディング- mikasafabric for MySQL + MySQL Router- 必要リソースの⾒積もり- MySQL, Percona Server, MariaDB, Mroonga, Spider, PXC, ..- バージョンアップ戦略の策定- 監視設計 Seconds̲Behind̲Master, Max̲connections, Show̲processlist, .. - PMP for Cacti- テーブルサイズ, 権限変更検知, パラメーター変更検知, ロック競合, ..- 19/105
  21. 21. DBに特化した運⽤, 設計, ショット作業 フツーの ALTER TABLE でないオンラインスキーマ変更 pt-osc- SET SESSION sql_log_bin= 0 からの ALTER TABLE .. ADD KEY .. ALGORITHM= INPLACE でRSU - スロークエリーチューニング 件数だけは毎⽇通知- 前⽇⽐でハネたら anemoeater でドリルダウン- メンテのついでにマイナーバージョンアップとかメジャーバ ージョンアップとか 20/105
  22. 22. 教育, 啓蒙活動 新⼊社員研修 社内勉強会 おもむろにPRやIssueに出現してマサカリを投げて去る 21/105
  23. 23. 技術研究 MySQL 8.0 エコシステム各種の検証 ⼿抜き監査ログクライアント mikasafabric for MySQL 何故かDocker全般 22/105
  24. 24. MySQL #とは 世界でもっとも普及している、オープン ソース データ ベース https://www.mysql.com/jp/ 23/105
  25. 25. MySQL #とは 永続化可能な サーバーまたいでアクセスできる 排他・共有ロック機能付きの グローバル変数のすごいやつ 異論は認める MySQLおじさんの逆襲 24/105
  26. 26. 置いとい て 25/105
  27. 27. 今⽇は基礎として SELECTステート メントの話(だけ) をします 26/105
  28. 28. 簡素化したSELECTステートメント SELECT column1, column2, .. FROM table1 WHERE column1 = '..' ORDER BY column2; 27/105
  29. 29. 肩慣らし 28/105
  30. 30. 肩慣らし 何のエラーが出る︖ SEECT -- Invalid Syntax nonexistent_column_in_select_list FROM nonexistent_table WHERE nonexistent_column_in_where_clause = '..' ORDER BY nonexistent_column_in_orderby_clause; 29/105
  31. 31. 答え MySQL error code 1064 (ER̲PARSE̲ERROR): %s near ʻ%-.80sʼ at line %d ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for th e right syntax to use near '..' 30/105
  32. 32. 肩慣らし 何のエラーが出る︖ SELECT nonexistent_column_in_select_list FROM nonexistent_table WHERE nonexistent_column_in_where_clause = '..' ORDER BY nonexistent_column_in_orderby_clause; 31/105
  33. 33. 答え MySQL error code 1146 (ER̲NO̲SUCH̲TABLE): Table ʻ%-.192s.%-.192sʼ doesnʼt exist ERROR 1146 (42S02): Table 'test.nonexistent_table' doesn't exist 32/105
  34. 34. 肩慣らし 何のエラーが出る︖ SELECT nonexistent_column_in_select_list FROM table1 WHERE nonexistent_column_in_where_clause = '..' ORDER BY nonexistent_column_in_orderby_clause; 33/105
  35. 35. 答え MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR): Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ ERROR 1054 (42S22): Unknown column 'nonexistent_column_in_select_ list' in 'field list' 34/105
  36. 36. 肩慣らし 何のエラーが出る︖ SELECT column1 FROM table1 WHERE nonexistent_column_in_where_clause = '..' ORDER BY nonexistent_column_in_orderby_clause; 35/105
  37. 37. 答え MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR): Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ ERROR 1054 (42S22): Unknown column 'nonexistent_column_in_where_c lause' in 'where clause' 36/105
  38. 38. 肩慣らし 何のエラーが出る︖ SELECT column1 FROM table1 WHERE column1 = '..' ORDER BY nonexistent_column_in_orderby_clause; 37/105
  39. 39. 答え MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR): Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ ERROR 1054 (42S22): Unknown column 'nonexistent_column_in_orderby _clause' in 'order clause' 38/105
  40. 40. ER̲BAD̲FIELD̲ERROR MySQL error code 1054 (ER̲BAD̲FIELD̲ERROR): Unknown column ʻ%-.192sʼ in ʻ%-.192sʼ ERROR 1054 (42S22): Unknown column 'nonexistent_column_in_select_ list' in 'field list' ERROR 1054 (42S22): Unknown column 'nonexistent_column_in_where_c lause' in 'where clause' ERROR 1054 (42S22): Unknown column 'nonexistent_column_in_orderby _clause' in 'order clause' 39/105
  41. 41. 取り敢えずわかること シンタックスエラーが⼀番強い パースできないとどれがオブジェクトでどれがキーワードかわからな い - FROM句だけ特別っぽい たぶん、対象オブジェクトを確定してアクセス権限のチェックしない といけないから - 他は頭から読んでる︖ SQLパーザーは先頭から再帰的に構⽂解析している- 40/105
  42. 42. シンプルな SELECTにも ⾊々ある 41/105
  43. 43. ストアドファンク ションとか使った 複雑なSELECTには もっと⾊々(ry 42/105
  44. 44. SELECTステートメント SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] https://dev.mysql.com/doc/refman/5.7/en/select.html 43/105
  45. 45. シンタックス このへんはフツーに使うだろうからやらない DISTINCT- STRAIGHT̲JOIN- LIMIT- INTO OUTFILE- [FOR UPDATE | LOCK IN SHARE MODE]- 44/105
  46. 46. シンタックス(1) select_expr select̲listとも- 雑に⾔うと「カラム名を列挙するとこ」- exprの名が⽰すように、式も記述できる- 最低1つ必要- 45/105
  47. 47. MySQLのbool評価式 真なら1, 偽なら0, UNKNOWNならNULLが返る mysql80 5> SELECT DAYOFWEEK('2017/06/23') = 6; +-----------------------------+ | DAYOFWEEK('2017/06/23') = 6 | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.03 sec) mysql80 5> SELECT DAYOFWEEK('2017/06/23') = 5; +-----------------------------+ | DAYOFWEEK('2017/06/23') = 5 | +-----------------------------+ | 0 | +-----------------------------+ 1 row in set (0.01 sec) 46/105
  48. 48. こんな結果セットがあった時に mysql80 5> WITH RECURSIVE june AS ( -> SELECT CAST('2017/06/01' AS DATE) AS dt -> UNION ALL -> SELECT DATE_ADD(dt, INTERVAL 1 DAY) AS dt FROM june WHER E dt < '2017/06/30') -> SELECT * FROM june; +------------+ | dt | +------------+ | 2017-06-01 | | 2017-06-02 | | 2017-06-03 | .. | 2017-06-28 | | 2017-06-29 | | 2017-06-30 | +------------+ 30 rows in set (0.00 sec) 47/105
  49. 49. こんな キモい こともできる 1または0だからSUMがきく mysql80 5> WITH RECURSIVE june AS ( -> SELECT CAST('2017/06/01' AS DATE) AS dt -> UNION ALL -> SELECT DATE_ADD(dt, INTERVAL 1 DAY) AS dt FROM june WHER E dt < '2017/06/30') -> SELECT SUM(WEEKDAY(dt) IN (5, 6)) AS not_working, SUM(WEEK DAY(dt) NOT IN (5, 6)) AS working FROM june; +-------------+---------+ | not_working | working | +-------------+---------+ | 8 | 22 | +-------------+---------+ 1 row in set (0.01 sec) 48/105
  50. 50. SELECTステートメント SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] 49/105
  51. 51. シンタックス(2) table_references テーブルじゃなくてテーブルリファレンス、なのが楽しいところ- JOINした結果やサブクエリーなど、割とあらゆるSELECTの出⼒結果 がそのままテーブルリファレンスになれる - 特別なキーワードとして FROM dual がある。FROM 句⾃体の省略もで きる - 50/105
  52. 52. こんな⼊れ⼦も mysql80 5> SELECT * FROM ( -> SELECT * FROM ( -> SELECT * FROM ( -> SELECT * FROM ( -> SELECT * FROM ( -> SELECT NOW() -> ) AS t1 -> ) AS t2 -> ) AS t3 -> ) AS t4 -> ) AS t5; +---------------------+ | NOW() | +---------------------+ | 2017-06-21 19:49:16 | +---------------------+ 1 row in set (0.00 sec) 51/105
  53. 53. SELECTステートメント SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] 52/105
  54. 54. シンタックス(3) where_condition WHEREとHAVINGで指定する- 真偽値(ところによりNULL)を返す式- 実は定数でもイケる- MySQLでは0が偽、0以外が真、NULLがUNKNOWN ただしFALSEは0のシノニム、TRUEは1のシノニム - WHERE 1 って書くと全ての⾏で真になる- 53/105
  55. 55. 知ってると⾯⽩い mysql80 5> SELECT * FROM t1; +-----+------+ | num | val | +-----+------+ | 1 | one | | 2 | two | +-----+------+ 2 rows in set (0.01 sec) mysql80 5> SELECT * FROM t1 WHERE num; +-----+------+ | num | val | +-----+------+ | 1 | one | <-- numは0じゃないので真 | 2 | two | <-- numは0じゃないので真 +-----+------+ 2 rows in set (0.00 sec) 54/105
  56. 56. 知ってると⾯⽩い mysql80 5> SELECT * FROM t1 WHERE num = TRUE; +-----+------+ | num | val | +-----+------+ | 1 | one | <-- TRUEは1だからnum = 1 +-----+------+ 1 row in set (0.00 sec) mysql80 24> SELECT * FROM t1 WHERE num IS TRUE; +-----+------+ | num | val | +-----+------+ | 1 | one | <-- 1 IS TRUE => 真 | 2 | two | <-- 2 IS TRUE => 真 +-----+------+ 2 rows in set (0.02 sec) 55/105
  57. 57. NULLに対する演算(1) NULL + 1 NULL - 1 NULL * 1 NULL / 1 CONCAT(NULL, 'ぽ', 'ガッ') 56/105
  58. 58. NULLに対する演算(1) mysql80 25> SELECT NULL + 1, NULL - 1, NULL * 1, NULL / 1, CONCAT (NULL, 'ぽ', 'ガッ')G *************************** 1. row *************************** NULL + 1: NULL NULL - 1: NULL NULL * 1: NULL NULL / 1: NULL CONCAT(NULL, 'ぽ', 'ガッ'): NULL 1 row in set (0.00 sec) 57/105
  59. 59. NULLに対する演算(2) NULL AND NULL NULL AND TRUE NULL AND FALSE NULL OR NULL NULL OR TRUE NULL OR FALSE 58/105
  60. 60. NULLに対する演算(2) mysql80 25> SELECT NULL AND NULL, NULL AND TRUE, NULL AND FALS E, NULL OR NULL, NULL OR TRUE, NULL OR FALSEG *************************** 1. row *************************** NULL AND NULL: NULL NULL AND TRUE: NULL NULL AND FALSE: 0 NULL OR NULL: NULL NULL OR TRUE: 1 NULL OR FALSE: NULL 1 row in set (0.00 sec) 59/105
  61. 61. NOT NULL推奨 ある整数Aは A = 1 または A <> 1- A == 1のテストとA == 0のテストを書けば境界値テストでカバーで きる - ある整数型のNULLABLEなカラムに格納された値Bは B = 1 または B <> 1 または B IS NULLである- B == 1のテストとB == 0とdefined(B) == falseの3つのテストを 書かないといけない - 60/105
  62. 62. テストケースの増⼤ WHERE句にカラムを並べたとして カラムの数 NOT NULL 境界値の数 1 o 2^1=2 2 o 2^2=4 3 o 2^3=8 1 x 3^1=3 2 x 3^2=9 3 x 3^3=27 61/105
  63. 63. NOT NULL推奨 62/105
  64. 64. (余談) NULLABLEは伝播する NULLに対する演算をしてもNULLが返らない演算をNULLセ ーフな演算と呼ぶ たとえば IS NULL 演算⼦はNULLセーフ演算⼦- NULLに対する非NULLセーフな演算の結果はNULL いくつかのカラムがNOT NULLであったとしても、それと NULLABLEなカラムの値を非NULLセーフな関数で演算して しまったらその結果はNULLABLE ひとつのNULLABLEなカラムと演算する可能性のあるカラム 全てに三値論理を適⽤する︖ 63/105
  65. 65. 閑話休題 64/105
  66. 66. SELECTステートメント SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] 65/105
  67. 67. シンタックス(4) col_name | expr | position GROUP BY や ORDER BY で指定するやつ- カラム名、評価式、select̲list内のオフセット(1オリジン)で指定で きる - ORDER BY RAND() なんてのは1⾏ごとに RAND() が⾛って、その結果 (0から1までのDOUBLE)でソートするからランダムな結果セットが 返る - ORDER BY NULL なんてキーワードもある- expr の⽰す通り、値を返す式でもイケる- 66/105
  68. 68. ⾶び道具っぽいORDER BY指定 mysql80 5> SELECT * FROM t1; +-----+-------+ | num | val | +-----+-------+ | 1 | one | | 2 | two | | 3 | three | | 4 | four | | 5 | five | +-----+-------+ 5 rows in set (0.00 sec) mysql80 5> SELECT num, val FROM t1 ORDER BY 2 DESC; -- select_listの2要素目=valのD ESCソート +-----+-------+ | num | val | +-----+-------+ | 2 | two | | 3 | three | | 1 | one | | 4 | four | | 5 | five | +-----+-------+ 5 rows in set (0.00 sec) 67/105
  69. 69. ⾶び道具ORDER BYその2 mysql80 23> SELECT * FROM t1 ORDER BY FIELD (num, 1, 4, 5, 3, 2); +-----+-------+ | num | val | +-----+-------+ | 1 | one | | 4 | four | | 5 | five | | 3 | three | | 2 | two | +-----+-------+ 5 rows in set (0.03 sec) mysql80 23> SELECT *, FIELD (num, 1, 4, 5, 3, 2) AS sort_expr FROM t1 ORDER BY FIEL D (num, 1, 4, 5, 3, 2); +-----+-------+-----------+ | num | val | sort_expr | +-----+-------+-----------+ | 1 | one | 1 | | 4 | four | 2 | | 5 | five | 3 | | 3 | three | 4 | | 2 | two | 5 | +-----+-------+-----------+ 5 rows in set (0.00 sec) 68/105
  70. 70. NULLABLEなカラムのソート mysql80 24> SELECT * FROM t1 ORDER BY num; +------+------+ | num | val | +------+------+ | NULL | NULL | | 1 | one | | 2 | two | +------+------+ 3 rows in set (0.00 sec) mysql80 24> SELECT * FROM t1 ORDER BY num DESC; +------+------+ | num | val | +------+------+ | 2 | two | | 1 | one | | NULL | NULL | +------+------+ 3 rows in set (0.00 sec) 69/105
  71. 71. SELECTステートメント SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] 70/105
  72. 72. クエリーキャッシュ関連 [SQL̲CACHE|SQL̲NO̲CACHE] クエリー単位でクエリーキャッシュの有効/無効を切り替え られる query̲cache̲type 指定なし SQL̲CACHE SQL̲NO̲CACHE 0(DISABLE) x x x 1(ENABLE) o o x 2(DEMAND) x o x 71/105
  73. 73. 笑えるコード 653 static bool has_no_cache_directive(const char *sql, uint offset, 654 size_t query_length) 655 { .. 671 if (my_toupper(system_charset_info, sql[i]) == 'S' && 672 my_toupper(system_charset_info, sql[i+1]) == 'Q' && 673 my_toupper(system_charset_info, sql[i+2]) == 'L' && 674 my_toupper(system_charset_info, sql[i+3]) == '_' && 675 my_toupper(system_charset_info, sql[i+4]) == 'N' && 676 my_toupper(system_charset_info, sql[i+5]) == 'O' && 677 my_toupper(system_charset_info, sql[i+6]) == '_' && 678 my_toupper(system_charset_info, sql[i+7]) == 'C' && 679 my_toupper(system_charset_info, sql[i+8]) == 'A' && 680 my_toupper(system_charset_info, sql[i+9]) == 'C' && 681 my_toupper(system_charset_info, sql[i+10]) == 'H' && 682 my_toupper(system_charset_info, sql[i+11]) == 'E' && 683 my_isspace(system_charset_info, sql[i+12])) 684 return true; mysql-5.7.18/sql/sql̲cache.cc 72/105
  74. 74. 過去の遺物 [HIGH̲PRIORITY] [SQL̲SMALL̲RESULT] [SQL̲BIG̲RESULT] [SQL̲BUFFER̲RESULT] [PROCEDURE analyse()] 73/105
  75. 75. 闇なやつ [SQL̲CALC̲FOUND̲ROWS] ORDER BY .. LIMIT .. のbreakを無効にする代わりに、 COUNT(*) も⼀緒に取得する 取得した COUNT(*) は SELECT FOUND_ROWS() でアクセス可能- 2回テーブルスキャンするよりは速いけど、 ORDER BY .. LIMIT .. の早抜けできなくなるので遅い 74/105
  76. 76. 闇なやつ mysql80 7397205> SELECT * FROM city ORDER BY population DESC LIMIT 10; .. 10 rows in set (0.01 sec) mysql80 7397205> SELECT FOUND_ROWS(); +--------------+ | FOUND_ROWS() | +--------------+ | 10 | +--------------+ 1 row in set (0.00 sec) mysql80 7397205> SELECT sql_calc_found_rows * FROM city ORDER BY population DESC LIMIT 10; .. 10 rows in set (0.00 sec) mysql80 7397205> SELECT FOUND_ROWS(); +--------------+ | FOUND_ROWS() | +--------------+ | 4079 | +--------------+ 1 row in set (0.00 sec) 75/105
  77. 77. 5.6とそれ以降ではパーティションがテーブルリファレン スに指定できる FROM t1 PARTITION (p1, p2) 特定のパーティションだけをあたかもテーブルのようにアク セスできる 上⼿く使うとWHERE句をいっこかっ⾶ばせたり、不要なパ ーティションへのアクセスをさせないように指定できる(実 際に1つのパーティションアクセスだけで完結するクエリー でも、オプティマイザーがそれを確定できない場合は全パー ティションアクセスになる、など) 76/105
  78. 78. パーティション指定アクセス mysql80 22> SHOW CREATE TABLE t2G *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `dt` date NOT NULL, `val` varchar(32) COLLATE utf8mb4_ja_0900_as_cs DEFAULT NULL, PRIMARY KEY (`dt`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_ja_0900_as_cs /*!50100 PARTITION BY LIST (month(dt) mod 2) (PARTITION p_odd VALUES IN (1) ENGINE = InnoDB, PARTITION p_even VALUES IN (0) ENGINE = InnoDB) */ 1 row in set (0.00 sec) $ ll /usr/mysql/8.0.1/data/d1/t2* -rw-r----- 1 yoku0825 yoku0825 131072 Jun 22 11:39 /usr/mysql/8.0.1/dat a/d1/t2#P#p_even.ibd -rw-r----- 1 yoku0825 yoku0825 131072 Jun 22 11:39 /usr/mysql/8.0.1/dat a/d1/t2#P#p_odd.ibd 77/105
  79. 79. パーティション指定アクセス mysql80 22> EXPLAIN SELECT * FROM t2 WHERE dt BETWEEN '2017/06/01' AND '2017/06/30'; +----+-------------+-------+--------------+-------+---------------+---------+---------+------+------+----------+--------- ----+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extr a | +----+-------------+-------+--------------+-------+---------------+---------+---------+------+------+----------+--------- ----+ | 1 | SIMPLE | t2 | p_odd,p_even | range | PRIMARY | PRIMARY | 3 | NULL | 5 | 100.00 | Using wh ere | +----+-------------+-------+--------------+-------+---------------+---------+---------+------+------+----------+--------- ----+ 1 row in set, 1 warning (0.04 sec) mysql80 22> EXPLAIN SELECT * FROM t2 PARTITION (p_even) WHERE dt BETWEEN '2017/06/01' AND '2017/06/30'; +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------- --+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extr a | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------- --+ | 1 | SIMPLE | t2 | p_even | range | PRIMARY | PRIMARY | 3 | NULL | 5 | 100.00 | Using wher e | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------- --+ 1 row in set, 1 warning (0.00 sec) 78/105
  80. 80. SELECT処理のイメージ イメージなのでちょくちょく 嘘 79/105
  81. 81. SELECT処理のイメージ(1) まず結果セットのベースになるFROM句の要素全体に注目 ただし相関サブクエリー以外のサブクエリーはこれに先⽴って解決される- Whole Table 80/105
  82. 82. SELECT処理のイメージ(2) WHERE句に従ってフィルタリング Whole Table Filtered Set 81/105
  83. 83. SELECT処理のイメージ(3) ソートしたり集約したり Whole Table Filtered Set Sorted Set 82/105
  84. 84. SELECT処理のイメージ(4) 結果セットに必要な列だけをバッファに詰めてできあがり Whole Table Filtered Set Sorted Set 83/105
  85. 85. GROUP BY, HAVING, ORDER BY, LIMIT WHEREで件数を絞り込んだあとに GROUP BYで集約した後に HAVINGでフィルターして ORDER BYで並べ替えてから LIMITで指定した⾏数だけ返す 84/105
  86. 86. もうちょっ と細かく︖ 85/105
  87. 87. よく使う図 InnoDB API Handler API Executor Optimizer Parser MySQL Protocol HS Protocol HS Plugin memcached Protocol InnoDB Memcached HTTP/MySQL X 86/105
  88. 88. クエリーのライフサイクル Connection Handling Parser Optimizer Executor Handler Storage Engine 87/105
  89. 89. Connection Handling ソケット, ポートからの接続を待ち受ける 接続があったらclone(またはスレッドキャッシュから取り 出してディスパッチ) ⼀次認証 88/105
  90. 90. Parser MySQLプロトコルのパース SQL構⽂のパース ⼆次認証(データベース, テーブル単位のアクセス権限チ ェック) クエリーキャッシュ処理 ジェネラルログ 89/105
  91. 91. Optimizer 統計情報の取得(Storage Engine APIを叩いてるっぽい) クエリーの書き換えを含めた実⾏計画の決定 90/105
  92. 92. Executor オプティマイザーから渡された実⾏計画の通りにHandlerを 叩く Handlerから戻ってきた結果を使って実⾏計画の残りを実⾏ Using where; Using filesort; Using temporary; はコイツが頑張っ てる証拠 - スローログ, バイナリーログ 91/105
  93. 93. Handler ストレージエンジンの抽象化レイヤー あんまり意識することはない 92/105
  94. 94. Storage Engine 実際にデータを格納するレイヤー プラガブルアーキテクチャーなので、ほとんどの機能はこの レイヤーで実装されている ストレージエンジンごとにトランザクション対応が違うとか- ストレージエンジンごとにロック粒度が違うとか- ストレージエンジンごとにバッファが違うとか- 93/105
  95. 95. え︖ もっ と細かく︖ 94/105
  96. 96. SELECTステートメントの⼀⽣(1) 3306ポートへのアクセスがmysqld̲mainによって捕捉さ れ、⼦スレッドが割り当てられる handle̲connectionからdo̲commandを経て dispatch̲commandへ、ここでユーザー認証 dispatch̲commandでMySQLプロトコルをパースし、 COM̲QUERYパケットとしてSQLパーサーにかけられる mysql̲parseを通ってparse̲sqlからMYSQLparseを呼ぶ MYSQLparseの中でthd->lexに⾊々⼊る mysql̲parseまで戻ってここでジェネラルログ出⼒ Max Query per Hourの判定が⼊って パスワードがEXPIREされてないかの判定が⼊って やっとmysql̲execute̲commandに⾶ぶ 95/105
  97. 97. SELECTステートメントの⼀⽣(2) read̲onlyオプションの判定が⼊ったりしたあと lex->sql̲commandで振り分け処理がされつつ select̲precheckが呼ばれてアカウントの権限が評価され execute̲sqlcom̲selectにわたり、 MAX̲EXECUTION̲TIMEのタイマーがセットされて open̲tables̲for̲queryでテーブルキャッシュを開き sql̲select.ccのhandle̲queryに⾏ってオブジェクト名の評 価がされ query̲cache.store̲queryを呼び SELECT̲LEX::optimizeからのJOIN::optimize呼び出し、 ここからがオプティマイザー 96/105
  98. 98. SELECTステートメントの⼀⽣(3) 可能であればOUTER JOIN ⇒ INNER JOINの書き換えとか 結合条件をWHERE句に移動する処理とか SEMIJOINならここでビットマップインデックスを作る sql̲mode=ONLY̲FULL̲GROUP̲BYの場合の評価はここ パーティションプルーニングが効く場合はここでプルーニン グ アクセスプランを評価・確定させて JOIN::execからdo̲selectに渡って最終的にhandlerから ha̲innobaseクラスにわたる 97/105
  99. 99. SELECTステートメントの⼀⽣(4) ⾏のフェッチが終わったらソートしたりフィルタリングした り⾊々してから close̲thread̲tablesでテンポラリーテーブル消したり close̲thread̲tableでテーブル閉じてテーブルキャッシュ に⼊れて mdl̲context.release̲transactional̲locksでメタデータロ ックを解放して 使ったオブジェクトを⾊々freeして Query̲result̲send::send̲dataで結果セットを返す 98/105
  100. 100. 諸元 SQLパーサー sql/sql̲yacc.yy, sql/sql̲yacc.cc エグゼキューター sql/sql̲executor.cc, sql/sql̲select.cc 汎⽤ユーティリティー sql/sql̲class.cc InnoDBストレージエンジン storage/innobase/ 99/105
  101. 101. え、まだまだ ⾜りない︖ 100/105
  102. 102. ↑やら↑ 101/105
  103. 103. ↓ない↓ 102/105
  104. 104. まとめ︖ 普段何気なく使っているMySQLもアプリケーション ⾊んな内部実装があって、得意なことがあったり苦⼿なこと があったり それをユーザーに意識させないためにSQLというレイヤーが あるので それより下を勉強するのはなかなか⼤変 世界は広くて、そういう世界で戦っているエンジニアもいる にはいる 103/105
  105. 105. まとめ︖ 困った時はいつでもどうぞ MyNA ML: ⽇本MySQLユーザ会- MySQL Casual: Slack- おじさんズ welcome you! 104/105
  106. 106. Questions and/or Suggestions? 105/105

×