Sql-Server

在數據庫中添加新列的正確方法

  • September 17, 2019

當我們將新列添加到現有表中時,正確的方法是什麼?

例如,我已經有像 Foo1、Foo2、Bar1、Bar2 這樣的列。現在我想添加一個名為 Foo3 的新列。

當我想添加具有相似名稱的列時,標準方法是什麼(如果是這樣的話)?

我看到 2 個選擇:

  1. 創建具有新結構的臨時表,其中新列位於具有相同名稱的列旁邊,將數據從現有表複製到新表並刪除現有表並重命名臨時表。有點複雜的過程,但使數據庫欄位更具可讀性。
  2. 最後添加新列。操作更簡單。但是,如果最後列名可能無法清楚地理解。

為了獲得一些參考,我們正在使用數據庫項目來控制數據庫更改,並為應用程序開發人員提供更好的 GUI 來進行數據庫更改。我們正在使用某種 ORM 與數據庫互動,因此沒有人使用數據庫對象名稱查詢數據庫。

更新: 我在一些現有列上有幾個索引。但是名稱相似的列(包括我要添加的列)不是任何索引的一部分。

作為曾經嘗試像這樣將列保持在一起的人,我強烈建議您使用選項#2。

將列視覺上保持在一起的有爭議的好處(在 SSMS 列列表中/當您SELECT *從表格中時)與選項 #1 的缺點相比絕對相形見絀。

隨著表變得越來越大,執行此“複製和替換”操作將花費越來越長的時間,並使用更多資源(I/O、記憶體、CPU)。

此外,您確實需要確保在複製和替換期間不會失去任何數據,因此使用對並發最不友好的隔離級別 ( SERIALIZABLE) 將是必要的。這意味著修改現有表的訪問將被阻止,直到操作完成。因此,您可以將長時間的阻塞添加到缺點列表中。

SSDT publish 在重新排序這樣的列時會自動使用這種程式碼(來自我關於該主題的部落格文章):

BEGIN TRANSACTION;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

CREATE TABLE [dbo].[tmp_ms_xx_Post] (
   [Id]           INT          IDENTITY (1, 1) NOT NULL,
   [CommentCount] INT          NULL,
   [PostType]     VARCHAR (10) NOT NULL
);

IF EXISTS (SELECT TOP 1 1 
          FROM   [dbo].[Post])
   BEGIN
       SET IDENTITY_INSERT [dbo].[tmp_ms_xx_Post] ON;
       INSERT INTO [dbo].[tmp_ms_xx_Post] ([Id], [PostType])
       SELECT [Id],
              [PostType]
       FROM   [dbo].[Post];
       SET IDENTITY_INSERT [dbo].[tmp_ms_xx_Post] OFF;
   END

DROP TABLE [dbo].[Post];

EXECUTE sp_rename N'[dbo].[tmp_ms_xx_Post]', N'Post';

COMMIT TRANSACTION;

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

最重要的是,如果您手動執行此操作(而不是使用 SSDT 模式比較),那麼很容易出錯(將數據放入錯誤的列,複製/粘貼錯誤等) - 特別是在帶有很多列。

引用自:https://dba.stackexchange.com/questions/248977