Сеанс – это специфическое соединение пользователя к экземпляру Oracle через пользовательский процесс. При работе с выделенным сервером для каждого такого сеанса создается отдельный серверный процесс. Обмен пользователя с экземпляром базы данных происходит через пользовательский процесс на клиентской машине, который в свою очередь через драйвер клиента Oracle Net работает с выделенным серверным процессом, взаимодействующим непосредственно с самим экземпляром Oracle. Иногда возникают ситуации, когда требуется уничтожить какие либо сеансы. Такое обычно такое происходит, когда требуется прервать долго выполняющийся сеанс или возникает необходимость в проведении административных работ с отключением всех сеансов. Так же может понадобиться и просто откатить незафиксированную транзакцию, если за данным сеансом выстроилась большая очередь. Бывают и так называемые “потерянные сеансы”, нуждающиеся в уничтожении. В этой главе мы научимся идентифицировать такие сеансы, уничтожать их, а так же рассмотрим сложности, возникающие при этом процессе.

Идентифицируем сеанс

Процесс уничтожения сеанса заключается в откате всех незафиксированных транзакций сеанса, освобождении используемых им ресурсов и уничтожении серверного процесса. Выполняется эта операция с помощью SQL команды ALTER SYSTEM KILL SESSION 'sid,serial#'. Чтобы выполнить эту команду, нам необходимо знать идентификатор sid и порядковый номер serial# сеанса. Для этого нам необходимо обратится к системным представлениям v$session и v$process с целью поиска записи параметров конкретного сеанса. Но прежде мы вкратце ознакомимся с данными системными представлениями. Первое из них v$session показывает все установленные сеансы экземпляра Oracle. Второе v$process отображает соответствующие им выделенные серверные процессы. Оба этих представления основаны на так называемых x$ таблицах: x$ksuse и x$ksupr. Если мы сделаем запрос к этим таблицам, то обнаружим, что количество строк в этих таблицах соответствует параметрам инициализации sessions и processes, и не совпадает с количеством строк отображаемых представлениями v$session и v$process.

Подключение: SYS@XE AS SYSDBA
Oracle Database 10g Express Edition Release 10.2.0.1.0 – Production

SQL> SELECT 'x$ksuse' "X$TABLES", count(*) FROM x$ksuse union SELECT 
'x$ksupr',count(*) FROM x$ksup;
 
X$TABLES COUNT(*)
-------- --------
x$ksupr  40      
x$ksuse  49  

SQL> SELECT name, value FROM v$parameter WHERE name IN 
('processes','sessions');
 
NAME      VALUE
--------- -----
processes 40   
sessions  49   

SQL> SELECT 'v$session' "VIEW", count(*) FROM v$session union SELECT 
'v$process',count(*) FROM v$process;
 
VIEW      COUNT(*)
--------- --------
v$process 22      
v$session 16      

Так как x$ таблицы, по сути, являются наборами определённых структур в памяти SGA, то можно предположить, что память под структуры хранящие информацию о сеансах и серверных процессах выделяется заранее и их количество всегда равно значениям параметров инициализации session и process. Рассмотрим более подробно некоторые поля этих двух x$ таблиц. Одна из таблиц x$ksuse, хранит информацию о сеансах экземпляра Oracle и первое, интересующее нас в ней поле indx, обозначает идентификатор сеанса. Оно имеет сквозную нумерацию от 1 до значения параметра sessions и в представлении v$session соответствует полю sid. Значение в этом столбце практически указывает на номер записи в таблице x$ksuse и следовательно может быть повторно использовано после того как данный сеанс закончит работу. Второе поле ksuseser – это порядковый номер сеанса. В представлении v$session данное поле соответствует полю serial# и имеет уникальное неповторяющееся значение для каждого сеанса. Третье поле, которое мы рассмотрим это поле ksusepro – адрес структуры памяти серверного процесса, которому принадлежит данный сеанс. В представлении v$session оно отражается как поле paddr. В дополнении к таблице x$ksuse мы так же рассмотрим структуру таблицы x$ksupr, которая определяет выделенные серверные процессы Oracle. Здесь нас будут интересовать два поля. Это поле addr - адрес структуры памяти выделенного серверного процесса. В представлении v$process он имеет такое же название. И второе поле это ksuprpid – идентификатор процесса операционной системы. В представлении v$process поле spid. И так мы ознакомились с представлениями и параметрами идентифицирующими сеанс. Теперь в качестве примера попробуем получить sid и serial# сеанса предварительно созданного нами пользователя AH. Для этого выполним следующий запрос, соединив два представления v$session и v$process по полям addr и paddr:

SQL> SELECT sid, s.serial#, s.status, p.spid FROM v$session s, v$process p 
WHERE s.username = 'AH' AND paddr = addr(+)
 
SID SERIAL# STATUS   SPID
--- ------- -------- ----
22  11      INACTIVE 1568 

Параметры получены. Теперь можно приступить к уничтожению сеанса.

Уничтожаем неактивный сеанс

Выполним команду ALTER SYSTEM KILL SESSION для указанного выше сеанса:

