在市中心有一家开了十年的老字号餐厅。每天中午,前台点单员要在一秒内记下客人的点菜信息——菜品、口味、桌号、价格,这是“交易处理”。与此同时,老板每个月都会请总部会计来复盘:卖得最好的三道菜是什么?哪个时段人手不够?这需要翻遍一摞又一摞的订单本,汇总出规律,这是“分析查询”。 传统做法是开两家店:一家店专门记流水账(数据库 OLTP),另一家店专门把账本重新归档做报表(数仓 OLAP)。但账本要来回搬运,今天的数据往往明天才能分析,时效性大打折扣。TiFlash 的出现,打破了“鱼与熊掌不可兼得”的僵局。它像一位聪明的总厨,在同一套餐厅里同时保留了一本实时更新的流水账本和一套按菜品、价格分类的归档账本。主营业务的记账不会被分析动作拖慢,而分析工作又可以翻着分类账本快速得出结论。这套理念,就是 HTAP——让一个系统同时高效支撑交易与分析。

岗位关联

对 AI 与数据库从业者来说,理解 TiFlash 的列存、Raft Learner 与向量化设计,是规划实时数仓和混合负载架构的基本功,也是 TiDB 生态面试与选型评审的核心考点。

目录
  1. 可视化演示
  2. HTAP:一套系统两本账
  3. 列存原理:分类账本的艺术
  4. Raft Learner:不投票的传菜单副手
  5. 强一致读:时间戳与日志位置对齐
  6. 向量化执行:大锅铲批量烹饪
  7. 应用实践:从账本到实时决策
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

HTAP:一套系统两本账

想象一家日接待上千桌的连锁餐厅。店面收银台要最快速度记下每桌的菜名、金额、桌号,这是 OLTP——在线交易处理;而总部每周要复盘:哪道菜毛利最高?哪个城市翻台率最好?这是 OLAP——在线分析处理。过去,老板不得不维护两套系统:一套前台收银,一套把数据搬运到总部仓库做统计,中间存在着运输延迟。

TiDB 的野心就是打破这个局面。它把“交易型工作负载”和“分析型工作负载”放进同一套数据库:所有数据默认以行存形式存在于 TiKV 节点上,服务高频点单;同时用户可以给任意表增加 TiFlash 列存副本,让它承担分析型查询。这种在同一系统内同时支撑两类负载的架构,业界称为 HTAP,即混合事务与分析处理。

从一张表来看,行存相当于一本按时间顺序写的流水账,列存则像一本按“菜名”“金额”“城市”重新编排的分类账。行存扫描一张 20 列的表,哪怕只想要其中 2 列,也要把 20 列都读一遍;列存则直接走向那 2 列。这里的加速效果可以量化:

HTAP 的目标,就是让交易与分析在同一个集群内并行不悖:交易保持亚毫秒级延迟,分析也能在秒级返回。在 TiDB 生态中,TiKV 提供强一致、高可用的行存;TiFlash 提供列存与向量化分析能力;TiDB Server 负责 SQL 解析与优化,自动决定把查询发往哪一端。这就是后面每一节展开的地基。有了“两本账”的直觉,我们再看账本内部是怎么排版的。

IO加速比=N总列数M查询列数\displaystyle \text{IO加速比}=\frac{N_{\text{总列数}}}{M_{\text{查询列数}}}
公式读作:总列数除以查询列数,得到列存相对行存在“只读必要数据”上的 IO 收益倍数。
  1. 总列数一张表包含的全部字段数量,相当于账本里每一笔订单的完整信息项数。
    N总列数N_{\text{总列数}}
  2. 查询列数分析 SQL 实际需要读取的字段数量,比如只统计“金额”和“品类”两列。
    M查询列数M_{\text{查询列数}}
  3. 相除得加速比行存要读全表的代价与列存只读指定列的代价之比,倍数越大列存收益越明显。
    N总列数M查询列数\frac{N_{\text{总列数}}}{M_{\text{查询列数}}}

列存原理:分类账本的艺术

分类账本之所以高效,关键在于“同类信息放在一起”。列式存储把同一列的所有值连续排在磁盘上,而不是把整行数据排在一起。看一个小例子:订单表(订单号、客户、金额、品类、城市、时间)。行存磁盘上的顺序大致是:订单号1、客户1、金额1、品类1、城市1、时间1、订单号2、客户2……列存则是:所有订单号连续一段,接着是所有客户,再是所有金额,各占一段连续区域。

