diff --git a/api/core/db.py b/api/core/db.py new file mode 100644 index 000000000000..a97139188f1f --- /dev/null +++ b/api/core/db.py @@ -0,0 +1,5 @@ +from django.contrib.postgres.indexes import GinIndex + + +class UnrestrictedGinIndex(GinIndex): + max_name_length = 63 diff --git a/api/environments/identities/migrations/0003_add_idenity_identifier_gin_index.py b/api/environments/identities/migrations/0003_add_idenity_identifier_gin_index.py new file mode 100644 index 000000000000..f68556da1a17 --- /dev/null +++ b/api/environments/identities/migrations/0003_add_idenity_identifier_gin_index.py @@ -0,0 +1,47 @@ +# Generated by Django 4.2.18 on 2025-04-22 10:15 + +from django.contrib.postgres.operations import TrigramExtension +from django.db import migrations +import django.contrib.postgres.indexes +import django.db.models.functions.text + +from core.migration_helpers import PostgresOnlyRunSQL +import core.db + + +_create_index_sql = "CREATE INDEX CONCURRENTLY IF NOT EXISTS environments_identity_identifier_gin_idx ON environments_identity USING GIN (UPPER(identifier) gin_trgm_ops);" +_create_index_reverse_sql = ( + "DROP INDEX CONCURRENTLY IF EXISTS environments_identity_identifier_gin_idx;" +) + + +class Migration(migrations.Migration): + atomic = False + + dependencies = [ + ("identities", "0002_alter_identity_index_together"), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.AddIndex( + model_name="identity", + index=core.db.UnrestrictedGinIndex( + django.contrib.postgres.indexes.OpClass( + django.db.models.functions.text.Upper("identifier"), + name="gin_trgm_ops", + ), + name="environments_identity_identifier_gin_idx", + ), + ), + ], + database_operations=[ + TrigramExtension(), + PostgresOnlyRunSQL( + sql=_create_index_sql, + reverse_sql=_create_index_reverse_sql, + ), + ], + ), + ] diff --git a/api/environments/identities/models.py b/api/environments/identities/models.py index 9003fd65f3b0..9c812c141e32 100644 --- a/api/environments/identities/models.py +++ b/api/environments/identities/models.py @@ -1,11 +1,14 @@ import typing from itertools import chain +from django.contrib.postgres.indexes import OpClass from django.db import models from django.db.models import Prefetch, Q +from django.db.models.functions import Upper from django.utils import timezone from flag_engine.segments.evaluator import evaluate_identity_in_segment +from core.db import UnrestrictedGinIndex from environments.identities.managers import IdentityManager from environments.identities.traits.models import Trait from environments.models import Environment @@ -40,6 +43,12 @@ class Meta: # avoid any downtime. If people using MySQL / Oracle have issues with poor performance on the identities table, # we can provide them the SQL to add it manually in a small window of downtime. index_together = (("environment", "created_date"),) + indexes = [ + UnrestrictedGinIndex( + OpClass(Upper("identifier"), name="gin_trgm_ops"), + name="environments_identity_identifier_gin_idx", + ), + ] def natural_key(self): # type: ignore[no-untyped-def] return self.identifier, self.environment.api_key