MySQL – 视图的实现

本文参考了高性能MySQL

数据库中的视图是一个虚拟表。同真实的表一样,视图包含一系列带有名称的行和列数据。行和列数据来*定义视图查询所引用的表,并且在引用视图时动态生成。

 

视图的实现

视图中不存放任何数据,在使用SQL语句访问视图的时候,返回的数据时MySQL从其他表中生成的。视图和表在同一个命名空间,在很多地方对于视图和表是同样对待的。不过也有不同,不能对视图创建触发器,不能使用DROP TABLE命令删除视图。

 

假设我们创建一个视图:

create view Oceania as

select * from Country where Continent ='Oceania'

with check option;

 

实现视图最简单的方法是将select语句的结果存放到临时表中。当需要访问视图的时候,直接访问临时表就可以。比如:

select Code, Name from Oceania where Name =‘Australia’;

 

在实现上述查询时,有两种方式去实现,一种是使用临时表,还有一种是重写含有视图的查询,将视图的定义SQL直接包含进查询的SQL中:

使用临时表算法:

create temporary table TMP_Oceania_123 as

select * from Country where Continent = ‘Oceania’;

select Code, Name from TMP_Oceania_123where Name = ‘Australia’;

 

使用合并算法的:

select Code, Name from Country

where Continent = ‘Oceania’ and Name = ‘Australia’;

 

如果可能,会尽可能使用合并算法。下图是这两种算法实现的细节。

 MySQL – 视图的实现

 

如果视图中包含Group by, Distinct, 任何聚合函数,union,子查询等,只要无法在原表记录和视图记录中建立一一映射的场景中,MySQL都会使用临时表算法来实现。可以使用Explain来确定MySQL使用的具体算法。

 

更新视图

视图可以被更新。只要指定了合适的条件,就可以更新,删除甚至向视图中写入数据。如果视图定义中包含了group by, union, 聚合函数以及其他一些特殊情况,就不能被更新了。更新视图的查询可以是一个关联语句,但是有一个限制,被更新的列必须来自同一个表中。所有使用临时表算法实现的视图都无法被更新。

 

视图的性能

使用临时表算法实现的视图,在某些时候性能会很糟糕(可能比直接使用等效查询语句要好一点)。MySQL会以递归的方式执行这些视图,先会执行外层查询,即使外层查询优化器将其优化的很好,但是,内外结合的优化却无法做到非常好。如果打算使用视图来提升性能,需要做比较详细的测试。即便是合并算法实现的视图也会有额外的开销,而且使徒的性能很难预测。

 

视图的限制

视图有很多限制,比如,MySQL不支持物化视图(将视图结果数据存放在一个可以查看的表中,并定期充原始表中刷新数据到这个表中)。也不支持在视图中创建索引。当然,可以通过构建缓存表或者汇总表的办法来模拟。也可以直接使用工具Flexviews来实现这个目的。

 

MySQL并不会保存视图定义的原始SQL语句,所以,如果我们希望简单的修改视图的结果来重新定义,有的人可能会直接使用show create view语句来查看之前的定义,但是该语句查询出来的视图创建语句会让人大失所望,没有格式化,没有注释,没有缩进,基本不可读。