Understanding Long Sync IO in SQL Server: Scheduler in Nonpreemptive Mode Longer Than 1000 ms

Understanding Long Sync IO in SQL Server: Scheduler in Nonpreemptive Mode Longer Than 1000 ms – SQLYARD

Understanding Long Sync IO in SQL Server: Scheduler in Nonpreemptive Mode Longer Than 1000 ms


Compatibility: This warning and the troubleshooting approach apply to SQL Server 2012 and later. There are no version-specific changes to this behavior in SQL Server 2025. The message, the underlying mechanics, and the diagnostic steps are the same across all supported versions. For the Always On AG-specific impact of these warnings see the SQLYARD article on Error 833 and Long Sync IO in Always On.

One of the more concerning messages in the SQL Server error log is:

Long Sync IO: Scheduler <n> had <x> Sync IOs in nonpreemptive mode longer than 1000 ms

This message often appears alongside blocking complaints, slow performance, or application timeouts and commonly raises the question: is this a storage issue or a code issue?

The short answer is that the message confirms a serious I/O stall occurred but does not identify the root cause. In many environments, especially after a deployment or data growth event, this warning can become part of the system’s new steady state. Understanding what it means and how to diagnose it is what this article covers.

What the Message Actually Means

This warning indicates that a SQL Server worker thread issued a synchronous I/O request and waited longer than 1,000 milliseconds for the operating system to complete it. SQL Server logs the message as a signal that its I/O subsystem is experiencing stalls well beyond what normal operation should produce. The target context switch time for a SQL Server scheduler is around 4 ms, making 1,000 ms a significant overshoot.

  • The I/O is synchronous: the thread is blocked, not asynchronously waiting in the background
  • The thread is in nonpreemptive mode: SQL Server cannot interrupt it or yield to other work
  • The scheduler is effectively stalled: no other work can be dispatched on that scheduler while it waits
  • Other sessions pile up: any work queued behind that scheduler must wait until the I/O completes
  • This is not a wait statistic: it is a safety warning written to the error log when SQL Server detects an abnormally long kernel-level wait

Never ignore Long Sync IO messages. They confirm that real I/O stalls occurred and that the SQL Server scheduler was disrupted. The message does not explain why, but the fact that it appeared is not negotiable. Something took over a second to complete an I/O that should complete in single-digit milliseconds.

Why Nonpreemptive Mode Matters

SQL Server uses cooperative scheduling, not preemptive OS scheduling. Worker threads normally yield voluntarily so other threads can run. Nonpreemptive mode is an exception: it occurs when a worker executes code that directly calls the operating system, such as reading or writing a file. While in this state:

  • SQL Server cannot interrupt the thread; it must wait for the OS call to return
  • The scheduler cannot dispatch other work: the owned scheduler is frozen
  • Blocking chains grow quickly: sessions waiting for locks behind that scheduler keep accumulating
  • The effect is multiplied under load; a single stalled scheduler on a busy server can back up dozens of waiting sessions

This is by design. SQL Server must make synchronous OS calls for certain I/O operations. But it is also why a storage subsystem that is merely slow can produce blocking symptoms that look far more severe than the latency numbers alone would suggest.

Blocking vs I/O: How They Amplify Each Other

Blocking and I/O slowness are related but not the same thing. Understanding the relationship is critical for diagnosing these symptoms correctly.

  • Blocking occurs when sessions wait on locks held by other sessions
  • I/O delays extend the duration of transactions: a transaction that writes slowly holds its locks for longer
  • Longer lock hold times mean blocking becomes more severe and more visible to end users
  • Slow I/O does not usually cause blocking directly; it amplifies it by extending transaction lifetime

Long Sync IO messages often appear at exactly the same time as blocking complaints even though the blocking itself is lock-based. The I/O slowness is not the lock holder; it is the reason the lock holder is taking so long to finish its work. Fix the I/O and the blocking often resolves itself.

PAGEIOLATCH_* waits represent time spent waiting for physical data page reads from disk. WRITELOG waits represent time spent waiting for transaction log I/O to complete. Both contribute to extended transaction durations and therefore extended lock hold times.

Is This Code or Storage?

The correct answer is often both, but not equally. The distinction matters because the fix is different in each case.

