这个功能一年左右之前就以知晓,应该是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. Emgu-WPF 激光雷达研究-绘制雷达图

    原文:Emgu-WPF 激光雷达研究-绘制雷达图 硬件:Hokuyo URG04LX 环境:VS2017- win10- 64  Emgu_3.2.0.2682 语言:C#  WPF   数据解析参考 ...

  2. wpf 绑定数据无法更新ui控件可能存在的问题

    BindingMode的枚举值有: ① OneWay ② TwoWay ③ OneTime:根据源端属性值设置目标属性值,之后的改变会被忽略,除非调用BindingExpression.UpdateT ...

  3. uwp 获取系统字体库

    原文:uwp 获取系统字体库 效果图: 要获取到字体库首先要在 NuGet 添加 SharpDx.Direct2D1  api: /// <summary> /// 获取系统字体库列表 / ...

  4. Microsoft Enterprise Library 5.0 系列(四)

    企业库日志应用程序模块工作原理图: 从上图我们可以看清楚企业库日志应用程序模块的工作原理,其中LogFilter,Trace Source,Trace Listener,Log Formatter的信 ...

  5. 将多个文本文件内的数据导入到Datagridview

    private BindingList listXSxxInfoList = new BindingList(); openFileDialog1.Multiselect = true;//允许选择多 ...

  6. NET C#创建WINDOWS系统用户

    原文:NET C#创建WINDOWS系统用户   /前提是当前用户有相应的权限 /WinNT用户管理 using System; using System.DirectoryServices;  na ...

  7. 轮廓追踪与C#实现

    原文:轮廓追踪与C#实现 轮廓追踪是图像处理中常见的方法,主要目的是追踪二值图像中目标物体的外轮廓,所得结果为单像素闭合轮廓. 流       程: 1. 确定种子点,即追踪的起始像素(如最左上方在轮 ...

  8. 在Delphi中编辑res文件

    先用记事本编写一个rc的文件.如内容为:_Comms RCData Comms.jpg Comms.jpg为图片名称,然后在这个rc文件和图片拷贝到delphi安装路径的bin文件夹里面,选中这两个文 ...

  9. Delphi事件的广播

    原文地址:Delphi事件的广播 转作者:MondaySoftware 明天就是五一节了,辛苦了好几个月,借此机会应该尽情放松一番.可是想到Blog好久没有写文章,似乎缺些什么似的.这几个月来在项目中 ...

  10. C++虚函数表解析(图文并茂,非常清楚)( 任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法)good

    C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术 ...