我有一個 n8n 工作流程,可以從 API 拉取數千筆記錄、轉換它們,然後將結果寫入資料庫。
它在較小的資料集上運作良好,但當 API 傳回數萬筆記錄時,執行會變得非常緩慢,有時甚至會崩潰,因為太多資料被保存在記憶體中。
我目前正在考慮以較小的批次處理資料:const batchSize = 100;
return $input.all().slice(0, batchSize);
你會建議使用批次處理、分頁、串流、子工作流程,或這些的組合來保持低記憶體使用量,同時仍保持良好的效能和可靠性嗎?
描述問題/錯誤/問題
錯誤訊息是什麼(如有的話)?
請分享你的工作流程
(在畫布上選取節點,並使用鍵盤快捷鍵 CMD+C/CTRL+C 和 CMD+V/CTRL+V 來複製和貼上工作流程。)
分享最後一個節點傳回的輸出
關於你的 n8n 設定的資訊
- n8n 版本:
- 資料庫(預設值:SQLite):
- n8n EXECUTIONS_PROCESS 設定(預設值:own、main):
- n8n 執行方式(Docker、npm、n8n cloud、桌面應用程式):
- 作業系統:
你好 @Catherine
對於大型資料集,我會避免將所有內容載入到單一 n8n 執行中。我會使用分頁 + 批處理,並在需要時將較重的處理移至子工作流程中
例如:
const batchSize = 100;
const items = $input.all();
return items.slice(0, batchSize);
理想情況下,API 或資料庫應該處理分頁,而不是下載 50,000 筆記錄然後事後切片。
與其提出一個龐大的請求,不如使用 HTTP Request 節點的內建分頁。
在 HTTP Request 節點中,前往 新增選項 > 分頁。根據您的 API 是否使用「位移/限制」、「頁碼」或「遊標」來設定。
@Emmas 將較繁重的處理移至子工作流程的做法也是對的
嗨 @Catherine 歡迎!
分頁不會降低您的記憶體用量。文件將其描述為用於 API 無法在一次呼叫中返回的過大結果,它會將每一頁都抓取到節點的輸出中,因此 50,000 筆記錄仍然會在該執行中保持活躍。它解決的是 API 的限制,而不是崩潰。
在同一工作流程中進行批次處理也不會釋放記憶體,因為 n8n 會在整個執行過程中保留每個節點的輸出。釋放記憶體的方法是使用「Execute Workflow」將每批工作移到子工作流程中,並僅返回一個小結果,因為子工作流程的資料會在每批完成後立即消失。
另外,$input.all().slice(0, batchSize) 不是批次處理。它保留前 100 個項目並丟棄其餘的。
你需要在源頭處理分頁問題。$input.all() 被使用的事實是關鍵。該命令已經在 slice() 運行之前將所有項目加載到記憶體中,所以從長遠來看不會真正有幫助。
嘗試在迴圈內使用你的 API 分頁參數(page/offset 或 cursor),這樣你每次只會提取一頁,然後將每一頁透過「Loop Over Items」(Split In Batches)進行轉換和寫入步驟。這樣可以保持記憶體使用量固定,無論總記錄數有多少。
如果你的轉換步驟較重,嘗試將其卸載到子工作流。使用子工作流時,每次執行都會獲得自己的記憶體上下文,在完成時會被釋放;這對大規模運行很有幫助。N8n 在節點之間沒有真正的串流,所以最好在這裡使用子工作流和分頁組合。