pgjdbc/pgjdbc GitHub issues and pull requests (mirror)
help / color / mirror / Atom feedFrom: 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