Storage Is More Likely the Driver When

  • OS or SAN latency is consistently above SLA thresholds
  • Storage queue depth is persistently saturated
  • Multiple systems on the same storage show the same symptoms
  • The issue occurs independently of workload changes
  • Latency is elevated even during off-peak periods

Code or Workload Is More Likely the Driver When

  • A recent deployment increased write volume
  • New data loads increased transaction size or frequency
  • Index usage changed from seek to scan
  • Logging pressure increased after a schema change
  • Transactions became longer or less efficient

When Long Sync IO messages continue to appear weeks after a permanent code or load change, the question is no longer what changed; it is whether the platform can sustain the new steady workload. At that point two paths lead to different remediation choices:

If Storage Latency Is Within Acceptable Limits

  • Reduce I/O demand through query optimization
  • Improve index coverage to reduce scan-based reads
  • Reduce transaction scope or split large batch operations
  • Review logging pressure: minimize unnecessary writes

If Storage Latency Exceeds Acceptable Limits

  • Increase storage throughput or IOPS allocation
  • Move the transaction log to a dedicated faster volume
  • Review backup, snapshot, and maintenance overlap
  • Consider NVMe or dedicated log disk for write-heavy workloads

The error log message alone cannot choose the fix. Metrics are needed: SQL Server I/O latency figures, OS-level disk counters, and storage queue depth. These are needed before deciding whether to optimize the workload or upgrade the storage. Acting without data leads to changes that solve nothing.

Additional Cause: Idle Sessions Holding Open Transactions

A less obvious contributor to Long Sync IO symptoms is sessions that are idle but holding an open transaction. These sessions are not actively running. They appear quiet in sys.dm_exec_requests but they are keeping transactions open. Other sessions pile up behind those held locks, and the blocked work continues generating WRITELOG waits and I/O pressure as it retries or queues.

Common causes include a missing COMMIT or ROLLBACK, a user who opened a transaction and walked away, or connection pooling holding a transaction open longer than intended.

Check for Open Transactions

-- Confirm open transactions exist on the instance
DBCC OPENTRAN;

Find Idle Sessions with Open Transactions

SELECT
    s.session_id,
    s.login_name,
    s.host_name,
    s.program_name,
    s.status,
    r.blocking_session_id,
    at.transaction_begin_time,
    DATEDIFF(MINUTE, at.transaction_begin_time, GETDATE()) AS tran_age_min,
    t.text                                                  AS last_sql_text
FROM sys.dm_exec_sessions                   s
LEFT JOIN sys.dm_exec_requests              r  ON s.session_id     = r.session_id
LEFT JOIN sys.dm_tran_session_transactions  st ON s.session_id     = st.session_id
LEFT JOIN sys.dm_tran_active_transactions   at ON st.transaction_id = at.transaction_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE s.is_user_process = 1
  AND at.transaction_begin_time IS NOT NULL
ORDER BY tran_age_min DESC;
What to look for: Sessions with status = 'sleeping' and a large tran_age_min value are holding open transactions without doing active work. Any session idle for several minutes with an uncommitted transaction is a candidate for investigation. The fix is almost always application-side: ensure every transaction is committed or rolled back promptly, and avoid wrapping multiple statements in an explicit transaction unless absolutely necessary.

Workshop: Classifying Long Sync IO in a Steady Load System

Goal: Determine whether continued Long Sync IO events indicate a workload capacity problem, a storage capacity problem, or idle sessions amplifying I/O pressure so the right fix can be applied.

This walkthrough assumes the Long Sync IO messages continue to appear, the code and data load are now permanent, and the question is whether the system can sustain the new load.

1

Capture Timestamps of Long Sync IO Messages

Start with the error log. The time window they cluster in is what every subsequent step uses for correlation.

-- Read Long Sync IO messages from the current error log
EXEC sys.xp_readerrorlog 0, 1, 'Long Sync IO';

-- Read from the previous error log (after a restart)
EXEC sys.xp_readerrorlog 1, 1, 'Long Sync IO';
What to record: Date and time of each message. Whether they cluster during business hours or peak load windows. Whether multiple messages appear close together: a cluster within seconds indicates a scheduler stall, not an isolated incident. The time window identified here becomes the reference window for steps 2 through 6.
2

