oracle 11g 分区表创建(自动按年、月、日分区)

前言:工作中有一张表一年会增长100多万的数据,量虽然不大,可是表字段多,所以一年下来也会达到 1G,而且只增不改,故考虑使用分区表来提高查询性能,提高维护性。

  oracle 11g 支持自动分区,不过得在创建表时就设置好分区。

  如果已经存在的表需要改分区表,就需要将当前表 rename后,再创建新表,然后复制数据到新表,然后删除旧表就可以了。

一、为什么要分区(Partition)

  1、一般一张表超过2G的大小,ORACLE是推荐使用分区表的。

  2、这张表主要是查询,而且可以按分区查询,只会修改当前最新分区的数据,对以前的不怎么做删除和修改。

  3、数据量大时查询慢。

  4、便于维护,可扩展:11g 中的分区表新特性:Partition(分区)一直是 Oracle 数据库引以为傲的一项技术,正是分区的存在让 Oracle 高效的处理海量数据成为可能,在 Oracle 11g 中,分区技术在易用性和可扩展性上再次得到了增强。

  5、与普通表的 sql 一致,不需要因为普通表变分区表而修改我们的代码。

二、oracle 11g 如何按天、周、月、年自动分区

2.1 按年创建

numtoyminterval(1, ‘year‘) 

