2009-09-06 49 views
3

我需要编写一些代码来插入大约300万行数据。
同时我需要插入相同数量的伴随行。什么是快速插入SQL数据和相关行的最佳方式?

I.e.模式是这样的:

Item 
    - Id 
    - Title 

Property 
    - Id 
    - FK_Item 
    - Value 

我第一次尝试是一件隐约这样的:

BaseDataContext db = new BaseDataContext(); 
foreach (var value in values) 
{ 
    Item i = new Item() { Title = value["title"]}; 
    ItemProperty ip = new ItemProperty() { Item = i, Value = value["value"]}; 
    db.Items.InsertOnSubmit(i); 
    db.ItemProperties.InsertOnSubmit(ip); 
} 
db.SubmitChanges(); 

显然,这是非常缓慢的,所以我现在用的是这样的:

BaseDataContext db = new BaseDataContext(); 
DataTable dt = new DataTable("Item"); 
dt.Columns.Add("Title", typeof(string)); 
foreach (var value in values) 
{ 
    DataRow item = dt.NewRow(); 
    item["Title"] = value["title"]; 
    dt.Rows.Add(item); 
} 
using (System.Data.SqlClient.SqlBulkCopy sb = new System.Data.SqlClient.SqlBulkCopy(db.Connection.ConnectionString)) 
{ 
    sb.DestinationTableName = "dbo.Item"; 
    sb.ColumnMappings.Add(new SqlBulkCopyColumnMapping("Title", "Title")); 
    sb.WriteToServer(dt); 
} 

但是这不允许我添加相应的'Property'行。

我在想最好的解决方案可能是添加一个像this one这样的存储过程,它通常允许我进行批量插入(或者至少多次插入,但我可能会以某种方式禁止在存储过程中记录性能)以及然后返回相应的ID。

任何人都可以想到更好的(即更简洁,几乎相同的性能)解决方案吗?

回答

3

要结合前面的两个最好的答案,并添加所缺件的标识:

1)使用BCP将数据加载到这样

CREATE TABLE stage(Title AS VARCHAR(??), value AS {whatever}); 

定义一个临时的“临时”表而你所需要的性能以后适当的索引:

CREATE INDEX ix_stage ON stage(Title); 

2)使用SQL INSERT加载项表:

INSERT INTO Item(Title) SELECT Title FROM stage; 

3)通过与项目结合阶段最后加载属性表:

INSERT INTO Property(FK_ItemID, Value) 
SELECT id, Value 
FROM stage 
JOIN Item ON Item.Title = stage.Title 
+0

当然,但是这个假设标题是独一无二的(它可能是,但我不会依赖它,但这可能是最好的方向 – 2009-09-06 15:12:11

+0

我不得不承担一些,因为你没有提供源表的信息。你必须有一些方法来唯一地关联信息:依赖于记录顺序在SQL中是无效的 – RBarryYoung 2009-09-06 21:18:40

+0

也就是说,你可以在登台表上添加一个用于关联的ID(通常即使在顺序依赖关系下也可以),但它可以获得更复杂 – RBarryYoung 2009-09-06 21:19:54

3

将大量数据移入SQL Server的最佳方式是bcp。假设数据以某种文件形式开始,您需要编写一个小脚本将数据汇集到两个表中。或者,您可以使用bcp将数据汇集到一个表中,然后使用SP将数据插入到两个表中。

+0

问题是,我无法将第二批数据“汇集”到一张表中,而没有在第一个表中使用相应的ID。我想一个解决方案是分配一个虚假的ID,然后删除这个,但这似乎不是一个长期做这件事的好方法。 – 2009-09-06 13:32:40

+0

感谢指向我bcp,但看起来很有用。 – 2009-09-06 13:33:16

+0

+1指向BCP – RBarryYoung 2009-09-06 13:59:31

2

将数据批量复制到一个临时表中,然后调用一个存储过程,该过程将数据拆分为需要填充的两个表。

+0

谢谢,可能是最好的方法。 – 2009-09-06 13:42:02

+0

+1:加入使用BCP,除非你有充分的理由不这样做(这大约比SQLBulkCopy快大约30%),这就是SOP的答案。 – RBarryYoung 2009-09-06 13:45:36

+0

是的,如果可以,请使用BCP超过批量复制。 – Joe 2009-09-06 15:28:54

2

您可以在代码中批量复制,以及使用.NET SqlBulkCopy类。

+0

我使用.NET SqlBulkCopy类,你可以指向我应该看的地方? – 2009-09-06 15:10:53

+2

如果您完全控制了数据,也许您可​​以利用SqlBulkCopyOptions的KeepIdentity选项构造函数的参数。这样,您就可以获取当前可用的最高身份值,并从那里开始工作。 – 2009-09-06 15:20:38

+0

谢谢大卫......这只是帮助我。 – John 2009-09-09 21:25:20

相关问题