Share via


在適用於 MongoDB 的 Azure Cosmos DB 中管理索引編制

適用於: MongoDB

Azure Cosmos DB for MongoDB 會利用 Azure Cosmos DB 的核心索引管理功能。 本文著重於如何使用 Azure Cosmos DB for MongoDB 來新增索引。 索引是特殊化的資料結構,可讓您查詢資料的速度大約加快一個數量級。

為 MongoDB 伺服器 3.6 版和更高版本編制索引

Azure Cosmos DB for MongoDB 伺服器 3.6+ 版會自動編制 _id 欄位和分區金鑰 (只在分區化集合中) 的索引。 API 會自動根據分區索引鍵強制執行_id 欄位的唯一性。

API for MongoDB 行為與 Azure Cosmos DB for NoSQL 行為不同,後者預設為編制所有欄位的索引。

編輯編製索引原則

建議您在 Azure 入口網站內的資料總管中編輯您的編制索引原則。 您可以從資料總管中的編制索引原則編輯器新增單一欄位和萬用字元索引:

Indexing policy editor

注意

您無法使用資料總管中的編制索引原則編輯器來建立複合索引。

索引類型

單一欄位

您可以在任何單一欄位上建立索引。 單一欄位索引的排列順序並不重要。 下列命令會在欄位 name 上建立索引:

db.coll.createIndex({name:1})

您可以在 Azure 入口網站的 name 上建立相同的單一欄位索引:

Add name index in indexing policy editor

一個查詢會使用多個單一欄位索引 (如果可用的話)。 每個集合最多可以建立 500 個單一欄位索引。

複合索引 (MongoDB 伺服器 3.6+ 版)

在適用於 MongoDB 的 API 中,如果您的查詢需要一次排序多個欄位的能力,則需要複合索引。 查詢若具有多個不需要排序的篩選條件,請建立多個單一欄位索引,而不是複合索引,以節省索引成本。

複合索引或複合索引中每個欄位的單一欄位索引,都會對查詢中的篩選產生相同的效能。

由於陣列的限制,依預設不支援巢狀欄位上的複合索引。 如果您的巢狀欄位不包含陣列,則索引會如預期運作。 如果您的巢狀欄位包含陣列 (路徑上的任何位置),則會在索引中忽略該值。

例如,包含 people.dylan.age 的複合索引在此案例中會有作用,因為路徑上沒有陣列:

{
  "people": {
    "dylan": {
      "name": "Dylan",
      "age": "25"
    },
    "reed": {
      "name": "Reed",
      "age": "30"
    }
  }
}

這個相同的複合索引在此案例中無法運作,因為路徑中有陣列:

{
  "people": [
    {
      "name": "Dylan",
      "age": "25"
    },
    {
      "name": "Reed",
      "age": "30"
    }
  ]
}

啟用 'EnableUniqueCompoundNestedDocs' 功能,即可為您的資料庫帳戶啟用此功能。

注意

您無法在陣列上建立複合索引。

下列命令會在欄位 nameage 上建立複合索引:

db.coll.createIndex({name:1,age:1})

您可以使用複合索引,一次在多個欄位上有效率地排序,如下列範例所示:

db.coll.find().sort({name:1,age:1})

您也可以使用上述的複合索引,在所有欄位上以相反的排列順序有效率地排序查詢。 以下是範例:

db.coll.find().sort({name:-1,age:-1})

不過,複合索引中的路徑序列必須完全符合查詢。 以下是需要額外複合索引的查詢範例:

db.coll.find().sort({age:1,name:1})

多重索引鍵索引

Azure Cosmos DB 會建立多重索引鍵索引,為儲存在陣列中的內容編製索引。 如果您使用陣列值為欄位編制索引,Azure Cosmos DB 會自動為陣列中的每個元素編製索引。

地理空間索引

