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 TravelFail-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;

下面这张图把本节的对象模型、表类型差异、视图与物化视图的读取路径,以及序列与函数的调用关系放在同一张结构图中,便于对照理解。

Snowflake 对象模型与对象类型关系 三层命名空间:数据库 → 模式 → 对象 SALES_DB 数据库(业务域/环境) ODS / DWD / DWS / ADS 模式(数据分层) 表 / 视图 / 物化视图 / 序列 / 函数 对象(完整限定名 DB.SCHEMA.OBJECT) 表类型对比 PERMANENT 永久表 Time Travel 0–90 天 + Fail-safe 7 天 TRANSIENT 瞬态表 Time Travel 0–1 天,无 Fail-safe TEMPORARY 临时表 会话结束即消失,仅会话可见 视图 vs 物化视图 VIEW 视图 只存查询定义,查询时实时展开 适合逻辑封装、脱敏、权限收敛 MATERIALIZED VIEW 物化视图 预计算并存储结果,查询直接读取 单表约束,消耗存储与后台维护 序列与函数 SEQUENCE 序列 生成代理键,不保证连续无空洞 FUNCTION 函数 标量 UDF:一行进,一个值出 UDTF:一行进,多行出 外部函数:调用外部服务 典型读取路径:基表 → 视图/物化视图 → 分析查询 DWD.ORDER_WIDE 永久表(基表) ADS.V_ORDER_DAILY 视图:实时展开 ADS.MV_ORDER_DAILY 物化视图:预计算 分析查询 BI / 报表 / 看板 说明:视图不落数据,物化视图落数据;瞬态表与临时表不进入 Fail-safe,适合可重建的中间结果。
实践建议:先用 SHOW TABLES IN SCHEMA SALES_DB.DWD; 和 SHOW VIEWS IN SCHEMA SALES_DB.ADS; 盘点对象,再用 SELECT GET_DDL('TABLE','SALES_DB.DWD.ORDER_WIDE'); 导出定义,便于版本化管理。
注意:瞬态表和临时表不进入 Fail-safe,一旦误删且超出 Time Travel 窗口就无法恢复。对不可重建的事实数据,不要为了省存储而使用瞬态表。