PolarDB for MySQL automatically rewrites SQL statements at the optimizer stage to eliminate redundant subqueries and pre-compute constant ones. This reduces execution plan complexity and improves query performance — a common issue when Object-Relational Mapping (ORM) frameworks generate deeply nested queries.
Scope
Product series: Cluster Edition and Standard Edition
Kernel version: MySQL 8.0.2, revision 8.0.2.2.19 or later
Enable subquery optimization
Control subquery optimization with the loose_simplify_subq_mode parameter.
The parameter name differs depending on where you set it:
PolarDB console: Use the
loose_prefix (loose_simplify_subq_mode). Some parameters carry this prefix for compatibility with MySQL configuration files.Database session (command line or client): Remove the
loose_prefix and useSET simplify_subq_mode = '...'.
| Parameter | Level | Description |
|---|---|---|
loose_simplify_subq_mode | Global/Session | Controls subquery optimization. Valid values: REPLICA_ON (default) — enables optimization on read-only (RO) nodes only; ON — enables the feature; OFF — disables optimization. |
How it works
The optimizer applies three types of rewrites at the optimizer stage:
Redundant SELECT elimination — strips unnecessary SELECT wrapper layers around aggregate functions or constant expressions.
[NOT] EXISTS pre-evaluation — replaces EXISTS subqueries with
TRUEorFALSEwhen the result can be determined without executing the subquery.ANY/ALL LIMIT injection — adds
LIMIT 1to constant-projection subqueries inside ANY or ALL clauses to avoid full table scans.
Each scenario below shows the exact rewrite the optimizer applies.
Optimization scenarios
Scenario 1: Eliminate redundant SELECT nesting
When it applies: The subquery wraps only an aggregate function or expression with no other complex logic.
Rewrite pattern:
-- Before
SELECT (SELECT SUM(a) FROM t2) FROM dual;
-- After
SELECT SUM(`test`.`t2`.`a`) AS `sum(a)` FROM `test`.`t2`The same elimination applies in HAVING clauses, where the optimizer flattens multiple layers of nesting:
-- Before
SELECT SUM(a) FROM t2 HAVING (SELECT(SELECT(SELECT count(b))));
-- After
SELECT SUM(`testdb`.`t2`.`a`) AS `SUM(a)` from `testdb`.`t2` HAVING (0 <> count(`testdb`.`t2`.`b`))Verify with an example:
Prepare test data:
DROP TABLE IF EXISTS t2; CREATE TABLE t2 ( id INT PRIMARY KEY AUTO_INCREMENT, a INT, b INT ); INSERT INTO t2 (a, b) VALUES (10, 100), (20, NULL), (50, 200), (120, NULL);Check the execution plan without optimization:
SET simplify_subq_mode = 'OFF'; EXPLAIN SELECT SUM(a) FROM t2 HAVING (SELECT(SELECT(SELECT count(b)))); SHOW WARNINGS;Result — four nested SELECT layers remain:
/* select#1 */ select sum(`testdb`.`t2`.`a`) AS `SUM(a)` from `testdb`.`t2` having (0 <> (/* select#2 */ select (/* select#3 */ select (/* select#4 */ select count(`testdb`.`t2`.`b`)))))Check the execution plan with optimization enabled:
SET simplify_subq_mode = 'ON'; EXPLAIN SELECT SUM(a) FROM t2 HAVING (SELECT(SELECT(SELECT count(b)))); SHOW WARNINGS;Result — all nesting is eliminated:
/* select#1 */ select sum(`testdb`.`t2`.`a`) AS `SUM(a)` from `testdb`.`t2` having (0 <> count(`testdb`.`t2`.`b`))
Scenario 2: Pre-evaluate [NOT] EXISTS subqueries
When it applies: The optimizer can statically determine that an EXISTS or NOT EXISTS subquery always returns true (non-empty) or false (empty).
Rewrite pattern:
-- Non-empty result: EXISTS clause is removed entirely
-- Before
SELECT * FROM t1 WHERE EXISTS(SELECT MAX(a) FROM t2);
-- After
SELECT * FROM t1
-- Empty result (WHERE/HAVING evaluates to false, or LIMIT 0): replaced with false
-- Before
SELECT * FROM t1 WHERE EXISTS(SELECT max(a) FROM t2 HAVING 1=2);
-- After
SELECT * FROM t1 WHERE falseThis prevents the subquery from executing at all.
Verify with an example:
Prepare test data:
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1 (id INT); CREATE TABLE t2 (val INT); INSERT INTO t1 VALUES (1), (2);Check the execution plan without optimization:
SET simplify_subq_mode = 'OFF'; EXPLAIN SELECT * FROM t1 WHERE EXISTS(SELECT MAX(a) FROM t2); SHOW WARNINGS;Result — the EXISTS subquery is evaluated at runtime:
/* select#1 */ select `testdb`.`t1`.`id` AS `id` from `testdb`.`t1` where exists(/* select#2 */ select max(`testdb`.`t1`.`id`) from `testdb`.`t2`)Check the execution plan with optimization enabled:
SET simplify_subq_mode = 'ON'; EXPLAIN SELECT * FROM t1 WHERE EXISTS(SELECT MAX(a) FROM t2); SHOW WARNINGS;Result — the EXISTS clause is gone:
/* select#1 */ select `testdb`.`t1`.`id` AS `id` from `testdb`.`t1`
Scenario 3: Add LIMIT 1 to constant projections in ANY/ALL subqueries
When it applies: The subquery inside an ANY or ALL clause selects only a constant (no column references). Retrieving multiple identical rows is wasteful, so the optimizer injects LIMIT 1.
Rewrite pattern:
-- Before
SELECT * FROM t1 WHERE a > ANY (SELECT 1 FROM t2);
-- After
SELECT * FROM t1 WHERE a > ANY (SELECT 1 FROM t2 LIMIT 1);This avoids a full table scan on t2 when the constant result is the same for every row.
Apply in production
Before enabling subquery optimization for critical workloads, follow these steps:
Run full regression tests in a staging environment first. In rare edge cases — such as queries that depend on a specific execution order or subquery execution count — the optimization may produce different behavior, even though logical equivalence is guaranteed in most cases.
Keep table statistics up to date. Scenario 2 depends on table statistics to infer whether a set is empty or non-empty. Run
ANALYZE TABLEregularly so the optimizer makes accurate decisions.