SQL Server索引视图以(物化视图)及索引视图与查询重写

  经常听Oracle的同学说起来物化视图,物化视图的作用之一就是可以实现查询重写,听起来有一种高大上的感觉,   SQL Server也有类似于Oracle物化视图的功能,只不过叫做索引视图。   说实话,还是物化视图听起来比较合适,与普通视图比,物化视图就是直接将数据存储起来了   SQL Server中的索引视图也具有查询重写的功能,   所谓的查询重写,就是如果符合条件的数据在索引视图上,并且查询列都包含在在索引视图上,此时可以直接通过查询索引视图来替代基于原始表的查询

依旧惯例,先上代码做一个测试环境

--创建两张表,一张表头,一张明细,仅仅作为DEMO使用
CREATE TABLE HeadTable
(
    HeadId      INT PRIMARY KEY  ,
    HeadInfo    VARCHAR(50)      ,
    DataStatus  TINYINT          ,
    CreateDate  Datetime
)
GO

CREATE TABLE DetailTable
(
    HeadId      INT           ,
    DetailId    INT identity(1,1) PRIMARY KEY ,
    DatailInfo  VARCHAR(50)
)
GO

--写入数据
DECLARE @i int = 0
WHILE @i<200000
BEGIN
    INSERT INTO HeadTable values (@i,NEWID(),RAND()*10,GETDATE()-RAND()*100)
    INSERT INTO DetailTable(HeadId,DatailInfo) VALUES (@i,NEWID())
    SET @i=@i+1
END
GO

索引视图创建

那么如何创建索引视图呢?语法上跟创建普通视图差别不大,但是不允许出现select *,表名上要加上Scheme,因为这里不是专门说索引视图的,细节就不多说了。

CREATE VIEW V_IndexViewTest WITH SCHEMABINDING
AS
    SELECT H.HeadId,H.CreateDate,H.DataStatus,D.DetailId,D.DatailInfo
    FROM dbo.HeadTable H INNER JOIN
                dbo.DetailTable D ON H.HeadId = D.HeadId
    WHERE H.DataStatus = 0
GO

索引视图要求创建的第一个列为唯一聚集索引,所以如下,创建一个唯一的聚集索引

  对于其他索引,可以跟在表上创建索引一样

  

 

查询重写

  上面说了,查询重写就是将基于原始表的查询语句,直接在索引视图上查询实现,那么就来看一下查询重写是什么样子的?   下面来观察这么一个查询,SQL很明显地是基于原始表做的查询,跟普通查询并无二致,   但是观察执行计划就会发现:   这个执行计划走了一个索引查找,首先很清楚,HeadTable上的CreateDate是没有索引的,这里走的索引就是V_IndexViewTest上的CreatDate列上的索引   也就是在索引视图上创建的第二个索引。

  

  如果,查询语句这么写,如下,在查询条件中增加了一个索引视图中没有的列,此时查询就不会被重写,直接走的是基于原始表的查询,跟普通查询并无二致。   其实原理不难理解,因为视图中并不包含HeadInfo这个列,如果在查询列上加上这个字段,视图中是没有这个字段的,那只能基于原始表做查询了。

  

为什么查询会被重写

  上面我们看到了,对于合适的查询,查询是会被重写的,也就是查询直接基于索引视图来实现,那么为什么会直接基于视图来实现呢?   还是处于性能上的考虑,因为索引视图在创建唯一的聚集索引之后,视图就“固化了”原始表的结果集,   此时的视图与普通视图最大的区别就是,视图中直接存储了数据本身,而非一个查询,   此时的视图中的数据集,相当于基于原表的一个“子集”,因为是子集,这个结果集必然小于原始表,   那么同样的查询字段和查询条件,不但可以减少表与表之间的链接操作,且结果集更小,从这个视图上查询,   同等条件下可以更快地返回结果,所以查询重写也就不难理解了。   此时只要查询字段和查询条件一样,基于原始表的查询和直接查询索引视图是一样的,如下截图

  

