SQL SERVER 2008 筆記之行壓縮和頁壓縮
/*
2008 壓縮
行壓縮
SQL SERVER 2008 引進了行壓縮這個新特性,只有企業版具有該新特性.行壓縮只需要最低的空間對行資料進行壓縮.行壓縮可以在CREATE一個表,索引或者ALTER一個表,索引的時候進行建立.壓縮可以在行級別,也可以在頁級別.同樣備份的時候也可以進行壓縮.以下先舉例說明如何建立一個錶行壓縮和ALTER表的時候新增行壓縮.
建立測試資料
*/
CREATE DATABASE COMPRESSION_TEST
GO
USE COMPRESSION_TEST
GO
/*建立一個具有行壓縮的表*/
CREATE TABLE Compression_tb1
(id
departid int not null,
JOBdesc CHAR(2000) not null --為了效果明顯一點,可以設定長點
)
with( DATA_COMPRESSION=ROW)--建立到有行壓縮選項的表
/*可以用如下語句從新配置壓縮選項*/
ALTER TABLE Compression_tb1 REBUILD
WITH (DATA_COMPRESSION=NONE) --去除壓縮選項
/*
以上個語句可以顛倒過來譬如先建立沒有壓縮選項的表,然後通過ALTER表配置獲得壓縮選項
其中DATA_COMPRESSION有個引數
下面對測試表填充垃圾資料來演示壓縮的效果
*/
INSERT Compression_tb1(departid ,JOBdesc)
VALUES(CAST(RAND()*20 as int)
, REPLICATE('a',50))
GO 100000
/*
資料新增好,我可以用系統SP sp_estimate_data_compression_savings 來估計使用行壓縮或者頁壓縮可以節省多少磁碟空間.sp_estimate_data_compression_savings有個引數:需要壓縮的表的架構名稱、物件名稱、索引ID、分割槽號和壓縮方式。如下的示例先檢查行壓縮可以節省多少空間。
*/
EXEC SYS.sp_estimate_data_compression_savings
@SCHEMA_NAME='DBO',
@OBJECT_NAME='Compression_tb1',
@INDEX_ID=NULL,
@PARTITION_NUMBER=NULL,
@DATA_COMPRESSION='ROW'
/*
結果(行轉列好閱讀)
object_nameCompression_tb1
schema_nameDBO
index_id1
-- 索引的索引ID:= 堆,1 = 聚集索引,>1 = 非聚集索引
partition_number1
-- 分割槽號。對於未分割槽的表或索引,返回1
size_with_current_compression_setting(KB)266720
--當前存在的所請求的表、索引或分割槽的大小。
size_with_requested_compression_setting(KB)8808
--使用請求的壓縮設定及現有填充因子(如果適用)且假定不存在碎片
--時的表、索引或分割槽的估計大小。
sample_size_with_current_compression_setting(KB)29536
sample_size_with_requested_compression_setting(KB)976
--使用請求的壓縮設定及現有填充因子(如果適用)且假定不存在碎片
--時的表、索引或分割槽的估計大小。
上面的結果看可以看出對當前表使用行壓縮可以節省-6712=194040 KB.樣本大小資料是基於儲存過程將樣本資料載入到TEMPDB的克隆表中,並驗證相應的壓縮率.
但是有的情況可能無法節省空間,因為這取決於填充因子和行大小。例如,如果某行長度為8000 位元組並且您將該行的大小減少40%,則資料頁上仍只能容納一行。因此不會節省空間。
下面給表新增行壓縮選項
*/
ALTER TABLE Compression_tb1 REBUILD
WITH (DATA_COMPRESSION=ROW)
EXEC sp_spaceusedCompression_tb1
/*
namerowsreserveddataindex_sizeunused
-----------------------------------------------------------------
Compression_tb11000006544 KB6440 KB8 KB96 KB
結果看以看出壓縮後的表使用看6544 KB的空間.
對於那些已經存在資料的表經行行壓縮我們可以使用ALTER TABLE... WITH(DATA_COMPRESSION=ROW)
下面演示索引的行壓縮
*/
CREATE TABLE Compression_tb2
(id int not null identity(1,1),
departid int not null,
JOBdesc CHAR(2000) not null --為了效果明顯一點,可以設定長點
)
INSERT Compression_tb2(departid ,JOBdesc)
VALUES(CAST(RAND()*20 as int)
, REPLICATE('a',50))
GO 100000
/*
建立聚集索引後再檢視佔用空間
*/
create clustered index id_Compression_tb2_1 ON Compression_tb2(ID)
EXEC sp_spaceusedCompression_tb2
/*
namerowsreserveddataindex_sizeunused
------------------------------------------------------------
Compression_tb2100000200472 KB200000 KB376 KB96 KB
聚集索引的基礎上建立非聚集索引再檢視佔用空間
*/
create nonclustered index departid_Compression_tb2_1 ON Compression_tb2(departid)
EXEC sp_spaceusedCompression_tb2
/*
namerowsreserveddataindex_sizeunused
-------------------------------------------------------------
Compression_tb2100000201712 KB200000 KB1520 KB192 KB
*/
/*
新增壓縮選項.
*/
ALTER INDEX id_Compression_tb2_1 ON Compression_tb2
REBUILD WITH (DATA_COMPRESSION=ROW)
EXEC sp_spaceusedCompression_tb2
/*
namerowsreserveddataindex_sizeunused
-----------------------------------------------------------
Compression_tb21000007864 KB6432 KB1192 KB240 KB
*/
ALTER INDEX departid_Compression_tb2_1 ON Compression_tb2
REBUILD WITH (DATA_COMPRESSION=ROW)
EXEC sp_spaceusedCompression_tb2
/*
namerowsreserveddataindex_sizeunused
-----------------------------------------------------------
Compression_tb21000007656 KB6432 KB1016 KB208 KB
*/
/*
以上的結果對比可以看到在聚集索引和非聚集索引的基礎上建立行壓縮可以節省很多的空間.
當然對於索引行壓縮的建立同樣可以在索引建立的時候指定壓縮選項.
CREATE INDEX ...
WITH (DATA_COMPRESSION=ROW)
*/
/*
頁壓縮的實現
頁壓縮包含行壓縮,以及字首壓縮和字典壓縮,當使用頁壓縮時,將僅使用行壓縮來壓縮索引的非葉級別頁,行壓縮上面已經介紹.
頁壓縮對錶、表分割槽、索引和索引分割槽都是類似的。以下針對表的頁壓縮的說明同樣適用於所有物件型別的頁壓縮。以下示例壓縮的是字串,但對於其他資料型別而言,字首壓縮和字典壓縮的原理都是相同的。
字首壓縮
對於要壓縮的每一頁,字首壓縮採用以下步驟:
1 對於每一列,將確定一個值,此值可用於減少每一列中的值的儲存空間。
2 將建立表示每一列的字首值的行,並將其儲存在緊隨頁頭之後的壓縮資訊(CI) 結構中。
3 列中重複的字首值將由指向對應字首的引用進行替換。如果行中的值與所選字首值並不完全匹配,則
仍會指示存在部分匹配。
下圖顯示了字首壓縮之前表的一個示例頁。
下圖顯示的是同一頁在字首壓縮之後的樣子。字首移至頁頭,列值更改為指向字首的引用
在第一行的第一列,值4b 指示為該行顯示字首的前四個字元(aaab) 和字元b。這樣的話,結果值就是aaabb,這是原始值。
字典壓縮
字首壓縮完成後,將應用字典壓縮。字典壓縮搜尋頁面上任意位置的重複值,然後將它們儲存在CI 區域中。與字首壓縮不同,字典壓縮不侷限於一列。字典壓縮可以替換頁面上任意位置出現的重複值。
下圖顯示的是同一頁在字典壓縮之後的樣子。
請注意,值4b 已由頁的其他列引用。
進行頁壓縮時,當建立具有頁壓縮的新表時,不會進行壓縮。但是,表的元資料會指示應使用頁壓縮。當將資料新增到第一個資料頁時,會對資料進行行壓縮。因為此頁未滿,所以無法通過頁壓縮獲得任何益處。如果頁已滿,則新增下一行將引導頁壓縮操作。將檢視整個頁;計算每一列以進行字首壓縮,然後計算所有列以進行字典壓縮。如果頁壓縮已在頁上為要新增的行建立了足夠的空間,則新增該行,並對資料進行行壓縮和頁壓縮。如果通過頁壓縮獲得的空間減去CI 結構所需空間之後剩餘的空間並不充足,則不會對此頁使用頁壓縮。以後,行將新增到新頁上,如果新頁中也無法再容納更多的行,則將再向表中新增一個新頁。與第一頁類似,新頁最初也不進行頁壓縮。
頁壓縮的建立
*/
CREATE TABLE Compression_tb3
(id int not null identity(1,1),
departid int not null,
JOBdesc CHAR(2000) not null
)
with( DATA_COMPRESSION=PAGE) --頁壓縮選項
--去掉頁壓縮選項
ALTER TABLE Compression_tb3 REBUILD
WITH (DATA_COMPRESSION=NONE)
--建立聚集索引頁壓縮
CREATE CLUSTERED INDEX id_Compression_tb3_1 ON Compression_tb3(ID)
WITH (DATA_COMPRESSION=PAGE)
--建立非聚集索引頁壓縮
CREATE NONCLUSTERED INDEX departid_Compression_tb3_1 ON Compression_tb3(ID)
WITH (DATA_COMPRESSION=PAGE)
/*
建立壓縮之後查詢佔用空間可以非常肯定,頁級壓縮肯定比行級壓縮帶來更大的好處.
同樣作為代價,壓縮通常會增加CPU的使用,所以在你決定使用壓縮之前要在C盤空間
和CPU的開銷之間做出權衡.
不想寫了,分割槽級別的壓縮配置下次寫.
*/