shardingsphere-分表-按创建日期分表
前提介绍
将your_table_name表按创建时间分表,每半年一张表,分表步骤如下;
因为系统只有这一张表分了表,所以对关联查询影响不大,但是若多张表分表,可能会造成1*n或者n*n的现象;
查询必带分表键,否则会查所有的表
yml配置
需要注意的是
table-strategy:
standard:
sharding-column: create_time
precise-algorithm-class-name: com.xx.TableShardingStrategy
range-algorithm-class-name: com.xx.RangeShardingStrategy
actual-data-nodes: 这个配置的数据库.xx是逻辑库default-data-source-name 的名字
spring:
#数据库读写分离分库分表配置
shardingsphere:
datasource:
names: "testdb,testdb-slave"
testdb:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.mariadb.jdbc.Driver
url:
username:
password:
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=1000
filters: stat
initialSize: 5
maxActive: 200
maxWait: 5000
maxOpenPreparedStatements: -1
minEvictableIdleTimeMillis: 30000
timeBetweenEvictionRunsMillis: 20000
minIdle: 1
logAbandoned: true
poolPreparedStatements: false
removeAbandoned: true
removeAbandonedTimeout: 1800
testOnBorrow: false
testOnReturn: false
testWhileIdle: true
useGlobalDataSourceStat: true
validationQuery: SELECT 1 FROM DUAL
testdb-slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.mariadb.jdbc.Driver
url: jdbc:
username:
password:
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=1000
filters: stat
initialSize: 5
maxActive: 200
maxWait: 5000
maxOpenPreparedStatements: -1
minEvictableIdleTimeMillis: 30000
timeBetweenEvictionRunsMillis: 20000
minIdle: 1
logAbandoned: true
poolPreparedStatements: false
removeAbandoned: true
removeAbandonedTimeout: 1800
testOnBorrow: false
testOnReturn: false
testWhileIdle: true
useGlobalDataSourceStat: true
validationQuery: SELECT 1 FROM DUAL
sharding:
master-slave-rules: #配置读写分离
testdb-r:
master-data-source-name: testdb
slave-data-source-names: testdb-slave
default-data-source-name: testdb-r
tables:
your_table_name:
actual-data-nodes: testdb-r.your_table_name_$->{2023..2024}_$->{1..2}
table-strategy:
standard:
sharding-column: create_time
precise-algorithm-class-name: com.xx.TableShardingStrategy
range-algorithm-class-name: com.xx.RangeShardingStrategy
props:
sql:
show: true
建表
CREATE TABLE your_table_name_202301 LIKE your_table;
CREATE TABLE your_table_name_202302 LIKE your_table;
CREATE TABLE your_table_name_202401 LIKE your_table;
CREATE TABLE your_table_name_202402 LIKE your_table;
-- 依此类推,创建每年的表
分表算法
配置在了上面的配置类里
public class TableShardingStrategy implements PreciseShardingAlgorithm<LocalDateTime> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<LocalDateTime> shardingValue) {
LocalDateTime date = shardingValue.getValue();
int year = date.getYear();
int month = date.getMonthValue();
String suffix = (month <= 6) ? "_1" : "_2";
String tableName = shardingValue.getLogicTableName() + "_" + year + suffix;
if (availableTargetNames.contains(tableName)) {
return tableName;
}
throw new UnsupportedOperationException("Table not found: " + tableName);
}
}
范围分片
若时间字段有范围查询的需要用到范围分片,不加的话会报错:
Cannot find range sharding strategy in sharding rule.
配置文件
range-algorithm-class-name: com.xx.RangeShardingStrategy
代码
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm; import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class RangeShardingStrategy implements RangeShardingAlgorithm<LocalDate> { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<LocalDate> shardingValue) { String tableNameSufix = shardingValue.getLogicTableName(); LocalDate lower = shardingValue.getValueRange().hasLowerBound() ? shardingValue.getValueRange().lowerEndpoint() : LocalDate.of(2023, 1, 1); LocalDate upper = shardingValue.getValueRange().hasUpperBound() ? shardingValue.getValueRange().upperEndpoint() : LocalDate.of(2030, 1, 1); //设置最大最小的上限 if(lower.compareTo(LocalDate.of(2023,1,1))<0){ lower=LocalDate.of(2023,1,1); } if(upper.compareTo( LocalDate.now().plusMonths(6))>0){ upper=LocalDate.now().plusMonths(6); } //把上限设置为年底或年中 if(upper.getMonthValue()>6){ upper=LocalDate.of(upper.getYear(),12,30); }else{ upper=LocalDate.of(upper.getYear(),6,30); } List<String> tableNames = new ArrayList<>(); LocalDate current = lower; while (current.isBefore(upper) || current.isEqual(upper)) { tableNames.add(getTableNameByDate(tableNameSufix, current)); current = current.plusMonths(6); } return tableNames; } public static String getTableNameByDate(String sufix, LocalDate dateTime) { int year = dateTime.getYear(); int month = dateTime.getMonthValue(); String suffix = (month <= 6) ? "1" : "2"; return sufix + "_" + year + "_" + suffix; } }
maven
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
常见分表的策略
-
分表键的选择:
- 唯一性:分表键应该尽量具有唯一性,以避免数据倾斜。
- 查询频率:选择查询频率较高的字段作为分表键,可以提高查询效率。
- 业务逻辑:分表键应符合业务逻辑,便于数据的管理和维护。
常见的分表键有:
- 用户ID(user_id):适用于用户相关的数据表。
- 时间戳(timestamp):适用于按时间分表的场景,如日志表。
- 订单ID(order_id):适用于订单相关的数据表。
-
分表策略:
- 哈希分表:通过对分表键进行哈希运算,将数据分布到不同的表中。适用于数据量大且需要均匀分布的场景。
- 范围分表:根据分表键的范围进行分表,如按时间范围分表。适用于数据有明显时间周期的场景。
- 取模分表:对分表键进行取模运算,将数据分布到不同的表中。适用于数据量较大且需要均匀分布的场景。
-
实现方式:
- 手动分表:在代码中手动实现分表逻辑,适用于简单的分表需求。
- 使用分表中间件:如Sharding-JDBC、MyCat等,可以简化分表的实现过程,适用于复杂的分表需求。
使用时间对比ID分表的优劣
如果分表键是创建时间而不是ID,会对系统的设计和性能产生一些影响。以下是一些可能的影响:
-
数据分布:
- 均匀性:使用创建时间作为分表键,数据可能会集中在某些时间段内,导致某些表的数据量过大,而其他表的数据量较小。这种不均匀的数据分布可能会影响查询性能。
- 热数据问题:如果系统在某些时间段内有大量数据写入,可能会导致某些表成为“热表”,从而引发性能瓶颈。
-
查询性能:
- 范围查询:使用创建时间作为分表键,进行时间范围查询时可能会比较方便,因为数据是按时间分布的。
- 随机查询:如果需要根据其他字段(如ID)进行查询,可能需要扫描多个表,增加查询复杂度和时间。
-
数据管理:
- 归档和清理:使用创建时间作为分表键,可以更方便地进行数据归档和清理操作。例如,可以按时间段删除过期数据。
- 扩展性:如果数据量持续增长,可以按时间段创建新的表,扩展性较好。
分表后多表关联的配置
1.这里的绑定表也叫关联表。指分片规则一致的主表和子表。例如: order 表和 order_item 表,均按照 order_id 分片,则此两张表互为绑定表关系
2.简单举例,需要关联的表加上这个配置
binding-tables:
- order, order_item
spring:
shardingsphere:
datasource:
names: ds0, ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/demo_ds_0
username: root
password: password
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/demo_ds_1
username: root
password: password
sharding:
tables:
order:
actual-data-nodes: ds$->{0..1}.order_$->{0..1}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: order_$->{order_id % 2}
order_item:
actual-data-nodes: ds$->{0..1}.order_item_$->{0..1}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: order_item_$->{order_id % 2}
binding-tables:
- order, order_item
default-database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds$->{user_id % 2}
更多推荐



所有评论(0)