【问题标题】:Why PHP Mysql multi_query() is slower than loop query()为什么 PHP Mysql multi_query() 比循环查询() 慢
【发布时间】:2016-06-02 13:51:21
【问题描述】:

我正在使用 MySQL 开发 HHVM。我很困惑地发现使用 multi_query() 批处理 2000 个 sql 查询比使用单个 query() 的 2000 个循环慢得多(请参阅最后的代码和结果)。通过进一步分析,我发现 API next_result() 占用了大部分时间(~70%)。

我的问题是:
(1) 为什么 API next_result() 这么慢?
(2) 如果我想一起做成千上万个 sql 查询,有没有比天真的循环更好的方法?
谢谢!

这里是代码(php):

$conn = new mysqli("localhost", "root", "pwd", "table");

$loop = 2000;
$q = "select * from ContactInfo;";

// single query in a loop
$results = array();
$sq_start = microtime(true);
for ($i=0; $i < $loop; $i++) {
  $ret = $conn->query($q);
  $results[] = $ret;
}
for ($i=0; $i < $loop; $i++) {
  $xx = $results[$i]->fetch_all();
}
$sq_end = microtime(true);

// construct the multi-query
for ($i=0; $i < $loop; $i++) {
  $m_q .= $q; 
}

// multi-query in one round-trip
$mq_start = microtime(true);
$conn->multi_query($m_q);
do {
  $ret = $conn->store_result();
  $xx = $ret->fetch_all();
} while($conn->next_result());
$mq_end = microtime(true);

echo "Single query: " . ($sq_end - $sq_start)*1000 . " ms\n";
echo "Multi query: " . ($mq_end - $mq_start)*1000 . " ms\n";

结果如下:

Single query: 526.38602256775 ms
Multi query: 1408.7419509888 ms

注意:在这种情况下,next_result() 将消耗 922 毫秒。

【问题讨论】:

  • 如果您正在执行数千个相同的查询(仅更改参数,如果有的话),您将使用 PHP 的 PDO 库中的预处理语句获得最佳性能
  • @MatthewHerbst 所以你会说用 PHP 的 mysqli 库准备的语句不是那么快吗?
  • @MatthewHerbst 感谢您的建议,我刚刚尝试了 mysqli::prepare() API,稍后将尝试 PDO。分享一些感受:使用 prepare() 在 HHVM 中获得想要的结果真的很难(如果不是不可能的话),原因如下:(1)HHVM 不支持 mysqli_stmt::get_result() API (2) For "select * . .." 查询,mysqli_stmt::bind_result() API 很难使用。
  • 是的,如果你不能让 mysqli 工作,试试 PDO,虽然 PDO 会迫使你学习一种稍微新的做事风格,因为 PDO 没有程序风格,只有对象-导向的。就您的麻烦而言,请确保您在调用bind_result()“在mysqli_stmt_execute() 之后和在调用mysqli_stmt_fetch() 之前”

标签: php mysql mysqli multi-query


【解决方案1】:

这里最简单的答案是开销。 multi_query() 为每个结果集构建一个数据对象。然后它必须一遍又一遍地存储该对象。

相比之下,您一遍又一遍地运行相同的查询,但只编写一个简单的数据数组来存储结果。然后 PHP 可以释放上一个结果集的内存,因为您不断地覆盖同一个变量(一旦数据对象在内部没有任何指向它的对象,它可以是 garbage collected)。

不过,这不是一个很好的用例。这里没有真实世界的应用程序,因为不需要一遍又一遍地运行相同的查询(您的数据库应该缓存第一次运行的结果,然后将数据存储在内存中以更快地检索)。 对于单个结果集,这里的差异可以忽略不计。

【讨论】:

  • 感谢您的回答。但令人怀疑的是,即使是“一遍又一遍地复制”也会花费 900 毫秒。内存复制超级快。我检查了 HHVM 的源代码,并确认 HHVM 除了调用 MySQL 的 C API mysql_next_result() 之外什么都不做。
  • 是的...但是您一遍又一遍地存储 object 与一遍又一遍地存储 array 。是的,内存复制速度很快,但是您必须一遍又一遍地处理每个对象。这将涉及一些开销
猜你喜欢
  • 1970-01-01
  • 2017-11-09
  • 2015-10-07
  • 1970-01-01
  • 2019-12-08
  • 1970-01-01
  • 2015-02-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多