mediumLinked Server

OLEDB Wait Type Explained

Diagnose and fix SQL Server OLEDB waits caused by linked server operations. Learn root causes, diagnostic queries, and proven solutions for distributed query performance.

Quick Answer

OLEDB wait type occurs when SQL Server waits for OLE DB providers to complete operations during linked server calls, distributed queries, or bulk operations. This wait measures time spent in external data source calls, not internal SQL Server synchronization. High OLEDB waits typically indicate network latency, slow remote queries, or inefficient linked server configurations.

Root Cause Analysis

OLEDB waits occur when SQL Server's query processor delegates work to the OLE DB subsystem through the SQL Server Native Client (SQLNCLI) or Microsoft OLE DB Driver (MSOLEDBSQL). When a worker thread executes a distributed query or linked server operation, it transitions from the RUNNING state to SUSPENDED while the OLE DB provider processes the request on the remote system.

The scheduler releases the worker thread during OLE DB calls, allowing other tasks to utilize CPU resources. The wait accumulates from the moment SQL Server invokes the provider until the provider returns control with results or an error. Unlike synchronization waits, OLEDB waits represent actual work being performed externally.

SQL Server 2016 introduced changes to how distributed transactions interact with OLE DB providers, improving timeout handling. SQL Server 2019 enhanced connection pooling for OLE DB connections, reducing overhead for repeated operations. SQL Server 2022 improved error reporting granularity for OLE DB failures, making diagnosis more precise.

The query processor can trigger OLEDB waits through multiple code paths: four-part name queries (SELECT FROM [server].[database].[schema].[table]), OPENQUERY statements, OPENROWSET operations, and bulk insert operations using BULK INSERT or bcp utilities. Each path utilizes different OLE DB interfaces, with varying performance characteristics.

AutoDBA checks Linked server timeouts, connection pooling settings, and distributed query optimization configurations across your entire SQL Server instance in 60 seconds. Download the free diagnostic script and see what else needs attention.

Diagnostic Queries

-- Identify current OLEDB waits and their source sessions
SELECT 
    s.session_id,
    s.login_name,
    s.host_name,
    s.program_name,
    r.wait_type,
    r.wait_time,
    r.blocking_session_id,
    t.text,
    s.last_request_start_time
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.wait_type = 'OLEDB'
ORDER BY r.wait_time DESC;
-- Analyze OLEDB wait patterns over time using wait stats
SELECT 
    wait_type,
    waiting_tasks_count,
    wait_time_ms,
    max_wait_time_ms,
    signal_wait_time_ms,
    wait_time_ms - signal_wait_time_ms AS resource_wait_time_ms,
    CASE 
        WHEN waiting_tasks_count > 0 
        THEN wait_time_ms / waiting_tasks_count 
        ELSE 0 
    END AS avg_wait_time_ms
FROM sys.dm_os_wait_stats 
WHERE wait_type = 'OLEDB'
    AND waiting_tasks_count > 0;
-- Examine linked server configurations and connection details
SELECT 
    s.server_id,
    s.name AS linked_server_name,
    s.product,
    s.provider,
    s.data_source,
    s.provider_string,
    s.catalog,
    s.connect_timeout,
    s.query_timeout,
    l.remote_name,
    l.uses_self_credential
FROM sys.servers s
LEFT JOIN sys.linked_logins l ON s.server_id = l.server_id
WHERE s.is_linked = 1;
-- Monitor active distributed transactions causing OLEDB waits
SELECT 
    dt.transaction_id,
    dt.transaction_begin_time,
    dt.transaction_type,
    dt.transaction_state,
    dt.transaction_status,
    s.session_id,
    s.login_name,
    r.wait_type,
    r.wait_time,
    t.text
FROM sys.dm_tran_database_transactions dt
INNER JOIN sys.dm_tran_session_transactions st ON dt.transaction_id = st.transaction_id
INNER JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
LEFT JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.wait_type = 'OLEDB' OR dt.transaction_type = 4; -- distributed transaction
-- Identify frequently executed distributed queries with performance metrics
SELECT TOP 20
    cp.objtype,
    cp.cacheobjtype,
    cp.size_in_bytes,
    cp.usecounts,
    qs.execution_count,
    qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time_ms,
    qs.total_worker_time / qs.execution_count AS avg_cpu_time_ms,
    qs.creation_time,
    qs.last_execution_time,
    t.text
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) t
LEFT JOIN sys.dm_exec_query_stats qs ON cp.plan_handle = qs.plan_handle
WHERE t.text LIKE '%OPENQUERY%'
    OR t.text LIKE '%OPENROWSET%' 
    OR t.text LIKE '%[[]%].[[]%].[[]%].[[]%]%'
ORDER BY qs.total_elapsed_time DESC;

