1.不一定unusable,可以先删除data (index 再删除过程中会更新结构)再drop/truncate.
----------------------
CREATE TABLE interval_sale
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
)
PARTITION BY RANGE (time_id)
INTERVAL(NUMTOYMINTERVAL(1, 'YEAR'))
( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2003', 'DD-MM-YYYY')),
PARTITION p1 VALUES LESS THAN (TO_DATE('1-1-2004', 'DD-MM-YYYY')),
PARTITION p2 VALUES LESS THAN (TO_DATE('1-1-2005', 'DD-MM-YYYY')),
PARTITION p3 VALUES LESS THAN (TO_DATE('1-1-2006', 'DD-MM-YYYY')));
insert into interval_sale values(1, 1, to_date('2002-01-01','yyyy-mm-dd'));
insert into interval_sale values(2, 2, to_date('2003-01-01','yyyy-mm-dd'));
insert into interval_sale values(3, 3, to_date('2004-01-01','yyyy-mm-dd'));
insert into interval_sale values(4, 4, to_date('2005-01-01','yyyy-mm-dd'));
commit;
select *from interval_sale;
create index idx_01 on interval_sale(cust_id);
create index idx_02 on interval_sale(prod_id) local;
select dp.table_name,dp.num_rows,dp.partition_name,to_char(dp.last_analyzed,'yyyymmdd HH24MISS') from dba_tab_partitions dp where dp.table_name='INTERVAL_SALE' ;
select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS'),di.partition_name,di.distinct_keys ,di.status from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
select dt.table_name,dt.num_rows,to_char(dt.last_analyzed,'yyyymmdd HH24MISS') from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS') ,di.distinct_keys ,status from dba_indexes di where di.index_name like 'IDX_0%' ;
alter index idx_01 rebuild ;
alter index idx_02 rebuild partition P0;
alter index idx_02 rebuild partition P1;
alter index idx_02 rebuild partition P2;
alter index idx_02 rebuild partition P3;
alter table INTERVAL_SALE drop partition p2 UPDATE INDEXES;
alter table INTERVAL_SALE MERGE PARTITIONS p0, p1 INTO PARTITION p01 UPDATE INDEXES;
alter table INTERVAL_SALE MERGE PARTITIONS p01, p3 INTO PARTITION p0123 UPDATE global INDEXES;
alter table INTERVAL_SALE MERGE PARTITIONS p012, p3 INTO PARTITION p0123 UPDATE INDEXES;
----------------------------
㈡ 对全局索引的作用
大分区表truncate partition后,需要对全局索引进行维护,否则,global index会变成unusable
问题介绍:
① 在drop partition时,为了维护global索引,要加update indexes或是update global indexes条件
请问,大家研究过这两个条件的区别吗?
UPDATE GLOBAL INDEXES只维护全局索引
UPDATE INDEXES同时维护全局和本地索引
对于DROP/TRUNCATE PARTITION而言 ,二者没有太大的区别
对于MERGE和SPLIT PARTITION,你就可以看到二者的区别了
-----UPDATE GLOBAL INDEXES 时 Partition 没reubild 好
---------------------坏了之后还能好,肯定是rebuild了
虽然index是变得valid了,但是index的空间没有释放
因为该操作不等于REBUILD,只是在进行DDL的时候,同步维护索引信息而已?
不太认可,虽然update indexes后row num确实没变,不太等同于rebuild index,但是这个过程中其实类似rebuild index 的。否则update会很快,不会出现上亿记录update好几分钟。
IDX_01 在drop paritition后rownum 应该会变少,但这里没变,rebuild 后会变,
上例子merge也是Partition变,global 不确定变没变,因为merge 不会改变数据,可能也不会update global的数据量的。
-------再次验证。 dba_ind_partitions 和dba_tab_partitions(之前都没变) 都会变,dba_tables,dba_indexes 不变
SQL> select dp.table_name,dp.num_rows,dp.partition_name,to_char(dp.last_analyzed,'yyyymmdd HH24MISS') from dba_tab_partitions dp where dp.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS PARTITION_NAME TO_CHAR(DP.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- --------------------------------------------
INTERVAL_SALE P0
INTERVAL_SALE P1
INTERVAL_SALE P2
INTERVAL_SALE P3
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS'),di.partition_name,di.distinct_keys ,di.status from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') PARTITION_NAME DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- -------------------------------------------------------------------------------- ------------- --------
SQL> select dt.table_name,dt.num_rows,to_char(dt.last_analyzed,'yyyymmdd HH24MISS') from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS TO_CHAR(DT.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- --------------------------------------------
INTERVAL_SALE
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS') ,di.distinct_keys ,status from dba_indexes di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- ------------- --------
SQL>
SQL> select dp.table_name,dp.num_rows,dp.partition_name,to_char(dp.last_analyzed,'yyyymmdd HH24MISS') from dba_tab_partitions dp where dp.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS PARTITION_NAME TO_CHAR(DP.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- --------------------------------------------
INTERVAL_SALE P0
INTERVAL_SALE P1
INTERVAL_SALE P2
INTERVAL_SALE P3
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS'),di.partition_name,di.distinct_keys ,di.status from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') PARTITION_NAME DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- -------------------------------------------------------------------------------- ------------- --------
IDX_02 7 20240801 200718 P0 1 USABLE
IDX_02 7 20240801 200718 P1 1 USABLE
IDX_02 7 20240801 200718 P2 1 USABLE
IDX_02 7 20240801 200718 P3 1 USABLE
SQL> select dt.table_name,dt.num_rows,to_char(dt.last_analyzed,'yyyymmdd HH24MISS') from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS TO_CHAR(DT.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- --------------------------------------------
INTERVAL_SALE
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS') ,di.distinct_keys ,status from dba_indexes di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- ------------- --------
IDX_01 28 20240801 200718 4 VALID
IDX_02 28 20240801 200718 1 N/A
SQL> alter table INTERVAL_SALE MERGE PARTITIONS p0, p1 INTO PARTITION p01 UPDATE INDEXES;
Table altered
SQL>
SQL> select dp.table_name,dp.num_rows,dp.partition_name,to_char(dp.last_analyzed,'yyyymmdd HH24MISS') from dba_tab_partitions dp where dp.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS PARTITION_NAME TO_CHAR(DP.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- --------------------------------------------
INTERVAL_SALE 14 P01 20240801 200810
INTERVAL_SALE P2
INTERVAL_SALE P3
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS'),di.partition_name,di.distinct_keys ,di.status from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') PARTITION_NAME DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- -------------------------------------------------------------------------------- ------------- --------
IDX_02 14 20240801 200811 P01 2 USABLE
IDX_02 7 20240801 200718 P2 1 USABLE
IDX_02 7 20240801 200718 P3 1 USABLE
SQL> select dt.table_name,dt.num_rows,to_char(dt.last_analyzed,'yyyymmdd HH24MISS') from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS TO_CHAR(DT.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- --------------------------------------------
INTERVAL_SALE
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS') ,di.distinct_keys ,status from dba_indexes di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- ------------- --------
IDX_01 28 20240801 200718 4 VALID
IDX_02 28 20240801 200718 1 N/A
SQL> alter table INTERVAL_SALE drop partition p2 UPDATE INDEXES;
Table altered
SQL>
SQL> select dp.table_name,dp.num_rows,dp.partition_name,to_char(dp.last_analyzed,'yyyymmdd HH24MISS') from dba_tab_partitions dp where dp.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS PARTITION_NAME TO_CHAR(DP.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- --------------------------------------------
INTERVAL_SALE 14 P01 20240801 200810
INTERVAL_SALE P3
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS'),di.partition_name,di.distinct_keys ,di.status from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') PARTITION_NAME DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- -------------------------------------------------------------------------------- ------------- --------
IDX_02 14 20240801 200811 P01 2 USABLE
IDX_02 7 20240801 200718 P3 1 USABLE
SQL> select dt.table_name,dt.num_rows,to_char(dt.last_analyzed,'yyyymmdd HH24MISS') from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
TABLE_NAME NUM_ROWS TO_CHAR(DT.LAST_ANALYZED,'YYYYMMDDHH24MISS')
-------------------------------------------------------------------------------- ---------- --------------------------------------------
INTERVAL_SALE
SQL> select di.index_name,di.num_rows,to_char(di.last_analyzed,'yyyymmdd HH24MISS') ,di.distinct_keys ,status from dba_indexes di where di.index_name like 'IDX_0%' ;
INDEX_NAME NUM_ROWS TO_CHAR(DI.LAST_ANALYZED,'YYYYMMDDHH24MISS') DISTINCT_KEYS STATUS
-------------------------------------------------------------------------------- ---------- -------------------------------------------- ------------- --------
IDX_01 28 20240801 200718 4 VALID
IDX_02 28 20240801 200718 1 N/A
SQL>
-----------------------------1---------------
下面的情况为什么会慢的原因是,truncate后,可能更新了Statistics,导致了分区的num rows=0,所以其后的执行计划都是错误的。 在有数据的情况下rebuild index,Oracle 会更新index Statistics. table的Statistics不变。
13亿记录的大表truncate后来接着晚上有人继续插入这个表的时候,告诉我慢的要命,(truncate后有人手动更新了Statistics)
本来一个小时至少可以跑完400万条记录,现在3个小时了才跑130万
我马上想到会不会是本地索引问题,因为我听说虽然分区交换或者TRUNCATE对局部索引没影响,
但是实际上是有问题的,还是重建的好(gather Statistics 更好):
alter index bill.UNQ_RRATING_CHARGE_D_591_0712 rebuild partition PART_20
把这个刚才我TRUNCATE的分区的涉及到的局部索引重新建了一下
结果立马见效果了,10分钟跑了200万条记录,600万条记录在20分钟全部跑好!比以前同期跑的还快一点
---DDL重新index会更新index 的Statistics, truncate 不会。
CREATE TABLE interval_sale
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
)
PARTITION BY RANGE (time_id)
INTERVAL(NUMTOYMINTERVAL(1, 'YEAR'))
( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2003', 'DD-MM-YYYY')),
PARTITION p1 VALUES LESS THAN (TO_DATE('1-1-2004', 'DD-MM-YYYY')),
PARTITION p2 VALUES LESS THAN (TO_DATE('1-1-2005', 'DD-MM-YYYY')),
PARTITION p3 VALUES LESS THAN (TO_DATE('1-1-2006', 'DD-MM-YYYY')));
insert into interval_sale values(1, 1, to_date('2002-01-01','yyyy-mm-dd'));
insert into interval_sale values(2, 2, to_date('2003-01-01','yyyy-mm-dd'));
insert into interval_sale values(3, 3, to_date('2004-01-01','yyyy-mm-dd'));
insert into interval_sale values(4, 4, to_date('2005-01-01','yyyy-mm-dd'));
commit;
select *from interval_sale
create index idx_01 on interval_sale(cust_id);
select table_name, index_name, partitioned, status
from user_indexes where table_name='INTERVAL_SALE';
create index idx_02 on interval_sale(prod_id) local;
select dp.table_owner,dp.table_name,dp.num_rows,dp.partition_name,dp.last_analyzed from dba_tab_partitions dp
where dp.table_name='INTERVAL_SALE' ;
select di.index_owner,di.index_name,di.num_rows,di.last_analyzed,di.partition_name,di.distinct_keys
from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
select dt.owner,dt.table_name,dt.num_rows, dt.last_analyzed from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
select di.owner,di.index_name,di.num_rows,di.last_analyzed ,di.distinct_keys from dba_indexes di
where di.index_name like 'IDX_0%' ;
alter index idx_01 rebuild ;
alter index idx_02 rebuild partition P0;
alter index idx_02 rebuild partition P1;
alter index idx_02 rebuild partition P2;
alter index idx_02 rebuild partition P3;
SQL> select dp.table_owner,dp.table_name,dp.num_rows,dp.partition_name,dp.last_analyzed from dba_tab_partitions dp
2 where dp.table_name='INTERVAL_SALE' ;
TABLE_OWNER TABLE_NAME NUM_ROWS PARTITION_NAME LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- -------------
AAA INTERVAL_SALE P0
AAA INTERVAL_SALE P1
AAA INTERVAL_SALE P2
AAA INTERVAL_SALE P3
------分区表上Statistics为空
SQL> select di.index_owner,di.index_name,di.num_rows,di.last_analyzed,di.partition_name,di.distinct_keys
2 from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED PARTITION_NAME DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------------------------------------------------------------------------- -------------
AAA IDX_02 0 01/08/2024 6: P0 0
AAA IDX_02 0 01/08/2024 6: P1 0
AAA IDX_02 1 01/08/2024 6: P2 1
AAA IDX_02 1 01/08/2024 6: P3 1
-----index 先插入记录再创建 index ,自动更新,但是创建完index 再insert,不会更新。
SQL> select dt.owner,dt.table_name,dt.num_rows, dt.last_analyzed from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
OWNER TABLE_NAME NUM_ROWS LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------
AAA INTERVAL_SALE
---- table上面也是空的
SQL> select di.owner,di.index_name,di.num_rows,di.last_analyzed ,di.distinct_keys from dba_indexes di
2 where di.index_name like 'IDX_0%' ;
OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------
AAA IDX_01 2 01/08/2024 6: 2
AAA IDX_02 2 01/08/2024 6: 1
----分区也是,先建再加会显示
SQL> insert into interval_sale values(1, 1, to_date('2002-01-01','yyyy-mm-dd'));
1 row inserted
SQL> insert into interval_sale values(2, 2, to_date('2003-01-01','yyyy-mm-dd'));
1 row inserted
SQL> insert into interval_sale values(3, 3, to_date('2004-01-01','yyyy-mm-dd'));
1 row inserted
SQL> insert into interval_sale values(4, 4, to_date('2005-01-01','yyyy-mm-dd'));
1 row inserted
----------进一步验证 index创建后插入数据没有任何改变
SQL>
SQL> select dp.table_owner,dp.table_name,dp.num_rows,dp.partition_name,dp.last_analyzed from dba_tab_partitions dp
2 where dp.table_name='INTERVAL_SALE' ;
TABLE_OWNER TABLE_NAME NUM_ROWS PARTITION_NAME LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- -------------
AAA INTERVAL_SALE P0
AAA INTERVAL_SALE P1
AAA INTERVAL_SALE P2
AAA INTERVAL_SALE P3
SQL> select di.index_owner,di.index_name,di.num_rows,di.last_analyzed,di.partition_name,di.distinct_keys
2 from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED PARTITION_NAME DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------------------------------------------------------------------------- -------------
AAA IDX_02 0 01/08/2024 6: P0 0
AAA IDX_02 0 01/08/2024 6: P1 0
AAA IDX_02 1 01/08/2024 6: P2 1
AAA IDX_02 1 01/08/2024 6: P3 1
SQL> select dt.owner,dt.table_name,dt.num_rows, dt.last_analyzed from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
OWNER TABLE_NAME NUM_ROWS LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------
AAA INTERVAL_SALE
SQL> select di.owner,di.index_name,di.num_rows,di.last_analyzed ,di.distinct_keys from dba_indexes di
2 where di.index_name like 'IDX_0%' ;
OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------
AAA IDX_01 2 01/08/2024 6: 2
AAA IDX_02 2 01/08/2024 6: 1
----------------------DDL on index,index Statistics 会变---------------------------
SQL> alter index idx_01 rebuild;
SQL>
SQL> select dp.table_owner,dp.table_name,dp.num_rows,dp.partition_name,dp.last_analyzed from dba_tab_partitions dp
2 where dp.table_name='INTERVAL_SALE' ;
TABLE_OWNER TABLE_NAME NUM_ROWS PARTITION_NAME LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- -------------
AAA INTERVAL_SALE P0
AAA INTERVAL_SALE P1
AAA INTERVAL_SALE P2
AAA INTERVAL_SALE P3
SQL> select di.index_owner,di.index_name,di.num_rows,di.last_analyzed,di.partition_name,di.distinct_keys
2 from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED PARTITION_NAME DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------------------------------------------------------------------------- -------------
AAA IDX_02 0 01/08/2024 6: P0 0
AAA IDX_02 0 01/08/2024 6: P1 0
AAA IDX_02 1 01/08/2024 6: P2 1
AAA IDX_02 1 01/08/2024 6: P3 1
SQL> select dt.owner,dt.table_name,dt.num_rows, dt.last_analyzed from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
OWNER TABLE_NAME NUM_ROWS LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------
AAA INTERVAL_SALE
SQL> select di.owner,di.index_name,di.num_rows,di.last_analyzed ,di.distinct_keys from dba_indexes di
2 where di.index_name like 'IDX_0%' ;
OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------
AAA IDX_01 8 01/08/2024 6: 4
AAA IDX_02 2 01/08/2024 6: 1
SQL>
SQL> alter index idx_02 rebuild partition P0;
Index altered
SQL> alter index idx_02 rebuild partition P1;
Index altered
SQL> alter index idx_02 rebuild partition P2;
Index altered
SQL> alter index idx_02 rebuild partition P3;
Index altered
SQL>
SQL>
SQL> select dp.table_owner,dp.table_name,dp.num_rows,dp.partition_name,dp.last_analyzed from dba_tab_partitions dp
2 where dp.table_name='INTERVAL_SALE' ;
TABLE_OWNER TABLE_NAME NUM_ROWS PARTITION_NAME LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- -------------
AAA INTERVAL_SALE P0
AAA INTERVAL_SALE P1
AAA INTERVAL_SALE P2
AAA INTERVAL_SALE P3
SQL> select di.index_owner,di.index_name,di.num_rows,di.last_analyzed,di.partition_name,di.distinct_keys
2 from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED PARTITION_NAME DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------------------------------------------------------------------------- -------------
AAA IDX_02 2 01/08/2024 6: P0 1
AAA IDX_02 2 01/08/2024 6: P1 1
AAA IDX_02 2 01/08/2024 6: P2 1
AAA IDX_02 2 01/08/2024 6: P3 1
SQL> select dt.owner,dt.table_name,dt.num_rows, dt.last_analyzed from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
OWNER TABLE_NAME NUM_ROWS LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------
AAA INTERVAL_SALE
SQL> select di.owner,di.index_name,di.num_rows,di.last_analyzed ,di.distinct_keys from dba_indexes di
2 where di.index_name like 'IDX_0%' ;
OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------
AAA IDX_01 8 01/08/2024 6: 4
AAA IDX_02 2 01/08/2024 6: 1
SQL> drop index IDX_02;
Index dropped
SQL> create index idx_02 on interval_sale(prod_id) local;
Index created
SQL> select dp.table_owner,dp.table_name,dp.num_rows,dp.partition_name,dp.last_analyzed from dba_tab_partitions dp
2 where dp.table_name='INTERVAL_SALE' ;
TABLE_OWNER TABLE_NAME NUM_ROWS PARTITION_NAME LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- -------------
AAA INTERVAL_SALE P0
AAA INTERVAL_SALE P1
AAA INTERVAL_SALE P2
AAA INTERVAL_SALE P3
SQL> select di.index_owner,di.index_name,di.num_rows,di.last_analyzed,di.partition_name,di.distinct_keys
2 from dba_ind_partitions di where di.index_name like 'IDX_0%' ;
INDEX_OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED PARTITION_NAME DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------------------------------------------------------------------------- -------------
AAA IDX_02 2 01/08/2024 6: P0 1
AAA IDX_02 2 01/08/2024 6: P1 1
AAA IDX_02 2 01/08/2024 6: P2 1
AAA IDX_02 2 01/08/2024 6: P3 1
SQL> select dt.owner,dt.table_name,dt.num_rows, dt.last_analyzed from dba_tables dt where dt.table_name='INTERVAL_SALE' ;
OWNER TABLE_NAME NUM_ROWS LAST_ANALYZED
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- -------------
AAA INTERVAL_SALE
SQL> select di.owner,di.index_name,di.num_rows,di.last_analyzed ,di.distinct_keys from dba_indexes di
2 where di.index_name like 'IDX_0%' ;
OWNER INDEX_NAME NUM_ROWS LAST_ANALYZED DISTINCT_KEYS
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------- ------------- -------------
AAA IDX_01 8 01/08/2024 6: 4
AAA IDX_02 8 01/08/2024 6: 1
SQL>
-----------------2--------------------
为什么下面会慢,因为update global indexes对于Partitiontable,他的并行会对表的,比如有10个分区,起10个并行,那么一个分区只有一个并行,如果10个分区只有一个分区有数据,那么另外9个分区都在等最后一个分区rebuild. 相当于并行没有生效。
半夜被叫起来干活了
奇怪,如下写法怎么半天都执行不好
alter table bill.recur_rating_charge_d_591_0712 truncate partition PART_21 update global indexes ;
select count(*) from bill.recur_rating_charge_d_591_0712 partition(PART_21)
数据始终不变
但是我看v$session_longops看到这个SID很快就做好事了,
而我看表分区记录始终在
我晕,只好采用老办法,杀掉会话后,
alter table bill.RECUR_RATING_CHARGE_d_591_0712 truncate partition PART_20不加update global indexes
然后分别维护了普通索引和局部索引,这次加NOLOGGING和PARALLEL 8 ,也很快,3亿的大表,维护普通索引只花了200秒
alter index bill.IDX_CHARGE_D_591_0712_SID rebuild parallel 8 nologging ;
alter index bill.UNQ_RRATING_CHARGE_D_591_0712 rebuild partition PART_21 parallel 8 nologging;
猜测原因:
truncate partition PART_20后,这个分区的和这个分区上的本地索引的统计信息是不会更新也不会丢失
当我往这个分区插入数据的时候,执行计划是根据错误的统计信息生成的,所以会很慢
当我rebuild index partition PART_20 后,会导致这个索引的统计信息丢失,
而我的执行计划就有可能改变了,所以我的插入变快了
当你truncate后应该立即对这个分区做分析cascade => true(增加对索引的统计信息),
同时rebuild global index 并分析global index才对
㈢ 空间释放问题
其实空间等都已经释放了,但数据字典没有被更新,
例如你查dba_segments视图,发现这个分区的bytes其实还为原来的大小
我们可执行alter table **** allocate extent即可更新数据字典为正常状态
例如针对范围分区如下操作:
alter table *** modify partition PART_*** allocate extent;
我们先从实验,了解这个问题,首先创建分区表,他存在4个分区,每个分区中,都存在数据,
SQL> CREATE TABLE interval_sale
2 ( prod_id NUMBER(6)
3 , cust_id NUMBER
4 , time_id DATE
5 )
6 PARTITION BY RANGE (time_id)
7 INTERVAL(NUMTOYMINTERVAL(1, 'YEAR'))
8 ( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2003', 'DD-MM-YYYY')),
9 PARTITION p1 VALUES LESS THAN (TO_DATE('1-1-2004', 'DD-MM-YYYY')),
10 PARTITION p2 VALUES LESS THAN (TO_DATE('1-1-2005', 'DD-MM-YYYY')),
11 PARTITION p3 VALUES LESS THAN (TO_DATE('1-1-2006', 'DD-MM-YYYY')));
SQL> insert into interval_sale values(1, 1, to_date('2002-01-01','yyyy-mm-dd'));
1 row created.
SQL> insert into interval_sale values(2, 2, to_date('2003-01-01','yyyy-mm-dd'));
1 row created.
SQL> insert into interval_sale values(3, 3, to_date('2004-01-01','yyyy-mm-dd'));
1 row created.
SQL> insert into interval_sale values(4, 4, to_date('2005-01-01','yyyy-mm-dd'));
1 row created.
SQL> commit;
Commit complete.
创建全局索引,当前状态是VALID,
SQL> create index idx_01 on interval_sale(cust_id);
Index created.
SQL> select table_name, index_name, partitioned, status
2 from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME INDEX_NAME PARTITIONED STATUS
--------------- --------------- ------------ --------
INTERVAL_SALE IDX_01 NO VALID
删除第一个分区,
SQL> alter table interval_sale drop partition for (to_date('2002-01-01','yyyy-mm-dd'));
Table altered.
此时,看到这个全局索引是UNUSABLE的状态,和我们的设想是相同的,即删除分区,会导致全局索引的失效,
SQL> select table_name, index_name, status
2 from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME INDEX_NAME STATUS
--------------- --------------- ----------
INTERVAL_SALE IDX_01 UNUSABLE
结论告诉我们,删除分区,确实会导致全局索引的失效,我们从问题入手,为什么分区删除,会导致全局索引的失效?
我们知道,Oracle中索引是以B树的结构存储的,包括了索引键值、rowid信息,而且按照索引键值有序排列,当通过索引扫描需要回表的时候,能利用rowid直接定位到索引键值对应的数据块,这是最快的数据访问方式。当我们删除表中数据的时候,同时要删除他对应的索引,由于索引是有序排列的,如果要删除一条索引数据,他的组织结构,就需要调整,以保证正确的排列顺序,12c之前,因为某种原因,无法在删除分区的同时,对索引重新构建,所以此时索引的状态是失效的,与其是错的,宁可不让用,删除分区,需要手工rebuild重建索引才能让其生效,
我们换种思路,之所以全局索引的状态失效,根本问题就是索引对应的分区中数据被删除了,那么,如果不删除分区中的数据,索引结构无需任何调整,他的状态是不是就是正常的?
首先重建索引,让其生效,
SQL> alter index idx_01 rebuild online;
Index altered.
SQL> select table_name, index_name, status
2 from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME INDEX_NAME STATUS
--------------- --------------- --------
INTERVAL_SALE IDX_01 VALID
此时,通过delete删除即将删除的第二个分区的数据,
SQL> delete from interval_sale where time_id <= to_date('2003-01-01','yyyy-mm-dd');
1 row deleted.
SQL> commit;
Commit complete.
再次执行分区删除的操作,
SQL> alter table interval_sale drop partition for (to_date('2003-01-01','yyyy-mm-dd'));
Table altered.
此时,再看全局索引,他的状态正常,VALID,并未因为分区删除的操作,导致其失效,
SQL> select table_name, index_name, status
2 from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME INDEX_NAME STATUS
--------------- --------------- --------
INTERVAL_SALE IDX_01 VALID
通过以上实验,可以得到结论,如果待删除的分区中没有任何数据,执行分区删除,不会导致全局索引状态的失效。原因已经说了,因为分区删除时,不存在任何数据需要删除,意味着无需调整索引结构,所以全局索引的状态,就无需置为失效,这个算是对待分区删除避免全局索引失效的一种另类解决方案了。
通过这个问题,能让我体会到的,就是一个看着很简单的问题背后,其实蕴涵着丰富的知识,同时对待任何一个知识点,从原理层理解地越深入,找到问题的本质,就可以让你和真相更近,豁然开朗,这可能就需要日常的积累,碰到问题的时候,多问一句为什么,就可能让你大开眼界,这就是Oracle以及技术领域最吸引人的地方了。---屁话,这是oracle进行改进了原因