更新时间:2024-04-01 GMT+08:00

HASH算法

适用场景

适用于需要将数据均匀分布的场景对数据进行拆分的场景,在SQL查询条件中,使用“=”、“IN”之类运算符相对较多。

使用说明

  • 拆分键的数据类型必须是整数类型(INT, INTEGER, BIGINT, MEDIUMINT, SMALLINT, TINYINT, DECIMAL(支持精度为0的情况))或字符串类型(CHAR,VARCHAR)。如果使用日期函数结合hash算法,拆分键的数据类型必须是DATE / DATETIME / TIMESTAMP其中之一。
  • 在SQL语句中对数字类型拆分键设置值时不要进行类型转换,类型转换可能造成路由计算失败后路由至默认分片,造成目标数据查询不到。

路由方式

首先102400对分库数/分表数进行分范围。

假如逻辑库分8个分片,那么102400/8=12800,则每一个分片对应的范围是:0=[0-12799],1=[12800-25599],2=[25600-38399],3=[38400-51199],4=[51200-63999],5=[64000-76799],6=[76800-89599],7=[89600-102399]。

当计算路由结果时,计算拆分键值的CRC32值然后对102400取余,根据计算结果落到某个范围进行路由。

算法计算方式

方式一:拆分键非日期类型

表1 拆分键非日期类型

条件

算法

举例

拆分键非日期类型

分库路由结果 = crc32(分库拆分键值) % 102400

分表路由结果 = crc32(分表拆分键值) % 102400

分库/分表:crc32(16) % 102400 = 49364;

49364属于3=38400-51199,则路由到分片3;

方式二:拆分键是日期类型

表2 支持的日期函数

日期函数

算法

举例

year()

year(yyyy-MM-dd)=yyyy

year('2019-10-11')=2019

month()

month(yyyy-MM-dd)=MM

month('2019-10-11')=10

weekofyear()

weekofyear(yyyy-MM-dd)=该日期是今年的第几周

说明:

关于一年中的第几周的定义请参见WEEKOFYEAR(date)

weekofyear('2019-10-11')=41

day()

day(yyyy-MM-dd)=该日期是月份的第几天

day('2019-10-11')=11

表3 拆分键是日期类型

条件

算法

举例

拆分键是日期类型

分库路由结果 = crc32(日期函数(分库拆分键值)) % 102400

分表路由结果 = crc32(日期函数(分表拆分键值)) % 102400

分库/分表:crc32(year('2019-10-11')) % 102400 = 5404

5404属于0=[0-12799],则路由到分片0。

建表语法

假设用户需要对ID列按HASH函数进行分库不分表:

create table hash_tb (
    id int,
    name varchar(30) DEFAULT NULL,  
    create_time datetime DEFAULT NULL,
    primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash (ID);

假设用户需要对ID列按HASH函数既分库又分表:

create table mod_hash_tb (
    id int,
    name varchar(30) DEFAULT NULL,  
    create_time datetime DEFAULT NULL,
    primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
dbpartition by hash (ID)
tbpartition by hash (ID) tbpartitions 4;

注意事项

无。