A LEFT JOIN That Silently Dropped 40% of Report Data During a Database Migration
Database migrations from MySQL or PostgreSQL to a new system often surface silent data corruption that has existed for years. A LEFT JOIN that silently becomes an INNER JOIN drops rows without errors, and the only reliable way to catch it is by inspecting the execution plan—not by trusting that the SQL runs without exceptions.
A production report lost 40% of its data after migrating from MySQL to KingbaseES (KES), not because of a database bug, but because a long-standing SQL error was finally exposed. The culprit was a LEFT JOIN with a WHERE clause filtering on a column from the right table, which the optimizer correctly rewrites as an INNER JOIN under SQL standard rules. The old MySQL system had been running the same incorrect logic for years, but no one had ever reconciled the numbers closely enough to notice.
KES, PostgreSQL, MySQL, and all SQL:2008-compliant databases perform this outer join elimination when they detect a null-rejecting condition on the nullable side. The fix is straightforward: move the filter condition from the WHERE clause into the ON clause, or use COALESCE to create a null-preserving comparison. The execution plan reveals the truth instantly—a plain `Hash Join` instead of a `Hash Left Join` confirms the outer join has been eliminated.
Six common trap patterns extend beyond the basic case: non-equality operators, strict functions wrapping right-table columns, IN/BETWEEN clauses, mixing IS NULL with other right-table conditions, transitive elimination across nested joins, and views whose outer joins are reversely eliminated by outer WHERE clauses. A practical checklist combining static regex scanning, EXPLAIN sampling, and EXCEPT-based regression testing catches over 90% of these semantic traps during migration.
A migration project's real value is often not the new platform itself, but the forced audit of legacy SQL that exposes years-old semantic bugs no one had ever reconciled.
Optimizer behavior is consistent across databases; what differs is the tooling and community knowledge available to diagnose it quickly, which is where KES's EXPLAIN visibility and community knowledge base provide an edge.
The hardest traps to spot are cross-layer ones where a view's internal LEFT JOIN looks correct, but an outer WHERE clause on the calling query reversely eliminates it after the optimizer inlines the view.
Transitive elimination across nested joins can cascade: one null-rejecting condition on t3 can eliminate outer joins on both t2→t3 and t1→t2, multiplying the data loss.