这样的排版带来两个直接好处。第一是 IO 更少:分析查询只需读取涉及的列,比如只统计金额和品类,就完全跳过客户、城市等无关列。第二是压缩更高效:同一列数据往往重复度很高,城市列大量出现“北京”“上海”,用字典编码能省出很大空间;数字列用差分编码或通用压缩也能压到几分之一。此外,TiFlash 还支持筛选下推:像 WHERE city = 'beijing' 这样的过滤条件,会下推到列存层提前执行,只返回满足条件的行,进一步减少上层处理的数据量。

但列存的痛点在于写入。随机小写入如果直接改大列块,代价会很高。TiFlash 用 Delta Tree 解决:新写入的数据先进入一个小的 Delta 暂存区,读取时同时读 Delta 区和主列存区;当 Delta 区积累到阈值,再后台合并进大的列块。这样既保留了列存的高压缩与高性能扫描,又让写入不必频繁重写大列文件。回到比喻:分类账本旁边搁着一叠待誊录的便签条,写完一批菜就抽空工整地抄进大账本;合账之前,算账的人两处都要看。账本主体始终整洁,便签条让新记录随到随记。

压缩率=原始数据大小压缩后数据大小\displaystyle \text{压缩率}=\frac{\text{原始数据大小}}{\text{压缩后数据大小}}
公式读作:原始数据大小除以压缩后数据大小,得到列存压缩带来的空间节省倍数。
  1. 原始数据大小未压缩时某一列数据占用的字节数。
    原始数据大小\text{原始数据大小}
  2. 压缩后数据大小经过字典编码、差分编码或通用压缩之后的字节数。
    压缩后数据大小\text{压缩后数据大小}
  3. 相除压缩率大于 1 表示空间变小,数值越大,磁盘占用与扫描 IO 越低。
    原始数据大小压缩后数据大小\frac{\text{原始数据大小}}{\text{压缩后数据大小}}

Raft Learner:不投票的传菜单副手

分类账本不能凭空变出来,它需要持续从收银流水账本同步。Raft 是 TiKV 实现多副本一致性的协议:一个 Leader 负责接收写请求,若干 Follower 同步日志;写入必须获得多数派,也就是超过一半投票节点的确认,才能提交。

TiFlash 想要这份数据,却不希望自己的存在拖慢收银台。它可以加入 TiKV 的 Raft 组,但以 Learner 身份加入。Raft Learner 是一个只复制日志、不参与投票的特殊角色:它持续从 Leader 拉取日志并应用数据,但在选举和提交确认中没有任何话语权。这意味着主链路的确认节点数完全由 TiKV 的投票成员决定,无论添加多少个 TiFlash 节点,前台写入的等待时间都不会多一秒。这就是“链路隔离”:同步分析副本的动作被完美隔离在交易链路之外。

注意,这个公式里的 n 只数 TiKV 的投票节点,TiFlash Learner 数量不进入 n。即使给 20 张表各配 3 个 TiFlash 副本,前台交易确认速度依然由 TiKV 自己的多数派决定。用故事收尾:餐厅前台和收银系统是核心链路,传菜单的副手只是默默把每一单背下来,不参与收银台找零确认,自然不会让顾客多等一秒。

多数派确认数=⌊n2⌋+1\displaystyle \text{多数派确认数}=\lfloor\frac{n}{2}\rfloor+1
公式读作:五节点 Raft 组中,至少 3 个节点确认才能提交写入,这就是多数派门槛。
  1. 节点总数TiKV Raft 组内参与投票的节点个数。
    nn
  2. 半数向下取整把节点数除以二,向下取整,得到不超过一半的最大整数。
    ⌊n2⌋\lfloor\frac{n}{2}\rfloor
  3. 加一得到多数派门槛,也就是超过半数所需的最少确认节点数。
    ⌊n2⌋+1\lfloor\frac{n}{2}\rfloor+1

强一致读:时间戳与日志位置对齐

副手把菜单一份份背回总部,但他可能比前台慢半拍。如果老板恰好在这半拍里打开账本,会不会看到缺了一两单的旧数据?TiFlash 用两样东西来保证不看到旧账:全局时间戳和 Raft 日志位置。

