Snowflake DCM 多环境数据库变更管理指南
DataHot 速览
文章介绍在 Snowflake 中跨 DEV、QA、PROD 三套环境管理数据库变更的实践。作者最初使用 SchemaChange,但随着环境、对象和贡献者增多,出现命名规范、变更遗漏和反复 rebase 等运维负担。随后他们转向 Snowflake DCM Projects,希望通过声明式定义和 plan-then-deploy 工作流,实现版本控制、可重复的多环境部署。DCM 允许在定义文件中声明数据库、schema、表等对象的目标状态,由 Snowflake 计算并应用变更。
为什么值得关注:对负责 Snowflake 多环境发布的数据平台工程师有直接参考价值,解释了从命令式 SQL 变更管理转向声明式 DCM 的动因与机制。
本文目录 14 节
译文
AI 逐段翻译
说实话,当你只有一个环境时,schema 变更很简单。
加一列。建一张表。修改一个角色。部署这个变更。
当同一个 Snowflake 项目必须同时存在于 DEV、QA 和 PROD 环境中时,噩梦就开始了。
这正是我们所处的境况。
我们希望按照相同的逻辑结构来管理我们的环境,但它们不可能完全相同。DEV、QA 和 PROD 需要不同的数据库、仓库规模和保留设置。与此同时,我们也在寻找一种高效且可靠的方式,确保在开发环境中引入的 schema 变更不会在从开发到生产的某个环节中丢失。
我们最初的方法是使用 SchemaChange,它通过 SQL 和源代码控制来管理变更。这在环境、对象和贡献者数量开始增加之前一直有效,之后我们不得不开始管理 SchemaChange 在每个用户部署时遵循的严格命名约定。我们还遇到了跨环境缺失变更的问题,不得不开始对生产环境和 QA 环境进行 rebase,以确保我们的对象在各个环境中都存在,并且各环境拥有相同的变更。所有这些都成了我们在决定使用哪种工具来管理数据库变更时未曾预料到的额外开销。
于是问题不再是关于我们如何执行一条 CREATE TABLE 语句,而更多是关于我们如何定义数据库应该是什么样子,并高效地将该定义跨不同环境迁移,而不增加运营开销。
这就是促使我们开始试验 Snowflake Database Change Management (DCM) 的原因。
为什么选择 Snowflake DCM Projects?
Snowflake DCM Projects 支持版本控制、可跨环境(例如我们 Snowflake 对象的 DEV、QA 和 PROD)重复部署。它为我们提供了一种声明式的方法,将 Snowflake 对象作为代码来管理。我们可以在定义文件中定义数据库、schema、表和其他对象的目标状态,Snowflake 将确定并应用必要的变更以达到该状态。它使用在基础设施即代码工具中常见的先计划后部署工作流。
我们要构建的内容
- 一个三环境设置——DEV、QA 和 PROD——其中每个环境都有自己的 DCM 项目和目标数据库,同时共享相同的底层定义。
- 一个由 GitHub 支持的 Snowflake DCM 项目,将我们的数据库基础设施和 schema 定义视为版本控制的代码。
- 一个声明式 schema 管理工作流,我们使用 DCM DEFINE 语句定义数据库、schema、表、仓库、角色和授权的目标状态,而不是维护一组特定于环境的迁移脚本。
- 一个先计划后部署的工作流,在 snow dcm deploy 将变更应用到目标环境之前,使用 snow dcm plan 审查变更。
- 一条从 DEV → QA → PROD 的受控推进路径,降低环境彼此偏离的风险,并使基础设施变更可重复。
架构概览
这个生命周期帮助我们以受控、有版本且可审计的方式构建、测试、部署和监控数据库变更。

