Prepare Statement与直接查询相比非常慢| Oracle数据库

问题描述 投票:0回答:1

我的申请中有一条准备好的陈述,需要3分钟才能得出结果。但是,我在sql developer中执行了相同的查询,并且只需要不到0.1秒就可以得出结果。上周我一直对此进行研究,但找不到合适的解决方案。这是我的代码。

public List<ResponseDto> loadData(RequestDto request) throws SQLException {
        List<ResponseDto> responseDto = new ArrayList<>();
        int sortBy = request.getSortBy();
        String sql = "SELECT *" +
                "FROM (SELECT r.*, ROWNUM RNUM, COUNT(*) OVER () RESULT_COUNT " +
                "      FROM (SELECT *" +
                "FROM" +
                "  (SELECT r.VALUE_4," +
                "    r.DATE," +
                "    r.ID," +
                "    r.AMOUNT," +
                "    r.TO_AGENT_ID," +
                "    r.FROM_AGENT_ID," +
                "    a.NAME," +
                "    r.VALUE_2," +
                "    r.VALUE_1," +
                "    r.STATUS," +
                "    r.VALUE_3," +
                "    r.TEXT" +
                "  FROM MY_TABLE r" +
                " INNER JOIN AGENT a " +
                " ON a.AGENT_ID=r.TO_AGENT_ID" +
                "  WHERE r.STATUS        = 1 " +
                "  AND r.ID IN" +
                "    (SELECT T.ID FROM TEST_TABLE T" +
                "    INNER JOIN AGENT af" +
                "    ON af.AGENT_ID = T.FROM_AGENT_ID " +
                "    INNER JOIN AGENT at" +
                "    ON at.AGENT_ID=T.TO_AGENT_ID" +
                "    WHERE T.FROM_AGENT_ID=?";
        StringBuilder sbQuery = new StringBuilder(sql);

        if (request.getToAgentId() != 0) {
            sbQuery.append(" AND T.TO_AGENT_ID = ? ");
        } else if (request.getQueryParam() != null && !request.getQueryParam().equalsIgnoreCase("")) {
            sbQuery.append(" AND UPPER(at.NAME) like UPPER( ? ) ");
        }

        String secondPart =
                "    AND T.STATUS = 1" +
                "    AND TO_DATE(T.DATE) BETWEEN TO_DATE(?, 'yyyy-MM-dd') AND TO_DATE(?, 'yyyy-MM-dd')" +
                "    ) " +
                "    or r.VALUE_3=?";

        sbQuery.append(secondPArt);

        if (sortBy == 1) {
            sbQuery.append("  ORDER BY a.NAME ");
        } else if (sortBy == 2) {
            sbQuery.append("  ORDER BY r.AMOUNT ");
        } else if (sortBy == 3) {
            sbQuery.append("  ORDER BY r.VALUE_4 ");
        }
        if (request.getSortingOrder() == 1) {
            sbQuery.append("DESC ");
        } else if (request.getSortingOrder() == 2) {
            sbQuery.append("ASC ");
        }
        sbQuery.append("  )) R)" +
                "WHERE RNUM between ? and ?");
        String sqlq = sbQuery.toString();
        log.info(sqlq);
        try(Connection con = dataSource.getConnection(); PreparedStatement pstmt = con.prepareStatement(sbQuery.toString()) ) {
            con.setAutoCommit(false);
            String nameParam = "%" + request.getQueryParam() + "%";
            pstmt.setLong(1, request.getFromAgentId());
            if (request.getToAgentId() != 0) {
                pstmt.setLong(2, request.getToAgentId());
            } else if(request.getQueryParam() != null && !request.getQueryParam().equalsIgnoreCase("")) {
                pstmt.setString(2, request.getQueryParam());
            }
            pstmt.setString(3, request.getFromDate());
            pstmt.setString(4, request.getToDte());
            pstmt.setString(5, request.getQueryParam());
            pstmt.setLong(6, request.getFromIndex());
            pstmt.setLong(7, request.getToIndex());
            responseDto = helperMethod(pstmt);
            con.commit();
        } catch (SQLException e) {
            log.error(e.getMessage());
            throw e;
        }
        return responseDto;
    }


    public List<MyDto> helperMethod(PreparedStatement pstmt) throws SQLException {
        List<MyDto> myDtoList = new ArrayList<>();
        try( ResultSet rs = pstmt.executeQuery()) {
            while (rs.next()) {
                MyDto myDto = new MyDto();
                myDto.setValue4(rs.getLong("VALUE_4"));
                myDto.setDate(rs.getDate("DATE"));
                myDto.setTransactionId(rs.getLong("ID"));
                myDto.setAmount(rs.getLong("AMOUNT"));
                myDto.setToAgentId(rs.getLong("TO_AGENT_ID"));
                myDto.setFromAgentId(rs.getLong("FROM_AGENT_ID"));
                myDto.setName(rs.getString("NAME"));
                myDto.setValue2(rs.getLong("VALUE_2"));
                myDto.setValue1(rs.getLong("VALUE_1"));
                myDto.setStatus(rs.getInt("STATUS"));
                myDto.setValue3(rs.getString("VALUE_3"));
                myDto.setText(rs.getString("TEXT"));
                myDtoList.add(myDto);
            }
        }catch (Exception ex){
            log.error(ex.getMessage());
            throw ex;
        }
        return myDtoList;
    }

正如我所说,相同的查询以毫秒为单位。我真的不知道我在做什么错。

任何帮助将不胜感激!

sql oracle spring-boot prepared-statement
1个回答
0
投票

这不是直接的答案,但希望可以为您指明正确的方向。首先,根据您的条件,所执行的SQL会有不同的变化。我会尝试以下方法:

  1. 编辑选择字符串并在其中嵌入唯一注释,以便我们在下一步中找到它。示例:“ [select /*mytest*/ * from ..."
  2. 执行程序。然后在v $ sqlarea中找到查询,例如:select sql_id from v$sqlarea where instr(sql_fulltext,'mytest') > 0;
  3. 使用步骤2中的sql_id值,execute SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('sql_id',0));

这将为您显示执行计划,希望您能看到差异,可能正在进行全表扫描或未使用索引。等等。对于直接sql查询,请执行类似的步骤,该步骤更快,并查看它们之间的区别。

© www.soinside.com 2019 - 2024. All rights reserved.