Home › Database › ORA-02291 Integrity Constraint — Parent Row Missing
Intermediate 5 min · September 23, 2026

ORA-02291 Integrity Constraint — Parent Row Missing

Fix Oracle ORA-02291 by inserting the parent row first, ordering loads, or deferring constraints.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
✓ Production
production tested
September 23, 2026
last updated
1,942
articles · all by Naren
Before you start⏱ 11 min
  • ✓An Oracle database with FK constraints you can inspect
  • ✓The failing load's child and parent table names
  • ✓Read access to all_constraints and all_cons_columns
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • ORA-02291 means your child row points at a parent key that doesn't exist — the message names the constraint, and the dictionary maps that name to the exact parent table and columns
  • Translate it in one query: join all_constraints to all_cons_columns on the named constraint to learn the parent table, then anti-join your staged rows to list every orphan
  • Load in dependency order (parents before children), or mark the constraint DEFERRABLE INITIALLY DEFERRED so Oracle checks once at COMMIT instead of per row
  • Decide each orphan's fate deliberately: insert the missing parent, reassign the child to a real parent, or delete the row — after archiving what you remove
✦ Definition~90s read
What is ORA-02291 Integrity Constraint Fix?

ORA-02291 is raised when an INSERT or UPDATE creates a child row whose foreign-key value matches no parent primary (or unique) key. The message names the constraint (SHOP.FK_ORDER_CUSTOMER), not the tables — all_constraints plus all_cons_columns translate the name into child table, child columns, parent owner/table, and parent columns in one join.

★
Picture a library where every loan must link to a member card.

Enforcement is immediate by default: every row checked at write time, first violation fails the statement.

Three scenarios dominate. Load-order inversion: ETL parallelization or file reordering delivers children before parents — the classic 'worked serially, fails in parallel.' True orphans: the parent never existed (bad source key, mistyped id) or was deleted while children pointed at it (missing ON DELETE handling).

Cross-system drift: the child references a parent in another database or a not-yet-migrated partition, so no local ordering can satisfy it.

Two release valves exist for legitimate timing gaps. DEFERRABLE INITIALLY DEFERRED constraints check once at COMMIT instead of per row, letting a single transaction insert parents and children in any order. SET CONSTRAINTS ... DEFERRED flips deferrable constraints for the transaction.

Both preserve the guarantee (commit still fails on real orphans) while tolerating ordering — which is precisely the semantics bulk loads need. For structural drift, the answer isn't deferral but repair: adopt, create, or delete the orphans.

Plain-English First

Picture a library where every loan must link to a member card. ORA-02291 is the scanner rejecting slip 9917 — a card never issued. Maybe new members are not registered yet (parents load later), the card was mistyped (bad key), or the member left years ago (deleted parent). The fix is registering members first (insert order), checking all slips together at closing time (deferred constraints), or ruling on ghost slips (orphan cleanup).

ORA-02291: integrity constraint (SHOP.FK_ORDER_CUSTOMER) violated - parent key not found. It arrives during bulk loads, ETL cutovers, and parallelized migrations: thousands of child rows rejected because their parents aren't there (yet). The application worked row-by-row for years; the loader just changed the order, the parallelism, or the source — and referential integrity did exactly what it was built to do.

Foreign keys enforce a simple law: no child without its parent. That law spans insert order (parents first), deletions (no orphaning parents without CASCADE or child cleanup), and concurrent loads (two streams racing). Break any of the three and error 02291 rejects the write — loudly, per row, until the loader gives up.

This guide moves from the constraint name to the parent table, lists orphans with anti-joins, restores dependency order, uses deferred constraints for cyclic loads, cleans up strays, and gates future loads with pre-flight orphan checks that fail fast every time.

Read the Constraint Name, Not Just the Code

The message names SHOP.FK_ORDER_CUSTOMER — owner plus constraint — and the dictionary does the rest. Join all_constraints (constraint type R, status, deferrability, delete rule) to all_cons_columns (the child columns in position order), then resolve r_constraint_name back through all_cons_columns to the parent table and its columns. One query returns the complete relationship: child table, child columns, parent table, parent columns, and whether the constraint even permits deferral.

