7

当 Sebastien 说他在每次使用mysqli_multi_query()@ Can mysqli_multi_query 执行 UPDATE 语句之间断开连接和重新连接时,我感到畏缩?因为这似乎不是最佳实践。

但是,Craig @ mysqli multi_query 后跟 query在他的案例中表示,在每次使用之间断开和重新连接mysqli_multi_query()比使用mysqli_next_result().

我想问一下,当程序员应该选择“新连接”还是“下一个结果”方法时,是否有人有进一步的第一手知识或基准证据来建议一个近似的“截止”(基于查询量或其他东西)。

我也很高兴听到与速度无关的任何/所有问题。Craig 使用连接函数对速度有影响吗?

Craig 的 while 语句之间是否存在速度差异:

while ($mysqli->next_result()) {;}

- 相对 -

我建议的 while 声明:

while(mysqli_more_results($mysqli) && mysqli_next_result($mysqli));

- 相对 -

在首先运行之前为每个预期的 multi_query 创建一个新连接multi_query。我刚刚对此进行了测试,这两个mysqli_multi_query()s 没有错误 =close()不需要:

$mysqli1=mysqli_connect("$host","$user","$pass","$db");
$mysqli2=mysqli_connect("$host","$user","$pass","$db");

- 相对 -

mysqli_multi_query()像塞巴斯蒂安和克雷格这样的人之间的打开和关闭:

$mysqli = newSQL();
$mysqli->multi_query($multiUpdates);
$mysqli->close();

- 相对 -

任何人都有另一种选择来测试?

4

2 回答 2

10

这不是next_result()责怪,而是质疑自己。代码运行时间取决于实际查询的执行时间。

尽管mysqli_multi_query()返回控制权相当快,但这并不意味着所有查询都在那个时候执行。恰恰相反,到mysqli_multi_query()完成时, 只有第一个查询被执行。 而所有其他查询都在 mysql 端排队等待异步执行。

由此您可以得出结论,next_result()调用本身不会添加任何超时 - 它只是在等待下一个查询完成。如果查询本身需要时间,那么next_result()也必须等待。

知道您已经知道选择哪种方式:如果您不关心结果,则可以关闭连接。但实际上,它只是扫除地毯下的污垢,将所有缓慢的查询留在原地。因此,最好保持next_result()循环到位(尤其是因为您必须检查错误/受影响的行/等等),但要加快查询本身的速度。

因此,事实证明,要解决next_result()您的问题,实际上必须解决查询速度的常规问题。所以,这里有一些建议:

  1. 对于选择查询,它通常是索引/解释分析,已经在其他答案中解释过。
  2. 对于 DML 查询,尤其是批量运行,还有其他方法:

说到 Craig 的案例,它非常类似于已知的 innodb 写入速度问题。默认情况下,innodb 引擎设置为非常谨慎的模式,在引擎确保前一个成功完成之前不会执行后续写入。因此,它使写入速度非常慢(大约只有 10 个查询/秒)。常见的解决方法是一次进行所有写入。对于插入查询,有很多方法:

  • 您可以使用多个值插入语法
  • 您可以使用 LOAD DATA INFILE 查询
  • 您可以将所有查询包装在事务中。

而对于更新和删除只有事务仍然是可靠的方式。因此,作为一种通用解决方案,可以提供这样的解决方法

 $multiSQL = "BEGIN;{$multiSQL}COMMIT;";
 $mysqli->multi_query($multiSQL);
 while ($mysqli->next_result()) {/* check results here */}

如果它在您的情况下不起作用/不适用,那么我建议更改mysqli_multi_query()循环中运行的单个查询,调查并优化速度,然后返回到 multi_query。

于 2014-03-20T13:41:45.313 回答
4

要回答您的问题:

跳之前先看看

我希望您的mysqli_more_results()调用(跳转前的查看)不会加快速度:如果您有 n 个结果,您将对数据库执行 (2*n)-1 次调用,而 Craig 执行 n+1 次。

多个连接

multi_query 执行 async,因此您只会增加连接开销。

打开和关闭数据库

听听你的常识;-) 但不要忘记你在做什么。在事务中包装查询,将使它们成为原子的。这意味着,他们都失败了,或者他们都成功了。有时需要这样做才能使数据库永远不会与您的话语领域发生冲突。但是使用事务来加速,可能会产生不必要的副作用。考虑其中一个查询违反约束的情况。这将使整个交易失败。这意味着,如果它们一开始就不是逻辑事务并且大多数查询应该成功,那么您将必须找出哪些出错了,哪些必须重新发出。成本核算你更多,而不是提供加速。

Sebastien的查询实际上看起来应该是某个更大事务的一部分,其中包含父级的删除或更新。

相反,试着记住

没有勺子

在您的示例中,不需要多个查询。INSERT ... VALUES形式为 VALUES 采用多个元组。因此,不要准备一个准备好的语句并将其重复执行包装在像 Your Common SenseSuggest 那样的事务中。您可以准备一条语句并让它执行并自动提交。根据mysqli 手册,这可以为您节省大量往返行程。

所以做一个如下形式的 SQL 语句:

INSERT INTO r (a, b, c) VALUES (?, ?, ?), (?, ?, ?), ...

并绑定并执行它。mysqldump --opt做到了,那我们为什么不呢?mysql 参考手册作为语句优化的一节。在其 DML 部分中查找插入和更新查询。但是了解--opt它为什么会这样做是一个好的开始。

准备声明的低估价值

对我来说,prepared statements 的真正价值不是你可以多次执行它们,而是自动输入转义。对于一个微不足道的额外客户端-服务器往返,您可以避免 SQL 注入。SQL 注入是一个重要的注意点,尤其是当您使用multi_query. multi_query告诉 mysql期待多个查询并执行它们。因此,如果无法正确逃脱,您将获得一些乐趣:

妈妈的功劳

所以我的最佳做法是:

  1. 真的需要多个查询吗?
  2. 如果我这样做了,好好逃离他们,或者做好准备
于 2014-03-28T11:25:44.780 回答