我在生产数据库中有一个表,该表的大小为525 GB,其中383 GB未使用:
我想回收一些空间,但是在弄乱生产数据库之前,我正在用较少数据的测试数据库中的同一表上测试一些策略。该表有一个类似的问题:
有关表的一些信息:
- 填充因子设置为0
- 大约有30列
- 列之一是图像类型的LOB,它存储的文件大小从几KB到几百MB不等
- 该表没有任何与之相关的假设索引
服务器正在运行SQL Server 2017(RTM-GDR)(KB4505224)-14.0.2027.2(X64)。数据库正在使用SIMPLE
恢复模型。
我尝试过的一些事情:
- 重建索引:
ALTER INDEX ALL ON dbo.MyTable REBUILD
。这产生的影响可以忽略不计。 - 重组索引:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
。这产生的影响可以忽略不计。 将LOB列复制到另一个表,删除该列,重新创建该列,然后将数据复制回(如本文章中概述的:释放未使用的空间SQL Server表)。这减少了未使用的空间,但似乎只是将其转换为已用空间:
使用了bcp实用程序来导出表,截断表并重新加载表(如本文所述:如何为表释放未使用的空间)。这也减少了未使用的空间,并将使用的空间增加到与上述图像相似的程度。
- 即使不建议这样做,我也尝试了DBCC SHRINKFILE和DBCC SHRINKDATABASE命令,但是它们对未使用的空间没有任何影响。
- 跑步
DBCC CLEANTABLE('myDB', 'dbo.myTable')
并没有改变 - 在保持图像和文本数据类型以及将数据类型更改为varbinary(max)和varchar(max)之后,我都尝试了上述所有方法。
- 我尝试将数据导入到新数据库中的新表中,这也仅将未使用的空间转换为已用空间。我在这篇文章中概述了这种尝试的细节。
如果我期望这些结果,我不想在生产数据库上进行这些尝试,因此:
- 为什么将其中一些尝试之后的未使用空间仅转换为已用空间?我觉得我不太了解幕后发生的事情。
- 我还能做些其他事情来减少未使用的空间而不增加已使用的空间吗?
编辑:这是表的磁盘使用情况报告和脚本:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MyTable](
[Column1] [int] NOT NULL,
[Column2] [int] NOT NULL,
[Column3] [int] NOT NULL,
[Column4] [bit] NOT NULL,
[Column5] [tinyint] NOT NULL,
[Column6] [datetime] NULL,
[Column7] [int] NOT NULL,
[Column8] [varchar](100) NULL,
[Column9] [varchar](256) NULL,
[Column10] [int] NULL,
[Column11] [image] NULL,
[Column12] [text] NULL,
[Column13] [varchar](100) NULL,
[Column14] [varchar](6) NULL,
[Column15] [int] NOT NULL,
[Column16] [bit] NOT NULL,
[Column17] [datetime] NULL,
[Column18] [varchar](50) NULL,
[Column19] [varchar](50) NULL,
[Column20] [varchar](60) NULL,
[Column21] [varchar](20) NULL,
[Column22] [varchar](120) NULL,
[Column23] [varchar](4) NULL,
[Column24] [varchar](75) NULL,
[Column25] [char](1) NULL,
[Column26] [varchar](50) NULL,
[Column27] [varchar](128) NULL,
[Column28] [varchar](50) NULL,
[Column29] [int] NULL,
[Column30] [text] NULL,
CONSTRAINT [PK] PRIMARY KEY CLUSTERED
(
[Column1] ASC,
[Column2] ASC,
[Column3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column4] DEFAULT (0) FOR [Column4]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column5] DEFAULT (0) FOR [Column5]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column15] DEFAULT (0) FOR [Column15]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column16] DEFAULT (0) FOR [Column16]
GO
这是在Max Vernon的答案中执行命令的结果:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
更新:
我按照Max Vernon的建议运行了以下内容:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
这是输出:
DBCC UPDATEUSAGE: Usage counts updated for table 'MyTable' (index 'PK_MyTable', partition 1):
USED pages (LOB Data): changed from (568025) to (1019641) pages.
RSVD pages (LOB Data): changed from (1019761) to (1019763) pages.
这将更新表的磁盘使用情况:
以及整体磁盘使用情况:
因此,问题似乎出在SQL Server跟踪的磁盘使用情况与实际磁盘使用情况完全不同步。我认为此问题已解决,但我很想知道为什么会首先发生这种情况!
DBCC UPDATEUSAGE
更新了未使用的空间和未使用的页数。看起来SQL Server报告的磁盘使用情况和页面信息非常不同步-我用详细信息更新了我的帖子。我很好奇这会如何发生,但至少发现了问题。感谢您的所有帮助,我非常感谢!