HomeNikola Knezevic

In this article

Banner

Efficient Similarity Search using Vector Indexes

02 Apr 2026
5 min

Special Thanks to Our Sponsors:

Sponsor Logo

EF Core is too slow? Discover how you can easily insert 14x faster (reducing saving time by 94%).

Boost your performance with our method within EF Core: Bulk Insert, update, delete and merge.

Thousands of satisfied customers have trusted our library since 2014.

👉 Learn more

Sponsor Newsletter

When we need semantic search over embeddings, vector similarity search is the natural tool. It finds items that are closest to a query vector using a distance metric such as cosine similarity or Euclidean distance.

I've written a dedicated blog on the basics, embeddings and VectorDistance() in EF Core 10 that you can read here if you want the full picture first, Vector Similarity Search in EF Core 10.

That approach is exact search. The database computes distance between the query vector and every row. That full scan gets slower as the table grows. Even with tuning, latency often stops matching what modern apps expect.

There is another path we will look at in this blog, approximate vector search, backed by vector indexes.

Approximate Nearest Neighbor (ANN) search looks for vectors that are close enough to the query without promising the single mathematically closest match. It relies on specialized structures and algorithms so the engine does not evaluate every row.

That introduces a deliberate speed vs accuracy trade-off. You may skip a marginally better match, but queries stay fast and scale far better. In most products, ranked results stay highly relevant while response times drop sharply.

Vector indexes are what make ANN practical. They organize embeddings so the server can jump to strong candidates instead of scanning the full table.

Getting Started

You'll need SQL Server 2025 (vector features and index types depend on that release) and the following package so the provider lines up with SQL Server's vector types.

shell
Install-Package Microsoft.EntityFrameworkCore.SqlServer

Register DbContext as usual. Map the embedding column to a fixed-size VECTOR type so dimensions match your model

csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Document>(entity =>
    {
        entity.Property(e => e.Embedding)
            .HasColumnType("VECTOR(1024)");
    });
}

A typical Document entity for search looks like this.

csharp
public sealed class Document
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public SqlVector<float> Embedding { get; set; }
}

To create a vector index, your table must have a clustered primary key on a single column of type INT.

Creating a Vector Index

Official docs show the HasVectorIndex() method but at the time of writing this blog, this method as well as the VectorSearch() method are not exposed in the EF Core API yet, they are still in development, so we create the index with raw SQL.

csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Document>(entity =>
    {
        entity.Property(e => e.Embedding)
            .HasColumnType("VECTOR(1024)");

        entity.HasVectorIndex(e => e.Embedding, "cosine")
    });
}

NOTE: Current vector index behavior treats the table as read-only while the index exists. Plan to bulk-load or finish writes first, then create the index. If you must change data later, you may need to drop the index, update rows, and recreate it.

Here is a DiskANN-style index with cosine distance.

sql
CREATE VECTOR INDEX vec_idx ON Documents(Embedding)
WITH (METRIC = 'cosine', TYPE = 'diskann');
GO

Choosing a distance metric matches what we already covered for exact search, vector distance functions in the earlier post. Align METRIC with how you embed and rank (for example cosine, euclidean or manhattan) so index semantics and query metrics stay consistent.

Vector Search with Indexes

EF Core will expose something like VectorSearch() on DbSet in the future, until that ships, we call SQL Server's VECTOR_SEARCH table-valued function from EF Core using SqlQueryRaw and parameters.

Results include a distance column for ranking, smaller values mean closer matches under the chosen metric.

The commented block shows the intended VectorSearch shape, the active code uses raw SQL.

csharp
app.MapPost("/api/search", async (
    string query,
    ApplicationDbContext db,
    IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator) =>
{
    var embeddingResult = await embeddingGenerator.GenerateAsync([query]);
    var queryVector = new SqlVector<float>(embeddingResult.Single().Vector);

    // This is what the code would look like with the new VectorSearch method,
    // but since it's not implemented yet, we will use raw SQL

    //var results = db.Documents
    //    .VectorSearch(b => b.Embedding, "cosine", queryVector, topN: 5)
    //    .ToListAsync();

    var sql = """
        SELECT TOP(3)
            t.id,
            t.title,
            t.content,
            s.distance
        FROM VECTOR_SEARCH(
            TABLE = dbo.Documents AS t,
            COLUMN = Embedding,
            SIMILAR_TO = @qv,
            METRIC = 'cosine',
            TOP_N = 5
        ) AS s
        ORDER BY s.distance;
        """;

    var param = new Microsoft.Data.SqlClient.SqlParameter("@qv", queryVector);

    var results = await db.Database
        .SqlQueryRaw<DocumentSearchResult>(sql, param)
        .ToListAsync();

    return Results.Ok(results);
});

Conclusion

Exact vector search is a solid starting point. Once volume grows, full scans become the bottleneck.

ANN search with vector indexes targets a different goal, fast and relevant results instead of exhaustive comparison on every row.

Use exact search when datasets are small or correctness demands optimal results. Move to approximate indexed search when latency and scale matter and slightly softer guarantees are acceptable.

If you want to check out examples I created, you can find the source code here:

Source Code

I hope you enjoyed it, subscribe and get a notification when new blog is up!

Subscribe

Stay tuned for valuable insights every Thursday morning.