在 Couchbase 中,INCLUDE MISSING
选项会直接影响索引的行为和覆盖范围,进而决定查询优化器的选择。以下是两个索引的区别及查询命中原因:
1. 两个索引的区别
索引 1:idx_pi_content_storeId
CREATE INDEX idx_pi_content_storeId
ON `default`:`origin`.`pi`.`pi_content`(`storeId`);
- 行为:
- 这是一个标准的 二级索引,仅索引
storeId
字段存在的文档(即storeId
不为NULL
或未缺失的文档)。 - 如果文档的
storeId
字段不存在(缺失)或值为NULL
,则该文档 不会被索引。
- 这是一个标准的 二级索引,仅索引
索引 2:adv_storeId
(含 INCLUDE MISSING
)
CREATE INDEX adv_storeId
ON `default`:`origin`.`pi`.`pi_content`(`storeId` INCLUDE MISSING);
- 行为:
- 通过
INCLUDE MISSING
选项,索引会包含所有文档,无论storeId
是否存在或为NULL
。 - 对于
storeId
缺失的文档,索引会将其视为一个特殊值(类似MISSING
)并存储。
- 通过
2. 为什么 SELECT storeId
只能命中 adv_storeId
?
当执行以下查询时:
SELECT storeId FROM `default`:`origin`.`pi`.`pi_content`;
关键原因:
-
覆盖索引(Covering Index):
- 如果索引本身包含查询所需的所有字段(这里是
storeId
),优化器会优先选择该索引,避免回表(Fetch)操作,直接通过索引返回结果。 adv_storeId
索引由于包含INCLUDE MISSING
,会覆盖所有文档(包括storeId
缺失的文档),因此可以直接通过索引返回完整的storeId
值列表。- 而
idx_pi_content_storeId
仅包含storeId
存在的文档,若查询需要返回所有文档(包括storeId
缺失的),优化器无法使用此索引,因为它无法覆盖缺失值的文档。
- 如果索引本身包含查询所需的所有字段(这里是
-
数据完整性:
- 如果表中存在
storeId
字段缺失的文档,只有adv_storeId
能确保查询结果的完整性。若使用idx_pi_content_storeId
,缺失storeId
的文档会被排除在结果外,导致结果不准确。
- 如果表中存在
-
优化器决策:
- Couchbase 优化器会根据统计信息(如索引的文档覆盖率、数据分布)选择更高效的索引。由于
adv_storeId
覆盖了全部文档,优化器认为它更适合此查询。
- Couchbase 优化器会根据统计信息(如索引的文档覆盖率、数据分布)选择更高效的索引。由于
3. 验证示例
场景模拟:
假设表中包含以下文档:
{ "id": 1, "storeId": 100 }, // storeId 存在
{ "id": 2, "storeId": NULL }, // storeId 为 NULL
{ "id": 3 }, // storeId 缺失
-
使用
idx_pi_content_storeId
:- 仅索引文档
id=1
(因为storeId
存在)。 - 查询
SELECT storeId
会返回[100]
,但遗漏id=2
和id=3
的文档。
- 仅索引文档
-
使用
adv_storeId
:- 索引所有文档,包括
id=2
(storeId=NULL
)和id=3
(storeId=MISSING
)。 - 查询
SELECT storeId
会返回[100, NULL, MISSING]
,结果完整。
- 索引所有文档,包括
4. 如何强制使用特定索引?
若需验证索引选择行为,可通过 USE INDEX
提示强制指定索引:
SELECT storeId
FROM `default`:`origin`.`pi`.`pi_content`
USE INDEX (idx_pi_content_storeId);
此时查询结果将不包含 storeId
缺失或为 NULL
的文档。
总结
索引 | 覆盖范围 | 适用场景 |
---|---|---|
idx_pi_content_storeId | 仅包含 storeId 存在的文档 | 精确查询 storeId 存在的场景 |
adv_storeId | 包含所有文档(含 MISSING/NULL ) | 需要返回完整数据的查询(如 SELECT storeId ) |
若查询需要返回所有文档的 storeId
(包括缺失或 NULL
值),必须使用 INCLUDE MISSING
的索引。