数据库系统工程师上午综合知识考试中,"视图"是常年驻场的高频考点,几乎每年都以不同面目出现:有时考定义与本质,有时考更新限制,有时考它在三级模式中的位置,还有时用一句"关于视图说法错误的是"让考生左右为难。更麻烦的是,视图横跨概念定义、SQL语法、系统实现和安全管理四个层面,只背一句"视图是虚表"难以应对命题人的陷阱。本文以2024年上半年真题为线索,从三级模式结构讲起,深入到视图消解、可更新视图的判定规则、WITH CHECK OPTION的语义与物化视图的底层机制,把这一考点从定义到实现、从应试到工程实践一次讲透。
要准确理解视图,必须先把它放回数据库系统的基本结构中去定位。数据库系统教材中有一个贯穿始终的经典框架——三级模式两级映像。三级模式指的是外模式、概念模式(通常简称为模式)和内模式。外模式面向用户,是不同用户眼中的数据视图;模式面向全局,描述整个数据库的逻辑结构;内模式面向物理存储,描述数据的存储方式和存取路径。两级映像则是指外模式与模式之间的映像、模式与内模式之间的映像,正是这两级映像保证了程序与数据之间的逻辑独立性和物理独立性。
视图就生长在外模式这个层面上。准确地说,视图不是外模式本身,而是构成外模式的直接材料——外模式由若干视图和部分基本表共同组成。数据库管理员为不同的用户、不同的应用定义不同的视图,再把这些视图连同若干基本表组合成用户所能看到的那一个外模式。用户通过视图看到的数据,只是他有权看到、且与其业务相关的那个局部。因此,视图天然具有两层身份:它既是逻辑数据独立性的实现手段,也是数据库安全控制的第一道门户。在三级模式两级映像这个考点上,命题人经常问"视图属于哪一级模式",标准答案是外模式层面的用户视图,考生务必与"模式"和"内模式"划清界限。
教材给视图下的标准定义是:视图是从一个或几个基本表(或视图)导出的表,它是一个虚拟表。这个定义里最关键的词是"虚拟"二字,命题人对它的考察方式几乎是固定的。
第一,视图在物理上不存在。基本表在数据库中实实在在占有存储空间,表中的每一行数据都以物理记录的形式躺在磁盘上;而视图并不保存任何数据,数据库里保存的只是视图的定义——一段存储在系统目录(数据字典)中的查询语句文本。当用户查询视图时,数据库管理系统临时执行这段定义语句,把结果计算出来呈现给用户。从这个意义上说,视图是一扇窗,而不是一间房:透过窗子看到风景,但窗子本身不产生风景。
第二,视图的数据来自基表。视图一经定义,就可以和基本表一样被查询、被删除,甚至在满足条件时被更新。但所有针对视图的操作最终都会转化为对基本表的操作,视图本身不独立持有数据。当基本表中的数据发生变化时,从视图中查询到的数据随之自动变化,这正是"导出"一词的含义。
第三,视图的定义存储在数据字典中。创建视图的语句执行之后,数据库管理系统并不执行它,而是把视图名称、所属模式、定义文本、列名列表等信息作为元数据写入系统目录。这也解释了为什么视图被称为"存储的查询"——存储的是查询定义,而非查询结果。
真题题干中,视图相关的表述还有几种常见变体,考生需能相互对应。其一,"视图是逻辑数据独立性的体现"——基本表结构变化时,修改视图定义即可让用户程序看到的外部接口不变。其二,"视图是数据安全性的手段"——通过视图把敏感的列、敏感的行隐藏起来,实现列级和行级控制。其三,"视图不能提高查询效率"——普通视图每次查询都要执行视图消解,不但不提速,还可能因定义复杂而增加开销,这是命题人爱挖的坑,后文会专门展开。把这三种表述与视图本质对应起来,概念题基本可以不丢分。
视图之所以能像基本表一样被查询,靠的是一套被称为"视图消解"的机制。当用户提交一条针对视图的查询语句时,数据库管理系统的查询处理流程会经历一个基本表查询所没有的额外环节:查询改写。具体过程是,系统先从数据字典中取出该视图的定义语句,把用户查询中引用视图的部分替换为视图定义中的子查询,从而把"对视图的查询"改写成一条"只涉及基本表的等价查询",然后再交给常规的查询优化器去生成执行计划。
举例来说,假设职工表上定义了视图"高级职工视图",只含工资高于一万的记录。当用户查询"高级职工视图中年龄大于五十的记录"时,系统会把它改写为"查询职工表中工资高于一万且年龄大于五十的记录"再执行。用户完全感知不到改写过程,这正是视图透明性的含义。
视图消解带来的一个直接推论是:视图的查询效率取决于改写后等价查询的执行计划,而不取决于视图本身的"复杂度"这种空泛概念。如果视图定义中包含了复杂的连接、分组、排序,每次查询都要重复执行这些运算,性能开销自然高于直接查基本表。只有在视图定义简单且查询改写能够充分利用基表索引的情况下,视图查询的开销才与基本表查询接近。所以考试中若出现"视图可以加快查询速度"之类的选项,直接判错即可,这条判断背后就是视图消解的原理。
从系统实现的角度看,创建视图分为定义和存储两个阶段。第一阶段是语法检查和语义检查。数据库管理系统检查视图定义语句的语法是否正确,再检查定义中引用的基本表和视图是否存在、用户是否拥有相应的查询权限、列名是否合法。第二阶段是把视图定义写入系统目录。系统目录中会记录视图的名称、定义者、列名、定义文本等信息,之后所有涉及该视图的操作都以系统目录中的这份定义为依据。值得注意的是,定义阶段并不访问基本表中的数据,所以创建视图的代价很低,与表中有多少行数据没有关系。
视图一经建立,即可像基本表一样被引用,也可以基于视图再定义新视图,形成层层嵌套。嵌套层次理论上没有硬性上限,但过深会使改写后的语句急剧膨胀,工程中一般不超过两三层。命题人在此处的常见考法是"视图可以基于其他视图建立",此说法正确;"视图只能基于基本表建立"则是错误表述。
视图"虚"的规则有一个重要例外,那就是物化视图。物化视图把视图的查询结果实际存储到磁盘上,因此它既保留了视图的逻辑接口,又拥有基本表那样的物理数据。物化视图解决的问题是:当视图定义涉及的运算非常昂贵,而底层数据又很少变化时,与其每次查询都现场计算,不如把结果算好存起来,查询时直接读取,牺牲一部分实时性换取查询性能。
物化视图的维护是它的核心难题。基本表数据一旦更新,物化视图的结果就会过时,需要维护机制保证一致。维护策略大体两类:即时维护在基本表更新事务提交时同步更新物化视图,保证强一致性,代价是更新延迟增加;延迟维护先允许视图暂时陈旧,再择机整体或增量刷新,适合对实时性要求不高的统计分析场景。考题中物化视图出现频率低于普通视图,命题点通常集中在"与普通视图的本质区别"和"为何能提高查询性能"上。考生记住一句话即可:普通视图存定义、物化视图存数据,二者各得其所。
按照定义中查询语句的形态,视图可以划分出几种典型类别。第一种是行列子集视图,即从单个基本表出发,用选择操作取出部分行、用投影操作取出部分列,构成的视图。这类视图结构最简单,也是唯一一类理论上必然可以更新的视图。第二种是分组视图,定义中带有GROUP BY子句和聚合函数,比如按部门统计平均工资的视图。分组视图把多行压缩成一行,基本表与视图行之间不再一一对应,因此不可更新。第三种是连接视图,定义中带有多表连接,把多个基本表的数据横向拼合。连接视图的更新规则复杂,通常只有满足特定条件的连接视图才允许部分更新。第四种是基于视图的视图,即嵌套视图,其性质取决于最终展开后的定义语句。
命题人通常给出一段视图定义问其类别,或反过来问"哪一类视图一定可以更新"。行列子集视图与基本表存在一一对应的行列映射,更新可无歧义翻译到基本表上,所以"行列子集视图可更新"是教材明确结论,务必记牢。
"视图到底能不能更新"是考试中失分最严重的区域之一。教材对可更新视图给出了明确的限制条件,这些限制可以归纳为五个方面。
其一,视图定义中不能含有集合运算。如果视图的查询语句使用了UNION、INTERSECT、EXCEPT等集合操作,视图行与基本表行之间不存在可逆的映射关系,更新操作无法定位到唯一的基表行,视图不可更新。
其二,视图定义中不能含有GROUP BY和聚合函数。分组与聚合把多行折叠为一行,视图中一行可能对应基本表中的成百上千行,此时执行一条更新语句,数据库管理系统无法判断应该修改基本表中的哪些行,因此不可更新。
其三,视图定义中不能含有DISTINCT去重操作。去重同样破坏了一一对应关系:视图里的一行可能由基本表中多个相同行合并而来,更新自然无法翻译。
其四,视图中未包含的基表列若定义为非空且无默认值,则不能执行插入操作。插入一行视图数据时,视图中没有出现的
本篇完!