我看到很多人说你应该总是使用预准备语句进行数据库查询。但是,PHP文档说:
每个预准备语句都占用服务器资源。声明应该 使用后立即明确关闭。如果没有明确地完成, 当语句句柄被释放时,语句将被关闭 PHP。
使用预准备语句并不总是最有效的方法 执行一份声明。准备好的语句只执行一次导致 比未准备好的声明更多的客户端 - 服务器往返。
来自http://php.net/manual/en/mysqli.quickstart.prepared-statements.php
鉴于上述情况,如果您只打算使用一次查询,那么不使用预准备语句会不是更好?
答案 0 :(得分:5)
差异被认为可以忽略不计。
然而,必须将原生预备陈述与预备陈述的一般概念区分开来。
前者只是大多数DBMS支持的运行查询的一种形式,解释here。它的用法可以质疑
后者是用占位符代替实际数据的一般概念,意味着进一步处理替代数据。它广泛用于编程,一个着名的printf()
函数就是一个例子。并且后一种方法必须始终用于对数据库运行查询,无论它是否由本机预准备语句支持。这是因为:
因此,即使您考虑不使用本机预处理语句(这是非常好的),您也必须始终使用占位符而不是实际数据创建查询。为此,您可以使用PDO,它完全按照上述方式工作 - 默认情况下它只是模拟准备,表示正在创建的查询和数据的常规SQL查询,然后针对数据库运行。
但是,PDO缺乏对许多重要数据类型的支持,例如标识符或数组 - 因此它使您无法始终使用占位符,从而使注入成为可能。幸运的是,safeMysql具有每种数据类型的占位符,并允许您安全地运行查询。
答案 1 :(得分:1)
除非你能够对此进行基准测试并证明它们对性能有可测量的拖累,因为它的速度至少要慢10-15%,所以没有理由对此大惊小怪。即使这样,只要几乎绝对确定数据完整性,这是一个很小的代价,假设你只使用占位符。
准备好的语句,即使只使用一次,也很容易实现正确,如果你从不使用字符串插值来注入数据,那么很难出错。
任何认为自己是专业程序员的人都必须定期审核他们的应用程序,以确保其中没有SQL注入错误。如果事情没有明显地显而易见,那么就不能假定逃脱,所以你必须进行调查。
占位符还使您不太可能错误地混合列及其相关值。 PDO的命名参数功能可以很好地避免这种情况。
答案 2 :(得分:1)
准备语句会生成适合变量的查询计划。然后它可以多次使用。
与他们有关联,顺便说一下。请考虑以下声明:
select * from posts order by post_date limit 10 offset ?;
如果您准备好了,那么您将无法进行索引扫描。因为,对于所有规划人员都知道,你想要最后几行,而且当你浏览索引时,一个接一个地浏览你的数百万个帖子是不可能的。
如果直接使用参数运行,您将获得小偏移的索引扫描,并且没有索引扫描超过阈值,原因与预准备语句不使用索引的原因相同。
有鉴于此,考虑到大多数应用只运行一次查询,您通常可以坚持模拟准备。特别参见PDO::ATTR_EMULATE_PREPARES
。
答案 3 :(得分:0)
SQL注入是预处理语句首选方式的原因。如果您的查询是常量,那么没有理由使用预准备语句。如果您确定即使通过字符串连接构造查询也是安全的,那么可以跳过预准备语句。
常数没问题。
$sql = "SELECT * FROM foobar";
如果$ id变量不可能包含除int之外的任何其他类型的数据,那么这是可以的。
$sql = "SELECT * FROM users WHERE id=".$id;
通常很难确保变量中包含的数据是正确的类型,因此准备好的语句是构建查询的更安全的方式。