SQL 预编译语句
Posted
技术标签:
【中文标题】SQL 预编译语句【英文标题】:SQL precompiled statements 【发布时间】:2013-11-06 16:17:40 【问题描述】:我有一个这样的 sql 查询。
select * from table where owner='b' value=? and chanel='5'
我将始终仅使用所有者 b 和 chanel 5 进行搜索,将其保留为如下所示的占位符是否有意义。
select * from table where owner=? and value=? and chanel=?
它提高了性能还是有什么优势?
亚当。
【问题讨论】:
我认为处理其他两个参数的差异会很小,根本不重要。最后的过程成本是两个prepared statement的过程。在java端。对于数据库,查询本身就准备好了。关于应用程序,我建议您选择第二个,因为今天您的范围是仅搜索owner b and chanel 5
如果明天有人要求您更改它怎么办?您不必更改代码、准备包和部署。
【参考方案1】:
Oracle 可以使用第一个问题中的额外信息,因此它可能会更好地优化它。
这会带来显着的不同吗?取决于您的数据和索引。 在大多数情况下,不会有明显的差异,或者第一个会稍微快一些。
在某些特定情况下(尤其是在统计信息不是最新的情况下),第一种形式的表现可能会更差。 (例如见Oracle SQL: additional restriction causes performance issues)
【讨论】:
【参考方案2】:我认为性能优势可以忽略不计,但使用占位符的安全优势可能很大。真正的性能改进将来自重用PreparedStatement(而不是为每个查询创建一个)。
考虑“b”和“5”来自用户的情况(例如,Web 应用程序中的请求参数)。如果您使用字符串连接创建了字符串,则会将您的应用程序打开到SQL Injection 攻击。使用占位符可以保护您的应用免受 SQL 注入攻击。
这幅漫画很好地解释了这个问题:http://xkcd.com/327/
【讨论】:
【参考方案3】:准备好的语句确实可以提高性能,但前提是您要在项目中多次使用相同的查询。
但它也带来了一些优点,例如避免 SQL 注入,并允许您将所有特定于数据库的内容集中到数据库管理类中。如果从 Oracle 更改为其他内容,您只需更改代码中的一个类。
这个相同的数据库管理类可以在您的程序启动时初始化所有准备好的语句,以便它们在您以后需要时随时准备好,从而获得性能。
Here is an exemple 使用此模型的开源项目。它是 C++,但可能会给你一个想法。
【讨论】:
【参考方案4】:使用文字的一些优点:
-
避免奇怪的优化器限制和错误。这是尽可能使用文字的主要原因。 Oracle 可以使用adaptive cursor sharing 为同一 SQL 语句构建不同的计划,具体取决于绑定变量的值。构建基于绑定值更改的计划很困难,并且存在许多限制和错误。例如,它最多只支持 14 个绑定变量,不支持
LIKE
谓词。如果您的其中一个非真正绑定变量为真正的绑定变量禁用了此功能,则可能会导致问题。
语句更容易阅读。 特别是对于从 V$SQL 查看语句的 DBA。将绑定信息添加到查询是额外的工作,有时该数据不可用。它可能使解释计划更容易生成和阅读。例如,使用文字,解释计划可能会显示正在使用的确切分区。使用绑定变量时,它可能只显示KEY
,这并不清楚是哪个
小幅性能改进。我不知道优化器的具体工作原理,但可以肯定的是,它必须存储绑定变量并查找它们以比较用于现有计划的值。避免这些查找应该会有所帮助,尽管差异可能非常小。
文字的明显缺点,您可能已经考虑过:
-
如果您只是直接从用户那里插入数据,则可能存在 SQL 注入。
如果您想稍后更改代码,则不灵活。
【讨论】:
以上是关于SQL 预编译语句的主要内容,如果未能解决你的问题,请参考以下文章