【Oracle】セッションの確認・強制切断方法完全ガイド|V$SESSION・ロック調査・ALTER SYSTEM KILL SESSION

【Oracle】セッションの確認・強制切断方法完全ガイド|V$SESSION・ロック調査・ALTER SYSTEM KILL SESSION Oracle

Oracleデータベースを運用していると、「バッチ処理が終わらない」「画面が固まってロールバックもできない」といったトラブルに直面することがあります。こうした状況の多くは、ロック待ちやゾンビセッションが原因です。本記事では、セッション情報を確認するV$SESSIONの使い方から、ロックを保持するセッションの特定、そしてALTER SYSTEM KILL SESSIONによる強制切断まで、実務で使える手順を体系的に解説します。

この記事でわかること

  • V$SESSIONを使った現在のセッション一覧の確認方法
  • ロック待ちセッションの特定(V$LOCK・DBA_BLOCKERS・DBA_WAITERS)
  • ALTER SYSTEM KILL SESSIONによる強制切断の手順
  • IMMEDIATE オプションとの使い分け
  • 接続数の上限確認・変更方法
  • デッドロック(ORA-00060)の検出と対処
スポンサーリンク

V$SESSIONとは

V$SESSIONはOracleの動的パフォーマンスビュー(V$ビュー)の一つで、現在データベースに接続しているすべてのセッション情報を保持しています。SELECT権限さえあれば一般ユーザーでも参照できますが、全ユーザーのセッションを見るにはDBAロールまたはSELECT ANY DICTIONARYシステム権限が必要です。

主要な列は次のとおりです。

列名 説明
SID セッションID(KILLコマンドに使用)
SERIAL# 同一SIDの再利用を区別するシリアル番号(KILLコマンドに使用)
USERNAME ログインしているDBユーザー名
STATUS セッション状態(ACTIVE / INACTIVE / KILLED / CACHED / SNIPED)
OSUSER OSユーザー名
MACHINE クライアントのマシン名
PROGRAM 接続に使用しているプログラム名
SQL_ID 現在実行中のSQL識別子
WAIT_CLASS 待機クラス(Idle / Application / Concurrency 等)
SECONDS_IN_WAIT 現在の待機時間(秒)
LOGON_TIME セッションのログイン時刻
LAST_CALL_ET 最後のSQL実行からの経過時間(秒)

全セッション一覧を確認する

まず基本的なセッション一覧取得から始めます。

V$SESSION ── 全セッション確認
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.osuser,
    s.machine,
    s.program,
    s.logon_time,
    s.last_call_et AS last_call_sec
FROM
    v$session s
ORDER BY
    s.logon_time;

SYS や SYSTEMのバックグラウンドプロセスも含まれるため、ユーザー接続だけを確認したい場合は WHERE username IS NOT NULL を追加します。

V$SESSION ── ユーザーセッションのみ抽出
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    TO_CHAR(s.logon_time, 'YYYY-MM-DD HH24:MI:SS') AS logon_time,
    s.last_call_et AS last_call_sec
FROM
    v$session s
WHERE
    s.username IS NOT NULL
ORDER BY
    s.logon_time;

アクティブセッションだけを絞り込む

障害対応時は STATUS = ‘ACTIVE’ のセッションだけに絞ると情報が整理しやすくなります。ACTIVE はSQLを実行中(CPUを使っているか、何かを待っている)の状態を指します。

V$SESSION + V$SQL ── 実行中SQL付きアクティブセッション
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.wait_class,
    s.seconds_in_wait,
    q.sql_text
FROM
    v$session s
    LEFT JOIN v$sql q ON s.sql_id = q.sql_id
                      AND s.sql_child_number = q.child_number
WHERE
    s.status = 'ACTIVE'
    AND s.username IS NOT NULL
ORDER BY
    s.seconds_in_wait DESC;

V$SQLを結合することで、そのセッションが現在実行しているSQLテキストも合わせて確認できます。V$SQLの詳しい使い方は【Oracle】V$SQLビューを使用して直前に発行されたSQLを確認する方法を参照してください。

