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

  1. Increase the optimizer timeout: SET SESSION optimizer_timeout = '60s' (or raise it in properties config)
  2. Simplify the query (fewer joins/subqueries, add explicit joins instead of relying on reordering)
  3. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/ec6488de749d968b. Report an issue: GitHub.