#37287: Add Index on LogEntry.action_time to optimize admin dashboard performance
-------------------------------------+-------------------------------------
Reporter: Ali Rafiei | Type:
| Cleanup/optimization
Status: new | Component:
| contrib.admin
Version: dev | Severity: Normal
Keywords: | Triage Stage:
admin,index,logentry,performance | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Problem & Motivation
In high-traffic production environments, the django_admin_log table often
grows to millions of rows. Every time a user loads the main Django Admin
Index (dashboard) page, the framework displays the "Recent actions"
sidebar. This forces the following query to execute:
SELECT ... FROM "django_admin_log" ORDER BY
"django_admin_log"."action_time" DESC LIMIT 10;
Because LogEntry explicitly defines ordering = ['-action_time'] in its
Meta options but lacks any indexing on the action_time field, database
engines must perform a highly inefficient sequential table scan to
retrieve these 10 rows. This causes severe CPU spikes and long page-load
delays on large datasets, as highlighted in recent community discussions
(e.g., Django Forum thread #41943).
Historical Context & Precedent
The structural performance limitations of django_admin_log are well-
documented. Similar bottlenecks regarding missing indexes were flagged in
**Ticket #17659** and **Ticket #36414**.
While previous community efforts to index django_admin_log faced
roadblocks—specifically regarding the object_id column because MySQL
struggles to index unbounded text columns—**action_time is a standard
DateTimeField**. Adding an index here carries no cross-database
compatibility issues and is universally supported across PostgreSQL,
MySQL, SQLite, and Oracle.
Proposed Solution
To address this bottleneck, I propose adding an explicit descending index
on action_time directly to LogEntry.Meta.indexes (e.g.,
models.Index(fields=['-action_time'] and generate the corresponding core
migration for contrib.admin. This targets an un-bypassable query built
into Django's default UI and guarantees predictable performance scaling
for enterprise installations.
--
Ticket URL: <
https://code.djangoproject.com/ticket/37287>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.