计算机的空间换时间的本质是不会变化的,就像计算机只是一台0,1对比的机器一样,只是在认识了表象之后,让我们慢慢的去揭开其神秘的面纱吧。
问题:
1:数据库中的各种表是如何存储的,最后都是转换为了二进制文件,但是在此的各种性能优化的工具都是产生了新的二进制文件吗?
2:视图与索引的各种合理使用过程
3:视图与索引的各种基本书写格式问题
4:sqlserver客户端的高效使用过程
视图
视图可以看作定义在SQL Server上的虚拟表.视图正如其名字的含义一样,是另一种查看数据的入口.常规视图本身并不存储实际的数据,而仅仅存储一个Select语句和所涉及表的metadata.
为什么要使用视图(View)
从而我们不难发现,使用视图将会得到如下好处:
- 视图隐藏了底层的表结构,简化了数据访问操作
- 因为隐藏了底层的表结构,所以大大加强了安全性,用户只能看到视图提供的数据
- 使用视图,方便了权限管理,让用户对视图有权限而不是对底层表有权限进一步加强了安全性
- 视图提供了一个用户访问的接口,当底层表改变后,改变视图的语句来进行适应,使已经建立在这个视图上客户端程序不受影响
视图(View)的分类
视图在SQL中可以分为三类
- 普通视图(Regular View)
- 索引视图(Indexed View)
- 分割视图(Partitioned View)
下面从这几种视图类型来谈视图
普通视图由一个Select语句所定义,视图仅仅包含其定义和被引用表的metadata.并不实际存储数据。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:这个选项用于更新数据做限制,下面会在通过视图更新数据一节解释.
当然了,创建视图除了需要符合上面的语法规则之外,还有一些规则需要遵守:
- 在View中,除非有TOP关键字,否则不能用Order By子句(如果你一意孤行要用Order by,这里有个hack是使用Top 100 percent…..)
- View在每个Schema中命名必须独一无二
- View嵌套不能超过32层(其实实际工作中谁嵌套超过两层就要被打PP了-.-)
- Compute,compute by,INTO关键字不允许出现在View中
- View不能建立在临时表上
- View不能对全文索引进行查询
索引视图可以看作是一个和表(Table)等效的对象!
SQL Server中的索引视图和Oracle中的Materialized View是一个概念.想要理解索引视图,必须先理解聚集索引。聚集索引简单来说理解成主键,数据库中中的数据按照主键的顺序物理存储在表中,就像新华字典,默认是按照ABCD….这样的方式进行内容设置。ABCD….就相当于主键.这样就避免了整表扫描从而提高了性能.因此一个表中只能有一个聚集索引。
对于索引视图也是,为一个视图加上了聚集索引后。视图就不仅仅再是select语句和表的metadata了,索引视图会将数据物理存在数据库中,索引视图所存的数据和索引视图中所涉及的底层表保持同步。
谈完了索引视图的基本原理和好处与坏处之后,来看看在SQL Server中的实现:
在SQL Server中实现索引视图是一件非常,简单的事,只需要在现有的视图上加上唯一聚集索引.但SQL Server对于索引视图的限制却使很多DBA对其并不青睐:
比如:
- 索引视图涉及的基本表必须ANSI_NULLS设置为ON
- 索引视图必须设置ANSI_NULLS和QUOTED_INDETIFIER为ON
- 索引视图只能引用基本表
- SCHEMABINDING必须设置
- 定义索引视图时必须使用Schema.ViewName这样的全名
- 索引视图中不能有子查询
- avg,max,min,stdev,stdevp,var,varp这些聚合函数不能用
分割视图(Partitioned View)
分割视图其实从微观实现方式来说,整个视图所返回的数据由几个平行表(既是几个表有相同的表结构,也就是列和数据类型,但存储的行集合不同)进行UNION连接(对于UNION连接如果不了解,请看我之前的博文)所获得的数据集.
分割视图总体上可以分为两种:
1.本地分割视图(Local Partitioned View)
2.分布式分割视图(Distributed Partitioned View)
因为本地分割视图仅仅是为了和SQL Server 2005之前的版本的一种向后兼容,所以这里仅仅对分布式分割视图进行说明.
分布式分割视图其实是将由几个由不同数据源或是相同数据源获得的平行数据集进行连接所获得的,一个简单的概念图如下:
上面的视图所获得的数据分别来自三个不同数据源的表,每一个表中只包含四行数据,最终组成了这个分割视图.
使用分布式分割视图最大的好处就是提升性能.比如上面的例子中,我仅仅想取得ContactID为8这位员工的信息,如果通过分布式视图获取的话,SQL Server可以非常智能的仅仅扫描包含ContactID为8的表2,从而避免了整表扫描。这大大减少了IO操作,从而提升了性能.
这里要注意的是,分布式分割视图所涉及的表之间的主键不能重复,比如上面的表A ContactID是1-4,则表B的ContactID不能是2-8这个样子.
还有一点要注意的是,一定要为分布式分割索引的主键加Check约束,从而让SQL Server的查询分析器知道该去扫描哪个表,下面来看个例子.
在微软示例数据库AdventureWorks数据库,我通过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
这时来建立分布式分割视图:
这时我们对这个索引进行查询操作:
通过视图(View)更新数据
通过视图更新数据是我所不推荐的.因为视图并不能接受参数.我更推荐使用存储过程来实现.
使用View更新数据和更新Table中数据的方式完全一样(前面说过,View可以看作是一个虚拟表,如果是索引视图则是具体的一张表)
通过视图来更新数据需要注意以下几点
1.视图中From子句之后至少有一个用户表
2.View的查询无论涉及多少张表,一次只能更新其中一个表的数据
3.对于表达式计算出来的列,常量列,聚合函数算出来的列无法更新
4.Group By,Having,Distinct关键字不能影响到的列不能更新
这里说一下创建View有一个WITH Check Option选项,如果选择这个选项,则通过View所更新的数据必须符合View中where子句所限定的条件,比如:
我创建一个View:
视图(View)中的几个小技巧
1.通过视图名称查到视图的定义
2.前面说过,普通视图仅仅存储的是select语句和所引用表的metadata,当底层表数据改变时,有时候视图中表的metadata并没有及时同步,可以通过如下代码进行手动同步
EXEC sp_refreshview 视图名称
视图(View)的最佳实践
这是我个人一些经验,欢迎补充
- 一定要将View中的Select语句性能调到最优(貌似是废话,不过真理都是废话…)
- View最好不要嵌套,如果非要嵌套,最多只嵌套一层
- 能用存储过程和自定义函数替代View的,尽量不要使用View,存储过程会缓存执行计划,性能更优,限制更少
- 在分割视图上,不要使用聚合函数,尤其是聚合函数还包含了Distinct
- 在视图内,如果Where子句能加在视图内,不要加在视图外(因为调用视图会返回所有行,然后再筛选,性能杀手,如果你还加上了order by…..)