TiDB 的每个事务在开始时都会从 TSO 全局授时中心申请一个递增的时间戳,作为这个事务的“生效时刻”。TiKV 在 Raft 日志中写入数据时,该日志项就带着这个时间戳;TiFlash 从 Raft 日志复制数据时,会记录自己已经应用到的日志位置,也就是 apply index 对应的最大时间戳。当一个查询要读取某个快照时间 t 的数据时,TiFlash 把这个 t 与本地已应用时间比较:如果快照时间不大于本地进度,说明所有 t 之前的修改都已落账,直接读即可;如果快照时间太新,本地还没追上,引擎会等待日志继续同步,或者把查询转发给 TiKV,让行存来接这个查询。无论哪条路,对用户来说拿到的都是强一致的结果。

所谓“异步复制”绝不意味着“弱一致读”。餐厅里的副手虽然晚半拍,但端菜前会仔细核对手上单据的更新时间,如果发现缺的正是客人点的招牌菜,他会让客人稍等或者直接跑到前台拿最新菜单——顾客永远不会看到上一轮的旧菜单。

t快照≤t已应用⇒可安全读\displaystyle t_{\text{快照}}\le t_{\text{已应用}}\Rightarrow\text{可安全读}
公式读作:查询快照时间小于等于 TiFlash 本地已应用时间时,本次读取是强一致的,可以直接返回数据。
  1. 快照时间查询希望看到的时间点,由 TSO 在事务开始时获得。
    t快照t_{\text{快照}}
  2. 已应用时间TiFlash 本地日志已经应用到的最大时间戳。
    t已应用t_{\text{已应用}}
  3. 判定式快照时间不晚于本地进度,说明本地已经包含本次查询所需的最新数据,可以安全返回。
    t快照≤t已应用t_{\text{快照}}\le t_{\text{已应用}}

向量化执行:大锅铲批量烹饪

账本建好了,怎么快速算账?如果会计一行一行地看订单、一列一列地加总,速度肯定跟不上老板的实时提问。TiFlash 采用向量化执行引擎,把数据按批处理,而不是按行处理。

所谓向量化,是指每次操作面对的是一个批次的数据,比如 1024 行。传统执行器像一个嵌套循环:每来一行,执行一次表达式、做一次条件判断;向量化执行器则把一批数据放入连续内存,循环体内部没有分支,批量做算术、批量比较、批量聚合。得益于这套设计,TiFlash 的列式算子可以逐个批次处理数据,而不是逐行调用函数。

从底层硬件看,CPU 的 SIMD 指令让向量化如虎添翼。现代 CPU 的寄存器可以同时装多个数:例如 AVX2 的 256 位寄存器一次能放下 8 个 32 位浮点数。标量代码一次算 1 个,向量代码一次算 8 个,理论加速比就是 8 倍。再加上批量数据在内存中连续紧凑排列,让 CPU 缓存命中率极高,进一步减少了等待内存的时间。

回到厨房:与其一份牛排一块煎板慢慢煎,不如把十块牛排同时放进一个超大平底锅,锅铲一挥,十块一起翻面。CPU 的 SIMD 就是这把大锅铲,向量化执行就是那个超大平底锅。

加速比≈N标量循环N向量指令≈WSIMD宽度\displaystyle \text{加速比}\approx\frac{N_{\text{标量循环}}}{N_{\text{向量指令}}}\approx W_{\text{SIMD宽度}}
公式读作:把逐行循环次数除以向量指令次数,得到的比值近似等于 SIMD 一次并行处理的数据个数。
  1. 标量循环次数用逐行方式处理同一批数据所需的循环次数。
    N标量循环N_{\text{标量循环}}
  2. 向量指令次数同一批数据以批处理方式执行时所需的指令条数。
    N向量指令N_{\text{向量指令}}
  3. 两式相除二者之比近似为 SIMD 并行度,即一条指令同时处理的数据份数。
    N标量循环N向量指令≈WSIMD宽度\frac{N_{\text{标量循环}}}{N_{\text{向量指令}}}\approx W_{\text{SIMD宽度}}

应用实践:从账本到实时决策

账本和厨房都备齐了,餐厅老板终于可以随时翻开分类账本回答实时问题。TiFlash 最常见的落地场景是“实时数仓”。传统数仓通常是 T+1,每天夜里的任务把业务库数据同步到数仓,白天看到的都是昨天的数据。引入 TiFlash 后,业务库 TiKV 的数据通过 Raft Learner 实时流到列存副本,秒级可见,BI 报表可以做到近实时刷新,运营不必再等一天。

