SQL Server ->> Computed Column(計算列)


Computed Column(計算列)是自SQL Server 2005開始就有的特性。計算列的定義是一個表達式。表達式可以是非計算列,常量,函數間的組合。但是不可以是子查詢。

 

計算列數據固化

默認情況下計算列的數據是存儲在磁盤上,僅當計算列被查詢引用是才進行實時計算。只在計算列在定義是添加了PERSISTED關鍵詞是才將數據固化。

 

計算列上創建索引或者作為分區函數的引用列

計算列上是運行創建索引和作為分區函數的引用列。但是必須指定PERSISTED關鍵詞。

 

用法其實很簡單。那么這里有些問題。使用計算列的代價到底有多大?

 

INSERT發生時使用計算列和非計算列的性能區別

這里做一個測試。首先創建好兩張表

IF EXISTS(SELECT * FROM sys.tables WHERE name = 'computed_column_test_computed')
BEGIN
    DROP TABLE dbo.computed_column_test_computed
END

IF EXISTS(SELECT * FROM sys.tables WHERE name = 'computed_column_test_noncomputed')
BEGIN
    DROP TABLE dbo.computed_column_test_noncomputed
END

CREATE TABLE dbo.computed_column_test_computed
(
    dttm DATETIME,
    dttm_year AS YEAR(dttm) PERSISTED,
    dttm_month AS MONTH(dttm) PERSISTED,
    dttm_nextday AS DATEADD(DAY,1,dttm) PERSISTED,
    dttm_previousday AS DATEADD(DAY,-1,dttm) PERSISTED,
    dttm_week AS DATEPART(ww,dttm),
    dttm_monthname AS CASE DATEPART(mm, dttm)
                        WHEN 1 THEN 'January'
                        WHEN 2 THEN 'February'
                        WHEN 3 THEN 'March'
                        WHEN 4 THEN 'April'
                        WHEN 5 THEN 'May'
                        WHEN 6 THEN 'June'
                        WHEN 7 THEN 'July'
                        WHEN 8 THEN 'August'
                        WHEN 9 THEN 'September'
                        WHEN 10 THEN 'October'
                        WHEN 11 THEN 'November'
                        WHEN 12 THEN 'December'
                      END PERSISTED,
    dttm_quarter AS DATEPART(qq,dttm) PERSISTED
)


CREATE TABLE dbo.computed_column_test_noncomputed
(
    dttm DATETIME,
    dttm_year SMALLINT,
    dttm_month SMALLINT,
    dttm_nextday DATETIME,
    dttm_previousday DATETIME,
    dttm_week INT,
    dttm_monthname VARCHAR(30),
    dttm_quarter VARCHAR(30)
)

 

然后開啟IO和TIME的統計信息開關,然后分別對兩張表進行數據插入。

SET STATISTICS TIME ON
SET STATISTICS IO ON

INSERT dbo.computed_column_test_computed(
dttm
)
SELECT DATEADD(SECOND, Num, GETDATE())
FROM dbo.Numbers
WHERE Num <= 1000000

INSERT dbo.computed_column_test_noncomputed(dttm ,
    dttm_year ,
    dttm_month ,
    dttm_nextday ,
    dttm_previousday ,
    dttm_week ,
    dttm_monthname ,
    dttm_quarter)
SELECT     GETDATE(),
        YEAR(GETDATE()) PERSISTED,
        MONTH(GETDATE()) PERSISTED,
        DATEADD(DAY,1,GETDATE()) ,
        DATEADD(DAY,-1,GETDATE()),
        DATEPART(ww,GETDATE()),
        CASE DATEPART(mm, GETDATE())
        WHEN 1 THEN 'January'
        WHEN 2 THEN 'February'
        WHEN 3 THEN 'March'
        WHEN 4 THEN 'April'
        WHEN 5 THEN 'May'
        WHEN 6 THEN 'June'
        WHEN 7 THEN 'July'
        WHEN 8 THEN 'August'
        WHEN 9 THEN 'September'
        WHEN 10 THEN 'October'
        WHEN 11 THEN 'November'
        WHEN 12 THEN 'December'
        END,
    DATEPART(qq,GETDATE())
