Sharding-JDBC自定义分片算法StandardShardingAlgorithm按年分表实践
目前我这个项目的需求比较特殊,是一个收集股票相关数据的场景,拿日线数据举例,目前5千只股票,每年240个交易日左右,也就是1年120万条数据,10年1200万条数据,20年2400万条数据,虽然数据增长慢,但是为了提升查询性能,这个表也要进行分表,好了,问题来了,怎么分?按股票的TS代码来分还是按年分?这里其实要考虑后续查询场景,能简单的定义按代码或者是按年,后面的查询的时候要带上分片键才能走分表,否则就会走广播,得不偿失,我们查日线或者日统计数据的时候,基本都是基于时间进行查询的,所以这里只能根据交易时间字段来分表,但是又出现一个问题,按年分的话,1年120万条数据会不会少?mysql数据库一张表1000万以内查的话,走索引还是很快的,这样,按5年分一张表,这样每张分表600万左右的数据,还是很合理。那按交易时间的年,每5年一张分表怎么分呢?下面就是具体的实现:
先定义一个分表后缀枚举类:
public enum YearRange {
Y2015("20150101", "20191231", "2015"), Y2020("20200101", "20241231", "2020"),
Y2025("20250101", "20291231", "2025"), Y2030("20300101", "20341231", "2030");
private String begin;
private String end;
private String year;
private YearRange(String begin, String end, String year) {
this.begin = begin;
this.end = end;
this.year = year;
}
public String getBegin() {
return begin;
}
public String getEnd() {
return end;
}
public String getYear() {
return year;
}
}
其中year定义了表名后缀,begin和end定义了判断交易时间是否属于这个范围,这是一个完全闭合的范围。
下面定义切片算法YearTableShardingAlgorithm:
public class YearTableShardingAlgorithm implements StandardShardingAlgorithm<String> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
String date = shardingValue.getValue();
if (date == null) {
throw new UnsupportedOperationException("Date column[" + shardingValue.getColumnName() + "] value can not be null");
}
String year = date.substring(0, 4);
String suffix = getSuffix(year);
for (String name : availableTargetNames) {
if (name.endsWith(suffix)) {
return name;
}
}
throw new UnsupportedOperationException("Can not found available target name for suffix" + suffix);
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<String> shardingValue) {
Range<String> dates = shardingValue.getValueRange();
YearRange[] yrs = YearRange.values();
Set<String> suffix = Sets.newHashSet();
for (YearRange yr : yrs) {
if (dates.isConnected(Range.closed(yr.getBegin(), yr.getEnd()))) {
suffix.add(yr.getYear());
}
}
if (!suffix.isEmpty()) {
return availableTargetNames.parallelStream().filter(n -> {
String s = n.substring(n.length() - 4);
return suffix.contains(s);
}).collect(Collectors.toList());
}
throw new UnsupportedOperationException("Can not found available target name for range[" + dates.toString() + "]");
}
private String getSuffix(String year) {
int endWith = Integer.valueOf(year.substring(3));
if (endWith >= 5) {
endWith = 5;
} else {
endWith = 0;
}
return year.substring(0, 3) + endWith;
}
@Override
public void init(Properties props) {
}
}
下面是Sharding的配置:
Sharding提供的自定义算法实现起来还是非常灵活的,能够自己去定义分片键和表后缀的实现逻辑,可以应对很多场景了。
标题:Sharding-JDBC自定义分片算法StandardShardingAlgorithm按年分表实践
作者:michael
地址:https://blog.junxworks.cn/articles/2021/09/23/1632376141483.html