视图性能优化——索引视图

视图性能优化——索引视图
http://blog.csdn.net/eriato/article/details/41039985

索引视图

索引视图有助于提高 T-SQL 的性能

Itzik Ben-Gan

T-SQL 是一种允许您以逻辑方式设计请求的语言。这里所说的“逻辑”的意思是,当编写查询时,您指定的是希望获得什么 结果,而不是希望以何种方式 获得结果。对如何处理查询进行设计是查询优化器的工作。您所遇到的需要 T-SQL 解决方案的每个问题通常都有许多不同的解决方案,它们最终会返回同样的结果。在理想情况下,假设有两个执行同一任务的不同查询,优化器会为二者生成相同的执行计划 - 最优化的计划。SQL Server 开发组似乎正在朝这个方向努力。利用 SQL Server 的每个发行版本,优化器会设计出更高级、更有效的计划,执行同一任务的不同查询使用这个相同计划的可能性也在提高。

不过,在许多情况下,您编写查询的方式仍然会动态地影响查询的性能。为了使优化器在不同的计划中作出选择并找到一个高效的计划,您需要完成一些准备工作 - 也就是,创建索引。大多数人是将普通索引作为其数据库优化的一部分创建的,但我还没有看到索引视图的广泛实现。索引视图可以极大地提高查询性能,尤其在聚合数据的时候。在某些情况下,对视图进行创建并索引后,您甚至不需要更改引用基表的原始查询,这是因为优化器的智能程度足以使用那些索引。

下面我们将讨论使用索引视图来获得性能提高的两个问题。我假设您已经很熟悉索引视图的基本概念。(有关索引视图的详细信息,请参阅 Kalen Delaney 的 "Introducing Indexed Views" (2000 年 5 月发表,InstantDoc ID 8410)一文。)

关于新客户的问题

第一个问题涉及一个典型的市场营销请求 - 在每个期间(例如,月份),根据定单活动而定的新客户、现有客户和全部客户的数量分别是多少?某个月的新客户就是第一次下达定单的客户。现有客户是那些在以前的月份下达过定单的客户。您可以将 Northwind 数据库中的 Orders 表作为最初的基本数据。表 1(表 1)显示了预期输出的简化版本。创建解决方案并验证您的代码在逻辑上正确无误之后,可针对一个更大的 Orders 表测试其性能,您可以通过运行第 18 页 清单 1 显示的代码,在 tempdb 中创建该表。

第 18 页 清单 2 显示了我针对此问题的第一个解决方案。定义派生表 M 的最内部查询从 Orders 返回了不同的月份和客户组合。月份表示为指向当月第一天的一个 datetime 值。定义派生表 N 的查询使用 CASE 表达式,对于每个月份和客户组合,如果该客户在当月之前还没有下达过定单,则该表达式返回 1,否则,返回 0。也就是说,如果客户是新客户,CASE 表达式返回 1。最外部查询按月份对 N 中的行进行分组,并通过对 N 表中名为 new 的列中的所有 1 进行汇总,来计算新客户的总数。客户的总数就是该组中的行数 (COUNT(*)),因为该组中的每一行都代表一个不同的客户。现有客户的数量是客户总数减去新客户的数量。

当我编写此解决方案时,我并没有考虑性能,我只想到要用逻辑方式来编写该查询。在我的笔记本电脑上,对我在 tempdb 中创建的较大的 Orders 表运行该查询时,该查询发生了超过 137,000 次的逻辑读取,运行的时间长达 17 秒。普通索引并没有提供多少帮助 - 当我在 customerid 列和 orderdate 列上创建了组合索引后,该查询运行了 15 秒。看来,这个问题需要采用另一种方法,这次,我决定先考虑性能。

这个较大的 Orders 表会包括每个月份的每个客户的许多定单。如果您有一个只包含月份和客户的不同组合的汇总表,就可以编写一个更易于执行的查询。索引视图的实质就是对表进行汇总。请运行 清单 3 中的代码,创建一个名为 Vymcusts 的索引视图,该视图只包含月份和客户的不同组合。注意,如果您希望对一个使用聚合的视图进行索引,则必须在该视图内包括 COUNT_BIG(*) 函数。如果 SQL Server 知道每组中的行数,就可以有效地维护索引视图。

接下来,我测试了几个不同的解决方案,所有方案执行起来都比第一个要好得多。我们来看一下我编写出的执行效果最好的解决方案。我创建了另一个名为 Vnewcusts 的视图,该视图包含每个客户的最小年/月份 (ym) 值:

CREATE VIEW Vnewcusts
AS
SELECT customerid, MIN(ym) AS min_ym
FROM Vymcusts (NOEXPAND)
GROUP BY customerid

