Slow compilation with jOOQ 3.6+, plain SQL, and the javac compiler [duplicate]

亡梦爱人 提交于 2019-11-30 04:47:45

问题


The following bug was reported to the jOOQ user group. It really seems to be a bug in the javac compiler related to rather "complex" type inference work done by the compiler in the context of using an internal DSL like jOOQ is.

Given the general nature of the bug, I'm documenting it here on Stack Overflow for others to help apply workarounds if they run into it. On a high level, it seems to be a compiler performance regression due to JEP 101: Generalized Target-Type Inference, which was introduced in Java 8 and has caused 1-2 issues in the past.

The following relatively harmless class takes around 20 seconds to compile with jdk 1.8.0_60 or 1.8.0_66 on Windows using Maven and jOOQ 3.7:

import static org.jooq.impl.DSL.field;

import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
        ;
    }
}

pom.xml:

<project 
        xmlns="http://maven.apache.org/POM/4.0.0" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>compilation-issues</groupId>
    <artifactId>compilation-issues</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq</artifactId>
            <version>3.7.1</version>
        </dependency>
    </dependencies>
</project>

Configurations when this issue doesn't appear:

  • Using jOOQ 3.5 (anything prior to 3.6.0)
  • Using jOOQ with generated classes rather than the above "plain SQL" API
  • Using Java 7
  • Using the Eclipse compiler

回答1:


Explanation

In jOOQ 3.6 (when this problem first appears), the DSL.field() API saw 22 new overloads taking different Row types as arguments:

  • DSL.field(Row1<T1>)
  • DSL.field(Row2<T1, T2>)
  • DSL.field(Row3<T1, T2, T3>)
  • ...

It appears that with this particular API usage above, the new overloads cause a lot of trouble when the javac compiler tries to find the most specific overload among all the possible overloads. The following workaround compiles instantly:

Fix

A fix is under way for releases 3.9.0, 3.8.1, 3.7.4, 3.6.5, removing these methods again from the public API, and providing a renamed substitute that does not cause any overloading issues.

Workarounds

1. Helping the compiler select the most specific DSL.field() overload

import static org.jooq.impl.DSL.field;

import org.jooq.Field;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        Field<Object> f1 = field("client.id");
        Field<Object> f2 = field("client_id");
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
        ;
    }
}

2. Preventing target type inference in the context of the and() method entirely

import static org.jooq.impl.DSL.field;

import org.jooq.Condition;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        Condition condition = field("client.id").eq(field("client_id"));
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
        ;
    }
}

More info

This has actually been reported on Stack Overflow before:

  • Troubleshoot slow compilation
  • http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8086048

And it has been discussed also on the jOOQ user group:

  • https://groups.google.com/forum/#!topic/jooq-user/vuaG9d9krDk
  • https://groups.google.com/forum/#!topic/jooq-user/grv6Wu_sFtA


来源:https://stackoverflow.com/questions/34223249/slow-compilation-with-jooq-3-6-plain-sql-and-the-javac-compiler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!