StarRocks CREATE VIEW 详解:逻辑视图创建、安全视图(SECURITY)与源码级实现原理
【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks
CREATE VIEW 是 StarRocks 中创建逻辑视图(Logical View)的核心 DDL 语句。它把一段查询固化为可复用的虚拟表,不占用物理存储,查询视图等价于执行其背后的子查询。本文以官方 SQL 参考文档为基础,完整覆盖CREATE VIEW的语法、参数、安全视图(SECURITY NONE/INVOKER,自 v3.4.1 起支持)、使用注意事项与实战示例,并结合当前仓库 FE 源码(解析、分析、授权、执行全链路)与单元测试,深入剖析视图的底层实现,帮助读者在 StarRocks 中正确地创建、管理并安全地使用视图。
一、什么是逻辑视图
视图(View),又称逻辑视图(Logical View),是一种虚拟表:它的数据并不真实存储,而是由一条针对其他物理表(或视图)的查询语句派生而来。因此:
- 视图不占用任何物理存储,不复制底层数据;
- 查询视图等价于执行构建该视图的查询语句作为子查询;
- 视图对使用者隐藏了底层表结构,可以沉淀常用的复杂查询(多表关联、聚合、窗口函数等)为可复用对象,同时是 StarRocks 实现行级/列级安全的重要手段。
StarRocks 中的视图分为两类:
| 类型 | 说明 | 官方文档 |
|---|---|---|
| 逻辑视图(View) | 本文主题,无物理存储,查询时动态展开 | 本文 |
| 同步物化视图 | 与基表同步维护,有物理存储 | Synchronous materialized views |
| 异步物化视图 | 异步刷新,可跨表、跨 catalog | Asynchronous materialized views |
物化视图会物化(存储)查询结果以加速查询,而逻辑视图仅做"查询的封装",两者定位不同,创建与维护语法也完全不同。
二、CREATE VIEW 完整语法
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [<database>.]<view_name> ( <column_name>[ COMMENT 'column comment'] [, <column_name>[ COMMENT 'column comment'], ...] ) [COMMENT 'view comment'] [SECURITY {NONE | INVOKER}] AS <query_statement>注意:
CREATE VIEW与CREATE MATERIALIZED VIEW语法并不相同,前者创建逻辑视图,后者创建物化视图。
参数说明
| 参数 | 描述 |
|---|---|
OR REPLACE | 替换已存在的同名视图。若目标视图不存在,CREATE OR REPLACE VIEW直接创建新视图。 |
IF NOT EXISTS | 若同名视图已存在则不执行创建(不报错)。注意:IF NOT EXISTS与OR REPLACE不能同时出现(解析器会直接报冲突错误,见下文源码分析)。 |
database | 视图所在的数据库名称,可省略,省略时默认使用当前数据库。 |
view_name | 视图名称,命名需遵循 System limits 中的对象命名规范(仅可由数字、字母、下划线组成,以字母或下划线开头,长度不超过 64 字符,且区分大小写)。 |
column_name | 视图的列名列表。视图列的数量必须与query_statement查询输出列的数量一致;若不显式指定列名,则直接继承查询输出列的名称。 |
COMMENT | 列的注释或视图本身的注释,用于元数据管理与人可读描述。 |
SECURITY | 指定视图被调用(invocation)时进行权限校验的安全上下文,决定谁能查询该视图。合法取值:NONE(默认)与INVOKER,详见下文"安全视图"章节。 |
query_statement | 构建视图的查询语句,可以是 StarRocks 支持的任何查询语句,包括多表 JOIN、聚合、窗口函数等。 |
三、安全视图:SECURITY NONE 与 SECURITY INVOKER
从v3.4.1开始,StarRocks 支持安全视图(Secure View)。安全视图解决的核心问题是:能否限制"对视图有 SELECT 权限、但对基表没有 SELECT 权限"的用户查询该视图。
SECURITY取值 | 行为 | 适用场景 |
|---|---|---|
NONE(默认) | 用户只需对视图本身拥有 SELECT 权限即可查询视图,不额外检查其对基表的权限。 | 通过视图做行/列级权限收敛:把 SELECT 权限授予视图而非底层表,实现"白名单列"数据暴露。 |
INVOKER | 用户必须同时对视图本身和视图引用的所有基表拥有 SELECT 权限,才能查询视图。 | 基表本身敏感(如含手机号、身份证列),禁止通过视图间接绕过基表权限管控。 |
也就是说,SECURITY INVOKER会阻止"只对视图有权限、对底层基表无权限"的用户利用视图越权读取数据。
会话级默认值:default_view_sql_security
在 SQL 语句省略SECURITY子句时,视图的安全特性由会话变量default_view_sql_security决定:
NONE(默认值):等价于显式声明SECURITY NONE;INVOKER:等价于显式声明SECURITY INVOKER。
设置方式示例:
SET default_view_sql_security = 'INVOKER';从源码看,该逻辑在分析阶段完成。ViewAnalyzer.java 的visitCreateViewStatement中,当语句未显式指定SECURITY时(!stmt.isSecurityExplicit()),会读取context.getSessionVariable().getDefaultViewSqlSecurity()回填安全特性:
if (!stmt.isSecurityExplicit()) { DefaultViewSqlSecurity defaultSecurity = context.getSessionVariable().getDefaultViewSqlSecurity(); stmt.setSecurity(defaultSecurity == DefaultViewSqlSecurity.INVOKER); }而DefaultViewSqlSecurity枚举定义于 SessionVariableConstants.java,默认值为NONE:
public enum DefaultViewSqlSecurity { NONE, // 仅检查调用者对视图本身的权限(映射 SECURITY NONE) INVOKER; // 额外检查调用者对视图所引用基表的权限(映射 SECURITY INVOKER) public static DefaultViewSqlSecurity getDefault() { return NONE; } }优先级规则(由单元测试 CreateViewTest.java 的testDefaultViewSqlSecurity与testDefaultViewSqlSecurityWithReplace完整覆盖):
- 语句中显式声明的
SECURITY子句永远优先于会话默认值; - 省略
SECURITY子句时,采用会话变量default_view_sql_security的值; CREATE OR REPLACE VIEW在替换既有视图时,同样遵循上述规则——会话默认值变化会改变被替换后视图的安全特性,而显式SECURITY子句则固定其取值。
安全视图的权限校验语义
查询视图时,StarRocks 的授权器(Authorizer)会根据视图的security标记决定校验范围。视图的安全标记存储在 FE 元数据对象 View.java 中(private boolean security = false,默认即SECURITY NONE):
- 视图
security == false(SECURITY NONE):查询仅校验用户对视图本身的 SELECT 权限; - 视图
security == true(SECURITY INVOKER):查询同时校验用户对视图及视图所引用基表的 SELECT 权限。
四、使用注意事项
- 查询一个视图,需要拥有对该视图的 SELECT 权限;若视图为
SECURITY INVOKER安全视图,还需要对其引用的全部基表拥有 SELECT 权限。 - 如果构建视图的查询语句因基表发生Schema Change(表结构变更)而无法继续执行,StarRocks 会在你查询该视图时返回错误——因此对视图所依赖的基表做结构变更前,需要评估对既有视图的影响。
- 视图不能基于**临时表(Temporary Table)**创建。该限制在分析器中有显式校验(
ViewAnalyzer中AnalyzerUtils.hasTemporaryTables检查,命中时抛出SemanticException: View can't base on temporary table)。 - 视图的查询语句中禁止使用Time Travel(时间旅行)查询(分析器通过
AnalyzerUtils.prohibitTimeTravelQuery(..., "create view")拦截)。
权限要求
- 执行
CREATE VIEW需要拥有目标数据库的CREATE VIEW 权限; - 同时,创建视图所用查询语句涉及的表,要求执行者拥有相应查询权限。
从源码看,这两条权限检查在 AuthorizerStmtVisitor.java 的visitCreateViewStatement中依次完成:先通过Authorizer.checkDbAction(catalog, dbName, PrivilegeType.CREATE_VIEW)校验数据库级CREATE_VIEW权限,再通过check(statement.getQueryStatement(), context)校验查询语句涉及对象的权限。
五、实战示例
以下示例均以表example_table(含列c1、k1、k2、k3、v1)为基础。
示例 1:创建基础视图(聚合查询)
在example_db中创建名为example_view的视图,封装对example_table的聚合查询,视图列名为k1, k2, k3, v1:
CREATE VIEW example_db.example_view (k1, k2, k3, v1) AS SELECT c1 as k1, k2, k3, SUM(v1) FROM example_table WHERE k1 = 20160112 GROUP BY k1,k2,k3;这里通过c1 AS k1将基表列c1重命名为视图列k1,视图列的数量(4 个)与查询输出列的数量严格对应。
示例 2:带注释的视图
为视图本身和每个视图列添加注释,便于元数据管理:
CREATE VIEW example_db.example_view ( k1 COMMENT 'first key', k2 COMMENT 'second key', k3 COMMENT 'third key', v1 COMMENT 'first value' ) COMMENT 'my first view' AS SELECT c1 as k1, k2, k3, SUM(v1) FROM example_table WHERE k1 = 20160112 GROUP BY k1,k2,k3;注释会写入视图的元数据,可以通过SHOW CREATE VIEW等语句查看。单元测试createViewWithComment也验证了视图定义中的注释(如 SQL 行内注释-- This is a comment from user)会被完整保留在视图定义中。
示例 3:创建安全视图(SECURITY INVOKER)
在example_db中创建安全视图example_view,要求查询者必须同时拥有基表example_table的 SELECT 权限:
CREATE VIEW example_db.example_view (k1, k2, k3, v1) COMMENT 'my secure view' SECURITY INVOKER AS SELECT c1 as k1, k2, k3, SUM(v1) FROM example_table WHERE k1 = 20160112 GROUP BY k1,k2,k3;创建后,仅对视图有 SELECT 权限、对example_table无 SELECT 权限的用户将无法查询该视图。
示例 4:幂等创建与替换
-- 仅当视图不存在时创建 CREATE VIEW IF NOT EXISTS example_db.example_view AS SELECT k1, k2 FROM example_table; -- 视图已存在则原子替换(不可与 IF NOT EXISTS 同时使用) CREATE OR REPLACE VIEW example_db.example_view AS SELECT k1, k2, k3 FROM example_table;六、视图的查看、修改与删除
创建视图后,可配合以下语句完成视图生命周期管理:
SHOW CREATE VIEW:查看视图定义
SHOW CREATE VIEW返回创建视图时的 CREATE VIEW 语句,帮助理解视图定义并作为修改、重建的参考。需要拥有视图及其基表的 SELECT 权限(自 v2.5.4 起也支持查询物化视图的创建语句)。
SHOW CREATE VIEW [db_name.]view_name输出结果包含View(视图名)、Create View(视图的 CREATE 语句)、character_set_client与collation_connection四个字段。完整说明见 SHOW CREATE VIEW。
ALTER VIEW:修改视图定义
视图是逻辑对象,修改视图定义等价于修改其query_statement:
ALTER VIEW [db_name.]view_name (column1[ COMMENT "col comment"][, column2, ...]) AS query_stmt例如:
ALTER VIEW example_db.example_view ( c1 COMMENT "column 1", c2 COMMENT "column 2", c3 COMMENT "column 3" ) AS SELECT k1, k2, SUM(v1) FROM example_table GROUP BY k1, k2;完整说明见 ALTER VIEW。
DROP VIEW:删除视图
DROP VIEW [IF EXISTS] [db_name.]view_name示例:
DROP VIEW IF EXISTS example_db.example_view;IF EXISTS可避免视图不存在时抛错。完整说明见 DROP VIEW。
七、源码级原理:一条 CREATE VIEW 语句的完整旅程
结合 FE 源码,CREATE VIEW的执行链路可分为五个阶段:
1. 语法解析(Parser)
AstBuilder.java 的visitCreateViewStatement将 SQL 文本解析为 AST 节点 CreateViewStmt.java:
- 解析
IF NOT EXISTS与OR REPLACE标志,且两者互斥——同时出现时直接抛出ParsingException(conflictedOptions("if not exists", "or replace")); - 解析显式的
SECURITY NONE / SECURITY INVOKER,记录securityExplicit(是否显式指定); - 解析视图注释、列名与列注释(
ColWithComment列表)以及查询语句,并记录查询语句在原始 SQL 中的起止位置(queryStartIndex/queryStopIndex),供后续截取原始视图定义文本使用。
2. 语义分析(Analyzer)
ViewAnalyzer.java 的visitCreateViewStatement负责:
- 归一化表引用、校验视图名称合法性(
FeNameFormat.checkTableName); - 处理上文所述的
SECURITY会话默认值回填逻辑; - 校验视图不允许基于临时表、不允许时间旅行查询;
- 通过
analyzeViewColumns推导视图列:若用户未显式指定列名,则从查询输出字段(RelationFields)自动生成视图列(类型取自字段类型以保证 UNION 等场景下类型正确);若用户指定了列名/注释,则校验列数量必须与查询输出列数量一致,否则报错(ERR_VIEW_WRONG_LIST),并检测重复列名; - 生成两段视图定义文本并存储:
inlineViewDef(重写后的规范化视图 SQL,AstToSQLBuilder.toSQLWithCredential)与originalViewDefineSql(从原始语句中截取的用户书写原文)。
3. 权限校验(Authorizer)
AuthorizerStmtVisitor.java 校验执行者拥有目标库的CREATE_VIEW权限,并校验查询语句涉及对象的权限(见第四节)。
4. 执行与元数据落库(Executor)
DDLStmtExecutor.java 的visitCreateViewStatement将执行委托给元数据管理器:
GlobalStateMgr.getCurrentState().getMetadataMgr().createView(context, stmt);对于内部 Catalog,视图定义、列信息、注释与安全标记写入 FE 元数据(对应View表对象 View.java);对于外部 Catalog,视图定义会转换为ConnectorViewDefinition写入对应连接器(如 Iceberg)。另外,CreateViewStmt中的properties仅允许为Iceberg 视图设置属性,对其他 Catalog 会抛出SemanticException。
5. 查询时展开(Runtime)
视图在查询时被当作内联子查询展开:StarRocks 读取视图的inlineViewDef,将其替换进查询计划,再对底层基表执行真实的扫描与计算。这正是"查询视图等价于子查询"这一特性的底层机制。
八、测试验证
仓库中的单元测试 CreateViewTest.java 覆盖了本文涉及的关键行为,可作为复现与验证的参考:
createViewWithComment:验证视图定义(含注释)可被SHOW CREATE VIEW完整还原;testDefaultViewSqlSecurity:验证default_view_sql_security会话变量的NONE/INVOKER默认值行为,以及显式SECURITY子句对默认值的覆盖优先级;testDefaultViewSqlSecurityWithReplace:验证CREATE OR REPLACE场景下会话默认值与显式SECURITY的交互。
九、总结
CREATE VIEW是 StarRocks 中创建逻辑视图的标准入口,语法简洁但功能完整:支持OR REPLACE原子替换、IF NOT EXISTS幂等创建、列注释与视图注释、任意查询语句封装,以及自 v3.4.1 起的安全视图能力(SECURITY NONE/INVOKER,受会话变量default_view_sql_security控制)。理解其"查询时展开为子查询"的物理本质,掌握安全视图的权限语义,并配合SHOW CREATE VIEW、ALTER VIEW、DROP VIEW完成全生命周期管理,即可在 StarRocks 中安全、高效地复用查询逻辑并实施细粒度的数据权限管控。
若需要真正的查询加速能力(存储结果、自动刷新),请参考 Synchronous materialized views 与 Asynchronous materialized views。
【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考