列表分页查询,求总数;
select count(*) AS num from tb_student stu inner join tb_student_parent stu_pa on stu.id = stu_pa.student_id AND stu.is_del=0 and stu_pa.is_del=0 inner join tb_parent pa on stu_pa.parent_id = pa.id and pa.is_del=0 where pa.phone = stu.phone;
数据量: 每张表平均150W, 查询耗时: 114s
where后面还有选项条件,先忽略; 求解优化;
提供一种思路,不是从数据库优化上的。不返回总页数,比如 一页 10条, 后端就查11条,前端收到如果有第11条时,可以加载第二页的按钮,如果少于11条,那正好没有下一页咯。
从 explain 的结果来看,主要耗时应该在第一次联表的时候,也就是你贴的 explain 结果的第一行,他返回了 69w 条记录,怎么能不慢...... 你说你一张表大概150w 数据,这个数据就占了一半了吧,时间复杂度上来看那几乎就等于全表扫描的平均时间了
原因的话我猜应该是 is_del 这个 key 了,如果数据量占一半以上,那在这个 key 上加索引实际应该是会降低查询效率的 你可以去掉这个 is_del 的索引再试试
@wangbinlml 如果是光count都有150W的话,如果硬要优化,倒是可以走一个比较极端的方法,减少每个字段遍历的时间 这是一个和9楼完全相反的方法,不过你要确定is_del数字在127以内 is_del先改成tinyint count(*) 改为count(is_del) where的第一个条件改为 is_del=0 来命中is_del的索引 这样应该会快很多,但要质的飞跃,还是劝你放弃count 150W+次,因为这个相加mysql都是一个一个加的,索引做字典优化意义已经不大了
楼主这样的语句,从索引角度来优化,效果不大,因为这几乎是全表扫描了。但办法总是人想出来的,虽然mysql不像oralce有物理视图,但我们可以使用物理视图的概念。做法很简单,把楼主要的数据查出放到一个张表中,写一个存储过程每天更新一次,以后分页就是单表查询了。如果你对数据的时实要求很高,就在原来表中增加触发器,当数据改动时触发。但这样会造成性能上的损失,如何把握,楼主可以自已思考一下。