聊聊项目中分表的实际应用-2022新项目
一、业务场景
Web项目开发中,分表是时常会使用到的方式。分表的一个目的是为了缓解单表数据量过大,导致操作时
性能下降的问题。可是在实际开发中应该如何进行进行分表呢?那种分表方式更符合实际呢?
二、需求分析
网上随便去搜索一下就会发现有很多的分表方式,比如常规的垂直拆分或者水平拆分。垂直拆分的方式就是将一个表中
的字段拆分到两张表中,可以将需要经常使用的字段放在一个表中,不经常使用的字段放在另一个表中,查询的时候需要两
张表同时进行取数据进行查询。操作比较麻烦,理论上可行,实际开发中自己从没遇到过这么分表的。第二种方式是进行
水平拆分,其中一种方式是可以按照时间段进行拆分,比如按照年份进行拆分,不同的年份查询不同的表。这种分法在实际
的项目开发中遇到过,比如一些统计表中使用的就是这种方式,按照年为单位来进行数据统计操作。示例为tabl_2022,taible_2023,
table_2024.
三、解决方案
自己在真实开发中还遇到过其他的分表方案,也主要是应对数据量比较大的情况来进行处理的。以贵州省为例,分为各地州市,
在建表的时候,以各地州市的区号作为表的后缀进行分表。这样在查询的时候,就可以根据不同的表去查询需要的数据,由于数据
分散在各个地州市的表中,查询的效率也会高很多。这种方式有特定的应用场景,除了根据地州市进行分表外,也可以根据其他方式,
比如说省份编号,如果是全国性的项目。总之就是根据实际数据的特点来进行具体的分表操作。示例table_0851,table_0852,table_0853,
table_0854,table_0855,table_0856,table_0857,table_0858,table_0859.
自己还遇到过另外一种分表方式也比较实用,那就是先大致确定要创建多少张表,然后使用表中的一个具体的字段比如
用户id对表的总数取余,就可以知道将数据存储在哪一张表当中。举个简单的示例,如果需要分表总数为30,表的后缀
可以是0到29。如果用户ID为1到30,就会均匀的散落在这张表当中。测试代码如下:
int uerId;
int tableTotal = 30;
int tableSuffix;
for(int i = 0; i < 30; i++) {
uerId = i + 1;
tableSuffix = uerId % tableTotal;
System.out.println("用户IDuerId->" + uerId + ";表后缀tableSuffix->" + tableSuffix);
}
测试结果如下:
用户IDuerId->1;表后缀tableSuffix->1
用户IDuerId->2;表后缀tableSuffix->2
用户IDuerId->3;表后缀tableSuffix->3
用户IDuerId->4;表后缀tableSuffix->4
用户IDuerId->5;表后缀tableSuffix->5
用户IDuerId->6;表后缀tableSuffix->6
用户IDuerId->7;表后缀tableSuffix->7
用户IDuerId->8;表后缀tableSuffix->8
用户IDuerId->9;表后缀tableSuffix->9
用户IDuerId->10;表后缀tableSuffix->10
用户IDuerId->11;表后缀tableSuffix->11
用户IDuerId->12;表后缀tableSuffix->12
用户IDuerId->13;表后缀tableSuffix->13
用户IDuerId->14;表后缀tableSuffix->14
用户IDuerId->15;表后缀tableSuffix->15
用户IDuerId->16;表后缀tableSuffix->16
用户IDuerId->17;表后缀tableSuffix->17
用户IDuerId->18;表后缀tableSuffix->18
用户IDuerId->19;表后缀tableSuffix->19
用户IDuerId->20;表后缀tableSuffix->20
用户IDuerId->21;表后缀tableSuffix->21
用户IDuerId->22;表后缀tableSuffix->22
用户IDuerId->23;表后缀tableSuffix->23
用户IDuerId->24;表后缀tableSuffix->24
用户IDuerId->25;表后缀tableSuffix->25
用户IDuerId->26;表后缀tableSuffix->26
用户IDuerId->27;表后缀tableSuffix->27
用户IDuerId->28;表后缀tableSuffix->28
用户IDuerId->29;表后缀tableSuffix->29
用户IDuerId->30;表后缀tableSuffix->0
数据会均匀的分散在各个表当中。随机测试用户ID,代码如下,
public static void main(String[] args) {
int uerId;
int tableTotal = 30;
int tableSuffix;
for(int i = 0; i < 30; i++) {
uerId = createUserId();
tableSuffix = uerId % tableTotal;
System.out.println("用户IDuerId->" + uerId + ";表后缀tableSuffix->" + tableSuffix);
}
}
private static Random random = new Random();
public static int createUserId() {
return random.nextInt(200000) + 1;
}
测试结果如何预期,数据也会按照一定的规律散落在不同的表当中,测试结果如下
用户IDuerId->54631;表后缀tableSuffix->1
用户IDuerId->128276;表后缀tableSuffix->26
用户IDuerId->83817;表后缀tableSuffix->27
用户IDuerId->68859;表后缀tableSuffix->9
用户IDuerId->182986;表后缀tableSuffix->16
用户IDuerId->103205;表后缀tableSuffix->5
用户IDuerId->70934;表后缀tableSuffix->14
用户IDuerId->146739;表后缀tableSuffix->9
用户IDuerId->118293;表后缀tableSuffix->3
用户IDuerId->149639;表后缀tableSuffix->29
用户IDuerId->141622;表后缀tableSuffix->22
用户IDuerId->159620;表后缀tableSuffix->20
用户IDuerId->167884;表后缀tableSuffix->4
用户IDuerId->115932;表后缀tableSuffix->12
用户IDuerId->68012;表后缀tableSuffix->2
用户IDuerId->143793;表后缀tableSuffix->3
用户IDuerId->159777;表后缀tableSuffix->27
用户IDuerId->138104;表后缀tableSuffix->14
用户IDuerId->85888;表后缀tableSuffix->28
用户IDuerId->5910;表后缀tableSuffix->0
用户IDuerId->138018;表后缀tableSuffix->18
用户IDuerId->152221;表后缀tableSuffix->1
用户IDuerId->117515;表后缀tableSuffix->5
用户IDuerId->22838;表后缀tableSuffix->8
用户IDuerId->183603;表后缀tableSuffix->3
用户IDuerId->99599;表后缀tableSuffix->29
用户IDuerId->158027;表后缀tableSuffix->17
用户IDuerId->111455;表后缀tableSuffix->5
用户IDuerId->39728;表后缀tableSuffix->8
用户IDuerId->61524;表后缀tableSuffix->24
这种分表方式很好的实现了对数据的分表存储和查询操作。在操作的时候传入表后缀,然后使用Mybatis中提供的
拦截器,在查询的时候进行统一的替换表名,可以查看之前写的博文 https://www.cnblogs.com/yilangcode/p/16482816.html
这样就可以很好的实现分表操作。这种方式也是项目中正在使用的一种方式。
具体的分表操作可以根据实际的需求进行选用,如果有其他方法进行分表,欢迎各位留言讨论。