oci8 拡張モジュールは Oracle に接続するための 3 つの異なる関数を提供しています。標準の接続関数は oci_connect() です。これは Oracle データベースへの接続を作成し、 それ以降のデータベースで使うリソースを返します。
Oracle サーバーへの接続は、完了まで要する時間という点から見ると、 かなりコストのかかる操作です。 oci_pconnect() 関数は、 異なるスクリプトリクエスト間で接続の再利用が可能な 持続的キャッシュを使用します。 これは、PHP プロセス (もしくは Apache の子プロセス) 毎の接続に関するオーバーヘッドを一度のみ負うということを意味しています。
もしアプリケーションが信用された異なる Web ユーザー毎に Oracle に接続する場合、 oci_pconnect() による持続的キャッシュは、 同時ユーザー数の増加と共に有効ではなくなるでしょう。 これは、多くのアイドル状態の接続が維持されることが原因で、 Oracle サーバー全体のパフォーマンスに不利な影響を与え始めるためです。 もしアプリケーションがこの方法で構成されている場合、 oci8.max_persistent や oci8.persistent_timeout (持続的接続のキャッシュサイズや生存期間の制御が可能になります) を使用してアプリケーションをチューニングする、もしくは代わりに oci_connect() を使用することが推奨されます。
oci_connect() と oci_pconnect() の両者とも接続キャッシュを使用します。もし、同一パラメータと共に oci_connect() を複数回コールする場合、 2 番目以降は既存の接続ハンドルを返します。 oci_connect() によって使用されるキャッシュは、スクリプト実行終了時、 もしくは明示的に接続ハンドルを閉じた時にクリアされます。 oci_pconnect() も同様の動作をしますが、 キャッシュは独立して維持され、リクエスト間で残存します。
このキャッシュ機能は忘れてはならないほど重要です。 それは、2 つのハンドルがトランザクション的に独立していない (実際には同じ接続なので、どのような種類の独立もありません) ためです。もしアプリケーションが 2 つの別々でトランザクション的に独立した接続を必要とする場合、 oci_new_connect() を使用すべきです。
PHP プロセス終了時に oci_pconnect() キャッシュは消去され、 データベース接続は全て閉じられます。 そのため、持続的接続を効果的に使用するには、 PHP は Apache のモジュールであるか、または FCGI によって使用されるか、 または同様のものでなければいけません。 PHP が CGI によって、またはコマンドラインを介して使用される場合、 持続的接続には oci_connect() 以上に全く利益がありません。
oci_new_connect() は、他の既存の接続が存在したとしても 常に Oracle サーバーへの新規接続を生成します。 特にアプリケーションの最も負荷が高い部分など、 高トラフィックな Web アプリケーションに対しては oci_new_connect() の使用を避けてください。
PHP 5.3 (PECL OCI8 1.3) では、 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 1.3 エクステンション及び Oracle 11g ライブラリと共に PHP をビルドし、これらのステップを続けます。
データベース内の接続プールを開始するために、 特権を持つデータベース管理者として 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 の制約に典拠が示されています。
OCI8 1.3 エクステンションでは、ユーザーが持続的接続を直ちに閉じることができます。 これにより、接続リソースの使用量に対して、より良く制御することができます。 持続的接続を参照する PHP 変数が無い場合、例えば PHP ユーザー関数の終了後に、 持続的接続もすぐに自動的に閉じられます。 この時、コミットされなかったトランザクションを全てロールバックします。 持続的な接続に対するこれらの変更により、非持続的接続と同様にふるまいます。 それは、インターフェイスを単純化し、アプリケーションの一貫性と予知可能性をより大きくします。 過去の動作を保つためには、oci8.old_oci_close_semantics を On に設定してください。
もし、Oracle データベースのバージョンが 11.1.0.6 なら、DRCP を使うためには、 Oracle bug 6474441 に対する Oracle データベース・パッチを適用しなければいけません。 そのパッチがないと、 ORA-01000: maximum open cursors exceeded や、 ORA-01001 invalid cursor 、 ORA-01002 fetch out of sequence のようなエラーが発生するかもしれません。 このバグは Oracle 11.1.0.7 以降では修正されました。
もし、Oracle 11.1.0.6 データベース・パッチが適用できない場合は、 代わりに下記の3つのワークアラウンドのいずれかを使用できます。
Oracle データベース 11.1.0.7 および Oracle データベース 11.1.0.6 の Oracle バグ 6474441 に対するパッチにより、DRCP 接続を使った PHP アプリケーションで セッション生成時にセッションプロパティを設定するために データベースの LOGON トリガーを使用できます。 そのような設定の例は、NLS言語と日付表示形式です。
もし、Oracle 11.1.0.6 データベース・パッチが適用できない場合は、 LOGON トリガーを使う代わりに、 下記のワークアラウンドのいずれかを使用できます。
Apache や FCGI のプロセスを再起動すると、 PHP の持続的接続は自動的に再確立されます。つまり、PHP で LOGON トリガーが使えるのはセッション属性を設定している場合のみで、 アプリケーションごとのユーザー接続要求には使えないということです。 DRCP の場合はなおさらです。 プールサイズの自動調整もあるし、DRCP の認証時に LOGON トリガーが起動するからでもあります。
FAN サポートにより、高速な接続フェールオーバが得られます。これは高可用性フィーチャーです。 これにより、データベース・マシンまたはデータベース・インスタンスが利用できなくなると、 PHP OCI8 スクリプトに通知されます。 FAN 無しでは、 TCP のタイムアウトが起きてエラーが返されるまで OCI8 はハングする場合があります。 それは数分間かもしれません。 OCI8 で FAN を有効にすると、 web のユーザーが機能不全を気づかないように、 アプリケーションでエラーを検出して利用可能なデータベース・インスタンスに再接続できます。
FAN サポートは、 PHP がリンクする Oracle クライアント・ライブラリーと Oracle データベースがバージョン 10gR2 かまたは 11g の場合に利用可能です。
FAN は、 Oracle の クラスタリング・テクノロジー (RAC) の利用者に有益です。 なぜなら、生き残ったデータベース・インスタンスへの接続を直ちに作成できるからです。 ブローカーを持つ Oracle の Data Guard の利用者は、 スタンバイ・データベースがオンラインになる際に生成される FAN イベントに気づくでしょう。 スタンドアロンのデータベースは、データベース再起動の際に FAN イベントを送信します。
アクティブな接続に関して、マシンまたはデータベース・インスタンスが利用できなくなると、 現在コールされている OCI エクステンションの関数によって、 接続失敗エラーが返されます。 以降の PHP スクリプト再接続で、 生き残ったデータベース・インスタンスへの接続が確立されます。 データベースマシンやインスタンスの失敗で影響を受けたアイドル状態の接続を OCI8 エクステンションも全て透過的にクリーンアップします。 こうして、スクリプトでサービスの中断に気づくことなく、 PHP 接続コールにより新たな接続が確立されます。
oci8.events が On の場合、 疎通確認を無効にするために oci8.ping_interval を -1 に設定することを提案します。 なぜなら、 FAN イベントを有効にすると、アイドル状態の接続の能動的な接続管理を サービスの中断によって無効にしてしまうからです。
PHP で FAN サポートを有効にするには、 Oracle 10gR2 または 11g ライブラリと共にPHP をビルドし、これらのステップを続けます。
SQL> execute dbms_service.modify_service( SERVICE_NAME => 'sales', AQ_HA_NOTIFICATIONS => TRUE);
oci8.events = On