Oracle 19c入门学习教程,从入门到精通,Oracle 表分区与索引分区 —— 语法详解与综合实践(12)

Oracle 表分区与索引分区 ------ 语法详解与综合实践


一、环境准备(Oracle 安装与配置)

说明 :本章内容基于 Oracle Database 21c XE(Express Edition),适用于 Windows / Linux。

1. 下载与安装(简要步骤)

⚠️ 注意: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');

⚠️ 不能在 MAXVALUEDEFAULT 分区后添加新分区。


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;

七、综合性案例

场景:电商平台订单系统

需求:

  1. 订单表按 年+月 自动分区(Interval)
  2. 客户ID 建立散列子分区(负载均衡)
  3. 为订单ID建 全局唯一索引
  4. 为订单日期建 本地索引
  5. 演示删除旧分区(归档)

步骤 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 ... 需手动维护

九、最佳实践建议

  1. 选择合适分区键

    • 时间字段 → Range / Interval
    • 离散值 → List
    • 高并发写入 → Hash 避免热点
  2. 索引策略

    • 查询条件含分区键 → 优先用本地索引
    • 唯一约束(如主键)→ 全局索引
  3. 维护操作

    • 删除分区前加 UPDATE GLOBAL INDEXES
    • 定期监控分区大小,避免倾斜
  4. 开发注意

    • 应用 SQL 最好包含分区键,触发 分区裁剪(Partition Pruning)
    • 避免 SELECT * FROM table 扫全表

通过本章学习,您已掌握 Oracle 表与索引分区的核心技术,能够设计高性能、易维护的大表架构,为海量数据处理提供坚实支撑。

相关推荐
翱翔的苍鹰2 小时前
智谱(Zhipu)大模型的流式使用 response.iter_lines() 逐行解析 SSE 流
服务器·前端·数据库
hzb666662 小时前
basectf2024
开发语言·python·sql·学习·安全·web安全·php
代码游侠2 小时前
学习笔记——I2C(Inter-Intergrated Circuit)总线详解
arm开发·笔记·嵌入式硬件·学习·架构
酉鬼女又兒2 小时前
SQL18 分组计算练习题
数据库·sql
科技林总2 小时前
【系统分析师】5.3 数据库控制
学习
深蓝海拓2 小时前
Qt(PySide/PyQt)的信号槽机制的比较深入的学习笔记
qt·学习·pyqt
后来后来啊2 小时前
20261.23 &1.24学习笔记
笔记·学习·算法
Ronin3053 小时前
第三方库介绍——SQLite3
数据库·sqlite·轻量级数据库
杨浦老苏3 小时前
将Waline从LeanCloud迁移到MongoDB
数据库·博客·blog·waline