【StarRocks系列】Update语句

发布于:2025-06-24 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

简要流程

详细流程

1. UPDATE 语句执行流程

2. 如何更新表的数据

3. 是否支持事务

总结关键点


简要流程

  1. 前端处理(FE)
    • 解析 SQL 并验证主键条件
    • 生成包含主键列表和新值的更新计划
    • 按主键哈希分发到对应 BE
  1. 后端执行(BE核心流程)
    • 通过主键索引快速定位数据位置
    • 采用"读-改-写"模式(非就地更新)
    • 对同一主键的多版本数据保留最新值

  1. 提交与清理
    • 元数据原子切换确保查询一致性
    • 异步 Compaction 回收旧数据空间
    • 写时复制(Copy-on-Write)机制保证读稳定性

详细流程

StarRocks 的 UPDATE 语句是其 异步主键更新模型 的核心功能(自 2.3 版本引入,并持续优化),专为高效处理按主键进行批量更新的场景设计。其实现与传统的 OLTP 数据库有显著区别,充分利用了列式存储和 MPP 架构的优势。下面详细介绍你关心的三个方面:

1. UPDATE 语句执行流程

StarRocks 的 UPDATE 操作是一个异步、批处理的过程,主要发生在后台的 BE(Backend)节点上,大致流程如下:

  1. 用户提交 UPDATE 语句:
    • 用户通过 MySQL 客户端或其他兼容工具向 FE(Frontend)提交标准的 SQL UPDATE 语句。
    • 示例:UPDATE table_name SET column1 = value1 [, column2 = value2 ...] WHERE pk_column = some_value [AND ...];
  1. FE 解析与计划生成:
    • FE 解析 SQL,验证语法、权限、目标表和列是否存在、WHERE 条件是否包含完整主键(或其等价条件)。
    • FE 生成一个逻辑更新计划。这个计划主要包含两部分信息:
      • 需要更新的行定位信息: 基于 WHERE 条件(必须能精确定位到主键)计算出哪些主键值对应的行需要被修改。
      • 新的列值: 指定的 SET 子句中的新值。
  1. 数据分发到 BE:
    • FE 将逻辑更新计划(主要是主键列表和对应的新值集合)分发给存储了相关数据分片的 BE 节点。
    • 分发策略基于主键的哈希值,确保包含特定主键行的 Tablet(数据分片)所在的 BE 收到该行的更新请求。
  1. BE 执行更新操作(核心 - 读改写):
    • 每个 BE 收到属于自己 Tablet 的更新任务后,执行以下关键步骤:
      • a. 定位数据文件: 利用主键索引快速定位包含目标主键行的数据文件(Segment 文件)。主键索引是存储在内存中的。
      • b. 读取原始行: 读取包含目标行的整个 Segment 文件(或相关的行组)。
      • c. 应用更新: 在内存中,根据 UPDATE 语句的 SET 子句,修改读取到的目标行的对应列值。
      • d. 排序与去重: 对这批更新后的行(可能包含同一主键的多次更新)按主键排序,并只保留最新版本(基于操作序列号或时间戳)。这是保证主键唯一性和最终一致性的关键。
      • e. 写入新文件: 将排序去重后的这批更新行(连同该 Segment 中未修改的行)写入一个新的 Segment 文件。原始文件不会被就地修改
      • f. 提交元数据: 向 FE 报告新生成的 Segment 文件信息,并更新元数据(如版本号)。
  1. 垃圾回收(Compaction):
    • 新 Segment 文件写入成功后,旧的 Segment 文件(包含被更新行原始数据)会被标记为可删除。
    • 后台的 Compaction 进程(Base Compaction 或 Cumulative Compaction)会异步地将包含多个版本数据的 Segment 文件合并压缩,物理删除被覆盖的旧数据行,回收存储空间。

