Oracle12 外连接发明列值
Oracle12 outer join invents column values
如果我在 Oracle12 数据库上执行以下语句,我会得到一个我无法解释的结果:
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 不应存在,因为 table 仅包含值 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(@"SELBFA4EE4")
MERGE(@"SEL12AA4E")
OUTLINE(@"SEL8754D7")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL12AA4E")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
INDEX(@"SELBFA4EE4" "TABLE_A"@"SEL" ("TABLE_A"."A_ID"))
INDEX_RS_ASC(@"SELBFA4EE4" "TABLE_B"@"SEL" ("TABLE_B"."B_ID"))
LEADING(@"SELBFA4EE4" "TABLE_A"@"SEL" "TABLE_B"@"SEL")
USE_NL(@"SELBFA4EE4" "TABLE_B"@"SEL")
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.
目前我查到的结果是正确的,如果
- 上面的语句是在较低的 Oracle 版本上执行的
- 我不查询
col_1
- 省略了 where 子句
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(@"SELBFA4EE4")
MERGE(@"SEL12AA4E")
OUTLINE(@"SEL8754D7")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL12AA4E")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
INDEX(@"SELBFA4EE4" "TABLE_A"@"SEL" ("TABLE_A"."A_ID"))
INDEX(@"SELBFA4EE4" "TABLE_B"@"SEL" ("TABLE_B"."B_ID"))
LEADING(@"SELBFA4EE4" "TABLE_A"@"SEL" "TABLE_B"@"SEL")
USE_NL(@"SELBFA4EE4" "TABLE_B"@"SEL")
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(@"SELBFA4EE4")
MERGE(@"SEL12AA4E")
OUTLINE(@"SEL8754D7")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL12AA4E")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
INDEX(@"SELBFA4EE4" "TABLE_A"@"SEL" ("TABLE_A"."A_ID"))
FULL(@"SELBFA4EE4" "TABLE_B"@"SEL")
LEADING(@"SELBFA4EE4" "TABLE_A"@"SEL" "TABLE_B"@"SEL")
USE_HASH(@"SELBFA4EE4" "TABLE_B"@"SEL")
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.
我有一种强烈的感觉,即 Oracle 优化器在某种程度上严重错误地配置,以至于查询结果是错误的。但不幸的是我无法直接访问它。
问题:select上面的查询结果是否正确?如果不是,我需要更改哪些优化器设置才能获得正确的结果?
我得到以下结果:
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3
4
...我认为这是正确答案。
你能运行查询吗,然后紧接着,运行下面,post输出:
select * from table( dbms_xplan.display_cursor( null, null, '+OUTLINE' ) );
总而言之,我 post 这个对我自己的问题的回答,可以帮我解决。
如果我按照我的问题创建表并插入数据,那么以下会产生错误的结果(我添加了优化器参数以使我当前的全局设置更加清晰。如果我省略,则会返回相同的输出提示):
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
唯一让我困惑的是,没有人能够重现这个问题。所以似乎还有更多的东西...
如果我在 Oracle12 数据库上执行以下语句,我会得到一个我无法解释的结果:
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 不应存在,因为 table 仅包含值 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(@"SELBFA4EE4")
MERGE(@"SEL12AA4E")
OUTLINE(@"SEL8754D7")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL12AA4E")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
INDEX(@"SELBFA4EE4" "TABLE_A"@"SEL" ("TABLE_A"."A_ID"))
INDEX_RS_ASC(@"SELBFA4EE4" "TABLE_B"@"SEL" ("TABLE_B"."B_ID"))
LEADING(@"SELBFA4EE4" "TABLE_A"@"SEL" "TABLE_B"@"SEL")
USE_NL(@"SELBFA4EE4" "TABLE_B"@"SEL")
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.
目前我查到的结果是正确的,如果
- 上面的语句是在较低的 Oracle 版本上执行的
- 我不查询
col_1
- 省略了 where 子句
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(@"SELBFA4EE4")
MERGE(@"SEL12AA4E")
OUTLINE(@"SEL8754D7")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL12AA4E")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
INDEX(@"SELBFA4EE4" "TABLE_A"@"SEL" ("TABLE_A"."A_ID"))
INDEX(@"SELBFA4EE4" "TABLE_B"@"SEL" ("TABLE_B"."B_ID"))
LEADING(@"SELBFA4EE4" "TABLE_A"@"SEL" "TABLE_B"@"SEL")
USE_NL(@"SELBFA4EE4" "TABLE_B"@"SEL")
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(@"SELBFA4EE4")
MERGE(@"SEL12AA4E")
OUTLINE(@"SEL8754D7")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL12AA4E")
ANSI_REARCH(@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
INDEX(@"SELBFA4EE4" "TABLE_A"@"SEL" ("TABLE_A"."A_ID"))
FULL(@"SELBFA4EE4" "TABLE_B"@"SEL")
LEADING(@"SELBFA4EE4" "TABLE_A"@"SEL" "TABLE_B"@"SEL")
USE_HASH(@"SELBFA4EE4" "TABLE_B"@"SEL")
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.
我有一种强烈的感觉,即 Oracle 优化器在某种程度上严重错误地配置,以至于查询结果是错误的。但不幸的是我无法直接访问它。
问题:select上面的查询结果是否正确?如果不是,我需要更改哪些优化器设置才能获得正确的结果?
我得到以下结果:
A_ID B_ID COL_1
---------- ---------- ----------
1 1 100
3
4
...我认为这是正确答案。
你能运行查询吗,然后紧接着,运行下面,post输出:
select * from table( dbms_xplan.display_cursor( null, null, '+OUTLINE' ) );
总而言之,我 post 这个对我自己的问题的回答,可以帮我解决。
如果我按照我的问题创建表并插入数据,那么以下会产生错误的结果(我添加了优化器参数以使我当前的全局设置更加清晰。如果我省略,则会返回相同的输出提示):
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
唯一让我困惑的是,没有人能够重现这个问题。所以似乎还有更多的东西...