MySQL 重写查询语句的三种策略


Posted in MySQL onMay 10, 2021

在优化存在问题的查询时,我们需要改变方式去获取查询结果——但这并不意味着从 MySQL获取同样的结果集。有些时候我们可以将查询转换为获取相同结果,但更好性能的查询形式。然而,我们也需要考虑重写查询去获取不同的结果,因为这样可以提高开发效率。也可以通过修改应用程序代码来取得相同的效果。本篇文章将介绍如何重写查询的技巧。

复杂查询与分步查询

一个重要的查询设计课题是将复杂查询分解为多个简单查询是否会更好。在传统的数据库设计中强调尽可能地用更少的查询解决大量工作。在过往,这种方式会更好。这是因为以前的网络通讯成本更高以及考虑查询解析器和优化器的负荷。

然而,这种建议并不怎么适用于 MySQL,这是由于 MySQL 处理建立连接和断开连接的方式十分高效,并且对简单查询的响应很快。当今的网络速度相比以前也有了大幅度的提升。根据不同的服务端版本,MySQL 可以在普通机器上一秒内运行超过10万次的简单查询,并且在千兆网络上完成每秒2000次的查询通讯。因此,进行分布查询并不是过往说的那么糟糕。

相比于每秒遍历的数据行数,连接响应依旧是比较慢的。在内存数据中,这个时间达到了毫秒级。当然,使用尽可能的查询次数依旧是一个不错的选择。但是,有时我们可以通过拆分复杂查询为几个简单的查询来提高性能。接下来我们将展示一些示例。

在程序设计中,使用过多的查询是一个常犯的错误。例如,有些应用执行了10个单独的查询来获取10行数据(使用循环一条条获取),而这本可以通过一条查询10行数据的查询来完成。因此,这并不是倡导每次都做查询的拆分,而是根据实际情况来。

切分查询语句

另一个方式是拆分查询后重新再组合。通过在大数据量的查询拆分为更小范围的查询以减少每次影响的行数。

清洗旧数据就是一个典型的例子。周期性的清洗数据工作需要移除大量数据,进行这样的操作会长时间锁定大量数据行。这种操作还会产生事务日志、消耗大量资源并且会阻塞那些本不应该被打断的小数据量的查询。将DELETE语句切分后,使用中等规模的查询可以显著改善性能,并且在查询是重复的时候可以减少重复查询产生的额外延迟。例如下面的删除语句:

DELETE FROM messages WHERE created < DATE_SUB(NOW(), INTERVAL 3 MONTH);

应用的伪代码的形式如下:

