mysql left join 耗时_MySQL Left Join(左连接) 耗时严重的问题

现象:列表页因超时查不出来东西,使用postman模拟请花费40多秒,将sql语句单独提出来后查询速度非常慢,40多秒

先上结论:

在两个表关联字段上建立索引解决此问题,下面的内容比这句话爽多了,请继续看

表结构如下:

users(用户)表:id,name

integal_record(分数记录)表:id,user_id,integal_id

其中,integal_record表的user_id关联着users表的id,业务目的是查询每个员工阅读次数、评论次数和积分总和,查询语句如下:

(里面写死的值是我从mybatis里扣出来的)

integral_id=1代表着阅读,integral_id=2代表着评论

SELECT u.`name`

, IF(SUM(ir.integral_id = 1) > 0, SUM(ir.integral_id = 1), 0) AS 'read'

, IF(SUM(ir.integral_id = 2) > 0, SUM(ir.integral_id = 2), 0) AS 'comment'

, IF(SUM(ir.integral_id = 1) > 0, SUM(ir.integral_id = 1), 0) + IF(SUM(ir.integral_id = 2) > 0, SUM(ir.integral_id = 2), 0) AS count

FROM users u

LEFT JOIN integral_record ir ON ir.user_id = u.id

WHERE u.role_code = 1

AND u.actived = 1

AND u.deleted_at > now()

AND u.network_id = 29

AND u.id NOT IN (

SELECT user_id

FROM roles

WHERE role_item_id = 7

)

GROUP BY u.id

ORDER BY ifnull(SUM(ir.integral_id = 1), 0) + ifnull(SUM(ir.integral_id = 2), 0) DESC, u.pinyin ASC;

共11644条 查询时间:27.976s

查询时间快半分钟是无法让人接受的,从表象的SQL语句来说,首先我们看到有很多SUM函数,因此我们来测试下SUM函数的计算时间,如下查询每个人阅读的累计次数:

select SUM(integral_id=1) as 'count' from integral_record group by user_id;

共13000条 查询时间:0.084s

可以看出来计算时间很长和SUM函数没什么关系,再看整个SQL除了一些SUM函数外就剩下users表左联integal_record表,我们把条件去掉,直接就写个左查询试试

select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;

共13001条 查询时间:69.919s

amazing,我的users表里有13400条数据,关联的integral_record 表里也有13000条数据,仅仅做了左连接竟然花费了70秒,这肯定是超时的元凶;所以我们explain一下,看看mysql对这条数据的查询策略:

EXPLAIN select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;

查看结果:

096977d33441?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

1550470363(1).jpg

我们看到type字段的结果是All,也就是代表全表扫描,那么就好办了,建立索引即可,其中users表中的id属于主键,策略自增,有默认的索引,不在考虑范围内,我们仅需对integral_record表增加索引即可:

alter table integral_record add index user_id_index(user_id)

继续执行左联语句查看运行时间:

select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;

共13406条 查询时间:67.549s

时间仍然很久,索引并没有起作用,这里排除一些逃避困难时的迷信想法:mysql有bug 或者navicat有bug,有网络问题 哈哈哈.....我们来看左联的关键属性:

096977d33441?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

索引.jpg

user_id竟然是varchar的 ,但是users表中的id是int,这就造成了left join on users.id =integral_record.user_id时有类型转换的问题而不能使用索引,因此,我们把user_id更改成int,再看看时间....(尽管两三句就写完了,这个数据类型烦扰了我整整找了一上午去找)

select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;

共13406条 查询时间:0.375s

执行时间从60多秒变成了0.375s,整个世界都安静了,再次explain一下

EXPLAIN select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;

096977d33441?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

explain改.jpg

发现mtemp(integal)表的检索方式从all变成了ref,索引,快的一批,深呼吸....

后记

希望继续遇到这种sql需要优化的问题来增加sql调优相关经验

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值