设为首页 收藏本站
查看: 982|回复: 0

[经验分享] msyql sql优化一列

[复制链接]

尚未签到

发表于 2018-10-21 11:00:01 | 显示全部楼层 |阅读模式
  一个在SSD硬盘64核CPU服务器上跑出来的慢sql,执行时间在2s左右,写出来做个记录:
  select
  a.sub_id subid,
  a.sub_user_type subtype,
  a.longitude lng,
  a.latitude lat,
  a.sub_content subcontent,
  case
  when b.is_top = 1 and b.top_start_time  = now() then 1
  else 0
  end istop,
  a.perfect_sign isperf,
  a.vote_sign isvote,
  a.publisher,
  UNIX_TIMESTAMP(a.sub_time) subtime,
  a.show_persons vnum,
  (select count(1) from app_find_praise where object_id = a.sub_id and object_class =0) znum,
  (select count(1) from app_find_comment where object_id = a.sub_id and object_class= 0 and comment_status = 0) rnum,
  if((select count(1) from app_find_praise where object_id = a.sub_id and object_class = 0 and user_id = 'd7b4e485d9fe11e5a9c95fa622b527a1') > 0, 1, 0) iszan,
  if((select count(1) from app_find_mycollect where object_id = a.sub_id and       object_type = 0 and user_id = 'd7b4e485d9fe11e5a9c95fa622b527a1') > 0, 1, 0) iscoll,
  if((select count(1) from app_find_subject_hot where sub_id = a.sub_id) > 0, 1, 0) isHot
  from app_find_subject a
  inner join app_find_subject_hot b
  on b.sub_id = a.sub_id
  where (a.sub_status = 0 or (a.sub_status in (0, 3) and a.publisher='d7b4e485d9fe11e5a9c95fa622b527a1'))
  and a.is_public = 1
  order by b.is_top = 1 and b.top_start_time = now() desc,
  a.sub_time desc
  limit 10
  第一眼看有limit 10做限制,应该不会执行太慢,查看执行计划等逐一排查导致慢的原因在于order by的使用,这个order by的写法在于按扫描顺序对满足条件的进行排序,其余的都是乱序的(PS:我也是第一次见这种写法),结果和开发沟通是否业务上需求的能不能改掉这order by,答案是不可以改...........
  首先说下为什么使用limit效率会相当慢,首先sql语句的执行顺序为查询数据->where条件->order/group by->limit ,这样的一个顺序limit要等数据查询完成在order by时才能起到优化作用,而前面又有几个嵌套子查询和join,不需要的数据也执行了嵌套查询,这导致很多执行时间是对最终结果无用的
  优化思路:观察order by使用的是a、b两个表的字段,经过查询结构数据,发现a、b两个表连接条件都为主键,这可以确定数据唯一,不会在嵌套时产生一对多的情况,那就利用延迟关联的方式先把满足order by条件的10条数据先取出来,再利用这10条数据进行对其他数据表的关联查找
  下面是修改过后的sql:
  select a.sub_id subid,
  a.sub_user_type subtype,
  a.longitude lng,
  a.latitude lat,
  a.sub_content subcontent,
  b.istop,
  a.perfect_sign isperf,
  a.vote_sign isvote,
  a.publisher,
  UNIX_TIMESTAMP(a.sub_time) subtime,
  a.show_persons vnum,
  (select count(1) from app_find_praise where object_id = a.sub_id and object_class =0) znum,
  (select count(1) from app_find_comment where object_id = a.sub_id and object_class = 0 and comment_status = 0) rnum,
  if((select count(1) from app_find_praise where object_id = a.sub_id and object_class = 0 and user_id = 'd7b4e485d9fe11e5a9c95fa622b527a1') > 0, 1, 0) iszan,
  if((select count(1) from app_find_mycollect where object_id = a.sub_id and object_type = 0 and user_id = 'd7b4e485d9fe11e5a9c95fa622b527a1') > 0, 1, 0) iscoll,
  if((select count(1) from app_find_subject_hot where sub_id = a.sub_id) > 0, 1, 0) isHot
  from
  (select bb.sub_id as sub_id,case
  when bb.is_top = 1 and bb.top_start_time = now() then 1
  else 0
  end istop from app_find_subject_hot bb join app_find_subject aa on aa.sub_id = bb.sub_id
  order by  bb.is_top = 1 and bb.top_start_time = now() desc,
  aa.sub_time desc limit 10) b
  join app_find_subject a on (a.sub_id = b.sub_id);
  现在来进行效率对比(采用profiles查看分别都执行两次的时间):
  优化前:
  |        1 | 2.29620150 |
  |        2 | 2.33743150 |
  优化后:
  |        3 | 0.08940750 |
  |        4 | 0.09856800 |
  经过执行时间来看优化提升是很多的,该优化增加了一个子查询作为整个嵌套循环的驱动表,删除了a表查询的条件语句,通过业务结构判断从b表查询出来的10条数据基本不会不满足a表这些条件,看到这可能有人已经发现对a表做了两次嵌套,会觉得这里写成一次不会更好么,下面看改为一次查询效率:
  select
  a.sub_id subid,
  a.sub_user_type subtype,
  a.longitude lng,
  a.latitude lat,
  a.sub_content subcontent,
  case
  when b.is_top = 1 and b.top_start_time  = now() then 1
  else 0
  end istop,
  a.perfect_sign isperf,
  a.vote_sign isvote,
  a.publisher,
  UNIX_TIMESTAMP(a.sub_time) subtime,
  a.show_persons vnum
  from
  app_find_subject_hot b
  JOIN app_find_subject a
  on (b.sub_id = a.sub_id)
  order by b.is_top = 1 and b.top_start_time = now()     desc,a.sub_time DESC
  limit 10;
  改成这样把a表所需字段数据一起查询出来,看看执行效果:
  |        1 | 0.24470025 |
  |        2 | 0.20582050 |
  这还是没有对其他子查询进行查找的情况下,所需时间比多一次嵌套的优化执行时间更长,这是因为这样对a表字段进行查找时,在limit之前需要返回足够多数据,而每次对a表进行嵌套时都进行了数据扫描,如果不查询其他字段只需要sub_id,a表就只进行了主键索引查找,不会去对数据进行扫描,对CPU时间消耗更低,再次嵌套时就只对表数据进行了10次扫描,当然开销更小,这告诉我们sql优化是门复杂课程,需要结合具体场景进行,书上或者网上别人说的知识都是死的,怎样的方式更优需结合具体的场景


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-624418-1-1.html 上篇帖子: oracle11G不存在scott.sql文件解决方法 下篇帖子: sql随笔
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表