第十章——维护索引(8)——在计算列中创建索引提高性能

原文:第十章——维护索引(8)——在计算列中创建索引提高性能

前言:

在理解计算列上的索引之前,先了解计算列的基本知识。计算列由可以使用同一表中的其他列的表达式计算得来。表达式可以是非计算列的列名、常量、函数,也可以是用一个或多个运算符连接的上述元素的任意组合。表达式不能为子查询。

默认情况下,计算列是一个虚拟的列,并且可以在调用时重新计算,直到在CREATE TABLE或者ALTER TABLE 命令中使用PERSISTED。

如果列定义成PERSISTED,会存放计算值,并存放在原始列上更新后的汇总值,不能对计算列进行INSERT、UPDATE。

 

准备工作:

首先要了解是否有需要在计算列上创建索引,计算列在下面情况可以考虑创建索引:

1、 如果计算列的数据来源于IMAGE,TEXT和NTEXT数据类型,只能作为非聚集索引的部分列。

2、 计算列表达式不能是REAL或者FLOAT数据类型。

3、 计算列必须明确。

4、 计算列必须具有稳定性。可以使用COLUMNPROPERTY函数的IsDeterministic属性来判断是否稳定。

5、 如果函数使用了任何函数,不管是自定义还是系统内置的,那么表和函数的拥有者必须是相同的。

6、 不能用于通过聚集函数获得的函数值上的列。

7、 需要开启下面的配置:

1、 ARITHABORT

2、 CONCAT_NULL_YIELDS_NULL

3、 QUOTED_IDENTIFIER

4、 ANSI_WARNINGS

5、 ANSI_NULLS

6、 ANSI_PADDING

7、 NUMERIC_ROUNDABORT——OFF,其他为ON 。

 

步骤:

1、 创建一个测试表:

 USE AdventureWorks2012
GO
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、 现在创建一个用于计算列的自定义函数,并添加计算列NetPrice到新表中,这个列通过自定义函数UDFTotalAmount来计算值:

 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

--添加计算列:
ALTER TABLE SalesOrderDetailDemo ADD [NetPrice] AS
dbo.UDFTotalAmount(OrderQty*UnitPrice,5)
GO

3、 现在在表上创建一个聚集索引。使得表不会再是堆表,然后按照前面说的,修改相关的SET选项,然后开启STATISTICS,记住目前没有创建任何索引在计算列上: 

 --创建聚集索引
CREATE CLUSTERED INDEX idx_SalesOrderID_SalesOrderDetailID_SalesOrderDetailDemo ON
SalesOrderDetailDemo(SalesOrderID,SalesOrderDetailID)
GO

--开启统计数据
SET STATISTICS IO ON
SET STATISTICS TIME ON
GO

--执行查询
SELECT  *
FROM    SalesOrderDetailDemo
WHERE   NetPrice > 5000
GO

得到结果:


SQL Server 分析和编译时间:

   CPU 时间= 920 毫秒,占用时间= 967 毫秒。

SQL Server 分析和编译时间:

   CPU 时间= 0 毫秒,占用时间= 5 毫秒。

 

(3864 行受影响)

表'salesorderdetaildemo'。扫描计数1,逻辑读取757 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。

 

 SQL Server 执行时间:

   CPU 时间= 780 毫秒,占用时间= 1643 毫秒。

 

4、 在创建索引到计算列前,先检查是否符合创建条件:

SELECT  COLUMNPROPERTY(OBJECT_ID('SalesOrderDetailDemo'), 'NetPrice',
                       'IsIndexable') AS 'Indexable?' ,
        COLUMNPROPERTY(OBJECT_ID('SalesOrderDetailDemo'), 'NetPrice',
                       'IsDeterministic') AS 'Deterministic?' ,
        OBJECTPROPERTY(OBJECT_ID('UDFTotalAmount'), 'IsDeterministic') ,
        'UDFDeterministic?' ,
        COLUMNPROPERTY(OBJECT_ID('SalesOrderDetailDemo'), 'NetPrice',
                       'IsPrecise') AS 'Precise?'

5、 现在在计算列上创建索引,如果你前面说的条件都满足,那么可以创建了:

CREATE INDEX idx_SalesOrderDetailDemo_NetPrice
ON SalesOrderDetailDemo(NetPrice)
GO

然后再次执行查询:

SET STATISTICS IO ON
SET STATISTICS TIME ON
GO
SELECT  *
FROM    SalesOrderDetailDemo
WHERE   NetPrice > 5000
GO

 

6、 结果如下:


 SQL Server 分析和编译时间:

   CPU 时间= 0 毫秒,占用时间= 0 毫秒。

SQL Server 分析和编译时间:

   CPU 时间= 0 毫秒,占用时间= 0 毫秒。

SQL Server 分析和编译时间:

   CPU 时间= 0 毫秒,占用时间= 3 毫秒。

SQL Server 分析和编译时间:

   CPU 时间= 0 毫秒,占用时间= 0 毫秒。

 

(3864 行受影响)

表'salesorderdetaildemo'。扫描计数1,逻辑读取757 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。

 

 SQL Server 执行时间:

   CPU 时间= 780 毫秒,占用时间= 1534 毫秒。

 

 

 

分析:

        在计算列创建一个索引,存储键值到叶子节点并在SELECT的时候利用索引的统计信息,在大部分的情况下是工作得很好的。但是也有很多情况下不能用计算列。

        在统计数据上,可以看到SQLServer Parse和Compile 时间还有SQLServer执行时间。如果数据量很大,那么创建了索引在计算列上的效能提高将会很明显。

