最近做了一个关于数据压缩的项目,要把整个SQL SERVER服务器下所有的表对象要改成页压缩。于是趁此机会了解了一下SQL SERVER下压缩技术。
这篇文章几乎就是完全指导手册了
https://technet.microsoft.com/en-us/library/dd894051(v=sql.100).aspx
当然这里还有技术wiki page
https://msdn.microsoft.com/en-us/library/cc280449.aspx
那看了这么多,这里总结一下:
1)SQL SERVER下一共有两种压缩类型:Row Compression和Page Compression
2)Row Compression把固定长度的数据列存成可变长度的格式,然后每列取4位(bits)来记录数据的长度,NULL和0除了那4位对数据存储空间不做任何影响。翻译过来是这样,但其实还是不是很懂。然而Page Compression则易懂得多了,前缀压缩和字典压缩技术。先进行前缀压缩,然后对整个页面进行字典压缩达到压缩比的最大化。
3)想知道一个数据库是否已经应用了压缩,查下这张DMV:select * from sys.dm_db_persisted_sku_features;
4)预估空间上的节省(Estimated space savings)
这个存储过程可以用来预估单张表大概可以节省多少数据库存储空间:sp_estimate_data_compression_savings. 整个计算过程是取样放到tempdb下而不是全表扫描。
5)什么样的数据压缩比率最大最有效?空值,大部分空间都用不到的固定长度数据(字符或者数字),前缀值重复率高的数据。
6)压缩对LOB、ROW_OVERFLOW数据页和FILESTREAM数据不奏效
7)压缩完的数据页从磁盘读进内存是不解压的,数据页只有在参与排序(sort)、连接(Join)、筛选(filter)或者被更新的时候才会被解压缩
8)解压缩的过程并非说在内存里面复制出另外一份数据来解压缩,而是用CPU计算后解压。
9)压缩技术对于表扫描的作用显然要比查找大,这样才能体现出在大存储空间下压缩对IO优化的优势
10)那么按理来说,压缩提升了IO和内存,以CPU作为代价。而Row Compression的CPU代价显然要比Page Compression要低,但是Page Compression的压缩比要更高。文章中说到Row Compression仅比没压缩的CPU多出10 percent,我没有实际测试过。
11)对于Page Compression,建议是用在那些少更新的大表、服务器上CPU的占用还算低的情况下。而虽然前面提到了数据页在参与排序(sort)、连接(Join)、筛选(filter)或者被更新的时候才会被解压缩,但是文章中提到了如果查询语句的本身就存在复杂的聚合运行逻辑和连接,那压缩对其造成的影响将不是一个大的方面。其实按道理来讲,可以说压缩技术即便消耗了更多的CPU资源,但是考虑到在一个大的压缩比的前提下,即便参与数据在参与聚合或者连接的时候需要被解压缩,但是这一切毕竟是在内存里面,比起没有压缩的页面需要重新被读取到内存里面(一般情况下,如果是数据仓库的话,数据页面很难停留在内存里面太久),我想要更划算,毕竟内存的读写能力和磁盘的读写能力不是能相提并论的。
12)那是决定Row Compression还是Page Compression?原则是U(update)和S(scan)。被更新得越频繁的表越适合Row Compression,更多参与查询的表越适合Page Compression。不过我觉得,这个还要更数据量的大小有关。比如如果某张表的数据量非常大,10几个G或者数亿行数据行的数据量的话,Page Compression的高压缩比的优势太大了。下列语句可以查出数据库中表更新和扫描的频率
--Update SELECT o.name AS [Table_Name], x.name AS [Index_Name], i.partition_number AS [Partition], i.index_id AS [Index_ID], x.type_desc AS [Index_Type], i.leaf_update_count * 100.0 / (i.range_scan_count + i.leaf_insert_count + i.leaf_delete_count + i.leaf_update_count + i.leaf_page_merge_count + i.singleton_lookup_count ) AS [Percent_Update] FROM sys.dm_db_index_operational_stats (db_id(), NULL, NULL, NULL) i JOIN sys.objects o ON o.object_id = i.object_id JOIN sys.indexes x ON x.object_id = i.object_id AND x.index_id = i.index_id WHERE (i.range_scan_count + i.leaf_insert_count + i.leaf_delete_count + leaf_update_count + i.leaf_page_merge_count + i.singleton_lookup_count) != 0 AND objectproperty(i.object_id,‘IsUserTable‘) = 1 ORDER BY [Percent_Update] ASC --Scan SELECT o.name AS [Table_Name], x.name AS [Index_Name], i.partition_number AS [Partition], i.index_id AS [Index_ID], x.type_desc AS [Index_Type], i.range_scan_count * 100.0 / (i.range_scan_count + i.leaf_insert_count + i.leaf_delete_count + i.leaf_update_count + i.leaf_page_merge_count + i.singleton_lookup_count ) AS [Percent_Scan] FROM sys.dm_db_index_operational_stats (db_id(), NULL, NULL, NULL) i JOIN sys.objects o ON o.object_id = i.object_id JOIN sys.indexes x ON x.object_id = i.object_id AND x.index_id = i.index_id WHERE (i.range_scan_count + i.leaf_insert_count + i.leaf_delete_count + leaf_update_count + i.leaf_page_merge_count + i.singleton_lookup_count) != 0 AND objectproperty(i.object_id,‘IsUserTable‘) = 1 ORDER BY [Percent_Scan] DESC
那么如果要压缩,需要注意些什么呢?或者说对系统有哪些影响呢?
压缩都是通过REBUILD INDEX来完成。
SORT_IN_TEMPDB选项影响tempdb的空间增长
ONLINE影响用户数据库的空间增长和事务日志文件大小的增长
RECOVERY MODE影响事务日志文件大小的增长
表或者索引在被压缩的过程中,旧的索引在被替换前是和被压缩后的索引同时存在用户数据库里面的,替换后才把空间还给文件组,那么最起码一条索引所需要的空间只是索引现有空间大小+(索引现有空间大小-savings)
Online选项会消耗更多的CPU
对于tempdb空间增长的影响,
如果RECOVERY MODE是SIMPLE,每次CHECK