VARCHAR(MAX) 中的空字符串消耗无法恢复的空间

Dav*_*yes 5 sql-server-2008 disk-space

我有一个带有不可为空VARCHAR(MAX)列的表,其中每一行都包含一个空字符串(第三方数据库,因此我无法更改它)。我看到了大量的空间使用,超过 15GB 的 100 万行。

如果我运行以下查询,我会看到 LOB_DATA 的大量 used_pa​​ges,即使该列中没有数据。不包括VARCHAR(MAX)行大小低于 8000 字节。

 SELECT o.name AS table_name,p.index_id, au.type, au.type_desc, au.total_pages, au.used_pages, au.data_pages
 FROM sys.allocation_units AS au
   JOIN sys.partitions AS p ON au.container_id = p.partition_id
   JOIN sys.objects AS o ON p.object_id = o.object_id
 WHERE o.name = 'table
 ORDER BY o.name, p.index_id;

type    type_desc             total_pages   used_pages  data_pages
1   IN_ROW_DATA 23258             23252           23188
2   LOB_DATA              1880733             1880455             0
3   ROW_OVERFLOW_DATA   0             0           0
Run Code Online (Sandbox Code Playgroud)

评论更新:

  • 该表是一个存档表,因此数据不应更改(仅插入)
  • 我在一个单独的数据库(同一个服务器)中有一个相同的表,其中有类似的数据,但没有出现这个问题
  • 重建索引没有帮助
  • large_value_types_out_of_row 为 0
  • DBCC CLEANTABLE 没有帮助

Aar*_*and 4

是否有可能该列已填充​​并且已被清除,或者数据类型最近更改为 varchar(max)?您是否尝试过重建聚集索引(与某些 ALTER 不同,它将触及每一行)?

编辑

由于重建聚集索引没有帮助,我不知所措,而且由于现有数据的大小非常小,我建议只创建一个新版本的表并将数据移过去。您可以通过显式地重新创建表然后复制数据来完成此操作,也可以使用它SELECT INTO来最大限度地减少步骤。

SELECT ... other cols ...,
    varchar_max_col = CONVERT(VARCHAR(MAX), NULL) 
    INTO dbo.newtable FROM dbo.oldtable;
CREATE CLUSTERED INDEX ... ON dbo.newtable( ...cols... );
CREATE INDEX ... ON dbo.newtable( ...cols... );
...
GO
BEGIN TRANSACTION;
EXEC sp_rename 'dbo.oldtable', 'oldtable_backup', OBJECT;
EXEC sp_rename 'dbo.newtable', 'oldtable', OBJECT;
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)