索引视图什么时候更新

  上面说了查询重写,如果条件允许,基于原始表的查询会直接从索引视图上来实现。   可能有人会不放心,毕竟数据都是基于物理表做增删改的,而索引视图中的数据又是物理存在的,那就就会有一个担心,基于视图的查询会不会不准确?   毕竟是我好好的一个查询,你默认给我定位到索引视图上,查询结果会跟原始表查询一致吗?

  那么就要求证一下,索引视图中的数据是如何更新的。   我们做这么一个测试,在基表,也就是DetailTable中查询一条数据,看看到底在执行计划中发生了什么   可以明显地看到,不仅仅是王DetailTable中写入了一条数据,同时,基于索引视图的查询也往索引视图中写入了一条数据,   因此可以放心地使用索引视图而不必担心索引视图中的数据和基表的数据不一致的问题。

  但是要注意的就是,此时的写,是写入基表的同事,也写入了索引视图,对写入的影响是肯定有一些的,如果对写入效率要求非常高,就要谨慎一点了。   其实索引视图也是一种冗余写来实现查询效率的提高的。

改变基于视图的查询

  上面说了,某些基于视图的查询,是直接定位到视图,从视图中查询结果返回的,如下图

但是如果真的不想从视图中查询,我就是想对比一下原始表和基于视图查询的(效率上的)区别,该怎么办? 这个也好办,可以通过查询提示,将查询来基于原始表实现,也就是展开这个索引视图了 OPTION (EXPAND VIEWS)这个查询提示就是将视图展开,从原始表进行查询,默认情况下是不展开的 如截图,可以强制展开索引视图,从原始表查询

那么效率对比呢?如下截图,粗看起来,这个效率差别还是挺大的,可见,SQL Server默认选择下,载效率上还是有一定的考虑的

  这里从索引视图查询,一是减少了表之间的join,而是索引视图的结果集更小,从中筛选符合条件的数据效率就会更好一些。   所以,默认情况下是会从视图查询来对SQL进行查询重写的。  

   索引视图的查询提示:with(noexpand) 强制不展开,OPTION (EXPAND VIEWS)强制展开

总结:

  本文粗浅地分析了SQL Server 中的索引视图以及索引视图带来的查询重写功能,通过索引视图固化基表的结果集,   可以在一定程度上提高查询效率,尤其是在超级大的多表join的时候,直接将原始结果存为一个索引视图,   通过对索引视图查询来减少表之间的join和IO来提高效率,不失为一种优化选择。   需要注意的是,SQL Server的索引视图限制非常多,具体可以参考链接丛书或者MSND,并不是所有的情况都可以使用索引视图来实现。

时间: 2024-08-06 12:52:12

SQL Server索引视图以(物化视图)及索引视图与查询重写的相关文章

SQL Server调优系列基础篇(索引运算总结)

原文:SQL Server调优系列基础篇(索引运算总结) 前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方式可以指导我们如何建立索引.调整我们的查询语句,达到性能优化的目的. 闲言少叙,进入本篇的正题. 技术准备 基于SQL Server2008R2版本,利用微软的一个更简洁的案例库(Northwind)进行解析. 简介 所谓的索引应用就是在我们

SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)

前言 前面几篇我们分析了关于SQL Server关于性能调优的一系列内容,我把它分为两个模块. 第一个模块注重基础内容的掌握,共分6篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划.掌握执行计划优化点,并一一列举了日常我们平常所写的T-SQL语句所会应用的运算符.我相信你平常所写的T-SQL语句在这几篇文章中都能找到相应的分解运算符. 第二个模块注重SQL Server执行T-SQL语句的时候一些内幕解析,共分为5篇文章完成,其中包括:查询优化器的运行方式.运行时几个优化指标值

SQL Server导入导出不丢主键和视图的方法

SQL Server导入导出 SQL Server 导入导出 工具/原料 使用Microsoft SQL Server Management Studio 导入导出数据. 直接使用Microsoft SQL Server Management Studio 导入导出数据会丢失主键.视图等等. 正确的保存方法如下: 一.选择本地的需要导出的数据库 右键-->任务-->生成脚本. 按向导选择需要导出的数据库下一步到“选择脚本选项” 选择需要生成的类型,注意“为服务器版本编写脚本”处选择对应的脚本.

