带有循环的SQL SERVER INSERT语句需要优化

时间:2016-03-16 12:29:42

标签: sql-server tsql

我在SQL Server 2014中运行SQL语句。 我有3列:id,text1,text2 在text1,text2中插入记录 text1是nvarchar text2是varchar 到目前为止,在大约3.5小时内插入了120万行 试图插入300万需要帮助以减少插入时间

CODE:

DECLARE @i as int  
SET @i  = 0 

WHILE  @i < 3000000
BEGIN
    SET @i = @i + 1
    insert into test (text1 , text2)
    values(N'你好','VJ'+ cast(@i as varchar(20)))
END

3 个答案:

答案 0 :(得分:1)

您可以尝试这样

WITH CTE_TEST
AS
(
    SELECT N'你好' AS CODE,'VJ'+ cast(1 as varchar(20)) NAME, 1 AS VCOUNT
    UNION ALL
    SELECT N'你好' ,'VJ'+ cast(VCOUNT+1 as varchar(20)) NAME, VCOUNT+1 AS VCOUNT
    FROM    CTE_TEST
    WHERE   VCOUNT+1 < 3000000
)
INSERT INTO test (text1 , text2)
SELECT CODE,NAME FROM CTE_TEST
OPTION (MAXRECURSION 0)

您可以在CTE中使用其他逻辑,只需将结果集插入实际表中即可。这里的insert语句在循环之外(带有3000000条记录的1个insert语句),因此它比在3000000次循环中插入记录要快得多(3000000个insert语句,每条记录1条记录)

默认情况下,MAXRECURSION为100以避免无限循环,在这里你需要覆盖它(但这不是一个好习惯)。

答案 1 :(得分:1)

不使用递归CTE的替代方法是使用具有足够记录的已知表,以便您可以对其进行迭代:

-- generation parameters
declare @batchCount INT = 100000
declare @totalCount INT = 30000000
declare @loopCount INT = @totalCount / @batchCount

DECLARE @i as int = 0
-- loops are slow, but here we have only a few
WHILE (@i < @loopCount)
BEGIN
    -- insert can be put just here to actually perform the insert
    -- ROW_NUMBER gives us the numbering, but order does not matter, so using SELECT 1
    select TOP (@batchCount) N'你好','VJ'+ cast(@i * @batchCount + ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as varchar(20))
    from sys.messages

    SET @i = @i + 1
END 

sys.messages是一个非常大的表(至少200K条记录),因此它可以安全地用于100K批次。

使用recursive CTE的时间:51s

使用上述解决方案的时间:28s

(在SQL Server 2014 Express个实例上测试,仅限SELECT

答案 2 :(得分:1)

这是另一种方法...它完成得非常快......在我的SQL服务器上不到5秒

if object_id('tempdb..#Numbers') is not null drop table #Numbers
create table #Numbers (Num int)

insert into #Numbers (Num)
SELECT TOP (3000000) n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);

if object_id('tempdb..#test') is not null drop table #test
create table #test (text1 nvarchar(50), text2 nvarchar(50))

insert into #test (text1, text2)
select N'你好' [text1], 'VJ' + cast(Num as nvarchar) [text2] from #Numbers