pgjdbc/pgjdbc GitHub issues and pull requests (mirror)  
help / color / mirror / Atom feed
From: lukaseder (@lukaseder) <[email protected]>
To: pgjdbc/pgjdbc <[email protected]>
Subject: [pgjdbc/pgjdbc] issue #3865: Avoid well known slow JDK libraries String.format() and DecimalFormat in PGInterval::getValue to get drastic performance boost
Date: Thu, 13 Nov 2025 16:40:42 +0000
Message-ID: <[email protected]> (raw)

**Describe the issue**

`PGInterval::getValue` uses `Stirng::format` and `DecimalFormat` to format the interval value to the PostgreSQL notation:

```java
  public @Nullable String getValue() {
    if (isNull) {
      return null;
    }
    DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.US);
    df.applyPattern("0.0#####");

    return String.format(
      Locale.ROOT,
      "%d years %d mons %d days %d hours %d mins %s secs",
      years,
      months,
      days,
      hours,
      minutes,
      df.format(getSeconds())
    );
  }
```

This performs terribly and should be avoided. I'm suggesting this alternative implementation, which should do the same thing (except it always renders trailing zeros):

```java
  public String getValue() {
    if (isNull) {
      return null;
    }

    StringBuilder sb = new StringBuilder();
    sb.append(years).append(" years ")
      .append(months).append(" mons ")
      .append(days).append(" days ")
      .append(hours).append(" hours ")
      .append(minutes).append(" mins ");

    if (wholeSeconds < 0 || microSeconds < 0)
      sb.append('-');

    sb.append(Math.abs(wholeSeconds));

    if (microSeconds != 0) {
      sb.append('.');
      String s = "" + Math.abs(microSeconds);

      for (int i = s.length(); i < 6; i++)
        sb.append('0');

      sb.append(s);
    }

    sb.append(" secs");
    return sb.toString();
  }
```

**Driver Version?** 

42.7.8

**Java Version?**

openjdk version "21.0.7" 2025-04-15 LTS

**OS Version?**

Microsoft Windows [Version 10.0.26100.7171]

**PostgreSQL Version?**

N/A

**To Reproduce**

Run this JMH benchmark:

```java
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;

@Fork(value = 3)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
public class PGIntervalBenchmark {

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

        PGInterval interval;

        @Setup(Level.Trial)
        public void setup() throws Exception {
            interval = new PGInterval(0, 0, 0, 0, 0, 0);
        }

        @TearDown(Level.Trial)
        public void teardown() throws Exception {
            interval = null;
        }
    }

    @Benchmark
    public String testGetValue(BenchmarkState state) {
        return state.interval.getValue();
    }
}
```

**Expected behaviour**

The current version produces these benchmark results:

```
PGIntervalBenchmark.testGetValue  thrpt   15   1447069.902 ± 67832.795  ops/s
```

My version produces a 32x improvement:

```
PGIntervalBenchmark.testGetValue  thrpt   15  46957485.917 ± 497298.690  ops/s
```

view thread (4+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: github://pgjdbc/pgjdbc
  Cc: [email protected], [email protected]
  Subject: Re: [pgjdbc/pgjdbc] issue #3865: Avoid well known slow JDK libraries String.format() and DecimalFormat in PGInterval::getValue to get drastic performance boost
  In-Reply-To: <<[email protected]>>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox