Query Cache
その昔、Sun Microsystems の公式サイトに「OLTP技術資料」というコーナーがあった。Oracle と Sun のサーバーを組み合わせた構成での、チューニングポイントと性能特性が事細かに書かれていた。個人では到底買えない、数千万円クラスのエンタープライズ機を、これでもかと贅沢に使う前提の話が延々と続いていた。
エンジニアになりたてだったわたしは、毎日それを熟読していた。手元にあるのはせいぜい中古の PC サーバーで、書いてある世界とはまるで縁がなかったのに、なぜか読み続けた。インターネットがまだ「繋ぐもの」だった時代の話だ。
そこで覚えたのが、OLTP の RDBMS では、キャッシュ機構のチューニングが性能を決めるということだった。Oracle で言えば SGA の中のバッファキャッシュ、INIT.ORA に書く DB_BLOCK_BUFFERS の値。ブロックサイズとバッファ数を細かく刻んで、ヒット率を 1% 上げる議論が並んでいた。そういう世界の話だ。キャッシュは速さの源泉だと、そのときに刷り込まれた。
だから、MySQL のクエリキャッシュにも夢を見ていた。
クエリキャッシュとは、同じ SELECT 文が来たら前回の結果をそのまま返す仕組みだ。完全一致ならパースも実行もスキップして、結果セットをキャッシュから返す。速い。ただし、対象テーブルに1行でも INSERT が走ると、そのテーブルに紐づくキャッシュは全部吹き飛ぶ。書き込みが多いサービスでは、キャッシュが温まる前に消える。意味がないどころか、管理コストだけが残る。
小規模なサービスではよく効いた。参照がほとんどで、書き込みが少なく、同じページを何度も見に来る。条件が揃うと劇的に効いた。my.cnf に query_cache_size を一行書くだけで、レスポンスタイムが目に見えて速くなった。新人にチューニングを教えるときの最初の一歩、みたいな時期もあった。
問題はスケールだった。マルチコアの時代になっても、クエリキャッシュはグローバルな mutex で守られていた。コアが増えるほどロック競合が支配的になる。キャッシュからヒットしている間も、他のスレッドが待つ。速くするための仕組みが、速さの足を引っ張る。
MySQL 5.6 のあたりから query_cache_type=0 が事実上のベストプラクティスになり、公式ドキュメントも無効化を推奨するようになった。8.0 で機能ごと削除されたときは、もう死んでいたものを片付けただけ、という感覚だった。
いまは、キャッシュはアプリケーション層に置く。Redis、Memcached。キー単位で無効化できる分、責任は自分が持つ。
my.cnf の一行でレスポンスが速くなった時代が懐かしい。いや、あれは幻想だった。