2016-03-12 85 views
13

我需要保持iOS應用上的本地數據與DynamoDB表中的數據保持同步。的DynamoDB表是〜2K行,只有一個散列密鑰(id),和以下屬性:如何按日期查詢DynamoDB(範圍鍵),沒有明顯的散列鍵?

  • id(UUID)
  • lastModifiedAt(時間戳)
  • name
  • latitude
  • longitude

我目前正在掃描並通過lastModifiedAt篩選,其中lastModifiedAt大於應用程序的上次刷新日期,但我想這會變得很昂貴。

最好的answer我可以找到的是添加一個全局二級索引lastModifiedAt作爲範圍,但沒有明顯的GSI的散列鍵。

當需要使用GSI進行範圍查詢時,什麼是最佳實踐,但沒有明顯的散列鍵?或者,如果全面掃描是唯一的選擇,是否有任何最佳實踐來降低成本?

回答

6

雖然D.Shawley的回答幫我指出了正確的方向,它錯過了GSI兩個方面的考慮:

  1. 散列+範圍必須是唯一的,但天+時間戳(他推薦的方法)將不一定是唯一的。
  2. 通過只使用一天作爲散列,我需要使用大量的查詢來獲取自上次刷新日期(可能是幾個月或幾年前)以來每天的結果。

因此,這裏是我採取的方法:用哈希鍵創建一個全球次級指數(GSI)爲YearMonth

  • (例如,201508)和範圍爲id
  • 查詢的GSI多次,自上次刷新日期以來每月查詢一次。查詢也通過lastModifiedAt > [given timestamp]過濾。
+0

請參閱我的回答以瞭解其他注意事項。問候。 – bsd

+3

我有和你一樣的情況,來到同一個解決方案。感謝您在此發佈此信息。一注:GSI不需要是唯一的:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForGSI.html – ustroetz

2

您可以使用時間戳的「日」部分作爲散列並使用完整的時間戳作爲範圍。

+0

由於散列鍵需要一個'eq'條件,我會那麼需要爲,因爲應用程序的最後一次刷新已通過每天進行查詢? (該應用程序在本地存儲'lastRefreshedAt'時間戳)。看起來像這樣會比掃描更昂貴。 –

+0

也許我可以將時間戳的「年份」部分存儲爲散列鍵?這將大大減少某人第一次打開他們的應用程序時所需的查詢次數,比如使用「day」部分。此時,似乎範圍鍵變得無關緊要,因爲通過散列鍵查詢將帶來自lastRefreshedAt後更新的所有項目。 –

17

雖然Global Secondary Index似乎符合您的要求,任何企圖包括timestamp相關的信息作爲你的Hash Key的部分將很可能創造了被稱爲「熱分區」,這是非常不可取的。

不均勻的訪問將發生,因爲最近的項目將以比舊的更頻繁的方式來檢索。這不僅會影響您的表現,還會使您的解決方案降低成本效益。

見一些細節從文檔:

例如,如果表中有非常少量的大量訪問 分區鍵值,甚至可能是單個非常頻繁使用的 分區鍵值的,請求交通專注於分區的小數字 - 可能只有一個分區。如果工作負載爲 嚴重不平衡,這意味着它不成比例地集中在一個或幾個分區上,請求將無法達到預配置吞吐量級別的總體 。要充分利用DynamoDB 吞吐量,請創建表,其中分區鍵具有不同值的大數 ,並且請求的值相當均勻,因爲 儘可能隨機。

基於什麼說明,id看來確實是你的Hash Key(亦稱Partition Key)一個不錯的選擇,我不會改變,作爲GSI鍵相同的方式工作,至於分區。作爲一個單獨的說明,當您通過提供整個Primary Key來檢索數據時,性能會得到高度優化,所以我們應該盡力找到一個儘可能提供該解決方案的解決方案。

我建議創建單獨的表來存儲基於最近更新的主鍵。您可以根據最適合您的用例的粒度將數據分割成表格。例如,假設您想要按天分段更新:

a。您的每日更新可以使用以下命名約定存儲在表格中:updates_DDMM

b。 updates_DDMM表將只有id的(另一個表的哈希鍵)

現在說最新的應用程序刷新日期是從2天前(04/07/16),你需要得到最近的記錄,那麼你需要:

i。掃描表updates_0504updates_0604以獲取所有散列鍵。

ii。最後通過提交BatchGetItem所有獲得的散列鍵,從主表中獲取記錄(包含緯度/經度,名稱等)。

BatchGetItem速度超快,並會像沒有其他操作一樣完成工作。

人們可以爭辯說,創建額外的表會增加成本,你的整體解決方案......嗯,跟你GSI基本上是複製你的表(如果你正在投影的所有字段),並補充說,額外費用爲所有〜2K記錄,被他們最近更新的或不...

似乎直覺創建表這樣的,但它實際上是時間序列數據處理(從AWS DynamoDB文檔)時,最好的做法:

[。 ..該應用程序可能會顯示橫跨在客戶的最新數據更相關和您的 應用程序可以訪問最新的項目更頻繁,隨着時間的 通過這些項目較少訪問,最終上了年紀的項目表中的所有項目 不均勻訪問模式很少訪問 。如果這是一種已知的訪問模式,那麼在設計表模式時可以考慮到它 。取而代之的 存儲在一個表中的所有項目,您可以使用多個表 存儲這些項目。例如,您可以創建表來存儲每月或每週數據 。對於表存儲從最新 按月或按周,其中的數據訪問率高的數據,要求更高 吞吐量和表中存儲舊數據,你可以撥下來的 吞吐量和節省資源。

您可以通過將「熱」項存儲在一個表中,節省資源,其中 的吞吐量設置較高,另一個表中的「冷」項的吞吐量設置較低。您可以通過簡單地刪除 表刪除舊的項目。您可以選擇將這些表備份到其他存儲 選項,如Amazon Simple Storage Service(Amazon S3)。刪除 整個表是顯著更有效的不是刪除項目 一個接一個,正如你做 儘可能多的刪除操作是把操作寫入吞吐量基本翻倍。

來源: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html

我希望幫助。問候。

+1

這是一個偉大的建議。謝謝你對此的深思。考慮到訪問基於時間的數據的複雜性,這讓我懷疑RDS是否是更好的解決方案。 –

+1

請注意,BatchGetItem僅限於100個項目。 –