视图可以看做定义在SQL Server上的虚拟表,视图正如其名字的含义一样,是另一种查看数据的入口,常规视图本身并不存储实际的数据,而仅仅存储一个select语句和所涉及的表的关系。
通过视图,客户端不再需要知道底层table的表结构及其之间的关系,视图提供了一个统一访问的数据的接口。
视图的优点
1、视图隐藏了底层的表的结构,简化了数据访问的操作
2、因为隐藏了底层的表结构,所以大大加强了安全性,用户只能看到视图提供的数据
3、使用了视图,方便了权限管理,让用户对视图的权限而不是度底层表的权限进一步加强了安全性
4、提供了一个用户访问的接口,当底层表改变后,改变视图语句来进行适应,使已经建立在这个视图客户端程序不受影响
5、对相关联的表进行封装,有点OO的感觉
视图的分类
1、普通视图(Regular view)
2、索引视图 (Indexed view)
3、分割视图 (Parritoned View)
普通视图
普通视图由一个select语句所定义,视图仅仅包含其定义和被引用表的关系,并不实际存数数据,MSDN中模板
CREATE VIEW [ schema_name . ] view_name [ (column [ ,...n ] ) ]
[ WITH <view_attribute> [ ,...n ] ]
AS select_statement
[ WITH CHECK OPTION ] [ ; ]
<view_attribute> ::=
{
[ ENCRYPTION ]
[ SCHEMABINDING ]
[ VIEW_METADATA ] }
encryption:视图是加密的,如果选上这个选项,则无法修改,创建视图的时候需要将脚本保存,否则再也不能修改了
schemabinding:和底层引用到的表进行定义绑定。这个选项选上的话,则视图所引用的表不能随便更改框架(比如列数据类型),如果需要更改底层表架构,则先drop或者alter在底层表上绑定的视图。
view_metadata:不选择,返回客户端的metadata是view所引用表的metadata,如果选择了这个选项,则返回view的metadata,再通俗点解释,view_metadata可以让视图看起来貌似表一样。view的每一个列的定义等直接告诉客户,而不是底层表列的定义。
with check option:这个选项用于更新数据库做限制,下面会在通过视图更新数据以及解释
视图需遵守的几点
1、view中,除非有top关键字,否则不能用order by子句(如果你一意孤行需要用order by,这里有个hack使用TOP 100 percent....)
2、view在每个schema中命名独一无二
3、view嵌套不能超过32层,实际应用中超过两层的都不多
4、compute,compute by,INTO关键字不允许出现在View中
5、View不能建立在临时表中
6、View不能对全文索引进行查询
建立一个简单的View的例子:
create view v_test_view
as
select Top 100* from Employee
视图建立完成后,就可以像访问表一样访问视图了:
select * from V_test_view
索引视图(Indexed View)
索引视图就是在普通视图的基础上,为视图建立唯一性聚集索引,这时这个视图就变成了索引视图简单点讲:视图+聚集索引=索引视图
索引视图可以看做是一个和表(Table)等效的对象
SQL Server中的索引视图和Orcle中的Materialized View是一个概念,想要理解索引视图,必须先理解聚集索引。聚集索引简单来说理解成主键,数据库中的数据按照主键的顺序物理存储在表中,就像新华字典,默认是按照ABCD...这样的方式进行内容设置。ABCD...就相当于主键,这样就避免了整表扫描从而提高了性能,因此一个表中只能有一个聚集索引。
对于索引视图也是,为一个视图加上了聚集索引后。视图就不仅仅再是select语句和表的meatadata了,索引视图会将数据物理存储在数据库中,索引视图的数据和索引视图中所涉及的底层保持同步。
理解了索引视图的原理之后,我们可以看出,索引视图对于OLAP这种大量数据分析和查询来说,性能将会得到大幅度提升。尤其是索引视图中有聚合函数,涉及大量高成本的join,因为聚合函数计算的结果物理存入索引视图,所以当面对大量数据使用到了索引视图之后,并不必要每次都进行聚合运算,这无疑会大大提升性能。
谈完了索引视图的基本原理和好处与坏处之后,来看看在SQL Server中的实现:
在SQL Server中实现索引视图是一件非常简单的事,只需要在现有的视图上加上唯一性聚集索引,但SQL Server对于索引视图的限制却是很多DBA对其并不青睐:
比如:
1、索引视图涉及的基本表必须ansi_nulls这是为ON
2、索引视图必须设置ansi_nulls和Quoted_indetifier为ON
3、索引视图只能引用基本表
4、schemabinding必须设置
5、定义索引视图必须使用Schema.ViewName这样的全名
6、索引视图中不能有子查询
7、avg、max、min、sdev、sdevp、var、varp这些聚合函数不能用
下面我们来通过一个例子来说明索引视图:
select p.Name,s.OrderQty
from Production.Product p
inner join Sales.SalesOrderDetail s
on p.ProductID=s.ProductID
这个查询的执行计划:
这时,我建立视图并在这个视图上建立唯一性索引:
--建立视图
create View V_Test_IndexedView
with Schemabinding
as
select p.Name,s.OrderQty,s.SalesOrderDetailID
from Production.product p
inner join Sale.SalesOrderDetail s
on p.ProductID=s.ProductID
Go
--create index
careate unique clustered index indexedview_test1
on V_Test_IndexedView(SalesOrderDetailID)
接下来,我们再次执行之前的查询
从上面的例子中,可以体会到索引视图的强大威力,即使你的查询语句中不包含索引视图,查询分析器会自动选择这个视图,从而大大提高了性能,当然,这么强大的性能,只有在SQL Server企业版和开发版才有(虽然我见过很多SQL Server的开发任何让公司掏着Enterprise版的钱,用着Express版的功能...)
分割视图(Partitoned view)
分割视图其实从微观实现方式来说,整个视图所返回的数据有几个平行表(即使几个表有相同表结构,也就是列和数据类型,但存储行集合不同)进行union所获得数据集
分割视图总体上可以分为两种:
1、本地分割视图(Local Partitoned View)
2、分布式分割视图(Distributed Partitioned View)
因为本地分割视图仅仅是为了和SQL Server2005之前的版本的一种向后兼容,这里仅仅对分布式分割视图进行说明,分布式分割视图其实是将有几个不同数据源或是相同数据源获得的萍乡数据集进行连接所获得,一个简单的概念图如下:
上面的视图获得的数据分别来自不同的数据源的表,每一个表诸葛弩只包含四行数据,最终组成了这个分割图
使用分布式分割图视图最大的好处就是提升性能,比如上面的例子中,我仅仅想去的ContactID为8这位员工的信息,如果通过分布式视图获取的话,SQL Server可以非常智能的仅仅扫描包含ContactID为8的表2,从而避免了整表扫描,着大大减少了IO操作,提升了系能。
这里需要注意的是,分布式分割视图所涉及的表之间的主键不能重复,比如上面表A ContactID是1-4,则表B的ContactID不能使2-8这个样子
还有一点要注意的是,一定要为分布,视图索引主键加Check约束,从而让SQL Server的查询分析器知道该去扫描那个表。
在微软实例数据库中AdvertureWorks数据库,我通过ContactID从前100和100-200行的数据分别存入两个表Employee100和Employee200,代码如下:
--create Employee100
SELECT TOP 100 * INTO Employee100
FROM HumanResources.Employee
ORDER BY EmployeeID
--create Employee200
SELECT * INTO Employee200
FROM
(SELECT TOP 100 *
FROM HumanResources.Employee
WHERE EmployeeID NOT IN (SELECT TOP 100 EmployeeID FROM HumanResources.Employee ORDER BY EmployeeID)
ORDER BY HumanResources.Employee.EmployeeID)AS e
这时来建立分布式分割视图:
CREATE VIEW v_part_view_test
AS
SELECT * FROM Employee100
UNION
SELECT * FROM Employee200
这时我们对这个索引进行查询操作
SELECT * FROM v_part_view_test
WHERE EmployeeID=105
下面是执行计划:
从上图中可以看出,通过分割的方式,执行计划仅仅是扫描Employee200,从而避免了扫描所有的数据,这无疑提升了性能,所以,当你将不同的数据表之间放到不同的数据服务器或是使用RAID5磁盘阵列时,分布式分割图进一步会提升查询性能。
使用分布式分割视图并不是在所有情况下提升性能,使用这种方式如果面对的查询包含了聚合函数,尤其是聚合函数还包含了distinct。或是不加where条件进行排序,那绝对是性能的杀手。因为聚合函数需要扫描分布式分割图中所有的表,然后进行Union操作后在进行运算。
通过视图(View)更新数据
通过视图更新数据时我们不推荐的,因为视图并不能接受参数,我们更推荐使用存储过程实现。
使用View更新数据和更新table的方式完全一样。View可以看做是一个虚拟表,如果是索引视图则是具体的一张表。
通过视图啦更新数据需要注意一下几点:
1、视图中from子句之后至少有一个用户表
2、View的查询无论设计多少张表,一次只能更新其中一张表的数据
3、对于表达式计算出来的列,常量列,聚合函数算出来的列无法更新
4、Group by,Having,Distinct关键字不能影响的列不能更新
这里说一下创建View有一个WITH Check Option选项,如果选择这个选项,则通过View所更新的数据必须符合View中where子句所限定的条件,比如:
我创建一个View:
视图(View)使用的几个小技巧
1、通过视图名称查到视图的定义
select * from sys.sql_modules
where object_id=OBJRCT_ID('视图的名称')
2、前面说过,普通视图仅仅存储的而是select语句和所引用表的Metadata,当底层表数据改变时,有时候视图中表的metadata并没有及时同步,可以通过如下代码进行手动同步
EXEC sp_refreshview 视图名称
视图(View)的最佳实践
这是我个人一些经验,欢迎补充
- 一定要将View中的Select语句性能调到最优(貌似是废话,不过真理都是废话…)
- View最好不要嵌套,如果非要嵌套,最多只嵌套一层
- 能用存储过程和自定义函数替代View的,尽量不要使用View,存储过程会缓存执行计划,性能更优,限制更少
- 在分割视图上,不要使用聚合函数,尤其是聚合函数还包含了Distinct
- 在视图内,如果Where子句能加在视图内,不要加在视图外(因为调用视图会返回所有行,然后再筛选,性能杀手,如果你还加上了order by…..)
本文转自:http://www.cnblogs.com/CareySon/archive/2011/12/07/2279522.html