原理解读|PolarDB-X 列存索引、列存快照

简介: 列存快照是PolarDB-X基于列存索引提供的轻量级历史数据查询能力,无需数据搬运与额外存储,通过“钉住”版本链节点实现秒级AS OF TSO查询,适用于历史分析与误操作恢复,成本低、易用性强。(239字)

在数据库的日常使用中,"查看过去某一时刻的数据长什么样"是一个常见但不容易解决的需求。传统做法通常依赖 ETL 定期导出或逻辑备份,链路长、成本高、时效差。列存快照的出现,就是为了在列存索引的基础上,以极低的额外成本提供历史数据的查询能力。

为什么需要列存快照

主要适用于两类场景:

场景一:历史数据分析。 业务需要定期回看过去某个时间点的数据,例如每月初分析上个月的经营情况。传统方式需要在月底单独将数据拉出来存到另一个地方,而有了列存快照,只需在月底打一个快照点,后续随时通过 SELECT ... AS OF TSO 查询即可,无需额外的数据搬运和存储。

场景二:数据变更保护与恢复。 在 AI 时代,Agent 驱动的自动化开发越来越普遍,但 Agent 操作数据库时缺乏人工审查,容易误改或破坏数据。列存快照提供了一种轻量级的"后悔药":在每次变更前打一个快照,一旦数据被搞坏,可以直接基于快照查询变更前的状态,用于数据恢复或问题排查,而不必依赖全量备份回滚。

而列存快照是 PolarDB-X 提供的一种基于列存索引的历史数据查询能力。它允许用户:

  1. 创建快照点

自动或手动生成快照点(一个历史版本对应的 TSO),后续可以基于快照点查询历史数据。

  1. 保留快照点

通过指定快照保留时间,系统会保留该时间范围内的快照点及其关联文件,不被 Purge 清理。

  1. 按时间点查询

通过 SELECT ... AS OF TSO 语法,查询任意保留的快照点对应的历史数据。

具有以下特点:

  • 无需数据搬运

快照数据就存储在 OSS 上的列存文件中,不需要额外导出。

  • 查询即恢复

可以直接用 SQL 查询历史数据,也可以通过 INSERT ... SELECT ... AS OF TSO 将数据恢复到当前表。

  • 成本低

快照只是保留版本链元信息和延迟文件清理,无需复制全量数据。

接下来,我们先了解 PolarDB-X 列存索引的整体架构,再深入了解列存快照的使用方式与实现原理。

PolarDB-X 列存架构速览

2.1 整体架构与核心组件

要理解列存快照的原理,需要先了解 PolarDB-X 列存索引的整体架构。本章不展开所有细节,只介绍与快照机制直接相关的核心概念。

PolarDB-X 采用存算分离的分布式架构,与列存相关的核心组件包括:

  • CN(计算节点)

:SQL 入口,负责查询解析、优化和 MPP 执行。列存查询由 CN 协调,构建快照并调度分布式扫描任务。

  • DN(存储节点)

:行存引擎,处理 OLTP 事务,产生 Binlog。

  • CDC

:采集 DN 产生的 Binlog,合并为全局有序的 Global Binlog,供列存节点消费。

  • Columnar(列存节点)

:消费 Global Binlog,将行存数据实时转换为列式存储文件(CSV/ORC/Delete Bitmap),写入 OSS。

  • GMS(元数据服务)

:存储全局元数据,包括列存版本链、快照信息。同时提供 TSO(全局授时)服务。

  • OSS(对象存储)

:列存数据的持久化介质,存储 CSV、ORC 和 Delete Bitmap 文件。

2.2数据存储模型

列存数据在 OSS 上采用 CSV + ORC 的分层组织方式,涉及三种文件:

  • CSV 文件

:增量数据的落盘格式。Columnar 节点消费 Binlog 后,将新写入的数据以追加写的方式写入 CSV 文件。CSV 是无序的行式存储,写入效率高。

  • ORC 文件

:列式存储格式,经过压缩和编码,扫描效率高。由后台 Compaction 任务异步转换而来(CSV 转 ORC,或多个 ORC 合并成一个),数据按列有序分布,读取性能好。

  • Delete Bitmap

:基于 RoaringBitmap 的删除标记,CSV/ORC中的数据被删除时,在 Bitmap 中标记为已删除,而无需直接修改 CSV/ORC 文件。

三者的关系:CSV 负责"快写",ORC 负责"快读",Delete Bitmap 负责标记哪些行已失效。查询时需要综合三者才能得到正确结果。

