上一篇把多個 saved Analysis 放進 Workflow,一次平行執行。
第一次跑 7 個 Analysis 時,Workflow 總共花了 51 秒。
但每個 script 本身其實只有 0.8–1.5 秒,7 個 Analysis 加起來的 CPU time 也只有 7 秒。
所以這篇要回答的是:
時間到底花在哪裡?
對每個 Analysis Run,我記錄:
queued_at
sandbox_at
script started_at
finished_at
因此一次 run 可以拆成幾個 phase:
Waiting / Sandbox Startup
→ Moving Data
→ Script
→ Moving Output
Script 執行期間另外每 0.1 秒 sample memory 和 CPU。
這些資料會顯示在 Workflow 的 Performance Page,Report 看結果,Performance 看 execution cost。
原本 7 個 Analysis 的 Workflow:

Performance Page 很快就指出真正的 bottleneck:
原本的 sandbox usage 也很明顯:

7 個 Analysis,最後開了 7 個 sandbox。
問題不是 computation 太慢,而是 execution overhead 太高。
第一個改動是不要每個 Analysis 都重新開 sandbox。
Workflow 改成固定數量的 Lane。
目前一個 account 最多 3 個 sandbox,Workflow 使用 2 個,另外保留 1 個給 Chat。
Lane 1: A → C → E → G
Lane 2: B → D → F
兩條 Lane 平行執行,同一條 Lane 裡的 Analysis 則依序 reuse sandbox。
每次換 Analysis 前會:
如果 sandbox OOM 或 cleanup 失敗,就不 reuse,直接換新的。
除了 reuse sandbox,還做了幾個調整:
needs_optimization 的 node 擋掉,不浪費 sandbox小 Analysis 如果 inputs + script <= 48 KB,現在甚至可以在一次 sandbox call 裡完成 setup、execute 和 small output return。
同樣 7 個 Analysis,最後變成:
| Before | After | |
|---|---|---|
| Total | 51s | 16s |
| Sandboxes started | 7 | 2 |
| Workflow Execution | new sandbox per Analysis | 2 reusable lanes |
| Script CPU | ~7s | ~7s |
| Highest peak memory | ~204 MB | ~205 MB |

Sandbox usage 也從每個 Analysis 一個 sandbox:

變成兩條 reusable lanes:

Optimization 也不是一次完成的:
Rebalancing 之後,sandbox startup 已經不再是最大問題。
16 秒這次 Run 剩下比較明顯的是:
Median Session Length 等 database query 約 5.1s
我也試過替 events_enterprise(event_time) 加 index,但 query 本身會保留大量 rows 再 aggregation,實際改善很小,所以最後拿掉。
這次比較明顯的一件事是:
Performance optimization 不是先決定要改哪裡,而是先 measure,再找下一個 bottleneck。
從 51 秒到 16 秒,Analysis recipe 幾乎沒有變。
真正改的是 Workflow 的 execution strategy。