數據壓縮


對於行存儲(相比列存儲)的表和索引,啟用數據壓縮最直接效果是能夠減小數據占用的存儲空間的大小;除了節省空間之外,數據壓縮還能提高 I/O 密集型查詢的性能,因為數據存儲在更少的數據頁(Data Page)中,SQL Server需要從磁盤讀取的數據頁更少,數據從Disk加載到內存的速度更快,查詢的性能更好。但是,壓縮和解壓縮的過程都需要消耗額外的CPU資源,開發者必須均衡CPU資源,數據存儲和硬盤IO的開銷。

SQL Server提供兩種數據壓縮方式:行(Row)壓縮和頁壓縮(Page),用於壓縮表或索引數據,數據壓縮對應用程序是透明的。

一,行壓縮(Row Compression)

行壓縮是將固定長度類型存儲為可變長度存儲類型,行壓縮是自動進行的,對應用程序不可見,應用程序不需要做任何修改。

1,對於字符型

Char(200),這是一個固定長度的數據類型,但是在實際存儲的時候,可能不會存儲200個字符。在物理存儲數據時,SQL Server后補空格以達到200個字符。如果將其轉換為varchar(200),不需要后補空格,節省存儲空間。行壓縮無法處理XML、BLOB和MAX數據類型

2,對於數值型

在SQL Server 2005 SP2之前,decimal類型總是以固定數據存儲的。根據值的精確度,每個decimal值都需要5到17字節的空間。新引入的Vardecimal存儲格式是把decimal值以一個可變長度的格式進行存儲。這種格式把小數值前后的零都去除,可以減少存儲所需的空間。

SOL Server 2008數據壓縮擴展了這個功能,對所有固定長度的數據類型都進行了處理,包括integer、char和float。現在數據不是以固定大小的字節進行存儲,而是用最小所需的字節。開發者不需要修改數據類型,只需要啟用行壓縮功能,SOL Server 2008及其之后的版本就會使用最小的可變數據類型來存儲數據。

3,行壓縮的實現 

啟用行壓縮只會更改與數據類型相關聯的數據的物理存儲格式,將固定長度的類型修改為可變長度的類型進行存儲,而不會更改其語法或語義。新的記錄存儲格式主要有以下更改:

  • 減少了與記錄相關聯的元數據開銷。此元數據為有關列、列長度和偏移量的信息。在某些情況下,元數據開銷可能大於舊的存儲格式;
  • 它對於數值類型(例如,integer、decimal 和 float)和基於數值的類型(例如,datetime 和 money)使用可變長度存儲格式。 例如將decimal 修改為vardecimal;
  • 它通過使用不存儲空字符的可變長度格式來存儲定長字符串。例如,將char 修改為varchar;

實現的原理,通俗解釋是通過修改物理存儲格式,將定長類型轉換為變長類型,達到壓縮數據的目的,但是物理存儲格式的修改不會影響該字段使用的語法,例如:

  • 對於數值類型和基於數值的類型來說,數據類型的長度是一定的,如BIGINT占用8個字節,但對於值1來說,只需要一個字節便可以存放,啟用行壓縮便可以節省7個字節的空間;
  • 對於定長字符串類型,如果存放的數據未達到指定長度,會補空字符來填滿,如類型CHAR(200)用來存放字符串"1"會花費200個字節,但啟用行壓縮后,會將填充的空字符移除,只需要1個字節便可以存放。將char(200)修改為Varchar(200)來存儲數據。
  • 對於類型bit來說,除自身消耗的空間外,還需要額外的4個bit來存放元數據,因此也可以從行壓縮中獲益。

4,數據壓縮存在額外的開銷(每列占用4Bit)

對於行壓縮,每個column占用4bits,用於存儲Column的長度。對所有數據類型的 NULL 和 0 值進行優化,除了4bits之外,使它們不占用任何字節。

二,頁壓縮(Page Compression)

行壓縮是對每個數據行進行壓縮存儲,頁壓縮是對位於同一個數據頁上的多行數據進行優化存儲,減少數據的冗余,節省存儲空間。頁壓縮是在行壓縮的基礎上進行前綴壓縮,然后再進行字典壓縮。

  • 對於葉級別的數據頁,頁壓縮首先對數據進行行壓縮,然后再依次進行前綴壓縮和字典壓縮;
  • 對於非葉級別的數據頁,頁壓縮只對數據進行行壓縮;

1,前綴壓縮(Prefix Compression)

