一、什么是数据库表分区
数据库表分区,和数据库分表是不同的概念,分表是指将一个表分成N多个小表进行数据存储,对外显示有N个表;而表分区是将一个表的数据分成N个区进行存储,对外显示还是只有一个表。本次文章主要记录表分区的实现,将不在对数据库分表进行多说明。现实中可表分区和数据库分表一起使用,增加数据库对数据量大的支持。
1.1、为什么要使用表分区?
在日常的开发中,我们经常会遇到大表,即数据量达到数百万条乃至数千万条的情况。这样的表过于庞大,以至于在进行查询、修改的时候耗时太长,性能低下,所以我们需要使用分区。
二、Oracle实现表分区
oracle对表分区是实现的最好,可直接在建表中配置,实现表根据日期自动分区,相对mysql和pgsql的通过事件或者触发器人为实现自动分区的手段,要方便很多,效率也更高。
使用分区表存储,按每天自动生成一张分区表保存当天数据。经测试如果在T day往数据库里插入一条T + 1 day的数据,数据库也会自动创建T + 1 day分区,同时第二天不会再自动创建新的分区。
2.1、建表语句
create table tablename
(
ID NUMBER(20) not null,
REMARK VARCHAR2(1000),
create_time DATE
)
PARTITION BY RANGE (CREATE_TIME) INTERVAL (NUMTODSINTERVAL(1, 'day')) --设定通过字段'CREATE_TIME'来分区,自动创建间隔1天
(partition part_t01 values less than(to_date('2018-11-12', 'yyyy-mm-dd'))); --初始建立一个分区,注意使用less than的时候,日期设定为当天日期+1,代表今天的数据存储在当前分区。
--创建主键
alter table tablename add constraint test_part_pk primary key (ID) using INDEX;
2.2、查询分区表
-- 查询所有分区表 一个表一条记录
select * from user_part_tables;
-- 查询所有分区表 一个表对应n个分区就有n条记录
select * from user_tab_partitions;
select * from user_tab_partitions where table_name='XXX';
2.3、指定分区查询数据
select * from tablename partition(partitionname);
2.4、不指定分区查询数据
select * from tablename;
2.5、分区索引相关
-- 查询所有分区索引 一个表索引一条记录
SELECT * FROM USER_PART_INDEXES;
-- 查询所有分区索引 一个索引对应n个分区就有n条记录
SELECT * FROM USER_IND_PARTITIONS;
-- 创建分区本地索引 有几个分区就会生成多少条local索引
create index idx_daily_partition on daily_partition(CREATE_TIME) local; --注:相同字段不能同时存在分区索引和全表索引
-- 删除索引
drop INDEX index_name;
2.6、全表索引
-- 创建全表索引
create index daily_partition_create_time on daily_partition (create_time); --注:相同字段不能同时存在分区索引和全表索引
-- 删除索引
drop INDEX index_name;
2.7、查询效率分析
·测试数据插入,三个分区,每个分区250w条数据,模拟流水服务一天的数据量。
a.不指定查询分区(数据未跨分区,只查询一天的数据),直接查表,在230w条数据中索引出10w条,耗时1.295s(检索出20w条,耗时2.4s)
select * from DAILY_PARTITION where create_time between TO_DATE('2020-10-14 05:00:00 AM','yyyy-mm-dd hh:mi:ss AM') and to_date('2020-10-14 06:00:00 AM','yyyy-mm-dd HH:mi:ss AM');
b.分析查询策略,走的是分区索引,耗时随返回数据量成线性递增。
c.跨分区查询,查询20w条数据,耗时2.732s(基本可以认为与1中未跨分区时间一致,耗时长短取决于返回的数据量大小,230w条全查是31.72s符合线性增长规律)
select * from DAILY_PARTITION where create_time between TO_DATE('2020-10-13 05:00:00 AM','yyyy-mm-dd hh:mi:ss AM') and to_date('2020-10-14 06:00:00 AM','yyyy-mm-dd HH:mi:ss AM');
后面又给表增加了全局索引,发现全局索引的效率没有分区的local索引效率高。