MySQL查询在PHP中作为代码中的准备语句运行时运行缓慢,但通过直接MySQL查询快速运行
我正在调试的一个PHP应用程序在一个更大的MySQL数据库上运行了几个设计糟糕的查询 有几页确实很慢,结果证明这是因为一些查询。我开始一个接一个地检查每一个查询,尽管它们很慢,但它们本身并没有那么慢 经过进一步的调试,结果表明,只有当应用程序将它们作为准备好的语句运行时,它们才会变慢MySQL查询在PHP中作为代码中的准备语句运行时运行缓慢,但通过直接MySQL查询快速运行,php,mysql,go,Php,Mysql,Go,我正在调试的一个PHP应用程序在一个更大的MySQL数据库上运行了几个设计糟糕的查询 有几页确实很慢,结果证明这是因为一些查询。我开始一个接一个地检查每一个查询,尽管它们很慢,但它们本身并没有那么慢 经过进一步的调试,结果表明,只有当应用程序将它们作为准备好的语句运行时,它们才会变慢 如果我通过MySQL客户端手动运行查询,大约需要300毫秒。如果我通过MySQL客户端运行create PREADED语句,设置参数并运行它,大约需要300毫秒 如果我从PHP(mysqli)运行简单查询,大约需
- 如果我通过MySQL客户端手动运行查询,大约需要300毫秒。如果我通过MySQL客户端运行create PREADED语句,设置参数并运行它,大约需要300毫秒
- 如果我从PHP(mysqli)运行简单查询,大约需要300毫秒
- 如果我像应用程序那样通过-as-prepared语句运行它,则需要100秒
mysqli
,所以我用PDO尝试了一下,结果是一样的。尝试了不同的PHP版本(5.6、7.2、7.3),得到了相同的结果
所以我给了最后一次机会,写了一个小的Go脚本来测试,我得到了同样的结果,事情也有所改善
现在,如果我从MySQL客户机、MySQL工作台或PHPStorms数据库客户机运行查询的预处理语句版本,速度会很快。如果我从代码中运行查询,速度会非常快
任何关于我应该注意什么、我应该在哪里继续调试的帮助都将不胜感激。因此,事实证明,这是由稍微不同的执行计划造成的。MySQL似乎完全基于语句创建执行计划,在通过
mysqli
或PDO
使用准备好的语句时不包括参数值,这是有意义的。然而,当它提供完整的查询时,在我们的例子中,它对其中一个表进行了优化,这产生了巨大的差异
其中一个表(有550万行)在使用非prepared语句运行时有Using join buffer(Block Nested Loop)
额外功能,而在使用prepared语句时则没有。这似乎使我们的性能相差近1000倍
我仍然不确定为什么通过PHPStorm或CLI
mysql
客户端这没有问题,我最好的猜测是,mysql中的某些API希望在准备语句时执行计划是完整的,而其他API和CLI客户端则不这样做。因此,这是由稍微不同的执行计划造成的。MySQL似乎完全基于语句创建执行计划,在通过mysqli
或PDO
使用准备好的语句时不包括参数值,这是有意义的。然而,当它提供完整的查询时,在我们的例子中,它对其中一个表进行了优化,这产生了巨大的差异
其中一个表(有550万行)在使用非prepared语句运行时有Using join buffer(Block Nested Loop)
额外功能,而在使用prepared语句时则没有。这似乎使我们的性能相差近1000倍
我仍然不确定为什么通过PHPStorm或CLI
mysql
客户端这没有问题,我的最佳猜测是,mysql中的某些API希望在准备语句时完成执行计划,而其他API和CLI客户端则不这样做。检查代码,看看它是否在循环中运行查询。在编码不好的应用程序中,这种情况并不少见。一个300毫秒的查询在一个循环中运行300次需要90秒。代码与此无关。我使用了一个纯脚本,它只包含两个版本的查询和执行时间的度量。请尝试在两个位置运行查询,并查看是否存在任何可能导致问题的差异。我们使用EXPLAIN运行了两个查询,执行计划是相同的,除了一个具有使用索引条件的表之外代码>准备版本的额外代码。此外,查询只执行一次,循环中没有任何内容,唯一的区别是预处理语句部分。参数的数量也不多(总共9个),它们也很简单(5个整数,值为0、1和2,以及3个短字符串)。在检查性能时,很明显所有负载都在mysql中,这会使CPU达到最大值。在大多数情况下,查询都处于发送数据的状态。请检查代码以查看它是否在循环中运行查询。在编码不好的应用程序中,这种情况并不少见。一个300毫秒的查询在一个循环中运行300次需要90秒。代码与此无关。我使用了一个纯脚本,它只包含两个版本的查询和执行时间的度量。请尝试在两个位置运行查询,并查看是否存在任何可能导致问题的差异。我们使用EXPLAIN运行了两个查询,执行计划是相同的,除了一个具有使用索引条件的表之外代码>准备版本的额外代码。此外,查询只执行一次,循环中没有任何内容,唯一的区别是预处理语句部分。参数的数量也不多(总共9个),它们也很简单(5个整数,值为0、1和2,以及3个短字符串)。在检查性能时,很明显所有负载都在mysql中,这会使CPU达到最大值。查询大部分时间处于发送数据
状态。