在计算列中创建索引提高性能

前言:
在理解计算列上的索引之前,先了解计算列的基本知识。计算列由可以使用同一表中的其他列的表达式计算得来。表达式可以是非计算列的列名、常量、函数,也可以是用一个或多个运算符连接的上述元素的任意组合。表达式不能为子查询。
默认情况下,计算列是一个虚拟的列,并且可以在调用时重新计算,直到在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-12-22 10:09:24

在计算列中创建索引提高性能的相关文章

CREATE INDEX 语句用于在表中创建索引

CREATE INDEX 语句用于在表中创建索引. 在不读取整个表的情况下,索引使数据库应用程序可以更快地查找数据. 索引 您可以在表中创建索引,以便更加快速高效地查询数据. 用户无法看到索引,它们只能被用来加速搜索/查询. 注释:更新一个包含索引的表需要比更新一个没有索引的表更多的时间,这是由于索引本身也需要更新.因此,理想的做法是仅仅在常常被搜索的列(以及表)上面创建索引. SQL CREATE INDEX 语法 在表上创建一个简单的索引.允许使用重复的值: CREATE INDEX ind

通过使用JanusGraph索引提高性能

翻译整理:纪玉奇 Extending JanusGraph Server JanusGraph支持两种类型的索引:graph index和vertex-centric index.graph index常用于根据属性查询Vertex或Edge的场景:vertex index在图遍历场景非常高效,尤其是当Vertex有很多Edge的情况下. Graph Index Graph Index是整个图上的全局索引结构,用户可以通过属性高效查询Vertex或Edge.如下面的代码: g.V().has('

在WPF中 使用StreamGeometry提高性能。

现在正在使用WPF开发一个股票K线图图表,性能考虑是最大的一方面. 每根柱子宽5像素,柱子和柱子之间的间隔3像素. 一个1920*1080分辨率的屏幕,势必要绘制超过200个柱子.如果选择的绘制方案不先进,对图表的绘制是有很大的性能影响的. 任何图形都由直线和曲线构成的.在WPF中,最底层的图形的绘制级别是Geometry. 在WPF中,使用DrawingContext的方法绘制一个直线,就内部创建了一个LineGeometry对象,绘制一个矩形,就内部创建了一个RectagleGeometry

lucene中创建索引库

package com.hope.lucene; import org.apache.commons.io.FileUtils;import org.apache.lucene.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.document.TextField;import org.apache.lucene.index.IndexWriter;import org.apach

通过在Oracle子表外键上建立索引提高性能

根据我的经验,导致死锁的头号原因是外键未加索引(第二号原因是表上的位图索引遭到并发更新).在以下两种情况下,Oracle在修改父表后会对子表加一个全表锁: 1)如果更新了父表的主键(倘若遵循关系数据库的原则,即主键应当是不可变的,这种情况就很少见),由于外键上没有索引,所以子表会被锁住. 2) 如果删除了父表中的一行,整个子表也会被锁住(由于外键上没有索引). 除了全表锁外,在以下情况下,未加索引的外键也可能带来问题: 1) 如果有ON DELETE CASCADE,而且没有对子表加索引:例如,

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

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

计算列建立索引

计算列上的索引 只要满足下列要求就可以为计算列定义索引: 1.所有权要求 2.确定性要求 3.精度要求 4.数据类型要求 5.SET 选项要求 所有权要求 计算列中的所有函数引用必须与表具有相同的所有者. 测试环境(MSSQL 2012): --自定义所有者为guest的标量函数GetMonth CREATE FUNCTION guest.GetMonth(@1 datetime) returns nvarchar(10) as begin DECLARE @return nvarchar(10

SQL语句-创建索引

  语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100GO USE 库名GOIF EXISTS (SELECT * FROM SYSINDEXES WHERE NAME='IX_TEST_TNAME')--检测是否已经存在IX_TEST_TNAME索引DROP INDEX TEST.IX_TEST_TNAME--如果存在则删除 --创建索引CREATE NONCLUSTERED INDEX IX_TEST_TNAME

MongoDB 基础(三)mongodb 中的索引使用

MongoDB中的索引和其他数据库索引类似,也是使用B-Tree结构.MongoDB的索引是在collection级别上的,并且支持在任何列或者集合内的文档的子列中创建索引. 下面是官方给出的一个使用索引查询和排序的一个结构图. 所有的MongoDB集合默认都有一个唯一索引在字段"_id"上,如果应用程序没有为 "_id"列定义一个值,MongoDB将创建一个带有ObjectId值的列.(ObjectId是基于 时间.计算机ID.进程ID.本地进程计数器 生成的)