プラグインを有効または無効にするには、rewriter_enabled
システム変数を有効または無効にします。 デフォルトでは、Rewriter
プラグインはインストール時に有効になります (セクション5.6.4.1「リライタのクエリーリライトプラグインのインストールまたはアンインストール」 を参照)。 プラグインの初期状態を明示的に設定するには、サーバーの起動時に変数を設定します。 たとえば、オプションファイルでプラグインを有効にするには、次の行を使用します:
[mysqld]
rewriter_enabled=ON
実行時にプラグインを有効または無効にすることもできます:
SET GLOBAL rewriter_enabled = ON;
SET GLOBAL rewriter_enabled = OFF;
Rewriter
プラグインが有効になっていると仮定すると、サーバーによって受信されたリライト可能な各ステートメントを調査し、場合によっては変更します。 プラグインは、query_rewrite
データベースの rewrite_rules
テーブルからロードされるリライトルールのインメモリーキャッシュに基づいてステートメントをリライトするかどうかを決定します。
次のステートメントはリライトの対象となります:
MySQL 8.0.12 の時点:
SELECT
,INSERT
,REPLACE
,UPDATE
およびDELETE
。MySQL 8.0.12 より前:
SELECT
only.
スタンドアロンステートメントおよびプリペアドステートメントはリライトの対象となります。 ビュー定義またはストアドプログラム内で発生するステートメントは、書き換えの対象にはなりません。
Rewriter
プラグインのルールを追加するには、rewrite_rules
テーブルに行を追加し、flush_rewrite_rules()
ストアドプロシージャを起動してテーブルからプラグインにルールをロードします。 次の例では、単一のリテラル値を選択するステートメントを照合する単純なルールを作成します:
INSERT INTO query_rewrite.rewrite_rules (pattern, replacement)
VALUES('SELECT ?', 'SELECT ? + 1');
結果のテーブルの内容は次のようになります:
mysql> SELECT * FROM query_rewrite.rewrite_rules\G
*************************** 1. row ***************************
id: 1
pattern: SELECT ?
pattern_database: NULL
replacement: SELECT ? + 1
enabled: YES
message: NULL
pattern_digest: NULL
normalized_pattern: NULL
このルールは、照合する SELECT
ステートメントを示すパターンテンプレートと、照合ステートメントのリライト方法を示す置換テンプレートを指定します。 ただし、rewrite_rules
テーブルにルールを追加するだけでは、Rewriter
プラグインでルールを使用できません。 テーブルの内容をプラグインインメモリーキャッシュにロードするには、flush_rewrite_rules()
を起動する必要があります:
mysql> CALL query_rewrite.flush_rewrite_rules();
リライトルールが正しく機能していないように見える場合は、flush_rewrite_rules()
をコールしてルールテーブルをリロードしたことを確認してください。
プラグインは、ルールテーブルから各ルールを読み取るときに、パターンおよびダイジェストハッシュ値から正規化された (ステートメントダイジェスト) フォームを計算し、それらを使用して normalized_pattern
および pattern_digest
カラムを更新します:
mysql> SELECT * FROM query_rewrite.rewrite_rules\G
*************************** 1. row ***************************
id: 1
pattern: SELECT ?
pattern_database: NULL
replacement: SELECT ? + 1
enabled: YES
message: NULL
pattern_digest: d1b44b0c19af710b5a679907e284acd2ddc285201794bc69a2389d77baedddae
normalized_pattern: select ?
ステートメントダイジェスト、正規化されたステートメント、およびダイジェストハッシュ値については、セクション27.10「パフォーマンススキーマのステートメントダイジェストとサンプリング」 を参照してください。
なんらかのエラーが原因でルールをロードできない場合、flush_rewrite_rules()
をコールするとエラーが発生します:
mysql> CALL query_rewrite.flush_rewrite_rules();
ERROR 1644 (45000): Loading of some rule(s) failed.
これが発生すると、プラグインはルール行の message
カラムにエラーメッセージを書き込み、問題を伝達します。 NULL
message
以外のカラム値を持つ行の rewrite_rules
テーブルをチェックして、どのような問題が存在するかを確認します。
パターンは、プリペアドステートメントと同じ構文を使用します (セクション13.5.1「PREPARE ステートメント」 を参照)。 パターンテンプレート内では、?
文字はデータ値と一致するパラメータマーカーとして機能します。 パラメータマーカーは、SQL キーワードや識別子などではなく、データ値を指定するべき場所にしか使用できません。 ?
文字を引用符で囲まないでください。
パターンと同様に、置換には ?
文字を含めることができます。 パターンテンプレートに一致するステートメントの場合、プラグインはそれを書き換え、置換内の ?
パラメータマーカーを、パターン内の対応するマーカーに一致するデータ値を使用して置き換えます。 結果は完全なステートメントの文字列になります。 プラグインはサーバーに解析を要求し、書き換えられたステートメントの表現として結果をサーバーに返します。
ルールを追加してロードした後、ステートメントがルールパターンと一致するかどうかに応じてリライトが行われるかどうかを確認します:
mysql> SELECT PI();
+----------+
| PI() |
+----------+
| 3.141593 |
+----------+
1 row in set (0.01 sec)
mysql> SELECT 10;
+--------+
| 10 + 1 |
+--------+
| 11 |
+--------+
1 row in set, 1 warning (0.00 sec)
最初の SELECT
ステートメントではリライトは行われませんが、次のステートメントでは行われます。 2 番目のステートメントは、Rewriter
プラグインがステートメントを書き換えると警告メッセージを生成することを示しています。 メッセージを表示するには、SHOW WARNINGS
を使用します:
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Note
Code: 1105
Message: Query 'SELECT 10' rewritten to 'SELECT 10 + 1' by a query rewrite plugin
ステートメントを同じタイプのステートメントにリライトする必要はありません。 次の例では、DELETE
ステートメントを UPDATE
ステートメントにリライトするルールをロードします:
INSERT INTO query_rewrite.rewrite_rules (pattern, replacement)
VALUES('DELETE FROM db1.t1 WHERE col = ?',
'UPDATE db1.t1 SET col = NULL WHERE col = ?');
CALL query_rewrite.flush_rewrite_rules();
既存のルールを有効または無効にするには、その enabled
カラムを変更し、プラグインにテーブルをリロードします。 ルール 1 を無効にするには:
UPDATE query_rewrite.rewrite_rules SET enabled = 'NO' WHERE id = 1;
CALL query_rewrite.flush_rewrite_rules();
これにより、ルールをテーブルから削除せずに非アクティブ化できます。
ルール 1 を再度有効にするには:
UPDATE query_rewrite.rewrite_rules SET enabled = 'YES' WHERE id = 1;
CALL query_rewrite.flush_rewrite_rules();
rewrite_rules
テーブルには、Rewriter
がデータベース名で修飾されていないテーブル名の照合に使用する pattern_database
カラムが含まれています:
ステートメントの修飾テーブル名は、対応するデータベース名とテーブル名が同一の場合、パターンの修飾名と一致します。
ステートメント内の修飾されていないテーブル名は、デフォルトのデータベースが
pattern_database
と同じで、テーブル名が同一の場合にのみ、パターン内の修飾されていない名前と一致します。
appdb.users
という名前のテーブルに id
という名前のカラムがあり、アプリケーションが次のいずれかの形式のクエリーを使用してテーブルから行を選択するとします。2 番目の形式は、appdb
がデフォルトデータベースの場合にのみ使用できます:
SELECT * FROM users WHERE appdb.id = id_value;
SELECT * FROM users WHERE id = id_value;
また、id
カラムの名前が user_id
に変更されたとします (場合によっては、テーブルを変更して別のタイプの ID を追加する必要があり、id
カラムが表す ID のタイプをより具体的に指定する必要があります)。
この変更は、アプリケーションが WHERE
句で id
ではなく user_id
を参照する必要があることを意味します。 ただし、生成される SELECT
クエリーを変更するために書き込めない古いアプリケーションがある場合は、正しく機能しなくなります。 Rewriter
プラグインはこの問題を解決できます。 テーブル名を修飾するかどうかに関係なくステートメントを照合およびリライトするには、次の 2 つのルールを追加してルールテーブルをリロードします:
INSERT INTO query_rewrite.rewrite_rules
(pattern, replacement) VALUES(
'SELECT * FROM appdb.users WHERE id = ?',
'SELECT * FROM appdb.users WHERE user_id = ?'
);
INSERT INTO query_rewrite.rewrite_rules
(pattern, replacement, pattern_database) VALUES(
'SELECT * FROM users WHERE id = ?',
'SELECT * FROM users WHERE user_id = ?',
'appdb'
);
CALL query_rewrite.flush_rewrite_rules();
Rewriter
では、最初のルールを使用して、修飾テーブル名を使用するステートメントを照合します。 デフォルトデータベースが appdb
(pattern_database
の値) の場合のみ、秒を使用して、修飾されていない名前を使用したステートメントを照合します。
Rewriter
プラグインは、ステートメントダイジェストとダイジェストハッシュ値を使用して、着信ステートメントを段階的なリライトルールと照合します。 max_digest_length
システム変数は、ステートメントダイジェストの計算に使用されるバッファのサイズを決定します。 値が大きいほど、長いステートメントを区別するダイジェストの計算が可能になります。 値が小さいほどメモリー使用量は少なくなりますが、同じダイジェスト値と競合する長いステートメントの可能性が高くなります。
プラグインは、次のように各ステートメントをリライト規則と照合します:
ステートメントダイジェストハッシュ値を計算し、ルールダイジェストハッシュ値と比較します。 これは誤検出の対象ですが、迅速な拒否テストとして機能します。
ステートメントダイジェストハッシュ値がパターンダイジェストハッシュ値と一致する場合は、ステートメントの正規化された (ステートメントダイジェスト) 形式を一致ルールパターンの正規化された形式と照合します。
正規化されたステートメントがルールと一致する場合は、ステートメントのリテラル値とパターンを比較します。 パターン内の
?
文字は、ステートメント内の任意のリテラル値と一致します。 ステートメントがステートメントを準備する場合、パターン内の?
もステートメント内の?
と一致します。 それ以外の場合、対応するリテラルは同じである必要があります。
複数のルールがステートメントに一致する場合は、プラグインがステートメントを書き換えるために使用する非決定的です。
パターンに置換より多くのマーカーが含まれている場合、プラグインは余分なデータ値を破棄します。 パターンに含まれるマーカーが置換より少ない場合は、エラーになります。 プラグインは、ルールテーブルがロードされたときにこれに気付き、問題を伝えるためにルール行の message
カラムにエラーメッセージを書き込み、Rewriter_reload_error
ステータス変数を ON
に設定します。
プリペアドステートメントは、後で実行されるときではなく、解析時 (つまり準備時) にリライトされます。
プリペアドステートメントは、パラメータマーカーとして ?
文字を含むことができるという点で、プリペアドステートメントと異なります。 プリペアドステートメントの ?
と一致させるには、Rewriter
パターンの同じ場所に ?
が含まれている必要があります。 リライトルールに次のパターンがあるとします:
SELECT ?, 3
次のテーブルに、いくつかの準備済 SELECT
ステートメントと、ルールパターンがそれらに一致するかどうかを示します。
プリペアドステートメント | パターンがステートメントと一致するかどうか |
---|---|
PREPARE s AS 'SELECT 3, 3' |
はい |
PREPARE s AS 'SELECT ?, 3' |
はい |
PREPARE s AS 'SELECT 3, ?' |
いいえ |
PREPARE s AS 'SELECT ?, ?' |
いいえ |
Rewriter
プラグインは、いくつかのステータス変数を使用して、その操作に関する情報を使用可能にします:
mysql> SHOW GLOBAL STATUS LIKE 'Rewriter%';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| Rewriter_number_loaded_rules | 1 |
| Rewriter_number_reloads | 5 |
| Rewriter_number_rewritten_queries | 1 |
| Rewriter_reload_error | ON |
+-----------------------------------+-------+
これらの変数の説明については、セクション5.6.4.3.4「リライタのクエリーリライトプラグインステータス変数」を参照してください。
flush_rewrite_rules()
ストアドプロシージャをコールしてルールテーブルをロードすると、一部のルールでエラーが発生した場合、CALL
ステートメントによってエラーが生成され、プラグインによって Rewriter_reload_error
ステータス変数が ON
に設定されます:
mysql> CALL query_rewrite.flush_rewrite_rules();
ERROR 1644 (45000): Loading of some rule(s) failed.
mysql> SHOW GLOBAL STATUS LIKE 'Rewriter_reload_error';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Rewriter_reload_error | ON |
+-----------------------+-------+
この場合、rewrite_rules
テーブルで NULL
以外の message
カラム値を持つ行をチェックして、どのような問題が存在するかを確認します。