哈希分区表必须指定高唯一性分区键,优先选主键或唯一列;分区数应为2的幂次以优化性能;仅支持等值查询,范围查询失效;MySQL、Oracle、DM8语法差异大,需按引擎适配。
哈希分区表建表时必须指定分区键,且该列值要尽量唯一
哈希分区的核心是把 partition_key 的值喂给哈希函数,再模上分区数决定落哪个分区。如果选了个大量重复的列(比如 status 只有 '0'/'1' 两个值),那所有数据全挤进 2 个分区里,其他分区空转——这比不分区还糟。
实操建议:
- 优先选主键或带唯一约束的列,例如
user_id、order_id; - 避免用
gender、is_deleted这类低基数列; - 若只有组合列才够唯一,可用表达式:
PARTITION BY HASH(year(create_time)*10000 + month(create_time))(MySQL 支持); - Oracle 不支持表达式,得先建虚拟列再分区。
分区数量不是越多越好,推荐用 2 的幂次(如 4/8/16/32)
哈希分区内部靠 MOD(hash_value, partition_count) 定位分区。当 partition_count 是 2 的幂时,数据库能用位运算快速取模,性能更稳;非幂次数(比如 6 或 12)可能触发取模除法,部分引擎还会隐式重映射导致分布失真。
常见错误现象:
- 建了
PARTITIONS 6,结果发现 p0/p1 数据量是其他分区的 2 倍; - 扩容时从 8→9 个分区,几乎全部数据重分布(因哈希值映射关系全变);
- DM8 中若不显式命名分区,会自动生成
DMHASHPART0、DMHASHPART1等,但数量仍需是 2 的幂才保证底层散列均匀。
哈希分区对等值查询友好,但范围查询和 ORDER BY 几乎无效
因为哈希打散后,原本有序的值(如时间、ID)在物理存储上完全随机。查 WHERE user_id = 12345 能精准定位单一分区;但查 WHERE user_id BETWEEN 1000 AND 2000 就得扫全部分区——失去了分区剪枝能力。
使用场景判断:
- 适合高频点查(登录校验、订单详情页);
- 不适合报表类按时间范围拉取、分页列表、需要
ORDER BY create_time的场景; - 想兼顾范围查询?别硬扛哈希分区,考虑组合方案:按时间范围做 RANGE 分区,再在每个子分区里按 ID 做 HASH 子分区(MySQL 5.7+ / Oracle 支持)。
MySQL 和 Oracle 的语法差异容易导致迁移失败
表面都叫 PARTITION BY HASH,但细节差很多。比如 MySQL 允许直接写 PARTITIONS 8,Oracle 必须显式列出每个 PARTITION p1 名称;DM8 则强制用 DMHASHPART+数字 命名,且不支持自定义名。
典型报错与绕过方式:
- Oracle 报错
ORA-14019: partition bound must be specified→ 必须写全PARTITION p1, PARTITION p2, ...,不能只写数量; - MySQL 执行
PARTITION BY HASH(id) PARTITIONS 20成功,但迁到 Oracle 就语法报错; - DM8 中若漏写
storage(...)参数,可能默认用极小初始大小,插入几万行就爆空间。

















