最近在测试Oracle并行DML(PDML)时发现了一些有趣的现象:16并行(parallel)模式下执行时间为38分钟,而启用PDML后仅需3分钟。理论上16并行应该有16倍的性能提升,但实际只有12倍左右(38/3≈12.x)。这引发了我对并行处理机制和存储特性的深入探究。
关键发现:并行DML通过空间换时间的方式显著提升性能 - 测试数据显示存储空间消耗比为248MB/17MB≈14.5倍,而时间消耗为3*16=48分钟>实际38分钟,说明并行化存在额外开销。
Oracle的并行处理通过将大任务拆分为多个子任务,由不同进程并行执行来实现加速。但实际测试中发现几个关键现象:
并行度与加速比:设置parallel 16但未达到理想加速比,主要因为:
DB时间解读:AWR报告中的"DB Time"在并行和非并行模式下相近,这是因为:
sql复制-- 典型并行DML启用方式
ALTER SESSION ENABLE PARALLEL DML;
INSERT /*+ PARALLEL(16) */ INTO target_table SELECT * FROM source_table;
测试数据显示明显的空间换时间特征:
| 指标 | 并行DML | 非并行 | 比值 |
|---|---|---|---|
| 执行时间 | 3min | 38min | 1:12 |
| 表空间占用 | 248MB | 17MB | 14.5:1 |
| 索引大小 | 较大 | 较小 | 1.2-1.3:1 |
空间增长的主要原因:
测试中发现一个反常现象:对TRUNCATE后的表使用INSERT APPEND,DELETE操作后的表比TRUNCATE后的表大了一倍,但索引大小却基本相当。
根本原因分析:
测试数据显示非PDML模式的索引比PDML小20-30%,这是因为:
并行DML的索引构建特点:
非并行模式的索引优势:
分析测试中的AWR报告,发现几个关键性能差异:
| 指标 | 并行DML | 非并行 | 比值 |
|---|---|---|---|
| CPU Time | 14s | 6.6s | 2.1:1 |
| I/O等待 | 4 | 1 | 4:1 |
| 其他等待 | 10s | 5s | 2:1 |
| 并发度 | 高 | 低 | - |
现象解释:
测试中的两个关键时间指标:
并行DML的优势在于:
适合使用并行DML的情况:
应避免使用的情况:
sql复制-- 优化并行参数设置
ALTER SESSION SET parallel_degree_policy='AUTO';
ALTER SESSION SET parallel_min_time_threshold=30; -- 设置并行最小时间阈值(秒)
ALTER SESSION SET parallel_degree_limit=16; -- 限制最大并行度
-- 针对大表的优化设置
ALTER TABLE large_table PARALLEL 8;
ALTER INDEX large_table_idx PARALLEL 8;
sql复制-- 使用MOVE重组表
ALTER TABLE large_table MOVE TABLESPACE users;
-- 在线重建索引
ALTER INDEX large_table_idx REBUILD ONLINE;
sql复制-- 检查表空间使用情况
SELECT segment_name, bytes/1024/1024 MB
FROM user_segments
WHERE segment_name IN ('TABLE_NAME','INDEX_NAME');
-- 检查高水位线
SELECT table_name, blocks, empty_blocks
FROM user_tables
WHERE table_name = 'TABLE_NAME';
sql复制-- 确认并行DML已启用
SELECT pdml_status, pdml_enabled FROM v$session WHERE sid = USERENV('SID');
-- 检查并行度设置
SELECT degree FROM user_tables WHERE table_name = 'TABLE_NAME';
sql复制EXPLAIN PLAN FOR
INSERT /*+ PARALLEL(8) */ INTO target_table SELECT * FROM source_table;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
sql复制-- CPU利用率
SELECT * FROM v$sysmetric WHERE metric_name LIKE '%CPU%';
-- I/O负载
SELECT * FROM v$iostat_file;
sql复制-- 计算碎片率
SELECT table_name,
blocks,
empty_blocks,
ROUND(empty_blocks/(blocks+empty_blocks)*100,2) frag_pct
FROM user_tables;
在实际应用中,我发现并行DML的最佳效果往往出现在数据量超过50GB的表上,并行度设置为CPU核心数的50-70%时性价比最高。对于频繁更新的表,建议每月重组一次以维护存储效率。