Read the status columns while you're there: STATUS (ENABLED/DISABLED), VALIDATED/NOVALIDATE, DEFERRABLE/DEFERRED. A DISABLED or NOVALIDATE constraint that 'lets everything through' explains the opposite symptom (bad data present, no errors) and warns that re-enabling will surface every accumulated orphan at once. Know the constraint's state before you change the data's.

Save the translation in the ticket: 'FK_ORDER_CUSTOMER = orders.customer_id -> customers.customer_id, immediate, NO ACTION.' That single line lets anyone reproduce the orphan query without re-deriving the relationship — and trend analysis on constraint names shows whether failures cluster on one relationship (topology bug) or scatter (source drift).

translate_fk_2291.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
-- Constraint name -> full relationship in one join
SELECT c.table_name AS child_table, cc.column_name AS child_col,
  c.r_owner AS parent_owner,
  (SELECT table_name FROM all_constraints
    WHERE owner = c.r_owner AND constraint_name = c.r_constraint_name) AS parent_table,
  c.delete_rule, c.deferrable, c.deferred, c.status
FROM all_constraints c
JOIN all_cons_columns cc
  ON cc.owner = c.owner AND cc.constraint_name = c.constraint_name
WHERE c.owner = 'SHOP' AND c.constraint_name = 'FK_ORDER_CUSTOMER'
ORDER BY cc.position;
📊 Production Insight
Teams grep logs for 02291 while the dictionary names the parent table in one join. The translation query belongs in the runbook's first five lines.
🎯 Key Takeaway
Translate the named constraint into child, parent, columns, and state — one join answers all four.

Find the Orphans With an Anti-Join

The anti-join is the definitive orphan census: staged (or live) child rows with no matching parent. NOT EXISTS reads most clearly and stops at the first match per row; NOT IN risks NULL semantics (a single NULL parent key voids the whole result); LEFT JOIN ... IS NULL works but scans awkwardly. Standardize on NOT EXISTS and the team reads every orphan query at sight.

Always count before listing: the COUNT(*) with the identical predicate sizes the response (dozens = surgical fixes, millions = topology or source bug) without flooding your terminal. Then list with the child key plus the offending FK value — the pair is what the cleanup acts on. Timestamp the orphans too: a tight recent cluster means ordering, a wide historical scatter means drift, and the two get different owners.

Run the census against staging before production loads, and against production after any parent-side delete or archive job without exception. Archive purges are the quiet orphan factories: the purge deletes parents its WHERE clause matched while children outside its scope keep pointing at the grave. Every purge job earns a post-flight orphan count run by the job itself, failing the batch when strays appear.

orphan_census.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
-- Count first (sizes the response)
SELECT COUNT(*) AS orphans
FROM stage_orders s
WHERE NOT EXISTS (SELECT 1 FROM shop.customers c
  WHERE c.customer_id = s.customer_id);

-- Then list (child key + offending value + recency)
SELECT s.order_id, s.customer_id, s.loaded_at
FROM stage_orders s
WHERE NOT EXISTS (SELECT 1 FROM shop.customers c
  WHERE c.customer_id = s.customer_id)
ORDER BY s.loaded_at DESC;
💡Count Before You List
Run COUNT(*) with the orphan predicate before listing rows. Dozens mean surgical fixes; millions mean a topology or source bug — and the count decides which runbook you open.
📊 Production Insight
A 2M-row orphan count proved topology in one query — no source re-pulls needed. The count-first habit has saved three reload cycles since.
🎯 Key Takeaway
NOT EXISTS anti-joins census orphans precisely — count to size it, timestamp to classify it, stage it before loading.

Insert Order: Parents Before Children

Dependency order is the primary fix and it belongs in the loader's DAG, not in tribal knowledge. Phase the job: all parent streams to completion, a barrier, then child streams — with the barrier as a first-class DAG node that fails loudly if a parent phase partial-fails. Hash-partitioning rows across workers is fine within a phase; across phases it recreates the race. The incident's 16 workers were correct parallelism applied to the wrong dimension.

For single-database migrations, order the DML the same way: INSERT parents, then children, then create (or enable) the FK — or load with constraints DISABLED and ENABLE ... VALIDATE after, letting validation census all violations at once instead of failing on the first row. Staging tables make this clean: raw files land unconstrained, validated sets move in dependency order, and the live tables never see an orphan.