客户的 ym 最小值就是该客户的第一份定单的月份。NOEXPAND 提示要求优化器将索引视图视为表,不要尝试使用来自基表 Orders 的索引。最后,我将 Vymcusts (VY) 左联接到了 Vnewcusts (VN)。如果 VY 和 VN 同时拥有同一个客户,并且 VY 中的当前月份是该客户的最小月份 (VY.ym = VN.min_ym),则 VY 中的某一行会在 VN 中寻找匹配的行。如果该月份不是该客户的最小月份,则外部联接在 VN.customerid 中以及在 VN 的所有列中均返回 NULL。查询按 VY.ym 列对外部联接的结果进行分组。SQL Server 通过对 VN.customerid 中的非 Null 值进行计数来计算新客户的总数。清单 4 显示了这个最终的查询,该查询在我的笔记本电脑上只运行了 1 秒,仅发生了 280 次逻辑读取。这样的性能令人非常满意。

列基数

我发现索引视图对解决另一个问题也非常有用,这就是计算列基数 - 列中不同的值的数量。计算表中每列的基数会占用大量系统开销,因为 SQL Server 需要重新排列每列的值,这样就可以很容易地对不同的值进行计数。现在我们来看一些示例,它们使用一个具有三个数据列和一百万行的表。请运行 清单 5 显示的脚本,在 tempdb 中创建一个名为 T1 的表,该表包括的各列是 c1、c2 和 c3,这些列分别包含 50,000、100,000 和 200,000 个不同的值。

在没有适当索引的情况下,下面的查询将计算每个数据列的基数,该查询的执行性能比较差:

SET STATISTICS TIME ON
SET STATISTICS IO ON
SELECT COUNT(DISTINCT c1),
COUNT(DISTINCT c2), COUNT(DISTINCT c3) FROM T1

我们在查询分析器中看看该查询的执行计划,我们注意到,SQL Server 对 T1 的聚集索引扫描了三次,对每一列中的值都执行了哈希操作来计数不同值的数量。因此,该查询用了很长的时间才完成,并且发生了大量 I/O 系统开销。在我的笔记本电脑上,该查询运行了 23 秒,发生了 9294 次逻辑读取。

为了获得更好的性能,很明显,第一个步骤就是对每一列进行索引:

CREATE NONCLUSTERED INDEX idx_nc_c1 ON T1(c1)
CREATE NONCLUSTERED INDEX idx_nc_c2 ON T1(c2)
CREATE NONCLUSTERED INDEX idx_nc_c3 ON T1(c3)

这样一来,SQL Server 可以用排序的方式单独扫描每个索引,并对不同的值进行计数。现在,查询只运行 5 秒钟,发生 4083 次逻辑读取。

您可能对这样的性能提高感到满意,但对于包括更多列和更多行的表,可能还需要进一步提高性能。获得更好查询性能的一个方式(不过要以修改性能为代价)是编写 INSERT、UPDATE 和 DELETE 触发器,它们在单独的非正式表中维护每列的非重复计数值。您也可以在不使用触发器的情况下解决该问题,方法是:使用索引视图,而不是普通的非聚集索引。

对于每一列,您可以创建一个只包含感兴趣的列和 COUNT_BIG(*) 函数的索引视图,该函数是对有聚合的视图进行索引所必需的。例如,可为 c1 创建以下索引视图:

CREATE VIEW V_T1_c1 WITH SCHEMABINDING
AS
SELECT c1, COUNT_BIG(*)
  AS cnt FROM dbo.T1 GROUP BY c1
GO
CREATE UNIQUE CLUSTERED INDEX
 idx_uc_c1 ON V_T1_c1(c1)

然后,运行 清单 6 显示的脚本,为 c2 和 c3 创建索引视图。现在,重新运行该查询,测量一下持续时间和 I/O,并查看执行计划。优化器的智能程度足以理解该执行计划,对列的非重复计数进行计算,它可以只对在其 GROUP BY 子句中使用该列的索引视图内的行数进行计数。现在,该查询运行的时间不到一秒,发生的逻辑读取不到 1000 次。

时间: 2024-10-22 10:22:43

视图性能优化——索引视图的相关文章

Android应用性能优化系列视图篇——隐藏在资源图片中的内存杀手

图片加载性能优化永远是Android领域中一个无法绕过的话题,经过数年的发展,涌现了很多成熟的图片加载开源库,比如Fresco.Picasso.UIL等等,使得图片加载不再是一个头疼的问题,并且大幅降低了OOM发生的概率.然而,在图片加载方面我们是否可以就此放松警惕了呢? 开源图片加载库能为我们解决绝大部分有关图片的问题,然而并不是所有! 首先,图片从来源上可以分成三大类:网络图片.手机图片.APK资源图片.网络图片和手机图片都在图片加载库功能的覆盖范围内,基本上不用开发者太操心,但是APK资源

