は、 上で Python などのコードを実行できる仕組みです。データを外に出さずに処理できます。
便利ですが、SQL で書ける処理をあえて置き換える理由は薄いというのが率直な評価です。この回は線引きを扱います。
1. SQL のままにすべき理由
同じ処理を SQL で書けるなら、SQL のほうが有利な点がいくつもあります。
- 他のツールと連携しやすい — をはじめ、SQL を前提とした道具が多い
- 読める人が多い — 分析担当も含めてレビューできる
- 実行計画が確認できる — 遅いときに原因を追いやすい
- 移植性がある — 別の基盤へ移すときの負担が小さい
- 変換の系譜を追える — どの表からどう作られたかが機械的に辿れる
5番目は運用で効きます。SQL で書かれていれば、どの表がどこから作られたかを機械的に把握できます。コードの中に処理が入ると、この追跡が難しくなります。数値の出どころを問われたとき、SQL なら定義を辿れば答えられますが、コードの中で加工されていると読み解く作業が必要になります。運用が長くなるほど、この差は効いてきます。
書き手にとっての書きやすさは、読み手にとっての読みやすさとは別です。数年運用する処理では、後から読む人の人数のほうが効いてきます。判断は書きやすさではなく、SQL で表現できるかどうかで行ってください。
2. 使うべき場面
では、どういうときに使うのか。SQL では表現しにくい、あるいは表現すると極端に読みにくくなる処理です。
| 処理 | SQL で書けるか | 判断 |
|---|---|---|
| 集計・結合・絞り込み | 書ける | SQL のまま |
| 窓関数を使った順位や累計 | 書ける | SQL のまま |
| 複雑な文字列処理 | 書けるが読みにくい | 場合による |
| 機械学習の推論 | 書けない | 使う |
| 外部ライブラリを使う処理 | 書けない | 使う |
| 行ごとの複雑な条件分岐 | 書けるが極端に読みにくい | 使う価値がある |
4行目と5行目が本来の用途です。既存のライブラリを使いたい、学習済みのモデルで推論したい ── こうした処理は SQL では表現できません。そしてデータを外に出さずに実行できるという点が、ここで決定的に効きます。逆に言えば、この2つに当てはまらないなら、わざわざ選ぶ理由はほとんどありません。
3. データを持ち出さないという価値
最も強い選定理由は、データを外に出さずに処理できることです。持ち出しに制約があるデータでは、これが決め手になります。
従来は、処理のためにデータを取り出し、別の環境で計算し、結果を書き戻す必要がありました。この経路には持ち出しの承認、転送中の保護、取り出した先の管理という手当てが必要です。それが不要になります。
from snowflake.snowpark import Sessionfrom snowflake.snowpark.functions import col, when
def classify_orders(session: Session) -> None: """データを手元に取り出さず、基盤側で処理して書き戻す。""" df = session.table("prod.analytics.fct_orders")
classified = df.with_column( "size_class", when(col("amount") >= 100_000, "large") .when(col("amount") >= 10_000, "medium") .otherwise("small"), )
# 結果も基盤側に書く。ネットワークを経由するのは指示だけ classified.write.mode("overwrite").save_as_table( "prod.analytics.fct_orders_classified" )ただし、この例の処理は SQL でも書けます。あえて例として挙げたのは、書けるものを書き換えても得るものが少ないことを示すためです。この程度なら SQL のほうが適切です。
4. 制約を先に確認する
採用を検討する際、先に制約を確認してください。後から判明すると設計のやり直しになります。
- 1使えるライブラリ — 任意のものが使えるわけではない。必要なものが揃うか
- 2外部通信の可否 — 外に出られるか、出られる場合の設定はどうか
- 3実行時間の上限 — 長時間の処理が想定どおり動くか
- 4利用できる資源 — メモリの上限で処理が収まるか
- 5運用の方法 — どう配置し、どう更新し、どう権限を管理するか
5番目が見落とされがちです。開発時は動いても、運用に載せる段になって困るというのはよくある形です。誰がどう更新するのか、テストはどう回すのか。SQL なら既存の仕組みに乗りますが、コードは別の管理が要ります。
制約の確認は、資料を読むより実際に小さいものを動かすほうが速く確実です。必要なライブラリが読み込めるか、想定する規模で時間内に終わるか。1日使って試す価値があります。
5. テストをどうするか
SQL からコードに移ると、検証の方法も変わります。これは利点でもあり、負担でもあります。
利点は、通常の単体テストが書けることです。LLM時代のテスト戦略 EP.02 で扱ったとおり、純粋な関数として切り出せる部分は普通にテストできます。
# 基盤に依存しない純粋な判定ロジックとして切り出すdef size_class(amount: int) -> str: if amount >= 100_000: return "large" if amount >= 10_000: return "medium" return "small"
def test_size_class_boundaries(): # 境界値を明示的に確認する assert size_class(9_999) == "small" assert size_class(10_000) == "medium" assert size_class(99_999) == "medium" assert size_class(100_000) == "large"判定ロジックを基盤から切り離すのが要点です。切り離せば、基盤に接続せずに境界値を確認できます。逆に、処理と基盤の操作が絡み合っていると、検証のたびに実際のデータが必要になり、テストが重くなります。
一方で負担もあります。SQL なら dbt のテスト機構に乗りますが、コードは別の仕組みを用意することになります。既存の検証の流れに乗らない処理が増えることは、それ自体がコストです。
6. 判断の整理
この回の結論をまとめます。既定は SQL、例外的に使うというのが基本姿勢です。
| 問い | 答え | 判断 |
|---|---|---|
| SQL で表現できるか | できる | SQL のまま |
| SQL で表現できるか | できない | 次の問いへ |
| データを外に出せるか | 出せない | 使う(最も強い理由) |
| データを外に出せるか | 出せる | 既存の処理環境も選択肢に入る |
| 運用の仕組みを用意できるか | できない | 採用しない。運用できない処理は負債になる |
最下行を軽視しないでください。動かせることと、運用できることは別です。作った人しか触れない処理が基盤の中に増えると、エンジニア引き継ぎ で扱うような問題に直結します。
既定は SQL のまま。他ツールとの連携・読める人の多さ・系譜の追跡で有利だから。使うべきは SQL で表現できない処理(外部ライブラリ、機械学習の推論)で、データを持ち出さずに済むという点が最も強い理由になる。採用前にライブラリ・資源・運用方法を小さく試して確認し、運用の仕組みを用意できないなら採用しない。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。