知识卡片

二级索引分区本地索引与全局索引在读写代价上互为镜像

结构图卡

内容

按主键分区能直接确定去哪个节点,但二级索引(如”查所有红色汽车”)不唯一标识记录, 不能整齐地映射到某一个分区,只有两种处理方式,且两者的代价结构正好相反。基于文档 的分区(本地索引):每个分区维护只覆盖自己那部分文档的索引——比如分区0里的红色 汽车记录进分区0自己的color:red索引条目,分区1同理;写入时只需要更新写入文档所在 那一个分区的索引,代价很低;但因为红色汽车可能分散在所有分区里,查询”所有红色 汽车”就必须把请求发给全部分区、再合并结果,这种方式叫分散/聚集,读取代价高,还 容易导致尾部延迟放大(哪怕并行查询,只要有一个分区响应慢,整体就慢)——MongoDB、 Riak、Cassandra、Elasticsearch、SolrCloud都用这种默认方式。基于关键词的分区(全局 索引):反过来,把索引本身也按”关键词”(如颜色的取值范围)而不是按主键切分,全部 分区的红色汽车统一进入”color:red”所在的那个索引分区;查询时只需要定位到包含目标 关键词的那个索引分区,不用扇出到所有分区,读取效率高;但写入一份新文档,可能同时 触发多个索引分区的更新(这份文档命中的每个关键词字段可能落在不同的索引分区上), 写入变慢也变复杂,理想情况下索引应该实时反映每次写入,但这需要跨分区的分布式事务, 不是所有数据库都支持,实践中全局索引的更新通常是异步的(DynamoDB全局二级索引 正常情况下1秒内更新,但基础设施故障时可能延迟更久)。两种方式本质是把”扇出”这个 代价放在读时还是写时——本地索引写快读慢,全局索引写慢读快,没有免费的选择。

结构图

flowchart LR
    A[本地索引: 每分区维护自己的二级索引] --> A1[写入只需更新所属分区: 快]
    A1 --> A2[读取需扇出到所有分区再合并: 慢, 分散/聚集]
    B[全局索引: 按关键词而非主键切分索引] --> B1[写入可能触发多个索引分区更新: 慢]
    B1 --> B2[读取只需定位目标关键词所在分区: 快]
    B2 -.实时更新需跨分区分布式事务, 实践中常异步.-> B2

参考来源

- 位置:《数据密集型应用系统设计》第六章《分区》"基于文档的二级索引进行分区""基于 关键词(Term)的二级索引进行分区"(源文件:_epub-src/ch6_split_003.html) - 结论依据:原文说明文档分区索引写入只需处理单个分区、但读取需要分散/聚集所有 分区合并结果,关键词分区索引读取只需定位目标分区、但写入可能影响多个索引分区 且通常是异步更新,直接支撑本卡片对两种方式代价互为镜像的结构梳理。 - 原始内容:在这种索引方法中,每个分区是完全独立的……如果要搜索红色汽车,则需要 将查询发送到所有分区,并合并所有返回的结果……关键词分区的全局索引优于文档分区 索引的地方点是它可以使读取更有效率……全局索引的缺点在于写入速度较慢且较为 复杂……在实践中,对全局二级索引的更新通常是异步的。