MySQL SQL优化

MySQL SQL优化

1 分批处理

博主小时候看到鱼塘挖开小口子放水,水面有各种漂浮物。浮萍和树叶总能顺利通过出水口,而树枝会挡住其他物体通过,有时还会卡住,需要人工清理。MySQL就是鱼塘,最大并发数和网络带宽就是出水口,用户SQL就是漂浮物。不带分页参数的查询或者影响大量数据的update和delete操作,都是树枝,我们要把它打散分批处理,举例说明:
业务描述:更新用户所有已过期的优惠券为不可用状态。
SQL语句:
update status=0 FROM coupon WHERE expire_date <= #{currentDate} and status=1;
如果大量优惠券需要更新为不可用状态,执行这条SQL可能会堵死其他SQL,分批处理伪代码如下:
int pageNo = 1;
int PAGE_SIZE = 100;while(true) {
List batchIdList = queryList(‘select id FROM coupon WHERE expire_date <= #{currentDate} and status = 1 limit #{(pageNo-1) * PAGE_SIZE},#{PAGE_SIZE}’);
if (CollectionUtils.isEmpty(batchIdList)) {
return;
}
update(‘update status = 0 FROM coupon where status = 1 and id in #{batchIdList}’)
pageNo ++;
}

2 操作符<>优化

通常<>操作符无法使用索引,举例如下,查询金额不为100元的订单:
select id from orders where amount != 100;
如果金额为100的订单极少,这种数据分布严重不均的情况下,有可能使用索引。鉴于这种不确定性,采用union聚合搜索结果,改写方法如下:
(select id from orders where amount > 100)
union all
(select id from orders where amount < 100 and amount > 0)

3 OR优化

在Innodb引擎下or无法使用组合索引,比如:
select id,product_name from orders where mobile_no = ‘13421800407’ or user_id = 100;
OR无法命中mobile_no + user_id的组合索引,可采用union,如下所示:
(select id,product_name from orders where mobile_no = ‘13421800407’)
union
(select id,product_name from orders where user_id = 100);
此时id和product_name字段都有索引,查询才最高效。

4 IN优化

IN适合主表大子表小,EXIST适合主表小子表大。由于查询优化器的不断升级,很多场景这两者性能差不多一样了。
尝试改为join查询,举例如下:
select id from orders where user_id in (select id from user where level = ‘VIP’);
采用JOIN如下所示:
select o.id from orders o left join user u on o.user_id = u.id where u.level = ‘VIP’;

5 不做列运算

通常在查询条件列运算会导致索引失效,如下所示:
查询当日订单
select id from order where date_format(create_time,’%Y-%m-%d’) = ‘2019-07-01’;
date_format函数会导致这个查询无法使用索引,改写后:
select id from order where create_time between ‘2019-07-01 00:00:00’ and ‘2019-07-01 23:59:59’;

6 避免Select all

如果不查询表中所有的列,避免使用SELECT *,它会进行全表扫描,不能有效利用索引。

7 Like优化

like用于模糊查询,举个例子(field已建立索引):
SELECT column FROM table WHERE field like ‘%keyword%’;
这个查询未命中索引,换成下面的写法:
SELECT column FROM table WHERE field like ‘keyword%’;
去除了前面的%查询将会命中索引,但是产品经理一定要前后模糊匹配呢?全文索引fulltext可以尝试一下,但Elasticsearch才是终极武器。

8 Join优化

join的实现是采用Nested Loop Join算法,就是通过驱动表的结果集作为基础数据,通过该结数据作为过滤条件到下一个表中循环查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再次到后一个表中查询数据。

驱动表和被驱动表尽可能增加查询条件,满足ON的条件而少用Where,用小结果集驱动大结果集。
被驱动表的join字段上加上索引,无法建立索引的时候,设置足够的Join Buffer Size。
禁止join连接三个以上的表,尝试增加冗余字段。

9 Limit优化

limit用于分页查询时越往后翻性能越差,解决的原则:缩小扫描范围,如下所示:
select * from orders order by id desc limit 100000,10
耗时0.4秒select * from orders order by id desc limit 1000000,10
耗时5.2秒
先筛选出ID缩小查询范围,写法如下:
select * from orders where id > (select id from orders order by id desc limit 1000000, 1) order by id desc limit 0,10
耗时0.5秒
如果查询条件仅有主键ID,写法如下:
select id from orders where id between 1000000 and 1000010 order by id desc
耗时0.3秒
如果以上方案依然很慢呢?只好用游标了,感兴趣的朋友阅读JDBC使用游标实现分页查询的方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值