rows_affected = 0
do {
  rows_affected = do_query (
  "DELETE FROM messages WHERE created < DATE_SUB(NOW(), INTERVAL 3 MONTH)
  LIMIT 10000")
  } while rows_affected > 0

一次删除10000行对于提高每次查询的效率来说已经是一个足够大的任务了。一个足够短的任务会减少对服务端的影响(事务存储引擎会从中受益)。在 DELETE 语句中插入一些休眠时间也是一个不错的主意,这样可以在时间上分散负荷并且缩短持有锁的持续时间。

拆解联合查询

很多高性能的应用会拆解联合查询。可以通过将联合查询拆分为多个单表查询,然后在应用中再将结果组合起来。例如:

SELECT * FROM tag
	JOIN tag_post ON tag_post.tag_id=tag.id
  JOIN post ON tag_post.post_id=post.id
WHERE tag.tag='mysql';

可以将这个联合查询拆分如下是哪个部分。

SELECT * FROM tag WHERE tag='mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123, 456, 567, 9098, 8904);

注:这里的 tag_id=1234和post.id IN (123, 456, 567, 9098, 8904)都是基于前面查询的结果得到的值。为什么要这么做?第一眼看过去好像是毫无必要的——增加了查询的次数而已。然而,这种重建查询可以带来如下优势:

  • 缓存机制会更有效。很多应用直接使用 ORM 映射数据表。在这个例子中,如果 tag 为 mysql 的对象已经被缓存了,第一条查询就会跳过。如果 posts 中 id 为123,567或9908在缓存中,则可以从 IN 列表中移除这几个。通过这种策略,查询缓存会得到相应的受益。如果只有其中的一个表经常变化,拆解联合查询可以减少缓存失效的次数。
  • 单独执行这些查询有时候可以减少锁表的机会。
  • 通过这种方式很容易扩展数据库,并把数据表放到不同的机器上。
  • 查询自身可以进行优化。这个例子中,使用 IN 查询替代联合查询后,MySQL 对行 ID 进行排序和获取数据行有可能会更优。
  • 可以减少冗余的行访问。使用这种方式意味着只做一次数据行获取,而在联合查询中有可能重复获取相同的数据。基于这种原因,这种拆解方式也可能会减少整个网络负荷和内存占用。
  • 扩展一下,也可以通过人为进行哈希联合查询来替代MySQL联合查询的嵌套循环,哈希联合查询也可能会更有效。

最终可以看到,通过拆解联合查询可以使得缓存复用性更高,多服务器分布式数据方案更简单,并可以在大的数据表中使用 IN 查询替代联合查询或同一张表的多次重复查询。

以上就是MySQL 重写查询语句的三种策略的详细内容,更多关于MySQL 重写查询语句的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
MySQL kill不掉线程的原因
May 07 MySQL
深入解析MySQL索引数据结构
Oct 16 MySQL
SQL实战演练之网上商城数据库商品类别数据操作
Oct 24 MySQL
记一次Mysql不走日期字段索引的原因小结
Oct 24 MySQL
SQL 聚合、分组和排序
Nov 11 MySQL
MySQL的索引你了解吗
Mar 13 MySQL
MySql分区类型及创建分区的方法
Apr 13 MySQL
MySQL 语句执行顺序举例解析
Jun 05 MySQL
Mysql表数据比较大情况下修改添加字段的方法实例
Jun 28 MySQL
MySQL事务的隔离级别详情
Jul 15 MySQL
mysql sock文件存储了什么信息
Jul 15 MySQL
MySQL池化框架学习接池自定义
Jul 23 MySQL
详解MySQL 联合查询优化机制
mysql对于模糊查询like的一些汇总
May 09 #MySQL
MySQL Threads_running飙升与慢查询的相关问题解决
MySQL sql_mode的使用详解
May 08 #MySQL
MySQL 数据丢失排查案例
May 08 #MySQL
MySQL update set 和 and的区别
May 08 #MySQL
MySQL查询学习之基础查询操作
May 08 #MySQL
You might like
dede3.1分页文字采集过滤规则详说(图文教程)续二
2007/04/03 PHP
使用php伪造referer的方法 利用referer防止图片盗链
2014/01/20 PHP
redis查看连接数及php模拟并发创建redis连接的方法
2016/12/15 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
2017/08/28 PHP
Yii2.0使用阿里云OSS的SDK上传图片、下载、删除图片示例
2017/09/20 PHP
分析Node.js connect ECONNREFUSED错误
2013/04/09 Javascript
Nodejs进程管理模块forever详解
2014/06/01 NodeJs
ajaxFileUpload.js插件支持多文件上传的方法
2014/09/02 Javascript
javascript中Date对象的getDay方法使用指南
2014/12/22 Javascript
JavaScript取得键盘按下方向键是哪个的方法
2015/08/04 Javascript
IScroll5 中文API参数说明和调用方法
2016/05/21 Javascript
Angularjs cookie 操作实例详解
2017/09/27 Javascript
vue+element-ui实现表格编辑的三种实现方式
2018/10/31 Javascript
JavaScript实现无限级递归树的示例代码
2019/03/29 Javascript
[02:03]完美世界DOTA2联赛10月30日赛事集锦
2020/10/31 DOTA
写了个监控nginx进程的Python脚本
2012/05/10 Python
Python中decorator使用实例
2015/04/14 Python
python基础_文件操作实现全文或单行替换的方法
2017/09/04 Python
python实现识别手写数字 python图像识别算法
2020/03/23 Python
Django使用中间键实现csrf认证详解
2019/07/22 Python
python 一篇文章搞懂装饰器所有用法(建议收藏)
2019/08/23 Python
500行代码使用python写个微信小游戏飞机大战游戏
2019/10/16 Python
python实现双色球随机选号
2020/01/01 Python
关于pytorch中全连接神经网络搭建两种模式详解
2020/01/14 Python
浅谈Python线程的同步互斥与死锁
2020/03/22 Python
python matplotlib:plt.scatter() 大小和颜色参数详解
2020/04/14 Python
html5 Canvas画图教程(9)—canvas中画出矩形和圆形
2013/01/09 HTML / CSS
英国现代绅士品牌:Hackett
2017/12/17 全球购物
Bose美国官网:购买Bose耳机和音箱
2019/03/10 全球购物
沃达丰英国有限公司:Vodafone英国
2019/04/16 全球购物
电气工程自动化求职信
2014/03/14 职场文书
庆祝新中国成立65周年“向国旗敬礼”网上签名寄语
2014/09/27 职场文书
党的群众路线教育实践活动制度建设计划
2014/11/03 职场文书
2016年10月份红领巾广播稿
2015/12/21 职场文书
python实现web邮箱扫描的示例(附源码)
2021/03/30 Python
Typescript类型系统FLOW静态检查基本规范
2022/05/25 Javascript