分库分表实战:小试牛刀—千万级数据之SQL优化
来源:51cto
时间:2023-01-16 17:04:28 154浏览 收藏
本篇文章向大家介绍《分库分表实战:小试牛刀—千万级数据之SQL优化》,主要包括优化、监控、SQL,具有一定的参考价值,需要的朋友可以参考一下。
前 言
sql优化是非常重要,因为即使再好的MySQL设计架构,也扛不住一个频繁查询的垃圾sql语句。
关于sql的优化,我们也是有一定的原则和先后顺序的,大体的步骤的我们用一张流程图来看一下:
总体呢,大概可以分为以下几个步骤:
(1)首先,我们得要看下sql语句中是否有join语句,比如内连接查询inner join,外连接查询 left join right join等;因为join语句一般都涉及到跨表查询了,所以首先我们得要为join语句中,负责连接两张表的字段创建索引,这样的话可以利用索引加快两张表关联的速度。
(2)接下来,我们会再看一下sql语句中的where语句,我们可以根据当前表中的数据量,以及where语句的过滤条件,预估下查询结果的数据量是否会很大,如果数据量很大的话,查询的速度肯定就会很慢,所以,为了提高sql语句的执行效率,我们得要为where语句中过滤字段单独创建索引。
(3)当我们把join语句以及where语句中的字段优化完之后,就可以来看一下其他的一些细节部分,比如sql语句中如果使用了聚合函数,或者对查询的结果进行了排序,那么,一般我们都建议为聚合函数中的字段,以及排序的字段都创建索引,让这些操作利用索引速度更快点。
sql优化中不管是对where语句、聚合函数、还是排序操作的优化,优化起来相对而言会简单点,为对应的字段创建合适的索引就可以了,但是,join语句这块的优化涉及到一些比较重要的原理,我们还是有必要来看下的。
简单来说,在mysql中使用join语句关联2张表的话,比如执行这条sql:
select * from order_info t1 left join order_item_detail t2 on t1.order_no = t2.order_no
这个时候,join关联查询的过程是什么样子的呢?其实,这个就取决于当前join语句用到的算法了,join语句一共有3种算法,最基础的是Simple nested loop算法,接下来,我们一起来看下。
Simple nested loop算法
Simple nested loop算法,说白了就是一个双重for循环遍历的算法,Simple nested loop算法匹配的过程是这样的:
从左边的驱动表order_info中,每取出一条记录都要遍历一遍被驱动表order_item_detail,说白了就是一个双重for循环。
如果驱动表和被驱动表中都有100条数据的话,那么此时就需要匹配 100 * 100 = 10000次,可见效率是非常低的,所以,MySQL并没有选择使用 Simple nested loop 算法,而是使用了优化后的Block nested loop 算法。
Block nested loop 算法
Block nested loop 算法对 Simple nested loop 算法进行了优化,它引入了 join buffer,join buffer 主要用于优化不带索引条件的 join 查询,它会缓存连接过程中用到的字段,这样可以有效减少匹配次数,就像这样:
可以看到,Block nested loop的优化思路,是减少被驱动表的匹配次数,它主要是通过一次性缓存驱动表的多条数据,以此来减少被驱动表的匹配次数,从而可以达到提升性能的目的。
需要注意的是,MySQL提供了一个参数join buffer_size,它是用来控制 join buffer 大小的,而MySQL默认的join_buffer_size 是 256K,所以如果驱动表的数据太多的话,默认的join buffer可能一次性放不下全部的数据。
这个时候,join buffer就会采用分段缓存的机制来缓存驱动表的数据,但是这种分段缓存方式的性能,是比一次性缓存全部数据要差一些的。
所以,我们可以通过join_buffer_size参数,适当调大join buffer的大小,使join buffer可以一次性放下驱动表的所有数据,这样可以提升join的性能。
Index nested loop算法
最后还有一种Index nested loop算法:
它的优化思路主要是减少被驱动表数据的匹配次数, 就是驱动表直接与被驱动表的索引进行匹配,这样就不用和被驱动表的每条记录比较了。
原来的匹配次数为:驱动表行数 * 被驱动表行数,而现在变成了:驱动表行数 * 被驱动表索引的高度,这样就极大的减少了被驱动表的匹配次数,极大的提升了join的性能。
如果join关联查询能使用到索引的话,MySQL就会使用Indexnestedloop算法,如果无法使用Indexnestedloop算法,MYSQL默认会使用Blocknestedloop算法。
到底能不能使用join?
好了,我们刚才了解了Simple nested loop 、 Block nested loop、Index nested loop 这三种算法,那么现在可以回答开头的问题了:到底能不能使用join?
其实,如果能用上被驱动表上的索引,说白了就是可以用上 Index nested loop 算法的话,是可以使用 join 的。
而如果使用的是 Block nested loop 算法的话,由于扫描行数和比较次数会比较多,所以会占用大量的系统资源,所以这种情况能不用join就不用join。
我们平常使用explain优化sql的时候,如果 explain 结果中的 Extra 字段,如果包含 ' Using join buffer (Block Nested Loop) ' 的话,这个时候就代表使用了 Block nested loop 算法了。
如果能使用上被驱动表上的索引的话,join还是可以使用的,这个时候基本不会影响性能,那么我们这里为什么要优化掉join呢?
主要由于2个原因,首先后边我们有分库分表的计划,所以为了有更好的扩展性,我们会优化掉join,其次MySQL是专门用来做数据存储的,所以,还是尽量不要把业务相关的逻辑放到MySQL层面来做。
所以基于这2个原因,我们会将单体应用版本的join给优化掉。
join关联查询优化实战
被驱动表order_no列未加索引
(1)join关联查询sql语句
可以看到,sql语句中,left join语句中,订单明细表是通过order_no字段和订单表关联的,此时驱动表order_info的order_no是加了索引的,而被驱动表order_item_detail的order_no字段没有添加索引
(2)看一下查询时间
此时order_info中的数据量为2500万条,而订单明细表 order_item_detail 的数据量是1亿条。
可以看到被驱动表order_item_detail没使用到索引时,查询效率是非常低下的。
优化:被驱动表order_no列添加索引
(1)为被驱动表添加索引
现在我们为被驱动表order_item_detail的order_no添加索引,添加索引sql如下:
create index inx_item_order_no on order_item_detail (order_no);
(2)再次查看join关联查询的时间
此时我们发现被驱动表order_item_detail的关联字段order_no用上索引后,查询效率提升的非常明显。
进一步优化:去掉join
此时我们为了更好的扩展性,需要将join关联查询给优化掉
(1)看下join优化后的代码:
拆分join,改成单表查询,内存中再组装数据
(2)看一下优化后的时间
可以看到,将join关联查询优化掉之后,我们除了可以获取到更大的扩展性外,可以发现对查询性能的提升也是非常大的。
被动向主动的转变,监控系统诞生
在sql优化这个例子中,这个问题是由DBA同学发现的,然后DBA同学将问题反馈给了我们,实际在工作中呢,也可能是产品同学发现订单信息查询页面有点慢,然后将问题反馈给我们。
不管是谁发现的,对于我们订单系统的开发人员来说都是非常被动的,因为我们不能及时主动的发现问题,比如某一个接口变慢了,我们不能及时知道,只能等别人反馈给我们,这样被动的发现问题,会在一定程度上扩大问题的影响。
为了解决这个问题,我们建立了一套完善的监控系统,这个监控系统呢,可以添加很多监控面板,比如我们可以添加订单的监控面板,订单监控面板中的核心指标包含:订单核心接口的请求次数、失败次数、TP50、TP99等等。
然后,为了及时发现问题,这个监控系统还集成了报警的功能,说白了就是针对某一个监控指标,我们会设置一个报警规则,比如每天的某一个时间段,在多少分钟内,失败请求超过多少,那么就会报警给对应的开发人员,报警方式呢,会分为2种,分别是报警电话和消息推送(推送给公司内部的办公聊天软件)
报警的时候为了避免开发人员的单点故障,报警接收人一般会添加多个,如果第一个人不接报警电话的话,那么就顺延给第二个人打电话,这样就可以最大程度的及时发现问题了,就可以真正的由被动转为主动了。
今天关于《分库分表实战:小试牛刀—千万级数据之SQL优化》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
-
481 收藏
-
136 收藏
-
483 收藏
-
268 收藏
-
320 收藏
-
475 收藏
-
266 收藏
-
273 收藏
-
283 收藏
-
210 收藏
-
371 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 明理的发带
- 这篇博文出现的刚刚好,up主加油!
- 2023-02-20 06:56:40
-
- 慈祥的老师
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢老哥分享文章!
- 2023-02-18 20:59:49
-
- 生动的抽屉
- 这篇文章真是及时雨啊,很详细,写的不错,码起来,关注楼主了!希望楼主能多写数据库相关的文章。
- 2023-02-02 04:54:04
-
- 俊秀的向日葵
- 很详细,码起来,感谢大佬的这篇技术贴,我会继续支持!
- 2023-01-26 06:55:06
-
- 正直的棒棒糖
- 这篇技术贴真是及时雨啊,太全面了,感谢大佬分享,码起来,关注作者大大了!希望作者大大能多写数据库相关的文章。
- 2023-01-18 11:52:04