:分区管理 读书笔记
Posted dingdingfish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:分区管理 读书笔记相关的知识,希望对你有一定的参考价值。
本文为Oracle 19c VLDB and Partitioning Guide第4章Partition Administration的读书笔记。
使用分区表和索引时,分区管理是一项重要任务。
本章描述了创建和维护分区表和索引的各个方面。
注意:在您尝试创建分区表或索引,或对任何分区表执行维护操作之前,建议您查看分区概念中的信息。
4.1 Specifying Partitioning When Creating Tables and Indexes
创建分区表或索引与创建非分区表或索引非常相似。
创建分区表或索引时,在 CREATE TABLE 语句中包含一个分区子句。 您包含的分区子句和子条款取决于您要实现的分区类型。
常规(堆组织)表和索引组织表都可以进行分区,但包含 LONG 或 LONG RAW 列的表除外。 您可以在分区表上创建非分区全局索引、范围或哈希分区全局索引以及本地索引。
创建(或更改)分区表时,可以指定行移动子句(ENABLE ROW MOVEMENT 或 DISABLE ROW MOVEMENT)。 如果更新了其键,则此子句启用或禁用将行迁移到新分区。 默认值为禁用行移动。
这篇文章讲述了需要row movement的3种情形。
您可以为单级分区表指定最多 1024K-1 个分区,或为复合分区表指定子分区。
创建自动列表复合分区表和间隔子分区可以节省空间,因为这些方法仅在存在数据的情况下创建子分区。 在按需创建新分区时延迟创建子分区段可确保仅在插入第一个匹配行时创建子分区段。
4.1.1 About Creating Range-Partitioned Tables and Global Indexes
CREATE TABLE 语句的 PARTITION BY RANGE 子句指定要对表或索引进行范围分区。
PARTITION 子句标识单独的分区范围,并且 PARTITION 子句的可选子句可以指定特定于分区段的物理属性和其他属性。 如果未在分区级别覆盖,分区将继承其基础表的属性。
4.1.1.1 Creating a Range-Partitioned Table
使用 CREATE TABLE 语句的 PARTITION BY RANGE 子句创建范围分区表。
示例 4-1 创建了一个包含四个分区的表,每个分区对应一个季度的销售额。 time_id 是分区列,而它的值构成特定行的分区键。 VALUES LESS THAN 子句确定分区界限:分区键值比较小于子句指定的有序值列表的行存储在分区中。 每个分区都有一个名称(sales_q1_2006、sales_q2_2006、sales_q3_2006、sales_q4_2006),每个分区都包含在一个单独的表空间中(tsa、tsb、tsc、tsd)。 time_id=17-MAR-2006 的行将存储在分区 sales_q1_2006 中。
Live SQL:在 Oracle Live SQL-创建范围分区表中查看并运行相关示例。
示例 4-1 创建范围分区表
CREATE TABLE 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_q1_2006 VALUES LESS THAN (TO_DATE('01-APR-2006','dd-MON-yyyy'))
TABLESPACE tsa
, PARTITION sales_q2_2006 VALUES LESS THAN (TO_DATE('01-JUL-2006','dd-MON-yyyy'))
TABLESPACE tsb
, PARTITION sales_q3_2006 VALUES LESS THAN (TO_DATE('01-OCT-2006','dd-MON-yyyy'))
TABLESPACE tsc
, PARTITION sales_q4_2006 VALUES LESS THAN (TO_DATE('01-JAN-2007','dd-MON-yyyy'))
TABLESPACE tsd
);
注意:插入不在range中的值会报错:
ORA-14400: inserted partition key does not map to any partition ORA-06512: at "SYS.DBMS_SQL", line 1721
4.1.1.2 Creating a Range-Partitioned Table With More Complexity
使用属性和存储参数,可以为范围分区表的创建增加更多复杂性。
在示例 4-2 中,存储参数和 LOGGING 属性在表级别指定。 这些替换了从表本身的表空间级别继承的相应默认值,并由范围分区继承。 但是由于第一季度业务很少,所以分区sales_q1_2006的存储属性变小了。 指定 ENABLE ROW MOVEMENT 子句以允许在对键值进行更新时将行自动迁移到新分区,这会将行放置在不同的分区中。
示例 4-2 使用 LOGGING 和 ENABLE ROW MOVEMENT 创建范围分区表
CREATE TABLE 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)
)
STORAGE (INITIAL 100K NEXT 50K) LOGGING
PARTITION BY RANGE (time_id)
( PARTITION sales_q1_2006 VALUES LESS THAN (TO_DATE('01-APR-2006','dd-MON-yyyy'))
TABLESPACE tsa STORAGE (INITIAL 20K NEXT 10K)
, PARTITION sales_q2_2006 VALUES LESS THAN (TO_DATE('01-JUL-2006','dd-MON-yyyy'))
TABLESPACE tsb
, PARTITION sales_q3_2006 VALUES LESS THAN (TO_DATE('01-OCT-2006','dd-MON-yyyy'))
TABLESPACE tsc
, PARTITION sales_q4_2006 VALUES LESS THAN (TO_DATE('01-JAN-2007','dd-MON-yyyy'))
TABLESPACE tsd
)
ENABLE ROW MOVEMENT;
4.1.1.3 Creating a Range-Partitioned Global Index
创建范围分区全局索引的规则与创建范围分区表的规则相似。
示例 4-3 在 sale_month 上为前面示例中创建的表创建了一个范围分区的全局索引。 每个索引分区都已命名,但存储在索引的默认表空间中。
示例 4-3 创建范围分区表的全局索引
CREATE INDEX amount_sold_ix ON sales(amount_sold)
GLOBAL PARTITION BY RANGE(sale_month)
( PARTITION p_100 VALUES LESS THAN (100)
, PARTITION p_1000 VALUES LESS THAN (1000)
, PARTITION p_10000 VALUES LESS THAN (10000)
, PARTITION p_100000 VALUES LESS THAN (100000)
, PARTITION p_1000000 VALUES LESS THAN (1000000)
, PARTITION p_greater_than_1000000 VALUES LESS THAN (maxvalue)
);
注意:如果您的企业有使用不同字符集的数据库,则在对字符列进行分区时要小心,因为所有字符集中的字符排序顺序并不相同。 有关详细信息,请参阅 Oracle 数据库全球化支持指南。
4.1.2 Creating Range-Interval-Partitioned Tables
CREATE TABLE 语句的 INTERVAL 子句为表建立间隔分区。
您必须使用 PARTITION 子句指定至少一个范围分区。 范围分区键值决定了范围分区的高值,称为过渡点,数据库自动为超过该过渡点的数据创建区间分区。 每个区间分区的下边界是前一个范围或区间分区的非包含上边界。
例如,如果您创建具有每月间隔的间隔分区表,并且转换点位于 2010 年 1 月 1 日,则 2010 年 1 月间隔的下限是 2010 年 1 月 1 日。2010 年 7 月间隔的下限是 7 月 1 日 , 2010,无论之前是否创建了 2010 年 6 月分区。 但是请注意,使用分区的上限或下限超出存储范围的日期会导致错误。 例如,TO_DATE(‘9999-12-01’, ‘YYYY-MM-DD’) 导致上限为 10000-01-01,如果 10000 超出合法范围,则无法存储该上限。
可选的 STORE IN 子句允许您指定一个或多个表空间,数据库使用循环算法将间隔分区数据存储到随后创建的间隔分区中。
对于间隔分区,您只能指定一个分区键列,并且数据类型受到限制。
以下示例指定了四个具有不同间隔宽度的分区。 它还指定在 2010 年 1 月 1 日的过渡点之上,以一个月的间隔宽度创建分区。 分区 p3 的上限表示过渡点。 p3 和它下面的所有分区(本例中的 p0、p1 和 p2)都在范围部分,而它上面的所有分区都属于区间部分。
CREATE TABLE interval_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)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')),
PARTITION p1 VALUES LESS THAN (TO_DATE('1-1-2009', 'DD-MM-YYYY')),
PARTITION p2 VALUES LESS THAN (TO_DATE('1-7-2009', 'DD-MM-YYYY')),
PARTITION p3 VALUES LESS THAN (TO_DATE('1-1-2010', 'DD-MM-YYYY')) );
4.1.3 About Creating Hash Partitioned Tables and Global Indexes
CREATE TABLE 语句的 PARTITION BY HASH 子句标识要对表进行散列分区。
然后可以使用 PARTITIONS 子句指定要创建的分区数,以及可选的存储它们的表空间。或者,您可以使用 PARTITION 子句来命名各个分区及其表空间。
您可以为散列分区指定的唯一属性是 TABLESPACE。 表的所有散列分区必须共享相同的段属性(TABLESPACE 除外),这些属性是从表级别继承的。
4.1.3.1 Creating a Hash Partitioned Table
分区列是 id,创建了四个分区并分配了系统生成的名称,它们被放置在四个命名的表空间中(gear1、gear2、gear3、gear4)。
CREATE TABLE scubagear
(id NUMBER,
name VARCHAR2 (60))
PARTITION BY HASH (id)
PARTITIONS 4
STORE IN (gear1, gear2, gear3, gear4);
在下面的示例中,在创建哈希分区表时指定了分区数,但系统生成的名称被分配给它们,并且它们存储在表的默认表空间中。
CREATE TABLE departments_hash (department_id NUMBER(4) NOT NULL,
department_name VARCHAR2(30))
PARTITION BY HASH(department_id) PARTITIONS 16;
在以下示例中,指定了各个分区的名称以及它们要驻留的表空间。 每个散列分区(段)的初始扩展区大小也在表级别明确说明,所有分区都继承此属性。
CREATE TABLE departments_hash (department_id NUMBER(4) NOT NULL,
department_name VARCHAR2(30))
STORAGE (INITIAL 10K)
PARTITION BY HASH(department_id)
(PARTITION p1 TABLESPACE ts1, PARTITION p2 TABLESPACE ts2,
PARTITION p3 TABLESPACE ts1, PARTITION p4 TABLESPACE ts3);
如果您为此表创建本地索引,则数据库会构建索引,以便它与基础表进行平均分区。 数据库还确保在对基础表执行维护操作时自动维护索引。 以下是在表上创建本地索引的示例:
CREATE INDEX loc_dept_ix ON departments_hash(department_id) LOCAL;
您可以选择命名要存储本地索引分区的哈希分区和表空间,但如果您不这样做,则数据库使用相应基本分区的名称作为索引分区名称,并存储索引分区在与表分区相同的表空间中。
4.1.3.2 Creating a Hash Partitioned Global Index
哈希分区全局索引可以提高索引中少量叶子块在多用户OLTP环境中具有高争用的索引的性能。
哈希分区全局索引还可以限制索引倾斜对单调增加的列值的影响。 涉及索引分区键上的相等和 IN 谓词的查询可以有效地使用哈希分区全局索引。
创建哈希分区全局索引的语法类似于用于哈希分区表的语法。 例如,示例 4-4 中的语句创建了一个哈希分区全局索引:
示例 4-4 创建散列分区全局索引
CREATE INDEX hgidx ON tab (c1,c2,c3) GLOBAL
PARTITION BY HASH (c1,c2)
(PARTITION p1 TABLESPACE tbs_1,
PARTITION p2 TABLESPACE tbs_2,
PARTITION p3 TABLESPACE tbs_3,
PARTITION p4 TABLESPACE tbs_4);
4.1.4 About Creating List-Partitioned Tables
创建列表分区的语义与创建范围分区的语义非常相似。
但是,要创建列表分区,您可以在 CREATE TABLE 语句中指定 PARTITION BY LIST 子句,并且 PARTITION 子句指定文字值列表,这些文字值是分区列的离散值,用于限定要包含在分区中的行。 对于列表分区,分区键可以是表中的一个或多个列名。
仅适用于列表分区,您可以使用关键字 DEFAULT 来描述分区的值列表。 这标识了一个分区,该分区容纳不映射到任何其他分区的行。
与范围分区一样,PARTITION 子句的可选子句可以指定特定于分区段的物理属性和其他属性。 如果未在分区级别覆盖,分区将继承其父表的属性。
4.1.4.1 Creating a List-Partitioned Table
示例 4-5 创建了表 q1_sales_by_region,该表按由美国各州组组成的区域进行分区。 通过检查行的分区列的值是否与描述分区的值列表中的值匹配,将行映射到分区。 例如,以下列表描述了如何将一些示例行插入到表中。
- (10, ‘accounting’, 100, ‘WA’) 映射到分区 q1_northwest
- (20, ‘R&D’, 150, ‘OR’) 映射到分区 q1_northwest
- (30, ‘sales’, 100, ‘FL’) 映射到分区 q1_southeast
- (40, ‘HR’, 10, ‘TX’) 映射到分区 q1_southwest
- (50, ‘systems engineering’, 10, ‘CA’) 未映射到表中的任何分区并引发错误
Live SQL:在 Oracle Live SQL:创建列表分区表中查看并运行有关 Oracle Live SQL 的相关示例。
示例 4-5 创建列表分区表
CREATE TABLE q1_sales_by_region
(deptno number,
deptname varchar2(20),
quarterly_sales number(10, 2),
state varchar2(2))
PARTITION BY LIST (state)
(PARTITION q1_northwest VALUES ('OR', 'WA'),
PARTITION q1_southwest VALUES ('AZ', 'UT', 'NM'),
PARTITION q1_northeast VALUES ('NY', 'VM', 'NJ'),
PARTITION q1_southeast VALUES ('FL', 'GA'),
PARTITION q1_northcentral VALUES ('SD', 'WI'),
PARTITION q1_southcentral VALUES ('OK', 'TX'));
4.1.4.2 Creating a List-Partitioned Table With a Default Partition
与范围分区不同,使用列表分区,分区之间没有明显的顺序。
您还可以指定一个默认分区,将不映射到任何其他分区的行映射到该分区。 如果在前面的示例中指定了默认分区,则状态 CA 将映射到该分区。
示例 4-6 创建表 sales_by_region 并使用 list 方法对其进行分区。 前两个 PARTITION 子句指定物理属性,它们覆盖表级默认值。 其余的 PARTITION 子句不指定属性,并且这些分区从表级默认值继承其物理属性。 还指定了默认分区。
示例 4-6 创建具有默认分区的列表分区表
CREATE TABLE sales_by_region (item# INTEGER, qty INTEGER,
store_name VARCHAR(30), state_code VARCHAR(2),
sale_date DATE)
STORAGE(INITIAL 10K NEXT 20K) TABLESPACE tbs5
PARTITION BY LIST (state_code)
(
PARTITION region_east
VALUES ('MA','NY','CT','NH','ME','MD','VA','PA','NJ')
STORAGE (INITIAL 8M)
TABLESPACE tbs8,
PARTITION region_west
VALUES ('CA','AZ','NM','OR','WA','UT','NV','CO')
NOLOGGING,
PARTITION region_south
VALUES ('TX','KY','TN','LA','MS','AR','AL','GA'),
PARTITION region_central
VALUES ('OH','ND','SD','MO','IL','MI','IA'),
PARTITION region_null
VALUES (NULL),
PARTITION region_unknown
VALUES (DEFAULT)
);
4.1.4.3 Creating an Automatic List-Partitioned Table
自动列表分区方法可以按需创建列表分区。
自动列表分区表与常规列表分区表类似,只是该分区表更易于管理。 您可以仅使用已知的分区键值来创建自动列出分区表。 当数据加载到表中时,如果加载的分区键值与任何现有分区都不对应,数据库会自动创建一个新分区。 因为分区是按需自动创建的,所以自动列表分区方法在概念上类似于现有的区间分区方法。
对值变化非常频繁的数据类型进行自动列表分区不太适合这种方法,除非您可以调整数据。 例如,带有日期值的 SALES_DATE 字段,当格式未被剥离时,将每秒增加。 每个 SALES_DATE 值(例如 05-22-2016 08:00:00、05-22-2016 08:00:01 等)都会生成自己的分区。 为避免创建大量分区,您必须了解将要输入的数据并进行相应调整。 例如,您可以将 SALES_DATE 日期值截断为一天或某个其他时间段,具体取决于所需的分区数。
CREATE 和 ALTER TABLE SQL 语句使用附加子句进行更新,以指定 AUTOMATIC 或 MANUAL 列表分区。 自动列表分区表在创建时必须至少有一个分区。 因为新分区是为新的和未知的分区键值自动创建的,所以自动列表分区不能有 DEFAULT 分区。
您可以检查 *_PART_TABLES 视图的 AUTOLIST 列以确定表是否是自动列表分区的。
Live SQL:在 Oracle Live SQL:创建自动列表分区表中查看并运行有关 Oracle Live SQL 的相关示例。
示例 4-7 是使用 AUTOMATIC 关键字对 sales_state 字段进行自动列表分区的 CREATE TABLE 语句示例。 CREATE TABLE SQL 语句根据需要创建至少一个分区。 随着插入额外的行,当添加新的 sales_state 值时,分区的数量会增加。
示例 4-7 创建自动列表分区表
CREATE TABLE sales_auto_list
(
salesman_id NUMBER(5) NOT NULL,
salesman_name VARCHAR2(30),
sales_state VARCHAR2(20) NOT NULL,
sales_amount NUMBER(10),
sales_date DATE NOT NULL
)
PARTITION BY LIST (sales_state) AUTOMATIC
(PARTITION P_CAL VALUES ('CALIFORNIA')
);
SELECT TABLE_NAME, PARTITIONING_TYPE, AUTOLIST, PARTITION_COUNT FROM USER_PART_TABLES WHERE TABLE_NAME ='SALES_AUTO_LIST';
TABLE_NAME PARTITIONING_TYPE AUTOLIST PARTITION_COUNT
---------------- ----------------- -------- ---------------
SALES_AUTO_LIST LIST YES 1
SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE FROM USER_TAB_PARTITIONS WHERE TABLE_NAME ='SALES_AUTO_LIST';
TABLE_NAME PARTITION_NAME HIGH_VALUE
–--------------- –-------------- –---------------
SALES_AUTO_LIST P_CAL 'CALIFORNIA'
INSERT INTO SALES_AUTO_LIST VALUES(021, 'Mary Smith', 'FLORIDA', 41000, TO_DATE ('21-DEC-2018','DD-MON-YYYY'));
1 row inserted.
INSERT INTO SALES_AUTO_LIST VALUES(032, 'Luis Vargas', 'MICHIGAN', 42000, TO_DATE ('31-DEC-2018','DD-MON-YYYY'));
1 row inserted.
SELECT TABLE_NAME, PARTITIONING_TYPE, AUTOLIST, PARTITION_COUNT FROM USER_PART_TABLES WHERE TABLE_NAME ='SALES_AUTO_LIST';
TABLE_NAME PARTITIONING_TYPE AUTOLIST PARTITION_COUNT
---------------- ----------------- -------- ---------------
SALES_AUTO_LIST LIST YES 3
INSERT INTO SALES_AUTO_LIST VALUES(015, 'Simone Blair', 'CALIFORNIA', 45000, TO_DATE ('11-JAN-2019','DD-MON-YYYY'));
1 row inserted.
INSERT INTO SALES_AUTO_LIST VALUES(015, 'Simone Blair', 'OREGON', 38000, TO_DATE ('18-JAN-2019','DD-MON-YYYY'));
1 row inserted.
SELECT TABLE_NAME, PARTITIONING_TYPE, AUTOLIST,PARTITION_COUNT FROM USER_PART_TABLES WHERE TABLE_NAME ='SALES_AUTO_LIST';
TABLE_NAME PARTITIONING_TYPE AUTOLIST PARTITION_COUNT
---------------- ----------------- -------- ---------------
SALES_AUTO_LIST LIST YES 4
SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE FROM USER_TAB_PARTITIONS WHERE TABLE_NAME ='SALES_AUTO_LIST';
TABLE_NAME PARTITION_NAME HIGH_VALUE
–--------------- –-------------- –---------------
SALES_AUTO_LIST P_CAL 'CALIFORNIA'
SALES_AUTO_LIST SYS_P478 'FLORIDA'
SALES_AUTO_LIST SYS_P479 'MICHIGAN'
SALES_AUTO_LIST SYS_P480 'OREGON'
4.1.4.4 Creating a Multi-column List-Partitioned Table
多列列表分区使您可以根据多列的列表值对表进行分区。
与单列列表分区类似,单个分区可以包含包含值列表的集合。
对表的多个列使用 PARTITION BY LIST 子句的表支持多列列表分区。 例如:
PARTITION BY LIST (column1,column2)
Live SQL:在 Oracle Live SQL:创建多列列表分区表中查看并运行有关 Oracle Live SQL 的相关示例。
以下是在状态列和通道列上使用多列分区的 CREATE TABLE 语句的示例。
示例 4-8 创建多列列表分区表
CREATE TABLE sales_by_region_and_channel
(dept_number NUMBER NOT NULL,
dept_name VARCHAR2(20),
quarterly_sales NUMBER(10,2),
state VARCHAR2(2),
channel VARCHAR2(1)
)
PARTITION BY LIST (state, channel)
(
PARTITION yearly_west_direct VALUES (('OR','D'),('UT','D'),('WA','D')),
PARTITION yearly_west_indirect VALUES (('OR','I'),('UT','I'),('WA','I')),
PARTITION yearly_south_direct VALUES (('AZ','D'),('TX','D'),('GA','D')),
PARTITION yearly_south_indirect VALUES (('AZ','I'),('TX','I'),('GA','I')),
PARTITION yearly_east_direct VALUES (('PA','D'), ('NC','D'), ('MA','D')),
PARTITION yearly_east_indirect VALUES (('PA','I'), ('NC','I'), ('MA','I')),
PARTITION yearly_north_direct VALUES (('MN','D'),('WI','D'),('MI','D')),
PARTITION yearly_north_indirect VALUES (('MN','I'),('WI','I'),('MI','I')),
PARTITION yearly_ny_direct VALUES ('NY','D'),
PARTITION yearly_ny_indirect VALUES ('NY','I'),
PARTITION yearly_ca_direct VALUES ('CA','D'),
PARTITION yearly_ca_indirect VALUES ('CA','I'),
PARTITION rest VALUES (DEFAULT)
);
SELECT PARTITION_NAME, HIGH_VALUE FROM USER_TAB_PARTITIONS WHERE 以上是关于:分区管理 读书笔记的主要内容,如果未能解决你的问题,请参考以下文章