2015年も残すところあとわずかですね。
年末年始の時期は暇になるので、みんなでMySQLと戯れましょう!
・・・というわけで、今回はMySQLの処理の流れについて書いてみました。
※MySQLの処理、といっても、今回の記事はRDBMSであれば共通のところが多いです。
ちなみに、正直、今回書いたような仕組みを知らなくても、MySQLを使うことはできます。
しかし、MySQLで高パフォーマンスを得たいと思った時、これらを知らないと、
ただメモリを積む!
などのおおざっぱな対応しかできません。
先に書いてしまいますが、今回の記事がパフォーマンスチューニングに直結しているか、
というと、答えは残念ながらNOです。
ですが、MySQLの処理の流れを知らずにパフォーマンスチューニングを行うことはできません。
パフォーマンスチューニングを始めるための前提条件、くらいに思って下さい。
仕組みを知る、というだけでも、自分の使っている道具を把握するという意味で重要ですし、
知っているからこそできるパフォーマンスチューニング、
そのパフォーマンスチューニングによって得られる、
リソースを使い倒す高パフォーマンスなシステム、
というのはなんかかっこいいよね、、、
というわけで、早速行ってみましょう!
MySQLに投げられたクエリがどのように処理されていくのか、
その大まかな流れを図にしてみました。
図 MySQLのクエリ処理の流れ
- スレッド
MySQLではプロセスはただ1つ、mysqldのみが存在します。
例えばOracleでは、リスナーに対して接続要求がくるとリスナーがサーバープロセスを生成しますが、
MySQLではいくら接続要求が来ようが、プロセスを新たに生成したりはせず、
代わりにmysqldプロセス内部で接続を受け付けるスレッドを生成します。
このスレッドを介して、MySQLとクライアントが通信を行い、
通信が完了し次第、スレッドは消滅します。
しかしながら、接続の開始・終了のたびにスレッドを生成・消滅するのでは効率が悪いので、
MySQLではスレッドキャッシュといって、
一度生成したスレッドをしばらく消滅させずに残しておいて、
次の接続に再利用する、という方法が採用されています。
関連サーバ変数:thread_cache_size
- クエリキャッシュ
MySQLにはクエリキャッシュ機能があります。
クエリキャッシュとは、
「全く同じ」SQLがデータベースに投げられた場合、その結果も同じであることを利用し、
結果を覚えておいて構文解析以下の過程をすっ飛ばして結果を返す、
という目的のため、
SQLと結果のセットを記憶しておくキャッシュのことです。
ハマった時には大いに役立つわけですが、
クエリ実行の度に結果が変わるようなクエリ(now()など)についてはそもそもキャッシュしないので利用できません。
また、更新の多いシステムにおいてはクエリキャッシュでのデータの出入りがオーバーヘッドとなり、
逆に性能低下を招くこともあります。
5.7.9(5.7最初のGA)ではONになっていますが、利用はシステムの特性を考えて慎重に行った方が良いでしょう。
※2015/12/30 追記
確認したところ、5.7.9ではクエリキャッシュはOFFになっていました。
(have_query_cacheはONですが、query_cache_typeでOFFとなっているので、クエリキャッシュは行いません)
大変失礼いたしました。
関連サーバ変数:have_query_cache、query_cache_size
- 構文解析(パーサ)
MySQLサーバに届いたクエリは、まずパーサにより構文解析が行われます。
MySQLに限ったことではありませんが、
パーサでは文法の誤りがないか、アクセス対象のテーブルが存在するか、
などをチェックした上で、人間が読めるSQL文(select * from …など)からコンピュータが読む命令(001101011…など)に変換します。
- オプティマイザ
これもMySQLに限ったことではありませんが、
パーサで解析されたSQLは、必ずしも効率的なデータアクセスができないため、
オプティマイザによって実行計画が立てられ、短時間でクエリが実行できるように最適化されます。
たとえば、INNER JOINをする時にどちらを駆動表にした方が良いか、
とか、
アクセスするカラムにはインデックスがついているからこれを使おう、
とか、
インデックスがついているといってもアクセスすべきエントリが多すぎるからテーブルフルスキャンにしよう、
とか、そういう話です。
最適化は、RDBMSが持っているデータの統計に基づいて行われます。
「最」適化といっても、本当に最も適切な実行計画を検討しているのでは
時間がかかってしょうがないので、
まあまあいい実行計画を求めよう、というのがオプティマイザのスタンスです。
ここで実行計画が決まれば、データをselectするなりinsertするなりの準備完了です。
- ストレージエンジン
ストレージエンジンはトランザクションをどう処理するか、実データをどのように格納するか、
などを司るものです。
ストレージエンジンでデータの参照・更新などの処理が行われます。
ストレージエンジンにはいくつかの種類があり、テーブルごとにどのストレージエンジンを利用するか選択できます。
このストレージエンジンはプラグインであり、
独自のプラグインを作って実装することも可能です(もちろん並大抵のことではないですが)。
よく利用されるストレージエンジンはInnoDBであり、5.6(5.5も?)以降のデフォルトストレージエンジンとなっています。
他には、MyISAM、ARCHIVE、MEMORYなどがあり、
MySQLのシステムデータベース(スキーマ)であるmysqlデータベースのテーブルはMyISAMが利用されています。
・・・と、ざっくりとしたMySQLの処理の流れは以上になります。
書いておいてなんですが、やはりこれを知っているだけでは、
残念ながらパフォーマンスチューニングをするのは難しい、
と言わざるを得ません。
高速な処理を実現するためにMySQLが行っている工夫については、
また次以降の記事に書くつもりですので、是非そちらも読んでみてください。
※2015/12/31 追記
書きました。是非こちらもご一読下さい。
UCO-Tech(MySQL高速処理のための仕組み)
では。