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秒で作成できることになり、ループを使用して作成するより圧倒的に高速で
データが作成できるようになりました。
ストアドプロシージャにしてテーブル名や作成する件数を変数化してやればもっと汎用的に
使用できるようにもなり、データ作成も高速に行えると思います。