【问题标题】:Best practices for loading extremely large datasets into a relational database via Java通过 Java 将超大型数据集加载到关系数据库中的最佳实践
【发布时间】:2018-10-22 19:35:47
【问题描述】:

虽然我过去曾使用过大型数据集,但从未使用过如此庞大的数据集。这是细分:

  • 每个月我都会收到一个 5GB 的平面文件,其中每行包含 1 条数据库记录
  • 此文件包含大约 1000 万行数据,随后的每个月包含的数据都比前一个月多
  • 数据可能有完全重复的数据,需要忽略
  • 数据也可能有不精确的重复,需要对其进行分析,只插入其中一行,其余行丢弃

我需要为价值 10 年的数据(大约 15 亿行)设置初始加载。我对处理这个问题的数据库没有任何问题,但是我很难快速加载这些数据。

我目前一次插入一行,允许主键约束让我知道我是否有需要审查的行,这些行放在单独的表中。

加载一个 5GB 的文件大约需要 10 个小时,这是我能做到的最快速度。我将其设置为一次预处理大约 25,000 行,然后通过一条语句循环遍历它们,如下所示:

public void saveBatchSql(String[] sql) {
    try {
        Statement stmt = dbCon.createStatement();

        for (String query : sql) {
            try {
                stmt.execute(query);
            }
            catch (Exception ee) {
                query = query.replace("component_detail", "component_detail_duplicate");
                stmt.execute(query);
            }
        }

        stmt.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }

}

到目前为止,这是我能想到的最好的。有没有人对我如何让它更快地工作有任何想法?据我所知,我无法处理内存中的所有记录,但也许还有其他方法?

顺便说一下,我要加载的数据库是 Sybase 版本 16。

【问题讨论】:

  • 您可以尝试批处理语句。顺便说一句:从内存的角度来看,一次预处理 25,000 行可能效率低下。
  • 你有没有分析过是否可以对表进行分区,然后将输入数据分块并通过多线程插入?您还可以为每一行添加校验和哈希/键,以快速检查数据是否更改。
  • 我认为第一步应该是使用分析器分析正在运行的代码。我敢打赌,瓶颈远非你想象的那样。
  • @markspace 我怀疑分析是否会产生任何重要结果,因为瓶颈不是 Java 代码而是数据库。
  • 根本不要使用java。使用 Sybase 的批量加载实用程序。

标签: java sql jdbc sybase


【解决方案1】:

这取决于数据库,但通常推荐的方法是使用数据库工具从一些简单的格式(如 CSV)加载数据。根据数据库,您可能需要在导入之前删除索引并在导入后重新创建它们。数据库文档通常会提供一些关于如何提高批量数据加载性能的提示。

我建议不要使用 Java 进行批量加载。干什么用的?

只是为了加载?数据库工具已为此进行了优化,您将无法在 Java 中做得更好。

加载时的数据处理?好吧,通常您可以在数据库中使用 SQL 完成大部分数据处理。因此,将数据加载到传入表中并在其上运行 SQL 查询。与 Java 中的硬编码处理逻辑相比,它更加灵活。在大多数情况下,它也会更有效,因为数据库在优化 SQL 查询/语句方面非常聪明。

【讨论】:

  • 您对效率的看法是正确的,但我正在尝试为我的客户提供一种通过实用程序自己上传此内容的方法。除了加载之外,他们还需要其他功能,但我想我可以将负载拆分为特定于 sybase 的格式。我会调查一下。还有一些数据按摩发生,以及一些验证,这在触发器中可能会很棘手,当数据达到数亿行时,这实际上可能会使它变得更慢。我想一些实验是有序的。
  • 也许通过 Java 检查这个线程重新批量加载(即 BCP)选项:stackoverflow.com/questions/2112395/…
  • @RichCampbell 请对问题发表评论,我认为 OP 没有收到您的评论通知。
【解决方案2】:

假设您谈论的是 Sybase ASE 16,请与您的 DBA 一起监控您的负载,了解您遇到瓶颈的地方。

主要强调捕获/分析 MDA 数据(master..mon% 表);要查找的关键项目是等待事件/计时以及各个插入的性能(cpu/内存使用情况、逻辑 IO 等)。

弄清楚您是否必须更新大量索引……或者可能导致触发 RI/外键检查……或者触发触发器……所有这些都会大大降低你的插入。


一些通用的设计理念...

1) 使用准备好的语句(并确保您重复使用准备好的语句而不是为每个插入创建一个新的准备好的语句) - 目的是消除让数据库编译每个插入语句的开销

2) 批处理您的插入(即,包装在 begin/commit tran 中)并测试以查看最适合您的大小 - 目标是减少数据库必须为每个操作执行的相对较慢的日志写入次数交易

3) 由于读取(从您的文件)可能比写入(到数据库)更快,请考虑让您的读取器线程馈入多个/并行写入器线程 - 目标是确保您不会遇到写入瓶颈

4) 将您的读取并行化(每个读取器馈入多个/并行写入器),例如,让单独的读取器线程从不同的数据文件读取

5) 正如 lexicore 所提到的,看看您是否可以使用 ASE 的 bcp(操作系统级别)实用程序来帮助批量加载数据

【讨论】:

  • 谢谢你,这让我有很多需要研究的地方。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
  • 2011-04-17
  • 2014-08-01
  • 2022-08-18
  • 1970-01-01
  • 2011-03-07
  • 2016-04-04
相关资源
最近更新 更多