2014-09-11 90 views
2

我正在使用以下脚本将100,000条记录插入到表中。基本上int从500,001到600,000被插入。我将整型转换为一个字符串,然后在表格中以字符串的形式插入一个整数。我正在使用合并来检查记录是否已经存在。将100000条记录插入SQL Server的最快方法

DECLARE @first AS INT 
SET @first = 500001 
DECLARE @step AS INT 
SET @step = 1 
DECLARE @last AS INT 
SET @last = 600000 

BEGIN TRANSACTION 
WHILE(@first <= @last) 
BEGIN 
MERGE dbo.Identifiers As target 
USING (SELECT CAST(@first as varchar(10)) AS Identifier) AS source 
    ON (source.Identifier = target.Identifier) 
WHEN NOT MATCHED THEN 
INSERT (Identifier) 
VALUES (source.Identifier); 
SET @first += @step 
END 
COMMIT TRANSACTION 

它需要2分钟以上的加载。我正在做一些非常错误的事情,但无法追查到哪里。 注意:该表在标识符列上具有唯一的非聚簇索引。

+2

“加载时间超过2分钟” - 您为什么认为这太多?我们不知道您的硬件设置。 – 2014-09-11 07:05:35

+0

它是我们应用程序中加载过程的一部分。我读了数百万条记录的快速插入,这是10万条记录。我假设我做了一些错误的事情,所以想澄清一下。 i7处理器与8 GB的RAM 64位操作系统是我的系统配置 – Vinoth 2014-09-11 07:10:16

回答

3

我想知道有多少你的程序循环和MERGE(而不是一个简单的INSERT)有助于性能不良。我会选择一个严格的基于集合的解决方案是这样的:

INSERT INTO dbo.Identifiers (Identifier) 
SELECT n FROM dbo.GetNums(500001, 600000) 
WHERE n NOT IN (SELECT Identifier FROM dbo.Identifiers); 

现在,这依赖于返回包含在列500,001和600,000的所有数字的表称为n用户定义的表值函数dbo.GetNums 。你怎么写这个功能?您需要在其中动态生成一系列数字。

以下实施摘自"Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions" by Itzik Ben-Gak一书。

CREATE FUNCTION dbo.GetNums(@low AS BIGINT, @high AS BIGINT) RETURNS TABLE 
AS 
    RETURN 
    WITH L0 AS (SELECT c FROM (VALUES(1),(1)) AS D(c)), 
     L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B), 
     L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B), 
     L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B), 
     L4 AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B), 
     L5 AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B), 
     Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rownum FROM L5) 
    SELECT @low + rownum - 1 AS n 
    FROM Nums 
    ORDER BY rownum 
    OFFSET 0 ROWS FETCH FIRST @high - @low + 1 ROWS ONLY; 

(因为这是来自一本书的SQL Server 2012上,它可能不是SQL Server 2008上工作外的开箱,但它应该是可以适应的。)

+0

这对我很好!我正在使用2012年 – Vinoth 2014-09-11 08:41:19

5

试试这个。它使用一个理货表。参考:http://www.sqlservercentral.com/articles/T-SQL/62867/

create table #temp_table(
    N int 
) 

declare @first as int 
set @first = 500001 
declare @step as int 
set @step = 1 
declare @last as int 
set @last = 600000 

with 
    e1 as(select 1 as N union all select 1), --2 rows 
    e2 as(select 1 as N from e1 as a, e1 as b), --4 rows 
    e3 as(select 1 as N from e2 as a, e2 as b), --16 rows 
    e4 as(select 1 as N from e3 as a, e3 as b), --256 rows 
    e5 as(select 1 as N from e4 as a, e4 as b), --65,356 rows 
    e6 as(select 1 as N from e5 as a, e1 as b), -- 131,072 rows 
    tally as (select 500000 + (row_number() over(order by N) * @step) as N from e6) -- change 500000 with desired start 
insert into #temp_table 
select cast(N as varchar(10)) 
from tally t 
where 
    N >= @first 
    and N <[email protected] 
    and not exists(
     select 1 from #temp_table where N = t.N 
    ) 

drop table #temp_table 
+0

真棒..它只需要一秒钟加载整个100,000条记录!谢谢,谢谢 – Vinoth 2014-09-11 07:37:58

+0

很高兴我能帮上忙。 – 2014-09-11 07:43:21

+0

尽管这个解决方案第一次工作得很好,但是当我运行脚本第二次时,这是一个合并,它花费了4分多钟(不知道需要多长时间,因为我在第4分钟停止了) – Vinoth 2014-09-11 08:40:35

0

在标识符列创建索引,然后尝试上面插入

+0

我不能那样做。它已经有一些记录 – Vinoth 2014-09-11 07:38:24

+0

那么在创建索引时有什么问题? – Yogesh86 2014-09-11 07:41:14

+0

我的意思是,表已经创建了索引。 – Vinoth 2014-09-11 08:22:28

2

Vinoth,下面给出的东西也可以帮助你。

Declare @tab table (id int identity(1,1),num int) 
Insert into @tab (num) Values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 

Declare @start as int 
set @start = 500000 

Insert into dbo.Identifiers (Identifier) 
Select @start + ((E.id-1)*10000) +((D.id-1)*1000) +((C.id-1)*100) + ((B.id-1) * 10) + A.id 
from @tab A,@tab B,@tab C,@tab D,@tab E 
Order by @start + ((E.id-1)*10000) +((D.id-1)*1000) +((C.id-1)*100) + ((B.id-1) * 10) + A.id 

在我的数据库,dbo.Identifiers是没有任何索引的表。只需要插入230 ms

相关问题