長時間実行中のセッションを特定する

バッチ処理が長時間止まっている場合、LAST_CALL_ET(最終SQL呼び出しからの経過秒数)を使ってフィルタリングします。

V$SESSION ── 30分以上実行中のセッション
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    ROUND(s.last_call_et / 60, 1)    AS elapsed_min,
    s.wait_class,
    s.event,
    s.seconds_in_wait
FROM
    v$session s
WHERE
    s.username IS NOT NULL
    AND s.last_call_et > 1800        -- 1800秒 = 30分
ORDER BY
    s.last_call_et DESC;
LAST_CALL_ET の注意点
LAST_CALL_ET は「最後のSQLが呼ばれてからの経過時間」であり、INACTIVEセッションの場合はSQLが終了してからのアイドル時間を示します。ACTIVEセッションの場合は現在のSQLが開始してからの実行時間を意味します。

ロック待ちセッションを特定する

ロック競合は最もよく遭遇するトラブルの一つです。段階的に調査する方法を解説します。

V$LOCK でロック状況の全体像を把握する

V$LOCK ── ロック一覧(TM/TXロックのみ)
SELECT
    l.sid,
    l.type,
    l.id1,
    l.id2,
    l.lmode,          -- 保持しているロックモード(2=RS, 3=RX, 4=S, 5=SRX, 6=X)
    l.request,        -- 要求しているロックモード(0=なし、>0=待機中)
    l.block,          -- 1=他のセッションをブロックしている
    l.ctime           -- このロック状態になってからの秒数
FROM
    v$lock l
WHERE
    l.type IN ('TM', 'TX')  -- TM=テーブルロック, TX=トランザクションロック
ORDER BY
    l.block DESC, l.ctime DESC;

BLOCK = 1 のセッションが「加害者」(ロックを保持して他をブロックしている側)です。REQUEST > 0 のセッションが「被害者」(ロック待ちしている側)です。

DBA_BLOCKERS / DBA_WAITERS でブロック関係を可視化する

Oracle 10g以降はDBA_BLOCKERSとDBA_WAITERSビューを使うと、ブロック関係をシンプルに把握できます。

DBA_BLOCKERS ── ロックを保持して他をブロックしているセッション
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.machine,
    s.program,
    s.status,
    s.last_call_et AS elapsed_sec
FROM
    v$session s
WHERE
    s.sid IN (SELECT blocking_session FROM v$session WHERE blocking_session IS NOT NULL);
V$SESSION ── ロックを待っているセッション
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.machine,
    s.program,
    s.blocking_session,       -- このセッションをブロックしているSID
    s.seconds_in_wait,
    s.wait_class,
    s.event
FROM
    v$session s
WHERE
    s.blocking_session IS NOT NULL;

どのオブジェクトがロックされているか確認する

ロックされているテーブル名を特定するには、V$LOCKED_OBJECTとDBA_OBJECTSを結合します。

V$LOCKED_OBJECT + DBA_OBJECTS ── ロック中オブジェクト特定
SELECT
    lo.session_id                    AS sid,
    s.serial#,
    s.username,
    s.machine,
    o.owner,
    o.object_name,
    o.object_type,
    lo.locked_mode,                  -- 2=RS, 3=RX, 4=S, 5=SRX, 6=X
    s.status
FROM
    v$locked_object lo
    JOIN v$session   s ON lo.session_id = s.sid
    JOIN dba_objects  o ON lo.object_id  = o.object_id
ORDER BY
    o.object_name;

ブロック連鎖を一覧表示する(総合クエリ)

実務では「誰が誰をブロックし、どのテーブルをロックしているか」を一画面で把握したい場面が多くあります。次のクエリがそれを実現します。

