2014-07-22 79 views
1

我對索引視圖的最佳方式有些懷疑。CouchDB查看索引性能

比方說,我存儲「用戶」鏈接到「組」這樣的文件:

{ 
    "groupId": "<group_id>", 
    "userId": "<user_id>" 
} 

我想要檢索鏈接到用戶的所有組,所以很明顯映射的最佳方法是:

emit(doc.userId, doc.groupId); 

我可以通過查詢key=<user_id>查看視圖來檢索組。

但是現在,如果我想要刪除與特定用戶/組對相對應的文檔,我需要瀏覽查看查詢的所有結果,直到找到正確的值並獲取文檔的ID。

所以我認爲索引視圖的更好的方式是這樣的:

emit([doc.userId, doc.groupId], null); 

我可以讓所有的組通過發出一系列查詢和解析返回的行鍵鏈接到用戶,並還用「全部」鍵直接打一個特定的文件(如果存在)。但是我擔心範圍查詢(比「完整」查詢更頻繁地被調用)會比最初的方法有更差的性能。

任何有識之士將不勝感激,謝謝!

回答

1

當然,最終的答案是衡量對你而言重要的任何指標。

但是,我認爲性能會大致相同。在每種情況下,您將爲每個{user,group}對發出一個視圖行。

視圖可以有多個具有相同「密鑰」的行。因此,當您查詢key=<user_id>時,您仍在執行範圍查詢(「CouchDB,顯示所有查看以user_id開頭並以user_id結尾的行」)。因此,我認爲您會在那裏看到類似的性能。

對我而言,您最大的性能問題看起來像延遲:多次往返查詢此視圖,然後跟進文檔。當然,您可以添加?include_docs=true,但仍會增加額外的I/O負載。 (在我看來,額外費用大部分是理論上的,在實際應用中並不是那麼糟糕。)

要刪除文檔,您需要的不止是id。你也需要修改。因此,爲了提升性能並減少往返次數和延遲,您可以發出更有用的值,而不是null。例如,發出整個文件!或者可能發出{"_id":doc._id, "_rev":doc._rev}。這樣,您可以通過發出DELETE到/db/<id>?rev=<rev>來刪除文檔「視力未見」。

+0

謝謝。我不認爲往返旅行對我來說是一個問題,因爲這兩個查詢不相關:它或者是「獲取列表」,或者「(嘗試)刪除一個條目」,但這些是兩個不同的事情。 – ThomasWeiss

2

我相信你應該抵制的衝動,創造了太多的小文件(這是我們與我們帶來從我們的SQL數據庫的經驗)。在這個(不可否認的例子)用例中,單個用戶列表或單個用戶的組列表可以是單個文檔。

顯然,用戶對單個組極有可能有導致衝突的多個併發的編輯 - 但不太可能是多個併發的編輯組的單個用戶列表。

因此,我建議您爲每個用戶創建一個單個文檔,列出他們的組(或者將其作爲一個數組添加到其他一些以用戶爲中心的文檔中)。根據用戶ID使用固定的文檔ID方案,以便您可以直接按ID訪問文檔,而無需在視圖中查看它。現在您只需要爲特定的組發佈用戶視圖。

如果用戶離開一個組,您只需更新他們的組首選項。如果某個組被刪除,那麼您就可以從每個組成員的首選項中找到並刪除組ID,但這將是一個不太常見的任務,並且通常只能由一個對冗長更寬容的管理員執行運行過程。

+0

感謝您的貢獻!我知道你建議不要創建小文檔,而是將他們的數據在單個文檔中聯合起來,但是有許多小文檔的實際缺點是什麼? – ThomasWeiss

+0

用於構建模型的文檔越多,需要的內容越多:a)添加大量視圖以將它們放在一起,並b)在其中嵌入documentID以創建關係(如關係數據庫,但不保證關係完整性)。 CouchDB是一個文檔存儲 - 您應該尋找將完整結構存儲爲單個文檔以獲得最大利益的方法。高文檔計數的另一個問題是複製(特別是第一次)需要永久性,因爲每個文檔都代表GET。 –

+0

我恭敬地不同意。通過避免引用由於非規範化而導致大量丟失的其他文檔(如果用戶更改其名稱),您認爲自己贏了什麼。這不是關於小文件還是大文件,而是關於正確的總體設計。 – reddy