如何提高Java应用程序从Oracle数据库中获取大量数据的性能?

wtzytmuj  于 2023-05-05  发布在  Java
关注(0)|答案(8)|浏览(244)

我有3个数据库表-项目,审计和评论。我必须从 Items 表中获取大量数据,比如100万条记录,对于每个获取的项目,我必须从 AuditsComments 检索数据,并将报告写入分隔文件。所以输出可能看起来像,

Item entry 1
    Audit entry 1 for Item 1
    Audit entry 2 for Item 1
    Audit entry 3 for Item 1
    Comment entry 1 for Item 1
    Comment entry 2 for Item 1
Item entry 2 
    Audit entry 1 for Item 2
    .
    .
    .

现在这需要花费很多时间,因为程序要为每个 item 查询oracle 100万次。我想通过线程来提高性能,但我不熟悉线程。有人能帮我提高性能吗?

k4ymrczo

k4ymrczo1#

您可以检索项目、一个连接查询以获取审核,另一个连接查询以获取注解。
加快查询结果的一种方法是将选择行作为单个连接字符串返回,然后自己拆分该行。这用于将检索速度提高2-3倍。较新版本的Oracle在这方面可能更智能,开销更少。
但是,无论如何,您拥有的数据量可能需要一段时间才能从Oracle获得。

vshtjzan

vshtjzan3#

您可以编写一个存储过程,它将输出带有utl_file包的文件,并从java调用它。这样你就可以使用类似

f := utl_file.fopen('my_dir','my_file','w');
FOR r_items IN (SELECT * FROM items) LOOP
  utl_file.put_line(f,r_items.name);

  FOR r_audit IN (SELECT * FROM audit WHERE item_id = r_items.id) LOOP
    utl_file.put_line(f,r_audit.some_field);
  END LOOP;

  FOR r_comments IN (SELECT * FROM comments WHERE item_id = r_items.id) LOOP
    utl_file.put_line(f,r_comments.some_field);
  END LOOP;
END LOOP;
bwntbbo3

bwntbbo34#

从你提供的有限信息来看,不清楚你在做什么,你真实的的问题是什么。

  • 如果您正在执行一百万个单独的(小的)查询,则应该考虑重新构造应用程序,以便将它们成批组合,或者对整个表执行SELECT。
  • 如果问题是在一个查询中获取一百万行,那么可以考虑使用更复杂的查询,或存储查询,或在数据库端进行一些数据缩减。
h7wcgrx3

h7wcgrx35#

也许最好将UNION和JOIN结合起来,以最好的方式获取所有数据。查询可能看起来像这样:

select itm.itemid
,      tmp.what || ' ' || tmp.entry || ' for Item ' || tmp.itemid line
from   items itm
join
(
    select itemid
    ,      entry 
    ,      'Audit' what
    from   audits
    union all
    select itemid
    ,      entry 
    ,      'Comment' what
    from   comments
) tmp on itm.itemid = tmp.itemid
a0zr77ik

a0zr77ik6#

我的想法是运行三个查询(一个返回所有项目,一个返回所有评论,一个返回所有审计条目),每个查询都按项目ID排序

SELECT * FROM
  (SELECT itemid, 1 type, null seq, item_line line
   from items
   union all
   select itemid, 2, audit_seq, audit_line
   from audit
   union all
   select itemid, 3, comment_seq comment_line 
   from comments)
order by itemid, type, seq

这意味着将所有构建行条目的逻辑放入数据库中,但它可能比java代码运行得快得多。

brccelvz

brccelvz7#

如果你的系统(硬件,配置等)的大小可以处理你放入其中的数据量,最好,最快和最简单的方法是简单地在一个查询中连接表,获取行(参见其他关于fetch_size的评论),然后以任何你想要的格式转储它。
从示例输出格式来看,您需要按排序顺序(item、audit、comments)处理行。您将遍历这些行并跟踪最后处理的项,只要当前的ITEM_ID与前一个不同,就输出项数据。
当你决定如何实现它时,你要考虑的最重要的一个方面是连接和排序是否适合内存。如果排序/连接溢出到磁盘,您将不得不解决这个问题,以实现所需的性能。关于如何避免磁盘溢出的一些示例:
根据ITEM_ID对表(或表的副本)进行散列分区。然后,您可以按分区连接表,以便每个连接都适合内存。
或者,您可以从所有表中获取所有数据,并在Java代码中,将项目放在链表中,将审计/注解放在以item_no为关键字的基于散列的结构中。然后,您将遍历这些项,并通过item_id查询审计/注解。这种解决方案避免了排序操作,并且不需要将连接结果放入内存中。
或者您可以实现一些自己动手的分区。例如,查询数据9次。在第一个查询中,只获取ITEM_ID以1开头或结尾的项。第二个查询获取以2开头/结尾的所有项目,等等。这种解决方案导致对所有表进行9次表扫描,这显然不是很有效。但是如果你能避免溢出到磁盘,它实际上可能会更快。

slsn1g29

slsn1g298#

锁定,本次有disputes about this answer’s content正在解析。它目前不接受新的交互。

在你按照BazzPsychoNut所说的那样管理你的UNION/JOIN之后,如果ResultSet很大的话,把FetchSize的值调整到更大的值可能会有帮助。Oracle的默认值为10。

Statement stmt = conn.createStatement();
stmt.setFetchSize(200);
ResultSet rset = stmt.executeQuery(sql);

相关问题