第二个典型场景是“混合负载隔离”。在线交易系统白天压力最大,如果此时运营发起一个全表聚合大查询,很容易拖垮交易。TiDB 的优化器会自动识别分析型查询,并把这类查询派发给 TiFlash 执行,交易继续走 TiKV,互不干扰。副本管理的灵活性也值得一提:DBA 可以执行 ALTER TABLE orders SET TIFLASH REPLICA 2 来为订单表增加两个列存副本,也可以随时调整副本数量,整个过程不需要重启集群,副本数据会由后台任务自动补齐。

三者相加通常在秒级以内,远小于传统 T+1 的“天”级。现代 HTAP 的真正价值,不是把数仓搬得更近,而是让分析查询与交易数据在时间维度几乎零距离——老板刚收到钱,账本上就已经能算出这一桌的毛利了。

ΔT可见性=T提交+T同步+T合并\displaystyle \Delta T_{\text{可见性}}=T_{\text{提交}}+T_{\text{同步}}+T_{\text{合并}}
公式读作:从写入提交到列存可查的总延迟,等于交易提交时间、日志同步时间与 Delta 合并时间之和。
  1. 交易提交时间业务写入在 TiKV 完成 Raft 多数派提交所花的时间。
    T提交T_{\text{提交}}
  2. 日志同步时间Raft 日志被 TiFlash Learner 拉取并应用的时间。
    T同步T_{\text{同步}}
  3. Delta 合并时间新写入的数据从 Delta 暂存区合并进入主列块的时间。
    T合并T_{\text{合并}}

AI 应用场景

实时金融风控看板

阶段:数据采集与实时分析

解决的问题:银行交易系统的核心库白天承受着每秒数千笔的写入,如果风控团队直接在上面跑大聚合 SQL,很容易拖慢在线交易。传统方案是把数据同步到 Hadoop,但延迟有分钟级甚至 T+1。借助 TiFlash,风控 SQL 自动路由到列存副本执行,交易库完全无感。

具体案例:某支付公司给交易流水表增加 2 个 TiFlash 副本,风控团队实时查询“过去 5 分钟金额大于 5000 元的交易在城市维度上的分布”,查询耗时从分钟级降到 2 秒以内。

电商运营实时大屏

阶段:数据可视化与业务监控

解决的问题:运营大屏需要看今日实时 GMV、热销品类 Top。过去依赖 Kafka、Flink、Redis 的复杂链路,开发和维护成本高。TiFlash 直连 TiDB 业务数据,一条 SQL 就能完成多维聚合。

具体案例:某电商平台让订单明细表同时拥有行存和列存副本,运营查询“今日实时 GMV 按品类分组”,一条 SELECT SUM(amount) FROM orders WHERE ts >= today GROUP BY category 在 TiFlash 上毫秒级返回。

多租户 SaaS 工作负载隔离

阶段:资源调度与混合负载治理

解决的问题:多租户系统中,分析型大查询和交易型小请求共用一份数据,极容易互相干扰。TiFlash 承担全部分析查询,交易流量在 TiKV 上持续稳定,实现真正的负载隔离。

具体案例:某 SaaS 平台把租户的报表查询全部切到 TiFlash,交易请求 P99 延迟从 120ms 下降到 40ms,报表响应速度反而提升了 10 倍。

Python 演示

python68 行
import random class RowStore:    """行式存储, 一行的所有字段挨着存"""     def __init__(self):        self.rows = []     def insert(self, row):        self.rows.append(row)     def scan(self, cols):        cost = 0        result = []        for row in self.rows:            cost += len(row)  # 读整行 6 个字段            result.append((row[cols[0]], row[cols[1]]))        return result, cost  class ColumnStore:    """列式存储, 每个字段单独存一列"""     def __init__(self):        self.columns = {}     def insert(self, row):        for k, v in row.items():            self.columns.setdefault(k, []).append(v)     def scan(self, cols):        cost = 0        result = []        for c in cols:            cost += len(self.columns[c])  # 只读需要的列            result.append(self.columns[c])        return result, cost  def make_order(i):    return {        "order_id": i,        "customer": "user%d" % random.randint(1, 5000),        "amount": random.randint(1, 1000),        "category": random.choice(["food", "cloth", "digital", "book"]),        "city": random.choice(["beijing", "shanghai", "shenzhen", "hangzhou"]),        "ts": random.randint(1600000000, 1700000000),    }  def main():    row_store = RowStore()    col_store = ColumnStore()    for i in range(100000):        order = make_order(i)        row_store.insert(order)        col_store.insert(order)     selected = ("amount", "category")    _, row_cost = row_store.scan(selected)    _, col_cost = col_store.scan(selected)    print("行存读取格子数: %d" % row_cost)    print("列存读取格子数: %d" % col_cost)    print("列存节省比例: %.1f%%" % (1 - col_cost / float(row_cost)))  if __name__ == "__main__":    main()
目的:用 10 万笔模拟订单对比行式存储与列式存储在“只查 2 列”的分析查询上读取数据量的差距,直观展示列存省 IO 的原理。
  1. self.columns.setdefault(k, []).append(v)新订单各字段分别落到自己的列列表,天然形成列存结构
  2. for row in self.rows:行存扫描从第一行遍历到最后一行,所有字段都逃不过
  3. cost += len(row)整行的 6 个字段都被“读进内存”,即使只需要其中 2 个字段
  4. cost += len(self.columns[c])列存只统计被选中列的长度,与表的总列数完全无关
  5. result.append(self.columns[c])直接取整个列数据块,不需要逐行过滤
  6. row_store.scan(selected)虽然只查询 2 列,行存依然全表扫描
  7. col_store.scan(selected)列存按列名直达数据区,只读取需要的两列
  8. print("列存节省比例: %.1f%%" % ...)输出行存读取格子数与列存的量化对比,演示 IO 加速比

