クエリキャッシュの効果

なんかやけにこのネタを引っぱっている気もするが、データが採れたので恐らくこれで最後。
MySQLに対して、sysbenchで単純なSELECTの実行速度を測ったもの。

データはそれぞれクエリキャッシュ無効のとき、クエリキャッシュを有効にしたがキャッシュにはヒットしないとき、クエリキャッシュにヒットしたときの3通りの毎秒のSELECT回数をプロットしたもの。横軸はクエリ発行側のthread数をとったが、今回はあまり意味がなかったかもしれない。
クエリキャッシュを有効にしてもprepared statementの場合はそもそもキャッシュ対象とはならないので、若干のオーバーヘッドがあるのみで性能向上はない。オーバーヘッド自体は先日コードを読んだ結果からもわかる通り、それほど大きくないと予想していたが、最大でも約10%程度、並列度が高いケースでは5%未満だった。
「キャッシュヒット時」というのはsysbenchの実行モード指定で敢えてprepared statementを無効にしたときの結果。このときのキャッシュヒット率は全てのケースで93%後半でほぼ一定していた。このとき、キャッシュ無効時との性能比は約20%から40%程度の向上がみられた。
MyISAMInnoDBでそれぞれ同じベンチマークを実行したが、グラフの通り傾向も個々の数字もほぼ同一。テーブルサイズを小さめにしてI/Oをほとんど発生しない条件にしたため、ストレージエンジンでの差がつきにくかったのかもしれない。特にキャッシュヒット時はストレージエンジンに処理が渡る前に結果が返されるので、なおさら差が出にくかったのだろう。
通常の使い方で今回のケースのように高いヒット率が出ることはあまり考えられないので、一般的な性能向上は1割から2割程度と見ておくのが妥当だと思う。この程度はテーブルの設計やインデックスの張り方次第ですぐに帳消しになるので、やはりクエリキャッシュという機能はMySQLでのチューニングの最後の手段ぐらいに考えておくべきだろう。
今回のケースではCPU boundなクエリをキャッシュしたときの性能向上を測ったけど、実際のケースでは逆に実際のケースではI/Oを抑えられる可能性もある。ただ、キャッシュがあれば上手くヒットするけど無ければI/Oが生じるという状況は、何か設計が間違っていることが考えられるので、やはりまずは設計を良く練ることが肝要。

実行環境

key_buffer = 16M
query_cache_size = 5242880
innodb_flush_method = O_DIRECT
innodb_buffer_pool_size = 16M

  • sysbench 0.4.8

mode=simple
table-size=10000
max-time=300
max-requests=100000000