Cloud Firestore 中的索引类型

索引是决定数据库性能的一个重要因素。与一本书中的索引可以将书中的主题与页码相对应类似,数据库中的索引可以将数据库中的内容映射到对应的位置。当您向数据库发送一个查询请求时,数据库可以使用索引快速查找所请求的内容的位置。

本文介绍了 Cloud Firestore 使用的两种索引类型:单字段索引复合索引

每个查询都有一个索引

如果一个查询没有索引,大部分数据库需要一项一项的抓取其中的内容,这个过程非常缓慢,且数据库越大,速度越慢。Cloud Firestore 为所有查询使用索引,以确保较高的查询性能。正因为此,查询性能高低与否取决于结果集的大小,而不是数据库中的项目数量。

减少索引管理,专注应用开发

Cloud Firestore 具有减少管理索引所需时间的功能,它会自动为您创建最基本的查询所需的索引。在您使用并测试应用的期间,Cloud Firestore 会帮助您识别并创建您的应用所需的其他索引

单字段索引

单字段索引会为一个集合中包含某个特定字段的每个文档存储一个映射,并按顺序排序。单字段索引中的每个条目会记录一个文档中一个特定字段的值,以及该文档在数据库中的位置。

Cloud Firestore 会自动为文档中的每个字段定义并保留两个单字段索引,一个按升序排列 (arrow_upward),另一个按降序排列 (arrow_downward)。对于包含映射对象的字段,Cloud Firestore 会为映射中的每个子字段创建一个以升序排序的索引和一个以降序排序的索引。

由于 Cloud Firestore 会自动为您创建这类索引,因此您的应用可以快速执行最基本的数据库查询。您可以使用单字段索引执行基于字段值和比较运算符(<<===>=>)的简单查询。

为了详细地予以说明,我们将从创建索引的角度来看看 cities 示例。下面的示例在 cities 集合中创建了一些 city 文档并为每个文档设置了 namestatecountrycapitalpopulation 字段。

网页
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000 });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000 });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000 });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000 });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000 });

对于每个 set 操作,Cloud Firestore 会为每个字段更新两个单字段索引。下表中的每一行代表的是一个单字段索引:

集合 编入索引的字段
cities arrow_upward name
cities arrow_downward name
cities arrow_upward state
cities arrow_downward state
cities arrow_upward country
cities arrow_downward country
cities arrow_upward capital
cities arrow_downward capital
cities arrow_upward population
cities arrow_downward population

您可以使用这些自动创建的索引运行简单的查询,如下所示:

网页
citiesRef.where("state", "==", "CA")
citiesRef.where("population", "<", 100000)
citiesRef.where("name", ">=", "San Francisco")

您还可以创建基于等式 (==) 的复合查询:

网页
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA").where("capital", "==", false).where("state", "==", "CA").where("population", "==", 860000)

如果您需要运行使用范围比较运算符(<<=>>=)的复合查询,或者您需要按照不同的字段进行排序,则您必须为该查询创建一个复合索引。

复合索引

复合索引与单字段索引类似,不过它会为一个集合中包含多个特定的字段(而不是一个字段)的每个文档存储一个映射,并按顺序排序。复合索引还会为每个字段定义排序模式(升序或降序),索引将会根据这些排序模式排序。Cloud Firestore 使用复合索引执行单字段索引尚不支持的复合查询。例如,您可能需要使用复合索引执行下列查询:

网页
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)

这些查询需要使用下列复合索引。请注意,由于该查询为 country 字段使用了等式,因此该字段的排序模式可以为降序,也可以为升序。默认情况下,根据不等式字句中所使用的字段,不等式查询会应用升序排序顺序。

集合 编入索引的字段
cities arrow_upward(或 arrow_downward)country、arrow_upward population

不同于单字段索引,Cloud Firestore 不会自动创建复合索引,因为可能的字段组合数太多。但是,Cloud Firestore 可以帮您在构建应用时识别并创建必需的复合索引

如果您在没有创建必需的索引之前尝试执行上述查询,Cloud Firestore 会返回一个包含链接的错误消息,按照链接中的说明操作即可创建缺少的索引。如果您尝试运行不被索引支持的查询,就会出现这种情况。您还可以使用控制台或 Firebase CLI 手动定义并管理复合索引。如需详细了解如何创建并管理索引,请参阅管理索引

如果您想要使用降序排序顺序运行相同的查询,您需要为 population 额外创建一个降序的复合索引:

网页
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")
集合 编入索引的字段
cities arrow_upward country、arrow_upward population
cities arrow_upward countryarrow_downward population

索引和价格

如果使用索引,您的应用会产生存储费用。如需详细了解如何计算索引的存储空间使用量,请参阅索引条目大小

充分利用索引合并功能

虽然 Cloud Firestore 会为每个查询使用一个索引,但实际上没有必要这么做。如果查询使用多等式 (==) 子句以及可选择使用的 orderBy 子句,Cloud Firestore 可以重复利用现有的索引。Cloud Firestore 可以将针对单个等式过滤条件创建的索引合并起来,构建运行较大规模的等式查询所需的复合索引。

通过找出可利用索引合并的情况,您可以降低索引产生的费用。例如,假设一个餐厅评分应用有一个 restaurants 集合:

  • collections_bookmark restaurants

    • class burgerthyme

      name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

现在,假设该应用使用下列查询。请注意,该应用使用的是 categorycityeditors_pick 等式子句的组合,并始终采用降序的顺序为 star_rating 排序:

网页
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

您可以为每个查询创建一个索引:

集合 编入索引的字段
restaurants arrow_upward category、arrow_upward star_rating
restaurants arrow_upward city、arrow_upward star_rating
restaurants arrow_upward category、arrow_upward city、arrow_upward star_rating
restaurants arrow_upward category、arrow_upward city、arrow_upward editors_pick、arrow_upward star_rating

更好的方式是,充分利用 Cloud Firestore 为等式子句合并索引的功能,减少索引的数量:

集合 编入索引的字段
restaurants arrow_upward category、arrow_upward star_rating
restaurants arrow_upward city、arrow_upward star_rating
restaurants arrow_upward editors_pick、arrow_upward star_rating

此索引集不仅更小,还支持执行额外的查询:

网页
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

索引限制

索引存在以下限制。如需了解与配额和限制有关的全部信息,请参阅配额和限制

限制 详情
一个文档的复合索引条目的大小总和上限 2 MiB
一个数据库的复合索引数量上限 200

每个文档的索引条目数量上限

20000

索引条目的数量是文档的以下各项数量的总和:

  • 单字段索引条目的数量
  • 复合索引条目的数量

Cloud Firestore 会自动为每个字段创建两个单字段索引条目:一个以升序排序的索引和一个以降序排序的索引。

每个文档的索引条目数量上限为 20000,考虑到这一点,每个文档可以编入索引的字段数量上限为 10000 减去文档的复合索引条目的数量。

索引条目的大小上限

1500 字节

超出 1500 字节的索引条目会被截断。包含被截断的索引值的查询可能会返回不一致的结果。

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面