在我的数据库中,在几个地方开发人员使用动态sql而不是静态。他们说这是为了提高绩效。有人能告诉我,如果动态sql能真正提高存储过程或plsql块的性能吗?
哪个会更快执行?为什么? 1.
begin
execute immediate 'delete from X';
end;
2
begin
delete from X;
end;
答案 0 :(得分:13)
您的示例代码非常简单,几乎没有区别,但在这种情况下,静态版本很可能会更好地执行。
使用动态SQL提高性能的主要原因是SQL语句可能会发生重大变化 - 即您可能会在运行时根据系统状态向WHERE子句添加额外代码(限制为地址上的子查询,输入的地址等)。
另一个原因是,有时使用Bind变量作为参数可能会适得其反。
例如,如果你有类似状态字段的东西,那里的数据分布不均匀(但被索引)。
当95%的数据是'P'rocessed
时,请考虑以下3个陈述 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。然而,这使代码变得复杂,并且只是因为我们需要速度而完成。
答案 1 :(得分:0)
不幸的是,这确实因具体情况而异。
对于您给出的示例,可能没有可测量的差异。但是对于一个更复杂的例子,你可能想测试自己的代码。
@DumbCoder在评论中给出的链接有一些优秀的经验法则,大部分也适用于Oracle。你可以使用这样的东西来帮助你做出决定,但没有简单的规则,比如“动态比静态更快”。