[英]In Ruby, how do I split a range into chunks for batch operations?
對於您所有的Ruby高爾夫球手和體操運動員來說,這都是一個有趣的小難題。
問題:我有數百萬個SQL數據庫記錄,我需要以相反的ID順序(可能是1000個左右)將它們轉移到NoSql數據庫中(所以find_each不是有效的解決方案)。
這將在小型服務器上運行,因此我不想一次將所有ID都保留在內存中,而只希望將一個ID保留在內存中。
我希望在我的代碼庫中使用以下內容:
chunkify max_id, step_size do |ids|
copy_to_nosql SqlTable.where(id: ids)
end
你能寫成chunkify
嗎?
解決方案不應重復任何ID,它應覆蓋所有ID,第一個產生的數組應包含max_id,返回的最低ID應該為1。
PS。 我正在使用Rails框架,因此可以隨時使用Rails特定的語言增強功能。
PPS。 我不想使用數據庫驅動的解決方案,例如“限制”和“偏移”,至少對於我的數據庫實現而言,隨着偏移量的增加,查詢需要更長的時間來處理。
編輯
這是一個可行的解決方案。 任何提高可讀性,簡潔性或效率的替代方法都受到歡迎:
# yields arrays of ints (chunks), of [chunk_size] or lower length, which,
# when added together, would cover all values from 0 to [top_value], exactly
# once each. The highest value 'chunk' is provided first.
#
# > chunkify(100, 10) { |chunk| puts chunk.inspect }
# [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
# [81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
# ...
# [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# => 100
# > chunkify(27, 8) { |chunk| puts chunk.inspect }
# [20, 21, 22, 23, 24, 25, 26, 27]
# [12, 13, 14, 15, 16, 17, 18, 19]
# [4, 5, 6, 7, 8, 9, 10, 11]
# [1, 2, 3]
# => 27
def chunkify(top_value, chunk_size)
top_value.step(1, -chunk_size) do |i|
yield ((i-chunk_size > 0 ? i-chunk_size+1 : 1)...i+1).to_a
end
end
您是否正在尋找像這樣簡單的東西?
def chunkify(max_val,chunk_size);
max_val.downto(1).each_slice(chunk_size) {|chunk| yield chunk.reverse }
end
chunkify(100,10) {|c| puts c.inspect }
#[91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
#[81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
#[71, 72, 73, 74, 75, 76, 77, 78, 79, 80]
#[61, 62, 63, 64, 65, 66, 67, 68, 69, 70]
#[51, 52, 53, 54, 55, 56, 57, 58, 59, 60]
#[41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
#[31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
#[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
#[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#=> nil
正如@SergioTulentsev指出的那樣,這似乎微不足道。
而且,由於SQL並不關心IN()
子句的順序,所以反向操作的效率較低,並且效果與遞減順序相同。
ActiveRecord提供了find_each
方法,可用於加載小批量記錄並在結果集上執行特定操作。
循環遍歷數據庫中的記錄集合(例如,使用all方法)效率很低,因為它將嘗試立即實例化所有對象。
在這種情況下,批處理方法使您可以批量處理記錄,從而大大減少了內存消耗。
find_each
方法使用批處理大小為1000
(或由:batch_size
選項指定)的find_in_batches
。
您可能要向必須遷移的列中添加一個新的布爾字段,以確保您將查詢過濾掉,只查找processed
為假的記錄。 這樣,即使進程由於某種原因而終止,您也可以恢復它,並且它不會從頭開始。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.