【问题标题】:Oracle sql STRUCT creation taking too much timeOracle sql STRUCT 创建时间过长
【发布时间】:2014-09-18 15:13:53
【问题描述】:

Java 导入 sn-p:

import oracle.sql.StructDescriptor;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;

PLSQL代码sn-p:

one_user_type

CREATE OR REPLACE TYPE one_user_type ABCD IS OBJECT
(
   user_id    VARCHAR2(120),
   user_name VARCHAR2(120)
)

Java 代码 sn-p:

// 连接连接;

Object[] userObject1 = new Object[] {
                    "101", "peter" };

StructDescriptor userDescriptor = StructDescriptor
                    .createDescriptor("one_user_type", conn);


// The below line takes 2.5 seconds approx to execute.          

STRUCT user1 = new STRUCT(userDescriptor, conn, userObject1);


注释:ojdbc6.jar; jdk1.6、Oracle 11g

问题 - 知道为什么这会花费太多时间,以及如何减少时间吗?

编辑 1 回应@Lalit Kumar B cmets:“太多时间”与实际查询执行有关。创建 STRUCT 是为了将记录表/对象表传递给 PLSQL 过程。实际的查询执行只需要 93 毫秒,而当调用两个这样的过程时 UI 等待大约 5 秒,它们都获取对象表和我们需要创建 STRUCT 的位置。 因此 2.5 秒被认为是这么多,我喜欢对其进行微调。当我检查其他 Java 对象构造、转换、查询执行等的执行时间时,与这个 STRUCT 创建相比,它们都非常低。 考虑到我真正调用 5 个以对象表作为参数的存储过程的场景,我进行了 5 次不同的调用来为每个存储过程创建 STRUCT,仅创建 STRUCT 总共需要大约 7 秒。这个想法是调用过程,获取结果,放入包装器并发送回 UI。

编辑 2:[09/20] 为了最大限度地缩短时间,创建了一个过程,该过程接受一个对象表并充当内部调用 5 个过程的包装器。因此,从 Java 代码来看,它只是一个存储过程调用。尽管如此,必须创建一次 STRUCT 以作为包装程序的输入。在多次运行时,它观察到 STRUCT 创建可以在 2 秒到 8 秒之间进行!我在创建 STRUCT 的方式上做错了吗?我从下面提供的链接中检查了 Oracle 文档,但我无法确定我是否偏离了。

如果您需要更多详细信息,请告诉我。

更新:创建 STRUCT 对象和描述符 http://docs.oracle.com/cd/B12037_01/java.101/b10979/oraoot.htm

编辑 3:解决方案的附加组件[09/23] 公认的解决方案是存储单个对象的理想选择。如果要传递对象表,情况如下:

PLSQL:

TYPE one_user_table_type IS TABLE OF one_user_type; // Table of Objects

Java:

UserType user = new UserType( "101", "Peter" );
ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor(
                    "ONE_USER_TABLE_TYPE", conn);
UserType[] userArray = { user };
Array users = new ARRAY(arrayDescriptor, conn, userArray );
callableStatement.setArray(1, users);

【问题讨论】:

  • Too much time 在技术上无法与您认为的更短时间框架相比。所以,请发布所需的详细信息,如经过的时间、执行计划等。现实世界中的 2.5 秒被认为是相当快的,也许你眨了两次眼睛。但如果您不这么认为,则需要提供所要求的详细信息。
  • @LalitKumarB,谢谢,用编辑 cmets 更新
  • 好的,现在你离得到答案有点近了。但是,我想知道为什么需要 PL/SQL,如何使用纯 SQL 将结果集返回给 UI?它将减少 PL/SQL 和 SQL 这两个引擎之间的context switching
  • 还有一个重要的,是并发操作还是隔离?
  • 为什么是PLSQL程序? bcoz 数据通过 PLSQL 包和过程进行处理/检索/管理。 UI Java PLSQL 。其隔离操作[串行执行]

标签: java oracle plsql


【解决方案1】:

我遇到了同样的情况:STRUCT Constructor真的很慢,因为Oracle查询数据库的属性和完整的依赖链,这不仅是一个单独的DB调用,这会减慢你的速度,而且是一个查询一些系统词典。 这一点在 STRUCT-Constructor 的 JavaDoc 中有所暗示,因为约束和有效性在构造时进行测试,这只能通过数据库查询整个对象定义来实现。

解决方案是使用自定义 java-class 并将值直接流式传输到过程调用中,这将完全消除构造函数时间!

看起来像这样:

public final class MyUserType implements SQLData
{
    public String userId;
    public String userName;

    public MyUserType(){}

    public MyUserType( final String userId, final String userName )
    {
        this.userId = userId;
        this.userName = userName;
    }

    @Override
    public String getSQLTypeName() throws SQLException
    {
        return "one_user_type";
    }

    @Override
    public void readSQL( final SQLInput stream, final String typeName ) throws SQLException
    {
        userId = stream.readString();
        userName = stream.readString();
    }

    @Override
    public void writeSQL( final SQLOutput stream ) throws SQLException
    {
        stream.writeString( userId );
        stream.writeString( userName );
    }
}

然后你只需使用:

MyUserType param = new MyUserType( "010", "Peter" );
statement.setInputParameter( 1, param );

【讨论】:

  • 太好了,谢谢!我已经实现了这种类型的自定义类来读取对象表,覆盖readSQL() 方法。想知道何时覆盖writeSQL() 方法:)。这是确切的解决方案。我将修改我的问题并进行编辑以描述相同的用例以传递对象数组。在这种情况下,我们只设置一个对象。
  • 您能否在 STRUCT 构造函数的第一点上引用一些源/参考链接?
  • JDBC 文档很麻烦,Oracle 并不真正符合 JDBC 标准。我尝试了几种方法,还使用 ​​OraData 和自定义描述符,并测量了性能和网络流量......我不知道是否有关于此的官方文档。
  • @user007 我认为 JavaDoc 暗示了这一点:docs.oracle.com/cd/E18283_01/appdev.112/e13995/oracle/sql/…
【解决方案2】:

也许你在打开和关闭连接上浪费了很多时间,为什么不尝试创建一个单例连接并为每个数据操作重用它。

【讨论】:

  • 好点,但这里不是这样。我包含的上述 sn-p 仅涉及一个连接。获取连接,创建STRUCT,调用过程;以及我在创建 STRUCT 对象时所说的时间延迟
猜你喜欢
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 2023-04-05
  • 2014-10-09
  • 2017-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多