前言
大家好,我是华仔。
欢迎加入华仔的星球,你将获得: 专属的中间件专栏 / 1v1 提问 / 简历修改指导/ 学习打卡 / 每月赠书 / 社群讨论
《从四大维度开始带你精通 RocketMQ》 已爆肝完毕,基于 RocketMQ 5.1.2 版本进行源码讲解。 《从四大维度开始带你精通 Kafka》 已爆肝完毕,基于 Kafka 2.8 以及 3.x 版本进行源码讲解。 截止目前,累计输出 500w+ 字,讲解图 2000+ 张,还在持续爆肝中.. 后续还会上新更多项目和专栏,目标是打造地表最强中间件星球,戳我加入学习,已有440+小伙伴加入,电商实战项目火热更新中,结束时会有简历指导包装,需要的抓紧来。
这里说几点,解答一些疑惑,可以认真看下:
1、星球内容只会越来越完善,价格越来越贵,一年时间从69元开始发售到现在已经涨到了199元,还会继续涨价,所以需要抓紧来,越早越受益,别错过。
2、只筛选认可且支持我的老铁,我不喜欢白嫖怪,尊重别人就是尊重自己。
3、对于星球年费说下,只是到期后新内容看不到,已经更完的内容相当于一次付费永久看,所以认可我内容的可以放心来,有疑问文末加我好友进行答疑。
4、除专栏外,我会提供专属的一对一答疑服务,包括不限于工作中、专栏中遇到的问题,简历修改指导、职业规划服务等。这也是星球的特色服务。
我们去面试的时候,经常被问到,日常工作中,是如何优化SQL的。今天跟大家再聊聊哈。
这里应该如何去回答呢?可以从各种不同维度的,今天我再换个角度。
加索引 避免常见的索引不生效场景 避免返回不必要的数据 减少不必要的逻辑 分批量进行思想 读写分离 优化sql结构 分库分表 性能优化分析神器—explain 慢SQL排查思路
1. 加索引
很多时候,我们的慢查询,都是因为历史原因没有加索引,或者忘记加索引导致的。如果没有加索引的话,会导致全表扫描的。因此,应考虑在where的条件列,建立索引,尽量避免全表扫描。
反例:
select * from user_info where name ='捡田螺的小男孩公众号' ;
正例:
//添加索引
alter table user_info add index idx_name (name);
2. 避免常见的索引不生效场景
我之前整理了常见的十种索引不生效的场景,大家可以看看:
隐式的类型转换,索引失效 查询条件包含or,可能导致索引失效 like通配符可能导致索引失效 查询条件不满足联合索引的最左匹配原则 在索引列上使用mysql的内置函数 对索引进行列运算(如,+、-、*、/) 索引字段上使用(!=或者<>),索引可能失效 索引字段上使用is null,is not null,索引可能失效 左右连接,关联的字段编码格式不一样 优化器选错了索引
3. 避免返回不必要的数据
这个点,我在昨天的文章,其实就提到一个点,包括尽量使用limit,避免不必要的返回。
其实这不仅仅是一个点,而是一种思想,就是要什么查什么,而不是返回一些不必要的数据。还有:查询SQL尽量不要使用select *,而是select具体字段。也是这种思想。
反例子:
select * from employee;
正例子:
select id,name, age from employee;
select具体字段,节省资源、减少网络开销。 select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。
4. 减少不必要的逻辑
其实,尽量用 union all 替换 union,就是这种思想。
如果我们明知道,检索结果中不会有重复的记录,推荐union all 替换 union。
因为:
如果使用union,不管检索结果有没有重复,都会尝试进行合并,然后在输出最终结果前进行排序。如果已知检索结果没有重复记录,使用union all 代替union,这样会提高效率。
5. 分批量进行思想
我们更推荐批量查询、插入、删除。
反例:
for(User u :list){
INSERT into user(name,age) values(#name#,#age#)
}
正例:
//一次500批量插入,分批进行
insert into user(name,age) values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.name},#{item.age})
</foreach>
理由:
批量插入性能好,更加省时间 打个比喻: 假如你需要搬一万块砖到楼顶,你有一个电梯,电梯一次可以放适量的砖(最多放500),你可以选择一次运送一块砖,也可以一次运送500,你觉得哪个时间消耗大?
6. 读写分离
一般情况我们的数据库架构,都要做主从的,然后进行读写分离。主库主要负责写,和一些实时性比较高的读。而从库就负责读实时性要求不高的请求。
这样的话,我们不用所有请求都到主库,大大降低了主库的压力。你试想一下,如果所有读请求都到主库,查询压力肯定很大,处理也会相对慢一点。
7. 优化sql结构、逻辑
有些时候,优化SQL结构,都能有一些预想不到的优化效果。
假设我们有个客户表和一个订单表。其中订单表有10万记录,客户表只有1000行记录。
现在要查询下单过的客户信息,可以这样写:
SELECT * FROM customers
WHERE id IN (
SELECT customer_id FROM orders
);
in 查询会先执行内部查询部分 SELECT customer_id FROM orders,获得 orders 表(大表)中的所有 customer_id,然后在 customers 表(小表)中查找匹配的 id。
也可以这样实现:
SELECT * FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
EXISTS 会逐行扫描 customers 表(即小表),对每一行 c.id,在 orders 表(大表)中检查是否有 customer_id = c.id 的记录。
因为orders表的数据量比较大,因此这里用exists效果会相对更好一点。其实这就是小表驱动大表的思想。我们也只是调整SQL结构,用exists去替换in,优化效果也是比较明显的。
8. 分库分表
如果单表的数据量很大,达到百万甚至千万级别,我们这种时候,就是加了索引,可能效果也不是很明显。这时候我们可以考虑分库分表啦~~
分库分表一般都是依赖客户号、用户Id、或者时间来拆分。但是需要注意一下,分库分表存在的一些一些问题:
事务问题 跨库关联JOIN 排序问题 分页问题 分布式ID选择
9. 性能优化分析神器—explain
之前我写SQL习惯的时候,有提到explain,就是每次写完查询SQL,都用explain看一下它的执行计划。
有些面试官会单独问这个,我们可以走面试官的路,让面试官无路可走。在回答SQL优化的时候,就把这个回答了。
一般在使用explain的时候,我们要关注:type、rows、filtered、extra、key。
9.1 type
type表示连接类型,查看索引执行情况的一个重要指标。以下性能从好到坏依次:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system:这种类型要求数据库表中只有一条数据,是const类型的一个特例,一般情况下是不会出现的。 const:通过一次索引就能找到数据,一般用于主键或唯一索引作为条件,这类扫描效率极高,,速度非常快。 eq_ref:常用于主键或唯一索引扫描,一般指使用主键的关联查询 ref : 常用于非主键和唯一索引扫描。 ref_or_null:这种连接类型类似于ref,区别在于MySQL会额外搜索包含NULL值的行 index_merge:使用了索引合并优化方法,查询使用了两个以上的索引。 unique_subquery:类似于eq_ref,条件用了in子查询 index_subquery:区别于unique_subquery,用于非唯一索引,可以返回重复值。 range:常用于范围查询,比如:between ... and 或 In 等操作 index:全索引扫描 ALL:全表扫描
9.2 rows
该列表示MySQL估算要找到我们所需的记录,需要读取的行数。对于InnoDB表,此数字是估计值,并非一定是个准确值。
9.3 filtered
该列是一个百分比的值,表里符合条件的记录数的百分比。简单点说,这个字段表示存储引擎返回的数据在经过过滤后,剩下满足条件的记录数量的比例。
9.4 extra
该字段包含有关MySQL如何解析查询的其他信息,它一般会出现这几个值:
Using filesort:表示按文件排序,一般是在指定的排序和索引排序不一致的情况才会出现。一般见于order by语句 Using index :表示是否用了覆盖索引。 Using temporary: 表示是否使用了临时表,性能特别差,需要重点优化。一般多见于group by语句,或者union语句。 Using where : 表示使用了where条件过滤. Using index condition:MySQL5.6之后新增的索引下推。在存储引擎层进行数据过滤,而不是在服务层过滤,利用索引现有的数据减少回表的数据。
9.5 key
该列表示实际用到的索引。一般配合possible_keys列一起看。
10. 慢SQL排查思路
如果大家平时有优化过生产的慢SQL,有自己的一套排查那一套最好哈。如果没有的话,可以在自己搞个深分页,或者因为数据量、或者因为没加索引等原因,导致的慢SQL,然后按照这个思路去排查一遍。
查看慢查询日志记录,分析慢SQL explain分析SQL的执行计划 profile 分析执行耗时 Optimizer Trace分析详情 确定问题并采用相应的措施
如果不熟悉的话,可以多操作几遍,尽量熟悉操作流程,在面试的时候,讲一下这个主要流程。
最后推荐下两个不错的产品,感兴趣的可以 上车了,这里只吸引同频的人,如果加入几分钟 就直接退出的就不要来了,浪费我的名额。 第一个来自码哥的小报童,仅需 19 元,刚开始更新,需要的可以扫码加入。 本专栏内容涵盖 Java 基础、Java 高级进阶、Redis、MySQL、消息中间件、微服务
架构设计等面试必考点、面试高频点。本专栏不只是单纯教大家学会背八股文知识,
更多是结合实际大厂高并发项目的场景,去学习面试技术要点。从面试官的角度去出
发,介绍互联网 Java 流行技术体系各个面试要点。
本专栏适合于准备进阶 Java 后端技术、有面试或提升技术需求,希望学习互联网大
厂 Java 流行技术体系的程序员和面试官,助你拿到名企高薪 Offer。
第二个是我的知识星球,已涨价到 199 元,需要的可以扫码加入。 关于星球介绍点击: 超 500 万字详解,从零到一带你彻底吃透 Kafka + RocketMQ 小红书实战 需要续费的扫这个,优惠15元 另外必须要注意的是上车的老铁一定要加我微信 好友,拉你们加入星球专属交流群。