oracle 根據(jù)時(shí)間范圍查詢(xún)緩慢問(wèn)題排查解決

???????今天生產(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。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容