MySQL水平拆分及垂直拆分优化样例

水平拆分或垂直拆分

将数据量特别大的表,将其做水平或垂直拆分。水平拆分即将查询频率很低的字段另外拆成一张表,垂直拆分则是按某个维度将记录分成不同的表,两种拆分方式可以尝试一种或结合使用。

Sample

垂直拆分

1.准备,为了生成较多的实验数据,多次执行:

INSERT INTO bus_zcfz_yingshou_detail
SELECT * FROM bus_zcfz_yingshou_detail
;
最终bus_zcfz_yingshou_detail 总表记录数60w条。

在这里插入图片描述
2.原语句压力测试:结果见 测试结果对比图

mysqlslap -c 50 -uroot -p0000 --query="SELECT count(*) from fxst.bus_zcfz_yingshou_detail where iyear=2020 and imonth>=4" --create-schema fxst

3.创建分表:

create table bus_zcfz_yingshou_detail_2019 as 
SELECT * 
from bus_zcfz_yingshou_detail 
where iyear<=2019
;
create table bus_zcfz_yingshou_detail_2020 as 
SELECT * 
from bus_zcfz_yingshou_detail 
where iyear>2019
;
bus_zcfz_yingshou_detail_2020 分表记录数37w条

4.分表后测试 结果见 测试结果对比图

mysqlslap -c 50 -uroot -p0000 --query="SELECT count(*) from fxst.bus_zcfz_yingshou_detail_2020 where iyear=2020 and imonth>=4" --create-schema fxst

5.测试结果对比:
①耗费时间
在这里插入图片描述
分表后的时间要比分表前减少近4秒。

②CPU使用情况:
在这里插入图片描述
左边的是未分表,右边的是分表后的,使用率虽然都是100%,但分表后耗时明显变短。

6.分表查询存储过程样例

show CREATE PROCEDURE `p_分表查询样例`;
CREATE DEFINER=`root`@`localhost` PROCEDURE `p_分表查询样例`(IN `_date` date)
BEGIN
-- 根据传入的日期参数,计算出所在的年份分表,然后返回数据
-- 定义变量信息
DECLARE year_,month_ VARCHAR(20);
DECLARE table_name VARCHAR(100);

set year_=year(_date);
set month_=month(_date);
set @sql_=concat(
              "select count(*) from ",
              "bus_zcfz_yingshou_detail_",year_," "
              "where iyear=",year_," ",
              "and imonth=",month_," "
             );
PREPARE sql_ from @sql_; 
EXECUTE sql_;
-- 提交事务
COMMIT;
END

备注:
上面的按年份进行水平拆分的方式,如果查询是跨年的,就需要修改原有的查询语句,从相应的分表查询后再合并起来。

水平拆分
  • 创建新表结构,注意一定要有主键 id,新表在维度字段上将名称去掉,在值字段上将各月数据去掉。
CREATE TABLE `bus_zcfz_yingshou_detail_cols` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ddate` date DEFAULT NULL COMMENT '数据日期',
  `iyear` int(4) DEFAULT NULL COMMENT '年份',
  `imonth` int(2) DEFAULT NULL COMMENT '月份',
  `iday` int(2) DEFAULT NULL COMMENT '数据天数',
  `ctype` varchar(10) DEFAULT NULL COMMENT '数据类型',
  `cbk_code` varchar(20) DEFAULT NULL COMMENT '编码1',
  `cxw_code` varchar(20) DEFAULT NULL COMMENT '编码2',
  `cjyt_code` varchar(20) DEFAULT NULL COMMENT '编码3',
  `cfr_code` varchar(20) DEFAULT NULL COMMENT '公司编码',
  `ccus_code` varchar(20) DEFAULT NULL COMMENT '客户编码',
  `iysyue_qichu` double(18,2) DEFAULT NULL COMMENT '应收余额-期初',
  `iysyue_benyue` double(18,2) DEFAULT NULL COMMENT '应收余额-本月',
  `iysyue_tongqi` double(18,2) DEFAULT NULL COMMENT '应收余额-同期',
  PRIMARY KEY (`id`),
  KEY `cxw_code` (`cxw_code`)
) ENGINE=InnoDB AUTO_INCREMENT=607777 DEFAULT CHARSET=utf8
;
  • 插入数据
TRUNCATE bus_zcfz_yingshou_detail_cols;
INSERT INTO bus_zcfz_yingshou_detail_cols
(ddate,iyear,imonth,iday,ctype,cbk_code,cxw_code,cjyt_code,
 cfr_code,ccus_code,iysyue_qichu,iysyue_benyue,iysyue_tongqi )
SELECT 
 ddate,iyear,imonth,iday,ctype,cbk_code,cxw_code,cjyt_code,
 cfr_code,ccus_code,iysyue_qichu,iysyue_benyue,iysyue_tongqi
from bus_zcfz_yingshou_detail
;
  • 对比测试
-- 0.677s
SELECT 
 -- t0.cxw_code,t1.cname,t0.cjyt_code,t0.cfr_code,t0.iysyue_qichu
 count(*)
FROM bus_zcfz_yingshou_detail t0 
LEFT JOIN sys_department t1
on t0.cxw_code=t1.ccode
where t0.iyear=2020 and imonth=4 and iday=30
;
-- 0.541s
SELECT 
 -- t0.cxw_code,t1.cname,t0.cjyt_code,t0.cfr_code,t0.iysyue_qichu
  count(*)
FROM bus_zcfz_yingshou_detail_cols t0 
LEFT JOIN sys_department t1
on t0.cxw_code=t1.ccode
where t0.iyear=2020 and imonth=4 and iday=30
;

结果:拆分后的新表的查询时间0.541s,拆分前是0.677s,优化还是比较明显的。

备注

附录

参考文章:https://database.51cto.com/art/201809/583857.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值