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

在不影响的情况下更改SQL Server表

  •  5
  • lakshminb7  · 技术社区  · 16 年前

    我有一个表,大约有30列,已经在应用程序中广泛使用。也就是说,这个表的选择、插入和更新操作以许多不同的方式(无论开发人员认为它们是以什么方式编写的)以存储过程和UDF的数量编写。我现在有一个任务要扩展表所服务的功能,我需要向表中添加额外的细节(通常可以假定为表的附加列)。在表中添加额外的列是一项庞大而低效的任务,考虑到它在其他地方会造成的影响,我不想这样做。

    我现在可以想到的另一种方法是创建一个新表,其中包含主表的外键,并在新表中维护记录。我也对此表示怀疑。在表的模式中处理这种修改的有效方法是什么?

    如果需要,可以使用SQL Server 2000。

    编辑:

    不幸的是,列不应接受空值。确实错过了这个关键信息

    我认为,由于已实施的不良做法可能产生的影响是:

    1)“选择*”并绑定到一些 数据报直接到前端。(非常) 极低概率)

    2)使用列号从 数据集或数据表而不是列 使用“选择”时在前端显示名称 *

    3)“插入”并给出值 按顺序而不是按列 名字。

    某种程度上,如果我可以使列接受“空”值(通过稍微调整需求),那么由于以上几点,会有什么影响呢?

    我怀疑分析现有代码,因为使用此表的SP和函数的数量可能会达到数百个。

    12 回复  |  直到 16 年前
        1
  •  5
  •   Chris McCall    16 年前
    1. 用您需要的所有列构建一个新表,您可以随意调用它。
    2. 创建一个视图,将其命名为与旧表相同的名称,并让它返回旧表使用的所有列。
    3. ????
    4. $

    (是的,我知道这对于维护来说可能会很混乱,因为许多DBA使用视图的命名约定:v_viewname。我从来没有按照SQL对象的类型来命名它,也没有看到这种约定的好处)

        2
  •  3
  •   John Saunders    16 年前

    问问自己,为什么添加一个专栏会产生巨大的影响。也许您有使用select*的查询?找出影响重要的原因-然后将这些视为bug,并修复它们。

    大多数情况下,添加列不应破坏任何内容。添加非空列将影响执行插入操作的任何内容,否则,如果数据库设计正确,则影响应该很小。


    非空更新后编辑

    解决方案很明显:将列添加为空,更新数据以包含每行的非空值,然后将列更改为非空。

        3
  •  1
  •   Jesse    16 年前

    添加新表以适应此新列的建议在技术上称为 vertical partitioning 尽管它在数据库设计中有一席之地,但这些关注点必须与性能有关。

    理想情况下,您应该能够简单地将新列添加到现有表中。如果每次要添加新列时都必须向数据库中添加一个新表,那么系统将很快变得无法管理。我假设您没有独立于产品的开发/测试环境。这可能是说服你的老板你需要一个完美的机会。

        4
  •  0
  •   Steven A. Lowe    16 年前

    任何一种方法都有效,但需注意以下几点:

    • 如果您有选择*…在某些地方,您的新列将显示在结果集中,这可能是不需要的,例如。

      插入tmptable select*from sometable where blah blah blah

    除非在临时表中定义了新列,否则将导致错误。

    • 使用“扩展”表的影响较低,但效率较低,但是,它是保证不会干扰现有存储过程、视图等的唯一方法。
        5
  •  0
  •   Cătălin Pitiș    16 年前

    如果不接受在现有表中添加新列,请在与旧表的一对一关系中添加新表。它应该包含主关键字字段(与旧表中的字段相同)和新列。这个键字段也是新表的主键(用于强制一对(零或一)基数)。

    缺点是:

    • 为了找到新的数据,您需要 进行连接(实际上是外部连接)。
    • 插入/更新/删除时 记录,你必须分两次做 桌子
        6
  •  0
  •   Macarse    16 年前

    我将在重构代码和数据库时添加所需的表,并向原始表添加触发器。

        7
  •  0
  •   tmeisenh    16 年前

    您必须评估对现有代码库的影响,这就是您的答案。如果它符合时间表,那么我通常建议把它做对。如果它超出了时间线,那么很明显,你只需破解它,并在另一个时间修复它。

    有时候我们不能解决所有的问题,唯一的解决办法就是使用创可贴。

        8
  •  0
  •   Robin Day    16 年前

    我将首先调查一下您在更改原始表时遇到的问题。如果您只是添加可以为空的列,那么您可能会发现根本没有问题。

    从现有代码的角度来看,可能存在的问题是,开发人员可能已经完成了一个select*from表,如果添加更多的代码,它可能会把这个代码搞得一团糟。但是,不应该执行select*是一个相当广泛的最佳实践。

    如果沿着第二个表路径走,您可以向这两个表添加一个视图,这样任何新的开发都可以基于这个视图。

    不过,在我看来,我可能只需要修改现有的表,并处理您遇到的任何问题。这当然取决于现实生活中出错的“代价”,人们会死吗?

        9
  •  0
  •   Eric    16 年前

    我喜欢创建新表的想法。我认为这是最安全的方法。但如果要添加的新列可以允许空值,则不应该有任何问题。只需确保列允许空值。

    如果不允许空值,请将列设置为允许空值,在现有数据的列中插入所需的值,然后确保将列设置回允许空值。

        10
  •  0
  •   Dusty    16 年前

    我想您最好是在扩展桌上。当您从sys表中获取表的使用位置列表并准备进行更改时,我建议您为链接到新扩展表的表创建一个新视图,并在select语句中使用该视图。这将为您将来提供一些灵活性。

    编辑:我不会在这个扩展表中保持一对一的关系。只有在视图中需要并左联接时,我才会在扩展表中输入一行。这样就不必担心触发器或大量的数据验证,从而确保表是同步的。

        11
  •  0
  •   HLGEM    16 年前

    如果使用alter table并添加一个默认值以便所有记录都得到一个值,那么除非您有数百万条记录,否则它不应该太糟糕。不要通过Enterprise Manager来执行此操作(您不应该使用Enterprise Manager更改表,因为它完全重新创建了不更改表的表)。如果有太多的记录无法自动填充deafult,则首先需要更改表以添加一个包含空值的列,然后根据用于确定现有记录的正确值。然后,在知道没有没有没有没有值的记录时,更改表以使列不可为空。此时,您可能需要考虑没有值的任何新记录的默认值。

    添加列将对现有代码产生影响。如果开发人员没有使用select*(在生产代码中不应该使用它),它将不会有太大的影响,除非您必须为某个目的添加新列,并且与该目的相关的任何代码都需要更新为incmclude新列。由于这是一个不可为空的列,因此至少需要更改要插入记录的代码,并可能更改要更新它们的代码(取决于这是否是一个值,该值一旦就位就将被更新。)可能还有一些选择可能会受到影响。插入代码必须与使列不可为空的更改大致相同,否则所有插入都将失败,直到您将其放置到位。你可以把它做成一个大剧本。

    如果你认为很多都会受到影响,那就需要一些时间把它们全部解决掉。创建包含新列的新表。从旧表中填充它。更改插入/更新/删除以转到新表。然后删除旧表并创建一个视图,该视图的名称为旧表,它只有旧列。在脚本中完成所有这些操作,以便它可以一起在prod上运行。不要在一天中的主要时间段运行此数据库,请安排它在数据库使用的最短时间段运行。

        12
  •  0
  •   Ian Boyd    12 年前

    向表中添加附加列 是一项庞大而低效的任务 不想考虑 会对其他地方造成影响。

    你能详细解释一下吗?

    将列添加为可以为空或使用默认值,意味着实际上没有人必须提供值。 无冲击

    如果您担心将列添加到表中时的锁定时间,请将列添加到表的末尾(这样SQL Server就不必创建新表、将数据复制到表中、删除旧表并将新表重命名)。 几乎没有运行时影响

    添加5000万行数据几乎不会对运行时产生影响?

    user@brianwhite似乎对向包含5000万行的表中添加列几乎没有运行时影响感到困惑。他似乎认为向大表中添加列是一项昂贵的操作,因为扩展操作会阻止用户,这会给其他用户带来问题。他似乎认为添加一列会导致服务器写入5000万行:

    它将保存一个表锁,以保持写入5000万条数据所需的时间。

    重要的是它会 写5000万条数据。为了证明这一点,正好有一张桌子 二千八百一十七万六千二百六十六 行( 4557兆字节 ):

    --How many rows in the table
    SELECT COUNT(*) FROM BigTable
    
    28176266
    (1 row(s) affected)
    
    --How big is the table
    EXECUTE sp_spaceused 'BigTable'
    
    name      rows      reserved    data        index_size  unused
    --------  --------  ----------  ----------  ----------  ------
    BigTable  28176266  4681560 KB  4666984 KB  14536 KB    40 KB
    

    既然我们已经确定我有一个 2800万 行表,即 4.6 GB ,让我们在此表中添加一列:

    ALTER TABLE BigTable ADD NewColumn int NULL
    

    等待!问题是: 要多长时间?在创建2800万个条目时,这不是一个需要表锁的长操作吗?

    不! 让我们来计算一下需要多长时间:

    PRINT 'Time before adding the column: '+CONVERT(varchar(50), getdate(), 126)
    ALTER TABLE BigTable ADD NewColumn int NULL
    PRINT 'Time after adding the column: '+CONVERT(varchar(50), getdate(), 126)
    

    在2800万行4.6GB的表中添加列需要多长时间?

    Time before adding the column: 2012-11-06T14:14:33.493
    Time after adding the column: 2012-11-06T14:14:33.503
    

    答案:关于 10ms

    毫秒 .