Laravel联合表查询使用left join造成的性能问题

Laravel联合表查询使用join造成的性能问题

问题背景:公司某单个页面查询速度缓慢,一次查询8~12秒一次,被拉去做优化,优化之后2s

具体问题

项目使用了4个join和查询了一堆用不到的数据,首先先把不需要的去掉,结果是并不会有多大的速度提升。因为你从一个表里取一列数据还是很多列数据其实它已经在这之前进行全表搜寻了(假设无索引状态),比如 select a from c where c.id = d.id,无论你最后select 出来了a还是a,b,没有很大影响。

然后是join

参考

https://blog.csdn.net/jhgdike/article/details/55052064 Mysql为什么不建议使用join
https://www.cnblogs.com/BeginMan/p/3754322.html Mysql Join语法解析与性能分析
https://my.oschina.net/jun24bryant/blog/787375 sql语句中join on和where用法的区别和联系

如果你不想理解on 和 where在 join的区别和优先顺序,更不想写一大堆join最后把自己写蒙了。更更不想你好不容易写出来之后结果其实是负优化。最好不要用join(尤其是left join)

去掉一个left join改为with,就是现在的2s了,是不是感觉 就这?

那该怎么做?

Eloquent里 return $this->hasMany or hasOne(你要链接的表::class, ‘两个你想查找’,‘的表的关联的键’)(如’id’, ‘patient_id’)->select(‘你要找出来的东西’)
然后在控制器里with一下这个function。其实就是去mysql里select xxxx where akey=bkey 而join是会生成中间表。在这里理解的不太好,抱歉,时间比较紧迫。

意外的学习:paginate导致的性能问题

通过查看sql慢查询发现,每一次访问数据paginate会生成两条sql语句,其中一条是访问会count(*) 查看总条数,如果你联合了很多表,这可能会导致很慢。然后又学习到了其实count(*)的速度并不会比加了索引的count(id)速度慢,因为count(*)不会取值

下面是教程, 不想仔细看可以不看 ->
count()是一个聚合函数,对于返回的结果集,一行行地判断,如果count函数的参数不是NULL,累计值就加1,否则不加。最后返回累计值。
count的用法有多种,分别是count(*)、count(字段)、count(1)、count(主键id)。那么多种用法,到底有什么差别呢?当然,前提是没有where条件语句。
count(id):InnoDB引擎会遍历整张表,把每一行的id值都取出来,返回给server层。server层拿到id后,判断是不可能为空的,就按行累加。
count(1):InnoDB引擎遍历整张表,但不取值。server层对于返回的每一行,放一个数字1进去,判断是不可能为空的,按行累加。
count(字段):

如果这个“字段”是定义为not null的话,一行行地从记录里面读出这个字段,判断不能为null,按行累加;
如果这个字段定义允许为null,那么执行的时候,判断到有可能是null,还要把值取出来再判断一下,不是null才累加。
count():不会把全部字段取出来,而是专门做了优化,不取值。count()肯定不是null,按行累加。
所以结论很简单:按照效率排序的话,count(字段)<count(主键id)<count(1)≈count(),所以建议读者,尽量使用count()。
注意:这里肯定有人会问,count(id)不是走的索引吗,为什么查询效率和其他的差不多呢?陈某在这里解释一下,虽然走的索引,但是还是要一行一行的扫描才能统计出来总数。

https://www.cnblogs.com/kehoudaan/p/12631571.html Mysql性能优化:为什么你的count(*)这么慢?

最终结论

如果还需要继续优化的话会想着解决一下paginate的问题。但绝对不是用简单分页里压根不查询总页这么2的解决方案,因为解决问题的方案绝对不是删掉整个问题。我目前的想法是缓存下查询到的总页在之后的访问不再访问(当然如果你的数据在频繁改变就不好用了)。
在这个问题出现之初查到的方案总是在说分库分表,加索引。优化sql的问题一定要先从语句有没有问题开始,没有问题就索引,再不行再分表,分库,再再不行再换库,mysql做好优化绝对性能不止如此。如果你语句性能都不行,问题很多,你光想着给我换一个天河一号跑起来是不是就不卡了,真的不能叫程序员。请叫土大款。

(mysql深入了解过后会发现要知道的事情可太多了,还要注意eloquent里语句的执行顺序,我曾经以为paginate写在后面会导致查询到所有数据后再limit,其实paginate执行顺序倒数第二。。。,会先收集到你写的所有语句,然后按照顺序转化为sql语句再执行下去,我还在那里吹说我发现了奇点。)最后的最后。实习生一枚,如有错误,请直接指出,我喜欢学习错误,感谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值