前綴壓縮是指:在每個數據頁上的所有數據行(Rows)中,對於給定的列(Column),如果其前綴模式相同,那么將相同的前綴壓縮存儲,以節省存儲空間;

  • 對於每一列,找出一個共用模式( Common Pattern),將列值替換為共用模式能夠減少列的存儲空間;共用模式存儲在壓縮信息CI(Compression Information)中,CI存儲在每個Page中,靠近Page Header的下一個數據行中;
  • 在Page Header之后,創建一個數據行,用於存儲每列的共用模式;
  • 對於每一列中的數據值,替換為共用,即引用短的前綴模式,以減少列的存儲空間;

比如,有一個數據頁,有三個數據行,每行有三個數據列:

對Page使用前綴壓縮存儲之后,SQL Server在Page Header之后,創建CI數據行,存儲該數據頁中每列數據的共用模式,數據頁的存儲結構如圖:

2,字典壓縮(Dictionary Compression)

字典壓縮在前綴壓縮之后執行,字典壓縮是指:在每個數據頁上的所有數據行(Rows)中,對所有列(Columns)查找重復的值,並將重復的值存儲在壓縮信息CI(Compression  Information)中,將長的重復值替換為短的數據值,以節省數據空間。

Dictionary compression searches for repeated values anywhere on the page, and stores them in the CI area. Dictionary compression can replace repeated values that occur anywhere on a page. 

頁壓縮比行壓縮節省的存儲空間更多。當表和索引使用頁壓縮后,對於一個新的頁面,插入數據行時會對該行啟用行壓縮,直到該頁已滿無法存放新增加的行時,才會使用頁壓縮的算法計算啟用頁壓縮是否能存放新增加的行,如果可以存放,則對該頁進行頁壓縮並將新增加的行放到該頁,如果不能存放,則不對該頁啟用頁壓縮,申請新頁來存放新行。

三,表數據壓縮

1,在表的Storage 選項卡查看表的存儲屬性

在壓縮數據之前,通過 sys.partitions 的字段:data_compression 和data_compression_desc 查看table 或 index在每個Partition上的壓縮狀態;通過 sys.allocation_units 查看 total_Pages, Used_pages 等信息

select
    object_name(p.object_id) as table_name,
    p.partition_number,
    p.index_id,
    p.rows,
    p.data_compression_desc,
    au.Type_desc,
    au.total_pages,
    au.used_pages,
    au.data_pages
from sys.partitions p
inner join sys.allocation_units au
    on p.partition_id=au.container_id 
where p.object_id=object_id('table_name','U')
order by p.partition_number
    ,p.index_id

2,在創建表時,指定數據壓縮選項

create table dbo.Table_Name
(
    Column_Definition
)
with( data_compression=page|row|none)

3,壓縮存儲現有表數據

alter table dbo.Table_Name
rebuild
with (data_compression=row|page) 

4,在新建索引時,指定數據壓縮選項

create index index_name 
on dbo.Table_Name
(
index_key
)
with (data_compression=row|page) 

5,壓縮存儲現有索引的數據

alter index index_name 
on dbo.Table_Name
rebuild
with (data_compression=row|page) 

四,估算數據壓縮的效果(sp_estimate_data_compression_savings )

使用 sys.sp_estimate_data_compression_savings 估算對表或分區啟用數據壓縮(行或頁),可能節省的存儲空間

 

exec sys.sp_estimate_data_compression_savings
       @schema_name='dbo',
       @object_name='table_name',
       @index_id=NULL,
       @partition_number=NULL,
       @data_compression='page'

 

五,查看壓縮成功的pages數量

通過函數 sys.dm_db_index_operational_stats 查看以Page類型壓縮,節省的Page數量。該函數返回的結果集中有

  • page_compression_attempt_count: Number of pages that were evaluated for PAGE level compression for specific partitions of a table, index, or indexed view.
  • page_compression_success_count: Number of data pages that were compressed by using PAGE compression for specific partitions of a table, index, or indexed view.
SELECT
    ios.database_id,
    ios.object_id,
    ios.index_id,
    ios.page_compression_attempt_count,
    ios.page_compression_success_count,
    ios.page_compression_success_count/ios.page_compression_attempt_count as comression_rate
FROM sys.dm_db_index_operational_stats(DB_ID(), OBJECT_ID('[dbo].[UserCDC]','U'), 1, NULL) AS ios

 

參考文檔:

Data Compression: Strategy, Capacity Planning and Best Practices

Page Compression Implementation

Data Compression


免責聲明!

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



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