ブロック連鎖の総合確認クエリ
SELECT
    b.sid                            AS blocker_sid,
    b.serial#                        AS blocker_serial,
    b.username                       AS blocker_user,
    b.machine                        AS blocker_machine,
    b.program                        AS blocker_program,
    b.last_call_et                   AS blocker_elapsed_sec,
    w.sid                            AS waiter_sid,
    w.serial#                        AS waiter_serial,
    w.username                       AS waiter_user,
    w.seconds_in_wait                AS waiter_wait_sec,
    o.owner || '.' || o.object_name  AS locked_object
FROM
    v$session w
    JOIN v$session      b  ON w.blocking_session = b.sid
    JOIN v$locked_object lo ON lo.session_id = b.sid
    JOIN dba_objects      o  ON lo.object_id  = o.object_id
ORDER BY
    waiter_wait_sec DESC;
ポイント:読み方
BLOCKER_SIDがロックを保持している「加害者」セッションです。WAITER_SIDが待ち続けている「被害者」セッションです。KILLするのはBLOCKER側であり、WAITER側をKILLしても根本解決になりません。

セッションを強制切断する(ALTER SYSTEM KILL SESSION)

ロックしているセッションが特定できたら、ALTER SYSTEM KILL SESSION で強制切断します。実行にはALTER SYSTEMシステム権限(DBAロール等)が必要です。

ALTER SYSTEM KILL SESSION ── 基本構文
-- 構文: ALTER SYSTEM KILL SESSION 'SID,SERIAL#';
ALTER SYSTEM KILL SESSION '123,456';

SIDとSERIAL#はV$SESSIONから取得した値を使います。セッションが切断されると、そのセッションのトランザクションはロールバックされ、保持していたロックは解放されます。

KILL SESSION の動作とステータス遷移

KILL SESSION を実行しても、セッションがすぐに消えるとは限りません。状態は次のように遷移します。

STATUSの値 説明
ACTIVE 通常実行中(またはKILL前)
KILLED KILLコマンドを受け付けた。ロールバック中または次のSQL発行時に切断される
SNIPED プロファイルの接続時間制限により切断対象になったがまだ残っている状態

STATUSが「KILLED」のまま長時間消えない場合は、大きなトランザクションのロールバックが進行中であることが多く、通常は待つのが正しい対応です。無理に操作するとデータ不整合の原因になります。

IMMEDIATE オプション(即時切断)

通常のKILL SESSIONはロールバックが完了してから切断しますが、IMMEDIATEオプションを付けると強制的に即時切断します。ただし、OSレベルのプロセスを強制終了するため、アーカイブログが大量に発生することがあり、本番環境では慎重に使用してください。

KILL SESSION IMMEDIATE ── 即時切断
-- 通常(ロールバック後に切断)
ALTER SYSTEM KILL SESSION '123,456';

-- 即時切断(ロールバック中でも強制終了)
ALTER SYSTEM KILL SESSION '123,456' IMMEDIATE;

-- DISCONNECT SESSION(ネットワーク接続も即時切断)
ALTER SYSTEM DISCONNECT SESSION '123,456' IMMEDIATE;
注意:IMMEDIATE の使いどころ
IMMEDIATE は長時間のロールバックを待てない緊急時に使います。ただし Oracleプロセスが異常終了することがあり、その場合は PMON(プロセスモニター)が後処理を引き継ぎます。本番環境では影響を十分確認してから実行してください。

複数セッションをまとめてKILLするスクリプト生成

多数のセッションを一括切断したい場合、KILLコマンドを動的に生成すると便利です。

