2013年6月21日金曜日

クエリーキャッシュはカレントデータベースやキャラクターセットも区別する

クエリーキャッシュに載ってるかどうかの判定はSQLがパースされる前に比較されるから、SELECTステートメントは一字一句同じでないとクエリキャッシュ利かないよ、というのは有名な話。

http://dev.mysql.com/doc/refman/5.5/en/query-cache-operation.html

取り敢えず↑に答えが書いてあったがメモ。

MariaDBのinformation_schema.QUERY_CACHE_INFOをいじっていて気が付いたんだけど、クエリーキャッシュってカレントデータベースも区別してクエリキャッシュに登録してる。
(↓の出力は、そのプラグインをMySQL5.5向けに書き直したやつだけど)

mysql55> RESET QUERY CACHE;
Query OK, 0 rows affected (0.00 sec)

mysql55> SHOW GLOBAL STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 0     |
+-------------------------+-------+
1 row in set (0.00 sec)

mysql55> USE d1; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE information_schema; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE mysql; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> SELECT * FROM information_schema.query_cache_info;
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| STATEMENT_SCHEMA   | STATEMENT_TEXT              | RESULT_BLOCKS_COUNT | RESULT_BLOCKS_SIZE | RESULT_BLOCKS_SIZE_USED |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| d1                 | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| information_schema | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| mysql              | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
3 rows in set (0.01 sec)

mysql55> SHOW GLOBAL STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 3     |
+-------------------------+-------+
1 row in set (0.01 sec)


とはいえこれはよく考えれば当たり前で、↑のクエリはたまたまデータベース名まで修飾してるけど、テーブル名だけの場合はカレントデータベースが違えば当然別のクエリだもんね。
SQLステートメントの大文字小文字が違っただけで別のクエリーとしてキャッシュに押し込むsql/cache.ccが、データベース名まで修飾されてるからってよしなにやってくれるとは当然思えないので、これはこれで良い。

でもでも。

さっきのマニュアル、キャラクターセットやプロトコル(MySQLプロトコル)のバージョンも区別するって書いてあるぞ。。。

mysql55> SET NAMES sjis;
Query OK, 0 rows affected (0.00 sec)

mysql55> USE d1; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE information_schema; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE mysql; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> SELECT * FROM information_schema.query_cache_info;
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| STATEMENT_SCHEMA   | STATEMENT_TEXT              | RESULT_BLOCKS_COUNT | RESULT_BLOCKS_SIZE | RESULT_BLOCKS_SIZE_USED |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| d1                 | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| information_schema | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| mysql              | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| information_schema | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| d1                 | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| mysql              | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
6 rows in set (0.02 sec)

mysql55> SHOW GLOBAL STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 6     |
+-------------------------+-------+
1 row in set (0.00 sec)

うええええ、ホントだ。これ知らなかった。
確かにbyte単位でSQLステートメントを比較してるだけなら、キャラクターセットが違ったら一致しないねぇ。

プロトコルバージョンの違いは、どのバージョンで変わってるのかよく判らなくて断念。
取り敢えず4.0.30だとプロトコルバージョン違いそうなんだけど、Authのアレで蹴られるので試せず。

最近クエリーキャッシュ漬け。

0 件のコメント :

コメントを投稿