From c9716252f06110c3ddb1c2a346cda1e2e95e7d5a Mon Sep 17 00:00:00 2001 From: Trenton H <797416+stumpylog@users.noreply.github.com> Date: Mon, 20 Jul 2026 06:12:54 -0700 Subject: [PATCH] Performance: Add DB indexes for common query/sort patterns (#13167) Adds indexes on Document.checksum, Document.page_count, and a composite (owner, created) index on Document, plus composite (field, value_*) indexes on CustomFieldInstance for each typed value column. Benchmarked against a 100k-document / 200k-custom-field-instance SQLite dataset: Document.checksum lookups ~69x faster, page_count sort ~40x, owner+created list queries ~6x. CustomFieldInstance composite indexes show large gains (10-24x) on realistic narrow-selectivity queries matching the workflow scheduler and custom-field search code paths. --- .../migrations/0022_add_perf_indexes.py | 73 +++++++++++++++++++ src/documents/models.py | 12 ++- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/documents/migrations/0022_add_perf_indexes.py diff --git a/src/documents/migrations/0022_add_perf_indexes.py b/src/documents/migrations/0022_add_perf_indexes.py new file mode 100644 index 000000000..fe66e8c49 --- /dev/null +++ b/src/documents/migrations/0022_add_perf_indexes.py @@ -0,0 +1,73 @@ +# Generated by Django 5.2.16 on 2026-07-19 20:33 + +import django.core.validators +from django.conf import settings +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + dependencies = [ + ("documents", "0021_widen_workflow_integer_fields"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name="document", + name="checksum", + field=models.CharField( + db_index=True, + editable=False, + help_text="The checksum of the original document.", + max_length=64, + verbose_name="checksum", + ), + ), + migrations.AlterField( + model_name="document", + name="page_count", + field=models.PositiveIntegerField( + db_index=True, + help_text="The number of pages of the document.", + null=True, + validators=[django.core.validators.MinValueValidator(1)], + verbose_name="page count", + ), + ), + migrations.AddIndex( + model_name="customfieldinstance", + index=models.Index( + fields=["field", "value_date"], + name="documents_c_field_i_30b51d_idx", + ), + ), + migrations.AddIndex( + model_name="customfieldinstance", + index=models.Index( + fields=["field", "value_int"], + name="documents_c_field_i_d25ab0_idx", + ), + ), + migrations.AddIndex( + model_name="customfieldinstance", + index=models.Index( + fields=["field", "value_float"], + name="documents_c_field_i_c35174_idx", + ), + ), + migrations.AddIndex( + model_name="customfieldinstance", + index=models.Index( + fields=["field", "value_monetary_amount"], + name="documents_c_field_i_53ce4e_idx", + ), + ), + migrations.AddIndex( + model_name="document", + index=models.Index( + fields=["owner", "created"], + name="documents_d_owner_i_ec6ab3_idx", + ), + ), + ] diff --git a/src/documents/models.py b/src/documents/models.py index a77447512..c9b7109bc 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -217,6 +217,7 @@ class Document(SoftDeleteModel, ModelWithOwner): # type: ignore[django-manager- _("checksum"), max_length=64, editable=False, + db_index=True, help_text=_("The checksum of the original document."), ) @@ -234,7 +235,7 @@ class Document(SoftDeleteModel, ModelWithOwner): # type: ignore[django-manager- blank=False, null=True, unique=False, - db_index=False, + db_index=True, validators=[MinValueValidator(1)], help_text=_( "The number of pages of the document.", @@ -338,6 +339,9 @@ class Document(SoftDeleteModel, ModelWithOwner): # type: ignore[django-manager- ordering = ("-created",) verbose_name = _("document") verbose_name_plural = _("documents") + indexes = [ + models.Index(fields=["owner", "created"]), + ] constraints = [ models.UniqueConstraint( fields=["root_document", "version_index"], @@ -1190,6 +1194,12 @@ class CustomFieldInstance(SoftDeleteModel): ordering = ("created",) verbose_name = _("custom field instance") verbose_name_plural = _("custom field instances") + indexes = [ + models.Index(fields=["field", "value_date"]), + models.Index(fields=["field", "value_int"]), + models.Index(fields=["field", "value_float"]), + models.Index(fields=["field", "value_monetary_amount"]), + ] constraints = [ models.UniqueConstraint( fields=["document", "field"],