4. 基于共享的直接数据分发

Snowflake 的共享(Share)是一种“零拷贝”的数据分发机制:数据仍然只存放在提供方账户的数据库中,消费者账户通过共享对象获得对指定对象的只读访问权,而不会产生数据副本。理解这一点非常关键——共享不是导出文件,也不是复制表,而是把“访问权”授予另一个账户。因此,一次完整的直接数据分发任务,本质上由四个动作构成:创建共享容器 → 向共享中授予对象权限 → 把消费者账户加入共享 → 以消费者身份验证访问。下面按真实操作顺序展开。

一、创建共享:先有容器,再谈内容

共享本身是一个空的命名容器,创建时并不包含任何数据对象。使用提供方账户的 ACCOUNTADMIN 角色(或拥有 CREATE SHARE 权限的角色)执行:

USE ROLE ACCOUNTADMIN;

CREATE SHARE sales_share_retail
  COMMENT = '零售部门向外部合作方分发的销售汇总数据';

创建后可用 SHOW SHARES; 查看,此时 sales_share_retail 的 kind 为 OUTBOUND,表示这是一个对外共享。注意:共享是账户级对象,不属于某个数据库,因此命名时建议带上部门或用途前缀,便于多部门治理时区分归属。

二、授予对象权限:把“哪些对象、什么权限”放进共享

共享中只能放入数据库、模式、表、视图、安全视图、外部表、函数等对象,且授予的权限只能是 USAGE(对库和模式)与 SELECT(对表、视图等)。关键规则是:要共享一个表,必须先共享它所在的数据库和模式,否则消费者看不到路径。示例中提供方有一个数据库 retail_db,模式 sales_mart,其中有一张汇总表 monthly_sales_summary:

GRANT USAGE ON DATABASE retail_db
  TO SHARE sales_share_retail;

GRANT USAGE ON SCHEMA retail_db.sales_mart
  TO SHARE sales_share_retail;

GRANT SELECT ON TABLE retail_db.sales_mart.monthly_sales_summary
  TO SHARE sales_share_retail;

这里有一个治理上的重要选择:如果直接共享基表,消费者能看到表内全部行与列;如果只想暴露部分数据,应先创建安全视图(Secure View),在视图里做行过滤或列裁剪,再共享视图。例如只暴露华东区域、且隐藏成本列:

CREATE OR REPLACE SECURE VIEW retail_db.sales_mart.v_region_sales
  AS SELECT region, month, revenue
     FROM retail_db.sales_mart.monthly_sales_summary
     WHERE region = 'East';

GRANT SELECT ON VIEW retail_db.sales_mart.v_region_sales
  TO SHARE sales_share_retail;

安全视图的定义对消费者不可见,消费者只能查询结果,这使共享在“直接分发”的同时仍保留最小权限原则。授予完成后,可用 SHOW GRANTS TO SHARE sales_share_retail; 核对共享内对象清单,确认没有多授、漏授。

三、添加消费者账户:把共享指向具体账户

共享必须绑定到具体的消费者账户。Snowflake 支持两种方式:一是按账户名直接添加(适用于同一区域内已知账户),二是通过账户定位符(account locator)或组织中的账户名添加。以直接添加为例:

ALTER SHARE sales_share_retail
  ADD ACCOUNTS = partner_retail_acct;

如果消费者账户与提供方不在同一区域,则需要使用数据共享复制或跨区域共享能力,此时共享会先复制到目标区域再被消费。添加成功后,消费者账户会在其 SHOW SHARES; 中看到该共享,但此时还看不到任何数据——必须由消费者主动“挂载”。

四、消费者侧挂载与验证访问

消费者账户使用 ACCOUNTADMIN 角色,从共享创建数据库:

CREATE DATABASE partner_sales_db
  FROM SHARE provider_acct.sales_share_retail;

SHOW OBJECTS IN DATABASE partner_sales_db;

创建后,消费者即可像查询本地表一样查询共享对象,但只能读、不能写:

SELECT region, month, SUM(revenue) AS total_rev
FROM partner_sales_db.sales_mart.v_region_sales
GROUP BY region, month
ORDER BY month;

验证访问是否真正生效,建议从三个角度检查:可见性——SHOW OBJECTS 能看到预期对象;可读性——查询返回数据且行数与提供方视图一致;权限边界——尝试对共享对象执行 INSERT/UPDATE 应报错,尝试访问未共享的表应提示对象不存在。若消费者看不到对象,优先检查提供方是否漏授了库或模式的 USAGE 权限;若查询报“insufficient privileges”,则检查表或视图的 SELECT 是否已授予共享。

基于共享的直接数据分发:四步任务链 提供方账户 Provider ① 创建共享容器 CREATE SHARE sales_share_retail kind = OUTBOUND,初始为空 ② 授予对象权限 GRANT USAGE ON DATABASE retail_db GRANT USAGE ON SCHEMA sales_mart GRANT SELECT ON VIEW v_region_sales ③ 添加消费者账户 ALTER SHARE ... ADD ACCOUNTS = partner_retail_acct 跨区域需先复制共享到目标区域 消费者账户 Consumer ④ 挂载共享 CREATE DATABASE partner_sales_db FROM SHARE provider_acct.sales_share_retail 查询共享对象(只读) SELECT region, month, SUM(revenue) FROM partner_sales_db.sales_mart .v_region_sales GROUP BY ... 验证访问三要素 可见性:SHOW OBJECTS 有预期对象 可读性:查询返回数据且行数一致 边界:写入报错、未共享对象不可见 共享定义 账户绑定 数据不复制:消费者读取的仍是提供方存储中的对象

五、治理要点与常见排障

直接数据分发虽然操作简洁,但在多部门场景下必须配合治理约束。第一,共享对象最小化:优先共享安全视图而非基表,避免把整张明细表暴露给外部。第二,权限可追溯:定期执行 SHOW GRANTS TO SHARE 与 SHOW SHARES,形成共享清单,明确“哪个共享、给了哪个账户、包含哪些对象”。第三,撤销要及时:合作结束时用 REVOKE SELECT ON ... FROM SHARE 收回对象权限,或用 ALTER SHARE ... REMOVE ACCOUNTS 移除消费者账户,二者作用不同,前者影响所有消费者,后者只影响指定账户。

常见问题与判断依据可以归纳为:消费者看不到数据库,通常是提供方未授予数据库或模式的 USAGE;能看到库但看不到表,通常是表或视图的 SELECT 未授予共享;查询报权限不足,通常是消费者角色未被授予对该共享数据库的 USAGE;跨区域消费者无法挂载,通常是共享未复制到目标区域。掌握这条“容器—权限—账户—验证”的链路,就能在多部门数据分发中既快速交付,又保持权限边界清晰。