1. 程式人生 > >ORACLE 用ROWID 刪除資料竟然的走索引-不得其解

ORACLE 用ROWID 刪除資料竟然的走索引-不得其解

下午一個同事執行一條刪除語句1個小時才執行了11萬條

該語句是DELETE FROM TABLE_NAME WHERE ROWID=’XXXXAAAA’

執行計劃確實走索引一個以CREATE_TIME為主的索引.

後來很多同事不得其解本以為寫了ROWID,那該直接去表裡把資料給刪了,為啥還要去訪問索引呢? 我們的DBA解釋到因為該表沒做分析索引也沒做分析.

不過回家實驗了一把瞧瞧看

SQL> create table t_test (id number,name varchar2(35),create_time date);

Table created

SQL> create index idx_test_createtime on t_test(create_time);

Index created

SQL> insert into t_test  select object_id,object_name,sysdate from dba_objects;

50333 rows inserted

SQL> commit;

Commit complete

不做分析:

一些預設的引數

SQL> show parameter optimizer_index_cost_adj

optimizer_index_cost_adj             integer     100

optimizer_index_caching              integer     0

db_block_buffers                     integer     0

db_block_checking                   string      FALSE

db_block_checksum                  string      TRUE

db_block_size                       integer     8192

db_file_multiblock_read_count         integer     32

執行刪除語句看執行計劃

delete t_test where id >500

delete t_test where id=:1

delete t_test where rowed=’ AAAM3OAAEAAAAOEAAA’

結果執行計劃沒走索引

DELETE STATEMENT, GOAL = ALL_ROWS   Depth=0 Operation=DELETE STATEMENT      DELETE  Depth=1    Operation=DELETE    Object name=T_TEST                        TABLE ACCESS BY USER ROWID Depth=2    Operation=TABLE ACCESS     

分析下

SQL> analyze table t_test compute statistics;

Table analyzed

發現還是不走索引

試下分割槽表

create table t_test_2 as select * from t_test

SQL> update t_test_2 set create_time=sysdate-1 where id<=10000;

9581 rows updated

SQL> update t_test_2 set create_time=sysdate-2 where id<=20000 and id>10000;

9974 rows updated

SQL> update t_test_2 set create_time=sysdate-3 where id<=30000 and id>20000;

10000 rows updated

SQL> update t_test_2 set create_time=sysdate-4 where id<=40000 and id>30000;

9997 rows updated

SQL> update t_test_2 set create_time=sysdate-5 where id<=50000 and id>40000;

9089 rows updated

SQL> commit;

Commit complete

SQL> select to_char(create_time,'yyyymmdd') as statedate,count(*) t from t_test_2 group by to_char(create_time,'yyyymmdd');

STATEDATE          T

--------- ----------

20120528        9974

20120527       10000

20120530        1692

20120529        9581

20120526        9997

20120525        9089

6 rows selected

建立時間範圍分割槽表:

-- Create table

create table t_test_3

(  id          number,

  name        varchar2(35),

  create_time date

)partition by range (create_time)

(  partition test_20120525 values less than (to_date('2012-05-26','yyyy-mm-dd')),

  partition test_20120526 values less than (to_date('2012-05-27','yyyy-mm-dd')),

  partition test_20120527 values less than (to_date('2012-05-28','yyyy-mm-dd')),

  partition test_20120528 values less than (to_date('2012-05-29','yyyy-mm-dd')),

  partition test_20120529 values less than (to_date('2012-05-30','yyyy-mm-dd')),

  partition test_20120530 values less than (to_date('2012-05-31','yyyy-mm-dd'))

);

建立本地索引並插入資料

SQL> create index idx_local_createtime on t_test_3 (create_time) local;

Index created

SQL> insert into t_test_3  select id,name,create_time from t_test_2;

50333 rows inserted

SQL> commit;

Commit complete

delete t_test where id=:1

delete t_test where rowed=’ AAAM3OAAEAAAAOEAAA’

執行計劃依舊是TABLE ACCESS BY USER ROWID

分別設定引數

SQL> alter system set optimizer_index_caching=100;

System altered

SQL> alter system set optimizer_index_cost_adj=1;

System altered

結果執行計劃依舊是TABLE ACCESS BY USER ROWID

執行分析

SQL> EXEC dbms_stats.gather_table_stats

  (ownname=>'SHARK', tabname=>'T_TEST_3',estimate_percent=>100,cascade=>true);

PL/SQL procedure successfully completed

執行計劃依舊是TABLE ACCESS BY USER ROWID

建立子分割槽

SQL> update t_test_2 set id=mod(id,10);

50333 rows updated

SQL>CREATE TABLE SHARK.t_test_4
(
 
id           NUMBER,
  name         VARCHAR2(35),
 
create_time  DATE
)
PARTITION BY RANGE (create_time)
SUBPARTITION BY LIST (id)
SUBPARTITION TEMPLATE
  (SUBPARTITION "A" VALUES (0),
  
SUBPARTITION "B" VALUES (1),
  
SUBPARTITION "C" VALUES (2),
  
SUBPARTITION "D" VALUES (3),
  
SUBPARTITION "E" VALUES (4),
  
SUBPARTITION "F" VALUES (5),
  
SUBPARTITION "G" VALUES (6),
  
SUBPARTITION "H" VALUES (7),
  
SUBPARTITION "J" VALUES (8),
  
SUBPARTITION "K" VALUES (9)
 
)

  PARTITION TEST_20120525 VALUES LESS THAN (to_date('2012-05-26', 'yyyy-mm-dd')), 
  PARTITION TEST_20120526 VALUES LESS THAN  (to_date('2012-05-27', 'yyyy-mm-dd')) , 
  PARTITION TEST_20120527 VALUES LESS THAN (to_date('2012-05-28', 'yyyy-mm-dd'))   
  PARTITION TEST_20120528 VALUES LESS THAN  (to_date('2012-05-29', 'yyyy-mm-dd'))   
  PARTITION TEST_20120529 VALUES LESS THAN (to_date('2012-05-30', 'yyyy-mm-dd'))   
  PARTITION TEST_20120530 VALUES LESS THAN  (to_date('2012-05-31', 'yyyy-mm-dd'))   
);

SQL> insert into t_test_4 select * from t_test_2;

50333 rows inserted

SQL> commit;

Commit complete

SQL> create index idx_local_createtime_test4 on t_test_4 (create_time) local;

Index created

SQL> EXEC dbms_stats.gather_table_stats 

(ownname=>'SHARK', tabname=>'T_TEST_4',estimate_percent=>100,cascade=>true);

PL/SQL procedure successfully completed

SQL> create index idx_local_id_test4 on t_test_4 (id) local;

Index created

很不幸運的是執行計劃依舊是TABLE ACCESS BY USER ROWID

只有下面的語句才用到了索引

delete t_test_4 where id =4

delete

partition range all

partition list single

index range scan

SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

 公司的資料庫伺服器應該是10.2.0.4的吧? 涉及到表都是分割槽,或者子分割槽.本地索引,未分析!