OCI8 接続のハンドリングおよびプーリング

接続関数

oci8 拡張モジュールは Oracle に接続するための 3 つの異なる関数を提供しています。標準の接続関数は oci_connect です。これは Oracle データベースへの接続を作成し、 それ以降のデータベースで使うリソースを返します。

Oracle サーバーへの接続は、完了まで要する時間という点から見ると、 かなりコストのかかる操作です。oci_pconnect 関数は、 異なるスクリプトリクエスト間で接続の再利用が可能な 持続的キャッシュを使用します。 これは、PHP プロセス (もしくは Apache の子プロセス) 毎の接続に関するオーバーヘッドを一度のみ負うということを意味しています。

もしアプリケーションが信用された異なる Web ユーザー毎に Oracle に接続する場合、oci_pconnect による持続的キャッシュは、 同時ユーザー数の増加と共に有効ではなくなるでしょう。 これは、多くのアイドル状態の接続が維持されることが原因で、 Oracle サーバー全体のパフォーマンスに不利な影響を与え始めるためです。 もしアプリケーションがこの方法で構成されている場合、 oci8.max_persistentoci8.persistent_timeout (持続的接続のキャッシュサイズや生存期間の制御が可能になります) を使用してアプリケーションをチューニングする、あるいは Oracle Database Resident Connection Pooling を使う (Oracle Database 11g 以降の場合)、もしくは oci_connect を使用することが推奨されます。

oci_connectoci_pconnect の両者とも接続キャッシュを使用します。もし、同一パラメータと共に oci_connect を複数回コールする場合、 2 番目以降は既存の接続ハンドルを返します。oci_connect によって使用されるキャッシュは、スクリプト実行終了時、 もしくは明示的に接続ハンドルを閉じた時にクリアされます。 oci_pconnect も同様の動作をしますが、 キャッシュは独立して維持され、リクエスト間で残存します。

このキャッシュ機能は忘れてはならないほど重要です。 それは、2 つのハンドルがトランザクション的に独立していない (実際には同じ接続なので、どのような種類の独立もありません) ためです。もしアプリケーションが 2 つの別々でトランザクション的に独立した接続を必要とする場合、 oci_new_connect を使用すべきです。

PHP プロセス終了時に oci_pconnect キャッシュは消去され、 データベース接続は全て閉じられます。 そのため、持続的接続を効果的に使用するには、 PHP は Apache のモジュールであるか、または FPM によって使用されるか、 または同様のものでなければいけません。 PHP が CGI によって、またはコマンドラインを介して使用される場合、 持続的接続には oci_connect 以上に全く利益がありません。

oci_new_connect は、他の既存の接続が存在したとしても 常に Oracle サーバーへの新規接続を生成します。 特にアプリケーションの最も負荷が高い部分など、 高トラフィックな Web アプリケーションに対しては oci_new_connect の使用を避けてください。

持続的接続をユーザーが閉じることができます。 これにより、接続リソースの使い方をユーザーがより強く制御できます。 持続的接続は、PHP の変数が参照していない場合にも、 自動的に閉じられるようになっています。 たとえば、PHP のユーザ関数のスコープの最後に到達した場合です。 これによって、コミットされていないトランザクションは全てロールバックされます。 持続的接続に対するこれらの変更によって、 持続的接続でない、通常の接続と似たような振る舞いをするようになります。 さらに、インターフェイスがシンプルになり、 アプリケーションの一貫性と予測可能性が改善されます。 歴史的な振る舞いを維持するには、 oci8.old_oci_close_semantics の設定を On にして下さい。

Apache や FPM のプロセスが再度 fork した後、 PHP の持続的接続は再接続されます。 これは、Oracle Database の LOGON トリガに セッション属性を設定するべきであり、 アプリケーションのユーザー接続単位で設定すべきではないということです。

DRCP 接続プーリング

PHP は、Oracle 11g のデータベース常駐接続プーリング (DRCP) をサポートします。 DRCP によりデータベースマシンのメモリをより効率的に使用し、 高い拡張性が得られます。 DRCP を使うためにアプリケーションを変更する必要はないか、または 最小限です。

DRCP は、ごく少数のデータベーススキーマを使用し、データベース接続を短時間オープン状態に 保つアプリケーションに適しています。 その他のアプリケーションは、 Oracle のデフォルトの Dedicated データベースサーバープロセスか、または Shared サーバーを使用しなければいけません。

DRCP は3つの接続機能全てに有益ですが、 oci_pconnect で接続を作成すると最高の拡張性が得られます。

OCI8 で DRCP を利用可能にするには、 PHP で使用する Oracle クライアントライブラリ、 及び Oracle データベースのバージョンが共に 11g 以降でなければいけません。

DRCP についてのドキュメントはいくつかの Oracle マニュアルに見つかります。 例えば、使用法の情報のために、 Oracle ドキュメントで » データベース常駐接続プーリングの構成 をご覧ください。 » DRCP ホワイトペーパー には、 DRCP についての 予備知識となる情報が含まれています。

DRCP を使用するには、 OCI8 拡張モジュール及び Oracle 11g 以降のライブラリをインストールし、 以下のステップを続けます。

  • データベース内の接続プールを開始するために、 特権を持つデータベース管理者として SQL*Plus のようなプログラムを使います。

        SQL> execute dbms_connection_pool.start_pool;
    

  • DRCP の設定を構成するために、 任意で dbms_connection_pool.alter_param() を使用します。 現行のプール設定は、 DBA_CPOOL_INFO ビューで照会できます。

  • 使用する接続文字列を更新します。 MYDB のようなネットワーク接続名を使って現在接続する PHP アプリケーションでは、

        $c = oci_pconnect("myuser", "mypassword", "MYDB");
    

    tnsnames.ora ファイルを修正して、 (SERVER=POOLED) 節を追加します。 例えば、

        MYDB = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp) (HOST=myhost.dom.com)
               (PORT=1521))(CONNECT_DATA=(SERVICE_NAME=sales)
               (SERVER=POOLED)))
    

    あるいは、 PHP で Easy Connect 構文を修正して、サービス名の後に :POOLED を追加します。

        $c = oci_pconnect("myuser", "mypassword", "myhost.dom.com:1521/sales:POOLED");
    

  • php.ini を編集して、接続クラス名を選択してください。 この名前は、接続プールの論理的なディビジョンを指示し、 個別のアプリケーションごとにプーリングを分離するために使われます。 同一のユーザー名と接続クラスをもつ PHP アプリケーションは、 プール内の接続を共有できます。これにより、より大きな拡張性が得られます。

        oci8.connection_class = "MY_APPLICATION_NAME"
    

  • アプリケーションを実行して、 11g 以降のデータベースに接続します。

注意:

持続的接続のパフォーマンスを必要とする Oracle クライアントライブラリ 10g を使うアプリケーションでは、 Oracle Shared サーバー(マルチスレッドサーバーとして既知)を使用することにより、 必要なデータベース・メモリー量を減らせます。 詳細は Oracle ドキュメントを参照ください。

注意:

DRCP 接続に対するパスワードを変更すると、 ORA-56609: Usage not supported with DRCP というエラーで失敗します。 これは Oracle データベース 11g の制約に典拠が示されています。