許多地理空間運算子將受益於地理空間索引。 目前,Azure Cosmos DB for MongoDB 支援 2dsphere 索引。 API 尚不支援 2d 索引。

以下是在 location 欄位上建立地理空間索引的範例:

db.coll.createIndex({ location : "2dsphere" })

文字索引

Azure Cosmos DB for MongoDB 目前不支援文字索引。 對於字串的文字搜尋查詢,您應使用 Azure AI 搜尋服務與 Azure Cosmos DB 的整合。

萬用字元索引

您可以使用萬用字元索引,來支援針對未知欄位的查詢。 讓我們假設您有一個包含系列相關資料的集合。

以下是該集合中範例文件的一部分:

"children": [
   {
     "firstName": "Henriette Thaulow",
     "grade": "5"
   }
]

以下是另一個範例,這次在 children 中有一組稍微不同的屬性:

"children": [
    {
     "familyName": "Merriam",
     "givenName": "Jesse",
     "pets": [
         { "givenName": "Goofy" },
         { "givenName": "Shadow" }
         ]
   },
   {
     "familyName": "Merriam",
     "givenName": "John",
   }
]

在此集合中,文件可以具有許多不同的可能屬性。 如果想要為 children 陣列中的所有資料編制索引,您有兩個選項:為每個個別屬性建立個別索引,或為整個 children 陣列建立萬用字元索引。

建立萬用字元索引

下列命令會在 children 內的任何屬性上建立萬用字元索引:

db.coll.createIndex({"children.$**" : 1})

與 MongoDB 不同的是,萬用字元索引可支援查詢述詞使用多個欄位。 若您使用單一個萬用字元索引,而不是為各屬性建立個別索引,查詢效能不會有差異。

您可以使用萬用字元語法來建立下列索引類型:

  • 單一欄位
  • 地理空間

為所有屬性編制索引

以下是您可以在所有欄位上建立萬用字元索引的方式:

db.coll.createIndex( { "$**" : 1 } )

您也可以使用 Azure 入口網站中的資料總管來建立萬用字元索引:

Add wildcard index in indexing policy editor

注意

如果您只是開始開發,強烈建議您從所有欄位上的萬用字元索引開始進行。 這可以簡化開發,讓最佳化查詢更為容易。

由於寫入和更新,具有許多欄位的文件可能會有高要求單位 (RU) 費用。 因此,如果您有大量寫入的工作負載,則應該個別選擇索引路徑,而不是使用萬用字元索引。

注意

預覽版中提供在具有資料的現有集合上支援唯一索引。 啟用 'EnableUniqueIndexReIndex' 功能,即可為您的資料庫帳戶啟用此功能。

限制

萬用字元索引不支援下列任何索引類型或屬性:

  • 複合
  • TTL
  • 唯一

不同於 MongoDB,在 Azure Cosmos DB for MongoDB 中,您無法使用萬用字元索引來進行下列動作:

  • 建立包含多個特定欄位的萬用字元索引

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection " :
            {
               "children.givenName" : 1,
               "children.grade" : 1
            }
        }
    )
    
  • 建立排除多個特定欄位的萬用字元索引

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection" :
            {
               "children.givenName" : 0,
               "children.grade" : 0
            }
        }
    )
    

但是,您可以建立多個萬用字元索引。

索引屬性

下列作業常見於提供網路通訊協定 4.0 版的帳戶,以及提供較早版本的帳戶。 您可以深入了解支援的索引和索引屬性

唯一索引

唯一索引有助於強制兩份以上文件不得對索引欄位包含相同的值。

下列命令可在 student_id 欄位上建立唯一索引:

globaldb:PRIMARY> db.coll.createIndex( { "student_id" : 1 }, {unique:true} )
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 4
}

針對分區化集合,您必須提供分區 (分割區) 索引鍵來建立唯一索引。 換句話說,分區化集合上的所有唯一索引,都是其中有一個欄位是分區索引鍵的複合索引。 依照順序,第一個欄位應為分區索引鍵。

