ORA-04031: unable to allocate xx bytes of shared memory 是 Shared Pool 記憶體耗盡的經典錯誤。根因多為「大型 SQL 佔用 Shared Pool 且無法老化淘汰」,導致新 SQL 無法載入。本文提供監控查詢、Metalink 根因分析、SQL 優化策略、參數調整與應急重啟方案。
-- 佔用 > 100KB 的 SQL (可調整門檻)
SELECT sql_text, sharable_mem, executions, loads, version_count
FROM v$sql
WHERE sharable_mem > 100000
ORDER BY sharable_mem DESC;
-- 搭配 V$SQLAREA 彙總相同 SQL_TEXT
SELECT sql_text, SUM(sharable_mem) AS total_mem, COUNT(*) AS child_count
FROM v$sql
GROUP BY sql_text
HAVING SUM(sharable_mem) > 100000
ORDER BY total_mem DESC;
-- 詳細記憶體分佈
SELECT pool, name, bytes/1024/1024 AS "MB"
FROM v$sgastat
WHERE pool = 'shared pool'
ORDER BY bytes DESC;
-- Library Cache 命中率
SELECT namespace, gets, gethits, (gethits/gets)*100 AS hit_ratio
FROM v$librarycache;
若
SHARED_POOL_SIZE已足夠,大多數 ORA-04031 由 動態 SQL 碎片化 導致,主因三點:
- 不共享 SQL:字面值硬編碼、未使用綁定變數。
- 不必要的軟解析:重複開啟/關閉 Cursor、應用端未啟用 Statement Cache。
- 未使用綁定變數:導致每次硬解析、產生大量 Child Cursor (高
VERSION_COUNT)。
| 層面 | 措施 | 預期效果 |
|---|---|---|
| 應用開發 | 全面使用綁定變數、啟用 Statement Cache (JDBC/OracleParameter/ODP.NET) | 消除硬解析、降低 Child Cursor 爆炸 |
| SQL 寫法 | 避免超大 SQL (拆分 View/CTE)、固定欄位順序、統一大小寫/縮排 | 提高 Cursor 共享率 |
| 參數調整 | CURSOR_SHARING=FORCE (謹慎、僅作緩解)、SESSION_CACHED_CURSORS=50~200 | 強制字面值轉綁定、減少軟解析開銷 |
| Shared Pool 管理 | DBMS_SHARED_POOL.KEEP 釘住核心 Package/Trigger、DBMS_SHARED_POOL.PURGE 手動淘汰垃圾 SQL | 保護關鍵物件、回收碎片空間 |
| 記憶體擴充 | 增加 SHARED_POOL_SIZE 或 SGA_TARGET、啟用 SHARED_POOL_RESERVED_SIZE (預設 5%) | 提高上限、預留大型分配緩衝 |
當 ORA-04031 發生,無法透過指令釋放已載入 Shared Pool 的物件,唯有重啟執行個體。因此:
V$SGASTAT Free Memory < 10% 即告警。CURSOR_SHARING=FORCE 可能導致部分查詢計畫劣化,必須在測試環境全面回歸 後上線。SHARED_POOL_RESERVED_SIZE 過大反而減少可用空間,建議維持預設 5% 或依 V$SHARED_POOL_RESERVED 監控調整。KEEP。Shared Pool 管理核心在於「減少硬解析、控制 Child Cursor 版本、預留緩衝空間」。建立 監控→優化→預留 的閉環機制,才能徹底杜絕 ORA-04031。