SNIReadSyncOverAsync
performance issue
duplicate
troubleshooting
SQL Server

SNIReadSyncOverAsync Performance issue

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

SNIReadSyncOverAsync showing up as a performance hotspot usually means synchronous database reads are occurring on top of an asynchronous network stack. In practice, that is a sign that your application is blocking threads during I/O, which reduces throughput and increases latency under load.

What the Name Is Telling You

The name itself is a clue:

  • 'SNI refers to the SQL Server network layer.'
  • 'Read means data is being read from the database connection.'
  • 'SyncOverAsync suggests synchronous waiting over an asynchronous implementation path.'

That combination is usually not what you want in a high-concurrency application. It often means a thread is waiting instead of letting I/O complete naturally through async flow.

Why Sync-Over-Async Hurts

When you block synchronously on database I/O, you pay in several ways:

  • More threads are tied up waiting.
  • Thread-pool pressure increases under load.
  • Request latency grows.
  • Scalability drops even if the database is healthy.

This is why the hotspot matters. It is not just a cosmetic profiler entry. It often points to a real throughput bottleneck.

Typical Causes in Application Code

A common pattern is mixing asynchronous APIs with synchronous waiting, such as:

csharp
var result = command.ExecuteReaderAsync().Result;

Or:

csharp
var result = command.ExecuteReaderAsync().GetAwaiter().GetResult();

Or simply using synchronous ADO.NET calls everywhere in a workload that should scale asynchronously.

The fix is usually not inside SNI itself. The fix is higher up in the application call chain.

Prefer Async All the Way Through

If the request path is meant to be asynchronous, keep it asynchronous from the controller or service layer down to the database call.

csharp
1using System.Data.SqlClient;
2
3public async Task<List<string>> LoadNamesAsync(string connectionString)
4{
5    var names = new List<string>();
6
7    await using var connection = new SqlConnection(connectionString);
8    await connection.OpenAsync();
9
10    await using var command = new SqlCommand("SELECT Name FROM Users", connection);
11    await using var reader = await command.ExecuteReaderAsync();
12
13    while (await reader.ReadAsync())
14    {
15        names.Add(reader.GetString(0));
16    }
17
18    return names;
19}

The important part is not just ExecuteReaderAsync. It is the end-to-end async flow.

When Synchronous Calls Are Still Acceptable

Synchronous database calls are not automatically wrong. In a low-concurrency console tool or one-off batch script, sync code may be fine. The performance issue becomes meaningful when the application is serving many concurrent requests or when thread blocking becomes a bottleneck.

So the real question is workload shape, not ideological purity.

Diagnose Before You Guess

If this hotspot appears in profiling, check:

  • Whether request handlers are truly async.
  • Whether any .Result, .Wait(), or .GetAwaiter().GetResult() calls exist.
  • Whether synchronous ADO.NET APIs are being used in throughput-sensitive paths.
  • Whether the database itself is slow, which can amplify the thread-blocking cost.

The profiler name points to sync-over-async behavior, but the application architecture determines how harmful it becomes.

Common Pitfalls

  • Calling async database APIs and then blocking on them synchronously.
  • Assuming that one Async method name makes the whole path asynchronous.
  • Blaming SQL Server immediately when the real issue is application-side thread blocking.
  • Mixing sync and async code paths inconsistently under load.
  • Optimizing micro-details before confirming where the thread-blocking pattern actually starts.

Summary

  • 'SNIReadSyncOverAsync usually indicates synchronous waiting over asynchronous database I/O.'
  • The performance cost is thread blocking, especially under concurrency.
  • The usual fix is to use async all the way through the request path.
  • Blocking on async calls with .Result or .Wait() is a common cause.
  • Treat the hotspot as a design signal, not just a low-level library curiosity.

Course illustration
Course illustration

All Rights Reserved.