資料工程面試:如何驗證 DataFusion 巢狀欄位下推真的降低掃描成本?
題目
DataFusion 53 可以把 get_field 這類表達式下推到資料源。你如何設計查詢、執行計畫和基準,證明它減少 I/O 與解碼成本且不改變結果?
場景與適用邊界
假設 Parquet 表含有寬大的 struct 欄位 s,查詢只需要 s['label'] 並用 s['value'] 過濾。回答要涵蓋批次掃描、統計資訊、Null、Schema 演進和下推不生效時的回退;不要把「計畫出現 projection」直接當成端到端收益。
面試官考察點
考察你能否把優化拆成語意正確性、計畫改寫、資料源能力和可觀測收益四層。DataFusion 53 將巢狀欄位存取推近掃描節點,避免讀取整個 struct;設定文件說明 enableleafexpressionpushdown 會把 getfield 從過濾、排序或連接表達式提取到更靠近葉節點的位置。
回答前可以先確認:
- 資料源是否支援欄位級投影,檔案格式是否為 Parquet?
s['label']和s['value']的型別、Null 語意及缺失欄位如何定義?- 基線是關閉優化、舊版 DataFusion,還是讀取整個 struct 的手寫查詢?
- 需要比較掃描位元組、解碼 CPU、峰值記憶體、延遲,還是雲端儲存請求數?
30 秒回答框架
先給出帶巢狀欄位投影和過濾的 SQL;再說明如何比較優化前後邏輯計畫、實體計畫和 Parquet reader 的投影;最後用相同資料、快取狀態和並行度測量掃描位元組、解碼時間、峰值記憶體及結果校驗,並說明何時回退。
分步驟深入解答
- 建構資料:產生相同分割、行群組和統計資訊的 Parquet 檔案,控制 struct 寬度、Null 比例和欄位選擇性。
- 定義基線:固定 DataFusion 版本、執行緒數、物件儲存延遲和快取狀態,分別執行關閉下推、讀取完整 struct、只讀葉欄位三組查詢。
- 驗證計畫:確認
get_field位於掃描附近,投影只包含id、s.label和過濾所需的s.value;不能只看 SQL 文字。 - 觀察資料源:記錄 Parquet 讀取欄位、行群組裁剪、讀取位元組和解碼批次,區分欄位投影收益與謂詞下推收益。
- 校驗結果:對結果做排序後的雜湊或逐行比較,涵蓋缺失欄位、Null、型別變化、空 struct 和重複列。
- 設定回退:資料源不支援欄位下推、計畫無法安全改寫或收益低於門檻時,保留正確的完整讀取路徑並記錄原因。
高品質示範回答
我會先用固定的 Parquet 資料集建立三組基線:讀取完整 s、關閉 enableleafexpression_pushdown,以及開啟優化並查詢葉欄位。查詢如下:
SELECT id, s['label']
FROM events
WHERE s['value'] > 150;接著保存邏輯和實體計畫,確認 get_field 被推到掃描節點附近,掃描投影不再包含整個 s。基準在冷快取和熱快取各跑多輪,記錄讀取位元組、物件儲存請求、Parquet 解碼 CPU、峰值記憶體、端到端延遲和輸出列數。結果用穩定排序後的雜湊與完整 struct 基線比較,專門涵蓋 Null、缺失欄位和新舊 Schema。若資料源不支援欄位級投影,我會保留完整讀取並發出指標,而不是為了計畫好看犧牲正確性。上線前把掃描位元組和結果雜湊加入回歸門檻。
常見錯誤
- 只比較端到端延遲,沒有控制快取、並行和檔案布局。
- 把欄位投影、謂詞下推和行群組裁剪混成一個收益數字。
- 只驗證正常值,忽略 Null、缺失欄位和 Schema 演進。
- 看到計畫改寫就宣布優化成功,沒有檢查 reader 實際讀取的欄位和位元組。
- 下推失敗時強行改寫結果,缺少正確性優先的回退路徑。
評估時看能否連接 SQL、計畫、資料源和指標四層,給出可重現基線與結果校驗,明確收益歸因和回退條件。一般回答只說「投影下推會更快」,沒有實驗控制或正確性證據。
追問及應對
為什麼讀取葉欄位可能仍然沒有收益?
檔案可能按列儲存、struct 未被實體拆分、物件儲存請求成為瓶頸,或資料源沒有實作欄位級投影。要看實際讀取位元組和解碼時間,不能只看計畫。
如果 s['value'] 大多為 Null,如何避免改變結果?
先固定 SQL 的 Null 語意和型別規則,用完整讀取基線逐列比較;優化只能減少不需要的欄位讀取,不能把 Null 當成缺失或錯誤值。
Schema 新增巢狀欄位後,舊檔案怎麼辦?
讀取器應按欄位名稱和預設值解析舊檔案,缺失欄位保持定義的 Null 或預設語意;基準必須同時包含舊、新檔案,並驗證合併掃描結果。
面試作答要點
一句話總結
證明下推優化要同時驗證計畫位置、實際掃描、結果一致性和不可用時的安全回退。