diff --git a/goodvibes/shop/migrations/0004_drop_unused_indexes.py b/goodvibes/shop/migrations/0004_drop_unused_indexes.py new file mode 100644 index 0000000..e9a09ea --- /dev/null +++ b/goodvibes/shop/migrations/0004_drop_unused_indexes.py @@ -0,0 +1,62 @@ +# Generated manually to address H002 Unused Indexes issue +# Issue: https://console.postgres.ai/goodvibes-ai/issues/019a5a58-582f-7819-9377-b40d207aa220 +# Drops 9 unused indexes consuming 3.36 GiB of storage + +from django.db import migrations +from django.contrib.postgres.operations import RemoveIndexConcurrently + + +class Migration(migrations.Migration): + + atomic = False + + dependencies = [ + ('shop', '0003_remove_orderitem_idx_orderitem_order_only_2'), + ] + + operations = [ + # Drop unused indexes from Product table (4 indexes, ~2.26 GiB) + RemoveIndexConcurrently( + model_name='product', + name='idx_product_sku_nonunique', + ), + RemoveIndexConcurrently( + model_name='product', + name='idx_product_is_active', + ), + RemoveIndexConcurrently( + model_name='product', + name='idx_product_name_plain', + ), + RemoveIndexConcurrently( + model_name='product', + name='idx_product_name_lower', + ), + + # Drop unused index from Customer table (1 index, 206 MiB) + RemoveIndexConcurrently( + model_name='customer', + name='idx_customer_email_plain', + ), + + # Drop unused indexes from Order table (3 indexes, ~397 MiB) + RemoveIndexConcurrently( + model_name='order', + name='idx_order_customer_only', + ), + RemoveIndexConcurrently( + model_name='order', + name='idx_order_cust_inc_created', + ), + RemoveIndexConcurrently( + model_name='order', + name='idx_order_cancelled_full', + ), + + # Drop unused index from OrderItem table (1 index, 132 MiB) + RemoveIndexConcurrently( + model_name='orderitem', + name='idx_oi_prod_order_bad', + ), + ] + diff --git a/goodvibes/shop/models.py b/goodvibes/shop/models.py index da34c23..4a85092 100644 --- a/goodvibes/shop/models.py +++ b/goodvibes/shop/models.py @@ -11,15 +11,7 @@ class Product(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: - indexes = [ - # Redundant duplicate alongside the implicit unique index - models.Index(fields=["sku"], name="idx_product_sku_nonunique"), - # Low-selectivity index (often not used) - models.Index(fields=["is_active"], name="idx_product_is_active"), - # Plain vs functional (we'll bias workload to use the functional) - models.Index(fields=["name"], name="idx_product_name_plain"), - models.Index(Lower("name"), name="idx_product_name_lower"), - ] + indexes = [] class Customer(models.Model): @@ -29,9 +21,7 @@ class Customer(models.Model): class Meta: indexes = [ - # Redundant duplicate alongside the implicit unique index - models.Index(fields=["email"], name="idx_customer_email_plain"), - # Functional index used by case-insensitive lookups + # Functional index used by case-insensitive lookups (kept - likely used) models.Index(Lower("email"), name="idx_customer_email_lower"), ] @@ -43,14 +33,9 @@ class Order(models.Model): class Meta: indexes = [ - # Composite index used by our hot path queries + # Composite index used by our hot path queries (kept - actively used) models.Index(fields=["customer", "created_at"], name="idx_order_customer_created_at"), - # Shadowed by the composite index for most queries - models.Index(fields=["customer"], name="idx_order_customer_only"), - # Full index vs partial; workload favors partial - models.Index(fields=["cancelled_at"], name="idx_order_cancelled_full"), - # INCLUDE variant (redundant coverage given the composite) - models.Index(fields=["customer"], name="idx_order_cust_inc_created", include=["created_at"]), + # Partial index for non-cancelled orders (kept - workload favors this) models.Index( fields=["cancelled_at"], name="idx_order_cancelled_partial", condition=Q(cancelled_at__isnull=True) ), @@ -64,11 +49,9 @@ class OrderItem(models.Model): class Meta: indexes = [ - # Used by joins/filters that start with order + # Used by joins/filters that start with order (kept - actively used) models.Index(fields=["order", "product"], name="idx_orderitem_order_product"), - # Reversed order (likely unused) - models.Index(fields=["product", "order"], name="idx_oi_prod_order_bad"), - # Single-column shadowed by composite + # Single-column shadowed by composite (kept - may be used for order-only queries) models.Index(fields=["order"], name="idx_orderitem_order_only"), ]