Check Average I/O Latency Inside SQL Server

Run this during or immediately after the problem window. This is SQL Server’s own view of storage performance, which is the most direct evidence of whether I/O is slow from the database engine’s perspective.

-- File-level I/O latency from SQL Server's perspective
SELECT
    DB_NAME(vfs.database_id)                                AS database_name,
    mf.name                                                 AS file_name,
    mf.type_desc,
    vfs.num_of_reads,
    vfs.io_stall_read_ms  / NULLIF(vfs.num_of_reads,  0)   AS avg_read_ms,
    vfs.num_of_writes,
    vfs.io_stall_write_ms / NULLIF(vfs.num_of_writes, 0)   AS avg_write_ms,
    vfs.io_stall_read_ms + vfs.io_stall_write_ms           AS total_io_stall_ms
FROM sys.dm_io_virtual_file_stats(NULL, NULL)               vfs
JOIN sys.master_files                                        mf
    ON vfs.database_id = mf.database_id
   AND vfs.file_id     = mf.file_id
ORDER BY total_io_stall_ms DESC;

A concrete example of what concerning output looks like:

DatabaseFile NameTypeavg_read_msavg_write_ms
tempdbtempdevROWS8530
Salessales_logLOG2114
Ordersorders_dataROWS224

In this example TempDB is read-heavy and underperforming, likely on slow or shared storage. The Sales log at 114 ms write latency is the most urgent: transaction log writes at that latency will produce WRITELOG waits and extend every transaction’s commit time. Move TempDB to SSD or a separate LUN. Move the Sales log file to dedicated fast storage and enable Instant File Initialization to reduce growth stall duration.

How to read this: Look at log files first, as they are the most write-sensitive. Sustained average write latency above 20 ms is concerning for OLTP workloads; anything above 50 ms needs immediate attention. Good averages with occasional extreme spikes point to burst saturation rather than sustained degradation. These are cumulative since the last SQL Server restart. Run the query at the start of a window, then again at the end, and compare the delta for a more accurate picture of the problem period.
3

Identify Dominant Wait Types

This confirms whether SQL Server is primarily waiting on data file reads or transaction log writes.

SELECT
    wait_type,
    waiting_tasks_count,
    wait_time_ms,
    wait_time_ms / NULLIF(waiting_tasks_count, 0) AS avg_wait_ms
FROM sys.dm_os_wait_stats
WHERE wait_type LIKE 'PAGEIOLATCH%'
   OR wait_type = 'WRITELOG'
   OR wait_type = 'ASYNC_IO_COMPLETION'
ORDER BY wait_time_ms DESC;
How to interpret:
  • WRITELOG dominating: transaction log write pressure. Focus on the LDF file, logging volume, and transaction batch sizes.
  • PAGEIOLATCH_SH or PAGEIOLATCH_EX dominating: data file read pressure. Focus on MDF/NDF files, missing indexes, and scan-heavy queries.
  • ASYNC_IO_COMPLETION elevated: backup or large file operation overlap with peak workload.
  • High avg_wait_ms confirms sustained pressure rather than rare spikes.
4

Check for Idle Sessions Holding Open Transactions

Before correlating with blocking, rule out idle sessions with open transactions. These are invisible to standard blocking queries but are often the real amplifier.

DBCC OPENTRAN;

SELECT
    s.session_id,
    s.login_name,
    s.host_name,
    s.program_name,
    s.status,
    r.blocking_session_id,
    at.transaction_begin_time,
    DATEDIFF(MINUTE, at.transaction_begin_time, GETDATE()) AS tran_age_min,
    t.text AS last_sql_text
FROM sys.dm_exec_sessions                   s
LEFT JOIN sys.dm_exec_requests              r  ON s.session_id     = r.session_id
LEFT JOIN sys.dm_tran_session_transactions  st ON s.session_id     = st.session_id
LEFT JOIN sys.dm_tran_active_transactions   at ON st.transaction_id = at.transaction_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE s.is_user_process = 1
  AND at.transaction_begin_time IS NOT NULL
