githubEdit

SQL Debugging Guide

This guide explains how to debug SQL queries in the Gyrinx application, including logging configuration, performance analysis, and troubleshooting slow queries.

Overview

The application includes a comprehensive SQL logging system that captures:

  • All SQL queries executed by Django

  • Query execution times

  • Slow query analysis with PostgreSQL EXPLAIN plans

  • Separate logging for debugging vs. production

Quick Start

To enable SQL debugging, add these lines to your .env file:

# Enable SQL query logging
SQL_DEBUG=True

# Set slow query threshold (in seconds, default 0.01 = 10ms)
SQL_MIN_DURATION=0.01

# Optional: Enable EXPLAIN ANALYZE (executes queries!)
SQL_EXPLAIN_ANALYZE=False

Then restart your Django development server. SQL queries will be logged to:

  • logs/sql.log - All SQL queries

  • logs/slow_sql.log - Slow queries with EXPLAIN plans

Configuration Options

Environment Variables

Variable
Default
Description

SQL_DEBUG

False

Enable/disable SQL query logging

SQL_MIN_DURATION

0.01

Threshold for slow queries (seconds)

SQL_EXPLAIN_ANALYZE

False

Add ANALYZE to EXPLAIN (executes SELECT queries!)

SQL_EXPLAIN_DB_ALIAS

default

Database alias for EXPLAIN queries

Log Files

All SQL logs are written to the logs/ directory:

  • sql.log: Complete SQL query log

    • Includes all queries when SQL_DEBUG=True

    • Shows query text, parameters, and execution time

    • Rotates at 10MB, keeps 5 backup files

  • slow_sql.log: Slow query analysis

    • Only queries exceeding SQL_MIN_DURATION

    • Includes PostgreSQL EXPLAIN output

    • Shows query plan and estimated costs

    • Rotates at 10MB, keeps 5 backup files

Common Use Cases

1. Finding N+1 Query Problems

Enable SQL debugging and look for repeated patterns in sql.log:

If you see hundreds of similar queries, you likely have an N+1 problem. Use select_related() or prefetch_related() to fix it.

2. Identifying Slow Queries

Set a low threshold to catch all potentially slow queries:

Look for queries with:

  • Sequential scans on large tables

  • Missing indexes

  • Complex joins

  • Large result sets

3. Analyzing Query Plans

The slow query log includes EXPLAIN output. Key things to look for:

  • Seq Scan: Table scan, slow on large tables

  • Index Scan: Using an index, generally good

  • cost: First number is startup cost, second is total cost

  • rows: Estimated number of rows

4. Query Performance Comparison

To compare query performance with different approaches:

Warning: SQL_EXPLAIN_ANALYZE=True executes SELECT queries twice (once for EXPLAIN ANALYZE, once for the actual query).

5. Debugging Specific Views

To debug SQL queries for a specific view:

Understanding the Log Format

sql.log Format

  • DEBUG: Log level

  • 2025-08-20 07:14:21,426: Timestamp

  • utils: Logger name

  • 46103: Process ID

  • 8350441664: Thread ID

  • (0.005): Query execution time in seconds

  • SELECT...: The SQL query

  • args=: Query parameters

  • alias=: Database alias

slow_sql.log Format

Includes the same query information plus the PostgreSQL EXPLAIN output showing the query execution plan.

Best Practices

  1. Development Only: Keep SQL_DEBUG=False in production to avoid performance impact and large log files.

  2. Threshold Tuning: Start with a higher threshold (0.1 seconds) and gradually lower it as you optimize queries.

  3. Regular Monitoring: Check slow_sql.log regularly during development to catch performance issues early.

  4. Index Analysis: Use EXPLAIN output to identify missing indexes:

  5. Query Optimization: Common optimizations based on EXPLAIN:

    • Use select_related() for foreign keys

    • Use prefetch_related() for many-to-many and reverse foreign keys

    • Use only() or defer() to limit fields

    • Use exists() instead of count() for existence checks

Troubleshooting

Logs Directory Not Created

If the logs directory doesn't exist, the system will try to create it. If that fails, it falls back to the system temp directory. Check the Django logs for:

Empty Log Files

If log files are empty:

  1. Verify SQL_DEBUG=True in .env

  2. Restart the Django server after changing settings

  3. Check that queries are actually being executed

  4. Verify file permissions on the logs directory

EXPLAIN Errors

If you see [EXPLAIN ERROR: ...] in slow_sql.log:

  • The query might not be a SELECT statement (EXPLAIN only works with SELECT)

  • The query might be too complex for automatic EXPLAIN

  • Try running the query manually with EXPLAIN in manage shell

Performance Impact

SQL logging has minimal performance impact, but:

  • File I/O for logging can slow down high-traffic applications

  • SQL_EXPLAIN_ANALYZE=True doubles SELECT query execution

  • Log rotation happens at 10MB, which may cause brief pauses

Advanced Configuration

Custom Slow Query Threshold per View

You can temporarily adjust the threshold for specific code:

Analyzing Log Files

Use command-line tools to analyze patterns:

Implementation Details

The SQL logging system is implemented in gyrinx/settings_dev.py:

  1. SlowQueryFilter: Filters queries based on execution time

  2. ExplainFileHandler: Custom handler that adds EXPLAIN output

  3. Logging Configuration: Configures Django's database backend logger

The system hooks into Django's database layer to capture all SQL queries automatically, requiring no changes to application code.

Last updated