一文搞懂mysql两大重要存储引擎innodb和myisam区别-业务优化实战mysql5.7

4 篇文章 0 订阅
2 篇文章 0 订阅
本文讲述了在MySQL5.7环境下,针对一个百万级数据的大表和两个维表的复杂查询优化过程。通过更新统计信息、SQL改写以及选择合适的存储引擎(MyISAM),将原本在生产库中执行十几分钟的查询优化至20秒内,显著提升了查询效率。作者强调了MyISAM在OLAP场景的优势,并分享了优化经验。
摘要由CSDN通过智能技术生成

业务场景

 

mysql5.7 版本,一个一百万数据表 a, 一个3千多的维表 t 一个两百多的维表补充表 s,业务逻辑如下:

  1. 维表t和维表s关联 ,拿到在表t且不在表s的数据,结果记为b
  2. 大表a和b关联 ,且要筛选a表的数据时间区间在一年内
  3. 最后基于第二步结果 对大a表发现机构字段、b表指标编号、违法行为为维度 做分组聚合 求违法数

sql如下:

 

​

select rpad(substr(fxjg,1,4),10,'0') fxjg,a.zbbh,a.zbmc,sum(wfnum) wfnum
from
(
select a.tjsj,a.fxjg,a.wfnum,b1.zbbh,b1.zbmc 
from bcht_bd_dsjmh.app_vio_gdsd_yzwf_hour -- 报表表名
a
join (
select t.zbbh,t.zbmc,t.wfxw from base_report_wf as t
left join (select zbbh,zbmc,wfxw from base_report_wf_user where userid = '8a948b446f82e6ed016f82ea6f760000'  and reportid = 'app_vio_gdsd_yzwf_hour' ) as s
on t.zbbh = s.zbbh and t.wfxw = s.wfxw 
where t.reportid = 'app_vio_gdsd_yzwf_hour'
and s.wfxw is null
)b on a.zbbh like CONCAT('%',b.zbbh,'%') and a.wfxw=b.wfxw
-- join 
-- (select zbbh ,wfxw,zbmc from base_report_wf a where  a.reportid = -'app_vio_gdsd_yzwf_hour'
-- and  not exists (select 1 from base_report_wf_user b where --b.userid='8a948b446f82e6ed016f82ea6f760000' 
-- and b.reportid = 'app_vio_gdsd_yzwf_hour' and a.zbbh=b.zbbh and a.wfxw=b.wfxw)
-- )b1 on instr(a.zbbh,b1.zbbh)>0 and a.wfxw=b1.wfxw
where a.day_id>='20130101' and a.day_id<='20210130' 
)a
group by rpad(substr(fxjg,1,4),10,'0') ,zbbh,zbmc

[点击并拖拽以移动]
​

问题

 

此sql执行在测试库需要12s,在生产库十几min,觉得有些慢,毕竟一百万的数据不是特别多,而且客户经常会查这个报表sql,一查就是1年的数据。而服务接口设置的时间是30s,之前查询总是超时错误。

看了之前生产库的执行计划

最后一步的 rows估算的大的离谱,好几分钟都查不出来,执行计划肯定是有问题得了。

 

解决

 

更新统计信息

先试了下重新更新下大表的统计信息 ,没有效果

因为对trace不熟,先手工测试 大表只关联一个维表a的情况,发现执行计划没问题

 

sql改写

然后测试把这个子查询

-- select t.zbbh,t.zbmc,t.wfxw from base_report_wf as t
-- left join (select zbbh,zbmc,wfxw from base_report_wf_user where userid = '8a948b446f82e6ed016f82ea6f760000'  and reportid = 'app_vio_gdsd_yzwf_hour' ) as s
-- on t.zbbh = s.zbbh and t.wfxw = s.wfxw 
-- where t.reportid = 'app_vio_gdsd_yzwf_hour'
-- and s.wfxw is null
-- )b

拆开,写成和大表a并列 的两个join ,执行计划依然有问题

最后 想到了用not exists 改写子查询测试下,因为not exists 是 ANTI JOIN ,属于部分连接的反义 ,与join 或者left join的enqu 等值连接不同,

希望能够给执行计划带来变化,能够产生解决问题的契机

 

初步效果

果然 执行计划发生了变化,最后一步的rows变成了百万级别,符合预期,生产库也能在20s左右查询出来了。

 

继续优化

 

但是这个速度还是不太理想,找了一些库级别的调优参数,但都是基于OLTP型业务的,对批量读写报表查询场景感觉没什么用。

最后想到了 之前浏览文档发现的mysql 存储引擎参数 engine,它可以对表级的engine设置。于是在测试库分别设置测试了一下速度

alter table bcht_bd_dsjmh.app_vio_gdsd_yzwf_hour engine=myisam;

 

 

alter table bcht_bd_dsjmh.app_vio_gdsd_yzwf_hour engine=innodb;

其他不变的情况下 ,只对大表A进行engine变更为myisam,查询速度提高了一倍.

 

思考

myisam虽然不支持外键和事物 ,但是更适合批量读写的OLAP场景。可以根据业务情况合适选择

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值