我有一个包含大约30列的表,已广泛用于该应用程序中。即,在许多存储过程和UDF中,以多种不同的方式(以开发人员认为他们都很熟悉的方式)编写此表的选择,插入和更新操作。我现在已经完成了扩展表所服务的功能的任务,我需要在表中添加额外的细节(通常可以假设为表的附加列)。考虑到它会在其他地方造成的影响,在表中添加额外的列是一项庞大而低效的任务我不想做。
我现在能想到的另一种方法是创建一个新表,其中包含主表的外键并在新表中维护记录。我对此也持怀疑态度。在表的模式中处理这种修改的有效方法是什么?
在需要时使用SQL Server 2000。
编辑:
不幸的是,列不应该接受NULL值。错过了这个至关重要的信息
影响我认为由于已经实施的不良做法可能会发生,
1)“SELECT *”并绑定到某些 datagrid直接到前端。 (非常 非常低的可能)
2)使用列号来获取 数据集或数据表而不是列 使用“SELECT”时前端的名称 *“
3)“插入”给出的值 顺序而不是列 名。
从某种程度上说,如果我可以让列接受“NULL”值(通过稍微调整一下要求)对上述各点产生什么影响?
我对分析现有代码感到怀疑,因为使用此表的SP和函数数量可能会达到数百个。
答案 0 :(得分: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不必创建新表,将数据复制到它,删除旧表,并重新命名新表。)几乎没有运行时影响
用户@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只有旧列。在脚本中执行所有这些操作,以便它可以一起运行。不要在当天的主要部分运行它,安排它在数据库使用的最轻时间内运行。