【问题标题】:How to reduce size of SQL Server table that grew from a datatype change如何减少因数据类型更改而增长的 SQL Server 表的大小
【发布时间】:2010-10-22 21:31:01
【问题描述】:

我在 SQL Server 2005 上有一个大小约为 4GB 的表。

(大约 1700 万条记录)

我将其中一个字段从数据类型 char(30) 更改为 char(60)(总共有 25 个字段,其中大部分是 char(10),因此字符空间的数量加起来约为 300)

这导致表的大小增加了一倍(超过 9gb)

然后我将char(60)更改为varchar(60),然后运行一个函数从数据中去除多余的空格(从而将字段中数据的平均长度减少到大约15)

这并没有减少表格的大小。缩小数据库也无济于事。

实际上没有重新创建表结构并复制数据(即 1700 万条记录!),是否有一种不那么激烈的方法可以再次减小大小?

【问题讨论】:

  • 您究竟是如何缩小数据库的?
  • 在管理工作室。任务->收缩->文件->释放未使用的空间

标签: sql-server types database-table


【解决方案1】:

即使使用“收缩数据库”,您也没有清理或压缩任何数据。

DBCC CLEANTABLE

从表或索引视图中删除的可变长度列中回收空间。

不过,simple index rebuild如果有聚集索引也应该这样做

ALTER INDEX ALL ON dbo.Mytable REBUILD

A worked example from Tony Rogerson

【讨论】:

  • 也感谢您提供答案。虽然我第一次看到了另一个人。对不起。 :)
  • 谢谢。虽然我在他修改后的几分钟内添加了我的答案:他的第一个答案没有提到索引重建
【解决方案2】:

很明显,您没有获得任何空间! :-)

当您将文本字段更改为 CHAR(60) 时,它们都会被空格填满。因此,您的所有字段现在实际上都是 60 个字符长。

将其改回 VARCHAR(60) 将无济于事 - 字段仍然都是 60 个字符长......

您真正需要做的是对所有字段运行 TRIM 函数,以将它们缩减回修剪后的长度,然后进行数据库收缩。

完成此操作后,您需要重建聚集索引以回收部分浪费的空间。聚集索引确实是您的数据所在的位置 - 您可以像这样重建它:

ALTER INDEX IndexName ON YourTable REBUILD 

默认情况下,您的主键是您的聚集索引(除非您另有指定)。

马克

【讨论】:

  • 我这样做了...“运行了一个函数来从数据中删除额外的空白”
  • 具体来说,我确实更新了 table [table] set [column] = replace([column],' ','') where year = 2009(然后又是 2008、2007 等等)
  • 您是否尝试过所有年份的 UPDATE Table SET Column = RTRIM(Column)?还是没有变化?
  • 所有年份一次?还是一年一年的所有时间?我目前正在尝试一年一次
  • 对。我这样做了。没有区别,
【解决方案3】:

我知道我没有按照您的要求回答您的问题,但是您是否考虑过将一些数据归档到历史记录表中并使用更少的行?

大多数时候,乍一看,您可能会认为您一直需要所有这些数据,但当您真正坐下来检查它时,有些情况并非如此。或者至少我以前经历过这种情况。

【讨论】:

  • 11 年后我偶然发现了这个老问题。给你的答案一个赞成票,因为我最终做了这件事。
【解决方案4】:

我在SQL Server, Converting NTEXT to NVARCHAR(MAX) 遇到了类似的问题,这与将 ntext 更改为 nvarchar(max) 有关。

我必须做一个UPDATE MyTable SET MyValue = MyValue 才能让它很好地调整所有东西的大小。

这显然需要相当长的时间,有很多记录。关于如何更好地做到这一点,有很多建议。他们的关键之一是一个临时标志,指示它是否已经完成,然后在循环中一次更新几千个,直到全部完成。这意味着我可以“部分”控制它的工作量。

不过,另一方面,如果您真的想尽可能地缩小数据库,可以将恢复模式降低为简单,缩小事务日志,重新组织页面中的所有数据,然后设置它回到完全恢复模式。但要小心,通常不建议缩减数据库,如果您减少活动数据库的恢复模型,您就是在要求出现问题。

【讨论】:

    【解决方案5】:

    或者,您可以进行全表重建,以确保任何地方都没有多余的数据:

    CREATE TABLE tmp_table(<column definitions>);
    GO
    INSERT INTO tmp_table(<columns>) SELECT <columns> FROM <table>;
    GO
    DROP TABLE <table>;
    GO
    EXEC sp_rename N'tmp_table', N'<table>';
    GO
    

    当然,身份、索引等变得更加复杂......

    【讨论】:

    • 这可能更容易一些: SELECT * INTO tmp_table FROM my_table GO DROP TABLE my_table GO EXEC sp_rename N'tmp_table', N'my_table';去
    • 同意上面海滩的评论。除了更容易之外,它还避免了在将 * 选择到 NewTable 时使用记录事务,因此应该更快。
    猜你喜欢
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 2011-05-17
    • 2010-10-12
    相关资源
    最近更新 更多