代码之家  ›  专栏  ›  技术社区  ›  Harold Bamford

如何从Perl快速访问许多大型csv文件中的数据?

  •  7
  • Harold Bamford  · 技术社区  · 17 年前

    我有许多脚本,目前从一些.csv文件中读取大量数据。为了提高效率,我使用 Text::CSV_XS 模块读取它们,然后使用其中一列作为索引创建哈希。但是,我有一个 许多 文件的数量很大。每个脚本都需要重新读取数据。

    问题是:我如何能够持久地存储这些Perl散列,以便在最少CPU的情况下读回它们?

    组合脚本不是一个选项。我希望…

    我应用了第二条优化规则并使用分析发现,绝大多数CPU(约90%)位于:

    Text::CSV_XS::fields
    Text::CSV_XS::Parse
    Text::CSV_XS::parse
    

    所以,我做了一个测试脚本,可以读取所有.csv文件( 正文::CSVX-XS ,使用 可储存的 模块,然后返回并使用 可储存的 模块。我对此进行了分析,以便了解CPU时间:

    $ c:/perl/bin/dprofpp.bat
    Total Elapsed Time = 1809.397 Seconds
      User+System Time = 950.5560 Seconds
    Exclusive Times
    %Time ExclSec CumulS #Calls sec/call Csec/c  Name
     25.6   243.6 243.66    126   1.9338 1.9338  Storable::pretrieve
     20.5   194.9 194.92 893448   0.0002 0.0002  Text::CSV_XS::fields
     9.49   90.19 90.198 893448   0.0001 0.0001  Text::CSV_XS::Parse
     7.48   71.07 71.072    126   0.5641 0.5641  Storable::pstore
     4.45   42.32 132.52 893448   0.0000 0.0001  Text::CSV_XS::parse
     (the rest was in terms of 0.07% or less and can be ignored)
    

    所以,使用 可储存的 正文::CSVX-XS 大约35%点。没有多少积蓄…

    有没有人对我如何更有效地阅读这些数据提出建议?

    谢谢你的帮助。

    5 回复  |  直到 17 年前
        1
  •  9
  •   Sinan Ünür    17 年前

    分析数据一次并将其放入 SQLite db . 查询使用 DBI .

        2
  •  11
  •   Brad Gilbert    17 年前

    在磁盘上放置非常大的哈希的最简单方法是 BerkeleyDB . 它速度快、经过时间测试且坚如磐石,CPAN模块提供了一个绑定的API。这意味着您可以像在内存中使用数据结构一样继续使用散列,但它将自动通过BerkeleyDB读写到磁盘。

        3
  •  3
  •   Harold Bamford    17 年前

    好吧,我接受了Sinan_n_¼R的建议(谢谢!)并创建了一个sqlite数据库,重新运行我的测试程序,将通过csv文件获取数据与从sqlite数据库获取数据进行比较:

    $ c:/perl/bin/dprofpp.bat
    Total Elapsed Time = 1705.947 Seconds
      User+System Time = 1084.296 Seconds
    Exclusive Times
    %Time ExclSec CumulS #Calls sec/call Csec/c  Name
     19.5   212.2 212.26 893448   0.0002 0.0002  Text::CSV_XS::fields
     15.7   170.7 224.45    126   1.3549 1.7814  DBD::_::st::fetchall_hashref
     9.14   99.15 99.157 893448   0.0001 0.0001  Text::CSV_XS::Parse
     6.03   65.34 164.49 893448   0.0001 0.0002  Text::CSV_XS::parse
     4.93   53.41 53.412 893574   0.0001 0.0001  DBI::st::fetch
       [ *removed the items of less than 0.01 percent* ]
    

    csv_xs的总数为34.67%,而sqlite的总数为20.63%,这比我以前尝试过的可存储解决方案要好一些。但是,这不是一个公平的比较,因为与csv_xs解决方案相比,我必须加载 整个的 csv文件,但是有了sqlite接口,我可以加载我想要的部分。因此,在实践中,我期望比这个简单的测试显示出更多的改进。

    我没有尝试用BerkeleyDB(抱歉,Friedo)代替sqlite,主要是因为在我参与sqlite的试用之前,我没有看到这个建议。设置测试是一项非常重要的任务,因为我几乎从来没有机会使用SQL数据库。

    不过,解决方案显然是将所有数据加载到数据库中,并通过DBI模块进行访问。谢谢大家的帮助。非常感谢所有的回应。

        4
  •  2
  •   bmdhacks    17 年前

    每次运行脚本时,最好不要将整个列表拖到内存中。使用磁盘上的数据库将允许您这样做。如果出于某种原因,每次运行时都必须触摸csv文件中的每个条目,我可能建议将其存储在RAM磁盘上,而不是物理磁盘上。它显然适合内存,我认为通过更改存储它的磁盘格式,您不会得到很大的改进。唯一真正加快速度的方法就是把它储存在一个更快的媒介上。

        5
  •  1
  •   Axeman maxelost    17 年前

    如果只需要访问每个脚本中的部分数据,而不需要访问全部数据, DBM::Deep 可能是你最好的选择。

    无论您做什么,磁盘/IO都可能是您最大的瓶颈。也许您可以使用一个数据提供程序将所有数据保存在一个mmap缓存中——使用类似的 Sys::Mmap::Simple 我从来没有必要做这种事,所以我没有其他的东西可以提供。