一、背景
博主的一个线上IT项目,由于Oracle单表数据量超过了10亿条,出现线上查询超时,无法正确响应用户请求的问题。因此,计划在现有代码工程 中整合shardingsphere-jdbc组件,对该表进行分表处理,优化用户查询速度。
现有代码工程的技术框架为:SpringBoot+MybatisPlus+Oracle
二、注意事项
- 现有代码工程整合shardingsphere-jdbc组件后,发现工程里的所有Mapper统一使用shardingsphere-jdbc,暂未研究指定Mapper使用shardingsphere-jdbc的方式。博主的IT项目功能模块较少,因此整合后对IT项目功能进行了全量回归;
- 由于设计按照年份进行分表,但配置项中actual-data-nodes内容是写死,需要在新增分表后修改该配置项内容,或者研究动态修改该配置项的方法。
三、版本号
shardingsphere-jdbc不同版本之间配置方式有差异,博主花费了不少时间编辑配置项的内容,最后使用的shardingsphere-jdbc版本信息如下:
xml
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.0</version>
</dependency>
四、配置文件
ini
spring.shardingsphere.mode.type=Standalone
spring.shardingsphere.props.sql-show=true
spring.shardingsphere.datasource.names=shard-test
spring.shardingsphere.datasource.shard-test.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.shard-test.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.shardingsphere.datasource.shard-test.jdbc-url=jdbc:oracle:thin:@10.101.30.196:1528/zcgj
spring.shardingsphere.datasource.shard-test.username=zcgj
spring.shardingsphere.datasource.shard-test.password=zcgj@2023poiuy
spring.shardingsphere.rules.sharding.tables.SHARD.table-strategy.standard.sharding-column=create_year #自定义分表字段
spring.shardingsphere.rules.sharding.tables.SHARD.actual-data-nodes=shard-test.SHARD_$->{2020..2025} #自定义表名区间
spring.shardingsphere.rules.sharding.tables.SHARD.table-strategy.standard.sharding-algorithm-name=create-year #自定义分表逻辑命名
spring.shardingsphere.rules.sharding.sharding-algorithms.create-year.type=inline #分表逻辑类型枚举值
spring.shardingsphere.rules.sharding.sharding-algorithms.create-year.props.algorithm-expression=SHARD_${create_year} #分表逻辑
五、分表结果验证
接口验证用例如下,结论在以下注释中:
scss
@Test
public void test() {
// 数据可以按照逻辑,插入到不同create-year的表中
List<ShardEntity> list = new LinkedList<>();
for (int k = 2020; k <= 2025; k++) {
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 1000; j++) {
ShardEntity shardEntity = new ShardEntity();
shardEntity.setId(UUID.randomUUID().toString().replace("-",""));
shardEntity.setCreateTime(new Date());
shardEntity.setCreateYear(String.valueOf(k));
list.add(shardEntity);
}
this.shardService.saveBatch(list);
list.clear();
}
}
// 列表查询数据范围涉及多张分表时,list接口返回的是各个分表的汇总数据,如下返回了20条数据,而非10条
LambdaQueryWrapper<ShardEntity> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.in(ShardEntity::getCreateYear, new String[]{"2024", "2025"})
.orderByDesc(ShardEntity::getCreateTime) // 按时间降序排序
.apply("ROWNUM <= 10"); // 限制只返回第一条记录
List<ShardEntity> shards = this.shardService.list(queryWrapper);
log.info("shards=[{}]", shards);
// 分页查询数据范围涉及多张分表时,page接口返回条数为10条,优先返回SHARD_2024表中的内容
queryWrapper = Wrappers.lambdaQuery();
queryWrapper.in(ShardEntity::getCreateYear, new String[]{"2024", "2025"})
.orderByDesc(ShardEntity::getCreateTime); // 按时间降序排序
Page page = new Page();
page.setCurrent(1);
page.setSize(10);
Page<ShardEntity> shardEntityPage = this.shardService.page(page, queryWrapper);
log.info("shardEntityPage=[{}]", shardEntityPage);
}
附:建表语句
less
CREATE TABLE "SHARD_2020"
( "ID" VARCHAR2(32),
"REQ_ID" VARCHAR2(64),
"REQ_SOURCE" VARCHAR2(32),
"ERRCODE" NUMBER(16,0),
"ERRMSG" VARCHAR2(1024),
"CREATE_TIME" DATE DEFAULT SYSDATE,
"UPDATE_TIME" DATE DEFAULT SYSDATE,
"CREATE_USER" VARCHAR2(16),
"UPDATE_USER" VARCHAR2(16),
"CREATE_YEAR" VARCHAR2(8),
PRIMARY KEY ("ID")
)