文章

Oracle 分区和分区索引

Oracle 分区和分区索引

前言

记录一下 Oracle 的分区表和索引官方文档位置,以及分区索引的失效操作记录,方便后续查询

分区表和分区索引

Index Partitioning

About Merging Partitions and Subpartitions

测试样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 创建分区表(按范围分区)
CREATE TABLE part_tab (
  id NUMBER,
  col3 NUMBER,
  create_date DATE
)
PARTITION BY RANGE (col3) (
  PARTITION p1 VALUES LESS THAN (10000),
  PARTITION p2 VALUES LESS THAN (20000),
  PARTITION p_max VALUES LESS THAN (MAXVALUE)
);

-- 插入测试数据
-- 落入 p1
INSERT INTO part_tab VALUES (1, 5000, SYSDATE);
-- 落入 p2
INSERT INTO part_tab VALUES (2, 15000, SYSDATE);
-- 落入 p_max
INSERT INTO part_tab VALUES (3, 25000, SYSDATE);
COMMIT;

-- 创建全局索引和局部索引
CREATE /* 全局索引 */ INDEX gidx_part_id ON part_tab(id) GLOBAL;
CREATE /* 局部索引 */INDEX lidx_part_col3 ON part_tab(col3) LOCAL;

测试场景

Truncate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
-- 执行 Truncate 分区(不更新索引)
ALTER TABLE part_tab TRUNCATE PARTITION p1;

-- 验证全局索引状态
SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME
----------------------------------------------------------------------------------------------------
STATUS
--------
GIDX_PART_ID
UNUSABLE


Elapsed: 00:00:00.05
WXJ@pdb1 19,1109022 SQL> set linesize 300
WXJ@pdb1 19,1109022 SQL>
WXJ@pdb1 19,1109022 SQL> /

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     UNUSABLE

-- 验证局部索引状态
SELECT index_name, partition_name, status
FROM user_ind_partitions
WHERE index_name = 'LIDX_PART_COL3'
AND partition_name = 'P1';

WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status
  2  FROM user_ind_partitions
  3  WHERE index_name = 'LIDX_PART_COL3'
  4  AND partition_name = 'P1';


INDEX_NAME                                                                                                                       PARTITION_NAME                                                          STATUS
-------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --------
LIDX_PART_COL3                                                                                                                   P1                                                                      USABLE


-- 手动重建/更新全局索引
alter index WXJ.GIDX_PART_ID rebuild ;

WXJ@pdb1 19,1109022 SQL> alter index WXJ.GIDX_PART_ID rebuild ;

Index altered.

Elapsed: 00:00:00.04
WXJ@pdb1 19,1109022 SQL>
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

可以看出,Truncate 分区后,全局索引失效,局部索引不受影响。如果避免全局索引失效,可以在 Truncate 分区时指定UPDATE GLOBAL INDEXES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 避免失效操作(重新执行并更新索引)
ALTER TABLE part_tab TRUNCATE PARTITION p1 UPDATE GLOBAL INDEXES;

-- 再次验证全局索引状态(预期:VALID)
WXJ@pdb1 19,1109022 SQL> ALTER TABLE part_tab TRUNCATE PARTITION p1 UPDATE GLOBAL INDEXES;

Table truncated.

Elapsed: 00:00:00.01
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.01

Drop 分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
--查询分区表详情
col OWNER for a10
col SEGMENT_NAME for a25
col PARTITION_NAME for a30
set lin 200 pagesize 500
select OWNER,SEGMENT_NAME,PARTITION_NAME from dba_segments where OWNER in ('WXJ') and SEGMENT_NAME in ('PART_TAB') order by 2,3;

WXJ@pdb1 19,1109022 SQL> select OWNER,SEGMENT_NAME,PARTITION_NAME from dba_segments where OWNER in ('WXJ') and SEGMENT_NAME in ('PART_TAB') order by 2,3;


OWNER      SEGMENT_NAME              PARTITION_NAME
---------- ------------------------- ------------------------------
WXJ        PART_TAB                  P1
WXJ        PART_TAB                  P2
WXJ        PART_TAB                  P_MAX

-- 执行 Drop 分区(不更新索引)
ALTER TABLE part_tab DROP PARTITION p2;
WXJ@pdb1 19,1109022 SQL> ALTER TABLE part_tab DROP PARTITION p2;

Table altered.

Elapsed: 00:00:00.02
WXJ@pdb1 19,1109022 SQL>
WXJ@pdb1 19,1109022 SQL> select OWNER,SEGMENT_NAME,PARTITION_NAME from dba_segments where OWNER in ('WXJ') and SEGMENT_NAME in ('PART_TAB') order by 2,3;

OWNER      SEGMENT_NAME              PARTITION_NAME
---------- ------------------------- ------------------------------
WXJ        PART_TAB                  P1
WXJ        PART_TAB                  P_MAX

-- 验证全局索引状态(预期:UNUSABLE)
SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     UNUSABLE

-- 查看全局索引情况
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     UNUSABLE

Elapsed: 00:00:00.00
WXJ@pdb1 19,1109022 SQL> -- 验证局部索引状态
WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status FROM user_ind_partitions WHERE index_name = 'LIDX_PART_COL3' ;

INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P1                             USABLE
LIDX_PART_COL3                                                                                                                   P_MAX                          USABLE

-- 重新添加分区
-- ALTER TABLE part_tab ADD PARTITION p2 VALUES LESS THAN (20000);
ALTER TABLE part_tab
SPLIT PARTITION p_max AT (30000)
INTO (PARTITION p2, PARTITION p_max);
WXJ@pdb1 19,1109022 SQL> select OWNER,SEGMENT_NAME,PARTITION_NAME from dba_segments where OWNER in ('WXJ') and SEGMENT_NAME in ('PART_TAB') order by 2,3;

OWNER      SEGMENT_NAME              PARTITION_NAME
---------- ------------------------- ------------------------------
WXJ        PART_TAB                  P1
WXJ        PART_TAB                  P2
WXJ        PART_TAB                  P_MAX

-- 再次检查索引状态
WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status FROM user_ind_partitions WHERE index_name = 'LIDX_PART_COL3' ;

INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P1                             USABLE
LIDX_PART_COL3                                                                                                                   P2                             USABLE -- 重建后的本地索引状态正常
LIDX_PART_COL3                                                                                                                   P_MAX                          USABLE

WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     UNUSABLE

-- 重建全局索引
WXJ@pdb1 19,1109022 SQL> alter index WXJ.GIDX_PART_ID rebuild ;

Index altered.

Elapsed: 00:00:00.01
WXJ@pdb1 19,1109022 SQL>
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

-- 避免失效操作(带 UPDATE GLOBAL INDEXES)
ALTER TABLE part_tab DROP PARTITION p2 UPDATE GLOBAL INDEXES;
WXJ@pdb1 19,1109022 SQL> ALTER TABLE part_tab DROP PARTITION p2 UPDATE GLOBAL INDEXES;

Table altered.

Elapsed: 00:00:00.02
WXJ@pdb1 19,1109022 SQL>
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.00
-- 验证全局索引状态(预期:VALID)

Split 分区(有记录的 MAX 分区)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
-- 确保 p_max 有数据
SELECT * FROM part_tab PARTITION (p_max);
WXJ@pdb1 19,1109022 SQL> SELECT * FROM part_tab PARTITION (p_max);

no rows selected

Elapsed: 00:00:00.00

-- 上面 split p2 的时候搞错了范围,重新插入新的数据
INSERT INTO part_tab VALUES (4, 30000, SYSDATE);
INSERT INTO part_tab VALUES (5, 50000, SYSDATE);
INSERT INTO part_tab VALUES (6, 60000, SYSDATE);
INSERT INTO part_tab VALUES (7, 70000, SYSDATE);
COMMIT;

-- 执行 Split 分区
ALTER TABLE part_tab
SPLIT PARTITION p_max AT (40000)
INTO (PARTITION p3, PARTITION p_max);

