snowflake-platform
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSnowflake Platform Skill
Snowflake平台技能
Build and deploy applications on Snowflake's AI Data Cloud using the snow CLI, Cortex AI functions, Native Apps, and Snowpark.
借助snow CLI、Cortex AI函数、Native Apps和Snowpark,在Snowflake的AI数据云上构建并部署应用。
Quick Start
快速开始
Install Snowflake CLI
安装Snowflake CLI
bash
pip install snowflake-cli
snow --version # Should show 3.14.0+bash
pip install snowflake-cli
snow --version # 应显示3.14.0+Configure Connection
配置连接
bash
undefinedbash
undefinedInteractive setup
交互式设置
snow connection add
snow connection add
Or create ~/.snowflake/config.toml manually
或手动创建~/.snowflake/config.toml
```toml
[connections.default]
account = "orgname-accountname"
user = "USERNAME"
authenticator = "SNOWFLAKE_JWT"
private_key_path = "~/.snowflake/rsa_key.p8"
```toml
[connections.default]
account = "orgname-accountname"
user = "USERNAME"
authenticator = "SNOWFLAKE_JWT"
private_key_path = "~/.snowflake/rsa_key.p8"Test Connection
测试连接
bash
snow connection test -c default
snow sql -q "SELECT CURRENT_USER(), CURRENT_ACCOUNT()"bash
snow connection test -c default
snow sql -q "SELECT CURRENT_USER(), CURRENT_ACCOUNT()"When to Use This Skill
适用场景
Use when:
- Building applications on Snowflake platform
- Using Cortex AI functions in SQL queries
- Developing Native Apps for Marketplace
- Setting up JWT key-pair authentication
- Working with Snowpark Python
Don't use when:
- Building Streamlit apps (use skill)
streamlit-snowflake - Need data engineering/ETL patterns
- Working with BI tools (Tableau, Looker)
适用场景:
- 在Snowflake平台上构建应用
- 在SQL查询中使用Cortex AI函数
- 开发用于Marketplace的Native Apps
- 设置JWT密钥对认证
- 使用Snowpark Python
不适用场景:
- 构建Streamlit应用(使用技能)
streamlit-snowflake - 需要数据工程/ETL模式
- 使用BI工具(Tableau、Looker)
Cortex AI Functions
Cortex AI函数
Snowflake Cortex provides LLM capabilities directly in SQL. Functions are in the schema.
SNOWFLAKE.CORTEXSnowflake Cortex直接在SQL中提供大语言模型(LLM)能力。函数位于 schema中。
SNOWFLAKE.CORTEXCore Functions
核心函数
| Function | Purpose | GA Status |
|---|---|---|
| Text generation from prompt | GA Nov 2025 |
| Summarize text | GA |
| Translate between languages | GA Sep 2025 |
| Sentiment analysis | GA Jul 2025 |
| Natural language filtering | GA Nov 2025 |
| Categorize text/images | GA Nov 2025 |
| Aggregate insights across rows | GA Nov 2025 |
| 函数 | 用途 | 正式发布(GA)状态 |
|---|---|---|
| 根据提示生成文本 | 2025年11月正式发布 |
| 文本摘要 | 已正式发布 |
| 语言翻译 | 2025年9月正式发布 |
| 情感分析 | 2025年7月正式发布 |
| 自然语言过滤 | 2025年11月正式发布 |
| 文本/图像分类 | 2025年11月正式发布 |
| 跨行聚合洞察 | 2025年11月正式发布 |
COMPLETE Function
COMPLETE函数
sql
-- Simple prompt
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'llama3.1-70b',
'Explain quantum computing in one sentence'
) AS response;
-- With conversation history
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'llama3.1-70b',
[
{'role': 'system', 'content': 'You are a helpful assistant'},
{'role': 'user', 'content': 'What is Snowflake?'}
]
) AS response;
-- With options
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'mistral-large2',
'Summarize this document',
{'temperature': 0.3, 'max_tokens': 500}
) AS response;Available Models:
- ,
llama3.1-70b,llama3.1-8bllama3.2-3b - ,
mistral-large2mistral-7b snowflake-arcticgemma-7b- (200K context)
claude-3-5-sonnet
Model Context Windows (Updated 2025):
| Model | Context Window | Best For |
|---|---|---|
| Claude 3.5 Sonnet | 200,000 tokens | Large documents, long conversations |
| Llama3.1-70b | 128,000 tokens | Complex reasoning, medium documents |
| Llama3.1-8b | 8,000 tokens | Simple tasks, short text |
| Llama3.2-3b | 8,000 tokens | Fast inference, minimal text |
| Mistral-large2 | Variable | Check current docs |
| Snowflake Arctic | Variable | Check current docs |
Token Math: ~4 characters = 1 token. A 32,000 character document ≈ 8,000 tokens.
Error: → Use smaller model or chunk your input.
Input exceeds context window limitsql
-- 简单提示
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'llama3.1-70b',
'用一句话解释量子计算'
) AS response;
-- 带对话历史
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'llama3.1-70b',
[
{'role': 'system', 'content': '你是一个乐于助人的助手'},
{'role': 'user', 'content': '什么是Snowflake?'}
]
) AS response;
-- 带参数选项
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'mistral-large2',
'总结这份文档',
{'temperature': 0.3, 'max_tokens': 500}
) AS response;可用模型:
- ,
llama3.1-70b,llama3.1-8bllama3.2-3b - ,
mistral-large2mistral-7b snowflake-arcticgemma-7b- (200K上下文窗口)
claude-3-5-sonnet
模型上下文窗口(2025年更新):
| 模型 | 上下文窗口 | 最佳适用场景 |
|---|---|---|
| Claude 3.5 Sonnet | 200,000 tokens | 大型文档、长对话 |
| Llama3.1-70b | 128,000 tokens | 复杂推理、中型文档 |
| Llama3.1-8b | 8,000 tokens | 简单任务、短文本 |
| Llama3.2-3b | 8,000 tokens | 快速推理、极简文本 |
| Mistral-large2 | 可变 | 查看最新文档 |
| Snowflake Arctic | 可变 | 查看最新文档 |
Token计算:约4个字符=1个token。32,000字符的文档≈8,000 tokens。
错误处理: → 使用更小的模型或拆分输入内容。
Input exceeds context window limitSUMMARIZE Function
SUMMARIZE函数
sql
-- Single text
SELECT SNOWFLAKE.CORTEX.SUMMARIZE(article_text) AS summary
FROM articles
LIMIT 10;
-- Aggregate across rows (no context window limit)
SELECT AI_SUMMARIZE_AGG(review_text) AS all_reviews_summary
FROM product_reviews
WHERE product_id = 123;sql
-- 单条文本摘要
SELECT SNOWFLAKE.CORTEX.SUMMARIZE(article_text) AS summary
FROM articles
LIMIT 10;
-- 跨行聚合摘要(无上下文窗口限制)
SELECT AI_SUMMARIZE_AGG(review_text) AS all_reviews_summary
FROM product_reviews
WHERE product_id = 123;TRANSLATE Function
TRANSLATE函数
sql
-- Translate to English (auto-detect source)
SELECT SNOWFLAKE.CORTEX.TRANSLATE(
review_text,
'', -- Empty = auto-detect source language
'en' -- Target language
) AS translated
FROM international_reviews;
-- Explicit source language
SELECT AI_TRANSLATE(
description,
'es', -- Source: Spanish
'en' -- Target: English
) AS translated
FROM spanish_products;sql
-- 翻译为英文(自动检测源语言)
SELECT SNOWFLAKE.CORTEX.TRANSLATE(
review_text,
'', -- 空值=自动检测源语言
'en' -- 目标语言
) AS translated
FROM international_reviews;
-- 显式指定源语言
SELECT AI_TRANSLATE(
description,
'es', -- 源语言:西班牙语
'en' -- 目标语言:英语
) AS translated
FROM spanish_products;AI_FILTER (Natural Language Filtering)
AI_FILTER(自然语言过滤)
Performance: As of September 2025, AI_FILTER includes automatic optimization delivering 2-10x speedup and up to 60% token reduction for suitable queries.
sql
-- Filter with plain English
SELECT * FROM customer_feedback
WHERE AI_FILTER(
feedback_text,
'mentions shipping problems or delivery delays'
);
-- Combine with SQL predicates for maximum optimization
-- Query planner applies standard filters FIRST, then AI on smaller dataset
SELECT * FROM support_tickets
WHERE created_date > '2025-01-01' -- Standard filter applied first
AND AI_FILTER(description, 'customer is angry or frustrated');Best Practice: Always combine AI_FILTER with traditional SQL predicates (date ranges, categories, etc.) to reduce the dataset before AI processing. This maximizes the automatic optimization benefits.
Throttling: During peak usage, AI function requests may be throttled with retry-able errors. Implement exponential backoff for production applications (see Known Issue #10).
性能优化:截至2025年9月,AI_FILTER包含自动优化功能,可为合适的查询带来2-10倍的速度提升,最多减少60%的token使用量。
sql
-- 用自然语言过滤
SELECT * FROM customer_feedback
WHERE AI_FILTER(
feedback_text,
'提及运输问题或配送延迟'
);
-- 结合SQL谓词实现最大优化
-- 查询规划器会先应用标准过滤,再对更小的数据集执行AI过滤
SELECT * FROM support_tickets
WHERE created_date > '2025-01-01' -- 先应用标准过滤
AND AI_FILTER(description, '客户感到愤怒或沮丧');最佳实践:始终将AI_FILTER与传统SQL谓词(日期范围、分类等)结合使用,在AI处理之前先缩小数据集规模,以最大化自动优化的收益。
限流处理:在高峰使用时段,AI函数请求可能会被限流并返回可重试错误。生产应用中需实现指数退避重试机制(详见已知问题#10)。
AI_CLASSIFY
AI_CLASSIFY
sql
-- Categorize support tickets
SELECT
ticket_id,
AI_CLASSIFY(
description,
['billing', 'technical', 'shipping', 'other']
) AS category
FROM support_tickets;sql
-- 分类支持工单
SELECT
ticket_id,
AI_CLASSIFY(
description,
['账单', '技术', '运输', '其他']
) AS category
FROM support_tickets;Billing
计费说明
Cortex AI functions bill based on tokens:
- ~4 characters = 1 token
- Both input AND output tokens are billed
- Rates vary by model (larger models cost more)
Cost Management at Scale (Community-sourced):
Real-world production case study showed a single AI_COMPLETE query processing 1.18 billion records cost nearly $5K in credits. Cost drivers to watch:
- Cross-region inference: Models not available in your region incur additional data transfer costs
- Warehouse idle time: Unused compute still bills, but aggressive auto-suspend adds resume overhead
- Large table joins: Complex queries with AI functions multiply costs
sql
-- This seemingly simple query can be expensive at scale
SELECT
product_id,
AI_COMPLETE('mistral-large2', 'Summarize: ' || review_text) as summary
FROM product_reviews -- 1 billion rows
WHERE created_date > '2024-01-01';
-- Cost = (input tokens + output tokens) × row count × model rate
-- At scale, this adds up fastBest Practices:
- Filter datasets BEFORE applying AI functions
- Right-size warehouses (don't over-provision)
- Monitor credit consumption with QUERY_HISTORY views
- Consider batch processing instead of row-by-row AI operations
Source: The Hidden Cost of Snowflake Cortex AI (Community blog with billing evidence)
Cortex AI函数基于token计费:
- 约4个字符=1个token
- 输入和输出token都会被计费
- 费率因模型而异(大型模型成本更高)
大规模成本管理(社区贡献):
实际生产案例显示,一个处理11.8亿条记录的AI_COMPLETE查询花费了近5000美元的积分。需要关注的成本驱动因素:
- 跨区域推理:如果您的区域没有可用模型,会产生额外的数据传输成本
- 仓库空闲时间:未使用的计算资源仍会计费,但过于激进的自动暂停会增加恢复开销
- 大型表连接:包含AI函数的复杂查询会成倍增加成本
sql
-- 这个看似简单的查询在大规模场景下可能成本高昂
SELECT
product_id,
AI_COMPLETE('mistral-large2', '总结:' || review_text) as summary
FROM product_reviews -- 10亿行数据
WHERE created_date > '2024-01-01';
-- 成本 = (输入token + 输出token) × 行数 × 模型费率
-- 在大规模场景下,成本会快速累积最佳实践:
- 在应用AI函数之前先过滤数据集
- 合理设置仓库规模(不要过度配置)
- 使用QUERY_HISTORY视图监控积分消耗
- 考虑使用批处理代替逐行AI操作
来源:Snowflake Cortex AI的隐性成本(包含计费证据的社区博客)
Authentication
认证机制
JWT Key-Pair Authentication
JWT密钥对认证
Critical: Snowflake uses TWO account identifier formats:
| Format | Example | Used For |
|---|---|---|
| Organization-Account | | REST API URLs, connection config |
| Account Locator | | JWT claims ( |
These are NOT interchangeable!
关键注意事项:Snowflake使用两种账户标识符格式:
| 格式 | 示例 | 用途 |
|---|---|---|
| 组织-账户格式 | | REST API URL、连接配置 |
| 账户定位器 | | JWT声明( |
这两种格式不可互换!
Discover Your Account Locator
查看您的账户定位器
sql
SELECT CURRENT_ACCOUNT(); -- Returns: NZ90655sql
SELECT CURRENT_ACCOUNT(); -- 返回:NZ90655Generate RSA Key Pair
生成RSA密钥对
bash
undefinedbash
undefinedGenerate private key (PKCS#8 format required)
生成私钥(必须为PKCS#8格式)
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out ~/.snowflake/rsa_key.p8 -nocrypt
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out ~/.snowflake/rsa_key.p8 -nocrypt
Generate public key
生成公钥
openssl rsa -in ~/.snowflake/rsa_key.p8 -pubout -out ~/.snowflake/rsa_key.pub
openssl rsa -in ~/.snowflake/rsa_key.p8 -pubout -out ~/.snowflake/rsa_key.pub
Get fingerprint for JWT claims
获取JWT声明所需的指纹
openssl rsa -in ~/.snowflake/rsa_key.p8 -pubout -outform DER |
openssl dgst -sha256 -binary | openssl enc -base64
openssl dgst -sha256 -binary | openssl enc -base64
undefinedopenssl rsa -in ~/.snowflake/rsa_key.p8 -pubout -outform DER |
openssl dgst -sha256 -binary | openssl enc -base64
openssl dgst -sha256 -binary | openssl enc -base64
undefinedRegister Public Key with User
向用户注册公钥
sql
-- In Snowflake worksheet (requires ACCOUNTADMIN or SECURITYADMIN)
ALTER USER my_user SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';sql
-- 在Snowflake工作表中执行(需要ACCOUNTADMIN或SECURITYADMIN权限)
ALTER USER my_user SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';JWT Claim Format
JWT声明格式
iss: ACCOUNT_LOCATOR.USERNAME.SHA256:fingerprint
sub: ACCOUNT_LOCATOR.USERNAMEExample:
iss: NZ90655.JEZWEB.SHA256:jpZO6LvU2SpKd8tE61OGfas5ZXpfHloiJd7XHLPDEEA=
sub: NZ90655.JEZWEBiss: ACCOUNT_LOCATOR.USERNAME.SHA256:fingerprint
sub: ACCOUNT_LOCATOR.USERNAME示例:
iss: NZ90655.JEZWEB.SHA256:jpZO6LvU2SpKd8tE61OGfas5ZXpfHloiJd7XHLPDEEA=
sub: NZ90655.JEZWEBSPCS Container Authentication (v4.2.0+)
SPCS容器认证(v4.2.0+)
New in January 2026: Connector automatically detects and uses SPCS service identifier tokens when running inside Snowpark Container Services.
python
undefined2026年1月新增功能:当在Snowpark Container Services中运行时,连接器会自动检测并使用SPCS服务标识符令牌。
python
undefinedNo special configuration needed inside SPCS containers
SPCS容器内无需特殊配置
import snowflake.connector
import snowflake.connector
Auto-detects SPCS_TOKEN environment variable
自动检测SPCS_TOKEN环境变量
conn = snowflake.connector.connect()
This enables seamless authentication from containerized Snowpark services without explicit credentials.
**Source**: [Release v4.2.0](https://github.com/snowflakedb/snowflake-connector-python/releases/tag/v4.2.0)conn = snowflake.connector.connect()
这使得容器化的Snowpark服务无需显式凭证即可实现无缝认证。
**来源**:[v4.2.0版本发布说明](https://github.com/snowflakedb/snowflake-connector-python/releases/tag/v4.2.0)Snow CLI Commands
Snow CLI命令
Project Management
项目管理
bash
undefinedbash
undefinedInitialize project
初始化项目
snow init
snow init
Execute SQL
执行SQL
snow sql -q "SELECT 1"
snow sql -f query.sql
snow sql -q "SELECT 1"
snow sql -f query.sql
View logs
查看日志
snow logs
undefinedsnow logs
undefinedNative App Commands
Native App命令
bash
undefinedbash
undefinedDevelopment
开发阶段
snow app run # Deploy and run locally
snow app deploy # Upload to stage only
snow app teardown # Remove app
snow app run # 部署并本地运行
snow app deploy # 仅上传到stage
snow app teardown # 移除应用
Versioning
版本管理
snow app version create V1_0
snow app version list
snow app version drop V1_0
snow app version create V1_0
snow app version list
snow app version drop V1_0
Publishing
发布应用
snow app publish --version V1_0 --patch 0
snow app publish --version V1_0 --patch 0
Release Channels
发布渠道
snow app release-channel list
snow app release-channel add-version --channel ALPHA --version V1_0
snow app release-directive set default --version V1_0 --patch 0 --channel DEFAULT
undefinedsnow app release-channel list
snow app release-channel add-version --channel ALPHA --version V1_0
snow app release-directive set default --version V1_0 --patch 0 --channel DEFAULT
undefinedStreamlit Commands
Streamlit命令
bash
snow streamlit deploy --replace
snow streamlit deploy --replace --openbash
snow streamlit deploy --replace
snow streamlit deploy --replace --openStage Commands
Stage命令
bash
snow stage list
snow stage copy @my_stage/file.txt ./local/bash
snow stage list
snow stage copy @my_stage/file.txt ./local/Native App Development
Native App开发
Project Structure
项目结构
my_native_app/
├── snowflake.yml # Project config
├── manifest.yml # App manifest
├── setup_script.sql # Installation script
├── app/
│ └── streamlit/
│ ├── environment.yml
│ └── streamlit_app.py
└── scripts/
└── setup.sqlmy_native_app/
├── snowflake.yml # 项目配置文件
├── manifest.yml # 应用清单文件
├── setup_script.sql # 安装脚本
├── app/
│ └── streamlit/
│ ├── environment.yml
│ └── streamlit_app.py
└── scripts/
└── setup.sqlsnowflake.yml
snowflake.yml
yaml
definition_version: 2
native_app:
name: my_app
package:
name: my_app_pkg
distribution: external # For marketplace
application:
name: my_app
source_stage: stage/dev
artifacts:
- src: manifest.yml
dest: manifest.yml
- src: setup_script.sql
dest: setup_script.sql
- src: app/streamlit/environment.yml
dest: streamlit/environment.yml
- src: app/streamlit/streamlit_app.py
dest: streamlit/streamlit_app.py
enable_release_channels: true # For ALPHA/BETA channelsyaml
definition_version: 2
native_app:
name: my_app
package:
name: my_app_pkg
distribution: external # 用于Marketplace发布
application:
name: my_app
source_stage: stage/dev
artifacts:
- src: manifest.yml
dest: manifest.yml
- src: setup_script.sql
dest: setup_script.sql
- src: app/streamlit/environment.yml
dest: streamlit/environment.yml
- src: app/streamlit/streamlit_app.py
dest: streamlit/streamlit_app.py
enable_release_channels: true # 启用ALPHA/BETA渠道manifest.yml
manifest.yml
yaml
manifest_version: 1
artifacts:
setup_script: setup_script.sql
default_streamlit: streamlit/streamlit_app.pyyaml
manifest_version: 1
artifacts:
setup_script: setup_script.sql
default_streamlit: streamlit/streamlit_app.pyNote: Do NOT include privileges section - Native Apps can't declare privileges
注意:不要包含权限部分 - Native Apps无法声明权限
undefinedundefinedExternal Access Integration
外部访问集成
Native Apps calling external APIs need this setup:
sql
-- 1. Create network rule (in a real database, NOT app package)
CREATE DATABASE IF NOT EXISTS MY_APP_UTILS;
CREATE OR REPLACE NETWORK RULE MY_APP_UTILS.PUBLIC.api_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('api.example.com:443');
-- 2. Create integration
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION my_app_integration
ALLOWED_NETWORK_RULES = (MY_APP_UTILS.PUBLIC.api_rule)
ENABLED = TRUE;
-- 3. Grant to app
GRANT USAGE ON INTEGRATION my_app_integration
TO APPLICATION MY_APP;
-- 4. CRITICAL: Attach to Streamlit (must repeat after EVERY deploy!)
ALTER STREAMLIT MY_APP.config_schema.my_streamlit
SET EXTERNAL_ACCESS_INTEGRATIONS = (my_app_integration);Warning: Step 4 resets on every . Must re-run after each deploy!
snow app run调用外部API的Native Apps需要进行以下设置:
sql
-- 1. 创建网络规则(在真实数据库中创建,而非应用包)
CREATE DATABASE IF NOT EXISTS MY_APP_UTILS;
CREATE OR REPLACE NETWORK RULE MY_APP_UTILS.PUBLIC.api_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('api.example.com:443');
-- 2. 创建集成
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION my_app_integration
ALLOWED_NETWORK_RULES = (MY_APP_UTILS.PUBLIC.api_rule)
ENABLED = TRUE;
-- 3. 授予应用访问权限
GRANT USAGE ON INTEGRATION my_app_integration
TO APPLICATION MY_APP;
-- 4. 关键步骤:关联到Streamlit(每次部署后必须重复执行!)
ALTER STREAMLIT MY_APP.config_schema.my_streamlit
SET EXTERNAL_ACCESS_INTEGRATIONS = (my_app_integration);警告:步骤4会在每次执行后重置,每次部署后必须重新执行!
snow app runShared Data Pattern
共享数据模式
When your Native App needs data from an external database:
sql
-- 1. Create shared_data schema in app package
CREATE SCHEMA IF NOT EXISTS MY_APP_PKG.SHARED_DATA;
-- 2. Create views referencing external database
CREATE OR REPLACE VIEW MY_APP_PKG.SHARED_DATA.MY_VIEW AS
SELECT * FROM EXTERNAL_DB.SCHEMA.TABLE;
-- 3. Grant REFERENCE_USAGE (CRITICAL!)
GRANT REFERENCE_USAGE ON DATABASE EXTERNAL_DB
TO SHARE IN APPLICATION PACKAGE MY_APP_PKG;
-- 4. Grant access to share
GRANT USAGE ON SCHEMA MY_APP_PKG.SHARED_DATA
TO SHARE IN APPLICATION PACKAGE MY_APP_PKG;
GRANT SELECT ON ALL VIEWS IN SCHEMA MY_APP_PKG.SHARED_DATA
TO SHARE IN APPLICATION PACKAGE MY_APP_PKG;In , reference (NOT the original database).
setup_script.sqlshared_data.view_name当您的Native App需要访问外部数据库的数据时:
sql
-- 1. 在应用包中创建shared_data schema
CREATE SCHEMA IF NOT EXISTS MY_APP_PKG.SHARED_DATA;
-- 2. 创建引用外部数据库的视图
CREATE OR REPLACE VIEW MY_APP_PKG.SHARED_DATA.MY_VIEW AS
SELECT * FROM EXTERNAL_DB.SCHEMA.TABLE;
-- 3. 授予REFERENCE_USAGE权限(关键!)
GRANT REFERENCE_USAGE ON DATABASE EXTERNAL_DB
TO SHARE IN APPLICATION PACKAGE MY_APP_PKG;
-- 4. 授予共享访问权限
GRANT USAGE ON SCHEMA MY_APP_PKG.SHARED_DATA
TO SHARE IN APPLICATION PACKAGE MY_APP_PKG;
GRANT SELECT ON ALL VIEWS IN SCHEMA MY_APP_PKG.SHARED_DATA
TO SHARE IN APPLICATION PACKAGE MY_APP_PKG;在中,引用(而非原始数据库)。
setup_script.sqlshared_data.view_nameMarketplace Publishing
Marketplace发布
Security Review Workflow
安全审核流程
bash
undefinedbash
undefined1. Deploy app
1. 部署应用
snow app run
snow app run
2. Create version
2. 创建版本
snow app version create V1_0
snow app version create V1_0
3. Check security review status
3. 检查安全审核状态
snow app version list
snow app version list
Wait for review_status = APPROVED
等待review_status = APPROVED
4. Set release directive
4. 设置发布指令
snow app release-directive set default --version V1_0 --patch 0 --channel DEFAULT
snow app release-directive set default --version V1_0 --patch 0 --channel DEFAULT
5. Create listing in Snowsight Provider Studio (UI only)
5. 在Snowsight Provider Studio中创建列表(仅支持UI操作)
undefinedundefinedSecurity Review Statuses
安全审核状态
| Status | Meaning | Action |
|---|---|---|
| Scan hasn't run | Check DISTRIBUTION is EXTERNAL |
| Scan running | Wait |
| Passed | Can publish |
| Failed | Fix issues or appeal |
| Human reviewing | Wait (can take days) |
Triggers manual review: External access integrations, Streamlit components, network calls.
| 状态 | 含义 | 操作 |
|---|---|---|
| 尚未执行扫描 | 检查DISTRIBUTION是否设置为EXTERNAL |
| 扫描进行中 | 等待 |
| 审核通过 | 可发布 |
| 审核失败 | 修复问题或申诉 |
| 人工审核中 | 等待(可能需要数天) |
触发人工审核的场景:外部访问集成、Streamlit组件、网络调用。
Provider Studio Fields
Provider Studio字段
| Field | Max Length | Notes |
|---|---|---|
| Title | 72 chars | App name |
| Subtitle | 128 chars | One-liner |
| Description | 10,000 chars | HTML editor |
| Business Needs | 6 max | Select from dropdown |
| Quick Start Examples | 10 max | Title + Description + SQL |
| Data Dictionary | Required | Mandatory for data listings (2025) |
| 字段 | 最大长度 | 说明 |
|---|---|---|
| Title | 72字符 | 应用名称 |
| Subtitle | 128字符 | 一句话描述 |
| Description | 10,000字符 | HTML编辑器 |
| Business Needs | 最多6个 | 从下拉列表选择 |
| Quick Start Examples | 最多10个 | 标题 + 描述 + SQL |
| Data Dictionary | 必填 | 2025年起数据列表必填 |
Paid Listing Prerequisites
付费列表前提条件
| # | Requirement |
|---|---|
| 1 | Full Snowflake account (not trial) |
| 2 | ACCOUNTADMIN role |
| 3 | Provider Profile approved |
| 4 | Stripe account configured |
| 5 | Provider & Consumer Terms accepted |
| 6 | Contact Marketplace Ops |
Note: Cannot convert free listing to paid. Must create new listing.
| # | 要求 |
|---|---|
| 1 | 完整的Snowflake账户(非试用版) |
| 2 | ACCOUNTADMIN角色 |
| 3 | 供应商资料已审核通过 |
| 4 | 已配置Stripe账户 |
| 5 | 已接受供应商与消费者条款 |
| 6 | 联系Marketplace运营团队 |
注意:无法将免费列表转换为付费列表,必须创建新的列表。
Snowpark Python
Snowpark Python
Session Setup
会话设置
python
from snowflake.snowpark import Session
connection_params = {
"account": "orgname-accountname",
"user": "USERNAME",
"password": "PASSWORD", # Or use private_key_path
"warehouse": "COMPUTE_WH",
"database": "MY_DB",
"schema": "PUBLIC"
}
session = Session.builder.configs(connection_params).create()python
from snowflake.snowpark import Session
connection_params = {
"account": "orgname-accountname",
"user": "USERNAME",
"password": "PASSWORD", # 或使用private_key_path
"warehouse": "COMPUTE_WH",
"database": "MY_DB",
"schema": "PUBLIC"
}
session = Session.builder.configs(connection_params).create()DataFrame Operations
DataFrame操作
python
undefinedpython
undefinedRead table
读取表
df = session.table("MY_TABLE")
df = session.table("MY_TABLE")
Filter and select
过滤与选择
result = df.filter(df["STATUS"] == "ACTIVE")
.select("ID", "NAME", "CREATED_AT")
.sort("CREATED_AT", ascending=False)
.select("ID", "NAME", "CREATED_AT")
.sort("CREATED_AT", ascending=False)
result = df.filter(df["STATUS"] == "ACTIVE")
.select("ID", "NAME", "CREATED_AT")
.sort("CREATED_AT", ascending=False)
.select("ID", "NAME", "CREATED_AT")
.sort("CREATED_AT", ascending=False)
Execute
执行并显示结果
result.show()
result.show()
Collect to Python
收集到Python本地
rows = result.collect()
undefinedrows = result.collect()
undefinedRow Access (Common Gotcha)
行访问注意事项(常见误区)
python
undefinedpython
undefinedWRONG - dict() doesn't work on Snowpark Row
错误示例 - dict()无法处理Snowpark Row对象
config = dict(result[0])
config = dict(result[0])
CORRECT - Access columns explicitly
正确示例 - 显式访问列
row = result[0]
config = {
'COLUMN_A': row['COLUMN_A'],
'COLUMN_B': row['COLUMN_B'],
}
undefinedrow = result[0]
config = {
'COLUMN_A': row['COLUMN_A'],
'COLUMN_B': row['COLUMN_B'],
}
undefinedDML Statistics (v4.2.0+)
DML统计信息(v4.2.0+)
New in January 2026: property exposes granular DML statistics for operations where is insufficient (e.g., CTAS queries).
SnowflakeCursor.statsrowcountpython
undefined2026年1月新增功能:属性公开了细粒度的DML统计信息,适用于不足以提供信息的操作(例如CTAS查询)。
SnowflakeCursor.statsrowcountpython
undefinedBefore v4.2.0 - rowcount returns -1 for CTAS
v4.2.0之前 - CTAS查询的rowcount返回-1
cursor.execute("CREATE TABLE new_table AS SELECT * FROM source WHERE active = true")
print(cursor.rowcount) # Returns -1 (not helpful!)
cursor.execute("CREATE TABLE new_table AS SELECT * FROM source WHERE active = true")
print(cursor.rowcount) # 返回-1(无帮助!)
After v4.2.0 - stats property shows actual row counts
v4.2.0之后 - stats属性显示实际行数
cursor.execute("CREATE TABLE new_table AS SELECT * FROM source WHERE active = true")
print(cursor.stats) # Returns {'rows_inserted': 1234, 'duplicates': 0, ...}
**Source**: [Release v4.2.0](https://github.com/snowflakedb/snowflake-connector-python/releases/tag/v4.2.0)cursor.execute("CREATE TABLE new_table AS SELECT * FROM source WHERE active = true")
print(cursor.stats) # 返回{'rows_inserted': 1234, 'duplicates': 0, ...}
**来源**:[v4.2.0版本发布说明](https://github.com/snowflakedb/snowflake-connector-python/releases/tag/v4.2.0)UDFs and Stored Procedures
UDF与存储过程
python
from snowflake.snowpark.functions import udf, sprocpython
from snowflake.snowpark.functions import udf, sprocRegister UDF
注册UDF
@udf(name="my_udf", replace=True)
def my_udf(x: int) -> int:
return x * 2
@udf(name="my_udf", replace=True)
def my_udf(x: int) -> int:
return x * 2
Register Stored Procedure
注册存储过程
@sproc(name="my_sproc", replace=True)
def my_sproc(session: Session, table_name: str) -> str:
df = session.table(table_name)
count = df.count()
return f"Row count: {count}"
undefined@sproc(name="my_sproc", replace=True)
def my_sproc(session: Session, table_name: str) -> str:
df = session.table(table_name)
count = df.count()
return f"行数:{count}"
undefinedREST API (SQL API v2)
REST API(SQL API v2)
The REST API is the foundation for programmatic Snowflake access from Cloudflare Workers.
REST API是从Cloudflare Workers以编程方式访问Snowflake的基础。
Endpoint
端点地址
https://{org-account}.snowflakecomputing.com/api/v2/statementshttps://{org-account}.snowflakecomputing.com/api/v2/statementsRequired Headers (CRITICAL)
必填请求头(关键)
ALL requests must include these headers - missing causes silent failures:
Accepttypescript
const headers = {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json',
'Accept': 'application/json', // REQUIRED - "null" error if missing
'User-Agent': 'MyApp/1.0',
};所有请求必须包含以下请求头 - 缺少会导致静默失败:
Accepttypescript
const headers = {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json',
'Accept': 'application/json', // 必填 - 缺少会返回"null"错误
'User-Agent': 'MyApp/1.0',
};Async Query Handling
异步查询处理
Even simple queries return async (HTTP 202). Always implement polling:
typescript
// Submit returns statementHandle, not results
const submit = await fetch(url, { method: 'POST', headers, body });
const { statementHandle } = await submit.json();
// Poll until complete
while (true) {
const status = await fetch(`${url}/${statementHandle}`, { headers });
if (status.status === 200) break; // Complete
if (status.status === 202) {
await sleep(2000); // Still running
continue;
}
}即使是简单的查询也会返回异步结果(HTTP 202状态码),必须始终实现轮询机制:
typescript
// 提交请求返回statementHandle,而非结果
const submit = await fetch(url, { method: 'POST', headers, body });
const { statementHandle } = await submit.json();
// 轮询直到查询完成
while (true) {
const status = await fetch(`${url}/${statementHandle}`, { headers });
if (status.status === 200) break; // 查询完成
if (status.status === 202) {
await sleep(2000); // 仍在运行
continue;
}
}Workers Subrequest Limits
Workers子请求限制
| Plan | Limit | Safe Polling |
|---|---|---|
| Free | 50 | 45 attempts @ 2s = 90s max |
| Paid | 1,000 | 100 attempts @ 500ms = 50s max |
| 套餐 | 限制 | 安全轮询策略 |
|---|---|---|
| 免费版 | 50 | 45次尝试 × 2秒 = 最长90秒 |
| 付费版 | 1,000 | 100次尝试 × 500毫秒 = 最长50秒 |
Fetch Timeouts
请求超时设置
Workers has no default timeout. Always use AbortController:
fetch()typescript
const response = await fetch(url, {
signal: AbortSignal.timeout(30000), // 30 seconds
headers,
});Workers的没有默认超时,必须始终使用AbortController:
fetch()typescript
const response = await fetch(url, {
signal: AbortSignal.timeout(30000), // 30秒超时
headers,
});Cancel on Timeout
超时取消查询
Cancel queries when timeout occurs to avoid warehouse costs:
POST /api/v2/statements/{statementHandle}/cancelSee for complete implementation.
templates/snowflake-rest-client.ts当发生超时时,取消查询以避免仓库成本:
POST /api/v2/statements/{statementHandle}/cancel完整实现请参考。
templates/snowflake-rest-client.tsKnown Issues
已知问题
1. Account Identifier Confusion
1. 账户标识符混淆
Symptom: JWT auth fails silently, queries don't appear in Query History.
Cause: Using org-account format in JWT claims instead of account locator.
Fix: Use to get the actual account locator.
SELECT CURRENT_ACCOUNT()症状:JWT认证静默失败,查询未出现在查询历史中。
原因:在JWT声明中使用了组织-账户格式,而非账户定位器。
解决方法:使用获取实际的账户定位器。
SELECT CURRENT_ACCOUNT()2. External Access Reset
2. 外部访问权限重置
Symptom: API calls fail after .
snow app runCause: External access integration attachment resets on every deploy.
Fix: Re-run after each deploy.
ALTER STREAMLIT ... SET EXTERNAL_ACCESS_INTEGRATIONS症状:执行后API调用失败。
snow app run原因:外部访问集成的关联会在每次部署后重置。
解决方法:每次部署后重新执行。
ALTER STREAMLIT ... SET EXTERNAL_ACCESS_INTEGRATIONS3. Release Channel Syntax
3. 发布渠道语法错误
Symptom: fails.
ALTER APPLICATION PACKAGE ... SET DEFAULT RELEASE DIRECTIVECause: Legacy SQL syntax doesn't work with release channels enabled.
Fix: Use snow CLI:
snow app release-directive set default --version V1_0 --patch 0 --channel DEFAULT症状:执行失败。
ALTER APPLICATION PACKAGE ... SET DEFAULT RELEASE DIRECTIVE原因:旧版SQL语法在启用发布渠道后无法使用。
解决方法:使用Snow CLI命令:
snow app release-directive set default --version V1_0 --patch 0 --channel DEFAULT4. Artifact Nesting
4. 工件嵌套问题
Symptom: Files appear in instead of .
streamlit/streamlit/streamlit/Cause: Directory mappings in snowflake.yml nest the folder name.
Fix: List individual files explicitly in artifacts, not directories.
症状:文件出现在目录下,而非。
streamlit/streamlit/streamlit/原因:snowflake.yml中的目录映射导致文件夹名称嵌套。
解决方法:在artifacts中显式列出单个文件,而非目录。
5. REFERENCE_USAGE Missing
5. 缺少REFERENCE_USAGE权限
Symptom: "A view that is added to the shared content cannot reference objects from other databases"
Cause: Missing for shared data.
GRANT REFERENCE_USAGE ON DATABASEFix: Always grant REFERENCE_USAGE before when using external databases.
snow app run症状:"添加到共享内容的视图无法引用其他数据库中的对象"
原因:使用外部数据库时缺少权限。
GRANT REFERENCE_USAGE ON DATABASE解决方法:在执行前,始终授予REFERENCE_USAGE权限。
snow app run6. REST API Missing Accept Header
6. REST API缺少Accept请求头
Symptom: "Unsupported Accept header null is specified" on polling requests.
Cause: Initial request had but polling request didn't.
Accept: application/jsonFix: Use consistent headers helper function for ALL requests (submit, poll, cancel).
症状:轮询请求时出现"Unsupported Accept header null is specified"错误。
原因:初始请求包含,但轮询请求未包含。
Accept: application/json解决方法:对所有请求(提交、轮询、取消)使用统一的请求头辅助函数。
7. Workers Fetch Hangs Forever
7. Workers Fetch请求无限挂起
Symptom: Worker hangs indefinitely waiting for Snowflake response.
Cause: Cloudflare Workers' has no default timeout.
fetch()Fix: Always use on all Snowflake requests.
AbortSignal.timeout(30000)症状:Worker无限等待Snowflake响应。
原因:Cloudflare Workers的没有默认超时。
fetch()解决方法:对所有Snowflake请求始终使用。
AbortSignal.timeout(30000)8. Too Many Subrequests
8. 子请求数量过多
Symptom: "Too many subrequests" error during polling.
Cause: Polling every 1 second × 600 attempts = 600 subrequests exceeds limits.
Fix: Poll every 2-5 seconds, limit to 45 (free) or 100 (paid) attempts.
症状:轮询时出现"Too many subrequests"错误。
原因:每秒轮询1次 × 600次尝试 = 600次子请求,超过限制。
解决方法:每2-5秒轮询一次,限制尝试次数为45次(免费版)或100次(付费版)。
9. Warehouse Not Auto-Resuming (Perceived)
9. 仓库未自动恢复(感知问题)
Symptom: Queries return statementHandle but never complete (code 090001 indefinitely).
Cause: means "running" not error. Warehouse IS resuming, just takes time.
090001Fix: Auto-resume works. Wait longer or explicitly resume first:
POST /api/v2/warehouses/{wh}:resume症状:查询返回statementHandle但从未完成(持续返回代码090001)。
原因:表示"运行中"而非错误,仓库正在恢复,只是需要时间。
090001解决方法:自动恢复功能正常,等待更长时间或显式恢复仓库:
POST /api/v2/warehouses/{wh}:resume10. Memory Leaks in Connector 4.x (Active Issue)
10. Connector 4.x版本中的内存泄漏(活跃问题)
Error: Long-running Python applications show memory growth over time
Source: GitHub Issue #2727, #2725
Affects: snowflake-connector-python 4.0.0 - 4.2.0
Why It Happens:
- uses
SessionManagerwhich prevents garbage collectiondefaultdict - holds references that leak during query execution
SnowflakeRestful.fetch()
Prevention:
Reuse connections rather than creating new ones repeatedly. Fix is in progress via PR #2741 and PR #2726.
python
undefined错误:长时间运行的Python应用随时间推移出现内存增长。
影响版本:snowflake-connector-python 4.0.0 - 4.2.0
问题原因:
- 使用
SessionManager导致无法垃圾回收defaultdict - 在查询执行期间持有引用导致泄漏
SnowflakeRestful.fetch()
python
undefinedAVOID - creates new connection each iteration
避免 - 每次迭代创建新连接
for i in range(1000):
conn = snowflake.connector.connect(...)
cursor = conn.cursor()
cursor.execute("SELECT 1")
cursor.close()
conn.close()
for i in range(1000):
conn = snowflake.connector.connect(...)
cursor = conn.cursor()
cursor.execute("SELECT 1")
cursor.close()
conn.close()
BETTER - reuse connection
推荐 - 重用连接
conn = snowflake.connector.connect(...)
cursor = conn.cursor()
for i in range(1000):
cursor.execute("SELECT 1")
cursor.close()
conn.close()
**Status**: Fix expected in connector v4.3.0 or laterconn = snowflake.connector.connect(...)
cursor = conn.cursor()
for i in range(1000):
cursor.execute("SELECT 1")
cursor.close()
conn.close()
**状态**:预计在connector v4.3.0或更高版本中修复。11. AI Function Throttling During Peak Usage
11. 高峰时段AI函数限流
Error: "Request throttled due to high usage. Please retry."
Source: Snowflake Cortex Documentation
Affects: All Cortex AI functions (COMPLETE, FILTER, CLASSIFY, etc.)
Why It Happens:
AI/LLM requests may be throttled during high usage periods to manage platform capacity. Throttled requests return errors and require manual retries.
Prevention:
Implement retry logic with exponential backoff:
python
import time
import snowflake.connector
def execute_with_retry(cursor, query, max_retries=3):
for attempt in range(max_retries):
try:
return cursor.execute(query).fetchall()
except snowflake.connector.errors.DatabaseError as e:
if "throttled" in str(e).lower() and attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
time.sleep(wait_time)
else:
raiseStatus: Documented behavior, no fix planned
错误:"Request throttled due to high usage. Please retry."
影响范围:所有Cortex AI函数(COMPLETE、FILTER、CLASSIFY等)
问题原因:
在高使用时段,AI/LLM请求可能会被限流以管理平台容量。被限流的请求会返回错误,需要手动重试。
预防措施:
实现带指数退避的重试逻辑:
python
import time
import snowflake.connector
def execute_with_retry(cursor, query, max_retries=3):
for attempt in range(max_retries):
try:
return cursor.execute(query).fetchall()
except snowflake.connector.errors.DatabaseError as e:
if "throttled" in str(e).lower() and attempt < max_retries - 1:
wait_time = 2 ** attempt # 指数退避
time.sleep(wait_time)
else:
raise状态:已记录的行为,暂无修复计划。
References
参考资料
Related Skills
相关技能
- - Streamlit in Snowflake apps
streamlit-snowflake
- - Snowflake应用中的Streamlit开发
streamlit-snowflake