• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Setting the JDBC Assertion.setFetchSize() to 1 for Single Row Queries – Java, SQL and jOOQ.

Admin by Admin
June 2, 2025
Home Coding
Share on FacebookShare on Twitter


An fascinating trace by Vladimir Sitnikov has made me take into consideration a brand new benchmark for jOOQ:

Fascinating thought. Do you’ve a benchmark prepared for this, maybe?

— Lukas Eder (@lukaseder) June 23, 2021

The benchmark ought to examine whether or not single row queries ought to have a JDBC Assertion.setFetchSize(1) name made to them by default. The Javadoc of the strategy says:

Offers the JDBC driver a touch as to the variety of rows that needs to be fetched from the database when extra rows are wanted for ResultSet objects generated by this Assertion. If the worth specified is zero, then the trace is ignored. The default worth is zero.

If an ORM (e.g. jOOQ) is aware of that it’s going to fetch only one row, or if it is aware of that there could be only one row, then that trace actually is smart. Examples in jOOQ embody:

  • When customers name ResultQuery.fetchSingle(), or fetchOne(), or fetchOptional(), or any comparable methodology, then it’s cheap to anticipate solely 0 – 1 rows to be returned. Within the case of these strategies returning greater than 1 row, an exception is thrown, so even when there are extra rows, 2 rows can be fetched at most.
  • When customers add a LIMIT 1 clause on a high stage question, there can by no means be greater than 1 row.
  • When the question is trivial (no joins, or solely to-one joins, no GROUP BY GROUPING SETS, no UNION, and so on.) and an equality predicate on a UNIQUE constraint is current, there will also be not more than 1 row.

The database optimiser is aware of all of this stuff as effectively. Should you add LIMIT 1 to a question, then the optimiser could be moderately anticipated to take that as a robust trace in regards to the consequence set measurement. However the JDBC driver doesn’t know this stuff (or at the very least, it shouldn’t be anticipated to), as a result of it’s unlikely that it parses the SQL and calculates statistics on it, or considers meta information for such optimisations.

So, the consumer might trace. And since that may be very tedious for customers, even higher, the ORM (e.g. jOOQ) ought to trace. Or so it appears.

Benchmarks

However ought to it? Is it actually definitely worth the bother? Right here’s Vladimir’s evaluation in regards to the pgjdbc driver, the place he wouldn’t anticipate an enchancment now, however maybe sooner or later.

Simply in case, the cells in pgjdbc are created “as they’re acquired”, so setFetchSize() doesn’t trigger instantiation of all of the 50’000 byte[] arrays

— Vladimir Sitnikov (@VladimirSitnikv) June 23, 2021

Higher than making assumptions, let’s measure, utilizing a JMH benchmark. JMH is generally used for microbenchmarking issues on the JVM, to check assumptions about JIT runtime behaviour. That is clearly not a microbenchmark, however I nonetheless like JMH’s strategy and output, which incorporates commonplace deviations and errors, in addition to ignores warmup penalties, and so on.

First off, the outcomes:

As a result of benchmark outcomes can’t be printed for some industrial RDBMS (at the very least not when evaluating between RDBMS), I’ve normalised the outcomes so a comparability of precise execution velocity between RDBMS isn’t attainable. I.e. for every RDBMS, the quicker execution is 1, and the slower one is a few fraction of 1. That means, the RDBMS is simply benchmarked towards itself, which is truthful.

The outcomes are beneath. We’re measuring throughput, so decrease is worse.

Db2
---
Benchmark                            Mode   Rating 
JDBCFetchSizeBenchmark.fetchSize1   thrpt   0.677
JDBCFetchSizeBenchmark.noFetchSize  thrpt   1.000

MySQL
-----
Benchmark                            Mode   Rating 
JDBCFetchSizeBenchmark.fetchSize1   thrpt   0.985
JDBCFetchSizeBenchmark.noFetchSize  thrpt   1.000

