Oracle | erp、mrp、性能优化 | 设计文档
Oracle | erp、mrp、性能优化 | 设计文档
一、项目背景
DBA 对 MRP 相关表执行了 SHRINK 操作:
ALTER TABLE xxxxx ENABLE ROW MOVEMENT; -- 允许行物理移动ALTER TABLE xxxxx SHRINK SPACE COMPACT CASCADE; -- 压缩数据,不降高水位ALTER TABLE xxxxx SHRINK SPACE CASCADE; -- 降低高水位线(HWM)ALTER TABLE xxxxx DISABLE ROW MOVEMENT; -- 禁用行移动保护 ROWID目的: 回收表碎片空间,降低高水位线(HWM)。
结果: MRP 排产并发请求显著变慢,正式环境排产耗时超过 50 分钟。
二、根本原因:聚簇因子(Clustering Factor)恶化
什么是聚簇因子
聚簇因子衡量索引键值顺序与表物理行存储顺序的吻合程度。
| CF 范围 | 含义 | 对范围扫描的影响 |
|---|---|---|
| 接近块数 | 行按索引顺序集中存储 | 快,顺序读 ✅ |
| 接近行数 | 行分散在各个块 | 慢,随机读 ❌ |
记忆规则:索引范围扫描 + 扫描行数多 + CF 大 → 需要访问的块越多 → 越慢。
SHRINK 为什么会恶化 CF
SHRINK 在压缩数据时会物理移动行(ROWID 改变),导致行的存储顺序与索引键值顺序不再对应。原本顺序读 2 个块,移动后每行都可能落在不同块,索引范围扫描变成随机跳块读,CR 暴增。
恶化后的等待事件
| 等待事件 | 场景 | 原因 |
|---|---|---|
latch cache buffer chain | 单节点 / RAC | 随机块访问过多,Buffer Get 过高,latch 成为瓶颈 |
GC buffer busy | RAC 集群 | 跨节点传输散乱数据块,Global Cache 争用 |
聚簇因子检测
-- 先收集统计信息EXEC dbms_stats.gather_index_stats(ownname => 'SCHEMA', indname => 'INDEX_NAME');
-- 查询 CF 异常索引(CF > 行数/2 且 CF > 块数)SELECT * FROM ( SELECT d.clustering_factor, d.table_name, d.index_name, d.num_rows, d.last_analyzed FROM dba_indexes d WHERE d.clustering_factor > d.num_rows / 2 AND d.clustering_factor > ( SELECT t.blocks FROM dba_tables t WHERE t.table_name = d.table_name AND t.owner = d.table_owner ) ORDER BY 1 DESC ) WHERE rownum <= 10;三、分析方法
工具链
| 工具 | 用途 |
|---|---|
tkprof | 解析 Trace 文件,输出各 SQL 的 CR、PR、执行次数、耗时 |
| AWR 报告 | Top SQL / Top Wait Events 全局视角 |
| SQL 执行计划 | 确认访问路径(INDEX RANGE SCAN、FULL SCAN 等) |
v$session_wait | 实时等待事件观察 |
关键指标
| 指标 | 含义 |
|---|---|
cr | Consistent Reads,逻辑读次数,越高说明扫描越多 |
pr | Physical Reads,物理读,有 pr 说明数据未命中缓存 |
elapsed | SQL 总耗时 |
executions | 执行次数,高频低耗的 SQL 累计影响同样不可忽视 |
定位流程
AWR Top Wait Events → 发现 latch / GC buffer busy 占比高 → AWR Top SQL by Buffer Gets 找 CR 最高的 SQL → tkprof 分析 Trace,确认执行次数 × CR 贡献最大的 SQL → 查执行计划,确认 INDEX RANGE SCAN + 高 CF 组合 → 查 DBA 操作记录,SHRINK 时间与性能劣化吻合 → 确认根因,制定优化方案四、优化方案
4.1 在线表重定义(降低聚簇因子)
核心原理: 按特定索引键列顺序重建表的物理存储顺序,等效于:
CREATE TABLE new_table AS SELECT * FROM old_table ORDER BY <目标索引列>;在线重定义(DBMS_REDEFINITION)可在不停业务的情况下完成;若允许停机维护,直接 CTAS + 重命名速度更快。
4.1.1 BOM_COMPONENTS_B — 优化等级:🔴 高
问题定位:
文件 20640,1210 行,执行次数 1 次,SQL 执行时间 17 秒,返回 9418 行INDEX RANGE SCAN BOM_COMPONENTS_B_N2 (cr=89869 pr=0 pw=0 time=320951 us cost=2 card=20)问题分析:
- 执行仅 1 次,但 CR 高达 89,869,是最理想的重定义优化目标
- 问题索引
BOM_COMPONENTS_B_N2仅含BILL_SEQUENCE_ID单列,选择性差 - 每次范围扫描都随机访问大量分散数据块
相关索引:
| 索引名 | 类型 | 列 |
|---|---|---|
| BOM_COMPONENTS_B_N1 | Normal | COMPONENT_ITEM_ID, BILL_SEQUENCE_ID, EFFECTIVITY_DATE |
| BOM_COMPONENTS_B_N2 | Normal | BILL_SEQUENCE_ID |
| BOM_COMPONENTS_B_N8 | Normal | BILL_SEQUENCE_ID, EFFECTIVITY_DATE, COMPONENT_ITEM_ID, OPERATION_SEQ_NUM |
| BOM_COMPONENTS_B_U2 | Unique | COMPONENT_SEQUENCE_ID |
重定义策略: 按 COMPONENT_SEQUENCE_ID(主键序列)排序重定义
主键按序列号写入,BILL_SEQUENCE_ID 也近似有序写入,聚簇因子随之显著下降。
4.1.2 BOM_STRUCTURES_B — 优化等级:🔴 高
问题定位:
文件 20640,1208 行,执行次数 1 次,SQL 执行时间 17 秒,返回 9418 行INDEX RANGE SCAN BOM_STRUCTURES_B_N2 (cr=9336 pr=0 pw=0 time=57158 us cost=2 card=1)问题分析: 虽然是小表(约 25 万行),但一次范围扫描 CR 达 9,336,读取了全表近 1/5 的数据,聚簇严重失序。
重定义策略: 按 U1 主键顺序(OBJ_NAME, PK1_VALUE, PK2_VALUE, ALTERNATE_BOM_DESIGNATOR)重定义
不按 N2 索引列(ASSEMBLY_ITEM_ID, ORGANIZATION_ID)排序,原因:为优化单个索引而改变物理顺序会导致其他索引效率下降;按主键排序是恢复数据到自然写入状态的最优平衡。
4.1.3 MRP_SCHEDULE_DATES — 优化等级:🟡 低
INDEX RANGE SCAN MRP_SCHEDULE_DATES_N3 (cr=2300 pr=45 time=291062 us)INDEX RANGE SCAN MRP_SCHEDULE_DATES_N3 (cr=5598 pr=0 time=486020 us)说明: 由于业务存在频繁增删(详见 5.1 节),重定义效果会随运行时间持续退化,N3 索引聚簇甚至反而有所上升,非根治方案。
重定义顺序: MPS_TRANSACTION_ID, SCHEDULE_LEVEL, SUPPLY_DEMAND_TYPE(U1 主键)
4.1.4 MRP_SOURCING_HISTORY — 优化等级:🟡 低
INDEX RANGE SCAN MRP_SOURCING_HISTORY_N1 (cr=3 pr=0 time=17 us cost=3 card=1)说明: 索引选择性极好(每次仅读 3 个块),上榜原因是 SQL 执行次数较多(16,309 次),重定义收益有限,已改用修改 INITRANS 方案(详见 4.3 节)。
4.1.5 MRP_SYSTEM_ITEMS — 优化等级:🔴 高
INDEX RANGE SCAN MRP_SYSTEM_ITEMS_N1 (cr=2684 pr=0 time=22149 us cost=71 card=14577)执行次数:147,556重定义顺序: ORGANIZATION_ID, COMPILE_DESIGNATOR, INVENTORY_ITEM_ID(U1 唯一索引)
效果: 聚簇因子有明显降低。
4.1.6 MTL_ITEM_REVISIONS_B — 优化等级:⚫ 非常低
INDEX RANGE SCAN MTL_ITEM_REVISIONS_B_N1 (cr=9773142 pr=0 time=10366045 us cost=3 card=1)执行次数:9,523,591结论: N1 聚簇降低不明显,重定义收益小于风险,暂不推荐。
4.1.7 MTL_ITEM_REVISIONS_TL — 优化等级:🔴 高
INDEX UNIQUE SCAN MTL_ITEM_REVISIONS_TL_U1 (cr=7279966 pr=0 time=7849002 us cost=1 card=1)执行次数:9,523,591特殊说明: 已缓存进 Keep Pool,但聚簇因子仍偏高,重定义后聚簇降低明显,进一步减少内存命中时的 latch 争用。
重定义顺序: INVENTORY_ITEM_ID, ORGANIZATION_ID, REVISION_ID, LANGUAGE(U1 主键)
4.1.8 MTL_SYSTEM_ITEMS_B — 优化等级:🟡 低
INDEX UNIQUE SCAN MTL_SYSTEM_ITEMS_B_U1 (cr=485300 pr=0 time=333503 us cost=2 card=1)执行次数:294,088结论: U1 聚簇降低不明显,且 N1、N2 索引聚簇有上升趋势,重定义反而可能劣化。
4.1.9 RCV_SHIPMENT_LINES — 优化等级:⚫ 非常低
INDEX RANGE SCAN RCV_SHIPMENT_LINES_N1 (cr=4 pr=0 time=13 us cost=3 card=71)执行次数:约 14,000+结论: 单次范围扫描块数极低(cr=4),执行慢主因是次数多。重定义后 N1 聚簇从 0.7 降为 0.05,但实测第一次执行时间反而有所上升,性价比低。
4.2 修改索引
4.2.1 RCV_TRANSACTIONS 添加新索引
高频关联 SQL:
SELECT rct.transaction_type trans_type, rct.transaction_id trans_id, rct.parent_transaction_id parent_trans_id, rct.primary_quantity trans_qty FROM rcv_shipment_lines rsl, rcv_transactions rct WHERE rct.source_document_code = 'PO' AND rsl.item_id = :b3 AND rct.shipment_line_id = rsl.shipment_line_id AND rct.transaction_type = 'DELIVER' AND rct.transaction_date BETWEEN :b2 AND :b1 AND EXISTS (SELECT 1 FROM po_headers_all poh WHERE rsl.po_header_id = poh.po_header_id AND nvl(poh.vendor_site_id, -99) = nvl(:b5, -99) AND poh.vendor_id = :b4 AND rownum = 1)统计信息:
Execute 16309 0.14 0.15 0 42 0 0Fetch 16309 23.44 27.19 46 12044152 0 0优化效果:
| 操作 | 执行时间 |
|---|---|
| 优化前 | 100 秒 |
| 添加 RCV_TRANSACTIONS 新索引后 | 18 秒 |
| 进一步将视图改为基表 MTL_ITEM_REVISIONS_B | 5 秒 |
4.3 修改存储参数(MRP_SOURCING_HISTORY)
背景: mrp_get_sourcing_history 存储过程执行 16,309 次,每次为自治事务,包含频繁的增删操作。
-- 备份原始参数-- ALTER TABLE MRP.MRP_SOURCING_HISTORY PCTFREE 10;-- ALTER TABLE MRP.MRP_SOURCING_HISTORY INITRANS 1;-- ALTER INDEX MRP.MRP_SOURCING_HISTORY_N1 INITRANS 11;
-- 执行优化ALTER TABLE MRP.MRP_SOURCING_HISTORY PCTFREE 0; -- 原 10ALTER TABLE MRP.MRP_SOURCING_HISTORY INITRANS 20; -- 原 1ALTER INDEX MRP.MRP_SOURCING_HISTORY_N1 INITRANS 20; -- 原 11参数说明:
- PCTFREE 0: 不预留块内更新空间,同等行数占用块数更少,范围扫描需访问的块数减少。该表存储过程内无 UPDATE 操作,设为 0 安全。
- INITRANS 20: 提高事务槽数量,支持更多并发事务同时修改同一数据块,避免默认值 1/11 在高并发写入时的块级 latch 争用。
4.4 核心表缓存至 Keep Pool
操作: 将 2 个核心高频全表扫描的表(合计约 1.2 GB)固定缓存至 Keep Buffer Pool(保留池)。
Keep Pool 大小设置: 直接设置为 10 GB(标准建议为段大小的 2 倍,考虑 UNDO 影响,为未来类似需求预留充裕空间)。
效果: 第二次执行时,Snapshot Monitor 从缓存读取,耗时降低约 50%。
Keep Pool 优势:
- 命中率极高,碎片极少(运行良好的保留池无频繁页入页出)
- 避免大表全表扫描将共享池中其他 SQL 解析缓存刷出
- 在 RAC 环境下减少跨节点 GC 传输
五、深度分析
5.1 MRP_SCHEDULE_DATES 频繁增删导致聚簇持续退化
问题现象: 每次 MRP 排产对 MRP_SCHEDULE_DATES 执行大批量 DELETE + INSERT(schedule_level=3 数据全量删除重建),每批次限 75,000 行循环执行。
核心 SQL:
-- DELETE 操作DELETE FROM mrp_schedule_dates WHERE schedule_level = 3 AND (schedule_designator, organization_id) IN ( SELECT input_designator_name, input_organization_id FROM mrp_plan_schedules_v WHERE organization_id = :b0 AND compile_designator = :b1 AND input_designator_type = 1 ) AND rownum <= :b2;
-- INSERT 操作(紧随其后)INSERT INTO mrp_schedule_dates ( inventory_item_id, reference_schedule_id, organization_id, schedule_designator, schedule_level, ...)SELECT inventory_item_id, reference_schedule_id, organization_id, schedule_designator, 3, ... FROM mrp_schedule_dates WHERE schedule_level = 2 AND supply_demand_type = 1 AND (organization_id, schedule_designator) IN ( SELECT input_organization_id, input_designator_name FROM mrp_plan_schedules_v WHERE organization_id = :b2 AND compile_designator = :b3 AND input_designator_type = 1 );根因: 频繁增删彻底破坏行的物理有序性,重定义只能是临时手段。
建议方向:
- 业务层面使用 TRUNCATE PARTITION(若表已分区)替代批量 DELETE
- 减少中间临时数据的写入量
- 评估是否可将 schedule_level=3 的数据改为内存计算,不落库
5.2 SQL 高频执行累计消耗大
相关 SQL:
SELECT RCT.TRANSACTION_TYPE TRANS_TYPE, RCT.TRANSACTION_ID TRANS_ID, RCT.PARENT_TRANSACTION_ID PARENT_TRANS_ID, RCT.PRIMARY_QUANTITY TRANS_QTY FROM RCV_SHIPMENT_LINES RSL, RCV_TRANSACTIONS RCT WHERE RCT.SOURCE_DOCUMENT_CODE = 'PO' AND RSL.ITEM_ID = :B3 AND RCT.SHIPMENT_LINE_ID = RSL.SHIPMENT_LINE_ID AND RCT.TRANSACTION_TYPE = 'DELIVER' AND RCT.TRANSACTION_DATE BETWEEN :B2 AND :B1 AND EXISTS ( SELECT 1 FROM PO_HEADERS_ALL POH WHERE RSL.PO_HEADER_ID = POH.PO_HEADER_ID AND NVL(POH.VENDOR_SITE_ID, -99) = NVL(:B5, -99) AND POH.VENDOR_ID = :B4 AND ROWNUM = 1 )性能数据:
Fetch 16309 23.44 27.19 46 12044152 0 0问题分析:
- 单次执行快(毫秒级),但执行 16,309 次,累计 CPU 时间 23 秒,Elapsed 27 秒
NVL(POH.VENDOR_SITE_ID, -99)函数包裹导致 vendor_site_id 列的索引完全失效- EXISTS 子查询每次均需全量扫描 PO_HEADERS_ALL
建议改写:
-- 将 NVL 函数改为等效的条件判断,使 vendor_site_id 索引可用AND ( (POH.VENDOR_SITE_ID = :B5 AND :B5 IS NOT NULL) OR (POH.VENDOR_SITE_ID IS NULL AND :B5 IS NULL))或为 NVL(VENDOR_SITE_ID, -99) 创建函数索引:
CREATE INDEX PO_HEADERS_ALL_FN1 ON PO_HEADERS_ALL (NVL(VENDOR_SITE_ID, -99), VENDOR_ID);5.3 自治事务频繁提交导致 log file sync 等待
统计信息:
Execute 16309 30.16 34.79 46 12120936 166836 16309
等待事件: log file sync Waited: 16309 Max.Wait: 0.32 Total Waited: 70.09根因: mrp_get_sourcing_history 使用 PRAGMA AUTONOMOUS_TRANSACTION(自治事务),每次调用均独立提交。16,309 次调用即产生 16,309 次 COMMIT,每次 COMMIT 强制 LGWR 将 Redo Buffer 刷入在线重做日志,前台进程挂起等待(log file sync),累计等待 70 秒。
Oracle Redo 刷新触发条件:
| 触发条件 | 说明 |
|---|---|
| Redo Buffer 超过 1/3 或 1 MB | LGWR 自动后台刷新 |
| DBWn 写脏块前 | 约 3 秒超时,强制刷新 |
| COMMIT 调用 | 无条件立即刷新,前台进程挂起等待 |
类比说明:
把 Redo Buffer 比作水桶,本来是接了三分之一水才往外倒;现在每插入一行就发一次”快倒水”的命令,相当于每接一杯水就强制倒一次,效率极低。前台进程必须等 LGWR 倒完才能继续,这段等待就是 log file sync。
日志组状态(v$log):
| Group | Sequence | Status |
|---|---|---|
| 2 | 1001 | ACTIVE(日志已写磁盘,但 Buffer Cache 脏块尚未全部写入数据文件) |
| 3 | 1002 | CURRENT(正在接收 Redo 写入) |
| 4 | 1003 | INACTIVE(已完成检查点) |
最优提交频率估算:
- 若每 1,000 行 INSERT 产生约 1 MB Redo → 最优提交间隔 ≥ 每 1,000 行一次
- 若循环处理 100 行需 3 秒 → 最优提交间隔 ≥ 每 100 行一次(避免超过 3 秒后台刷新触发时 Redo 浪费)
建议方案: 修改存储过程逻辑,改为批量操作后统一提交,或缩短自治事务使用范围(仅对真正需要独立提交的操作使用自治事务)。
注意: 长时不提交的代价是 UNDO 维护量增大,严重时导致 ORA-01555(快照太旧)。需根据业务场景权衡提交间隔。
5.4 视图替代基表导致全表扫描
问题 SQL(执行一次耗时 57 秒):
SELECT MAX(rev.revision), items.inventory_item_id, items.organization_id FROM mtl_item_revisions rev, -- ← 此处为视图,含 TL 多语言表 JOIN mrp_system_items items, mrp_plan_organizations_v mpo WHERE trunc(rev.effectivity_date) = ( SELECT trunc(MAX(rev2.effectivity_date)) FROM mtl_item_revisions rev2 -- ← 相关子查询自关联 WHERE rev2.implementation_date IS NOT NULL AND rev2.effectivity_date <= (trunc(SYSDATE) + .99999) AND rev2.organization_id = rev.organization_id AND rev2.inventory_item_id = rev.inventory_item_id ) AND rev.organization_id = items.organization_id AND rev.inventory_item_id = items.inventory_item_id AND items.organization_id = mpo.planned_organization AND items.compile_designator = mpo.compile_designator AND mpo.organization_id = :b0 AND mpo.compile_designator = :b1 GROUP BY items.inventory_item_id, items.organization_id执行统计:
Fetch 1477 54.64 57.21 30019 26034502 28 147556 ↑ 物理读 30,019 块,CR 超 2,600 万性能对比:
| SQL 版本 | 执行时间 |
|---|---|
| 使用视图 mtl_item_revisions | 约 57 秒 |
| 使用基表 MTL_ITEM_REVISIONS_B | 约 11 秒(降至原来约 1/5) |
根因: mtl_item_revisions 是包含多语言(TL)表 JOIN 的视图,查询时额外关联 MTL_ITEM_REVISIONS_TL,大幅增加数据量和 JOIN 操作,且相关子查询存在自关联,优化器难以有效处理。
阻碍: 该 SQL 位于 Oracle EBS 标准 Package(源代码不可直接修改),需通过以下方式解决:
- 申请 Oracle Support Patch
- 联系 Oracle 客服提交 SR
- 使用 Oracle Application 的个性化开发机制(若有)
六、优化效果汇总
| 优化手段 | 涉及对象 | 优化等级 | 状态 | 核心收益 |
|---|---|---|---|---|
| 在线表重定义 | BOM_COMPONENTS_B | 🔴 高 | ✅ 已完成 | CR 89,869 → 大幅降低 |
| 在线表重定义 | BOM_STRUCTURES_B | 🔴 高 | ✅ 已完成 | 小表读 1/5 问题解决 |
| 在线表重定义 | MRP_SYSTEM_ITEMS | 🔴 高 | ✅ 已完成 | 聚簇明显降低 |
| 在线表重定义 | MTL_ITEM_REVISIONS_TL | 🔴 高 | ✅ 已完成 | 9.5M 次唯一扫描 CR 大幅下降 |
| 在线表重定义 | MRP_SCHEDULE_DATES | 🟡 低 | ✅ 已完成 | 效果随时间退化,非根治方案 |
| 在线表重定义 | RCV_SHIPMENT_LINES | ⚫ 非常低 | ✅ 已完成 | 收益极有限,首次反而略慢 |
| 添加/修改索引 | RCV_TRANSACTIONS | 🔴 高 | ✅ 已完成 | 100s → 18s;改用基表后 → 5s |
| 修改存储参数 | MRP_SOURCING_HISTORY | 🟡 中 | ✅ 已完成 | PCTFREE 10→0;INITRANS 提升至 20 |
| Keep Pool 缓存 | 核心全扫表(1.2GB) | 🔴 高 | ✅ 已完成 | Snapshot Monitor 耗时降约 50% |
| SQL 改写(基表替换视图) | mtl_item_revisions | 🔴 高 | ⏳ 待解决 | 可降至 1/5 时间,需修改 EBS 标准包 |
| 减少自治事务提交频率 | mrp_get_sourcing_history | 🔴 高 | ⏳ 待解决 | log file sync 等待 70s 可消除 |
| MRP_SCHEDULE_DATES 架构优化 | MRP 增删逻辑 | 🟡 中 | ⏳ 待解决 | 根治聚簇退化问题 |
| SQL 改写(NVL 函数索引失效) | PO_HEADERS_ALL | 🟡 中 | ⏳ 待解决 | 高频 SQL 索引可用性提升 |
七、MRP 性能优化扩展框架
基于 Oracle Support 官方调优指南(Doc 100956.1 / 100964.1),结合本次优化实践,整理完整优化框架如下:
7.1 数据库基础资源层
| 检查项 | 说明 | 本次涉及 |
|---|---|---|
| 物理内存是否充足 | SGA/PGA 配置 | — |
| 日志组数量和大小 | log file sync 等待是否成为瓶颈 | ✅ |
| Redo Buffer 空间 | 空间不足导致重做竞争(redo log space requests) | — |
| UNDO 表空间磁盘分离 | 与数据文件在同一磁盘会产生 I/O 竞争 | — |
| SSD vs 机械硬盘 | SSD 无寻道延迟,适合随机 I/O 密集场景 | — |
| PGA 排序区 | 多趟排序(sort disk)表明 PGA 不足,可提高 PGA_AGGREGATE_TARGET | — |
7.2 缓存与共享池层
| 检查项 | 说明 | 本次涉及 |
|---|---|---|
| Buffer Cache 命中率 | < 95% 需扩大 Buffer Cache | — |
| Keep Pool 配置 | 固定热点小表,防止被全扫大表刷出 | ✅ |
| 共享池碎片 | 大量游标解析导致共享池碎片化 | — |
| 库缓存(Library Cache)命中率 | 使用绑定变量,减少硬解析 | — |
| 数据字典缓存命中率 | V$ROWCACHE 中 GETS/MISSES 比 | — |
| DBWR 进程数 | 脏块写入速度跟不上时增加 DB_WRITER_PROCESSES | — |
7.3 索引与表设计层
| 检查项 | 说明 | 本次涉及 |
|---|---|---|
| 聚簇因子(CF) | 索引范围扫描核心指标,重点关注 | ✅ |
| 行链接与行迁移 | PCTFREE 不足或行变大导致,影响读取效率 | — |
| 统计信息准确性 | 过期统计信息导致错误执行计划 | ✅(部分) |
| 表分区与索引分区 | 大表分区可显著降低 DML 和扫描代价 | — |
| 列组统计信息 | 多列联合过滤时,单列统计不准,需创建列组统计 | — |
| 高水位(HWM) | 有全表扫描时需关注;无全表扫描则影响有限 | ✅(已通过重定义降低) |
7.4 SQL 执行计划层
| 检查项 | 说明 | 本次涉及 |
|---|---|---|
| 函数包裹导致索引失效 | NVL、TO_CHAR 等包裹索引列时索引无法使用 | ✅ |
| 绑定变量窥视(Bind Peeking) | 绑定变量数据倾斜时可能生成错误执行计划 | — |
| 视图展开 | 视图内包含多余 JOIN 时阻止合理优化 | ✅ |
| 相关子查询转换 | 相关子查询往往可改写为 JOIN 提升效率 | — |
| 执行次数 × 单次耗时 | 高频低耗 SQL 累计影响同样不可忽视 | ✅ |
7.5 并发与事务层
| 检查项 | 说明 | 本次涉及 |
|---|---|---|
| INITRANS 事务槽不足 | 并发 DML 同一块时产生等待 | ✅ |
| 自治事务提交频率 | 每次提交均触发 LGWR 刷盘 | ✅ |
| RAC GC 等待 | 跨节点数据块传输开销 | ✅ |
| 锁争用 | 行锁、表锁分析 | — |
7.6 应用配置层
| 检查项 | 说明 | 本次涉及 |
|---|---|---|
| BOM 深度和大小 | BOM 层级越深,低层码计算越耗时 | — |
| 并发管理器配置 | Worker 数量与服务器核数匹配 | — |
| 是否安装最新补丁 | Oracle EBS 补丁包含已知性能修复 | — |
| SQL*Net 网络带宽 | 非瓶颈则不需特别关注 | — |
八、总结
项目一句话定位
Oracle EBS MRP 核心排产链路性能优化,从 50 分钟降至可接受范围,核心手段是通过 Trace/AWR 定位根因后综合运用表重定义、索引优化、Redo 调优和 Keep Pool。
逻辑链(这是整个项目的叙事骨架)
DBA 执行 SHRINK → 行物理移动,存储顺序打乱 → Clustering Factor 急剧升高 → Index Range Scan 变随机读 → CR 暴增,latch / GC buffer busy 等待 → MRP 排产从正常水平劣化到 50 分钟 → 通过重定义恢复行顺序 → CF 下降 → CR 下降 → 性能恢复这条链讲清楚了,整个项目的技术深度就到位了。面试时不管从哪个环节问,都能顺着链条向前和向后延伸。
几个值得强调的细节
重定义为什么按主键排序而不是按业务索引排序。 按业务索引排序只优化那一个索引的 CF,其他索引会变差;按主键排序是恢复数据自然写入状态,是全局最优平衡。
CF 高不一定要处理。 判断标准是实际 CR,不是 CF 绝对值。没有范围扫描,或者扫描行数极少,CF 高也可以不管。
log file sync 的本质。 不是 IO 慢,而是提交太频繁,把异步的 LGWR 刷盘变成了同步等待。解法是减少提交次数,不是加快磁盘。
MRP_SCHEDULE_DATES 是未根治的遗留问题。 重定义只是治标,业务频繁增删会让 CF 持续退化。这个问题如果被追问,说明面试官在考察你对优化局限性的认知,诚实讲清楚比硬撑更好。
PCTFREE 改为 0 的前提一定要说清楚。 必须确认表没有 UPDATE 操作才能改,否则行更新扩行会导致行迁移(Row Migration),反而劣化性能。这个细节体现了操作严谨性。
九、参考资料
| 文档 | 说明 |
|---|---|
| Oracle Support Doc 100956.1 | MRP Core/Mfg 性能调优及故障处理指南 |
| Oracle Support Doc 100964.1 | 数据库和 Core/MFG MRP 相关性能问题排查 |
| Oracle Support Doc 223603.1 | MRP 性能优化扩展参考 |
| Oracle Support Doc 836809.1 | MRP 相关补丁及解决方案 |
| Oracle Support Doc 1931325.1 | MRP 性能问题 CAUSE 分析 |
| Oracle MRP 官方文档 | Oracle MRP 架构示意图 |
报告整理于 Oracle EBS MRP 优化实践文档,适用于 Oracle Database 11g/12c/19c + RAC 环境。