Mysql PDO 准备语句效率
我正在接管一个 PHP 应用程序,该应用程序每次运行 SQL 语句时都使用 MySQL PDO 准备好的语句。 我知道当您要对同一语句进行多次迭代时,准备 SQL 会更加高效。
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->execute(array(150, 'red'));
$red = $sth->fetchAll();
$sth->execute(array(175, 'yellow'));
$yellow = $sth->fetchAll();
然而,我正在接管的应用程序在 PDO 之上构建了一个层,该层调用通用的“执行”函数,并且它似乎准备了每个 SQL 查询。例如:
$query = self::$DB->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$query->execute($bindvars);
如果应用程序执行数百或数千条“INSERT INTO ...... ON DUPLICATE KEY UPDATE”SQL 语句,则 $DB->prepare() 步骤如果每次运行一次,是否会产生显着的开销时间?
非常感谢,杰森。
I am taking over a PHP app that uses MySQL PDO prepared statements for each time it runs an SQL statement.
I know that Preparing SQL can be more efficient when the you are about to do many iterations of the same statement.
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->execute(array(150, 'red'));
$red = $sth->fetchAll();
$sth->execute(array(175, 'yellow'));
$yellow = $sth->fetchAll();
However, the app I am taking over has an built a layer on top of PDO that calls a common "execute" function, and it appears that it prepares every single SQL query. For example:
$query = self::$DB->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$query->execute($bindvars);
If the app does many hundreds or thousands of "INSERT INTO ...... ON DUPLICATE KEY UPDATE" SQL statements, does the $DB->prepare() step create a significant overhead if it is run every single time?
Many thanks, Jason.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
从文档中:
我并没有真正在这里透露任何信息,但“优化性能”的反义词确实是“开销”。至于它是否重要,为什么不运行一个循环并测量呢?然后,您可以自己做出决定,用硬数据来支持您的决定。
From the documentation:
I 'm not really making any revelations here, but the opposite of "optimizes the performance" would indeed be "overhead". As to whether it's significant or not, why don't you run a loop either way and measure? You can then decide for yourself with hard data to back up your decision.
除了查询重用之外,在 PDO 中使用准备好的语句的主要原因是执行占位符绑定。
在此代码中,
$sql
变量中存在的问号(或:named
)占位符将替换为中的值$bindvars
数组。此替换可确保变量被正确引用和转义,从而使执行 SQL 注入变得更加困难。准备/执行过程中可能会产生少量开销,但考虑到 SQL 注入的风险,这一点小开销根本不算什么。唯一的其他选项是将 SQL 字符串连接在一起,这可能会带来巨大的安全风险,除非每次都完美地完成。
前任开发人员知道他或她在做什么,至少在这种特定情况下是这样,并且您不应该撤消他或她在这里所做的工作。恰恰相反,您应该在未来的所有代码中继续使用准备好的语句。
(另一方面,我不能保证 MySQL 的游标性能......)
Besides query reuse, the primary reason to use prepared statements in PDO is to perform placeholder binding.
In this code, the question marks (or
:named
) placeholders present in the$sql
variable are replaced with the values in the$bindvars
array. This replacement ensures that the variables are properly quoted and escaped, making it much more difficult to perform SQL injection.There may be a small amount of overhead in the prepare/execute, but that small overhead is nothing given the risk of SQL injection. The only other option is concatenating together the SQL string, and that can be a huge security risk unless it's done perfectly every time.
The previous developer knew what he or she was doing, at least in this specific case, and you should not undo the work he or she did here. Quite the opposite, you should continue using prepared statements in all of your future code.
(On the other hand, I can't vouch for MySQL's cursor performance...)
如果没记错的话,MySQL 会看到您准备好的语句,并预计您正在运行的应用程序可能会多次调用同一语句。因此,它会缓存语句字符串,因此再次准备它并不会产生太大的开销,尽管它不仅仅是将语句的引用保留在内存中。它仍然肯定比每次从字符串解析一个全新的查询要好。
不过,这只是我对我所听到的的模糊记忆。这是重要的一点:如果在同一个请求中运行数百或数千个插入,请考虑重构数据库类,以便在此类情况下准备一次并执行多次。了解它会产生多大差异的唯一方法是自己进行基准测试:/
If memory serves, MySQL sees your prepared statement and expects that you're probably running an application that is likely to call the same statement multiple times. As such, it caches the statement string, so preparing it again isn't much overhead, though it's more than just keeping the reference to the statement in memory. It's still definitely better than parsing a whole new query from a string each time.
This is just from my vague memory of what I think I've heard, though. Here's the important bit: if these hundreds or thousands of inserts are running in the same request, consider refactoring the database class to prepare once and execute many times in situations like these. The only way to know how much of a difference it will make is to benchmark it yourself :/