达梦数据库 DM 支持对表进行水平分区。对于水平分区,提供以下分区方式:
范围(range) 水平分区:对表中的某些列上值的 范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上,比如 时间范围。
哈希 (hash ) 水平分区:通过指定分区编号来 均匀分布数据的一种分区类型,通过在 I/O 设备上进行散列分区,使得这些 分区大小基本一致;
列表(list )水平分区:通过指定表中的 某个列的离散值集,来确定应当存储在一起的数据。例如,可以对表上的 status 列的值在('A','H','O')放在一个分区,值在('B','I','P')放在另一个分区,以此类推; 比如地区。
多级分区表:按上述 三种分区方 式 进行任意组合,将表进行多次分区,称为多级分区表。
范围分区是按照 某个列或几个列的值的范围来创建分区,当用户向表中写入数据时,数据库服务器将按照这些列上的值进行判断,将数据写入相应的分区中。
在创建范围分区时,首先要指定分区列,即按照哪些列进行分区,然后为每个分区指定数据范围。范围分区支持 MAXVALUE 范围值的使用,MAXVALUE 相当于一个比任何值都大的值。范围分区非常适用于数据按时间范围组织的表,不同的时间段的数据属于不同的分区。
创建一个范围分区表 callinfo,用来记录用户的 2010 年的电话通讯信息,包括主叫号码、被叫号码、通话时间和时长,并且根据季度进行分区。
创建范围分区表:
--VALUES EQU OR LESS THAN(包含上限)
CREATE TABLE callinfo(
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
)
PARTITION BY RANGE(time)(
PARTITION p1 VALUES LESS THAN ('2020-04-01'),
PARTITION p2 VALUES LESS THAN ('2020-07-01'),
PARTITION p3 VALUES LESS THAN ('2020-10-01'),
PARTITION p4 VALUES EQU OR LESS THAN ('2020-12-31'));
--VALUES LESS THAN(不包含上限)
CREATE TABLE callinfo2(
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
)
PARTITION BY RANGE(time)(
PARTITION p1 VALUES LESS THAN ('2020-04-01'),
PARTITION p2 VALUES LESS THAN ('2020-07-01'),
PARTITION p3 VALUES LESS THAN ('2020-10-01'),
PARTITION p4 VALUES LESS THAN ('2020-12-31'),
PARTITION p5 VALUES LESS THAN (maxvalue));
--增加存放超出范围数据的分区
alter table callinfo add partition pn values less than(maxvalue);
通过数据字典查看分区的信息:
--查看表是否为分区表属性:
select table_name,partitioned from dba_tables where table_name='CALLINFO';
行号 TABLE_NAME PARTITIONED
---------- ---------- -----------
1 CALLINFO YES
--查看表的分区类型:
select table_name,partitioning_type,partition_count from dba_part_tables where
table_name='CALLINFO';
行号 TABLE_NAME PARTITIONING_TYPE PARTITION_COUNT
---------- ---------- ----------------- --------------------
1 CALLINFO RANGE 4
--查看表每个分区的最大值:
select table_name,partition_name,HIGH_VALUE from dba_tab_partitions;
行号 TABLE_NAME PARTITION_NAME HIGH_VALUE
---------- ---------- -------------- -----------------------------
1 CALLINFO P4 DATETIME'2020-12-31 00:00:00'
2 CALLINFO P1 DATETIME'2020-04-01 00:00:00'
3 CALLINFO P2 DATETIME'2020-07-01 00:00:00'
4 CALLINFO P3 DATETIME'2020-10-01 00:00:00'
插入数据:
insert into callinfo values('art','add','2020-01-01 10:00:00',10);
insert into callinfo values('art','add','2020-02-01 11:00:00',3);
insert into callinfo values('art','add','2020-04-01 00:00:00',5);
insert into callinfo values('srt','bdd','2020-07-01 11:00:00',5);
insert into callinfo values('brt','ddd','2020-12-31 11:00:00',5);
insert into callinfo values('brt','ddd','2020-12-31 11:00:00',5);
insert into callinfo values('brt','ddd','2020-12-31 00:00:00',5);
insert into callinfo values('crt','ddd','2021-1-1 00:00:00',5);
insert into callinfo values('crt','ddd','2021-1-1 00:00:00',5);
查看数据:
select * from callinfo partition(p1);
select * from callinfo partition(p2);
select * from callinfo partition(p3);
select * from callinfo partition(p4);
创建分区表,每个分区指定表空间:
--创建表空间:
create tablespace test1 datafile 'test101.dbf' size 64;
create tablespace test2 datafile 'test201.dbf' size 64;
create tablespace test3 datafile 'test301.dbf' size 64;
create tablespace test4 datafile 'test401.dbf' size 64;
--创建分区表:
create table callinfo3 (
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
)
PARTITION BY RANGE(time)(
PARTITION p1 VALUES LESS THAN ('2020-04-01') tablespace test1,
PARTITION p2 VALUES LESS THAN ('2020-07-01') tablespace test2,
PARTITION p3 VALUES LESS THAN ('2020-10-01') tablespace test3,
PARTITION p4 VALUES EQU OR LESS THAN (maxvalue) tablespace test4);
--查看分区所在表空间:
select table_name,partition_name,HIGH_VALUE,tablespace_name from dba_tab_partitions where
table_name='CALLINFO3';
行号 TABLE_NAME PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
---------- ---------- -------------- ----------------------------- ---------------
1 CALLINFO3 P4 MAXVALUE TEST4
2 CALLINFO3 P1 DATETIME'2020-04-01 00:00:00' TEST1
3 CALLINFO3 P2 DATETIME'2020-07-01 00:00:00' TEST2
4 CALLINFO3 P3 DATETIME'2020-10-01 00:00:00' TEST3
所有子分区必须在同一个表空间
create table callinfo4 (
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
)
PARTITION BY RANGE(time)(
PARTITION p1 VALUES LESS THAN ('2020-04-01'),
PARTITION p2 VALUES LESS THAN ('2020-07-01'),
PARTITION p3 VALUES LESS THAN ('2020-10-01'),
PARTITION p4 VALUES EQU OR LESS THAN (maxvalue)) storage(on test1,nobranch);
属于范围分区表的扩展,当插入的数据超出分区范围后,按照指定的间隔规则, 自动创建分区,实现分区自动管理。不允许手动添加分区。不支持 NUMTODSINTERVAL(1,'day')。
间隔分区关键字:
numtoyminterval(年、月)
numtodsinterval(日、小时、分钟、秒)
创建以月为单位的间隔分区:
CREATE TABLE interval_sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
( PARTITION p0 VALUES LESS THAN ('2008-1-1'),
PARTITION p1 VALUES LESS THAN ('2009-1-1'),
PARTITION p2 VALUES LESS THAN ('2009-7-1'),
PARTITION p3 VALUES LESS THAN ('2010-1-1') );
查看分区信息:
select partition_name,SUBPARTITION_COUNT,HIGH_VALUE from dba_tab_partitions where table_name like '%SALES%';
插入超出范围数据:
insert into interval_sales values(1,1,'2010-2-1',2000);
Commit;
再次查看分区信息:
select partition_name,SUBPARTITION_COUNT,HIGH_VALUE from dba_tab_partitions where table_name like '%SALES%';
创建以年为间隔的分区:
CREATE TABLE interval_sales_new
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id)
INTERVAL(NUMTOYMINTERVAL(1, 'YEAR'))
( PARTITION p0 VALUES LESS THAN ('2008-1-1'),
PARTITION p1 VALUES LESS THAN ('2009-1-1'),
PARTITION p2 VALUES LESS THAN ('2010-1-1'),
PARTITION p3 VALUES LESS THAN ('2011-1-1') );
范围分区是按照某个列上的数据范围进行分区的,如果某个列上的数据无法通过划分范围的方法进行分区,并且该列上的数据是相对固定的一些值,可以考虑使用 LIST 分区。
一般来说,对于 数字型或者日期型的数据,适合采用 范围分区的方法;而对于字符型数据,取值比较固定的,则适合于采用 LIST 分区的方法。
例如,创建一个产品销售记录表 sales,记录产品的销量情况。由于产品只在几个 固定的城市销售,所以可以按照销售城市对该表进行分区。
创建list分区表:
--创建list分区表
CREATE TABLE sales(
sales_id INT,
saleman CHAR(20),
saledate DATETIME,
city CHAR(10)
)
PARTITION BY LIST(city)
(
PARTITION p1 VALUES ('北京', '天津'),
PARTITION p2 VALUES ('上海', '南京', '杭州'),
PARTITION p3 VALUES ('武汉', '长沙'),
PARTITION p4 VALUES ('广州', '深圳')
);
--插入数据
insert into sales VALUES(4,'CCCCCC','2022-03-14','西安');
--增加存放超出列表数据的分区
alter table sales add partition pn values(default);
--通过指定 default 来存放超出列表的数据
CREATE TABLE sales1(
sales_id INT,
saleman CHAR(20),
saledate DATETIME,
city CHAR(10)
)
PARTITION BY LIST(city)
(
PARTITION p1 VALUES ('北京', '天津'),
PARTITION p2 VALUES ('上海', '南京', '杭州'),
PARTITION p3 VALUES ('武汉', '长沙'),
PARTITION p4 VALUES ('广州', '深圳'),
PARTITION p5 VALUES (default)
);
在很多情况下,用户无法预测某个列上的数据变化范围,因而无法实现创建固定数量的范围分区或 LIST 分区。
在这种情况下,DM 哈希分区提供了一种在 指定数量的分区中均等地划分数据的方法,基于 分区键的散列值将行映射到分区中。当用户向表中写入数据时,数据库服务器将根据一个哈希函数对数据进行计算,把数据均匀地分布在各个分区中。在哈希分区中,用户无法预测数据将被写入哪个分区中。
现在重新考虑产品销售表的例子。如果 销售城市不是相对固定的,而是遍布全国各地,这时很难对表进行 LIST 分区。如果为该表进行哈希分区,可以很好地解决这个问题。
CREATE TABLE sales01(
sales_id INT,
saleman CHAR(20),
saledate DATETIME,
city CHAR(10)
)
PARTITION BY HASH(city)(
PARTITION p1,
PARTITION p2,
PARTITION p3,
PARTITION p4
);
--如果不需指定分区表名,可以通过指定哈希分区个数来建立哈希分区表。
CREATE TABLE sales02(
sales_id INT,
saleman CHAR(20),
saledate DATETIME,
city CHAR(10)
)
PARTITION BY HASH(city)
PARTITIONS 4 STORE IN (test1, test2, test3, test4);
**说明:**PARTITIONS 后的数字表示哈希分区的分区数,STORE IN 子句中指定了哈希分区依次使用的表空间。使用这种方式建立的哈希分区表分区名是匿名的,DM 统一使用DMHASHPART+分区号(从 0 开始)作为分区名。
在很多情况下,经过一次分区并不能精确地对数据进分类,这时需要多级分区表。
例如,创建一个产品销售记录表 sales,记录产品的销量情况。由于产品需要 按地点和销售时间进行统计,则可以对该表进行 LIST-RANGE 分区。
创建组合分区:
--创建list-rang组合分区
CREATE TABLE SALES03(SALES_ID INT,SALEMAN CHAR(20),SALEDATE DATETIME,CITY CHAR(10))
PARTITION BY LIST(CITY) --主分区
SUBPARTITION BY RANGE(SALEDATE) --子分区
SUBPARTITION TEMPLATE( --子分区模板
SUBPARTITION P11 VALUES LESS THAN ('2012-04-01'),
SUBPARTITION P12 VALUES LESS THAN ('2012-07-01'),
SUBPARTITION P13 VALUES LESS THAN ('2012-10-01'),
SUBPARTITION P14 VALUES EQU OR LESS THAN (MAXVALUE))
(PARTITION P1 VALUES ('北京', '天津')
(SUBPARTITION P11_1 VALUES LESS THAN ('2012-10-01'),
SUBPARTITION P11_2 VALUES EQU OR LESS THAN (MAXVALUE)),
PARTITION P2 VALUES ('上海', '南京', '杭州'),
PARTITION P3 VALUES (DEFAULT));
--插入数据
insert into SALES03 values(1,'AAA','2012-05-01','北京');
insert into SALES03 values(1,'BBB','2012-05-01','武汉');
ALTER TABLE callinfo ADD PARTITION p5 VALUES LESS THAN ('2021-4-1');
ALTER TABLE callinfo DROP PARTITION p1;
要想将两个范围分区的内容融合到一个分区,就要使用 ALTER TABLE MERGE PARTITION语句。
ALTER TABLE callinfo MERGE PARTITIONS p3, p4 into partition p3_4;
ALTER TABLE 语句的 SPLIT PARTITION 子句被用于将一分区中的内容重新划分成两个新的分区。当一个分区变得太大以至于要用很长时间才能完成备份、恢复或维护操作时,就应考虑做分割分区的工作,还可以用 SPLIT PARTITION 子句来分重新划分 I/O 负载。
--拆分分区会导致数据的重组和分区索引的重建
ALTER TABLE callinfo SPLIT PARTITION p3_4 AT ('2020-9-30') INTO (PARTITION p3, PARTITION p4);
CREATE TABLE callinfo_2020Q2(
caller CHAR(15),
callee CHAR(15),
time DATETIME,
duration INT
);
ALTER TABLE callinfo EXCHANGE PARTITION p2 WITH TABLE callinfo_2020Q2;
临时表 ON COMMIT 关键词指定表中的数据是事务级还是或会话级的,默认情况下是事务级的。
1.on commit delete rows:指定临时表是事务级的,每次事务提交或回滚之后,表中所有数据都被删除;
2.on commit preserve rows:指定临时表是会话级的,会话结束时才清空表,并释放临时B树。
创建事务级临时表:
--创建临时表
CREATE GLOBAL TEMPORARY TABLE TMP_EMP(
EMPNO INT PRIMARY KEY,
ENAME VARCHAR(15) NOT NULL,
JOB VARCHAR(10))
ON COMMIT DELETE ROWS;
--插入数据
insert into tmp_emp values(1,'LILY','DBA');
insert into tmp_emp values(2,'TEST','DBA');
--未提交查询
select * from tmp_emp;
行号 EMPNO ENAME JOB
---------- ----------- ----- ---
1 1 LILY DBA
2 2 test DBA
--提交后查询
commit;
select * from tmp_emp;
未选定行
查询临时表:
select t.TABLE_NAME, t.TABLESPACE_NAME, t.DURATION from USER_TABLES t where
t.TEMPORARY='Y';
创建会话级临时表:
--创建临时表
CREATE GLOBAL TEMPORARY TABLE TMP_EMP2(
EMPNO INT PRIMARY KEY,
ENAME VARCHAR(15) NOT NULL,
JOB VARCHAR(10))
ON COMMIT PRESERVE ROWS;
--插入数据
insert into tmp_emp2 values(1,'LILY','DBA');
insert into tmp_emp2 values(2,'TEST','DBA');
--未提交查询
select * from tmp_emp2;
行号 EMPNO ENAME JOB
---------- ----------- ----- ---
1 1 LILY DBA
2 2 TEST DBA
--提交后查询
commit;
select * from tmp_emp2;
行号 EMPNO ENAME JOB
---------- ----------- ----- ---
1 1 LILY DBA
2 2 TEST DBA
查询临时表:
select t.TABLE_NAME, t.TABLESPACE_NAME, t.DURATION from USER_TABLES t where
t.TEMPORARY='Y';
**实验1:**指定控制文件创建外部表,新版本需要创建directory
#1.编写数据文件,/dm8/data/ext_dept1.txt
101|总经理办|1001|1
102|行政部|1002|1
103|开发部|1003|1
104|市场部|1004|1
105|技术支持部|1005|1
201|总经理办|2001|2
202|行政部|2002|2
204|市场部|2004|2
301|总经理办|3001|3
302|行政部|3002|3
303|开发部|3003|3
304|市场部|3004|3
305|技术支持部|3005|3
#2.编写控制文件,/dm8/data/ext_dept1.ctl
options
(character_code='UTF-8')
LOAD DATA
INFILE '/dm8/data/ext_dept1.txt'INTO TABLE EXT_DEPT1
FIELDS '|'
#3.创建外部表,并加载数据,from省略datafile关键字表示通过控制文件
CREATE EXTERNAL TABLE EXT_DEPT1 (
"DEPARTMENT_ID" INT,
"DEPARTMENT_NAME" VARCHAR(30),
"MANAGER_ID" INT,
"LOCATION_ID" INT
) FROM '/dm8/data/ext_dept1.ctl';
#4.查询外部表数据
select * from EXT_DEPT1;
**实验2:**指定数据文件创建外部表
#1.编写数据文件,/dm8/data/ext_dept2.txt
101|总经理办|1001|1
102|行政部|1002|1
103|开发部|1003|1
104|市场部|1004|1
105|技术支持部|1005|1
201|总经理办|2001|2
202|行政部|2002|2
204|市场部|2004|2
301|总经理办|3001|3
302|行政部|3002|3
303|开发部|3003|3
304|市场部|3004|3
305|技术支持部|3005|3
#2.创建外部表并加载数据
CREATE EXTERNAL TABLE EXT_DEPT2 (
"DEPARTMENT_ID" INT,
"DEPARTMENT_NAME" VARCHAR(30),
"MANAGER_ID" INT,
"LOCATION_ID" INT
) from datafile '/dm8/data/ext_dept2.txt' parms(fields delimited by '|',character_code 'UTF-8');
#4.查询外部表数据
select * from EXT_DEPT2;
文章
阅读量
获赞