---
# System prepended metadata

title: 'Index, or not index? That is not a question'

---

# Index, or not index? That is not a question

## 背景

在真实的业务场景中，数据库索引的选择往往是困扰很多开发/DBA的难题之一。索引可以用于辅助查询，同时更多的索引也有助于面对未来可能的需求变更，很多数据库事故都是由于一些非热点SQL突然流量增加却缺失关键索引引起的。但构建过多的索引会给在线业务带来更大的写延迟，其中的 trade off 比较难把控。

学术界也提出过一些 idea 来解决这个问题，如 self-driven database 的一大优化场景就是预测未来的 workload 以自动构建 index。但这种实现一旦预测错误，对业务是雪崩式的影响，落地非常困难。

## 方案

我们想引进一种新的索引机制，这里简称 Async Index，它并不直接在在线业务的时候写入，而是基于 TiCDC 异步地同步到 TiKV。而在读取时根据 Index 的 watermark 和事务的 start_ts 比较，决定是否需要等待。

Sync Index 和 Async Index 可以根据 workload 动态转换，分别应对 read heavy 和 write heavy 的业务场景。如果一个字段有潜在的索引需求，可以先把索引建上，我们的 detector 发现索引使用频率很低以后，就会将其转为 Async Index，从而减少在线写入的事务的影响。反之，如果 Async Index 被一些热点 SQL 命中，我们也可以自动将其转换为 Sync Index，减少读等待。针对一些特殊的读取不频繁的场景（导入数据或者作为备库），所有的索引都是 Async Index，写入只需要1PC写主表就行。

这种方案仅适用于没有 constraint 的 Non unique index，但可以覆盖大部分的场景。

## 实现细节

在这个过程中，我们需要 hack 三个主要方面：

1. Write Path 上，Async Index 不可见，需要被忽略。
2. 一个独立的 agent，订阅 TiCDC 的数据（需要打开 old-data 开关），并向 TiKV 灌数据。
3. Read Path 上，需要根据 watermark 做等待。
4. Sync/Async Index 的动态转换需要 hack DDL 的状态机。具体来说，Async Index 转化为 Sync Index 的过程等价于一个已经完成了 99% 的 CREATE INDEX，所以找到一个合适的点 hack 进去，让它等到 100% 即可。

## Future Story

* 可以利用 placement rule，将 async index 物理隔离，进一步减少对在线业务的影响。
* TBD