Бесконечный цикл Postgresql после списка критериев гибернации

1

В течение нескольких дней меня задерживает проблема с базой данных. Приложение зависает после определенного hibernate criteria.list(). Именно следующим стеком:

java.net.SocketInputStream.read(byte[], int, int)
org.postgresql.core.VisibleBufferedInputStream.readMore(int)
org.postgresql.core.VisibleBufferedInputStream.ensureBytes(int)
org.postgresql.core.VisibleBufferedInputStream.read()
org.postgresql.core.PGStream.ReceiveChar()
org.postgresql.core.v3.QueryExecutorImpl.processResults(ResultHandler, int)
org.postgresql.core.v3.QueryExecutorImpl.execute(Query, ParameterList, ResultHandler, int, int, int)
org.postgresql.jdbc2.AbstractJdbc2Statement.execute(Query, ParameterList, int)
org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(int)
org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery()
org.hibernate.internal.CriteriaImpl.list()

После некоторых исследований и тестов я обнаружил, что проблема не является блокирующим запросом, а запросом, который выполняется навсегда.

Это приложение java spring со следующей конфигурацией sessionFactory и менеджера транзакций:

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="org.postgresql.Driver" />
    <property name="url" value="jdbc:postgresql://localhost:5432/database" />
    <property name="username" value="username" />
    <property name="password" value="password" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.myapp.domain" /> 
    <property name="configLocation" value="/WEB-INF/hibernate.cfg.xml" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />

Базовая база данных - PostgreSQL, и здесь находится текущая конфигурация спящего режима

<hibernate-configuration>
    <session-factory>       
        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>

        <property name="hbm2ddl.auto">none</property>
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="cache.use_query_cache">true</property>

        <property name="hibernate.transaction.factory_class">
        org.hibernate.transaction.JDBCTransactionFactory</property>
        <property name="show_sql">false</property>
        <property name="format_sql">true</property>
        <property name="use_sql_comments">false</property>
        <property name="order_updates">true</property>
    </session-factory>
</hibernate-configuration>

Критическая область в коде:

private void fillEmptyNames() throws CablewatchException {
    List<Device> devicesList = deviceDao.getDevices();
    if (devicesList != null) {
        for (Device device : devicesList {
            String name = deviceDao.getDeviceName(device.getModule().getObjectIdentifier(), device.getSubrack(), device.getSlot());
    ...
        }
    }
}

Приложение зависает во второй функции dao "getDeviceName". который реализуется следующим образом:

@Transactional(timeout=30)
public String getDeviceName(long moduleId, int subrackNr, int slotNr) throws CablewatchException {
    Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Device.class).add(Restrictions.eq("module.objectIdentifier", moduleId)).add(Restrictions.eq("subrack",subrackNr)).add(Restrictions.eq("slot",slotNr)).addOrder(Order.desc("objectIdentifier")).setMaxResults(1);

    List<Device> devicesList = criteria.list();

    if (devicesList != null && !devicesList.isEmpty() && devicesList.get(0) instanceof Device) {
        Device device = devicesList.get(0);
        return device.getName();
    }
    return null;
}

Кроме того, я сталкиваюсь с тем, что тот же самый проход отлично работает под Windows, поэтому в настоящее время проблема возникает только в Linux.

UPDATE: сгенерированный запрос:

select
    this_.objectIdentifier as objectId1_0_9_,
    this_.ackId as ackId11_0_9_,
    this_.alarmInfoId as alarmIn12_0_9_,
    this_.cleared as cleared2_0_9_,
    this_.clearedTime as clearedT3_0_9_,
    this_.logIndex as logIndex4_0_9_,
    this_.module as module5_0_9_,
    this_.neId as neId13_0_9_,
    this_.occurenceTime as occurenc6_0_9_,
    this_.serial as serial7_0_9_,
    this_.severityId as severit14_0_9_,
    this_.slot as slot8_0_9_,
    this_.subrack as subrack9_0_9_,
    this_.value as value10_0_9_,
    acknowledg2_.objectIdentifier as objectId1_2_0_,
    acknowledg2_.comment as comment2_2_0_,
    acknowledg2_.username as username3_2_0_,
    alarminfo3_.objectIdentifier as objectId1_1_1_,
    alarminfo3_.cw_alarmMessage as cw_alarm2_1_1_,
    alarminfo3_.cw_alarmOid as cw_alarm3_1_1_,
    ne4_.OBJECTIDENTIFIER as OBJECTID1_8_2_,
    ne4_.cw_neActive as cw_neAct2_8_2_,
    ne4_.cw_neCategory as cw_neCat3_8_2_,
    ne4_.cw_neFirmware as cw_neFir4_8_2_,
    ne4_.cw_neHasWebInterface as cw_neHas5_8_2_,
    ne4_.cw_neInetAddress as cw_neIne6_8_2_,
    ne4_.cw_neInfo as cw_neInf7_8_2_,
    ne4_.cw_neMacAddress as cw_neMac8_8_2_,
    ne4_.cw_neModel as cw_neMod9_8_2_,
    ne4_.cw_neName as cw_neNa10_8_2_,
    ne4_.cw_neSerial as cw_neSe11_8_2_,
    ne4_.cw_neSysDescription as cw_neSy12_8_2_,
    ne4_.cw_neType as cw_neTy13_8_2_,
    ne4_.cw_installationDate as cw_inst14_8_2_,
    ne4_.cw_instance as cw_inst15_8_2_,
    ne4_.cw_lastAlarmLogIndex as cw_last16_8_2_,
    ne4_.cw_locationId as cw_loca19_8_2_,
    ne4_.cw_readCommunity as cw_read17_8_2_,
    ne4_.cw_severityId as cw_seve20_8_2_,
    ne4_.cw_writeCommunity as cw_writ18_8_2_,
    location5_.objectIdentifier as objectId1_5_3_,
    location5_.cw_imageName as cw_image2_5_3_,
    location5_.cw_locationCity as cw_locat3_5_3_,
    location5_.cw_locationCode as cw_locat4_5_3_,
    location5_.cw_locationContact as cw_locat5_5_3_,
    location5_.cw_locationDescription1 as cw_locat6_5_3_,
    location5_.cw_locationDescription2 as cw_locat7_5_3_,
    location5_.cw_locationName as cw_locat8_5_3_,
    location5_.cw_locationStreet as cw_locat9_5_3_,
    location5_.cw_locationType as cw_loca10_5_3_,
    location5_.cw_parentLocationId as cw_pare11_5_3_,
    location5_.cw_severityId as cw_seve12_5_3_,
    location5_.cw_sublocationSeverityId as cw_subl13_5_3_,
    location6_.objectIdentifier as objectId1_5_4_,
    location6_.cw_imageName as cw_image2_5_4_,
    location6_.cw_locationCity as cw_locat3_5_4_,
    location6_.cw_locationCode as cw_locat4_5_4_,
    location6_.cw_locationContact as cw_locat5_5_4_,
    location6_.cw_locationDescription1 as cw_locat6_5_4_,
    location6_.cw_locationDescription2 as cw_locat7_5_4_,
    location6_.cw_locationName as cw_locat8_5_4_,
    location6_.cw_locationStreet as cw_locat9_5_4_,
    location6_.cw_locationType as cw_loca10_5_4_,
    location6_.cw_parentLocationId as cw_pare11_5_4_,
    location6_.cw_severityId as cw_seve12_5_4_,
    location6_.cw_sublocationSeverityId as cw_subl13_5_4_,
    severity7_.id as id1_15_5_,
    severity7_.cw_severityColor as cw_sever2_15_5_,
    severity7_.cw_severityName as cw_sever3_15_5_,
    severity8_.id as id1_15_6_,
    severity8_.cw_severityColor as cw_sever2_15_6_,
    severity8_.cw_severityName as cw_sever3_15_6_,
    severity9_.id as id1_15_7_,
    severity9_.cw_severityColor as cw_sever2_15_7_,
    severity9_.cw_severityName as cw_sever3_15_7_,
    severity10_.id as id1_15_8_,
    severity10_.cw_severityColor as cw_sever2_15_8_,
    severity10_.cw_severityName as cw_sever3_15_8_ 
from
    CW_ALARM this_ 
left outer join
    CW_Acknowledgment acknowledg2_ 
        on this_.ackId=acknowledg2_.objectIdentifier 
left outer join
    CW_ALARMINFO alarminfo3_ 
        on this_.alarmInfoId=alarminfo3_.objectIdentifier 
left outer join
    CW_NE ne4_ 
        on this_.neId=ne4_.OBJECTIDENTIFIER 
left outer join
    CW_LOCATION location5_ 
        on ne4_.cw_locationId=location5_.objectIdentifier 
left outer join
    CW_LOCATION location6_ 
        on location5_.cw_parentLocationId=location6_.objectIdentifier 
left outer join
    CW_SEVERITY severity7_ 
        on location6_.cw_severityId=severity7_.id 
left outer join
    CW_SEVERITY severity8_ 
        on location6_.cw_sublocationSeverityId=severity8_.id 
left outer join
    CW_SEVERITY severity9_ 
        on ne4_.cw_severityId=severity9_.id 
left outer join
    CW_SEVERITY severity10_ 
        on this_.severityId=severity10_.id 
where
    this_.neId=?
    and this_.subrack=?
    and this_.slot=?
    and this_.module<>?
order by
    this_.objectIdentifier desc limit ?

Я выполнил его из pgAdmin (и заменил параметры своими значениями), и он отлично работает. Ниже приведен план запроса:

