绑定变量在 Oracle 中应该走多远?

Mic*_*l-O 3 oracle oracle-11g-r2 plsql

我目前正在检查我们部门所有数据库用户的 SQL 代码是否没有使用绑定变量。我们确实在一段时间内遇到了 ORA-04031 错误。

现在,我非常清楚在何处使用它们,但我不确定这应该走多远。现在,我是否必须用绑定变量替换所有文字?

例如:

select 1 from t1 ; => select :one from table t;
Run Code Online (Sandbox Code Playgroud)

或者

select c1, c2, from t2 where id = :id and status = 2 =>
select c1, c2, from t2 where id = :id and status = :two
Run Code Online (Sandbox Code Playgroud)

或者

select * from t3 where c3 > :value and exists (select 1 from t4 where <some condition>) =>
select * from t3 where c3 > :value and exists (select :one from t4 where <some condition>)
Run Code Online (Sandbox Code Playgroud)

这同样适用于 DML。

我的直觉是,一切都必须是一个绑定变量才能实现最佳性能。

Jus*_*ave 5

在您可能实际更改传入值的任何位置使用绑定变量。

例如,EXISTS在第三个示例中的子句中使用绑定变量可能没有意义,因为任何人似乎都不太可能想要为该EXISTS子句传入不同的常量。

在您的第二个示例中,假设应用程序可能希望针对不同的idandstatus值运行此查询,使用绑定变量而不是硬编码状态可能确实有意义。另一方面,如果代码只status为这个查询传入2 的值,那么使用绑定变量可能没有意义。假设它status不是均匀分布的,你最好向优化器提供你总是会使用status2的信息,而不是试图依靠绑定变量偷看来向优化器提供该信息。

如果该值永远不会改变——即,如果status第二个查询中的 始终为 2——则您可以根据需要多次执行该查询,并且它只会在v$sql或 中出现一次v$sqlarea。就我而言,我将执行查询 10 次

SQL> ed
Wrote file afiedt.buf

  1* select * from v$sql where sql_text like '%jc_bind_test%'
SQL> select /* jc_literal_test */ count(*)
  2    from emp
  3   where ename = 'KING';

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1

SQL> /

  COUNT(*)
----------
         1
Run Code Online (Sandbox Code Playgroud)

v$sqlor v$sqlarea,您将只看到具有硬编码文字的查询的一行。该行将显示查询执行了 10 次

SQL> ed
Wrote file afiedt.buf

  1* select sql_text, executions, loaded_versions, parse_calls from v$sqlarea where sql_text like '%jc_literal_test%'
SQL> /

SQL_TEXT                                 EXECUTIONS LOADED_VERSIONS PARSE_CALLS
---------------------------------------- ---------- --------------- -----------
select * from v$sql where sql_text like           1               1           1
'%jc_literal_test%'

select sql_text, executions, loaded_vers          5               1           5
ions, parse_calls from v$sql where sql_t
ext like '%jc_literal_test%'

select sql_text, executions, loaded_vers          1               1           1
ions, parse_calls from v$sqlarea where s
ql_text like '%jc_literal_test%'

select /* jc_literal_test */ count(*)            10               1          10
from emp  where ename = 'KING'
Run Code Online (Sandbox Code Playgroud)