这个功能一年左右之前就以知晓,应该是5.7的高版本中。今天难得有兴致测试、随之也就总结一下。

前言
一般来说,我们都会让开发自己去改sql。这样需要重启应用,单节点不可避免有或多或少的停服时间。同事主动权也就不在自己手里。
 
 
MySQL5.7某个版本开始有查询改写这个功能。所为查询改写,就是某种SQL写的非常不友好场景下,在MySQL服务端通过查询改写,将这SQL改写成相对友好的形式。

Rewriter
 
需要先安装服务端插件Rewriter。
查询改写特性在mysql5.7中开始出现。
8.0.12之前只能改写SELECT语句。
8.0.12开始,可以改写SELECT, INSERT, REPLACE, UPDATE, and DELETE.
 
  需要记住的一点是,一旦安装,势必会给系统增加一定负担,即便不启用它。所以如果不打算用该特性,不要安装。
 

安装

需要做的事,有以下几件。
  • 首先创建一个query_rewrite库, 库中一个rewrite_rules表。用来保存定义的改写规则。
  • 安装rewriter插件,实现函数。
  • 创建一个函数load_rewrite_rules的自定义函数,其实现为rewriter共享库。
  • 创建一个存储过程,存储过程里面定义刷新查询改写缓存的方法。
  • 从查询缓存集中移除所有查询缓存。(8.0移除了QueryCache,自然也就没有这个。)
安装就是执行一个脚本。脚本里面封装了需要做的事。
 
说了这么多,非全是废话,主要为了引出下列脚本。只要执行这个脚本,即可完成上面的几个步骤。文件在$MysqlHomeDir/share目录下。
mysql -udba_yix -p < /usr/local/mysql/share/install_rewriter.sql

  

  顺便说一个卸载。其文件内容,不过是做了大致相反的事。有兴趣可以自己去看,实际上就三行内容。
mysql -udba_yix -p < /usr/local/mysql/share/uninstall_rewriter.sql

  

启用并测试
   安装好过后,默认就是启用的。
    
 
   增加改写规则
INSERT INTO query_rewrite.rewrite_rules (pattern, replacement)
VALUES('SELECT ?', 'SELECT ? + 1');

  

  执行以下语句、发现没有生效,原因是要将这个新插入的规则生效。这里就用到了,上面脚本中的定义的一个存储过程。这个和 update权限表,要flush privileges是一个道理。
    
  

CALL query_rewrite.flush_rewrite_rules();

  

  刷新过后发现,查询改写生效了。

  
 
 
  再次查询查询规则,发现不一样了。

  

 
 
  说明一下。?是一个占位符。匹配数据的值,并不匹配关键字、标识符。? 符不能有 单双引号包裹。同样必须的是,? 符号,最好一一对应上。
 
 
  

  案列2:将删除语句改写成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();

  

  发现报了错。如果有报错,需要结合 query_rewrite.rewrite_rules表中的message字段查看原因。

  

  这就是我们上面提到的在8.0.12之前只能改写select。

灵活配置

  如果发现某个规则,需要临时关闭,可使用修改语句将其关闭。

UPDATE query_rewrite.rewrite_rules SET enabled = 'NO' WHERE id = ;
CALL query_rewrite.flush_rewrite_rules();

  重启则参考下面语句。

UPDATE query_rewrite.rewrite_rules SET enabled = 'YES' WHERE id = ;
CALL query_rewrite.flush_rewrite_rules();

  同样的语句在不同库中不通对待。

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();
  如果使用下述查询来匹配上述规则

SELECT * FROM users WHERE appdb.id = id_value;
SELECT * FROM users WHERE id = id_value;

  则重写器(rewriter)会使用第一条规则匹配第一条SQL。第二条规则匹配第二条SQL(前提是默认的数据库是appdb)。

重写器如何工作的?
 
  重写器插件使用语句的内容以及内容计算出的哈希值来匹配传入语句和重写规则。
  max_digest_length 系统变量决定了用以计算语句的buffersie.较小的值使用较少的内存,但会增加较长语句与相同摘要值冲突的可能性(hash碰撞)。
 
  如果多个规则与一个语句匹配,那么重写器用来重写语句的是不确定的。
  如果匹配模式中(被替换的)?多余替换(replacement)中的?,则重写器会忽略多余的数据。反之,会报错(Rewriter_reload_error状态变量会被置为on)。所以最好要保持两边的?占位符个数相等。
 
  重写prepare 语句需要注意的是,由于prepare中有 ? 。需要在模式中和其对应上。如一个pattern:
SELECT ?, 
  几个prepare匹配情况如下:
 

Prepared Statement
Whether Pattern Matches Statement
PREPARE s AS 'SELECT 3, 3'
Yes
PREPARE s AS 'SELECT ?, 3'
Yes
PREPARE s AS 'SELECT 3, ?'
No
PREPARE s AS 'SELECT ?, ?'
No

  

重写器状态统计信息

mysql> SHOW GLOBAL STATUS LIKE 'Rewriter%';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| Rewriter_number_loaded_rules | |
| Rewriter_number_reloads | |
| Rewriter_number_rewritten_queries | |
| Rewriter_reload_error | ON |
+-----------------------------------+-------+
  需要注意的一点:重写器使用的字符集。如果全局变量character_set_client更改,查询规则要重新reload。正常情况,我们会在client块配置它。所以在jdbc连接中,不要指定或者不要定义错。即可。
 
 
  IT相关技术交流群:472983519 (Java,PHP,运维、开发、架构师)
  各类技术电子书获取群:814183658 (需要提供PDF书籍、电子文档等相关链接)
  DBA专用群:323842783 (Oracle OCM,MySQL内核探秘者、mongodb、redis等)
  (为防止广告主,加群还请备注475982055)

 

