Работа с соединениями OCI8 и Connection Pooling

Функции подключения

Расширение OCI8 предоставляет три различных функции для подключения к серверу Oracle. Стандартная функция соединения - это oci_connect(). Она создает соединение к базе данных Oracle и возвращает ресурс, который используется при последующих обращениях к БД.

Подключение к серверу Oracle является достаточно дорогостоящей операцией с точки зрения времени, которое требуется для выполнения. Функция oci_pconnect() использует постоянный кэш соединений, которые могут быть повторно использованы различными запросами скриптов. Это означает, что затраты на установку соединения, как правило, происходят только единожды на один процесс PHP (или на потомка Apache).

Если приложение соединяется к серверу Oracle, используя особый набор данных для каждого веб-пользователя, то постоянный кэш соединений, используемый функцией oci_pconnect() будет менее полезным, т.к. количество одновременных пользователей вырастает до того уровня, где он может начать оказывать негативное влияние на общую производительность сервера Oracle из-за поддержания слишком большого количества простаивающих соединений. Если приложение настроено таким образом, то рекомендуется либо настроить его с помощью параметров конфигурации oci8.max_persistent и oci8.persistent_timeout (это даст возможность управления размером кэша постоянных соединений и их время жизни), либо использовать Oracle Database Resident Connection Pooling (в Oracle Database 11g и новее), либо использовать функцию oci_connect() вместо нее.

Вместе oci_connect() и oci_pconnect() используют кэш подключений; если множество вызовов oci_connect() использует одинаковые параметры в данном скрипте, второй и последующие вызовы вернут существующий дескриптор соединения. Кэш, используемый функцией oci_connect(), очищается по завершению выполнения скрипта, или когда соединение неявно закрывается. У функции oci_pconnect() похожее поведение, хотя ее кэш обрабатывается отдельно и остается действующим между запросами HTTP.

Эта возможность кеширования означает, что два дескриптора не изолированы транзакционно (они на самом деле являются одним и тем же дескриптором, поэтому здесь нет никакой изоляции). Если приложению необходимы два отдельных транзакционно изолированных соединения, то необходимо использовать функцию oci_new_connect().

Кеш функции oci_pconnect() очищается и закрываются все соединения к БД, когда завершается процесс PHP. Поэтому эффективное использование постоянных соединений требует, чтобы PHP был модулем Apache или использовался с FCGI или подобным. Постоянные соединения не будут иметь никаких преимуществ перед oci_connect(), когда PHP используется с CGI или через командную строку.

Функция oci_new_connect() всегда создает новое соединение с сервером Oracle, невзирая на то, что другие соединения могут уже существовать. Высоконагруженным веб-приложениям следует избегать использования oci_new_connect(), особенно в самых загруженных частях приложения.

Создание пула соединений DRCP

PHP начиная с 5.3 (PECL OCI8 1.3) поддерживает постоянный пул соединений Oracle 11g (DRCP). DRCP позволяет более эффективно использовать память СУБД и предоставляет высокую масштабируемость. Изменять код приложения для использования DRCP либо нет необходимости, либо требуются минимальные изменения.

DRCP подходит для приложений, которые подключаются используя несколько схем БД и сохраняют соединения к БД открытыми короткий промежуток времени. Другим приложениям следует использовать доступные по умолчанию Dedicated серверные процессы или использовать Shared сервера.

DRCP приносит пользу всем трем функциям подключения, однако предоставляет самую высокую масштабируемость, когда соединения создаются с помощью функции oci_pconnect().

Чтобы функционал DRCP был доступен в OCI8, клиентские библиотеки Oracle, используемые в PHP, и версия сервера баз данных должны быть 11g и новее.

Документация по DRCP находится в нескольких руководствах Oracle. К примеру, см. » Конфигурирование пула постоянных соединений базы данных в документации Oracle для информации по использованию. Документ » техническое описание DRCP содержит дополнительную информацию по DRCP.

