一次性能测试
名词解释
热数据:状态还未到结束状态的数据。
归档数据:状态已是最终状态的数据。
需求
表数量级在千万级以上,该表会被程序每隔30秒查询符合特定条件的数据一次,并且如果符合特定条件会被执行修改,被执行修改的数据是多条数据,不是单条;该表也会承担查询所有的需求,如后台管理;该表数据也会出现不定期的批量增加操作,暂可定为1分钟执行一次插入。
现做一次测试,检测一下此场景下两种方案的执行效率。
方案一:一表。即所有数据都保存到一个表,所有操作都操作此表
优点:读写都只操作一个表
缺点:表数据量大,对于频繁的查询操作会降低效率
方案二:两个表:一个表表A保存所有数据,一个表表B只保存热数据。频繁的查询,修改,插入操作都访问表B,只有后台管理的查询查询表A,表B的数据,检测到数据已是归档数据时执行删除操作。
优点:频繁查询的表数据量小,提高了查询速度
缺点:1、每次插入、修改数据需要操作两个表,增加了写的压力
2、增加了删除操作步骤,也会影响数据库效率
测试方案
编写三个接口分别模拟新增,查询,修改。其中新增接口每隔1分钟调用一次,查询接口每隔30秒执行一次,修改接口每隔5分钟执行一次。表字段status代表状态,目前设置两个状态,0和1,1表示结束状态,0表示开始状态,一条数据初始状态为0。插入操作使用多线程(模拟多用户**),查询和新增均为单线程。修改接口查询所有状态为0的数据,选择修改状态的数,通过三种方式选择每次择其一,第一种方式id是2的倍数的,第二种方式id是3的倍数的,第三种方式id是质数的,先选择筛选数据的方式,然后再通过方式进行筛选符合的数据,然后进行状态的修改。
硬件准备:
数据库服务器:
Os:Centos 7.1
64位
CPU:2核
系统盘:20G
数据盘:200G
带宽:5mbps
软件准备:
Mysql
Jmeter
应用程序:
语言:java
Jdk:1.7
表结构设计:
字段
|
说明
|
类型
|
长度
|
是否必填
|
primarykey
|
id
|
|||||
status
|
状态:0--开始 1--结束 | ||||
userId
|
用户ID | long | 20 | 是 | 否 |
issue
|
期次 | varchar | 8 | 是 | 否 |
lotteryCode
|
彩种编码 | varchar | 8 | 是 | 否 |
price
|
价格 | varchar | 25 | 是 | 否 |
multiple
|
倍数 | int | 10 | 是 | 否 |
部分代码
1、方案一查询
@RequestMapping(value = "/info",method = RequestMethod.GET) public String getBystatus(){ List<Long> ids = ticketService.getTicketIdByStatus(0); logger.info(" ids = "+ids); return "manager"; }2、方案二查询
@RequestMapping(value = "/info",method = RequestMethod.GET) public String getByStatus(){ List<Long> ids = tempService.getTicketIdByStatus(0); logger.info(" ids = "+ids); return "manager"; }
3、方案一新增
@RequestMapping(method = RequestMethod.POST) public String add(){ logger.info(" add start "); ticketService.add(); return "manager"; }
4、方案二新增
@RequestMapping(method = RequestMethod.POST) public String add(){ logger.info(" temp & ticket add start "); tempService.add(); ticketService.add(); return "manager"; }
5、方案一修改
@RequestMapping(method = RequestMethod.PUT) public String update(){ List<Long> updateIds = new LinkedList<Long>();//只添加不查询,用链表效率较好 List<Long> ids = ticketService.getTicketIdByStatus(0); Random random = new Random(); int result = random.nextInt(3); logger.info(" random result = "+result); int i = 0; for(Long id : ids){ if(result ==0 ){ //更新id是2的倍数的数据 if(id%2==0){ updateIds.add(id); } }else if(result == 1){ //更新id是3的倍数的数据 if(id%3==0){ updateIds.add(id); } }else if (result ==2){ //更新查出来的前3条数据 if(i<3){ updateIds.add(id); }else break; i++; } } logger.info(" id = "+ids.size()+" updateIds size = "+updateIds.size()); ticketService.updateList(updateIds); return "manager"; }
6、方案二修改
@RequestMapping(method = RequestMethod.PUT) public String update(){ logger.info(" temp delete ,ticket update start "); List<Long> updateIds = new LinkedList<Long>();//只添加不查询,用链表效率较好 List<Long> ids = tempService.getTicketIdByStatus(0); Random random = new Random(); int result = random.nextInt(3); logger.info(" random result = "+result); int i = 0; for(Long id : ids){ if(result ==0 ){ //更新id是2的倍数的数据 if(id%2==0){ updateIds.add(id); } }else if(result == 1){ //更新id是3的倍数的数据 if(id%3==0){ updateIds.add(id); } }else if (result ==2){ //更新查出来的前3条数据 if(i<3){ updateIds.add(id); }else break; i++; } } logger.info(" id = "+ids.size()+" updateIds size = "+updateIds.size()); tempService.deleteList(updateIds); ticketService.updateList(updateIds); return "manager"; }
测试报告
1、8万条数据结果
方案一:
方案二:
方案二对比方案一没有太大优势。
2、50万条数据
方案一
方案二:
方案二依然没有太大优势,并且在新增和修改的接口,处理时间略高于方案一
3、230万条数据
方案一:
方案二:
综上,如果数据量较少的时候,可选方案一,如果数据量较大比如200万,则方案二。
这个表的特点是读多写多。