我有大约300个表,每个表有5.5kk行。其中一行使用nvarchar(128)作为数据类型(SQL Server 2012) 我们决定将其更改为int并将FK添加到包含所有nvarchars的字典表中。
完成所有操作后,我删除了nvarchar列,但表的大小保持不变。 我使用DBCC CLEANTABLE并重建索引以回收可用空间,但表的大小仍未改变。
到目前为止,我找到的唯一方法是将所有数据复制到新表中。
问题:我在这里缺少什么?为什么空间仍被标记为已使用且我无法释放是通过缩小或CREANTABLE命令?
谢谢!
答案:看起来答案非常简单,由于我缺乏知识,我无法找到答案。 这里的主要问题是堆碎片。这个查询对我有用:
ALTER TABLE [TABLE_NAME] REBUILD
我不确定这是最好的方式,但至少它是一个有效的方式。
Edited1 : 对不起,我想我忘了提 - 我在Text字段上有聚集索引,所以我不得不删除索引才能真正删除该字段。现在我没有索引。
Edited2 :
老桌子: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
)
新表:
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_
答案 0 :(得分:2)
您是否确定因为此列更改而导致表格变小? nvarchar(128)并不意味着SQL Server将分配128个字节(+2)来保存数据,例如字符串' test'。字符串'测试'只需要6个字节。也许您需要先检查表中的可用空间:
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
答案 1 :(得分:1)
如果您不关心理解问题并且只是想摆脱它,那么重建索引是消除任何浪费的可靠方法。这是因为索引重建新建了物理数据结构。无论旧索引包含什么都不重要。
将此与CLEANTABLE
进行比较时需要权衡利弊。如果重建为你完成了这项工作,我总是这样做,因为它是一个完整的解决方案。
当我说" index"在这个答案中,我的意思是包含您关注的一个列的所有物理结构。这可以是b-tree索引或表所基于的堆。