- 在 Snowflake Workspace、远程 Git 仓库或本地目录中创建 DCM 项目文件(manifest.yml 和 SQL 定义文件)。
- 为每个目标环境创建一个新的 DCM 项目。
- 在 DCM 项目文件中定义 Snowflake 对象。
- 执行 DCM PLAN 命令来模拟部署并预览变更。
- 部署项目版本以在 Snowflake 中应用变更。
- 监控项目执行情况。
- 迭代你的 DCM 项目。更新项目文件,审查计划输出,并根据需要部署新版本。
接口: 我们可以使用 Snowflake Workspaces、本地 IDE 中的 Snowflake CLI、使用 Cortex Code 的自然语言提示、SQL 命令或自动化 CI/CD 流水线来处理 DCM Projects
设置
本指南将引导我们在同一账户上设置一个具有三个环境(DEV、QA、PROD)的 Snowflake DCM(数据库变更管理)项目。
先决条件
- 具有 ACCOUNTADMIN 角色的 Snowflake 账户
- Snowflake CLI(snow)3.24+ 版本
- 一个 GitHub 仓库
1.1 创建项目数据库和 Schema
DCM 项目元数据将存放在专用的数据库/schema 中。项目不会定义自己的父数据库或 schema。
CREATE DATABASE IF NOT EXISTS ACME_DB;
CREATE SCHEMA IF NOT EXISTS ACME_DB.DCM_SCHEMA;1.2 创建 DCM 项目对象(每个环境一个)
每个环境都需要自己的项目对象以避免冲突。注意:-c 默认值是一个 Snowflake CLI 连接配置,根据你的私有配置,每个用户可能不同。
-- run the commands in the Snowflake CLI to create our environments
snow dcm create ACME_DB.DCM_SCHEMA.ACME_PROJECT_DEV -c default
snow dcm create ACME_DB.DCM_SCHEMA.ACME_PROJECT_QA -c default
snow dcm create ACME_DB.DCM_SCHEMA.ACME_PROJECT_PROD -c default1.3 将 Snowflake 连接到 GitHub
在 GitHub 中创建个人访问令牌(PAT)
- 前往 https://github.com/settings/tokens
- 生成一个具有 repo 范围的 Classic 令牌
- 复制该令牌
将 PAT 存储在 Snowflake 中并创建 API 集成
-- Store PAT as a secret
CREATE OR REPLACE SECRET ACME_DB.DCM_SCHEMA.GITHUB_PAT
TYPE = PASSWORD
USERNAME = 'your-github-username'
PASSWORD = '<your-github-pat>';
-- Create API integration
CREATE OR REPLACE API INTEGRATION acme_git_pat_integration
API_PROVIDER = git_https_api
API_ALLOWED_PREFIXES = ('https://github.com/your-org/')
ALLOWED_AUTHENTICATION_SECRETS = (ACME_DB.DCM_SCHEMA.GITHUB_PAT)
ENABLED = TRUE;从你的 Git 仓库创建工作区
- 在 Snowsight 中:Projects → Workspaces → + Add new → From Git repository
- 仓库 URL:https://github.com/your-org/your-repo.git
- API 集成:ACME_GIT_PAT_INTEGRATION
- 密钥:ACME_DB.DCM_SCHEMA.GITHUB_PAT
- 点击 Create
1.4 项目文件结构
在你的工作区/仓库中创建以下结构:

