???????今天生產(chǎn)環(huán)境上碰到個(gè)奇怪問(wèn)題,在oracle數(shù)據(jù)庫(kù)一個(gè)根據(jù)時(shí)間范圍的查詢(xún)語(yǔ)句居然執(zhí)行了二十多分鐘。一開(kāi)始打印了執(zhí)行sql日志之后就毫無(wú)反應(yīng)了,任何錯(cuò)誤都沒(méi)有。把進(jìn)程反復(fù)重啟幾次也一樣。直到二十分鐘后就出現(xiàn)了數(shù)據(jù)業(yè)務(wù)處理日志。表的數(shù)據(jù)量是千萬(wàn)級(jí)別,但是時(shí)間字段也加了索引的,不至于這么慢吧。查詢(xún)的時(shí)間范圍區(qū)間也就一分鐘。
???????實(shí)在想不出原因在哪里,就寫(xiě)個(gè)簡(jiǎn)單的查詢(xún)語(yǔ)句試試:???????
select t.* from IMS_NTF_REMIND_HIS_201711 t where t.SO_DATE>(sysdate-1/24/60) AND t.SO_DATE<sysdate
奇跡發(fā)生,這個(gè)查詢(xún)語(yǔ)句瞬間就出結(jié)果。馬上查代碼看查詢(xún)語(yǔ)句怎么寫(xiě)的。
String sql = "select t.* from " + tableName + " t where " + " t.SO_DATE >=? and t.SO_DATE < ?";
if (logger.isDebugEnabled()) {
logger.debug("執(zhí)行query的SQL:{}" , sql);
}
conn = ServiceManager.getSession().getConnection(dbAct);
prepare = conn.prepareStatement(sql);
prepare.setTimestamp(1, startTime);
prepare.setTimestamp(2, endTime);
從這個(gè)來(lái)看貌似也沒(méi)發(fā)現(xiàn)什么問(wèn)題,兩條sql也沒(méi)有什么區(qū)別??匆幌聰?shù)據(jù)庫(kù)SO_DATE字段是date類(lèi)型。至于為什么使用PreparedStatement.setTimestamp,是因?yàn)镻reparedStatement.setDate();方法參數(shù)java.sql.Date的日期是沒(méi)有時(shí)分秒的,
不符合查詢(xún)要求。這里想說(shuō)明一點(diǎn),oracle數(shù)據(jù)庫(kù)字段是date類(lèi)型的,普通jdbc查詢(xún)出來(lái)的是不帶時(shí)分秒的,java.util.Date才帶時(shí)分秒。要有時(shí)分秒就要做個(gè)轉(zhuǎn)換
HashMap<String, Object> map = new HashMap<String, Object>();
ResultSetMetaData metaData = rs.getMetaData();
int columns = metaData.getColumnCount();
for (int i = 1; i <= columns; i++) {
if ("DATE".equals(metaData.getColumnTypeName(i))) {
map.put(metaData.getColumnName(i), rs.getTimestamp(i));
} else {
map.put(metaData.getColumnName(i), rs.getObject(i));
}
}
rtn.add(map);
言歸正傳,看到這里估計(jì)也猜出來(lái)了,oracle字段類(lèi)型的隱式轉(zhuǎn)換,將date類(lèi)型轉(zhuǎn)換為timestamp類(lèi)型。導(dǎo)致索引失效,就會(huì)全表掃描,從而查詢(xún)緩慢。知道問(wèn)題所在解決就簡(jiǎn)單了,時(shí)間字符串,使用to_date()函數(shù)來(lái)轉(zhuǎn)換字符串為日期和date做比較。改完之后重新測(cè)試查詢(xún)速度變?yōu)榱撕撩爰?jí)別。
總結(jié):
oracle date 和 timestamp類(lèi)型混用時(shí)需要注意索引失效問(wèn)題。如果oracle數(shù)據(jù)庫(kù)字段是date類(lèi)型,需要時(shí)分秒的就用字符串時(shí)間格式,使用to_date()函數(shù)轉(zhuǎn)換做比較。不需要時(shí)分秒的就用java.sql.Date。