--=====================================================================數據庫
事件原由:開發發現有表插入數據失敗,查看後發現INT類型自增值已經到了最大值,沒法繼續插入,須要修改INT類型爲BIGINT類型。併發
--=====================================================================工具
做爲一羣自認爲還算有點經驗的老DBA,你們相互商量下,決定刪除複製,而後禁止訪問,刪除索引,再使用ALTER TABLE修改,最後再加回索引,再修改訪問,再不初始化訂閱,多完美的步驟。測試
因而在一羣人嘻哈圍觀中,執行了上述步驟,運行修改腳本:spa
ALTER TABLE TableName ALTER COLUMN ID BIGINT
而後你們開始預估執行時間,有預估十幾分鐘的,有預估半小時的,有預估兩小時的,而後開始坐等。。。線程
半小時過去,沒有完成,有人開始坐不住,一個小時過去,沒有完成,你們開始着急,兩個小時過去,仍是沒有完成,老闆坐不住啦,殺過來質問。。。3d
這下玩大啦。。。日誌
--=====================================================================code
因爲在多臺機器上執行,一些取消執行,一些硬抗等着執行成功,不管是取消執行仍是繼續執行,都不知道啥時能回滾成功或者執行成功,你們一邊在惶恐中祈禱早點執行完成,一邊還得給老大們解釋各類緣由。blog
--=====================================================================
錶行數: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每秒能產生的日誌記錄數限制,所以每秒寫入的日誌量較小,修改的行數比較少,致使整個修改操做持續大量時間。
--======================================================================
夜深了,妹子提神