下列命令會建立分區化集合 coll (分區索引鍵是 university),其 student_iduniversity 欄位上有一個唯一索引:

globaldb:PRIMARY> db.runCommand({shardCollection: db.coll._fullName, key: { university: "hashed"}});
{
    "_t" : "ShardCollectionResponse",
    "ok" : 1,
    "collectionsharded" : "test.coll"
}
globaldb:PRIMARY> db.coll.createIndex( { "university" : 1, "student_id" : 1 }, {unique:true});
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 3,
    "numIndexesAfter" : 4
}

在上述範例中,省略 "university":1 子句會傳回錯誤與下列訊息:

cannot create unique index over {student_id : 1.0} with shard key pattern { university : 1.0 }

限制

如果集合是空的,則必須建立唯一索引。

由於陣列的限制,依預設不支援巢狀欄位上的唯一索引。 如果您的巢狀欄位不包含陣列,則索引會如預期般運作。 如果您的巢狀欄位包含陣列 (路徑上的任何位置),則會在唯一索引中忽略該值,而且不會保留該值的唯一性。

例如,people.tom.age 的唯一索引在此案例中會有作用,因為路徑上沒有陣列:

{ "people": { "tom": { "age": "25" }, "mark": { "age": "30" } } }

但在此案例中無法運作,因為路徑中有陣列:

{ "people": { "tom": [ { "age": "25" } ], "mark": [ { "age": "30" } ] } }

啟用 'EnableUniqueCompoundNestedDocs' 功能,即可為您的資料庫帳戶啟用此功能。

TTL 索引

若要在特定集合中啟用文件到期,您必須建立存留時間 (TTL) 索引。 TTL 索引是 _ts 欄位上具有 expireAfterSeconds 值的索引。

範例:

globaldb:PRIMARY> db.coll.createIndex({"_ts":1}, {expireAfterSeconds: 10})

上述命令會刪除 db.coll 集合中最近 10 秒內未修改的任何文件。

注意

_ts 是 Azure Cosmos DB 特有欄位,而且無法從 MongoDB 用戶端存取。 這是保留 (系統) 屬性,其中包含上次修改文件的時間戳記。

追蹤索引進度

Azure Cosmos DB for MongoDB API 3.6 版支援 currentOp() 命令,可追蹤資料庫執行個體上的索引進度。 此命令會傳回一份文件,其中包含資料庫執行個體上進行中作業的相關資訊。 您可以使用 currentOp 命令,來追蹤原生 MongoDB 中的所有進行中作業。 在 Azure Cosmos DB for MongoDB 中,此命令只支援追蹤索引作業。

以下是一些範例,說明如何使用 currentOp 命令來追蹤索引進度:

  • 取得集合的索引進度:

    db.currentOp({"command.createIndexes": <collectionName>, "command.$db": <databaseName>})
    
  • 取得資料庫中所有集合的索引進度:

    db.currentOp({"command.$db": <databaseName>})
    
  • 取得 Azure Cosmos DB 帳戶中所有資料庫和集合的索引進度:

    db.currentOp({"command.createIndexes": { $exists : true } })
    

索引進度輸出的範例

索引進度詳細資料會顯示目前索引作業的進度百分比。 以下範例顯示索引進度不同階段的輸出文件格式:

  • 在完成 60% 的 "foo" 集合和 "bar" 資料庫上,索引作業將具有下列輸出文件。 Inprog[0].progress.total 欄位會將 100 顯示為目標完成百分比。

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 60 %",
                  "progress" : {
                          "done" : 60,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
          "ok" : 1
    }
    
  • 如果索引作業剛在 "foo" 集合和 "bar" 資料庫上開始,則輸出文件可能會顯示 0% 進度,直到其達到可測量的層級為止。

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 0 %",
                  "progress" : {
                          "done" : 0,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
         "ok" : 1
    }
    
  • 當進行中索引作業完成時,輸出文件會顯示空白的 inprog 作業。

    {
        "inprog" : [],
        "ok" : 1
    }
    

