ORA-12004: REFRESH FAST Cannot Be Used for Materialized View
ORA-12004 is thrown by Oracle when you attempt to perform a FAST REFRESH on a Materialized View (MV) that doesn't meet the necessary prerequisites for incremental refresh. Unlike a COMPLETE REFRESH which rebuilds the entire MV, FAST REFRESH only applies incremental changes — but this requires specific structural conditions to be in place. Understanding and resolving ORA-12004 quickly is critical to keeping your data pipelines and reporting layers running smoothly.
Top 3 Causes
1. Missing Materialized View Log on the Base Table
The most common cause. FAST REFRESH relies on MV Logs to track row-level changes (INSERT, UPDATE, DELETE) on source tables. Without them, Oracle has no way to determine what changed.
-- Check if MV Log exists
SELECT log_owner, master, log_table
FROM dba_mview_logs
WHERE master = 'EMP';
-- Create MV Log if missing
CREATE MATERIALIZED VIEW LOG ON scott.emp
WITH ROWID, SEQUENCE (empno, ename, sal, deptno)
INCLUDING NEW VALUES;
-- For join-based MVs, all participating tables need MV Logs
CREATE MATERIALIZED VIEW LOG ON scott.dept
WITH ROWID, SEQUENCE (deptno, dname, loc)
INCLUDING NEW VALUES;
2. Unsupported SQL Constructs in the MV Query
FAST REFRESH does not support all SQL syntax. Queries using DISTINCT, UNION, MINUS, CONNECT BY, analytic functions, or certain outer joins are incompatible with FAST REFRESH. Always validate the MV query before creation.
-- Run EXPLAIN_MVIEW to validate FAST REFRESH eligibility
-- (Run utlxmv.sql once to create the mv_capabilities_table)
@$ORACLE_HOME/rdbms/admin/utlxmv.sql
BEGIN
DBMS_MVIEW.EXPLAIN_MVIEW(
mv => 'SELECT e.empno, e.ename, d.dname
FROM scott.emp e, scott.dept d
WHERE e.deptno = d.deptno',
stmt_id => 'CHECK_FAST_01'
);
END;
/
-- Review the result
SELECT capability_name, possible, msgtxt
FROM mv_capabilities_table
WHERE statement_id = 'CHECK_FAST_01'
AND capability_name LIKE 'REFRESH_FAST%';
-- BAD: DISTINCT prevents FAST REFRESH
-- GOOD: Rewrite using GROUP BY
CREATE MATERIALIZED VIEW mv_dept_count
REFRESH FAST ON DEMAND
AS
SELECT deptno, COUNT(*) AS cnt
FROM scott.emp
GROUP BY deptno;
3. MV Created Without REFRESH FAST Option
If the MV was originally created with REFRESH COMPLETE or no explicit refresh method, attempting a manual FAST REFRESH will fail. The MV must be dropped and recreated with the correct option.
-- Check current refresh method
SELECT mview_name, refresh_method, refresh_mode, staleness
FROM dba_mviews
WHERE mview_name = 'MV_EMP_DEPT';
-- Drop and recreate with FAST REFRESH
DROP MATERIALIZED VIEW mv_emp_dept;
CREATE MATERIALIZED VIEW mv_emp_dept
BUILD IMMEDIATE
REFRESH FAST ON DEMAND
ENABLE QUERY REWRITE
AS
SELECT e.empno, e.ename, e.sal, d.dname, d.loc
FROM scott.emp e, scott.dept d
WHERE e.deptno = d.deptno;
Quick Fix Solutions
If you need an immediate workaround while troubleshooting, fall back to COMPLETE REFRESH:
-- Temporary fix: use COMPLETE REFRESH
BEGIN
DBMS_MVIEW.REFRESH(
list => 'MV_EMP_DEPT',
method => 'C', -- C = COMPLETE, F = FAST
atomic_refresh => FALSE
);
END;
/
Once the root cause is resolved (MV Log created, query simplified, MV recreated), switch back to FAST REFRESH:
-- Execute FAST REFRESH after prerequisites are met
BEGIN
DBMS_MVIEW.REFRESH(
list => 'MV_EMP_DEPT',
method => 'F',
atomic_refresh => FALSE
);
END;
/
Prevention Tips
Always run
EXPLAIN_MVIEWbefore creating any MV. Make it a mandatory step in your deployment checklist. This surfaces FAST REFRESH incompatibilities before they hit production.Monitor MV health regularly. Query
DBA_MVIEWSto trackSTALENESSandLAST_REFRESH_DATE. Set up Oracle Scheduler jobs to alert your team when a refresh fails or when an MV becomes unexpectedly stale.
-- Quick health check for all MVs
SELECT mview_name, refresh_method, last_refresh_date, staleness
FROM dba_mviews
WHERE staleness != 'FRESH'
ORDER BY last_refresh_date;
Related Errors
- ORA-12000 – MV Log already exists on the table
- ORA-12054 – ON COMMIT refresh not supported for the MV
- ORA-23413 – Table has no MV Log
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)