Document the dependency graph beside the loader config: which tables are parents of which, kept in load order. The graph is the onboarding doc and the incident map in one — when 02291 names a constraint, the graph shows its position and which phase owns it. Topology you can see is topology you can fix quickly and safely every time.

ordered_load.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
-- Phase 1: parents to completion first
INSERT INTO shop.customers (customer_id, name)
SELECT customer_id, name FROM stage_customers;
COMMIT;
-- (DAG barrier: fail here if parent phase partial-fails)

-- Phase 2: children only after the barrier
INSERT INTO shop.orders (order_id, customer_id, total)
SELECT order_id, customer_id, total FROM stage_orders s
WHERE EXISTS (SELECT 1 FROM shop.customers c
  WHERE c.customer_id = s.customer_id);

-- Strays stay staged (loaded later, never forced)
📊 Production Insight
A two-phase DAG with a real barrier node replaced hash-parallel chaos — the same 2M rows loaded cleanly the next night with zero rejections.
🎯 Key Takeaway
Phase loads by dependency with hard barriers; partition within phases, never across them.

Deferred Constraints for Cyclic Loads

Some loads can't order cleanly: cyclic references (A points at B, B points at A), single-transaction migrations that must interleave, or windows too tight for phasing. DEFERRABLE INITIALLY DEFERRED constraints move the check to COMMIT — insert in any order inside the transaction, and Oracle validates the whole graph once at commit. Real orphans still fail, with the same 02291, just at COMMIT time instead of row time.

Prefer INITIALLY IMMEDIATE for deferrable constraints you add: day-to-day behavior stays immediate (fail fast per row), and transactions that need freedom call SET CONSTRAINTS ALL DEFERRED explicitly. Blanket INITIALLY DEFERRED hides genuine violations until commit across all sessions, turning quick feedback into end-of-transaction surprises. Deferral is a tool you reach for, not a default you live in.

Convert with care: ALTER TABLE ... MODIFY CONSTRAINT ... DEFERRABLE re-locks briefly, so always convert off-peak. And never defer to mask drift — if the anti-join census shows true orphans (no parent anywhere, at any time), deferral just postpones the failure to COMMIT. Deferral tolerates ordering within a single transaction; only repair fixes the true absence of parents.

defer_fk.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- Make deferral available (default behavior stays immediate)
ALTER TABLE shop.orders
MODIFY CONSTRAINT fk_order_customer DEFERRABLE INITIALLY IMMEDIATE;

-- Single transaction, any order, validated once at COMMIT
SET CONSTRAINTS ALL DEFERRED;
INSERT INTO shop.orders (order_id, customer_id, total)
VALUES (101, 9917, 5000);
INSERT INTO shop.customers (customer_id, name)
VALUES (9917, 'New Buyer');
COMMIT;  -- 02291 here means a REAL orphan, not ordering

-- Check deferrability before relying on it
SELECT constraint_name, deferrable, deferred, status
FROM all_constraints WHERE owner = 'SHOP';
⚠ Deferral Tolerates Order, Not Absence
Deferred constraints still fail at COMMIT on true orphans — they forgive sequencing, not missing parents. Census with the anti-join first; defer only when every orphan has a parent arriving in the same transaction.
📊 Production Insight
Deferral saved a cyclic migration that phasing couldn't order — but the team census-first, so COMMIT-time failures meant real drift, never surprises.
🎯 Key Takeaway
DEFERRABLE INITIALLY IMMEDIATE plus SET CONSTRAINTS DEFERRED: freedom per transaction, immediate checks by default.

Cleanup: Adopt, Create, or Delete Orphans

True orphans need a fate decision per batch, made with the data owner, not the loader. Adopt: the child points at the wrong parent but the right one exists — UPDATE the FK to the correct key (common after source-system merges that renumbered parents). Create: the parent is genuinely missing but reconstructible — INSERT it from the child's distinct key values plus source defaults, marked for review. Delete: the child is junk (test rows, abandoned carts past retention) — archive then DELETE.

