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

时间:2009-06-17 13:20:59

标签: sql-server database

我有一个包含大约30列的表,已广泛用于该应用程序中。即,在许多存储过程和UDF中,以多种不同的方式(以开发人员认为他们都很熟悉的方式)编写此表的选择,插入和更新操作。我现在已经完成了扩展表所服务的功能的任务,我需要在表中添加额外的细节(通常可以假设为表的附加列)。考虑到它会在其他地方造成的影响,在表中添加额外的列是一项庞大而低效的任务我不想做。

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

在需要时使用SQL Server 2000。

编辑:

不幸的是,列不应该接受NULL值。错过了这个至关重要的信息

影响我认为由于已经实施的不良做法可能会发生,

  

1)“SELECT *”并绑定到某些   datagrid直接到前端。 (非常   非常低的可能)

     

2)使用列号来获取   数据集或数据表而不是列   使用“SELECT”时前端的名称   *“

     

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

从某种程度上说,如果我可以让列接受“NULL”值(通过稍微调整一下要求)对上述各点产生什么影响?

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

12 个答案:

答案 0 :(得分:5)

  1. 使用您需要的所有列构建一个新表,并随意调用它。
  2. 创建一个视图,将其命名为与旧表相同,并让它返回旧表所用的所有列。
  3. ???
  4. $
  5. (是的,我知道这可能会让维护变得混乱,因为许多DBA使用视图的命名约定:V_Viewname。我从来没有在它是什么类型的对象之后命名一个SQL对象,并且没有看到这种惯例的好处)

答案 1 :(得分:3)

问问自己为什么添加专栏会产生巨大影响。也许您有使用SELECT *的查询?找出影响重大的原因 - 然后考虑那些是错误,并修复它们。

大多数情况下,添加列不应该破坏任何内容。添加NOT NULL列会影响执行INSERT的任何操作,但是如果您的数据库设计得当,那么应该会产生很小的影响。


NOT NULL更新后编辑

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

答案 2 :(得分:1)

添加新表以容纳此新列的建议在技术上称为vertical partitioning,虽然在数据库设计中有一个位置,但这些问题与性能有关。

理想情况下,您应该只需将新列添加到现有表中即可。如果每次要添加新列时都必须向数据库添加新表,则系统将很快变得无法管理。我假设您没有与生产分开的开发/测试环境。这可能是让老板相信你需要的绝佳机会。

答案 3 :(得分:0)

任何一种方法都可行,但需要注意以下几点:

  • 如果您在某处有SELECT * ...,您的新列将显示在结果集中,这可能是不合需要的,例如。

    插入#tmpTable select * from sometable where blah-blah-blah

除非在临时表中定义了新的列,否则

将导致错误

  • 使用'扩展'表影响较小但效率较低,但是,它是保证不会干扰现有存储过程,视图等的唯一方法

答案 4 :(得分:0)

如果在现有表中添加新列是不可接受的,请使用旧表以一对一的关系添加新表。它应包含旧表中的主键字段和新列。此关键字段也是新表的主键(强制执行一对一(零或一)基数)。

缺点是:

  • 为了找到新数据,您需要 进行连接(实际上是外连接)。
  • 插入/更新/删除时 记录,你必须做两个 表

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

有时我们无法解决所有问题,唯一的解决方案就是提供创可贴。

答案 7 :(得分:0)

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

从现有代码的角度来看,可能出现的问题是开发人员可能已经完成了SELECT * FROM TABLE,如果添加更多内容,可能会破坏此代码。但是,这是一种相当普遍的最佳实践,您永远不应该执行SELECT *。

如果你沿着第二个表路线走下去,你可以在这两个表中添加一个VIEW,这样任何新的开发都可以基于这个视图。

在我看来,我可能会修改现有的表并处理你遇到的任何问题。这当然取决于错误的现实生活“成本”,人们会死吗?

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

我认为扩展表是您最好的选择。当您从sys表中获取表的使用位置列表并进行更改时,我建议您创建链接到新扩展表的表的新视图,并在select语句中使用它。这应该会为你带来一些灵活性。

编辑:我不会尝试在此扩展表中保持一对一的relatinoship。我只在必要时在扩展表中输入一行并在视图中保持连接。这样您就不必担心触发器或大量数据验证,确保表格同步。

答案 10 :(得分:0)

  

向表中添加其他列   我是一项庞大而低效的工作   不想考虑   影响它将导致其他地方。

你能详细说明吗?

将列添加为可空或默认值意味着没有人真正必须提供值。 没有影响

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

添加5000万行数据几乎没有运行时影响?

用户@BrianWhite似乎很困惑,如何向包含5000万行的表添加列几乎不会对运行时产生影响。他似乎认为向大型表添加列是一项昂贵的操作,这会导致其他用户出现问题,因为扩展操作会阻止用户。他似乎认为添加一列会导致服务器写入5000万行:

  

它将保存一个表锁,用于写入5000万条数据

所需的时间

重要的是,它将写入5000万条数据。为了证明这一点,恰好有一个 28,176,266 行( 4,557 MB )的表:

--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.6 GB表中需要多长时间?

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

答案:关于 10ms

毫秒

答案 11 :(得分:0)

如果您使用alter table并添加一个默认值以便所有记录都获得一个值,那么除非您有数百万条记录,否则它不应该太糟糕。不要通过企业管理器执行此操作(您不应该使用企业管理器更改表,因为它完全重新创建Alter表没有的表)。如果你有太多的记录要自动填充deafult,你首先需要改变表以添加一个全部空值的列,然后将列更新为正确的值(如果你有很多记录,你可能想要这样做根据您用于确定现有记录的正确值的规则,在baches中而不是锁定整个表。然后,当您知道没有没有值的记录时,更改表以使列不可为空。此时,您可能需要考虑没有值的任何新记录的默认值。

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

如果您认为很多会受到影响,则需要一些时间对它们进行整理。创建一个包含新列的新表。从旧表中填充它。更改插入/更新/删除以转到新表。然后删除旧表并创建一个具有旧表名称的视图,thaat只有旧列。在脚本中执行所有这些操作,以便它可以一起运行。不要在当天的主要部分运行它,安排它在数据库使用的最轻时间内运行。