📌 Indexes in EF Core

Indexes are one of the most powerful tools for query performance tuning.

In Entity Framework Core (EF Core), indexes help:

⚡ Speed up lookups, filtering, and sorting
🔒 Enforce uniqueness
🏢 Support multi-tenant and domain-specific rules

This guide walks through everything you need to know — from the basics to advanced scenarios — with real-world code samples and best practices.


✅ What is an Index in EF Core?

An index is a database object that allows the database to locate rows faster.

Use .HasIndex() → to create indexes via Fluent API Use .IsUnique() → to enforce uniqueness EF Core automatically creates indexes for foreign key columns

✅ Defining Indexes in EF Core

TypeDescription
Basic Index Creates a non-unique index on the Name column.
Unique Index Ensures no two rows share the same Sku (enforced at the DB level).
Composite Index (Multi-Column) Used when queries filter on multiple fields together.
Example: WHERE Name='Laptop' AND Category='Electronics'
Shadow Property Index Indexes a property not defined in the C# model.
Custom Index Name Useful when aligning with existing database conventions.

✅ Filtered Indexes (Manual SQL via Migrations)

EF Core does not support filtered indexes via Fluent API. Use raw SQL in migrations.

Common Use Cases:

  • Enforce uniqueness only for active rows (IsActive = 1)
  • Allow multiple NULLs, enforce uniqueness when NOT NULL:
CREATE UNIQUE INDEX IX_Unique_Email ON Users(Email) WHERE Email IS NOT NULL;

✅ Data Integrity with Indexes

MethodPurpose
.HasIndex().IsUnique() Creates a unique index (good for queries)
.HasAlternateKey() Creates a unique constraint (FK principal)

👉 Use .HasAlternateKey() when the column is involved in relationships.
👉 Use .HasIndex().IsUnique() for query optimization + uniqueness.


✅ Performance Considerations

✔️ Benefits❌ Downsides
  • Improves read/query speed
  • Crucial for large datasets or frequent filters
  • Slows down writes (INSERT, UPDATE, DELETE)
  • Consumes extra disk space
  • Too many indexes → may confuse the optimizer

👉 Best Practice: Only index columns you frequently filter, sort, or join on.


✅ Common Scenarios & EF Core Solutions

ScenarioEF Core Code
Single property index.HasIndex(p => p.Name)
Unique value.HasIndex(p => p.Sku).IsUnique()
Composite index.HasIndex(p => new { p.Name, p.Category })
Unique + nullable columnmigrationBuilder.Sql(...) (filtered index)
Shadow property index.HasIndex("ShadowPropertyName")
Only one active record per usermigrationBuilder.Sql(... WHERE IsActive=1)
Custom index name.HasDatabaseName("IX_Custom_Name")

✅ Frequently Asked Questions (FAQs)

QuestionAnswer
Can EF Core create multiple indexes on the same column?✅ Yes, but duplicates are prevented.
Does EF Core support index hints?❌ No. Use FromSqlRaw() for raw SQL with index hints.

Difference between .HasIndex().IsUnique() and .HasAlternateKey():

Feature.HasIndex().IsUnique().HasAlternateKey()
TypeUnique IndexUnique Constraint
Used for FKs?❌ No✅ Yes
Performance✅ Optimized for queries❌ Slightly heavier
Identity/Relationships❌ Not entity identity✅ Used for identity & FKs

🔄 Advanced Indexing Scenarios

FeatureSupport & Example
Clustered / Non-clustered✅ SQL Server (via migration SQL)
Covering Index (INCLUDE)✅ Use raw SQL (migrationBuilder.Sql(...))
Partial Index✅ PostgreSQL via raw SQL
JSON Column Indexing✅ Provider-specific (Postgres, SQL Server)
Descending Index (EF 7+).IsDescending(true, false)

📊 Quick Reference – Index Types

TypeSupported?Example
Single-column Index✅ Yes.HasIndex(p => p.Name)
Composite Index✅ Yes.HasIndex(p => new { p.Name, p.Category })
Unique Index✅ Yes.HasIndex(p => p.Sku).IsUnique()
Shadow Property Index✅ Yes.HasIndex("Sku")
Custom Index Name✅ Yes.HasDatabaseName("IX_Custom")
Filtered Index⚠️ ManualmigrationBuilder.Sql(...)
Covering Index⚠️ ManualmigrationBuilder.Sql(...)
Clustered Index⚠️ ManualSQL Server migration SQL
Descending Index✅ EF 7+.IsDescending(true, false)
Partial Index⚠️ ManualPostgreSQL raw SQL

📌 Key Takeaways

  • Use .HasIndex() → to define indexes
  • Use .IsUnique() → to enforce uniqueness
  • Use .HasAlternateKey() → when property acts as a principal key
  • Use filtered indexes → for conditional uniqueness (nullable fields, active-only rows)
  • Avoid over-indexing → balance read performance vs write efficiency

🔑 Final Thoughts

Indexes are easy to implement but extremely powerful for performance and integrity.

A solid indexing strategy can:

  • ✅ Boost query performance
  • ✅ Enforce domain-specific rules
  • ✅ Scale with your data

👉 Golden Rule: Index what you query — not what you hope you might query.

Comments

Popular posts from this blog

Factory Method Design Pattern in .NET — Real-Time Finance Example

Logging in .NET Core: Built-in Logging vs Serilog with Full Implementation Guide

Implementing Single Sign-On (SSO) in .NET Core and Angular