最近因为公司业务关系每天需要将300w+的数据,双十一高峰时期为3000w+的数据快速查询并进行转储,而这个过程中查询是个头疼的问题,因为加上老数据总量将近3.2亿的数据量,查询起来如果不得当则会一不小心就暴掉了Mongodb,就容易发生惨烈的从删库到跑路。
基础条件:
SpringBoot项目
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
// application.yml引入配置
data:
mongodb:
uri: mongodb://root:123565@localhost:27017/admin
难点:
- 查询优化
- 数据存储优化
- 异步编程数据安全
方案:
- 查询需要同步总数据量
- 查询当天Mysql是否进行分区
- 根据日期条件查询并进行根据商户、用户、批次进行分组
- 对其最终商户、用户、批次、日期进行条件查询统计该批次需同步总数量(num)
- 对其最终商户、用户、批次、日期进行条件查询按照id排序进行查询(只查询一条,划重点了:根据id排序升序排序)
- 采用分页进行查询每页查询数量然后进行同步,比如 (pageSize = 1w,则需同步pageCount = num /pageSize +1)
- 使用分页查询但是不要使用skip+limit查询(如果使用skip+limit数据量大时会出现mongodb连接超时,其他查询业务无法进行),因为skip效率太低,使用大于当前id和limit pageSize进行查询
- 每次查询前对id进行更新,查询到的数据最后一条数据的id进行替换
因为涉及到公司安全只能提供思路部分代码 (=.=)
数据同步单表查询保存效率在 (10w+/minute)
Mongodb操作
一、条件+分组查询
Criteria criteria = new Criteria();
criteria.andOperator(
Criteria.where("createDate").gte(new Date(startDate)),
Criteria.where("createDate").lt(new Date(endDate))
);
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(criteria),
Aggregation.group("userId").count().as("count")
).withOptions(AggregationOptions.builder().allowDiskUse(true).build());
List<Map> list = mongoTemplate.aggregate(aggregation, item, Map.class).getMappedResults();
二、基本多条件查询
Criteria criteria = new Criteria();
// 等于条件 (mysql:=)
criteria.and("userName").is(queryForm.getUserName());
// 模糊条件查询 (mysql:like ('%content%'))
criteria.and("content").regex(queryForm.getContent(), "i");
// 大于等于条件 (mysql:>=)
criteria.and("createDate").gte(DateUtil.beginOfDay(queryForm.getStartDate()));
// 小于等于条件 (mysql:<=)
criteria.and("createDate").lte(DateUtil.endOfDay(queryForm.getEndDate()));
// 分页查询
int start = (pageNum - 1) * pageSize;
int limit = pageSize;
Query query = new Query(criteria).with(Sort.by(Sort.Direction.DESC, "createDate")).skip(start).limit(limit);