WXJ@pdb1 19,1109022 SQL> select OWNER,SEGMENT_NAME,PARTITION_NAME from dba_segments where OWNER in ('WXJ') and SEGMENT_NAME in ('PART_TAB') order by 2,3;

OWNER      SEGMENT_NAME              PARTITION_NAME
---------- ------------------------- ------------------------------
WXJ        PART_TAB                  P1
WXJ        PART_TAB                  P3
WXJ        PART_TAB                  P_MAX

-- 验证全局索引状态(预期:UNUSABLE)
SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     UNUSABLE

-- 验证局部索引状态(预期:UNUSABLE)
SELECT index_name, partition_name, status
FROM user_ind_partitions
WHERE index_name = 'LIDX_PART_COL3'
AND partition_name IN ('P3', 'P_MAX');

INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P3                             UNUSABLE
LIDX_PART_COL3                                                                                                                   P_MAX                          UNUSABLE

-- 重建全局索引
WXJ@pdb1 19,1109022 SQL> alter index WXJ.GIDX_PART_ID rebuild ;

Index altered.

-- 重建局部索引
ALTER INDEX lidx_part_col3 REBUILD PARTITION p3;
ALTER INDEX lidx_part_col3 REBUILD PARTITION p_max;
WXJ@pdb1 19,1109022 SQL> ALTER INDEX lidx_part_col3 REBUILD PARTITION p3;

Index altered.

Elapsed: 00:00:00.02
WXJ@pdb1 19,1109022 SQL> ALTER INDEX lidx_part_col3 REBUILD PARTITION p_max;

Index altered.

Elapsed: 00:00:00.02

-- 查看索引状态
SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

SELECT index_name, partition_name, status
FROM user_ind_partitions
WHERE index_name = 'LIDX_PART_COL3' ;

WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.00
WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status FROM user_ind_partitions WHERE index_name = 'LIDX_PART_COL3' ;


INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P1                             USABLE
LIDX_PART_COL3                                                                                                                   P3                             USABLE
LIDX_PART_COL3                                                                                                                   P_MAX                          USABLE

Elapsed: 00:00:00.04

-- 使用 UPDATE GLOBAL INDEXES 避免失效
ALTER TABLE part_tab
SPLIT PARTITION p_max AT (50000)
INTO (PARTITION p4, PARTITION p_max)
UPDATE GLOBAL INDEXES;

-- 验证全局索引状态(预期:VALID)
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.00
WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status FROM user_ind_partitions WHERE index_name = 'LIDX_PART_COL3' ;

INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P1                             USABLE
LIDX_PART_COL3                                                                                                                   P3                             USABLE
LIDX_PART_COL3                                                                                                                   P4                             USABLE
LIDX_PART_COL3                                                                                                                   P_MAX                          USABLE

Elapsed: 00:00:00.00

Add 分区

已经存在 max 分区,无法直接通过 add partition 来添加分区,需要通过 split 分区来添加分区。可以新建一张表,然后 add partition 来测试。为了方便直接将 max 分区删除,然后重新添加分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
-- 删除 MAX 分区
ALTER TABLE part_tab DROP PARTITION p_max;

-- drop 分区会使全局索引失效,需要重建
alter index WXJ.GIDX_PART_ID rebuild ;

-- 验证状态
WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status
  2  FROM user_ind_partitions
  3  WHERE index_name = 'LIDX_PART_COL3'
  4  ;

INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P1                             USABLE
LIDX_PART_COL3                                                                                                                   P3                             USABLE
LIDX_PART_COL3                                                                                                                   P4                             USABLE

Elapsed: 00:00:00.04
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.01

-- 执行 Add 分区
ALTER TABLE part_tab
ADD PARTITION p6 VALUES LESS THAN (60000);

-- 验证全局索引和局部索引状态(预期:VALID)
SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';
SELECT index_name, partition_name, status
FROM user_ind_partitions
WHERE index_name = 'LIDX_PART_COL3' ;

WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.00
WXJ@pdb1 19,1109022 SQL> SELECT index_name, partition_name, status
  2  FROM user_ind_partitions
  3  WHERE index_name = 'LIDX_PART_COL3' ;

