トップ / 基礎知識

UDF・Vectorized UDF・UDTF・ストアドプロシージャの使い分け

Snowflake上でカスタムロジックを実行する4つの手段を、入出力の形とSQLからの呼び出し方で整理します。

スカラUDF1行1つの値Vectorized UDFN行N個の値UDTF1行複数行複数行ストアドプロシージャ表の形にとらわれない条件分岐・ループ・DDL/DMLを実行

この4つは「入出力の形」で区別する

名前が似ていて混同しやすいですが、判断基準は1つです。1行の入力に対して、何を返すか。

1. スカラUDF:1行 → 1つの値 2. Vectorized UDF:複数行のバッチ → バッチ分の値 3. UDTF:1行 → 0行以上の複数行 4. ストアドプロシージャ(SPROC):表の形にとらわれない任意の処理

1. スカラUDF:1行→1つの値

スカラUDFは行ごとに呼び出され、1つの値を返す関数です。SELECT句やWHERE句などのSQL式の中から直接呼び出せます。

from snowflake.snowpark.functions import udf
from snowflake.snowpark.types import IntegerType

@udf(name="celsius_to_fahrenheit", return_type=IntegerType(), input_types=[IntegerType()])
def celsius_to_fahrenheit(celsius: int) -> int:
    return celsius * 9 // 5 + 32

Python UDFの場合、1行ずつPythonの関数を呼び出すため、行数が多いとPythonの呼び出しオーバーヘッドが積み重なります。

2. Vectorized UDF:複数行をまとめて処理

Vectorized UDF(バッチUDF)は、複数行をPandasのSeriesやDataFrameとしてまとめて受け取り、まとめて結果を返す仕組みです。

import pandas as pd
from snowflake.snowpark.functions import udf
from snowflake.snowpark.types import PandasSeriesType, IntegerType

@udf(
    name="batch_double",
    input_types=[PandasSeriesType(IntegerType())],
    return_type=PandasSeriesType(IntegerType()),
    max_batch_size=1000,
)
def batch_double(values: pd.Series) -> pd.Series:
    return values * 2

Snowflake公式ドキュメントは「Vectorized Python UDFは、入力行のバッチをPandas DataFrameとして受け取り、結果のバッチをPandas配列またはSeriesとして返すPython関数を定義できる」と説明しています。1行ずつPythonを呼び出すオーバーヘッドを避けられるため、機械学習の推論のようにバッチ処理に向く場面で特に有効です。

3. UDTF:1行(以上)の入力→複数行の出力

UDTF(ユーザー定義テーブル関数)は、入力に対して0行以上の複数行を出力できる関数です。公式ドキュメントによれば、UDTFのハンドラクラスは行ごとに呼び出されるprocessメソッドを実装し、そこでタプルとして表形式の値をyieldします。

from snowflake.snowpark.functions import udtf
from snowflake.snowpark.types import StructType, StructField, StringType

@udtf(output_schema=StructType([StructField("word", StringType())]))
class SplitWords:
    def process(self, sentence: str):
        for word in sentence.split():
            yield (word,)

SQLのFROM句から呼び出す点がスカラUDFと異なり、1行の文章から複数の単語行への展開のような「表を膨らませる」処理に使います。

4. ストアドプロシージャ:制御フローそのものをパッケージ化

ストアドプロシージャ(SPROC)は、条件分岐・ループ・トランザクション管理・DDL/DMLの実行といった「処理の手順そのもの」をパッケージ化したものです。SQL式の中から呼び出すのではなく、CALL文で独立して実行します。

from snowflake.snowpark.functions import sproc

@sproc(name="archive_old_rows", is_permanent=True, stage_location="@my_stage", replace=True)
def archive_old_rows(session, cutoff_date: str) -> str:
    session.sql(f"INSERT INTO archive SELECT * FROM orders WHERE order_date < '{cutoff_date}'").collect()
    session.sql(f"DELETE FROM orders WHERE order_date < '{cutoff_date}'").collect()
    return "archived"

UDF・UDTFにはできないDDL/DMLの実行が可能な点が大きな違いです。

使い分けの早見表

種類主な目的戻り値SQL式内から直接呼べるかDDL/DMLの実行
スカラUDF行ごとの計算・変換単一の値可能不可
Vectorized UDFバッチ単位の高速演算単一の値(バッチ処理)可能不可
UDTF表構造への展開・変換複数行・複数列可能(FROM句内)不可
ストアドプロシージャパイプライン制御・自動化任意不可(CALL文)可能

で、どれを選べばいいか

Polarsはローカルで動くライブラリなので、この4分類そのものが存在しません。Polarsで「カスタムロジック」というと、map_elementsのようなメソッドにPython関数を渡す形が中心で、SQLエンジン側にプッシュダウンして実行させるという概念がそもそもありません。

出典

公式ドキュメントの記載にもとづく解説です(実行検証はしていません)。確認日:2026-08-27