1.5 manifest.yml
关键规则:
- 同一账户上的每个 target 必须具有唯一的 project_name
- 使用 Jinja 变量({{db}}、{{env}}、{{wh_size}})来处理环境差异
- 当未指定 --target 标志时,使用 default_target
manifest_version: 2
type: DCM_PROJECT
default_target: 'DEV'
targets:
DEV:
account_identifier: <snowflake org-acc> # Your org-account identifier
project_name: 'ACME_DB.DCM_SCHEMA.ACME_PROJECT_DEV'
project_owner: ACCOUNTADMIN
templating_config: 'DEV'
QA:
account_identifier: <snowflake org-acc> # e.g xxx00xx-xxx00xxx
project_name: 'ACME_DB.DCM_SCHEMA.ACME_PROJECT_QA'
project_owner: ACCOUNTADMIN
templating_config: 'QA'
PROD:
account_identifier: <snowflake org-acc>
project_name: 'ACME_DB.DCM_SCHEMA.ACME_PROJECT_PROD'
project_owner: ACCOUNTADMIN
templating_config: 'PROD'
templating:
defaults:
env: 'DEV'
db: 'ACME_DWH_DEV'
wh_size: 'XSMALL'
data_retention_days: 1
configurations:
DEV:
env: 'DEV'
db: 'ACME_DWH_DEV'
wh_size: 'XSMALL'
data_retention_days: 1
QA:
env: 'QA'
db: 'ACME_DWH_QA'
wh_size: 'SMALL'
data_retention_days: 7
PROD:
env: 'PROD'
db: 'ACME_DWH_PROD'
wh_size: 'LARGE'
data_retention_days: 901.6 定义文件
infrastructure.sql 关键规则:
- 数据库和 schema 使用 {{db}},以便每个环境都有自己的
- 仓库是账户级对象(没有 database.schema 前缀)
-- Database per environment
DEFINE DATABASE {{db}};
-- Functional schemas
DEFINE SCHEMA {{db}}.EXTRACT;
DEFINE SCHEMA {{db}}.STAGE;
DEFINE SCHEMA {{db}}.WAREHOUSE;tables.sql 关键规则:
- 始终使用带有 {{db}} 的完全限定名称
- 按数据层组织(EXTRACT → STAGE → WAREHOUSE)
-- EXTRACT layer: raw/landing tables
DEFINE TABLE {{db}}.EXTRACT.CUSTOMERS_RAW (
id NUMBER AUTOINCREMENT,
raw_data VARIANT,
source_system VARCHAR(100),
loaded_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
)
CHANGE_TRACKING = TRUE
COMMENT = 'Raw customer data';
-- STAGE layer: cleansed tables
DEFINE TABLE {{db}}.STAGE.CUSTOMERS_CLEANED (
id NUMBER,
name VARCHAR(255) NOT NULL,
email VARCHAR(255),
staged_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
)
COMMENT = 'Cleansed customer data';
-- WAREHOUSE layer: modeled tables
DEFINE TABLE {{db}}.WAREHOUSE.DIM_CUSTOMER (
id NUMBER,
name VARCHAR(255) NOT NULL,
email VARCHAR(255),
updated_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
)
DATA_RETENTION_TIME_IN_DAYS = {{data_retention_days}}
COMMENT = 'Customer dimension table';access.sql 关键规则:
- 角色是账户级的,因此使用 {{env}} 后缀以避免冲突
- 授予最小权限:读取者只能看到 WAREHOUSE schema
-- Roles per environment
DEFINE ROLE ACME_ADMIN_{{env}};
DEFINE ROLE ACME_READER_{{env}};
-- Role hierarchy
GRANT ROLE ACME_READER_{{env}} TO ROLE ACME_ADMIN_{{env}};
GRANT ROLE ACME_ADMIN_{{env}} TO ROLE ACCOUNTADMIN;
-- Admin: full access
GRANT USAGE ON DATABASE {{db}} TO ROLE ACME_ADMIN_{{env}};
GRANT USAGE ON SCHEMA {{db}}.EXTRACT TO ROLE ACME_ADMIN_{{env}};
GRANT USAGE ON SCHEMA {{db}}.STAGE TO ROLE ACME_ADMIN_{{env}};
GRANT USAGE ON SCHEMA {{db}}.WAREHOUSE TO ROLE ACME_ADMIN_{{env}};
GRANT ALL ON ALL TABLES IN SCHEMA {{db}}.EXTRACT TO ROLE ACME_ADMIN_{{env}};
GRANT ALL ON ALL TABLES IN SCHEMA {{db}}.STAGE TO ROLE ACME_ADMIN_{{env}};
GRANT ALL ON ALL TABLES IN SCHEMA {{db}}.WAREHOUSE TO ROLE ACME_ADMIN_{{env}};
-- Reader: consumption layer only
GRANT USAGE ON DATABASE {{db}} TO ROLE ACME_READER_{{env}};
GRANT USAGE ON SCHEMA {{db}}.WAREHOUSE TO ROLE ACME_READER_{{env}};
GRANT SELECT ON ALL TABLES IN SCHEMA {{db}}.WAREHOUSE TO ROLE ACME_READER_{{env}};1.7 手动部署
在我们的更改准备就绪后,在 Snowsight 中你可以点击 Plan 来查看将要部署的对象,一旦你对这些更改满意,就将它们部署到目标环境。

我们学到了什么
Snowflake DCM 项目为我们提供了一种将数据库结构作为代码进行管理,并在 DEV、QA 和 PROD 之间一致地部署更改的方式。最大的转变是从手动管理架构更改转向声明式、由 Git 支持的方法,我们可以在应用更改之前先对其进行计划。
这是关于使用 Snowflake DCM 项目进行基础设施即代码的两部分系列指南中的第一篇。
后续步骤
- 在 docs.snowflake.com
- 注册一个 Snowflake 试用账户
- 注册一个 GitHub 账户
如果你觉得这有用,请在 LinkedIn 上关注我,以获取更多数据工程和 Snowflake AI 数据云用例。
Snowflake DCM 项目设置指南:数据库变更管理 最初发布于 Snowflake Builders Blog: Data Engineers, App Developers, AI, & Data Science 在 Medium 上,人们通过高亮和回应这个故事来继续对话。
这篇内容对你有用吗?
反馈只用于改善内容筛选,不等同于收藏