静态与动态 sql
Posted
技术标签:
【中文标题】静态与动态 sql【英文标题】:Static vs dynamic sql 【发布时间】:2010-08-24 08:59:30 【问题描述】:在我的数据库中,开发人员在多个地方都使用了动态 sql 而不是静态的。他们说这样做的原因是为了提高性能。有人能告诉我动态sql是否真的可以提高存储过程或plsql块的性能吗?
哪个执行得更快,为什么? 1.
begin
execute immediate 'delete from X';
end;
2.
begin
delete from X;
end;
【问题讨论】:
publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/… 我不确定“从 X 中删除”之类的查询,但总的来说,如果您的查询有参数,动态查询可以更快地工作,我见过很多次。为什么?看起来当你编译你的 sproc DB 时不知道参数可以是什么,并且可以选择错误的计划。在动态查询的情况下,当我用查询创建字符串然后执行它时,所有参数都被插入并且计划执行更好。这听起来很奇怪,但是当性能很重要时,我也会这样做。回到你的问题 -> 你的查询是像你写的那样,还是更复杂(通过 sproc 插入参数)? 大部分查询都很简单,可以用静态方式编写。这就是为什么我想知道当它可以以静态方式编写时为什么要进行动态查询。 我认为你的论点是正确的——如果它可以写成静态的,那最好写成静态的。 经验法则(可能涉及失去所述经验):OLTP 应用程序和处理应绑定/参数化 SQL; DSS(决策支持)/DW 系统应该是动态/文字 SQL。 【参考方案1】:您的示例代码非常简单,几乎没有区别,但在这种情况下,静态版本很可能会执行得更好。
使用动态 SQL 来提高性能的主要原因是当 SQL 语句可以以显着方式变化时 - 即您可能能够在运行时根据系统状态向 WHERE 子句添加额外代码(由地址的子查询,如果输入了地址等)。
另一个原因是有时使用 Bind 变量作为参数可能会适得其反。
例如,如果您有类似状态字段的内容,其中数据分布不均(但已编入索引)。
考虑以下 3 个语句,当 95% 的数据被“处理”时
SELECT col FROM table
WHERE status = 'U'-- unprocessed
AND company = :company
SELECT col FROM table
WHERE status = 'P' -- processed
AND company = :company
SELECT col FROM table
WHERE status = :status
AND company = :company
在最终版本中,Oracle 将选择一个通用的解释计划。在第一个版本中,它可能决定最好的计划是从状态索引开始(知道“未处理的条目”只占总数的很小一部分)。
您可以通过不同的静态语句来实现这一点,但是如果您有更复杂的语句(仅更改几个字符),则动态 SQL 可能是更好的选择。
缺点
同一动态 SQL 语句的每次重复都会引发一次软解析,这与静态语句相比开销很小,但仍然是开销。
每个新的 sql 语句(动态或静态)也会导致 SGA(共享内存)上的锁定,并可能导致将“旧”语句推出。
一个糟糕但常见的系统设计是让某人使用动态 SQL 来生成仅因键而异的简单选择 - 即
SELECT col FROM table WHERE id = 5
SELECT col FROM table WHERE id = 20
SELECT col FROM table WHERE id = 7
单个语句会很快,但整体系统性能会下降,因为它会扼杀共享资源。
另外 - 使用动态 SQL 在编译时捕获错误要困难得多。如果使用 PL/SQL,这将丢弃一个很好的编译时间检查。即使使用 JDBC 之类的东西(将所有数据库代码移动到字符串中 - 好主意!),您也可以使用预解析器来验证 JDBC 内容。动态 SQL = 仅运行时测试。
开销
立即执行的开销很小 - 它在千分之一秒内 - 但是,如果这是在循环内/在每个对象调用一次的方法上/等等,它可以加起来。我曾经获得了 10 倍的速度提升通过用生成的静态 SQL 替换动态 SQL。然而,这使代码变得复杂,而且只是因为我们需要速度。
【讨论】:
JulesLt 在他的回答中有很好的观点,并在讨论开销时暗示了一些需要明确说明的内容——抛开绑定变量的考虑、解析等,在 PL/SQL 块中立即执行将始终与等效的 PL/SQL 调用相比有一个缺点,因为执行将涉及到 SQL 引擎的上下文切换。【参考方案2】:不幸的是,这确实因具体情况而异。
对于您给出的示例,可能没有可测量的差异。但对于更复杂的示例,您可能需要测试自己的代码。
@DumbCoder 在 cmets 中提供的链接有一些优秀的经验法则,这些法则大部分也适用于 Oracle。您可以使用类似的方法来帮助您做出决定,但没有像“动态比静态更快”这样的简单规则。
【讨论】:
以上是关于静态与动态 sql的主要内容,如果未能解决你的问题,请参考以下文章