---
title: "列存表与列存索引实践 - OceanBase 数据库 V4.6.0 | OceanBase 文档中心"
description: 列存表与列存索引实践 本篇文章介绍 OceanBase 中列存表、列存索引及其与行存表、行存索引的组合方案，并结合 支付流水 场景给出可落地的建表、建索引与查询示例，帮助将选型结论落实到具体 SQL。 列存表与列存索引的概念 列存表 ：主表基线以列存格式存储；创建方式为 WITH COLUMN GROUP(each …
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.6.0

# 列存表与列存索引实践

更新时间：2026-07-14 14:32:08

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.6.0/zh-CN/620.obap/200.obap-data-design/800.data-design-best-practice/500.column-store-index-and-table-usage.md)  

本篇文章介绍 OceanBase 中列存表、列存索引及其与行存表、行存索引的组合方案，并结合**支付流水**场景给出可落地的建表、建索引与查询示例，帮助将选型结论落实到具体 SQL。

## 列存表与列存索引的概念

- **列存表**：主表基线以列存格式存储；创建方式为 `WITH COLUMN GROUP(each column)`（纯列存），或 `WITH COLUMN GROUP(all columns, each column)`（行列混存）。详见 [列存概述 — 如何创建列存表与行列混存表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000006278429)。
 - **列存索引**：索引**表本身**以列存格式存储，而不是“在列存表上再建一种特殊索引类型”。创建索引时通过 `WITH COLUMN GROUP(each column)` 指定列存索引；索引表同样可指定行存或列存列组。
 - **行存索引**：索引表按行存组织（默认或 `WITH COLUMN GROUP(all columns)`），适合点查与覆盖索引回表路径。

下文示例均围绕同一张业务宽表 **`payment_ledger`（支付流水）**：字段含 `order_id`、`pay_time`、`pay_channel`、`txn_status`、`amount` 等，便于对比不同组合下的读写特征。

## 场景组合

| 场景 | 适用业务 | 策略 | 优点 | 缺点 |
| --- | --- | --- | --- | --- |
| **行存表 + 列存索引** | 以事务型业务为主，同时存在一定的分析型查询需求，且表为大宽表。 | 创建列存索引来提升分析类查询性能。 | 只对部分列进行冗余存储，且是列存格式。 | 需要根据查询语句的情况识别合适的字段创建列存索引，且数据写入时需要维护索引表数据，写入性能相对差一点。 |
| **列存表 + 行存索引** | 以分析型业务为主，但需支持高效的简单查询（如点查）。 | 创建索引时为了避免回表可以创建覆盖索引。 | 只冗余存储部分列数据，目前不支持在线将列存表转换为行存表或行列冗余表，可以通过添加行存索引来达到优化查询的目的。 | 需要根据查询语句的情况识别合适的字段创建行存索引，且数据写入时需要维护索引表数据，写入性能相对差一点。 |
| **行列混存表** | 需要同时兼顾事务型和分析型查询，且查询方式多样化。 | 可以直接冗余存储两份基线数据，让系统根据查询特点生成合适的执行计划，查询逻辑默认范围扫描走列存模式, 点查回退到行存模式。 | 不需要分析业务的查询特点， 分析类查询结果是强一致的。 | 会占用更多的磁盘空间，且执行计划容易出现不准的情况。 |
| **纯列存表（无索引）** | AP 场景 | 使用 `WITH COLUMN GROUP(each column)` 建列存表，列式存储数据 | 大批量导入与宽表少列扫描效率高 | 按主键/订单号点查慢 |

## 示例

### 示例一：行存表 + 列存索引

支付核心链路是 `INSERT` 与按 `order_id` 查状态；运营报表按渠道、日期对 `amount` 做 `SUM`/`COUNT`，表列数多但分析只扫少数列。

**建表与列存索引**：

```sql
CREATE TABLE payment_ledger (
    txn_id       BIGINT        NOT NULL,
    order_id     BIGINT        NOT NULL,
    user_id      BIGINT        NOT NULL,
    pay_time     DATETIME      NOT NULL,
    pay_channel  VARCHAR(32)   NOT NULL,
    txn_status   TINYINT       NOT NULL,
    amount       DECIMAL(18,2) NOT NULL,
    merchant_id  BIGINT        NOT NULL,
    remark       VARCHAR(256)  DEFAULT NULL,
    PRIMARY KEY (order_id, pay_time, txn_id)
)
PARTITION BY HASH(order_id) PARTITIONS 64
WITH COLUMN GROUP(all columns);

-- 列存索引：冗余分析常用列，避免宽表全列扫描
CREATE INDEX idx_pay_analytics
    ON payment_ledger (pay_time, pay_channel, txn_status, amount)
    WITH COLUMN GROUP(each column);

```

**典型 TP 查询**（走主表行存 + 主键）：

```sql
SELECT txn_id, txn_status, amount, pay_channel
FROM payment_ledger
WHERE order_id = 10086001
ORDER BY pay_time DESC
LIMIT 1;

```

**典型分析查询**（优化器可能选择列存索引，仅扫描索引中的列）：