KILL SESSION コマンドの一括生成
-- 特定ユーザーの全セッションに対するKILLコマンドを生成
-- CHR(39)は単一引用符(')を表す
SELECT
    'ALTER SYSTEM KILL SESSION ' || CHR(39) || sid || ',' || serial# || CHR(39) || ' IMMEDIATE;'
        AS kill_command
FROM
    v$session
WHERE
    username = 'APPUSER'          -- KILLしたいユーザー名に変更
    AND status != 'KILLED';       -- すでにKILL済みは除外

生成されたKILLコマンドを確認してから手動で実行します。WHERE句をカスタマイズすることで、特定のMACHINEからの接続や、一定時間以上アイドルのセッションなども絞り込めます。

接続数(セッション数)の確認と上限変更

「ORA-00018: セッション数の上限に達しました」エラーが出た場合、現在の接続数上限を確認して必要に応じて変更します。

現在の接続数と上限を確認する

接続数の現状確認
-- 初期化パラメータの確認
SELECT name, value, description
FROM   v$parameter
WHERE  name IN ('processes', 'sessions', 'transactions');

-- 現在の接続セッション数(ユーザーセッションのみ)
SELECT COUNT(*) AS current_sessions
FROM   v$session
WHERE  username IS NOT NULL;

-- ステータス別の内訳
SELECT status, COUNT(*) AS cnt
FROM   v$session
WHERE  username IS NOT NULL
GROUP BY status
ORDER BY cnt DESC;

PROCESSES はOSプロセス数の上限で、SESSIONS は論理セッション数の上限です。通常 SESSIONS = PROCESSES * 1.1 + 5 として自動計算されますが、明示的に設定することもできます。

接続上限を変更する(SPFILEが必要)

PROCESSES/SESSIONS 上限変更
-- 現在の値を確認
SHOW PARAMETER processes;
SHOW PARAMETER sessions;

-- SPFILEを使って変更(再起動後に有効)
ALTER SYSTEM SET processes  = 500 SCOPE = SPFILE;
ALTER SYSTEM SET sessions   = 555 SCOPE = SPFILE;

-- 変更後は再起動が必要
SHUTDOWN IMMEDIATE;
STARTUP;

-- 反映確認
SHOW PARAMETER processes;
SHOW PARAMETER sessions;
注意:PROCESSESの変更は再起動が必要
PROCESSESとSESSIONSは静的パラメータのため、SCOPE=SPFILEを指定し、データベースを再起動しないと反映されません。本番環境では計画メンテナンスウィンドウで実施してください。

アイドルセッションを検出する

長時間アイドルのセッションが大量に残ると接続枠を圧迫します。定期的に確認してKILLするか、プロファイルでIDLE_TIME(接続時間制限)を設定することを検討します。

アイドルセッションの検出(1時間以上)
SELECT
    s.sid,
    s.serial#,
    s.username,
    s.machine,
    s.program,
    ROUND(s.last_call_et / 3600, 1) AS idle_hours,
    TO_CHAR(s.logon_time, 'YYYY-MM-DD HH24:MI:SS') AS logon_time
FROM
    v$session s
WHERE
    s.username IS NOT NULL
    AND s.status = 'INACTIVE'
    AND s.last_call_et > 3600        -- 3600秒 = 1時間以上アイドル
ORDER BY
    s.last_call_et DESC;

デッドロック(ORA-00060)の検出と対処

2つのセッションがお互いのロックを待つ「デッドロック」が発生すると、Oracleは自動的に一方のセッションにORA-00060エラーを返して解消します。ただし、エラーを受けたセッションのトランザクションは自動的にはロールバックされないため、アプリ側でのハンドリングが必要です。

デッドロックの発生をアラートログで確認する

アラートログの場所確認
-- アラートログのパスを確認
SELECT value FROM v$parameter WHERE name = 'background_dump_dest';

-- または診断ディレクトリから確認
SELECT value FROM v$diag_info WHERE name = 'Diag Trace';

アラートログ(alert_<SID>.log)に「ORA-00060: deadlock detected」というメッセージとトレースファイル名が記録されます。トレースファイルを確認することで、どのセッションがどのオブジェクトに対してデッドロックを起こしたかを特定できます。

デッドロックが発生しやすいパターンと対策

デッドロックを引き起こしやすいパターン
-- セッションA                      セッションB
-- ───────────────────              ────────────────────
UPDATE tbl SET col=1 WHERE id=1;   UPDATE tbl SET col=2 WHERE id=2;
                                   UPDATE tbl SET col=2 WHERE id=1; -- Aが保持するidのロックを待つ
UPDATE tbl SET col=1 WHERE id=2;   -- Bが保持するidのロックを待つ → デッドロック

デッドロック対策の基本は「複数テーブル・複数行を更新する場合は常に同じ順序でアクセスする」ことです。また、トランザクションをできるだけ短くし、必要な行だけを最初にロック(SELECT FOR UPDATE)してから処理を進める設計も有効です。

よくある質問と対処

ALTER SYSTEM KILL SESSIONで「ORA-27143」が発生する

OSプロセスがすでに存在しない(クライアントとの接続が物理的に切れているが、サーバー側のセッション情報が残っている)場合に発生します。IMMEDIATE オプションを付けて再度実行するか、数分待ってから再確認してください。

KILL後もSTATUS=KILLEDが続く

トランザクションのロールバック中です。変更量が大きいほど時間がかかります。V$SESSION から消えるまで待つのが原則です。ただし、OracleのPMONプロセスがロールバックを代行しているため、手動介入は不要です。

自分のセッションのSIDを確認する

自セッションのSID/SERIAL#確認
SELECT sid, serial#, username, status
FROM   v$mystat
WHERE  statistic# = 0;

-- または
SELECT sys_context('USERENV', 'SID') AS my_sid FROM dual;

別のセッションが保持するトランザクションの内容を確認する

V$TRANSACTION ── アクティブなトランザクション確認
SELECT
    t.addr,
    t.xidusn,
    t.xidslot,
    t.xidsqn,
    t.status,
    t.used_ublk * 8192 / 1024          AS undo_kb,
    t.used_urec                         AS undo_records,
    s.sid,
    s.serial#,
    s.username,
    ROUND(t.start_date - SYSDATE, 4)   AS start_offset_day
FROM
    v$transaction t
    JOIN v$session s ON t.addr = s.taddr
ORDER BY
    undo_kb DESC;

UNDO_KBが大きいほどロールバックに時間がかかります。遅いSQLのさらに詳しい特定方法は【Oracle】遅いSQLを特定する方法|V$SQLやAWRレポートの活用法も参考にしてください。

セッション管理の実務チェックリスト

状況 使うビュー・コマンド
セッション全体の把握 V$SESSION
実行中SQLを確認したい V$SESSION + V$SQL(SQL_ID結合)
ロックの全体像確認 V$LOCK(BLOCK=1 がブロッカー)
ブロッカー特定 V$SESSION.BLOCKING_SESSION カラム
ロックされているテーブル名 V$LOCKED_OBJECT + DBA_OBJECTS
セッション強制切断 ALTER SYSTEM KILL SESSION ‘SID,SERIAL#’
即時切断 ALTER SYSTEM KILL SESSION ‘…’ IMMEDIATE
接続数上限確認 V$PARAMETER(processes / sessions)
デッドロック発生確認 アラートログ(alert_SID.log)

まとめ

Oracleのセッション管理はV$SESSIONを起点に、V$LOCK・V$LOCKED_OBJECT・DBA_OBJECTSといったビューを組み合わせることで体系的に調査できます。

  • ブロッカーの特定には V$SESSION.BLOCKING_SESSION カラムが最も手早い
  • ロックされているオブジェクトはV$LOCKED_OBJECTとDBA_OBJECTSの結合で特定する
  • 強制切断にはALTER SYSTEM KILL SESSIONを使い、緊急時のみIMMEDIATEを付ける
  • KILL後のKILLED状態はロールバック中なので、完了を待つのが原則
  • 接続数上限の変更はPROCESSESパラメータをSPFILEで変更して再起動が必要

ユーザー権限の確認方法については【Oracle】ユーザ権限を確認する方法完全ガイド、データベースへの接続ができない場合の原因調査は【Oracle】ORA-12560: TNS プロトコル・アダプタ・エラーの原因と解決方法も合わせて参照してください。