ORA-02049 Distributed Lock Timeout - Resolution Guide
ORA-02049: Timeout - Distributed Transaction Waiting for Lock
Section titled “ORA-02049: Timeout - Distributed Transaction Waiting for Lock”Error Overview
Section titled “Error Overview”Error Text: ORA-02049: timeout: distributed transaction waiting for lock
This error occurs when a distributed transaction (one that spans multiple databases via database links) waits for a lock on a remote database and the wait exceeds the DISTRIBUTED_LOCK_TIMEOUT parameter. It’s common in environments with database links, distributed applications, and cross-database operations.
Common Causes
Section titled “Common Causes”1. Lock Contention on Remote Database
Section titled “1. Lock Contention on Remote Database”- Another session on the remote database holds a conflicting lock
- Long-running transactions on remote tables
- Uncommitted changes blocking the distributed transaction
2. DISTRIBUTED_LOCK_TIMEOUT Too Low
Section titled “2. DISTRIBUTED_LOCK_TIMEOUT Too Low”- Default is 60 seconds — often too short for complex operations
- Large distributed DML operations timing out
- Network latency adding to wait time
3. Network Latency
Section titled “3. Network Latency”- Slow network between databases
- Database link going through WAN connections
- Intermittent connectivity issues adding to lock wait
4. Distributed Deadlocks
Section titled “4. Distributed Deadlocks”- Circular lock dependencies across databases
- Two transactions locking resources in opposite order on different databases
5. In-Doubt Transactions
Section titled “5. In-Doubt Transactions”- Failed two-phase commits leaving locks held
- Pending distributed transactions blocking new operations
Diagnostic Queries
Section titled “Diagnostic Queries”Check DISTRIBUTED_LOCK_TIMEOUT
Section titled “Check DISTRIBUTED_LOCK_TIMEOUT”-- Current setting (default: 60 seconds)SHOW PARAMETER distributed_lock_timeout;
-- Or query from v$parameterSELECT name, value, descriptionFROM v$parameterWHERE name = 'distributed_lock_timeout';Identify Distributed Transactions
Section titled “Identify Distributed Transactions”-- Active distributed transactionsSELECT local_tran_id, global_tran_id, state, mixed, advice, tran_comment, fail_timeFROM dba_2pc_pending;
-- Distributed transaction locks on LOCAL databaseSELECT s.sid, s.serial#, s.username, s.machine, s.sql_id, s.status, l.type, l.id1, l.id2, l.lmode, l.requestFROM v$session sJOIN v$lock l ON s.sid = l.sidWHERE s.taddr IN ( SELECT taddr FROM v$transaction WHERE flag = 15 -- Distributed flag);Check Remote Database Locks
Section titled “Check Remote Database Locks”-- Run on the REMOTE database to find blocking sessionsSELECT s.sid, s.serial#, s.username, s.machine, s.program, o.object_name, l.type, l.lmode, l.request, s.sql_id, s.status, s.last_call_et as seconds_waitingFROM v$session sJOIN v$lock l ON s.sid = l.sidLEFT JOIN dba_objects o ON l.id1 = o.object_idWHERE l.type IN ('TX', 'TM')ORDER BY s.last_call_et DESC;
-- Find the actual blocking chainSELECT s1.sid as blocking_sid, s1.username as blocking_user, s1.machine as blocking_machine, s2.sid as waiting_sid, s2.username as waiting_user, s2.event as wait_eventFROM v$session s1JOIN v$session s2 ON s1.sid = s2.blocking_session;Check Database Link Health
Section titled “Check Database Link Health”-- Verify database links are functioningSELECT db_link, username, host, createdFROM dba_db_linksWHERE owner = 'YOUR_SCHEMA';
-- Test connectivitySELECT * FROM dual@your_db_link;
-- Check active database link sessionsSELECT username, command, server, machine, program, sql_id, statusFROM v$session@your_db_linkWHERE program LIKE '%TNS%' OR machine = (SELECT host_name FROM v$instance);Check In-Doubt Transactions
Section titled “Check In-Doubt Transactions”-- In-doubt transactions can hold locks indefinitelySELECT local_tran_id, global_tran_id, state, mixed, host, db_user, commit#, advice, fail_time, force_timeFROM dba_2pc_pending;
-- Related locks from in-doubt transactionsSELECT * FROM dba_2pc_neighborsWHERE local_tran_id IN (SELECT local_tran_id FROM dba_2pc_pending);Resolution Steps
Section titled “Resolution Steps”Solution 1: Increase DISTRIBUTED_LOCK_TIMEOUT
Section titled “Solution 1: Increase DISTRIBUTED_LOCK_TIMEOUT”-- Increase timeout for complex distributed operationsALTER SYSTEM SET distributed_lock_timeout = 300 SCOPE=BOTH;-- 300 seconds = 5 minutes
-- For a specific session only (not commonly supported, use system level)-- Note: This is a system-level parameter onlySolution 2: Resolve Lock Contention on Remote Database
Section titled “Solution 2: Resolve Lock Contention on Remote Database”-- On the REMOTE database, find and resolve blocking sessions
-- 1. Identify the blockerSELECT sid, serial#, username, sql_id, status, last_call_etFROM v$sessionWHERE sid IN (SELECT blocking_session FROM v$session WHERE blocking_session IS NOT NULL);
-- 2. If safe to kill, terminate the blocking sessionALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
-- 3. If it's an in-doubt transaction, force rollbackROLLBACK FORCE 'local_transaction_id';-- Or force commit if appropriateCOMMIT FORCE 'local_transaction_id';Solution 3: Resolve In-Doubt Transactions
Section titled “Solution 3: Resolve In-Doubt Transactions”-- Check for pending distributed transactionsSELECT local_tran_id, state, advice FROM dba_2pc_pending;
-- If advice is 'ROLLBACK' or state is 'prepared'ROLLBACK FORCE '1.23.456'; -- Use actual local_tran_id
-- Purge the pending transaction entryEXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.23.456');
-- Clean up on both local and remote databasesSolution 4: Redesign to Avoid Distributed Locks
Section titled “Solution 4: Redesign to Avoid Distributed Locks”-- Instead of distributed DML, use local staging tables-- Step 1: Pull data locallyCREATE TABLE local_staging ASSELECT * FROM remote_table@db_link WHERE conditions;
-- Step 2: Process locallyUPDATE local_staging SET ...;
-- Step 3: Push back in a single transactionINSERT INTO remote_table@db_linkSELECT * FROM local_staging;COMMIT;DROP TABLE local_staging;Solution 5: Use Autonomous Transactions for Logging
Section titled “Solution 5: Use Autonomous Transactions for Logging”-- If distributed transaction is for logging/auditing,-- use autonomous transactions to avoid holding locks
CREATE OR REPLACE PROCEDURE log_event(p_msg VARCHAR2) AS PRAGMA AUTONOMOUS_TRANSACTION;BEGIN INSERT INTO audit_log@logging_db (msg, ts) VALUES (p_msg, SYSTIMESTAMP); COMMIT;END;/Prevention Strategies
Section titled “Prevention Strategies”1. Minimize Distributed Transaction Scope
Section titled “1. Minimize Distributed Transaction Scope”-- Keep distributed transactions as short as possible-- BAD: Long transaction spanning multiple databasesBEGIN UPDATE local_table SET ...; -- ... many operations ... UPDATE remote_table@db_link SET ...; -- Lock held for entire transaction COMMIT;END;
-- GOOD: Separate local and remote operationsBEGIN UPDATE local_table SET ...; COMMIT; -- Release local locks firstEND;/BEGIN UPDATE remote_table@db_link SET ...; COMMIT; -- Separate, shorter distributed transactionEND;/2. Monitor Distributed Lock Wait Times
Section titled “2. Monitor Distributed Lock Wait Times”-- Track distributed lock waitsSELECT event, total_waits, time_waited_micro/1000000 as time_waited_secFROM v$system_eventWHERE event LIKE '%distributed%'ORDER BY time_waited_micro DESC;3. Set Appropriate Timeout Values
Section titled “3. Set Appropriate Timeout Values”-- Based on your network latency and transaction complexity-- Low latency LAN: 60-120 seconds-- WAN connections: 300-600 seconds-- Complex batch operations: 900+ secondsALTER SYSTEM SET distributed_lock_timeout = 120 SCOPE=BOTH;Related Errors
Section titled “Related Errors”- ORA-00060: Deadlock Detected - Local deadlock detection
- ORA-02063: Database Link Error - Database link connectivity problems
- ORA-00054: Resource Busy - Local lock timeout
- ORA-03113: End-of-file on Communication - Connection lost during distributed operation