記錄一次資料量巨大的表索引損壞處理
阿新 • • 發佈:2019-01-09
簡介:索引損壞的表XSDTM129.RT是個歷史資料表,該表資料是在實時插入的,所以表內資料量巨大,多達6億多條,而由於索引損壞,無法先進行資料的刪除,而傳統的刪索引—重建索引的時間消耗非常大,所以考慮能否用重建RT表來代替原表,並把需要所需資料匯入新RT表,刪除舊錶的方式來提高索引損壞修復的效率。
注:由於此次操作的表資料是實時插入的,而此法在執行過程中需要將資料庫設為單使用者模式,所以在執行換表的那段時間內的資料會存在丟失的情況,所以採用此法時要慎重!!!
(該方案在生產伺服器已經實施,保留資料1500000條,語句執行3分鐘,後續等採集程式採數到正常資料存入資料庫大約幾分鐘~) 具體方案:把XSDTM129.RT表重新命名為XSDTM129.MT---新建XSDTM129.RT表(注意:同一架構下不能有同名索引及主鍵)---將需要的資料匯入到新的RT表。 為測試方案是否可行,先在測試伺服器上做如下實驗。 環境:測試伺服器上一命名例項,XSDTM129.RT表,資料量約為3億。 我寫了一個萌萌噠的小儲存過程用於測試更換表名對儲存過程往表查資料的影響,並手動向XSDTM129.RT表插入資料。
然後將XSDTM129.RT更名為XSDTM129.MT。 EXECsp_rename'XSDTM129.RT','MT' 建立RT表
再次手動執行往RT插資料的儲存過程,為保證正確性,手動插入了兩次。並選出結果。
由上圖可以看出,資料全部插入了新的RT表。 同理測試了檢視,選出的是新RT表裡的資料。 由此基本可以判斷更換表名對儲存過程和檢視的影響是沒有的! 接下來就是如何把需要的資料匯入到新表,由於RT表資料是每隔幾秒都會有插入,哪怕三天的資料量都達到一百多萬,所以考慮插入的時候,查詢的判斷條件用record_id(該表在record_id列上建有索引)。
注:由於此次操作的表資料是實時插入的,而此法在執行過程中需要將資料庫設為單使用者模式,所以在執行換表的那段時間內的資料會存在丟失的情況,所以採用此法時要慎重!!!
(該方案在生產伺服器已經實施,保留資料1500000條,語句執行3分鐘,後續等採集程式採數到正常資料存入資料庫大約幾分鐘~) 具體方案:把XSDTM129.RT表重新命名為XSDTM129.MT---新建XSDTM129.RT表(注意:同一架構下不能有同名索引及主鍵)---將需要的資料匯入到新的RT表。 為測試方案是否可行,先在測試伺服器上做如下實驗。 環境:測試伺服器上一命名例項,XSDTM129.RT表,資料量約為3億。 我寫了一個萌萌噠的小儲存過程用於測試更換表名對儲存過程往表查資料的影響,並手動向XSDTM129.RT表插入資料。
然後將XSDTM129.RT更名為XSDTM129.MT。 EXECsp_rename'XSDTM129.RT','MT' 建立RT表
再次手動執行往RT插資料的儲存過程,為保證正確性,手動插入了兩次。並選出結果。
由上圖可以看出,資料全部插入了新的RT表。 同理測試了檢視,選出的是新RT表裡的資料。 由此基本可以判斷更換表名對儲存過程和檢視的影響是沒有的! 接下來就是如何把需要的資料匯入到新表,由於RT表資料是每隔幾秒都會有插入,哪怕三天的資料量都達到一百多萬,所以考慮插入的時候,查詢的判斷條件用record_id(該表在record_id列上建有索引)。
Attention!! 為保證過程實施的穩定性,最好用以下指令碼殺掉程序、把資料庫切換為單使用者模式,可以先把採集程式關了,等全部執行完後再次開啟。如果整體執行報錯的話,可以手動的一段一段的執行。 詳情請見指令碼!!INSERT INTO xsdtm129.rt (ts_id , class_num , ord_class , team_set , class_start_server , class_end_server , record_timestamp , runtime_s , article_id , current_class_output , total_output , total_output_c , a_output , b_output , c_output , d_output , a_total , b_total , c_total , d_total ,current_length ,fixed_length ,rolla_v ,spindle_v ,twist_ratio ,class_num_plc ,Dev_GUID ,i_signal ,q_signal ,sec_A_length ,sec_B_length ,sec_C_length ,sec_D_length ,sec_A_change_amount ,sec_B_change_amount ,sec_C_change_amount ,sec_D_change_amount ,run_efc ,device_state ,Article_GUID ,a_total_calc ,b_total_calc ,c_total_calc ,d_total_calc , row_interval ,statecode ,machineNo) SELECT ts_id , class_num , ord_class , team_set , class_start_server , class_end_server , record_timestamp , runtime_s , article_id , current_class_output , total_output , total_output_c , a_output , b_output , c_output , d_output , a_total , b_total , c_total , d_total ,current_length ,fixed_length ,rolla_v ,spindle_v ,twist_ratio ,class_num_plc ,Dev_GUID ,i_signal ,q_signal ,sec_A_length ,sec_B_length ,sec_C_length ,sec_D_length ,sec_A_change_amount ,sec_B_change_amount ,sec_C_change_amount ,sec_D_change_amount ,run_efc ,device_state ,Article_GUID ,a_total_calc ,b_total_calc ,c_total_calc ,d_total_calc , row_interval ,statecode ,machineNo FROM XSDTM129.mt WHERE record_id>614217880
--殺掉程序 USE master GO DECLARE @kill varchar(max) = ''; SELECT @kill = @kill + 'KILL ' + CONVERT(varchar(10), spid) + '; ' FROM master..sysprocesses WHERE spid > 50 AND dbid = DB_ID('A') --A為資料庫名 PRINT @kill EXEC(@kill); GO SET DEADLOCK_PRIORITY HIGH USE A --A為資料庫名 GO --更換表名 ALTER DATABASE A SET SINGLE_USER; GO --更換表名 EXEC sp_rename 'XSDTM129.RT', 'MT'; GO --新建XSDTM.RT表代替原表 CREATE TABLE [XSDTM129].[RT] ( [record_id] [BIGINT] IDENTITY(1, 1) NOT NULL , [ts_id] [INT] NULL , [class_num] [TINYINT] NULL , [ord_class] [NCHAR](1) NULL , [team_set] [NCHAR](1) NULL , [class_start_server] [DATETIME] NULL , [class_end_server] [DATETIME] NULL , [record_timestamp] [DATETIME] NOT NULL , [runtime_s] [INT] NULL , [article_id] [INT] NULL , [current_class_output] [INT] NULL , [total_output] [INT] NULL , [total_output_c] [BIGINT] NULL , [a_output] [INT] NULL , [b_output] [INT] NULL , [c_output] [INT] NULL , [d_output] [INT] NULL , [a_total] [INT] NULL , [b_total] [INT] NULL , [c_total] [INT] NULL , [d_total] [INT] NULL , [current_length] [INT] NULL , [fixed_length] [INT] NULL , [rolla_v] [DECIMAL](9, 2) NULL , [spindle_v] [INT] NULL , [twist_ratio] [INT] NULL , [class_num_plc] [INT] NULL , [Dev_GUID] [UNIQUEIDENTIFIER] NOT NULL , [i_signal] [INT] NULL , [q_signal] [INT] NULL , [sec_A_length] [INT] NULL , [sec_B_length] [INT] NULL , [sec_C_length] [INT] NULL , [sec_D_length] [INT] NULL , [sec_A_change_amount] [INT] NULL , [sec_B_change_amount] [INT] NULL , [sec_C_change_amount] [INT] NULL , [sec_D_change_amount] [INT] NULL , [run_efc] [DECIMAL](5, 2) NULL , [device_state] [INT] NULL , [Article_GUID] [UNIQUEIDENTIFIER] NULL , [a_total_calc] [INT] NULL , [b_total_calc] [INT] NULL , [c_total_calc] [INT] NULL , [d_total_calc] [INT] NULL , [row_interval] [INT] NULL , [statecode] [TINYINT] NULL , [machineNo] [INT] NULL , [article_name] [NVARCHAR](32) NULL , CONSTRAINT [PK_RT_RecordID] PRIMARY KEY NONCLUSTERED ( [record_id] ASC ) WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY] ) ON [PRIMARY]; GO ALTER TABLE [XSDTM129].[RT] ADD CONSTRAINT [DF_RT_record_timestamp] DEFAULT (GETDATE()) FOR [record_timestamp]; GO ALTER TABLE [XSDTM129].[RT] ADD CONSTRAINT [DF_RT_runtime_s] DEFAULT ((0)) FOR [runtime_s]; GO --為表建索引,在以下空白處可加上新增索引的程式碼 SET IDENTITY_INSERT XSDTM129.RT ON; GO BEGIN TRAN; INSERT INTO XSDTM129.RT ( record_id , ts_id , class_num , ord_class , team_set , class_start_server , class_end_server , record_timestamp , runtime_s , article_id , current_class_output , total_output , total_output_c , a_output , b_output , c_output , d_output , a_total , b_total , c_total , d_total , current_length , fixed_length , rolla_v , spindle_v , twist_ratio , class_num_plc , Dev_GUID , i_signal , q_signal , sec_A_length , sec_B_length , sec_C_length , sec_D_length , sec_A_change_amount , sec_B_change_amount , sec_C_change_amount , sec_D_change_amount , run_efc , device_state , Article_GUID , a_total_calc , b_total_calc , c_total_calc , d_total_calc , row_interval , statecode , machineNo , article_name ) SELECT record_id , ts_id , class_num , ord_class , team_set , class_start_server , class_end_server , record_timestamp , runtime_s , article_id , current_class_output , total_output , total_output_c , a_output , b_output , c_output , d_output , a_total , b_total , c_total , d_total , current_length , fixed_length , rolla_v , spindle_v , twist_ratio , class_num_plc , Dev_GUID , i_signal , q_signal , sec_A_length , sec_B_length , sec_C_length , sec_D_length , sec_A_change_amount , sec_B_change_amount , sec_C_change_amount , sec_D_change_amount , run_efc , device_state , Article_GUID , a_total_calc , b_total_calc , c_total_calc , d_total_calc , row_interval , statecode , machineNo , article_name FROM XSDTM129.mt(NOLOCK) WHERE record_id > 1799926237 --order by record_id;--我想著用先查出一個record_id值,然後查詢條件用這個會快些,因為該值是索引列。 COMMIT TRAN; SET IDENTITY_INSERT XSDTM129.RT OFF; GO ALTER database A SET MULTI_USER --切換回多使用者模式 GO