SQL> ALTER SYSTEM KILL SESSION '22,11' 

System altered 

Посмотрим состояние сеанса:

SQL> SELECT sid,s.serial#,s.status,p.spid FROM v$session s, v$process p WHERE 
s.username = 'AH' AND paddr = addr(+)
 
SID SERIAL# STATUS SPID
--- ------- ------ ----
22  11      KILLED

Если сеанс неактивный и не содержит незавершенных транзакций, то он помечается со статусом KILLED . Поле PADDR уже не указывает на адрес структуры выделенного серверного процесса. Но серверный процесс не освобождается:

SQL> SELECT addr, pid, spid FROM v$process WHERE spid = 1568
 
ADDR     PID SPID
-------- --- ----
2A136324 21  1568

Такое состояние будет продолжаться до тех пор, пока пользователь снова попытается использовать сеанс или отключиться от сервера. В первом случае пользователю выдается сообщение об ошибке ORA-00028:

SQL> SELECT sysdate FROM dual
 
SELECT sysdate FROM dual
*
Ошибка в строке 1:
ORA-00028: your session has been killed 

Информация при этом о сеансе из представления v$session исчезает:

SQL> SELECT sid, s.serial#, s.status, p.spid FROM v$session s, v$process p 
WHERE s.username = 'AH' AND paddr = addr(+)
 
SID SERIAL# STATUS SPID
--- ------- ------ ----

Выбрано: 0 строк

Но остаётся в таблице x$ksuse:

SQL> SELECT count(*) FROM x$ksuse WHERE ksuudsna = 'AH'
 
COUNT(*)
--------
1       

Выбрано: 1 строка

Серверный процесс при этом всё ещё существует:

SQL>  SELECT addr, pid, spid FROM v$process WHERE spid = 1568
 
ADDR     PID SPID
-------- --- ----
2A136324 21  1568

Если пользователь продолжит пытаться выполнять команды, то экземпляр на все дальнейшие попытки будет отвечать ошибкой ORA-01012: not logged on:

SQL> SELECT sysdate FROM dual
 
SELECT sysdate FROM dual
*
Ошибка в строке 1:
ORA-01012: not logged on

В дальнейшем серверный процесс будет уничтожен только в том случае, если пользователь предпримет попытку сам разорвать соединение. Только в этом случае процесс уничтожения сеанса можно считать законченным.

Уничтожаем сеанс с незафиксированными транзакциями

Если в сеансе имеются незафиксированные транзакции, то при выдаче команды ALTER SYSTEM KILL SESSION происходит откат этих транзакций. Занимается откатом мертвых транзакции фоновый процесс Oracle SMON . Убедимся в этом, выполнив следующий пример:

SQL> CREATE TABLE table1 (id NUMBER(11),name VARCHAR2(20));

Таблица создана

SQL> DECLARE
  2>   i INTEGER;
  3> BEGIN
  4>   FOR i IN 1..500000 LOOP
  5>     INSERT INTO table1 (id,name) VALUES (i,'ITEM'||i);
  6>   END LOOP;
  7> END;  
 
PL/SQL procedure successfully completed

Теперь попытаемся уничтожить этот сеанс:

SQL> ALTER SYSTEM KILL SESSION '14,151'; 

System altered  

Сеанс уничтожается, не дожидаясь окончания отката транзакции. Через некоторое время в каталоге, определяемом параметром background_dump_dest, появится трассировочный файл процесса SMON, который будет содержать строку примерно следующего вида:

Dead transaction 0x0006.00a.00000091 recovered by SMON

Это означает, что мёртвая транзакция 0x0006.00a.00000091 была восстановлена процессом SMON. Если же в экземпляре используется параллельное восстановление, то функции отката берёт на себя вновь образующийся от SMON дочерний процесс. Его можно увидеть, если выполнить следующий запрос сразу после уничтожения сеанса:

SQL> SELECT sid, username, status, program FROM v$session WHERE program LIKE 
'% P00%'; 

SID USERNAME STATUS PROGRAM  
--- -------- ------ -----------------  
16           ACTIVE ORACLE.EXE (P000) 

Выбрано: 1 строка

В данном случае трассировочного файла не образуется, но в журнальном файле Oracle появляется запись вида о попытке параллельного восстановления:

SMON: Parallel transaction recovery tried

Так как фоновый процесс SMON обладает низким приоритетом обработки, то при большой загрузке он может длительное время откатывать транзакции. Поэтому надо с осторожностью уничтожать такие сеансы.

Уничтожаем серверный процесс

