SQL Serverの負荷テストで大量のデータを作成しないといけなくなり、できるだけ高速で作成する方法を探してみました。
まず、単純にループを使用して100万件のデータを作成するSQLを作成してみました。
・ループを使用して100万件のデータを作成するSQL
SET NOCOUNT ON 
        DECLARE @RowCount INT
        SET @RowCount = 0
        WHILE @RowCount < 1000000
        BEGIN
                INSERT INTO T_Test (Data1,
                                    Data2,
                                    Data3,
                                    Data4,
                                    Data5)
                VALUES
                        (@RowCount, 
                        'DATA' + right('0000000000' + convert(varchar, @RowCount), 10),
                        '0',
                        '0',
                        '0')
                SET @RowCount = @RowCount + 1
        END
上記SQLを実行した結果。
 
    
ループ処理で100万件データを作成した結果、処理時間は3分6秒でした。
もし1000万件のデータを作成しようとした場合、単純計算で30分かかります。
テーブル数が多い場合やデータ件数が増えてしまうと、実用的には厳しい感じです。
他にいい方法がないかと調べた結果、再帰クエリを使用した場合、飛躍的に高速でデータが作成できました。
・再帰クエリを使用し、大きなSELECTデータをINSERTするSQL
DECLARE @p_NumberOfRows Bigint 
SELECT @p_NumberOfRows=1000000; 
WITH Base AS
  (
    SELECT 1 AS n
    UNION ALL
    SELECT n+1 FROM Base WHERE n < p_NumberOfRows
  ),
  Nums AS
  (
    SELECT Row_Number() OVER(ORDER BY n) AS n FROM Base
  )
  
  INSERT INTO T_Test 
   SELECT n, 
     'DATA' + right('0000000000' + convert(varchar, n), 10),
     '0',
     '0',
     '0'
    FROM Nums  WHERE n <= @p_NumberOfRows
OPTION (MaxRecursion 0); 
上記SQLを実行した結果。
 
    
再帰クエリを使用して100万件のデータを作成した結果、処理時間は9秒でした。
この方法だと、1000万件のデータでも90秒で作成できます。
1億件でも約15分程度で作成できることになり、実用的なレベルで使用できると思います。
上記SQLでも十分かなと思っていたのですが、もう一工夫することでもっと早く作成できることができました。
・再帰クエリを修正したSQL
DECLARE @p_NumberOfRows Bigint 
SELECT @p_NumberOfRows=1000000; 
WITH Base AS
  (
    SELECT 1 AS n
    UNION ALL
    SELECT n+1 FROM Base WHERE n < CEILING(SQRT(@p_NumberOfRows))
  ),
  Expand AS
  (
    SELECT 1 AS C FROM Base AS B1, Base AS B2
  ),
  Nums AS
  (
    SELECT Row_Number() OVER(ORDER BY C) AS n FROM Expand
  )
  
  INSERT INTO T_Test 
   SELECT n, 
     'DATA' + right('0000000000' + convert(varchar, n), 10),
     '0',
     '0',
     '0'
    FROM Nums  WHERE n <= @p_NumberOfRows
OPTION (MaxRecursion 0); 
上記SQLを実行した結果。
 
    
先ほどの再帰クエリを修正して実行したところ、100万件のデータを作成する処理時間は4秒でした。
1000万件でも約40秒で作成できることになり、ループを使用して作成するより圧倒的に高速で
データが作成できるようになりました。
ストアドプロシージャにしてテーブル名や作成する件数を変数化してやればもっと汎用的に
使用できるようにもなり、データ作成も高速に行えると思います。