Для использования DRCP, скомпилируйте PHP с расширением OCI8 1.3 (и новее)ы и библиотеками Oracle 11g (и новее) и затем выполните следующие действия:

  • Как привилегированный администратор БД воспользуйтесь программой наподобие SQL*Plus, чтобы запустить пул соединений в СУБД:

        SQL> execute dbms_connection_pool.start_pool;
    

  • Дополнительно можно использовать dbms_connection_pool.alter_param(), чтобы конфигурировать параметры DRPC. Текущие настройки пула могут быть получены из представления DBA_CPOOL_INFO.

  • Обновите используемую строку соединения. К примеру, для приложений PHP, которые сейчас соединяются, используя Network Connect Name MYDB:

        $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 и добавить туда :POOLED после имени сервиса:

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

  • Отредактируйте php.ini и выберите имя класса соединения. Это имя устанавливает логическое разделение пула соединений и может использоваться, чтобы изолировать пул для отдельных приложений. Любое PHP-приложение с одинаковым именем пользователя и классом для соединения будет иметь возможность совместно использовать соединения в пуле, получая бОльшую масштабируемость.

        oci8.connection_class = "MY_APPLICATION_NAME"
    

  • Запустите приложение, соединяющееся с базой 11g и новее.

Замечание:

Приложения, использующие Oracle 10g, которые требуют производительности от постоянных соединений, могут уменьшить количество памяти сервера БД, которое используется Shared-серверами Oracle (ранее известные как многопоточные сервера). Обратитесь к документации Oracle для более подробной информации.

Рекомендации по DRCP и известные ограничения

При изменении пароля через DRCP-соединение будет выдаваться ошибка ORA-56609: Usage not supported with DRCP. Это документированное ограничение of Oracle Database 11g.

Начиная с расширения OCI8 версии 1.3 постоянные соединения теперь могут быть закрыты пользователем. Это позволяет получить больший контроль над использованием ресурсов соединений. Постоянные соединения теперь будут также закрываться автоматически, когда отсутствует указывающая на них переменная PHP, например, в таких случаях, как в конце области видимости пользовательской функции PHP. Это откатит любую незавершенную транзакцию. Эти изменения в постоянных соединениях делают их поведение похожим на поведение непостоянных соединений, упрощая интерфейс и позволяя приложениям быть более логичными и предсказуемыми. Для сохранения предыдущего поведения используйте директиву oci8.old_oci_close_semantics, принимающую значение On .

Если СУБД Oracle версии 11.1.0.6, то для использования DRCP должен быть применен патч для СУБД Oracle для устранения ошибки 6474441. Без этого патча могут происходить ошибки, такие как 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 не может быть применен, тогда вместо этого можно воспользоваться тремя методами:

  • Соединение используя Oracle Dedicated или Shared сервера вместо DRCP.
  • Установить директиву PHP oci8.statement_cache_size в 0.
  • Установить событие в файле параметров инициализации базы: event="56699 trace name context forever, level 128".

Патч 6474441 для БД Oracle версий 11.1.0.7 и 11.1.0.6 позволяет приложениям на PHP с DRCP-соединением использовать триггер базы LOGON для установки параметров сессии в момент ее создания. Примерами таких параметров являются язык NLS и формат даты.

Если патч к БД Oracle 11.1.0.6 не может быть установлен, то можно использовать несколько методов вместо использования триггеров LOGON:

  • После авторизации, явно установите свойства сессии используя код приложения PHP.
  • Соединитесь, используя Oracle Dedicated или Shared сервера вместо DRCP.

Автоматическое повторное установление постоянного соединения PHP после порождения нового процесса Apache или FCGI означает, что использование триггеров LOGON в PHP рекомендуется только для установки атрибутов сессии, а не для пользовательских запросов на соединение для каждого приложения. Это даже более проявляется с DRCP за счет автоматического изменения размера буфера соединений и со способом триггеров LOGON конфликтующим с DRCP аутентификацией.