2011-03-12 3 views
13

이 소프트웨어에는 이상한 문제가 있습니다. 가 5 년 동안 생산에 있고 우리는 그러한 문제 ...쿼리가 멈 춥니 다 oracle 10g

문제가 없었 :

우리는 최대 절전 모드를 통해 쿼리를 만드는 스프링 작업 (스케줄러)가, 객체를 검색하고이를 수정합니다.

글쎄, 몇 년 동안 일했지만 한 달 전에 쿼리가 하루에 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 
     } 
    }); 
} 

데이터 소스가 I이이 제품에 있어야되지 않는다는 것을 알고있다 (이 정의되어 있지만, 이것은 작동하는 유일한 방법입니다 - 나는 오라클을 사용하려고 연결 풀하지만 다음 쿼리는 더 자주 중단 ..) :

<?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)
  • 오라클 JDBC 10.1.0.2
  • 레드햇은 3 EL
  • 자바 1.5_06

내가 그렇게 해봤 무엇 지금까지 :

  • 사용 오라클 연결 데이터로 풀 소스 ->은걸려 실패했습니다개 연결
  • 사용 오라클 JDBC 10.2.0.5 -> 나는 그것을 해결했습니다 ... 그리고 몇 시간 후 다시 교수형 :(생각

오라클에는 데이터베이스 잠금은 지금까지 내가 할 수 없습니다 참조 ...

무엇이 문제 일 수 있습니까?

UPDATE :

ADDM 결과 : 오라클 EM에

상당한 데이터베이스 시간을 소비 SQL 문이 발견되었다. 이 쿼리는 상당한 데이터베이스 시간을 소모합니다. 영향 81 %. 사용자 I/O는 97 %를 대기합니다. 중요한 사용자에 대한 책임

  • 개별 SQL 문은 I/O 대기 찾을 했다.
  • 상당한 사용자 I/O를 담당하는 개별 데이터베이스 세그먼트 대기가 발견되었습니다.
  • I/O 하위 시스템 의 처리량은 보다 현저히 낮습니다.

UPDATE : (15.03.2011)

를 들어 지금은 서비스가 매달려없이 거의 48 시간 동안 작동합니다.

나는이 문제를 해결할 것을 회의적하지만 일부 코드를 변경 한 : 쿼리에서 decode(delivered,null,0,1) = 0decode(" + sqlCustAlias + ".deleteDate,null,1,0) = 1 기능을 제거

is null 진술로 교체.
배달 된 필드는 인덱싱되지만 인덱싱은 decode 함수에서 사용할 수 없습니다.

이것이 우연의 일치라고 생각하십니까?

UPDATE : (2011년 3월 16일)는

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 전 일 .. 232,624초 것 같다!

+5

+1 분명히 주말에 프로덕션 문제를 해결하기 위해 노력하고 있기 때문에 +1해야합니다. 우리 직업에는 시간외 근무는 없지만 적어도 몇 명의 담당자가 있습니다 :-) – corsiKa

+0

대단히 감사합니다. 주말은 EMCY를 위해 예약 됨 :-) – alesko

+4

내 경험에 따르면, 무언가가 작동했다면 지금은 그렇지 않다는 것입니다. 이 코드는 변경되지 않았으므로 데이터에 있음을 의미합니다. 자, 저기있는 바위만큼이나 최대 절전 모드에 대해서 알고 있습니다. 그래서 문제를 잘 찾을 수있는 코드를 분석 할 수는 없지만, 데이터로 무엇이 바뀌 었는지 살펴볼 것입니다. 물론, 당신은 이미 끝났습니다 ...하지만 * 어깨를 으 *하는 것은 말할 가치가 있습니다. – corsiKa

답변

3

이 쿼리가 중단되면 V $ SESSION_WAIT를 검사하여 세션이 무엇을 기다리고 있는지 확인하십시오.

두 번째 관찰 : benefitType 매개 변수가 null이 아닌 경우를 제외하고 위 코드는 max 매개 변수를 무시한 것으로 보입니다. 이것은 의도적입니까? benefitType 매개 변수가 null 일 때만 쿼리가 "매달리기"가능성이 있습니까?

죄송합니다. 오라클 내에서 올바른 세션을 식별 할 수있는 방법이 있다고 가정했습니다. 이 같은 쿼리를 시도 : 현재 모든 SQL을 보여줍니다

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; 

가 실행되고, 그것은에 대기 관련 세션 ID 어떤 이벤트 가능합니다. 관심있는 세션을 식별하기 위해 SQL 텍스트를 사용할 수 있어야합니다.

+0

다시 발생하면 바로 확인하겠습니다. 오래 걸리지 않아야합니다. – alesko

+0

그리고 분명히하기 위해 몇 번 확인하여 대기 이벤트가 변경되거나 일련 번호가 변경되는지 확인하십시오. 같은 이벤트에서 기다리고 있지만 시퀀스 번호가 바뀌더라도 작업이 진행 중임을 의미합니다. –

+0

질문은 매달려있는 세션을 찾는 방법입니다. "SQL * Net message from/to client"이벤트가있는 16 개 이상의 세션이 있습니다. – alesko

관련 문제