対応バージョン

Oracle Database 11.2 – 12.1

更新履歴

日付更新概要
2014/12/01記事公開
2015/02/10出力メッセージについて記載、言い回しなどの文言修正(内容修正なし)

ORA-20はORA-1555等のように、運用を続けているうえでよく散見されるエラーとなりますので、DBA運用経験の間もない方でもエラーに遭遇することが多いかと思います。

メッセージ

ORA-00020: 最大プロセス数(string)を超えました。
ORA-00020: maximum number of processes (string) exceeded.

stringにはPROCESSES初期化パラメータに設定している値(起動できるプロセスの最大値)が入ります。

発生原因

ORA-20はOracle Databaseで設定したプロセス数の設定値を超えてプロセスが起動した場合に発生するエラーです。このプロセスにはOracle Databaseのシステムで使用されるバックグラウンド・プロセスを含みます。

発生要因例

よくあるのはシステムの肥大化やユーザ数の増加、プログラムのバグにより発生する事があります。

プログラムのバグの例でいうと、JDBCから直接接続を行い、不要なコネクションをクローズせずに次のコネクションを開始するなど、正しい使い方をしていない場合や、Oracle Databaseのソフトウェアバグ等です。

他には設定値の変更によって、アーカイブプロセスや、パラレルスレーブの数を増やした際に、そちらを起因として発生することがあります。

対処方法

基本的にはPROCESSES初期化パラメータを増やすことにより対処を行います。
※ PROCESSESの変更にはインスタンスの再起動を伴います。

同時にSESSIONSについても増加する必要がありますが、設定なしであれば自動で適正値に変更されます。

但し、共有サーバ・モードでの接続を行っており、PROCESSESより算出されるデフォルト値(1.5 * PROCESSES + 22)より大きな値をとっている場合がありますので、その場合はSESSIONSの値は小さくしないでください。

共有サーバ・モード環境ではSESSIONSの値を バックグラウンドプロセスを含めた想定ユーザ最大接続数 * 1.1 の合計 程度にすることを推奨しています。

参考資料
https://docs.oracle.com/cd/E16338_01/server.112/b56311/initparams234.htm
Oracle Databaseリファレンス 11gリリース2 (11.2)
B56311-12
SESSIONS

PROCESSESの増加に伴い、OS側でのリソース増加も必要な場合があります。
例えばLinuxではulimit -aにて出力される、プロセス数の最大値やカーネルパラメータのセマフォの変更です。

また、プロセス数の異常が認められる場合は、発生起因となった処理の特定をする必要があります。(日毎にプロセス数が増加していくプログラムがないかなどを探ります)

対処例

以下PROCESSESの増加の対処例を記載します。

SPFILEを使用している場合の変更

SQL*Plusにログイン後、以下のコマンドを実行します。

$ sqlplus / as sysdba
-- 以下コマンドにて使用しているspfileのパスが出力される場合は、SPFILEを使用しています。
SQL> show parameter spfile
 
SQL> set line 120 pages 1000 trim on
SQL> col name for a15
SQL> col value for a20
SQL> col sid for a10
 
-- 現在値の確認
SQL> select INST_ID, NAME, VALUE from gv$parameter where name in ('processes','sessions');
 
-- SPFILEの内容の確認
SQL> select SID, NAME, VALUE from gv$spparameter where name in ('processes','sessions');
 
-- バックアップ取得
SQL> create pfile='<フルパス指定のバックアップファイル名>' from spfile;
SPFILEを使用した起動が出来なくなった場合、以下のように上記のバックアップしたPFILEにて起動を行うか、SPFILEを再作成します。
SQL> startup pfile='<フルパス指定のバックアップファイル名>'
SQL> create spfile from pfile='<フルパス指定のバックアップファイル名>'; -- DBが停止している状態でも作成可能です。
-- 値の変更
SQL> ALTER SYSTEM SET PROCESSES = <変更後の値> SCOPE=SPFILE;
SQL> ALTER SYSTEM RESET SESSIONS;
SESSIONSの設定が元からない場合は、以下のエラーが発生しますが無視しして問題ありません。
ORA-32010: SPFILEには削除するエントリが見つかりません
また共有サーバ・モードによる接続の場合はセッション数を大きくとっている場合があります。その場合はSESSIONSの値をリセットしないように気を付けてください。
-- SPFILEの内容が更新されていることの確認
SQL> select SID, NAME, VALUE from gv$spparameter where name in ('processes','sessions');

対象インスタンスの再起動後、反映されているかを確認します。

-- インスタンスを再起動します。
SQL> shutdown immediate
SQL> startup

SQL> set line 120 pages 1000 trim on
SQL> col name for a15
SQL> col value for a20
SQL> col sid for a10

-- 現在値の確認
SQL> select INST_ID, NAME, VALUE from gv$parameter
   2 where name in ('processes','sessions');

-- SPFILEの内容の確認
SQL> select SID, NAME, VALUE from gv$spparameter
   2 where name in ('processes','sessions');

SQL> exit

PFILEを使用している場合の変更

SQL*Plusにログイン後、以下のコマンドを実行します。

$ sqlplus / as sysdba
-- SPFILEのVALUEに値がなく、PFILEで起動されていることを確認します。
SQL> show parameter spfile
 
