SQL Server ->> 談表數據遷移時,先建索引再插入數據,還是先插入數據再建索引的問題


這個事情源於我前陣子做一個數據遷移時遇到的慘痛經歷。幾個月前我們生產環境有張10幾億行數據的表因為自增列是INT類型,數據類型需要改成BIGINT,只能遷移數據到新表后通過重命名表的方式來實現表遷移。這個我在另外一篇博文SQL Server ->> 談SQL Server數據庫大表遷移中有談到。這里主要談過程中我遇到的問題。

其實這個問題准確來說是三種選擇,而不是題目的兩種。應該是:到底是:1、先建索引再全表插入數據;2、先插入數據再建索引;3、先建索引,再批次插入數據

 

先建索引再全表插入數據:

這是三者風險最高最高的一種選擇,絕對是。先說風險性,整個表的數據一次性插入,整個事務大小級別是極其恐怖的(假設表數據量非常大,而且索引還不少),風險性極高,一旦出現問題,整個回滾的時間是完全不可預期的。你可以想象這個過程要耗費多少系統資源:

1、事務日志會按插入數據量增長,等同於日志文件大小增量只是是表數據寫入數據量的大小,假設你的數據本身是100G,那你要保證你的事務日志磁盤空間至少要大於100G;

2、數據插入過程SQL SERVER不僅要把申請數據本身的內存空間,還需要申請索引本身所需的內存空間,也就是SQL SERVER一遍插入數據,一遍還要維護索引。這個時候系統資源壓力最大的,我覺得是內存。

3、最后是磁盤IO,連續的數據寫入會消耗整個磁盤的最大吞吐,其他的數據查詢請求就必須等待。堵塞數據庫。

所以先建索引再全表插入數據這種做法,除非表的數據量在百萬級別以下,且是在數據庫相對空閑的時間點去做這個事情。

 

先插入數據再建索引:

這種應該性能最好的,這里指的性能做好是指所需的時間最短。因為首先先插入數據,數據庫無需維護索引,所以整個過程只需要按照聚集索引的順序寫入數據到磁盤。后續建索引的時候,由於建索引可以觸發並行處理,所以會盡可能多的利用服務器資源。但是它的風險點很高,就是當表的數據量達到一定量級的時候,雖然比起第一種全體回滾,它的回滾成本要更小,但是如果表的數據量非常大,而且索引的寬度也不小的情況下,即便回滾單挑索引的創建,回滾也是需要一定時長。

這點我犯了一個很致命的錯誤,就是在遷移一張10幾億行數據的表(聚集索引數據大小就高達450G),選擇了先插入數據再建索引。最后在創建索引的時候,由於並行處理,導致服務器內存資源和線程吃緊,服務器出現其他的線程無法連接上數據庫的情況。還好是短暫的3分鍾,當時是晚上8點多。但是我還是低估了影響,以為服務器性能那么強,服務器是一台Azure的雲服務器,32核 128G內存的配置,磁盤是Azure的P50高性能SSD。

所以除非你的表是千萬級以下的表,而且服務器窗口期比較長,服務器資源也不錯,我覺得用這種方式也不是不行。經過測試,千萬級以下的表還是挺快的。

 

先建索引,再批次插入數據:

這種方式是比較推薦的。降低了風險,雖然性能上可能是三者時間消耗最長的(也不一定,和第一種方式比較,都有可能久,反正肯定比第二種要長)。

通過批次的方式,每個幾十萬一個批次的輸入插入,雖然性能上會比較差,尤其表中的數據累計到一定體量后索引維護的耗時會很長。但是風險小。

所以我建議,如果你的表上千萬,遷移數據還是先建索引,然后按一個批次一個批次這樣插入數據導新表。

 


免責聲明!

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



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