JDBC驱动程序如何实现setMaxRows方法

时间:2015-09-25 07:24:35

标签: mysql sql-server oracle postgresql jdbc

根据JDBC规范,Statement.setMaxRows(int maxRows)方法应该是:

  

设置任何ResultSet的最大行数限制   此Statement对象生成的对象可以包含给定的对象   数。如果超出限制,则多余的行是静默的   丢弃。

在针对限制SQL级别的结果集(ROWSET,TOP和LIMIT)进行测试时,JDBC和SQL构造似乎都表现得非常好。

即使选择了数百万行,setMaxRows似乎也没有表现得更差。

可能是因为数据库Executor可能使用只按需提取记录的数据库游标,所以当驱动程序达到maxRows阈值时,可以指示数据库关闭游标吗?

这样,数据库就不必选择一个巨大的结果集并将其发送到线路,只能在客户端丢弃。

3 个答案:

答案 0 :(得分:4)

在PostgreSQL中,PgJDBC在协议级别发送一个请求,相当于在查询中附加STKAudioPlayer。因此,数据库服务器知道尽量减少它所做的工作量。它可能会选择一个获取所有行的成本更高的计划,但是可以更快地返回某些行或避免大的全行排序,例如。

我希望其他引擎的客户端驱动程序类似 - 在幕后设置限制,或使用游标并读取,直到它们有足够的结果。

每个DBMS和驱动程序都会有所不同,因此很难找到一个明确的答案。

答案 1 :(得分:1)

大多数JDBC驱动程序将根据需要获取行(基于获取大小),因此通常maxRows非常有效。它们通常甚至可以优化,只需获取不超过maxRows

ROWSTOP可能会为数据库服务器提供一些优化查询的额外提示,因此设置maxRows可能不如在查询本身中包含max那样高效。确切的行为取决于驱动程序和数据库,因此很难概括行为和性能特征。

值得注意的例外是MySQL驱动程序(可能还有MariaDB)默认在查询执行时立即获取所有行(除非提取大小设置为Integer.MIN_VALUE)。

作为Jaybird(Firebird JDBC驱动程序)中的示例,following已完成(TYPE_FORWARD_ONLY):

public void fetch() throws SQLException {
    synchronized (syncProvider.getSynchronizationObject()) {
        checkClosed();
        int maxRows = 0;

        if (this.maxRows != 0) maxRows = this.maxRows - rowNum;

        int fetchSize = this.fetchSize;
        if (fetchSize == 0) fetchSize = MAX_FETCH_ROWS;

        if (maxRows != 0 && fetchSize > maxRows) fetchSize = maxRows;

        if (!allRowsFetched && (rows.isEmpty() || rows.size() == rowPosition)) {
            rows.clear();
            stmt.fetchRows(fetchSize);
            rowPosition = 0;
        }

        if (rows.size() > rowPosition) {
            setNextRow(rows.get(rowPosition));
            // help the garbage collector
            rows.set(rowPosition, null);
            rowPosition++;
        } else {
            setNextRow(null);
        }
    }
}

由于服务器可能决定发送超过请求的行数,因此会对next()进行额外检查。

答案 2 :(得分:1)

Oracle使用生产者 - 消费者设计模式。因此,在客户端开始从游标获取到ResultSet时生成行。有两个优化器目标:ALL_ROWS和FIRST_ROWS(分别为FIRST_ROWS(n))。当使用first_rows优化器目标时,Oracle倾向于在hash_joins上使用更多嵌套循环,因此它应该更快地返回第一批结果数据。但我不确定使用setMaxRows方法是否也会更改查询的优化程序目标。