4. 数据库、模式与对象模型
Snowflake 的对象模型是三层命名空间结构:数据库(Database)→ 模式(Schema)→ 对象(Object)。任何一张表、视图、序列或函数的完整限定名都是 数据库.模式.对象,例如 SALES_DB.ODS.ORDERS。理解这三层边界,是后续做数据湖仓分层建模、权限隔离和成本控制的前提。
数据库在 Snowflake 中更接近“业务域或环境”的容器,而不是传统数据库实例。常见做法是按业务域划分数据库,例如 SALES_DB、FIN_DB、LOG_DB;也可以按环境划分,如 DEV_DB、PROD_DB。模式则是数据库内部的二级分类,最典型的是按数据分层命名:ODS(贴源层)、DWD(明细层)、DWS(汇总层)、ADS(应用层),再辅以 STAGE(临时落地区)、UTIL(工具对象)等。这样命名后,一条查询语句本身就携带了数据血缘信息。
CREATE DATABASE IF NOT EXISTS SALES_DB;
CREATE SCHEMA IF NOT EXISTS SALES_DB.ODS;
CREATE SCHEMA IF NOT EXISTS SALES_DB.DWD;
CREATE SCHEMA IF NOT EXISTS SALES_DB.DWS;
CREATE SCHEMA IF NOT EXISTS SALES_DB.ADS;
模式设计要同时考虑三件事:命名一致性、权限边界、生命周期。命名上建议统一使用大写加下划线,避免大小写混用带来的引用歧义;权限上,通常把 ODS 的写权限只授予数据接入角色,把 DWD/DWS 的写权限授予建模角色,把 ADS 的读权限授予分析角色;生命周期上,STAGE 模式可以配置较短的 DATA_RETENTION_TIME_IN_DAYS,而核心明细层保留更长时间,以支持 Time Travel 回溯。
表类型:永久、临时、瞬态
Snowflake 的表按生命周期和故障恢复能力分为三类,选择依据是“数据是否可重建”和“需要保留多久”。
| 表类型 | 生命周期 | Time Travel | Fail-safe | 典型用途 |
|---|---|---|---|---|
| 永久表 PERMANENT | 持久,直到显式删除 | 0~90 天 | 7 天 | 核心明细、汇总、维表 |
| 瞬态表 TRANSIENT | 持久,直到显式删除 | 0~1 天 | 无 | 可重建的中间结果、大宽表 |
| 临时表 TEMPORARY | 会话结束即消失 | 0~1 天 | 无 | 会话内临时计算、调试 |
关键差异在存储成本:永久表会为 Time Travel 和 Fail-safe 保留历史数据,瞬态表和临时表不进入 Fail-safe,因此存储开销更低。对于“可以从 ODS 重新计算出来”的中间层,用瞬态表是常见且合理的降本手段;而订单、支付等不可重建的事实数据,应使用永久表。
CREATE OR REPLACE TRANSIENT TABLE SALES_DB.DWD.ORDER_WIDE (
ORDER_ID NUMBER(38,0),
CUSTOMER_ID NUMBER(38,0),
ORDER_AMOUNT NUMBER(18,2),
ORDER_TS TIMESTAMP_NTZ
);
CREATE OR REPLACE TEMPORARY TABLE SALES_DB.STAGE.TMP_ORDER_FILTER (
ORDER_ID NUMBER(38,0),
ORDER_TS TIMESTAMP_NTZ
);
视图与物化视图
视图(View)是保存下来的查询定义,不存储数据,每次查询时实时展开。它适合做逻辑封装、字段脱敏和权限收敛。物化视图(Materialized View)则预先计算并存储结果,查询时直接读取已物化的数据,适合对“基表变化不频繁、查询频繁且聚合较重”的场景加速。物化视图有额外约束:只能基于单表、不支持所有表达式、需要消耗存储与后台维护资源,因此不能把它当成通用加速手段。
CREATE OR REPLACE VIEW SALES_DB.ADS.V_ORDER_DAILY AS
SELECT DATE_TRUNC('day', ORDER_TS) AS ORDER_DATE,
COUNT(*) AS ORDER_CNT,
SUM(ORDER_AMOUNT) AS GMV
FROM SALES_DB.DWD.ORDER_WIDE
GROUP BY 1;
CREATE OR REPLACE MATERIALIZED VIEW SALES_DB.ADS.MV_ORDER_DAILY AS
SELECT DATE_TRUNC('day', ORDER_TS) AS ORDER_DATE,
COUNT(*) AS ORDER_CNT,
SUM(ORDER_AMOUNT) AS GMV
FROM SALES_DB.DWD.ORDER_WIDE
GROUP BY 1;
序列与函数
序列(Sequence)用于生成单调递增的数值,常作为代理键来源。Snowflake 的序列不保证连续无空洞,也不保证严格按调用顺序递增,因此只适合做唯一标识,不适合做业务序号。函数(Function)分为用户自定义函数(UDF)和外部函数,UDF 又分标量 UDF 与表函数(UDTF)。标量 UDF 接收一行返回一个值,适合封装清洗逻辑;UDTF 接收一行返回多行,适合做展开或解析。
CREATE OR REPLACE SEQUENCE SALES_DB.UTIL.SEQ_ORDER_SK START = 1 INCREMENT = 1;
CREATE OR REPLACE FUNCTION SALES_DB.UTIL.FN_NORMALIZE_PHONE(PHONE STRING)
RETURNS STRING
LANGUAGE SQL
AS $$
REGEXP_REPLACE(PHONE, '[^0-9]', '')
$$;
SELECT SALES_DB.UTIL.SEQ_ORDER_SK.NEXTVAL AS ORDER_SK,
SALES_DB.UTIL.FN_NORMALIZE_PHONE('138-0000-1234') AS PHONE_CLEAN;
下面这张图把本节的对象模型、表类型差异、视图与物化视图的读取路径,以及序列与函数的调用关系放在同一张结构图中,便于对照理解。
SHOW TABLES IN SCHEMA SALES_DB.DWD; 和 SHOW VIEWS IN SCHEMA SALES_DB.ADS; 盘点对象,再用 SELECT GET_DDL('TABLE','SALES_DB.DWD.ORDER_WIDE'); 导出定义,便于版本化管理。