数据提供方如何统计Snowflake共享安全UDF调用时的输出表规模
Snowflake 共享UDTF细粒度用量统计方案
原生能力边界
Snowflake 自带的共享使用审计能力只能到查询维度,做不到单UDTF调用的细粒度统计:
- 你可以在提供方账号的
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY视图里,查到所有消费者账号发起的、调用你共享安全函数的查询记录,能拿到整个查询的返回行数、执行时长、消费者账号ID、执行时间等信息,但如果单条查询里多次调用你的UDTF,原生视图无法拆分出每次UDTF调用单独的输出行数。 - 原生审计日志不会记录UDTF的入参值,没法直接统计输入参数的规模。
自定义实现细粒度统计的可行方案
安全UDTF的执行逻辑完全运行在提供方的计算上下文里,消费者看不到函数实现细节,你可以通过改写UDTF为支持自定义处理逻辑的多语言UDTF(Python/Java/Scala均可),结合Snowflake原生的事件日志能力实现统计,全程不需要消费者做任何配置,统计数据只有提供方能访问。
实现步骤
- 首次配置需要先在你的提供方账号创建事件表,用来存储UDTF运行时输出的日志,消费者完全没有该表的访问权限:
-- 仅需执行一次 CREATE EVENT TABLE IF NOT EXISTS <DB>.<SCHEMA>.UDTF_USAGE_EVENTS; ALTER ACCOUNT SET EVENT_TABLE = <DB>.<SCHEMA>.UDTF_USAGE_EVENTS;
- 将你原来的SQL UDTF改写为Python安全UDTF,在处理逻辑里累计返回行数、记录入参,在单轮调用结束时把统计信息写入日志:
CREATE OR REPLACE SECURE FUNCTION CLIENT_ACCESS (INPUT_RECORDID STRING, INPUT_LOOKUP INTEGER) RETURNS TABLE (RECORDID STRING, LOOKUP INTEGER, SENSITIVE_DATA STRING) LANGUAGE PYTHON RUNTIME_VERSION = '3.10' HANDLER = 'AccessUDTF' PACKAGES = ('snowflake-snowpark-python') EXECUTE AS OWNER AS $$ import logging logger = logging.getLogger("udtf_usage_tracker") class AccessUDTF: def __init__(self): self.row_count = 0 self.param_recordid = None self.param_lookup = None def process(self, INPUT_RECORDID, INPUT_LOOKUP): # 记录入参 self.param_recordid = INPUT_RECORDID self.param_lookup = INPUT_LOOKUP # 替换为你实际的业务查询逻辑 res = session.sql(""" SELECT %s AS RECORDID, LOOKUP, SENSITIVE_DATA FROM <DB>.<SCHEMA>.SHARED_DATA WHERE LOOKUP = %s """, (INPUT_RECORDID, INPUT_LOOKUP)).collect() # 逐行返回结果并计数 for row in res: self.row_count += 1 yield (row.RECORDID, row.LOOKUP, row.SENSITIVE_DATA) def end_partition(self): # 单轮调用结束,写入统计日志 logger.info(f"CALL_STAT|input_recordid={self.param_recordid}|input_lookup={self.param_lookup}|return_rows={self.row_count}") $$;
- 后续你只需要定时查询
UDTF_USAGE_EVENTS表,解析日志字段就能拿到每一次UDTF调用对应的入参值、返回行数,还可以结合日志里自带的调用时间、会话信息关联出消费者账号、调用IP等信息,完全满足你要的统计粒度。
注意事项
- Snowflake禁止UDF/UDTF执行DML修改数据,不要尝试在UDTF内直接执行INSERT语句写入统计表,会直接抛出运行时错误,事件表日志是官方支持的合法副作用输出方式。
- 如果你更熟悉Java/Scala,也可以用对应语言实现UDTF,逻辑完全一致,都是在分区处理的终结阶段输出统计日志。
- 如果需要区分不同消费者的调用,可以在process方法里查询
CURRENT_ACCOUNT()、CURRENT_ROLE()等上下文函数,把对应信息一起打到日志里即可。 - 如果需要实时统计,可以给事件表配置Snowpipe Stream和定时任务,自动解析日志写入结构化的用量统计表,直接对接可视化看板即可。
- 因为是安全UDTF,所有统计逻辑对消费者完全不可见,不存在被绕过的风险。
内容的提问来源于stack exchange,提问作者ConnorOSully
相关产品推荐
相关产品推荐

