2014-04-19 258 views
28

我想確定在mongo數據庫中處理複合主鍵的最佳方法。與該系統中的數據交互的主鍵由2個uuid組成。 uuids的組合保證是獨一無二的,但個人uuids都不是。MongoDB和複合主鍵

我看到一對夫婦的管理此的方法:

  1. 使用對象對於被向上的2個值(所建議here

  2. 使用標準自動取得的主鍵生成的mongo對象ID作爲主鍵,將我的密鑰存儲在兩個單獨的字段中,然後在這兩個字段上創建組合索引

  3. 使主鍵成爲2個字母的散列

  4. 是我目前不知道

什麼是這些方法的性能影響其他一些真棒的解決方案?

對於選項1,我擔心插入性能會影響非順序鍵。我知道這可以殺死傳統的RDBMS系統,我也看到了在MongoDB中這也可能是真的。

對於選項2,有一個永遠不會被系統使用的主鍵似乎有點奇怪。此外,似乎查詢性能可能不如選項1中的那麼好。在傳統RDBMS中,聚簇索引提供最佳查詢結果。這在MongoDB中有多相關?

對於選項3,這將創建一個單一的ID字段,但它也不會在插入時連續。這種方法有沒有其他優點/缺點?

對於選項4,那麼...什麼是選項4?

此外,還有一些討論可能會在未來某個時候使用CouchDB而不是MongoDB。使用CouchDB會提出一個不同的解決方案嗎?

更多信息:有關該問題的一些背景,可以發現here

+1

可能最重要的問題是你將如何訪問這些數據?寫明顯插入 - 更新?關於查詢呢?刪除有史以來? –

+0

晴寫道。然後更新(大部分以大爆發)。相當數量的插入(再次,大部分是大爆發)。偶爾刪除。 – herbrandson

+0

更新將使用哪些字段?一個或兩個uuids? –

回答

28

因爲我認爲,分片是最好的方式來擴展插入和更新集合,因爲您應該選擇1.

最主要的原因是你說你擔心性能 - 使用總是存在且已經唯一的_id索引將允許您保存必須保持第二個唯一索引。

對於選項1,我很擔心插入性能會對 非順序鍵產生影響。我知道這可以殺死傳統的RDBMS系統 ,我也看到了在MongoDB中這也可能是真的。

你的其他選擇不迴避這個問題,他們只是從_id指數二級唯一索引轉移 - 但現在你有兩個指標,一旦這是正確的平衡,另一個是很隨機訪問。

只有一個理由來質疑選項1,那就是如果您打算通過一個或僅僅一個UUID值訪問文檔。只要你一直在提供兩個值和(這部分是非常重要的),你總是命令他們在所有的疑問同樣的方式,那麼_id指數將有效地服務於它的全部目的。

至於爲什麼你必須確保你總是訂購兩個UUID值的方法相同的闡述,比較子文檔時{ a:1, b:2 }不等於{ b:2, a:1 } - 你可以有一個集合,其中兩個文件有那些值_id。所以,如果你存儲_id與現場第一個,那麼你必須始終保持在所有的文件和查詢的順序。

其他注意事項是在_id:1指數將查詢可用:

db.collection.find({_id:{a:1,b:2}}) 

但它對查詢可用

db.collection.find({"_id.a":1, "_id.b":2}) 
+0

嗨,你能告訴我如何實現複合主鍵嗎?我現在正在做的是'StringJoiner joiner = new StringJoiner(「/」); \t \t \t joiner.add(info.getUserID())。add(idOfApp); \t \t \t String idName = joiner.toString();',它工作正常,但使用複合鍵是我認爲是一種更好的方法,我嘗試了使用BasciDBObject並追加了我的字段的兩個值,但那沒用。也許我做錯了什麼。所以,如果你能向我展示完整的實施方案,那將會非常有幫助。提前致謝。 – Learner

+1

提出新的問題,這是不適用的評論。 –

+0

好的,謝謝,我會牢記這一點。我實際上是自己想出來的。 'BasicDBObject compositeKey = new BasicDBObject(「deviceId」,deviceID).append(「id」,id); \t \t \t \t \t \t String newID = compositeKey.toJson();'其中deviceID和id包含我需要附加的值。再次感謝。 – Learner

2

我會走到與選項2.您仍然可以作出這樣的處理既UUID字段的索引,和性能應該是相同的作爲一個複合主鍵,除了它會更容易處理。另外,根據我的經驗,我從來沒有後悔過給一些獨特的ID,即使它沒有被嚴格要求。雖然這可能是一個不受歡迎的觀點。

2

我會去爲2選項,並有爲什麼

  1. 有兩個不同的領域,而不是一個來自兩個串聯的UUID作爲第一個建議,會讓你靈活地創建索引的其他組合以支持未來的查詢請求,或者如果證明一個密鑰的基數高於另一個密鑰的話。
  2. 具有非順序鍵可以幫助您避免在分片環境中插入時的熱點,所以它不是一個很糟糕的選項。因爲寫入鎖定是在數據庫級別(2.6之前)或集合級別(2.6版本)
+0

謝謝,這很有幫助!只是爲了澄清,你說有非順序鍵可以幫助w/sharded環境。然而,選項#2是_would_給你連續ID的那個。我不理解什麼嗎? – herbrandson

+0

您是對的,非連續鍵註釋與您的問題中的語句相關,您說,連續鍵在RDBMS中有幫助 – Boris

+0

在大多數RDBMS中,記錄是物理存儲在按其主鍵排序的磁盤上的。在進行非順序插入時,所有記錄都必須實際移動。這是插入緩慢w /一個非序列號。這也是爲什麼針對羣集密鑰的查詢速度如此之快。 (你可能已經知道這一點,但我只是想把我的問題放在上下文中)。 你是說在MongoDB中不是這種情況嗎?我的閱讀讓我相信這仍然是一個考慮因素。我知道標準的MongoDB ObjectIDs是順序的。我認爲這是原因的一部分。 – herbrandson

6

我有一個選項4爲您提供:

使用自動_id字段併爲uuid而不是單個c添加2個單字段索引omposite索引。

  1. _id指數將是連續的(儘管這在MongoDB那麼重要),易shardable,你可以讓MongoDB管理。
  2. 2個uuid索引可讓您進行任何類型的查詢(第一個,第二個或任意順序),它們佔用的空間少於1個複合索引。
  3. 如果您在同一個查詢中使用兩個索引(以及其他索引)MongoDBintersect them(v2.6中的新增功能)就好像您正在使用複合索引一樣。
+0

對一個順序索引進行分片是一個壞主意,它不會在所有分片中均勻共享,因爲你有2個索引而不是1個(對大型集合有很大的影響),所以你將沒有足夠的索引空間。 –

+0

@JonathanMuller如果你使用散列對它們進行分片,那麼不是。 「散列鍵可以很好地處理像ObjectId那樣單調增加的字段」https://docs.mongodb.org/manual/core/sharding-shard-key/#sharding-hashed-sharding – i3arnon