Oracle JDBC驅動使用setDate()、setTimestamp()導致全表掃描

尛樣兒發表於2010-03-17
今天有一個專案組報說,一個業務流程在Oracle上無法執行完成,而在SQL SERVER卻非常的正常。

環境:ORACLE RAC 10.2.0.4.0 FOR AIX 64bit

於是開始查詢是什麼原因,該業務流程操作的表是一個非常大的表,億級的資料量。透過對業務流程SQL執行的監控,發現在執行對這個表做小部分資料刪除的SQL時候卡住不動了。檢視了SQL的執行計劃發現是全表掃描,沒有建索引,於是把索引建上,重新監控,問題依然。

透過select exectutions from v$sqlarea where sql_id='xxxxxxx' 發現值為0。
檢查select buffer_gets from v$sqlarea where sql_id='xxxxxxxx' 發現值一直在不停的增長。
說明這個SQL一次都沒執行過,刪除的資料只有很少的量,但是卻一直在讀資料,首先想到的是全表掃描。

於是讓開發人員看了一下程式碼,這個SQL用到了預編譯
PreparedStatement,where 條件要過濾一個時間欄位,賦值的時候使用的是setDate()方法。在單獨執行該SQL我使用的是to_date()函式來設定時間,執行速度很快,於是我讓開發人員把程式碼中的SQL過濾時間的部分加入to_date()函式,使用setString()方法賦值,再監控,就變得非常正常了。

後來同事在網上g了一下,發現這是oracle jdbc驅動確實有這個問題。在Java使用預編譯在where條件中使用setDate(),setTimeStamp()方法來給時間欄位賦值都會導致在執行該SQL的時候對錶進行全表掃描。

解決方法1:我們可以透過在SQL使用to_date('?','yyyy-mm-dd hh24:mi:ss')在繫結變數的時候使用setString()方法來代替使用setDate。

解決方法2:在配置連線的地方加入以下配置屬性:


解決方法3:
try {
            Class.forName("oracle.jdbc.OracleDriver");
Properties prop=new Properties();
prop.setProperty("user","sysuser");
prop.setProperty("password","sys");
prop.setProperty("oracle.jdbc.V8Compatible","true");

java.sql.Connection connection1 = DriverManager.getConnection("jdbc:oracle:thin:@192.168.8.200:1521:cdb", prop);
System.out.println(connection1);
            System.out.println(connection1.getMetaData().getDriverName()+"
"+connection1.getMetaData().getDriverVersion());
ResultSet rs = connection1.createStatement().executeQuery("select date1,date2 from t_test");
rs.next();
printInfo(rs,1);
printInfo(rs,2);
}
catch (Exception exception1) {
exception1.printStackTrace();
}


解決方法4:
在系統變數中使用引數-Doracle.jdbc.V8Compatible="true",例如
java -Doracle.jdbc.V8Compatible="true" MyApp


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23135684/viewspace-629761/,如需轉載,請註明出處,否則將追究法律責任。

相關文章