曲演雜壇--使用ALTER TABLE修改字段類型的吐血教訓


--=====================================================================

事件起因:開發發現有表插入數據失敗,查看后發現INT類型自增值已經到了最大值,無法繼續插入,需要修改INT類型為BIGINT類型。

--=====================================================================

作為一群自認為還算有點經驗的老DBA,大家相互商量下,決定刪除復制,然后禁止訪問,刪除索引,再使用ALTER TABLE修改,最后再加回索引,再修改訪問,再不初始化訂閱,多完美的步驟。

於是在一群人嘻哈圍觀中,執行了上述步驟,運行修改腳本:

ALTER TABLE TableName
ALTER COLUMN ID BIGINT

然后大家開始預估執行時間,有預估十幾分鍾的,有預估半小時的,有預估兩小時的,然后開始坐等。。。

半小時過去,沒有完成,有人開始坐不住,一個小時過去,沒有完成,大家開始着急,兩個小時過去,還是沒有完成,老板坐不住啦,殺過來質問。。。

這下玩大啦。。。

--=====================================================================

由於在多台機器上執行,一些取消執行,一些硬抗等着執行成功,無論是取消執行還是繼續執行,都不知道啥時能回滾成功或者執行成功,大家一邊在惶恐中祈禱早點執行完成,一邊還得給老大們解釋各種原因。

--=====================================================================

表行數:11億+

表數據:60GB+

表情況:1個BIGINT列+3個INT列+1個VARCHAR(50)列(VARCHAR(50)列平均每行長度11Byte)

修改操作:將字段類型INT改為BIGINT

對於繼續執行等待ALTER TABLE成功的:耗時9.5小時完成

對於執行四小時然后取消執行的:耗時超過10小時未完成

--=====================================================================

扯了這么多水貨,咱們來點干貨,為什么修改字段類型消耗這么長時間呢?

首先排查是否由硬件資源瓶頸導致,硬件配置為:

CPU: 48CORE

內存:128GB

IO: FIO卡或高級共享存儲

CPU使用未超過10%,磁盤每秒日志寫入8MB左右,內存未發現等待分配情況

那問題出在那呢?

問題還是出在日志上,可以輕松發現,無論是在FIO卡還是共享存儲上,磁盤每秒日志寫入8MB左右,這個數值太低,經過肖磊咨詢MS工程師了解到,修改數據類型,需要修改每一行的數據,每行數據生成一條日志記錄,從而導致大量的日志,而由於未知原因,每秒寫入磁盤的日志量較低,因此導致整個修改操作維持很長時間。

讓我們來做個測試:

--=======================
--使用測試數據庫DB2
use db2
GO
--================
--創建測試表
CREATE TABLE Test001
(
    C1 INT IDENTITY(1,1),
    C2 BIGINT
)
GO
--================
--往測試表中導入2000+行數據
INSERT INTO Test001(C2)
SELECT OBJECT_ID FROM sys.all_objects
GO
--================
--備份日志以截斷日志
BACKUP LOG [db2] TO DISK='NUL'
GO
--================
--查看當前日志情況
--由於日志截斷,當前日志記錄數很少
SELECT * FROM sys.fn_dblog(NULL,NULL)
ORDER BY [Current LSN] DESC

GO
--=====================
--修改字段類型
ALTER TABLE Test001
ALTER COLUMN C1 BIGINT
GO
--================
--再次查看當前日志情況
--發現增加4000+的日志記錄數
SELECT * FROM sys.fn_dblog(NULL,NULL)
ORDER BY [Current LSN] DESC


由於我們操作的數據有11億+條,整個ALTER TABLE 操作是一個完整的事務操作,因此是一個極其龐大的事務,再加上其他諸如復制日志讀取等操作影響,導致整個修改耗時9.5個小時,產生書300GB+的日志,對業務造成比較嚴重的影響。

--=====================================================================

推薦解決辦法:

創建新表,將數據導入到新表中,整個導入過程不影響業務訪問(在修改前業務已無法插入數據,沒有寫操作,但是還有讀請求),數據導入完成后,建立對於索引,然后使用SP_RENAME修改表名。這樣可以將業務影響降低到最低,並且導入數據可以並發進行,提高導入效率,減小整個操作周期。

使用此推薦方法,用SSMS自帶的導入導入工具,約4個小時完成導入。

--======================================================================

個人猜想:

整個修改數據類型操作,是單線程操作,並且可能受單個log buffer每秒能產生的日志記錄數限制,因此每秒寫入的日志量較小,修改的行數比較少,導致整個修改操作持續大量時間。

--======================================================================

夜深了,妹子提神

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM