2011-03-12 58 views
13

我有我们的软件这个奇怪的问题。 是是生产了5年,我们有没有这样的问题...查询挂起oracle 10g

问题:

我们有一个弹簧工作(调度器),它通过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 
     } 
    }); 
} 

数据源定义,因为这(我知道这是不应该出现在生产,但是这是它的工作的唯一办法 - 我试图使用Oracle连接池但随后的查询更常挂..):使用

<?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
  • 的Oracle 10.2.0.1(RAC)
  • 的Oracle JDBC 10.1.0.2
  • 红帽3 EL
  • 的Java 1.5_06

我一直如此远:

  • 使用oracle连接池作为数据 源 - >挂失败 个连接
  • 使用的Oracle JDBC 10.2.0.5 - >我想我已经解决了它,而且在几个小时后再次挂:(

有在Oracle数据库没有锁,据我可以请参阅...

可能是什么问题?

UPDATE:

在Oracle EM:

ADDM结果: 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天..232624秒!

+5

+1因为您显然正在周末解决生产问题。我们的行业没有加班,但至少有几个代表:-) – corsiKa 2011-03-12 19:13:13

+0

非常感谢。周末预留给EMCY :-) – alesko 2011-03-12 19:15:34

+4

我的经验是,如果某件事情正在发挥作用,但现在不行,那只是因为某些事情发生了变化。这段代码没有改变,这意味着你的数据可能有。现在,我对那里的hibernate了解的很多,所以我不能分析代码来很好地发现问题,但我会考虑数据可能发生的变化。当然,你已经完成了,我已经确定......但耸耸肩,只是值得一提。 – corsiKa 2011-03-12 19:21:55

回答

3

首先,当查询挂起时,请检查V $ SESSION_WAIT以查看会话等待的内容。

第二个观察:上面显示的代码似乎忽略了max参数,除非参数benefitType非空。这是故意的吗?只有当benefitType参数为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执行,如果可能的话相关的会话ID和什么事件是等待。您应该可以使用SQL文本来识别您感兴趣的会话。

+0

我会再检查它一次。这不应该花很长时间。 – alesko 2011-03-12 20:09:41

+0

要清楚,请检查几次,看看等待事件是否更改或序列号是否更改。即使它正在等待同一个事件,但序列号发生变化,这意味着它正在工作,只是非常缓慢。 – 2011-03-12 20:10:58

+0

问题是如何找出哪个会话是挂起的?有16个以上的会话有事件“来自/到客户端的SQL * Net消息”。 – alesko 2011-03-12 20:23:23