Oracle
------
Benchmark                            Mode   Rating 
JDBCFetchSizeBenchmark.fetchSize1   thrpt   0.485
JDBCFetchSizeBenchmark.noFetchSize  thrpt   1.000

PostgreSQL
----------
Benchmark                            Mode   Rating 
JDBCFetchSizeBenchmark.fetchSize1   thrpt   1.000
JDBCFetchSizeBenchmark.noFetchSize  thrpt   0.998

SQL Server
----------
Benchmark                            Mode   Rating 
JDBCFetchSizeBenchmark.fetchSize1   thrpt   0.972
JDBCFetchSizeBenchmark.noFetchSize  thrpt   1.000

For every RDBMS, I’ve run a trivial question producing a single row with 1 column. Every time, I’ve re-created a JDBC Assertion, and fetched the ResultSet. In fetchSize1, I’ve specified the fetch measurement trace. In noFetchSize, I left the default untouched. As could be summarised:

In these RDBMS, there was no impact

  • MySQL
  • PostgreSQL
  • SQL Server

In these RDBMS, issues obtained considerably worse (not higher!):

That is fairly stunning, because the benchmark consists of working your entire assertion on the server, so I’d have anticipated, at finest, a negligible consequence.

For this benchmark, I used to be utilizing these server and JDBC driver variations:

  • Db2 11.5.6.0 with jcc-11.5.6.0
  • MySQL 8.0.29 with mysql-connector-java-8.0.28
  • Oracle 21c with ojdbc11-21.5.0.0
  • PostgreSQL 14.1 with postgresql-42.3.3
  • SQL Server 2019 with mssql-jdbc-10.2.0

The benchmark logic is right here:

package deal org.jooq.check.benchmarks.native;

import java.sql.*;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

@Fork(worth = 1)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 7, time = 3)
public class JDBCFetchSizeBenchmark {

    @State(Scope.Benchmark)
    public static class BenchmarkState {

        Connection connection;

        @Setup(Degree.Trial)
        public void setup() throws Exception {
            Class.forName("org.postgresql.Driver");
            connection = DriverManager.getConnection(
                "jdbc:postgresql://localhost:5432/postgres",
                "postgres",
                "check"
            );
        }

        @TearDown(Degree.Trial)
        public void teardown() throws Exception {
            connection.shut();
        }
    }

    @FunctionalInterface
    interface ThrowingConsumer {
        void settle for(T t) throws SQLException;
    }

    non-public void run(
        Blackhole blackhole,
        BenchmarkState state,
        ThrowingConsumer c
    ) throws SQLException {
        attempt (Assertion s = state.connection.createStatement()) {
            c.settle for(s);

            attempt (ResultSet rs = s.executeQuery(
                "choose title from t_book the place id = 1")
            ) {
                whereas (rs.subsequent())
                    blackhole.eat(rs.getString(1));
            }
        }
    }

    @Benchmark
    public void fetchSize1(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        run(blackhole, state, s -> s.setFetchSize(1));
    }

    @Benchmark
    public void noFetchSize(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        run(blackhole, state, s -> {});
    }
}

Just a few remarks:

  • The question is on no account consultant of a manufacturing workload. But when issues did get improved by the fetchSize flag, the development ought to have manifested
  • The benchmark didn’t use ready statements, which might have eliminated some side-effects, or added some side-effects. Be at liberty to repeat the benchmark utilizing ready statements.
  • It’s not but understood why issues didn’t matter in some drivers, or why they did in others. For the conclusion, the “why” isn’t too vital, as a result of nothing can be modified on account of this weblog publish. If why (the db2 driver and ojdbc code isn’t open supply, regrettably), I’d be curious.

Conclusion

Optimisations are a difficult beast. Some issues appear to make loads of sense when reasoning about them, however in precise measurements, the seemingly extra optimum factor is definitely worse, or irrelevant.

