一、优化方法
说起mysql查询优化的方法,大家肯定都能说出一堆。
1 、避免返回大量数据,可使用分页。limit 有什么坏处:当 offset 太大是,查询速 度会降低!
2、 建合适的索引(对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引)
3、 尽量不要使用左右模糊查询,右模糊查询是可以走索引的
4 、尽量不要使用 or,!=导致全表扫描,可以改为分别查询使用 union all
5 、对索引字段不要使用函数、运算符,索引失效
6、很多时候用 exists 代替 in 是一个好的选择
7、 任何地方都不要使用 select * ,不要返回用不到的任何字段
8、 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用 索 引而进行全表扫描,如: select id from t where name is null 可以在 name 上设置默认值 “”,确保表中 name 列没有 null值
9、SQL 是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,male、 female 几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用
10 、索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低 了 insert 及update 的效率,一张表最好索引个数保持在6个以内
11、使用联合索引,将最常用字段放在前面,由于索引遵循最左原则,如索引(a,b,c) 条件查询 ab,a,abc 索引生效,其他就不行啦
12、对于千万级别的大表,不要轻易使用join,因为执行计划不好的话,肯定出现慢sql,甚至sql超时。
…
以上巴拉巴拉还有很多,BUT 你真的这么做了吗?
二、实践
1.示例一
最近我就遇到了索引走偏,导致生产环境重超时,解决问题的冷汗直冒…
sql如下:
a表索引 nid
b表索引item_id,单独索引brand_id
SELECT brand_name
FROM t_model a
INNER JOIN t_relation b
ON a.nid = b.nid
AND b.is_deleted = 0
AND b.item_id = '1130282'
WHERE b.brand_id IN (200, 201, 202, 2095, 100135, 100355, 101335, 101437, 1235, 101331)
GROUP BY brand_name
这条sql一直线上跑了半年都没出问题,突然有一天出问题了,查询超时。
收到反馈之后,立马看了下两种表的大小,a表30w数据,b表1300w数据。猜测b表数据太多引起的,果不其然是昨天晚上有同事导入了500w数据进去。但是也不应该啊,才1300w而已,并且我有索引啊,不是能走到item_id 索引,性能还能差到哪里去。
在线上mysql查看了执行计划,让我崩溃,尽然走的是brand_id索引,扫描函数80w条,查询下时间5s钟。由于我们用的是阿里云数据库,去阿里云hdm上查到相关应用查询慢sql,找到属于咱的那条记录,点击分析,可以看到当时的执行计划走的索引是brand_id。但是我在测试环境看的都是走的是item_id 啊,不去想了,解决线上问题为主,我指定了item索引去线上库查询耗时0.059s。不想了,直接删除brand_id,重新建联合索引(brand_id,item_id) 问题得到解决,影响市场约1小时,庆幸的是该接口调用量不高。
2.示例二
有人反映同一个界面,不同条件进去后,响应速度不一样。同样一条sql时快时慢,这确实值得探讨。难道是网络问题…哈哈哈哈。。。
只好自己复现啦。
发现
当brand_name过滤性不强时,a表它只会走brand_id索引;
当brand_name过滤性很强是,a表它只会走idx_nid_acc_id索引;
同样也是sql索引问题,只好指定走索引,查询有3.5s提升到0.056s。
不指定索引,a表它有时会走brand_id索引。
sql如下:
select distinct a.acc_id as accId, a.grade_no as gradeNo
from t_model c FORCE index(idx_brandname)
inner join t_relation a FORCE index(idx_nid_acc_id) on a.nid = c.nid
where a.brand_id = #{brandId}
and a.is_deleted =0
and c.brand_name = #{brandName} and c.nid = #{nid}
但是在代码里面写FORCE index() 是不提倡的做法,可以作为临时方案,但还是得想其他办法。
咋整!咋整!咋整!
拆sql,先根据条件查询t_model 的nid,
然后t_relation 中的nid in 一下,乖乖,两条sql执行的时间和指定索引去查几乎一样。于是乎欢天喜地替换了下。
本次场景中,多次单表查询会比关联查询快!我们在coding中主要编写对sql优化的代码。