gpt4 book ai didi

java - 对 BLOB 进行操作需要太多时间

转载 作者:行者123 更新时间:2023-12-02 09:37:08 48 4
gpt4 key购买 nike

我必须读取仅包含文本的BLOB 列。之前它的工作效率非常高(在 3 分钟内读取 100k blob),但在不同的环境中,尽管使用相同的硬件,却花费了大量的时间。

这是我的代码:-

    while (rs.next()) {
is = rs.getBinaryStream(3);

while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
is.close();
blobByte = baos.toByteArray();
baos.close();
String blob = new String(blobByte);
String msisdn = rs.getString(2);

blobData = blob.split("\\|");
//some operations
}

我每隔 5 秒获取一次 jstack,发现应用程序总是在这一行:-

    blobData = blob.split("\\|");

有时是:-

    new String(blobByte);

我的java选项:-

     -ms10g -mx12g -XX:NewSize=1g -XX:MaxNewSize=1g

我的代码的某些部分是否未优化?或者有没有一种非常有效的方法来读取BLOB

最佳答案

您将获得 InputStream BLOB 能够避免将整个 BLOB 数据存储在内存中。但随后,你却做了完全相反的事情

  • 您使用 ByteArrayOutputStream将整个数据传输到 byte[]大批。请注意,数据甚至在内存中存在两次,一次位于 ByteArrayOutputStream 内。自己的缓冲区,然后在 baos.toByteArray() 创建并返回的副本中
  • 然后,将整个数组转换为可能巨大的 String通过new String(blobByte) ,承担整个数据的第3次复制(包括字符集转换)。
  • split("\\|")将运行整个 String ,为分隔符之间的每个序列创建子字符串,这意味着将整个数据再次复制到子字符串中(减去分隔符字符),届时,内存中将拥有整个数据的四个副本,具体取决于源的缓冲,它可能是五次。此外,还会创建并填充一个包含对所有这些子字符串的引用的数组

并非所有复制操作都可以避免。但我们可以避免将整个数据存储在内存中:

try(Scanner s = new Scanner(is).useDelimiter("\\|")) {
while(s.hasNext()) {
String next = s.next();
System.out.println(next);// replace with actual processing
}
}

当您能够单独处理项目而不保留对前一个项目的引用时,这些字符串可能会被垃圾收集,在最好的情况下会进行少量收集。

即使 String[]处理时需要包含所有元素的数组,这使得整个数据的一份副本(以单个字符串的形式)不可避免,您可以避免所有其他副本:

try(Scanner s = new Scanner(is).useDelimiter("\\|")) {
List<String> list = new ArrayList<>();
while(s.hasNext()) list.add(s.next());
System.out.println(list);// replace with actual processing as List
String[] array = list.toArray(new String[0]); // when an array really is required
}

从 Java 9 开始,您可以使用

try(Scanner s = new Scanner(is).useDelimiter("\\|")) {
List<String> list = s.tokens().collect(Collectors.toList());
System.out.println(list); // replace with actual processing as List
}

try(Scanner s = new Scanner(is).useDelimiter("\\|")) {
String[] array = s.tokens().toArray(String[]::new);
System.out.println(Arrays.toString(array)); // replace with actual processing
}

但是单独处理元素,而不将所有元素保存在内存中,是首选方法。

<小时/>

另一种可能的优化是避免多个(内部)Pattern.compile("\\|")通过自己执行一次并传递准备好的 Pattern 来调用而不是 "\\|"字符串到 useDelimiter方法。

<小时/>

请注意,所有这些示例都使用系统的默认字符集编码,就像您的原始代码一样。由于运行代码的环境的默认字符集不一定与数据库相同,因此您应该明确,即使用 new Scanner(is, charset) ,就像您应该使用 new String(blobByte, charset) 一样在你的原始代码中,而不是 new String(blobByte) .

或者您首先使用 CLOB。

关于java - 对 BLOB 进行操作需要太多时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57408541/

48 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com