列存引擎每次提交数据(group commit),都会在 GMS 中生成一个新的版本节点,形成一条版本链:

V1 → V2 → V3 → V4 → ...

每个版本由一个 TSO 唯一标识。TSO 是 GMS 提供的全局单调递增时间戳,Binlog 中的每个事务都携带 TSO,列存引擎负责消费 Binlog 并推进版本。另外,Compaction 也会产生新的版本。

每个版本记录的信息包括:

  • 本次新增的 CSV 文件和 Delete Bitmap,以及这些文件的写入范围(偏移量)
  • Compaction 产生的文件变更(删除的旧文件 + 新增的 ORC 文件)

这条版本链是列存快照的基础——每个快照点本质上就是版本链上的一个节点,保留这个节点及其关联的文件,就能还原出该时刻的完整数据视图。

列存快照原理

3.1 一条数据的列存之旅:从行存写入到快照可见

为了直观理解列存快照的工作方式,我们跟踪一条 INSERT 语句,看它如何从行存写入,最终在列存快照中变得可见。

第一步:行存写入,事务提交。 用户执行 INSERT INTO t_order VALUES (...) ,DN 完成行存写入并提交事务。提交时,GMS 分配一个全局唯一的 TSO 作为该事务的提交时间戳,写入 Binlog。

第二步:Binlog 采集与传输。 CDC 组件从各 DN 采集 Binlog,按 TSO 排序后合并为全局有序的 Global Binlog,发送给 Columnar 节点。

第三步:列存引擎消费,数据落盘。 Columnar 节点消费 Global Binlog,将这条 INSERT 对应的数据追加写入 OSS 上的 CSV 文件。如果同一批次中有 DELETE 或 UPDATE(拆分为 DELETE + INSERT),则同时追加 Delete Bitmap。

第四步:版本提交,快照诞生。 当一个 group commit 周期结束,Columnar 节点将一段时间内的所有事务变更写入 CSV 和 Delete Bitmap 文件,持久化到 OSS 中,最后把文件名、偏移量、TSO 等信息注册到 GMS 的版本链上。

此时,版本链从 V(n) 推进到 V(n+1),新版本的 TSO 会大于等于这条 INSERT 事务的 TSO。

第五步:快照可见。 当用户执行 SELECT ... AS OF TSO 并指定 V(n+1) 的 TSO 时,CN 构建列存快照,该快照包含了新版本的文件列表和偏移量,因此这条数据对查询可见。

从写入到列存可见的延迟通常在秒级。

3.2 快照点的生成:columnar_flush 做了什么

在 上文中我们看到,列存引擎会随着 Binlog 消费不断推进版本链。但这些版本默认会被后台 Purge 机制逐步清理,只保留最新的一个。列存快照的核心就是将某个版本标记为"需要保留",使其不被清理,从而可以在未来被查询

用户可以通过 CALL polardbx.columnar_flush() 手动生成一个快照点。这个调用在内部触发的操作是:

  1. 触发一次强制 group commit。

列存引擎将当前所有已消费但尚未提交的增量数据立即落盘并提交,生成一个新的版本。这一步保证快照点反映的是调用时刻最新的已提交数据。

  1. 记录快照点元信息。

系统在 GMS 中将当前最新版本的 TSO 标记为一个快照点,这会告知 Purge 机制不去清理这个历史版本。这个 TSO 就是后续查询时使用的标识。

  1. 返回 TSO 给用户。

返回这个快照点对应的 TSO,用户可以保存它用于后续查询。

-- 手动生成快照点CALL polardbx.columnar_flush();-- 返回值示例:7206138458723582016-- 也可以指定具体的索引CALL polardbx.columnar_flush('db_name', 'table_name', 'index_name');

除了手动调用,还可以配置自动生成:

  • 按固定间隔:设置 auto_gen_columnar_snapshot_interval(单位:分钟,最小 5 分钟)。实现机制为系统每秒检测一次,若距上次生成快照点的时间超过该参数值,则立即生成新快照。
-- 修改为每隔一小时生成一个快照点CALL polardbx.columnar_set_config('db_name', 'table_name', 'index_name', 'auto_gen_columnar_snapshot_interval', 60);-- 关闭自动生成快照点CALL polardbx.columnar_set_config('db_name', 'table_name', 'index_name', 'auto_gen_columnar_snapshot_interval', -1);
  • 按 CRON 表达式(更常用)

