基础用法

更新时间:
复制 MD 格式

本节介绍列存索引的核心 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 删除,再创建新的索引。