2011-03-12 97 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