ORA-02020: Too Many Database Links in Use - OPEN_LINKS Tuning
ORA-02020: Too Many Database Links in Use
Section titled “ORA-02020: Too Many Database Links in Use”Error Overview
Section titled “Error Overview”Error Text: ORA-02020: too many database links in use
ORA-02020 occurs when a session attempts to use more concurrent database links than allowed by the OPEN_LINKS initialization parameter. Each session has a limit on how many remote connections can be open simultaneously, and exceeding this limit triggers the error.
Understanding OPEN_LINKS Parameters
Section titled “Understanding OPEN_LINKS Parameters”| Parameter | Default | Purpose |
|---|---|---|
OPEN_LINKS | 4 | Max concurrent DB links per session |
OPEN_LINKS_PER_INSTANCE | 4 | Max concurrent links across instance for migratable transactions |
Common Causes
Section titled “Common Causes”Too Low OPEN_LINKS Setting
Section titled “Too Low OPEN_LINKS Setting”- Default value of 4 too low for distributed application
- Application accesses many remote databases in single session
- Reporting queries spanning multiple remote sources
Links Not Being Closed
Section titled “Links Not Being Closed”- Application not calling
ALTER SESSION CLOSE DATABASE LINK - Session reuses connection pool entries with open links
- Long-running PL/SQL keeping links open across iterations
Cursor Holding Behavior
Section titled “Cursor Holding Behavior”- Cursors over remote tables hold link open until closed
FOR UPDATEcursors over@dblinktables- Implicit cursors in PL/SQL not finalizing
Distributed Transaction Sprawl
Section titled “Distributed Transaction Sprawl”- Two-phase commit involving many remote DBs
- Application architecture requiring many distributed sources
Diagnostic Steps
Section titled “Diagnostic Steps”Check Current Parameter Values
Section titled “Check Current Parameter Values”-- View current OPEN_LINKS settingSHOW PARAMETER open_links;
-- Or via v$parameterSELECT name, value, isdefault, isses_modifiable, issys_modifiableFROM v$parameterWHERE name LIKE 'open_links%';Identify Active Database Links
Section titled “Identify Active Database Links”-- Show open links in current sessionSELECT * FROM v$dblink;
-- All open distributed transactionsSELECT inst_id, sid, serial#, oct, schemaname, db_link, in_transactionFROM gv$dblink;
-- Sessions with high DB link usageSELECT s.sid, s.serial#, s.username, COUNT(*) AS link_countFROM v$session s, v$dblink dWHERE s.sid = USERENV('SID')GROUP BY s.sid, s.serial#, s.username;Check for Hanging Distributed Transactions
Section titled “Check for Hanging Distributed Transactions”-- 2PC pending transactionsSELECT local_tran_id, global_tran_id, state, mixed, fail_time, retry_timeFROM dba_2pc_pending;
-- Distributed transaction detailsSELECT * FROM dba_2pc_neighbors;Resolution Steps
Section titled “Resolution Steps”1. Increase OPEN_LINKS Parameter
Section titled “1. Increase OPEN_LINKS Parameter”-- Modify OPEN_LINKS (requires restart)ALTER SYSTEM SET open_links = 20 SCOPE=SPFILE;ALTER SYSTEM SET open_links_per_instance = 20 SCOPE=SPFILE;
-- Restart databaseSHUTDOWN IMMEDIATE;STARTUP;
-- VerifySHOW PARAMETER open_links;2. Close Links Explicitly
Section titled “2. Close Links Explicitly”-- Close specific link in sessionALTER SESSION CLOSE DATABASE LINK target_db;
-- Close after each use in PL/SQLDECLARE CURSOR c1 IS SELECT * FROM remote_table@target_db;BEGIN FOR r IN c1 LOOP -- process row NULL; END LOOP;
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK target_db';EXCEPTION WHEN OTHERS THEN BEGIN EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK target_db'; EXCEPTION WHEN OTHERS THEN NULL; END; RAISE;END;/Note: A link cannot be closed while there is an active transaction or open cursor using it. COMMIT first, then close.
3. Audit and Refactor Distributed Code
Section titled “3. Audit and Refactor Distributed Code”-- Find all remote queries in stored codeSELECT name, type, line, textFROM dba_sourceWHERE UPPER(text) LIKE '%@%'ORDER BY name, line;
-- Convert serial remote calls into single MV refreshCREATE MATERIALIZED VIEW remote_summaryREFRESH COMPLETE ON DEMANDAS SELECT * FROM remote_table@target_db;
-- Then query MV instead of remote table repeatedly4. Use Connection Pooling Intelligently
Section titled “4. Use Connection Pooling Intelligently”-- Set link to close at end of sessionALTER SESSION SET CLOSE_CACHED_OPEN_CURSORS = TRUE;
-- For application connection pools, close links before returning to poolEXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK link_a';EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK link_b';5. Cleanup Hung 2PC Transactions
Section titled “5. Cleanup Hung 2PC Transactions”-- Identify pendingSELECT local_tran_id, state FROM dba_2pc_pending;
-- Force commit (only if confirmed remote committed)COMMIT FORCE 'local_tran_id';
-- Force rollback (only if confirmed remote rolled back)ROLLBACK FORCE 'local_tran_id';
-- Clean up recordsEXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');Common Scenarios
Section titled “Common Scenarios”Scenario 1: Reporting Tool Hits Limit
Section titled “Scenario 1: Reporting Tool Hits Limit”Application queries 6 remote DBs in one session, OPEN_LINKS=4.ORA-02020: too many database links in useFix: Increase to OPEN_LINKS=10 and OPEN_LINKS_PER_INSTANCE=20.
Scenario 2: PL/SQL Loop Leaking Links
Section titled “Scenario 2: PL/SQL Loop Leaking Links”Procedure loops through 100 customers, each query against @customer_db.After 4 iterations, ORA-02020.Fix: Close link after each iteration or restructure to single batch query.
Scenario 3: ETL with Many Sources
Section titled “Scenario 3: ETL with Many Sources”ETL pulls from 12 source databases via DB links.ORA-02020: too many database links in useFix: Increase OPEN_LINKS to 15+, use materialized views to reduce concurrency.
Sample Output
Section titled “Sample Output”SQL> SELECT * FROM remote_table_5@db_link_5;SELECT * FROM remote_table_5@db_link_5 *ERROR at line 1:ORA-02020: too many database links in use
SQL> SELECT * FROM v$dblink;
DB_LINK OWNER_ID LOGGED_ON HETEROGENEOUS PROTOCOL--------------- --------- ---------- -------------- --------DB_LINK_1.WORLD 104 YES NO UNKNDB_LINK_2.WORLD 104 YES NO UNKNDB_LINK_3.WORLD 104 YES NO UNKNDB_LINK_4.WORLD 104 YES NO UNKN
-- 4 links open, OPEN_LINKS=4 reachedSQL> SHOW PARAMETER open_links;NAME TYPE VALUE--------------- ----------- ------open_links integer 4
-- Close one and retrySQL> COMMIT;SQL> ALTER SESSION CLOSE DATABASE LINK db_link_1;SQL> SELECT * FROM remote_table_5@db_link_5; -- now succeedsPrevention Strategies
Section titled “Prevention Strategies”Right-Size OPEN_LINKS at Setup
Section titled “Right-Size OPEN_LINKS at Setup”-- Calculate based on application architecture-- # remote DBs simultaneously needed × concurrent sessionsALTER SYSTEM SET open_links = 15 SCOPE=SPFILE;ALTER SYSTEM SET open_links_per_instance = 30 SCOPE=SPFILE;Use Materialized Views for Repeated Access
Section titled “Use Materialized Views for Repeated Access”-- Pull data locally onceCREATE MATERIALIZED VIEW mv_remote_customersBUILD IMMEDIATEREFRESH FAST ON DEMANDAS SELECT * FROM customers@remote_db;
-- Application queries MV, not remoteSELECT * FROM mv_remote_customers WHERE region = 'WEST';Application Design Patterns
Section titled “Application Design Patterns”- Aggregate remote queries into a single fetch
- Cache remote data in local tables for repeated access
- Close links explicitly when done
- Monitor
v$dblinkin long-running sessions
Monitoring Script
Section titled “Monitoring Script”-- Alert if any session approaches limitSELECT s.sid, s.username, COUNT(*) AS link_countFROM gv$session s, gv$dblink dWHERE s.sid = d.sid AND s.inst_id = d.inst_idGROUP BY s.sid, s.usernameHAVING COUNT(*) >= (SELECT TO_NUMBER(value) - 1 FROM v$parameter WHERE name = 'open_links');Related Errors
Section titled “Related Errors”- ORA-02011: Duplicate database link name
- ORA-02019: Connection description for remote database not found
- ORA-02050: Transaction X rolled back, some remote DBs may be in-doubt
- ORA-02063: Preceding line from database link
- ORA-02068: Following severe error from database link
Troubleshooting Checklist
Section titled “Troubleshooting Checklist”- Check current
OPEN_LINKSandOPEN_LINKS_PER_INSTANCE - Inspect
v$dblinkfor active connections - Close idle links with
ALTER SESSION CLOSE DATABASE LINK - Increase parameter if architecture demands it
- Audit code for unclosed links in loops
- Use materialized views for frequently-accessed remote data
- Clean up
dba_2pc_pendingentries