如何将800000记录插入MS Access表?

时间:2009-02-06 20:24:18

标签: delphi ms-access ado delphi-2007

我需要在MS Access表中插入800000条记录。我正在使用Delphi 2007和TAdoXxxx组件。该表包含一些整数字段,一个浮点字段和一个只有一个字符的文本字段。其中一个整数字段(不是autoinc)上有一个主键,另一个整数和float字段上有两个索引。

使用AdoTable.AppendRecord(...)插入数据需要> 10分钟是不可接受的,因为每次用户开始在程序中使用新数据库时都会这样做。我无法预填表,因为数据来自另一个数据库(无法通过ADO访问)。

通过将记录写入制表符分隔的文本文件并使用tAdoCommand对象执行

,我成功了大约1分钟
insert into table (...) select * from [filename.txt] in "c:\somedir" "Text;HDR=Yes"

但我不喜欢这个的开销。

我认为必须有更好的方法。

编辑:

其他一些信息:

  • 选择MS Access是因为它不需要在目标计算机上进行任何额外安装,并且整个数据库包含在一个可以轻松复制的文件中。
  • 这是一个单用户应用程序。
  • 数据只会插入一次,并且在数据库的生命周期内不会更改。但是,该表包含一个附加字段,该字段用作标志以指示用户已处理另一个数据库中的相应记录。
  • 一分钟 是可接受的(最多3分钟也是如此)并且我的解决方案有效,但对我来说似乎太复杂了,所以我认为应该有一种更简单的方法来做到这一点。 / LI>
  • 插入数据后,表的性能非常好。
  • 当我开始计划/实现使用Access数据库的程序的功能时,不需要该表。只有在客户要求另一个功能时才需要它。 (情况并非如此吗?)

编辑:

从我到目前为止得到的所有答案来看,似乎我已经有了将这么多数据插入Access表的最快方法。感谢大家,感谢您的帮助。

16 个答案:

答案 0 :(得分:9)

由于您已经说过800K记录数据在数据库的生命周期内不会改变,我建议将其作为表格链接到文本文件,并完全跳过插入。

如果您坚持将其拉入数据库,那么1分钟内的800,000条记录将超过13,000 /秒。我不认为你会在MS Access中击败它。

如果您希望它对用户更具响应性,那么您可能需要考虑加载一些最小的数据集,并设置后台线程以在其工作时加载其余数据。

答案 1 :(得分:5)

没有索引会更快。你可以在导入后添加它们吗?

此线程Slow MSAccess disk writing

中可能有许多建议

答案 2 :(得分:4)

如何跳过文本文件并使用ODBC或OLEDB直接从源表导入?这意味着要改变FROM子句以使用源表名和适当的连接字符串作为FROM子句的IN'部分。

编辑: 实际上我看到你说原始格式是xBase,所以应该可以使用作为Jet的一部分而不需要ODBC或OLEDB的xBase ISAM。这看起来像这样:

INSERT INTO table (...) 
SELECT * 
FROM tablename IN 'c:\somedir\'[dBase 5.0;HDR=NO;IMEX=2;];

您可能需要调整一下 - 我只是抓住指向DBF文件的链接表的连接字符串,因此参数可能略有不同。

答案 3 :(得分:3)

另一种安排怎么样......

是否可以选择创建具有此表所需的现有Access数据库文件的副本,然后删除除此一个大表之外的所有其他数据(不知道Access是否具有等效项)类似SQL Server中的“truncate table”?

答案 4 :(得分:3)

我会用另一个数据库替换MS Access,对于你的情况,我看到Sqlite是最好的选择,它不需要任何安装到客户端机器,它是非常快的数据库和最好的嵌入式之一数据库解决方案。

您可以通过两种方式在Delphi中使用它:

  1. 您可以从Sqlite网站下载数据库引擎Dll,并使用Free Delphi组件访问它,如Delphi SQLite componentsSQLite4Delphi

  2. 使用内置引擎的DISQLite3,您不必在应用程序中分发dll,它们有免费版本; - )

  3. 如果您仍然需要使用MS Access,请尝试直接使用TAdoCommand和SQL Insert语句而不是使用TADOTable,这应该比使用TADOTable.Append更快;

答案 5 :(得分:3)

