设为首页 收藏本站
查看: 918|回复: 0

[经验分享] 我对oracle分区技术的学习

[复制链接]

尚未签到

发表于 2018-9-9 06:42:51 | 显示全部楼层 |阅读模式
  分区技术纷繁复杂,从11g以后有更多的分区方式,但是在考虑使用分区之前要想好是否需要历史数据清理。
  比如罗敏的《品悟性能优化》书中P138那个案例。如果使用命名方式分区,那么以后清理历史数据无法根据分区特性进行清理,原因在于可能同一个名字的分区中包含好几年的数据。
  Oracle 分区表简单而言就是将一张大表按一定规则分为物理上的很多小表,而逻辑上仍然维持为一张大表。对应用是透明的。
  分区索引分为以下几种情况
  ·        表和索引都不分区
  ·        表分区,索引没分区
  ·        表没分区,索引分区
  ·        表和索引都分区
  先做几个实验,来感受感受分区表和分区索引。
1        创建本地分区索引
  本地分区索引指索引的分区方法与对应表的分区方法一样,
  在分区删除(DROP)操作之后,普通索引和全局分区索引都会失效(INVALID),必须重建。
  本地分区索引又分为本地前缀分区索引,和本地非前缀分区索引

  •   本地前缀分区索引,就是以分区键创建的索引,比如test_range_part     表以object_id     为分区键,那么在object_id上创建索引就是本地前缀分区索引。
  类似:
create index idx_part_object_id on test_range_part(object_id) local;  
create index idx_part_object_id on test_range_part(object_id,object_name) local;

  •   本地非前缀分区索引,就是以非分区键创建的索引,比如test_range_part表以object_id为分区键,那么在object_name上创建索引就是本地非前缀分区索引。
  类似:
create index idx_part_object_name on test_range_part(object_name) local;  本地非前缀分区索引的好处在于,在分区删除(DROP)操作之后,该本地非前缀分区索引依然有效。
  本地非前缀分区索引的缺点这里说一下,比如我想查询object_name='EMP'的行,由于object_name不是分区键,那么有一种可能,object_name在所有分区中都有值,比如EMP可能会在obj_10000和obj_20000...
等分区出现。那么通过object_name='EMP'条件回表访问的时候,可能会访问所有的本地分区索引。每次都访问不同的segment。如果我的索引不进行分区,那么可以直接通过大的索引直接访问。
  存在即合理,为什么非前缀分区索引仍然会用?因为在做数据清理的时候,可能会对分区进行drop,如果是本地非前缀分区索引,分区drop之后其他分区索引不会失效。如果这时候使用了非分区索引,那就死了。整个索引都失效,创建索引的时候还锁表!!!
  所以在创建索引之前要权衡好。
  创建分区表,下面创建了一张范围分区表。
create table test_range_part (object_id number,  
owner varchar2(30),
  
object_name varchar2(128))
  
partition by range (object_id)(
  
partition obj_10000 values less than(10000),
  
partition obj_20000 values less than(20000),
  
partition obj_30000 values less than(30000),
  
partition obj_40000 values less than(40000),
  
partition obj_50000 values less than(50000),
  
partition obj_60000 values less than(60000),
  
partition obj_70000 values less than(70000),
  
partition obj_80000 values less than(80000),
  
partition obj_max values less than(maxvalue)
  
);
  

  
insert into test_range_part select object_id,owner,object_name from test;
  
commit;
2        创建本地非前缀分区索引
  以object_name为索引列
create index idx_part_object_name on test_range_part(object_name) local;  以owner为索引列
create index idx_part_owner on test_range_part(owner) local;  从下面查询可以看出,本地费前缀分区索引的分区方式仍然是按照分区表的分区条件进行分区的。
  从下面查询视图中,num_rows列可以看出每个分区有多少行数据
SELECT INDEX_OWNER,  
      INDEX_NAME,
  
      PARTITION_NAME,
  
      PARTITION_POSITION,
  
      TABLESPACE_NAME,
  
      DISTINCT_KEYS,
  
       NUM_ROWS,
  
      LAST_ANALYZED
  
  FROM DBA_IND_PARTITIONS
  
WHERE INDEX_OWNER = 'SCOTT';
DSC0000.jpg

  运行下面查询看看每个分区有多少数据
SELECT COUNT(*)  
  FROM TEST_RANGE_PART PARTITION(OBJ_10000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_20000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_30000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_40000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_50000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_60000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_70000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_80000)
  
UNION ALL
  
SELECT COUNT(*)
  
  FROM TEST_RANGE_PART PARTITION(OBJ_MAX);
DSC0001.jpg

  下面实验对range分区表清理数据,并查看相关索引状态