SQL> set line 120 pages 1000 trim on
SQL> col name for a15
SQL> col value for a20
SQL> col sid for a10
 
-- 現在値の確認
SQL> select INST_ID, NAME, VALUE from gv$parameter
   2 where name in ('processes','sessions');
 
SQL> exit

以下のファイルのPROCESSESの値を変更します。(例として400にする場合の行を記載)
対象ファイル: [ORACLE_HOME]/dbs/init<インスタンス名>.ora

*.processes = 400

PROCESSESの行がない場合は、行を追加してください。
アルファベット大文字と小文字の区別はありません。

インスタンスの再起動後、値が反映されているか確認します。

$ sqlplus / as sysdba
-- インスタンスを再起動します。
SQL> shutdown immediate
SQL> startup

-- SPFILEのVALUEに値がなく、PFILEで起動されていることを確認します。
SQL> show parameter spfile

SQL> set line 120 pages 1000 trim on
SQL> col name for a15
SQL> col value for a20
SQL> col sid for a10

-- 現在値の確認
SQL> select INST_ID, NAME, VALUE from gv$parameter
SQL> where name in ('processes','sessions');

SQL> exit

エラー原因の確認と値の検討

データベースで発生した場合

プロセス数不足によるバックグラウンド・プロセス等の異常終了では、アラートログに以下のようなメッセージが出力されます。

ORA-00020: maximum number of processes <プロセス最大値> exceeded

※ORA-20により、バックグラウンドプロセスが異常終了することで他のエラーが併発することがよくあります。

SQL*Plus等のクライアントなどで新規接続をする場合には直接ORA-20が戻されます。

PROCESSESはユーザが接続するプロセス数の他にバックグラウンド・プロセスも含んでいる事に注意してください。
バックグラウンド・プロセスはシステムによって数が異なりますが、性能問題によるバックグラウンド・プロセス数の増加措置や内部ジョブの設定などがない場合は、PROCESSESパラメータを50~100程度多く見込んで設定しておけば問題ありません。

PROCESSESを多く使用しているプログラムを確認する

$ sqlplus / as sysdba
 
SQL> set line 120 pages 1000 trim on
SQL> col username for a15
SQL> col machine for a30
SQL> col program for a30
SQL> col logon_time for a20
SQL> select s.username "USERNAME", s.machine "MACHINE", s.program "PROGRAM",
   2 to_char(s.logon_time, 'yyyy/mm/dd') "LOGON_DATE", count(1) "COUNT"
   3 from v$session s, v$process p
   4 where s.paddr = p.addr
   5 group by s.username, s.machine, s.program, to_char(s.logon_time, 'yyyy/mm/dd')
   6 order by s.username, s.machine, s.program, to_char(s.logon_time, 'yyyy/mm/dd');

実行されているSQLを確認する
上記で出力したMACHINEやPROGRAMなどで対象を絞って出力してください。

SQL> set line 120 pages 1000 trim on
SQL> col username for a15
SQL> col machine for a30
SQL> col program for a30
SQL> col logon_time for a20
SQL> select s.sid "SID", s.username "USERNAME", s.machine "MACHINE", s.program "PROGRAM",
   2 to_char(s.logon_time, 'yy/mm/dd hh24:mi:ss') "LOGON_TIME", a.sql_text "SQL TEXT"
   3 from v$session s, v$process p, v$sqlarea a
   4 where s.paddr = p.addr
   5 and s.sql_address=a.address(+)
   6 and s.sql_hash_value=a.hash_value(+)
   7 and s.audsid != USERENV('SESSIONID')
   8 order by s.username, s.machine, s.program;

上記の情報で値が決められない場合は、一旦値の増加を行いプロセスの状況を確認します。

ASMで発生した場合

ASM側のアラートログでは以下のようなエラーが確認できます。

Process <プロセス名> started up but failed with error = 20

※こちらのエラーが発生した場合、データベース側のアラートログではORA-20が発生します。

ASMでのプロセス数についての見積もりは基本的にできません。
但し、Oracleが推奨値を出しています。(マニュアルに記載されていますが、バージョンごとに推奨する見積もり値が違いますので注意してください。)

Oracle 11gR2であれば以下が推奨の値となります。

50 + ( [ASMに接続するデータベースの数] * 50 )

※ マニュアルの値も変わることがありますので最新の値はマニュアルを参照してください。

設定後にプロセス数に異常が発生しないかを監視する場合は、gv$resource_limitを確認する等して使用状況を確認することで監視を行います。

PROCESSESの使用状況を確認する
ASMへログインして確認してください

$ sqlplus / as sysasm

SQL> set line 120 pages 1000 trim on
SQL> col resource_name for a30
SQL> col limit_value for a12
SQL> select inst_id, resource_name,current_utilization, max_utilization, limit_value
   2 from gv$resource_limit
   3 where resource_name in ('processes', 'sessions')
   4 order by inst_id, resource_name;
 
-- CURRENT_UTILIZATION 現在使用されている(リソースまたはロック、プロセスの)数
-- MAX_UTILIZATION 最後にインスタンスを起動してからのこのリソースの最大消費量
-- LIMIT_VALUE リソースおよびロックの場合は無制限。(無制限の場合、UNLIMITED)。