代码之家  ›  专栏  ›  技术社区  ›  xeraphim

更改SQL Server中列的数据类型

  •  2
  • xeraphim  · 技术社区  · 10 年前

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

    我们尝试了多种方法,但在大约14小时的执行之后,所有方法都导致了异常(transactionlog已满)。

    这些是我们尝试过的事情:

    1. 更改表格

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

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

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

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

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

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

    提前谢谢

    4 回复  |  直到 10 年前
        1
  •  4
  •   Community Mohan Dere    9 年前

    主要问题似乎是表中保存了大量数据。你的两次尝试似乎也不错。我必须说,由于数据量很大,这两者都需要时间。

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

    而且我想知道你有没有 触发 在桌子上。?

    好最后,我建议您遵循以下步骤。至少试试看

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

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

    希望这能有所帮助。:)

        2
  •  1
  •   Sean Pearce    10 年前

    解决方案是批量更新,减轻日志文件的压力。

    方法1:
    a) 使用新定义创建新表。
    b) 批量将数据复制到新表中。
    c) 放下旧桌子。
    d) 重命名新表。

    方法2:
    a) 使用正确的定义创建新列。
    b) 使用旧列中的数据批量更新新列。
    c) 删除旧列。
    d) 重命名新列。

    方法3:
    a) 将数据BCP到文件中。
    b) 截断表格。
    c) 更改列。
    d) 将恢复模式设置为大容量日志或简单恢复模式。
    e) 将文件中的数据BCP到表中。
    f) 将恢复模式设置回完整模式。

        3
  •  0
  •   paparazzo    10 年前

    添加新列作为最后一列
    如果尝试在最后一列之前插入,可能需要很长时间
    新坐标十进制(18,3)NULL

    select 1 
    while(@@rowcount > 0) 
    BEGIN
        UPDATE TOP(10000) Adress 
        SET   NewCoordinate  = Coordinate
        WHERE NewCoordinate <> Coordinate
    END
    
        4
  •  0
  •   Ali Elmi    10 年前

    这是我的建议: 将字段添加到表中,并按如下方式命名:

    新坐标十进制(18,3)为空

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

    尽量保持交易量小。

    最后删除坐标字段。