Help Center/ TaurusDB/ Kernel/ Query Optimization/ Left Join Elimination
Updated on 2026-07-24 GMT+08:00

Left Join Elimination

Scenarios

In enterprise applications, ORM frameworks, view expansions, reporting queries, and generic SQL templates frequently generate complex SQL statements containing multiple LEFT JOIN clauses. The table on the right side of a LEFT JOIN is referenced only within the join condition, meaning that the query does not actually read any columns from that table. In other cases, rows from the left-hand table may undergo row amplification due to the join, but subsequent GROUP BY or DISTINCT clauses eliminate the amplification effect. When executing such queries, community MySQL still generates access paths and executes the join operations for these LEFT JOIN clauses. For complex queries, this introduces additional table scans, index lookups, join computations, and intermediate result processing, all of which degrade query performance.

TaurusDB supports left join elimination, allowing the optimizer to remove right-hand tables that do not affect the final result before generating the execution plan. This ensures that the query engine accesses only the tables required to produce the correct output, reducing CPU, I/O, and join execution overhead.

This optimization primarily covers three scenarios:

  • Elimination based on GROUP BY or DISTINCT: If the right-hand table only amplifies the row count of the left-hand table, a subsequent GROUP BY or DISTINCT removes duplicates, and the query does not contain expressions (such as aggregate functions) that depend on the row count, the right-hand table can be removed.
  • Elimination based on uniqueness: If the equality predicates in the ON condition cover all columns of a unique key on the right-hand table, each row from the left-hand table can match at most one row from the right-hand table and the right-hand table can be removed. Derived tables that produce unique rows through GROUP BY or DISTINCT are also treated as unique.
  • Elimination based on subquery semantics (EXISTS/IN): When a LEFT JOIN appears inside an EXISTS, IN, NOT EXISTS, or NOT IN subquery and the right-hand table does not affect the boolean evaluation of that subquery, the right-hand table of the LEFT JOIN can be removed.

How It Works

Left join elimination is a semantic query-rewriting optimization based on equivalence rules of relational algebra. The optimizer identifies and removes redundant LEFT JOIN operations while guaranteeing that the final result set remains unchanged.

Consider the following query:
SELECT t1.a
FROM t1
LEFT JOIN t2 ON t2.a = t1.b;
If t2.a is a unique key and no columns from t2 are referenced in the SELECT, WHERE, GROUP BY, HAVING, or ORDER BY clauses, each row in t1 can match at most one row in t2. Because a LEFT JOIN never filters rows from t1 and t2 does not affect the final output, the optimizer rewrites the query to:
SELECT t1.a
FROM t1;

Left join elimination occurs during the query resolver phase, after join structure simplification and join information collection. The optimizer first simplifies the join tree and then analyzes whether the right-hand table of a LEFT JOIN is referenced externally and whether it satisfies uniqueness or deduplication criteria. If the table qualifies, it is removed from the subsequent execution plan. Consequently, once this feature is enabled, eliminated tables will not appear in EXPLAIN outputs. You can inspect the join_elimination node and check the number of eliminated tables in the join_preparation step of an optimizer_trace.

Conversion Process

Original query:
SELECT t1.a
FROM t1
LEFT JOIN t2 ON t2.a > t1.b
GROUP BY t1.a;
Rewritten query:
SELECT t1.a
FROM t1
GROUP BY t1.a;

Because t2 appears only in the ON condition of the LEFT JOIN, the predicate t2.a > t1.b may cause a single row in t1 to match multiple rows in t2. However, since GROUP BY t1.a removes all duplicate rows introduced by t2, the optimizer can eliminate access to the t2 table.

Prerequisites

  • The TaurusDB kernel version must be 2.0.75.260300 or later. For details about how to check the kernel version, see How Can I Check the Version of a TaurusDB Instance?
  • left_join_elimination in the optimizer_switch system parameter must be ON. For details, see Modifying TaurusDB Instance Parameters.
  • The SQL statement must contain LEFT JOIN or RIGHT JOIN and meet the conditions for left join elimination without affecting the final query results.

Supported Query Statements

  • SELECT
  • INSERT ... SELECT
  • REPLACE ... SELECT
  • CREATE TABLE ... SELECT
  • Subqueries within any query statement
  • Eligible queries inside views, derived tables, and prepared statements

Constraints

Table 1 Constraints

Category

Item

Description

Supported join types

LEFT JOIN

Elimination is supported.

RIGHT JOIN

It is converted to an equivalent LEFT JOIN during the resolver phase and is eligible for elimination if criteria are met.

