云原生多模数据库Lindorm的主键HASH打散功能是指通过HASH函数将数据分散到不同的分片(Region),实现数据的分布式存储和查询,避免数据倾斜和负载不均等问题。本文介绍主键HASH打散功能的使用方法。
背景信息
Lindorm宽表引擎是基于Range分区的分布式存储引擎。通常情况下,写入Lindorm宽表引擎的数据会均匀地分布在不同的分片中。
在实际使用过程中,如果流量分布不均匀,例如访问某些数据的频率明显高于其他数据,则可能会导致数据在分片上的分布不均衡进而产生热点问题,无法充分利用分布式系统的优势。此时,您可以通过调整访问方式解决数据分布问题。但如果该问题是由于主键以某种规则生成,无法打散(例如自增主键或格式为HH:mm:ss
的时间列),推荐您使用主键HASH打散功能。
主键HASH打散功能可以将上述无法打散的数据均匀地分散到不同的分片,提升系统的可扩展性。同时,支持在Range分区的基础上执行分布式查询,提高查询效率。
如果您的业务场景符合以上适用场景,那么在建表或创建二级索引时对指定主键列使用HASH算法,即可实现数据打散。
前提条件
宽表引擎为2.5.3及以上版本。如何查看或升级当前版本,请参见宽表引擎版本说明和升级小版本。
建议使用最新版本的宽表引擎。
注意事项
在主键列或索引中对指定列使用HASH算法时,HASH函数表达式必须放在最前面。例如错误用法为
PRIMARY KEY( p1, hash32(p1),p2)
,正确的用法为PRIMARY KEY(hash32(p1), p1, p2)
。在主键列或索引中对某列使用HASH算法时,必须指定该列为主键列或索引列。
已指定HASH算法的主键列不支持修改。
使用主键HASH打散功能后,不支持使用bulkload方式导入数据。
DDL
建表
建表时,在PRIMARY KEY中设置主键列,并对指定主键列使用HASH算法。目前支持8位、32位和64位HASH算法。您可以根据主键的特点,对任意一个或多个主键列使用不同的HASH算法。
HASH算法的位数越大,存储底层消耗的内存越多,存储成本越大。例如,采用32位HASH算法时,存储底层每对keyValue将额外消耗4 Bytes。
示例如下:
-- 对一个主键列使用HASH算法
CREATE TABLE t1 (
p1 bigint,
p2 integer,
c1 integer,
c2 varchar,
PRIMARY KEY(hash32(p1), p1, p2)
);
-- 对多个主键列使用HASH算法
CREATE TABLE t2 (
p1 bigint,
p2 integer,
c1 integer,
c2 varchar,
PRIMARY KEY(hash8(p1, p2), p1, p2)
);
hash32(p1)
表示对p1列使用32位HASH算法;hash8(p1, p2)
表示同时对p1列和p2列使用8位HASH算法。
创建二级索引
支持对索引表使用主键HASH打散功能。
如果在创建主表时已对指定列使用HASH算法,但在建二级索引时未对指定列使用HASH算法,则索引表默认不会打散数据。
CREATE INDEX idx ON t1 (hash64(c1, c2), c1, c2);
查看HASH列详情
您可以查看表结构来查看HASH列详情。
DESCRIBE table t1;
返回结果:
+--------------+------------+-------------+---------+----------------+------------+
| TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME | TYPE | IS_PRIMARY_KEY | SORT_ORDER |
+--------------+------------+-------------+---------+----------------+------------+
| test1 | t1 | hash32[p1] | INT | true | ASC |
| test1 | t1 | p1 | BIGINT | true | ASC |
| test1 | t1 | p2 | INT | true | ASC |
| test1 | t1 | c1 | INT | false | none |
| test1 | t1 | c2 | VARCHAR | false | none |
+--------------+------------+-------------+---------+----------------+------------+
DML
数据写入
写入数据时,无需在SQL语句中添加HASH相关参数,系统将根据写入的数据自动生成并填充HASH值。
UPSERT INTO t1(p1, p2, c1, c2) VALUES(1, 1, 1, 'a');
数据查询
查询数据时,无需在SQL语句中添加HASH相关参数,系统将自动根据查询条件计算HASH值。但需要注意以下两点:
必须指定所有已使用HASH算法的主键列的值。否则系统会因为列缺省而无法计算HASH值,导致无法定位到数据所在的分片从而查询全表。
以t1表为例,查询示例如下:
-- 推荐的使用方式 SELECT * FROM t1 WHERE p1=1 AND p2=1; -- 系统将查询hash(p1)=hash32(1)的分片 -- 不推荐的使用方式 SELECT * FROM t1 WHERE p2=1; -- 未指定主键列p1的值,会导致系统无法定位至HASH值对应的分片进而查询全表
对于使用了HASH算法的主键列,查询条件必须为等值查询,例如
p1=2
,不支持HASH列的范围查询,例如p1>1
。以t1表为例,查询示例如下:
-- 正确使用方式 SELECT * FROM t1 WHERE p1=2 AND p2>1; -- 错误使用方式 SELECT * FROM t1 WHERE p2=1 AND p1>2 AND p1<8; -- 不支持此查询方式(主键列p1设置为范围查询)
如需查看SELECT语句的执行情况,请参见EXPLAIN。
常见问题
为什么查询结果中显示了hash列,且列值为null
?
该问题已于宽表引擎2.6.0版本、SQL引擎2.6.2.1版本修复,请您升级小版本至2.6.0及以上版本。
升级小版本可能导致实例重启,请在业务低峰期操作。
- 本页导读 (1)
- 背景信息
- 前提条件
- 注意事项
- DDL
- 建表
- 创建二级索引
- 查看HASH列详情
- DML
- 数据写入
- 数据查询
- 常见问题
- 为什么查询结果中显示了hash列,且列值为null?