企业版索引概览
索引编制行为取决于数据库的版本。本页面介绍了 Firestore 企业版的索引编入功能。对于 Firestore 标准版,请参阅 Firestore 标准版索引概览。
本部分介绍了 Firestore 企业版的索引编入功能。默认情况下,Firestore 企业版不会创建任何索引。为了降低费用并提高数据库性能,请为最常用的查询创建索引。
索引对数据库的性能有很大影响。如果查询存在索引,数据库可以通过减少需要扫描的数据量和减少对结果进行排序所需的工作量来高效地返回结果。不过,索引条目会增加存储费用,并增加在对编入索引的字段执行写入操作期间所做的工作量。
索引定义和结构
索引包含以下内容:
- 集合 ID
- 给定集合中的字段列表
- 每个字段的索引模式(升序、降序或 array-contains)
索引排序
每个字段的顺序和排序方向用于唯一定义索引。例如,以下两个索引是不同的索引,不能互换:
| 集合 | 字段 |
|---|---|
| cities | 国家/地区(升序)、人口(降序) |
| cities | 人口(降序)、国家/地区(升序) |
创建用于支持查询的索引时,请按与查询相同的顺序添加字段。
索引密度
默认情况下,索引条目会存储集合中所有文档的数据。这称为非稀疏索引。无论文档是否包含索引中指定的任何字段,系统都会为该文档添加索引条目。在生成索引条目时,不存在的字段会被视为具有 NULL 值。如需更改此行为,您可以将索引定义为稀疏索引。
稀疏索引
稀疏索引只会将集合中至少有一个被编入索引字段包含值(包括 null)的文档编入索引。稀疏索引可降低存储费用并提高性能。
array-contains 索引
如需在使用 array-contains 或 array-contains-any 查询数组字段时优化查询性能,您可以采用 array-contains 模式为该字段编制索引。一个索引最多只能有一个处于 array-contains 模式的字段。
通过以 array-contains 模式为数组字段编制索引,查询引擎可以快速找到包含特定数组值的文档。如果没有索引,查询会通过对集合执行完整扫描来检查数组值,这会随着集合大小的增加而增加查询延迟时间和读取费用。
如需为数组字段编制索引,该字段必须满足以下要求:
- 非空数组要求:仅当数组字段存在于文档中且为非空数组时,系统才会创建索引条目。缺少字段、字段不是数组或字段是空数组的文档不会编入索引。
密度与 array-contains 索引的关系
对于包含 array-contains 字段的索引,索引密度规则仅适用于有序索引字段。如果满足非空数组要求,则密度规则会应用于索引中剩余的有序索引字段:
- 非稀疏索引 (
DENSE):为文档生成索引条目。 索引中任何缺失的有序索引字段都会在索引条目中存储为null。 - 稀疏索引 (
SPARSE):仅当文档中存在至少一个有序的编入索引的字段时,才会生成索引条目。
示例:索引条目生成
考虑索引 users (tags[*], status ASC):
| 文档 | NON-SPARSE 指数 |
SPARSE 指数 |
|---|---|---|
{ |
已编入索引: •(标记: "news",状态:"active") |
已编入索引: •(标记: "news",状态:"active") |
{ |
已编入索引: •(标记: "news",状态:"active")•(标记: "sports",状态:"active") |
已编入索引: •(标记: "news",状态:"active")•(标记: "sports",状态:"active") |
{ |
已编入索引: • (标记: "news",状态:"active")(已去重) |
已编入索引: •(标记: "news",状态:"active")(已去重) |
{ |
已编入索引: •(标记: null,状态:"active") |
已编入索引: •(标记: null,状态:"active") |
{ |
已编入索引: •(标记: "news",状态:null) |
未编入索引(缺少 status 字段) |
{ |
未编入索引(字段不是数组) | 未编入索引(字段不是数组) |
{ |
未编入索引(字段不是数组) | 未编入索引(字段不是数组) |
{ |
未编入索引(缺少 tags 字段) |
未编入索引(缺少 tags 字段) |
{ |
未编入索引(空数组) | 未编入索引(空数组) |
查询示例
Web
// Query for users where 'tags' contains 'news' and 'status' is 'active' const query = db.collection("users") .where("tags", "array-contains", "news") .where("status", "==", "active"); // Documents returned by the query: // [ // { // "id": "alice", // "tags": ["news", "tech"], // "status": "active" // } // ]
唯一索引
设置唯一索引选项,可强制确保编入索引的字段值是唯一的。对于多个字段上的索引,每个值组合在索引中都必须是唯一的。数据库会拒绝任何尝试创建具有重复值的索引条目的更新和插入操作。如果编入索引的字段的数据包含重复值,并且您尝试创建唯一索引,则索引构建会失败,并在操作详细信息中显示错误消息。
唯一索引中缺少字段
如果您插入的文档缺少唯一索引所需的字段,该索引会为这些缺少的字段设置 null 值。生成的索引条目必须是唯一的,否则操作会失败。
例如,使用此索引时:
| 集合 | 编入索引的字段 | 查询范围 |
|---|---|---|
| cities | 名称(升序) | 集合 |
如果您将文档 {"abbreviation": "LA"} 添加到集合中,唯一索引会创建一个条目,并将 name 设置为 null。如果您随后尝试添加文档 {"abbreviation": "NYC"},则操作会失败,因为生成的唯一索引条目是相同的。
相同的行为适用于包含多个字段的唯一索引。创建或更新文档时,缺少的编入索引的字段会设置为 null,并且生成的索引条目在索引中必须是唯一的。
数组值的唯一索引
唯一 array-contains 索引禁止使用具有重叠数组元素的文档。
此类索引不会强制要求数组在单个文档中具有唯一值。
例如,如果对名为 tags 的字段使用唯一索引:
以下文档 doc1 可以有效插入:
{
"tags": [ "news", "tech", "news", "music" ]
}
该索引允许单个文档的同一数组中存在重复值 ("news")。
如果您尝试插入具有重复元素的第二个文档 doc2,则操作会失败:
{
"tags": [ "sports", "music" ]
}
操作失败,因为 "music" 已存在于 doc1 的数组中,并且已在索引中进行映射。
如果您需要确保单个文档中同一数组内的元素是唯一的,请在应用逻辑中处理此问题。
空数组、缺失的字段和 null 值
通常,唯一索引中缺少的字段会被视为 null,并且在各个文档中必须是唯一的(请参阅唯一索引中缺少字段)。不过,对于数组字段上的唯一索引:
- 空数组、缺失的字段和独立 null:如果数组字段为空、完全缺失或包含独立的
null值(不在数组内),则不会为相应文档生成任何索引键。因此,多个文档可以具有空字段或独立的null值,而不会触发重复键错误。 - 数组中的 null 元素:如果数组包含
null值作为元素(例如["news", null]),则null元素会被编入索引。 如果后续任何文档的编入索引的数组字段中包含null元素,则会因键重复而失败。
排查索引构建错误
在管理索引时,您可能会遇到索引构建错误。如果数据库遇到数据问题,编入索引操作可能会失败。编入索引操作可能会由于以下原因而失败:
- 已达到索引限制。例如,操作可能已达到每个文档的索引条目数量上限。如果索引创建失败,您会看到一条错误消息。如果未达到索引限制,请重试编入索引操作。
- 您设置了唯一索引选项,但编入索引的字段的数据会创建重复的索引条目。如需继续,请从数据中移除重复的值组合。