Oracle 表分区与索引分区 ------ 语法详解与综合实践
一、环境准备(Oracle 安装与配置)
说明 :本章内容基于 Oracle Database 21c XE(Express Edition),适用于 Windows / Linux。
1. 下载与安装(简要步骤)
-
下载地址 :
https://www.oracle.com/database/technologies/xe-downloads.html -
安装步骤(Windows):
- 以管理员身份运行
OracleXE213_Win64.exe - 设置统一口令(如:
oracle123) - 安装路径默认即可
- 安装完成后自动启动服务:
OracleServiceXEOracleXETNSListener
- 以管理员身份运行
⚠️ 注意:Oracle XE 支持分区功能(自 18c 起),但部分高级特性(如复合分区)在 XE 中可能受限。建议使用 Enterprise Edition 进行完整测试。若仅用于学习,XE 已支持基本分区操作。
2. 创建练习用户
sql
-- 以 sysdba 登录
sqlplus sys/oracle123@localhost:1521/XE as sysdba
-- 创建表空间
CREATE TABLESPACE part_ts DATAFILE 'part_ts.dbf' SIZE 200M AUTOEXTEND ON;
-- 创建用户
CREATE USER part_user IDENTIFIED BY part123 DEFAULT TABLESPACE part_ts;
-- 授予权限(分区需要额外权限)
GRANT CONNECT, RESOURCE, CREATE ANY TABLE, CREATE ANY INDEX TO part_user;
使用 part_user/part123 登录进行本章练习。
二、分区技术简介
什么是分区?
- 将一个大表物理上划分为多个小段(分区),逻辑上仍为一张表。
- 优势 :
- 提升查询性能(分区裁剪)
- 简化维护(如删除整月数据只需
DROP PARTITION) - 提高可用性(一个分区损坏不影响其他分区)
分区类型概览
| 类型 | 依据 | 适用场景 |
|---|---|---|
| 范围分区(Range) | 值范围(如日期、ID) | 时间序列数据(日志、订单) |
| 散列分区(Hash) | 哈希函数 | 均匀分布数据,避免热点 |
| 列表分区(List) | 枚举值列表 | 地区、状态等离散值 |
| Interval 分区 | 自动按间隔扩展 | 按月/日自动创建新分区 |
| 组合分区 | 两级分区(如 Range + Hash) | 大数据量复杂场景 |
三、创建表分区
1. 范围分区(Range Partitioning)
语法:
sql
CREATE TABLE table_name (...)
PARTITION BY RANGE (column)
(
PARTITION part_name VALUES LESS THAN (value),
...
PARTITION part_max VALUES LESS THAN (MAXVALUE)
);
案例:按销售日期分区
sql
CREATE TABLE sales (
sale_id NUMBER,
product VARCHAR2(50),
region VARCHAR2(20),
amount NUMBER(10,2),
sale_date DATE
)
PARTITION BY RANGE (sale_date)
(
PARTITION p_2023_q1 VALUES LESS THAN (DATE '2023-04-01'),
PARTITION p_2023_q2 VALUES LESS THAN (DATE '2023-07-01'),
PARTITION p_2023_q3 VALUES LESS THAN (DATE '2023-10-01'),
PARTITION p_2023_q4 VALUES LESS THAN (DATE '2024-01-01'),
PARTITION p_future VALUES LESS THAN (MAXVALUE) -- 捕获未来数据
);
✅
MAXVALUE表示最大可能值,必须放在最后。
2. 散列分区(Hash Partitioning)
语法:
sql
CREATE TABLE ...
PARTITION BY HASH (column)
PARTITIONS n;
-- 或指定每个分区名
PARTITION BY HASH (column) (
PARTITION part1,
PARTITION part2,
...
);
案例:按客户 ID 均匀分布
sql
CREATE TABLE customers (
cust_id NUMBER,
name VARCHAR2(50),
email VARCHAR2(100)
)
PARTITION BY HASH (cust_id)
PARTITIONS 4; -- 自动创建 4 个分区:SYS_P1, SYS_P2...
✅ 适合无法预知数据分布的场景,确保 I/O 均衡。
3. 列表分区(List Partitioning)
语法:
sql
CREATE TABLE ...
PARTITION BY LIST (column)
(
PARTITION part_name VALUES ('val1', 'val2', ...),
PARTITION part_other VALUES (DEFAULT) -- 可选
);
案例:按地区分区
sql
CREATE TABLE orders (
order_id NUMBER,
customer VARCHAR2(50),
region VARCHAR2(10),
amount NUMBER(10,2)
)
PARTITION BY LIST (region)
(
PARTITION p_north VALUES ('BJ', 'TJ', 'HEB'),
PARTITION p_south VALUES ('GD', 'FJ', 'HN'),
PARTITION p_west VALUES ('SC', 'YN', 'XZ'),
PARTITION p_other VALUES (DEFAULT) -- 兜底分区
);
4. Interval 分区(自动范围分区)
- 在 Range 分区基础上,自动创建新分区。
- 适用于按时间周期(日/月/年)增长的数据。
案例:按月自动分区
sql
CREATE TABLE monthly_logs (
log_id NUMBER,
msg VARCHAR2(200),
log_time DATE
)
PARTITION BY RANGE (log_time)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH')) -- 每月一个分区
(
PARTITION p_start VALUES LESS THAN (DATE '2025-01-01')
);
✅ 插入
2025-03-15的数据时,系统自动创建2025-03分区。
5. 组合分区(Composite Partitioning)
支持两级分区,常见组合:
- Range-Hash
- Range-List
- List-Range 等
案例:Range(年) + Hash(客户ID)
sql
CREATE TABLE big_sales (
sale_id NUMBER,
cust_id NUMBER,
sale_date DATE,
amount NUMBER(10,2)
)
PARTITION BY RANGE (sale_date)
SUBPARTITION BY HASH (cust_id) SUBPARTITIONS 4
(
PARTITION p_2024 VALUES LESS THAN (DATE '2025-01-01'),
PARTITION p_2025 VALUES LESS THAN (DATE '2026-01-01')
);
✅ 每个年份分区下再分 4 个子分区,共 8 个物理段。
四、管理表分区
1. 添加分区(ADD PARTITION)
仅适用于 Range / List 分区(Interval 分区自动添加,无需手动)。
sql
-- 为 Range 分区添加新分区
ALTER TABLE sales ADD PARTITION p_2024_q1
VALUES LESS THAN (DATE '2024-04-01');
-- 为 List 分区添加
ALTER TABLE orders ADD PARTITION p_east
VALUES ('SH', 'JS', 'ZJ');
⚠️ 不能在
MAXVALUE或DEFAULT分区后添加新分区。
2. 合并分区(MERGE PARTITIONS)
将两个相邻分区合并为一个。
sql
-- 合并 Q1 和 Q2
ALTER TABLE sales
MERGE PARTITIONS p_2023_q1, p_2023_q2
INTO PARTITION p_2023_h1;
3. 删除分区(DROP PARTITION)
sql
-- 删除整个分区(数据一并删除)
ALTER TABLE sales DROP PARTITION p_2023_q1;
-- 删除分区但保留数据(移入其他表)
ALTER TABLE sales DROP PARTITION p_2023_q1
UPDATE GLOBAL INDEXES; -- 避免全局索引失效
✅
UPDATE GLOBAL INDEXES是关键,否则全局索引变UNUSABLE。
4. 并入范围分区(SPLIT PARTITION)
将一个分区拆分为两个。
sql
-- 将 p_future 按 2024-07-01 拆分
ALTER TABLE sales
SPLIT PARTITION p_future AT (DATE '2024-07-01')
INTO (PARTITION p_2024_h1, PARTITION p_future);
五、创建索引分区
1. 索引分区概述
| 类型 | 特点 | 适用场景 |
|---|---|---|
| 本地索引(Local) | 每个表分区对应一个索引分区,自动维护 | 大多数 OLAP 场景 |
| 全局索引(Global) | 索引独立于表分区,可跨分区 | 高频唯一查询(如主键) |
2. 本地索引分区(Local Index)
语法:
sql
CREATE INDEX index_name ON table_name (column) LOCAL;
案例:
sql
-- 为 sales 表的 sale_date 创建本地索引
CREATE INDEX idx_sales_date ON sales(sale_date) LOCAL;
-- 查看索引分区
SELECT index_name, partition_name, status
FROM user_ind_partitions
WHERE index_name = 'IDX_SALES_DATE';
✅ 本地索引自动与表分区对齐,维护简单。
3. 全局索引分区(Global Index)
语法:
sql
CREATE INDEX index_name ON table_name (column)
GLOBAL PARTITION BY RANGE (column) (...);
案例:全局唯一索引(主键)
sql
-- 假设 sale_id 需全局唯一
CREATE UNIQUE INDEX uk_sales_id ON sales(sale_id)
GLOBAL PARTITION BY HASH (sale_id) PARTITIONS 4;
⚠️ 全局索引在 DDL(如 DROP PARTITION)后可能失效,需
UPDATE GLOBAL INDEXES或重建。
六、管理索引分区
1. 删除索引分区(仅全局索引支持)
sql
-- 删除全局索引的某个分区(本地索引不能单独删)
ALTER INDEX uk_sales_id DROP PARTITION part1;
2. 重命名索引分区
sql
ALTER INDEX idx_sales_date RENAME PARTITION p_2023_q1 TO sales_2023_q1_idx;
✅ 本地索引分区名默认与表分区同名,可重命名便于识别。
3. 重建索引分区
sql
-- 重建本地索引分区
ALTER INDEX idx_sales_date REBUILD PARTITION p_2023_q1;
-- 重建整个本地索引
ALTER INDEX idx_sales_date REBUILD;
七、综合性案例
场景:电商平台订单系统
需求:
- 订单表按 年+月 自动分区(Interval)
- 按 客户ID 建立散列子分区(负载均衡)
- 为订单ID建 全局唯一索引
- 为订单日期建 本地索引
- 演示删除旧分区(归档)
步骤 1:创建组合分区表
sql
CREATE TABLE ecom_orders (
order_id NUMBER PRIMARY KEY,
cust_id NUMBER NOT NULL,
product VARCHAR2(100),
amount NUMBER(10,2),
order_date DATE DEFAULT SYSDATE
)
PARTITION BY RANGE (order_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
SUBPARTITION BY HASH (cust_id) SUBPARTITIONS 4
(
PARTITION p_start VALUES LESS THAN (DATE '2025-01-01')
);
步骤 2:创建索引
sql
-- 全局唯一索引(主键已隐式创建,此处显式演示)
-- 注意:主键默认创建全局唯一索引
-- 若需本地主键,需特殊处理(不推荐)
-- 本地索引加速按日期查询
CREATE INDEX idx_order_date ON ecom_orders(order_date) LOCAL;
-- 本地索引加速按客户查询
CREATE INDEX idx_order_cust ON ecom_orders(cust_id) LOCAL;
步骤 3:插入测试数据
sql
INSERT INTO ecom_orders (order_id, cust_id, product, amount, order_date)
VALUES (1001, 101, 'Laptop', 5999.00, DATE '2025-03-15');
INSERT INTO ecom_orders (order_id, cust_id, product, amount, order_date)
VALUES (1002, 102, 'Phone', 3999.00, DATE '2025-04-20');
-- 自动创建 2025-03 和 2025-04 分区
步骤 4:删除旧分区(如归档 2025-03 前数据)
sql
-- 先确认分区名
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'ECOM_ORDERS';
-- 假设要删除 2025-03 之前的分区(实际需根据 HIGH_VALUE 判断)
-- 此处演示删除 p_start(包含 <2025-01 的数据)
ALTER TABLE ecom_orders
DROP PARTITION p_start
UPDATE GLOBAL INDEXES; -- 保持全局索引有效
步骤 5:验证分区与索引状态
sql
-- 查表分区
SELECT partition_name, num_rows FROM user_tab_partitions WHERE table_name = 'ECOM_ORDERS';
-- 查本地索引分区
SELECT partition_name, status FROM user_ind_partitions WHERE index_name = 'IDX_ORDER_DATE';
-- 查全局索引状态
SELECT status FROM user_indexes WHERE index_name = 'SYS_C0012345'; -- 主键索引名
八、总结对比表
| 操作 | 语法 | 注意事项 |
|---|---|---|
| 创建 Range 分区 | PARTITION BY RANGE (...) |
需 MAXVALUE 或 Interval |
| 创建 Hash 分区 | PARTITION BY HASH (...) PARTITIONS n |
数据均匀分布 |
| Interval 分区 | INTERVAL (NUMTOYMINTERVAL(1,'MONTH')) |
自动扩展 |
| 添加分区 | ALTER TABLE ... ADD PARTITION |
不适用于 Interval |
| 删除分区 | DROP PARTITION ... UPDATE GLOBAL INDEXES |
避免索引失效 |
| 本地索引 | CREATE INDEX ... LOCAL |
自动对齐表分区 |
| 全局索引 | CREATE INDEX ... GLOBAL PARTITION BY ... |
需手动维护 |
九、最佳实践建议
-
选择合适分区键:
- 时间字段 → Range / Interval
- 离散值 → List
- 高并发写入 → Hash 避免热点
-
索引策略:
- 查询条件含分区键 → 优先用本地索引
- 唯一约束(如主键)→ 全局索引
-
维护操作:
- 删除分区前加
UPDATE GLOBAL INDEXES - 定期监控分区大小,避免倾斜
- 删除分区前加
-
开发注意:
- 应用 SQL 最好包含分区键,触发 分区裁剪(Partition Pruning)
- 避免
SELECT * FROM table扫全表
通过本章学习,您已掌握 Oracle 表与索引分区的核心技术,能够设计高性能、易维护的大表架构,为海量数据处理提供坚实支撑。