ORDER BY tran_age_min DESC;
What to act on: Any session with status = 'sleeping' and a tran_age_min of more than 1 to 2 minutes holding an open transaction is a problem. While that session sits idle, its held locks are forcing other sessions to wait. That wait generates continued I/O pressure as blocked sessions retry. The fix is application-side: ensure transactions are committed or rolled back promptly and are never left open waiting for user input or external calls.
5

Correlate Active Blocking with I/O Stalls

Run this during the problem window to identify what is actively blocking and whether it ties back to the I/O wait types identified in Step 3.

SELECT
    r.session_id,
    r.blocking_session_id,
    r.wait_type,
    r.wait_time / 1000.0    AS wait_time_sec,
    r.status,
    r.command,
    t.text                  AS sql_text
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id <> 0
ORDER BY r.wait_time DESC;
What to look for: A single session blocking many others. Long-running transactions performing heavy writes. wait_type values of WRITELOG or PAGEIOLATCH_* on blocked sessions confirm the I/O connection. If blocking aligns with the same time window as Long Sync IO messages, slow I/O is directly extending lock hold time and amplifying the blocking chain.
6

Validate Storage Metrics Externally

SQL Server has confirmed when the problem occurs, what type of I/O is slow, and that blocking is being extended. The final question is whether storage is underperforming or simply being asked to do more than it was sized for.

Ask the infrastructure or storage team for the following metrics covering the same time window identified in Step 1:

  • Disk latency at the OS or SAN level: compare to SQL Server’s view from Step 2
  • Storage queue depth: elevated queue depth during the window confirms saturation
  • Competing activity: backup jobs, snapshots, or compression running during peak hours
  • Firmware and driver versions: outdated HBA or RAID controller firmware is a surprisingly common cause

Two hidden causes worth checking before escalating to storage: First, confirm antivirus software excludes all SQL Server data, log, and backup files (*.mdf, *.ndf, *.ldf, *.bak) and the TempDB path. Real-time scanning of these files during peak workload directly causes I/O stalls that surface as Long Sync IO warnings. Second, on VMware or Hyper-V confirm the virtual disk controller is PVSCSI (VMware) or SCSI (Hyper-V), and that the host is not overcommitted on storage. Hypervisor-level latency can be invisible to SQL Server DMVs but fully visible in host-level counters.

Two possible conclusions:
  • Latency within SLA: storage is meeting targets, workload must be optimized. Reduce I/O demand through query tuning, index improvements, and smaller transaction batches.
  • Latency outside SLA: storage capacity must be addressed. The workload has grown beyond what the current storage tier can sustain. Increase IOPS, move log files to dedicated faster storage, or split I/O across additional volumes.

Workshop Outcome

By completing this walkthrough, the following statements should be supportable with evidence behind each one:

  • Long Sync IO is real and recurring, confirmed from the error log with specific timestamps
  • It aligns with a specific time window, correlated to business hours or known peak load periods
  • It is driven by read pressure, write pressure, or both, identified from wait stats
  • Idle sessions are or are not contributing, confirmed with DBCC OPENTRAN and transaction age query
  • Active blocking is or is not being amplified by the I/O stalls, confirmed from dm_exec_requests during the window
  • Storage is or is not meeting latency targets, confirmed from infrastructure metrics
  • The fix path is workload optimization or storage capacity, a decision based on data, not guesswork

Final Thoughts

Long Sync IO warnings are serious but not self-diagnosing. They confirm that SQL Server waited far longer than expected on synchronous I/O, but they do not explain why. That answer comes from correlating the error log timestamps with file-level latency metrics, wait statistics, active blocking data, and external storage counters.

When code and data loads become permanent, continued messages mean the system is operating near or beyond its I/O capacity. At that point the choice is clear: reduce I/O demand, increase I/O capacity, or fix the application-level transaction patterns that are holding locks far longer than necessary.

Treat Long Sync IO warnings as signals to investigate, not background noise to acknowledge and move on from. Every one of those messages represents a scheduler stall that affected concurrency and extended every transaction running behind it during that second.

References


Discover more from SQLYARD

Subscribe to get the latest posts sent to your email.

Leave a Reply

Discover more from SQLYARD

Subscribe now to keep reading and get access to the full archive.

Continue reading