我需要坚持准备好的陈述吗?
Posted
技术标签:
【中文标题】我需要坚持准备好的陈述吗?【英文标题】:Do I need to persist a prepared statement? 【发布时间】:2014-07-19 05:18:36 【问题描述】:我有以下代码:
public function getDefinitions($wordID)
$query = $this->dbc->prepare('SELECT * FROM definitions WHERE wordID = ?');
$query->bind_param('i', $wordID);
$query->execute();
// ...
$query->close();
return $result;
这似乎会为每次调用重新创建prepared statement。这似乎没有利用准备好的陈述的全部好处。特别是在这些准备语句是stored server side 的情况下。这是真的吗?
如果是这样,我应该存储准备语句(在这种情况下作为属性)以在调用之间保持它。有没有办法在请求之间保留准备好的语句?我假设这本质上是一个存储过程?
目前我正在使用 mysqli。如果我使用其他驱动程序(例如 PDO),请注意任何 API 差异。
【问题讨论】:
我会说持久化 $query 会很有意义,否则你不会从使用准备好的语句中获得任何好处,特别是如果你知道你将在同一次执行中多次调用它一个脚本。 您确实获得了一个好处,那就是使用绑定变量;但是持久化准备好的语句的一种简单方法可能是使 $query 成为静态的 除了占位符/参数之外,真正应该使用准备好的语句的唯一时间是您要一遍又一遍地使用 SAME 查询。准备一次性查询的额外开销绝对是“无用的”。但是正确使用占位符来防止 sql 注入攻击大大超过了开销。 @Marc B,明白了。是否有替代准备好的语句,但仍提供占位符的好处? 另一方面,说到 native 准备好的语句,肯定有一种称为“模拟准备好的语句”的替代方案,它利用了占位符的思想,无需两次准备。它在许多库中实现,从 PDO 开始。 【参考方案1】:我应该存储准备语句(在这种情况下作为属性)以在调用之间保持它。
我不会说你“应该”。如果您预见到大量后续调用(您不能一次分组调用),您可能会这样做。无论哪种方式,您几乎都无法注意到现实生活中的差异。
有没有办法在请求之间保留准备好的语句?
在 php 中 - 没有。准备好的语句是基于连接的,连接随着请求关闭,持久连接也无济于事,因为mysqli is using designated mechanism在重用之前清理连接状态。
如果我使用其他驱动程序(例如 PDO),请注意任何 API 差异。
PDO 比 mysqli 有一个优势,因为它可以模拟准备好的语句,甚至消除了两次数据库调用这样微不足道的开销,这使得它更适合现实生活中的使用(除了其他关键好处) .
简而言之,原生预处理语句的“准备一次多次执行”功能仅对大量查询(从数千个开始)才有显着效果。
【讨论】:
+1 表示彻底。快速跟进 - 而不是应该,您是否认为这样的 DAO 类将准备语句存储在类变量中是 最佳实践 - 不管性能差异如何?跨度> 我不建议这样做。在我看来,保持每一个准备好的语句都是打开的,你最终会得到几十个(甚至几百个)语句对象,直到 PHP 端的脚本终止,mysql 端也同样混乱,虽然只有很小他们中的许多人实际上被重用了。我宁愿将此功能设为可选。 公平。如果我为每个方法调用都生成它,我似乎没有充分利用准备语句(尽管可以忽略不计)。【参考方案2】:如果您打算再次使用该查询,则应该保留该查询。
当您使用 mysqli 准备好的语句时,应该始终是真正的准备好的语句。 (与 PDO 相矛盾,它基于使用的驱动程序模拟查询并且可能不会发送额外的数据库调用)。然后,替换占位符的数据以不同的数据包发送。 因此,如果只发出一次,自然准备的语句需要两次访问数据库。 发送此额外操作需要时间。如果您知道只想发出一次查询,那么在某些情况下使用传统查询可能是积极的。 (但是,只有当您完全确定标准查询与预准备语句相比可能带来的负面安全影响时,才建议这样做。使用预准备语句增加的安全级别超过了这样的好处在大多数情况下可能会发生变化。)
但是,如果您想重新运行查询准备它是正确的方法。 MySQL应该缓存转换后的语句,所以php-site是唯一优化和复用的方式。
您可以做的是通过使用静态变量或属性在方法中保留语句来防止对 prepare 方法的额外调用以及它可能在低级数据库连接器中触发的操作。然而,对大多数实际应用程序的影响是有争议的。
【讨论】:
-1 单独表示“不要使用准备好的语句”。 “如果你能安全地逃避数据”对于任何人来说都是过于假设和不确定的陈述。在现实世界中,如果你以一个普通的 PHP 用户为例,你不会让他告诉你什么是“安全转义”。 我建议重新措辞@YourCommonSense 提到的部分,在这种情况下你的答案是好的。看到其余的答案结构良好且可靠,因此根据上述事实对您投反对票是一种浪费。 @YourCommonSense 我希望更改可以改善答案。如果它仍然打开,我将删除该部分以更好地回答问题。 好吧,我会收回我的反对票,但请阅读this my answer关于“绝对保证”的问题以上是关于我需要坚持准备好的陈述吗?的主要内容,如果未能解决你的问题,请参考以下文章