DBA主宰一切请求,MySQL 查询重写的更多相关文章

  1. MySQL中间件之ProxySQL_读写分离/查询重写配置

    MySQL中间件之ProxySQL_读写分离/查询重写配置 Posted on 2016-12-25 by mark blue, mark Leave a comment MySQL 1.闲扯几句 读 ...

  2. MySQL 子查询(四)子查询的优化、将子查询重写为连接

    MySQL 5.7 ref ——13.2.10.10优化子查询 十.子查询的优化 开发正在进行中,因此从长远来看,没有什么优化建议是可靠的.以下列表提供了一些您可能想要使用的有趣技巧.See also ...

  3. mysql查询性能优化

    mysql查询过程: 客户端发送查询请求. 服务器检查查询缓存,如果命中缓存,则返回结果,否则,继续执行. 服务器进行sql解析,预处理,再由优化器生成执行计划. Mysql调用存储引擎API执行优化 ...

  4. MySQL查询性能优化(精)

    MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下 ...

  5. 170727、MySQL查询性能优化

    MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下 ...

  6. 生产要不要开启MySQL查询缓存

    一.前言 在当今的各种系统中,缓存是对系统性能优化的重要手段.MySQL Query Cache(MySQL查询缓存)在MySQL Server中是默认打开的,但是网上各种资料以及有经验的DBA都建议 ...

  7. [转]向facebook学习,通过协程实现mysql查询的异步化

    FROM : 通过协程实现mysql查询的异步化 前言 最近学习了赵海平的演讲,了解到facebook的mysql查询可以进行异步化,从而提高性能.由于facebook实现的比较早,他们不得不对php ...

  8. mysql查询中通配符的使用

    mysql查询中通配符的使用     在mysql查询中经常会使用通配符,并且mysql的通配符和pgsql的存在区别(稍候再讨论),而且mysql中还可以使用正则表达式. SQL模式匹配: “_” ...

  9. mysql查询更新时的锁表机制分析

    为了给高并发情况下的mysql进行更好的优化,有必要了解一下mysql查询更新时的锁表机制. 一.概述 MySQL有三种锁的级别:页级.表级.行级.MyISAM和MEMORY存储引擎采用的是表级锁(t ...

随机推荐

  1. 在运行Hfile的MR如果任务client结束OOM

    在运行MR将HDFS转换成HFile什么时候.例如,会发生以下的异常: 14/07/09 18:02:59 INFO mapred.JobClient:  map 83% reduce 0% 14/0 ...

  2. 数据源Source 目标Target

    数据源Source-目标Target 数据源实现INotifyPropertyChanged接口,实现“通知”目标实现依赖属性 举例 后台的数据源,实现INotifyPropertyChanged接口 ...

  3. 基于Spring开发

    1. XML Schema 1.1 最简单的标签 一个最简单的标签,形式如: <bf:head-routing key="1" value="1" to= ...

  4. 零元学Expression Blend 4 &ndash; Chapter 20 以实作案例学习Childwindow

    原文:零元学Expression Blend 4 – Chapter 20 以实作案例学习Childwindow 本章将教大家如何运用Blend 4内建的假视窗原件-「ChildWindow」 Chi ...

  5. 零元学Expression Blend 4 - Chapter 4元件重复运用的观念

    原文:零元学Expression Blend 4 - Chapter 4元件重复运用的观念 本章将教大家Blend元件重复运用的观念,这在Silverlight设计中是非常重要的,另外加码赠送渐层工具 ...

  6. Windows 10 UWP 部署

      原文  http://youthlin.com/20151105.html 我们知道VS连接手机可以直接部署到手机里,但平板貌似无法这样干,平板与电脑连接没有丝毫反应……那么想看VS里写的uwp应 ...

  7. 龙芯GO!龙芯平台上构建Go语言环境指南

    龙芯软件生态系列——龙芯GO!龙芯平台上构建Go语言环境指南2016-07-05 龙芯中科1初识Go语言Go语言是Google公司于2009年正式推出的一款开源的编程语言,是由Robert Gries ...

  8. 关于C中可变长参数

    前言 可变长参数指函数的参数个数在调用时才能确定的函数参数.基本上各种语言都支持可变长参数,在特定情形下,可变长参数使用起来非常方便.c语言中函数可变长参数使用“...”来表示,同时可变长参数只能位于 ...

  9. QThread的源码(直接搜索"thread.cpp"即可,或者在github里搜)

    void QThread::run() { (void) exec(); } int QThread::exec() { Q_D(QThread); QMutexLocker locker(& ...

  10. 大神为你分析 Go、Java、C 等主流编程语言(Go可以替代Java,而且最小化程序员的工作量,学习比较容易)

    本文主要分析 C.C++98.C++11.Java 与 Go,主要论述语言的关键能力.在论述的过程中会结合华为各语言编程专家和华为电信软件内部的骨干开发人员的交流,摒弃语言偏好或者语言教派之争,尽量以 ...