我有一个包含 4.9 亿行和 55 GB 表空间的表,因此每行大约 167 个字节。该表包含三列: a VARCHAR(100)
、 aDATETIME2(0)
和 a SMALLINT
。字段中文本的平均长度VARCHAR
约为 21.5,因此原始数据应约为每行 32 个字节: 22+2 用于VARCHAR
, 6 用于DATETIME2
, 2 用于 16 位整数。
请注意,上面的空间只是数据,而不是索引。我正在使用属性下报告的值 | 存储 | 一般 | 数据空间。
当然必须有一些开销,但是每行 135 个字节似乎很多,尤其是对于一个大表。为什么会这样?有没有其他人见过类似的乘数?哪些因素会影响所需的额外空间量?
为了比较,我尝试创建一个包含两个INT
字段和 1 M 行的表。所需的数据空间为 16.4 MB:每行 17 个字节,而原始数据为 8 个字节。另一个测试表使用与真实表相同的文本填充了一个INT
和一个,每行使用 39 个字节(44 K 行),我预计会多出 28 个字节。VARCHAR(100)
所以生产表的开销要大得多。这是因为它更大吗?我希望索引大小大约为 N * log(N),但我不明白为什么实际数据所需的空间是非线性的。
提前感谢您的任何指点!
编辑:
列出的所有字段都是NOT NULL
. VARCHAR
真实表在字段和DATETIME2
字段上按该顺序具有聚集的 PK 。对于这两个测试,第一个INT
是(集群)PK。
如果重要:该表是 ping 结果的记录。这些字段是 URL、ping 日期/时间和延迟(以毫秒为单位)。数据会不断地添加,并且永远不会更新,但会定期删除数据以将其减少到每个 URL 每小时仅几条记录。
编辑:
这里的一个非常有趣的答案表明,对于具有大量读写的索引,重建可能没有好处。在我的情况下,消耗的空间是一个问题,但如果写入性能更重要,那么使用松弛的索引可能会更好。
在对原始问题的评论中进行了讨论后,在这种情况下,丢失的空间是由选择聚集键引起的,这导致了大量的碎片。
在这些情况下,总是值得通过 sys.dm_db_index_physical_stats 检查碎片状态。
编辑:在评论中更新
平均页面密度(在重建聚集索引之前)为 24%,与原始问题完全吻合。这些页面只有 1/4 满,所以总大小是原始数据大小的 4 倍。
磁盘结构有开销:
取 2 x 4 字节 int 列,您有
哇 17 个字节!
您可以对第二个测试表进行相同的操作,该表的开销与原始测试表一样:
为什么有区别?另外(我不会链接到这些)
@updateusage = 'true'
请参阅:SQL Server:如何创建一个填满 8 KB 页的表?
从 SO:
数据类型是否随时间变化?是否删除了可变长度列?索引是否经常进行碎片整理但从未重建?是否有很多行被删除或有很多可变长度列被显着更新?