:通过 columnar_auto_snapshot_config 配置定时任务,例如每小时整点生成。实现机制为按 CRON 表达式定期生成一个全局的快照。

-- 每小时的整点生成一个全局快照CALL polardbx.columnar_auto_snapshot_config('ENABLE', '0 0 * * * ?', '+08:00');-- 查看定期快照配置CALL polardbx.columnar_auto_snapshot_config('SHOW');-- 关闭定期快照功能CALL polardbx.columnar_auto_snapshot_config('DISABLE');

需要注意的是columnar_flush 的本质是一次强制提交 + 元数据标记,它不会复制数据或创建物理副本。快照的存储成本来自于延迟清理,被快照引用的文件会被保留更长时间,仅此而已。

3.3 快照的保留与过期:版本链的 Purge 机制

列存引擎在运行过程中会持续产生新版本——每次 group commit 和每次 Compaction 都会在版本链上追加节点。如果所有历史版本都被永久保留,版本链的元数据和关联的物理文件会无限增长。因此,系统需要一个 Purge 机制来定期清理不再需要的旧版本。

Purge 的基本逻辑

Purge 定期扫描版本链,确定一个低水位(Low Watermark),将低水位之前、且未被任何快照引用的版本标记为可回收。具体规则:

  1. 计算低水位

:低水位 = 当前最新版本的 TSO - 保留窗口。保留窗口是一个系统参数,决定了"最近多长时间内的版本默认不清理"。

  1. 跳过被快照引用的版本

:如果某个版本的 TSO 对应了一个尚未过期的快照点,则该版本及其关联文件不会被清理,这保证了列存快照可以被一直保留。

  1. 清理可回收版本

:对于可回收的版本,Purge 会删除其独占的物理文件(不被任何版本引用的 CSV、ORC、Delete Bitmap 文件),并从版本链中移除该节点。

快照如何阻止 Purge

在 上文中我们看到,columnar_flush 会在 GMS 中将某个版本标记为快照点。这个标记的实际效果就是:告知 Purge 跳过该版本。快照保留的不仅仅是版本链上的一个节点,也包括该版本指向的所有物理文件。

快照的过期与清理

快照不会永久保留。用户可以通过以下方式控制快照的生命周期:

-- 设置快照保留时长(单位:秒),示例为保留 7 天CALL polardbx.columnar_set_config('db_name', 'table_name', 'index_name', 'columnar_snapshot_retention_time', 604800);

当快照的创建时间超过保留时长后,系统会自动将其标记为过期。下一次 Purge 扫描时,该版本将不再受保护,相关文件可以被正常清理。

3.4 快照查询:快照构建与缓存策略

当用户执行 SELECT ... AS OF TSO 时,CN 根据指定的 TSO 构建一个快照,确定哪些文件、哪些行对这次查询可见:

  1. 定位版本

:在 GMS 版本链上找到 TSO 小于等于指定值的最大版本节点,作为基准版本。

  1. 收集文件列表

:从版本链起点到基准版本,累积所有文件变更,得到完整的文件集合——所有可见的 ORC 文件、CSV 文件及其偏移量上界、Delete Bitmap 及其偏移量上界。偏移量截断是关键:同一个 CSV 文件在后续版本中可能被追加了新数据,但快照只读取到基准版本记录的偏移量为止。Delete Bitmap 同理。

  1. 下发执行

:将文件列表封装为快照,交给 MPP 引擎进行分布式扫描。

-- 查询历史快照数据SELECT * FROM t_order AS OF TSO 7206138458723582016WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31';-- 数据恢复:将快照数据写回临时表INSERT INTO t_order_backupSELECT * FROM t_order AS OF TSO 7206138458723582016;

缓存策略方面,快照查询采用 bypass cache 策略:CN 检测到 AS OF TSO 指向历史版本时,读取 OSS 文件不经过本地缓存。这是因为快照查询访问的历史数据通常是一次性的,如果写入缓存会挤出常规查询的热数据,造成缓存污染。以快照查询的单次延迟换取整体缓存效率,对于低频批量分析的典型场景是合理的取舍。

Compaction 与快照的交互

4.1 CSV 到 ORC 的合并

在 2.2 中我们提到,CSV 是增量数据的落盘格式,写入快但扫描慢;ORC 是列式格式,扫描快但不支持追加写。Compaction 的核心任务之一就是将 CSV 数据异步转换为 ORC,提升查询性能。

Compaction 在后台持续运行,主要包括两类操作:

  • CSV → ORC:

将一批 CSV 文件中未被删除的数据转换为 ORC 格式,按列有序存储。

  • ORC 合并:

