prestodb/presto · error · PrestoException
OPTIMIZER_TIMEOUT
OPTIMIZER_TIMEOUT
Error message
The optimizer exhausted the time limit of %d ms
What it means
The iterative optimizer enforces a wall-clock time budget per query optimization. When rule exploration exceeds the configured timeout, Presto aborts optimization with OPTIMIZER_TIMEOUT rather than hanging.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/planner/iterative/IterativeOptimizer.java:445
this.lookup = lookup;
this.idAllocator = idAllocator;
this.variableAllocator = variableAllocator;
this.startTimeInNanos = startTimeInNanos;
this.timeoutInMilliseconds = timeoutInMilliseconds;
this.session = session;
this.warningCollector = warningCollector;
this.costProvider = costProvider;
this.statsProvider = statsProvider;
this.metadata = metadata;
this.types = types;
this.rulesTriggered = new HashSet<>();
this.rulesApplicable = new HashSet<>();
}
public void checkTimeoutNotExhausted()
{
if ((NANOSECONDS.toMillis(System.nanoTime() - startTimeInNanos)) >= timeoutInMilliseconds) {
throw new PrestoException(OPTIMIZER_TIMEOUT, format("The optimizer exhausted the time limit of %d ms", timeoutInMilliseconds));
}
}
public void addRulesTriggered(String rule, PlanNode oldNode, PlanNode newNode, boolean isCostBased, String statsSource)
{
Optional<String> before = Optional.empty();
Optional<String> after = Optional.empty();
if (SystemSessionProperties.isVerboseOptimizerResults(session, rule)) {
before = Optional.of(PlannerUtils.getPlanString(oldNode, session, types, metadata, false));
after = Optional.of(PlannerUtils.getPlanString(newNode, session, types, metadata, false));
}
rulesTriggered.add(new RuleTriggered(rule, before, after, isCostBased, statsSource));
}
public void addRulesApplicable(String rule)
{View on GitHub (pinned to 55bb57d202)
Solutions
- Increase the optimizer timeout: SET SESSION optimizer_timeout = '60s' (or raise it in properties config)
- Simplify the query (fewer joins/subqueries, add explicit joins instead of relying on reordering)
- Reduce applicable rules via session optimizer feature flags, or check for query patterns that trigger rule explosion
Example fix
// before SELECT ... /* huge 30+ table join */; // after SET SESSION optimizer_timeout = '120s'; SELECT ... /* join split into CTEs or pre-aggregated */;
Defensive patterns
Strategy: retry
Validate before calling
// estimate complexity before running: count joins/subqueries
const isComplex = (sql.match(/\bJOIN\b/gi) || []).length > 15;
if (isComplex) setSessionProperty('optimizer_timeout', '120s'); Type guard
null
Try / catch
try {
runQuery(sql);
} catch (PrestoException e) {
if (e.getErrorCode() == OPTIMIZER_TIMEOUT.toErrorCode()) {
setSessionProperty("optimizer_timeout", "300s");
return retryQuery(sql);
}
throw e;
} Prevention
- Set a generous optimizer_timeout for analytical workloads
- Keep join counts per query manageable; split very large joins
- Monitor for queries repeatedly hitting the optimizer timeout
When it happens
Trigger: Running a query whose plan exploration (rule applications in the memo) exceeds the session/system 'optimizer-timeout' limit in milliseconds.
Common situations: Very large or highly nested queries with many join reorderings; optimizer-timeout set too low for complex analytical queries; pathological queries causing rule explosion.
Related errors
- INDEX_LOADER_TIMEOUT
- QUERY_PLANNING_TIMEOUT
- ATOP_READ_TIMEOUT
- Timed out waiting for query preprocessor after
- CLICKHOUSE_QUERY_GENERATOR_FAILURE
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/ec6488de749d968b.
Report an issue: GitHub.