alter table test_range_part drop partition(obj_10000);  从下面查询得到结论,如果对分区进行drop之后,其他分区的索引都可以使用,状态都是usable状态。
SELECT STATUS,  
      INDEX_NAME,
  
      PARTITION_NAME,
  
      PARTITION_POSITION,
  
      TABLESPACE_NAME,
  
      DISTINCT_KEYS,
  
       NUM_ROWS,
  
      LAST_ANALYZED
  
  FROM DBA_IND_PARTITIONS
  
WHERE INDEX_OWNER = 'SCOTT';
DSC0002.jpg

SELECT INDEX_NAME, TABLE_NAME, PARTITIONING_TYPE, PARTITION_COUNT, LOCALITY  
  FROM DBA_PART_INDEXES
  
WHERE OWNER = 'SCOTT'
  
   AND INDEX_NAME IN ('IDX_PART_OWNER', 'IDX_PART_OBJECT_NAME');
DSC0003.jpg

3        全局分区索引
  刚才本地分区表中,不管以什么列创建索引都是以分区表分区键分区。这里的全局分区索引不再使用分区键作为分区条件,而是自定义一个分区条件。创建索引。
  10g之前只有全局范围分区表,10g之后又多出了全局哈希分区表
  下面实验用来验证当分区被drop后,全局分区索引会失效
  用下面方法创建分区表,同样是范围分区表,比刚才的分区表多了很多个列。
drop table test_range_part1 purge;  
create table test_range_part1
  
partition by range (object_id)(
  
partition obj_10000 values less than(10000),
  
partition obj_20000 values less than(20000),
  
partition obj_30000 values less than(30000),
  
partition obj_40000 values less than(40000),
  
partition obj_50000 values less than(50000),
  
partition obj_60000 values less than(60000),
  
partition obj_70000 values less than(70000),
  
partition obj_80000 values less than(80000),
  
partition obj_max values less than(maxvalue)
  
)
  
as
  
select * from test;
  这里有个小插曲,关于创建本地分区索引,对索引分区命名的方法。
  用下面方法创建分区索引,并且自定义分区名称。如果分区名称不定义,那么默认跟表分区名相同。
drop index idx_test_objid;  
CREATE INDEX idx_test_objid ON test_range_part1(object_id)
  
LOCAL
  
(PARTITION part1,
  
PARTITION part2,
  
PARTITION part3,
  
PARTITION part4,
  
PARTITION part5,
  
PARTITION part6,
  
PARTITION part7,
  
PARTITION part8,
  
PARTITION part9);
  同样如果本地分区索引创建指定了分区名,而且定义的索引分区比表分区还要多,那么将要报错,ORA-14024
  如下图:
DSC0004.jpg

  根据创建时间(created)列创建全局分区索引
drop index idx_part_created;  
CREATE INDEX idx_part_created ON test_range_part1(created)
  
GLOBAL PARTITION BY RANGE(created)
  
(PARTITION part1 VALUES LESS THAN(to_date('2013-06-01','yyyy-mm-dd')) ,
  
PARTITION part2 VALUES LESS THAN(to_date('2014-01-01','yyyy-mm-dd')) ,
  
PARTITION part3 VALUES LESS THAN(to_date('2014-06-01','yyyy-mm-dd')) ,
  
PARTITION part4 VALUES LESS THAN(to_date('2015-01-01','yyyy-mm-dd')) ,
  
PARTITION part5 VALUES LESS THAN(to_date('2015-06-01','yyyy-mm-dd')) ,
  
PARTITION part6 VALUES LESS THAN(to_date('2016-01-01','yyyy-mm-dd')) ,
  
PARTITION part7 VALUES LESS THAN(to_date('2016-06-01','yyyy-mm-dd')) ,
  
PARTITION partmaxvalue VALUES LESS THAN(MAXVALUE));
  查询每个索引分区的行数。
SELECT STATUS,  
      INDEX_NAME,
  
      PARTITION_NAME,
  
      PARTITION_POSITION,
  
      TABLESPACE_NAME,
  
      DISTINCT_KEYS,
  
       NUM_ROWS,
  
      LAST_ANALYZED
  
  FROM DBA_IND_PARTITIONS
  
WHERE INDEX_OWNER = 'SCOTT'
  
   AND INDEX_NAME = 'IDX_PART_CREATED';
DSC0005.jpg

  如何分别全局分区索引和本地分区索引。
SELECT INDEX_NAME, TABLE_NAME, PARTITIONING_TYPE, PARTITION_COUNT, LOCALITY  
  FROM DBA_PART_INDEXES
  
WHERE OWNER = 'SCOTT';
DSC0006.jpg

4        删除分区并重建全局分区索引
  删除分区obj_10000
alter table test_range_part1 drop partition (obj_10000);  查看全局分区索引状态
  发现IDX_PART_CREATED索引的状态都变成了UNUSABLE,已经不可用了。为什么会这样呢?
  当创建全局分区索引的时候索引列使用的created会遍布到分区表的各个分区中。
  如果我删掉了其中一个分区,那么全局分区索引的每个分区中都会缺少分区表中第一个分区的数据。所以导致全局分区索引失效。
  如果不好理解我举个例子。可能created有100条2015-10-10。而分区表是按照object_id进行分区的。这100条2015-10-10可能分布在obj_10000,obj_20000,obj_30000,MAXVALUE中,当我做了drop
