Oracle 分区表(Partitioned Table)
Oracle 分区表(Partitioned Table)
适用版本:Oracle Database 8i / 9i / 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07
1. 概述
分区表 将大表拆分为小的管理单元[1]:
优势:
- 提升查询性能(分区裁剪)
- 简化维护(分区操作)
- 提高可用性
- 平衡 I/O
2. Range 分区
2.1 创建
CREATE TABLE sales (
id NUMBER,
sale_date DATE,
amount NUMBER
)
PARTITION BY RANGE (sale_date) (
PARTITION p2025 VALUES LESS THAN (TO_DATE('2026-01-01', 'YYYY-MM-DD')),
PARTITION p2026 VALUES LESS THAN (TO_DATE('2027-01-01', 'YYYY-MM-DD')),
PARTITION p2027 VALUES LESS THAN (TO_DATE('2028-01-01', 'YYYY-MM-DD')),
PARTITION p_future VALUES LESS THAN (MAXVALUE)
);
2.2 特点
- 按值范围分区
- 适合日期/数值
- 最常用
3. List 分区
3.1 创建
CREATE TABLE customers (
id NUMBER,
name VARCHAR2(100),
region VARCHAR2(20)
)
PARTITION BY LIST (region) (
PARTITION p_east VALUES ('NY', 'Boston', 'Miami'),
PARTITION p_west VALUES ('LA', 'SF', 'Seattle'),
PARTITION p_central VALUES ('Chicago', 'Dallas'),
PARTITION p_other VALUES (DEFAULT)
);
3.2 特点
- 按枚举值分区
- 适合地区/类别
4. Hash 分区
4.1 创建
CREATE TABLE orders (
id NUMBER,
customer_id NUMBER,
order_date DATE
)
PARTITION BY HASH (customer_id)
PARTITIONS 8;
4.2 特点
- 哈希分布
- 数据均匀
- 适合无明显规律列
5. Composite 分区
5.1 Range-Hash
CREATE TABLE sales (
id NUMBER,
sale_date DATE,
customer_id NUMBER,
amount NUMBER
)
PARTITION BY RANGE (sale_date)
SUBPARTITION BY HASH (customer_id)
SUBPARTITIONS 4 (
PARTITION p2025 VALUES LESS THAN (TO_DATE('2026-01-01', 'YYYY-MM-DD')),
PARTITION p2026 VALUES LESS THAN (TO_DATE('2027-01-01', 'YYYY-MM-DD'))
);
5.2 Range-List
CREATE TABLE sales (
id NUMBER,
sale_date DATE,
region VARCHAR2(20),
amount NUMBER
)
PARTITION BY RANGE (sale_date)
SUBPARTITION BY LIST (region) (
PARTITION p2025 VALUES LESS THAN (TO_DATE('2026-01-01', 'YYYY-MM-DD')) (
SUBPARTITION p2025_east VALUES ('NY', 'Boston'),
SUBPARTITION p2025_west VALUES ('LA', 'SF')
),
PARTITION p2026 VALUES LESS THAN (TO_DATE('2027-01-01', 'YYYY-MM-DD')) (
SUBPARTITION p2026_east VALUES ('NY', 'Boston'),
SUBPARTITION p2026_west VALUES ('LA', 'SF')
)
);
6. Interval 分区(11g+)
6.1 自动创建
CREATE TABLE sales (
id NUMBER,
sale_date DATE,
amount NUMBER
)
PARTITION BY RANGE (sale_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH')) (
PARTITION p_initial VALUES LESS THAN (TO_DATE('2026-01-01', 'YYYY-MM-DD'))
);
-- 自动按月创建新分区
7. System 分区
CREATE TABLE system_part_table (
id NUMBER,
name VARCHAR2(100)
)
PARTITION BY SYSTEM (
PARTITION p1,
PARTITION p2,
PARTITION p3
);
-- 插入必须指定分区
INSERT INTO system_part_table PARTITION(p1) VALUES (1, 'Alice');
8. Reference 分区
-- 父表
CREATE TABLE orders (
id NUMBER PRIMARY KEY,
order_date DATE,
customer_id NUMBER
)
PARTITION BY RANGE (order_date) (
PARTITION p2025 VALUES LESS THAN (TO_DATE('2026-01-01', 'YYYY-MM-DD')),
PARTITION p2026 VALUES LESS THAN (TO_DATE('2027-01-01', 'YYYY-MM-DD'))
);
-- 子表(继承父表分区)
CREATE TABLE order_items (
id NUMBER,
order_id NUMBER,
product_id NUMBER,
CONSTRAINT fk_order FOREIGN KEY (order_id) REFERENCES orders(id)
)
PARTITION BY REFERENCE (fk_order);
9. Virtual Column 分区
CREATE TABLE sales (
id NUMBER,
sale_date DATE,
sale_year AS (EXTRACT(YEAR FROM sale_date)),
amount NUMBER
)
PARTITION BY RANGE (sale_year) (
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027)
);
10. 分区维护
10.1 添加分区
ALTER TABLE sales ADD PARTITION p2028
VALUES LESS THAN (TO_DATE('2029-01-01', 'YYYY-MM-DD'));
10.2 删除分区
ALTER TABLE sales DROP PARTITION p2025;
10.3 截断分区
ALTER TABLE sales TRUNCATE PARTITION p2025;
10.4 合并分区
ALTER TABLE sales MERGE PARTITIONS p2025, p2026
INTO PARTITION p2025_2026;
10.5 拆分分区
ALTER TABLE sales SPLIT PARTITION p2025_2026
AT (TO_DATE('2026-01-01', 'YYYY-MM-DD'))
INTO (PARTITION p2025, PARTITION p2026);
10.6 交换分区
-- 分区与表交换
CREATE TABLE sales_2025 AS SELECT * FROM sales WHERE 1=0;
ALTER TABLE sales EXCHANGE PARTITION p2025
WITH TABLE sales_2025;
10.7 移动分区
ALTER TABLE sales MOVE PARTITION p2025 TABLESPACE users;
10.8 重命名分区
ALTER TABLE sales RENAME PARTITION p2025 TO p_old;
11. 分区索引
11.1 本地索引
-- 与分区表对应
CREATE INDEX idx_sales_date ON sales(sale_date) LOCAL;
-- 每个分区独立索引
-- 维护简单
-- 分区操作不影响其他
11.2 全局索引
-- 独立于分区
CREATE INDEX idx_sales_customer ON sales(customer_id) GLOBAL;
-- 可分区
CREATE INDEX idx_sales_customer ON sales(customer_id) GLOBAL
PARTITION BY RANGE (customer_id) (
PARTITION p1 VALUES LESS THAN (1000),
PARTITION p2 VALUES LESS THAN (MAXVALUE)
);
11.3 选择
| 类型 | 维护 | 性能 | 适用 |
|---|---|---|---|
| 本地 | 简单 | 分区裁剪好 | OLAP |
| 全局 | 复杂 | 整体查询好 | OLTP |
12. 分区裁剪
12.1 静态裁剪
-- WHERE 条件包含分区键
SELECT * FROM sales
WHERE sale_date BETWEEN '2026-01-01' AND '2026-12-31';
-- 仅扫描 p2026 分区
12.2 动态裁剪
-- 子查询条件
SELECT * FROM sales
WHERE sale_date IN (SELECT date_col FROM other_table);
-- 运行时裁剪
13. 查看分区
-- 表分区
SELECT table_name, partition_name, num_rows
FROM user_tab_partitions
WHERE table_name = 'SALES';
-- 分区键
SELECT name, column_name, column_position
FROM user_part_key_columns
WHERE name = 'SALES';
-- 子分区
SELECT * FROM user_tab_subpartitions WHERE table_name = 'SALES';
14. 常见坑与排错
14.1 ORA-14400: 分区不存在
-- 插入数据无对应分区
-- 1. 添加分区
-- 2. 或使用 MAXVALUE 分区
-- 3. 或使用 Interval 分区
14.2 ORA-14402: 更新分区键
-- 行跨分区移动
-- 启用 ROW MOVEMENT
ALTER TABLE sales ENABLE ROW MOVEMENT;
14.3 全局索引失效
-- 分区操作导致
ALTER TABLE sales DROP PARTITION p2025;
-- 全局索引失效
-- 修复
ALTER INDEX idx_sales_customer REBUILD;
-- 或操作时维护
ALTER TABLE sales DROP PARTITION p2025 UPDATE GLOBAL INDEXES;
14.4 ORA-14758: 不能删除最后一个分区
-- Interval 分区
-- 修复:先 MERGE 或使用其他方法
15. 最佳实践
- 大表分区:> 10GB
- Range 日期分区:常用
- Hash 均匀分布:无明显规律
- List 枚举值:地区/类别
- Interval 自动:减少维护
- 本地索引优先:维护简单
- 定期添加分区:避免失败
- 老分区归档:节省空间
- 使用分区裁剪:性能
- 统计信息及时:CBO
16. 参考资料
[1] Oracle Database VLDB and Partitioning Guide 19c https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/