使用SQL SERVER儲存過程實現歷史資料遷移

飛天心巨集發表於2021-09-19

今天講下軟體開發中最常見的歷史資料遷移方式。在講遷移之前,先簡單介紹下幾個基本概念。

1、什麼是歷史資料遷移?

簡單直白地說:就是將一些建立時間比較久而且不常用的歷史資料,儲存到另一個地方(可以是另一個資料,也可以是另一個表),一般歷史資料遷移的資料,都是不會更改了的資料,後續只可能需要查詢統計而已。

2、歷史資料遷移的目的

減少在用資料庫的數量,因為資料量越大,資料庫運算元據(包括:查詢、排序等等)的時間也就越長,當一個表的資料達到上千萬級以上,再來個多條件多表查詢的時候,是會有響應速度慢的可能。(因為不同開發人員寫的邏輯,不可能保障每個SQL都是高效率執行的SQL)

所以及時遷移走一些歷史資料,是對整個系統效能的提升是有一定好處的。

3、什麼時候需要做歷史資料遷移?

最簡單的情況,就是你感覺程式有變慢的趨勢,那就可以開始考慮歷史資料遷移了。

原則上,小企業伺服器不多,硬體配置也不是很高的情況下,單表500萬以上的資料,最好就開始慢慢遷移,別動不動就等到幾千萬的資料才開始遷移。

根據產生資料量的大小判斷,一般保持1年左右的業務資料即可,一年前的歷史資料都遷入歷史上資料庫。如果每天產生的資料量實在太大的話,一般就需要考慮自動分表儲存,當然如果沒做這個的話,可以在不影響日常業務的情況下,實時在用業務資料庫只保留最近3-6個月的資料。

4、資料遷移的基本思路

1)、第一次遷移建立一個一模一樣的表結構(只要第一次遷移前建立即可)

2)、按照資料的建立時間排序,把最早的資料N條資料查出,同時插入到歷史資料表中。

insert into ...  select  from

 

3)、檢測插入資料的準確性,一定要保證是N條沒錯。之後刪除在用的業務資料庫。

4)、當遷移資料中途有誤時,終止程式,但不能刪除在用資料庫,需要開發人員核對資料。

5)、根據遷移的對效能的影響,N不能太多,最多一次5W到10W條吧(根據伺服器的效能配置,推薦一次遷移1W至5W條資料影響較小)。如果要遷移大量資料,可以考慮分批執行。

5、資料遷移儲存過程程式碼示例