Unsupported scenarios

INNER JOIN

Inner join elimination is not supported.

Multi-table UPDATE

Left join elimination is not supported in multi-table UPDATE statements.

Multi-table DELETE

Left join elimination is not supported in multi-table DELETE statements.

Field reference restrictions

SELECT

General rule: If any query projection column references a column from the right-hand table, elimination is not applied.

Subquery exception: Inside EXISTS/IN subqueries, this restriction is bypassed. This is because EXISTS checks row existence and IN does not depend on right-hand column values. References here do not block elimination.

WHERE

General rule: If any filter predicate references a column from the right-hand table, elimination is not applied.

Subquery exception: Inside EXISTS/IN subqueries, this restriction is bypassed. This is because EXISTS checks row existence and IN does not depend on right-hand column values. References here do not block elimination.

GROUP BY

If columns of the right-hand table are referenced in the grouping columns, elimination is not applied.

HAVING

If columns of the right-hand table are referenced in the post-aggregation filtering conditions, elimination is not applied.

ORDER BY

If columns of the right-hand table are referenced in the sorting criteria, elimination is not applied.

Window functions

If columns of the right-hand table are referenced in the definition or invocation of a window function, elimination is not applied.

Other JOIN ON conditions

If columns of the right-hand table are referenced in the ON conditions of other joins, elimination is not applied.

ON DUPLICATE KEY UPDATE

If columns of the right-hand table are referenced in write-conflict update clauses, elimination is not applied.

DEFAULT(col) function

If columns of the right-hand table are referenced within the DEFAULT(col) function call, elimination is not applied.

Aggregate functions

Aggregate functions are included.

Elimination is not applied under the GROUP BY or DISTINCT rules.

Safety criteria met

Elimination may still be applied if other safety constraints (such as uniqueness rules) are fully satisfied.

DISTINCT + Window functions

Only DISTINCT is used for deduplication and window functions are included.

The right-hand table is not eliminated based on the DISTINCT rule.

GROUP BY also exists.

The optimizer continues to evaluate elimination using GROUP BY semantics.

Uniqueness evaluation restrictions

OR conditions

Join predicates containing OR conditions are ineligible for elimination.

<=> Comparison

NULL-safe equality comparisons are ineligible for elimination.

Non-deterministic expressions

Clauses containing non-deterministic functions, such as RAND(), are ineligible for elimination.

String and non-string comparison

Comparisons where the right-hand side is a string column and the other side is non-string are ineligible for elimination.

Collation mismatch

If both sides are strings but their collation does not match the right-hand column's collation, the predicate is ineligible for elimination.

Other cases

Even if uniqueness-based elimination is skipped, the table may still be eliminated through GROUP BY/DISTINCT or EXISTS/IN subquery semantics.

How to Use

You can manage left join elimination by configuring the optimizer_switch parameter.

Table 2 Parameters

Parameter

Level

Description

optimizer_switch

Global, Session

The left join elimination feature is controlled through the left_join_elimination flag within the optimizer_switch parameter. To enable this feature, set left_join_elimination to on. To disable this feature, set the parameter to off. It is disabled by default.

Enable the feature:
SET optimizer_switch='left_join_elimination=ON';
Disable the feature:
SET optimizer_switch='left_join_elimination=OFF';

Examples

Create test tables:
CREATE TABLE t1(a INT PRIMARY KEY, b INT);
CREATE TABLE t2(a INT PRIMARY KEY, b INT);
INSERT INTO t1 VALUES(1,1),(2,3),(7,NULL);
INSERT INTO t2 VALUES(2,2),(4,5),(5,4);
ANALYZE TABLE t1,t2;
First, disable left join elimination:
SET optimizer_switch='left_join_elimination=off';
EXPLAIN FORMAT=TREE SELECT t1.a
FROM t1
LEFT JOIN t2 ON t2.a > t1.b 
GROUP BY t1.a\G
After left join elimination is disabled, the execution plan retains table t2:
*************************** 1. row ***************************
EXPLAIN: -> Group (no aggregates)
    -> Nested loop left join  (cost=1.70 rows=9)
        -> Index scan on t1 using PRIMARY  (cost=0.55 rows=3)
        -> Filter: (t2.a > t1.b)  (cost=0.18 rows=3)
            -> Index range scan on t2 (re-planned for each iteration)  (cost=0.18 rows=3)