背景索引更新

無論針對背景索引屬性指定的值為何,索引更新一律會在背景中執行。 因為索引更新取用要求單位 (RU) 的優先順序低於其他資料庫作業,所以索引變更不會由於寫入、更新或刪除而造成任何停機。

新增索引時不會影響讀取可用性。 在索引轉換完成後,查詢才會使用新的索引路徑。 在索引轉換期間,查詢引擎會繼續使用現有的索引,因此您在索引轉換期間觀察到的讀取效能,與您在起始索引變更之前觀察到的讀取效能類似。 新增索引時,也沒有查詢結果不完整或不一致的風險。

移除索引並立即對卸除的索引執行具有篩選條件的查詢時,結果可能會不一致,直到索引轉換完成為止。 如果您移除索引,當查詢篩選這些剛移除的索引時,查詢引擎不會提供一致或完整的結果。 大部分開發人員不會在卸除索引後,隨即嘗試查詢這些索引,因此,實際上這種情況是不可能的。

注意

您可以追蹤索引進度

重新編制索引命令

reIndex 命令會重新建立集合上的所有索引。 在某些罕見的情況下,您可以執行 reIndex 命令,來解決查詢效能或集合中的其他索引問題。 如果您在編制索引時遇到問題,使用 reIndex 命令重新建立索引,這是建議的方法。

您可以使用下列語法執行 reIndex 命令:

db.runCommand({ reIndex: <collection> })

您可以使用下列語法,來檢查執行 reIndex 命令是否會改善集合中的查詢效能:

db.runCommand({"customAction":"GetCollection",collection:<collection>, showIndexes:true})

範例輸出:

{
        "database" : "myDB",
        "collection" : "myCollection",
        "provisionedThroughput" : 400,
        "indexes" : [
                {
                        "v" : 1,
                        "key" : {
                                "_id" : 1
                        },
                        "name" : "_id_",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                },
                {
                        "v" : 1,
                        "key" : {
                                "b.$**" : 1
                        },
                        "name" : "b.$**_1",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                }
        ],
        "ok" : 1
}

如果 reIndex 將改善查詢效能,requiresReIndex 將是 true。 如果 reIndex 無法改善查詢效能,系統將會省略此屬性。

移轉具有索引的集合

目前,您只能在集合未包含任何文件時建立唯一索引。 熱門 MongoDB 移轉工具會嘗試在匯入資料之後建立唯一索引。 若要規避這個問題,您可以手動建立對應集合和唯一索引,而不是允許移轉工具嘗試。 (您可以使用命令列中的 mongorestore 旗標,為 --noIndexRestore 實現此行為。)

為 MongoDB 3.2 版編制索引

對於與 3.2 版 MongoDB 有線通訊協定相容的 Azure Cosmos DB 帳戶,可用的編制索引功能和預設值不同。 您可以檢查您的帳戶版本,並升級至 3.6 版

如果您使用的是 3.2 版,本節將概述 3.6+ 版的主要差異。

卸除預設索引 (3.2 版)

不同於 Azure Cosmos DB for MongoDB 3.6+ 版,3.2 版預設會為每個屬性編制索引。 您可以使用下列命令,為集合 (coll) 卸除這些預設索引:

> db.coll.dropIndexes()
{ "_t" : "DropIndexesResponse", "ok" : 1, "nIndexesWas" : 3 }

在卸除預設索引之後,您可以新增更多索引,就像您在 3.6+ 版一樣。

複合索引 (3.2 版)

複合索引可存放文件中多個欄位的參考。 如果您想要建立複合索引,請升級至 3.6 或 4.0 版

萬用字元索引 (3.2 版)

如果您想要建立萬用字元索引,請升級至 4.0 或 3.6 版

下一步