Fix Scripts

-- Increase linked server timeout values for slow remote operations
-- TEST IN DEV FIRST: Affects all queries to specified linked server
EXEC sp_serveroption 
    @server = 'YOUR_LINKED_SERVER_NAME',
    @optname = 'query timeout',
    @optvalue = '300'; -- 5 minutes, adjust based on your requirements

EXEC sp_serveroption 
    @server = 'YOUR_LINKED_SERVER_NAME',
    @optname = 'connect timeout',
    @optvalue = '60'; -- 1 minute connection timeout
-- Enable connection pooling and RPC for better performance
-- Reduces connection overhead for repeated operations
EXEC sp_serveroption 
    @server = 'YOUR_LINKED_SERVER_NAME',
    @optname = 'rpc',
    @optvalue = 'true';

EXEC sp_serveroption 
    @server = 'YOUR_LINKED_SERVER_NAME',
    @optname = 'rpc out',
    @optvalue = 'true';

-- Enable connection pooling (SQL Server 2019+)
EXEC sp_serveroption 
    @server = 'YOUR_LINKED_SERVER_NAME',
    @optname = 'remote proc transaction promotion',
    @optvalue = 'false';
-- Create stored procedure to monitor OLEDB wait trends
-- Run periodically to capture wait patterns for analysis
CREATE OR ALTER PROCEDURE dbo.CaptureOLEDBWaits
AS
BEGIN
    SET NOCOUNT ON;
    
    -- Create logging table if it doesn't exist
    IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'OLEDBWaitLog')
    BEGIN
        CREATE TABLE dbo.OLEDBWaitLog (
            capture_time datetime2 DEFAULT GETDATE(),
            waiting_tasks_count bigint,
            wait_time_ms bigint,
            max_wait_time_ms bigint,
            avg_wait_time_ms bigint,
            signal_wait_time_ms bigint
        );
    END
    
    -- Capture current OLEDB wait statistics
    INSERT INTO dbo.OLEDBWaitLog (waiting_tasks_count, wait_time_ms, max_wait_time_ms, avg_wait_time_ms, signal_wait_time_ms)
    SELECT 
        waiting_tasks_count,
        wait_time_ms,
        max_wait_time_ms,
        CASE WHEN waiting_tasks_count > 0 THEN wait_time_ms / waiting_tasks_count ELSE 0 END,
        signal_wait_time_ms
    FROM sys.dm_os_wait_stats 
    WHERE wait_type = 'OLEDB';
END
-- Kill long-running distributed queries causing excessive OLEDB waits
-- CAUTION: Only kill sessions after confirming they are problematic
-- This script identifies candidates but requires manual review

SELECT 
    'KILL ' + CAST(s.session_id AS VARCHAR(10)) + ';' AS kill_command,
    s.session_id,
    s.login_name,
    s.program_name,
    r.wait_time,
    r.total_elapsed_time,
    t.text,
    s.last_request_start_time
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.wait_type = 'OLEDB'
    AND r.wait_time > 300000 -- 5 minutes
    AND s.session_id > 50 -- Exclude system sessions
ORDER BY r.wait_time DESC;

-- Review output carefully before executing any KILL commands

AutoDBA generates fix scripts like these automatically, with impact estimates and rollback SQL included.

Prevention

Configure linked server timeouts appropriately based on expected query execution times. Set query timeout to 2-3 times the longest expected query duration, and connect timeout to 30-60 seconds. Enable RPC and RPC OUT options to allow SQL Server to push operations to remote servers rather than pulling all data locally.

Use OPENQUERY instead of four-part naming when possible, as it allows the remote server to optimize the entire query. Four-part names force SQL Server to retrieve all rows locally before applying WHERE clauses. Replace SELECT * FROM [server].[database].[schema].[table] WHERE column = 'value' with SELECT * FROM OPENQUERY([server], 'SELECT * FROM database.schema.table WHERE column = ''value''').

Implement connection pooling by disabling distributed transaction promotion when full ACID compliance across servers is not required. Set "remote proc transaction promotion" to false for linked servers that do not need distributed transactions.

Monitor OLEDB waits using automated alerting when average wait times exceed baseline values by 200% or when waiting task counts spike above normal thresholds. Create dedicated monitoring stored procedures that capture wait statistics every 5-10 minutes during peak hours.

Consider replacing linked servers with alternative architectures for high-volume operations: SSIS packages for ETL workloads, replication for read-heavy scenarios, or Service Broker for asynchronous processing. These alternatives reduce OLEDB wait pressure while providing better control over data flow timing and error handling.

Need hands-on help?

Dealing with persistent oledb issues across your environment? Samix Technology provides hands-on SQL Server performance consulting with 15+ years of production DBA experience.