删除分区如何不让全局索引失效?

本文通过实验探讨了在Oracle中,删除分区如何导致全局索引失效,以及如何通过理解分区原理来避免这一问题。在12c之前,删除分区会使得全局索引变为UNUSABLE状态,需要手动重建。但若在删除分区前先删除该分区的数据,再执行分区删除操作,则全局索引状态可保持VALID。这种方法展示了对分区和索引工作原理的深入理解,提供了一种避免索引失效的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记得上次ACOUG年会(《ACOUG年会感想》),请教杨长老问题的时候,谈到分区,如果执行分区删除的操作,就会导致全局索引失效,除了使用12c以上版本能避免这个问题外,指出另外一种解决的方式,表面看很巧妙,实则是对分区原理的深入理解。

我们先从实验,了解这个问题,首先创建分区表,他存在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以及技术领域最吸引人的地方了。
 

https://blog.youkuaiyun.com/bisal/article/details/103856220

<think>嗯,用户想了解Oracle数据库中全局索引分区的创建和管理方法。首先,我需要回忆一下Oracle分区表和索引相关知识。根据之前学过的内容,分区表可以分为范围分区、列表分区、哈希分区等,而索引则有本地索引和全局索引之分。用户特别提到的是全局索引分区,所以重点应该放在全局索引上。 记得本地索引是和表分区一一对应的,每个表分区对应一个索引分区,而全局索引则不同,它是独立于表分区的结构。全局索引可以按照不同的分区策略来创建,比如范围分区或哈希分区。这可能意味着全局索引分区方式可以和表的分区方式不一致,这样在查询时可能更灵活,但维护起来可能也更复杂。 用户的问题包括概念、创建方法和管理方式。首先需要解释什么是全局索引分区,然后给出创建的SQL示例,最后讨论管理方面,比如维护、重建、删除等步骤。同时,用户提供的引用资料中提到,全局索引分区不需要与表分区一致,这点需要强调,说明其适用场景,比如跨分区查询效率高,但分区维护时可能需要重建索引。 接下来,创建方法部分,可能需要举例说明如何创建全局分区索引,比如使用范围分区或哈希分区。例如,在创建索引时使用GLOBAL关键字,并指定分区方式。例如,对于范围分区全局索引,需要指定每个分区的值范围,可能用MAXVALUE来容纳超出范围的值。 管理方面,需要提到当表分区发生变化时,比如删除或合并分区全局索引可能会失效,因此需要重建。或者使用UPDATE GLOBAL INDEXES选项来避免索引失效。此外,日常的维护操作如重建索引分区、监控索引状态也是管理的重要部分。 另外,用户提供的引用[2]提到,本地索引自动管理分区,而全局索引需要手动指定分区范围,这点在回答中需要对比说明,帮助用户理解两者的区别。适用场景方面,全局索引适合需要跨分区查询的情况,而本地索引更适合分区维护频繁的场景。 需要注意的是,用户可能在实际操作中遇到哪些问题,比如全局索引维护的复杂性,或者在分区维护时未使用UPDATE GLOBAL INDEXES导致索引不可用。因此,在管理部分需要提醒这些注意事项,以及如何避免常见错误。 最后,生成的相关问题可能需要涉及全局索引与本地索引的区别、适用场景、创建时的语法差异,以及维护的最佳实践。例如,如何选择全局索引和本地索引,或者在分区表上使用全局索引的优缺点。</think>### 关于Oracle全局索引分区的概念、创建与管理 #### 一、全局索引分区概念 **全局索引(Global Index)**是独立于表分区的索引结构,其分区方式无需与表分区保持一致[^2]。与本地索引(Local Index)不同,全局索引分区键和范围由用户显式定义,可覆盖多个表分区或跨表分区存储数据。 **适用场景**: 1. 查询条件频繁使用非分区键字段 2. 需要跨分区的高效查询 3. 表分区维护后需保持索引有效性 #### 二、全局索引分区的创建 ##### 1. 创建语法示例 ```sql -- 创建全局范围分区索引 CREATE INDEX g_idx_emp_id ON employees(employee_id) GLOBAL PARTITION BY RANGE(employee_id) ( PARTITION p1 VALUES LESS THAN (1000), PARTITION p2 VALUES LESS THAN (2000), PARTITION p3 VALUES LESS THAN (MAXVALUE) ); -- 创建全局哈希分区索引 CREATE INDEX g_idx_dept_hash ON departments(department_id) GLOBAL PARTITION BY HASH(department_id) PARTITIONS 4; ``` **关键说明**: - 使用`GLOBAL PARTITION BY`指定全局索引分区方式(如`RANGE`、`HASH`) - `MAXVALUE`用于容纳超出定义范围的键值[^1] - 分区数量由用户显式控制,与表分区无关 ##### 2. 管理方式 **(1)分区维护** - **新增分区**:需手动扩展分区范围 ```sql ALTER INDEX g_idx_emp_id ADD PARTITION p4 VALUES LESS THAN (3000); ``` - **删除分区**:使用`DROP PARTITION`并重建索引 ```sql ALTER INDEX g_idx_emp_id DROP PARTITION p3; ``` **(2)索引维护** - **重建分区**:解决索引碎片或失效问题 ```sql ALTER INDEX g_idx_emp_id REBUILD PARTITION p2; ``` - **维护表分区时保留全局索引**:通过`UPDATE GLOBAL INDEXES`选项避免索引失效 ```sql ALTER TABLE employees DROP PARTITION sales_q1 UPDATE GLOBAL INDEXES; ``` #### 三、全局索引与本地索引对比 | **特性** | **全局索引** | **本地索引** | |----------------|-----------------------------|-----------------------------| | 分区方式 | 独立于表分区 | 与表分区一一对应 | | 维护复杂度 | 高(需手动管理) | 低(自动同步表分区) | | 查询性能 | 跨分区查询更高效 | 分区内查询更高效 | | 适用场景 | 非分区键查询、跨分区操作 | 分区键查询、频繁分区维护 | #### 四、注意事项 1. **分区键选择**:全局索引分区键应覆盖高频查询条件 2. **维护操作影响**:表分区维护(如`TRUNCATE`)可能导致全局索引失效,需配合`UPDATE GLOBAL INDEXES`使用[^1] 3. **监控**:定期检查索引状态(`DBA_INDEXES.STATUS`)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值