簡體   English   中英

如何向大型sql server表添加列

[英]How do I add a column to large sql server table

我有一個生產中有數百萬行的SQL Server表,事實證明我需要為它添加一列。 或者,為了更准確,我需要向表所代表的實體添加一個字段。

從語法上講,這不是問題,如果表沒有那么多行而且沒有生產,這很容易。

我真正想要的是行動方案。 有很多網站都有非常大的桌子,他們必須不時添加字段。 如果沒有大量的停機時間,他們怎么做?

我應該補充一點,我不希望列允許空值,這意味着我需要一個默認值。

所以我要么想弄清楚如何及時添加具有默認值的列,或者我需要找出一種方法以便稍后更新列,然后將列設置為不允許空值。

ALTER TABLE table1 ADD
  newcolumn int NULL
GO

不應該花那么長時間...需要很長時間的是在其他列的中間插入列... b / c然后引擎需要創建一個新表並將數據復制到新表。

連續正常運行時間的唯一真正解決方案是冗余

我承認@ Nestor的答案是,在SQL Server中添加新列不應該花費很長時間,但是,它仍然可能是生產系統無法接受的中斷。 另一種方法是在並行系統中進行更改,然后在操作完成后,將舊的交換為舊的。

例如,如果需要添加列,則可以創建表的副本,然后將列添加到該副本,然后使用sp_rename()將舊表移到一邊並將新表放到適當的位置。

如果您具有指向此表的參照完整性約束,則可以使交換更加棘手。 在交換表時,您可能必須簡單地刪除約束。

對於某些類型的復雜升級,您可以在單獨的服務器主機上完全復制數據庫。 一旦准備就緒,只需交換兩個服務器的DNS條目即可!

我支持一家1990年代的股票交易所公司,他們一直運行三個重復的數據庫服務器。 這樣他們就可以在一台服務器上實現升級,同時保留一台生產服務器和一台故障轉移服務器。 他們的操作有一個標准的程序, 每天通過生產,故障轉移和維護角色旋轉三台機器。 當他們需要升級硬件,軟件或更改數據庫架構時,需要三天時間才能通過他們的服務器傳播更改,但他們可以在不中斷服務的情況下完成更改。 一切都歸功於冗余。

我不希望列允許空值,這意味着我需要一個默認值。

添加NOT NULL與列DEFAULT約束到任意數量的行(甚至數十億)的表成為在SQL Server中容易得多 ,從2012年(但僅限於企業版),因為它們允許它是一個在線操作(在大多數情況下, )其中,對於現有行,該值將從元數據中讀取,並且在更新行或重建聚簇索引之前不會實際存儲在行中。 而不是解釋,這里是ALTER TABLE的MSDN頁面中的相關部分:

添加NOT NULL列作為聯機操作

從SQL Server 2012 Enterprise Edition開始,添加帶有默認值的NOT NULL列是默認值為運行時常量時的聯機操作。 這意味着無論表中的行數如何,操作幾乎都是即時完成的。 這是因為表中的現有行在操作期間不會更新; 相反,默認值僅存儲在表的元數據中,並且在訪問這些行的查詢中根據需要查找值。 這種行為是自動的; 除了ADD COLUMN語法之外,不需要其他語法來實現在線操作。 運行時常量是一個表達式,它在運行時為表中的每一行生成相同的值,而不管其確定性如何。 例如,常量表達式“我的臨時數據”或系統函數GETUTCDATETIME()是運行時常量。 相反,函數NEWID()或NEWSEQUENTIALID()不是運行時常量,因為為表中的每一行生成唯一值。 添加具有非運行時常量的默認值的NOT NULL列始終是脫機執行的,並且在操作期間獲取獨占(SCH-M)鎖。

雖然現有行引用存儲在元數據中的值,但默認值存儲在插入的任何新行的行上,並且不為列指定其他值。 更新行時,存儲在元數據中的默認值將移動到現有行(即使未在UPDATE語句中指定實際列),或者重建了表或聚簇索引。

無法在聯機操作中添加varchar(max),nvarchar(max),varbinary(max),xml,text,ntext,image,hierarchyid,geometry,geography或CLR UDTS類型的列。 如果這樣做導致最大可能行大小超過8,060字節限制,則無法在線添加列。 在這種情況下,該列將添加為脫機操作。

“添加列,然后執行相對較小的UPDATE批處理,以使用默認值填充列。這應該可以防止任何明顯的減速”

之后,您必須將列設置為NOT NULL,這將在一個大事務中觸發。 所以一切都會快速運行,直到你這樣做,所以你可能真的獲得了很少。 我只從第一手經驗中知道這一點。

您可能希望將當前表從X重命名為Y.您可以使用此命令sp_RENAME'[OldTableName]','[NewTableName]'執行此操作。

將新表重新設置為X,新列設置為NOT NULL,然后從Y到X批量插入,並在新列的插入中包含默認值,或者在重新創建表X時在新列上放置默認值。

我在具有數億行的表上完成了這種類型的更改。 它仍然花了一個多小時,但它沒有吹滅我們的trans日志。 當我嘗試將列更改為NOT NULL並使用表中的所有數據時,我花了20多個小時才殺死進程。

您是否測試過只添加一個用數據填充的列並將列設置為NOT NULL?

所以最后我認為沒有靈丹妙葯。

選擇一個新表並重命名。 示例,將列i添加到表A:

select *, 1 as i
into A_tmp
from A_tbl

//Add any indexes here

exec sp_rename 'A_tbl', 'A_old'
exec sp_rename 'A_tmp', 'A_tbl'

應該是快速的,不會像批量插入那樣觸及您的事務日志。 (我今天剛剛在<2分鍾內完成了7000萬行表)。

如果您需要將其作為在線操作(可以在select into和renames之間的表中更改某些內容),您可以將其包裝在事務中。

另一種技術是將列添加到新的相關表中(假設一對一關系,您可以通過為FK提供唯一索引來強制執行該關系)。 然后,您可以批量填充它,然后您可以將連接添加到此表中您希望數據顯示的位置。 注意我只考慮這個列,我不想在原始表的每個查詢中使用,或者我原始表的記錄寬度變得太大,或者我是否添加了多個列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM