如何提高使用Spring检索REF CURSOR到Java的性能?

时间:2012-09-20 16:44:55

标签: java sql oracle spring

我正在执行对作为DB包的一部分的函数的调用。该软件包部署在两个位置。一个本地和另一个偏远地区(横跨大西洋)。

我正在通过Spring JDBC模板检索数据。

有一个函数返回大约1000行(并不是那么多),这在本地获取数据时大约需要1.5秒,但在远程获取数据时需要12秒。

在所有示例代码中,名称都已更改,代码已经过一些简化。

请参阅当前Java代码的示例:

SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getDataSource())
                                            .withSchemaName(MY_SCHEMA_NAME)
                                            .withCatalogName("REFCURSOR_PKG")
                                            .withFunctionName("GET_DATA")
                                            .returningResultSet("RESULT_SET", new DataEntryMapper());

        SqlParameterSource params = new MapSqlParameterSource()
                                    .addValue("the_name", name)
                                    .addValue("the_rev", rev);

        Map resultSet = simpleJdbcCall.execute(params);
        ArrayList list = (ArrayList) resultSet.get("RESULT_SET");

RowMapper类看起来像这样:

class RouteDataEntryMapper implements RowMapper {
        public RouteDataEntry mapRow(ResultSet resultSet, int rowNum) throws SQLException {
            return new DataEntry(resultSet.getString("name"), 
                                    Integer.parseInt(resultSet.getString("rev"));
        }
    }

SQL包规范片段:

TYPE REF_CURSOR IS REF CURSOR;  

SQL函数:

 FUNCTION GET_ROUTE_DATA(the_name VARCHAR2, the_rev VARCHAR2) RETURN REF_CURSOR AS

  RESULT_SET REF_CURSOR;

  BEGIN
    OPEN RESULT_SET FOR
    select *
    from table_name tn
    where tn.name = the_name
    and tn.rev = the_rev;

    RETURN RESULT_SET;

    CLOSE RESULT_SET;

    EXCEPTION WHEN OTHERS THEN
      RAISE;

  END GET_ROUTE_DATA;

我也尝试过使用常规的锅炉板JDBC(创建连接,准备语句,执行语句,从RESULT_SET中检索数据等),我发现绝大多数时间花在循环RESULT_SET上并从中提取数据它和一些pojos。对于上面的Spring代码,大部分时间都是在execute()方法中花费的,但这可能是因为它在那时使用RowMapper创建了对象。

因此,它们之间的共同点是执行以下操作:

rs.getString("name")

我猜这就是问题所在,但我可能错了。

正如我所说,在当地,延迟很好,但远程时间太长了。这是因为它会在每个rs.get上发送到DB吗?有更好的方法吗?

提前致谢。

2 个答案:

答案 0 :(得分:2)

  

rs.getString(“name”)

ResultSet.get*(String columnName)可以替换为ResultSet.get*(int columnNaumber),这稍微快一点,但我怀疑这里的主要问题。

  

这是因为它会在每个rs.get上发送到数据库......?

虽然这真的取决于司机我怀疑它不会。对于缓存的结果集,当您滚动光标时它可能会转到服务器,但它仍然会在每次往返中获取一堆行。

我还有两个建议:

  • 使用网络嗅探实用程序查看正在传输的数据
  • 检查您的驱动程序是否有任何预取选项等。

答案 1 :(得分:0)

添加以下行: -

.withoutProcedureColumnMetaDataAccess

在以下代码行中

SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getDataSource())
                                            .withSchemaName(MY_SCHEMA_NAME)
                                            .withCatalogName("REFCURSOR_PKG")
                                            .withFunctionName("GET_DATA")
                                            .withoutProcedureColumnMetaDataAccess  // to avoid fetching meta data info from database