15.2 DDL
15.2.4 拆分算法使用说明
15.2.4 拆分算法使用说明
15.2.4.1 MOD_HASH 算法
使用说明
拆分键的数据类型必须是整数类型(INT, INTEGER, BIGINT, MEDIUMINT, SMALLINT, TINYINT, DECIMAL, NUMERIC)或字符串类型。
路由方式
根据分库键的键值按分库数取余,使用HASH分库但不使用同一个拆分键进行HASH分 表时,分库键的键值按分库数取余。如果键值是字符串,则字符串会被计算成哈希值 再对分库/表数取余。
例如,MOD_HASH('6')等价于6 % D(D是分库数目)。
分库和分表使用同一个拆分键进行HASH时,拆分键的键值按总的分表数取余。
例如,有2个分库,每个分库4张分表,那么0库上保存分表0~3,1库上保存分表4~7。
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 mod_hash (ID)
tbpartition by mod_hash (ID) tbpartitions 6;
注意事项
● 拆分键和键值皆不能修改。
● MOD_HASH算法是简单取模,要求拆分列的值自身分布均衡才能保证哈希均衡。
15.2.4.2 MOD_HASH_CI 算法
须知
Mod_hash_ci算法除了不区分大小写外,其他与mod_hash算法完全一致。
比如:拆分键值’abcd’与拆分键值’ABCD’的路由结果在mod_hash_ci算法中是一 致的。
使用说明
拆分键的数据类型必须是整数类型(INT, INTEGER, BIGINT, MEDIUMINT, SMALLINT, TINYINT, DECIMAL, NUMERIC)或字符串类型。
路由方式
根据分库键的键值按分库数取余,使用HASH分库但不使用同一个拆分键进行HASH分 表时,分库键的键值按分库数取余。如果键值是字符串,则字符串会被计算成哈希值 再对分库/表数取余。
例如,MOD_HASH('6')等价于6 % D(D是分库数目)。
分库和分表使用同一个拆分键进行HASH时,拆分键的键值按总的分表数取余。
表15-7 拆分键是字符型时的计算方式
create table mod_hash_ci_tb ( id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by mod_hash_ci (ID)
tbpartition by mod_hash_ci (ID) tbpartitions 6;
注意事项
● 拆分键和键值皆不能修改。
● MOD_HASH_CI算法是简单取模,要求拆分列的值自身分布均衡才能保证哈希均 衡。
15.2.4.3 UNI_HASH 算法 适用场景
适用于需要按用户ID或订单ID进行分库的场景。
使用说明
拆分键的数据类型必须是整数类型(INT, INTEGER, BIGINT, MEDIUMINT, SMALLINT, TINYINT, DECIMAL, NUMERIC)或字符串类型。
路由方式
根据分库键的键值按分库/表数取余。如果键值是字符串,则字符串会被计算成哈希值 再对分库/表数取余。
例如,UNI_HASH('6')等价于6 % D(D是分库数目)。
算法计算方式
方式一:拆分键是整型
表15-8 拆分键是整型时的计算方式
create table uni_hash_tb(
id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by UNI_HASH(ID)
tbpartition by UNI_HASH(name) tbpartitions 3;
注意事项
● 拆分键和键值皆不能修改。
● UNI_HASH算法是简单取模,要求拆分列的值自身分布均衡才能保证哈希均衡。
与 MOD_HASH 的比较
● 在使用 UNI_HASH 分库但不分表时,UNI_HASH 和 MOD_HASH 的路由方式一 样,都是根据分库键的键值按分库数取余。
● 分库和分表都使用同一个拆分键进行 MOD_HASH 时,随着分表数的变化,同一 个键值分到的分库不是固定的。
● 分库和分表都使用同一个拆分键进行 UNI_HASH 时,无论分表数是多少,同一个 键值总是分到相同的分库。
● 如果两张逻辑表需要根据同一个拆分键进行分库分表,但分表数不同,那么当两 张表按该拆分键进行 JOIN 时,如果使用 MOD_HASH 会出现跨库 JOIN,而 UNI_HASH 不会有跨库 JOIN。
15.2.4.4 RIGHT_SHIFT 算法
适用场景
当拆分键大部分键值的低位部位区分度比较低而高位部分区分度比较高时,则适用于 通过此拆分算法提高散列结果的均匀度。
使用说明
拆分键的数据类型必须是整数类型(INT, INTEGER, BIGINT, MEDIUMINT, SMALLINT, TINYINT, DECIMAL, NUMERIC)。
路由方式
+ ((123456 >> 4)/8)%3= 13建表语法
create table RIGHT_SHIFT ( id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by RIGHT_SHIFT(id, 4)
tbpartition by RIGHT_SHIFT(id, 4) tbpartitions 2;
注意事项
● 拆分键和键值皆不能修改。
● 移位的数目不能超过整数类型所占有的位数目,路由到0分片。
15.2.4.5 YYYYMM 算法
适用场景
适用于需要按年份与月份进行分库的场景。
使用说明
拆分键的数据类型必须是DATE / DATETIME / TIMESTAMP其中之一。
路由方式
根据拆分键的时间值的年份与月份计算哈希值,然后再按分库数取余。
例如,YYYYMM(‘2018-12-31 12:12:12’) 等价于 (2018 * 12 + 12) % D(D是分库 数目)。
create table yyyymm_tb(
id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by YYYYMM(create_time)
tbpartition by YYYYMM(update_time) tbpartitions 12;
注意事项
● 拆分键和键值皆不能修改。
● YYYYMM算法不支持对于每一个年月都独立对应一张分库。
● 当月份经历一个轮回(如 2013-03 是 2012-03 的一个轮回)后,同一个月份有可 能被路由到同一个分库,请以实际的分库数目而定。
15.2.4.6 YYYYDD 算法
适用场景
适用于需要按年份与一年的天数进行分库的场景。
使用说明
拆分键的数据类型必须是DATE / DATETIME / TIMESTAMP其中之一。
路由方式
根据拆分键的时间值的年份与一年的天数计算哈希值,然后再按分库/表数取余。
例如,YYYYDD(‘2018-12-31 12:12:12’) 等价于 (2018 * 366 + 365) % D(D是分 库数目)。
说明
计算得出“2018-12-31”是 2018 年第 365 天。计算公式中“2018*366”的“366”为固定取 值。
create table yyyydd_tb(
id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by YYYYDD(create_time)
tbpartition by YYYYDD(update_time) tbpartitions 30;
注意事项
● 拆分键和键值皆不能修改。
● YYYYDD算法不支持对于每一个年天都独立对应一张分库。
● 当日期经历一个轮回(如 2013-03 是 2012-03 的一个轮回)后,同一个日期有可 能被路由到同一个分库,请以实际的分库数目而定。
15.2.4.7 YYYYWEEK 算法
适用场景
适用于需要按年份与一年的周数进行分库的场景。
使用说明
拆分键的数据类型必须是DATE / DATETIME / TIMESTAMP其中之一。
路由方式
根据拆分键的时间值的年份与一年的周数计算哈希值,然后再按分库/表数取余。
例如,YYYYWEEK(‘2018-12-31 12:12:12’) 等价于 (2019 * 54 + 1) % D(D是分库 数目)。
条件 计算方式 举例
create table yyyyweek_tb(
id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by YYYYWEEK(create_time)
tbpartition by YYYYWEEK(update_time) tbpartitions 54;
注意事项
● 拆分键和键值皆不能修改。
● YYYYWEEK算法不支持对于每一个年周都独立对应一张分库。
● 当周数经历一个轮回(如2013年第一周是2012年第一周的一个轮回)后,相同周 数有可能被路由到同一个分库,请以实际的分库数目而定。
15.2.4.8 HASH 算法
适用场景
适用于需要将数据均匀分布的场景或需要按时间(年、月、日、周及其组合)对数据 进行拆分的场景,在SQL查询条件中,使用“=”、“IN”之类运算符相对较多。
使用说明
拆分键为表字段或表字段+日期函数。若拆分键为表字段+日期函数,其中的数据表字 段必须是日期类型(DATE / DATETIME / TIMESTAMP),日期函数适用于需要按时 间(年、月、日、周及其组合)对数据进行拆分的场景。
算法计算方式
分库/分表:crc32(16) % 102400 = 49364;
year() year(yyyy-MM-dd)=yyyy year(‘2019-10-11’)=2019 month()
month(yyyy-MM-dd)=MM month(‘2019-10-11’)=10 weekofyea
r() weekofyear(yyyy-MM-dd)=该日期是今年的第几 周
weekofyear (‘2019-10-11’)=41
day() day(yyyy-MM-dd)=该日 期是月份的第几天
day (‘2019-10-11’)=11
表15-16 拆分键是日期类型
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;
注意事项
拆分键和键值皆不能修改。
15.2.4.9 Range 算法
适用场景
必须是日期类型(DATE / DATETIME / TIMESTAMP),日期函数适用于需要按时间(年、月、日、周及其组合)对数据进行拆分的场景。
表15-18 支持的日期函数
日期函数 计算方式 举例
year() year(yyyy-MM-dd)=yyyy year(‘2019-10-11’)=2019 month() month(yyyy-MM-dd)=MM month(‘2019-10-11’)=10 weekofyea
r() weekofyear(yyyy-MM-dd)=该日期
是今年的第几周 weekofyear
(‘2019-10-11’)=41 day() day(yyyy-MM-dd)=该日期是月份的
第几天 day (‘2019-10-11’)=11
表15-19 拆分键是日期类型时的计算方式
create table range_tb(
id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, primary key(id)
)
dbpartition by range(id) {
15.2.4.10 MM 算法
适用场景
MM 适用于按月份数进行分表,分表的表名就是月份数。
使用说明
● 拆分键的类型必须是 DATE / DATETIME / TIMESTAMP 其中之一。
● 只能作为分表函数使用,但不能作为分库函数。
路由方式
根据拆分键的时间值的月份数进行取余运算并得到分表下标。
例如:2019-1-15,当根据分库键确定分库后,确定分表的计算方式是:月份mod分表 数,即:1 mod 12 = 1。
算法计算方式
表15-20 算法举例
条件 计算方式 举例
无 分表路由结果 = 分表拆分键值 % 分表数 分表拆分键值 : 2019-1-15
分表:1 % 12 = 1
建表语法
create table test_mm_tb ( id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by MOD_HASH(id)
tbpartition by MM(create_time) tbpartitions 12;
注意事项
按 MM 进行分表,由于一年的月份只有 12 个月,所以各分库的分表数不能超过 12 张分表。
15.2.4.11 DD 算法 适用场景
DD 适用于按日期的天数进行分表,分表的表数就是日期的天数。
使用说明
● 拆分键的类型必须是 DATE / DATETIME / TIMESTAMP 其中之一。
● 只能作为分表函数使用,但不能作为分库函数。
路由方式
根据拆分键的时间值的日期的天数进行取余运算并得到分表下标。
例如:2019-1-15,当根据分库建确定分库后,确定分表的计算方式是:一个月的第几 天mod分表数,即:15 mod 31 = 15。
算法计算方式
表15-21 算法举例
条件 计算方式 举例
无 分表路由结果 = 分表拆分键值 % 分表数 分表拆分键值 : 2019-1-15
分表:15 % 31 = 15
建表语法
create table test_dd_tb ( id int,
name varchar(30) DEFAULT NULL, create_time datetime DEFAULT NULL, primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by MOD_HASH(id)
tbpartition by DD(create_time) tbpartitions 31;
注意事项
按 DD 进行分表,由于一个月的中日期(DATE_OF_MONTH)的取值范围是1~31,
所以各分库的分表数不能超过 31 张分表。
15.2.4.12 MMDD 算法
适用场景
MMDD 适用于按一年的天数(即一年中日期)进行分表,分表的表名的下标就是一年 中的第几天,一年最多 366 天。
使用说明
● 拆分键的类型必须是 DATE / DATETIME / TIMESTAMP 其中之一。
● 只能作为分表函数使用,但不能作为分库函数。
路由方式
根据拆分键的时间值所对应的日期在一年中对应的天数,然后进行取余运算并得到分 表下标。
例如:2019-1-15,当根据分库键确定分库后,确定分表的计算方式是:一年的第几天 mod分表数,即:15 mod 366 = 15; 2019-1-15是一年的第15天。
算法计算方式
create_time datetime DEFAULT NULL, primary key(id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by MOD_HASH(name)
tbpartition by MMDD(create_time) tbpartitions 366;
注意事项
由于一年最多只有 366 天,当按 MMDD 进行分表时,所以各个分库的分表数目不能 超过 366 张分表。
15.2.4.13 WEEK 算法
适用场景
算法计算方式
create_time datetime DEFAULT NULL, primary key(id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by HASH(name)
tbpartition by WEEK(create_time) tbpartitions 7;
注意事项
由于一周共有 7 天,当按 WEEK 进行分表时,所以各分库的分表数不能超过 7 张。