запрос висит оракул 10г - PullRequest
13 голосов
/ 12 марта 2011

У меня странная проблема с нашим программным обеспечением. На производстве уже 5 лет, и у нас не было таких проблем ...

Проблема:

У нас есть пружинное задание (планировщик), которое делает запрос через Hibernate, извлекает объекты и модифицирует их.

Ну, это работало в течение нескольких лет, но месяц назад запрос зависал 5-10 раз в день (запрос вызывается каждые 10 минут). И когда он зависает, мы должны перезапустить службу.

Следующий код выполняет запрос:

@SuppressWarnings("unchecked")
public List<Delivery> findScheduledForDelivery(final String inType, final int max, final String benefitType ) {


    //getHibernateTemplate().clear();

    return getHibernateTemplate().executeFind(new HibernateCallback() {
        public Object doInHibernate(Session session) throws SQLException {
            Criteria criteria = session.createCriteria(Delivery.class);

            criteria.createAlias("reward","r");
            criteria.createAlias("r.customer","c");
            criteria.createAlias("c.inNe","i");
            criteria.createAlias("r.promotion","p");
            criteria.createAlias("benefit","b");

            String sqlCustAlias = StringHelper.generateAlias("c", 2);

            criteria.add(Expression.disjunction()
                .add(Expression.eq("inStatus", INStatus.InterfaceFailure))
                .add(Expression.eq("inStatus",INStatus.Initial)));

            criteria.add(Expression.le("deliverAt", new Date()));

            String dateString = "2000/01/01";
            DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
            Date startDate = new Date();
            try {
                startDate = dateFormat.parse(dateString);
                criteria.add(Expression.ge("deliverAt", startDate));
            }
            catch(ParseException e) {
                e.printStackTrace();
            }

            String sqlEqual = "decode(delivered,null,0,1) = 0";
            criteria.add(Expression.sql(sqlEqual));

            sqlEqual = "decode(" + sqlCustAlias + ".deleteDate,null,1,0) = 1";
            criteria.add(Expression.sql(sqlEqual));

            if(inType  != null ) {
                for(INType i : INType.values())
                    if(i.toString().equals(inType)) {
                        criteria.add(Expression.eq("i.inType", i));
                        break;
                    }
            }

            criteria.add(Expression.eq("p.active", true));

            if(benefitType != null) {
                if(benefitType.equals("FREECREDIT")) 
                    criteria.add(Expression.disjunction()
                            .add(Expression.eq("b.type", BenefitType.FREE_CREDIT))
                            .add(Expression.eq("b.type", BenefitType.FREE_CREDIT_FTAM)));
                else if(benefitType.equals("NONFREECREDIT")) {
                    criteria.add(Expression.conjunction()
                            .add(Expression.ne("b.type", BenefitType.FREE_CREDIT))
                            .add(Expression.ne("b.type", BenefitType.OTHER))
                            .add(Expression.ne("b.type", BenefitType.VOUCHER)));
                    criteria.add(Expression.isNull("b.md3Profile")); 
                }
                if(max != 0)
                    criteria.setMaxResults(max);
            }

            criteria.addOrder( Order.desc("p.priority") );
            criteria.addOrder( Order.asc("deliverAt") );



            return criteria.list(); <===== hangs here
        }
    });
}

Источник данных определяется следующим образом (я знаю, что это не должно быть в рабочем состоянии, но это единственный способ, которым он работает - я пытался использовать пул соединений оракула, но затем запрос зависает чаще ..):

<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="connectionProperties">
         <props>
          <prop key="tcp.nodelay">yes</prop>
          <prop key="delayRowPrefetch">20</prop>
          <prop key="defaultBatchSize">5</prop>
         </props>
        </property>
      </bean>
    </beans>

Используемое программное обеспечение:

  • пружина 1.2.7
  • Спящий режим 3.0.5
  • оракул 10.2.0.1 (RAC)
  • oracle jdbc 10.1.0.2
  • Red Hat 3 EL
  • Java 1.5_06

