今天同事发给我一个sql,说查询不到结果,sql本身没有错误。而且在其他服务器上执行可以得到结果。
环境如下:
SQL> select * from v$version;
[@more@]
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production
PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Solaris: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production
表结构:
SQL> desc plt_plat
Name Null? Type
-------------------------------------- -------- ----------------
ID NOT NULL CHAR(24)
PLAT_FATHER CHAR(24)
PLAT_CLASS CHAR(1)
PLAT_GRADE NUMBER(2)
PLAT_NAME NOT NULL VARCHAR2(30)
PLAT_LEVEL VARCHAR2(10)
PLAT_DESC VARCHAR2(500)
PLAT_ROOT CHAR(24)
PLAT_CODE VARCHAR2(30)
查询语句:
select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
,province.id,province.plat_name,province.plat_class
from plt_plat pp,
plt_plat city,
plt_plat province
where pp.plat_father=city.id
and city.plat_father=province.id
and pp.plat_class=4
由于这张表是物化视图复制生成的,首先我检查了对象的状态,然后检查了物化视图的脚本,并重新刷新了这张物化视图。错误依旧。和其他服务器上的表进行表结构的对比,没有发现错误。检查表中的数据,发现和其他服务器上的完全一致。使用语句analyze table plt_plat validate structure cascade检查表和索引结构,未发现异常。
怀疑是否是错误的统计信息造成的,执行语句analyze table plt_plat delete statistics;,结果发现得到了正确的结果。
然后重新收集统计信息analyze table plt_plat compute statistics,错误又出现了。
怀疑和执行路径有关:
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=1 Bytes=132)
1 0 HASH JOIN (Cost=7 Card=1 Bytes=132)
2 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=1 Bytes=72)
3 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=330 Bytes=19800)
感觉很奇怪,怎么三张表的连接,执行计划里面只有两张表关联。
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
149 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=RULE
1 0 NESTED LOOPS
2 1 NESTED LOOPS
3 2 TABLE ACCESS (FULL) OF 'PLT_PLAT'
4 2 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
5 4 INDEX (UNIQUE SCAN) OF 'PK_PLT_PLAT' (UNIQUE)
6 1 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
7 6 INDEX (UNIQUE SCAN) OF 'PK_PLT_PLAT' (UNIQUE)
采用rule模式,执行计划是正确的。
下面是在其他服务器上相同表(也是通过物化视图复制生成的)上执行查询的结果。
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
149 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=8 Card=76 Bytes=12692)
1 0 HASH JOIN (Cost=8 Card=76 Bytes=12692)
2 1 HASH JOIN (Cost=5 Card=76 Bytes=9728)
3 2 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=2 Card=76 Bytes=4864)
4 2 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=2 Card=304 Bytes=19456)
5 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=2 Card=304 Bytes=11856)
错误已经很明显了,oracle的执行计划出错。
是什么原因造成的执行计划出错呢?仔细检查初始化参数后发现,query_rewrite_enabled的值是TRUE。
一直没有注意这个参数,是因为的建立物化视图复制的时候并没有指定ENABLE QUERY REWRITE子句,在PLT_PLAT表上也没有建立其它物化视图,而且初始化参数query_rewrite_integrity的值是enforced,这是最严格的设置,没有想到在这种情况下oracle仍然使用了query rewrite,而且查询重写后得到的结果也不正确。
这样看来oracle的查询重写、统计信息的收集以及CBO执行策略还是有些问题的。
下面简要描述一下不同情况下会出现什么问题。
1.将查询重写关闭,无论是否有统计信息,也无论统计信息生成的方式,查询都不会出错。
SQL> alter session set query_rewrite_enabled = false;
Session altered.
SQL> set autot on exp
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
149 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=11 Card=84 Bytes=14028)
1 0 HASH JOIN (Cost=11 Card=84 Bytes=14028)
2 1 HASH JOIN (Cost=7 Card=84 Bytes=10752)
3 2 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=84 Bytes=5376)
4 2 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=334 Bytes=21376)
5 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=334 Bytes=13026)
SQL> analyze table plt_plat delete statistics;
Table analyzed.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
149 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
2 1 NESTED LOOPS
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'PLT_PLAT'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
6 5 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE)
7 2 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE)
2.打开查询重写,基于rule的查询结果正确,如果没有统计信息,all_rows和first_rows结果都是错误的。
SQL> alter session set query_rewrite_enabled = true;
Session altered.
SQL> analyze table plt_plat delete statistics;
Table analyzed.
SQL> alter session set optimizer_mode = rule;
Session altered.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
149 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=RULE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
2 1 NESTED LOOPS
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'PLT_PLAT'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
6 5 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE)
7 2 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE)
SQL> alter session set optimizer_mode = first_rows;
Session altered.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=29 Card=13 Bytes=2132)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT' (Cost=2 Card=1 Bytes=72)
2 1 NESTED LOOPS (Cost=29 Card=13 Bytes=2132)
3 2 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=13 Bytes=1196)
4 2 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE) (Cost=1 Card=1)
SQL> alter session set optimizer_mode = all_rows;
Session altered.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=13 Bytes=2132)
1 0 HASH JOIN (Cost=7 Card=13 Bytes=2132)
2 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=13 Bytes=1196)
3 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=1307 Bytes=94104)
3.打开查询重写,只有使用带FOR ALL (INDEXED) COLUMNS子句的ANALYZE TABLE去收集统计信息,CBO的结果才是正确的,使用其他方式收集统计信息,CBO的查询结果都是错误的。
SQL> analyze table plt_plat delete statistics;
Table analyzed.
SQL> alter session set optimizer_mode = choose;
Session altered.
SQL> analyze table plt_plat compute statistics;
Table analyzed.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=155 Bytes=20460)
1 0 HASH JOIN (Cost=7 Card=155 Bytes=20460)
2 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=84 Bytes=6048)
3 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=334 Bytes=20040)
SQL> analyze table plt_plat delete statistics;
Table analyzed.
SQL> exec dbms_stats.gather_table_stats(user, 'PLT_PLAT', method_opt => 'FOR ALL COLUMNS');
PL/SQL procedure successfully completed.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=84 Bytes=11928)
1 0 HASH JOIN (Cost=7 Card=84 Bytes=11928)
2 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=151 Bytes=11778)
3 1 TABLE ACCESS (FULL) OF 'PLT_PLAT' (Cost=3 Card=334 Bytes=21376)
SQL> exec dbms_stats.delete_table_stats(user, 'PLT_PLAT');
PL/SQL procedure successfully completed.
SQL> analyze table plt_plat compute statistics for all columns;
Table analyzed.
SQL> select pp.id, pp.plat_name, pp.plat_class, city.id, city.plat_name, city.plat_class
2 ,province.id,province.plat_name,province.plat_class
3 from plt_plat pp,
4 plt_plat city,
5 plt_plat province
6 where pp.plat_father=city.id
7 and city.plat_father=province.id
8 and pp.plat_class=4
9 ;
149 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
2 1 NESTED LOOPS
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'PLT_PLAT'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'PLT_PLAT'
6 5 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE)
7 2 INDEX (RANGE SCAN) OF 'IND_PLT_PLAT_PLAT_FATHER' (NON-UNIQUE)
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7490392/viewspace-1041223/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/7490392/viewspace-1041223/