hash oracle 分表_数据库hash分表

前言

平常我们一直用的就是按时间进行分表,按时间分表可以减轻以时间维度的查询。但是如果查询的条件不是时间,那么当查询主表的时候,就会去遍历所有的分表,没有起到分表的优化效果。

方法

如果不能按照时间分表,我们可以采取按hash进行分表,如人员特别多的情况下,可以按照人员id进行hash分表,在查询的时候就可以根据hash到分表里面去查询人员信息了。

public class TableHashPartitionUtil {

public TableHashPartitionUtil() {

// NO_OP

}

/**

* 功能描述: 生成分区语句,分区语句不支持动态分区,只能在设计阶段预估数据量之后选择好分区个数,然后进行分区

*

* @param tableName 主表名称

* @param colName 分区依赖的字段名

* @param partitions 分区个数

* @return 返回信息:分区的执行语句

* @author wangcanfeng

* @date 2019/12/3-14:17

* @since 1.1.100

*/

public static String partitionSql(String tableName, String colName, Integer partitions) {

StringBuilder ps = new StringBuilder();

ps.append("do language plpgsql \n");

ps.append("$$\n");

ps.append("declare\n");

ps.append(" parts int := ").append(partitions).append(";\n");

ps.append("begin\n");

ps.append(" for i in 0..parts-1 loop \n");

ps.append(" execute format('create ").append(tableName).append("%s (like ").append(tableName)

.append(" including all) inherits (").append(tableName).append(")', i);\n");

ps.append(" execute format('alter table ").append(tableName)

.append("%s add constraint ck check(abs(mod(hashtext(")

.append(colName).append("),%s))=%s)', i, parts, i);\n");

ps.append(" end loop;\n");

ps.append("end; \n");

ps.append("$$;");

return ps.toString();

}

/**

* 功能描述: 触发器函数,引导数据,将写入到hash值一致的表中

* 注意: 表名称,列名称,分区数都要和分表语句中的相一致

*

* @param tableName 表名称

* @param colName 分区依赖的字段名

* @param partitions 分区个数

* @return 返回信息:分区的执行语句

* @author wangcanfeng

* @date 2019/12/3-14:23

* @since 1.1.100

*/

public static String insertFunction(String tableName, String colName, Integer partitions) {

StringBuilder helper = new StringBuilder();

helper.append("create or replace function ins_").append(tableName).append("() returns trigger as \n");

helper.append("$$\n");

helper.append("declare begin\n");

helper.append(" case abs(mod(hashtext(NEW.").append(colName).append("),").append(partitions).append("))\n");

for (int i = 0; i < partitions; i++) {

helper.append(" when ").append(i).append(" then\n");

helper.append(" insert into ").append(tableName).append(i).append(" values (NEW.*);\n");

}

helper.append(" else\n");

helper.append(" return NEW;\n");

helper.append(" end case;\n");

helper.append(" return null;\n");

helper.append("end;\n");

helper.append("$$\n");

helper.append("language plpgsql strict;\n");

return helper.toString();

}

/**

* 功能描述: 预防分表依赖的字段为空,为空的情况插入到主表中

*

* @param tableName 表名称

* @param colName 分区依赖的字段名

* @return 返回信息:

* @author wangcanfeng

* @date 2019/12/3-14:28

* @since 1.1.100

*/

public static String protectNull(String tableName, String colName) {

String pn="create trigger %s_ins_tg before insert on %s for each row when (NEW.%s is not null) execute procedure ins_%s();";

return String.format(pn, tableName,tableName,colName,tableName);

}

/**

* 功能描述: 查询的时候需要添加上这个约束条件,在where条件里面用and连接

* 注意:不加上这个约束将无法加速查询,查询将经历这些表

*

* @param colName 分区依赖的字段名,如果插入的参数不是分区依赖的字段,可能会出现异常或无效

* @param colValue 分区依赖的字段值

* @param partitions 分区数目

* @return 返回信息:加速查询的拼接语句

* @author wangcanfeng

* @date 2019/12/3-14:35

* @since 1.1.100

*/

public static String selectAppend(String colName, String colValue, Integer partitions) {

// 判断要查询的值在哪个分区

String judgePartition = "abs(mod(hashtext(%s::text), %d))=abs(mod(hashtext('%s'::text), %d))";

return String.format(judgePartition, colName, partitions, colValue, partitions);

}

缺点

(1)查询的时候没有像按时间分表一样自由,查询的时候需要在where的条件中增加"abs(mod(hashtext(字段名::text), %d))=abs(mod(hashtext('字段值'::text), %d))",同时因为是hash值,像时间一样需要范围查询的时候会比较麻烦

(2)在建表的时候需要先预估好数据量的大小,然后执行分表,不能想按时间分表一样动态分表

优势

按hash分表可以将一张表中的数据根据hash值分到各个子表中,可以根据hash值到指定的子表中进行查询,相当于只需要查1/n的数据量即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值