云原生多模数据库Lindorm的主键HASH打散功能是指通过HASH函数将数据分散到不同的分片(Region),实现数据的分布式存储和查询,避免数据倾斜和负载不均等问题。本文介绍主键HASH打散功能的使用方法。
背景信息
Lindorm宽表引擎是基于Range分区的分布式存储引擎。通常情况下,写入Lindorm宽表引擎的数据会均匀地分布在不同的分片中。
在实际使用过程中,如果流量分布不均匀,例如访问某些数据的频率明显高于其他数据,则可能会导致数据在分片上的分布不均衡进而产生热点问题,无法充分利用分布式系统的优势。此时,您可以通过调整访问方式解决数据分布问题。但如果该问题是由于主键以某种规则生成,无法打散(例如自增主键或格式为HH:mm:ss
的时间列),推荐您使用主键HASH打散功能。
主键HASH打散功能可以将上述无法打散的数据均匀地分散到不同的分片,提升系统的可扩展性。同时,支持在Range分区的基础上执行分布式查询,提高查询效率。
如果您的业务场景符合以上适用场景,那么在建表或创建二级索引时对指定主键列使用HASH算法,即可实现数据打散。
前提条件
注意事项
在主键列或索引中对指定列使用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。