DBCC CLEANTABLE 未释放已用 space
DBCC CLEANTABLE is not freeing used space
我有大约 300 个 table,每个 5.5kk 行。其中一行使用 nvarchar(128) 作为数据类型(SQL Server 2012)。
我们决定将其更改为 int 并将 FK 添加到包含所有 nvarchar 的字典 table。
完成所有操作后,我删除了 nvarchar 列,但 table 的大小保持不变。
我使用了 DBCC CLEANTABLE 并重建了索引以回收空闲 space,但是 table 的大小仍然没有改变。
到目前为止,我找到的唯一方法是将所有数据复制到新的 table。
问题:我在这里缺少什么?为什么 space 仍被标记为已使用而我无法通过收缩或 CREANTABLE 命令释放?
谢谢!
答案: 看起来答案很简单,由于我缺乏知识而无法找到它。
这里的主要问题是堆碎片。这个查询对我有用:
ALTER TABLE [TABLE_NAME] REBUILD
我不确定这是最好的方法,但至少它是一个有效的方法。
已编辑1:
抱歉,我想我忘了提 - 我在文本字段上有聚集索引,所以我必须删除索引才能真正删除该字段。现在我没有索引了。
编辑2:
旧 table:
CREATE TABLE [dbo].[Data_](
[ID] [bigint] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[Text] [nvarchar](128) NOT NULL,
[Category] [tinyint] NOT NULL,
[Country] [nvarchar](2) NOT NULL,
[ImportTimestamp] [date] NOT NULL
)
新 table:
CREATE TABLE [dbo].[Data_New](
[ID] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[Category] [tinyint] NOT NULL,
[Country] [nvarchar](2) NOT NULL,
[TextID] [int] NOT NULL)
ALTER TABLE [dbo].[Data_New] WITH CHECK ADD FOREIGN KEY([TextID])
REFERENCES [dbo].[Dictionary] ([Id])
复制脚本:
INSERT INTO Data_New
([Category]
,[Country]
,[TextID])
SELECT
[Category]
,[Country]
,[TextID]
FROM Data_
您确定 table 会因为此列更改而变小吗? nvarchar(128) 并不意味着 SQL 服务器将分配 128 个字节 (+2) 用于保存数据,例如字符串 'test'。字符串 'test' 只占用 6 个字节。也许您需要先检查 table 中的免费 space:
SELECT
t.NAME AS TableName,
s.Name AS SchemaName,
p.rows AS RowCounts,
SUM(a.total_pages) * 8 AS TotalSpaceKB,
SUM(a.used_pages) * 8 AS UsedSpaceKB,
(SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
t.NAME = 'TABLE_NAME'
AND t.is_ms_shipped = 0'
AND i.OBJECT_ID > 255
GROUP BY
t.Name, s.Name, p.Rows
ORDER BY
t.Name
如果您不关心问题的理解,只想摆脱它,那么重建索引是消除任何浪费的可靠方法。这是因为索引重建会重新构建物理数据结构。无论旧索引包含什么都不再重要。
将此与 CLEANTABLE
进行比较时需要权衡取舍。如果重建可以为您完成工作,我会一直这样做,因为它是一个完整的解决方案。
当我在这个答案中说 "index" 时,我指的是包含您关心的列之一的所有物理结构。这可以是 b 树索引或 table 所基于的堆。
我有大约 300 个 table,每个 5.5kk 行。其中一行使用 nvarchar(128) 作为数据类型(SQL Server 2012)。
我们决定将其更改为 int 并将 FK 添加到包含所有 nvarchar 的字典 table。
完成所有操作后,我删除了 nvarchar 列,但 table 的大小保持不变。 我使用了 DBCC CLEANTABLE 并重建了索引以回收空闲 space,但是 table 的大小仍然没有改变。
到目前为止,我找到的唯一方法是将所有数据复制到新的 table。
问题:我在这里缺少什么?为什么 space 仍被标记为已使用而我无法通过收缩或 CREANTABLE 命令释放?
谢谢!
答案: 看起来答案很简单,由于我缺乏知识而无法找到它。 这里的主要问题是堆碎片。这个查询对我有用:
ALTER TABLE [TABLE_NAME] REBUILD
我不确定这是最好的方法,但至少它是一个有效的方法。
已编辑1: 抱歉,我想我忘了提 - 我在文本字段上有聚集索引,所以我必须删除索引才能真正删除该字段。现在我没有索引了。
编辑2:
旧 table:
CREATE TABLE [dbo].[Data_](
[ID] [bigint] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[Text] [nvarchar](128) NOT NULL,
[Category] [tinyint] NOT NULL,
[Country] [nvarchar](2) NOT NULL,
[ImportTimestamp] [date] NOT NULL
)
新 table:
CREATE TABLE [dbo].[Data_New](
[ID] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[Category] [tinyint] NOT NULL,
[Country] [nvarchar](2) NOT NULL,
[TextID] [int] NOT NULL)
ALTER TABLE [dbo].[Data_New] WITH CHECK ADD FOREIGN KEY([TextID])
REFERENCES [dbo].[Dictionary] ([Id])
复制脚本:
INSERT INTO Data_New
([Category]
,[Country]
,[TextID])
SELECT
[Category]
,[Country]
,[TextID]
FROM Data_
您确定 table 会因为此列更改而变小吗? nvarchar(128) 并不意味着 SQL 服务器将分配 128 个字节 (+2) 用于保存数据,例如字符串 'test'。字符串 'test' 只占用 6 个字节。也许您需要先检查 table 中的免费 space:
SELECT
t.NAME AS TableName,
s.Name AS SchemaName,
p.rows AS RowCounts,
SUM(a.total_pages) * 8 AS TotalSpaceKB,
SUM(a.used_pages) * 8 AS UsedSpaceKB,
(SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
t.NAME = 'TABLE_NAME'
AND t.is_ms_shipped = 0'
AND i.OBJECT_ID > 255
GROUP BY
t.Name, s.Name, p.Rows
ORDER BY
t.Name
如果您不关心问题的理解,只想摆脱它,那么重建索引是消除任何浪费的可靠方法。这是因为索引重建会重新构建物理数据结构。无论旧索引包含什么都不再重要。
将此与 CLEANTABLE
进行比较时需要权衡取舍。如果重建可以为您完成工作,我会一直这样做,因为它是一个完整的解决方案。
当我在这个答案中说 "index" 时,我指的是包含您关心的列之一的所有物理结构。这可以是 b 树索引或 table 所基于的堆。