Snowflakeでは、組み込み関数だけでは実現できないカスタムロジックをUDF(User Defined Function)とStored Procedure(ストアドプロシージャ)で実装できます。UDFはSELECT文内で値の変換・計算に使用し、Stored ProcedureはCALL文でDDL/DMLを含む複雑な処理フローを実行します。
この記事では、UDFとStored Procedureの比較表・各言語での作成SQL・Vectorized UDF・権限モデル(Caller's Rights / Owner's Rights)を網羅的に解説します。SnowPro Core試験のData Transformationドメインで頻出するトピックです。
UDFとStored Procedureの違いを一覧表で整理します。SnowPro試験では両者の使い分けが頻繁に問われます。
| 比較項目 | UDF | Stored Procedure |
|---|---|---|
| 呼び出し方 | SELECT文内で呼び出し(SELECT my_udf(col)) | CALL文で呼び出し(CALL my_proc()) |
| DDL/DML実行 | 不可(副作用なし) | 可能(CREATE/INSERT/UPDATE/DELETE) |
| 副作用(Side Effect) | なし(Side Effect Free必須) | あり(DB状態変更可能) |
| 返り値 | スカラー値 or テーブル(UDTF) | 単一のスカラー値 |
| GRANT構文 | GRANT USAGE ON FUNCTION | GRANT USAGE ON PROCEDURE |
| 権限モデル | 呼び出し者の権限で実行 | Owner's Rights(デフォルト)/ Caller's Rights |
| トランザクション | 呼び出し元のトランザクション内 | 独自のトランザクション制御可能 |
| 使用場所 | SELECT / WHERE / JOIN / HAVING句 | CALL文のみ(SELECT内では使用不可) |
入力として1つ以上の値を受け取り、単一の値を返します。SELECT句・WHERE句・JOIN条件などあらゆる場所で使用でき、例えば独自のハッシュ関数やビジネスルール計算を定義します。
-- SQL スカラーUDF:税込価格の計算
CREATE OR REPLACE FUNCTION calc_tax_price(price NUMBER, tax_rate NUMBER)
RETURNS NUMBER(12,2)
LANGUAGE SQL
AS
$
price * (1 + tax_rate)
$;
-- 使用例
SELECT product_name, calc_tax_price(price, 0.10) AS tax_included
FROM products;テーブル形式(複数行・複数列)の結果を返す関数です。FROM句でTABLE(my_udtf(args))として呼び出し、1行の入力から複数行を生成する展開処理や、複数行をまたぐ集計に使います。
-- Python UDTF:CSV文字列を行に分割
CREATE OR REPLACE FUNCTION split_csv(csv_string VARCHAR)
RETURNS TABLE(item VARCHAR)
LANGUAGE PYTHON
RUNTIME_VERSION = '3.11'
HANDLER = 'SplitCSV'
AS
$
class SplitCSV:
def process(self, csv_string):
for item in csv_string.split(','):
yield (item.strip(),)
$;
-- 使用例
SELECT t.item
FROM my_table, TABLE(split_csv(my_table.tags)) t;| 言語 | スカラーUDF | UDTF | Vectorized UDF | Stored Procedure | 特徴 |
|---|---|---|---|---|---|
| SQL | ○ | ○ | - | ○(Snowflake Scripting) | 最軽量・外部ランタイム不要 |
| Python | ○ | ○ | ○ | ○ | Snowpark連携・ML/データサイエンス向き |
| JavaScript | ○ | ○ | - | ○ | 歴史的に最初のサポート |
| Java | ○ | ○ | ○ | ○ | JVM上で実行・エンタープライズ向き |
| Scala | ○ | ○ | ○ | ○ | JVM上で実行・Spark経験者向き |
Vectorized UDFはPython UDFの高速バージョンです。通常のスカラーUDFが1行ごとにPython関数を呼び出すのに対し、Vectorized UDFは入力をpandas.Seriesのバッチとして受け取り、ベクトル化演算を行います。大量行の数値計算で5〜50倍のスループット向上が見込めます。
-- Vectorized UDF:pandas.Seriesで受け取りバッチ処理
CREATE OR REPLACE FUNCTION normalize_score(score NUMBER)
RETURNS NUMBER
LANGUAGE PYTHON
RUNTIME_VERSION = '3.11'
PACKAGES = ('pandas')
HANDLER = 'normalize'
AS
$
import pandas as pd
def normalize(score: pd.Series) -> pd.Series:
return (score - score.mean()) / score.std()
$;Snowparkでは@udfデコレータのinput_typesにPandasSeriesを指定することで同等のVectorized UDFを定義できます。
Stored ProcedureはCALL文で呼び出すプログラムロジックで、DDL/DMLの実行・トランザクション制御・条件分岐・例外処理を含む複雑な処理を実装できます。
-- Snowflake Scripting(SQL)Stored Procedure
CREATE OR REPLACE PROCEDURE archive_old_orders(cutoff_date DATE)
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS OWNER
AS
$
BEGIN
INSERT INTO orders_archive
SELECT * FROM orders WHERE order_date < :cutoff_date;
DELETE FROM orders WHERE order_date < :cutoff_date;
RETURN 'Archived orders before ' || :cutoff_date;
EXCEPTION
WHEN OTHER THEN
ROLLBACK;
RETURN 'Error: ' || SQLERRM;
END;
$;
-- 実行
CALL archive_old_orders('2025-01-01');| 比較項目 | Owner's Rights(デフォルト) | Caller's Rights |
|---|---|---|
| 実行権限 | Stored Procedure所有者のロール | 呼び出し者のロール |
| 指定方法 | EXECUTE AS OWNER(デフォルト) | EXECUTE AS CALLER |
| アクセス範囲 | 所有者がアクセス可能なオブジェクト | 呼び出し者がアクセス可能なオブジェクト |
| 権限昇格 | あり(呼び出し者より広い権限で実行可能) | なし(呼び出し者の権限のまま) |
| ユースケース | 制限付きデータ操作・監査ログ記録 | 汎用ユーティリティ・動的SQL |
-- Caller's Rights の指定例
CREATE OR REPLACE PROCEDURE list_tables(db_name VARCHAR)
RETURNS TABLE(table_name VARCHAR)
LANGUAGE SQL
EXECUTE AS CALLER
AS
$
BEGIN
RETURN TABLE(
SELECT table_name FROM information_schema.tables
WHERE table_catalog = :db_name
);
END;
$;Snowpark APIでは@udf・@udtf・@sprocデコレータで関数を定義し、セッション経由でSnowflakeに登録します。
packagesパラメータで指定importsパラメータでアップロードis_permanent=TrueでPermanent UDF/Stored Procedureとして永続化UDF vs Stored Procedure
問題 1
Snowflake Stored ProcedureをEXECUTE AS OWNER(デフォルト)で作成した場合の動作として正しいものはどれですか?
正解: B
Owner's Rights(EXECUTE AS OWNER)はStored Procedureのデフォルトの権限モデルです。プロシージャ内のSQLは所有者(作成したロール)の権限で実行されるため、呼び出し者が直接アクセスできないテーブルでも所有者がアクセス権を持っていれば操作できます。これにより、一般ユーザーに直接のテーブルアクセス権を付与せずに、制御されたビジネスロジック経由でのデータ操作を許可できます。Caller's Rights(EXECUTE AS CALLER)は呼び出し者のロールで実行されるため、権限昇格は発生しません。
UDFとStored Procedureの最大の違いは何ですか?
最大の違いは「呼び出し方」と「副作用の有無」です。UDFはSELECT文の中で組み込み関数と同様に呼び出し、値を返します。DDL/DMLは実行できず副作用なし(Side Effect Free)が求められます。一方、Stored ProcedureはCALL文で呼び出し、CREATE TABLE・INSERT・UPDATE・DELETEなどのDDL/DML実行が可能です。また、UDFは常に呼び出し者の権限で実行されますが、Stored ProcedureにはOwner's Rights(デフォルト)とCaller's Rightsの2つの権限モデルがあり、EXECUTE AS CALLER句で切り替えられます。GRANTの違いとして、UDFにはGRANT USAGE ON FUNCTION、Stored ProcedureにはGRANT USAGE ON PROCEDUREを使います。
Vectorized UDF(Pandas UDF)はどのようなケースで有効ですか?
Vectorized UDFは大量行の数値演算・文字列変換に最も効果的です。通常のスカラーUDFは行ごとにPythonインタープリタを呼び出すため、100万行以上のデータでは関数呼び出しオーバーヘッドが支配的になります。Vectorized UDFは入力をpandas.Seriesのバッチ(デフォルト数千行)で受け取り、NumPy/pandasのベクトル化演算を活用するため、通常のスカラーUDFと比較して5〜50倍のスループット向上が報告されています。CREATE FUNCTION文で_sf_vectorized_inputハンドラーヒントを指定するか、Snowparkの@udf(input_types=[PandasSeries[int]])デコレータで作成します。
Caller's RightsとOwner's Rightsはどう使い分けますか?
Owner's Rights(デフォルト)は、呼び出し者がアクセスできないテーブルをStored Procedure経由で安全に操作させたい場合に使います。例えば、一般ユーザーに直接UPDATE権限を与えずに、特定のビジネスロジックを通じた更新のみ許可するケースです。Caller's Rights(EXECUTE AS CALLER)は、呼び出し者の権限で実行されるため、汎用的なユーティリティプロシージャ(テーブル情報の取得・ログ出力など)に適しています。セキュリティ上、Owner's Rightsでは権限昇格のリスクに注意が必要です。Stored Procedureの所有者ロールのGRANTを最小限にし、CURRENT_ROLE()やIS_ROLE_IN_SESSION()で呼び出し元を検証するパターンが推奨されます。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Snowflake資格一覧|全11試験(SnowPro)の難易度・費用
Snowflake認定資格(SnowPro)全11試験の一覧・難易度・費用・出題範囲を徹底解説。...
Snowflake試験の難易度ランキング|全11資格を徹底比較
Snowflake(SnowPro)認定全11試験の難易度をランキング形式で比較。学習時間・合格に必要なスキルから分析。...
Snowflake資格の勉強方法|効率的な学習ルートと合格のコツ
Snowflake認定資格(SnowPro)に最短で合格するための勉強方法。公式リソース・学習スケジュールを徹底ガイド。...
SnowPro Core試験完全解説|出題範囲・問題例・合格戦略
SnowPro Core Certification(COF-C03)を徹底解説。出題範囲・100問の試験形式・合格ライ...
SnowPro Platform Associate完全解説|入門試験の攻略
SnowPro Associate: Platform Certification(SOL-C01)を徹底解説。最も簡単...