功能差異:Amazon DocumentDB 和 MongoDB - Amazon DocumentDB

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

功能差異:Amazon DocumentDB 和 MongoDB

以下是 Amazon DocumentDB(與 MongoDB 兼容性)和 MongoDB 之間的功能差異。

Amazon DocumentDB 的功能優勢

隱含交易

在 Amazon DocumentDB 中,所有 CRUD 陳述式 (、findAndModifydelete) 都能保證原子性和一致性 updateinsert,即使是修改多個文件的作業也是如此。隨著 Amazon DocumentDB 4.0 的推出,現在支援為多重陳述式和多收集操作提供 ACID 屬性的明確交易。有關在 Amazon DocumentDB 中使用交易的更多信息,請參閱。交易

以下是 Amazon DocumentDB 中的操作範例,這些操作會修改多個滿足原子和一致性行為的文件。

db.miles.update( { "credit_card": { $eq: true } }, { $mul: { "flight_miles.$[]": NumberInt(2) } }, { multi: true } )
db.miles.updateMany( { "credit_card": { $eq: true } }, { $mul: { "flight_miles.$[]": NumberInt(2) } } )
db.runCommand({ update: "miles", updates: [ { q: { "credit_card": { $eq: true } }, u: { $mul: { "flight_miles.$[]": NumberInt(2) } }, multi: true } ] })
db.products.deleteMany({ "cost": { $gt: 30.00 } })
db.runCommand({ delete: "products", deletes: [{ q: { "cost": { $gt: 30.00 } }, limit: 0 }] })

構成 updateManydeleteMany 之類批量操作的個別操作是不可部分完成,但整個批量操作是可部分完成。例如,如果個別插入操作成功執行而沒有錯誤,則整個 insertMany 操作都是不可部分完成。如果 insertMany 操作遇到錯誤,則 insertMany 操作內的每個單獨插入陳述式都將當作不可部分完成操作來執行。如果您需要insertManyupdateMany、和deleteMany作業的 ACID 屬性,建議您使用交易。

更新的功能差異

Amazon DocumentDB 透過客戶要求我們建置的功能向後運作,持續改善與 MongoDB 的相容性。本節包含我們在 Amazon DocumentDB 中移除的功能差異,這些差異可讓客戶更輕鬆地進行遷移和建置應用程式。

編製陣列索引

自 2020 年 4 月 23 日起,Amazon DocumentDB 現在支援索引大於 2,048 位元組的陣列。數組中的單個項目的限制仍然保持為 2,048 個字節,這與 MongoDB 一致。

如果您要建立新索引,則不需要採取任何動作來利用改進的功能。如果您有現有的索引,您可以刪除索引再重新建立,以利用改進的功能。具有改進功能的最新索引版本為 "v" : 3

注意

對於生產叢集,刪除索引可能會影響您的應用程式效能。建議您在對生產系統變更時先加以測試並小心進行。此外,重新建立索引所需的時間,將是集合整體資料大小的函數。

您可以使用以下命令查詢索引的版本。

db.collection.getIndexes()

此操作的輸出將會如下所示。在此輸出中,索引的版本是 "v" : 3,這是最新的索引版本。