常见误区

误区我以为 TiFlash 是一个需要单独安装、单独连接的数据仓库,跑业务时要在代码里连两个数据源,手动切换查询去哪边执行。

正解TiFlash 是 TiDB 集群内部的一个存储引擎角色,和 TiKV 在同一个集群中。业务照常通过 TiDB Server 发 SQL,优化器自动决定把分析查询路由到 TiFlash,客户端完全无感知。就像分类账本和流水账本都放在同一家餐厅的账房里,而不是搬到另一栋楼。

为何常见:传统数仓“第二套系统”的观念深入人心,很多人天然觉得列存就该是独立软件。

误区既然 TiFlash 也要同步每一笔数据,那交易写入就要等所有 TiFlash 副本确认,否则数据怎么保证一致?

正解Learner 不参与投票,不会增加多数派确认数量。TiKV 的写入只需要满足自己 Raft 组的多数派确认,跟 TiFlash 节点数量无关。TiFlash 的异步复制在主链路提交完成之后继续消化,前台收银不会为传菜单的副手多等一秒。

为何常见:人容易把“要同步数据”等同为“要等同步完成”,忽略了 Raft 协议里不同角色的投票权差异。

误区TiFlash 既然是异步复制,那它永远可能读到落后的数据,只能做离线分析,不能对外提供实时查询。

正解TiFlash 通过快照时间和本地日志 apply 位置判断自己是否追齐。如果没追齐,查询会被等待或者转发到 TiKV。对客户端而言,读 TiFlash 和读 TiKV 的强一致语义一致,不会出现“刚写入就读不到”的情况。

为何常见:把“最终一致”的直觉套到所有异步复制方案上,没有深入了解 Learner 的日志同步与 TSO 时间戳机制。

误区列存就是把每一行的值拆开放到不同的列文件里,除了扫描少读点数据,和行存没有本质区别。

正解列存的收益远不止减少 IO。同列高重复度带来高压缩率、筛选下推减少行数、向量化执行打满 CPU 带宽、Delta Tree 专门处理随机小写入,这些是行存不具备的整套分析优化链。

为何常见:只从物理存储布局的直觉出发,忽略了存储格式对压缩算法和上层执行引擎的连锁影响。

误区所有写都走 TiKV,所有读都走 TiFlash,这不就是常见的读写分离架构吗?

正解读写分离通常是一份主库数据加多个从库;HTAP 则是行存和列存两份不同格式的副本,行存负责交易,列存负责分析,并通过强一致协议保证两份副本逻辑一致。TiDB 优化器是根据查询类型选择数据源,而不是简单按读写方向分流。

为何常见:HTAP 和读写分离表面上都是“写一边、读另一边”,但核心差异在副本存储格式、复制协议与一致性语义上。

面试题

Q1. HTAP 的完整含义是什么?

单选题 · easy

  • A.高速事务与处理平台
  • B.混合事务与分析处理← 正确答案
  • C.高吞吐实时分析系统
  • D.数据仓库通用加速器

答案:B。HTAP 是 Hybrid Transactional and Analytical Processing 的缩写,即混合事务与分析处理。A、C、D 都不是公认术语,只有 B 准确表达了“在一套系统里同时跑交易和分析”的含义,就像餐厅同时做前台接单与总部复盘。