您的基于文本的解决方案似乎速度最快,但如果您可以获得接近最终版本的预分配MS Access,则可以更快地获得它。您可以通过填充典型的用户数据库,关闭应用程序(以便刷新缓冲区)并手动删除该大表的所有记录来完成此操作 - 但不能缩小/压缩它。

因此,使用该文件启动实际填充 - Access不会请求任何(或极少)额外的磁盘空间。不要记得,如果MS Access有办法自动化这个,但它可以帮助很多......

答案 6 :(得分:2)

如有人提到的那样,你不会在不到一分钟内导入800,000条记录;那个真的已经很快了。

如果使用正确的方法(DAO记录集)进行插入,则可以跳过烦人的翻译到文本文件步骤。请参阅我在StackOverflow上提出并已回答的上一个问题:MS Access: Why is ADODB.Recordset.BatchUpdate so much slower than Application.ImportXML?

即使使用DAO也不要使用INSERT INTO;它很慢。不要使用ADO;它很慢。但DAO + Delphi + Recordsets +直接实例化DbEngine COM对象(而不是通过Access.Application对象)将为您提供更多的速度。

答案 7 :(得分:1)

你正在以一种方式寻找正确的方向。使用单个语句进行批量插入比尝试迭代数据并逐行插入更快。作为基于文件的数据库的访问在迭代写入中将非常慢。

问题在于Access正在处理它如何在内部优化写入,并且实际上没有任何方法可以控制它。您可能已达到INSERT语句的最大效率。为了提高速度,您应该评估每次启动应用程序时是否有任何方法可以将800,000条记录写入数据库。

答案 8 :(得分:1)

获取SQL Server Express(免费)并从Access外部表连接到它。 SQL express比MS Access快得多。

答案 9 :(得分:1)

我会预填充数据库,并将文件本身交给他们,而不是填充现有的(但是空的)数据库。

如果您要填充的数据发生变化,请使用一些代码在服务器上保持ODBC访问数据库(MDB文件)同步,以查看主数据库中的更改并将其复制到访问数据库。

当用户请求新数据库压缩MDB时,将其传输给他们,然后打开它。

或者,您可以找到打开的代码并直接将数据插入数据库。

或者,或者,您也可以找到另一种格式(csv除外),访问权限可以更快地导入。

- 亚当

答案 10 :(得分:0)

也许您可以使用锁定模式adLockBatchOptimistic和CursorLocation adUseClient打开ADO Recordset,将所有数据写入记录集,然后进行批量更新(rs.UpdateBatch)。

答案 11 :(得分:0)

还要检查复制文件所需的时间。这将是您写入数据的速度的下限。在db和SQL一样,它通常需要一个批量加载实用程序来接近这个速度。据我所知,MS从未创建过以bcp方式直接写入MS Access表的工具。专门的ETL工具还将优化插入周围的一些步骤,例如SSIS在内存中进行转换的方式,DTS同样有一些优化。

答案 12 :(得分:0)

如果它来自dbase,您可以直接复制数据和索引文件并直接附加而不加载吗?应该非常高效(来自为您带来FoxPro的人。)我想它也会使用现有的索引。

至少,它应该是一个非常有效的单命令导入。

答案 13 :(得分:0)

800,000条记录从一个创建到下一个创建的变化是多少?是否可以预先填充记录,然后在创建新数据库时更新外部数据库中已更改的记录?

这可以让您更快地创建新的数据库文件。

答案 14 :(得分:0)

你的磁盘转速有多快?如果它是7200RPM,那么在3分钟内800,000行仍然是每盘旋转37行。我认为你不会做得更好。

同时,如果目标是简化流程,表链接怎么样?

您说您无法通过ADO访问源数据库。您可以在MS Access中设置表链接到源数据库中的表或视图吗?然后,来自表链接的简单追加查询会将数据从源数据库复制到目标数据库。我不确定,但我认为这会很快。

如果在运行时之前无法设置表链接,也许可以通过ADO以编程方式构建表链接,然后以编程方式构建追加查询,然后调用追加查询。

答案 15 :(得分:-3)

HI 最好的方法是从文本文件中批量插入,如他们所说 您应该将您的记录插入到txt文件中,然后将txt文件批量插入表中 那个时间应该不到3秒。