将BLOB作为流插入比插入字节数组慢得多

时间:2013-01-25 12:43:53

标签: oracle spring hibernate blob

我有以下场景:客户端正在将文件上传到服务器。该文件已存储 通过Hibernate进入Oracle数据库。直到最近,为该文件建模的实体具有byte[]数组属性,用于对Blob进行建模。我们将其更改为InputStream,因为我们不希望将整个文件放在服务器的RAM中。在不久的将来,我们希望更多用户上传更大的文件,因此RAM确实是一个问题。

我做了一些性能测试,到目前为止结果显示,与插入字节数组相比,流式传输速度大约慢1.8倍。以下是为10次迭代插入100MB文件的一些结果:

Method       Mean Duration [ms]  SD [ms]
---------------------------------------
Byte Array   10733.0             264.0
Streaming    18089.0             913.0

客户端和服务器之间的通信使用Spring RMI完成,二进制数据本身的流式传输使用RMIIO完成。由于使用了RMIIO,我们必须编写自己的Blobtype,从客户端解包二进制文件并将其推送到blob的二进制流中。你可以在下面看到这个代码。

到目前为止我所做的事情:

  • 为了缩小问题所在,我在服务方法中打开RMIIO流并将其放入一个字节数组中,然后将其保存到数据库中。这样做,它产生与一直使用字节数组相同的性能。因此,性能消耗不是来自RMIIO包,而是来自服务器和数据库之间。
  • 更改缓冲区大小对性能影响非常小

与插入字节数组相比,任何人都可以分享一些有关插入流的原因的深入见解吗?

我的配置:

  • Spring 3.1.1
  • RMIIO 2.0.0
  • Hibernate 3.6.10
  • Oracle 11.2.0.1.0
  • 适用于JDBC的Oracle驱动程序10.2.0.5.0

带有字节数组的旧实体(插入更快):

@Entity
@Table(name = "MYBINARYOBJECT")
public class MyBinaryObject {

    @Id
    private Long id;

    @Lob
    private byte[] bytes;

}

带输入流的新实体(插入速度较慢):

@Entity
@Table(name = "MYBINARYSTREAMOBJECT")
public class MyBinaryStreamObject {

    @Id
    private Long id;

    @Type(type = "MyBlobType")
    private RemoteInputStream bytes;

}

我们的自定义Blob类型:

public class MyBlobType extends AbstractLobType {

    @Override
    protected Object nullSafeGetInternal(ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
            throws SQLException, IOException, HibernateException {

        RemoteInputStreamServer server = new GZIPRemoteInputStream(lobHandler.getBlobAsBinaryStream(rs, names[0]));
        return server.export();
    }

    @Override
    protected void nullSafeSetInternal(PreparedStatement ps, int index, Object value, LobCreator lobCreator)
            throws SQLException, IOException, HibernateException {

        BufferedInputStream stream = null;
        try {
             ((RemoteInputStream) value).available();
             stream = new BufferedInputStream(
                    RemoteInputStreamClient.wrap((RemoteInputStream) value, RemoteRetry.NEVER), 16384);
             lobCreator.setBlobAsBinaryStream(ps, index, stream, -1);
        } catch (IllegalArgumentException e) {
            throw new MyStreamingException();
        }

    }
}

0 个答案:

没有答案