クエリキャッシュは非常に優れた機能ですが、あまり注意を向けすぎたり、大きすぎたりしないようにしてください。その内部のいくつかを理解することはおそらくその点で役立つでしょう。
クエリキャッシュは、利用可能なメモリの1つの大きな連続したチャンクとして始まります。次に、この大きなブロックから「ブロック」が切り分けられます。
- キャッシュされた各クエリはブロックを取得します
- そのコンパニオン結果セットはブロックを取ります
- キャッシュされたクエリによって参照される各テーブル(キャッシュ内にそのテーブルを参照するクエリがいくつあるかに関係なく)も、テーブルごとに1つのブロックを取得します。
ブロックサイズは動的ですが、サーバーquery_cache_min_res_unit
はブロックごとに最小バイトを割り当て、通常のデフォルトは4096バイトです。
クエリ、それに付随する結果、およびテーブル参照がキャッシュから削除されるときはいつでも、基になるテーブルの変更によって無効になるか、プルーニングによって新しいクエリの余地ができるため、これらのブロックのサイズにかかわらず、新しいホールのサイズに新しい穴が残ります。通常、「フリーブロック」の数は増加しますが、2つ以上の隣接するブロックが解放された場合、「フリーブロック」の数は1だけ増加し、「フリーブロック」は、解放されたブロックは、すでに解放されたブロックと隣接しています-その解放されたブロックのサイズは大きくなるだけです。クエリキャッシュ内の空きメモリの開いているブロックは、1つの空きブロックとしてカウントされます。
もちろん、それよりも小さい空きブロックquery_cache_min_res_unit
はまったく使用されません。
したがって、クエリキャッシュは断片化します。サーバーが新しいクエリをキャッシュする必要があり、十分なサイズの空きブロックを配置できない場合(その説明は、基礎となるアルゴリズムが複雑であるため、一見シンプルですが)、他の何かを排除する必要があります...それがあなたのQcache_lowmem_prunes
です。何をプルーニングするかを決定する「最近使用されていない」(LRU)アルゴリズムがあります。
サーバーがメモリを最適化しない理由を尋ねるのは理にかなっていますが、それは意味がありません。クエリキャッシュは、可能な場合には役立ちますが、戦略的なものではありません。不要なメンテナンスタスクを使用して、処理時間(特にグローバルロックに費やされる時間)を費やしたくない場合。
キャッシュされた結果は常に変化しており、キャッシュの全体のポイントはパフォーマンスを向上させることになるため、サーバーがクエリキャッシュ内のメモリの再配置-デフラグ-に時間を費やすことは逆効果です。
グローバルロックは、過度に大きなクエリキャッシュを使用したくない非常に良い理由です...クエリが順番に待機してキャッシュが発生するかどうかを確認し、パフォーマンスが低下するため、サーバーはそこであまりにも多くの時間を費やします。 。
しかし、これqcache_free_blocks
は本質的に空き領域の断片化の指標です。これで、利用可能なメモリの多くの不連続なブロックがクエリキャッシュに存在します。新しいクエリをキャッシュに挿入するには、クエリ、その結果、および(場合によっては)テーブル参照を含めるのに十分な空き領域が必要です。ない場合は、何か他のことを実行する必要があります...これが表示されているものです。繰り返しになりますが、利用可能なスペースは必ずしも隣接している必要はありません(ソースコードを読むことでわかることから)が、断片化が発生したときにすべての穴が埋められるとは限りません。
ただし、特定のワークロードの場合、断片化は時間の経過とともに横ばいになる傾向があります。これは、通常、予想される限り何もクエリキャッシュに留まらないためです。
これは、いくつかの点で、クエリキャッシュはその単純さの点で優れているためです。
キャッシュされたクエリによって参照されるテーブル内のデータが変更されると、そのテーブルに関係するすべてのクエリがキャッシュから削除されます(変更がキャッシュされた結果に影響しない場合でも)。これは、ロールバックされるInnoDBトランザクションの場合のように、テーブルが変更されても変更されない場合にも当てはまります。そのテーブルを参照するクエリキャッシュエントリは既に削除されています。
また、サーバーが実際にクエリを解析する前に、受信クエリごとにクエリキャッシュがチェックされます。一致する唯一のものは、バイトごとにまったく同じであった別のクエリです。 SELECT * FROM my_table
またselect * from my_table
、バイトごとに同一ではないため、クエリキャッシュはそれらが同じクエリであることを認識しません。
FLUSH QUERY CACHE
クエリキャッシュを空にしません。クエリキャッシュを最適化するため、Qcache_free_blocks
「1」になります。すべての空き領域が統合されます。
RESET QUERY CACHE
実際にクエリキャッシュをフラッシュします(すべてのコンテンツをクリアします)。
FLUSH STATUS
はカウンタをクリアしますが、これはのステータス変数のほとんどをゼロにするため、日常的に行う必要のあるものではありませんSHOW STATUS
。
ここにいくつかの簡単なデモンストレーションがあります。
ベースライン:
mysql> show status like '%qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67091120 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 1 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
クエリを実行...
mysql> select * from junk where id = 2;
ブロックの総数は3増加し、挿入は1増加し、キャッシュ内のクエリは1です。
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67089584 |
| Qcache_inserts | 1 |
| Qcache_queries_in_cache | 1 |
| Qcache_total_blocks | 4 |
+-------------------------+----------+
同じクエリを実行しますが、大文字と小文字を使い分けます...
mysql> SELECT * FROM junk where id = 2;
このクエリは個別にキャッシュされました。テーブルにすでに割り当てられているブロックがあるため、合計ブロックは2だけ増加しました。
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67088560 |
| Qcache_inserts | 2 |
| Qcache_queries_in_cache | 2 |
| Qcache_total_blocks | 6 |
+-------------------------+----------+
次に、テーブルの別の行を変更します。
mysql> update junk set things = 'items' where id = 1;
クエリとテーブル参照の両方がキャッシュから無効化され、1つの連続した空きブロック、すべてのキャッシュメモリが解放され、すべての空き領域が1つのブロックに統合されます。
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67091120 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
MySQLは、決定論的ではないSELECT NOW();
クエリや、特にキャッシュしないように指定したクエリなどをキャッシュに保存しません。 SELECT SQL_NO_CACHE ...
結果をキャッシュに保存しないようサーバーに指示するディレクティブです。これは、以降の実行でキャッシュが一見して速い応答を示している場合に、クエリの実際の実行時間をベンチマークするのに役立ちます。