Enable left join elimination again:
SET optimizer_switch='left_join_elimination=on';
EXPLAIN FORMAT=TREE SELECT t1.a
FROM t1
LEFT JOIN t2 ON t2.a > t1.b 
GROUP BY t1.a\G
With left join elimination enabled, the execution plan contains only table t1 and table t2 is eliminated:
*************************** 1. row ***************************
EXPLAIN: -> Table scan on t1  (cost=0.55 rows=3)
When the ON join clause binds directly to the unique key of the right-hand table, the optimizer can prove that each row in the left table will match at most one row in the right-hand table:
SET optimizer_switch='left_join_elimination=off';
EXPLAIN FORMAT=TREE SELECT t1.a
FROM t1
LEFT JOIN t2 ON t2.a = t1.b\G
With left join elimination disabled, the execution plan retains table t2 and performs an eq_ref lookup using the primary key:
*************************** 1. row ***************************
EXPLAIN: -> Nested loop left join  (cost=1.60 rows=3)
    -> Table scan on t1  (cost=0.55 rows=3)
    -> Single-row index lookup on t2 using PRIMARY (a=t1.b)  (cost=0.28 rows=1)
With left join elimination enabled, the execution plan contains only table t1:
SET optimizer_switch='left_join_elimination=on';
EXPLAIN FORMAT=TREE SELECT t1.a
FROM t1
LEFT JOIN t2 ON t2.a = t1.b\G
*************************** 1. row ***************************
EXPLAIN: -> Table scan on t1  (cost=0.55 rows=3)
When a LEFT JOIN appears inside an EXISTS subquery and the right-hand table does not affect the boolean evaluation of that subquery, the right-hand table of the LEFT JOIN can be removed.
SET optimizer_switch='left_join_elimination=off';
EXPLAIN FORMAT=TREE SELECT t0.a
FROM t1 AS t0
WHERE EXISTS (
  SELECT t2.b
  FROM t1 LEFT JOIN t2 ON t2.a > t1.b
  WHERE t0.a = t1.b
)\G
With left join elimination disabled, table t2 remains in the execution plan after subquery conversion.
*************************** 1. row ***************************
EXPLAIN: -> Remove duplicate t0 rows using temporary table (weedout)  (cost=2.75 rows=9)
    -> Nested loop left join  (cost=2.75 rows=9)
        -> Nested loop inner join  (cost=1.60 rows=3)
            -> Filter: (t1.b is not null)  (cost=0.55 rows=3)
                -> Table scan on t1  (cost=0.55 rows=3)
            -> Single-row index lookup on t0 using PRIMARY (a=t1.b)  (cost=0.28 rows=1)
        -> Filter: (t2.a > t1.b)  (cost=0.55 rows=3)
            -> Index range scan on t2 (re-planned for each iteration)  (cost=0.55 rows=3)
With left join elimination enabled, table t2 is eliminated from the execution plan after subquery conversion.
SET optimizer_switch='left_join_elimination=on';
EXPLAIN FORMAT=TREE SELECT t0.a
FROM t1 AS t0
WHERE EXISTS (
  SELECT t2.b
  FROM t1 LEFT JOIN t2 ON t2.a > t1.b
  WHERE t0.a = t1.b
)\G
*************************** 1. row ***************************
EXPLAIN: -> Nested loop inner join  (cost=1.15 rows=3)
    -> Filter: (`<subquery2>`.b is not null)  (cost=0.60 rows=3)
        -> Table scan on <subquery2>  (cost=0.60 rows=3)
            -> Materialize with deduplication  (cost=0.55 rows=3)
                -> Filter: (t1.b is not null)  (cost=0.55 rows=3)
                    -> Table scan on t1  (cost=0.55 rows=3)
    -> Single-row index lookup on t0 using PRIMARY (a=`<subquery2>`.b)  (cost=0.35 rows=1)

The execution plan shows that table t2 inside the subquery has been eliminated, indicating that left join elimination was successfully executed.

Negative subqueries such as NOT EXISTS and NOT IN also trigger this optimization when they meet the same criteria. You can verify whether elimination has occurred through the optimizer_trace. Once the trace is enabled, if left join elimination is hit, the join_elimination node will appear in the join_preparation step:
{
  "steps": [
    {
      "join_preparation": {
        "steps": [
          {
            "join_elimination": {
              "number_of_eliminated_tables": 1,
              "expanded_query": "/* select#1 */ select `t0`.`a` AS `a` from `t1` `t0` semi join (`t1`) where ((`t0`.`a` = `t1`.`b`))"
            }
          }
        ]
      }
    }
  ]
}