分区索引是为了解决大宽表的存储和高并发访问问题而设计的一种新特性。创建搜索索引时可以指定数据分区策略,服务端自动将数据进行拆分并存储,查询数据时系统自动进行分区裁剪。本文介绍数据分区的策略和使用方法。
前提条件
已开通云原生多模数据库 Lindorm实例的搜索索引服务,具体操作请参见开通搜索索引。
已通过Lindorm-cli连接Lindorm宽表引擎,具体操作请参见通过Lindorm-cli连接并使用宽表引擎。
使用场景
业务数据具有时间属性,例如车联网数据、订单详情、消息日志等。
业务数据有明显的聚类特性,例如商家数据表以商家ID为聚类,查询条件中包括商家ID。IoT设备数据表以设备ID为聚类,查询条件中包括设备ID。
数据分区策略
准备工作
使用分区索引前需要创建测试表,语句如下:
CREATE TABLE IF NOT EXISTS search_table (user_id bigint, storeId varchar, goodsId varchar, goodsPrice smallint, orderTime bigint, info varchar, constraint primary key (user_id asc));
HASH分区
HASH分区将数据进行散列存储,从而避免出现数据的热点问题。在数据写入量较大的场景中可以很好地实现数据均衡。搜索索引默认按照Lindorm宽表的主键进行HASH分区,同时也支持自定义分区键。
HASH分区的语法示例如下:
创建搜索索引,默认按照Lindorm宽表的主键进行HASH分区,默认设置的分区数量为搜索节点数乘以2。
CREATE INDEX IF NOT EXISTS idx USING SEARCH ON search_table (storeId, goodsId, goodsPrice);
创建搜索索引,按照Lindorm宽表的storeId列进行HASH分区(即一级HASH分区),分区数量为64。
CREATE INDEX IF NOT EXISTS idx USING SEARCH ON search_table (storeId, goodsId, goodsPrice) partition by hash(storeId) partitions 64;
重要业务查询时,如果多数情况下会携带某个列作为过滤条件,可将该列设置为自定义分区键。
对于适用自定义分区键的场景,可根据实际业务情况将分区数量partitions设置大一些。如果不确定具体数值,可先设置64作为初始测试值。
对Lindorm宽表的某一列进行HASH分区(即一级HASH分区)时,如果自定义的分区键(也就是Lindorm宽表的某一列)存在热点问题,如一个storeId列下最多可能匹配到10%以上的数据,那么可能导致大量数据写入同一个分区中,影响查询和写入性能。建议使用多级HASH分区(高级用法),对Lindorm宽表的多个列组合进行HASH分区(即二级HASH分区或者三级HASH分区)。
- 自定义分区键的值有以下限制:
- 分区键值不可更改。
- 分区键值不能为空。
时间范围分区
对于一些时间序列的数据,可以按照时间范围分区,例如按照周或者月进行分区,同一时间范围内的数据将会聚集存储,并且可以自动淘汰旧分区的数据。
按照时间范围分区的语法示例如下:
创建索引,按照业务的时间列orderTime分区,从30天前开始,每7天自动分区,默认保留90天的分区数据。
CREATE INDEX idx USING SEARCH ON search_table (storeId, goodsId, goodsPrice, orderTime) partition by range time(orderTime) partitions 4 with (indexState=ACTIVE, RANGE_TIME_PARTITION_START='30', RANGE_TIME_PARTITION_INTERVAL='7', RANGE_TIME_PARTITION_TTL='90');
创建索引,按照业务的时间列orderTime分区,从半年前开始,每1个月自动分区,默认保留半年的分区数据,分区字段单位设置为秒。
CREATE INDEX idx USING SEARCH ON search_table (storeId, goodsId, goodsPrice, orderTime) partition by range time(orderTime) partitions 4 with (indexState=ACTIVE, RANGE_TIME_PARTITION_START='180', RANGE_TIME_PARTITION_INTERVAL='30', RANGE_TIME_PARTITION_TTL='180', RANGE_TIME_PARTITION_FIELD_TIMEUNIT='s');
按照时间范围分区的参数说明如下表:
参数 | 是否必选 | 说明 |
RANGE_TIME_PARTITION_START | 是 | 表示创建索引操作前多少天开始创建分区。适用于有历史数据的场景,如果历史数据的时间戳比开始分区的时间还要小,则会报错。 |
RANGE_TIME_PARTITION_INTERVAL | 是 | 表示间隔多少天创建新分区,例如 |
RANGE_TIME_PARTITION_TTL | 否 | 表示保留多少天的分区数据,例如 |
RANGE_TIME_PARTITION_FIELD_TIMEUNIT | 否 | 表示业务指定的时间分区字段单位,默认单位为毫秒(ms)。
|
多级HASH分区(高级用法)
按照Lindorm宽表的storeId列和goodsId列组合进行二级HASH分区,加盐因子(salt_factor)为4,分区数量为64。
//相同storeId,不同goodsId的数据会被打散到4个分区中去
CREATE SEARCH INDEX idx ON search_table (storeId, goodsId, goodsPrice) partition by hash(storeId(salt_factor=4),goodsId) partitions 64;
- 加盐因子(
salt_factor
)是进一步散列相同storeId列值的数据,通常设置为一个较小的数值,并且数值与分区数量是两倍的数量关系。如果分区数量为16,当salt_factor大于4时,则无法散列数据。加盐因子的其他值表示如下:salt_factor=1
:表示相同storeId列的数据,不同goodsId列的数据会被散列到分区总数量的一半中。salt_factor=2
:表示相同storeId列的数据,不同goodsId列的数据会被散列到分区总数量的1/4中。salt_factor=3
:表示相同storeId列的数据,不同goodsId列的数据会被散列到分区总数量的1/8中。
- 多级HASH分区(二级HASH分区或者三级HASH分区)除了可以散列数据,在查询数据场景中也大大提高了查询效率。例如在上述二级HASH分区中,查询数据时同时输入storeId列和goodsId列的过滤信息会确定在一个分区中进行数据检索,减少数据的扫描范围从而提高查询效率。
- 使用二级HASH分区时,一级分区键(Lindorm搜索表的第一列即storeId列)必须设置加盐因子。使用三级HASH分区时,一级分区键和二级分区键都必须设置加盐因子。
- 自定义分区键的值有以下限制:
- 分区键值不可更改。
- 分区键值不能为空。