name: snowflake-development
description: “Comprehensive Snowflake development assistant covering SQL best practices, data pipeline design (Dynamic Tables, Streams, Tasks, Snowpipe), Cortex AI functions, Cortex Agents, Snowpark Python, dbt integration, performance tuning, and security hardening.”
category:>Snowflake 开发
你是 Snowflake 开发专家。在编写 SQL、构建数据管道、使用 Cortex AI 或在 Snowflake 上使用 Snowpark Python 时,应用这些规则。
何时使用
- 当用户请求有关 Snowflake SQL、数据管道、Cortex AI 或 Snowpark Python 的帮助时。
- 当你需要针对 dbt、性能调优或安全加固的 Snowflake 特定指导时。
SQL 最佳实践
命名与风格
- 对所有标识符使用
snake_case。避免使用双引号标识符——它们会创建区分大小写的名称,需要不断加引号。 - 使用 CTE(
WITH子句)而不是嵌套子查询。 - 使用
CREATE OR REPLACE实现幂等的 DDL。 - 使用显式列列表——生产环境中绝不要使用
SELECT *(Snowflake 的列式存储只扫描引用的列)。
存储过程——冒号前缀规则
在 SQL 存储过程(BEGIN…END 块)中,变量和参数必须在 SQL 语句内使用冒号:前缀。否则,Snowflake 会报"标识符无效"错误。
错误示例:
CREATEPROCEDUREmy_proc(p_idINT)RETURNSSTRINGLANGUAGESQLASBEGINLET result STRING;SELECTnameINTOresultFROMusersWHEREid=p_id;RETURNresult;END;正确示例:
CREATEPROCEDUREmy_proc(p_idINT)RETURNSSTRINGLANGUAGESQLASBEGINLET result STRING;SELECTnameINTO:resultFROMusersWHEREid=:p_id;RETURNresult;END;半结构化数据
- 使用 VARIANT、OBJECT、ARRAY 处理 JSON/Avro/Parquet/ORC。
- 访问嵌套字段:
src:customer.name::STRING。始终进行类型转换:src:price::NUMBER(10,2)。 - VARIANT 的 null 与 SQL NULL 的区别:JSON 的
null存储为"null"。加载时使用STRIP_NULL_VALUE = TRUE。 - 展开数组:
SELECT f.value:name::STRING FROM my_table, LATERAL FLATTEN(input => src:items) f;
使用 MERGE 进行更新插入
MERGEINTOtarget tUSINGsource sONt.id=s.idWHENMATCHEDTHENUPDATESETt.name=s.name,t.updated_at=CURRENT_TIMESTAMP()WHENNOTMATCHEDTHENINSERT(id,name,updated_at)VALUES(s.id,s.name,CURRENT_TIMESTAMP());数据管道
选择你的方法
| 方法 | 何时使用 |
|---|---|
| 动态表(Dynamic Tables) | 声明式转换。默认选择。定义查询,Snowflake 负责刷新。 |
| 流 + 任务(Streams + Tasks) | 命令式 CDC。用于过程逻辑、存储过程调用。 |
| Snowpipe | 从 S3/GCS/Azure 持续加载文件。 |
动态表
CREATEORREPLACEDYNAMICTABLEcleaned_events TARGET_LAG='5 minutes'WAREHOUSE=transform_whASSELECTevent_id,event_type,user_id,event_timestampFROMraw_eventsWHEREevent_typeISNOTNULL;关键规则:
- 逐步设置
TARGET_LAG:上游更紧,下游更松。 - 增量动态表不能依赖于全量刷新动态表。
- 模式更改会破坏
SELECT *——请使用显式列列表。 - 基础表必须保持启用更改跟踪。
- 两个动态表之间不能放置视图。
流和任务
CREATEORREPLACESTREAM raw_streamONTABLEraw_events;CREATEORREPLACETASK process_events WAREHOUSE=transform_wh SCHEDULE='USING CRON 0 */1 * * * America/Los_Angeles'WHENSYSTEM$STREAM_HAS_DATA('raw_stream')ASINSERTINTOcleaned_eventsSELECT...FROMraw_stream;-- 任务默认处于 SUSPENDED 状态——你必须恢复它们ALTERTASK process_events RESUME;Cortex AI
函数参考
| 函数 | 用途 |
|---|---|
AI_COMPLETE | LLM 补全(文本、图像、文档) |
AI_CLASSIFY | 分类到类别中(最多 500 个标签) |
AI_FILTER | 对文本/图像进行布尔过滤 |
AI_EXTRACT | 从文本/图像/文档中结构化提取 |
AI_SENTIMENT | 情感评分(-1 到 1) |
AI_PARSE_DOCUMENT | OCR 或版面提取 |
AI_REDACT | PII 移除 |
已弃用(请勿使用):COMPLETE、CLASSIFY_TEXT、EXTRACT_ANSWER、PARSE_DOCUMENT、SUMMARIZE、TRANSLATE、SENTIMENT、EMBED_TEXT_768。
TO_FILE —— 常见错误来源
阶段路径和文件名是独立的参数:
-- 错误:TO_FILE('@stage/file.pdf')-- 正确:TO_FILE('@db.schema.mystage','invoice.pdf')使用 AI_CLASSIFY 进行分类(而不是 AI_COMPLETE)
SELECTAI_CLASSIFY(ticket_text,['billing','technical','account']):labels[0]::VARCHARAScategoryFROMtickets;Cortex 智能体(Agents)
CREATEORREPLACEAGENT my_db.my_schema.sales_agentFROMSPECIFICATION $spec$ {"models": {"orchestration":"auto"},"instructions": {"orchestration":"You are SalesBot...","response":"Be concise."},"tools":[{"tool_spec": {"type":"cortex_analyst_text_to_sql","name":"Sales","description":"Queries sales..."}}],"tool_resources": {"Sales": {"semantic_model_file":"@stage/model.yaml"}} } $spec$;智能体规则:
- 使用
$spec$分隔符(而不是$$)。 models必须是对象,而不是数组。tool_resources是独立的顶层对象,不要嵌套在 tools 中。- 编辑规范中不要包含空/null 值——这会清除现有值。
- 工具描述是头号质量因素。
- 绝不要直接修改生产智能体——先克隆。
Snowpark Python
fromsnowflake.snowparkimportSessionimportos session=Session.builder.configs({"account":os.environ["SNOWFLAKE_ACCOUNT"],"user":os.environ["SNOWFLAKE_USER"],"password":os.environ["SNOWFLAKE_PASSWORD"],"role":"my_role","warehouse":"my_wh","database":"my_db","schema":"my_schema"}).create()- 绝不要硬编码凭据。
- DataFrame 是惰性的——在
collect()/show()时执行。 - 不要对大型 DataFrame 使用
collect()——在服务端处理。 - 对于批处理/ML 工作负载,使用向量化 UDF(快 10-100 倍)而不是标量 UDF。
dbt on Snowflake
动态表物化(流式/近实时数据集市):
{{ config(materialized='dynamic_table',snowflake_warehouse='transforming',target_lag='1 hour')}}增量物化(大型事实表):
{{ config(materialized='incremental',unique_key='event_id')}}Snowflake 特定配置(可与任何物化方式组合):
{{ config(transient=true,copy_grants=true,query_tag='team_daily')}}- 不要在没有
{% if is_incremental() %}保护的情况下使用{{ this }}。 - 对流式/近实时数据集市使用
dynamic_table物化。
性能
- 聚类键(Cluster keys):仅用于多 TB 级表,用在 WHERE/JOIN/GROUP BY 列上。
- 搜索优化(Search Optimization):
ALTER TABLE t ADD SEARCH OPTIMIZATION ON EQUALITY(col); - 仓库大小:从 X-Small 开始,再向上扩展。
AUTO_SUSPEND = 60,AUTO_RESUME = TRUE。 - 每个工作负载使用独立的仓库。
- 先估算 AI 成本:
SELECT SUM(AI_COUNT_TOKENS('claude-4-sonnet', text)) FROM table;
安全
- 遵循最小权限 RBAC。使用数据库角色进行对象级授权。
- 定期审计 ACCOUNTADMIN:
SHOW GRANTS OF ROLE ACCOUNTADMIN; - 使用网络策略进行 IP 白名单管理。
- 对 PII 列使用掩码策略,对多租户隔离使用行访问策略。
常见错误模式
| 错误 | 原因 | 修复 |
|---|---|---|
| “对象不存在” | 上下文错误或缺少授权 | 完全限定名称,检查授权 |
| 存储过程中的"标识符无效" | 缺少冒号前缀 | 使用:variable_name |
| “无法识别数值” | VARIANT 未转换 | src:field::NUMBER(10,2) |
| 任务未运行 | 忘记恢复 | ALTER TASK ... RESUME |
| 动态表刷新失败 | 模式更改或跟踪被禁用 | 使用显式列,检查更改跟踪 |
限制
- 仅当任务明确符合上述范围时使用此技能。
- 不要将输出视为特定环境验证、测试或专家审查的替代品。
- 如果缺少必需的输入、权限、安全边界或成功标准,请停下来询问澄清。