时间: 2024-08-30 20:26:48

第十章——维护索引(8)——在计算列中创建索引提高性能的相关文章

数据库中创建索引的准则

索引是建立在数据库表中的某些列的上面. 一.应该创建索引的列 1.在经常需要搜索的列上,可以加快搜索的速度: 2.在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构: 3.在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度: 4.在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的: 5.在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间: 6.在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速

MongoDB中创建索引需要注意的事项_MongoDB

上周在 ruby-china 上发了帖子<MongoDB 那些坑>,反映相当热烈,许多回复很有见地,其中一位童鞋深入的提到 MongoDB 建索引方法的问题,引发我更深入的了解了 MongoDB 建索引的方法和一些注意事项. 在 <MongoDB 那些坑>中提到,在前台直接运行建立索引命令的话,将造成整个数据库阻塞,因此索引建议使用 background 的方式建立.但是这也会带来一定的问题,在 2.6 版本之前,在 secondary server 中即使使用 backgroun

SQL Server利用HashKey计算列解决宽字段查询的性能问题

SQL Server利用HashKey计算列解决宽字段查询的性能问题 主人翁        本文主人翁:MSSQL菜鸟和MSSQL老鸟. 问题提出        某年某月某日,某MSSQL菜鸟满脸愁容的跑到老鸟跟前,心灰意懒的对老鸟说"我最近遇到一个问题,很大的问题,对,非常大的问题".老鸟不急不慢的推了推2000度超级近视眼镜框,慢吞吞的说:"说来听听".        "我有一个100万数据量的表,有一个宽度为7500字段,不幸的是现在我需要根据这个字

SQL Server-聚焦计算列或计算列持久化查询性能(二十二)

前言 上一节我们详细讲解了计算列以及计算列持久化的问题,本节我们依然如前面讲解来看看二者查询性能问题,简短的内容,深入的理解,Always to review the basics. 持久化计算列比非持久化计算列性能要好 我们开始创建两个一样的表并都插入100条数据来进行比较,对于计算列我们重新进行创建计算列和非计算列持久化. CREATE TABLE [dbo].[ComputeColumnCompare] (ID INT, FirstName VARCHAR(100), LastName C

创建索引

8.2.1 用CREATE INDEX 命令创建索引CREATE INDEX 既可以创建一个可改变表的物理顺序的簇索引,也可以创建提高查询性能的非簇索引.其语法如下:CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED]INDEX index_name ON {table | view } column [ ASC | DESC ] [,...n])[WITH[PAD_INDEX][ [, ] FILLFACTOR = fillfactor][ [, ] IGNOR

SQL Server-聚焦计算列持久化(二十一)

前言 上一节我们结束了Hash Match Aggregate和Stream Aggregate的讲解,本系列我们来讲讲关于SQL Server中的计算列问题,简短的内容,深入的理解,Always to review the basics. 初探计算列持久化(Compued Column Persisted) 在SQL Server 2005就引入了计算列,我们首先稍微看下在msdn关于计算列的定义:计算列由可以使用同一表中的其他列的表达式计算得来.表达式可以是非计算列的列名.常量.函数,也可以

数据库快照,自定义函数与计算列

数据库快照,自定义函数与计算列 1.数据库快照 数据库快照就是保存某个数据库在快照那一瞬间的状态.快照和备份原理上有所不同,但是功能有一点相同那就是可以将数据还原为备份的那个时刻.快照的原理是新建一个数据库指针,在原数据库没有变化的情况下快照是不占用空间的,而数据库发生了变化,那么在变化前,被修改的数据页会先复制一份到快照文件中,然后再对原数据页进行修改.显然这样做的好处就是比备份数据库占用空间小.快照是只读的,你可以直接在SQL语句中把他当数据库用: use snap1;--使用快照 sele

SqlServer(索引)--创建复合索引时,复合索引列顺序对查询的性能影响[转]

http://www.cnblogs.com/wy123/p/5604400.html SQL Server创建复合索引时,复合索引列顺序对查询的性能影响 说说复合索引 写索引的博客太多了,一直不想动手写,有一下两个原因: 一是觉得有炒剩饭的嫌疑,有兄弟曾说:索引吗,只要在查询条件上建索引就行了,真的可以这么暴力吗? 二来觉得,索引是个非常大的话题,很难概括出所有的情况,你不整出点新意来,倒是有抄袭照搬的嫌疑 既然写了,就写一点稍微不一样的东西出来, 好了,废话打住, /* 20160814备注

SQL Server创建复合索引时,复合索引列顺序对查询的性能影响

原文:SQL Server创建复合索引时,复合索引列顺序对查询的性能影响    说说复合索引 写索引的博客太多了,一直不想动手写,有一下两个原因: 一是觉得有炒剩饭的嫌疑,有兄弟曾说:索引吗,只要在查询条件上建索引就行了,真的可以这么暴力吗? 二来觉得,索引是个非常大的话题,很难概括出所有的情况,你不整出点新意来,倒是有抄袭照搬的嫌疑 既然写了,就写一点稍微不一样的东西出来, 好了,废话打住,开搞   搭建测试环境: 创建一张表,模拟实际业务中的一个表,往里面填入数据, 时间字段上,相对按照时间