2016-07-04 56 views
1

我正在尋找一個很好的慣用導軌模式或寶石來處理效率低的問題after_commit模型回調。我們希望堅持一個回調來保證數據的完整性,但是我們希望它運行一次,無論是一條記錄還是一批交易中包裝的記錄。批量ActiveRecord? after_commit產生O(n)麻煩

這裏有一個用例:

一個Portfolio有許多positions

Position有一個after_commit掛鉤重新計算數字參考其在投資組合中的兄弟位置。

這可以直接編輯一個位置。

但是...

還有我們現在有進口商爲一個大INSERT帶來了大量的職位涵蓋多種資產組合。因此,每次調用這個回調函數都會查詢所有兄弟節點,並且每個兄弟節點都會調用一次 - 所以讀取操作是O(n ** 2)而不是O(n),而寫入操作是O(n),它們應該是O(1)。

'爲什麼不只是把回調放在家長組合上?'因爲在相關更新期間父母不一定會感動。我們不能冒險出現類似這樣的缺口可能導致的那種不一致的狀態。

有沒有什麼有它可以利用我們在交易中一次提交所有記錄的事實?原則上,找出哪些記錄發生了變化應該不會太難。

一個很好的界面可能會像after_batch_commit這可能提供一個光對象與所有更改的數據或至少受影響的行的ID。

我們的應用程序中有很多不相關的部分需要這樣的解決方案。

回答

0

一個解決方案可以將它們全部插入到一個SQL語句中,然後再驗證它們。

這篇文章中提出了將它們插入到單個語句中的可能方法。

INSERT multiple records using ruby on rails active record

或者你甚至可以生成SQL插入所有記錄在一個訪問數據庫。

的代碼可能是這個樣子:

max_id = Position.maximum(:id) 
Postion.insert_many(data) # not actual code 
faulty_positions = Position.where("id > ?", max_id).reject(&:valid?) 
remove_and_or_log_faulty_positions(faulty_positions) 

這樣,你只需要有每N個條目三次觸及該數據庫中的數據。如果是大型數據集,則可以按照您提到的方式批量執行。

+0

我在說的是類似於驗證,但更多的是做比檢查。 @我們已經用bulk_import gem做了一個大插入。關鍵是我們已經有了代碼來保證這個工作在'after_commit'回調中完成。要再次編寫該代碼,但批處理插入案例略有不同,看起來太難看了,因爲沒有更好的解決方案。此外,還有一種情況是通過表單批量編輯。 – Adamantish

+0

但是我的建議不適用於這種情況嗎?只需將'.reject(&:valid?)'改爲'.each(&:doing_method)'並跳過刪除和記錄步驟? – Albin

+0

這不是一個關於如何確保在批處理作業之後或之前完成工作的問題。我們已經這樣做了。這是關於將過程強化爲模型回調,以保證數據完整性並使其幹掉,但沒有大規模的低效率。 – Adamantish