读取用于数据库导入的csv文件时,ColdFusion内存峰值

时间:2011-12-29 20:23:48

标签: csv coldfusion

我们有一个ColdFusion 9脚本,它定期运行读取CSV文件并将记录插入Oracle 11g数据库。 CSV文件大约有50列,其中8列由CF使用(CSV格式无法修改)。 CFM的一般流程是:

  1. 将文件读入变量
  2. CFLOOP使用该变量作为列表属性,CHR(13)作为分隔符
  3. 使用ListGetAt
  4. 调用从文件中插入各种值的Oracle存储过程

    存储过程执行以下操作:

    1. 将包含2个字段的记录插入表1
    2. 将包含8个字段(包括表1的主键)的记录插入表2
    3. 什么都不返回
    4. 在大多数情况下,这会成功运行,只需几秒钟即可读取包含数百条记录的400 KB文件。但是,偶尔我们会获得大量的音量并最终得到13k的5MB文件。当我们尝试处理这么大的文件时,我看到JVM内存使用量在10-15秒的时间内从90MB上升到大约680MB,之后CF服务器监视器停止响应(CF也是如此),迫使我们重新启动服务。日志报告JVM内存不足错误:

        

      “错误”,“qtp4795249-38798”,“12/28/11”,“16:29:20”,,“超出GC开销限制”       java.lang.OutOfMemoryError:超出GC开销限制

      我们的JVM堆大小目前为768MB。我没有尝试增加它,因为即使它确实解决了这个问题,它也不会在未来保护我们,而服务器的其余正常负载并不需要那么多。我对使用需要重启才能在生产盒上生效的JVM设置犹豫不决。

      这很难测试,因为导入过程在我的本地开发机器和QA盒子上几乎没有明显的内存负载运行良好,但是这两者与数据库的连接速度要慢得多,需要10-15分钟到完整。

      我会很感激任何想法,特别是关于记忆的去向。我无法弄清楚5MB的数据如何变成700 MB的数据。我们确实打开了调试信息,但调用脚本的IP地址不在调试列表中,我使用cfsetting标签关闭此页面的调试。以前有一个步骤1.5将CSV数据转换为ColdFusion查询,但我为了提高效率而消除了这一点。两种方式都会导致错误。

4 个答案:

答案 0 :(得分:1)

不是在开始处理之前将整个文件读入内存,而是通过一次读取一行来遍历文件内容。 Ben Nadel(当然)有一篇很好的博客文章讨论这种技术:

Reading In File Data One Line At A Time Using ColdFusion's CFLoop Tag Or Java's LineNumberReader

另请参阅livedocs for cfloop,特别是文件attribtue:

答案 1 :(得分:1)

您是否考虑过直接导入数据库?对于MySQL,这是LOAD DATA INFILE,对于SQL Server,它是BULK INSERT。如果您需要一些额外的处理,那么可能的方法是将数据加载到临时表中,然后使用CFML处理它,这可以很容易地分批完成,以便进行繁重的处理。

答案 2 :(得分:0)

我们有一个CF应用程序进口房地产MLS列表并遇到类似的问题。我们使用的核心文件是推送100MB,读取它并立即循环它会产生很多问题。我们最终做了一些事情:

  1. 将文件拆分为块。导入过程使用cygwin中的split.exe实用程序将文件拆分为4,000个行块。然后我们使用CFDIRECTORY获取块的列表并一次处理一个块。

  2. 对于每个块,我们读取它,然后将文件内容拆分为一个数组(使用listToArray(),chr(13)作为分隔符。)

  3. 我们从1循环到arrayLen(chunkArray),而不是直接循环遍历文件内容。这比速度更快。在该循环中,我们还将每一行分成一个数组。我们发现这样做并访问值为thisRow [i](其中i是文件中的列号)比重复调用listGetAt()要快得多。我们导入的文件有90多列。

  4. 我们增加了JVM内存容量。我们的服务器非常繁忙,这增加了一些开销。我们最终将JVM推到了32位服务器(大约2GB)的最高位置,以便在需要时可以使用内存。

答案 3 :(得分:0)

另请参阅不循环查询。执行查询所花费的大部分时间只是建立数据库连接。

任何时候我必须从文件中执行这样的多次插入,我创建每个SQL插入语句并将它们保存在由分号分隔的变量中。然后,我每100个语句一次执行所有这些语句。

我不得不通过这样做来重写另一个程序员的一些程序,并且能够将处理时间缩短90%。这是在版本6中,因此连接共享可能会改善这一点。