[SQL Server 2005/2008] select语句中指定索引

一般情况下,SQL Server的查询优化器会对查询做优化,选择适合的索引. 当遇到一些宽表,索引和where 过滤条件多时, 查询优化器选择的可能并不是最佳的索引, 此时需要手动指定索引.具体效果可以在“执行计划中查看”. select * from 表名 with (nolock, index(索引表)) where ........

Sql Server之旅——第八站 复合索引和include索引到底有多大区别?

周末终于搬进出租房了,装了宽带....才发现没网的日子...那是一个怎样的与世隔绝呀...再也受不了那样的日子了....好了,既然网 安上去了,还得继续我的这个系列. 索引和锁,这两个主题对我们开发工程师来说,非常的重要...只有理解了这两个主题,我们才能写出高质量的sql语句,在之前的博客中,我所说的 索引都是单列索引...当然数据库不可能只认单列索引,还有我这篇的复合索引,说到复合索引,可能熟悉的人又会说到include索引,那这两个索引到底 有什么区别呢,当然我也是菜鸟一枚...所以下面的

SQL Server性能优化(9)聚集索引

一.索引的概念和分类 索引的概念大家都知道,日常开发中我们也会使用常见的聚集索引.非聚集索引.但是除了这两者以外,sqlserver中还提供其他的索引,如: a. 唯一索引:不包含重复键的索引,聚集索引或者非聚集索引都可以是唯一索引. b. 包含列的索引:它扩展后不仅包含键列,还包含非键列. c. 全文索引 d. 空间索引 e. 筛选索引 f. XML 当然以上几种除了a和b基本上没用到过. 二.聚集索引的结构 要想使用聚集索引,必须了解聚集索引的概念以及它的原理.网上对聚集索引描述的资料有很多

SQL Server 2016新特性:列存储索引新特性

行存储表可以有一个可更新的列存储索引,之前非聚集的列存储索引是只读的. 非聚集的列存储索引支持筛选条件. 在内存优化表中可以有一个列存储索引,可以在创建表的时候创建,也可以在之后的alter table语句上创建.之前内存优化表不支持列存储索引. 聚集的列存储索引可以有多个非聚集行存储索引,之前列存储索引不支持非聚集索引. 支持在聚集列存储索引上加入主键和外键约束,约束使用btree索引. 列聚集索引有一个压缩延迟选项,让事务复合收到的影响最小. 兼容级别为120,130的数据库性能: 列存储索

SQL server 主键,外键的使用及子查询的使用 11月20日

 今天上午学习了SQL server里面主键和外键的使用以及如何建立主键与外键的联系 下午学习了SQL server 里面子查询如何应用,里面还练习了函数的运用(字符串函数,聚合函数) 今日小结:通过学习了解了主键和外键的使用,以及子查询(select 查询嵌套)的用法,子查询把小的范围放在括号里面,外面再用大范围包含起来.

sql server 2000/2005 判断存储过程、触发器、视图是否存在并删除

1.判断是否存在addOneArticle这个存储过程  if Exists(select name from sysobjects where NAME = 'addOneArticle' and type='P') drop procedure addOneArticle 2.判断是否存在countAr这个触发器  if exists(select * from dbo.sysobjects where id = object_id(N'[dbo].[countAr]') and OBJEC

SQL Server修改表结构后批量更新所有视图

最近修改了数据库表结构,数据同步的时候出了问题,发现很多数据明明已经修改,但是通过视图筛选出来的还是原来的数据,所以怀疑应该是视图缓存了数据,在园子里找到下面的博文,在这里做个记录备忘. 原文链接:http://www.cnblogs.com/yashen/archive/2004/12/23/81000.html 我们在使用SqlServer时经常遇到这种情况,当修改某个表的结构后,相关的视图就不对了而导致程序错误,因此就有个下面这个存储过程. CREATE PROCEDURE Refresh