热衷技术,热爱交流
分类: Oracle
2013-06-20 20:56:59
把一个大的表或者索引分成一些小的片段,这些片段就叫做分区。
如果一个表中的数据量巨大时,可以将此表设计成分区表,提高查询性能和可管理性。表分区有多种,使用最多的是范围分区(range partition)。
范围分区是指根据表中的某一列(创建分区表时指定的分区键-Partition Key)的取值范围,将数据分布到不同的分区中。分区可以位于同一个表空间,也可以位于单独的表空间。常见的是按时间分区。
例如:
create table ok_EVENT
(
event_id NUMBER(20) not null,
end_time TIMESTAMP(3) not null,
uuid VARCHAR2(8) not null,
)
partition by range (END_TIME)
(
partition P20060324 values less than (TIMESTAMP' 2006-03-25 00:00:00') tablespace ok20060324,
partition P20120907 values less than (TIMESTAMP' 2012-09-08 00:00:00') tablespace ok20120907,
partition P20120908 values less than (TIMESTAMP' 2012-09-09 00:00:00') tablespace ok20120908
)
在上例中,ok_event表的end_time列作为分区键划分为3个分区,三个分区位于不同的表空间。当插入数据的时候,可以像对待普通的表一样使用insert语句,根据插入语句中end_time列的值决定数据插入到哪个分区,落在哪个分区内便插入哪个分区。如果没有命中任何分区,oracle会报错,插入失败。
各个分区不一定非要存放到单独的表空间,完全可以放到同一个表空间里。对于分区越来越多的情形,使用单独的表空间更方便管理。
1. 易于管理和维护:
在分区中,可以对单独的分区进行进行数据加载、备份、恢复以及索引的重建等。分区技术可以看做将大表分割成一个一个小表,小表总要比大表管理起来方便。比如一个按时间(天)分区的表,如果想删除某一天的数据,常规表的办法是使用delete,当这一天含有大量数据时,delete相当费时,且要占用大量的系统资源(比如生成大量的redo log及undo),而且不会释放系统文件的大小。如果采用分区表,只需要drop掉该天对应的分区即可,这是ddl操作,瞬间完成,只生成少量的redo和undo,而且可以回收空间。再如,当把分区放在不同的表空间上,当其中某一个分区的文件丢失或损坏时,只需要将该表空间离线即可,只对查询该分区数据的操作有影响,这称为分区消除。相反,如果是一个普通表,如果文件损坏,整个表都无法访问了。
2. 提高查询性能:
查询的时候可以查询指定分区的数据,就像查一张小表一样。另外,通过在where条件中使用分区键,可以将数据的扫描范围锁定在where条件限定的分区内,而不是扫描整个大表。这对于查询条件多样、索引有限、返回结果集巨大的系统带来很大好处。
分区表一般使用局部索引(local),一个表分区对应一个索引分区,由oracle自动维护。每个索引分区可以单独管理(如重建),大大方便了管理。
3. 在OLTP 系统中减少对共享资源的争用
设想,有多个用户在查询一个表,在没有使用分区的情况下,即使用户查询条件不一样,oracle始终是在访问一个文件。使用了分区,把不同时间段的数据放在不同数据文件,这样不同查询条件就可以访问不同的文件了。
从单一分方式(single-level)考虑,分区策略包括范围分区(range partition),列表分区(list partition),哈希分区(hash paritition)。分区策略还可以使用复合方式(composite partitioning),例如,可以首先采用第一种数据分配方式进行分区,在此基础上,再使用第二种数据分布方式进行子分区,这类似复合条件的排序。
数据库为超过跃点的值确定间隔分区(interval partition). 当插入到表中的数据超出所有已定义的表分区时,间隔分区指示数据库自动创建特定范围或特定间隔的分区,来扩展范围分区。
SYS >create tablespace hr_pt datafile '/u01/oradata2/hx/hr_pt.dbf'
SIZE 100M REUSE AUTOEXTEND ON NEXT 128M MAXSIZE UNLIMITED;;
HR >create table test_pt(end_time date)
NOLOGGING
PARTITION BY RANGE (END_TIME)
(
PARTITION P20060323 VALUES LESS THAN (TO_DATE('2006-03-24 00:00:00','yyyy-mm-dd hh24:mi:ss'))
NOLOGGING
TABLESPACE hr_pt
);
insert into test_pt values('2006-04-24 00:00:00'); *
ERROR at line 1:
ORA-14400: 插入的分区关键字未映射到任何分区
CREATE TABLE time_range_sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id)
(PARTITION SALES_1998 VALUES LESS THAN
(TO_DATE('01-JAN-1999','DD-MON-YYYY')),
PARTITION SALES_1999 VALUES LESS THAN
(TO_DATE('01-JAN-2000','DD-MON-YYYY')),
PARTITION SALES_2000 VALUES LESS THAN
(TO_DATE('01-JAN-2001','DD-MON-YYYY')),
);
HR >select * from time_range_sales partition(SALES_1998);
PROD_ID| CUST_ID|TIME_ID |C| PROMO_ID|QUANTITY_SOLD|AMOUNT_SOLD
----------|----------|-------------------|-|----------|-------------|-----------
116| 11393|1998-11-10 00:00:00|2| 999| 1| 12.18
116| 11393|1997-11-10 00:00:00|2| 999| 1| 12.18
116| 11393|1996-11-10 00:00:00|2| 999| 1| 12.18
HR >alter table time_range_sales add PARTITION SALES_2001 VALUES LESS THAN (MAXVALUE);
HR >insert into TIME_RANGE_SALES values(116, 11393, to_date('2012-11-10','yyyy-mm-dd'), '2',999, 1, 12.18) ;;
HR >select * from time_range_sales partition(SALES_2001);
PROD_ID| CUST_ID|TIME_ID |C| PROMO_ID|QUANTITY_SOLD|AMOUNT_SOLD
----------|----------|-------------------|-|----------|-------------|-----------
116| 11393|2012-11-10 00:00:00|2| 999| 1|
12.18
列表分区很简单,与范围分区有些类似,它的实质就是把满足一些值的特定行放在一定的分区,如果上面的范围分区是按照连续区间进行分区,那么列表分区就是按照不连续区间,也就是枚举方式进行分区:
SIM >create tablespace list_partition datafile '/u01/oradata2/hx/list_partition.dbf' size 10m;
SIM >create tablespace list_partition02 datafile'/u01/oradata2/hx/list_partition02.dbf' size 10m;
HR >create table list_partition(id number(10))
partition by list (id)
(partition list_partition values(1,2,3) tablespace LIST_PARTITION,
partition list_partition02 values(4,5,6) tablespace LIST_PARTITION02);
HR >insert into list_partition values(1);
HR >insert into list_partition values(4);
HR >select * from list_partition partition(list_partition);
ID
----------
1
HR >select * from list_partition partition(list_partition02);
ID
----------
4
如果插入的值是特定的,并且经常需要用这些值查询,而且这个分区键是一个重要字段,可能会用到列表分区。
哈希分区
在哈希分区中,基于用户所指定的将在分区键上应用的哈希算法,数据库将行映射到各个分区。行的目标分区是由数据库应用于行的内部哈希函数所决定的。哈希算法被设计为可以跨设备均匀分布行,以使每个分区包含大致相同同的行数。如果单纯考虑均匀分布行,不考虑按照日期,或者枚举值进行分区,哈希分区是个好办法。
HR >create table hash_partition(id number(10))
partition by hash (id)
partitions 3; --建表,指定行在三个分区之间均匀分布
Table created.
HR >select table_name,partition_name from user_tab_partitions where TABLE_NAME='HASH_PARTITION';
TABLE_NAME |PARTITION_NAME
------------------------------|------------------------------
HASH_PARTITION |SYS_P243
HASH_PARTITION |SYS_P244
HASH_PARTITION |SYS_P245
HR >insert into HASH_PARTITION values(100);
HR >insert into HASH_PARTITION values(200);
HR >insert into HASH_PARTITION values(300);
HR >select * from HASH_PARTITION partition(SYS_P243);
ID
----------
200
Elapsed: 00:00:00.02
HR >select * from HASH_PARTITION partition(SYS_P244);
ID
----------
300
Elapsed: 00:00:00.02
HR >select * from HASH_PARTITION partition(SYS_P245);
ID
----------
100
Elapsed: 00:00:00.01
HR >select SEGMENT_NAME,PARTITION_NAME,TABLESPACE_NAME from user_segments where segment_name='HASH_PARTITION';
SEGMENT_NAME |PARTITION_NAME |TABLESPACE_NAME
-------------------------|------------------------------|--------------------
HASH_PARTITION |SYS_P243 |HR
HASH_PARTITION |SYS_P245 |HR
HASH_PARTITION |SYS_P244 |HR
思考:
1.有一个表很重要,每天数据用一个分区存放,并且指定一个特定表空间。
2.表空间和分区生成方式如下:表中有一个属性叫做end_time,这个值正好等于行插入时的系统时间,就把他当作分区键。每周日晚上九点生成接下来七天的表空间和分区,这样接下来 七天的数据都可以插入了。
3. 如果某周日晚上九点这个点,数据库关闭,造成计划任务没能运行,那么数据库启动后必须要及时生成表空间和分区,使得新数据可以插入。
4.一旦系统时间改变,可能会存在无法插入数据的情况。所以改变时间后必须要保证及时生成最新一周的表空间和分区