この節は、クエリキャッシュのメカニズムを説明します。設定方法は、項4.5.5.3. 「クエリキャッシュの設定」 を参照してください。
解析前のクエリーには、解釈が始まる前にクエリキャッシュにあるクエリーとの照合を行います。そのため、次の 2 つのクエリーは、クエリキャッシュで異なるものである、と見なします。
SELECT * FROMtbl_name
Select * fromtbl_name
クエリーは、バイト同士など、完全に一致する しないかぎり、同一とは判断しません。また、ほかの理由から、同一のクエリー文字列が異なるものとして扱われることもあります。たとえば、クライアントで新しい形式の通信プロトコルを使用している場合や、別のクライアントが使用しているものとは異なるキャラクタセットを使用している場合も、同じものであるはずのクエリーが異なるものとして、認識することがあります。
次のようなクエリーにはキャッシュは使用されません。
クエリーが外部クエリーのサブクエリーである場合
ストアドファンクション、トリガー、イベントなどのボディ内で実行したクエリー
クエリー結果をキャッシュからフェッチする前に、MySQL
は、関連するすべてのデータベースとテーブルに対してそのユーザーが
SELECT
権限を持っているかどうかを確認します。権限がない場合は、キャッシュ結果は使用しません。
クエリー結果がキャッシュから返る度に、サーバーは
Qcache_hits
システム変数の値を増加します。Com_select
ではありません。項4.5.5.4. 「クエリキャッシュのステータスと保守」
を参照してください。
テーブルに変更があった場合、そのテーブルからキャッシュしたクエリーのすべてが無効になるため、キャッシュからは削除します。変更があったクエリーのマップである
MERGE
テーブルを使用するクエリーも削除の対象になります。INSERT
、UPDATE
、DELETE
、TRUNCATE
、ALTER
TABLE
、DROP
TABLE
、DROP
DATABASE
など、様々なステートメントでテーブルは変化します。
InnoDB
テーブルを使用するトランザクションでもクエリキャッシュを使用します。
MySQL 5.1 では、ビューでの
SELECT
クエリーの結果がキャッシュされます。
クエリキャッシュは、SELECT
SQL_CALC_FOUND_ROWS ...
のクエリーで動作し、後続する
SELECT FOUND_ROWS()
クエリーで返る値を格納します。FOUND_ROWS()
は前のクエリーがキャッシュからフェッチしていても、正確な値を返します。これは、検索したレコードの数をキャッシュで保管しているためです。SELECT
FOUND_ROWS()
クエリー自体はキャッシュの対象ではありません。
MySQL 5.1.17 より前では、準備済みステートメントでクエリーキャッシュは使用されません。5.1.17 以降では、特定の条件の下で、準備済みステートメントでクエリーキャッシュが使用されます。条件は準備方法によって異なります。
mysql_stmt_prepare()
および
mysql_stmt_execute()
を使用してバイナリプロトコルで発行されたステートメント。C API Prepared Statements
を参照してください。
バイナリプロトコルで実行された準備済みステートメントの場合、クエリーキャッシュ内のステートメントとの比較は、?
パラメータマーカーを展開したあとのステートメントのテキストに基づいて行われます。ステートメントは、バイナリプロトコルで実行されたキャッシュ内のほかのステートメントとのみ比較されます。つまり、クエリーキャッシュの目的では、バイナリプロトコルで発行されたステートメントとテキストプロトコルで発行されたステートメントは区別されます。
PREPARE
および
EXECUTE
を使用してテキスト (非バイナリ)
プロトコルで発行されたステートメント。詳しくは項8.7. 「準備済みステートメントのための SQL 構文」を参照してください。ここではこれらを
SQL PS ステートメントと呼びます。
MySQL 5.1.21
より前では、PREPARE
および
EXECUTE
で実行された準備済みステートメントの場合、?
パラメータマーカーを含んでいるものはキャッシュされません。その場合、パラメータを展開したあとのステートメントにはユーザー変数の参照が含まれているため、準備済みでないステートメントであっても、キャッシュの対象になりません。パラメータマーカーを含んでいないステートメントは、テキストプロトコルで実行されたクエリーキャッシュ内のステートメントと比較されます
(つまり、ほかの SQL PS
ステートメントおよび準備済みでないステートメントと比較されます)。MySQL
5.1.21
以降では、展開でユーザー変数の値が直接置換されるため、この制限はなくなり、パラメータマーカーを含んでいる準備済みステートメントもキャッシュの対象になります。
次のテーブルに示す関数を含む場合は、どのようなクエリーでもキャッシュの対象にはなりません。
BENCHMARK() |
CONNECTION_ID() |
CONVERT_TZ() |
CURDATE() |
CURRENT_DATE() |
CURRENT_TIME() |
CURRENT_TIMESTAMP() |
CURTIME() |
DATABASE() |
ENCRYPT()
(パラメータなし) |
FOUND_ROWS() |
GET_LOCK() |
LAST_INSERT_ID() |
LOAD_FILE() |
MASTER_POS_WAIT() |
NOW() |
RAND() |
RELEASE_LOCK() |
SLEEP() |
SYSDATE() |
UNIX_TIMESTAMP()
(パラメータなし) |
USER() |
UUID() |
UUID_SHORT() |
次の条件がある場合のクエリーもキャッシュの対象にはなりません。
ユーザー定義関数 (UDF) または格納された関数 (stored functions) を指す場合
ユーザー変数またはローカルに保存されたプログラム変数を指す場合
mysql
または
INFORMATION_SCHEMA
システムデータベースのテーブルを指す場合
次に示す形のものである場合
SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE SELECT ... INTO OUTFILE ... SELECT ... INTO DUMPFILE ... SELECT * FROM ... WHERE autoincrement_col IS NULL
最後の例がキャッシュにならない理由は、それが ODBC のワークアラウンド (特別の手段) として、最後のインサート ID 値が存在するため。Connectors and APIsの MyODBC 節をご参照ください。
SERIALIZABLE
遮断レベルを使用するトランザクション内のステートメントは
LOCK IN SHARE MODE
ロックを使用するため、このようなステートメントもキャッシュの対象になりません。
TEMPORARY
テーブルを使用している場合
テーブルをまったく使用しない場合。
警告を生成する場合。
関連テーブルのすべてに対して、ユーザーがカラムレベルの権限を持つ場合。