"Limit  (cost=25819.66..25819.66 rows=1 width=1185)"
"  ->  Sort  (cost=25819.66..25819.66 rows=1 width=1185)"
"        Sort Key: this_.objectidentifier"
"        ->  Nested Loop Left Join  (cost=0.00..25819.65 rows=1 width=1185)"
"              ->  Nested Loop Left Join  (cost=0.00..25811.37 rows=1 width=1021)"
"                    ->  Nested Loop Left Join  (cost=0.00..25803.09 rows=1 width=857)"
"                          ->  Nested Loop Left Join  (cost=0.00..25799.21 rows=1 width=693)"
"                                ->  Nested Loop Left Join  (cost=0.00..25795.33 rows=1 width=529)"
"                                      ->  Nested Loop Left Join  (cost=0.00..25793.45 rows=1 width=464)"
"                                            Join Filter: (ne4_.cw_locationid = location5_.objectidentifier)"
"                                            ->  Nested Loop Left Join  (cost=0.00..25791.22 rows=1 width=399)"
"                                                  Join Filter: (this_.neid = ne4_.objectidentifier)"
"                                                  ->  Nested Loop Left Join  (cost=0.00..25788.76 rows=1 width=225)"
"                                                        ->  Nested Loop Left Join  (cost=0.00..25780.48 rows=1 width=150)"
"                                                              Join Filter: (this_.ackid = acknowledg2_.objectidentifier)"
"                                                              ->  Seq Scan on cw_alarm this_  (cost=0.00..25779.32 rows=1 width=132)"
"                                                                    Filter: (((module)::text <> ''::text) AND (neid = 471) AND (subrack = (-1)) AND (slot = (-1)))"
"                                                              ->  Seq Scan on cw_acknowledgment acknowledg2_  (cost=0.00..1.07 rows=7 width=18)"
"                                                        ->  Index Scan using cw_alarminfo_pkey on cw_alarminfo alarminfo3_  (cost=0.00..8.27 rows=1 width=75)"
"                                                              Index Cond: (this_.alarminfoid = objectidentifier)"
"                                                  ->  Seq Scan on cw_ne ne4_  (cost=0.00..2.45 rows=1 width=174)"
"                                                        Filter: (objectidentifier = 471)"
"                                            ->  Seq Scan on cw_location location5_  (cost=0.00..2.10 rows=10 width=65)"
"                                      ->  Index Scan using cw_location_pkey on cw_location location6_  (cost=0.00..1.87 rows=1 width=65)"
"                                            Index Cond: (location5_.cw_parentlocationid = objectidentifier)"
"                                ->  Index Scan using cw_severity_pkey on cw_severity severity7_  (cost=0.00..3.87 rows=1 width=164)"
"                                      Index Cond: (location6_.cw_severityid = id)"
"                          ->  Index Scan using cw_severity_pkey on cw_severity severity8_  (cost=0.00..3.87 rows=1 width=164)"
"                                Index Cond: (location6_.cw_sublocationseverityid = id)"
"                    ->  Index Scan using cw_severity_pkey on cw_severity severity9_  (cost=0.00..8.27 rows=1 width=164)"
"                          Index Cond: (ne4_.cw_severityid = id)"
"              ->  Index Scan using cw_severity_pkey on cw_severity severity10_  (cost=0.00..8.27 rows=1 width=164)"
"                    Index Cond: (this_.severityid = id)"

После подробностей о Linux и Windows, я пробовал один и тот же тест, но вместо локальной базы данных postgresql_9.1.13 (Debian) я использовал удаленный доступ к postgresql_9.3.5 (Windows) и установил и попробовал postgresql_9.1.13 (Windows), Оба работали правильно.

Я также попытался использовать тот же код из моей системы Windows в удаленном postgresql_9.1.13 (Debian) и другой машине с удаленным postgresql_9.1.15 (Debian). В обоих случаях проблема возникает.

Похоже, проблема может заключаться в версии Linux postgresql_9.1.x.

Заранее спасибо.

  • 0
    Ну, а какой на самом деле запускается SQL? Получите его из представления pg_stat_activity или включив ведение журнала запросов в Hibernate. Отредактируйте свой вопрос, чтобы показать запрос, затем прокомментируйте здесь, когда закончите. Также, пожалуйста, повторите запрос в psql или PgAdmin3 с помощью EXPLAIN SELECT ... и вставьте план запроса здесь.
  • 0
    Спасибо Крейг за совет. Я обновил вопрос.
Показать ещё 3 комментария
Теги:
spring
hibernate

1 ответ

0
Лучший ответ

После отладки базы данных с помощью команд, которые мне предоставили Craig и Clemens (отобразить текущие запросы, pg_stat_activity, объяснить анализ select, pg_locks и т.д.), Я обнаружил, что это не бесконечный цикл, но из-за доступа более чем к 20 000 записей время работы было очень длинным. И из-за слоя ORM это время было даже увеличено до нескольких часов. Я работаю над небольшой редизайном базы данных, чтобы оптимизировать эту проблему.

Спасибо, ребята, за поддержку.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню