索引是加速数据查询的重要方法。列存索引可以增强宽表中海量数据的分析计算能力,主要适用于车联网与物联网的设备信息统计、电商领域的数据分析、物流行业的订单统计等场景。本文介绍列存索引新版的基础用法,帮助您快速上手并进一步掌握列存索引。
列存索引新版目前处于邀测阶段,如有使用需求,请联系Lindorm技术支持(钉钉号:s0s3eg3)申请使用。
核心优势
相比旧版列存索引,新版的核心优势如下:
特性 | 旧版 | 新版 |
同步延迟 | 15分钟 | 实时(秒级) |
架构介绍
适用场景
车联网:车辆轨迹实时分析
电商:订单实时统计
物流:运单实时监控
IoT:设备数据实时聚合
快速开始
前提条件
需开通以下引擎,并满足版本要求:
引擎 | 版本要求 | 作用 |
>= 2.8.6 | 源数据存储 | |
>= 3.9.1 | 日志实时订阅 | |
>= 3.10.15 | 索引数据存储 | |
- | 执行分析查询 |
快速示例
假设要对海量数据表 my_tbl 进行高效并行数据分析,您需要为该表创建列存索引。
示例表结构:
+------------+-------------+---------+----------------+
| TABLE_NAME | COLUMN_NAME | TYPE | IS_PRIMARY_KEY |
+------------+-------------+---------+----------------+
| my_tbl | pk0 | INT | true |
| my_tbl | pk1 | VARCHAR | true |
| my_tbl | pt_d | VARCHAR | true |
| my_tbl | col0 | INT | false |
| my_tbl | col1 | VARCHAR | false |
+------------+-------------+---------+----------------+pk0:数据标识,具有较大基数,适合作为 bucket 分区键。pt_d:数据产生的日期,通常按天进行分析,适合作为枚举分区键。
操作步骤:
参考以下代码示例,创建表和列存索引、查看索引状态、使用列存索引进行分析查询。
-- 1. 创建数据库并切换
CREATE DATABASE my_db;
USE my_db;
-- 2. 创建宽表
CREATE TABLE my_tbl (
pk0 INT,
pk1 VARCHAR,
pt_d VARCHAR,
col0 INT,
col1 VARCHAR,
PRIMARY KEY (pk0, pk1, pt_d)
);
-- 3. 创建列存索引
CREATE INDEX my_tbl_idx USING COLUMNAR ON my_tbl(pk0, pk1, pt_d, col0, col1)
PARTITION BY ENUMERABLE (pt_d, bucket(16, pk0))
WITH (
`lindorm_columnar.user.index.database` = 'my_db',
`lindorm_columnar.user.index.table` = 'my_tbl',
`lindorm_columnar.user.index.type` = 'LCE'
);
-- 4. 查看索引状态
SHOW INDEX FROM my_tbl;
-- 5. 使用列存索引进行分析查询
SELECT /*+ _use_ldps_(cg_name), _columnar_index_ */
pk1, SUM(col0)
FROM my_db.my_tbl
WHERE pt_d = '2024-01-01'
GROUP BY pk1;创建索引
语法
CREATE INDEX index_name USING COLUMNAR ON table_name(column_list)
PARTITION BY ENUMERABLE (partition_expression)
WITH (properties);参数说明:
参数 | 说明 |
| 索引名称。 |
| 宽表名称。 |
| 索引列,详见索引列。 |
| 分区表达式,详见分区配置。 |
| 索引属性,详见属性配置。 |
索引列
索引列必须包含宽表的全部主键字段。
支持的数据类型:TINYINT、SMALLINT、INTEGER、BIGINT、LONG、FLOAT、DOUBLE、VARCHAR、BINARY、VARBINARY、BOOLEAN、DECIMAL、JSON、DATE、TIMESTAMP。
其中 JSON 类型在列存侧存储为 VARCHAR。
分区配置
分区表达式用于指定索引数据按照枚举算法进行分区,提升查询时的检索效率。分区表达式包括枚举分区表达式和 bucket 分区表达式。
分区表达式中的分区键,必须来自于宽表主键列。
枚举分区表达式
可指定 0 个或多个,多个表达式用英文逗号(,)分隔。
枚举分区表达式通常选用城市、日期等主键字段,索引数据会按照不同的分区值构建,查询时可根据分区过滤条件高效定位数据。
bucket 分区表达式
至少指定 1 个。语法为 bucket(bucket_num, column_name):
bucket_num:bucket 分区数目。column_name:bucket 分区字段,用于计算 bucket 分区号。
bucket 分区号的计算方式:bucket_index = hash(column_name) % bucket_num
bucket 分区字段需为宽表主键字段,且应具有足够的离散特征,避免数据倾斜。
分区数量规划
枚举分区表达式和 bucket 分区表达式共同决定索引数据的分区数量,建议将每个分区的数据量控制在 50 MB ~ 512 MB 之间。
示例:宽表主键为 (uid, dt),单日数据量约 50 GB,可配置为:
PARTITION BY ENUMERABLE (dt, bucket(200, uid))设计分区策略时,应避免将高基数字段(具有大量唯一值的字段)用作枚举分区键,否则会产生大量分区,形成海量小文件,对存储系统造成影响。
属性配置
属性 | 必填 | 说明 |
| 是 | 必须设置为 |
| 是 | 列存引擎目标库名 |
| 是 | 列存引擎目标表名 |
| 否 |
|
lindorm_columnar.user.index.type = 'LCE' 为必填项,缺失将走旧版链路。
数据同步
模式 | 配置 | 说明 |
全量+增量 | 默认 | 同时同步存量数据和增量数据 |
仅增量 |
| 跳过存量,仅同步增量数据 |
仅增量同步示例:
CREATE INDEX my_tbl_idx USING COLUMNAR ON my_tbl(pk0, pk1, pt_d, col0, col1)
PARTITION BY ENUMERABLE (pt_d, bucket(128, pk0))
WITH (
`lindorm_columnar.user.index.database` = 'my_db',
`lindorm_columnar.user.index.table` = 'my_tbl',
`lindorm_columnar.user.index.type` = 'LCE',
`lindorm_columnar.user.syncer.skip.fullsync` = 'true'
);JSON 字段展开
使用 json_extract 函数将 JSON 字段展开为独立列,便于在列存引擎中进行高效查询和分析。
支持的函数
函数 | 返回类型 | 说明 |
| STRING | 提取字符串类型的值 |
| LONG | 提取长整型数值 |
| DOUBLE | 提取双精度浮点数值 |
| BOOLEAN | 提取布尔类型的值 |
如果 JSON 字段中指定路径不存在,或数据类型与函数不匹配,则返回 null。
示例
假设宽表 my_tbl 包含 JSON 列 json_col,其内容结构如下:
{
"a": {
"b": {
"c": "hello,world",
"d": 123
},
"e": false
},
"f": 3.14
}将 a.b.c、a.b.d、a.e、f 展开为独立列:
CREATE INDEX my_tbl_idx USING COLUMNAR ON my_tbl(
pk0, pk1, pt_d,
json_extract_string(json_col, '$.a.b.c'),
json_extract_long(json_col, '$.a.b.d'),
json_extract_boolean(json_col, '$.a.e'),
json_extract_double(json_col, '$.f')
)
PARTITION BY ENUMERABLE (pt_d, bucket(16, pk0))
WITH (
`lindorm_columnar.user.index.database` = 'my_db',
`lindorm_columnar.user.index.table` = 'my_tbl',
`lindorm_columnar.user.index.type` = 'LCE'
);列名映射规则
JSON 字段展开后,列存引擎中的列名格式为 <JSON列名>.<字段路径>,类型由 json_extract 函数决定。以上示例生成的列如下:
列名 | 类型 | 说明 |
| STRING | 存储 |
| LONG | 存储 |
| BOOLEAN | 存储 |
| DOUBLE | 存储 |
保留原始 JSON 内容
默认情况下,使用 json_extract 展开字段时,仅同步展开后的列,原始 JSON 列不会同步到列存引擎。如需同时保留原始 JSON 内容,可设置以下属性:
`lindorm_columnar.user.syncer.lci.json.syncOriginalJsonContent` = 'true'示例:
展开字段的同时保留原始 json_col 列,便于后续查询完整 JSON 内容。
CREATE INDEX my_tbl_idx USING COLUMNAR ON my_tbl(
pk0, pk1, pt_d, json_col,
json_extract_string(json_col, '$.a.b.c'),
json_extract_long(json_col, '$.a.b.d')
)
PARTITION BY ENUMERABLE (pt_d, bucket(16, pk0))
WITH (
`lindorm_columnar.user.index.database` = 'my_db',
`lindorm_columnar.user.index.table` = 'my_tbl',
`lindorm_columnar.user.index.type` = 'LCE',
`lindorm_columnar.user.syncer.lci.json.syncOriginalJsonContent` = 'true'
);查询索引
语法
通过 HINT 指定走列存索引查询,而非查询宽表原始数据。
SELECT /*+ _use_ldps_(cg_name), _columnar_index_ */ ...
FROM index_database.index_table
WHERE ...;其中 cg_name 为计算引擎 OLAP 资源组的名称。
示例
-- 聚合查询
SELECT /*+ _use_ldps_(cg_name), _columnar_index_ */
pk1, COUNT(*), SUM(col0)
FROM my_db.my_tbl
WHERE pt_d = '2024-01-01'
GROUP BY pk1;
-- 明细查询
SELECT /*+ _use_ldps_(cg_name), _columnar_index_ */ *
FROM my_db.my_tbl
WHERE pt_d = '2024-01-01' AND pk0 = 12345
LIMIT 100;索引管理
查看索引
SHOW INDEX FROM table_name;输出包含索引状态、同步进度等信息。
修改索引
添加列:
ALTER INDEX index_name ON table_name ADD COLUMNS (col1, col2);删除索引
DROP INDEX index_name ON table_name;常见问题
Q:分区表达式中是否可以包含非主键字段?
A:不可以。分区表达式中的字段必须全部为主键字段。
Q:bucket 分区表达式中,是否可以包含复杂分区表达式?
A:不可以。bucket 分区表达式中仅包括
bucket_num和bucket分区字段。Q:分区数目过大或过小会有什么影响?
A:分区数目过大,会导致元数据膨胀,从而影响查询效率,因此建议单分区数据量大于 50MB,
bucket分区表达式中的bucket_num小于 1024。分区数目过小,会影响数据读写吞吐或造成数据倾斜,建议单分区数据量小于 512MB。Q:能否为同一个宽表创建多个列存索引?
A:不能。一张宽表仅支持创建一个列存索引。
Q:宽表中数据因为 TTL 过期被清除后,列存索引数据是否会被自动清除?
A:不会。
Q:是否支持删除索引列?
A:不支持。