程式碼如下:(無需過多解釋,很簡單的程式碼,一看就懂)

  1 USE [Tyingsoft.GLPS]  
  2 GO
  3 /****** Object:  StoredProcedure [dbo].[TY_SP_ApiRequestToHis]    Script Date: 2021-09-16 15:35:55 ******/
  4 SET ANSI_NULLS ON
  5 GO
  6 SET QUOTED_IDENTIFIER ON
  7 GO
  8 -- =============================================
  9 -- Author:         
 10 -- Create date:    
 11 -- Last Edit date: 
 12 -- Description:    <介面請求記錄表GLPS_APIREQUEST資料遷移>
 13 -- =============================================
 14 ALTER PROCEDURE [dbo].[TY_SP_ApiRequestToHis]
 15     -- Add the parameters for the stored procedure here
 16     @PreCountN int = 2000     --每次執行的條數N
 17 AS
 18 BEGIN
 19     -- SET NOCOUNT ON added to prevent extra result sets from
 20     -- interfering with SELECT statements.
 21     SET NOCOUNT ON;
 22 
 23     declare @tableDataCount int;          --遷移前的資料條數
 24     declare @tableDataCountHis int;       --遷移前歷史資料庫的資料條數
 25     declare @tableDataCount2 int;         --遷移後的資料條數
 26     declare @tableDataCount2His int;      --遷移後歷史資料庫的資料條數
 27     declare @maxCreateTime datetime;      --取N條資料中最大的建立時間
 28     declare @maxCreateTimeHis datetime;   --歷史資料庫中的最大建立時間 
 29     declare @beginTime datetime;          --開始執行時間
 30     declare @endTime datetime;            --執行完成時間
 31     declare @execTimeMS int;              --執行時間(毫秒數)
 32 
 33     --中間步驟debugger耗時使用
 34     declare @tmpBeginTime datetime;       --(臨時)開始執行時間
 35     declare @tmpEndTime datetime;         --(臨時)執行完成時間
 36     declare @tmpExecTimeMS int;           --(臨時)執行時間(毫秒數)
 37 
 38     select @beginTime = getdate();
 39 
 40     --遷移前:先查詢資料條數
 41     select @tableDataCount = count(1) from [Tyingsoft.GLPS].dbo.GLPS_APIREQUEST;
 42     select @tableDataCountHis =count(1) from  [Tyingsoft.GLPS_His].dbo.GLPS_APIREQUEST;
 43 
 44     print '【介面請求記錄表(GLPS_APIREQUEST)資料遷移】開始執行時間:' + convert(nvarchar(50),@beginTime,20);
 45     print '本次計劃遷移資料條數:'+ cast( @PreCountN as nvarchar(20));
 46 
 47     --建立一個臨時公用表示式 (表中最早建立的N條資料)
 48     with topNRecord (FCREATETIME)
 49     as
 50     (
 51         select top (@PreCountN) FCREATETIME from GLPS_APIREQUEST  order by FCREATETIME 
 52     )
 53 
 54     --取N條資料中最大的建立時間
 55     select @maxCreateTime =max(FCREATETIME) from topNRecord
 56     
 57     print '對應遷移資料FCREATETIME為:'+ convert(nvarchar(50),@maxCreateTime,21); --日期轉化為字串格式:yyyy-MM-dd HH:mm:ss.fff
 58 
 59     
 60     select @tmpBeginTime = GETDATE();  --中間步驟開始計時
 61 
 62     --第一步:將N條數資料寫入到歷史資料庫
 63     insert into [Tyingsoft.GLPS_His].dbo.GLPS_APIREQUEST
 64     select * from [Tyingsoft.GLPS].dbo.GLPS_APIREQUEST  where  FCREATETIME <=@maxCreateTime
 65     
 66     select @tmpEndTime = GETDATE();   --中間步驟計時結束
 67     print '資料遷移,插入耗時(毫秒):' +cast( datediff(millisecond,@tmpBeginTime,@tmpEndTime) as nvarchar(20));
 68 
 69 
 70     --第二步:對比歷史資料庫的資料
 71     select @maxCreateTimeHis=max(FCREATETIME) from [Tyingsoft.GLPS_His].dbo.GLPS_APIREQUEST
 72 
 73     if @maxCreateTime = @maxCreateTimeHis  
 74        begin
 75             select @tmpBeginTime = GETDATE();  --中間步驟開始計時
 76 
 77             --第三步:執行完以後,再刪除資料
 78             delete from GLPS_APIREQUEST where FCREATETIME <=@maxCreateTime 
 79             print '遷移後刪除資料條數:' + cast( @@ROWCOUNT as nvarchar(50));
 80 
 81             select @tmpEndTime = GETDATE();       --中間步驟計時結束
 82             print '資料遷移,刪除耗時(毫秒):' +cast( datediff(millisecond,@tmpBeginTime,@tmpEndTime) as nvarchar(20));
 83         end
 84     else
 85         print '遷移後,日期校驗錯誤,未刪除資料!!!'
 86 
 87     --遷移後:再查詢資料條數
 88     select @tableDataCount2 = count(1) from [Tyingsoft.GLPS].dbo.GLPS_APIREQUEST;
 89     select @tableDataCount2His =count(1) from  [Tyingsoft.GLPS_His].dbo.GLPS_APIREQUEST;
 90 
 91     print '遷移前GLPS_APIREQUEST的資料條數:' + cast(@tableDataCount as nvarchar(20))
 92      + ',遷移後資料條數:'+cast(@tableDataCount2 as nvarchar(20))
 93      + ',差額:'+cast((@tableDataCount2-@tableDataCount) as nvarchar(20));
 94     
 95     print '遷移前His.GLPS_APIREQUEST的資料條數:' 
 96     + cast(@tableDataCountHis as nvarchar(20))
 97     +',遷移後資料條數:'+cast(@tableDataCount2His as nvarchar(20))
 98     + ',差額:'+cast((@tableDataCount2His-@tableDataCountHis) as nvarchar(20));
 99 
100     print '注意:正式環境一直有資料變動,所以會有一定的偏差!';
101 
102    
103     select @endTime = GETDATE();
104     print '總耗時(毫秒):' +cast( datediff(millisecond,@beginTime,@endTime) as nvarchar(20));
105     
106 
107 END

我們在測試資料庫中來簡單執行下試試效果:

 

6、使用場景特別說明

此方式是採用 insert into ... select from 的方式進行資料遷移。這個思路由於是最簡單的資料遷移邏輯,僅適用於小資料量的情況(一般表資料低於500萬),當資料量大於500萬之後千萬別用此方法,因為此時的insert into ... select from 會執行很慢,有很大可能會影響正式環境的執行。

還有就是此方法,由於是SQL直接訪問資料庫,所以要求當前業務庫和歷史資料都能訪問(也就是同一個資料庫例項),如果異地不同的資料庫也沒辦法處理。

所以此方法僅適用於簡單的歷史資料遷移場景,使用前提有限,適合小專案使用。

對於大資料量的(單表1千萬以上的資料),又不能影響當下業務效能指標的資料遷移方式,請看下篇文章介紹。

 

相關文章