MySQL插入,PHP比C++更快,这是预期的吗?

The*_*Man 5 php c++ mysql performance

最近我的任务是做一些速度检查,所以我可以判断是否更快使用php/php-cli或c ++将一定数量的行插入数据库.

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

  • php部分通过Apache运行,直接在浏览器中请求.
  • 正在运行的硬盘驱动器测试是SSD驱动器.我猜常规驱动器的速度会慢一些.这台机器本身并不特别,六年左右.
  • 所有插入都是通过准备好的声明完成的.我们在php和mysqlcppconn(由Oracle提供的mysql c ++连接器)上使用mysqli.
  • 所有插入都是通过输入完成的.我知道我们可以叠加它们,但我们正在这里进行测试.
  • 时间通过php中的microtime和c ++中的header显示.
  • 当然,代码本身并不等同.稍后会详细介绍.
  • 所有文本都是UTF-8.那里有俄语,中文,阿拉伯语,西班牙语,英语和各种疯狂的东西.mysql表位于utf8_4mb中.
  • c ++代码的数字是使用std :: vector和-O2级别用g ++编译的结果(向量优于map,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 ++一样天真......容器通过引用传递,其内容随时更改.容器只遍历一次.我确保容器"reserve()"所有必要的空间(记住,我最终选择向量)是固定的.容器在main函数上创建,然后通过代码通过引用传递.它永远不会被清空或调整大小:只有它的内容会改变.

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;
}
Run Code Online (Sandbox Code Playgroud)

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

我已经看到c ++在处理文件及其内容方面大大优于php,所以我希望在这里适用.不知怎的,我怀疑分裂算法,但也许只是数据库连接器速度较慢(仍然,当我禁用数据库交互时php仍然处理得更快)或者我的代码是低于...

对于分析,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
Run Code Online (Sandbox Code Playgroud)

其中"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结果:我不是专家,但我认为我们正试图找到一种更好的方法来分割字符串.

Ixa*_*ida 1

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