oci_set_prefetch
(PHP 5, PECL OCI8 >= 1.1.0)
oci_set_prefetch — Устанавливает количество строк, которые будут автоматически выбраны в буфер
Описание
$statement
, int $rows
)Устанавливает количество рядов, которые будут выбраны в буфер клиентскими библиотеками Oracle сразу после удачного вызова oci_execute() и для каждого последующего внутреннего запроса данных к базе. Производительность может быть значительно увеличена для запросов, возвращающих большое количество рядов, с помощью установки значения предварительной выборки больше значения по умолчанию oci8.default_prefetch.
Предварительная выборка - это эффективный механизм Oracle, позволяющий возвращать больше одного ряда результата из базы данных за каждый сетевой запрос. Это дает более рациональное использование сети и процессора. Буферизация рядов происходит внутри OCI8, поэтому поведение функций выборки OCI8 никак не зависит от размера предварительной выборки. Например, oci_fetch_row() всегда возвращает один ряд. Буфер предварительной выборки резервируется отдельно на каждый запрос и не используется второй раз в повторно запущенных запросахили в других соединениях.
Перед вызовом oci_execute() вызовите oci_set_prefetch().
Смысл настройки размера предварительной выборки состоит в подборе удобного значения для передачи в сети и обработки в базе данных. Для запросов, возвращающих очень большое количество рядов, общая производительность системы может быть лучше, если ряды будут возвращаться в несколько приемов (т.е. установить размер предварительной выборки меньше количества рядов). Это позволит базе данных обрабатывать запросы других пользователей в течение обработки PHP-скриптом текущего результата запроса.
Предварительная выборка запросов появилась в Oracle 8i. Предварительная выборка REF CURSOR появилась в Oracle 11gR2 и может быть применена в случае, если PHP слинкован с клиентскими библиотеками Oracle 11gR2 и старше. Предварительная выборка вложенных курсоров была добавлена в Oracle 11gR2 и требует наличия версии 11gR2 и старше как для клиентских библиотек Oracle, так и для используемой базы данных.
Предварительная выборка не поддерживается, если запросы содержат LONG или LOB столбцы. Значение предварительной выборки игнорируется и во всех ситуациях, не поддерживающих предварительную выборку, будет использована построчная выборка.
При использовании Oracle Database 12c, предварительная выборка заданная PHP может быть изменена конфигурационным файлом oraaccess.xml клиента Oracle. Обратитесь к документации Oracle за дополнительной информацией.
Список параметров
-
statement
-
Корректный идентификатор выражения OCI8, полученный из oci_parse() и исполненный функцией oci_execute(), или идентификатор выражения REF CURSOR.
-
rows
-
Количество рядов предварительной выборки, >= 0
Возвращаемые значения
Возвращает TRUE
в случае успешного завершения или FALSE
в случае возникновения ошибки.
Список изменений
Версия | Описание |
---|---|
5.3.2 (PECL OCI8 1.4) |
До этой версии rows должен был быть >= 1.
|
5.3.0 (PECL OCI8 1.3.4) |
До этой версии предварительная выборка была ограничена к меньшему
из значений rows рядов и 1024
* rows байт. Теперь ограничение по размеру
байт снято.
|
Примеры
Пример #1 Смена значения предворительной выборки по умолчанию для запроса
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'SELECT * FROM myverybigtable');
oci_set_prefetch($stid, 300); // Устанавливаем перед вызовом oci_execute()
oci_execute($stid);
echo "<table border='1'>\n";
while ($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
echo "<tr>\n";
foreach ($row as $item) {
echo " <td>".($item !== null ? htmlentities($item, ENT_QUOTES) : "")."</td>\n";
}
echo "</tr>\n";
}
echo "</table>\n";
oci_free_statement($stid);
oci_close($conn);
?>
Пример #2 Смена значения предварительной выборки по умолчанию для выборки REF CURSOR
<?php
/*
Создайте хранимую процедуру PL/SQL следующим образом:
CREATE OR REPLACE PROCEDURE myproc(p1 OUT SYS_REFCURSOR) AS
BEGIN
OPEN p1 FOR SELECT * FROM all_objects WHERE ROWNUM < 5000;
END;
*/
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'BEGIN myproc(:rc); END;');
$refcur = oci_new_cursor($conn);
oci_bind_by_name($stid, ':rc', $refcur, -1, OCI_B_CURSOR);
oci_execute($stid);
// Меняем размер предварительной выборки перед запуском курсора.
// Предварительная выборка REF CURSOR работает в случае линковки PHP
// с клиентскими библиотеками Oracle 11gR2 и старше
oci_set_prefetch($refcur, 200);
oci_execute($refcur);
echo "<table border='1'>\n";
while ($row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS)) {
echo "<tr>\n";
foreach ($row as $item) {
echo " <td>".($item !== null ? htmlentities($item, ENT_QUOTES) : "")."</td>\n";
}
echo "</tr>\n";
}
echo "</table>\n";
oci_free_statement($refcur);
oci_free_statement($stid);
oci_close($conn);
?>
Если PHP OCI8 производит выборку из REF CURSOR, а затем передает
REF CURSOR обратно в другую PL/SQL-процедуру для дальнейшей обработки,
необходимо установить размер предварительной выборки REF CURSOR в
0
, чтобы избежать "потери" рядов из результата.
Значение предварительной выборки - это количество "лишних" рядов, полученных
каждым внутренним запросом OCI8 к базе данных, поэтому установка его
в 0
означает выборку только одного ряда за один раз.
Пример #3 Установка значения предварительной выборки при передаче REF CURSOR обратно в Oracle
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/orcl');
// получение REF CURSOR
$stid = oci_parse($conn, 'BEGIN myproc(:rc_out); END;');
$refcur = oci_new_cursor($conn);
oci_bind_by_name($stid, ':rc_out', $refcur, -1, OCI_B_CURSOR);
oci_execute($stid);
// Отображаем два ряда, но больше не предвыбираем других рядов, иначе
// эти ряды не будут переданы обратно в myproc_use_rc().
// Нулевое значение предварительной выборки было разрешено в версии PHP 5.3.2 и PECL OCI8 1.4
oci_set_prefetch($refcur, 0);
oci_execute($refcur);
$row = oci_fetch_array($refcur);
var_dump($row);
$row = oci_fetch_array($refcur);
var_dump($row);
// передаем REF CURSOR в myproc_use_rc() для дальнейшей обработки результата
$stid = oci_parse($conn, 'begin myproc_use_rc(:rc_in); end;');
oci_bind_by_name($stid, ':rc_in', $refcur, -1, OCI_B_CURSOR);
oci_execute($stid);
?>
- PHP Руководство
- Функции по категориям
- Индекс функций
- Справочник функций
- Расширения для работы с базами данных
- Расширения для работы с базами данных отдельных производителей
- Oracle OCI8
- oci_bind_array_by_name
- oci_bind_by_name
- oci_cancel
- oci_client_version
- oci_close
- oci_commit
- oci_connect
- oci_define_by_name
- oci_error
- oci_execute
- oci_fetch_all
- oci_fetch_array
- oci_fetch_assoc
- oci_fetch_object
- oci_fetch_row
- oci_fetch
- oci_field_is_null
- oci_field_name
- oci_field_precision
- oci_field_scale
- oci_field_size
- oci_field_type_raw
- oci_field_type
- oci_free_descriptor
- oci_free_statement
- oci_get_implicit_resultset
- oci_internal_debug
- oci_lob_copy
- oci_lob_is_equal
- oci_new_collection
- oci_new_connect
- oci_new_cursor
- oci_new_descriptor
- oci_num_fields
- oci_num_rows
- oci_parse
- oci_password_change
- oci_pconnect
- oci_result
- oci_rollback
- oci_server_version
- oci_set_action
- oci_set_client_identifier
- oci_set_client_info
- oci_set_edition
- oci_set_module_name
- oci_set_prefetch
- oci_statement_type
Коментарии
If your are using Oracle's OCI libraries, on any project, which PHP does, you can use this limit.
I have done network level testing on the effect of this parameter. It does improved efficiency. Big Time.
Oracle uses SQL*Net as the transport mechanism for data between your connection and the database. That is why you must setup Oracle properly.
This parameter tells SQL*NET to Buffer more results. When SQL*NET (at the server) gets a request for data, it bundles up X rows (1,2,3,1000, etc) for transport. It sends the appropriate SQL*NET headers back to the client, Waits for an ACK then begins sending data in MTU sized chunks (ethernet is something like 1500 bytes and ATM's WANS are around 1000 bytes). The chunk size can also be tuned in SQL*NET, but with much less improvements.
TCP/IP then takes the data across the wire, breaking it up into multiple TCP/IP packets.
Once the exchange is done, the SQL*NET client sends an
ACK back to the SQL*NET Listener (the Oracle Server) and the transaction is complete.
Each round trip, SQL*NET looks up inside the server memory (UGA - user global area) to find the query results. It then grabs the rows necessary to send. If it is one row, versus 1000 rows. The process is the same.
There is much I could tell you on how the Database itself reacts. If you can significantly lessen the amount of round trips you are making... WOW.
For more info on Oracle OCI go to http://otn.oracle.com