两个Java应用从Oracle数据库查询结果不一致的原因排查
问题分析:直接查表与查询视图返回数据条数不一致
问题场景
- 两个运行在同一服务器的Java应用,从同一Oracle数据库获取实时更新数据
- 应用1直接关联
Indices和tipowner.idxm表查询,应用2通过视图vw_l_mkt_index查询数据 - 两者均通过250毫秒周期的线程拉取数据,预期返回记录条数一致,但实际应用1返回10条,应用2仅返回4条
应用1查询语句
select T.Id, T.Index_Name, T.xIndex, T.NetChange, T.PrcntChange, to_char(T.IDXM_RCV_DT+NUMTODSINTERVAL(3,'HOUR') ,'YYYY/MM/DD HH24:MI:SS.FF3') local_time , T.TradeVolume, T.TradeValue, T.TodayInitIndex, T.IndexHigh, T.IndexLow, T.YestCloseIndex, T.YestCloseAdjusted, T.ChangeDir, I.IDXM_LI_TOT_TRAD_SYM totalSym, I.IDXM_LI_TOT_TRAD_NB||'' totalTrades, I.IDXM_LI_TOT_TRAD_QTY||'' totalQty, I.IDXM_LI_TOT_TRAD_VAL||'' totalValue from Indices T, tipowner.idxm I where I.IDXM_IDX_ID=T.id AND T.IDXM_RCV_DT > (to_timestamp('2023/08/03 16:47:23.496','YYYY/MM/DD HH24:MI:SS.FF3')-(3/24))
视图vw_l_mkt_index定义
CREATE OR REPLACE VIEW vw_l_mkt_index ( market, name_en, name_ar, msg_timestamp, status, index_value, change, change_percent, trades_count, traded_symbols, traded_value, traded_volume, rising_symbols, dropping_symbols, flat_symbols, open_time, close_time ) AS SELECT /*+ INDEX(IDXM IX_IDXM_IDX_ID_RECV_DT) INDEX(T IX_TADAWUL_INDICES_TS) */ I.IDXM_IDX_ID AS MARKET, I.IDXM_DESC AS NAME_EN, I.IDXM_ADESC AS NAME_AR, to_timestamp(to_char(I.IDXM_RCV_DT+NUMTODSINTERVAL(3,'HOUR'),'dd.mm.yy HH24:MI:SS.FF3'), 'dd.mm.yy HH24:MI:SS.FF3') AS MSG_TIMESTAMP, P.MKT_STATUS AS STATUS, T.XINDEX AS INDEX_VALUE, DECODE(T.CHANGEDIR, '-', (T.NETCHANGE * -1), T.NETCHANGE)AS CHANGE, DECODE(T.CHANGEDIR, '-', (T.PRCNTCHANGE * -1), T.PRCNTCHANGE) AS CHANGE_PERCENT, I.IDXM_LI_TOT_TRAD_NB || '' AS TRADES_COUNT, I.IDXM_LI_TOT_TRAD_SYM AS TRADED_SYMBOLS, I.IDXM_LI_TOT_TRAD_QTY || '' AS TRADED_VOLUME, I.IDXM_LI_TOT_TRAD_VAL || '' AS TRADED_VALUE, I.IDXM_LI_ADV_TRAD_SYM AS RISING_SYMBOLS, I.IDXM_LI_DEC_TRAD_SYM AS DROPPING_SYMBOLS, I.IDXM_LI_UNC_TRAD_SYM AS FLAT_SYMBOLS, TO_CHAR(M.MK_FROM, 'HH24:MI:SS') AS OPEN_TIME, TO_CHAR(M.MK_TO, 'HH24:MI:SS') AS CLOSE_TIME FROM IDXM I, INDICES T, PARAM P, MARKET M WHERE IDXM.IDXM_IDX_ID = T.ID AND M.MK_CODE (+)= IDXM.IDXM_IDX_ID AND IDXM.IDXM_IDX_ID <> 'NOMU'
核心原因分析
1. 视图包含额外的过滤条件与关联表
- 排除特定ID数据:视图中有
IDXM.IDXM_IDX_ID <> 'NOMU'条件,直接过滤掉ID为NOMU的记录,而应用1的查询没有该条件,会保留这部分数据。 - 内连接
PARAM表导致数据丢失:视图的FROM子句中直接关联了PARAM P表,但未使用外连接(没有(+)),意味着只有在PARAM表中存在匹配IDXM_IDX_ID记录的数据,才会被视图返回。而应用1仅关联Indices和tipowner.idxm,不会受PARAM表的影响,因此会保留那些PARAM中无匹配的记录。
2. 时间过滤的字段差异
应用1的查询基于T.IDXM_RCV_DT做时间过滤,而如果应用2查询视图时是基于视图的MSG_TIMESTAMP(来源于I.IDXM_RCV_DT)做过滤,若T.IDXM_RCV_DT与I.IDXM_RCV_DT的值不一致,会导致两者的时间过滤范围不同,最终返回的记录条数出现差异。
3. 索引提示的潜在影响(概率较低)
视图中包含索引提示/*+ INDEX(IDXM IX_IDXM_IDX_ID_RECV_DT) INDEX(T IX_TADAWUL_INDICES_TS) */,如果索引未及时同步最新数据(比如索引失效、未实时更新),可能导致视图查询时无法获取到最新的部分记录,但这种情况需要结合数据库索引状态验证。
验证方法
- 在应用1的查询中添加视图的过滤条件:
AND I.IDXM_IDX_ID <> 'NOMU',并内连接PARAM P表,观察返回条数是否变为4条。 - 修改视图定义,移除
PARAM P的内连接和IDXM_IDX_ID <> 'NOMU'条件,查询视图看返回条数是否与应用1一致。 - 对比
T.IDXM_RCV_DT和I.IDXM_RCV_DT的取值,确认两者是否同步,以及应用2的时间过滤逻辑是否与应用1匹配。
内容的提问来源于stack exchange,提问作者ManKeer
相关产品推荐
相关产品推荐