2. 如何更新表的数据

  • 基于主键: UPDATE 必须指定完整的主键或能等价推导出主键的 WHERE 条件(例如 WHERE primary_key_col = ?)。这是 StarRocks 高效定位数据的基础。
  • 列式更新: 在 SET 子句中指定需要更新的列及其新值。未指定的列保持不变。
  • “读-改-写”模式: 核心机制是读取包含目标行的原始数据块 -> 在内存中修改目标列 -> 将修改后的整行(连同该块中未修改的行)写入新文件。不是直接在原存储位置修改位图或单个值。
  • 批量处理: 一次 UPDATE 操作通常涉及一批行的更新(即使 SQL 看起来只更新一行,内部也可能批量处理)。BE 在内存中处理一批更新,排序去重后一次性写入新文件,效率远高于单行更新。
  • 写时复制 (Copy-on-Write): 更新操作通过创建包含新数据的新文件(Segment)来实现,原始文件保持不变直到被异步回收。这保证了高并发读操作的稳定性(读操作总是访问旧的、一致的文件版本,直到新版本提交)。
  • 原子性与版本化: 新 Segment 文件的写入和元数据的更新(版本切换)是原子的。查询在某个时间点看到的总是某个一致的数据版本。

3. 是否支持事务

StarRocks 的 UPDATE 语句在单个语句级别提供原子性持久性

  • 原子性 (Atomicity per Statement):
    • 单行更新: 对一个主键行的所有列更新是原子的。要么所有指定列都更新成功,要么都不更新。
    • 多行更新: 同一批处理内更新的多行操作也具有原子性。这意味着在 BE 处理一批更新时,这批中的所有行更新要么全部成功写入新 Segment 并提交(元数据更新),要么全部失败(例如 BE 崩溃)。用户不会看到部分更新的状态。
  • 隔离性 (Isolation):
    • StarRocks 使用 MVCC (多版本并发控制)。UPDATE 操作创建数据的新版本。
    • 正在进行的 UPDATE 操作不会阻塞读操作。读操作(如 SELECT)会读取操作开始时已提交的最新版本数据(快照隔离),看不到正在进行的 UPDATE 产生的中间状态或未提交的新版本。
    • 多个并发的 UPDATE 操作修改同一主键行时,基于操作序列号或时间戳,只有最后一个成功的 UPDATE 会生效(最终一致性)。在 BE 处理阶段,排序去重步骤保证了这一点。用户可能会看到基于主键的“最后写入获胜”行为。
  • 持久性 (Durability): 一旦 UPDATE 操作成功提交(元数据更新完成),数据就持久化写入磁盘。即使发生节点故障,已提交的数据也不会丢失。
  • 多语句事务:
    • 社区版: 不支持 跨多个 SQL 语句(如 BEGIN; UPDATE ...; UPDATE ...; COMMIT;)的 ACID 事务。每个 UPDATE 语句是独立提交的。
    • 企业版: 支持 有限的多语句事务 (自 3.0 版本引入)。在一个显式的 BEGIN/COMMIT/ROLLBACK 块内执行的多个 DML 语句(INSERT, UPDATE, DELETE)可以作为一个原子操作提交或回滚。这是通过 FE 协调和内存队列实现的,但有容量和超时限制,主要用于小批量、短时操作。它不是传统 OLTP 数据库那种支持长时间运行、大事务的强事务模型。

总结关键点

  • 流程: 解析 -> 定位主键 -> 分发 -> (BE)读原始数据 -> 改内存数据 -> 排序去重 -> 写新文件 -> 提交元数据 -> 异步回收旧文件。
  • 更新机制: 基于主键批量处理,读-改-写模式,写时复制(创建新文件),利用主键索引排序去重保证效率与主键唯一性。
  • 事务: 单条 UPDATE 语句具有原子性和持久性,通过 MVCC 提供快照隔离级别的读一致性。社区版不支持多语句事务,企业版提供有限的多语句事务支持。

理解 StarRocks 的 UPDATE 是面向分析场景优化的、基于主键的异步批量更新机制,而非 OLTP 式的逐行实时更新,对于正确使用和性能调优至关重要。它非常适合数据修正、缓慢变化维度(SCD Type 1/2)、标签更新等场景。


网站公告

今日签到

点亮在社区的每一天
去签到