--=====================================================================
事件起因:開發發現有表插入數據失敗,查看后發現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每秒能產生的日志記錄數限制,因此每秒寫入的日志量較小,修改的行數比較少,導致整個修改操作持續大量時間。
--======================================================================
夜深了,妹子提神