2010-10-11 35 views
2

我已经实现了一个导入功能,该功能从Asp.Net应用程序中的csv文件获取数据。大小的文件可以从几kb到最大10 MB不等。最快将csv导入到数据库表

但是,当导入发生时,如果文件大小> 50000大约需要20分钟。 这是太多的时间。我需要在2-3分钟的时间内进行大约300000条记录的导入。

我知道导入到数据库还取决于数据库服务器的物理内存。我创建批量插入脚本并执行。我也知道使用SqlBulkCopy也是另一种选择,但在我的情况下,它并不是插入产品,而是更新和删除,这是一个名为“FUNCTION CODE”的字段,它决定是否插入,更新或删除。

关于如何去做这个任何建议将不胜感激。

这样做的一种方法是实现多个线程同时执行进程,但是我从未实现线程直到日期,因此我不知道执行相同的操作会导致复杂化。

感谢&问候, 弗朗西斯P.

+3

你使用哪种数据库?大多数常见的DBMS产品都有自己的用于处理导入数据的实用程序。 – APC 2010-10-11 06:46:12

+1

线程只会在CPU限制问题时起作用。只是说... – Arafangion 2010-10-11 06:49:05

+0

那么有些东西还不清楚:它是“一次性导入吗?是通过asp.net上传的文件吗? – 2010-10-11 06:49:07

回答

1

我猜你正在使用SQL Server ...

如果您使用的2005/2008考虑使用SSIS处理文件。 Technet

在asp.net进程中导入大量的数据并不是你能做的最好的事情。你可能会上传文件并开始一个对你来说很神奇的进程。

0

如果这是一个重复的过程,并通过asp.net上传文件,您正在做一些决定插入/更新或删除数据的决定,然后尝试http://www.codeproject.com/KB/database/CsvReader.aspx这是这个快速CSV阅读器。它非常快速和经济的内存

+0

不需要使用外部代码.net有一个(鲜为人知)的CSV阅读器内置。http://stackoverflow.com/questions/2405787/csv-parser-in-one-routine-function – spender 2010-10-11 10:35:50

0

你正在做所有的数据库查询连续1个连接。因此,对于每次插入/更新/删除,您都通过电线发送命令,等待数据库执行该操作,然后在发送某些内容时再次唤醒。

数据库针对重度并行访问进行了优化。所以有两条简单的路线可以实现显着的加速:

打开X到数据库的连接(您必须调整X但只是从5开始),并启动5个线程,每个线程完成一个相同的工作你在做。 或:使用asynchronous calls以及回拨到达时在下一个查询中拍摄。

+0

我不'我认为这是一个很好的解决方案,因为这个问题提到了asp.net。你的解决方案在从asp.net进程开始的单独进程中是可以的。 – 2010-10-11 07:49:57

+0

@Yves - 文件是* uploa通过asp.net的ded *与它应该如何处理无关。 – 2010-10-11 08:28:34

+0

@Winston史密斯:真的。但它是asp.net过程中最有力的过程。因为没有另行说明。这是不好的时期。 – 2010-10-11 08:42:20

4

SqlBulkCopy肯定会变得最快。我会通过将数据插入数据库的临时表来解决这个问题。一旦数据在临时表中,您可以使用SQL来相应地合并/插入/删除。

+0

你只看过我的第一句话吗?你能详细说明为什么这不起作用吗?以某种方式表示插入和更新是完全可能的,以便可以通过在数据库上运行的SQL语句来解释它们。我的回答是将数据快速传输到SQL服务器的合理方法。我并不是建议将批量插入操作直接插入所需的表格中。我建议通过批量插入传输数据并使用DB上的逻辑来执行正确的操作。当然这会起作用。 – spender 2010-10-11 10:28:52

+0

答案仍然正确。将TABLE加载到TEMPDB中,然后使用MERGE语句(2008向上)将更改合并到主数据表中。 – TomTom 2010-10-11 10:43:09

0

我建议在SQL Server 2005/2008中使用XML功能,这将允许您批量插入和批量更新。我会采取以下方法:

  • 将整个文件处理为内存数据结构。
  • 从此结构创建单个XML文档以传递给存储过程。
  • 创建一个存储过程,将XML文档中的数据加载到临时表中,然后执行插入和更新。请参阅下面有关创建存储过程的指导。

有许多优点,以这种方式:

  • 整个操作在一个数据库调用完成,但如果你的数据集是真正的大,你可能要批的。
  • 您可以轻松地将所有数据库写入包装到单个事务中,并在出现任何问题时回滚。
  • 您没有使用任何动态SQL,这可能会带来安全风险。
  • 您可以使用OUTPUT子句返回插入,更新和/或删除记录的ID。

在存储过程,你需要的方面,像下面应该工作:

CREATE PROCEDURE MyBulkUpdater 
(
    @p_XmlData VARCHAR(MAX) 
) 

AS 
DECLARE @hDoc INT 
EXEC sp_xml_preparedocument @hDoc OUTPUT, @p_XmlData 

-- Temporary table, should contain the same schema as the table you want to update 
CREATE TABLE #MyTempTable 
(
    -- ... 
) 

INSERT INTO #MyTempTable 
(
     [Field1], 
     [Field2] 
) 
SELECT 
     XMLData.Field1, 
     XMLData.Field2 
FROM OPENXML (@hdoc, 'ROOT/MyRealTable', 1) 
WITH 
(
     [Field1] int, 
     [Field2] varchar(50), 
     [__ORDERBY] int 
) AS XMLData 

EXEC sp_xml_removedocument @hDoc 

现在,你可以简单地插入,更新和从你的临时表中删除你的真正的表按要求如

INSERT INTO MyRealTable (Field1, Field2) 
SELECT Field1, Field2 
FROM #MyTempTable 
WHERE ... 

UPDATE MyRealTable 
SET rt.Field2 = tt.Field2 
FROM MyRealTable rt 
JOIN MyTempTable tt ON tt.Field1 = MyRealTable.Field1 
WHERE ... 

对于需要传递的XML的一个例子,你可以这样做:

SELECT TOP 1 *, 0 AS __ORDERBY FROM MyRealTable AS MyRealTable FOR XML AUTO, ROOT('ROOT') 

欲了解更多信息,请参见OPENXML,sp_xml_preparedocumentsp_xml_removedocument