【问题标题】:Change Datatype of Column in SQL Server在 SQL Server 中更改列的数据类型
【发布时间】:2016-10-22 16:09:28
【问题描述】:

我们有一个 SQL Server 2008 数据库,其中一个表包含超过 14 亿条记录。由于坐标系的调整,我们不得不将坐标列的数据类型从decimal(18, 2)扩展为decimal(18, 3)

我们尝试了多种方法,但在执行大约 14 小时后,一切都导致异常(事务日志已满)。

这些是我们尝试过的:

  1. 更改表格

    ALTER TABLE Adress
    ALTER COLUMN Coordinate decimal(18, 3) NULL
    
  2. 设计师

    • 取消选中Tools > Options > Designer > Prevent saving changes that require table re-creation
    • 打开设计器
    • 将列的数据类型更改为decimal(18, 3)
    • Right-click > Generate Change Script...

此脚本的作用是使用新数据类型创建一个新表,将旧数据复制到新表中,删除旧表并重命名新表。

不幸的是,两次尝试都在执行 14 小时后导致事务日志完整异常。

我想,通过ALTER TABLE... ALTER COLUMN... 更改数据类型只是更改元数据,应该在(毫秒)秒内完成?

  • 您知道我可以尝试的其他方法吗?
  • 为什么我的尝试(尤其是 #1)需要这么多时间?

提前致谢

【问题讨论】:

  • 一些表的更改可以仅作为元数据更改执行。这绝不是 all 更改,而您正在执行的更改确实需要更新每一行。所以,我猜你需要更多的日志空间。
  • 试试select CONVERT(binary(8),CONVERT(decimal(18,3),1.5)),CONVERT(binary(8),CONVERT(decimal(18,2),1.5)),你会发现表示完全不同。
  • A.表使用的空间有多大(磁盘使用情况报告)? B. 你的实验有多少磁盘空间?如果 B > A,那么您可以考虑从头开始创建新表并将数据 bcping 到它(这可以分批完成,从而最大限度地减少事务日志的使用)。作为副作用的好处,您将获得更紧凑和更少碎片化的数据组织。如果还没有使用,你也应该使用压缩
  • 完整的事务日志是完整的事务日志。这与 ALTER TABLE 命令无关。日志也不是一个怪癖,它允许您取消更改或处理任何故障。如果没有日志,取消查询会给您留下一个错误的数据库。备份日志以释放任何活动记录并添加更多空间。您也可以尝试添加存储在不同磁盘上的新日志文件
  • 完整的事务日志肯定与ALTER TABLE有关。数据修改正在记录在事务日志中。

标签: sql-server database sql-server-2008 tsql


【解决方案1】:

主要问题似乎是大量数据保存到表中。您的两次尝试似乎也很好。我必须说,由于数据很大,他们都肯定需要时间。

每次更改列数据类型时,SQL SERVER 都会尝试将现有数据转换为目标数据类型。处理大量数据的转换可能会导致执行延迟。

此外,我想知道您桌上是否有任何触发器。?

好吧!最后,我建议您按照以下步骤操作。至少试一试

  1. 删除所有指向旧列的主键/索引/约束,并禁用任何触发器(如果有)。
  2. 引入具有新数据类型的新 可为空 列(即使 它的意思是 NOT NULL) 到表中。
  3. 现在对表进行更新查询,将新列值设置为旧列值。您可以在更新 1000/100000 批记录的同时进行块更新。您还可以对查询应用条件以获得更好的结果。
  4. 一旦通过将新列值设置为旧列来更新所有表,然后将 NULL 字符从设计器中删除为 NOT NULL(如果它是 NOT NULL )。
  5. 删除/删除旧列。执行选择查询并验证您的更改。

我要补充的最后一点是您的数据库事务日志也已满,可以缩小但有一些预防措施。 Here 是一个很好的例子,如何重置你的事务日志。也应该看看这个。

希望这会有所帮助。 :)

【讨论】:

    【解决方案2】:

    解决办法是分批更新,减轻日志文件的压力。

    方法一:
    a) 使用新定义创建一个新表。
    b) 将数据批量复制到新表中。
    c) 删除旧表。
    d) 重命名新表。

    方法二:
    a) 创建一个具有正确定义的新列。
    b) 用旧列的数据批量更新新列。
    c) 删除旧列。
    d) 重命名新列。

    方法三:
    a) BCP 将数据写入文件。
    b) 截断表格。
    c) 更改列。
    d) 将恢复模式设置为批量记录或简单。
    e) BCP 将文件中的数据放入表中。
    f) 将恢复模式重新设置为完全。

    【讨论】:

      【解决方案3】:

      添加新列作为最后一列
      如果您尝试在最后一列之前插入,则可能需要很长时间
      NewCoordinate decimal(18, 3) NULL

      select 1 
      while(@@rowcount > 0) 
      BEGIN
          UPDATE TOP(10000) Adress 
          SET   NewCoordinate  = Coordinate
          WHERE NewCoordinate <> Coordinate
      END
      

      【讨论】:

        【解决方案4】:

        这是我的建议: 在表格中添加一个字段并将其命名如下:

        NewCoordinate DECIMAL(18, 3) NULL

        WHILE(1 = 1)
        BEGIN
            UPDATE TOP(1000) Adress SET NewCoordinate = Coordinate
            WHERE NewCoordinate IS NULL
              IF (@@ROWCOUNT < 1000)    
            BREAK    
        END
        

        尽量让您的交易保持小规模。

        最后删除您的坐标字段。

        【讨论】:

        • 新坐标 坐标
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-12
        • 1970-01-01
        相关资源
        最近更新 更多