Oracle 分区表性能优化
Oracle 分区表性能优化
适用版本:Oracle Database 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07
1. 概述
分区表性能优化关键[1]:
- 分区裁剪
- 智能 JOIN
- 并行
- 索引
2. 分区裁剪
2.1 静态裁剪
-- WHERE 包含分区键
SELECT * FROM sales
WHERE sale_date BETWEEN '2026-01-01' AND '2026-12-31';
-- 仅扫描 2026 分区
2.2 验证
EXPLAIN PLAN FOR SELECT ...;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- Partition Start/Stop 表示裁剪
2.3 动态裁剪
-- 子查询条件
SELECT * FROM sales s
WHERE s.sale_date IN (
SELECT date_col FROM filter_table
);
-- 运行时裁剪
-- 查看 V$SQL_PLAN
3. 分区智能 JOIN
3.1 Partition-Wise JOIN
-- 同分区方式 JOIN
SELECT /*+ PQ_DISTRIBUTE(s p, PARTITION) */
s.product_id, p.product_name, SUM(s.amount)
FROM sales s, products p
WHERE s.product_id = p.id
GROUP BY s.product_id, p.product_name;
3.2 完整 vs 部分
- 完整:两表相同分区
- 部分:一表分区
4. 并行查询
4.1 表级并行
ALTER TABLE sales PARALLEL 8;
SELECT /*+ PARALLEL(s 8) */ * FROM sales s WHERE ...;
4.2 分区并行
-- 每分区并行
SELECT /*+ PARALLEL(s 4) */ * FROM sales s PARTITION(p2026) WHERE ...;
5. 分区索引
5.1 本地索引
CREATE INDEX idx_sales_date ON sales(sale_date) LOCAL;
-- 与分区对应
-- 分区裁剪自动应用
5.2 全局索引
CREATE INDEX idx_sales_customer ON sales(customer_id) GLOBAL;
-- 整体索引
-- 分区操作需维护
5.3 选择
- 查询用分区键:本地
- 查询不用分区键:全局
6. 分区统计
6.1 收集
EXEC DBMS_STATS.GATHER_TABLE_STATS(
'SCOTT', 'SALES',
cascade => TRUE,
granularity => 'ALL'
);
-- granularity: ALL/GLOBAL/PARTITION/SUBPARTITION
6.2 增量
-- 12c+:仅变化分区
EXEC DBMS_STATS.SET_TABLE_PREFS('SCOTT', 'SALES', 'INCREMENTAL', 'TRUE');
7. 分区维护
7.1 添加分区
ALTER TABLE sales ADD PARTITION p2027 VALUES LESS THAN (...);
7.2 交换分区
-- 高速加载
ALTER TABLE sales EXCHANGE PARTITION p2026
WITH TABLE sales_stage
INCLUDING INDEXES;
7.3 截断
ALTER TABLE sales TRUNCATE PARTITION p2025;
7.4 删除
ALTER TABLE sales DROP PARTITION p2025 UPDATE GLOBAL INDEXES;
8. 分区裁剪场景
8.1 Range 分区
SELECT * FROM sales WHERE sale_date = '2026-07-21';
-- 单分区
8.2 List 分区
SELECT * FROM customers WHERE region = 'NY';
-- 单分区
8.3 Hash 分区
SELECT * FROM orders WHERE customer_id = 100;
-- Hash 计算,单分区
8.4 组合分区
SELECT * FROM sales
WHERE sale_date = '2026-07-21' AND region = 'NY';
-- Range-List,子分区裁剪
9. 性能对比
9.1 全表扫描 vs 分区
全表 1 亿行:100 秒
分区裁剪 1000 万行:10 秒
9.2 索引选择
| 查询 | 推荐索引 |
|---|---|
| 分区键等值 | 本地索引 |
| 分区键范围 | 本地索引 |
| 非分区键 | 全局索引 |
| 分区+非分区 | 复合本地 |
10. 常见坑与排错
10.1 不裁剪
-- 1. 检查 WHERE 条件
-- 2. 检查分区键
-- 3. 检查执行计划
-- 4. 函数阻止
WHERE EXTRACT(YEAR FROM sale_date) = 2026 -- 不裁剪
WHERE sale_date >= '2026-01-01' AND sale_date < '2027-01-01' -- 裁剪
10.2 全局索引失效
-- 分区操作导致
ALTER TABLE sales DROP PARTITION p2025;
-- 全局索引 UNUSABLE
-- 修复
ALTER INDEX idx_name REBUILD;
-- 或操作时维护
ALTER TABLE sales DROP PARTITION p2025 UPDATE GLOBAL INDEXES;
10.3 跨分区查询慢
-- 1. 检查 WHERE 是否限定
-- 2. 使用并行
-- 3. 优化索引
11. 最佳实践
- 大表分区:> 10GB
- Range 日期分区:常用
- 本地索引优先:易维护
- 分区裁剪验证:性能
- 定期添加分区:避免失败
- Interval 自动:减少维护
- 增量统计:12c+ 高效
- 并行查询:大分区
- 交换分区加载:高效
- 监控分区:状态
12. 参考资料
[1] Oracle Database VLDB and Partitioning Guide 19c https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/