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

Oracle OCI-如何在不获取数据的情况下获取选择集中的行数,oracle,select,count,row,oracle-call-interface,Oracle,Select,Count,Row,Oracle Call Interface,Noob(关于Oracle和OCI) 我正在写一个程序为我的公司做一些任务。在这些任务中,我必须更新oracle数据库,使其与其他操作保持同步 我希望有效地预分配内存,以保存在选择集上获取的结果。为了做到这一点,我需要知道选择集中有多少行 我可以用两个单独的语句来完成它;首先是SELECT COUNT语句,然后是SELECT语句,但从服务器的角度来看,这是低效的。我也可以只执行SELECT语句,并在从SELECT集中提取行时动态分配内存,但从客户机的角度来看,这是低效的 我只想执行SELECT语

Noob(关于Oracle和OCI)

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

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

我可以用两个单独的语句来完成它;首先是SELECT COUNT语句,然后是SELECT语句,但从服务器的角度来看,这是低效的。我也可以只执行SELECT语句,并在从SELECT集中提取行时动态分配内存,但从客户机的角度来看,这是低效的

我只想执行SELECT语句,在获取任何行之前,检索SELECT集中匹配行的数量

但我找不到包含此信息的属性。
存在OCI_ATTR_ROW_COUNT,但这是获取的行数,而不是选择集中的行总数。 然后是OCI_ATTR_PARAM_COUNT,它告诉您列的数量(似乎没有用,因为您已经知道在SQL中需要多少列)

有人知道如何在获取之前获取select set行数吗

谢谢
乔希,你不能。Oracle数据库通常在获取最后一行之前不知道查询将返回多少行

通常,客户机将被设计为从客户机获取特定大小的数据批,处理这些结果,然后获取下一批数据。例如,大多数PL/SQLGUI应用程序(TOAD、SQLDeveloper等)将执行一个查询,获取第一批50或100行,然后等待用户。当用户翻阅数据时,客户机将获取下一批数据,处理该数据,并进行迭代,直到最后一批数据被使用。您的应用程序需要确定是否可以从内存中丢弃以前的批处理,或者是否需要保留它们(例如,为了支持用户在不重新执行查询的情况下向后滚动的能力)


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

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

我想说,您根本不需要担心这个问题——只需动态分配内存即可。但我想如果这是一个非常大的结果集,您可能会有一些性能问题

我可以想出几个选择:

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

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


3) 根据您对可能返回的行数的期望,以合理大小的块分配内存。在某些情况下,您可能会过度分配,但如果您的数据块大小不太大,这不太可能是一个大问题。

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

例如,PostgreSQL的工作方式不同。它使用客户端的RAM作为缓冲区。所以对语句“execute”的调用将一直等到所有结果行都存储在客户机的RAM中。调用fetch只会在客户端RAM中的缓冲区上进行迭代。
(除非您使用的是显式游标)。

您可以使用可滚动语句句柄获取最后一行,然后询问当前位置:

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);
如果要重用语句句柄,请记住倒带它:

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

我们讨论了多少数据/行?什么是宿主语言?一些答案表示无法查询选择集中的行数。谢谢你的回复。我可以使用滚动光标解决这个问题吗?换句话说,我知道选择集中可能的最大行数(表中的行数)。我是否可以从最大值开始按顺序提取行,并以二进制搜索方式向下搜索,直到确定有多少行?使用二进制搜索算法,这不会超过25或30次回迁…我们最小的表有1行(实际上有一些表有0行,但它们不是很有趣),而我们最大的表有180万行。我们的选择集预计会在一个典型的表上生成20到50000个结果。我明白了。好的,让我问一个后续问题;在OCIStatementExecute函数期间,服务器端发生了什么?我的假设(显然是错误的)是,在这次通话中