oci_set_prefetch

(PHP 5, PHP 7, PHP 8, PECL OCI8 >= 1.1.0)

oci_set_prefetch设置查询预取的行数

描述

oci_set_prefetch(resource $statement, int $rows): bool

设置在成功调用 oci_execute() 以及后续对数据库的每个内部获取请求后,由 Oracle Client 库缓冲的行数。对于返回大量行的查询,通过将预取计数增加到默认 oci8.default_prefetch 值以上,可以显着提高性能。

预取是 Oracle 在每个网络请求中从数据库返回多行数据的一种有效方法。这可以带来更好的网络和 CPU 利用率。行的缓冲在 OCI8 内部,并且无论预取计数如何,OCI8 获取函数的行为都保持不变。例如,oci_fetch_row() 将始终返回一行。预取缓冲区是针对每个语句的,并且不会被重新执行的语句或其他连接使用。

在调用 oci_execute() 之前调用 oci_set_prefetch()

调整目标是将预取值设置为网络和数据库可以处理的合理大小。对于返回大量行的查询,如果从数据库中以几个块获取行(即,将预取值设置为小于行数),则整体系统效率可能更高。这允许数据库在 PHP 脚本处理当前行集时处理其他用户的语句。

查询预取在 Oracle 8i 中引入。REF CURSOR 预取在 Oracle 11gR2 中引入,并且在 PHP 与 Oracle 11gR2(或更高版本)Client 库链接时发生。嵌套游标预取在 Oracle 11gR2 中引入,要求 Oracle Client 库和数据库的版本都为 11gR2 或更高版本。

查询包含 LONG 或 LOB 列时,不支持预取。预取值将被忽略,并且在所有不支持预取的情况下将使用单行获取。

使用 Oracle Database 12c 时,PHP 设置的预取值可能会被 Oracle 的客户端 oraaccess.xml 配置文件覆盖。有关更多详细信息,请参阅 Oracle 文档。

参数

statement

oci_parse() 创建并由 oci_execute() 执行的有效 OCI8 语句标识符,或 REF CURSOR 语句标识符。

rows

要预取的行数,>= 0

返回值

成功时返回 true,失败时返回 false

示例

示例 #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) : "&nbsp;")."</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);

// 在执行游标之前更改预取值。\n// 当 PHP 与 Oracle 11gR2 或更高版本的客户端库链接时,REF 游标预取有效\noci_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) : "&nbsp;")."</td>\n";
}
echo
"</tr>\n";
}
echo
"</table>\n";

oci_free_statement($refcur);
oci_free_statement($stid);
oci_close($conn);

?>

如果 PHP OCI8 从 REF 游标中提取数据,然后将 REF 游标传递回第二个 PL/SQL 过程进行进一步处理,则将 REF 游标预取计数设置为 0 以避免结果集中的行“丢失”。预取值是在每个 OCI8 内部数据库请求中提取的额外行的数量,因此将其设置为 0 表示一次只提取一行。

示例 #3 将预取值传递回 Oracle 时设置预取值

<?php

$conn
= oci_connect('hr', 'welcome', 'localhost/orcl');

// 获取 REF 游标\n$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()\noci_set_prefetch($refcur, 0);
oci_execute($refcur);
$row = oci_fetch_array($refcur);
var_dump($row);
$row = oci_fetch_array($refcur);
var_dump($row);

// 将 REF 游标传递给 myproc_use_rc() 以对结果集进行更多数据处理\n$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);

?>

另请参阅

添加笔记

用户贡献笔记 1 笔记

bmichael at goldparrot dot com
21 年前
如果您在任何项目中使用 Oracle 的 OCI 库,PHP 使用的是这个库,您可以使用这个限制。

我已经对这个参数的效果进行了网络级测试。它确实提高了效率。非常有效。

Oracle 使用 SQL*Net 作为连接和数据库之间数据传输的机制。这就是为什么您必须正确设置 Oracle 的原因。

此参数告诉 SQL*NET 缓冲更多结果。当 SQL*NET(在服务器端)收到数据请求时,它会捆绑 X 行(1、2、3、1000 等)进行传输。它将相应的 SQL*NET 标头发送回客户端,等待 ACK,然后开始以 MTU 大小块发送数据(以太网约为 1500 字节,ATM WAN 约为 1000 字节)。块大小也可以在 SQL*NET 中调整,但改进要少得多。

然后,TCP/IP 会将数据通过网络传输,将其拆分成多个 TCP/IP 数据包。

交换完成后,SQL*NET 客户端向 SQL*NET 监听器(Oracle 服务器)发送
ACK,事务完成。

在每次往返过程中,SQL*NET 都会在服务器内存(UGA - 用户全局区域)中查找查询结果。然后,它会获取发送所需的那些行。无论是一行还是 1000 行,过程都是一样的。

我可以告诉您很多关于数据库本身如何反应的信息。如果您能显著减少往返次数... 哇。

有关 Oracle OCI 的更多信息,请访问 http://otn.oracle.com
To Top