Database performance is one of the most critical factors affecting the responsiveness of .NET applications. Even well-designed ASP.NET Core APIs can suffer from slow response times if SQL queries are inefficient. In many cases, the issue isn't SQL Server itself—it's how queries are written, indexed, or executed.
Performance tuning should focus on identifying the actual bottleneck rather than applying random optimizations. SQL Server provides powerful tools for analyzing execution plans, monitoring resource usage, and identifying expensive queries.
In this article, you'll learn a practical approach to troubleshooting SQL Server query performance and applying targeted optimizations that improve application responsiveness.
Recognizing Performance Problems
Slow queries typically manifest as:
High API response times
Long-running reports
Database CPU spikes
Blocking and deadlocks
Increased timeout exceptions
High disk I/O
Before optimizing, determine whether the problem originates from the database, application code, or infrastructure.
Start with the Execution Plan
The execution plan shows how SQL Server executes a query and is often the best place to begin troubleshooting.
It reveals operations such as:
Table scans
Index seeks
Index scans
Sort operations
Hash joins
Nested loop joins
A query performing a full table scan on a large table often indicates that an appropriate index is missing or the query isn't selective enough.
Rather than guessing, review the actual execution plan to understand where SQL Server spends most of its time.
Identify Expensive Queries
SQL Server's Query Store and Dynamic Management Views (DMVs) help identify queries consuming excessive resources.
Useful metrics include:
Execution count
Average duration
CPU usage
Logical reads
Physical reads
Memory consumption
Focus optimization efforts on queries that are both slow and frequently executed, as these typically have the greatest impact on application performance.
Use Appropriate Indexes
Indexes significantly reduce the amount of data SQL Server must scan.
For example, filtering by a frequently queried column:
CREATE INDEX IX_Products_CategoryId
ON Products(CategoryId);
Well-designed indexes can transform expensive table scans into efficient index seeks.
However, avoid creating indexes indiscriminately. Every additional index increases storage requirements and slows insert, update, and delete operations.
Select Only Required Columns
Avoid retrieving more data than necessary.
Instead of:
SELECT *
FROM Products;
Select only the required columns:
SELECT Id, Name, Price
FROM Products;
This reduces:
Network traffic
Memory usage
Disk I/O
The same principle applies when using Entity Framework Core—project only the fields your application actually needs.
Watch for Parameter Sniffing
Parameter sniffing occurs when SQL Server generates an execution plan based on the first parameter value it encounters.
For example:
EXEC GetOrdersByCustomer @CustomerId = 1;
If subsequent executions use significantly different parameter values, the cached execution plan may no longer be efficient.
Symptoms include:
Inconsistent query performance
Fast execution for some values
Slow execution for others
Understanding parameter sniffing helps explain why identical queries may behave differently under varying workloads.
Avoid Non-SARGable Queries
A query is SARGable (Search Argument Able) when SQL Server can efficiently use indexes.
Less efficient:
WHERE YEAR(OrderDate) = 2025
More efficient:
WHERE OrderDate >= '2025-01-01'
AND OrderDate < '2026-01-01'
Applying functions directly to indexed columns often prevents SQL Server from using available indexes effectively.
Minimize Blocking
Long-running transactions can block other queries, reducing overall throughput.
Good practices include:
Keep transactions short.
Commit work as soon as possible.
Avoid unnecessary locks.
Update only required rows.
Reducing transaction duration improves concurrency and minimizes contention.

Join the conversation! Your thoughts help the community grow.