一、表结构
ap_article 文章基本信息表
ap_article_config 文章配置表
ap_article_content 文章内容表
二、表的拆分
1、垂直拆分
将一个表的字段分散到多个表中,每个表存储其中一部分字段。
分表的好处:
(1)、减少IO争抢,减少锁表的几率,查看文章概述和文章详情互不影响。
(2)、充分发挥高频数据的操作效率,对文章概述数据操作的高效率不会被操作文章详情数据的低效率所拖累。
ap_article_content表的效率比较低,因为该表的content字段为longtext类型,内容比较多时,效率就比较慢。而ap_article表的效率相对比较快,拆分之后,操作ap_article表是高效率的,操作ap_article_content是低效率的。我们经常操作ap_article不会被ap_article_content影响。
垂直分表的原则
(1)、把不常用的字段单独放一张表。
(2)、把text、blob等大字段拆分出来单独放在一张表。
(3)、经常组合查询的字段单独放在一张表中。
2、水平拆分
水平分表有按年分表,按月分表,还可以根据key值取模来分表。
(1)、按年分表和按月分表比较简单,根据表名通过存储过程来创建表
CREATE DEFINER=`root`@`%` PROCEDURE `p_create_b_outstore_upload_log_table`(IN `v_table_name` varchar(50)) BEGIN #Routine body goes here... DECLARE v_sql varchar(1000); # 声明局部变量v_sql # 给局部变量v_sql赋值 set v_sql = CONCAT('create table ',v_table_name,"(id bigint(20) NOT NULL comment '主键',entity_id bigint(20) NOT NULL comment '所属企业',order_no VARCHAR(50) NOT NULL comment '单据号',file_path VARCHAR(200) NOT NULL comment '文件路径',upload_time datetime NOT NULL comment '上传时间',app_key VARCHAR(100) NOT NULL comment '接口用户名',deal_status VARCHAR(50) NOT NULL comment '处理状态(0:待处理,1:处理中,2:处理成功,3:失败)',deal_desc VARCHAR(2000) NOT NULL comment '处理结果描述',order_time datetime NOT NULL comment '单据时间',order_year char(4) NOT NULL comment '单据年份',order_id bigint(20) comment '关联单据ID',error_count int default 0 comment '错误次数',create_user VARCHAR(20) comment '创建人',create_time datetime default CURRENT_TIMESTAMP comment '创建时间',update_user VARCHAR(20) comment '修改人', update_time datetime comment '修改时间',primary key(id))ENGINE=InnoDB DEFAULT CHARSET=utf8"); # 给用户变量@v_sql赋值 set @v_sql = v_sql; PREPARE stmt from @v_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; # 创建普通索引 set v_sql = CONCAT('alter table ',v_table_name,' add index ix_',v_table_name,'_deal_status(deal_status)'); set @v_sql = v_sql; PREPARE stmt from @v_sql; EXECUTE stmt; # 添加表名 set v_sql = CONCAT('alter table ',v_table_name," comment '出库上传记录表(按月份分表)'"); set @v_sql = v_sql; PREPARE stmt from @v_sql; EXECUTE stmt; END
(2)、根据key值取模来分表
工具类:工具类种basketnum字段确定分表的个数,如果分20个表,如下所示:b_code_relation_000001,b_code_relation_000002.....b_code_relation_000020。
import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * @Description 根据key值获取分表策略 * @Author * @Date 2020/11/24 10:52 * @Version 1.0 */ public class SplitTables { public static Integer basketnum = 20; public static Double totalInteger = Math.pow(2.0D, 32.0D); /** * * @param key * @return */ public static String getTableNumByShardingKey(String key) { Integer tbnum = getBasketnumByShardingKey(key); String tableNum = String.valueOf(tbnum); tableNum = StringUtils.leftPad(tableNum,6,'0' ); return tableNum; } /** * * @param key * @return */ private static Integer getBasketnumByShardingKey(String key) { Long hashvalue = hash(key); BigDecimal Bigcirclenum = new BigDecimal(Double.toString(totalInteger)); if (hashvalue == 0L){ return 1; } else if (hashvalue == Bigcirclenum.longValue()) { return basketnum; } else { BigDecimal Bignumbasket = new BigDecimal(Integer.toString(basketnum)); BigDecimal Biggapnum = Bigcirclenum.divide(Bignumbasket); BigDecimal Bighashvalue = new BigDecimal(Long.toString(hashvalue)); BigDecimal basketindex = Bighashvalue.divide(Biggapnum,2); Double basketindexd = basketindex.doubleValue(); Integer basketno = (int) Math.ceil(basketindexd); return basketno; } } /** * * @param key * @return */ private static Long hash(String key) { ByteBuffer buf = ByteBuffer.wrap(key.getBytes()); Integer seed = 305441741; ByteOrder byteOrder = buf.order(); buf.order(ByteOrder.LITTLE_ENDIAN); long m = -4132994306676758123L; Integer r = 47; long h; for (h = (long) seed ^ (long) buf.remaining() * m; buf.remaining() >= 8; h *= m) { long k = buf.getLong(); k *= m; k ^= k >>> r; k *= m; h ^= k; } if (buf.remaining() > 0) { ByteBuffer finish = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); finish.put(buf).rewind(); h ^= finish.getLong(); h *= m; } h ^= h >>> r; h *= m; h ^= h >>> r; long kk = 4294967295L; h &= kk; buf.order(byteOrder); return h; } public static void main(String[] args) { System.out.println(getBasketnumByShardingKey("100")); } }
调用工具类:
String tableName = b_code_relaton + SplitTables.getTableNumByShardingKey(code);