您好,登錄后才能下訂單哦!
從MySQL 5.7.6開始,MySQL服務器支持查詢重寫插件它可以在服務器執行語句之前可以檢查和可能修改接收到的語句。MySQL包含一個名為Rewriter的查詢重寫插件和安裝插件與它相關組件的腳本。這些組件一起工作提供對select的重寫能力:
.服務端插件名為Rewriter檢查select語句并且可能基于緩存在內存中的重寫規則來重寫它們。標準select語句和預備語句中的select語句可能經受重寫。出現在視圖定義中或存儲過程中的select語句不會經受重寫。
.Rewriter插件使用一個包含rewrite_rules表的query_rewrite數據庫。表提供了對規則的永久存儲,插件使用它來決賽是否重寫語句。通過存儲在表中的規則集讓用戶與插件通信。通過設置表中記錄的message列來讓用戶與插件通信。
.query_rewrite數據庫包含一個名為flush_rewrite_rules()的存儲過程用來把規則表中的內容加載到插件中。
.用戶定義函數load_rewrite_rules()被flush_rewrite_rules()存儲過程來調用。
.Rewriter插件顯示了系統變量能讓插件配置和狀態變量來提供運行時操作信息。
下面將描述如何安裝與使用Rewriter插件并提供與它相關組件的信息。
安裝或卸載Rewriter查詢重寫插件
為了安裝或卸載Rewriter查詢重寫插件,在MySQL安裝目錄下的share目錄中選擇執行合適的腳本:
.install_rewriter.sql: 使用這個腳本來安裝Rewriter插件和它相關的組件。
.uninstall_rewriter.sql:使用這個腳本來卸載Rewriter插件和它相關的組件。
運行安裝腳本
[mysql@localhost share]$ mysql -uroot -p < install_rewriter.sql Enter password:
運行安裝腳本將會安裝與啟用插件。為了驗證它,連接到數據庫執行以下語句:
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | binlog | | mysql | | performance_schema | | query_rewrite | | sys | +--------------------+ 6 rows in set (0.00 sec) mysql> show global variables like 'rewriter_enabled'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | rewriter_enabled | ON | +------------------+-------+ 1 row in set (0.00 sec)
使用Rewriter查詢重寫插件
為了啟用或禁用Rewriter查詢重寫插件可以通過啟用或禁用rewriter_enabled系統變量來完成。默認情況是當你安裝Rewriter查詢重寫插件時是啟用的。為了顯式設置初始化Rewriter查詢重寫插件的狀態,可以在服務器啟動時設置rewriter_enabled變量。例如為了在選項文件中啟用Rewriter插件可以進行以下設置:
[mysqld]
rewriter_enabled=ON
也可以在運行時啟用或禁用Rewriter插件:
mysql> set global rewriter_enabled=OFF; Query OK, 0 rows affected (0.00 sec) mysql> show global variables like 'rewriter_enabled'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | rewriter_enabled | OFF | +------------------+-------+ 1 row in set (0.00 sec) mysql> set global rewriter_enabled=ON; Query OK, 0 rows affected (0.00 sec) mysql> show global variables like 'rewriter_enabled'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | rewriter_enabled | ON | +------------------+-------+ 1 row in set (0.01 sec) mysql> desc query_rewrite.rewrite_rules; +--------------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------------+------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | pattern | varchar(10000) | NO | | NULL | | | pattern_database | varchar(20) | YES | | NULL | | | replacement | varchar(10000) | NO | | NULL | | | enabled | enum('YES','NO') | NO | | YES | | | message | varchar(1000) | YES | | NULL | | | pattern_digest | varchar(32) | YES | | NULL | | | normalized_pattern | varchar(100) | YES | | NULL | | +--------------------+------------------+------+-----+---------+----------------+ 8 rows in set (0.00 sec) mysql> select * from query_rewrite.rewrite_rules; Empty set (0.00 sec)
假設Rewriter插件被啟用,它將檢查和可能修改由服務器所接收到的每個select語句。插件將基于內存中緩存的重寫規則(從query_rewriter數據庫的rewrite_rules表中加載的)來決定是否重寫語句。
添加重寫規則
為了向Rewriter插件添加規則,向rewrite_rules表中添加記錄,然后調用flush_rewrite_rules()存儲過程來從表中加載規則到插件中。下面的例子來創建一個簡單規則來匹配單個文本值的查詢語句。
mysql> insert into query_rewrite.rewrite_rules(pattern,replacement) values('select ?','select ?+1'); Query OK, 1 row affected (0.03 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from query_rewrite.rewrite_rules; +----+----------+------------------+-------------+---------+---------+----------------+--------------------+ | id | pattern | pattern_database | replacement | enabled | message | pattern_digest | normalized_pattern | +----+----------+------------------+-------------+---------+---------+----------------+--------------------+ | 1 | select ? | NULL | select ?+1 | YES | NULL | NULL | NULL | +----+----------+------------------+-------------+---------+---------+----------------+--------------------+ 1 row in set (0.00 sec) 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 1 row in set (0.00 sec)
規則指定一種模式模板指示那種查詢語句會被匹配,并且替換模板指示了如何重寫匹配的語句。然而添加規則到rewrite_rules表中不足以造成Rewriter插件使用這個規則。我們必須要調用flush_rewrite_rules()過程來將規則表的內容加載到插件內存緩存中:
mysql> call query_rewrite.flush_rewrite_rules(); Query OK, 0 rows affected, 1 warning (0.04 sec)
當插件從規則表中讀取每種規則時,它將計算一個標準化(語句摘要)格式的模式和一個摘要哈希值并使用它們來更新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: 3d4fc22e33e10d7235eced3c75a84c2c normalized_pattern: select ? 1 row in set (0.00 sec)
模式使用與預備語句相同的語法。使用模式模板,?字符實際上作為參數標記用來匹配數據值。參數標記只能用于應該出現數據值的地方,而不能用于SQL關鍵字、標識符等.?字符不應該使用引號括起來。
像模式一樣,替換可以包含?字符。對于匹配一種模式模板的語句,重寫插件將重寫它,通過模式中的相關標記所匹配的數據值來替換?字符標記。替換的結果是一種完整的語句字符。重寫插件要求服務器解析它并執行重寫之后的語句將結果返回。
在添加和加載重寫規則后,檢查匹配規則模式的語句是否會被重寫:
mysql> select pi(); +----------+ | pi() | +----------+ | 3.141593 | +----------+ 1 row in set (0.02 sec) mysql> select 10; +------+ | 10+1 | +------+ | 11 | +------+ 1 row in set, 1 warning (0.00 sec)
從上面的執行結果來看,第一個查詢語句沒有出現重寫,但第二個查詢被重寫了。因為第二個查詢語句Rewriter插件重寫語句后生成了一個警告信息。為了查看這個警告信息可以使用show warnings:
mysql> show warnings\g +-------+------+------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+------------------------------------------------------------------------+ | Note | 1105 | Query 'select 10' rewritten to 'select 10+1' by a query rewrite plugin | +-------+------+------------------------------------------------------------------------+ 1 row in set (0.00 sec)
為了啟用或禁用現有的規則,可以通過修改enabled列并重新加載規則表到重寫插件。
為了禁用規則1
mysql> update query_rewrite.rewrite_rules set enabled='NO' where id=1; Query OK, 1 row affected (0.03 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> call query_rewrite.flush_rewrite_rules(); Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select * from query_rewrite.rewrite_rules\G; *************************** 1. row *************************** id: 1 pattern: select ? pattern_database: NULL replacement: select ?+1 enabled: NO message: NULL pattern_digest: 3d4fc22e33e10d7235eced3c75a84c2c normalized_pattern: select ? 1 row in set (0.00 sec) mysql> select 10; +----+ | 10 | +----+ | 10 | +----+ 1 row in set (0.00 sec)
這就可以不同從表中刪除重寫規則來禁用重寫規則。
為了重新啟用重寫規則1:
mysql> update query_rewrite.rewrite_rules set enabled='YES' where id=1; Query OK, 1 row affected (0.03 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> call query_rewrite.flush_rewrite_rules(); Query OK, 0 rows affected (0.02 sec) 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: 3d4fc22e33e10d7235eced3c75a84c2c normalized_pattern: select ? 1 row in set (0.00 sec) mysql> select 10; +------+ | 10+1 | +------+ | 11 | +------+ 1 row in set, 1 warning (0.00 sec)
rewrite_rules表包含了一個pattern_database列它是Rewriter用來匹配沒有使用數據庫名限定的表名:
.如果相關的數據庫和表名相同,語句中限定表名匹配模式中的限定名。
.只有默認數據庫與pattern_database一樣并且表名相同時語句中的非限定表名匹配模式中的非限定名
假設表mysql.cs有一個名為id的列并且應用程序從以下形式的查詢中選擇一個來從表中查詢記錄,這里第二個查詢只能在默認數據庫為mysql的情況下被執行:
select * from mysql.cs where id=id_value;
select * from cs where id=id_value;
現在假設id列被重命名為user_id了。這種修改意味著應用程序必須引用user_id而不是id。但是如果舊的應用程序不能進行修改,那么它們將不能工作了。Rewriter重寫插件可以解決這個問題。為了匹配和重寫那些不管是否有限定名的查詢語句,添加以下兩個規則并重新加載規則表:
mysql> select * from cs where mysql.id=1; ERROR 1054 (42S22): Unknown column 'mysql.id' in 'where clause' mysql> insert into query_rewrite.rewrite_rules(pattern,replacement) -> values('select * from mysql.cs where id= ?','select * from mysql.cs where user_id= ?'); Query OK, 1 row affected (0.05 sec) mysql> insert into query_rewrite.rewrite_rules(pattern,replacement,pattern_database) -> values('select * from cs where id=?','select * from cs where user_id=?','mysql'); Query OK, 1 row affected (0.05 sec) mysql> call query_rewrite.flush_rewrite_rules(); Query OK, 0 rows affected, 1 warning (0.02 sec) 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: 3d4fc22e33e10d7235eced3c75a84c2c normalized_pattern: select ? *************************** 2. row *************************** id: 2 pattern: select * from mysql.cs where id= ? pattern_database: NULL replacement: select * from mysql.cs where user_id= ? enabled: YES message: NULL pattern_digest: 45281da14b71c1357dd053a4fe49dfac normalized_pattern: select `*` from `mysql`.`cs` where (`id` = ?) *************************** 3. row *************************** id: 3 pattern: select * from cs where id=? pattern_database: mysql replacement: select * from cs where user_id=? enabled: YES message: NULL pattern_digest: 0da2491bc4c0e1462cc020e4fcfde16b normalized_pattern: select `*` from `mysql`.`cs` where (`id` = ?) 3 rows in set (0.00 sec) mysql> select * from mysql.cs where id=1; +------+------+---------+ | id | name | user_id | +------+------+---------+ | 1 | jy | 1 | +------+------+---------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +-------+------+----------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+----------------------------------------------------------------------------------------------------------------------------+ | Note | 1105 | Query 'select * from mysql.cs where id=1' rewritten to 'select * from mysql.cs where user_id= 1' by a query rewrite plugin | +-------+------+----------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> select * from cs where id=1; +------+------+---------+ | id | name | user_id | +------+------+---------+ | 1 | jy | 1 | +------+------+---------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +-------+------+---------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+---------------------------------------------------------------------------------------------------------------+ | Note | 1105 | Query 'select * from cs where id=1' rewritten to 'select * from cs where user_id=1' by a query rewrite plugin | +-------+------+---------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
Rewriter插件使用第一個規則匹配有限定名的查詢,使用第二個規則匹配沒有限定名,但默認數據庫必須為mysql才能進行查詢重寫。
如何進行模式匹配
Rewriter插件使用語句摘要和摘要哈希值來使用重寫規則匹配輸入語句。max_digest_length系統變量決定了用于計算語句摘要的buffer大小。值越大計算的摘要越能區分更長的語句。值越小使用的內存越小但增加了更長語句使用相同摘要的可能性。
mysql> show global variables like 'max_digest_length'; +-------------------+-------+ | Variable_name | Value | +-------------------+-------+ | max_digest_length | 1024 | +-------------------+-------+ 1 row in set (0.00 sec)
插件匹配語句進行重寫的規則如下:
1.計算語句摘要的哈希值并將它與規則摘要哈希值進行比較。這可能會出現誤報,但可以作為快速的拒絕測試
2.如果語句摘要哈希值匹配任何一個模式摘要哈希值,則匹配規范化哈希值(語句摘要)將語句的形式轉化為匹配規則模式所規范化的形式。
3.如果規范化語句與規則匹配,請比較語句和模式中的文字值。模式中的一個?號值與語句中的任何文字值匹配。如果語句準備了一個SELECT語句,模式中的?也匹配語句中的?。否則,對應的文字必須相同。
如果多個規則匹配一個語句,則不確定插件使用哪個規則來重寫該語句。
如果一個模式包含比替換更多的標記,那么插件將丟棄多余的數據值。如果一個模式包含的標記比替換的少,這就是一個錯誤。當加載規則表時,插件會注意到這一點,它會向規則行的message列寫入一條錯誤消息來傳遞問題,并將Rewriter_reload_error狀態變量設置為ON。
重寫預備語句
預備語句是在解析時被重寫,而不是在執行時被重寫。預備語句與非預備語句的區別在于它們可能包含?字符作為參數標記。為了匹配預備語句中的?字符,重寫模式必須在同一個地方包含?字符。假設重寫規則具有這種模式
select ?, 3
下面列出了幾種預備語句和是否與它匹配的模式
預備語句 模式是否匹配語句
prepare s as 'select 3, 3' Yes
prepare s as 'select ?, 3' Yes
prepare s as 'select 3, ?' No
prepare s as 'select ?, ?' No
Rewriter插件操作信息
Rewriter插件通過幾種狀態變量來表示它的操作信息:
mysql> show global status like 'Rewriter%'; +-----------------------------------+-------+ | Variable_name | Value | +-----------------------------------+-------+ | Rewriter_number_loaded_rules | 3 | | Rewriter_number_reloads | 5 | | Rewriter_number_rewritten_queries | 5 | | Rewriter_reload_error | OFF | +-----------------------------------+-------+ 4 rows in set (0.01 sec)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。