
# 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*)](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_weekofyear)。 | 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 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;
```
#### 注意事项
无。