INDEX_NAME                                                                                                                       PARTITION_NAME                 STATUS
-------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
LIDX_PART_COL3                                                                                                                   P1                             USABLE
LIDX_PART_COL3                                                                                                                   P3                             USABLE
LIDX_PART_COL3                                                                                                                   P4                             USABLE
LIDX_PART_COL3                                                                                                                   P6                             USABLE

-- 可以看到,Add 分区后,全局索引和局部索引状态都是正常的

Exchange 分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-- 创建普通表并插入数据
CREATE TABLE normal_tab (id NUMBER, col3 NUMBER, create_date DATE);
INSERT INTO normal_tab VALUES (4, 7000, SYSDATE);
COMMIT;
create index idx_normal_col3 on normal_tab(col3);

-- 执行 Exchange 分区(不更新索引)
ALTER TABLE part_tab
EXCHANGE PARTITION p1
WITH TABLE normal_tab INCLUDING INDEXES;

-- 验证全局索引状态(预期:UNUSABLE)
SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';


WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     UNUSABLE

-- 避免失效操作(带 UPDATE GLOBAL INDEXES)
WXJ@pdb1 19,1109022 SQL> alter index WXJ.GIDX_PART_ID rebuild ;

ALTER TABLE part_tab
EXCHANGE PARTITION p1
WITH TABLE normal_tab INCLUDING INDEXES
UPDATE GLOBAL INDEXES;

-- 验证全局索引状态(预期:VALID)
WXJ@pdb1 19,1109022 SQL> SELECT index_name, status FROM user_indexes WHERE index_name = 'GIDX_PART_ID';

INDEX_NAME                                                                                                                       STATUS
-------------------------------------------------------------------------------------------------------------------------------- --------
GIDX_PART_ID                                                                                                                     VALID

Elapsed: 00:00:00.00

总结

不同的版本操作方法和影响会存在差异,最好查询官网文档

如果涉及的分区或子分区包含数据,则索引可能会被标记为 UNUSABLE,如下表所述:

Table Type Index Behavior
Regular (Heap) Unless you specify UPDATE INDEXES as part of the ALTER TABLE statement:
- The database marks UNUSABLE all resulting corresponding local index partitions or subpartitions.
- Global indexes, or all partitions of partitioned global indexes, are marked UNUSABLE and must be rebuilt.
Index-organized The database marks UNUSABLE all resulting corresponding local index partitions.
All global indexes remain usable.

会造成分区表索引失效的操作

操作动作 操作命令 全局索引 分区索引
Truncate ALTER TABLE part_tab_trunc TRUNCATE PARTITION p1; 是否失效: 失效
如何避免: UPDATE GLOBAL INDEXES;
是否失效: 无影响
如何避免: 无需操作
Drop ALTER TABLE part_tab_drop DROP PARTITION p1; 是否失效: 失效
如何避免: UPDATE GLOBAL INDEXES;
是否失效: 无影响
如何避免: 无需操作
Split ALTER TABLE part_tab_split SPLIT PARTITION p_max AT (30000) INTO (PARTITION p3, PARTITION p_max); 是否失效: 失效
如何避免: UPDATE GLOBAL INDEXES;
是否失效: 失效(若 MAX 分区有记录)
如何避免: 重建局部索引 ALTER INDEX idx_part_split_col3 REBUILD;
Add ALTER TABLE part_tab_add ADD PARTITION p6 VALUES LESS THAN (60000); 是否失效: 无影响
如何避免: 无需操作
是否失效: 无影响
如何避免: 无需操作
Exchange ALTER TABLE part_tab_exch EXCHANGE PARTITION p1 WITH TABLE normal_tab INCLUDING INDEXES; 是否失效: 失效
如何避免: UPDATE GLOBAL INDEXES;
是否失效: 无影响
如何避免: 无需操作
本文由作者按照 CC BY 4.0 进行授权

© TheDarkStarJack. 保留部分权利。

[本站总访问量次] [本站访客数人次] [本文总阅读量次]

本站采用 Jekyll 主题 Chirpy