【问题标题】:"Prevent saving changes that require the table to be re-created" negative effects“防止保存需要重新创建表的更改”负面影响
【发布时间】:2012-08-01 21:33:16
【问题描述】:

序言

我今天在 SQL Server 2008 中修改了一个列,将数据类型从货币(18,0)更改为(19,2)。

我从 SQL Server 收到错误“您所做的更改需要删除并重新创建以下表”。

在争相回答之前,请阅读以下内容:

我已经知道 工具 ► 选项 ► 设计器 ► 表和数据库设计器 ► 取消选中该框“防止保存需要重新创建表的更改”。 ...所以不要回答!

实际问题

我的实际问题是其他问题,如下:

这样做有什么负面影响/可能的缺点吗?

取消选中此框时,表实际上是否会自动删除并重新创建?

如果是,该表是否是源表的 100% 精确副本?

【问题讨论】:

标签: sql-server sql-server-2008 database-design sql-server-2005


【解决方案1】:

工具 --> 选项 --> 设计器节点 --> 取消选中“阻止保存需要重新创建表格的更改”。

【讨论】:

  • 阅读问题 - 这正是 OP 所说的不要打扰,因为他已经知道了。
【解决方案2】:

只有在 SQL Server 的 Management Studio 被编程为知道如何执行此操作的唯一方法时,才会删除并重新创建该表。

在某些情况下它会在不需要时执行此操作,但也存在您在 Management Studio 中所做的编辑不会删除并重新创建的情况,因为它不会不必。

问题在于枚举所有案例并确定它们落在哪一边会非常乏味。

这就是为什么我喜欢在查询窗口中使用ALTER TABLE,而不是隐藏他们正在做的事情的视觉设计师(坦率地说有错误)——我确切地知道会发生什么,我可以做好准备对于唯一可能是删除并重新创建表的情况(这比 SSMS 对您执行此操作的频率要少一些)。

这样做有什么负面影响/可能的缺点吗?

当然。如果您可以自己编写更改脚本而不重建整个表,那就更好了 - 考虑表为 10TB 并且数据库记录大量日志(想想同步 AG、更改跟踪、复制、编写不佳的触发器)和表的情况被高度访问-这是灾难的潜在秘诀。如果您的更改是您可以应用在线提示或添加列并分批复制数据而不是 GUI 会做的全有或全无,这会更好。

如果取消选中此框,表实际上是否会自动删除并重新创建?

可能。有一系列方案,结果取决于 SSMS 的版本、SQL Server 的版本,有时甚至是版本。您可以通过选中该框并尝试将更改首先应用于数据库的无意义副本来进行检查,但恕我直言,使用实际的 ALTER TABLE 脚本而不是点击式 GUI 是一种方法。

如果是,该表是否是源表的 100% 精确副本?

是的,如果 SSMS 必须重建表,它在完成后将是一个 100% 精确的副本(当然更改除外),但这可能是下周三。该过程创建表的新版本,将所有数据复制到其中,然后删除旧表并重命名新表。

【讨论】:

  • 虽然是一个非常好的答案,但我觉得它并没有为 OP 提出的所有问题提供答案,而这些问题实际上是我感兴趣的问题。特别是这样做是否有任何负面影响/可能的缺点?如果是这样,该表是否复制了源表的 100% 精确副本?。你有关于这些问题的任何信息吗?
  • @tfrascaroli 让 SSMS 为您重建表是否有缺点?当然。如果您可以在不重建整个表的情况下自己编写更改脚本,那就更好了 - 考虑表为 10TB 且数据库被大量记录(想想同步 AG、更改跟踪、复制)并且表被高度访问的情况 - 那就是一个潜在的灾难秘诀。完成后,该表将是 100% 精确的副本,但这可能是下周三。
【解决方案3】:

Reference - 关闭此选项可以帮助您避免重新创建表,它也可能导致更改丢失。例如,假设您启用 SQL Server 2008 中的更改跟踪功能来跟踪对表的更改。当您执行导致重新创建表的操作时,您会收到“症状”部分中提到的错误消息。但是,如果关闭此选项,则在重新创建表时会删除现有的更改跟踪信息。因此,Microsoft 建议您不要通过关闭该选项来解决此问题。

