6

我有大约 300 张桌子,每张桌子有 5.5kk 行。其中一行使用 nvarchar(128) 作为数据类型 (SQL Server 2012)。
我们决定将其更改为 int 并将 FK 添加到包含所有 nvarchars 的字典表中。

完成所有操作后,我删除了 nvarchar 列,但表的大小保持不变。我使用 DBCC CLEANTABLE 并重建索引以回收可用空间,但表的大小仍然没有改变。

到目前为止,我发现的唯一方法是将所有数据复制到新表中。

问题:我在这里缺少什么?为什么空间仍被标记为已使用并且我无法通过收缩或 CREANTABLE 命令释放?

谢谢!

Answ:看起来答案很简单,由于我缺乏知识,我无法找到它。这里的主要问题是堆碎片。这个查询对我有用:

ALTER TABLE [TABLE_NAME] REBUILD

我不确定这是不是最好的方法,但至少它是一种有效的方法。

Edited1:对不起,我想我忘了提 - 我在 Text 字段上有聚集索引,所以我必须删除索引才能真正删除该字段。现在我没有索引。

编辑2

旧表:

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_
4

2 回答 2

3

您确定表会因为此列更改而变小吗?nvarchar(128) 并不意味着 SQL Server 将分配 128 个字节 (+2) 用于保存数据,例如字符串“test”。字符串“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
于 2016-04-05T11:12:52.980 回答
1

如果您不关心理解问题而只想摆脱它,那么重建索引是消除任何浪费的可靠方法。这是因为索引重建重新构建了物理数据结构。无论旧索引包含什么都不再重要。

将其与CLEANTABLE. 如果重建为您完成了这项工作,我会一直这样做,因为它是一个完整的解决方案。

当我在这个答案中说“索引”时,我的意思是所有包含您关心的列之一的物理结构。这可以是 b 树索引或表所基于的堆。

于 2016-04-05T17:58:11.273 回答