Android app 性能优化之视图优化

Android app 性能优化之视图优化 前言: 每当一款App开始快速扩展的时候,随着业务功能的越来越复杂,功能模块的越来越多总会引起这样那样的性能问题.交互不流畅卡顿,ANR,手机发热量大等等性能问题在Android开发中一直都是一个坑爹的存在.不是大家不想去优化,可能是等你发现开始要搞搞性能的时候,发现工程貌似好大了,能跑不崩就万事大吉了,那么多代码要去看,去改.真心是一个让人想想都糟心的事.也可能,关键点不好找,可能一个性能问题是别的你想都想不到的地方引起的,为了优化这么一个点,可能花

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

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

Mysql5.7—mysql性能优化-索引、语句、配置(运维必备)

小生博客:http://xsboke.blog.51cto.com 小生 Q Q:1770058260 -------谢谢您的参考,如有疑问,欢迎交流 一. 数据库的类型 1) 第一代数据库: 基于层次模型与网状模型的数据库 层次型数据库比较经典的是IBM公司的IMS(InformationManagement System)数据库,层次型数据库提供了良好的完整性支持,模型简单,对具有一对多层关系的部们描述非常自然.直观,容易理解,比较适用于那些实体间联系是固定的且预先定义好的环境,其性能优于关

PLSQL_性能优化索引Index介绍(概念)

2014-06-01 BaoXinjian In Capgemini 一.摘要 在PLSQL查询优化中,使用和接触最多的应该是索引Index这个概念,个人也觉得对Index选择和优化是程式优化过程中比较重要的概念,特别是刚开始接触PLSQL性能优化 索引的一些概念 一个索引可以由一个或多个列组成, 对列设置索引其实就是对列的内容按一定的方式进行排序,检索数据的时候,检索排过序的数据,检索到最后一个有效数据之后就跳出检索 这样就不必进行全表扫描了,同时可以应用很多算法提高检索效率 数据库多用二分法

滚动视图性能优化的几种方式

目的: - 我们每次发布IOS时都会有一些新特性页面,当然还有广告条都会用到滚动视图.那么如何性能优化呢?目前就我所知有两种方案,一种就是常用的2-3张图片重复利用,另一种就是今天主要讲的利用UICollectionView来做. - 今天就做一个新特性页面为例 步骤: 方法一:利用UICollectionView 1.UICollectionView继承UIScrollView,我们要用滚动视图,肯定会用到ScrollView,而如何我们把collectionView中的一个Item当作滚动视

Android应用性能优化系列视图篇——恼人的分割线留白解决之道

相信很多一线的开发者都遇到过分割线,作为视觉设计中的最常用的元素之一,虽然简单易画,但在布局排版中往往却起影响视图层级结构的重要作用.往往由于一道小小的分割线,不仅在layout中多个数个视图,而且容易导致布局层级的加深,甚至还需要在Java代码中做逻辑控制. 虽然Android官方提供的布局中,比如ListView.LinearLayout等对分割线都有了相应的实现,但是在处理分割线留白这种设计时常常有心无力.而在越来越多的APP中,分割线留白已经成为了一种设计趋势,所以,如何简单高效地实现分

MySQL 性能优化---索引及优化

博主QQ:819594300 博客地址:http://zpf666.blog.51cto.com/ 有什么疑问的朋友可以联系博主,博主会帮你们解答,谢谢支持! 一.MySQL性能优化之-影响性能的因素 1.商业需求的影响 Myisam存储引擎内置一个计数器,count(*)时直接从计数器读取:而通过innodb存储引擎查找某个数据时,是必须扫描全表的,所以当执行对表的统计(即使用count(*)函数)时,myisam要比innodb要快的很多.所以一般在innodb上执行count(*)时一般要

mysql性能优化-索引与优化

http://hongge.blog.51cto.com/ 一.MySQL性能优化之-影响性能的因素 1.商业需求的影响 不合理需求造成资源投入产出比过低,这里我们就用一个看上去很简单的功能来分析一下. 需求:一个论坛帖子总量的统计,附加要求:实时更新 从功能上来看非常容易实现,执行一条SELECT COUNT(*) from 表名 的Query 就可以得到结果.但是,如果我们采用不是MyISAM 存储引擎,而是使用的Innodb 的存储引擎,那么大家可以试想一下,如果存放帖子的表中已经有上千万