On this case, at first, it seemed as if we should always trace the JDBC driver about our intentions of fetching only one row. I don’t know why the JDBC driver behaved worse than if I didn’t trace it. Maybe it allotted a buffer that was too small, and needed to enhance it, relatively than allocating a buffer that was too massive, however massive sufficient. I do know now, due to Douglas Surber’s touch upon the reddit dialogue. The issue is that ojdbc doesn’t know whether or not there can be extra rows, so the JDBC rs.subsequent() name has to do one other spherical journey. For extra particulars, see the linked remark above.

I’ve executed comparable benchmarks previously, attempting to “optimise” preliminary sizes of ArrayList or StringBuilder. I used to be hardly in a position to constantly outperform the defaults. Typically, the “enchancment” did appear to enhance issues. Typically, it worsened issues.

With no clear wins (that are understood, don’t blindly belief benchmark outcomes both, even when you’re successful!), I misplaced confidence in these enhancements, and didn’t implement them ultimately. This case right here is identical. I’ve not been in a position to obtain enhancements, however in 2/5 circumstances, issues obtained considerably worse.

Observe up

On /r/java, there had been a dialogue about this text. It instructed 2 further checks:

1. Strive utilizing a fetchSize of two

You’d be tempted to assume that different fetch sizes might nonetheless be acceptable, e.g. 2, to stop that potential buffer measurement increment. I simply tried that with Oracle solely, producing:

JDBCFetchSizeBenchmark.fetchSize1   thrpt  0.513
JDBCFetchSizeBenchmark.fetchSize2   thrpt  0.968
JDBCFetchSizeBenchmark.noFetchSize  thrpt  1.000

Whereas the penalty of setting the fetchSize to 1 has disappeared, there may be once more no enchancment over the default worth. For a proof, see once more Douglas Surber’s touch upon reddit

2. Strive utilizing PreparedStatements

In my view, PreparedStatement utilization shouldn’t matter for this particular benchmark, which is why I had initially left them out. Somebody on the reddit dialogue was keen to place all their cash on the only PreparedStatement card, so right here’s an up to date consequence, once more with Oracle solely, evaluating static statements with ready ones (up to date benchmark code beneath):

Benchmark                                    Mode     Rating
JDBCFetchSizeBenchmark.fetchSizePrepared1    thrpt    0.503
JDBCFetchSizeBenchmark.fetchSizeStatic1      thrpt    0.518
JDBCFetchSizeBenchmark.fetchSizePrepared2    thrpt    0.939
JDBCFetchSizeBenchmark.fetchSizeStatic2      thrpt    0.994
JDBCFetchSizeBenchmark.noFetchSizePrepared   thrpt    1.000
JDBCFetchSizeBenchmark.noFetchSizeStatic     thrpt    0.998

The consequence is identical for each. Not simply that, it may be seen that in my explicit setup (Querying Oracle XE 21c in docker, domestically), there’s completely no distinction between utilizing a static assertion and a ready assertion on this case.

It might once more be fascinating to research why that’s, hypotheses might embody e.g.

  • ojdbc caches additionally static statements within the ready assertion cache
  • the impact of caching a ready assertion is negligible in a benchmark that runs solely a single assertion, which is nowhere close to consultant of a manufacturing workload
  • the consumer aspect impact of getting ready statements is irrelevant in comparison with the advantages of the cursor cache on the server aspect, or in comparison with the detrimental impact of setting the fetchSize to 1

The up to date benchmark code:

package deal org.jooq.check.benchmarks.native;

import java.sql.*;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

@Fork(worth = 1)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 7, time = 3)
public class JDBCFetchSizeBenchmark {

    @State(Scope.Benchmark)
    public static class BenchmarkState {

        Connection connection;

