加快CSV文件的处理速度

时间:2011-05-22 19:47:11

标签: c++ multithreading performance csv mpi

我有一个项目,我必须提高其性能。我有一个庞大的Mysql数据库,由一个巨大的CSV文件(1亿行)构成。插入时间不是问题,但请求的响应时间非常重要,有时使用2个连接的查询大约需要20个小时......

在减少响应时间的目标中,我尝试将数据库迁移到Cassandra但没有成功:我的数据模型不适合Cassandra概念。然后我想尝试另一种方法来提高性能:并行虚拟文件系统。而是在Mysql数据库中插入数据并发送然后发送查询,我试图用多线程读取整个csv文件并完成我的计算。但结果并不好:2m20s只有1 000 000行。

目前,我的计算非常简单:在使用MPI-IO API的C ++中,我只计算2列中的不同对数值。为了进行计算,我使用了一个hashmap,其中每个键都是来自csv文件的一对值。最后,我返回hashmap大小。 这是一个小代码:

 MPI::Init(argc,argv); 
 cout << " INFO init done" << endl;
 int myrank = MPI::COMM_WORLD.Get_rank(); 
 int numprocs = MPI::COMM_WORLD.Get_size(); 
 get_filename(path_name, myrank);
 cout << " INFO open file : " << path_name << endl;
 MPI::File thefile = MPI::File::Open(MPI::COMM_WORLD, path_name.c_str(), 
                  MPI::MODE_RDONLY, 
                  MPI::INFO_NULL); 
 MPI::Offset offset = 101;
 MPI::Offset limit = thefile.Get_size();
 cout << " INFO go computing" << endl;
 do {
   thefile.Read_at(offset, buf, bufsize, MPI_CHAR, status);
   temp.assign(buf);
   Tokenize(temp,tokens,"\n");
   line.assign(tokens.at(0));
   tokens.clear();

   Tokenize(line,tokens,"\t");
   nidt_count(tokens);
   tokens.clear();
   offset += (line.size() + 1);
 }while(offset < limit);
 count = status.Get_count(MPI_INT);
 cout << "process " << myrank << " reads " << nidt_hash.size() << " nidt" << endl; 

我在一个4核,8GB内存的服务器上工作。我的数据是在我的服务器上安装在NFS或Samba上的NAS上。我可以添加2或3个服务器进行处理,但目前我只是在一台服务器上尝试了一个小文件(1百万行)来测量性能。

最后我的问题是:

  • 考虑到我的问题,改为PVFS是一种好方法吗?我想说我会处理更复杂的查询,例如:选择具有特定日期(范围小时)的所有行,以及来自特定列的特定对值。
  • 你知道其他可以帮助我改进csv文件处理的东西吗?我想使用Hadoop,Pytables或FasterCSV。

这是我的数据样本,由2个csv文件组成:

最大的(1亿行)组成如下:

ID        DATE             NUM_1        NUM_2     NB_UNITE TYPUNIT CODE_1 CODE_2

0  2007-05-13 15:37:48  33671624244  33698802900    547      s       0      17
0  2007-05-13 15:52:22  33671624244  33672211799      5      s       0      17 
....

第二个更简单,更小(90 000),它就像一个字典,从code_1code_2我得到一个名为CODEVAL的值:

CODE_1 CODE_2 CODEVAL

  0       17     VS
  0       34     SS

正如您所料,通常我为每个文件创建一个表,一个典型的查询是:

Select CODEVAL, hour(date) AS HEURE, COUNT(*) AS NBSMSSOR 
From Tables_1 Join CODEVAL using(CODE_1,CODE_2) 
Where CODEVAL='SS'

对于演示文稿感到抱歉,我不知道如何制作阵列。


这是我的数据样本,由2个csv文件组成:

  • 最大的一个(1亿行)组成如下:

    ID DATE NUM_1 NUM_2 NB_UNITE TYPUNIT CODE_1 CODE_2

    0 2007-05-13 15:37:48 33671624244 33698802900 547 s 0 17
    0 2007-05-13 15:52:22 33671624244 33672211799 5 s 0 17 ....

  • 第二个更简单,更小(90 000),它就像一个字典,从code_1和code_2我得到一个名为CODEVAL的值:

    CODE_1 CODE_2 CODEVAL

    0 17 VS

    0 34 SS

正如您所料,通常我为每个文件创建一个表,一个典型的查询是:

  • 选择CODEVAL,小时(日期)AS HEURE,COUNT(*)作为NBSMSSOR 来自Tables_1 使用(CODE_1,CODE_2)加入CODEVAL 其中CODEVAL ='SS'

对于演示文稿感到抱歉,我不知道如何制作阵列。

3 个答案:

答案 0 :(得分:2)

在我看来,就像你受到I / O限制一样。您的数据通过网络无济于事。我怀疑如果你只是添加更多的机器,那么由于额外的争用,你的性能将会下降。请记住,仍然只有一个主轴和一个HD头读取您的数据。对于MPI解决方案,我建议制作多个数据副本并将它们放在服务器上。

对于MySQL,我听到你在说什么。我发现MySQL的连接效率非常低。我看起来像是在没有它们的情况下可以离开时进行全表扫描。我记得MySQL在一个查询上花了一分钟,甲骨文需要不到一秒钟。也许试试PostgreSQL?我不确定它是否更好。 另一种方法可能是让db为您排序数据,以便您可以在没有hashmap的情况下进行扫描。

除非你的记录是巨大的,否则100M记录不应该那么糟糕。

答案 1 :(得分:0)

如果您从CSV中读取数据,我认为它不会经常更改。因此,您可以在CSV数据上构建自己的索引,而不是将其加载到通用数据库产品中。或者您是否需要完整的SQL支持?

除此之外,您提到要返回不同K,V-Pairs的NUMBER。但是,您确实计算了实际的对。我不知道你是否需要它们用于其他目的,但你也可以将这个数字作为#distinctKeys x #distinctValues而不用实际构建HashMap。

假设您为表单的每个列构建索引

value -> {r | r is a byteOffset of a row that has "value" in the index column}

你可以回答很多很多查询,尤其是确定不同对的数量应该只需要几毫秒。

我希望这个答案很有帮助,因为我不确定必须满足哪些其他要求。这个解决方案的功能明显不如支持SQL的数据库(特别是插入会使事情变得复杂得多),但至少确定不同对的数量应该快几个数量级

答案 2 :(得分:0)

分而治之    一百个小型数据库应该更快。    你决定如何分解它 - 使用split()或slice()    我目前正在使用每行第一个单词的第一个字符,所以曾经有一个巨大的慢DB现在(A - Z + a - z + 0 - 9)62个小的更快的数据库。另一个优点是,笔记本电脑现在可以完成只有功能强大,价格昂贵的PC才能完成的工作