場景數據結構的優化存儲快速查找和持久性
我有以下幾種方法:
public void AddItemSecurity(int itemId, int[] userIds)
public int[] GetValidItemIds(int userId)
起初我想在表單上存儲:
itemId -> userId, userId, userId
和
userId -> itemId, itemId, itemId
AddItemSecurity
基於我如何從第三方API獲取數據,GetValidItemIds
是我想如何在運行時使用它。
有潛在的2000個用戶和1000萬個項目。 商品標識的格式爲:2007123456,20100(10位數字,前四位代表年份)。
AddItemSecurity
不一定要執行超快速,但GetValidIds
需要亞秒。另外,如果現有的itemId
上有更新,我需要刪除不再在列表中的用戶的itemId。
我在想如何以最佳的方式存儲這個。最好在磁盤上(使用緩存),但我希望代碼可以維護和清潔。
如果項目ID從0開始,我想爲每個用戶創建一個長度爲MaxItemId/8
的字節數組,並且如果項目存在或不存在,則設置true/false位。這會將陣列長度限制在每用戶1mb以下,並提供快速查找以及更新每個用戶列表的簡單方法。通過堅持這個爲Memory Mapped Files與.Net 4框架,我想我也會得到體面的緩存(如果機器有足夠的內存),而不用自己實現緩存邏輯。解析ID,剝離年份,每年存儲一個數組可能是一個解決方案。
可以將ItemId - > UserId []列表直接序列化到磁盤,並使用正常FileStream
進行讀/寫操作,以便在發生更改時保留列表並進行區分。
每次添加新用戶時,所有列表也必須更新,但是這可以在每晚進行。
問題
我應該繼續嘗試這種方法,還是應探索以及有其他路徑?我認爲SQL服務器的執行速度不夠快,而且會給開銷帶來負擔(至少如果託管在另一臺服務器上),但我的假設可能是錯誤的。任何關於此事的想法或見解都值得讚賞。我想嘗試去解決它無需增加太多的硬件:)
[更新2010-03-31]
在下列條件下我現在已經與SQL Server 2008進行測試。
- 表有兩列(用戶ID,項ID)都是詮釋 上兩列
- 增補
- 簇索引〜800.000項180層的用戶 - 144萬行總計
- 分配4GB RAM,用於SQL服務器
- 雙核2.66GHz的筆記本電腦
- SSD磁盤
- 使用SqlDataReader讀取所有的itemid的成列表
- 循環遍歷所有用戶
如果我運行一個線程,它的平均值爲0.2秒。當我添加第二個線程時,它會上升到0.4秒,這仍然可以。從那裏的結果正在下降。添加第三個線程會將查詢的數量增加到2個。第四個線程,最多4秒,第五個線程可以將查詢延伸到50秒。
即使在一個線程中,CPU仍在進行屋頂工作。我的測試應用程序需要一些由於快速循環,其餘的SQL。
這使我得出結論,它不會很好地擴展。至少不是在我測試過的硬件上。有沒有方法來優化數據庫,比如說每個用戶存儲一個int數組而不是每個項目的一個記錄。但是這使得刪除項目變得更加困難。
[更新2010-03-31#2]
我做了一個快速測試與把它作爲內存映射文件的位相同的數據。它表現更好。六個線程的訪問時間在0.02s和0.06s之間。純粹的內存限制。映射文件由一個進程映射,並由六個人同時訪問。而作爲SQL基地採取4GB,在磁盤上的文件花費了23MB。
我知道你在使用C#,我不知道如何在那裏實現內存映射文件,但是你可能想看看這個Java:'http ://download.oracle.com/javase/6/docs/api/java/nio/channels/FileChannel.html#map(java.nio.channels.FileChannel.MapMode,long,long)' – user183037 2011-02-22 21:16:29
「對生成的緩衝區最終會傳播到文件中;對於映射相同文件的其他程序,它們可能會也可能不會被顯示。「 - 如果你使用多個線程,你會想要小心這部分。 – user183037 2011-02-22 21:19:04
我對多線程或多處理器訪問同一文件沒有任何問題。如果我沒有弄錯,如果訪問相同的數據,兩個線程/ proc將訪問操作系統中的同一內存頁面,操作系統將負責緩存/分頁/排隊請求。也就是說,我不是專家,在我的情況下,我有一位作家和多位讀者,而一次錯過就沒有什麼大不了的。如果你需要對事件序列100%確定,那麼你可能不想使用mmf。但是我相信這很重要,因爲mmf是推薦的應用之間共享數據的方式之一。 – 2011-02-23 08:39:56