RAC環境におけるロック競合の課題
Oracle RAC(Real Application Clusters)環境、特にOLTPとOLAPが混在するシステムでは、リソース管理が適切でない場合、パフォーマンスの低下を招くことがあります。その中でも特に深刻な問題の一つが、オブジェクトロックに起因するシステム停滞です。
例えば、あるPL/SQLパッケージが長時間のセッションで実行中に、別のセッションがそのパッケージをコンパイル(再定義)しようとするケースを想定してください。コンパイルを行うセッションは、対象オブジェクトに対する排他ロック(Exclusive Lock)の取得を試みます。しかし、実行中のセッションがロックを保持しているため、コンパイル・セッションはロック獲得のために他の全インスタンスに対してポーリングを繰り返します。
RAC環境では、インスタンス間の通信オーバーヘッドが大きいため、このポーリング処理がCPUリソースを大量に消費し、結果としてシステム全体の応答速度低下やログイン遅延を引き起こします。
監視のためのデータディクショナリ分析
標準的なDBA_DDL_LOCKSビューは単一インスタンス向けの情報しか提供せず、CDB(マルチテナント)環境やRAC全体での詳細な特定には限界があります。より詳細な情報を得るためには、内部固定表であるX$KGLLK(ライブラリキャッシュロック)とX$KGLOB(ライブラリキャッシュオブジェクト)を参照する必要があります。
- X$KGLOB: カーネル・ジェネリック・ライブラリ・キャッシュ・オブジェクト。オブジェクトの定義情報を保持します。
- X$KGLLK: カーネル・ジェネリック・ライブラリ・キャッシュ・ロック。オブジェクトに対するロックとセッション情報を管理します。
KGLLKMOD列は保持しているロックモード(0:なし、1:NULL、2:共有、3:排他)、KGLLKREQ列は要求しているロックモードを示します。
CDB対応RAC監視ビューの作成
全インスタンスおよび全PDB(Pluggable Database)にわたって、オブジェクトをロックしているセッションを特定するためのカスタムビューを作成します。以下のSQLでは、ANSI準拠の結合構文を使用し、可読性を高めた形で定義しています。このビューはCDB$ROOT上で作成してください。
CREATE OR REPLACE VIEW gv_ddl_lock_monitor AS
SELECT
s.con_id,
pdb.pdb_name,
s.inst_id,
s.sid,
s.serial#,
SUBSTR(obj.kglnaown, 1, 128) AS object_owner,
SUBSTR(obj.kglnaobj, 1, 1000) AS object_name,
CASE obj.kglhdnsp
WHEN 0 THEN 'Cursor'
WHEN 1 THEN 'Table/Procedure/Type'
WHEN 2 THEN 'Body'
WHEN 3 THEN 'Trigger'
WHEN 4 THEN 'Index'
WHEN 5 THEN 'Cluster'
WHEN 13 THEN 'Java Source'
WHEN 14 THEN 'Java Resource'
WHEN 32 THEN 'Java Data'
ELSE TO_CHAR(obj.kglhdnsp)
END AS object_type,
CASE lk.kgllkmod
WHEN 0 THEN 'None'
WHEN 1 THEN 'Null'
WHEN 2 THEN 'Share'
WHEN 3 THEN 'Exclusive'
ELSE 'Unknown'
END AS mode_held,
CASE lk.kgllkreq
WHEN 0 THEN 'None'
WHEN 1 THEN 'Null'
WHEN 2 THEN 'Share'
WHEN 3 THEN 'Exclusive'
ELSE 'Unknown'
END AS mode_requested
FROM
gv$session s
JOIN x$kgllk lk
ON lk.kgllkuse = s.saddr
AND lk.inst_id = s.inst_id
AND lk.con_id = s.con_id
JOIN x$kglob obj
ON lk.kgllkhdl = obj.kglhdadr
AND lk.inst_id = obj.inst_id
AND lk.con_id = obj.con_id
JOIN cdb_pdbs pdb
ON s.con_id = pdb.con_id
JOIN gv$db_object_cache gco
ON gco.inst_id = obj.inst_id
AND gco.con_id = obj.con_id
AND gco.addr = obj.kglhdadr
WHERE
obj.kglhdnsp != 0
AND gco.locks > 0;
運用上の注意点
この監視手法にはいくつかの制約があります。動的パフォーマンスビューを参照しているため、実行時間が極端に短いロック競合はキャプチャできない可能性があります。また、大規模なRAC/CDB環境では、このクエリ自体の実行コストが高くなる場合があるため、システム負荷を考慮して実行してください。
簡易的なロック確認
特定のセッション情報まで特定する必要がなく、単にロックされているオブジェクトの有無だけを確認したい場合は、以下のシステムビューを参照するのが最も簡便です。
SELECT * FROM gv$db_object_cache WHERE locks > 0 AND owner = 'TARGET_SCHEMA_NAME';