【讨论】:

    【解决方案4】:

    只有在以下情况下,SQL Server 才会删除并重新创建表:

    • 添加新列
    • 更改列的 Allow Nulls 设置
    • 更改表格中的列顺序
    • 更改列数据类型

    使用 ALTER 更安全,因为万一在您重新创建表时元数据丢失,您的数据也会丢失。

    【讨论】:

    • 您的清单并不详尽。例如,在列上添加/删除IDENTITY 属性。
    • 在为 NULLABLE 的字段末尾添加新列不需要重建表。
    【解决方案5】:

    是的,这有负面影响:

    如果您编写出被此标志阻止的更改,您会得到类似于下面的脚本(我只是将 Contact 中的 ID 列转换为自动编号的 IDENTITY 列,但该表具有依赖关系)。 请注意以下运行时可能发生的潜在错误:

    1. 甚至微软都警告说这可能会导致数据丢失(该评论是自动生成的)!
    2. 在一段时间内不强制执行外键。
    3. 如果您在 ssms 中手动运行它并且“EXEC('INSERT INTO' 失败,并且您让以下语句运行(默认情况下它们会运行,因为它们被 'go' 拆分),那么您将插入 0 行,然后删除旧表。
    4. 如果这是一张大表,则插入的运行时间可能很大,并且事务持有模式修改锁,因此阻塞了 许多 事物。

    --

    /* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
    
    BEGIN TRANSACTION
    GO
    ALTER TABLE raw.Contact
        DROP CONSTRAINT fk_Contact_AddressType
    GO
    ALTER TABLE ref.ContactpointType SET (LOCK_ESCALATION = TABLE)
    GO
    COMMIT
    BEGIN TRANSACTION
    GO
    ALTER TABLE raw.Contact
        DROP CONSTRAINT fk_contact_profile
    GO
    ALTER TABLE raw.Profile SET (LOCK_ESCALATION = TABLE)
    GO
    COMMIT
    BEGIN TRANSACTION
    GO
    CREATE TABLE raw.Tmp_Contact
        (
        ContactID int NOT NULL IDENTITY (1, 1),
        ProfileID int NOT NULL,
        AddressType char(2) NOT NULL,
        ContactText varchar(250) NULL
        )  ON [PRIMARY]
    GO
    ALTER TABLE raw.Tmp_Contact SET (LOCK_ESCALATION = TABLE)
    GO
    SET IDENTITY_INSERT raw.Tmp_Contact ON
    GO
    IF EXISTS(SELECT * FROM raw.Contact)
         EXEC('INSERT INTO raw.Tmp_Contact (ContactID, ProfileID, AddressType, ContactText)
            SELECT ContactID, ProfileID, AddressType, ContactText FROM raw.Contact WITH (HOLDLOCK TABLOCKX)')
    GO
    SET IDENTITY_INSERT raw.Tmp_Contact OFF
    GO
    ALTER TABLE raw.PostalAddress
        DROP CONSTRAINT fk_AddressProfile
    GO
    ALTER TABLE raw.MarketingFlag
        DROP CONSTRAINT fk_marketingflag_contact
    GO
    ALTER TABLE raw.Phones
        DROP CONSTRAINT fk_phones_contact
    GO
    DROP TABLE raw.Contact
    GO
    EXECUTE sp_rename N'raw.Tmp_Contact', N'Contact', 'OBJECT' 
    GO
    ALTER TABLE raw.Contact ADD CONSTRAINT
        Idx_Contact_1 PRIMARY KEY CLUSTERED 
        (
        ProfileID,
        ContactID
        ) 
    
    GO
    ALTER TABLE raw.Contact ADD CONSTRAINT
        Idx_Contact UNIQUE NONCLUSTERED 
        (
        ProfileID,
        ContactID
        ) 
    
    GO
    CREATE NONCLUSTERED INDEX idx_Contact_0 ON raw.Contact
        (
        AddressType
        ) 
    GO
    ALTER TABLE raw.Contact ADD CONSTRAINT
        fk_contact_profile FOREIGN KEY
        (
        ProfileID
        ) REFERENCES raw.Profile
        (
        ProfileID
        ) ON UPDATE  NO ACTION 
         ON DELETE  NO ACTION 
    
    GO
    ALTER TABLE raw.Contact ADD CONSTRAINT
        fk_Contact_AddressType FOREIGN KEY
        (
        AddressType
        ) REFERENCES ref.ContactpointType
        (
        ContactPointTypeCode
        ) ON UPDATE  NO ACTION 
         ON DELETE  NO ACTION 
    
    GO
    COMMIT
    BEGIN TRANSACTION
    GO
    ALTER TABLE raw.Phones ADD CONSTRAINT
        fk_phones_contact FOREIGN KEY
        (
        ProfileID,
        PhoneID
        ) REFERENCES raw.Contact
        (
        ProfileID,
        ContactID
        ) ON UPDATE  NO ACTION 
         ON DELETE  NO ACTION 
    
    GO
    ALTER TABLE raw.Phones SET (LOCK_ESCALATION = TABLE)
    GO
    COMMIT
    BEGIN TRANSACTION
    GO
    ALTER TABLE raw.MarketingFlag ADD CONSTRAINT
        fk_marketingflag_contact FOREIGN KEY
        (
        ProfileID,
        ContactID
        ) REFERENCES raw.Contact
        (
        ProfileID,
        ContactID
        ) ON UPDATE  NO ACTION 
         ON DELETE  NO ACTION 
    
    GO
    ALTER TABLE raw.MarketingFlag SET (LOCK_ESCALATION = TABLE)
    GO
    COMMIT
    BEGIN TRANSACTION
    GO
    ALTER TABLE raw.PostalAddress ADD CONSTRAINT
        fk_AddressProfile FOREIGN KEY
        (
        ProfileID,
        AddressID
        ) REFERENCES raw.Contact
        (
        ProfileID,
        ContactID
        ) ON UPDATE  NO ACTION 
         ON DELETE  NO ACTION 
    
    GO
    ALTER TABLE raw.PostalAddress SET (LOCK_ESCALATION = TABLE)
    GO
    COMMIT
    

    【讨论】:

      猜你喜欢
      • 2017-06-15
      • 2021-11-30
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 2014-03-22
      • 2021-02-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多