Oracle OCI - 如何在不获取的情况下获取选择集中的行数

时间:2015-05-19 18:41:52

标签: oracle select count row oci

Noob(关于Oracle和OCI)。

我正在编写一个程序来为我的公司完成一些任务。在这些任务中,我必须更新oracle数据库以使其与其他操作保持同步。

我想有效地预先分配内存以保存在选择集上获取的结果。为了做到这一点,我需要知道选择集中有多少行。

我可以用2个单独的陈述来做;首先是SELECT COUNT语句,后跟SELECT语句,但从服务器的角度来看效率很低。我也可以执行我的SELECT语句并在从选择集中提取行时动态分配内存,但从客户的角度来看这是低效的。

我想简单地执行SELECT语句,并在获取任何行之前,检索选择集中匹配行的数量。

但我无法找到包含此信息的属性 有OCI_ATTR_ROW_COUNT但这是FETCHED的行数,而不是选择集中的总行数。 然后有OCI_ATTR_PARAM_COUNT,告诉你COLUMNS的数量(似乎没用,因为你已经知道你在SQL中要求的列数)。

有人知道如何在获取之前获取选择集行数吗?

由于 约什

4 个答案:

答案 0 :(得分:5)

你做不到。 Oracle数据库通常不知道查询在获取最后一行之前将返回多少行。

通常,客户端将被设计为从客户端获取特别大小的批量数据,处理这些结果,然后获取下一批数据。例如,大多数PL / SQL GUI应用程序(TOAD,SQL Developer等)将执行查询,获取第一批50或100行,然后等待用户。当用户浏览数据时,客户端将获取下一批,处理该批处理并迭代直到最后一批被使用。您是否可以从内存中丢弃先前的批次,或者是否需要保留它们(以支持用户向后滚动的能力,例如,无需重新执行查询),这是您的应用程序需要确定的内容。

当您担心在客户端上动态分配内存时,您担心什么效率低下?这通常是最有效的做事方式。假设您选择了合理的批量大小,您将在客户端上请求合理大小的内存块(每个批处理一次或一次,具体取决于您是否需要在本地缓存数据),这非常有效。

答案 1 :(得分:2)

根据定义,Oracle不知道结果集中将有多少行,直到完成所有行的提取。根据用于查询的执行计划,它可能主要是在您获取它们时逐行构建结果集。

我说你根本不必担心这个问题 - 只需动态分配内存。但我想如果它是一个非常大的结果集,你可能会遇到一些性能问题。

我可以想到几个选项:

1)如你所说,做一个初始查询来计算匹配的行,并使用它来分配内存来保存完整的结果。

2)使用一些技术来执行查询并将其结果存储在服务器端,返回计数。这可能就像一个打包过程,它将结果存储在内存中,或者插入到工作表中。除非您已经确定了需要解决的实际问题,否则这可能比它的价值更多。

3)根据您对可能返回的行数的预期,以合理大小的块分配内存。在某些情况下,您可能最终会进行全面定位,但如果您的块大小不是太大,那么这可能不是一个大问题。

答案 2 :(得分:1)

您可以使用可滚动的Statement Handle并获取最后一行,然后询问当前位置:

OCIStmtExecute(pOCIServiceHnd, pOCIStmtHnd, pOCIErrorHnd, 0, 0, NULL, NULL,   OCI_STMT_SCROLLABLE_READONLY);

int rowCount = 0;
OCIStmtFetch2(pOCIStmtHnd, pOCIErrorHnd, 1, OCI_FETCH_LAST, 0, OCI_DEFAULT);
OCIAttrGet(pOCIStmtHnd, OCI_HTYPE_STMT, &rowCount, NULL, OCI_ATTR_CURRENT_POSITION, pOCIErrorHnd);

如果您要重复使用,请记住回放您的Statement Handle:

OCIStmtFetch2(pOCIStmtHnd, pOCIErrorHnd, 1, OCI_FETCH_FIRST, 0, OCI_DEFAULT);

答案 3 :(得分:0)

正如其他人所说,Oracle使用生产者 - 消费者设计模式。因此,结果数据不会保存在任何“缓冲区”中,但它们是在执行OCIStmtFetch时即时生成的。这也与SQL优化器目标(ALL_ROWS和FIRST_ROWS)有关。例如在Oracle Forms(或其他4GL工具)中 大多数复杂的查询永远不会到达终点。用户只需显示第一页数据,如果只是向下滚动,则从数据库返回的行数越多。这在概念上与Java / Web应用程序非常不同,在Java / Web应用程序中,您必须首先从数据库获取所有行,然后应用程序将整个块发送到客户端。

例如PostgreSQL的工作方式不同。它使用客户端的RAM作为缓冲区。因此,对语句的“执行”调用将等待,直到所有结果行都存储在客户端的RAM中。调用fetch仅迭代客户端RAM中的缓冲区。 (除非你使用显式游标)。