在 SQL 语句中外连接绑定变量 (Oracle 11g)

Posted

技术标签:

【中文标题】在 SQL 语句中外连接绑定变量 (Oracle 11g)【英文标题】:Outerjoining a Bind-Variable in SQL-Statement (Oracle 11g) 【发布时间】:2012-12-03 14:32:22 【问题描述】:

我们有很多使用可以为 Null 的绑定变量的 Select 语句。 Null 表示 Bind-Value 不应限制语句。

这是一个简单的例子:

CREATE TABLE PERSON AS
SELECT LEVEL AS ID, 'Person_'||LEVEL AS NAME
FROM DUAL 
CONNECT BY LEVEL <= 5000;

create index IPERSON1 on PERSON(NAME, ID);

begin
dbms_stats.gather_table_stats(user, 'PERSON');
end;

select * from PERSON
where NAME = nvl(:b1, NAME);

select * from PERSON
where (NAME =:b1 or :b1 is null);

这 2 个语句具有以下执行计划:

select * from PERSON where NAME =nvl(:b1, NAME): 
------------------------------------------------------------------------------------
| Id  | Operation              | Name     | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |          |        |       |     4 (100)|          |
|   1 |  CONCATENATION         |          |        |       |            |          |
|*  2 |   FILTER               |          |        |       |            |          |
|*  3 |    INDEX FAST FULL SCAN| IPERSON1 |    500 |  7500 |     2   (0)| 00:00:01 |
|*  4 |   FILTER               |          |        |       |            |          |
|*  5 |    INDEX RANGE SCAN    | IPERSON1 |      1 |    15 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------

select * from PERSON where (NAME =:b1 or :b1 is null): 
-----------------------------------------------------------------------------
| Id  | Operation         | Name   | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |        |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| PERSON |     26 |   390 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

那么,您认为这种外连接的最佳解决方案是什么?

【问题讨论】:

我在您的查询中看不到任何联接,更不用说外部联接了?所以我不太明白这个问题。 对不起,我使用“外连接”的意思是绑定值必须“存在”或“不存在” 【参考方案1】:

我认为这个问题不能被普遍回答,因为它取决于特定的表架构和可用索引。

一般可以说是:

两个提议的 WHERE 条件都无法通过索引查找直接找到相关行。相反,必须完全扫描表或索引。

将同一查询的不同变体合并为一个被认为是一种反模式,因为 Oracle 必须对所有变体使用相同的执行计划,这很可能对所有变体都不是最佳的。

所以可能会更好:

    动态构建查询,即仅当参数不为空时才添加 WHERE 条件。如果存在 WHERE 条件,那么您仍应使用绑定参数,这对于优化性能至关重要。

    或者,根据参数是否为空来实现单独的查询。

选项 1 是首选选项。如果您针对 C#、Java 或类似语言运行查询,它可能更容易实现。

选项 2 是您可能会在 PL/SQL 中使用的选项。但是,如果您有多个可以为空的参数,则可能会导致许多不同的查询。

【讨论】:

以上是关于在 SQL 语句中外连接绑定变量 (Oracle 11g)的主要内容,如果未能解决你的问题,请参考以下文章

oracle中如何获取最后执行的SQL语句并绑定变量值

在 Oracle PL/SQL 中重用绑定变量

oracle表查询优化

oracle = : := 和变量绑定 oracle通配符和运算符

Oracle绑定变量

不能在 sql 查询 APEX ORACLE 中使用绑定变量作为表名