【问题标题】:MySQL queries run slow in PHP when run as prepared statements in code but run quickly via direct MySQL queries当在代码中作为准备好的语句运行时,MySQL 查询在 PHP 中运行缓慢,但通过直接 MySQL 查询运行快速
【发布时间】:2019-06-30 17:07:00
【问题描述】:

我正在尝试调试的一个 PHP 应用程序在一个更大的 MySQL 数据库上运行几个设计不佳的查询。

有几页真的很慢,原来是因为几个查询。我开始一一检查每个查询,虽然它们很慢,但它们本身并没有那么慢。

经过进一步调试,结果发现它们只是在应用程序将它们作为准备好的语句运行时才会变慢。

  • 如果我通过 MySQL 客户端手动运行查询,大约需要 300 毫秒。如果我通过 MySQL 客户端运行 create aprepared statement 并设置参数并运行它,大约需要 300 毫秒。
  • 如果我从 PHP (mysqli) 运行简单查询,大约需要 300 毫秒。
  • 如果我像应用程序那样运行它——通过mysqli——作为准备好的语句,它需要 100 秒。

我想可能是mysqli 所以我用 PDO 试了一下,结果是一样的。尝试了不同的 PHP 版本(5.6、7.2、7.3)并得到相同的结果。

所以我给了最后一次机会,写了一个小的 Go 脚本来测试,我得到了相同的结果并且事情得到了改进。

现在,如果我从 MySQL 客户端或 MySQL Workbench 或 PHPStorms 数据库客户端运行查询的准备语句版本,它会很快。如果我从代码中运行查询,它会非常快。

任何关于我应该注意什么,我应该在哪里继续调试的帮助将不胜感激。

【问题讨论】:

  • 检查代码看它是否在循环中运行查询。在编码不佳的应用程序中看到这种情况并不少见。一个 300 毫秒的查询在一个循环中运行 300 次需要 90 秒。
  • 遗憾的是,代码与此无关。我使用了一个纯脚本,它只包含两个版本的查询和执行时间的测量
  • 尝试使用EXPLAIN 在这两个地方运行查询,看看是否存在可能导致问题的差异。
  • 我们已经使用 EXPLAIN 运行了两个查询,执行计划是相同的,除了准备好的版本有一个带有Uses index condition; Extra 的表。此外,查询只执行一次,循环中没有任何内容,唯一的区别是准备好的语句部分。参数的数量也不多(总共 9 个),它们也很简单(5 个整数,值为 0、1 和 2,以及 3 个短字符串)。在检查性能时,很明显所有负载都在 mysql 中,这会最大限度地利用 CPU。大多数情况下,查询处于sending data 状态。

标签: php mysql go


【解决方案1】:

事实证明,这是由于执行计划略有不同造成的。 MySQL 似乎纯粹基于语句创建执行计划,不包括通过 mysqli 或 PDO 使用准备好的语句时的参数值,这是有道理的。然而,当它提供完整的查询时,在我们的例子中,它引入了对其中一个表的优化,这产生了巨大的差异。

其中一个表(有 550 万行)在使用非准备好的语句运行时具有Using join buffer (Block Nested Loop) Extra,而使用准备好的语句则没有。这似乎为我们带来了接近 1000 倍的性能差异。

我仍然不确定为什么通过 PHPStorm 或 CLI mysql 客户端没有问题,我最好的猜测是,MySQL 中的某些 API 期望在准备语句时执行计划完成,而其他 API ,而 CLI 客户端则没有。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多