FROM dbo.Numbers
WHERE Num <= 1000000

 

我的例子里面分別進行10萬行、30萬行、50萬行和100萬行數據的插入測試。一共有7個計算列。每個例子測試兩次。

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 100840, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 164, physical reads 2, read-ahead reads 162, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 515 ms,  elapsed time = 1564 ms.

(100000 row(s) affected)




SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 1327 ms.
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 100833, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 164, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 265 ms,  elapsed time = 759 ms.

(100000 row(s) affected)






SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 5 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 100840, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 164, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 391 ms,  elapsed time = 411 ms.

(100000 row(s) affected)
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 100833, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 164, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 234 ms,  elapsed time = 273 ms.

(100000 row(s) affected)








 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 6 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 302521, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 487, physical reads 1, read-ahead reads 330, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1250 ms,  elapsed time = 1986 ms.

(300000 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 74 ms.
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 302499, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 487, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 813 ms,  elapsed time = 966 ms.

(300000 row(s) affected)




SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 14 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 302521, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 487, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1156 ms,  elapsed time = 1709 ms.

(300000 row(s) affected)
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 302499, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 487, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 734 ms,  elapsed time = 3089 ms.

(300000 row(s) affected)






SQL Server parse and compile time: 
   CPU time = 8 ms, elapsed time = 8 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 504201, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 809, physical reads 0, read-ahead reads 315, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2031 ms,  elapsed time = 2080 ms.

(500000 row(s) affected)
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 504166, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 809, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1297 ms,  elapsed time = 2915 ms.

(500000 row(s) affected)





SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 4 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 504201, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 809, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1984 ms,  elapsed time = 3540 ms.

(500000 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 2 ms.
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 504166, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 809, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 1266 ms,  elapsed time = 1341 ms.

(500000 row(s) affected)






SQL Server parse and compile time: 
   CPU time = 13 ms, elapsed time = 13 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 1008359, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 791, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 4500 ms,  elapsed time = 9110 ms.

(1000000 row(s) affected)
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 1008333, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2531 ms,  elapsed time = 3903 ms.

(1000000 row(s) affected)






SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 3 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 1008359, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 3797 ms,  elapsed time = 6559 ms.

(1000000 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 3 ms.
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 1008333, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2422 ms,  elapsed time = 3895 ms.

(1000000 row(s) affected)

 

可以看到確實使用computed column會對性能有一定的影響。當計算列數量越多的情況下性能的影響越大。但是當計算列數量很少的情況下,影響或者說差別其實很小很小。以我做的實驗為例,講計算列數量減少到只有3個,數據量依舊停留在100萬行的情況,兩者的性能差異其實已經很小了。

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 4 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 1005813, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 3203 ms,  elapsed time = 5058 ms.

(1000000 row(s) affected)
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 1005319, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2281 ms,  elapsed time = 4747 ms.

(1000000 row(s) affected)




SQL Server parse and compile time: 
   CPU time = 16 ms, elapsed time = 28 ms.
Table 'computed_column_test_computed'. Scan count 0, logical reads 1005813, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2984 ms,  elapsed time = 3512 ms.

(1000000 row(s) affected)
Table 'computed_column_test_noncomputed'. Scan count 0, logical reads 1005319, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 1615, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2672 ms,  elapsed time = 2859 ms.

(1000000 row(s) affected)

 

那么總結下,計算列的使用原則我認為是在表中計算列的數量本身不多,而且一次性數據行插入量不大,計算邏輯固定,計算復雜度大的情況下,推薦使用計算列。

 

比如像DimDate這種表,表中可能有非常多的屬性列用於表示當前日期的一些額外屬性,比如下一天的日期,前一天的日期等等。用計算列是一個很好的選擇。

 

參考:

Computed Columns

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM