Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Slow to Acquire Postgres Connection

I'm having a really difficult time debugging this problem. Whenever I try to establish a connection with postgres, it takes a whole minute. After the connection is established, everything is fine. I've tried disabling all the mappings and not loading any, but still the connection takes a long time to aquire. I've also tried disabling validation, no difference. When I use a simple a simple JDBC connection, it's instantaneous. Hibernate is doing something which takes considerable amount of time and I can't seem to narrow it down. Any input is greatly appreciated!

Postgres Driver:

postgresql-9.1-901.jdbc4.jar

Configuration settings:

<hibernate-configuration>
    <session-factory>
    <!-- properties -->
        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="connection.driver_class">org.postgresql.Driver</property>

        <property name="connection.url">jdbc:postgresql://xxxx.com:5432/xxxxx</property>
        <property name="connection.username">xxxxxxx</property>
        <property name="connection.password">xxxxxxx</property>

    </session-factory>
</hibernate-configuration>

Additional settings in code:

    config.setProperty("hibernate.hbm2ddl.auto", hbm2ddlMode);
    //config.setProperty("hibernate.cache.use_query_cache", "true");
    config.setProperty("hibernate.cache.use_second_level_cache", "true");
    //config.setProperty("hibernate.cache.region.factory_class", "net.sf.ehcache.hibernate.EhCacheRegionFactory");
    config.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider");
    //config.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
    config.setProperty("hibernate.jdbc.fetch_size", "100");
    config.setProperty("hibernate.jdbc.batch_size", "30");
    config.setProperty("hibernate.jdbc.use_scrollable_resultset", "true");
    config.setProperty("hibernate.connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");

    config.setProperty("hibernate.c3p0.acquire_increment", "1");
    config.setProperty("hibernate.c3p0.idle_test_period", "0");
    config.setProperty("hibernate.c3p0.min_size", "1");
    config.setProperty("hibernate.c3p0.max_size", "2");
    config.setProperty("hibernate.c3p0.timeout", "0");
    config.setProperty("javax.persistence.validation.mode", "none");

Here's the segment of code where the delay occurs:

private SessionFactory buildSessionFactory() throws Exception {
        ServiceRegistry serviceRegistry  = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();

            //Building session takes a whole minute without mappings!!!
        sessionFactory = config.buildSessionFactory(serviceRegistry);

        validateConnection();

        return sessionFactory;
    }

Here's the log results:

[main] 2012-04-09 10:40:32,823 110391 INFO  C3P0ConnectionProvider - HHH000046: 
Connection properties: {user=hgaidb_test, password=****}
[main] 2012-04-09 10:40:32,823 110391 INFO  C3P0ConnectionProvider - HHH000006: 
Autocommit mode: false
[main] 2012-04-09 10:40:34,100 111668 DEBUG JdbcServicesImpl - Database ->
       name : PostgreSQL
    version : 8.3.3
      major : 8
      minor : 3
[main] 2012-04-09 10:40:34,101 111669 DEBUG JdbcServicesImpl - Driver ->
       name : PostgreSQL Native Driver
    version : PostgreSQL 9.1 JDBC4 (build 901)
      major : 9
      minor : 1
*******************************************************************************
// 1 MINUTE DELAY
*******************************************************************************
[main] 2012-04-09 10:40:34,102 111670 DEBUG JdbcServicesImpl - JDBC version : 4.
0
[main] 2012-04-09 10:41:21,632 159200 INFO  Dialect - HHH000400: Using dialect: 
org.hibernate.dialect.PostgreSQLDialect
*******************************************************************************
[main] 2012-04-09 10:41:21,669 159237 INFO  LobCreatorBuilder - HHH000424: Disab
ling contextual LOB creation as createClob() method threw error : java.lang.refl
ect.InvocationTargetException
[main] 2012-04-09 10:41:21,814 159382 DEBUG SettingsFactory - Automatic flush du
ring beforeCompletion(): disabled
[main] 2012-04-09 10:41:21,814 159382 DEBUG SettingsFactory - Automatic session 
close at end of transaction: disabled
[main] 2012-04-09 10:41:21,815 159383 DEBUG SettingsFactory - JDBC batch size: 3
0
[main] 2012-04-09 10:41:21,816 159384 DEBUG SettingsFactory - JDBC batch updates
 for versioned data: disabled
[main] 2012-04-09 10:41:21,816 159384 DEBUG SettingsFactory - Scrollable result 
sets: enabled
[main] 2012-04-09 10:41:21,817 159385 DEBUG SettingsFactory - Wrap result sets: 
disabled
[main] 2012-04-09 10:41:21,818 159386 DEBUG SettingsFactory - JDBC3 getGenerated
Keys(): enabled
[main] 2012-04-09 10:41:21,818 159386 DEBUG SettingsFactory - JDBC result set fe
tch size: 100
[main] 2012-04-09 10:41:21,819 159387 DEBUG SettingsFactory - Connection release
 mode: auto
[main] 2012-04-09 10:41:21,819 159387 INFO  TransactionFactoryInitiator - HHH000
399: Using default transaction strategy (direct JDBC transactions)
[main] 2012-04-09 10:41:21,844 159412 DEBUG SettingsFactory - Default batch fetc
h size: 1
[main] 2012-04-09 10:41:21,844 159412 DEBUG SettingsFactory - Generate SQL with 
comments: disabled
[main] 2012-04-09 10:41:21,845 159413 DEBUG SettingsFactory - Order SQL updates 
by primary key: disabled
[main] 2012-04-09 10:41:21,846 159414 DEBUG SettingsFactory - Order SQL inserts 
for batching: disabled
[main] 2012-04-09 10:41:21,846 159414 DEBUG SettingsFactory - Query translator: 
org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory
[main] 2012-04-09 10:41:21,867 159435 INFO  ASTQueryTranslatorFactory - HHH00039
7: Using ASTQueryTranslatorFactory
[main] 2012-04-09 10:41:21,867 159435 DEBUG SettingsFactory - Query language sub
stitutions: {}
[main] 2012-04-09 10:41:21,867 159435 DEBUG SettingsFactory - JPA-QL strict comp
liance: disabled
[main] 2012-04-09 10:41:21,868 159436 DEBUG SettingsFactory - Second-level cache
: enabled
[main] 2012-04-09 10:41:21,868 159436 DEBUG SettingsFactory - Query cache: disab
led
[main] 2012-04-09 10:41:21,869 159437 DEBUG SettingsFactory - Cache region facto
ry : org.hibernate.cache.internal.NoCachingRegionFactory
[main] 2012-04-09 10:41:21,872 159440 DEBUG SettingsFactory - org.hibernate.cach
e.internal.NoCachingRegionFactory did not provide constructor accepting java.uti
l.Properties; attempting no-arg constructor.
[main] 2012-04-09 10:41:21,873 159441 DEBUG SettingsFactory - Optimize cache for
 minimal puts: disabled
[main] 2012-04-09 10:41:21,873 159441 DEBUG SettingsFactory - Structured second-
level cache entries: disabled
[main] 2012-04-09 10:41:21,873 159441 DEBUG SettingsFactory - Statistics: disabl
ed
[main] 2012-04-09 10:41:21,874 159442 DEBUG SettingsFactory - Deleted entity syn
thetic identifier rollback: disabled
[main] 2012-04-09 10:41:21,874 159442 DEBUG SettingsFactory - Default entity-mod
e: pojo
[main] 2012-04-09 10:41:21,875 159443 DEBUG SettingsFactory - Named query checki
ng : enabled
[main] 2012-04-09 10:41:21,875 159443 DEBUG SettingsFactory - Check Nullability 
in Core (should be disabled when Bean Validation is on): enabled
[main] 2012-04-09 10:41:21,876 159444 DEBUG SettingsFactory - multi-tenancy stra
tegy : NONE

I've done a little more research on this, stepping through the debugger. I don't have all the source in my classpath, but i can still see the variables. Durring that one minute wait, Hibernate is querying the pg_catalog.pg_type table:

[SELECT typname FROM pg_catalog.pg_type WHERE oid = , ]

Here's a screenshot:

DebugWindow

like image 675
Jason Huntley Avatar asked Apr 09 '12 14:04

Jason Huntley


3 Answers

I fixed it =) I really had to root around to find the answer for this one. Basically, it comes down to loading metadata and the JDBC driver. It's loading ALL META DATA, including comments beside sql columns and other various constructs, which are not needed for operation. I don't know why this is on by default but you should definitely turn this feature off unless you explicitly need it:

config.setProperty("hibernate.temp.use_jdbc_metadata_defaults","false"); 

Instant connection now!

The only info I could find on this is in code:

107     // 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value. 108     // The need for it is intended to be alleviated with future development, thus it is 109     // not defined as an Environment constant... 110     // 111     // it is used to control whether we should consult the JDBC metadata to determine 112     // certain Settings default values; it is useful to *not* do this when the database 113     // may not be available (mainly in tools usage). 114     boolean useJdbcMetadata = ConfigurationHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", configValues, true ); 

http://grepcode.com/file/repo1.maven.org/maven2/org.hibernate/hibernate-core/4.1.1.Final/org/hibernate/engine/jdbc/internal/JdbcServicesImpl.java#JdbcServicesImpl

like image 194
Jason Huntley Avatar answered Sep 17 '22 21:09

Jason Huntley


I had to also enable hibernate.jdbc.use_get_generated_keys otherwise Identity generation strategy was throwing an exception. Before it was enabled automatically based on metadata received from DB. So my whole solution was to add the following two lines to persistence.xml:

<property name="hibernate.jdbc.use_get_generated_keys" value="true" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
like image 36
mmm Avatar answered Sep 19 '22 21:09

mmm


Almost 7 years later and this is still an issue...

Turning the "temp" key off helps but it's a nuisance to enable properties one-by-one that would be auto-configured (see other answers).

In case of Oracle and Teradata I didn't notice such a slowdown so I digged deep and found where the slowest part is: https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java#L2237

This resultSet has in my case 372 rows (types). Then, for each driver fires couple of calls from https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/jdbc/TypeInfoCache.java#L204 which results in tons of SQL statements against the DB.

No idea how to speed this up right now, luckily it's needed once and then it's cached.

like image 29
zeratul021 Avatar answered Sep 21 '22 21:09

zeratul021