Archive before any destructive fate: INSERT the doomed rows into an orphan_archive table with timestamps and reason codes before UPDATE or DELETE touches them. Finance asking about row counts next quarter gets evidence, not recollection — and a mis-fated batch restores from the archive instead of the backup tapes.

Execute set-based with the same anti-join predicate as the census, so cleanup and diagnosis can't disagree. Re-run the census after each fate batch until zero: the loop (census, decide, act, re-census) is the procedure, and 'zero orphans' is the exit criterion every cleanup ticket records before it may close. Partial cleanups stopping at 'few enough' become next quarter's incident report.

orphan_fates.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- Archive first (evidence before destruction)
CREATE TABLE orphan_archive AS
SELECT s.*, SYSDATE AS archived_at, 'stale-cart' AS reason
FROM stage_orders s
WHERE NOT EXISTS (SELECT 1 FROM shop.customers c
  WHERE c.customer_id = s.customer_id);

-- Fate 1: adopt (repoint to the real parent)
-- UPDATE stage_orders SET customer_id = 1001 WHERE customer_id = 9917;

-- Fate 2: create (reconstruct missing parents, flagged)
INSERT INTO shop.customers (customer_id, name)
SELECT DISTINCT s.customer_id, 'REVIEW-' || s.customer_id
FROM stage_orders s
WHERE NOT EXISTS (SELECT 1 FROM shop.customers c
  WHERE c.customer_id = s.customer_id);

-- Fate 3: delete (junk only, archive already taken)
-- DELETE FROM stage_orders s WHERE <junk predicate>;
📊 Production Insight
An archive-first habit saved a quarter-close: a mis-fated batch restored from orphan_archive in minutes instead of waiting on backup restores.
🎯 Key Takeaway
Archive, then adopt/create/delete set-based with the census predicate — loop until the census reads zero.

Prevention: Validate Before Loading

Make orphan-free loads a gate, not a hope. The pre-flight anti-join count must read zero before the loader inserts anything — wire it as the DAG's first node with a hard fail, not a warning email. Warnings get snoozed through quarters; hard gates get fixed before lunch. Extend the gate per relationship: every FK the load touches gets its own census query, generated from the dictionary so new constraints join the gate automatically.

Monitor the error as a topology signal. Alert on the first ORA-02291 after any ETL deploy — ordering regressions never self-heal, and the first occurrence is the cheapest moment to catch them. Trend rejections per constraint across loads: a step-change names the deploy that reordered streams even when the diff looked innocent.

Keep staging tables deferrable and live tables immediate. Staging absorbs out-of-order arrivals with deferred checks at merge time; live tables fail fast per row so application bugs surface instantly. The two-tier discipline gives bulk loads freedom and OLTP strictness from the same constraint definitions — correct by construction. Generate the per-FK census queries from the dictionary so new relationships join the gate with zero manual wiring.

preload_gate_2291.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
# Pre-flight gate: zero orphans before the loader inserts anything
set -euo pipefail
CONNECT="etl/pass@//db-prod:1521/shop"
ORPHANS=$(sqlplus -S "$CONNECT" << 'EOF'
SET HEADING OFF FEEDBACK OFF
SELECT COUNT(*) FROM stage_orders s
WHERE NOT EXISTS (SELECT 1 FROM shop.customers c
  WHERE c.customer_id = s.customer_id);
EOF
)
ORPHANS=$(echo "$ORPHANS" | tr -d ' ')
if [ "$ORPHANS" != "0" ]; then echo "GATE-FAIL: $ORPHANS orphans"; exit 1; fi
echo "GATE-PASS: zero orphans"
📊 Production Insight
A pre-flight orphan gate now fails bad loads in seconds — three ordering regressions caught pre-insert this year, zero post-load aborts.
🎯 Key Takeaway
Gate every load on zero-orphan census counts, alert on first post-deploy 02291, and keep staging deferrable with live immediate.
● Production incidentPOST-MORTEMseverity: high

Parallel ETL Loaded 2M Children Before Their Parents

