我正在实现从一个数据库到另一个数据库的特定于应用程序的数据导入功能。
我有一个包含10000行的CSV文件。这些行需要插入/更新到数据库中。
在某些情况下,数据库中可能存在几行,这意味着需要更新这些行。如果数据库中不存在,则需要将其插入。
一种可能的解决方案是,我可以一行一行地读取,检查数据库中的条目并相应地构建插入/更新查询。但是此过程可能会花费很多时间来创建更新/插入查询并在数据库中执行它们。有时我的CSV文件可能有数百万条记录。
还有其他更快的方法来实现此功能吗?
我正在实现从一个数据库到另一个数据库的特定于应用程序的数据导入功能。
我有一个包含10000行的CSV文件。这些行需要插入/更新到数据库中。
在某些情况下,数据库中可能存在几行,这意味着需要更新这些行。如果数据库中不存在,则需要将其插入。
一种可能的解决方案是,我可以一行一行地读取,检查数据库中的条目并相应地构建插入/更新查询。但是此过程可能会花费很多时间来创建更新/插入查询并在数据库中执行它们。有时我的CSV文件可能有数百万条记录。
还有其他更快的方法来实现此功能吗?
Answers:
Oracle中有一项很好的技术,称为外部表。在您的方案中,您可以使用数据库中的“外部表”访问外部纯文本数据,并使用您喜欢并习惯的SQL语句更新数据库中的现有数据,例如INSERT
,MERGE
等等。
在大多数情况下,使用Oracle提供的实用程序是执行ETL的最佳方法。并且由于您的问题听起来更像是管理问题,因此建议您查看我先前在DBA Stack Exchange上发表的文章“从CSV更新Oracle数据库”。
更新:这种方法非常适合读取数据库中的外部数据。通常,每次需要处理具有新格式的纯文本文件时,都定义外部数据格式。创建外部表后,您可以像查询真正的数据库表一样对其进行查询。每当有新数据要导入时,您都可以即时替换基础文件,而无需重新创建外部表。由于可以像查询任何其他数据库表一样查询外部表,因此可以编写SQL语句来填充其他数据库表。
与使用手动实现的其他技术相比,使用外部表的开销通常较低,因为该技术在设计时考虑到了Oracle数据库体系结构的性能。
我认为您应该使用SQL * Loader将CSV文件加载到临时表中,然后使用MERGE语句将数据插入到工作表中。
与外部表相比,SQL * Loader将为您提供更大的灵活性,如果使用直接路径加载,则它的速度确实非常快。MERGE将完全满足您的需求-插入新记录并更新现有记录。
几个开始的链接:
http : //docs.oracle.com/cd/B19306_01/server.102/b14215/ldr_concepts.htm
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016 .htm
PreparedStatement将使创建插入或更新查询的速度非常快。您应该具有三个PreparedStatements
:一个用于插入,一个用于更新,以及一个用于检查表中是否已存在该行。如果您能够使CSV文件和新数据库之间的ID保持相同,则使用primaryID字段检查是否存在一行也应该非常快。
使用批处理插件可以提高性能。在流过CSV文件时,您将检查该行是否已经存在,然后进行更新或将该行添加到批处理插入命令中。您应该检查此SO问题以比较这两种方法的速度。
如果使用我上面概述的方法需要定期进行此数据库导入,而性能是一个问题,那么您可以尝试使用多个工作线程来处理任务。使用与运行此代码的计算机上的处理器一样多的线程。
int nThreads = Runtime.getRuntime().availableProcessors();
每个线程都有自己的数据库连接,并且随着您的代码遍历整个文件,可以将CSV行传递给各个线程。这要复杂得多,所以只有在性能要求迫使我这样做的情况下,我才这样做。
OutOfMemory
!