[ { "v" : 3, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.test" } ]

多金鑰索引

自 2020 年 4 月 23 日起,Amazon DocumentDB 現在支援在同一陣列中建立具有多個鍵的複合索引的功能。

如果您要建立新索引,則不需要採取任何動作來利用改進的功能。如果您有現有的索引,您可以刪除索引再重新建立,以利用改進的功能。具有改進功能的最新索引版本為 "v" : 3

注意

對於生產叢集,刪除索引可能會影響您的應用程式效能。建議您在對生產系統變更時先加以測試並小心進行。此外,重新建立索引所需的時間,將是集合整體資料大小的函數。

您可以使用以下命令查詢索引的版本。

db.collection.getIndexes()

此操作的輸出將會如下所示。在此輸出中,索引的版本是 "v" : 3,這是最新的索引版本。

[ { "v" : 3, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.test" } ]

字串中的 Null 字元

從 2020 年 6 月 22 日起,Amazon DocumentDB 現在支持字符串中的空字符('\0')。

以角色為基礎的存取控制

自 2020 年 3 月 26 日起,Amazon DocumentDB 支援內建角色的角色型存取控制 (RBAC)。如需進一步了解,請參閱 以角色為基礎的存取控制

$regex 索引功能

截至 2020 年 6 月 22 日,Amazon DocumentDB 現在支持$regex操作員使用索引的能力。

若要使用與 $regex 運算子的索引,您必須使用 hint() 命令。使用 hint() 時,您必須指定要套用 $regex 之欄位的名稱。例如,如果您在欄位 product 有名為 p_1 的索引,db.foo.find({product: /^x.*/}).hint({product:1}) 將使用 p_1 索引,但 db.foo.find({product: /^x.*/}).hint(“p_1”) 不會使用該索引。您可以使用 explain() 命令或使用分析工具的記錄慢速查詢功能來驗證是否已選擇索引。例如 db.foo.find({product: /^x.*/}).hint(“p_1”).explain()

注意

hint() 方法一次只能與一個索引一起使用。

$regex 查詢的索引使用已針對使用字首且未指定 I, 、mo 規則運算式選項的查詢進行最佳化。

$regex 搭配索引使用時,建議您在有高度選擇性的欄位上建立索引,其中重複值的數目會小於集合中文件總數的 1%。例如,如果您的集合包含 100,000 份文件,則只在相同值出現 1000 次或更少的欄位上建立索引。

巢狀文件的投影

有一個功能差異與 Amazon DocumentDB 和 MongoDB 之間的$project運營商 3.6 版已經在 Amazon DocumentDB 4.0 已經解決,但仍將在 Amazon DocumentDB 3.6 不受支持。

Amazon DocumentDB 3.6 應用投影時只考慮嵌套文檔中的第一個字段,而 MongoDB 3.6 將解析子文檔並將投影應用於每個子文檔以及。

例如:如果投影是“a.b.c”: 1,則該行為按預期在 Amazon DocumentDB 和 MongoDB 中工作。但是,如果投影是{a:{b:{c:1}}}那麼 Amazon DocumentDB 3.6 將只應用於投影,a而不b是或。c在 Amazon DocumentDB 4.0,投影{a:{b:{c:1}}}將被應用到 ab,和。c

MongoDB 的功能差異

Amazon DocumentDB 不支持$vectorSearch作為獨立運營商。相反,我們支持$search運營商vectorSearch內部。如需詳細資訊,請參閱 矢量搜索 Amazon DocumentDB

OpCountersCommand

Amazon 文檔數據庫的OpCountersCommand行為偏離 MongoDB 的,如下所示:opcounters.command

  • MongoDB 的opcounters.command計數除了插入,更新和刪除所有命令,而 Amazon DocumentDB 的OpCountersCommand也排除了命令。find

  • Amazon DocumentDB 計算內部命令(例如getCloudWatchMetricsV2)。OpCountersCommand

管理員資料庫和集合

Amazon DocumentDB 不支持管理員或本地數據庫,也不分別 MongoDB system.*startup_log集合。

cursormaxTimeMS

在 Amazon DocumentDB 中,為每個getMore請求cursor.maxTimeMS重置計數器。因此,如果指定了 3000MS,maxTimeMS則查詢需要 2800MS,並且每個後續getMore請求都需要 300MS,則光標不會超時。只有當單一作業 (查詢或個別要getMore求) 花費超過指定的作業時,游標才會逾時maxTimeMS。此外,檢查游標執行時間的掃描器會以五 (5) 分鐘的粒度執行。

explain()

Amazon DocumentDB 會在使用分散式容錯、自我修復儲存系統的專用資料庫引擎上模擬 MongoDB 4.0 API。因此,Amazon DocumentDB 和 MongoDB 之間的查詢計劃和輸出explain()可能會有所不同。想要控制其查詢計劃的客戶可以使用 $hint 運算子強制選取偏好的索引。

欄位名稱限制

Amazon DocumentDB 不支持點「.」 在文件欄位名稱中,例如,db.foo.insert({‘x.1’:1})

Amazon DocumentDB 也不支持字段名稱中的 $ 前綴。

例如,嘗試在 Amazon DocumentDB 或 MongoDB 下面的命令:

rs0:PRIMARY< db.foo.insert({"a":{"$a":1}})

MongoDB 將返回以下內容:

WriteResult({ "nInserted" : 1 })

Amazon DocumentDB 將返回一個錯誤:

WriteResult({ "nInserted" : 0, "writeError" : { "code" : 2, "errmsg" : "Document can't have $ prefix field names: $a" } })
注意

這種功能差異有一個例外。以 $ 前綴開頭的以下字段名稱已列入白名單,並且可以在 Amazon DocumentDB 中成功使用:$ ID,$ 參考和 $ 分貝。

索引建置

Amazon DocumentDB 只允許在任何給定時間在集合上建立一個索引。無論是在前景還是背景中。當索引建置目前正在進行時,如果在相同的集合上進行如 createIndex()dropIndex() 等操作,最新嘗試進行的操作將會失敗。

默認情況下,Amazon DocumentDB 和 MongoDB 4.0 版本中的索引構建發生在後台。MongoDB 版本 4.2,如果指定為 createIndexes 或其外殼助手和,則忽略後台索引構建選項。createIndex() createIndexes()

存留時間 (TTL) 索引會在索引建立完成後開始將到期的文件。

在路徑中使用空鍵查找

當您查找包含空字符串作為路徑一部分的鍵(例如,x..bx.,並且該對象在數組中具有空字符串鍵路徑(例如{"x" : [ { "" : 10 }, { "b" : 20 } ]})時,Amazon DocumentDB 將返回不同的結果,而不是在 MongoDB 中運行相同的查找。

在 MongoDB 中,當空字符串鍵不在路徑末尾查找時,空鍵路徑在數組中查找按預期工作。但是,當空字符串鍵位於路徑末尾查找時,它不會查看數組。

但是在 Amazon DocumentDB 中,只會讀取陣列中的第一個元素,因為getArrayIndexFromKeyString將空字串轉換為0,所以字串鍵查找會被視為陣列索引查找。

MongoDB API、營運和資料類型

Amazon DocumentDB 是與 MongoDB 3.6 和 4.0 的 API 兼容。如需支援功能的 up-to-date 清單,請參閱支援的 MongoDB API、營運和資料類型

mongodumpmongorestore公用事業

Amazon DocumentDB 不支援管理員資料庫,因此在使用或公用程式時不會傾印或還原管理員資料庫。mongodump mongorestore當您使用 Amazon DocumentDB 建立新資料庫時mongorestore,除了還原操作之外,還需要重新建立使用者角色。

注意

對於 Amazon DocumentDB,我們推薦 MongoDB 數據庫工具,並包括版本 100.6.1。您可以訪問 MongoDB 的數據庫工具下載這裡

結果排序

Amazon DocumentDB 不保證結果集的隱式結果排序順序。為確保結果集的排序,請使用 sort() 明確指定排序順序。

以下範例會根據庫存欄位以遞減順序排序庫存集合中的項目。

db.inventory.find().sort({ stock: -1 })

使用$sort彙總階段時,除非階段是彙總管線中的最後一個$sort階段,否則不會保留排序順序。將$sort彙總階段與彙總階段結合使用時,$sort彙總階段僅適用於$first$last累加器。$group在 Amazon DocumentDB 4.0 中,增加了支持$push以尊重上一$sort階段的排序順序。

可重試的寫入

從與 MongoDB 4.2 相容的驅動程式開始使用,可重試的寫入為預設啟用。不過,Amazon DocumentDB 目前不支援可重試寫入。功能差異會在類似下列錯誤訊息中以資訊清單列出。

{"ok":0,"errmsg":"Unrecognized field: 'txnNumber'","code":9,"name":"MongoError"}

可重試寫入可透過連接字串停用 (例如,MongoClient("mongodb://my.mongodb.cluster/db?retryWrites=false"))或 MongoClient 建構函式的關鍵字引數 (例如. MongoClient("mongodb://my.mongodb.cluster/db", retryWrites=False))

以下是透過連線字串停用可重試寫入的 Python 範例。

client = pymongo.MongoClient('mongodb://<username>:<password>@docdb-2019-03-17-16-49-12.cluster-ccuszbx3pn5e.us-east-1.docdb.amazonaws.com:27017/?replicaSet=rs0',w='majority',j=True,retryWrites=False)

稀疏索引

若要使用您在查詢中建立的稀疏索引,您必須在涵蓋索引的欄位上使用 $exists 子句。如果省略$exists,Amazon DocumentDB 不會使用稀疏索引。

以下是範例。

db.inventory.count({ "stock": { $exists: true }})

對於稀疏、多索引鍵索引,Amazon DocumentDB 不支援唯一索引鍵條件約束,如果查詢文件會導致一組值,且只遺失索引欄位的子集。例如,若輸入為 "a" : [ { "b" : 2 }, { "c" : 1 } ] 則不支援 createIndex({"a.b" : 1 }, { unique : true, sparse :true }),因為 "a.c" 會儲存在索引中。

使用 $all 表達式內的 $elemMatch

Amazon DocumentDB 目前不支持在表達式中使用$elemMatch運算符。$all您可以如下所示搭配 $elemMatch 使用 $and,解決問題。

原始操作:

db.col.find({ qty: { $all: [ { "$elemMatch": { part: "xyz", qty: { $lt: 11 } } }, { "$elemMatch": { num: 40, size: "XL" } } ] } })

更新的操作:

db.col.find({ $and: [ { qty: { "$elemMatch": { part: "xyz", qty: { $lt: 11 } } } }, { qty: { "$elemMatch": { qty: 40, size: "XL" } } } ] })

$ne$nin$nor$not$exists、和$elemMatch索引

Amazon DocumentDB 目前不支援使用索引與$ne、、$nin$nor$distinct運算子搭配使用的功能。$not $exists因此,使用這些運算子將導致收集掃描。在使用其中一個運算子之前執行篩選或比對會減少需要掃描的資料量,進而改善效能。

Amazon DocumentDB 增加了對亞 Amazon DocumentDB 5.0 和彈性集群中的$elemMatch操作員進行索引掃描的支持。如果僅查詢篩選具有一個層級的篩選器,則支援索引掃描,但如果包含巢狀$elemMatch查詢,則不支援索引掃描。$elemMatch

$elemMatch支援索引掃描 Amazon DocumentDB 狀:

db.foo.find( { "a": {$elemMatch: { "b": "xyz", "c": "abc"} } })

$elemMatch不支援索引掃描的 Amazon DocumentDB 狀:

db.foo.find( { "a": {$elemMatch: { "b": {$elemMatch: { "d": "xyz", "e": "abc"} }} } })

$lookup

Amazon DocumentDB 支援執行相等比對的功能 (例如,左外部聯結),但不支援不相關的子查詢。

利用索引 $lookup

您現在可以使用$lookup階段運算子的索引。根據您的使用案例,您可以使用多種索引演算法來最佳化效能。本節將說明不同的索引演算法,$lookup並協助您選擇最適合您工作負載的索引演算法。

根據預設,Amazon DocumentDB 在使用時會利用雜湊演算法,並allowDiskUse:false在使用時對合併進行排序。allowDiskUse:true對於某些使用案例,可能需要強制查詢最佳化工具使用不同的演算法。以下是$lookup聚合運算符可以利用的不同索引算法:

  • 巢狀迴圈:如果外部集合小於 1 GB,而外部集合中的欄位具有索引,巢狀迴圈計劃通常對工作負載有益。如果使用巢狀迴圈演算法,說明計畫會將階段顯示為NESTED_LOOP_LOOKUP

  • 排序合併:如果外部集合在查詢中使用的欄位上沒有索引,且工作資料集不適合記憶體,則排序合併計畫通常對工作負載有益。如果使用排序合併演算法,說明計畫會將階段顯示為SORT_LOOKUP

  • 雜湊:如果外部集合小於 1GB,且工作資料集適合記憶體,雜湊計畫通常對工作負載有益。如果正在使用雜湊演算法,說明計畫會將階段顯示為HASH_LOOKUP

您可以在查詢上使用 explain 來識別正在用於$lookup運算子的索引演算法。下面是一個例子。

db.localCollection.explain(). aggregate( [ { $lookup: { from: "foreignCollection", localField: "a", foreignField: "b", as: "joined" } } ] output { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.localCollection", "winningPlan" : { "stage" : "SUBSCAN", "inputStage" : { "stage" : "SORT_AGGREGATE", "inputStage" : { "stage" : "SORT", "inputStage" : { "stage" : "NESTED_LOOP_LOOKUP", "inputStages" : [ { "stage" : "COLLSCAN" }, { "stage" : "FETCH", "inputStage" : { "stage" : "COLLSCAN" } } ] } } } } }, "serverInfo" : { "host" : "devbox-test", "port" : 27317, "version" : "3.6.0" }, "ok" : 1 }

作為使用方法的替代方explain()法,您可以使用效能分析工具來檢閱您使用運算子時所使用的$lookup演算法。如需效能分析工具的詳細資訊,請參閱。分析亞馬遜文檔數據庫操作

使用 planHint

如果您想要強制查詢最佳化工具使用不同的索引演算法$lookup,您可以使用planHint. 若要這麼做,請使用彙總階段選項中的註解來強制執行不同的計劃。下面是評論的語法的一個例子:

comment : { comment : “<string>”, lookupStage : { planHint : “SORT” | “HASH” | "NESTED_LOOP" } }

下面是使用強制查詢優化器使用HASH索引算法的一個例子:planHint

db.foo.aggregate( [ { $lookup: { from: "foo", localField: "_id", foreignField: "_id", as: "joined" }, } ], { comment : "{ \\"lookupStage\\" : { \\"planHint\\": \\"HASH\\" }}"

若要測試哪種演算法最適合您的工作負載,您可以在修改索引演算explain法 (即HASH//SORT/NESTED_LOOP) 時,使用方法的executionStats參數來測量$lookup階段的執行時間。

下列範例顯示如executionStats何使用SORT演算法來測量$lookup階段的執行時間。

db.foo.explain(“executionStats”).aggregate( [ { $lookup: { from: "foo", localField: "_id", foreignField: "_id", as: "joined" }, } ], { comment : "{ \\"lookupStage\\" : { \\"planHint\": \\"SORT\\" }}"