Symptom
At 1:00 AM the parallelized customer-order load started; by 1:40 AM 2M order rows had been rejected with ORA-02291 on SHOP.FK_ORDER_CUSTOMER, the error table overflowed its partition, and the loader aborted. The warehouse missed its 6 AM SLA by 5 hours — finance, fraud, and personalization all stale for the morning. The serial loader it replaced had run the same data cleanly the night before.
Assumption
The team assumed the source extract was corrupt and re-pulled 40 GB from upstream twice, burning 3 hours. Checksums matched both times — because the data was fine and the order was the bug. Nobody compared stream completion times until the reloads also failed identically.
Root cause
The parallelism upgrade hashed rows across 16 workers by order_id, splitting each parent's customers from their orders across different workers with no barrier. The child stream consistently finished first (smaller rows, hotter cache), inserting into orders while customers landed minutes later. Immediate-mode FK checks rejected every early child. The constraint was correct; the load topology violated dependency order.
Fix
At 6:30 AM they reloaded with a two-phase topology — customers stream to completion, barrier, then orders — plus SET CONSTRAINTS ALL DEFERRED inside the child phase as a belt-and-braces. The load completed by 11 AM. Permanent fixes: dependency-ordered phases in the loader DAG, deferrable FKs on staging tables, and a pre-flight orphan count that fails the job before inserting a single row.
Key lesson
  • Order loads by dependency, not by row hash: parallel streams need phase barriers between parents and children, or the fast stream fails against missing parents.
  • Pre-flight orphan counts beat post-failure error tables: one anti-join before loading fails the job in seconds instead of aborting it after 2M rejections.
  • Keep deferral as a safety net, not the design: deferred constraints tolerate ordering, but phased topology is what makes ordering correct.
Production debug guideSix steps from the constraint name to ordered, orphan-free loads.6 entries
Symptom · 01
Load fails with ORA-02291 naming (SCHEMA.CONSTRAINT_NAME)
→
Fix
Translate the name to tables: SELECT c.table_name AS child, cc.column_name AS child_col, c.r_owner AS parent_owner, c.r_constraint_name FROM all_constraints c JOIN all_cons_columns cc ON cc.constraint_name = c.constraint_name WHERE c.owner='SHOP' AND c.constraint_name='FK_ORDER_CUSTOMER'; Then resolve the parent side via all_cons_columns on r_constraint_name. You now know exactly which parent rows must exist.
Symptom · 02
You need the full orphan list, not just the first failure
→
Fix
Anti-join staged children against parents: SELECT s.order_id, s.customer_id FROM stage_orders s WHERE NOT EXISTS (SELECT 1 FROM shop.customers c WHERE c.customer_id = s.customer_id); Count first (COUNT(*) with the same predicate sizes the cleanup), then list. Thousands of orphans with recent timestamps mean ordering; scattered old ones mean true drift.
Symptom · 03
Orphans exist because parents load later in the same job
→
Fix
Check stream completion order in the loader log: if the child phase finished before the parent phase, it's topology, not data. Fix by phasing the DAG (parents to completion, barrier, then children) and re-running the anti-join to prove zero orphans before the reload. For single transactions, wrap both phases and SET CONSTRAINTS ALL DEFERRED as a net.
Symptom · 04
Parents were deleted while children pointed at them
→
Fix
Audit the delete path: SELECT * FROM all_constraints WHERE r_constraint_name = '<parent PK>' AND delete_rule = 'NO ACTION'; NO ACTION means deletes orphan-block (good) only if nothing bypassed the constraint — direct-path loads and disabled constraints bypass it. Re-enable (ALTER TABLE ... ENABLE CONSTRAINT), clean the strays per the fate decision, and add ON DELETE policy deliberately.
Symptom · 05
You must load now despite ordering pain (cyclic refs, single window)
→
Fix
Defer for the transaction: SET CONSTRAINTS ALL DEFERRED; (constraints must be DEFERRABLE — check all_constraints.deferrable), load parents and children in any order, then COMMIT — Oracle validates at commit and fails only on real orphans. Convert key FKs with ALTER TABLE ... MODIFY CONSTRAINT ... DEFERRABLE INITIALLY IMMEDIATE so deferral is available without changing default behavior.
Symptom · 06
Recovered — now make the next load prove itself first
→
Fix
Add the pre-flight gate: the anti-join count must be zero before the loader inserts anything, and the job fails otherwise. Also alert on ORA-02291 in the alert log post-deploy — the first occurrence after an ETL change pages, because ordering regressions never self-heal.
ORA-02291 Causes at a Glance
Root CauseHow to ConfirmFixPrevention
Children loaded before parentsChild phase finished first in logsPhase DAG with barriers; defer as netDependency-ordered phases; pre-flight census
True orphans (bad/missing keys)Anti-join rows with no parent anywhereAdopt, create, or delete after archivingSource validation; CHECK-quality gates
Parent deleted under live childrenArchive/purge job touched parent tableRestore or repoint; policy ON DELETEPost-purge orphan counts; delete rules
Cross-system/partition driftParent in another DB or future partitionStage + reconcile before loadingSingle-system-of-record per relationship
Cyclic references, unorderableA<->B FK cycle in dictionaryDeferred constraints in one transactionModel cycles out where possible
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
translate_fk_2291.sqlSELECT c.table_name AS child_table, cc.column_name AS child_col,Read the Constraint Name, Not Just the Code
orphan_census.sqlSELECT COUNT(*) AS orphansFind the Orphans With an Anti-Join
ordered_load.sqlINSERT INTO shop.customers (customer_id, name)Insert Order
defer_fk.sqlALTER TABLE shop.ordersDeferred Constraints for Cyclic Loads
orphan_fates.sqlCREATE TABLE orphan_archive ASCleanup
preload_gate_2291.shset -euo pipefailPrevention

