resultSet.next():它是从缓冲区OR从数据库中获取数据吗?

时间:2017-02-21 21:38:21

标签: java database oracle jdbc resultset

我有一个如下代码,

try (Connection connection = this.getDataSource().getConnection();
         PreparedStatement statement = connection.prepareStatement(sqlQuery);) {


        try {
            statement.setFetchSize(10000); // Set fetch size
            resultSet = statement.executeQuery();

            while (true) {
                resultSet.setFetchSize(10000);
                boolean more = resultSet.next();
                if (! more) {
                    break;
                }
                // populating an arraylist from the value from resultSet
            }
        }
        catch (Exception e) {
            LOGGER.error("Exception : "+e);
        }
    } catch (SQLException e) {
        LOGGER.error("Exception : "+e);
    }

我的理解如下,

语句提取大小为10000.当执行statement.executeQuery()时,它返回ResultSet游标。它将在内存中有10000行。 调用resultSet.next时,它从内存缓冲区中获取一行。 (每次通话一排)。当内存中没有更多行时,将再次触发查询,并再次从数据库中提取10000行并将其存储在缓冲区中。这将继续,直到没有要从DB

获取的行

因此,如果我的理解是正确的, 总行数为210000,将会有多少实际数据库调用 ?是21岁吗? (210000/10000)

当调用DB时(当缓冲区中的行都被读取时)获取更多行(在我的情况下为10000)并存储在缓冲区中。缓冲区什么时候清除?

如果我理解错误,请纠正我。

我需要使用Oracle数据库中的数百万个数据。

感谢任何指针/信息

此致

SD

2 个答案:

答案 0 :(得分:4)

抱歉,但您的理解是错误的。没有"再次触发查询"。

执行一次查询。这将花费初始时间来处理查询(除了优化查询之外,您无法执行任何操作),然后它将开始在服务器上生成行,这些行需要传输到客户端。在传输行时,服务器可能会继续生成更多要传输的行,并在服务器上缓冲它们。这种服务器端缓冲与我们在本Q& A中讨论的缓冲类型完全无关,而您几乎无法控制它。 (也许通过服务器配置,如果有的话。)在某些时候,所有行都将在服务器上收集,然后唯一剩下的事情就是将剩余的行从服务器传输到客户端。

因此,就客户端可以判断,一旦它将查询发送到服务器,服务器在考虑它时会有一定的延迟,之后行的速度通常一样快因为电线可以携带它们。因此,客户端开始使用resultSet.next()读取这些行。

没有任何缓冲,每次调用resultSet.next()都会从客户端向服务器发送请求,告诉它发送下一行,服务器只响应该行。这会非常快地产生第一行,但从长远来看效率非常低,因为它会导致客户端和服务器之间的往返过多。

通过缓冲,第一次调用resultSet.next()将从服务器请求一堆行。这将对接收第一行的时间施加惩罚,因为您将不得不等待通过线路发送100行,但从长远来看,它将显着减少总网络开销,因为只会有每个行数的客户端和服务器之间的一次往返。

resultSet.setFetchSize()的理想策略是保持原样,不要过于担心。

但是如果你对性能很偏执,那么一个好的策略是从一个相当小的提取大小开始(比如10),以便快速获得你的第一行,然后保持加倍直到达到某个最大(比如说100),超过这个数字,实际上没有任何进步。

答案 1 :(得分:3)

唯一可以回复您问题的人是Oracle JDBC驱动程序的作者。

据说,调用db来读取下一个数据块的时间不会超过几毫秒(或更少),大部分时间将取决于传输速率,以及可能的方式来自结果集。

我认为,一旦你每次通话超过几百个记录,你就会减少回报,设置更大的提取量。

关于清除对结果集的引用松开缓冲区(主要是垃圾收集域)。

请确保您的声明仅为FORWARD,仅出于性能原因和内存占用。

connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY );