2.6 计算列

2.6  计算列


2.6.1  使用计算列的场景

  一般在设计 T-SQL 查询的时候应该避免在条件子句中使用函数和运算,因为这样往往不能有效地使用索引,从而无法生成高效的执行计划。

  例如,某些排序规则对大小写敏感,如果在设计数据库和应用程序时没有考虑到排序规则的影响,那么需要在查询的时候通过函数将该列强制转化为大写或小写。由于对该列使用了函数,查询执行计划将不使用该列上的索引。

SELECT * FROM SalesTerritory WHERE UPPER(CountryName) = 'CHN'


  又如,销售清单上的单项金额可以通过数量列和单价列计算出来。通常在设计数据库时不设计单项金额列,只在查询时才通过函数计算出一个单项金额。如果条件子句中需要引用该计算值,则查询执行计划将不使用索引。

SELECT *,OrderQty * UnitPrice AS LineTotal FROM OrderDetail

  WHERE LineTotal > 100


  计算列可以有效地解决上述问题。可以对上述表添加一个计算列,并对该计算列添加索引,从而在条件子句中通过使用该索引以提高查询效率。

  计算列由可以使用同一表中的其他列的表达式计算得来。表达式可以是非计算列的列名、常量、函数,也可以是用一个或多个运算符连接的上述元素的任意组合。计算列的表达式不能为子查询。

  计算列可用于选择列表、WHERE 子句、ORDER BY 子句或任何可使用正则表达式的其他位置。

但是计算列不能作为 INSERT 或 UPDATE 语句的目标。


2.6.2  持久化

  如果不使用PERSISTED 关键字,计算列是未实际存储在表中的虚拟列。每当在查询中引用计算列时,都将重新计算它们的值。

  在 CREATE TABLE 或 ALTER TABLE 语句中标记为 PERSISTED 的计算列实际存储在表中。如果在计算列的计算更改时涉及任何列,将更新计算列的值。 

CREATE TABLE [dbo].[OrderDetail](

[OrderNum] [int] NOT NULL,

[LineNum] [tinyint] NOT NULL,

[ProductNum] [int] NOT NULL,

[OrderQty] [smallint] NOT NULL,

[UnitPrice] [money] NOT NULL, 

[LineTotal]  AS (isnull(round([UnitPrice]*[OrderQty],(2)),(0.0))) PERSISTED 

)


  如果计算列使用确定性但不精确的表达式定义,但在 CREATE TABLE 或 ALTER TABLE 语句中标记为 PERSISTED,则可以在该列上创建索引。这意味着数据库引擎在表中存储计算值,并且在计算列所依赖的任何其他列发生更新时更新这些值。如果数据库引擎对列创建了索引并且该索引由某查询引用,则会使用这些持久值。

  以下是需要持久化的常见的场景。

(1)需要频繁访问的计算列可以考虑持久化。

(2)用作 CHECK、FOREIGN KEY 或 NOT NULL 约束的计算列必须标记为 PERSISTED。

(3)需要在计算列上创建索引。



2.6.3  数据类型

  计算列的值不能为 text、ntext 或 image 数据类型。

  只要计算列的数据类型可以作为索引键列,从 image、ntext、text、varchar(max)、nvarchar(max)、varbinary(max) 和 xml 数据类型派生的计算列上就可以创建索引。

  只要计算列的数据类型可以作为非键索引列,从 image、ntext 和 text 数据类型派生的计算列就可以作为非聚集索引中的非键(包含性)列。

  数据库引擎基于使用的表达式自动确定计算列的为 Null 性。即使只有非空列,大多数表达式的结果也“认为”可为空值,因为下溢或溢出生成的结果也可能为空。通过指定 ISNULL 函数可以将可为空值的表达式转换为不可为空值的表达式。



2.6.4  精确性

  计算列的值必须考虑精确性。计算列的表达式必须至少满足以下条件之一才是精确的。

(1)表达式的数据类型不是 float 或 real。

(2)表达式定义中没有使用 float 或 real 数据类型。


提示: 

  任何 float 或 real 表达式都被认为是不精确的,不能作为索引键;float 或 real 表达式可以在索引视图中使用,但不能作为键使用。对于计算列同样如此。

  如果任何函数、表达式或用户定义函数包含任何 float 或 real 表达式,则被认为是不精确的。这也包括逻辑表达式(比较)。


  如果计算列使用了不精确的表达式定义,为了能在该计算列上创建索引,则必须使用 PERSISTED 关键字将该计算列持久化。当数据库引擎不能准确证明返回计算列表达式的函数是否具精确时,使用此选项可以对计算列创建索引。

  这意味着数据库引擎在表中存储计算值,并且在计算列所依赖的任何其他列发生更新时自动更新这些计算列的值。如果某查询引用了该计算列的索引,则会使用这些持久化的值。



2.6.5  确定性

  计算列的表达式必须具有确定性,即对于一组指定的输入表达式始终返回相同的结果。为了实现确定性,计算列表达式必须至少满足以下之一的条件。

(1)表达式引用的所有函数都具有确定性,并且是精确的。这些函数包括用户定义函数和内置函数。

(2)表达式引用的所有列都来自包含该计算列的当前表。

(3)没有列引用从多行中请求数据。例如,聚合函数(如 SUM 或 AVG)依靠来自多行的数据,这使计算列表达式具有不确定性。

(4)没有系统数据访问或用户数据访问。


  如果计算列的值由具有确定性的表达式定义,并且索引列中允许使用计算结果的数据类型,则可将该列用作索引中的键列,或者用作 PRIMARY KEY 或 UNIQUE 约束的一部分。


本文出自 “SQL Server 管理员指南” 博客,谢绝转载!

你可能感兴趣的:(表,计算列)