Enterprise 版索引總覽

索引編製行為取決於資料庫版本。本頁說明 Firestore Enterprise 版的索引功能。如需 Firestore Standard 版,請參閱「Firestore Standard 版索引總覽」。

本節說明 Firestore Enterprise 版的索引。Firestore Enterprise 版預設不會建立任何索引。 如要降低成本及提升資料庫效能,請為最常使用的查詢建立索引。

索引對資料庫效能有極大影響。如果查詢有索引,資料庫就能減少需要掃描的資料量,以及排序結果所需的工作,進而有效率地傳回結果。不過,索引項目會增加儲存空間費用,以及在索引欄位上執行寫入作業時的工作量。

索引定義和結構

索引包含下列項目:

  • 集合 ID
  • 指定集合中的欄位清單
  • 每個欄位的索引模式,包括遞增、遞減或 array-contains

索引也可以啟用「sparse」或「unique」選項。

索引排序

每個欄位的順序和排序方向都會定義索引。舉例來說,下列索引是兩個不同的索引,不可互換:

集合 欄位
cities 國家/地區 (遞增)、人口 (遞減)
cities 人口 (遞減)、國家/地區 (遞增)、

建立索引來支援查詢時,請按照查詢中的欄位順序加入欄位。

索引密度

根據預設,索引項目會儲存集合中所有文件的資料。這稱為非稀疏索引。無論文件是否包含索引中指定的任何欄位,系統都會為文件新增索引項目。產生索引項目時,系統會將不存在的欄位視為具有 NULL 值。如要變更這項行為,您可以將索引定義為稀疏索引。

稀疏索引

稀疏索引只會為集合中符合以下條件的文件建立索引:在至少一個已建立索引欄位包含一個值 (包括空值在內)。稀疏索引可降低儲存費用,並提升效能。

陣列包含索引

如要使用 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 指數
{
  tags: ["news"],
  status: "active"
}
已建立索引:
• (標記:"news",狀態:"active")
已建立索引:
• (標記:"news",狀態:"active")
{
  tags: ["news", "sports"],
  status: "active"
}
已建立索引:
• (標記:"news",狀態:"active")
• (標記:"sports",狀態:"active")
已建立索引:
• (標記:"news",狀態:"active")
• (標記:"sports",狀態:"active")
{
  tags: ["news", "news"],
  status: "active"
}
已建立索引:
• (標記:"news",狀態:"active") (已去重複)
已建立索引:
• (標記:"news",狀態:"active") (已去重複)
{
  tags: [null],
  status: "active"
}
已建立索引:
• (標記:null,狀態:"active")
已建立索引:
• (標記:null,狀態:"active")
{
  tags: ["news"]
}
已建立索引:
• (標記:"news",狀態:null)
未編入索引 (缺少 status 欄位)
{
  tags: "news",
  status: "active"
}
未建立索引 (欄位不是陣列) 未建立索引 (欄位不是陣列)
{
  tags: null,
  status: "active"
}
未建立索引 (欄位不是陣列) 未建立索引 (欄位不是陣列)
{
  status: "active"
}
未編入索引 (缺少 tags 欄位) 未建立索引 (缺少 tags 欄位)
{
  tags: [],
  status: "active"
}
未建立索引 (空白陣列) 未建立索引 (空白陣列)

查詢示例

網頁
// 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 值做為元素 (例如 ["news", null]),系統會為 null 元素建立索引。如果後續文件在索引陣列欄位中包含 null 元素,就會發生重複鍵錯誤。

排解索引建立錯誤

管理索引時,可能會遇到索引建構錯誤。如果資料庫發生資料問題,索引作業可能會失敗。索引作業可能會因下列原因而失敗:

  • 已達索引上限。舉例來說,作業可能已達到每個文件的索引項目數量上限。如果索引建立失敗,您會看到錯誤訊息。如果尚未達到索引上限,請重試索引作業。
  • 您設定了不重複的索引選項,但索引欄位的資料會建立重複的索引項目。如要繼續,請從資料中移除重複的值組合。