将多个 ORC 文件的有效数据合并为一个 ORC 文件,减少文件数量和数据空洞,降低查询时的 IO 开销。

每次 Compaction 完成后,会在版本链上提交一个新版本,记录本次的文件变更:新增了哪些 ORC 文件、删除了哪些旧的 CSV/ORC 文件。

4.2 Compaction 对快照可见性的影响

Compaction 会替换文件,但不能破坏已有快照的数据完整性。

举一个具体的例子:

  1. 版本 V5 时,数据分布在 csv_1orc_1orc_2 三个文件中。用户在 V5 打了一个快照。
  2. 后台 Compaction 将 csv_1 转换为 orc_3,并在版本 V8 提交了这个变更。从 V8 开始,orc_3 替代了 csv_1
  3. 当用户查询 V5 的快照时,快照仍然指向 csv_1 + orc_1 + orc_2,与 Compaction 后的文件无关。

注意到:

  • Compaction 产生的文件变更记录在新版本(V8)上,不会修改历史版本的元数据。
  • Purge 在清理时会检查 csv_1 是否仍被某个快照引用,如果是,则跳过删除。

因此,Compaction 与快照可以安全地并行运行,互不干扰。代价是被快照引用的旧文件会延迟清理,占用额外的 OSS 存储空间,直到快照过期。由于列存数据本身具有较高的压缩率,且多个版本共享同一批物理文件(快照只额外保留元信息和延迟文件清理),实际的额外存储开销很低。

4.3 Schema Evolution 下的快照兼容

当用户对表执行 DDL(如 ALTER TABLE ADD COLUMN)后,列存索引的 Schema 会发生变化。新版本的 ORC/CSV 文件按新 Schema 写入,但快照可能指向旧 Schema 的文件。

PolarDB-X 通过 Schema 多版本机制解决这个问题:每个版本都能通过 GMS 的元信息找到该版本对应的 Schema 版本号。查询快照时,CN 根据最新版本的 Schema 构建查询计划,读取旧文件时按旧 Schema 解析,保证读取的正确性。

这意味着:

  • 快照查询能正确处理打快照之后发生的 ADD COLUMNDROP COLUMN 等变更。
  • 返回的数据始终符合快照时刻的表结构,不会因为后续的 DDL 而出错。

与其他恢复方式的对比

列存快照并不是唯一的历史数据恢复手段。PolarDB-X 还支持传统的备份恢复行存快照,三者适用于不同场景。

备份恢复

行存快照

列存快照

原理

全量备份 + 增量 Binlog 回放,恢复到指定时间点

保留 Undo 日志,查询时逐行回退到历史版本

保留列存版本链上的历史版本,按文件偏移量截断读取

恢复粒度

整个实例

表级别

表级别

资源开销

需要管控任务流创建新实例,占用额外的计算和存储资源

无需额外资源,复用当前实例的 Innodb 引擎

无需额外资源,复用当前实例的列存引擎

存储成本

高(全量数据拷贝)

较高(行存存储成本高于列存)

低(多版本共享物理文件)

查询效率

不支持直接查询,需恢复完成后才能访问

快(数据在本地行存中,点查无需读取无关数据)

适合批量分析(需远程读取 OSS 上的列存文件,按块读取)

适用场景

灾难恢复、整实例回滚

短时间内的行级回查、点查为主的场景

长周期历史分析、批量数据恢复

简而言之:备份恢复是"重建一个实例",行存快照是"原地回退单行",列存快照是"直接查历史文件"。三者的选择取决于恢复粒度、时间跨度和查询模式

总结

列存快照的本质是在列存版本链上"钉住"一个历史版本,使其不被 Purge 清理,从而支持按时间点查询历史数据。整个机制具有以下特点:

  • 无需数据搬运

快照数据就存储在 OSS 上的列存文件中,不需要额外导出。

  • 查询即恢复

可以直接用 SQL 查询历史数据,也可以通过 INSERT ... SELECT ... AS OF TSO 将数据恢复到当前表。

  • 成本低

快照只是保留版本链元信息和延迟文件清理,无需复制全量数据。

从使用角度看,用户只需关心两个操作:columnar_flush 生成快照点,SELECT ... AS OF TSO 查询快照。底层的版本链管理、文件保留、Purge 协调、Schema 兼容等复杂性,都由系统透明处理。

