体验千万级别慢查优化 --生产环境真的发生了慢查怎么办???

一、优化方法

说起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优化的代码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值