本节介绍列存索引的核心 DDL 语法、分区策略和常见查询模式。所有示例默认在OLAP 模式下运行,语法在 Lake 模式下同样适用。
示例表
以订单明细表 orders 为例,其中 id 为订单标识、dt 为订单日期,两者组成联合主键:
+------------+-------------+---------+----------------+
| TABLE_NAME | COLUMN_NAME | TYPE | IS_PRIMARY_KEY |
+------------+-------------+---------+----------------+
| orders | id | BIGINT | true |
| orders | dt | VARCHAR | true |
| orders | user_id | BIGINT | false |
| orders | amount | DECIMAL | false |
| orders | status | VARCHAR | false |
+------------+-------------+---------+----------------+创建列存索引
语法:
CREATE INDEX index_name USING COLUMNAR ON table_name(column_name(,...)) PARTITION BY ENUMERABLE ( column_name(,...), bucket(bucket_num, column_name) ) WITH ( `lindorm_columnar.user.index.database` = 'columnar_db_name', `lindorm_columnar.user.index.table` = 'columnar_tbl_name' );参数说明:
参数
说明
index_name列存索引名称,由大写字母、小写字母、数字、下划线(
_)组成。table_name宽表名称。
column_name(,...)需要创建列存索引的字段列表,多个字段用英文逗号分隔。必须包含宽表的全部主键字段;若为全部字段(主键 + 非主键)建索引,可简写为
(*)。支持的数据类型:TINYINT、SMALLINT、INTEGER、BIGINT、LONG、FLOAT、DOUBLE、VARCHAR、BINARY、VARBINARY、BOOLEAN、DECIMAL、JSON、DATE、TIMESTAMP。PARTITION BY ENUMERABLE(...)指定索引数据的分区策略,详见分区策略。
WITH(...)通过键值对指定列存索引的存储参数。常用参数:
•lindorm_columnar.user.index.database:列存索引表所在 Database 名称。
•lindorm_columnar.user.index.table:列存索引表名称。
其他参数请参见进阶用法与存储模式。示例:
以
orders为例,为全部字段创建列存索引,按订单日期dt分区,Bucket 数量为 128,Bucket 分区字段为订单标识id:CREATE INDEX orders_idx USING COLUMNAR ON orders(id, dt, user_id, amount, status) PARTITION BY ENUMERABLE (dt, bucket(128, id)) WITH ( `lindorm_columnar.user.index.database` = 'my_index_db', `lindorm_columnar.user.index.table` = 'orders_index' );
分区策略
分区表达式由普通分区表达式和 Bucket 分区表达式组合而成,两者共同决定了索引数据的分区数量。
普通分区表达式
可指定 0 个或多个,多个用英文逗号分隔。
表达式字段必须来自宽表的主键字段。
索引数据按分区值构建,查询时可利用分区过滤高效定位数据。
单分区数据量建议在 50 MB ~ 512 MB 之间,请谨慎将高基数字段作为普通分区键(例如订单 ID、用户 ID),否则会产生大量小分区并造成元数据膨胀。
如果宽表没有像 dt 这样天然的日期主键,仅有 create_time 之类的时间戳主键,可以在普通分区表达式中通过函数从时间戳推导日期(如按天分区)。具体写法请参见进阶用法 — 复杂分区表达式。
Bucket 分区表达式
至少指定 1 个。
语法
bucket(bucket_num, column_name):bucket_num为 Bucket 数目,column_name为 Bucket 分区字段。Bucket 编号的计算方式:
hash(column_name) % bucket_num。例如bucket(128, id)表示hash(id) % 128。Bucket 分区字段必须为主键字段,并且应具有足够的离散度,避免数据倾斜。
Bucket 数目建议 ≤ 1024。
查看列存索引
列存索引创建成功后,索引数据会持续构建。数据同步包括存量同步(对宽表历史数据回查构建)和增量同步(消费宽表 WAL 持续追加),进入增量阶段后同步延迟通常 < 1 小时。
语法介绍:通过
SHOW INDEX语句查看指定宽表上的所有索引(含二级索引和列存索引):SHOW INDEX FROM orders;返回示例:
+-------------+------------+------------+-------------+---------------------------------+------------+---------------+---------------------------------+-----------+-------------------------------------------------------------+ | TABLE_SCHEMA| DATA_TABLE | INDEX_NAME | INDEX_STATE | INDEX_PROGRESS | INDEX_TYPE | INDEX_COVERED | INDEX_COLUMN | INDEX_TTL | INDEX_DESCRIPTION | +-------------+------------+------------+-------------+---------------------------------+------------+---------------+---------------------------------+-----------+-------------------------------------------------------------+ | default | orders | orders_idx | ACTIVE | 2026-08-10 18:59:20.652 +0800 | COLUMNAR | NA | id,dt,user_id,amount,status | | index table: my_index_db.orders_index; partition by: [...] | +-------------+------------+------------+-------------+---------------------------------+------------+---------------+---------------------------------+-----------+-------------------------------------------------------------+字段说明:
字段
说明
TABLE_SCHEMA宽表所在 Database 名称。
DATA_TABLE宽表名称。
INDEX_NAME索引名称,即
CREATE INDEX时指定的名字。INDEX_STATE索引状态。列存索引常见取值:
•BUILDING:索引正在构建(存量或增量),暂不可用于查询。
•ACTIVE:索引可用于查询。INDEX_PROGRESS增量同步位点。
•BUILDING阶段该字段为空。
• 进入ACTIVE后为一个时间戳(如2026-08-10 18:59:20.652 +0800),表示该位点之前的宽表数据已完全同步到列存索引,位点会随增量同步持续推进。INDEX_TYPE索引类型。列存索引的取值恒为
COLUMNAR。INDEX_COVERED是否为覆盖索引。列存索引恒为
NA(不适用)。INDEX_COLUMN索引所覆盖的宽表列列表。
INDEX_TTL索引 TTL。列存索引不支持 TTL,恒为空。
INDEX_DESCRIPTION索引诊断信息,形如
index table: .; partition by: [...]; ...。其中index table是您在CREATE INDEX时指定的列存表库表名,业务查询直接访问该表;其余字段为内部诊断使用,出现问题时可提供给技术支持辅助排查。INDEX_COMMENT索引备注,通常为空。
存量构建阶段的 Spark 作业进度与实时状态,可以在 Lindorm 控制台的列存索引任务详情页查看。
使用列存索引
在 SELECT 语句中通过 Hint _use_ldps_(cg_name), _columnar_index_ 将查询路由到计算引擎,并命中列存索引。
大数据统计
SELECT /*+ _use_ldps_(cg0), _columnar_index_ */ dt, COUNT(*) AS order_cnt, SUM(amount) AS gmv, MAX(amount) AS max_amount FROM my_index_db.orders_index WHERE dt BETWEEN '2026-08-01' AND '2026-08-10' GROUP BY dt;大数据排序
SELECT /*+ _use_ldps_(cg0), _columnar_index_ */ id, user_id, amount FROM my_index_db.orders_index WHERE dt = '2026-08-10' AND status = 'PAID' ORDER BY amount DESC LIMIT 100;大数据关联
对多张宽表分别创建列存索引后,可跨索引进行 JOIN:
SELECT /*+ _use_ldps_(cg0), _columnar_index_ */ * FROM my_index_db.orders_index AS o JOIN my_index_db.users_index AS u ON o.user_id = u.id WHERE o.dt = '2026-08-10' LIMIT 100;
删除列存索引
DROP INDEX orders_idx ON orders;DROP INDEX 的完整语法请参见 DROP INDEX。
一张宽表不允许创建同名的列存索引,无论该索引当前状态是否为失败。构建失败的索引也需要先执行 DROP INDEX 删除,再创建新的索引。