加快插入 mdb

Posted

技术标签:

【中文标题】加快插入 mdb【英文标题】:Speed up insert mdb 【发布时间】:2010-02-11 23:34:44 【问题描述】:

有没有办法加快对 mdb 的插入?

 using (StreamReader sr = new StreamReader(_localDir + "\\" + _filename))
  while ((line = sr.ReadLine()) != null)

   //sanitize the data

这大约需要 20 秒来处理来自 csv 的约 200 万条记录 但是当我添加 mdb 插入时,我在 10 分钟内几乎无法获得 10,000 条记录,所以你可以看到它需要永远

 using (StreamReader sr = new StreamReader(_localDir + "\\" + _filename))
 while ((line = sr.ReadLine()) != null)

//sanitize the data
using (OleDbConnection con = new OleDbConnection(_conStr))
 using (OleDbCommand cmd = new OleDbCommand())
 cmd.Parameters.AddWithValue...//I have 22 params
cmd.ExecuteNonQuery();


有没有更好的方法?连接池?穿线? 这是我的 constr Provider=Microsoft.Jet.OLEDB.4.0;Data Source=mypath;Jet OLEDB:Engine 类型=5"

问候

_埃里克

【问题讨论】:

您需要将逻辑从一次插入一行更改为一次性插入整个批次。我不知道 C#,所以无法告诉您如何做到这一点,但在我看来,这似乎是您的代码与 CSV 导入之间存在差异的明显原因。我会说你最好的方法是@Remou 给出的方法。 【参考方案1】:

您是否可以使用直接从 csv 插入的查询?例如:

SELECT ID,Field1 INTO NewTable 
FROM [Text;HDR=YES;FMT=Delimited;IMEX=2;DATABASE=C:\Docs\].Some.CSV

您可以使用与非标准分隔符类似的东西,但您需要一个 Schema.ini 文件,该文件与要导入的文件位于同一目录中。它只需要包含:

[tempImportfile.csv]
TextDelimiter='

您将不得不稍微更改连接字符串,这似乎可行:

Text;HDR=YES;FMT=Delimited;DATABASE=C:\Docs\

【讨论】:

我会试一试,但是您知道将分隔符设置为逗号和单引号作为文本限定符的实际连接字符串吗? connectionstrings.com/textfile 不清除谢谢 FMT=Delimited 应该这样做。 以上是应该从 Access 连接运行的查询。 当我尝试 Select * into MyTable FROM [Text;HDR=YES;FMT=Delimited;IMEX=2;DATABASE=C:\\temp\\tempImportfile.csv] 我总是得到 ex.Message “Microsoft Jet 数据库引擎找不到输入表或查询 'Text;HDR=YES;FMT=Delimited;IMEX=2;DATABASE=C:\\temp\\tempImportfile.csv'。确保它存在并且它的名称拼写正确。”它就在那里。谢谢 您的方括号似乎放错了位置:[Text;HDR=YES;FMT=Delimited;IMEX=2;DATABASE=C:\temp\].tempImportfile.csv 连接字符串在 [] 作为 DB 和外部的文件作为 'table' 之间【参考方案2】:

Microsoft Jet 处理 Sql 解析(插入/更新)通常很慢。换句话说,您可能拥有最高效的代码,但瓶颈是 Jet。请记住,在您最初发布的每一行的连接(打开文件、创建锁、查找文件、插入行、释放锁、关闭文件、释放对象)中。需要连接ONCE(while外),读行,生成Sql(OleDbCommand),然后执行。

【讨论】:

这根本不是真的。如果你告诉它做正确的事情,Jet 对于这种事情通常非常快。据我了解,原始问题中的代码一次执行一行,这将比批量插入要慢得多(这是比较的重点)。任何数据库引擎在执行 200 万个单行插入时都会比在一批中插入 200 万行要慢。 我想看看你的基准与我的比较。我发现在与 Excel 或 Access 交谈时,通过 Interop 更快,完全绕过 Jet。如果我能看到 Jet 如何更有效率,那么我会轻而易举地接受我的反对票。关于批处理或无批处理,这不是我要解决的问题。请注意我对他打开/关闭(冲洗、重复)每一行的同一个 mdb 文件的方法的附加命令,以及这如何效率不高。 如果您正在访问 Access/Jet 数据,您不可能绕过 Jet!可以使用低效的方法与 Jet 通信并获得糟糕的性能,这就是原始问题中发生的情况(即,连续的单行插入,而不是批量插入)。【参考方案3】:

通过将循环移动到 using 块中,您可能会获得一些性能优势。创建 1 个连接/命令并执行 N 次,而不是创建 N 个连接/命令。

【讨论】:

using (StreamReader sr = new StreamReader(_localDir + "\\" + _filename)) using (OleDbConnection con = new OleDbConnection(_conStr)) using (OleDbCommand cmd = new OleDbCommand()) while (( line = sr.ReadLine()) != null) 并没有真正帮助,它在 1 分钟内完成了 275 条记录,但谢谢【参考方案4】:

另一个可能会加快速度的更改是一次性准备命令并创建所有参数。然后在循环中,只要给参数赋值,每次都执行。这可以避免每次迭代对语句的解析和语义检查,并且应该会缩短一些时间。但是,我认为这不会是一个显着的改进。语句解析应该占总开销的一小部分,即使每次都解析。

【讨论】:

谢谢,我想这就是我目前在使用 (OleDbCommand cmd = new OleDbCommand()) 之后尝试的方式我将 cmd 设置为 con 并打开它还将 cmd.command 文本设置为 INSERT INTO MyTable VALUES(@p1,@p2... 然后 b4 我在 while ((line = sr.ReadLine()) 中执行命令我执行 cmd.params.clear 并为当前行辞职。我什至可以循环除了 executenonquery 之外的所有内容,它非常活泼。没有 ExecuteNonquery,我可以在 32514 毫秒内循环 2m+ 条记录,当我添加 executeNonQuery 时,我每分钟得到 ~ 80000 @Eric:.mdb 文件是在本地驱动器上还是在网络驱动器上? 它是本地的。我已经放弃了这种方法,因为我可以在约 40 秒内读取->清理->写出 csv,然后只需调用 Process.Start("msaccess.exe",myNewFile) 并在不到一分钟的时间内完成所有操作 @Eric:酷。这样可行。很高兴您找到了一个快速的解决方案。【参考方案5】:

我在这里找到了一个很好的解决方案:Writing large number of records (bulk insert) to Access in .NET/C# 不要使用 OleDb,而是使用 DAO。

【讨论】:

以上是关于加快插入 mdb的主要内容,如果未能解决你的问题,请参考以下文章

向 MDB 插入和更新数据

从 MySQL 数据库插入 mdb

PHP, odbc mdb 插入最大 id +1

在 C# 中将 100 000 条记录插入 MDB 文件的最快方法是啥

需要帮助从 delphi 将新联系人插入访问 mdb

尝试使用 C# 和 OleDb 创建外键并将其值插入到 .mdb 数据库中