Key takeaways

1
02291 names the constraint
translate to parent table and columns via the dictionary.
2
Census orphans with NOT EXISTS
count to size, timestamps to classify.
3
Phase loads parents-then-children with hard barriers; partition within phases.
4
Defer per transaction for cycles; keep IMMEDIATE as the default behavior.
5
Archive before cleanup; fate batches as adopt, create, or delete; loop to zero.
6
Gate loads on zero-orphan counts and alert on first post-deploy 02291.

Common mistakes to avoid

5 patterns
×

Re-pulling the source when loads reject en masse

Symptom
Checksums match, reloads fail identically — hours burned on healthy data.
Fix
Census orphans and check phase order first; the topology is guilty far more often than the source.
×

Disabling the FK to 'finish the load'

Symptom
Load completes; orphans poison every downstream report until discovered.
Fix
Keep constraints enabled; fix order or defer — never trade the guarantee for green lights.
×

Using NOT IN for orphan hunts

Symptom
One NULL parent key voids the whole census — zero rows, false confidence.
Fix
Standardize on NOT EXISTS; it ignores NULL semantics correctly.
×

Deferring everything INITIALLY DEFERRED

Symptom
Genuine violations surface at COMMIT across all sessions — slow feedback everywhere.
Fix
INITIALLY IMMEDIATE by default; defer explicitly per transaction that needs it.
×

Deleting orphans without archiving

Symptom
Row-count questions next quarter have no evidence; mis-fates need backup restores.
Fix
Archive with reason codes first; restore from archive, not tape.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What does ORA-02291 mean?
Q02SENIOR
How do you list every orphan without false positives from NULLs?
Q03SENIOR
A parallel loader that worked serially now 02291s. Diagnose it.
Q04SENIOR
When do you use DEFERRABLE INITIALLY DEFERRED versus IMMEDIATE?
Q05SENIOR
How do you add an FK to tables that already hold orphans?
Q01 of 05JUNIOR

What does ORA-02291 mean?

ANSWER
A child row references a parent key that doesn't exist. The message names the constraint — join all_constraints to all_cons_columns to find the exact parent table and columns.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Should I disable the foreign key to finish an urgent load?
02
Why did serial loads work but parallel ones fail?
03
What's wrong with NOT IN for orphan checks?
04
Do deferred constraints weaken integrity?
05
Parent deleted — should the FK have CASCADE?
06
How do I find which loads touch a given FK?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
✓ Verified
production tested
September 23, 2026
last updated
1,942
articles · all by Naren
🔥

That's Oracle. Mark it forged?

5 min read · try the examples if you haven't

←
Previous
ORA-01400 Cannot Insert NULL Fix
4 / 5 · Oracle
Next
ORA-01555 Snapshot Too Old Fix
→