Oracle sql STRUCT创建花费了太多时间

时间:2014-09-18 15:13:54

标签: java oracle plsql

Java导入片段:

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

PLSQL代码段:

one_user_type

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

Java code snippet:

//连接conn;

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评论:“太多时间”与实际查询执行相关。创建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

爪哇:

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);

2 个答案:

答案 0 :(得分:4)

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

解决方案是使用自定义java-class并将值直接流入Procedure调用,这将完全消除构造函数时间!

看起来像这样:

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 );

答案 1 :(得分:0)

也许您在打开和关闭连接时失去了很多时间,为什么不尝试创建单例连接并将其用于每个数据操作。