SQLs to identify locks in DB
=============================
GRANTS
GRANT SELECT ON SYS.V_$SESSION to XXX;
GRANT ALTER SESSION TO XXX;
=============================
How to find and kill sessions involved in lock:
=============================
Just Kill version.
SET LINESIZE 120
SET PAGESIZE 100
COL "DB Kill" FOR A50
SELECT 'ALTER SYSTEM KILL SESSION '''||s.sid||','||s.serial#||''' IMMEDIATE; ' AS "DB Kill",
'kill -9 '||p.spid AS "Linux Kill"
FROM V$PROCESS p, V$SESSION s ,V$INSTANCE
WHERE p.addr=s.paddr
AND s.username = 'MY_USER';
Simple version
SELECT spid, osuser, s.username, s.sid,
s.program||' , '||s.module||' , '||s.action AS WHAT,
'ALTER SYSTEM KILL SESSION '''||s.sid||','||s.serial#||''' IMMEDIATE;' AS "DB Kill",
'orakill '||INSTANCE_NAME||' '||p.spid AS "Windows Kill" ,
'kill -9 '||p.spid AS "Linux Kill"
FROM V$PROCESS p, V$SESSION s ,V$INSTANCE
WHERE p.addr=s.paddr
AND s.username = 'DB_USER'
AND s.osuser = 'os_user'
AND s.program = 'sqlplus.exe';
Elaborate version
SELECT 'ALTER SYSTEM KILL SESSION '||SUBSTR(''''||S.sid||','||S.serial#||'''',1,15)||' IMMEDIATE;' AS "Kill Session",
SET LINESIZE 120
SET PAGESIZE 100
COL "DB Kill" FOR A50
SELECT 'ALTER SYSTEM KILL SESSION '''||s.sid||','||s.serial#||''' IMMEDIATE; ' AS "DB Kill",
'kill -9 '||p.spid AS "Linux Kill"
FROM V$PROCESS p, V$SESSION s ,V$INSTANCE
WHERE p.addr=s.paddr
AND s.username = 'MY_USER';
Simple version
SELECT spid, osuser, s.username, s.sid,
s.program||' , '||s.module||' , '||s.action AS WHAT,
'ALTER SYSTEM KILL SESSION '''||s.sid||','||s.serial#||''' IMMEDIATE;' AS "DB Kill",
'orakill '||INSTANCE_NAME||' '||p.spid AS "Windows Kill" ,
'kill -9 '||p.spid AS "Linux Kill"
FROM V$PROCESS p, V$SESSION s ,V$INSTANCE
WHERE p.addr=s.paddr
AND s.username = 'DB_USER'
AND s.osuser = 'os_user'
AND s.program = 'sqlplus.exe';
Elaborate version
SELECT 'ALTER SYSTEM KILL SESSION '||SUBSTR(''''||S.sid||','||S.serial#||'''',1,15)||' IMMEDIATE;' AS "Kill Session",
'kill -9 '||P.spid AS "Linux kill",
S.server,
P.spid AS "Linux process",
S.osuser,
S.module,
S.action,
S.schemaname,
W.event,
S.*, W.* , P.*
FROM V$SESSION_WAIT W, V$SESSION S, V$PROCESS P
WHERE W.sid = S.sid
AND S.paddr = P.addr
AND W.event <> 'SQL*Net message from client'
AND W.event <> 'SQL*Net message to client'
AND S.schemaname <> 'SYS'
--AND S.username = 'MY_USER'
Find sessions locking PL/SQL block
SELECT 'ALTER SYSTEM KILL SESSION '||SUBSTR(''''||SESSIONS.sid||','||SESSIONS.serial#||'''',1,15)||' IMMEDIATE;' AS "Kill Session",
'kill -9 '||PROCESSES.spid AS "Linux kill"
FROM V$SESSION SESSIONS,
V$PROCESS PROCESSES,
V$SQLTEXT SQLTEXT
WHERE SESSIONS.SQL_ADDRESS = SQLTEXT.ADDRESS
AND SESSIONS.paddr = PROCESSES.addr
AND SESSIONS.schemaname <> 'SYS'
AND SQLTEXT.SQL_TEXT LIKE '%<PACKAGE NAME>%';
How to find Locking Jobs:
SELECT 'ALTER SYSTEM KILL SESSION ' || SUBSTR(''''||v_session.sid||','||v_session.serial#||'''', 1,15)||' IMMEDIATE;' AS "Kill Session",
'kill -9 '||v_process.spid AS "LINUX Kill",
'orakill '||INSTANCE_NAME||' '||v_process.spid AS "orakill command",
v_session.machine AS "SERVER",
v_session.osuser AS OS_USER,
v_session.program,
v_session.sid,
v_session.serial#,
v_process.spid,
v_session.username,
v_session.status,
DBA_JOBS.schema_user,
DBA_JOBS.what
FROM v$session v_session,
v$process v_process,
V$INSTANCE,
DBA_JOBS_RUNNING stuck_jobs,
DBA_JOBS
WHERE v_process.addr = v_session.paddr
AND v_session.type != 'BACKGROUND'
AND v_session.osuser = 'MY_USER'
AND v_session.sid = stuck_jobs.sid
AND DBA_JOBS.job(+) = stuck_jobs.job;
How to kill all sessions of a user:
SQL> DROP USER SOME_USER CASCADE;
DROP USER SOME_USER CASCADE
*
ERROR at line 1:
ORA-01940: cannot drop a user that is currently connected
SELECT SESSIONS.sid,
SESSIONS.serial#,
SESSIONS.status,
PROCESSES.spid ,
'ALTER SYSTEM KILL SESSION '''||SESSIONS.sid||','||SESSIONS.serial#||''' IMMEDIATE; ' AS "DB Kill",
'kill -9 '||PROCESSES.spid AS "Linux Kill"
FROM V$SESSION SESSIONS,
V$PROCESS PROCESSES
WHERE SESSIONS.username = 'SOME_USER'
AND PROCESSES.addr(+) = SESSIONS.paddr;
'orakill '||INSTANCE_NAME||' '||v_process.spid AS "orakill command",
v_session.machine AS "SERVER",
v_session.osuser AS OS_USER,
v_session.program,
v_session.sid,
v_session.serial#,
v_process.spid,
v_session.username,
v_session.status,
DBA_JOBS.schema_user,
DBA_JOBS.what
FROM v$session v_session,
v$process v_process,
V$INSTANCE,
DBA_JOBS_RUNNING stuck_jobs,
DBA_JOBS
WHERE v_process.addr = v_session.paddr
AND v_session.type != 'BACKGROUND'
AND v_session.osuser = 'MY_USER'
AND v_session.sid = stuck_jobs.sid
AND DBA_JOBS.job(+) = stuck_jobs.job;
How to kill all sessions of a user:
SQL> DROP USER SOME_USER CASCADE;
DROP USER SOME_USER CASCADE
*
ERROR at line 1:
ORA-01940: cannot drop a user that is currently connected
SELECT SESSIONS.sid,
SESSIONS.serial#,
SESSIONS.status,
PROCESSES.spid ,
'ALTER SYSTEM KILL SESSION '''||SESSIONS.sid||','||SESSIONS.serial#||''' IMMEDIATE; ' AS "DB Kill",
'kill -9 '||PROCESSES.spid AS "Linux Kill"
FROM V$SESSION SESSIONS,
V$PROCESS PROCESSES
WHERE SESSIONS.username = 'SOME_USER'
AND PROCESSES.addr(+) = SESSIONS.paddr;
=============================
How to kill the session
=============================
Option A. Instruct session to terminate itself.Log as System and run command:
ALTER SYSTEM KILL SESSION '222,17163' IMMEDIATE;
When running ALTER SYSTEM KILL SESSION without IMMEDIATE option, the command does not actually kills the session, but rather marks the session as a valid session to be terminated, and it is up to the process, to terminate that session.
If within 60 seconds the process does not terminate the session, then ORA-00031 is thrown.
Option B. Instruct server to terminate session.
Log as System and run command:
ALTER SYSTEM DISCONNECT SESSION 'sid,serial#' POST_TRANSACTION;
ALTER SYSTEM DISCONNECT SESSION 'sid,serial#' IMMEDIATE;
Either POST_TRANSACTION or IMMEDIATE must be used.
The ALTER SYSTEM DISCONNECT SESSION syntax is an alternative method for killing Oracle sessions.
Unlike the KILL SESSION command which asks the session to kill itself, the DISCONNECT SESSION command kills the dedicated server process, which is equivalent to killing the server process from the operating system.
The basic syntax is similar to the KILL SESSION command with the addition of the POST_TRANSACTION clause.
POST_TRANSACTION clause waits for ongoing transactions to complete before disconnecting the session.
IMMEDIATE clause disconnects the session and ongoing transactions are rolled back immediately.
The POST_TRANSACTION and IMMEDIATE clauses can be used together, but the documentation states that in this case the IMMEDIATE clause is ignored.
In addition, the syntax diagram suggests both clauses are optional, but in reality, one or both must be specified or you receive an error.
Option C. Kill Oracle session on the host
Get the V$PROCESS.spid with below SQL.
spid is process ID on Linux, and thread ID on Windows.
SELECT P.spid, S.osuser, S.program
FROM v$process P,
v$session S
WHERE P.addr=S.paddr
Then kill the process(in Linux) / thread(in Windows)
For Windows - use orakill utility.
orakill <SID> <V$PROCESS.spid>
for example:
orakill orainst 2345
where sid = the Oracle instance to target, for example orainst
thread = the thread id of the thread to kill, it is V$PROCESS.spid.
For Linux - just do ps -ef | grep <spid> and the kill -9 <Linux pid>
Option D. set idle_time limit at oracle user profile
ALTER USER MY_PROFILE PROFILE APP_PROF
ALTER PROFILE APP_PROF LIMIT IDLE_TIME 480
Idle time is set in minutes
=============================
Grant to kill session
=============================
ALTER SYSTEM - Is the required privilege.
=============================
Overview=============================
SERVER side
ps ef | grep ora
oracle 6547 1 0 07:49 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 6696 1 0 07:49 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 12718 1 0 08:09 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 13179 1 0 08:11 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 17586 1 0 08:26 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 19932 1 0 08:33 ? 00:00:02 oracleinst (LOCAL=NO)
oracle 25807 1 0 08:53 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 26973 1 0 08:57 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 26975 1 0 08:57 ? 00:00:00 oracleinst (LOCAL=NO)
oracle 26977 1 0 08:58 ? 00:00:00 oracleinst (LOCAL=NO)
These connections are using SQL*net (localhost or remote machines).
Local sessions are identified by: (LOCAL=YES)
These are connections from the database server, a special configuration for the case where Listener and Server are on the same machine, and are configured to use Bequeath protocol.
For example:With Bequeath protocol,the process list these are show as:
oracledsid (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
Net 8 Administrator GuideFor example:With Bequeath protocol,the process list these are show as:
oracledsid (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
=============================
Finding the offending session.
=============================
For a Job
SELECT 'ALTER SYSTEM KILL SESSION ' || SUBSTR(''''||v_session.sid||','||v_session.serial#||'''', 1,15)||' IMMEDIATE;' AS "Kill Session",
'kill -9 '||v_process.spid AS "LINUX Kill",
'orakill '||INSTANCE_NAME||' '||v_process.spid AS "orakill command",
v_session.machine AS "SERVER",
v_session.osuser AS OS_USER,
v_session.program,
v_session.sid,
v_session.serial#,
v_process.spid,
v_session.username,
DBA_JOBS.schema_user,
DBA_JOBS.what
FROM v$session v_session,
v$process v_process,
V$INSTANCE,
DBA_JOBS_RUNNING stuck_jobs,
DBA_JOBS
WHERE v_process.addr = v_session.paddr
AND v_session.type != 'BACKGROUND'
AND v_session.sid = stuck_jobs.sid
AND DBA_JOBS.job(+) = stuck_jobs.job;
For a general session
SELECT 'ALTER SYSTEM KILL SESSION ' || SUBSTR(''''||sid||','||SESSIONS.serial#||'''', 1,15)||' IMMEDIATE;' AS "Kill Session",
'kill -9 '||PROCESSES.spid AS "LINUX Kill",
'orakill '||INSTANCE_NAME||' '||PROCESSES.spid AS "orakill command",
SESSIONS.sid,
SESSIONS.machine,
SUBSTR(SESSIONS.OSUSER,1,30) osuser ,
SESSIONS.PROGRAM,
SUBSTR(SESSIONS.username,1,20) DB_USER,
SUBSTR(SESSIONS.schemaname,1,20) DB_SCHEMA,
PROCESSES.spid,
SESSIONS.status,
PROCESSES.program,
ROUND(PROCESSES.pga_used_mem/1024) AS PROCESS_MEM_KB,
ROUND((SYSDATE-SESSIONS.logon_time)*24,1) AS CONNECTION_TIME_HR,
TO_CHAR(SESSIONS.logon_time,'dd/mm/yy hh24:mi') LOGON_TIME
FROM V$SESSION SESSIONS,
V$PROCESS PROCESSES,
V$INSTANCE
WHERE SESSIONS.paddr=PROCESSES.addr(+)
AND SESSIONS.status = 'ACTIVE'
AND SUBSTR(SESSIONS.schemaname,1,20) <>'SYS'
AND SESSIONS.type != 'BACKGROUND';
=============================
Investigations
=============================
Scenario A.
You have submitted some Oracle Package.
For some reason it is stuck...
SELECT * FROM V$LOCKED_OBJECTS;
SELECT OBJECTS.owner,
OBJECTS.object_name,
OBJECTS.object_type,
SESSIONS.sid,
SESSIONS.serial#,
SESSIONS.status,
SESSIONS.osuser,
SESSIONS.machine
FROM V$LOCKED_OBJECT LOCKED_OBJECT ,
V$SESSION SESSIONS,
DBA_OBJECTS OBJECTS
WHERE SESSIONS.sid = LOCKED_OBJECT.session_id
AND LOCKED_OBJECT.object_id = OBJECTS.object_id;
If there are entries, continue to Scenario C.
SELECT * FROM V$LOCK;
If there are entries, continue to Scenario D.
Scenario B.
A job was running for a long time, longer than normal.
Looks like it is "stuck"
====================
Investigation steps:
====================
SELECT * FROM USER_JOBS - it got valid entries
SELECT * FROM DBA_JOBS_RUNNING - it got the "zombie" job, with the job_id and SID. Let say the SID is 222.
SELECT * FROM V$LOCK WHERE sid=222 - There are entries for that SID.
SELECT * FROM DBA_SCHEDULER_RUNNING_JOBS - Another table to check, for DBMS_SCHEDULER submitted jobs.
Identify the stuck job, get session sid and serial#
SELECT 'ALTER SYSTEM KILL SESSION '''||v_session.sid||','||v_session.serial#||''' IMMEDIATE;'
AS "Kill Command",
'orakill '||instance_name||' '||v_process.spid
AS "orakill command",
v_session.machine AS "SERVER",
v_session.osuser AS OS_USER,
v_session.program,
v_session.sid,
v_session.serial#,
v_process.spid,
v_session.username,
DBA_JOBS.schema_user,
DBA_JOBS.what
FROM v$session v_session,
v$process v_process,
V$INSTANCE,
DBA_JOBS_RUNNING stuck_jobs,
DBA_JOBS
WHERE v_process.addr = v_session.paddr
AND v_session.type != 'BACKGROUND'
AND v_session.sid = stuck_jobs.sid
AND DBA_JOBS.job(+) = stuck_jobs.job;
Scenario C.
User has submitted a DML query, that is involved in a lock on an Object.
Run below SQL to identify the locking session.
SELECT 'ALTER SYSTEM KILL SESSION ' || ''''|| locked_obj.session_id || ',' || v_session.serial# || ''' IMMEDIATE;' ,
locked_obj.session_id||','||v_session.serial# sid_serial,
locked_obj.oracle_username ora_user,
objects.object_name,
objects.object_type,
DECODE(locked_obj.locked_mode,
0, 'None',
1, 'Null',
2, 'Row-S (SS)',
3, 'Row-X (SX)',
4, 'Share',
5, 'S/Row-X (SSX)',
6, 'Exclusive',
TO_CHAR(locked_obj.locked_mode)
) lock_mode,
objects.status,
to_char(objects.last_ddl_time,'dd.mm.yy') last_ddl
FROM DBA_OBJECTS objects,
GV$LOCKED_OBJECT locked_obj,
V$SESSION v_session
WHERE objects.object_id = locked_obj.object_id
and locked_obj.session_id=v_session.sid
ORDER BY 2,3;
Scenario D.
There is a lock, now need to find out why...
Out of scope for this post.
Locking stuff, here: Locks in Oracle by Example
PL/SQL code to Kill long running sessions
GRANT SELECT ON SYS.V_$SESSION to XXX;
GRANT ALTER SESSION TO XXX;
CREATE OR REPLACE PROCEDURE inactive_session_pr AS
v_str VARCHAR2(1000);
BEGIN
FOR i IN (
SELECT sid, serial#, username
FROM V$SESSION
WHERE username IS NOT NULL
AND status='INACTIVE'
AND program='JDBC Thin Client'
AND osuser in('nobody','iu')
AND last_call_et/60/60>8 ---- sessions connection time greater than 8 hours
) LOOP
v_str:='ALTER SYSTEM DISCONNECT SESSION '''||i.sid||','||i.serial#||''' IMMEDIATE';
EXECUTE IMMEDIATE v_str;
BEGIN
INSERT INTO SGA_W_LOG(procedure_name, data, ts_last_modified)
VALUES('inactive_session_pr', 'Killed Session of user '||i.username||' sid-serial#'||' : '||i.sid||'-'||i.serial#, SYSDATE);
commit;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
END LOOP;
END;
/
AWR report
When investigating for locks in AWR, look for Foreground Wait Events => enq: TX - row lock contention.
Below is an example of Instance having many locking issues.
No comments:
Post a Comment