SQL Server on an Azure VM — 8 cores, sluggish performance. The client wanted more cores. We tuned their indexing, fixed implicit conversions, and set up maintenance instead.
CPU usage dropped 20–30%.
We downsized the primary to 4 cores and used the freed budget to add a 4-core HA replica without increasing SQL licensing spend. Total monthly cost stayed roughly flat.
Key Takeaways
- Tune before you scale — fixing indexing and implicit conversions dropped CPU 20–30% on the same hardware.
- Table scans on large tables were the biggest offender — queries were scanning millions of rows to fetch tiny result sets.
- Implicit conversions silently killed index usage — data type mismatches often pushed SQL Server into scans because predicates stopped being sargable.
- Stale statistics caused bad cardinality guesses — the optimizer was building plans on data distributions that no longer reflected reality.
- The 8 cores got split, not expanded — 4 for primary, 4 for HA replica. Freed enough budget to add redundancy without increasing licensing spend.
The database was the bottleneck, not the hardware — after tuning, even 14-year-old application servers performed fine.
What We Found
The client was running SQL Server on an Azure VM (IaaS) — 8 cores, growing frustration. The assumption was straightforward: more cores, better performance.
We spent time investigating before recommending anything. We measured CPU usage and identified the worst queries using Query Store and the plan cache — so every improvement had a baseline to compare against.
The database had three compounding problems, all fixable without touching hardware. We also checked for plan instability (parameter sniffing), spills, and parallelism misconfiguration — the usual CPU multipliers — but indexing, conversions, and maintenance were the primary issues here.
Problem 1: Missing and Wrong Indexes
Scans aren’t always wrong — but in this workload, queries were scanning huge tables to fetch tiny result sets. The difference is enormous: a scan reads every row in the table, a seek goes directly to the rows it needs.
On a table with millions of rows, a single missing index can turn a 50-millisecond seek into a multi-second scan. Multiply that across dozens of queries running concurrently, and you have a server that looks CPU-starved but is actually just doing unnecessary work.
We analyzed the workload, identified the worst offenders through execution plans and DMV queries, and added the right indexes. The scan-on-large-tables problem disappeared.
Problem 2: Implicit Conversions
This one is subtle and easy to miss.
When data types don’t match between query parameters and table columns, SQL Server performs an implicit conversion. It silently converts one type to match the other. This often pushes SQL Server into scans (or at least far more reads) because the predicate stops being sargable. A perfectly good index sits there unused because the query is sending an nvarchar parameter against a varchar column, or int against bigint, or any other mismatch.
The execution plan won’t throw an error. Look for CONVERT_IMPLICIT in the plan — that’s the tell. Your CPU pays the price quietly. Here’s our deep dive on finding and fixing implicit conversions across your codebase.
We audited their stored procedures and application queries for type mismatches, fixed them at the source, and performance jumped.
Problem 3: Stale Statistics and Neglected Maintenance
Statistics were stale — bad cardinality guesses meant the optimizer was building execution plans based on data distributions that no longer reflected reality. Some indexes showed measurable fragmentation and page density issues — increasing logical reads and I/O.
SQL Server’s optimizer is good — but it’s only as good as the information it has. Feed it stale statistics and it’ll choose bad plans confidently.
We fixed stats first, then did targeted index maintenance where it actually mattered:
- Statistics updates on a schedule matched to their data change rate
- Index maintenance based on actual fragmentation levels and access patterns — not a blanket “rebuild everything nightly” approach
- Consistency checks during appropriate maintenance windows
The Result
After addressing all three issues, CPU usage dropped 20–30% on the same 8 cores. We measured before and after — same workload periods, same business cycle — so the improvement was real, not a quiet week.
That opened a conversation the client didn’t expect.
After tuning, we downsized the primary to 4 cores. That freed enough budget to add a 4-core HA replica without increasing SQL licensing spend (total monthly cost stayed roughly flat, depending on VM and storage choices).
They had redundancy they didn’t have before.
They approved immediately.
Related: How Real Workload Testing Cut Azure SQL Hyperscale Costs by 46% and Saved $86,000 a Year
Why Organizations Scale Hardware First
This pattern repeats across nearly every engagement. Performance is slow, so the request goes up for more cores, more RAM, a bigger VM.
It makes sense from an organizational perspective — infrastructure changes are faster to approve, easier to execute, and don’t require anyone to touch application code or database internals. You open a ticket, someone clicks a button, the VM gets bigger.
But it doesn’t fix the underlying problem. The same bad queries that were scanning tables on 8 cores will scan tables on 16 cores. They’ll scan faster, sure — but you’ve doubled your cloud spend to mask inefficiency.
The harder conversation is: your queries need work. Your indexing strategy needs attention. Your maintenance jobs either don’t exist or aren’t doing what you think they’re doing.
That conversation takes longer. The results last longer too.
The Hardware Question
In this case, the database was the bottleneck — not the application servers. The client’s app servers connecting to the database are 14 years old, running at 2.4 GHz. After tuning, even the old app tier was good enough.
When they eventually move to modern CPUs, they’ll have headroom to scale. But for now, the tuned database doesn’t need it.
Hardware matters — but it matters a lot less when your queries are efficient. A well-tuned database on modest hardware will outperform an untuned database on enterprise-grade infrastructure in most scenarios.
CPU Headroom After Tuning
After tuning, you want consistent headroom. If sustained CPU is consistently above 70–80% during normal peaks, you may have limited headroom for spikes or plan regressions.
If CPU is still high after tuning, either the workload genuinely needs more cores or there’s remaining optimization work to do.
After a core-count change, watch for plan changes — especially parallel plans. Don’t shotgun-recompile everything. Only recompile the few critical procedures if you see regressions, and do it in a controlled window.
Where to Start
If your SQL Server feels slow and the first instinct is “more cores”:
- Check for missing indexes. Look at execution plans for table scans on large tables. Query
sys.dm_db_missing_index_detailsfor the optimizer’s own recommendations — then validate them against your actual workload before creating anything. - Hunt implicit conversions. Query the plan cache for plans with
CONVERT_IMPLICITwarnings. Fix the data type mismatches at the application or stored procedure level. - Review maintenance. Are statistics being updated? Are indexes being maintained based on actual need? On many servers we see, the answer to all three is no.
- Check the usual CPU multipliers. Parameter sniffing, bad MAXDOP settings, low cost threshold for parallelism, and memory grant spills. Use wait stats to identify which of these is actually hurting you. These compound with bad indexing.
- Measure CPU after each fix. Don’t do everything at once and hope. Fix indexing, measure. Fix conversions, measure. Fix maintenance, measure. You need to know which changes moved the needle and by how much.
- Then decide on hardware. If CPU is still high after tuning, you have a genuine workload that needs more resources. Scale with confidence because you know you’re not throwing hardware at bad code.
Bottom Line
The client had 8 cores and wanted more. After tuning, they needed 4 — and used the savings to add high availability.
More cores mask problems. Better indexing, correct data types, and current statistics solve them. Start with the database before you scale the infrastructure.
Frequently Asked Questions
Should I tune queries before adding more CPU cores?
What are implicit conversions and why do they matter?
CONVERT_IMPLICIT in execution plans. Fix the data types at the source to restore seek efficiency.
How do I find missing indexes in SQL Server?
sys.dm_db_missing_index_details for the optimizer’s recommendations. Review execution plans for table scan operators on large tables returning small result sets. Focus on the queries with the highest cumulative CPU and read counts first — those deliver the biggest improvement per fix.
What CPU utilization should I target after tuning?
Can old hardware run SQL Server well after tuning?
Speak with a SQL Expert
In just 30 minutes, we will show you how we can eliminate your SQL Server headaches and provide operational peace of mind