```sql
SELECT pay_channel,
       SUM(amount) AS succ_amt,
       COUNT(*)    AS succ_cnt
FROM payment_ledger
WHERE pay_time >= '2025-01-01'
  AND pay_time <  '2025-02-01'
  AND txn_status = 1
GROUP BY pay_channel;

```

主表保持行存，不影响高并发写入与点查；分析负载由列存索引承接，相比把整张表改成纯列存，对 TP 更稳妥。索引列应覆盖过滤与聚合所需字段，避免回表扫宽行。

### 示例二：列存表 + 行存索引（分析为主，补点查）

流水已以批量导入/对账为主，日常 SQL 多为全分区扫描聚合；仅客服、风控等场景按 `order_id` 查单笔。

**建表与行存覆盖索引**：

```sql
CREATE TABLE payment_ledger_cs (
    txn_id       BIGINT        NOT NULL,
    order_id     BIGINT        NOT NULL,
    pay_time     DATETIME      NOT NULL,
    pay_channel  VARCHAR(32)   NOT NULL,
    txn_status   TINYINT       NOT NULL,
    amount       DECIMAL(18,2) NOT NULL,
    merchant_id  BIGINT        NOT NULL,
    PRIMARY KEY (txn_id, pay_time)
)
PARTITION BY RANGE COLUMNS(pay_time) (
    PARTITION p202501 VALUES LESS THAN ('2025-02-01 00:00:00'),
    PARTITION p202502 VALUES LESS THAN ('2025-03-01 00:00:00')
)
WITH COLUMN GROUP(all columns, each column);

-- 行存索引 + STORING：点查订单时避免回主表宽行
CREATE INDEX idx_order_lookup
    ON payment_ledger_cs (order_id)
    STORING (txn_status, amount, pay_time, pay_channel)
    WITH COLUMN GROUP(all columns);

```

**分析查询**（主表列存）：

```sql
SELECT merchant_id, SUM(amount) AS total
FROM payment_ledger_cs
WHERE pay_time >= '2025-01-01' AND txn_status = 1
GROUP BY merchant_id;

```

**点查查询**（行存索引）：

```sql
SELECT txn_status, amount, pay_time, pay_channel
FROM payment_ledger_cs
WHERE order_id = 10086001
ORDER BY pay_time DESC
LIMIT 5;

```

主表 `each column` 保证汇总类 SQL 的列存扫描优势；点查由行存索引承担。

### 示例三：纯列存表（大范围分析，弱 TP）

表仅服务日终对账、监管报送等批处理，无在线按单号查询，且可接受无主键表以换取导入性能。更多信息，参见 [AP 场景下的主键设计实践](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005682513)）。

```sql
CREATE TABLE payment_ledger_dw (
    txn_id       BIGINT,
    order_id     BIGINT,
    pay_time     DATETIME,
    pay_channel  VARCHAR(32),
    txn_status   TINYINT,
    amount       DECIMAL(18,2),
    merchant_id  BIGINT
)
WITH COLUMN GROUP(each column);

-- 批量导入后建议合并并收集统计信息

```

```sql
SELECT DATE(pay_time) AS dt,
       COUNT(*) AS txn_cnt,
       SUM(CASE WHEN txn_status = 1 THEN amount ELSE 0 END) AS succ_amt
FROM payment_ledger_dw
WHERE pay_time >= '2025-01-01' AND pay_time < '2025-02-01'
GROUP BY DATE(pay_time);

```

### 示例四：行列混存表

业务坚持一张 `payment_ledger` 同时承接支付查询与运营分析，且可接受双份基线存储与更高合并成本。

```sql
CREATE TABLE payment_ledger_htap (
    txn_id       BIGINT        NOT NULL,
    order_id     BIGINT        NOT NULL,
    pay_time     DATETIME      NOT NULL,
    pay_channel  VARCHAR(32)   NOT NULL,
    txn_status   TINYINT       NOT NULL,
    amount       DECIMAL(18,2) NOT NULL,
    merchant_id  BIGINT        NOT NULL,
    PRIMARY KEY (order_id, pay_time, txn_id)
)
PARTITION BY HASH(order_id) PARTITIONS 64
WITH COLUMN GROUP(all columns, each column);

```

```sql
-- 点查类（优化器倾向行存路径）
SELECT amount, txn_status FROM payment_ledger_htap
WHERE order_id = 10086001 AND txn_status = 1
ORDER BY pay_time DESC LIMIT 1;

-- 分析类（优化器倾向列存路径）
SELECT pay_channel, SUM(amount) FROM payment_ledger_htap
WHERE pay_time >= '2025-01-15' AND txn_status = 1
GROUP BY pay_channel;

```

## 相关文档

- [数据表概述 — 索引类型](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005682065)
 - [列存概述 — 如何创建列存表与行列混存表](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000006278429)
 - [MySQL 模式下创建表（含创建列存表）](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005683185)
 - [MySQL 模式下创建列存索引](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005683141)
 - [AP 表结构与查询性能优化](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005682513)
 - [列存 FAQ](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005681899)
 - [列存](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005683265)

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
