我很清楚什么是堆中的转发记录。因为我想将转发记录保持为 0,所以我们决定只更新无法扩展的列。
最近在我的系统上遇到转发记录。
表格设计是这样的:
CREATE TABLE dbo.test (
HashValue BINARY(16) NOT NULL,
LoadTime DATETIME NOT NULL,
LoadEndTime DATETIME NULL,
[other columns that never get updates]
) WITH(DATA_COMPRESSION=PAGE);
插入语句总是带HashValue
AND LoadTime
。我检查了查询日志。
我插入值“9999-12-31”。
现在系统执行这样的更新LoadTime
:
;WITH CTE AS (
SELECT *, COALESCE(LEAD(LoadTime) OVER(PARTITION BY HashValue ORDER BY LoadTime) ,'9999-12-31') as EndTimeStamp
)
UPDATE CTE SET LoadEndTime = EndTimeStamp;
由于该LoadEndTime
列始终被填充,因此在执行更新时,该列在行内不应有任何扩展。它应该是一个就地更新。在那个过程之后我仍然总是收到转发的记录......这对我来说没有意义。
插入语句是这样的:
INSERT INTO dbo.test (HashValue, LoadTime,LoadEndTime)
SELECT HASHBYTES(...), GETDATE(), '1900-01-01'
所以已经有一个虚拟值。即使压缩,日期时间 '1900-01-01 00:00:00' 的固定和可变表示也应该是 8 个字节。
这是由于压缩。
压缩表没有更多的
FixedVar
行格式,因此即使您使用固定长度的列,它们也不会以 Fixedvar 方式存储,也不会为(偶数NULL
)值保留更多的固定空间。当您使用页面压缩时,首先应用 ROW COMPRESSION。这就是我们所拥有的:行压缩实现
这是我的重现,我使用 dbo.Nums,1000000 个自然数的表来填充我的两个表:
dbo.test_comp
启用页面压缩和dbo.test_no_comp
不压缩:更新
这是完全不正确的,因为您使用
PAGE
创建字典并替换重复值的压缩:但我想指出另一件事。您是否测试过您的 PAGE 压缩对您的情况是否有意义?你有一个堆,它不是静态的,即你更新它。
因此,在您的情况下,即使您可以在 INSERT 上实现压缩(仅当您将批量插入与 一起使用时
tablock
),任何更新都只会破坏您的压缩。看看我的新测试。
我意识到在我的第一个测试中,当我在没有 tablock 的情况下执行 INSERT 时,只应用了行压缩,我插入了 1000000 行,我得到了 19688 页。现在我将 tablock 插入到同一个表中:
现在我只有 1387 页。1387 vs 19688 只是因为在第一种情况下页面压缩,即使定义了,也没有应用,因为我的 INSERT 没有tablock
现在我更新了我漂亮的压缩表:
哇,更新后我有 22422 页 vs 1387 个原始页面!
在这次测试之后,我真的永远不会在非静态堆上使用页面压缩。与未压缩的模拟表相比,最终表的大小并没有减少多少,但作为奖励,我在 1000000 条记录中转发了 990247 条记录
社区维基答案:
堆和压缩值得注意:
因此,您
UPDATE
无法执行就地更新,后果已说明。作为解决方法,如果您使用基于日期的分区,则可以不压缩最近的分区。Clustered columnstore 表也做类似的事情,初始插入到行存储,然后被压缩到 Column 段中。