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

2021-09-07 08:11:18 字數 4481 閱讀 6130

上一節我們結束了hash match aggregate和stream aggregate的講解,本系列我們來講講關於sql server中的計算列問題,簡短的內容,深入的理解,always to review the basics。

在sql server 2005就引入了計算列,我們首先稍微看下在msdn關於計算列的定義:計算列由可以使用同一表中的其他列的表示式計算得來。表示式可以是非計算列的列名、常量、函式,也可以是用乙個或多個運算子連線的上述元素的任意組合。表示式不能為子查詢。實際上就是為了定義乙個列來對其他列來進行計算可以是列名、函式等,那麼它的使用場景是什麼呢?下面我們首先來舉個例子。當需要匯出一些值時,此時這些值需要通過計算才能被匯出,同時呢,有一些列還依賴於另外的一列或者更多列,如果乙個列進行了更新則其依賴的列必須同步進行更新,上述場景通過對乙個列或者多個列進行計算,此時我們需要定義乙個將乙個列或者多個列進行計算得到的值的列,這就是計算列。我們來看乙個典型的例子,在乙個公司上班的所有員工,在公司內部系統中會存其所有員工的資訊,比如員工編號、出生日期等,如果此時我們需要匯出員工的退休日期呢,假設在中國現在男性退休時間為60年後,此時我們需要通過出生日期算出60年後的日期,也就說在表中還需要定義乙個退休日期列。下面我們建立表來看看計算列。

use tsql2012

gocreate table employee

( employeenumber int not null, --員工編號

employeebirth datetime not null,--出生日期

employeeretirement as (dateadd(year,

60, (employeebirth)-(1

))) persisted --退休日期

)

此時我們看到表中關於退休日期的設計,顯示其已經是持久化了的

接下來我們插入測試資料看看

use tsql2012

goinsert into dbo.employee( employeenumber, employeebirth )

select

305423 ,'

1985-12-13

'union all

select

587650 ,'

1989-11-18

'union all

select

221836 ,'

1990-01-19

'union all

select

746104 ,'

1993-06-13

'union all

select

139024 ,'

1995-07-23

'

然後我們來查詢表

此時我們通過查詢雇員表得到其每個雇員的退休日期,到這裡是沒什麼問題的,既然我們設定它是持久化的,也就說當其他列發生改變時計算列也會對應發生改變,突然有一天編號為305423的雇員和錄入資訊的同事交流,他其實是2023年出生的,上面的2023年是身份證上的,身份證搞錯了,此時我們需要更新其出生日期到2023年,如下

update dbo.employee set employeebirth = '

1986-12-13

' where employeenumber = '

305423

'

接下來我們再來查詢資料看看。

此時我們發現當出生日期發生修改時,其對應的計算列也進行了同步由原來的2045更新到了2046,上述我們新增在計算列中新增了persisted關鍵字,是不是因為新增這個關鍵字導致持久化從而當乙個列進行更新時,計算列也就同步更新了呢,難道這就是persisted持久化的作用嗎,實際情況不是這樣的,當你去掉persisted關鍵字此時也會進行同步更新(不信你可以試試),那麼persisted關鍵字的作用是什麼呢?事實情況是這樣的,當我們在列上建立了計算列時,此時計算出來的資料並沒有存在列中(至於存在**我也不知道),計算的資料是在執行時計算出來的,當用persisted關鍵字標識計算列之後,這個時候才是將計算結果存在表中計算列上。繼續往下看資料儲存空間使用情況就可以得到驗證。

下面我們來看看當未新增計算列、新增計算列、計算列持久化時表資料儲存空間情況。下面我們來建立測試表

use tsql2012

gocreate table [dbo].[computecolumn]

(id int,

firstname varchar(

100),

lastname varchar(

100)

)go

在表中插入10萬條資料

insert into [computecolumn] (id,firstname,lastname)

select top

100000

row_number() over (order by a.name) rowid,

'bob',

case when row_number() over (order by a.name)%2 = 1 then '

smith

'else

'brown

'end

from sys.all_objects a

cross join sys.all_objects b

go

此時我們來看看有關表儲存空間使用情況

上述我們得知儲存資料為2680kb,下面我們再來建立計算列看看。

從這裡我們可以得出當建立計算列時其資料根本沒有存在列上,我們再來看看新增持久化關鍵字時情況又是怎樣的呢

當新增持久化關鍵字時此時表儲存資料空間變為了4784kb,到此驗證了當未新增persisted關鍵字時,在計算列上的資料根本沒有存在列上而是在執行時進行了計算,當用persisted關鍵字標識計算列時此時資料才存在列上。

我們知道如果對列建立索引的話肯定需要一定空間來儲存索引,上述我們對列進行了持久化,此時會增加表儲存空間,要是我們建立索引是不是會增加表資料儲存空間大小呢?我們在未建立計算列前先建立索引看看其表中各種資料空間儲存大小,即在建立的列fullname上建立索引。

因為建立了索引,所以只是導致索引空間變大了,下面我們再建立計算列持久化並看看其表空間使用情況

從上我們可以看到增加索引未導致表資料大小的增加,而建立計算列持久化則需要額外的空間。分析到這裡為止,我們來給出乙個基本結論:

計算列分析結論:計算列的用途主要用於多個計算並且比較複雜的計算,如果對計算列進行持久化雖然能夠大大減少計算開銷但是它會額外增加磁碟空間。

本節我們學習了計算列以及將其持久化的基礎內容,下一節我們講講關於計算列以及計算列持久化的效能問題,簡短的內容,深入的理解,我們下節再會。 

SQL Server計算列是否占用空間

今天看網上有個問題 sql server計算列是否占用空間 其實這個問題查一下msdn或者bol就可以知道結果了 在建立計算列的時候有乙個引數可以指定persisted。使用這個引數可以指定資料庫引擎將在表中物理儲存計算值,並在計算列依賴的任何其他列發生更新時對這些計算值進行更新。而且將計算列標記為...

SQL Server聚集索引和非聚焦索引

1 什麼是索引?索引在資料庫中的作用類似於目錄在書籍中的作用,用來提高查詢資訊的速度。使用索引查資料無需進行全表掃瞄,可以快速查詢所需的資料。2 聚集索引和非聚集索引的區別?乙個表只能有乙個聚集索引但可以有多個非聚集索引。聚集索引的葉節點就是最終的資料節點,而非聚集索引的葉節仍然是索引節點,但它有乙...

SQL SERVER重置自動編號列 標識列

兩種方法 一種是用truncate truncate table name 可以刪除表內所有值並重置標識值 二是用dbcc checkident dbcc checkident table name reseed,new reseed value 如dbcc checkident bc pos re...