Q2. TiFlash 在 Raft 组中扮演什么角色?

单选题 · easy

  • A.Raft 主节点 Leader
  • B.Raft 从节点 Follower
  • C.Raft 学习节点 Learner← 正确答案
  • D.Raft 候选节点 Candidate

答案:C。TiFlash 以 Learner 身份加入 Raft 组,只复制日志不参与投票。Leader 负责接收写请求,Follower 参与投票,Candidate 是选举阶段的临时身份,都不是 TiFlash 的角色。

Q3. 列式存储对分析查询最大的优势是什么?

单选题 · mid

  • A.数据写入延迟更低
  • B.查询可以少读无用列← 正确答案
  • C.事务隔离能力更强
  • D.死锁检测更加简单

答案:B。列存把一列数据连续存放,分析查询只读所需列,减少大量无用 IO。写入延迟、事务隔离、死锁检测更多与索引结构和锁机制相关,并非列存的核心优势。

Q4. 一个 5 节点 Raft 组,写入需要几个节点确认?

单选题 · easy

  • A.任意 2 个节点即可
  • B.至少 3 个节点确认← 正确答案
  • C.全部 5 个节点确认
  • D.至少 4 个节点确认

答案:B。多数派 = floor(5 / 2) + 1 = 3。2 个不到一半,4 个和 5 个虽然也能提交但牺牲了可用性,不是 Raft 协议定义的最小多数派。

Q5. TiFlash 保证强一致读的手段包括哪些?

多选题 · mid

  • A.用全局时间戳对齐快照← 正确答案
  • B.把列存数据同步回行存
  • C.比较 Raft 日志应用位置← 正确答案
  • D.强制查询只走 TiKV 读取

答案:AC。TiDB 给事务分配全局 TSO 时间戳,TiFlash 把快照时间与本地 apply index 对应的已应用时间比较,满足条件才直接读。列存数据不需要回流到行存,查询也不强制走 TiKV。

Q6. 为表增加 TiFlash 副本的 SQL 写法是?

单选题 · mid

  • A.SET GLOBAL TIFLASH REPLICA
  • B.ALTER 语句设置 TiFlash 副本← 正确答案
  • C.CREATE 语句指定存储引擎
  • D.INSERT 语句写入列存分区

答案:B。正确用法是 ALTER TABLE orders SET TIFLASH REPLICA 2。SET GLOBAL 是全局变量设置,CREATE 只能指定建表时的初始存储,INSERT 是写数据语句,都与为已有表增加列存副本无关。

Q7. 向量化执行加速查询的原因包括哪些?

多选题 · hard

  • A.减少函数调用与分支判断开销← 正确答案
  • B.SIMD 指令一次处理多个数据← 正确答案
  • C.逐行计算避免列式布局
  • D.提升 CPU 缓存命中效率← 正确答案

答案:ABD。向量化把一批数据放入连续内存,循环内无分支,减少解释与函数调用;SIMD 并行一次算多份;连续内存让缓存命中率提升。C 说“逐行计算”正是向量化要避免的做法。

Q8. TiFlash 中 Delta Tree 的核心作用是什么?

单选题 · hard

  • A.将列式数据还原成行式
  • B.合并新写入形成大列块← 正确答案
  • C.为行存提供额外索引
  • D.替代 Raft 的日志复制

答案:B。Delta Tree 先用小分区承接高频随机写入,再在后台合并进主列块,保证列存的高压缩与高效扫描。它不还原列式数据,不提供行存索引,也不替代 Raft 日志复制。

Q9. Raft Learner 不参与投票带来的结果是?

单选题 · mid

  • A.增加主链路写入延迟
  • B.降低整个集群的可用性
  • C.主链路写入不受影响← 正确答案
  • D.分析数据无法保持一致

答案:C。Learner 不参与多数派投票,新增多少个 Learner 都不会增加写确认的等待节点数,主链路写入延迟完全不变。它反而提升分析可用性,并通过时间戳机制保证一致性。

Q10. 关于 TiFlash 与 HTAP 的正确说法有哪些?

多选题 · hard

  • A.列存行存共存于同一集群← 正确答案
  • B.分析走列存交易走行存← 正确答案
  • C.列存查询必须离线执行
  • D.列存副本支持在线调整← 正确答案

答案:ABD。TiDB 集群内 TiKV 行存与 TiFlash 列存共存,优化器把交易和分析计划分别路由到两端;TiFlash 查询是实时的,而不是离线批处理;副本数量可以动态调整,无需重启集群。