Иногда бывает, что пользовательское приложение завершается аварийно, вместе с ним аварийно завершается и пользовательский процесс. К примеру, отключите сеть, выгрузите приложение, затем снова включите сеть. Для того чтобы уничтожить такие сеансы, Oracle с периодичностью в минутах задаваемой параметром sqlnet.expire_time, который находится в файле sqlnet.ora посылает по всем соединениям пустые пакеты, которые игнорируются работающими пользовательскими процессами. Если физического соединения нет, то Oracle помечает сеанс как убитый и приступает к его уничтожению. В некоторых случаях данный механизм не срабатывает, и возникают так называемые “потерянные сеансы”, то есть сеансы не связанные с пользовательскими процессами. Такие сеансы могут находиться в неопределённом состоянии долгое время. Обычно они легко уничтожаются с помощью команды ALTER SYSTEM KILL SESSION. Но если выполнение команды не приносит результатов, и сеанс продолжает долгое время, находится в статусе KILLED, то придется вмешаться в уничтожение такого сеанса на уровне операционной системы, то есть уничтожить серверный процесс средствами ОС. Операция эта опасная и делать её надо очень аккуратно, чтобы случайно не уничтожить фоновые процессы экземпляра. Для этого желательно всегда запоминать значение идентификатора SPID серверного процесса относящегося к сеансу. Если же значение поля PADDR в представлении v$session уже не соотноситься с адресом в поле ADDR представления v$process , то серверный процесс придется искать приблизительно. В Unix это можно сделать с помощью команды ps , примерно сравнивая время соединения сеанса в поле logon_time представления v$session со временем образования процесса в колонке STARTED результата выполнения команды ps.

alfa> ps aux 
USER   PID   %CPU %MEM VSZ   RSS  TTY S  STARTED  TIME    COMMAND 
oracle 16051 0.0  0.0  2.16M 1.9M ??  I  16:55:14 0:01.88 oraclealfa 
(DESCRIPTION=( 

В системе Windows сеансы существуют в виде потоков. Поэтому определить такой сеанс будет сложнее. Чтобы облегчить задачу можно выполнить запрос к представлению v$process, который покажет все процессы, у которых значения поля ADDR не соответствует ни одному значению в поле PADDR представления v$session:

SQL> SELECT addr, pid, spid, program FROM v$process WHERE addr NOT IN (SELECT 
paddr FROM v$session) 
 
ADDR     PID SPID PROGRAM          
-------- --- ---- -----------------
2A12EC64 1        PSEUDO           
2A1333A4 13  1220 ORACLE.EXE (D000)
2A133994 14  1148 ORACLE.EXE (S000)
2A133F84 15  1200 ORACLE.EXE (S001)
2A134574 16  1204 ORACLE.EXE (S002)
2A134B64 17  1240 ORACLE.EXE (S003)
2A135154 18  652  ORACLE.EXE (SHAD)

Выбрано: 7 строк

Здесь мы видим такой процесс со значением идентификатора процесса в операционной системы SPID равным 652. Попробуем уничтожить данный серверный процесс. В системе Windows это делается с помощью утилиты командной строки orakill:

C:\>orakill XE 652

Kill of thread id 652 in instance XE successfully signalled.

В Unix с помощью команды kill -9 spid .

alfa> kill -9 16472 

Уничтожаем активный сеанс

Выше мы рассмотрели варианты уничтожения неактивных сеансов. Более сложная ситуация возникает в случае активности сеанса. Здесь всё зависит от того, что делает сеанс в момент времени уничтожения. Если выполняется оператор SQL , то сеанс уничтожается, и пользователь немедленно получает сообщение ошибки ORA-00028: your session has been killed. Если же сеанс выполняет, к примеру, откат транзакции или сетевой ввод-вывод, то его уничтожение произойдет только после завершения текущей операции. В этом случае сеанс, в котором выполняется команда ALTER SYSTEM KILL SESSION, будет ожидать. Если время ожидания превысит 60 секунд, то данному сеансу выдается сообщение ошибки ORA-00031. Уничтожаемый сеанс при этом обретает статус KILLED, но продолжает выполнять текущую операцию.

SQL> SELECT s.sid, s.serial#, s.status, p.spid FROM v$session s, v$process p 
WHERE s.username = 'AH' AND p.addr = s.paddr; 

SID SERIAL# STATUS SPID  
--- ------- ------ ----  
14       26 ACTIVE 1176 

Выбрано: 1 строка  

SQL> ALTER SYSTEM KILL SESSION '14,26'; 

ALTER SYSTEM KILL SESSION '14,26'  
*  
Ошибка в строке 1: 
ORA-00031: session marked for kill 

SQL> SELECT sid,s.serial#,s.status FROM v$session s WHERE s.username = 'TEST'; 

SID SERIAL# STATUS 
--- ------- ------  
14       26 KILLED  

Выбрано: 1 строка  

Выводы

  • Если сеанс не содержит незавершенных транзакций, то такой сеанс можно уничтожать без проблем.
  • Уничтожение серверного процесса сеанса на уровне OC необходимо выполнять только в случае крайней необходимости.
  • Если сеанс содержит незавершенные транзакции, то прежде чем уничтожать такой сеанс посмотрите, сколько изменений было сделано в транзакции и какова загрузка Oracle в текущий момент. Если эти значения высоки, то уничтожение сеанса лучше перенести на более спокойный отрезок времени.
  • Если сеанс активный и выполняет, к примеру, откат транзакции или сетевой вывод то лучше подождать завершения текущей операции сеанса. Если выполнение этой операции затягивается, то необходимо уничтожить серверный процесс на уровне OC . Но делать это лучше в случае крайней необходимости. Практическое администрирование Oracle – Экземпляр