SQLServer性能调优3之索引(Index)的维护(三)

2014-11-24 15:28:54 · 作者: · 浏览: 3
indUsage.user_seeks,0) = 0 AND isnull(indUsage.user_scans,0) = 0 AND isnull(indUsage.user_lookups,0) = 0) ORDER BY obj.name,ind.Name GO 获取这些信息后,采取怎样的行动由你决定。但是当你决定删除某个索引时请注意以下两点:如果当前索引是个主键或唯一键,他能保证数据的完整性唯一索引即使本身并没有被使用,但能给优化器提供信息,从而帮助它生成更好的执行计划

建立索引视图(indexed view)来改善性能

视图是个存储的查询,表现得像表一样。它有两个主要好处:

限制用户只能访问某几张表中特定字段及特定数据允许开发者通过自定义的方式把原始信息组织成面向用户的逻辑视图

索引视图在创建时就解析/优化好查询语句,并把相关信息以物理形式存放在数据库中。再决定使用索引视图前请考虑以下建议:

视图不应该参照其他视图试图可以参照任何原始表字段名必须显式明确的定义好合适的别名

另外如果针对该对象的处理查询少更新多,又或者原始表是个经常更新的表,那么使用索引视图并不是很合适。

如果你有个查询包含较多的合计(aggregation)/联合(join)而且表的数据量很大,那么可以考虑使用索引视图。使用索引视图必须设定以下参数(NUMERIC_ROUNDABORT为OFF,其余为ON)

ARITHABORTCONCAT_NULL_YIELDS_NULLQUOTED_IDENTIFIERANSI_WARNINGSANSI_NULLSANSI_PADDINGNUMERIC_ROUNDABORT

示例脚本:

CREATE VIEW POView
WITH SCHEMABINDING
AS
SELECT
  POH.PurchaseOrderID
  ,POH.OrderDate
  ,EMP.LoginID
  ,V.Name AS VendorName
  ,SUM(POD.OrderQty) AS OrderQty
  ,SUM(POD.OrderQty*POD.UnitPrice) AS Amount
  ,COUNT_BIG(*) AS Count
FROM
  [Purchasing].[PurchaseOrderHeader] AS POH
JOIN
  [Purchasing].[PurchaseOrderDetail] AS POD
ON
  POH.PurchaseOrderID = POD.PurchaseOrderID
JOIN
  [HumanResources].[Employee] AS EMP
ON
  POH.EmployeeID=EMP.BusinessEntityID
JOIN
  [Purchasing].[Vendor] AS V
ON
  POH.VendorID=V.BusinessEntityID
GROUP BY
  POH.PurchaseOrderID
  ,POH.OrderDate
  ,EMP.LoginID
  ,V.Name
GO

-- 在视图上建立一个聚集索引使得它成为使得它成为索引视图
CREATE UNIQUE CLUSTERED INDEX IndexPOView ON POView
(PurchaseOrderID)
GO
你可以对比一下查询语句与查询索引视图的执行计划,索引视图的方式提供了更好的查询性能:

\

SQL Server 的查询优化器总是尝试找到最佳的执行计划,有时候虽然你建立了索引视图,但优化器依然使用了原始表上的索引,此时你可以使用 WITH NOEXPAND 来强制使用索引视图上的索引(而不是原始表上的索引)。

索引视图在 SQL Server 2012 的各个版本上都有支持,在开发版或企业版中查询处理器甚至能以此来把匹配索引视图的查询都优化了。

索引视图建立时必须带上 WITH SCHEMABINDING,以此保证用到的字段不会被修改掉。

如果索引视图包含了 GROUP BY 子句,则必须在 SELECT 子句中包含 COUNT_BIG (*),并且不能指定 HAVING, CUBE, 以及 ROLLUP。

使用计算字段(Computed Columns)上的索引来改善性能

首先来介绍一下计算字段(Computed Columns),它通过一个表达式来引用同一张表的其他字段,然后运算出一个结果。这个字段的值会在每次被调用时都重新计算,除非你在建立时带上 PERSISTED 标记。

在决定是否在计算字段上建立索引前,需要考虑一下几点:

计算字段为 Image, Text, 或 ntext 的情况,它只能作为非聚集索引的非关键字段(non-key column)计算字段表达式不能是 REAL 或 FLOAT 类型计算字段应当是精确的(?)计算字段应当是确定的(输入相同的值,输出相同的结果)计算字段如果使用了函数(function),不管是用户函数还是系统函数,表及函数的拥有者必须是同一个针对多行记录的函数(比如:SUM, AVG)不能在计算字段中使用增删改会改变计算字段上索引的值,所以必须设定以下6个参数。
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET NUMERIC_ROUNDABORT OFF

下面我们来看一个完整的例子:

1. 设定系统变量,并建立我们的测试数据表

SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET NUMERIC_ROUNDABORT OFF

SELECT
  [SalesOrderID]
  ,[SalesOrderDetailID]
  ,[CarrierTrackingNumber]
  ,[OrderQty]
  ,[ProductID]
  ,[SpecialOfferID]
  ,[UnitPrice]
INTO
  SalesOrderDetailDemo
FROM
  [AdventureWorks2012].[Sales].[SalesOrderDetail]
GO
2. 建立一个用户自定义函数,然后再建立一个计算字段并使用这个函数
CREATE FUNCTION
[dbo].[UDFTotalAmount] (@TotalPrice numeric(10,3), @Freight
TINYINT)
RETURNS Numeric(10,3)
WITH SCHEMABINDING
AS
BEGIN
DECLARE @NetPrice Numeric(10,3)
SET @NetPrice = @TotalPrice + (@TotalPrice*@Freight/100)
RETURN @NetPrice
END
GO
--adding computed column SalesOrderDetailDemo tabl