The data has been transferred, the application connects, and the first functional tests were successful. Even so, saving takes longer in day-to-day operation. Or the import no longer finishes within its time window, even though the new environment has a similar number of vCores as the old one.
Three questions are decisive for the investigation: Which operation has become slower? What has changed in its database work? And where is additional time added?
This diagnostic path helps you answer these questions one after another. It applies to SQL Server on Azure VMs, Azure SQL Managed Instance and Azure SQL Database. The measurement sources and options for intervention differ by platform; the approach begins with the same business transaction.
The quickest way in: classify an observation
What are you observing? Choose the matching card; it leads to the first step.
An operation takes longer in the application, but the individual SQL calls seem fast
Start here Steps 1 and 5: measurement boundary, number of calls and network path
Go to Step 1 →Individual queries have become noticeably more expensive since the switch
Start here Steps 2 and 4: comparable executions, plans and data access
Go to Step 2 →Many operations become slow at peak time
Start here Steps 2 to 4: load volume, resources and mutual interference
Go to Step 2 →CPU looks unremarkable, but write processing stays slow
Start here Steps 3 and 4: log/IO limits, transactions and blocking
Go to Step 3 →Mainly the first call after a longer idle period is affected
Start here Step 5: connection setup, possibly serverless auto-resume, and warm-up
Go to Step 5 →There is hardly any data from the time before the switch
Start here Step 2: record the available limits and create a baseline for comparison today
Go to Step 2 →The observation determines where you start. It does not yet establish a cause.
Step 1: Name the slow work precisely
Choose one specific operation: saving an order, opening a list or running a particular import. Note the start, the end, the application involved and the business inputs. “The database is slow” is too vague to work with.
Next, clarify which time was measured. The response time in the application can include connection setup, several database calls, result transfer and further processing. The runtime of a SQL statement describes a different portion of that time.
- Response time in the application: from the start to the end of the entire operation.
- SQL measurement: only the runtime of one call at a time (1, 2, 3).
- In between: connection, transfer and processing in the application. In real applications, segments can overlap.
If an operation executes many database calls one after another, its response time can rise while the individual SQL calls stay about as fast. Conversely, a single expensive query can account for most of the time.
Record three values separately: the response time of the whole operation, the number of its database calls and the times measured on the database side. Overlapping or asynchronous work must be taken into account when assigning the times.
A measured difference between application time and statement time is not automatically pure network latency. Processing in the application, waiting for a connection or other services can contribute as well.
Step 2: Establish a fair comparison
A before/after comparison helps only if the work being compared is sufficiently similar. Therefore check:
- Data and inputs: the same business task, a comparable data volume and relevant parameter values.
- Load: calls per unit of time, work mix and concurrent processing.
- Configuration: source and target, version or service model, compatibility level and important settings.
- Time window: a common time base for application, SQL data and Azure metrics; changes and events with timestamps.
- Operating state: regular operation, first run after a restart or pause, ongoing maintenance and other special events.
Additionally compare the number of successful completions and the errors. A low measured utilization can also arise when many requests fail beforehand or wait on the application side.
Before old environment
- Operation
- Save order
- Data and parameters
- comparable volume, values notedmissing
- Calls
- number per operation countedmissing
- Concurrency
- work mix and parallel runs notedmissing
- Time window
- common time baseknown only roughly
- Operating state
- regular operationmissing
After Azure
- Operation
- Save order
- Data and parameters
- comparable volume, values noted
- Calls
- number per operation counted
- Concurrency
- work mix and parallel runs noted
- Time window
- common time base
- Operating state
- regular operationfirst run after pause Difference
Classify the result. Both cards describe the same work under similar conditions. Only now is it worth looking at response time, successful completions, errors and effort.
Clarify the difference first. A first run after a pause is not regular operation. Evaluate it separately or repeat the comparison under the same conditions.
Plan today’s comparison. Without data from before, the migration difference stays open. Compare a slow period with an unremarkable one today, as described below.
If the old baseline is missing
Preserve the data that is still available and write down what it can answer. Existing Query Store history, application logs or earlier operations reports can help. How informative they are depends on the period covered, how the data was collected and how comparable it is.
Missing data cannot be created retroactively. However, you can compare a period that is slow today with one that is unremarkable today, or check the same operation in a controlled way before and after a change. The finding then reads “improved under these current conditions.” That does not yet prove a complete explanation of the original migration difference.
Step 3: Consider the resources in the right frame
An Azure SQL environment has several possible performance limits. CPU is one of them. Data access, log throughput, memory or available execution capacity can also limit processing.
What matters is the frame of reference: A percentage metric refers to the resource and limit named in its definition. The utilization of a database does not automatically describe the utilization of the physical Azure hardware.
| Platform | Look at together | Typical checkpoint |
|---|---|---|
| SQL Server on an Azure VM | SQL measurements, guest operating system, VM metrics and disks | Do the VM or disks reach an IO/throughput limit? Does the SQL configuration fit the provisioned storage? |
| Azure SQL Managed Instance | Instance metrics, database load and SQL diagnostic data | Which databases or jobs draw on the shared instance, and which resource demands coincide in time? |
| Azure SQL Database | Database metrics, performance model and SQL diagnostic data | Which individual limit is reached in the problem window, such as CPU, data IO, log rate or worker threads? |
| SQL Database in an elastic pool | individual database and pool | Does the database limit, the pool limit or the shared load of several databases come into play? |
| SQL Database in Hyperscale | Database metrics, page server accesses and log generation rate | Do the pages come from the local cache or from the page server, and does the log generation rate limit throttle the write load? |
In Hyperscale, the data IO metric refers only to the local cache of the compute replica. Page accesses to the page servers do not appear there; Microsoft reports them in separate columns of DMVs, in the Query Store runtime statistics and in the execution plan. Throttled log generation shows up in wait types of the group RBIO_RG_*. A low data IO value therefore does not rule out slow data access in Hyperscale.
Which demand coincides in time in the problem window?
- CPUheadroom
- Data IOheadroom
- Log ratenear the limit
- Worker threadsheadroom
Schematic for a problem window with write load, not measured values. Right edge of each gauge: the limit of the selected performance model.
The combined load of several databases shares the pool limit.
Page access on a cache miss
Log generation rate (limit)
Simplified schematic without measured values and without fill levels. The arrows show where the compute replica requests pages and where it generates log.
Azure SQL Database: Consider database metrics, performance model and SQL diagnostic data together. Which individual limit is reached in the problem window? In the schematic, CPU has headroom and the log rate is near its limit.
SQL Server on an Azure VM: Consider SQL measurements, guest operating system, VM metrics and disks together. Do the VM or disks reach an IO/throughput limit? Does the SQL configuration fit the provisioned storage?
Azure SQL Managed Instance: Consider instance metrics, database load and SQL diagnostic data together. Which databases or jobs draw on the shared instance?
Azure SQL Database: Consider database metrics, performance model and SQL diagnostic data together. Which individual limit is reached in the problem window? In the schematic, CPU has headroom and the log rate is near its limit.
SQL Database in Hyperscale: Pages come from the buffer pool, the local cache or a page server. In the problem window, check page server reads and wait types of the group RBIO_RG_*; data IO % counts only the local cache.
SQL Database in an elastic pool: Consider the individual database and the pool separately. Does the database limit, the pool limit or the shared load of several databases come into play?
Pay attention to short peaks and to the aggregation of the metric. A smoothed average over a long period can hide a brief bottleneck. Therefore read CPU, IO or waits in the same problem window as the slow operations.
For write load, separating data IO from the transaction log is worthwhile. A bottleneck in the log path can slow down save or import operations while the CPU still has headroom. The appropriate next step follows from the combination of platform metrics, SQL wait behavior and affected operations.
Sources: Microsoft’s baseline recommendation for Azure VMs, MI monitoring and resource management in elastic pools; for Hyperscale, the performance diagnostics for Hyperscale.
Step 4: Check queries and mutual interference
Does the same work use more CPU, more logical reads or longer database runtimes after the switch? Or does more work arrive at the same time? These questions help separate causes from effects.
Use Query Store to trace a change
Query Store can show which queries and plans were captured in a period and how their aggregated runtime values have changed. First check whether the required history is available and whether the data capture is suitable for your question.
For executions that belong together in business terms, compare:
- execution count and work mix;
- CPU work and logical reads per execution;
- database runtime and, where captured, wait categories;
- plans used and the point in time of a change.
A new plan is a reason to investigate. Whether it explains the degradation becomes clear only through comparison with matching data, parameters and load conditions. Statistics and configuration changes also belong in this check.
Query Store aggregates runtime data in runtime statistics intervals. It is not a complete log of every user call. From an interval average, you can derive neither the exact course of an individual application error nor a correct 95th percentile of all user responses. For such questions you need suitable supplementary application or individual-event data.
One query with its plan, three intervals
- Execution count
- counted
- CPU per execution
- aggregated
- Runtime values
- aggregated
- Execution count
- counted
- CPU per execution
- aggregated
- Runtime values
- aggregated
- Execution count
- counted
- CPU per execution
- aggregated
- Runtime values
- aggregated
A single user call with its own response time or its own error. No automatic one-to-one assignment to an interval.
- Combining several intervals: take different execution counts into account.
- From interval averages, do not derive a 95th percentile of user responses.
If you combine values across several intervals, take their different execution counts into account. Simply averaging the interval averages can distort the result. When comparing separate systems, match queries by content and context; the numeric query and plan IDs alone are not a reliable identity across systems.
Source: Monitor performance by using the Query Store.
Investigate blocking and transactions
Operations can obstruct each other through locks in Azure as well. In the problem window, check who is waiting, which operation holds the required resource and how long the transaction in question stays open.
A slow transaction can trigger waiting in many other operations. High utilization is not a prerequisite for this. For example, the application may perform further work within a transaction or wait for the next interaction.
Waits help put things in context. Because of parallel and overlapping work, they are not consistently additive pieces of user response time. A large wait sum is therefore not the same as an equal number of seconds of additional waiting for an individual user.
For general diagnostic paths, we refer to our SQL Server performance guide. The measurement sources and permissions must each match the Azure platform.
Step 5: Check network paths, startup state and error recovery
Many small calls can multiply additional time
If the application stays at its previous location and the database moves, the communication path changes. For one large database call, this may be less noticeable than for a sequence of many small calls.
Illustrative calculation: An operation executes 100 database round trips serially. If each round trip takes an additional 10 milliseconds because of the changed path, this adds up to roughly one second of additional time in total. The calculation assumes these serial calls and the assumed additional round-trip time; it is not an Azure measurement and not a prediction for your application.
100 serial callsRound trips: 100
100 × 10 ms = 1,000 ms additional communication share in the teaching model
10 batched callsRound trips: 10
10 × 10 ms = 100 ms additional communication share in the teaching model
Assumption as in the text: The calls run serially, and each round trip takes an additional 10 ms; both rows use the same time scale. The values are not a measured Azure latency, not a total response time and not a guaranteed saving. Batching can change the SQL work and the semantics of an operation.
Check the actual number and sequence of calls. Possible starting points are where the application is placed, batching data access and avoiding unnecessary repetition. Whether such a change fits functionally and technically must be verified against the specific workflow.
Source: Microsoft’s tuning guidance for applications that communicate frequently.
Look at the first operation after an idle period separately
If the environment uses serverless, check the configured scaling and, where applicable, the auto-pause and auto-resume behavior. An automatically paused database needs time when it resumes. Warm-up of the environment can also affect the first operations.
Therefore separate the first connection after an idle period from regular operation. Check status events, connection attempts and the requirements of the application. Auto-pause is not available for every serverless configuration or in combination with other features; for Hyperscale serverless, it is in preview as of 27 October 2026.
In Hyperscale, the local cache comes into play. With provisioned compute, Microsoft keeps the cache of the high-availability replicas warmed up; with serverless, it does not. After a restart or a replica switch, the first read accesses may therefore go to the page servers more often.
Source: Serverless FAQ from Microsoft.
Make retries visible
An application can catch a transient connection fault and try to execute the operation again. From the user’s perspective, this may appear only as a longer response time. Without suitable logging, the retries remain invisible.
Check which errors occur, whether connections are re-established and how many attempts take place. Retries need suitable limits and must be matched to the error. For write operations, it must also be clarified whether the previous transaction already took effect and how duplicate processing can be prevented.
A higher timeout value alone does not explain the cause. It initially changes only how long an application waits for a result.
Step 6: Justify a change and verify its effect
Before the change, formulate a concrete expectation. For example: “After the index change, this query needs fewer logical reads” or “Batching the calls shortens the affected application operation under the same load.”
Next, define how the expectation will be verified. Use the same business operations and sufficiently similar conditions. Compare response time, successful completions, errors and the relevant resource demand. For critical processes, also take the remaining workload into account: A change should not speed up just one individual test while slowing down other important operations at the same time.
A larger configuration can help as an immediate action or as a limited comparison. If it improves the situation, an effect has initially been observed under the tested conditions. Which resource and which mechanism explain the improvement must be narrowed down further.
Next, evaluate the economic consequence. With fixed provisioned capacity, a more efficient query lowers the bill only when it leads to, for example, a suitably smaller configuration. For usage-based models, their specific billing rules apply. A measured technical improvement and a demonstrated change in cost are two separate results.
- Observationmany serial calls
- Hypothesischeck communication share
- Changebatch suitably
- Comparisoncompare the same operation
- Remaining questionWhich mechanism explains the effect?
Result of the comparison, recorded separately
Compare response time, successful completions, errors and resource demand for the same operation.
Stays open until a change in cost is demonstrated, for example through a suitably smaller configuration or the billing rules of a usage-based model.
Your findings sheet for the next check
With these details, “slow since Azure” becomes an investigation that can be worked on.
| Field | What you record |
|---|---|
| Affected operation | business task, application, relevant inputs |
| Problem window | start, end and time zone; comparison period |
| Platform | Azure VM, MI or SQL Database; sizing and, if applicable, pool/serverless |
| Observation | application time, errors, successful completions; the specific change |
| Database evidence | associated queries, available plans, execution count and effort |
| Platform evidence | relevant resource metrics for the same period, scaling/maintenance events |
| Open explanation | for example more round trips, higher effort per execution or blocking |
| Next check | a defined test with expected result and fallback path |
Findings sheet to fill in
Stays in this browser window: Nothing is sent or saved. The sheet is not connected to the contact form; copy the details into it yourself if needed. Please do not enter credentials, personal customer data or complete business data.
For an initial inquiry, the available key data is sufficient. Production credentials and complete SQL or business data do not belong in the contact form; we will agree on a suitable analysis access separately.
Frequently asked questions
CPU is low. Does that rule out Azure as the cause?
No. Check, among other things, data IO, log throughput, blocking, connection recovery and the measurement on the application side. Which of these explanations is relevant must emerge from your problem window.
We have the same number of vCores as before. Shouldn’t it be equally fast?
The number alone describes neither the entire platform nor the behavior of the workload. Storage, IO, service model and configuration can differ. What is meaningful is the comparison of the specific work and its resource requirements.
Should we increase the sizing first?
If operations are acutely at risk, a coordinated capacity change can be a sensible part of stabilization. Preserve the existing evidence where possible and document the point in time. For a lasting recommendation, check which bottleneck existed and what the change achieved.
Can we simply force the old execution plan?
A previously favorable plan can be a starting point. Its suitability must be checked for the current environment and relevant parameters. Even a short-term action on the plan needs a check of its effect and a later assessment of its cause and side effects.
Query Store does not contain the affected period. Can we still investigate?
Yes, with the data that exists and a clear limit on what the findings can state. Application logs, current SQL and platform metrics and a targeted comparison can enable the next step. For problems that occur again, suitable data capture is agreed on.
Sources and limits
The figures on this page are structural models and teaching examples. They contain no measured values from Azure environments or customer systems; the round-trip calculation rests solely on the stated assumptions.
Product limits change over time; this page reflects the status of 27 October 2026. It is based on public Microsoft documentation; it is not based on our own measurements in Azure environments. For a specific decision, check the information that is current at that time.
Sources from Microsoft (documentation reviewed on 27 October 2026): Baseline for SQL Server on Azure VMs · Monitor Managed Instance with Azure Monitor · Resource management in elastic pools · Monitor performance by using the Query Store · Tuning guidance for Azure SQL Database · Serverless FAQ · Transient connection faults and retry logic · Performance diagnostics for Hyperscale
Let us turn the symptom into a finding together
PSG combines SQL Server analysis with a view of the application and infrastructure. We help you classify the data you have, develop a verifiable explanation and verify the effect of an agreed change.