相关文章
|
12天前
|
关系型数据库 分布式数据库 PolarDB
PolarDB开源新作:DuckDB-paimon,助力企业构建面向AI的多模数据底座
DuckDB-paimon 是 PolarDB 团队开发的 DuckDB 插件,支持直接查询 Apache Paimon 数据湖表(本地/OSS),无需 Flink/Spark 集群。基于 paimon-cpp 原生 C++ 实现,具备列裁剪、多线程扫描、Secret 安全凭证等特性,实现秒级轻量分析。
210 9
|
4月前
|
关系型数据库 MySQL Java
开源PolarDB-X备份恢复操作实操
作者介绍: 付文革,航天壹进制(江苏)信息科技有限公司产品研发,专注于数据库备份,主攻MySQL相关数据库以及各种国产分布式数据库的备份恢复,主要使用Java 、Python、Shell等编程语言 航天壹进制(江苏)信息科技有限公司(简称航天壹进制)作为中国航天科工集团有限公司旗下上市公司航天工业发展股份有限公司的全资下属企业,专注于数据安全领域,自主研发并提供数据保护与业务连续性管理产品、解决方案及服务。
|
18天前
|
算法 物联网 API
魔搭推出Twinkle: 训练即服务, 让模型训练回归算法语义
Twinkle是ModelScope推出的开源模块化训练框架,采用Client-Server架构,支持本地、集群及Serverless训练。它以算法语义API抽象为核心,兼顾易用性与灵活性,提供细粒度控制、动态组件配置和多租户LoRA并发训练能力,并原生兼容Tinker API,全面开源,助力大模型训练服务化(TaaS)落地。
391 14
|
19天前
|
人工智能 安全 Serverless
让 AI Agent 安全“跑”在云端:基于函数计算打造 Agent 代码沙箱
Agent 代码沙箱是保障 AI 智能体安全执行的核心基础设施。依托函数计算构建强隔离、有状态、低成本的 AI 运行时。
|
18天前
|
存储 人工智能 关系型数据库
OpenClaw怎么可能没痛点?用RDS插件来释放OpenClaw全部潜力
OpenClaw插件是深度介入Agent生命周期的扩展机制,提供24个钩子,支持自动注入知识、持久化记忆等被动式干预。相比Skill/Tool,插件可主动在关键节点(如对话开始/结束)执行逻辑,适用于RAG增强、云化记忆等高级场景。
739 56
OpenClaw怎么可能没痛点?用RDS插件来释放OpenClaw全部潜力
|
18天前
|
人工智能 自然语言处理 IDE
养虾只需丢给 Qoder 1个 Skill:安装、配置、上手OpenClaw 一次性搞定
本文介绍如何用Qoder快速对接OpenClaw:三步完成——安装Qoder IDE、配置OpenClaw与钉钉/飞书机器人、通过ACP协议接入Qoder CLI。无需手动部署,丢个Skill文件,泡杯茶的功夫,AI虾塘就跑起来了!
1690 66
|
1月前
|
人工智能 API 机器人
OpenClaw 用户部署和使用指南汇总
本文档为OpenClaw(原MoltBot)官方使用指南,涵盖一键部署(阿里云轻量服务器年仅68元)、钉钉/飞书/企微等多平台AI员工搭建、典型场景实践及高频问题FAQ。同步更新产品化修复进展,助力用户高效落地7×24小时主动执行AI助手。
24281 159
|
19天前
|
Arthas 人工智能 Java
我们做了比你更懂 Java 的 AI-Agent -- Arthas Agent
Arthas Agent 是基于阿里开源Java诊断工具Arthas的AI智能助手,支持自然语言提问,自动匹配排障技能、生成安全可控命令、循证推进并输出结构化报告,大幅降低线上问题定位门槛。
679 64
我们做了比你更懂 Java 的 AI-Agent -- Arthas Agent
|
5天前
|
缓存 监控 数据可视化
实战指南:通过API高效获取全球股票数据分析
本文为量化交易者提供StockTV API实战指南:涵盖美股/日股数据获取、实时行情查询、多周期K线调用、技术指标计算及可视化(mplfinance),并详解WebSocket实时推送、缓存优化与容错机制,助你高效构建金融分析系统。(239字)
|
25天前
|
人工智能 安全 前端开发
Team 版 OpenClaw:HiClaw 开源,5 分钟完成本地安装
HiClaw 基于 OpenClaw、Higress AI Gateway、Element IM 客户端+Tuwunel IM 服务器(均基于 Matrix 实时通信协议)、MinIO 共享文件系统打造。
8992 19

热门文章

最新文章