行压缩的实现

适用于: SQL Server Azure SQL 数据库 Azure SQL 托管实例

本文总结了数据库引擎实现行压缩的方式。 此摘要提供了有助于您规划数据所需存储空间的基本信息。

启用压缩只会更改与数据类型相关联的数据的物理存储格式,而不会更改其语法或语义。 当对一个或多个表启用压缩时,不需要更改应用程序。 新的记录存储格式主要有以下更改:

  • 减少了与记录相关联的元数据开销。 此元数据为有关列、列长度和偏移量的信息。 在某些情况下,元数据开销可能大于旧的存储格式。

  • 它对于数值类型(例如, integerdecimalfloat)和基于数值的类型(例如, datetimemoney)使用可变长度存储格式。

  • 它通过使用不存储空字符的可变长度格式来存储定长字符串。

注意

优化了所有数据类型的 NULL0 值,从而使其不占用任何字节。

行压缩影响存储的方式

下表介绍了行压缩是如何影响 SQL Server 和 Azure SQL 数据库中的现有类型的。 此表不包括可以通过使用页压缩节省的空间。

Data type 是否影响存储? 说明
tinyint 1 个字节是所需的最小存储单位。
smallint 如果值使用 1 个字节即可存储,则只使用 1 个字节。
int 只使用所需字节数。 例如,假设某个值可以用 1 个字节存储,则将只占用 1 个字节的存储空间。
bigint 只使用所需字节数。 例如,假设某个值可以用 1 个字节存储,则将只占用 1 个字节的存储空间。
decimal 仅使用所需的字节数,而无需考虑所指定的精度。 例如,假设某个值可以用 3 个字节存储,则将只占用 3 个字节的存储空间。 此存储空间占用情况与 vardecimal 存储格式完全相同
numeric 仅使用所需的字节数,而无需考虑所指定的精度。 例如,假设某个值可以用 3 个字节存储,则将只占用 3 个字节的存储空间。 此存储空间占用情况与 vardecimal 存储格式完全相同
bit 元数据开销使此类型达到 4 个位。
smallmoney 使用 4 字节整数表示整数数据。 货币值乘以 10,000,并在存储生成的整数值时删除小数点之后的所有位数。 此类型具有类似于整数类型存储优化的存储优化。
money 使用 8 字节整数表示整数数据。 货币值乘以 10,000,并在存储生成的整数值时删除小数点之后的所有位数。 此类型的范围比 smallmoney更大。 此类型具有类似于整数类型存储优化的存储优化。
float 不存储带零的最低有效字节。 float 压缩主要适用于尾数中的非小数值。
real 不存储带零的最低有效字节。 real 压缩主要适用于尾数中的非小数值。
smalldatetime 使用两个 2 字节整数表示整数数据,并且为自 1900-01-01 起的天数。 smalldatetime 的日期部分不能使用行压缩。

时间是自午夜以来经过的分钟数。 超过 4AM 后,时间值就开始使用第二个字节。

如果 smalldatetime 只用于表示日期(常见情况),则时间为 0.0。 通过为行压缩以最高有效字节格式存储时间,压缩操作可节省 2 个字节。
datetime 使用两个 4 字节整数表示整数数据。 此整数值表示自基准日期 1900-01-01 以来经过的天数。 前 2 个字节最高可以表示 2079 年。 在 2079 年之前,此类压缩始终可以节省 2 个字节。 每个整数值表示 3.33 毫秒。 压缩在前五分钟只占用前 2 个字节,在 4PM 之后将使用第四个字节。 因此,压缩在 4PM 之后只能节省 1 个字节。 当 datetime 像任何其他整数一样进行压缩时,压缩可在日期方面节省 2 个字节。
date 使用 3 个字节表示整数数据。 这表示自 0001-01-01 起的日期。 对于当代日期,行压缩使用所有 3 个字节。 这不会节省任何空间。
time 使用 3 - 6 个字节表示整数数据。 有从 0 到 9 的各种精度,会占用 3 - 6 个字节。 压缩后的空间按如下方式使用:

精度 = 0。 字节数 = 3。 每个整数值表示一秒。 使用 2 个字节,压缩最长可表示到 6PM,这样可以节省 1 个字节。

精度 = 1。 字节数 = 3。 每个整数值表示 1/10 秒。 在 2AM 之前,压缩使用第三个字节。 结果是只能节省很少的空间。

精度 = 2。 字节数 = 3。 与前一情况类似,节省空间的可能性很小。

精度 = 3。 字节数 = 4。 由于凌晨 5 点都将使用前 3 个字节,因而此选项可节省的空间很小。

精度 = 4。 字节数 = 4。 前 27 秒会使用前 3 个字节。 不会节省任何空间。

精度 = 5,字节数 = 5。 在中午 12 点之后,将使用第五个字节。

精度 = 6 和 7,字节数 = 5。 不能实现任何节省。

精度 = 8,字节数 = 6。 在凌晨 3 点之后将使用第六个字节。

进行行压缩时存储不做任何更改。 总体上而言,压缩 time 数据类型不会获得很大的空间节省。
datetime2 使用 6 - 9 个字节表示整数数据。 前 4 个字节表示日期。 时间占用的字节数取决于指定的时间精度。

此整数值表示自 0001-01-01 日以来经过的天数,上限为 9999 年 12 月 31 日。 要表示 2005 年的日期,压缩操作将使用 3 个字节。

时间值不会节省任何空间,这是因为压缩后可让各种时间精度仅占用 2 - 4 个字节。 因此,当时间精度为一秒时,压缩使用 2 个字节来存储时间,在 255 秒之后将使用第二个字节。
datetimeoffset 类似于“datetime2”,占用 2 个字节的时区格式除外 (HH:mm)。

就像 datetime2,压缩可以节省 2 个字节。

对于时区值,mm 值在大多数情况下可能都是 0。 因此,压缩可能会节省 1 个字节。

进行行压缩时存储不做任何更改。
char 将删除尾随填充字符。 不论使用哪种排序规则,数据库引擎均将插入相同的填充字符。
varchar 无效。
text 无效。
nchar 1 将删除尾随填充字符。 不论使用哪种排序规则,数据库引擎均将插入相同的填充字符。
nvarchar 1 无效。
ntext 无效。
binary 将删除尾随的零。
varbinary 无效。
image 无效。
cursor 无效。
timestamp / rowversion 使用 8 个字节表示整数数据。 每个数据库均维护有一个时间戳计数器,并且它的值从 0 开始。 会像压缩任何其他整数值一样压缩此值。
sql_variant 无效。
uniqueidentifier 无效。
table 无效。
xml 2 无效。
用户定义类型 这在内部表示为 varbinary
FILESTREAM 这在内部表示为 varbinary

1 Unicode 压缩支持固定长度的“nchar”和“nvarchar”数据类型。 存储于行外或“nvarchar(max)”列中的数据值不会被压缩。 nvarchar(max) 不支持 Unicode 压缩,即使数据存储于行内。

2 启用数据压缩时不会压缩行外数据。 例如,大于 8,060 字节的 XML 记录将使用不压缩的行外页面。