[20130319]一條sql語句的優化.txt

lfree發表於2013-03-19
[20130319]一條sql語句的優化.txt

生產系統,遇到這樣一條語句:
SELECT MAX (LENGTH (pe_id)) FROM pe_master_index WHERE SUBSTR (pe_id, 1, 2) = 'TJ';

--真不知道開發人員如何想的,寫出這樣的語句.欄位pe_id是主鍵.
--資料庫版本
SQL> select * from v$version where rownum<=1;

BANNER                                                         
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
1 row selected.

SQL> SELECT MAX (LENGTH (pe_id)) FROM pe_master_index WHERE SUBSTR (pe_id, 1, 2) = 'TJ';

MAX(LENGTH(PE_ID))
------------------
                10

SQL> @dpc ''

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  awfcmwrca41fc, child number 0
-------------------------------------
SELECT MAX (LENGTH (pe_id)) FROM pe_master_index WHERE SUBSTR (pe_id,1, 2) = 'TJ'
Plan hash value: 2553983512
-------------------------------------------------------------
| Id  | Operation             | Name               | E-Rows |
-------------------------------------------------------------
|   1 |  SORT AGGREGATE       |                    |      1 |
|*  2 |   INDEX FAST FULL SCAN| PK_PE_MASTER_INDEX |   7053 |
-------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX_FFS(@"SEL$1" "PE_MASTER_INDEX"@"SEL$1"
              ("PE_MASTER_INDEX"."PE_ID"))
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SUBSTR("PE_ID",1,2)='TJ')

--建立 SUBSTR (pe_id, 1, 2),LENGTH (pe_id),這樣的函式索引在這個版本下,會使用新建的索引,但是執行計劃還是INDEX FAST FULL
--SCAN.優化效果不明顯.好像10.2.0.4可以很好的使用這樣的索引,並且執行計劃走INDEX RANGE SCAN (MIN/MAX).

自己在11G下做一個測試:

create table t1 as select 'tj'||lpad(rownum,8,'0') pe_id,lpad('x',100,'x') vc from dual connect by level<=10000;
create unique index scott.pk_t1 on t1(pe_id) ;
alter table t1 add constraint pk_t1  primary key (pe_id);
exec dbms_stats.gather_table_stats(USER,'T1',METHOD_OPT => 'FOR ALL COLUMNS SIZE 1 ',No_Invalidate => FALSE);

SQL> SELECT MAX (LENGTH (pe_id)) FROM t1 WHERE SUBSTR (pe_id, 1, 2) = 'tj';
MAX(LENGTH(PE_ID))
------------------
                10

SQL> @dpc '' ''

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
SQL_ID  02mdzdry4jpt9, child number 0
-------------------------------------
SELECT MAX (LENGTH (pe_id)) FROM t1 WHERE SUBSTR (pe_id, 1, 2) = 'tj'

Plan hash value: 1953966236

-------------------------------------------------------------
| Id  | Operation             | Name  | E-Rows | Cost (%CPU)|
-------------------------------------------------------------
|   0 | SELECT STATEMENT      |       |        |    11 (100)|
|   1 |  SORT AGGREGATE       |       |      1 |            |
|*  2 |   INDEX FAST FULL SCAN| PK_T1 |    100 |    11  (10)|
-------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SUBSTR("PE_ID",1,2)='tj')

SQL> create  index if_t1_pe_id on t1(SUBSTR (pe_id, 1, 2),LENGTH (pe_id)) ;

SQL> SELECT MAX (LENGTH (pe_id)) FROM t1 WHERE SUBSTR (pe_id, 1, 2) = 'tj';

MAX(LENGTH(PE_ID))
------------------
                10

SQL> @dpc '' ''

PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  02mdzdry4jpt9, child number 0
-------------------------------------
SELECT MAX (LENGTH (pe_id)) FROM t1 WHERE SUBSTR (pe_id, 1, 2) = 'tj'

Plan hash value: 2812640901

--------------------------------------------------------------------------
| Id  | Operation                    | Name        | E-Rows | Cost (%CPU)|
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |        |     2 (100)|
|   1 |  SORT AGGREGATE              |             |      1 |            |
|   2 |   FIRST ROW                  |             |      1 |     2   (0)|
|*  3 |    INDEX RANGE SCAN (MIN/MAX)| IF_T1_PE_ID |      1 |     2   (0)|
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("T1"."SYS_NC00003$"='tj')

--11G下可以使用這樣的索引走INDEX RANGE SCAN (MIN/MAX).

參看
http://space.itpub.net/267265/viewspace-715313
http://space.itpub.net/267265/viewspace-715314
http://space.itpub.net/267265/viewspace-715315
http://space.itpub.net/267265/viewspace-715390

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

相關文章