question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Performance Issues reading LocalDate,LocalDateTime, and LocalTime

See original GitHub issue

Driver version

7.2.1.jre8

SQL Server version

Microsoft SQL Server 2014 (SP3) (KB4022619) - 12.0.6024.0 (X64) Sep 7 2018 01:37:51 Copyright © Microsoft Corporation Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: )

Client Operating System

Ubuntu 16.04

JAVA/JVM version

openjdk version “12” 2019-03-19 OpenJDK Runtime Environment (build 12+33) OpenJDK 64-Bit Server VM (build 12+33, mixed mode, sharing)

Table schema

CREATE TABLE test.DatePerformance (
	someDate DATE
)

-- Populate Table with Random Dates
INSERT INTO test.DatePerformance
SELECT DATEADD(DAY, -RAND(12313456) * 1000, GETDATE())

WHILE((SELECT COUNT(*) FROM test.DatePerformance) < 2500)
INSERT INTO test.DatePerformance
SELECT DATEADD(DAY, -RAND() * 1000, GETDATE())

Problem description

  1. Expected behaviour:

    • Reading Date objects from the database should have low overhead.
  2. Actual behaviour:

    • There is substantial overhead creating GregorianCalendars and converting them to the LocalDate, LocalDateTime, LocalTime classes
    • Calling Calendar.getInstance(TimeZone.getTimeZone(“UTC”)) is 30% of the getObject call for LocalDate, LocalDateTime, LocalTime classes
  3. Error message/stack trace:

  4. Any other details that can be helpful:

Sample Profiling Snapshots

	com.microsoft.sqlserver.jdbc.SQLServerResultSet.getObject () 15.094s
>	com.microsoft.sqlserver.jdbc.DDC.convertTemporalToObject () 9.206s
>>	java.util.GregorianCalendar.<init> () 6.01s
>>	java.util.Calendar.getTimeInMillis () 3.005s
>	java.util.Calendar.getInstance () 5.088s

	com.microsoft.sqlserver.jdbc.SQLServerResultSet.getObject () 7.601s
>	com.microsoft.sqlserver.jdbc.DDC.convertTemporalToObject () 3.906s
>>	java.util.GregorianCalendar.<init> () 2.498s
>>	java.util.Calendar.getTimeInMillis () 1.407s
>	java.util.Calendar.getInstance () 3.302s

Reproduction code

    /**
    Using JMH (LocalDate)

    Result: 338.352 ±(99.9%) 27.177 ops/s [Average]
    Statistics: (min, avg, max) = (5.716, 338.352, 435.926), stdev = 115.069
    Confidence interval (99.9%): [311.175, 365.529]


    # Run complete. Total time: 00:08:10

    Benchmark                        Mode  Samples    Score  Score error  Units
    c.c.m.MyBenchmark.testMethod    thrpt      200  338.352       27.177  ops/s
    */

    @Benchmark
    public void testMethod()
    {
        List<LocalDate> dates = new ArrayList<>();

        try (
                Connection conn = dataSource.getConnection();
                PreparedStatement ps = conn.prepareStatement("SELECT someDate from test.DatePerformance");
                ResultSet rs = ps.executeQuery()
        )
        {
            while(rs.next())
                dates.add(rs.getObject("someDate", LocalDate.class));

        } catch (SQLException e)
        {
            e.printStackTrace();
        }
    }

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:31 (24 by maintainers)

github_iconTop GitHub Comments

3reactions
peterbaecommented, Aug 30, 2019

Hi @cogman, thanks for the input. I agree that we should use as little of GregorianCalendar as possible. I’d like to replace all instances of Calendar in the driver, but the JDBC specs state that the driver needs to provide public APIs that accept Calendar objects (mostly from getters/setters for temporal objects in prepared/callable statements).

Looking at how the driver actually uses the Calendar objects passed from the client, most of the time they’re used for the timezone information. I’ll look into extracting the necessary information from the Calendar object as soon as it’s passed from the public API, while replacing as many instances of Calendar parameters with TimeZone parameters in internal methods. I’ll also make sure that the driver never initializes any GregorianCalendar objects, either.

It’ll take a while, but I’ll update everyone once the initial PR/design has been made. Please let me know if you have any other input in the meantime.

3reactions
cogmancommented, Jun 19, 2019

@gordthompson Care should be taken in the fact that the Calendar object is not thread safe.

Ideally, the driver would switch away from using the calendar object and instead look at using ZonedDateTime or straight local dates. If my reading of the TDS standard is correct, than a SQL “Date” ends up on the wire as the integer “number of days since 1-1-1” That would be a trivial conversion to localDates because it would simply be “LocalDate.of(1,1,1).addDays(tdsIntValue);” (or, whatever that API is.

The new system is much faster and thread safe to boot. Converting to java.sql.Date is also pretty simple because it is just a “Date.from(ZonedDateTime.toInstant())” away.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Performance Issues Related to LocalDateTime and Instant ...
This article discusses some performance issues that an Alibaba engineered encountered during serialization operations which were related to ...
Read more >
Java 8 LocalDateTime.now() only giving precision of ...
My problem is that I need to do logging using both Java and Javascript and they need ... LocalDate hpDate = LocalDate.now(microsecondClock);.
Read more >
Still using java.util.Date? Don't! - Programming Hints
The LocalDateTime combines together LocaleDate and LocalTime and holds a date with time but without a time-zone in the ISO-8601 calendar system. ZonedDateTime ......
Read more >
Migrating to the New Java 8 Date Time API - Baeldung
LocalDate – represents a date (year, month, day); LocalDateTime – same as LocalDate, but includes time with nanosecond precision; OffsetDateTime ...
Read more >
99487: Mysql connector for java 8.0.20 shifts back LocalDate ...
But the driver can follow this change only when cacheDefaultTimezone=false. We have other issues with LocalDate/LocalTime/LocalDatetime reported ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found