oracle 11g 分区表创建(自动按年、月、日分区)
--按年创建分区表
create table test_part
(
   ID NUMBER(20) not null,
   REMARK VARCHAR2(1000),
   create_time DATE
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (numtoyminterval(1, ‘year‘))
(partition part_t01 values less than(to_date(‘2018-11-01‘, ‘yyyy-mm-dd‘)));

--创建主键
alter table test_part add constraint test_part_pk primary key (ID) using INDEX;
-- Create/Recreate indexes 
create index test_part_create_time on TEST_PART (create_time); 
oracle 11g 分区表创建(自动按年、月、日分区)

2.2 按月创建

numtoyminterval(1, ‘month‘)

oracle 11g 分区表创建(自动按年、月、日分区)
--按月创建分区表
create table test_part
(
   ID NUMBER(20) not null,
   REMARK VARCHAR2(1000),
   create_time DATE
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (numtoyminterval(1, ‘month‘))
(partition part_t01 values less than(to_date(‘2018-11-01‘, ‘yyyy-mm-dd‘)));

--创建主键
alter table test_part add constraint test_part_pk primary key (ID) using INDEX;
oracle 11g 分区表创建(自动按年、月、日分区)

2.3 按天创建

NUMTODSINTERVAL(1, ‘day‘)

oracle 11g 分区表创建(自动按年、月、日分区)
--按天创建分区表
create table test_part
(
   ID NUMBER(20) not null,
   REMARK VARCHAR2(1000),
   create_time DATE
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (NUMTODSINTERVAL(1, ‘day‘))
(partition part_t01 values less than(to_date(‘2018-11-12‘, ‘yyyy-mm-dd‘)));

--创建主键
alter table test_part add constraint test_part_pk primary key (ID) using INDEX;
oracle 11g 分区表创建(自动按年、月、日分区)

2.4 按周创建

NUMTODSINTERVAL (7, ‘day‘)

oracle 11g 分区表创建(自动按年、月、日分区)
--按周创建分区表
create table test_part
(
   ID NUMBER(20) not null,
   REMARK VARCHAR2(1000),
   create_time DATE
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (NUMTODSINTERVAL (7, ‘day‘))
(partition part_t01 values less than(to_date(‘2018-11-12‘, ‘yyyy-mm-dd‘)));

--创建主键
alter table test_part add constraint test_part_pk primary key (ID) using INDEX;
oracle 11g 分区表创建(自动按年、月、日分区)

2.5 测试

可以添加几条数据来看看效果,oracle 会自动添加分区。

--查询当前表有多少分区
select table_name,partition_name from user_tab_partitions where table_name=‘TEST_PART‘;

--查询这个表的某个(SYS_P21)里的数据
select * from TEST_PART partition(SYS_P21);

三、numtoyminterval 和 numtodsinterval 的区别 

3.1 numtodsinterval(<x>,<c>) ,x 是一个数字,c 是一个字符串。

把 x 转为 interval day to second 数据类型。

常用的单位有 (‘day‘,‘hour‘,‘minute‘,‘second‘)。

测试一下:

 select sysdate, sysdate + numtodsinterval(4,‘hour‘) as res from dual;

结果:

oracle 11g 分区表创建(自动按年、月、日分区)

3.2 numtoyminterval (<x>,<c>)

将 x 转为 interval year to month 数据类型。

常用的单位有 (‘year‘,‘month‘)。

测试一下:

select sysdate, sysdate + numtoyminterval(3, ‘year‘) as res from dual;

结果:

oracle 11g 分区表创建(自动按年、月、日分区)

四、默认分区

4.1 partition part_t01 values less than(to_date(‘2018-11-01‘, ‘yyyy-mm-dd‘))。

表示小于 2018-11-01 的都放在 part_t01 分区表中。

五、给已有的表分区

需要先备份表,然后新建这个表,拷贝数据,删除备份表。

oracle 11g 分区表创建(自动按年、月、日分区)
-- 1. 重命名
alter table test_part rename to test_part_temp;

-- 2. 创建 partition table
create table test_part
(
   ID NUMBER(20) not null,
   REMARK VARCHAR2(1000),
   create_time DATE
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (numtoyminterval(1, ‘month‘))
(partition part_t1 values less than(to_date(‘2018-11-01‘, ‘yyyy-mm-dd‘)));


-- 3. 创建主键
alter table test_part add constraint test_part_pk_1 primary key (ID) using INDEX;

-- 4. 将 test_part_temp 表里的数据迁移到 test_part 表中
insert into test_part_temp select * from test_part;

-- 5. 为分区表设置索引
-- Create/Recreate indexes 
create index test_part_create_time_1 on TEST_PART (create_time); 

-- 6. 删除老的 test_part_temp 表
drop table test_part_temp purge;

-- 7. 作用是:允许分区表的分区键是可更新。
-- 当某一行更新时,如果更新的是分区列,并且更新后的列植不属于原来的这个分区,
-- 如果开启了这个选项,就会把这行从这个分区中 delete 掉,并加到更新后所属的分区,此时就会发生 rowid 的改变。
-- 相当于一个隐式的 delete + insert ,但是不会触发 insert/delete 触发器。
alter table test_part enable row movement;
oracle 11g 分区表创建(自动按年、月、日分区)

 六、全局索引和 Local 索引

我的理解是:

  当查询经常跨分区查,则应该使用全局索引,因为这是全局索引比分区索引效率高。

  当查询在一个分区里查询时,则应该使用 local 索引,因为本地索引比全局索引效率高。

 

扩展:https://blog.csdn.net/lively1982/article/details/9398485 

分区索引:

https://www.cnblogs.com/grefr/p/6095005.html

https://blog.csdn.net/w892824196/article/details/82803889

 

来源:https://www.cnblogs.com/yuxiaole/p/9809294.html

 

 

 

--------------------------------------------------

 

Oracle 分区表相关语法

来源:https://blog.csdn.net/LRjava/article/details/52650149

Oracle offers six different ways to partition your table data:

  1. range partition
  2. interval partition
  3. hash partition
  4. list partition
  5. reference partition
  6. system partition

range partition

范围分区是第一个被引入到Oracle中的分区技术。范围分区技术一般用在准备以时间作为分区列的表上。

范围分区一-单一的分区键值

create table TABLE_RANGE1
(
  as_of_date      DATE not null,
  org_unit_id     VARCHAR2(32),
  gl_account_id   VARCHAR2(10),
  iso_currency_cd CHAR(3)
)
partition by range (AS_OF_DATE)
(
  partition P20160720 values less than (TO_DATE(‘ 2016-07-21 00:00:00‘, ‘SYYYY-MM-DD HH24:MI:SS‘, ‘NLS_CALENDAR=GREGORIAN‘)),
  partition P20160721 values less than (TO_DATE(‘ 2016-07-22 00:00:00‘, ‘SYYYY-MM-DD HH24:MI:SS‘, ‘NLS_CALENDAR=GREGORIAN‘))
);

 

范围分区二-多分区键值

-- Create table
create table TABLE_RANGE2
(
  order_no       NUMBER,
  year_of_order  INTEGER not null,
  month_of_order INTEGER not null,
  day_of_order   INTEGER not null
)
partition by range (YEAR_OF_ORDER, MONTH_OF_ORDER, DAY_OF_ORDER)
(
  partition PART_Q1 values less than (2016, 4, 1),
  partition PART_Q2 values less than (2016, 7, 1),
  partition PART_Q3 values less than (2016, 10, 1),
  partition PART_Q4 values less than (2017, 1, 1)
);

 

Caution
It is common in range-partition tables to use a catchall partition as the very last one. The last partition will contain values less than a value called maxvalue, which is simply any value higher than the values in the second-to-last partition.
这段话的意思就是说,不管怎么样,建议在最大的分区上定义一个叫 maxvalue 的分区用于兜底,一旦发生超过最大分区的数据产生,那么可以进行使用 maxvalue 分区进行保存数据。

范围分区三-有maxvalue分区

create table TABLE_RANGE3
(
  as_of_date      DATE not null,
  org_unit_id     VARCHAR2(32),
  gl_account_id   VARCHAR2(10),
  iso_currency_cd CHAR(3)
)
partition by range (AS_OF_DATE)
(
  partition P20160720 values less than (TO_DATE(‘ 2016-07-21 00:00:00‘, ‘SYYYY-MM-DD HH24:MI:SS‘, ‘NLS_CALENDAR=GREGORIAN‘)),
  partition P20160721 values less than (TO_DATE(‘ 2016-07-22 00:00:00‘, ‘SYYYY-MM-DD HH24:MI:SS‘, ‘NLS_CALENDAR=GREGORIAN‘)),
  partition pmax values less than (maxvalue)
);

 

Note that each partition has a specific name and is stored in a separate tablespace.
需要注意的是每一个分区都有一个名字,保存在独立的空间中。

Interval Partition

Interval partitioning is an extension of the traditional range-partitioning method. In order to implement interval partitioning for a table, you must first specify a minimum of one range partition for that table. Whether you use the minimum singe-range partition or multiple-range partitions, the high value of the range partitioning key is called the transition point. The database automatically creates interval partitions after the data in the table crosses the transition point.

Interval分区技术是传统的范围分区的一种延伸,可以为超过分区键值的数据自动创建对应的分区。但是为了使用Interval分区,那么必须在分区表上至少含有一个以上的分区。

Interval 分区一-根据时间(年)

create table TABLE_INTERVAL1
(
  as_of_date    DATE,
  org_unit_id   VARCHAR2(30),
  gl_account_id VARCHAR2(30)
)
partition by range (AS_OF_DATE)
INTERVAL(NUMTOYMINTERVAL(1, ‘YEAR‘))
(
  partition P2016 values less than (TO_DATE(‘ 2017-01-01 00:00:00‘, ‘SYYYY-MM-DD HH24:MI:SS‘, ‘NLS_CALENDAR=GREGORIAN‘))
  partition P2017 values less than (TO_DATE(‘ 2018-01-01 00:00:00‘, ‘SYYYY-MM-DD HH24:MI:SS‘, ‘NLS_CALENDAR=GREGORIAN‘))
);

 

Interval 分区二-根据时间(月)

create table TABLE_INTERVAL2
(
  as_of_date    DATE,
  org_unit_id   VARCHAR2(30),
  gl_account_id VARCHAR2(30)
)
partition by range (AS_OF_DATE)
INTERVAL(NUMTOYMINTERVAL(1, ‘MONTH‘))
(
  partition P201701 values less than (TO_DATE(‘ 2017-02-01‘, ‘YYYY-MM-DD‘)),
  partition P201702 values less than (TO_DATE(‘ 2018-03-01‘, ‘YYYY-MM-DD‘))
);

 

Interval 分区三-根据时间(天)

create table TABLE_INTERVAL3
(
  as_of_date    DATE,
  org_unit_id   VARCHAR2(30),
  gl_account_id VARCHAR2(30)
)
partition by range (AS_OF_DATE)
INTERVAL(NUMTODSINTERVAL(1, ‘DAY‘))
(
  partition P20170101 values less than (TO_DATE(‘ 2017-01-02‘, ‘YYYY-MM-DD‘)),
  partition P20170102 values less than (TO_DATE(‘ 2018-01-03‘, ‘YYYY-MM-DD‘))
);

 

Interval 分区四-根据数字

-- Create table
create table TABLE_INTERVAL4
(
  id   INTEGER not null,
  name VARCHAR2(30)
)
partition by range (ID)
INTERVAL(1000)
(
  partition P1 values less than (1000),
  partition P2 values less than (2000)
);

 

Interval 分区五-指定分区

create table TABLE_INTERVAL5
(
  id   INTEGER not null,
  name VARCHAR2(20)
)
partition by range (ID)
INTERVAL(1000) STORE IN (REPORT_TS, ETL_TS)
(
  partition P1 values less than (1000),
  partition P2 values less than (2000)
);

 

Range 分区转换为 Interval 分区

ALTER TABLE TABLE_RANGE2 SET INTERVAL(NUMTODSINTERVAL(1, ‘DAY‘));

Caution
具有maxvalue分区的范围分区无法变成Interval分区。

Interval 分区转换为 Range 分区

ALTER TABLE TABLE_INTERVAL4 SET INTERVAL();

Interval 分区添加指定分区(添加RAYLEE)

ALTER TABLE TABLE_INTERVAL5 SET STORE IN (REPORT_TS, ETL_TS, RAYLEE);

Interval 分区删除指定分区(删除RAYLEE)

ALTER TABLE TABLE_INTERVAL5 SET STORE IN (REPORT_TS, ETL_TS);

如果要删除的表空间上已经存在分区

ALTER TABLE TABLE_NAME MOVE PARTITION PARTITION_NAME TABLESPACE TARGET_TABLESPACE;

Interval 分区注意事项

  • Use the INTERVAL caluse in the CREATE TABLE statement to create an
    interval-partitioned table.
    在建表语句中使用INTERVAL关键字创建Interval 分区

  • Specify at least one range partition using the partition clause,
    before specifying your interval partitions.
    创建Interval 分区最少使用存在一个范围分区

  • The partitioning key must be of the NUMBER or DATE type.
    分区的列必须是 NUMBER 或者 DATE 类型

  • You can optionally specify the tablespaces for the partition data by
    including the STORE IN clause in the CREATE TABLE statement.
    可以选择是否在建表语句中使用 STORE IN 子句用于指定表空间

HASH 分区

Use the hash-partitioning, all you have to do is decide on the number of partitions, and Oracle’s hashing algorithms will assign a hash value to each row’s partitioning key and place it in the appropriate partition.

对于 HASH 分区,你所需要做的就是决定要 hash 成多少个分区,Oracle的 hash 分区算法将会给每一个行的分区列的键值一个hash 值,并把它放置到对应的分区去

HASH 分区代码

CREATE TABLE TABLE_HASH
(   ID INT NOT NULL,
    YEAR_OF_ORDER INT NOT NULL,
    MONTH_OF_ORDER INT NOT NULL,
    DAY_OF_ORDER INT NOT NULL)
PARTITION BY HASH(ID)
PARTITIONS 2
STORE IN (REPORT_TS, ETL_TS);

 

LIST 分区

对于非连续型的分区的一种补充使用 LIST 分区。

LIST 分区代码-使用默认分区

-- Create table
create table TABLE_LIST1
(
  alpha_id CHAR(1),
  name     VARCHAR2(20)
)
partition by list (ALPHA_ID)
(
  partition P_AG values (‘A‘, ‘B‘, ‘C‘, ‘D‘, ‘E‘, ‘F‘, ‘G‘),
  partition P_H values (‘H‘, ‘I‘, ‘J‘, ‘K‘, ‘L‘, ‘M‘, ‘N‘)
);

 

 

LIST 分区代码-指定分区

create table TABLE_LIST2
(
  alpha_id CHAR(1),
  name     VARCHAR2(20)
)
partition by list (ALPHA_ID)
(
  partition P_AG values (‘A‘, ‘B‘, ‘C‘, ‘D‘, ‘E‘, ‘F‘, ‘G‘) 
  TABLESPACE REPORT_TS,
  partition P_H values (‘H‘, ‘I‘, ‘J‘, ‘K‘, ‘L‘, ‘M‘, ‘N‘) 
  TABLESPACE ETL_TS
);

 

 

oracle 11g 分区表创建(自动按年、月、日分区)

上一篇:odoo 分布式,服务器多开,单一数据库


下一篇:Mysql数据库sql_mode参数only_full_group_by引发的报错