ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

「詳解MySQL5.7 〜止まらぬ進化に乗り遅れないためのテクニカルガイド」を読んだ

はじめに

読んだ。

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

表紙に「どれだけ詳しいの!?」ある通り、かなり詳しい。私はMySQL5.7を使っているわけではなく、普段はMariaDBの5.5/10系を使っている。ただ、MariaDBを学ぶためにも、ベースとなるMySQLを学ぶのが先(だし情報も多い)と思ったので本書を購入した。

実際、本書の主眼であるMySQL 5.7の175の新機能はほとんど読み飛ばしている。しかし、これら新機能は内容でカテゴライズされており、さらに各章では新機能の単体説明に入る前に概要説明があり、これが非常に詳しい。この部分を読むだけでも非常に価値がある本である。

それでは振り返っていこう。

1章 MySQLの概要

その名前の通りMySQLの概要。無料のコミュニティ版と商用版の違いなど。

MySQLサーバアーキテクチャが図になってるのは助かりますね。

様々なアプリケーションクライアントが、mysqldプロセス内部のコネクションスレッドに接続し、SQLの解析と最適化(パーサ、オプティマイザ、エクゼキュータ、バイナリログ、レプリケーション、アクセス管理)を行う共通部分があり、そこからストレージエンジンAPIを通じて各ストレージエンジンにアクセスし、実際にデータが保存される。

バージョンごとの歴史の変遷も記載されているので、MySQLの歴史を紐解きたいひとにはいいだろう。

ある意味、この章でMySQLはここ数年でとてつもない進化を遂げてきたことがわかる。5.7に対してここまで詳細な説明が書かれているのは本書しかないだろう。

著者の奥野さんが、DB関連で検索するとよくひっかかる「漢(オトコ)のコンピュータ道」を書いているが、そこでは5.8、、ならぬ8.0に対しても本書のようなものを書くかというと、書かないと言っていた。ちなみに8.0の新機能詳解の記事はこちら。

nippondanji.blogspot.jp

2章 レプリケーション

レプリケーションがもっとも変更点が多く、インパクトが多いそうで2章にきている。

ここで学べるのはMySQLレプリケーションの基本原則だ。レプリケーションの構造概要(図2.1)が非常にわかりやすい。

クライアントが接続するコネクションスレッドは、ストレージエンジンに対してPREPAREした後、バイナリログに書き込む。バイナリログに書き込んだあとはマスターのストレージにコミットする。

そのあと、マスタースレッドはスレーブI/Oスレッドに対してバイナリログを送信し、スレーブ側のスレーブI/Oスレッド

コミットあと、マスタースレッドはスレーブI/Oスレッドにバイナリログを送信し、リレーログに記録。(マスターのバイナリログに値する存在かな?) そしてスレーブSQLスレッドがそれをストレージエンジンに書き込む。ちょっとマスターとスレーブのスレッドの名前があまり対称的でないからわかりづらい。

これは「同期」「準同期」「非同期」でいうと準同期レプリケーションだ。先日紹介した本でもあった。プラグインをいれれば準同期をサポートできるようで、それも本書に記載されています。

gihyo.jp

take-she12.hatenablog.com

また、master/slaveでどちらが先のデータまで受信できているかを識別するGTID(Global Transaction ID)の紹介もある。各トランザクションにIDをふっている。

3章 オプティマイザ

実行されたSQLに対して、そのSQL構文を解析し、実際にどのようにデータを取得、解析し求める答えを出すか、その"最適な答え"を出すのがオプティマイザだ。

その用途で使われるEXPLAIN、実際に使ったことがないので本章は流したが、なぜか遅いクエリがある場合には重宝するだろう。

今の仕事では、アプリそのものを作ってるわけではないので、クエリを変えるわけにはいかない。代わりに、同じクエリで結果がよくなるのであればオプティマイザのチューニングも価値があるだろうが、ちょっとまだ手が出せないですね。

4 InnoDB

