为什么Oracle查询在Java中很慢,但在sqlDeveloper中直接执行时却要快得多?

yshpjwxd  于 2023-10-14  发布在  Java
关注(0)|答案(1)|浏览(133)

我在db表中有大约100k条记录,当我在oracle sqlDeveloper中执行此查询时,获取100k条记录需要大约33秒。

select wflworkflo1_.REF_ID from ( select REF_ID, START_DATE from OS_HISTORYSTEP WHERE START_DATE < to_date('20/09/2023' , 'dd/mm/yyyy') UNION ALL select REF_ID, START_DATE from OS_CURRENTSTEP WHERE START_DATE < to_date('20/09/2023' , 'dd/mm/yyyy')) wflworkflo1_ WHERE REF_ID NOT IN (SELECT DISTINCT REF_ID FROM (select REF_ID, START_DATE from OS_HISTORYSTEP WHERE START_DATE >= to_date('20/09/2023' , 'dd/mm/yyyy') UNION ALL select REF_ID, START_DATE from OS_CURRENTSTEP WHERE START_DATE >= to_date('20/09/2023' , 'dd/mm/yyyy')) INT_WFL GROUP BY REF_ID) group by wflworkflo1_.REF_ID having max(wflworkflo1_.START_DATE) < to_date('20/09/2023' , 'dd/mm/yyyy');

在我的java程序中,这是运行查询的方法。

public List<String> findCurrHistStepRefIdWithStartDate(String targetStartDate)
        throws BocException {
    
    StringBuffer sql = new StringBuffer();
    sql.append(
            "select wflworkflo1_.REF_ID from ( select REF_ID, START_DATE from OS_HISTORYSTEP WHERE START_DATE < to_date(?, 'dd/mm/yyyy') UNION ALL select REF_ID, START_DATE from OS_CURRENTSTEP WHERE START_DATE < to_date(?, 'dd/mm/yyyy')) wflworkflo1_ WHERE REF_ID NOT IN (SELECT DISTINCT REF_ID FROM (select REF_ID, START_DATE from OS_HISTORYSTEP WHERE START_DATE >= to_date(?, 'dd/mm/yyyy') UNION ALL select REF_ID, START_DATE from OS_CURRENTSTEP WHERE START_DATE >= to_date(?, 'dd/mm/yyyy')) INT_WFL GROUP BY REF_ID) group by wflworkflo1_.REF_ID having max(wflworkflo1_.START_DATE) < to_date(?, 'dd/mm/yyyy')");
    
    JdbcTemplate template = getJdbcTemplate();
    
    return template.queryForList(sql.toString(), String.class,
            targetStartDate, targetStartDate, targetStartDate, targetStartDate,
            targetStartDate);

}

这个Java函数需要1个多小时才能返回结果。为什么会有这么大的差别呢?

ryhaxcpt

ryhaxcpt1#

重写与分析函数的连接应该可以避免大多数潜在的数据库问题。由于重写的查询没有连接,所以执行计划出错的可能性很小。作为一个额外的好处,新的代码更小,可以说更简单。

-- ref_ids that only have old data.
select distinct ref_id
from
(
    --all data along with counts of new dates per ref_id.
    select ref_id, start_date,
        sum(case when start_date >= to_date('20/09/2023' , 'dd/mm/yyyy') then 1 else 0 end) 
        over (partition by ref_id) new_dates_per_ref_id
    from
    (
        --all data
        select ref_id, start_date from os_historystep
        union all
        select ref_id, start_date from os_currentstep
    )
)
where start_date < to_date('20/09/2023' , 'dd/mm/yyyy')
    and new_dates_per_ref_id = 0;

然而,这个答案仅仅是一个解决方案。您可能需要深入研究执行计划并找出为什么会发生此问题。为此,我建议您遵循astentx的建议并使用dbms_sql_monitor.report_sql_monitor。但是解决困难的Oracle性能问题可能需要很长时间,所以如果您没有时间花在查询调优上,那么避免这个问题也没有什么错。

相关问题