在 Mango 查询中如何强制使用“use_index”并验证是否覆盖?
解读
国内一线互联网与政企项目普遍把 CouchDB 作为离线优先场景的核心存储,面试时考官不仅要求“能写”,更要“能调”。
Mango 查询默认由查询规划器选索引,若出现“选错索引导致全表扫描”或“明明建了复合索引却被忽略”这类性能事故,DBA 需要显式干预执行计划。
因此考点集中在两条:
- 如何强制指定索引(use_index 语法与注意事项);
- 如何验证执行计划确实命中该索引(覆盖验证与回退策略)。
答不出覆盖验证,基本会被追问“你怎么证明线上走了你指定的索引”,直接决定面试成败。
知识点
- use_index 语法:在 selector 同级增加
"use_index": "<设计文档>/<索引名>"或["<设计文档>", "<索引名>"];只能指定已持久化的 JSON 索引,不能指向临时索引。 - 覆盖验证三要素:
- 返回体里的
"mrargs": {"index": "…"}必须出现指定索引; "covering"字段为true表示覆盖索引(无需回表);- 若
warning字段出现"no matching index found"说明指定索引失效,查询已回退到_all_docs,必须立即处理。
- 返回体里的
- 强制失败策略:当指定索引因字段顺序或类型不匹配而无法使用时,CouchDB 不会报错,而是默默回退;线上环境务必配合
"execution_stats": true观察"total_docs_examined",若该值等于集合文档数即证明全表扫描。 - 国内踩坑点:
- 中文字段名需完全匹配 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" == 集合文档数,说明强制失败,需检查字段顺序、类型或索引可用性。
拓展思考
- 线上灰度场景:如何在不停写的情况下验证新索引?
先在建索引时带"w": 2保证副本写成功,再通过"stale": "ok"做轻量探测,确认无警告后,再切换正式查询。 - 多租户 SaaS 场景:同一数据库内几百个索引,如何防止
use_index误指?
把索引命名规范为<租户ID>_<业务域>_<字段组合>,并在 CI 阶段跑自动化 case:断言"execution_stats.total_docs_examined" < 阈值,未通过即阻断发布。 - 与 PostgreSQL 的对比:MySQL 的
FORCE INDEX会在索引不存在时直接报错,而 CouchDB 静默回退,因此必须显式监控 warning 字段,这是国内 DBA 最容易忽视的差异点。