待ってましたの章!「RDBMSをアスリートに例えると、オプティマイザが身体を動かす頭脳に相当するものだろう。では実際に身体を動かす筋肉に相当するものは何かというと、ストレージエンジンだ。」と冒頭で語られる通り、MySQL(MariaDB)の活用に関してInnoDBの理解は避けて通れない。この章はかなり重要であり、詳しく書かれているので本当に重宝する。

ここでInnoDBへどのように書き込みが行われるか整理しよう。

クライアントからのリクエストがあると、まず「データベースキャッシュ」であるバッファプールに書き込みが走る。これはinnodbで最重要と言われるinnodb_buffer_pool_sizeが示す領域である。

このあと、ログバッファへ書き込む。いずれも、メモリ上の領域である。このあと、いよいよストレージに書き込むため、ログバッファから「ステーブルログ」であるログファイルに書き込む。これは実際にはiblogfileのことだ。ここまで書き込んでようやくコミットし、クライアントに応答を返す。(トランザクション

ちなみに、ログバッファからログへの書き込みタイミングは(MariaDBのドキュメントを参照するが)innodb_flush_log_at_trx_commitによって、挙動が変わる。

mariadb.com

もちろん、各トランザクションごとに、毎回、ログバッファに書き込んだらログに書き込むのがACID特性を守るために必要であり、もっとも重要である。ただ、性能を考慮して、1秒に1度書き込む0、毎回書き込むんだけどその書き込みが非同期な2、あとよくわかってないがgroup commitを模した3があるようだ。

さて、ログに書き込んだ時点では「ステーブルデータベース」であるテーブルスペース(実際にはibdata1、あるいは.ibd)に書き込まれていない。これをダーティページと呼ぶが、適宜書き込まれていく。テーブルスペースに書き込まれたログは不要である。

さて、ここで分離レベルについてもおさらいしておこう。

分離レベル

以下を思い切り参照するが、データベースを読み込むとき、「Dirty Reads」「Non-Repeatable Reads」「Phantom Reads」の3種類の事象が存在する。

分離レベル

Dirty Readsは、コミット前にログに書き込む最中に別のクライアントがアクセスした場合、実際のデータではなくバッファから読み込む。このとき、1つめのアクセスがロールバックした場合は偽の値を得ることになる事象のこと。

Non-Repeatable Readsは、1度読み込んだあと、別のクライアントによって変更または削除によって、求める値が取得できなくなる事象のこと。

Phantom Readsは逆に、1度読み込んだあと、結果は得られなかったが、別のクライアントの挿入によって突如として値が得られる事象のこと、

と理解しました。いずれにしても、このような現象はトランザクションでは起こってほしくないので、これをどれだけ防げるか、を示したレベルが分離レベルです。以下から、下に行くほど強固になります。

READ-UNCOMMITTED

変更時にテーブルのロックをするが、読み込みにロックがかからないので、結果変更しなかった場合にDirty Readsが起きるし、変更してしまえばNon-Repeatable ReadsやPhantom Readsが起きる。

READ-COMMITTED

読み取りと変更にロックがかかる。読み取り後はロック解除される。変更はトランザクション終わるまでロックされる。Dirty Readsは発生しない。しかし、変更される場合、Non-Repeatable ReadsとPhantom Readsは起こりうる。

REPEATABLE-READ

トランザクションの終わりまで読み書きにロックがかかるので、Non-Repeatableロックも発生しない。しかし変更不可能なアクセス構造(インデックスやハッシュ構造)は読み取り後に解除されるので、Phantom Readsは起きる。

SERIALIZABLE

トランザクションが終わるまですべての処理にロックがかかる。

うーん、ちょっとイマイチまだ理解しきれてませんが、分離レベルがあがるほど、同時実行性能は下がってしまうということですね。

REDOログ = ログ

まず、REDOログへ書き込まれる前に、バッファプールに乗った変更はログバッファに乗る。ログバッファではトランザクションよりもっと小さい、MTR(Mini Transaction)という単位で書き込まれる。そうして積みかさなったログバッファから、COMMITなどのタイミングでこのREDOログに書き込まれる。

REDOの名称は、クラッシュし、REDOログには記録があるが、ストレージスペースに記録がない場合のクラッシュリカバリをする際、「再書き込み」をREDOログから行うからだろうか?

ダブルライトバッファ

ログとテーブルスペースの時点でダブルライトじゃないかーと思ったんですが、それとは別に、データファイルの書き込みレベルで2回行うようです。"データファイルの連続した2MBの領域にデータを書き、その次に実際のデータページを書き込む"とあります。これによって"オールオアナッシング"を実現できます。堅牢ですね。

imai-factory.hatenablog.com

MVCC

分離レベル"Non-Repeatable Reads"を実現するための仕組みにMVCC(Multi Version Conccurency Control)がある。

一貫性の制御のために、テーブルにバージョンという概念をいれ、例えばロックをかけて変更する場合、そのトランザクション中は変更前の値(バージョン)を他の読み取りに対して見せる仕組み。readにロックをかけることなく、writeを行ってる間の一貫性維持が実現できる。

過去の行は完全なコピーとして"UNDOログ"という領域に保存され、ここを見せている。そしてトランザクションロールバック時はこのUNDOログを次々とたどって復元するわけだ。

パージ処理

増え続けるUNDOログをいつ消去するのか。トランザクションがコミットさえされれば使うことはないので削除可能である。コミットごとに削除するのではなく、パージスレッドという専用のスレッドが順次巡回して削除するようである。

5章 パフォーマススキーマとsysスキーマ

パフォーマンススキーマ

性能情報を1つのデータベースとして記憶するパフォーマンススキーマ。使いこなせるといいなと思ってますが、いまいちよくわかっていません。

パフォーマンススキーマそのものの有効/無効化、そして計器(計測項目)ごとのON/OFFもあるようだ。

とはいえ、合計(実質)78個もあるパフォーマンススキーマ、どう活用していいか正直わからない。

本当にこの機能を活用しないといけないときにまた見直したい。

sysスキーマ

「パフォーマンスキーマは、極めて豊富なデータを取得できるので、エキスパートにとっては便利なツールであるが、初心者や中級者にはややとっつきにくい面もある」そうそう!

100個のビューと47個のストアドプログラムがあるとのこと。多い。。。

  • user_summaryビュー
    • アプリにアクセスするユーザが異なる場合、どのユーザが一番処理を食ってるのかがわかりそう
  • innodb_lock_waitsビュー
    • lockによる待ちが多発してる場合に役立ちそう

ビューがどうやって見れるのかわかってないが。。。

6章 JSONデータ型

この章は今は興味がないのでスルーしました。NoSQLでJSONがサポートされている昨今で、RDBMSでの対抗手段なんでしょうかね。

実際、OpenStackを含むREST APIをサポートするWebアプリケーションは、bodyに含まれるJSONをそのままDBに保存できれば楽なような気も、直感的にはします。

7章 パーティション

この章も概要だけ抑えて流し読みです。データアクセス高速化を目的に、テーブルを一定の法則で分割します。

8章 セキュリティ

ユーザを含む権限テーブルの話。またはプロキシユーザや暗号化について。この章も流し読みです。

9章 クライアント&プロトコル

クライアントとして、各言語のライブラリの紹介は有益ですね。あとはmysqldumpやmysqladimnなどのプログラムもクライアントの一種として紹介されていました。

ちなみに各バージョンごとのmysql_upgradeの挙動が知りたい。。。すなわちバージョン間差異だろうからなぁ。

10章 その他の新機能

そもそも新機能よりは概要説明だけさらうような読み方をしてるのでこの章も流し読みで終わりました。

おわりに

MySQLを以前のバージョンから5.7にupgradeし、運用するひとには必携の本であり、もちろんMySQL(あるいは私のようにMariaDB)初学者でも、各章の前半をおさえることでMySQLの全体像がつかめ、次のステップに進めることのできる良書です。