通过 Java 将超大型数据集加载到关系数据库中的最佳实践



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

  • 每个月我都会收到一个 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。

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

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

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

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

假设您正在谈论 Sybase ASE 16,请与您的 DBA 一起监视负载,以查看您遇到瓶颈的地方。

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

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


一些一般的设计思路...

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

2(批量插入(即,包裹在begin/commit tran中(并测试以查看哪种尺寸最适合您 - 目标是减少数据库必须为每个事务执行的相对缓慢的日志写入次数

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

4(整理你的读取(每个读取器馈送到多个/并行写入器(,例如,从不同的数据文件中读取单独的读取器线程

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

最新更新