partition 操作后,导致索引中的数据丢失。
  所以做完drop
partition 操作后要做一个rebuild操作。
DSC0007.jpg

  使用这条查询语句拼出创建索引的语句:
SELECT 'alter index ' || INDEX_OWNER || '.' || INDEX_NAME ||  
       ' rebuild partition ' || PARTITION_NAME ||';'
  
  FROM DBA_IND_PARTITIONS
  
WHERE STATUS = 'UNUSABLE';
  

  

  
'ALTERINDEX'||INDEX_OWNER||'.'||INDEX_NAME||'REBUILDPARTITION'||PARTITION_NAME
  
--------------------------------------------------------------------------------------------------------------------------
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PARTMAXVALUE;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART7;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART6;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART5;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART4;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART3;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART2;
  
alter index SCOTT.IDX_PART_CREATED rebuild partition PART1;
  

  
8 rows selected.
  使用上面语句创建好索引后,查看视图,得到下面的结果。
  从status列能看出全局分区索引都已经重建好,并且可以使用了。
DSC0008.jpg

SELECT INDEX_NAME,  
      INDEX_TYPE,
  
      TABLESPACE_NAME,
  
       STATUS,
  
      PARTITIONED,
  
      GLOBAL_STATS,
  
      SEGMENT_CREATED
  
  FROM DBA_INDEXES
  
WHERE OWNER = 'SCOTT';
DSC0009.jpg

  GLOBAL_STATS列的意思。如果是YES,那么使用analyze命令会收统计信息,如果是NO,那么使用analyze命令不会收集统计信息,只有分区索引和子分区索引才是NO状态。
  SEGMENT_CREATED的意思为是否分配了SEGMENT。
  在实际环境中更多使用如下方法对索引进行维护
在分区表上创建普通索引  
SQL> create index idx_norm_name on test_range_part(object_name);
  

  
Index created.
  

  

  
SQL> select table_name,partition_name from dba_tab_partitions where table_owner='SCOTT';
  

  
TABLE_NAME                     PARTITION_NAME
  
------------------------------ ------------------------------
  
TEST_RANGE_PART1               OBJ_MAX
  
TEST_RANGE_PART1               OBJ_80000
  
TEST_RANGE_PART1               OBJ_70000
  
TEST_RANGE_PART1               OBJ_60000
  
TEST_RANGE_PART1               OBJ_50000
  
TEST_RANGE_PART1               OBJ_40000
  
TEST_RANGE_PART1               OBJ_30000
  
TEST_RANGE_PART1               OBJ_20000
  
TEST_RANGE_PART                OBJ_MAX
  
TEST_RANGE_PART                OBJ_80000
  
TEST_RANGE_PART                OBJ_70000
  

  
TABLE_NAME                     PARTITION_NAME
  
------------------------------ ------------------------------
  
TEST_RANGE_PART                OBJ_60000
  
TEST_RANGE_PART                OBJ_50000
  
TEST_RANGE_PART                OBJ_40000
  

  
14 rows selected.
  

  

  

  
删掉分区表TEST_RANGE_PART上的一个分区
  
SQL> alter table test_range_part drop partition obj_40000;
  

  
Table altered.
  

  

  

  
查看索引状态,其中unusable状态的就是刚才创建的idx_norm_name
  
如果恰好你的实验也到这一步,那么可以通过dba_indexes 这个视图得到查询结果
  
这里我就不查询了。
  

  
SQL> select distinct status from dba_indexes;
  

  
STATUS
  
--------
  
UNUSABLE
  
VALID
  
N/A
  

  

  

  
重建索引的方式已经在前面介绍过了,语法不同的是多了一个rebuild online
  
SQL> alter index idx_norm_name rebuild online;
  

  
Index altered.
  

  

  

  
再次查看索引状态,idx_norm_name重建好之后,dba_indexes中unusable状态的索引就消失了
  
SQL> select distinct status from dba_indexes;
  

  
STATUS
  
--------
  
VALID
  
N/A
  

  

  

  
再次删除一个分区,但是删除分区后面跟了一句update global indexes
  
表示删除分区的时候同时维护索引。
  
SQL> alter table test_range_part drop partition obj_50000 update global indexes;
  

  
Table altered.
  

  

  

  
发现没有索引是unusable状态了。 前面这种update global indexes 同样适用于全局分区索引。
  
SQL> select distinct status from dba_indexes;
  

  
STATUS
  
--------
  
VALID
  
N/A



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-568307-1-1.html 上篇帖子: oracle数据库软件静默安装 下篇帖子: ORACLE日期时间函数大全
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表