如果我在Oracle12 db上执行以下语句,我得到一个结果,我根本无法解释:
CREATE TABLE table_a (
a_id NUMBER NOT NULL ,
PRIMARY KEY ( a_id )
);
CREATE TABLE table_b (
b_id NUMBER NOT NULL ,
col_1 NUMBER ,
PRIMARY KEY ( b_id )
);
ALTER TABLE table_b
ADD FOREIGN KEY (b_id) REFERENCES table_a (a_id);
insert into table_a (a_id) values (1);
insert into table_a (a_id) values (2);
insert into table_a (a_id) values (3);
insert into table_a (a_id) values (4);
insert into table_b (b_id, col_1) values (1, 100);
insert into table_b (b_id, col_1) values (2, 101);
select a_id, b_id, col_1
from table_a left outer join table_b on a_id=b_id
where a_id in (1 , 3 , 4);
这导致以下输出:
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3 3
4 4
根据我的理解,B_ID
列中的值3和4不应该存在,因为该表仅包含值1和2:
select * from table_b;
B_ID COL_1
---------- ----------
1 100
2 101
为了列出完整的数据,这里是table_a
:
select * from table_a;
A_ID
----------
1
2
3
4
以下是有关执行路径的更多信息:
select * from table( dbms_xplan.display_cursor( null, null, '+OUTLINE' ) );
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 6wg8b65y25utv, child number 2
-------------------------------------
select a_id, b_id, col_1 from table_a left outer join table_b on
a_id=b_id where a_id in (1 , 3 , 4)
Plan hash value: 2951123891
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | NESTED LOOPS OUTER | | 1 | 39 | 2 (0)| 00:00:01 |
| 2 | INLIST ITERATOR | | | | | |
|* 3 | INDEX UNIQUE SCAN | SYS_C0013651 | 3 | 39 | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| TABLE_B | 1 | 26 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | SYS_C0013653 | 1 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('12.1.0.2')
DB_VERSION('12.1.0.2')
OPT_PARAM('optimizer_dynamic_sampling' 11)
OPT_PARAM('optimizer_index_cost_adj' 20)
OPT_PARAM('optimizer_index_caching' 90)
ALL_ROWS
OUTLINE_LEAF(@"SEL$2BFA4EE4")
MERGE(@"SEL$8812AA4E")
OUTLINE(@"SEL$948754D7")
ANSI_REARCH(@"SEL$2")
OUTLINE(@"SEL$8812AA4E")
ANSI_REARCH(@"SEL$1")
OUTLINE(@"SEL$2")
OUTLINE(@"SEL$1")
INDEX(@"SEL$2BFA4EE4" "TABLE_A"@"SEL$1" ("TABLE_A"."A_ID"))
INDEX_RS_ASC(@"SEL$2BFA4EE4" "TABLE_B"@"SEL$1" ("TABLE_B"."B_ID"))
LEADING(@"SEL$2BFA4EE4" "TABLE_A"@"SEL$1" "TABLE_B"@"SEL$1")
USE_NL(@"SEL$2BFA4EE4" "TABLE_B"@"SEL$1")
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access(("TABLE_A"."A_ID"=1 OR "TABLE_A"."A_ID"=3 OR "TABLE_A"."A_ID"=4))
5 - access("A_ID"="B_ID")
filter(("B_ID"=1 OR "B_ID"=3 OR "B_ID"=4))
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
- statistics feedback used for this statement
- this is an adaptive plan
58 rows selected.
到目前为止我发现的结果是正确的,如果
col_1
and (b_id is null or b_id=1)
被添加到where子句table_b
如果没有col_1
,则会有以下执行计划信息(产生正确的结果):
SQL> select a_id, b_id
from table_a left outer join table_b on a_id=b_id
where a_id in (1 , 3 , 4);
A_ID B_ID
---------- ----------
1 1
3
4
SQL> select * from table( dbms_xplan.display_cursor( null, null, '+OUTLINE' ) );
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID cnycu7vr2k975, child number 0
-------------------------------------
select a_id, b_id from table_a left outer join table_b on a_id=b_id
where a_id in (1 , 3 , 4)
Plan hash value: 2928418244
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | NESTED LOOPS OUTER | | 3 | 78 | 2 (0)| 00:00:01 |
| 2 | INLIST ITERATOR | | | | | |
|* 3 | INDEX UNIQUE SCAN| SYS_C0013651 | 3 | 39 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | SYS_C0013653 | 1 | 13 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('12.1.0.2')
DB_VERSION('12.1.0.2')
OPT_PARAM('optimizer_dynamic_sampling' 11)
OPT_PARAM('optimizer_index_cost_adj' 20)
OPT_PARAM('optimizer_index_caching' 90)
ALL_ROWS
OUTLINE_LEAF(@"SEL$2BFA4EE4")
MERGE(@"SEL$8812AA4E")
OUTLINE(@"SEL$948754D7")
ANSI_REARCH(@"SEL$2")
OUTLINE(@"SEL$8812AA4E")
ANSI_REARCH(@"SEL$1")
OUTLINE(@"SEL$2")
OUTLINE(@"SEL$1")
INDEX(@"SEL$2BFA4EE4" "TABLE_A"@"SEL$1" ("TABLE_A"."A_ID"))
INDEX(@"SEL$2BFA4EE4" "TABLE_B"@"SEL$1" ("TABLE_B"."B_ID"))
LEADING(@"SEL$2BFA4EE4" "TABLE_A"@"SEL$1" "TABLE_B"@"SEL$1")
USE_NL(@"SEL$2BFA4EE4" "TABLE_B"@"SEL$1")
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access(("TABLE_A"."A_ID"=1 OR "TABLE_A"."A_ID"=3 OR
"TABLE_A"."A_ID"=4))
4 - access("A_ID"="B_ID")
filter(("B_ID"=1 OR "B_ID"=3 OR "B_ID"=4))
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
如果没有主键约束但包括col_1
,则会有以下执行计划信息(也会产生正确的结果):
SQL> alter table table_b drop primary key;
Table altered.
SQL> select a_id, b_id, col_1
from table_a left outer join table_b on a_id=b_id
where a_id in (1 , 3 , 4);
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3
4
SQL> select * from table( dbms_xplan.display_cursor( null, null, '+OUTLINE' ) );
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 6wg8b65y25utv, child number 2
-------------------------------------
select a_id, b_id, col_1 from table_a left outer join table_b on
a_id=b_id where a_id in (1 , 3 , 4)
Plan hash value: 3493943395
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 4 (100)| |
|* 1 | HASH JOIN OUTER | | 3 | 117 | 4 (0)| 00:00:01 |
| 2 | INLIST ITERATOR | | | | | |
|* 3 | INDEX UNIQUE SCAN| SYS_C0013651 | 3 | 39 | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | TABLE_B | 1 | 26 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('12.1.0.2')
DB_VERSION('12.1.0.2')
OPT_PARAM('optimizer_dynamic_sampling' 11)
OPT_PARAM('optimizer_index_cost_adj' 20)
OPT_PARAM('optimizer_index_caching' 90)
ALL_ROWS
OUTLINE_LEAF(@"SEL$2BFA4EE4")
MERGE(@"SEL$8812AA4E")
OUTLINE(@"SEL$948754D7")
ANSI_REARCH(@"SEL$2")
OUTLINE(@"SEL$8812AA4E")
ANSI_REARCH(@"SEL$1")
OUTLINE(@"SEL$2")
OUTLINE(@"SEL$1")
INDEX(@"SEL$2BFA4EE4" "TABLE_A"@"SEL$1" ("TABLE_A"."A_ID"))
FULL(@"SEL$2BFA4EE4" "TABLE_B"@"SEL$1")
LEADING(@"SEL$2BFA4EE4" "TABLE_A"@"SEL$1" "TABLE_B"@"SEL$1")
USE_HASH(@"SEL$2BFA4EE4" "TABLE_B"@"SEL$1")
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A_ID"="B_ID")
3 - access(("TABLE_A"."A_ID"=1 OR "TABLE_A"."A_ID"=3 OR
"TABLE_A"."A_ID"=4))
4 - filter(("B_ID"=1 OR "B_ID"=3 OR "B_ID"=4))
Note
-----
- dynamic statistics used: dynamic sampling (level=AUTO)
56 rows selected.
我有强烈的感觉,Oracles优化器在某种程度上错误地配置错误,以至于查询结果是错误的。但不幸的是,我无法直接访问它。
问题:上面的选择查询结果是否正确?如果没有,我需要更改哪些优化器设置才能获得正确的结果?
答案 0 :(得分:0)
我得到以下结果:
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3
4
......我认为这是正确答案。
您可以运行查询,然后立即运行以下内容并发布输出:
select * from table( dbms_xplan.display_cursor( null, null, '+OUTLINE' ) );
答案 1 :(得分:0)
总而言之,我将这个答案发布到我自己的问题上,这可以解决它。
如果我按照我的问题所示创建表并插入数据,则以下内容会产生错误的结果(我添加了optimizer参数以使我当前的全局设置更加清晰。如果我省略提示,则会返回相同的输出):
SQL> select /*+ OPT_PARAM('optimizer_index_cost_adj' 20) */ a_id, b_id, col_1
from table_a left outer join table_b on a_id=b_id
where a_id in (1 , 3 , 4);
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3 3
4 4
如果我将优化器参数optimizer_index_cost_adj
的值从20(当前在我的Oracle上全局配置)更改为100(默认值),则会显示正确的结果:
SQL> select /*+ OPT_PARAM('optimizer_index_cost_adj' 100) */ a_id, b_id, col_1
from table_a left outer join table_b on a_id=b_id
where a_id in (1 , 3 , 4);
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3
4
唯一令我困惑的是,没有人能够重现这个问题。所以似乎还有更多东西......