使用prepared statement来防止SQL注入会影响性能吗?

Posted

技术标签:

【中文标题】使用prepared statement来防止SQL注入会影响性能吗?【英文标题】:Does using prepared statement to prevent SQL injection affect performance? 【发布时间】:2015-03-20 22:49:58 【问题描述】:

显然是防止 SQL 注入的最佳方法is to use prepared statements。然而,准备好的语句完全是为其他东西设计的:

在数据库管理系统中,准备好的语句或参数化的 语句是用于执行相同或相似数据库的功能 高效重复语句。 [...] 另一方面,如果查询只执行一次,服务器端 由于额外的往返行程,准备好的语句可能会更慢 到服务器。实施限制也可能导致性能 处罚:某些版本的mysql没有缓存prepared结果 查询,并且某些 DBMS(例如 PostgreSQL)不执行额外的 执行期间的查询优化。

我猜测准备好的语句主要设计用于在紧密循环中使用,以减少重复语句的编译时间。 SQL 注入预防只是一个奖励。

假设我们不使用 PDO 或“模拟”预准备语句,那么对页面上仅使用一次的查询使用预准备语句是否有意义。

【问题讨论】:

这取决于使用的 dbms。您使用的是哪个 dbms? 防止 sql 注入的好处应该超过性能问题,除非这成为瓶颈 @jarlh 我正在寻找一个通用的答案,因为我同时使用 SQL Server 和 MySQL(但在不同的项目中)。 【参考方案1】:

只是个人想法..

尽管每页执行一次 SQL 语句可能会造成性能损失,但我相信这是有道理的。

每个应用程序通常由 SQL 语句的组合组成。有些只执行一次。有的多次。但是,通常不能忽略某些地方的 SQL 注入。通过应用程序将其全部参数化可使代码更加一致。也许更优雅(例如,如果我考虑 strings 中的撇号 - 不必通过将它们加倍等来逃避它们)。准备好的语句会处理所有这些。我从未测量过参数化查询的性能损失,但如果出现任何性能问题,我可能永远不会关注它们。如果我有性能问题,这通常意味着其他地方的问题(执行计划、正确的索引、统计信息等)。

【讨论】:

【参考方案2】:

答案当然取决于您使用的 RDBMS。

对于 Web 应用程序,我总是认为安全问题高于性能问题,尤其是在性能差异可能几乎无法衡量的情况下。

也就是说,Oracle(可能还有其他 RDBMS)区分软解析和硬解析。当 Oracle 被要求准备一个语句时,它首先为该语句计算一个哈希值,并将其与已准备好的语句列表进行比较。如果在这个列表中找到它,Oracle 就知道它已经解析了该语句,不需要再次解析它。这称为软解析。如果语句是真的新的(所以在这个列表中没有找到),它必须硬解析语句。硬解析通常被认为比软解析更昂贵。

因此,当您的应用程序每页仅发出一次语句时,RDBMS 仍会多次看到相同的语句,并且能够从第 2 次开始软解析语句。与为每个页面请求使用不同语句的替代方案相比,这甚至是一个巨大的好处,因为在替代方案中,每个语句都必须进行硬解析。

【讨论】:

【参考方案3】:

以下适用于 SQL Server

单个准备好的语句可能比临时查询执行得更差。不过,整体的表现应该会更好。

Prepared statement 的性能比 ad hoc 查询差

假设我们有一个表,其中包含 过去 10 年的记录和 10 种可能的状态。假设数据是均匀分布的,我们有这些查询:

... WHERE date >= '2017-01-01' AND status = 1
... WHERE date >= '2009-01-01' AND status = 1
... WHERE date >= ? AND status = ?

对于前两个查询(即席),SQL Server 可以为每个查询生成单独的执行计划,例如第一次查询使用日期列索引,第二次查询使用状态列索引。

对于第三个查询(准备),SQL Server 将生成一个执行计划,该计划可能最适合大多数情况,但不是所有情况。例如,SQL Server 可能会生成一个使用日期列索引的执行计划,这对于最近的日期而不是过去的日期是有效的。

即席查询的性能比预准备语句差

即席查询的问题之一是它们最终会导致“计划缓存膨胀”。发生这种情况时,计划经常被从计划缓存中踢出,并在再次执行相同的查询时重新编译。查询编译是一个昂贵的过程。

观察

将我的 Web 应用程序从即席查询转换为预准备语句后,我注意到执行时间有了显着改善。计划缓存膨胀已被消除,查询不会像使用临时查询那样频繁地重新编译,从而节省宝贵的 CPU 周期和内存。

【讨论】:

以上是关于使用prepared statement来防止SQL注入会影响性能吗?的主要内容,如果未能解决你的问题,请参考以下文章

当 Statement 与 Java 和 Oracle 一起使用时,Prepared Statement 不起作用

Postgresql:prepared statement "S_1" already exists

使用 Prepared Statement 设置 LONG 数据类型

A prepared statement is generated from a nonconstant String 问题的解决

cannot insert multiple commands into a prepared statement问题原因及解决办法

使用 PDO Prepared Statement 在 MySQL 中插入 BIT 值