11G繫結變數情況下的選擇率不再是5%?BUG?

wei-xh發表於2011-06-13

10G的時候
SQL> select * from v$version where rownum=1;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

SQL> select num_rows from user_tables where table_name='WXH_TBD1';

  NUM_ROWS
----------
    200000

explain plan for
select * from wxh_tbd1 where object_id>:a;
SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-----------------------------------------------
Plan hash value: 1038246325

-----------------------------------------------
| Id  | Operation         | Name     | Rows  |
-----------------------------------------------
|   0 | SELECT STATEMENT  |          | 10000 |
|*  1 |  TABLE ACCESS FULL| WXH_TBD1 | 10000 |
-----------------------------------------------


explain plan for
select * from wxh_tbd1 where object_id>:a and object_id<:b>
SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-----------------------------------------------
Plan hash value: 1744766238

-----------------------------------------------
| Id  | Operation          | Name     | Rows  |
-----------------------------------------------
|   0 | SELECT STATEMENT   |          |   500 |
|*  1 |  FILTER            |          |       |
|*  2 |   TABLE ACCESS FULL| WXH_TBD1 |   500 |
-----------------------------------------------

10G都是對的,開區間的時候,10000/200000=5%,閉區間的時候,500/200000=5%*5%,都是正確的。


看看11G
select * from v$version where rownum=1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production

select num_rows from user_tables where table_name='WXH_TBD';
  NUM_ROWS
----------
     19366

explain plan for
  select * from wxh_tbd where object_id>:A;
Explained.

select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3295978849
-----------------------------------------------------------------------------
| Id  | Operation         | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |   966 | 89838 |   144   (3)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| WXH_TBD |   966 | 89838 |   144   (3)| 00:00:01 |
-----------------------------------------------------------------------------

966/19366=5%,是OK的。

explain plan for
select * from wxh_tbd where object_id>:A AND OBJECT_ID<:b>select * from table(dbms_xplan.display);
------------------------------------------------------------------------------
| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |   966 | 89838 |   144   (3)| 00:00:01 |
|*  1 |  FILTER            |         |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| WXH_TBD |   966 | 89838 |   144   (3)| 00:00:01 |
------------------------------------------------------------------------------

我們看到沒變化。

還是966.看來11G以後不管是開區間還是閉區間,都是預設的5%了,而不會像以前那樣相乘了。(都是繫結變數的情況)

select /*+ index(wxh_tbd) */ object_name from wxh_tbd where object_id > :a;
-------------------------------------------------------
| Id  | Operation                   | Name    | Rows  |
-------------------------------------------------------
|   0 | SELECT STATEMENT            |         |  2492 |
|   1 |  TABLE ACCESS BY INDEX ROWID| WXH_TBD |  2492 |
|*  2 |   INDEX RANGE SCAN          | PK_N    |   449 |
-------------------------------------------------------

  2 - access("OBJECT_ID">TO_NUMBER(:A))

最終表的選擇率是5%。2492/49842=5%.
可是索引的基數449不知道咋算的,沒查到資料,讓人摸不到頭腦,不按套路來

 

非繫結變數的情況下的選擇性和基數都是可以算出來的。我只是不知道這個開區間,繫結變數的情況下,索引如何去計算的這個選擇性和基數。
explain plan for select /*+ index(wxh_tbd1 T_1) */ object_name from wxh_tbd1 where object_id >12345;
select * from table(dbms_xplan.display);
--------------------------------------------------------
| Id  | Operation                   | Name     | Rows  |
--------------------------------------------------------
|   0 | SELECT STATEMENT            |          | 17913 |
|   1 |  TABLE ACCESS BY INDEX ROWID| WXH_TBD1 | 17913 |
|*  2 |   INDEX RANGE SCAN          | T_1      | 17913 |
--------------------------------------------------------

這種非繫結變數的情況,我是可以算出來的。
select min(object_id) from wxh_tbd1;

MIN(OBJECT_ID)
--------------
             2
select max(object_id) from wxh_tbd1;

MAX(OBJECT_ID)
--------------
        159398
select count(*) from wxh_tbd1;

  COUNT(*)
----------
     19463
SELECT column_name,NUM_NULLS FROM USER_TAB_COLS WHERE TABLE_NAME='WXH_TBD1' and column_name='OBJECT_ID';

COLUMN_NAME           NUM_NULLS
-------------------- ----------
OBJECT_ID                    47

選擇率=(最大值-開區間值)/最大值
基數=選擇率*總行數(非空)
select ((159398-12345)/159398)*(19463-47) FROM DUAL;


((159398-12345)/159398)*(19463-47)
----------------------------------
                        17912.2765

可以看到最後計算的結果跟ORACLE計算出來的是一樣的。
只是不知道開區間繫結變數的情況,ORACLE是怎麼計算的。


[ 本帖最後由 wei-xh 於 2011-6-13 10:04 編輯 ]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-697788/,如需轉載,請註明出處,否則將追究法律責任。

相關文章