Oracle AskTOM 分区表最佳实践

Oracle AskTOM 分区表最佳实践

来源:AskTOM (asktom.oracle.com) 适用版本:Oracle Database 8i+ / 19c / 23ai 文档版本:v1.0 / 2026-07-22


1. 概述

分区表是 Tom Kyte 在 AskTOM 多次讨论的主题[1]。

详细见:Oracle 分区表设计详解Oracle 分区表性能优化


2. Tom Kyte 核心观点

2.1 分区不是性能银弹

- 分区解决管理问题
- 性能取决于分区消除
- 错误分区 → 性能更差
- 按业务设计

2.2 分区主要目的

- 管理(可用性)
- 维护(删除、归档)
- 性能(分区消除、并行)

3. 分区类型

3.1 Range

CREATE TABLE orders (
  id NUMBER,
  order_date DATE
)
PARTITION BY RANGE (order_date) (
  PARTITION p2023 VALUES LESS THAN (TO_DATE('2024-01-01','YYYY-MM-DD')),
  PARTITION p2024 VALUES LESS THAN (TO_DATE('2025-01-01','YYYY-MM-DD')),
  PARTITION p2025 VALUES LESS THAN (TO_DATE('2026-01-01','YYYY-MM-DD'))
);

3.2 List

CREATE TABLE customers (
  id NUMBER,
  region VARCHAR2(20)
)
PARTITION BY LIST (region) (
  PARTITION p_north VALUES ('北京','上海'),
  PARTITION p_south VALUES ('广州','深圳')
);

3.3 Hash

CREATE TABLE emp (
  id NUMBER
)
PARTITION BY HASH (id) PARTITIONS 8;

3.4 Composite

-- Range + List / Hash
PARTITION BY RANGE (order_date)
  SUBPARTITION BY LIST (region)

4. 何时分区

4.1 Tom 建议

- 表大于 2GB
- 按时间归档
- 维护窗口
- 并行处理

4.2 业务场景

- 日志表:按天/月
- 订单表:按月
- 历史表:按年
- 大数据表:Hash

4.3 不分区

- 小表
- 不可预测查询
- 简单 OLTP

5. 分区消除

5.1 原理

- 查询条件包含分区键
- CBO 跳过无关分区
- 性能提升

5.2 示例

-- 分区消除
SELECT * FROM orders 
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
-- 只扫描 p2024

5.3 失效

-- 函数导致失效
SELECT * FROM orders 
WHERE TO_CHAR(order_date,'YYYY') = '2024';
-- 扫描所有分区

6. 分区策略

6.1 按时间

- Range
- 月/季度/年
- 便于归档

6.2 按业务

- List
- 地区/类型
- 便于管理

6.3 按数据

- Hash
- 均匀分布
- 大数据

7. 维护操作

7.1 添加

ALTER TABLE orders ADD PARTITION p2026 
  VALUES LESS THAN (TO_DATE('2027-01-01','YYYY-MM-DD'));

7.2 删除

ALTER TABLE orders DROP PARTITION p2023;
-- 快速删除大量数据

7.3 交换

ALTER TABLE orders EXCHANGE PARTITION p2023 
  WITH TABLE orders_archive;
-- 数据迁移

7.4 合并

ALTER TABLE orders MERGE PARTITIONS p2023, p2024 
  INTO PARTITION p2023_2024;

7.5 拆分

ALTER TABLE orders SPLIT PARTITION p2023_2024 
  AT (TO_DATE('2024-01-01','YYYY-MM-DD'))
  INTO (PARTITION p2023, PARTITION p2024);

8. 索引

8.1 Local Index

- 每分区独立
- 易维护
- 推荐
CREATE INDEX idx_orders_local ON orders(order_date) LOCAL;

8.2 Global Index

- 跨分区
- 维护成本
- 慎用
CREATE INDEX idx_orders_global ON orders(customer_id) GLOBAL;

8.3 Tom 建议

- 优先 Local
- Global 慎用
- 维护成本高

9. 11g+ 新特性

9.1 Interval

CREATE TABLE orders (...)
PARTITION BY RANGE (order_date)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
  PARTITION p0 VALUES LESS THAN (TO_DATE('2024-01-01','YYYY-MM-DD'))
);
-- 自动创建分区

9.2 Reference

-- 子表按父表分区
PARTITION BY REFERENCE (fk_orders);

9.3 Virtual

- 虚拟列分区
- 灵活

10. 监控

10.1 分区信息

SELECT table_name, partition_name, num_rows, bytes
FROM user_tab_partitions;

10.2 分区统计

EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'ORDERS');

10.3 查询分区

SELECT * FROM orders PARTITION (p2024);

11. 常见问题

11.1 性能下降

- 分区消除失效
- 检查查询
- 优化

11.2 ORA-14400

- 插入无匹配分区
- 添加分区
- 或 Interval

11.3 Global Index 失效

- 分区操作
- 重建
- Local 优先

12. 最佳实践

  1. 按业务:设计
  2. 分区消除:保证
  3. Local Index:优先
  4. Interval:自动
  5. 统计信息:收集
  6. 监控:分区大小
  7. 归档:定期
  8. 测试:性能
  9. 文档:策略
  10. 评估:定期

13. 参考资料

[1] AskTOM, “Partitioning Best Practices”, https://asktom.oracle.com [2] Oracle Database VLDB and Partitioning Guide 19c