2014-12-04 67 views
5

最近我的任务是进行一些速度检查,以便我可以判断使用php/php-cli或C++将特定数量的行插入数据库的速度是否更快。MySQL的插入速度比PHP更快,这是预期的吗?

在我们开始之前,让我告诉你一些细节,让一切都清楚了:

  • PHP的一部分是通过运行Apache,在浏览器中直接提出要求。
  • 正在运行的硬盘驱动器测试是SSD驱动器。我猜在普通硬盘中事情会变慢。机器本身没什么特别的,六岁左右。
  • 所有插入操作都是通过准备好的语句完成的。我们使用php上的mysqli和mysqlcppconcon(由Oracle提供的mysql C++连接器)。
  • 所有插入都按条目输入。我知道我们可以堆叠它们,但是我们正在测试。
  • 时间通过microtime在php中显示,并通过C++头文件显示。
  • 当然,代码本身并不等同。稍后更多。
  • 所有文本都是UTF-8。那里有俄罗斯,中国,阿拉伯,西班牙,英国和各种疯狂的东西。 mysql表格在utf8_4mb中。
  • C++代码的数字是使用g ++编译的std :: vector和-O2 levels的结果(向量优于maps,unordered_maps和std :: arrays)。

所以,这是过程:

  • 连接到数据库。
  • 用N行打开一个文本文件。
  • 阅读文件的一行。
  • 拆分分隔符上的行。
  • 使用分割线的某些部分来获取插入值(例如,0,1和3索引)。
  • 将这些零件发送到准备好的语句以插入它们。
  • 重复,直到完全读取文件。

两个代码的工作方式与预期完全相同。下面是导致数字:

PHP:

  • 5000个条目:1.42 - 1.27秒。
  • 20000条目:5.53-6.18秒。
  • 50000条目:14.43-15.69秒。

C++:

  • 5000个条目:1.78 - 1.81秒。
  • 20000条目:7.19 - 7.22秒。
  • 50000条目:18.52-18.84秒

php优于C++,因为文件中的行数增加......起初,我怀疑行分裂函数:在PHP中的分裂是用“爆炸”完成的。该算法与C++一样天真......容器通过引用传递,其内容随时更改。该容器仅被遍历一次。我确保容器“保留()”所有必要的空间(记住,我最终选择向量),这是固定的。容器在主函数上创建,然后通过代码通过引用传递。它永远不会被清空或调整大小:只有其内容发生变化。

template<typename container> void explode(const std::string& p_string, const char p_delimiter, container& p_result) 
{ 
    auto it=p_result.begin(); 
    std::string::const_iterator beg=p_string.begin(), end=p_string.end(); 
    std::string temp; 

    while(beg < end) 
    { 
     if((*beg)==p_delimiter) 
     { 
      *(it)=temp; 
      ++it; 
      temp=""; 
     } 
     else 
     { 
      temp+=*beg; 
     } 

     ++beg; 
    } 

    *(it)=temp; 
} 

如前所述,执行的任务是等效的,但生成它的代码不是。 C++代码具有通常的try-catch块来控制mysql的交互。至于其余部分,主循环一直运行到EOF到达,并且每次迭代检查插入是否失败(无论是在C++还是php中)。

我已经看到C++在处理文件和它们的内容方面大大优于php,所以我期望在这里适用。不知何故,我怀疑分裂算法,但也许它只是数据库连接器速度较慢(仍然,当我禁用数据库交互PHP仍然处理更快)或我的代码是sub par ...

至于分析, gprof的吐出了这一点,关于C++代码:

Each sample counts as 0.01 seconds. 
    % cumulative self    self  total   
time seconds seconds calls ns/call ns/call name  
60.00  0.03  0.03 50000 600.00 600.00 void anc_str::explotar_cadena<std::vector<std::string, std::allocator<std::string> > >(std::string const&, char, std::vector<std::string, std::allocator<std::string> >&) 
40.00  0.05  0.02        insertar(sql::PreparedStatement*, std::string const&, std::vector<std::string, std::allocator<std::string> >&) 
    0.00  0.05  0.00  1  0.00  0.00 _GLOBAL__sub_I__ZN7anc_str21obtener_linea_archivoERSt14basic_ifstreamIcSt11char_traitsIcEE 

其中“explotar_cadena”是“爆炸”和“insertar”是“拆分此行并设置事先准备好的声明了”。正如你所看到的,有60%的时间花在那里(并不令人惊讶......它运行了50000次,并且做了这个疯狂的分裂事情)。 “obtener_linea_archivo”只是“请将下一行转储到字符串中”。

没有MySQL的相互作用(只是加载文件,读取线和分割他们)我得到这些测量:

PHP

  • 5000个条目:0.019 - 0.036秒。
  • 20000个条目:0.09-0.10秒。
  • 50000个条目:0.14-0.17秒

C++

  • 5000个条目:0.07 - 0.10秒。
  • 20000个条目:0.25 - 0.26秒。
  • 50000个条目:0.49-0.55秒。

好吧,这两个时代都很好,现实生活中还很难察觉,我很惊讶...所以这里的问题是:我应该期待这个吗?有经验的人愿意伸出援助之手吗?

在此先感谢。

编辑:这里是一个包含输入文件,C++代码和php代码的精简版的快速链接[http://www.datafilehost.com/d/d31034d6]。注意,没有sql交互:只有文件打开,字符串分割和时间测量。请原谅匆忙完成的屠杀代码和半西班牙语评论和变量名称。另外,请注意上面的gprof结果:我不是专家,但我认为我们试图找到一种更好的分割字符串的方法。

+0

你能否认为用[Very Sleepy](http://www.codersnotes.com/sleepy)来测试你的C++程序并在这里添加结果。 – 2014-12-04 10:29:24

+0

不是窗户的人在这里,对不起...我试过gprof。将编辑帖子以反映这一点。 – 2014-12-04 10:35:51

+1

从代码中删除定时器,使用控制台上的系统时间命令来获取测量结果。您不包括PHP的启动和关闭时间,结果偏差。 – 2014-12-04 10:57:23

回答

1

它的某些部分可能与每种语言中使用的驱动程序/接口有关。例如,在PHP/MySQL中,您可能会发现mysqli比mysql更快,这比PDO快。这是因为图书馆逐渐更抽象(或更少维护)。您可以尝试在数据库服务器上自行分析查询,以查看执行时间是否有任何差异。然而,正如其他评论者指出的那样,可能还会有更多的事情发生。

+0

非常感谢您的回答。我想我可以假设实现本身有更多的层次,因此速度更慢。尽管如此,没有任何数据库交互,我用PHP获得了更好的数字(正如你在编辑的问题中看到的那样)。如前所述,C++代码似乎比简单的php代码生成更多的指令。 – 2014-12-09 08:02:07