        @Setup(Degree.Trial)
        public void setup() throws Exception {
            Class.forName("oracle.jdbc.OracleDriver");
            connection = DriverManager.getConnection(
                "jdbc:oracle:skinny:@localhost:1521/XEPDB1",
                "TEST",
                "TEST"
            );
        }

        @TearDown(Degree.Trial)
        public void teardown() throws Exception {
            connection.shut();
        }
    }

    @FunctionalInterface
    interface ThrowingConsumer {
        void settle for(T t) throws SQLException;
    }

    non-public void runPrepared(
        Blackhole blackhole,
        BenchmarkState state,
        ThrowingConsumer c
    ) throws SQLException {
        attempt (PreparedStatement s = state.connection.prepareStatement(
            "choose title from t_book the place id = 1")
        ) {
            c.settle for(s);

            attempt (ResultSet rs = s.executeQuery()) {
                whereas (rs.subsequent())
                    blackhole.eat(rs.getString(1));
            }
        }
    }

    non-public void runStatic(
        Blackhole blackhole,
        BenchmarkState state,
        ThrowingConsumer c
    ) throws SQLException {
        attempt (Assertion s = state.connection.createStatement()) {
            c.settle for(s);

            attempt (ResultSet rs = s.executeQuery(
                "choose title from t_book the place id = 1")
            ) {
                whereas (rs.subsequent())
                    blackhole.eat(rs.getString(1));
            }
        }
    }

    @Benchmark
    public void fetchSizeStatic1(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        runStatic(blackhole, state, s -> s.setFetchSize(1));
    }

    @Benchmark
    public void fetchSizeStatic2(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        runStatic(blackhole, state, s -> s.setFetchSize(2));
    }

    @Benchmark
    public void noFetchSizeStatic(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        runStatic(blackhole, state, s -> {});
    }

    @Benchmark
    public void fetchSizePrepared1(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        runPrepared(blackhole, state, s -> s.setFetchSize(1));
    }

    @Benchmark
    public void fetchSizePrepared2(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        runPrepared(blackhole, state, s -> s.setFetchSize(2));
    }

    @Benchmark
    public void noFetchSizePrepared(Blackhole blackhole, BenchmarkState state)
    throws SQLException {
        runPrepared(blackhole, state, s -> {});
    }
}

Like this:

Like Loading…



Tags: JavaJDBCjOOQQueriesRowSettingSingleSQLStatement.setFetchSize
Admin

Admin

Next Post
Flowable’s Good Automation Instruments Are Reshaping How Enterprises Function in 2025

Flowable’s Good Automation Instruments Are Reshaping How Enterprises Function in 2025

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recommended.

I Ran 10 Prompts to See Who Wins

I Ran 10 Prompts to See Who Wins

April 21, 2025
The Darkish Prince’ iOS Evaluation – A lot Higher Than Swap, however Missing in Two Methods – TouchArcade

The Darkish Prince’ iOS Evaluation – A lot Higher Than Swap, however Missing in Two Methods – TouchArcade

April 7, 2025

Trending.

Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

April 10, 2025
Expedition 33 Guides, Codex, and Construct Planner

Expedition 33 Guides, Codex, and Construct Planner

April 26, 2025
How you can open the Antechamber and all lever places in Blue Prince

How you can open the Antechamber and all lever places in Blue Prince

April 14, 2025
Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

April 28, 2025
Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

May 5, 2025

AimactGrow

Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

Categories

  • AI
  • Coding
  • Cybersecurity
  • Digital marketing
  • Gaming
  • SEO
  • Technology

Recent News

Borderlands 4 is a daring departure for the collection, however 2K could have carved off a few of its soul within the pursuit of killing cringe – preview

Borderlands 4 is a daring departure for the collection, however 2K could have carved off a few of its soul within the pursuit of killing cringe – preview

June 18, 2025
Coding a 3D Audio Visualizer with Three.js, GSAP & Internet Audio API

Coding a 3D Audio Visualizer with Three.js, GSAP & Internet Audio API

June 18, 2025
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved