在 Mango 查询中如何强制使用“use_index”并验证是否覆盖?

解读

国内一线互联网与政企项目普遍把 CouchDB 作为离线优先场景的核心存储,面试时考官不仅要求“能写”,更要“能调”。
Mango 查询默认由查询规划器选索引,若出现“选错索引导致全表扫描”或“明明建了复合索引却被忽略”这类性能事故,DBA 需要显式干预执行计划
因此考点集中在两条:

  1. 如何强制指定索引(use_index 语法与注意事项);
  2. 如何验证执行计划确实命中该索引(覆盖验证与回退策略)。
    答不出覆盖验证,基本会被追问“你怎么证明线上走了你指定的索引”,直接决定面试成败。

知识点

  1. use_index 语法:在 selector 同级增加 "use_index": "<设计文档>/<索引名>"["<设计文档>", "<索引名>"];只能指定已持久化的 JSON 索引,不能指向临时索引。
  2. 覆盖验证三要素
    • 返回体里的 "mrargs": {"index": "…"} 必须出现指定索引;
    • "covering" 字段为 true 表示覆盖索引(无需回表);
    • warning 字段出现 "no matching index found" 说明指定索引失效,查询已回退到 _all_docs,必须立即处理。
  3. 强制失败策略:当指定索引因字段顺序或类型不匹配而无法使用时,CouchDB 不会报错,而是默默回退;线上环境务必配合 "execution_stats": true 观察 "total_docs_examined",若该值等于集合文档数即证明全表扫描。
  4. 国内踩坑点
    • 中文字段名需完全匹配 Unicode,大小写敏感;
    • 复合索引顺序必须与查询排序一致,否则即使 use_index 指定也被拒绝;
    • 云厂商托管版(如阿里云 CouchDB 兼容版)对 use_index 做了白名单限制,需提前在控制台申请权限,否则返回 403 index forbidden

答案

步骤一:创建可用索引

POST /my_db/_index
{
  "index": {
    "fields": ["dept", "age"]
  },
  "name": "idx_dept_age",
  "ddoc": "idx_dept_age_ddoc"
}

步骤二:在 Mango 查询中强制使用并带回执行统计

POST /my_db/_find
{
  "selector": {
    "dept": "R&D",
    "age": { "$gte": 30 }
  },
  "use_index": "idx_dept_age_ddoc/idx_dept_age",
  "execution_stats": true,
  "fields": ["_id", "dept", "age"]
}

步骤三:验证覆盖
查看返回体:

  • "execution_stats""index_used": "idx_dept_age_ddoc/idx_dept_age" 出现且 "total_docs_examined" 远小于集合文档数;
  • 若增加 "covering": true" 字段(CouchDB 3.3+)直接返回 "covering": true,证明索引覆盖
  • 若出现 "warning": "no matching index found, using _all_docs""total_docs_examined" == 集合文档数,说明强制失败,需检查字段顺序、类型或索引可用性。

拓展思考

  1. 线上灰度场景:如何在不停写的情况下验证新索引?
    先在建索引时带 "w": 2 保证副本写成功,再通过 "stale": "ok" 做轻量探测,确认无警告后,再切换正式查询。
  2. 多租户 SaaS 场景:同一数据库内几百个索引,如何防止use_index误指?
    把索引命名规范为 <租户ID>_<业务域>_<字段组合>,并在 CI 阶段跑自动化 case:断言 "execution_stats.total_docs_examined" < 阈值,未通过即阻断发布。
  3. 与 PostgreSQL 的对比:MySQL 的 FORCE INDEX 会在索引不存在时直接报错,而 CouchDB 静默回退,因此必须显式监控 warning 字段,这是国内 DBA 最容易忽视的差异点。