ORACLE:分区表range,hash,list
2015-07-29 20:15
676 查看
对表数据进行水平分割的一种手段!
降低I/O
分散I/O
基本概念:把一个大表分成几个部分
分区的方式:
好处:
可以分散IO,不同的分区可以放在不同的表空间上。
如有的表是按照手机号码的后两位分区,这个表就有100个分区,可以把IO分散到100个不同的segment上。
可靠性
一个分区故障,不会影响其它的分区。可以建立再不同的表空间上,然后再集合起来用,有点像lvm。
创建管理range分区
create table t_range( hiredate date,id number(10)) partition by range(hiredate)
(
partition p1 values less than (to_date('2010-01-01','yyyy-mm-dd')),
partition p2 values less than (to_date('2014-01-01','yyyy-mm-dd'))
);
SQL> insert into t_range values (to_date('2008-01-01','yyyy-mm-dd'),1);
SQL> insert into t_range values (to_date('2009-01-01','yyyy-mm-dd'),2);
SQL> insert into t_range values (to_date('2010-01-01','yyyy-mm-dd'),3);
SQL> insert into t_range values (to_date('2011-01-01','yyyy-mm-dd'),4);
SQL> insert into t_range values (to_date('2012-01-01','yyyy-mm-dd'),5);
这几条记录insert完成后,p1里面有几条记录,p2分区里面有几条记录
SQL> select * from t_range partition(p1);
HIREDATE ID
--------- ----------
01-JAN-08 1
01-JAN-09 2
2条
seleSQL> select * from t_range partition(p2);
HIREDATE ID
--------- ----------
01-JAN-10 3
01-JAN-11 4
01-JAN-12 5
3条
如果我insert一条分区关键字中没有的记录呢?、
INSERT INTO t_range VALUES (TO_DATE('2017-02-02','YYYY-MM-DD'),6);
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
报错,为什么??
解决这个问题两个方式
1、添加非最大分区
alter table t_range add partition p3 values less than (to_date('2018-01-01','yyyy-mm-dd'));
当然,也可以给他一个最大分区
2、添加最大分区
alter table t_range add partition p_max values less than (maxvalue); 添加最大分区
问题,有了最大分区后,如果我还想划分分区呢?比如还想要p4
alter table t_range add partition p4 values less than (to_date('2020-01-01','yyyy-mm-dd'));
报错
添加分区的要求,后面的分区必须要大于最后一个分区,现在表中的最后一个分区的值是maxvalue,还能添加吗?
3、split 分区:
alter table t_range split partition p_max
at (to_date('2020-01-01','yyyy-mm-dd')) --at后面加条件,默认是less than
into (partition p4,partition p_max) --into后面是分区,p_4是新劈的分区,就相当于把p_max分区来一刀,左边的叫p4,右边的叫p_max
/
注意:1、生产环境中及时add分区
在生产环境中要注意的是,在没有最大分区一定要注意检查分区范围。 如,你的分区只是在2015年,那么到了2016年的1月1日的时候你的业务就崩溃了。。。 移动故障
2、split分区要注意max分区的数据量情况
注意的第二点:有的时候有最大分区,但是由于某些原因很多数据匹配不到分区就insert到了最大分区中,如果后面要进行修复,如split的例子,要尽量保证max分区中的数据较少,否则会导致split的时间很长影响业务,alter table加的锁是6级别的锁啊!! 方法可以是使用expdp把max分区中的数据导出来,spilt后在impdp导入进去
能不能有一个方法,把分区均匀的分到不同的地方??
hash 分区的特定:
1、更好的办法DML
why 已经把数据均匀的分开了,避免了热点块热点盘的问题
2、分区自动管理
根据 partition key oracle自动决定你放到那个分区中
3、hash分区的个数最好是2的幂次方个
缺点:range能精确的把某一行分到某一个分区上,hash却不能
create tablespace ts1 datafile '/oradata/vicdb/ts1.dbf' size 30m autoextend off;
create tablespace ts2 datafile '/oradata/vicdb/ts2.dbf' size 30m autoextend off;
create table t_hash (hiredate date,id number(10)) partition by hash(hiredate)
( partition p1 tablespace ts1,
partition p2 tablespace ts2
);
--insert 数据
insert into t_hash values (to_date('2008-01-01','yyyy-mm-dd'),1);
insert into t_hash values (to_date('2009-01-01','yyyy-mm-dd'),2);
insert into t_hash values (to_date('2010-01-01','yyyy-mm-dd'),3);
insert into t_hash values (to_date('2011-01-01','yyyy-mm-dd'),4);
insert into t_hash values (to_date('2012-01-01','yyyy-mm-dd'),5);
--验证数据平均分布
select * from t_hash partition(p1);
select * from t_hash partition(p2);
hash分区的分区消除
注意在hash分区中,对于不等值连接,如> <等,分区消除不可用,也就是说会扫描所有的分区。
比如,大于xx就可能意味结果不止一行,对于结果不止一行的情况,无法判断那些结果是否在同一个分区(range可以判断,因为他是有序的)
SQL> select * from t_hash where hiredate < to_date('2010-05-05','yyyy-mm-dd');
Execution Plan
----------------------------------------------------------
Plan hash value: 249093498
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 66 | 4 (0)| 00:00:01 | | |
| 1 | PARTITION HASH ALL| | 3 | 66 | 4 (0)| 00:00:01 | 1 | 2 |
|* 2 | TABLE ACCESS FULL| T_HASH | 3 | 66 | 4 (0)| 00:00:01 | 1 | 2 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("HIREDATE"<TO_DATE(' 2010-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
Note
-----
- dynamic sampling used for this statement (level=2)
SQL> select * from t_hash where hiredate = to_date('2010-05-05','yyyy-mm-dd');
Execution Plan
----------------------------------------------------------
Plan hash value: 616068738
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 22 | 3 (0)| 00:00:01 | | |
| 1 | PARTITION HASH SINGLE| | 1 | 22 | 3 (0)| 00:00:01 | 2 | 2 |
|* 2 | TABLE ACCESS FULL | T_HASH | 1 | 22 | 3 (0)| 00:00:01 | 2 | 2 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("HIREDATE"=TO_DATE(' 2010-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
------------------
create table list_t
partition by LIST(DEPTNO)
( PARTITION D10_20 VALUES ('10','20') TABLESPACE users,
PARTITION D30 VALUES ('30') TABLESPACE users,
PARTITION D00 VALUES (DEFAULT) TABLESPACE USERS)
AS SELECT * FROM EMP;
SELECT * FROM EMP3 PARTITION (D10);
SELECT * FROM EMP3 PARTITION (D20);
SELECT * FROM EMP3 PARTITION (D00);
----------------------------------------------------
create table comp
(range_key date,
hash_key int,
data date)
partition by range(range_key)
subpartition by hash(hash_key) subpartitions 2
(
partition p1 values less than(to_date('2014-04-01','yyyy-mm-dd'))
(subpartition h1,
subpartition h2
),
partition p2 values less than(to_date('2015-04-01','yyyy-mm-dd'))
(subpartition h11,
subpartition h22
)
)
==================================================
降低I/O
分散I/O
基本概念:把一个大表分成几个部分
分区的方式:
range
如上面的清单表,按照时间范围进行分区好处:
可以分散IO,不同的分区可以放在不同的表空间上。
如有的表是按照手机号码的后两位分区,这个表就有100个分区,可以把IO分散到100个不同的segment上。
可靠性
一个分区故障,不会影响其它的分区。可以建立再不同的表空间上,然后再集合起来用,有点像lvm。
创建管理range分区
create table t_range( hiredate date,id number(10)) partition by range(hiredate)
(
partition p1 values less than (to_date('2010-01-01','yyyy-mm-dd')),
partition p2 values less than (to_date('2014-01-01','yyyy-mm-dd'))
);
SQL> insert into t_range values (to_date('2008-01-01','yyyy-mm-dd'),1);
SQL> insert into t_range values (to_date('2009-01-01','yyyy-mm-dd'),2);
SQL> insert into t_range values (to_date('2010-01-01','yyyy-mm-dd'),3);
SQL> insert into t_range values (to_date('2011-01-01','yyyy-mm-dd'),4);
SQL> insert into t_range values (to_date('2012-01-01','yyyy-mm-dd'),5);
这几条记录insert完成后,p1里面有几条记录,p2分区里面有几条记录
SQL> select * from t_range partition(p1);
HIREDATE ID
--------- ----------
01-JAN-08 1
01-JAN-09 2
2条
seleSQL> select * from t_range partition(p2);
HIREDATE ID
--------- ----------
01-JAN-10 3
01-JAN-11 4
01-JAN-12 5
3条
如果我insert一条分区关键字中没有的记录呢?、
INSERT INTO t_range VALUES (TO_DATE('2017-02-02','YYYY-MM-DD'),6);
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
报错,为什么??
解决这个问题两个方式
1、添加非最大分区
alter table t_range add partition p3 values less than (to_date('2018-01-01','yyyy-mm-dd'));
当然,也可以给他一个最大分区
2、添加最大分区
alter table t_range add partition p_max values less than (maxvalue); 添加最大分区
问题,有了最大分区后,如果我还想划分分区呢?比如还想要p4
alter table t_range add partition p4 values less than (to_date('2020-01-01','yyyy-mm-dd'));
报错
添加分区的要求,后面的分区必须要大于最后一个分区,现在表中的最后一个分区的值是maxvalue,还能添加吗?
3、split 分区:
alter table t_range split partition p_max
at (to_date('2020-01-01','yyyy-mm-dd')) --at后面加条件,默认是less than
into (partition p4,partition p_max) --into后面是分区,p_4是新劈的分区,就相当于把p_max分区来一刀,左边的叫p4,右边的叫p_max
/
注意:1、生产环境中及时add分区
在生产环境中要注意的是,在没有最大分区一定要注意检查分区范围。 如,你的分区只是在2015年,那么到了2016年的1月1日的时候你的业务就崩溃了。。。 移动故障
2、split分区要注意max分区的数据量情况
注意的第二点:有的时候有最大分区,但是由于某些原因很多数据匹配不到分区就insert到了最大分区中,如果后面要进行修复,如split的例子,要尽量保证max分区中的数据较少,否则会导致split的时间很长影响业务,alter table加的锁是6级别的锁啊!! 方法可以是使用expdp把max分区中的数据导出来,spilt后在impdp导入进去
hash
为了解决range 中数据不均匀的问题,有的时候用户是密集查询某个分区的数据能不能有一个方法,把分区均匀的分到不同的地方??
hash 分区的特定:
1、更好的办法DML
why 已经把数据均匀的分开了,避免了热点块热点盘的问题
2、分区自动管理
根据 partition key oracle自动决定你放到那个分区中
3、hash分区的个数最好是2的幂次方个
缺点:range能精确的把某一行分到某一个分区上,hash却不能
create tablespace ts1 datafile '/oradata/vicdb/ts1.dbf' size 30m autoextend off;
create tablespace ts2 datafile '/oradata/vicdb/ts2.dbf' size 30m autoextend off;
create table t_hash (hiredate date,id number(10)) partition by hash(hiredate)
( partition p1 tablespace ts1,
partition p2 tablespace ts2
);
--insert 数据
insert into t_hash values (to_date('2008-01-01','yyyy-mm-dd'),1);
insert into t_hash values (to_date('2009-01-01','yyyy-mm-dd'),2);
insert into t_hash values (to_date('2010-01-01','yyyy-mm-dd'),3);
insert into t_hash values (to_date('2011-01-01','yyyy-mm-dd'),4);
insert into t_hash values (to_date('2012-01-01','yyyy-mm-dd'),5);
--验证数据平均分布
select * from t_hash partition(p1);
select * from t_hash partition(p2);
hash分区的分区消除
注意在hash分区中,对于不等值连接,如> <等,分区消除不可用,也就是说会扫描所有的分区。
比如,大于xx就可能意味结果不止一行,对于结果不止一行的情况,无法判断那些结果是否在同一个分区(range可以判断,因为他是有序的)
SQL> select * from t_hash where hiredate < to_date('2010-05-05','yyyy-mm-dd');
Execution Plan
----------------------------------------------------------
Plan hash value: 249093498
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 66 | 4 (0)| 00:00:01 | | |
| 1 | PARTITION HASH ALL| | 3 | 66 | 4 (0)| 00:00:01 | 1 | 2 |
|* 2 | TABLE ACCESS FULL| T_HASH | 3 | 66 | 4 (0)| 00:00:01 | 1 | 2 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("HIREDATE"<TO_DATE(' 2010-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
Note
-----
- dynamic sampling used for this statement (level=2)
SQL> select * from t_hash where hiredate = to_date('2010-05-05','yyyy-mm-dd');
Execution Plan
----------------------------------------------------------
Plan hash value: 616068738
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 22 | 3 (0)| 00:00:01 | | |
| 1 | PARTITION HASH SINGLE| | 1 | 22 | 3 (0)| 00:00:01 | 2 | 2 |
|* 2 | TABLE ACCESS FULL | T_HASH | 1 | 22 | 3 (0)| 00:00:01 | 2 | 2 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("HIREDATE"=TO_DATE(' 2010-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
------------------
list
LIST方式分区create table list_t
partition by LIST(DEPTNO)
( PARTITION D10_20 VALUES ('10','20') TABLESPACE users,
PARTITION D30 VALUES ('30') TABLESPACE users,
PARTITION D00 VALUES (DEFAULT) TABLESPACE USERS)
AS SELECT * FROM EMP;
SELECT * FROM EMP3 PARTITION (D10);
SELECT * FROM EMP3 PARTITION (D20);
SELECT * FROM EMP3 PARTITION (D00);
----------------------------------------------------
组合分区
对应分区还可以进行分区在分区,也就是子分区。 子分区一般是用于大规模数据的。create table comp
(range_key date,
hash_key int,
data date)
partition by range(range_key)
subpartition by hash(hash_key) subpartitions 2
(
partition p1 values less than(to_date('2014-04-01','yyyy-mm-dd'))
(subpartition h1,
subpartition h2
),
partition p2 values less than(to_date('2015-04-01','yyyy-mm-dd'))
(subpartition h11,
subpartition h22
)
)
==================================================
相关文章推荐
- Oracle中的临时表
- oracle bi publisher报表插入图片
- oracle pctfree和pctused详解
- 我的第一篇
- Oracle事务
- Mybatis+Oracle批处理
- ORACLE创建IOT(索引组织表)
- ORACLE创建cluster表
- ORACLE的TX锁和TM锁及解锁
- 如何查看Oracle数据库表空间大小(空闲、已使用),是否要增加表空间的数据文件
- oracle字符集乱码及返回 REF CURSOR 的存储过程执行问题
- 【sql】oracle 数据库instr函数的用法详解
- Oracle语句优化规则汇总(7)
- .net excel利用NPOI导入oracle
- oracle数据同步方案
- oracle表查询(5)
- oracle表管理(4)
- oracle数据类型(3)
- oracle数据库常用plsql语句
- ORACLE Initialization or shutdown in progress