用户反映MYSQL中某个表前端查询很慢,前端显示需要10多秒,于是我方把监控到的SQL语句执行查询,结果如下:
SELECT sum(num)FROM `user_coin_log` force index (ix_5)WHERE `create_time` >= 1584892800AND `create_time` < 1584979200AND `source` = 5AND `uid` IN ( 23, 24, 26, 29, 32, 33, 38, 42, 52, 59, 68, 69, 71, 72, 73, 79, 83, 85, 108, 111, 139, 229, 261, 280, 281, 283, 296, 298, 308, 401, 423, 490, 523, 650, 653, 776, 903, 913, 966, 997, 1030, 1381, 1704, 1809, 1922, 1943, 2011, 2037, 2146, 2459, 2757, 3055, 3087, 3098, 3280, 3315, 3427, 3701, 5132, 5625, 6646, 7628, 8040, 8464, 23304)AND `coin_id` = 1LIMIT 1
执行时间需要5.466S,于是分析这个SQL语句,从语句的结构来看,where条件有时间create_time,uid等条件过滤,直觉应该不至于如此慢,而且该表上是有一个索引ix_5,同时覆盖了create_time,uid,source,coin_id,num等列的,但此SQL执行计划并没有走这个索引,而是走了一个单列索引UID不太合理,于是经过多方面排查与尝试,如果把这个UID条件去掉,或把UID里面的列表值大量减少,这个时候会走ix_5索引,甚至如果让uid in一个临时表(把所有的uid值建成1个临时表),这个时候也会走ix_5索引,执行时间会在0.8s内!
顺着这个方向继续排查,发现网上有不少类似的案例,其现象都是:in后面如有太多值,MYSQL会认为全面扫描会更有效率,看来这一点还是不够oracle的优化器智能啊!于是尝试采用强制索引的方案来解决,具体加上(force index (ix_5))后,语句变成:
SELECT sum(num)FROM `user_coin_log` force index (ix_5) WHERE `create_time` >= 1584892800AND `create_time` < 1584979200AND `source` = 5AND `uid` IN ( 23, 24, 26, 29, 32, 33, 38, 42, 52, 59, 68, 69, 71, 72, 73, 79, 83, 85, 108, 111, 139, 229, 261, 280, 281, 283, 296, 298, 308, 401, 423, 490, 523, 650, 653, 776, 903, 913, 966, 997, 1030, 1381, 1704, 1809, 1922, 1943, 2011, 2037, 2146, 2459, 2757, 3055, 3087, 3098, 3280, 3315, 3427, 3701, 5132, 5625, 6646, 7628, 8040, 8464, 23304) AND `coin_id` = 1LIMIT 1
再次执行:
加上HINT后,SQL效率得到了10倍以上的提升,由原来的5.4S下降到0.3S,性能提升效果显著!
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