Что я пробовал до сих пор:

  • использовать пул соединений оракула в качестве данных источник -> не удалось с зависанием соединения
  • использовал oracle jdbc 10.2.0.5 -> Я думал, что решил это ... и через несколько часов он снова завис: (

На oracle нет блокировок базы данных, насколько я вижу ...

В чем может быть проблема?

UPDATE:

в оракуле ЭМ:

Выводы ADDM: Были найдены операторы SQL, занимающие значительное время базы данных. Запрос занимает значительное время базы данных. Влияние 81%. Пользовательский ввод / вывод ожидает 97%.

  • Ответственные за отдельные операторы SQL для значительного пользовательского ожидания ввода / вывода были найдено.
  • отдельные сегменты базы данных отвечает за значительный пользовательский ввод / вывод ждать были найдены.
  • Пропускная способность подсистемы ввода / вывода был значительно ниже, чем ожидается.

ОБНОВЛЕНИЕ: (15.03.2011)

На данный момент сервис работает почти 48 часов без зависаний.

Я скептически отношусь к тому, что это решит проблему, но я внес некоторые изменения в код:

Удалены функции decode(delivered,null,0,1) = 0 и decode(" + sqlCustAlias + ".deleteDate,null,1,0) = 1 в запросе и заменены на операторы is null.
Доставленное поле индексируется, но индексирование нельзя использовать в decode функциях.

Как вы думаете, это просто совпадение?

ОБНОВЛЕНИЕ: (16.03.2011)

alert.log теперь показывает много записей, подобных этой:

ORA-01555 caused by SQL statement below (SQL ID: affkpm4j7azc4, Query Duration=232624 sec, SCN: 0x0003.dca70559):
Tue Mar 15 17:43:06 2011
select * from ( select this_.id as id5_, this_.deliverAt as deliverAt68_5_, this_.delivered as delivered68_5_, this_.inDelivery as inDelivery68_5_, this_.lastDeliveryTry as lastDeli5_68_5_, this_.tries as tries68_5_, this_.sentAt as sentAt68_5_, this_.sent as sent68_5_, this_.retry as retry68_5_, this_.inStatus as inStatus68_5_, this_.errorMessage as errorMe11_68_5_, this_.inCvsDelivery as inCvsDe12_68_5_, this_.cvsDelivered as cvsDeli13_68_5_, this_.cvsLastDeliveryTry as cvsLast14_68_5_, this_.cvsTries as cvsTries68_5_, this_.collectedPoints as collect16_68_5_, this_.smsMessage as smsMessage68_5_, this_.inOldStatus as inOldSt18_68_5_, this_.replacedDate as replace19_68_5_, this_.oldMsisdn as oldMsisdn68_5_, this_.deletedDate as deleted21_68_5_, this_.addManualDate as addManu22_68_5_, this_.stornoPromiseDate as stornoP23_68_5_, this_.stornoINDate as stornoI24_68_5_, this_.activationCode as activat25_68_5_, this_.activationExpirationDate as activat26_68_5_, this_.rewardId as rewardId68_5_, this_.benefitId as b

Это похоже на сеансы за 3 дня до .. 232624секунд!

1 Ответ

3 голосов
/ 12 марта 2011

Прежде всего, когда этот запрос зависает, проверьте V $ SESSION_WAIT, чтобы увидеть, что ожидает сеанс.

Второе наблюдение: код, который вы показали выше, по-видимому, игнорирует параметр max, если параметр benefitType не является нулевым. Это намеренно? Возможно ли, что запрос «зависает» только в том случае, если для параметра profitType указано значение NULL?

Извините, я предположил, что у вас есть какой-то способ определить правильный сеанс в Oracle. Попробуйте запрос, подобный этому:

select v2.sid,
       v2.module,
       substr(v1.sql_text,1,180) sql_text,
       v1.rows_processed,
       v2.event,
       v2.seq#
from v$sqlarea v1, v$session v2
where v1.users_executing > 0
  and v2.sql_address (+) = v1.address;

Это покажет весь выполняемый в настоящий момент SQL, и, если возможно, связанный идентификатор сеанса и какое событие он ожидает. Вы должны быть в состоянии использовать текст SQL для определения интересующего вас сеанса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...