原文:https://blog.csdn.net/chuangxin/article/details/84574557

《SQLite权威指南》中作者是这么定义视图的:视图即是虚拟表,也称为派生表,因为它们的内容都派生自其它表的查询结果。虽然视图看起来感觉和基本表一样,但是它们不是基本表。基本表的内容是持久的,而视图的内容是在使用过程中动态产生的。

1、视图创建、修改SQL语法
MySql参考手册5.7 14.1.21 CREATE VIEW Syntax

CREATE [OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] [DEFINER = { user | CURRENT_USER }]
[SQL SECURITY { DEFINER | INVOKER }]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]

Sqlyog, Navicat等客户端工具都可以可视化定义、修改视图,因此不再赘述。

2、视图用途及使用场景
用途:
视图根本用途在我看来就一个:简化sql查询,提高开发效率。如果说还有另外一个用途那就是兼容老的表结构。

使用场景:
1)计算列的需要,数据库设计范式要求我们减少冗余字段,因此现在很多数据表都没有计算列字段,如采购单:有价格、数量、税率、含税金额,多半没有不含税金额、税额,而这些字段在很多报表中有都会用到,所以我们可以创建一个含有计算列字段的视图来解决这个问题。

2)不同表字段聚合,信息重组,如:经销商通常有业务员,业务员通常有上下级关系(客户经理、区域经理、大区经理等),因此查看经销商业务员时我们需要看到直管业务员是谁?该业务员对应的区域经理、大区经理是谁(可能NULL)?因此我们可以联合经销商表、业务员信息表、业务员上下级关系表定义一个经销商视图。

3)安全性需要,主要是早期遗留系统集成需要,如:需要xx系统数据,又没接口,怎么办?直接操作数据库,这时就涉及数据安全性,合理利用视图则可以减少很多授权工作和保证数据安全性。当下新构建的系统几乎都是暴露api接口,因此数据安全性更多关注在接口的身份认证和数据粒度方面。

4)兼容老的数据表,曾经碰到过这么个问题。
公司自主研发的进销存管理系统,一开始自用的,后来合作伙伴企业也要用,所以打算Saas化,当初做了一个最大的变动就是几乎所有表增加了一个使用单位(co_id)字段。悲催的是另外一个外购系统用到了采购单表,该系统已经停止维护、又继续在用。于是就创建了一个co_id=自有公司的视图,命名为原采购单表,而原采购单表改成新表名。这样一来外购系统可以继续使用,而且数据也没问题。

3、视图性能及使用注意事项
又要sql简化提高开发效率,又要提升性能,这确实有点鱼和熊掌不可兼得,更何况查询有点弱鸡的MySql,那怎么办?我的建议是使用视图可以获取预期数据又不至于性能变差就很好了。如何不使性能变差呢?
MySQL在处理视图时有两种算法,分别称为MERGE和TEMPTABLE。
在执行"CREATE VIEW"语句时可以指定使用哪种算法。不显现指定的话,Mysql默认使用Merge算法。

MERGE,将视图sql合并到主查询sql中,重新构成新sql进行查询。网上有个大侠说的挺好“有点类似于C语言中的宏展开”
TEMPTABLE,见文知意,就是将视图单作临时表来处理。
所谓MERGE是指在处理涉及到视图的操作时,将对视图的操作根据视图的定义进行展开,有点类似于C语言中的宏展开。
一般来说在能够使用MERGE算法的时候MySQL处理视图上没什么性能问题,因为可以使用索引、mysql查询优化算法,但并非在任何时候都能使用MERGE算法。事实上,只要视图的定义稍稍有点复杂,MySQL就没办法使用MERGE算法了。准确的说,只要视图定义中使用了以下SQL构造块就无法使用MERGE算法:

聚集函数
DISTINCT
GROUP BY
HAVING
集合操作(UNION, UNION ALL)
子查询

对于复杂视图定义,MySQL使用了一种以不变应万变的方法,即先执行视图定义,将其结果使用临时表保存起来,这样后续对视图的操作就转化为对临时表的操作。不能不说从单从软件设计的角度看,这样的方法非常的优雅,然而从性能角度,这一方法也是非常的差。

使用注意事项:
1)尽量让视图采用merge算法,视图定义中避免DISTINCT、GROUP BY等集合相关运算;
2)如果视图很复杂采用TEMPTABLE的话,想办法减少TEMPTABLE记录数。

05-28 19:18