クエリキャッシュは切ったほうがいいんじゃなイカ?
KLab Advent Calendar 2011 「DSAS for Social を支える技術」の2日目は、昨日に引き続き、MySQLを骨までしゃぶるためのテクニックです。
ソーシャルゲームは一般サイトよりもDBへの更新クエリの割合が多くなりがちです。更新クエリが多いMySQLでは、通常は有益なクエリキャッシュが無益どころか有害になります。
- そもそもキャッシュヒット率が低い。20%以下なんてこともザラにある
- しかもクエリキャッシュの更新はグローバルなロックを取得する
からです。特に後者は問題です。ただの参照クエリもクエリキャッシュを更新する上に、更新クエリはクエリキャッシュの全エントリをチェックして、更新したテーブルに影響がありそうな全キャッシュをdiscardしていくためです。たとえばユーザーの行動力のようなパラメータを格納した参照も更新も多いテーブルでクエリキャッシュが有効になっていると、せっかくたくさんコアを載せた高性能サーバーでも全然パフォーマンスが出なくなります。
クエリキャッシュが有効になっている実行中のMySQLでも、次の操作でオンラインでクエリキャッシュを切ることができます。(どちらか片方だけでも有効)
MySQL> SET @@global.query_cache_type=0; MySQL> SET @@global.query_cache_size=0;
残念ながらこの設定をした当時のグラフは用意できてないのですが、過去に高負荷時にDBの応答性能に問題を抱えていたゲームでは「DBの接続数がめちゃくちゃ減った!」「平均応答時間が5ms減った!」「平均睡眠時間が1時間増えた!」などの喜びの声が聞こえてきた記憶があります。(一部誇張があります)
念のため、クエリキャッシュを切るデメリットについても触れておきます。参照系クエリのパフォーマンスですが、PK参照やインデックスによるシンプルな参照では、バッファプールが足りている状況ではInnoDBは十分に高性能なので、問題になりません。複数のNICを束ねて利用しない限り、先にネットワーク周りがボトルネックになるはずです。
問題になり得るのは重い参照クエリです。バッチなどでしか更新が無いテーブルに対して重い参照クエリを投げる場合、クエリが重くてもクエリキャッシュが効いているので高負荷になっていない可能性があります。この場合、クエリキャッシュを切る前にMemcachedなど外部のキャッシュを使うようにしておかなければなりません。
もし、どうしてもクエリキャッシュを切るのが難しい場合は、更新が多いテーブルに対するSELECTクエリに "SQL_NO_CACHE" を付けるという手段もあります。詳細は MySQL のマニュアルを参照してください。