当在代码中作为准备好的语句运行时,MySQL 查询在 PHP 中运行缓慢

我试图调试的 PHP 应用程序在更大的 MySQL 数据库上运行了几个设计糟糕的查询。

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

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

  • 如果我通过 MySQL 客户端手动运行查询,大约需要 300 毫秒。如果我通过 MySQL 客户端运行 create a Prepared statement 并设置参数并运行它,大约需要 300 毫秒。

  • 如果我从 PHP (mysqli) 运行简单查询,大约需要 300 毫秒。

  • 如果我像应用程序那样运行它——通过mysqli——作为准备好的语句,它需要 100 秒。

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

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

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

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


qq_笑_17
浏览 138回答 1
1回答

梵蒂冈之花

事实证明,这是由略有不同的执行计划引起的。MySQL 似乎纯粹根据语句创建执行计划,不包括通过mysqli或使用准备好的语句时的参数值PDO,这是有道理的。然而,当它提供完整的查询时,在我们的例子中它引入了对其中一个表的优化,这产生了巨大的差异。其中一个表(有 550 万行)在Using join buffer (Block Nested Loop)使用非准备语句运行时具有 Extra,而使用准备好的语句则没有。这似乎对我们产生了接近 1000 倍的性能差异。我仍然不确定为什么通过 PHPStorm 或 CLImysql客户端这没有问题,我最好的猜测是,MySQL 中的某些 API 期望在准备语句时执行计划是完整的,而其他 API 和 CLI 客户端则不'不。
打开App,查看更多内容
随时随地看视频慕课网APP