質問
DataFusion 53はget_fieldのような式をデータソースへプッシュダウンできます。結果を変更することなく、I/Oとデコードコストの低減を証明するために、クエリ、プラン、ベンチマークをどのように設計しますか?
前提条件とスコープ
Parquetテーブルに幅の広いstruct列sが存在し、クエリはs['label']のみを必要とし、s['value']でフィルタリングを行うと仮定します。バッチスキャン、統計情報、NULL、スキーマ進化、およびプッシュダウンが適用されない場合の安全なフォールバックを網羅してください。「プランにプロジェクションが表示されている」ことをエンドツーエンドの証拠として扱わないでください。
面接官が見ているポイント
評価されるスキルは、意味的な正確性、プランの書き換え、データソースの機能、および観測可能なメリットを明確に区別することです。DataFusion 53は、struct全体を読み取る必要がないように、ネストされたフィールドアクセスをスキャン処理の近くへと移動させます。その設定ドキュメントでは、enable_leaf_expression_pushdownがフィルタ、ソート、または結合式からget_fieldを抽出し、リーフノードに向けてプッシュダウンすることが説明されています。
まず以下の点を確認してください:
- ソースはフィールドレベルのプロジェクションをサポートしているか、またファイル形式はParquetか?
s['label']およびs['value']の型、NULLセマンティクス、および欠損フィールドのルールは何か?- ベースラインは、最適化の無効化、古いDataFusionバージョン、またはstruct全体を読み取るクエリのどれか?
- 比較の主眼は、スキャンバイト数、デコードCPU、ピークメモリ、レイテンシ、またはオブジェクトストレージへのリクエスト数のどれに置くべきか?
30秒の回答要約
ネストされたプロジェクションとフィルタリングを含むSQLから始めます。次に、最適化の前後の論理プラン、物理プラン、およびParquetリーダーのプロジェクションを比較します。最後に、同一のデータ、キャッシュ状態、同時実行性を用いて、スキャンバイト数、デコード時間、ピークメモリ、結果の検証を測定しつつ、フォールバックすべき状況を明示します。
詳細な解説
- データの作成:structの幅、NULL率、フィールドの選択性を制御しながら、同一のパーティション、行グループ、統計情報を持つParquetファイルを作成します。
- ベースラインの定義:struct全体の読み取り、プッシュダウンの無効化、およびリーフフィールドの読み取りに対して、DataFusionバージョン、スレッド数、オブジェクトストレージのレイテンシ、キャッシュ状態を一定に保ちます。
- プランの検証:
get_fieldがスキャンの近くに配置され、プロジェクションにid、s.label、およびフィルタフィールドs.valueのみが含まれていることを確認します。SQLテキストのみでは不十分です。 - ソースの観測:読み取られたParquetの列、行グループのプルーニング、取得バイト数、デコードバッチを記録し、プロジェクションのメリットと述語のメリットを分離します。
- 結果の確認:ソートされたハッシュまたは行を比較し、欠損フィールド、NULL、型の変更、空のstruct、重複行を網羅します。
- フォールバックの定義:ソースにフィールドプッシュダウン機能がない場合、書き換えが安全でない場合、またはメリットが閾値を下回る場合は、正確なフル読み取りパスを維持し、その理由を記録します。
模範解答
1つの固定されたParquetデータセットから3つのベースラインを作成します。完全なsの読み取り、enable_leaf_expression_pushdownの無効化、そしてリーフフィールドを選択しながら最適化を有効化することです。クエリは次のとおりです:
SELECT id, s['label']
FROM events
WHERE s['value'] > 150;論理プランと物理プランを保存し、get_fieldがスキャンの近くに配置され、スキャンのプロジェクションにsのすべてが含まれなくなっていることを確認します。コールドキャッシュとウォームキャッシュで複数回実行し、読み取りバイト数、オブジェクトストレージのリクエスト数、ParquetデコードCPU、ピークメモリ、エンドツーエンドのレイテンシ、および出力行数を記録します。安定したソート済みハッシュを完全なstructのベースラインと比較し、NULL、欠損フィールド、新旧のスキーマを明示的に網羅します。ソースがフィールドを射影できない場合は、見た目の良いプランのために正確性を犠牲にするのではなく、フル読み取りを維持してメトリクスを出力します。本番展開の前には、スキャンバイト数と結果ハッシュをリグレッションの判定基準とします。
よくある落とし穴
- キャッシュ、同時実行性、ファイルレイアウトを制御せずに、エンドツーエンドのレイテンシのみを比較すること。
- フィールドプロジェクション、述語プッシュダウン、行グループプルーニングを、説明のない単一の数値に合算してしまうこと。
- 通常の値のみをテストし、NULL、欠損フィールド、スキーマ進化を無視すること。
- リーダーが実際に消費した列やバイト数を確認せずに、書き換えられたプランのみを見て成功と判断すること。
- 正確性を最優先するフォールバックを維持せず、プッシュダウンが失敗した際に無理に書き換えを強制すること。
優れた回答は、SQL、プラン、ソース、メトリクスを結びつけ、再現可能なベースラインと結果確認を提供し、要因の特定とフォールバックについて説明します。不十分な回答は、実験の対照条件や正確性の証拠を示すことなく、「プロジェクションプッシュダウンの方が高速である」と述べるにとどまります。
想定される追加質問
リーフフィールドの読み取りでもメリットが見られない場合があるのはなぜですか?
ファイルが行指向である、structが物理的に分離できない、オブジェクトストレージへのリクエストが支配的である、あるいはソースがフィールドプロジェクションを実装していない可能性があります。プランだけでなく、実際のバイト数とデコード時間を検査してください。
s['value']の大部分がNULLである場合、結果をどのように担保しますか?
まずSQLのNULLと型のセマンティクスを修正し、その上でフル読み取りのベースラインと行を比較します。最適化によって不要なフィールドを回避することは可能ですが、NULLを欠損やエラーとして扱ってはなりません。
ネストされたフィールドが追加された後、古いファイルはどうなりますか?
リーダーはフィールドを名前で解決し、古いファイルに対して定義されたNULLまたはデフォルトのセマンティクスを適用する必要があります。ベンチマークには新旧両方のファイルを含め、結合されたスキャンを検証する必要があります。
面接チェックリスト
一言まとめ
プランの配置、実際のスキャン動作、結果の同等性、およびソースが最適化できない場合の安全なフォールバックを検証することで、プッシュダウンを証明します。