Oracle Database Troubleshooting Guide for LIMS Environments

Table of Contents

[Prerequisites and Setup](#prerequisites-and-setup)

[Discovery SQL Queries](#discovery-sql-queries)

[Problem-Based Troubleshooting](#problem-based-troubleshooting)

[Quick Emergency Fixes](#quick-emergency-fixes)

Prerequisites and Setup

Database Connection Requirements

Required Privileges


-- Check your current privileges
SELECT * FROM USER_SYS_PRIVS WHERE PRIVILEGE LIKE '%SELECT%';
SELECT * FROM USER_TAB_PRIVS WHERE PRIVILEGE = 'SELECT';

---

Oracle Analysis Queries

Using Discovered Values

Use usernames from this discovery command:


-- FROM DISCOVERY SECTION - Get LIMS usernames (these ARE the schema names in Oracle):
SELECT username FROM dba_users 
WHERE UPPER(username) LIKE '%LIMS%' 
   OR UPPER(username) LIKE '%LAB%'
   OR UPPER(username) LIKE '%SAMPLE%'
ORDER BY username;

Use tablespace names from this discovery command:


-- FROM DISCOVERY SECTION - Get LIMS tablespace names:
SELECT DISTINCT tablespace_name 
FROM dba_tables 
WHERE owner IN (SELECT username FROM dba_users WHERE UPPER(username) LIKE '%LIMS%')
ORDER BY tablespace_name;

Use session IDs from this discovery command:


-- FROM DISCOVERY SECTION - Get current sessions:
SELECT sid, serial#, username, machine, program
FROM v$session 
WHERE username IS NOT NULL
ORDER BY username;

---

Check specific schema performance:


SELECT s.sid, s.serial#, s.username, s.machine, s.program, s.status,
       s.last_call_et/60 as minutes_idle_or_running,
       sq.sql_text
FROM v$session s
LEFT JOIN v$sql sq ON s.sql_id = sq.sql_id
WHERE s.username = '<USERNAME>'  -- Use username from LIMS username discovery above
ORDER BY s.last_call_et DESC;

Use table names from this discovery command:


-- FROM DISCOVERY SECTION - Get LIMS tables:
SELECT table_name FROM dba_tables 
WHERE owner = 'YOUR_LIMS_USERNAME'  -- Use username from above
ORDER BY table_name;

---

Monitor tablespace usage:


SELECT 
    ROUND(total_mb,2) as total_mb,
    ROUND(used_mb,2) as used_mb,
    ROUND(free_mb,2) as free_mb,
    ROUND(pct_used,2) as pct_used
FROM (
    SELECT 
        df.total_mb,
        df.total_mb - NVL(fs.free_mb,0) as used_mb,
        NVL(fs.free_mb,0) as free_mb,
        (1 - NVL(fs.free_mb,0)/df.total_mb)*100 as pct_used
    FROM (
        SELECT SUM(bytes)/1024/1024 as total_mb
        FROM dba_data_files
        WHERE tablespace_name = '<TABLESPACE_NAME>'  -- Use tablespace from LIMS tablespace discovery above
    ) df
    LEFT JOIN (
        SELECT SUM(bytes)/1024/1024 as free_mb
        FROM dba_free_space
        WHERE tablespace_name = '<TABLESPACE_NAME>'  -- Use tablespace from LIMS tablespace discovery above
    ) fs ON 1=1
);

Check locks for specific schema:


SELECT s.sid, s.serial#, s.username, s.machine, s.program,
       DECODE(l.type,
              'TM','Table Lock',
              'TX','Transaction Lock',
              'UL','User Lock',
              l.type) as lock_type,
       DECODE(l.lmode,
              0,'None',
              1,'Null',
              2,'Row Share',
              3,'Row Exclusive', 
              4,'Share',
              5,'Share Row Exclusive',
              6,'Exclusive',
              l.lmode) as lock_mode,
       o.object_name
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
LEFT JOIN dba_objects o ON l.id1 = o.object_id
WHERE s.username = '<USERNAME>'  -- Use username from LIMS username discovery above
ORDER BY o.object_name;

Analyze SQL performance for schema:


SELECT sql_id, executions,
       ROUND(elapsed_time/1000000,2) as total_seconds,
       ROUND(elapsed_time/executions/1000000,2) as avg_seconds,
       ROUND(cpu_time/1000000,2) as cpu_seconds,
       ROUND(disk_reads/executions,2) as avg_disk_reads,
       SUBSTR(sql_text,1,100) as sql_preview
FROM v$sql 
WHERE parsing_schema_name = '<USERNAME>'  -- Use username from LIMS username discovery above
  AND executions > 0
ORDER BY elapsed_time DESC
FETCH FIRST 20 ROWS ONLY;

Check table statistics for schema:


SELECT table_name, num_rows, last_analyzed, 
       CASE WHEN last_analyzed < SYSDATE - 7 THEN 'STALE'
            WHEN last_analyzed IS NULL THEN 'NEVER'
            ELSE 'CURRENT' END as stats_status
FROM dba_tables 
WHERE owner = '<USERNAME>'  -- Use username from LIMS username discovery above
ORDER BY num_rows DESC;

Monitor specific session:


SELECT s.sid, s.serial#, s.username, s.machine, s.program, s.status,
       s.event, s.wait_class, s.seconds_in_wait,
       s.last_call_et, s.logon_time,
       st.value as cpu_used_seconds
FROM v$session s
LEFT JOIN v$sesstat st ON s.sid = st.sid
LEFT JOIN v$statname sn ON st.statistic# = sn.statistic#
WHERE s.sid = <SESSION_ID>  -- Use sid from current sessions discovery above
  AND (sn.name = 'CPU used by this session' OR sn.name IS NULL);

Check wait events for schema:


SELECT s.username, s.machine, s.event, s.wait_class,
       COUNT(*) as session_count,
       ROUND(AVG(s.seconds_in_wait),2) as avg_wait_seconds
FROM v$session_wait s
JOIN v$session sess ON s.sid = sess.sid
WHERE sess.username = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
  AND s.event NOT LIKE 'SQL*Net%'
GROUP BY s.username, s.machine, s.event, s.wait_class
ORDER BY session_count DESC;

Analyze table growth:


SELECT table_name, num_rows, 
       ROUND(avg_row_len * num_rows / 1024 / 1024, 2) as estimated_mb,
       last_analyzed
FROM dba_tables 
WHERE owner = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
  AND table_name = '<TABLE_NAME>'  -- Use table_name from LIMS tables discovery above
ORDER BY estimated_mb DESC;

Check index usage:


SELECT i.index_name, i.table_name, i.status, i.last_analyzed,
       ROUND(s.bytes/1024/1024,2) as size_mb
FROM dba_indexes i
LEFT JOIN dba_segments s ON i.owner = s.owner AND i.index_name = s.segment_name
WHERE i.owner = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
  AND i.table_name = '<TABLE_NAME>'  -- Use table_name from LIMS tables discovery above
ORDER BY size_mb DESC;

Monitor connection history:


SELECT username, machine, program, logon_time, status,
       ROUND((SYSDATE - logon_time) * 24, 2) as hours_connected
FROM v$session 
WHERE username = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
ORDER BY logon_time DESC;

Check object sizes:


SELECT segment_name, segment_type, 
       ROUND(bytes/1024/1024,2) as size_mb,
       blocks, extents
FROM dba_segments 
WHERE owner = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
  AND segment_type IN ('TABLE', 'INDEX')
ORDER BY bytes DESC
FETCH FIRST 20 ROWS ONLY;

Analyze redo log usage:


SELECT group#, thread#, status, 
       ROUND(bytes/1024/1024,2) as size_mb,
       members, archived, first_time
FROM v$log 
WHERE group# = <LOG_GROUP_NUMBER>  -- Use group# from redo log discovery above
ORDER BY group#;

Check blocking sessions:


SELECT 
    s1.sid as blocking_sid,
    s1.serial# as blocking_serial,
    s1.username as blocking_user,
    s1.machine as blocking_machine,
    s2.sid as waiting_sid,
    s2.username as waiting_user,
    s2.machine as waiting_machine,
    o.object_name as locked_object
FROM v$lock l1
JOIN v$session s1 ON l1.sid = s1.sid
JOIN v$lock l2 ON l1.id1 = l2.id1
JOIN v$session s2 ON l2.sid = s2.sid
JOIN dba_objects o ON l1.id1 = o.object_id
WHERE l1.block = 1 AND l2.request > 0
  AND (s1.username = '<SCHEMA_NAME>' OR s2.username = '<SCHEMA_NAME>');  -- Use username from LIMS schema discovery above

Monitor SGA components:


SELECT component, 
       ROUND(current_size/1024/1024,2) as current_mb,
       ROUND(min_size/1024/1024,2) as min_mb,
       ROUND(max_size/1024/1024,2) as max_mb,
       ROUND((current_size/max_size)*100,2) as pct_used
FROM v$sga_dynamic_components
WHERE component = '<COMPONENT_NAME>'  -- Use component from SGA discovery above
ORDER BY current_size DESC;

Check PGA usage by session:


SELECT s.sid, s.username, s.machine, s.program,
       ROUND(p.pga_used_mem/1024/1024,2) as pga_used_mb,
       ROUND(p.pga_alloc_mem/1024/1024,2) as pga_alloc_mb,
       ROUND(p.pga_max_mem/1024/1024,2) as pga_max_mb
FROM v$process p
JOIN v$session s ON p.addr = s.paddr
WHERE s.username = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
ORDER BY p.pga_used_mem DESC;

Analyze temp usage:


SELECT s.sid, s.username, s.machine, s.program,
       ROUND(t.blocks * 8192 / 1024 / 1024, 2) as temp_mb,
       t.tablespace, t.segtype
FROM v$tempseg_usage t
JOIN v$session s ON t.session_addr = s.saddr
WHERE s.username = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
ORDER BY temp_mb DESC;

Check datafile usage:


SELECT file_name, tablespace_name,
       ROUND(bytes/1024/1024,2) as size_mb,
       ROUND(maxbytes/1024/1024,2) as max_mb,
       autoextensible,
       status
FROM dba_data_files 
WHERE tablespace_name = '<TABLESPACE_NAME>'  -- Use tablespace from LIMS tablespace discovery above
ORDER BY bytes DESC;

Monitor archive log generation:


SELECT TO_CHAR(first_time, 'YYYY-MM-DD HH24') as hour,
       COUNT(*) as logs_generated,
       ROUND(SUM(blocks * block_size) / 1024 / 1024, 2) as mb_generated
FROM v$archived_log 
WHERE first_time > SYSDATE - 1  -- Last 24 hours
GROUP BY TO_CHAR(first_time, 'YYYY-MM-DD HH24')
ORDER BY hour DESC;

Check invalid objects for schema:


SELECT object_name, object_type, status, last_ddl_time
FROM dba_objects 
WHERE owner = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
  AND status = 'INVALID'
ORDER BY object_type, object_name;

Analyze cursor usage:


SELECT s.sid, s.username, s.machine, 
       COUNT(*) as open_cursors,
       MAX(last_active_time) as last_cursor_activity
FROM v$open_cursor oc
JOIN v$session s ON oc.sid = s.sid
WHERE s.username = '<SCHEMA_NAME>'  -- Use username from LIMS schema discovery above
GROUP BY s.sid, s.username, s.machine
ORDER BY open_cursors DESC;

Discovery SQL Queries

Run These First

Get database instance information:


SELECT instance_name, host_name, version, status, startup_time 
FROM v$instance;

Get LIMS usernames (these are schema/owner names in Oracle):


SELECT username, account_status, created 
FROM dba_users 
WHERE UPPER(username) LIKE '%LIMS%' 
   OR UPPER(username) LIKE '%LAB%'
   OR UPPER(username) LIKE '%SAMPLE%'
ORDER BY username;

Get all schema names:


SELECT username FROM dba_users WHERE account_status = 'OPEN' ORDER BY username;

Get current database connections:


SELECT username, machine, program, status, COUNT(*) as connection_count
FROM v$session 
WHERE username IS NOT NULL
GROUP BY username, machine, program, status
ORDER BY connection_count DESC;

Get tablespace names:


SELECT tablespace_name FROM dba_tablespaces ORDER BY tablespace_name;

Get LIMS tablespace names:


SELECT DISTINCT tablespace_name 
FROM dba_tables 
WHERE owner IN (SELECT username FROM dba_users WHERE UPPER(username) LIKE '%LIMS%')
ORDER BY tablespace_name;

Get service names:


SELECT name, network_name FROM v$services;

Get database name:


SELECT name FROM v$database;

Get Oracle version:


SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';

Get database character set:


SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET';

Get session limits:


SELECT value FROM v$parameter WHERE name = 'sessions';

Get process limits:


SELECT value FROM v$parameter WHERE name = 'processes';

Get SGA size:


SELECT ROUND(SUM(value)/1024/1024,2) as sga_mb FROM v$sga;

Get all LIMS tables:


SELECT owner, table_name, num_rows, last_analyzed
FROM dba_tables 
WHERE owner IN (SELECT username FROM dba_users WHERE UPPER(username) LIKE '%LIMS%')
ORDER BY owner, table_name;

Get LIMS indexes:


SELECT owner, index_name, table_name, status
FROM dba_indexes 
WHERE owner IN (SELECT username FROM dba_users WHERE UPPER(username) LIKE '%LIMS%')
ORDER BY owner, table_name;

Get database timezone:


SELECT dbtimezone FROM dual;

Get archive log mode:


SELECT log_mode FROM v$database;

Get redo log groups:


SELECT group#, status, bytes/1024/1024 as mb FROM v$log ORDER BY group#;

Get datafile locations:


SELECT file_name, tablespace_name, ROUND(bytes/1024/1024,2) as mb 
FROM dba_data_files ORDER BY tablespace_name;

Get temp tablespace info:


SELECT tablespace_name, file_name, ROUND(bytes/1024/1024,2) as mb 
FROM dba_temp_files ORDER BY tablespace_name;

Get invalid objects:


SELECT owner, object_name, object_type, status
FROM dba_objects 
WHERE status = 'INVALID' 
ORDER BY owner, object_type;

Get database parameters:


SELECT name, value FROM v$parameter 
WHERE name IN ('db_name', 'instance_name', 'service_names', 'processes', 'sessions', 'sga_target', 'pga_aggregate_target')
ORDER BY name;

Get current SCN:


SELECT current_scn FROM v$database;

Get active sessions by user:


SELECT username, COUNT(*) as session_count
FROM v$session 
WHERE status = 'ACTIVE' AND username IS NOT NULL
GROUP BY username ORDER BY session_count DESC;

Get session wait events:


SELECT event, COUNT(*) as session_count
FROM v$session_wait 
GROUP BY event ORDER BY session_count DESC;

Get top SQL by executions:


SELECT sql_id, executions, SUBSTR(sql_text,1,50) as sql_preview
FROM v$sql 
WHERE executions > 100
ORDER BY executions DESC
FETCH FIRST 10 ROWS ONLY;

Get locks by session:


SELECT s.username, s.sid, l.type, l.lmode, o.object_name
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
LEFT JOIN dba_objects o ON l.id1 = o.object_id
WHERE s.username IS NOT NULL
ORDER BY s.username;

---

Problem-Based Troubleshooting

PROBLEM: "LIMS is slow - everything takes forever"

STEP 1: Check if database is the problem


-- Find slow running queries RIGHT NOW
SELECT s.sid, s.username, s.machine, s.program,
       sq.sql_text, s.last_call_et/60 as minutes_running
FROM v$session s
JOIN v$sql sq ON s.sql_id = sq.sql_id
WHERE s.username IN ('LIMS_USER1', 'LIMS_USER2')  -- Use actual LIMS usernames from discovery
  AND s.status = 'ACTIVE'
  AND s.last_call_et > 60  -- Running for more than 1 minute
ORDER BY s.last_call_et DESC;

WHAT IT SHOWS: Queries that are running too long

WHAT TO DO:

STEP 2: Kill the slow queries


-- Kill a specific slow session (use SID from above query)
ALTER SYSTEM KILL SESSION '123,456';  -- Replace with actual SID,SERIAL# from above

WHEN TO USE: Query running over 30 minutes and LIMS is hanging

PROBLEM: "LIMS says it can't connect to database"

STEP 1: Check if database accepts connections


-- Check connection limits
SELECT 
    (SELECT COUNT(*) FROM v$session) as current_sessions,
    (SELECT value FROM v$parameter WHERE name = 'sessions') as max_sessions,
    ROUND(((SELECT COUNT(*) FROM v$session) / 
           (SELECT value FROM v$parameter WHERE name = 'sessions')) * 100, 2) as pct_used
FROM dual;

WHAT IT SHOWS: If database is at connection limit

WHAT TO DO:

STEP 2: Kill dead connections


-- Find dead/idle connections to kill
SELECT s.sid, s.serial#, s.username, s.machine, s.program,
       s.last_call_et/3600 as hours_idle
FROM v$session s
WHERE s.username IN ('LIMS_USER1', 'LIMS_USER2')  -- Use actual LIMS usernames from discovery
  AND s.status = 'INACTIVE'
  AND s.last_call_et > 3600  -- Idle for more than 1 hour
ORDER BY s.last_call_et DESC;

WHAT TO DO: Kill sessions idle for hours:


ALTER SYSTEM KILL SESSION '123,456';  -- Use SID,SERIAL# from above

PROBLEM: "LIMS gives errors when trying to save data"

STEP 1: Check for locks blocking saves


-- Find what's blocking LIMS saves
SELECT 
    s1.username as blocking_user,
    s1.machine as blocking_machine,
    s1.sid as blocking_sid,
    s1.serial# as blocking_serial,
    s2.username as waiting_user,
    s2.machine as waiting_machine,
    s2.sid as waiting_sid,
    o.object_name as locked_table
FROM v$lock l1
JOIN v$session s1 ON l1.sid = s1.sid
JOIN v$lock l2 ON l1.id1 = l2.id1
JOIN v$session s2 ON l2.sid = s2.sid
JOIN dba_objects o ON l1.id1 = o.object_id
WHERE l1.block = 1 AND l2.request > 0;

WHAT IT SHOWS: Which session is blocking which table

WHAT TO DO: Kill the blocking session:


ALTER SYSTEM KILL SESSION '123,456';  -- Use blocking_sid,blocking_serial from above

STEP 2: Check if tablespace is full


-- Check if LIMS tablespace is full
SELECT df.tablespace_name,
       ROUND(df.total_mb,2) as total_mb,
       ROUND(df.total_mb - NVL(fs.free_mb,0),2) as used_mb,
       ROUND(NVL(fs.free_mb,0),2) as free_mb,
       ROUND((1 - NVL(fs.free_mb,0)/df.total_mb)*100,2) as pct_used
FROM (
    SELECT tablespace_name, SUM(bytes)/1024/1024 as total_mb
    FROM dba_data_files
    GROUP BY tablespace_name
) df
LEFT JOIN (
    SELECT tablespace_name, SUM(bytes)/1024/1024 as free_mb
    FROM dba_free_space
    GROUP BY tablespace_name
) fs ON df.tablespace_name = fs.tablespace_name
WHERE df.tablespace_name IN (
    SELECT DISTINCT tablespace_name 
    FROM dba_tables 
    WHERE owner = 'LIMS_SCHEMA'  -- Use actual LIMS username from discovery
);

WHAT IT SHOWS: How full your LIMS tablespaces are

WHAT TO DO:

PROBLEM: "LIMS was working fine, now suddenly very slow"

STEP 1: Check for recent high-impact queries


-- Find queries using lots of CPU in last hour
SELECT sql_id, executions, 
       ROUND(elapsed_time/1000000,2) as total_seconds,
       ROUND(elapsed_time/executions/1000000,2) as avg_seconds_per_execution,
       SUBSTR(sql_text,1,100) as sql_preview
FROM v$sql 
WHERE parsing_schema_name = 'LIMS_SCHEMA'  -- Use actual LIMS username from discovery
  AND last_active_time > SYSDATE - 1/24  -- Last hour
  AND executions > 0
ORDER BY elapsed_time DESC
FETCH FIRST 10 ROWS ONLY;

WHAT IT SHOWS: Which LIMS queries are eating up time

WHAT TO DO:

STEP 2: Find the expensive query details


-- Get full text of problem query
SELECT sql_fulltext 
FROM v$sql 
WHERE sql_id = 'abc123def456';  -- Use sql_id from above query

PROBLEM: "LIMS keeps giving deadlock errors"

STEP 1: Check current deadlock victims


-- Check for current deadlocks
SELECT s.username, s.machine, s.program, 
       DECODE(l.type,
              'TM','Table Lock',
              'TX','Transaction Lock') as lock_type,
       DECODE(l.lmode,
              2,'Row Share',
              3,'Row Exclusive',
              4,'Share',
              5,'Share Row Exclusive',
              6,'Exclusive') as lock_mode,
       o.object_name as locked_object
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
LEFT JOIN dba_objects o ON l.id1 = o.object_id
WHERE s.username = 'LIMS_SCHEMA'  -- Use actual LIMS username from discovery
  AND l.type IN ('TM','TX')
ORDER BY o.object_name;

WHAT IT SHOWS: What LIMS is trying to lock

WHAT TO DO: Look for multiple sessions locking the same object_name

---

Quick Emergency Fixes

EMERGENCY: "LIMS is completely frozen"

1. Kill all LIMS sessions:


-- Find all LIMS sessions
SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''';' as kill_command
FROM v$session 
WHERE username = 'LIMS_SCHEMA';  -- Use actual LIMS username from discovery

Copy the output and run each ALTER SYSTEM command

2. Check if database is responsive:


SELECT SYSDATE FROM dual;

If this takes more than 2 seconds = database problem

EMERGENCY: "Database says tablespace full"

Check available space:


-- Quick tablespace check
SELECT tablespace_name, 
       ROUND((1 - NVL(free_mb,0)/total_mb)*100,2) as pct_used,
       CASE WHEN (1 - NVL(free_mb,0)/total_mb)*100 > 95 THEN 'CRITICAL - CALL DBA NOW'
            WHEN (1 - NVL(free_mb,0)/total_mb)*100 > 90 THEN 'WARNING'
            ELSE 'OK' END as status
FROM (
    SELECT df.tablespace_name,
           df.total_mb,
           fs.free_mb
    FROM (SELECT tablespace_name, SUM(bytes)/1024/1024 as total_mb FROM dba_data_files GROUP BY tablespace_name) df
    LEFT JOIN (SELECT tablespace_name, SUM(bytes)/1024/1024 as free_mb FROM dba_free_space GROUP BY tablespace_name) fs 
    ON df.tablespace_name = fs.tablespace_name
);

EMERGENCY: "Too many connections error"

Kill oldest idle sessions:


-- Kill sessions idle for more than 2 hours
SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''';' as kill_command
FROM v$session 
WHERE status = 'INACTIVE'
  AND last_call_et > 7200  -- 2 hours
  AND username IS NOT NULL
ORDER BY last_call_et DESC;

---

What Each Problem Means

SLOW QUERIES = Bad SQL or missing indexes = Call developer

CONNECTION LIMITS = Too many sessions = Kill old ones

LOCKS/DEADLOCKS = Two processes fighting over same data = Kill one

TABLESPACE FULL = No disk space = Call DBA immediately

HIGH CPU = Database overloaded = Find expensive queries

WHEN TO CALL DBA:

WHEN TO CALL DEVELOPER:

This guide tells you exactly what problem each query solves and what to do with the results.