MySQLでクエリ結果をキャッシュする

以前Alternative PHP Cacheを導入してPHPの高速化を行いましたが、今回はMySQLサーバの高速化を試みたいと思います。

方法は今回もキャッシュです。
PHPのときみたいに特別なプログラムを導入するのではなく、MySQLサーバのキャッシュ機能を利用して高速化を図ります。


まず、コンソールからMySQLの任意のデータベースにログインし、

$ mysql mydb -p
mysql> SHOW VARIABLES LIKE 'query_cache_%';

と入力します。
見て分かる通り、MySQLに設定された変数一覧の中から、QueryCacheに関するものだけを表示しろという命令ですね。

すると、

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 0        |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
5 rows in set (0.02 sec)

初期設定のままの場合、このように表示されると思います。
この中の query_cache_type の行を見ると、クエリのキャッシュ機能はオンになっていますが、 query_cache_size の行を見ると、クエリのキャッシュサイズとして設定されてる値がゼロ。つまりキャッシュが有効化されていないということが分かります。

そこで、 /etc/my.cnf を編集し、キャッシュサイズを設定します。
このファイルを開くと [mysqld] と書かれた部分があると思うので、その下に下記の設定を追加します。キャッシュサイズはとりあえず24MBとでもしておきましょう。

[mysqld]
query_cache_limit=1M
query_cache_min_res_unit=4k
query_cache_size=24M
query_cache_type=1

既に設定がされている場合は、その値を変更または確認します。

設定できたら、MySQLサーバを再起動し、再びコンソールからログインします。

$ sudo service mysqld restart
$ mysql mydb -p

そして、先ほどと同じコマンドで設定を確認すると、今設定した値が反映されているのがわかります。

mysql> SHOW VARIABLES LIKE 'query_cache_%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 25165824 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
5 rows in set (0.00 sec)

そしたら、MySQLを利用しているブログなどを開いてみて、効果を実感してみましょう。
……と思ったのですが、このブログではほとんど効果は見られませんでした(汗)。MySQLはもともとボトルネックにはなっていなかったようです。

実際にキャッシュがどのように効いているかは、下のようにして確認します。

mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 644      | 空きメモリブロック数
| Qcache_free_memory      | 22102056 | 空きメモリのサイズ(バイト)
| Qcache_hits             | 281611   | キャッシュにヒットしたクエリの数
| Qcache_inserts          | 24859    | キャッシュに保存したクエリの数
| Qcache_lowmem_prunes    | 6466     | メモリが足りないために削除されたクエリの数
| Qcache_not_cached       | 99       | キャッシュされなかったクエリの数
| Qcache_queries_in_cache | 2799     | キャッシュに存在するクエリの数
| Qcache_total_blocks     | 6263     | 合計ブロック数
+-------------------------+----------+
8 rows in set (0.00 sec)

各行の説明は右に緑字で書いた通りです。
これを見ると、「メモリが足りないために削除されたクエリの数」が多いので、もっとキャッシュ容量を増やした方がいいということが分かりますね。

また、「空きメモリブロックの数」が多ければ多いほど、フラグメント化が進んでいますので、以下のようにしてキャッシュをデフラグする必要があるそうです。

mysql> FLUSH QUERY CACHE;

FLUSH QUERY CACHE文を実行するには、RELOAD権限が必要です。

ERROR 1227 (42000): Access denied; you need the RELOAD privilege for this operation

と表示された場合は、rootでログインしてから、GRANT文を使ってユーザーにRELOAD権限を与えて下さい。

以上、MySQLのクエリ結果のキャッシュを使った高速化でした。
この他にもクエリの見直しなど、高速化の方法はいくつかありますが、Nucleusのような既製品でクエリを変えるのが難しく、また書き込みより読み込みが圧倒的に多い場合には、この方法が一番有効なんじゃないかと思います。

コメントを残す