Skip to content

SQL panel freezes or crashes when queries contain large IN clauses (e.g., thousands of UUIDs) #2293

@kkm-horikawa

Description

@kkm-horikawa

Description

When SQL queries contain large IN clauses with thousands of parameters (e.g., UUIDs), the SQL panel either:

  • Freezes for 10-18+ seconds (sqlparse < 0.5.5)
  • Crashes with SQLParseError (sqlparse >= 0.5.5)

This is a common pattern when fetching IDs from one query and filtering by them in another:

job_ids = list(Campaign.objects.filter(...).values_list('job_id', flat=True))
# job_ids contains 5000+ UUIDs

applications = JobApplication.objects.filter(job_id__in=job_ids)
# Database query is fast, but debug toolbar freezes/crashes

Behavior Matrix

debug-toolbar sqlparse When Behavior
<= 5.x < 0.5.5 Page load Freezes 10-18+ seconds
<= 5.x >= 0.5.5 Page load SQLParseError crash
>= 6.x < 0.5.5 SQL panel click Freezes 10-18+ seconds
>= 6.x >= 0.5.5 SQL panel click SQLParseError crash

Benchmark Results (sqlparse 0.5.3)

IN clause size Format time
100 UUIDs 0.01s
500 UUIDs 0.08s
1,000 UUIDs 0.26s
3,000 UUIDs 1.81s
5,000 UUIDs 4.87s
10,000 UUIDs 18.02s

Root Cause

The bottleneck is in debug_toolbar/panels/sql/utils.py:

@lru_cache(maxsize=128)
def parse_sql(sql, *, simplify=False):
    stack = get_filter_stack(simplify=simplify)
    return "".join(stack.run(sql))  # sqlparse tokenizes entire SQL string

For a query with 5000 UUIDs:

  • SQL string length: ~170,000 characters
  • Token count: ~15,000+ tokens
  • Each token processed by filters (indent, bold keywords, HTML escape)

The LRU cache doesn't help because each query with different parameters is a cache miss.

Steps to Reproduce

A minimal reproduction project is available:
https://github.com/kkm-horikawa/debug-toolbar-perf-issue

git clone https://github.com/kkm-horikawa/debug-toolbar-perf-issue.git
cd debug-toolbar-perf-issue
uv sync
uv run python manage.py migrate
uv run python manage.py runserver
# Visit http://127.0.0.1:8000/ and click on test links

Current Workaround

DEBUG_TOOLBAR_CONFIG = {
    'PRETTIFY_SQL': False,  # Disables ALL SQL formatting
}

This is suboptimal because it disables formatting for all queries, not just problematic ones.

Proposed Solution

I have submitted PR #2291 that:

  1. Adds SQL_PRETTIFY_MAX_LENGTH setting (default 50000) to skip formatting for long queries
  2. Catches SQLParseError from sqlparse >= 0.5.5 gracefully
  3. Shows informative message with SQL preview when formatting is skipped

This provides:

  • Normal formatting for typical queries
  • Graceful degradation for extreme cases
  • Configurable threshold

Related Issues

Environment

  • Python 3.11+
  • Django 5.0+
  • django-debug-toolbar 5.2.0 / 6.1.0
  • sqlparse 0.5.3 / 0.5.5+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions