数据库视图:为数据量身定制的那扇“魔法窗户“
请你想象这样一个场景。在一座庞大的图书馆里藏书数以百万计分门别类地存放在一排排望不到头的书架上。这里有古籍善本有外文原著有内部资料也有面向大众的普通读物。现在来了一位小学生他只想看适合他这个年龄的童话和科普读物。你总不能把整座图书馆的钥匙都交给他让他在那浩如烟海、鱼龙混杂的书架间自己去翻找吧那既不安全也太过繁琐。聪明的图书馆管理员会怎么做呢他会专门为这个小学生开辟一个小小的儿童阅览区只把适合孩子的那些书精心挑选出来整齐地摆在这个区域里。小学生走进这个阅览区看到的就是一片专属于他的、干净而合适的天地他既看不到那些不该他看的内部资料也不必在百万藏书中费力搜寻所需要的一切都已经被妥帖地准备好了。这个为特定读者量身打造的专属阅览区恰恰就是我们今天要认识的数据库视图的绝妙写照。在数据库的世界里真实的数据存放在一张张被称为基本表的表里这些表往往庞大、复杂而且常常包含着各种各样的信息并非所有的使用者都需要、或者都应该看到其中的全部内容。这时候我们就需要一种机制能够像那个儿童阅览区一样从庞杂的基本表中按照特定的需要提炼、筛选、组合出一片专属的、量身定制的数据天地呈现给特定的使用者。这种神奇的机制就是数据库中一项极为重要的高级特性它的名字叫做视图。今天我们就来生动形象地认识这扇为数据量身定制的魔法窗户看一看数据库视图究竟有着怎样的奇妙本领。一、视图是什么一扇看得见数据却不存数据的窗户我们首先要弄清楚视图到底是个什么东西。这里有一个最关键、也最容易让初学者困惑的特点那就是视图本身并不真正存储数据它只是一扇窗户一扇透过它能看见底层真实数据的窗户。我们打个比方来体会。真实的数据好比是停在院子里的一辆辆汽车它们实实在在地占着地方是真正存在的实体这就好比数据库里的基本表。而视图呢则好比是房间墙上的一扇窗户。你站在窗前向外望去能清清楚楚地看到院子里的汽车但这些汽车并不在窗户里窗户里什么也没存它只是为你提供了一个观看院子的视角和画框而已。如果院子里的汽车开走了一辆你透过窗户看到的画面立刻就少了一辆如果又开进来一辆你看到的画面也立刻就多了一辆。窗户本身从不保存汽车它只是忠实地、实时地展现着院子里当下的真实情形。数据库的视图正是如此。视图是建立在一张或多张基本表之上的它实质上是一条被保存起来的查询语句。当我们去查看一个视图时数据库实际上是即时地去执行这条预先定义好的查询从底层的基本表里把相应的数据取出来呈现给我们看。所以视图里的数据永远是底层基本表里数据的实时反映。基本表里的数据一旦发生变化我们透过视图所看到的内容也会随之立刻变化因为视图根本就没有自己的数据它展现的本就是基本表的数据。正因为视图是这样一扇看得见数据却不存数据的窗户我们也常常把它叫做虚表。说它是表是因为它看起来就像一张实实在在的二维表有行有列可以像查询普通表一样去查询它。说它是虚的是因为它名下并没有真正存储任何数据它的数据都是从基本表里实时变出来的。理解了视图这种虚而不实、却又真实反映数据的特性我们就抓住了视图最核心的奥秘。二、如何创建视图把一条查询保存为一扇窗户理解了视图的本质我们来看看怎么动手创建一个视图。创建视图的过程说白了就是把一条查询语句保存下来并给它起一个名字今后这个名字就代表了这扇窗户。我们来设定一个具体的场景。假设有一张员工表叫做employees它记录了一家公司全体员工的信息包含这样几列员工编号id、姓名name、部门department、薪水salary、电话phone。这张表内容如下。idnamedepartmentsalaryphone1张三技术部12000138000000012李四技术部15000138000000023王五市场部9000138000000034赵六市场部11000138000000045孙七人事部800013800000005现在假设市场部的经理他只关心市场部的员工并不需要看到其他部门的人。我们就可以为他量身打造一扇只看得见市场部员工的窗户也就是创建一个视图。创建视图使用的是CREATE VIEW语句具体写法如下。CREATEVIEW市场部员工ASSELECTid,name,department,salary,phoneFROMemployeesWHEREdepartment市场部;这条语句的含义很清楚。CREATE VIEW后面跟着的市场部员工是我们为这个视图起的名字。AS后面跟着的就是这扇窗户所对应的那条查询语句意思是从employees表里把部门是市场部的所有员工的相关信息查出来。这条语句执行之后一个名叫市场部员工的视图就创建成功了。需要再次强调的是执行了这条语句数据库并不会把市场部的员工数据真的复制一份存起来它只是把这条查询语句记录了下来挂上市场部员工这个名字。从此市场部员工这个名字就成了一扇透视市场部数据的窗户。三、如何使用视图像查询普通表一样查询窗户视图创建好了怎么使用它呢这正是视图最方便的地方我们可以像查询一张普通的表那样去查询这个视图使用起来完全感觉不到它是虚的。比如市场部经理想看看市场部都有哪些员工他只需要这样查询。SELECT*FROM市场部员工;这条语句和我们平时查询一张普通表的写法一模一样。数据库收到这条语句后会去执行市场部员工这个视图当初定义的那条查询实时地从employees表里把市场部的员工捞出来呈现的结果如下。idnamedepartmentsalaryphone3王五市场部9000138000000034赵六市场部1100013800000004我们看到结果里清清爽爽地只有市场部的王五和赵六其他部门的张三、李四、孙七全都被挡在了这扇窗户之外看不见了。市场部经理透过这扇专属的窗户看到的就是一片只属于市场部的、干净的数据天地。不仅如此我们还能在视图的基础上做进一步的查询就像视图真是一张表一样。比如经理想从市场部员工里再筛选出薪水超过一万的人他可以这样写。SELECTname,salaryFROM市场部员工WHEREsalary10000;数据库会先通过视图取出市场部的员工再从中筛出薪水大于一万的结果如下。namesalary赵六11000可见视图用起来和普通表毫无二致我们可以查询它、筛选它、排序它而完全不必关心它背后那条复杂的查询语句是怎么写的。这正是视图带给我们的极大便利它把背后的复杂性藏了起来只把简单、合用的结果端到我们面前。四、视图的妙用之一化繁为简把复杂查询藏起来认识了视图的创建和使用我们接下来重点领略一下视图的种种妙用。视图的第一大妙用就是化繁为简能把异常复杂的查询封装起来藏在一扇简单的窗户后面。在实际工作中我们常常会遇到一些极其复杂的查询可能要把好几张表连接起来还要经过层层的筛选、分组、统计。比如要查询每个部门的平均薪水并且只显示平均薪水超过一万的部门这就需要写一条带有分组和筛选的、相对复杂的语句。如果这样的查询需要被频繁地使用每次都重新写一遍那么长的语句既麻烦又容易出错。这时视图就派上了大用场。我们可以把这条复杂的查询一次性地定义成一个视图。CREATEVIEW高薪部门ASSELECTdepartment,AVG(salary)AS平均薪水FROMemployeesGROUPBYdepartmentHAVINGAVG(salary)10000;这个视图把分组、求平均、筛选这一整套复杂的逻辑统统封装了起来。从此以后无论谁想查询高薪部门的情况都不必再去面对那条复杂的语句只需要简简单单地查询这个视图即可。SELECT*FROM高薪部门;结果便清晰地呈现出来。department平均薪水技术部13500你看多么简洁优雅。背后的复杂逻辑被彻底地隐藏了使用者面对的永远是一扇简单易用的窗户。这就好比一道工序繁琐的菜肴厨师把所有的烹饪步骤都在后厨完成了端到你面前的是一盘做好的、可以直接享用的美味你完全不必关心后厨里那些复杂的操作。视图化繁为简的这种本领极大地提升了数据库使用的便利性让复杂查询的复用变得轻而易举。五、视图的妙用之二保护数据把不该看的挡在窗外视图的第二大妙用是保护数据的安全能够把那些不该让某些人看到的敏感信息巧妙地挡在窗户之外。这正是开头那个图书馆例子的精髓所在。我们回头看那张员工表它包含了薪水和电话这样的敏感信息。薪水是隐私电话也属于个人信息并非所有人都有资格查看。比如公司里有一个普通的前台文员他可能需要知道每位员工的姓名和所属部门以便接待和指引但他绝对没有权限查看任何人的薪水和电话。如果我们直接把整张员工表的查看权限交给前台文员那薪水和电话也就一并暴露了这显然是不行的。视图为我们提供了一个绝妙的解决方案。我们可以专门为前台创建一个视图在这个视图里只暴露姓名和部门而把敏感的薪水和电话彻底排除在外。CREATEVIEW员工通讯录ASSELECTname,departmentFROMemployees;这个员工通讯录视图就像一扇特制的窗户透过它只能看到姓名和部门这两列薪水和电话根本不在这扇窗户的视野之内。然后我们把这个视图的查看权限授予前台文员而不直接给他原始员工表的权限。前台文员查询这个视图时看到的是这样的。namedepartment张三技术部李四技术部王五市场部赵六市场部孙七人事部他看到了所有员工的姓名和部门足以满足他的工作需要但薪水和电话被严严实实地挡在了窗外他无论如何也看不到。这样我们既满足了前台的合理需求又妥善地保护了员工的敏感隐私。视图就像一道精心设计的过滤屏障决定了哪些数据可以透过窗户被看见哪些数据必须被遮挡。这种保护数据安全的本领使视图成为数据库权限管理中一件极为有用的工具。六、视图的妙用之三提供逻辑独立性让窗外变化窗内安稳视图还有一个比较深层、但同样重要的妙用那就是它能为应用程序提供一种逻辑上的独立性起到一种缓冲和隔离的保护作用。我们设想这样一种情况。某个应用程序长期以来都依赖于某张表来获取数据程序里到处都写着对这张表的查询。有一天由于业务发展的需要数据库的设计者决定对底层的表结构进行调整比如把原来一张大表拆分成了两张小表。如果应用程序当初是直接面对那张大表来写查询的那么这一拆分就会导致程序里所有相关的查询统统失效需要大动干戈地逐一修改牵一发而动全身麻烦极了。可是如果当初应用程序面对的不是基本表而是一个视图情况就大不一样了。底层的表无论怎么拆分、怎么调整我们只需要相应地修改一下视图的定义让这个视图依然能从新的表结构中提取出和原来一模一样的数据、呈现出和原来一模一样的样子那么对于上层的应用程序来说它面对的那扇视图窗户看起来没有任何变化窗内的景象依旧如故程序就完全不需要修改可以照常运行。这就好比你房间的那扇窗户外面的院子重新整修了把停车场挪了个位置但只要管理员调整一下窗户的朝向和角度让你透过窗户看到的依然是那些汽车、依然是那个熟悉的画面那么你坐在房间里根本感觉不到外面发生了翻天覆地的变化你的生活照旧。视图就这样在底层数据结构和上层应用之间架起了一道隔离带、一层缓冲垫让窗外的变化不至于直接冲击窗内的安稳。这种逻辑独立性大大增强了数据库系统的可维护性和稳定性是视图一项不可小觑的深层价值。七、使用视图的注意事项窗户也有它的脾性视图虽然好处多多但我们在使用它时也要了解它的一些脾性和局限做到心中有数。首先最需要明白的一点前面已反复强调视图不存储数据每次查询视图数据库都要实时地去执行其背后的查询语句。这意味着如果一个视图背后的查询本身就非常复杂、非常耗时那么每次查询这个视图都要承担这份复杂查询的开销频繁使用可能会带来性能上的负担。所以对于那些极其复杂的视图要注意它对性能的潜在影响。其次通过视图来修改数据是受到诸多限制的。在某些简单的情况下我们确实可以通过视图来更新底层基本表的数据但这种可更新的视图有严格的条件。一旦视图的定义中涉及了分组、统计、多表连接等复杂操作比如前面那个统计平均薪水的高薪部门视图那它通常就是不可更新的了。道理也不难理解一个显示部门平均薪水的视图你怎么可能直接去修改那个平均值呢平均值是算出来的并不直接对应某条原始数据。所以对于复杂的视图我们一般只把它当作查看数据的窗户而不指望通过它去修改数据。了解了视图的这些脾性我们才能更恰当、更稳妥地驾驭它。八、结语行文至此我们以图书馆的专属阅览区作喻并辅以一系列具体的代码案例生动而完整地认识了数据库视图这扇为数据量身定制的魔法窗户。我们首先弄清了视图的本质明白了它是一扇看得见数据却并不存储数据的虚表是一条被保存起来、能够实时反映基本表数据的查询。接着我们通过员工表的例子亲手创建了视图并见识了查询视图就如同查询普通表一般简便。然后我们重点领略了视图的三大妙用它能化繁为简把复杂查询封装在简单的窗户之后它能保护数据把敏感信息巧妙地挡在窗外它还能提供逻辑独立性在底层数据和上层应用之间架起一道缓冲的隔离带。最后我们也了解了视图不存数据带来的性能考量以及复杂视图通常不可更新等需要注意的脾性。回顾这一番对视图的探寻我们能够深刻地体会到视图所体现的是一种封装与抽象的精妙思想。它在真实的、底层的、复杂的基本表之上构建了一个虚拟的、面向使用者的、简洁的呈现层。它就像一位贴心的中间人一头连着繁复的真实数据一头面对着各式各样的使用者根据每一类使用者的不同需要量身定制出最合适、最简洁、最安全的数据视角。需要简便的它就化繁为简需要保密的它就遮挡过滤需要稳定的它就缓冲隔离。这种把复杂留给自己、把简单和安全奉献给使用者的设计哲学正是视图最为可贵的价值所在。更值得我们品味的是视图的智慧启发着我们去思考软件设计中一个普遍而深刻的原则那就是适当的隔离与抽象往往能带来巨大的便利、安全与灵活。不让使用者直接面对底层的复杂与敏感而是为他们提供一个恰到好处的、经过精心裁剪的接口这一思想不仅贯穿于数据库的视图更广泛地体现在各类软件系统的设计之中。当我们今天能够透彻地理解视图的原理娴熟地运用它来化繁为简、保护数据、隔离变化时我们便真正掌握了这扇魔法窗户的奥秘。希望大家把视图的这份智慧牢记于心在今后与数据打交道的旅途中善用这扇神奇的窗户为不同的需求、不同的使用者巧妙地裁剪出一片片专属而妥帖的数据天地让我们经手的数据库系统既强大坚实又简洁优雅处处透着那份周到与从容。