使用 JDBC 迭代大表的最快方法

Posted

技术标签:

【中文标题】使用 JDBC 迭代大表的最快方法【英文标题】:Fastest way to iterate through large table using JDBC 【发布时间】:2010-11-08 00:39:13 【问题描述】:

我正在尝试创建一个 java 程序来清理和合并表中的行。该表很大,大约有 500k 行,我当前的解决方案运行非常缓慢。我想做的第一件事就是简单地获取一个代表我表中所有行的对象的内存数组。这是我正在做的事情:

一次选择 1000 行的增量 使用 JDBC 获取以下 SQL 查询的结果集 从 ID > 0 且 ID 将结果数据添加到内存数组中 以 1000 为增量继续查询直至 500,000,每次添加结果。

这需要很长时间。事实上,它甚至没有超过从 1000 到 2000 的第二个增量。查询需要永远完成(尽管当我直接通过 mysql 浏览器运行相同的东西时,它的速度相当快)。自从我直接使用 JDBC 以来已经有一段时间了。有更快的替代方案吗?

【问题讨论】:

【参考方案1】:

首先,你确定你需要内存中的整个表吗?也许您应该考虑(如果可能)选择要更新/合并/等的行。如果您真的必须拥有整个表格,您可以考虑使用可滚动的 ResultSet。你可以像这样创建它。

// make sure autocommit is off (postgres)
con.setAutoCommit(false);

Statement stmt = con.createStatement(
                   ResultSet.TYPE_SCROLL_INSENSITIVE, //or ResultSet.TYPE_FORWARD_ONLY
                   ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery("select * from ...");

它使您可以使用“绝对”和“相对”方法移动到您想要的任何行。

【讨论】:

太棒了。那成功了。回答您关于选择性获取数据的观点。不幸的是,我不知道要提前合并和修复哪些行——我必须遍历所有行并检查,构建适当的内存哈希图,然后根据某些质量返回并清理表。跨度> 这种方法比较脆弱。如果您有数百万行和一些处理工作,您可能会遇到网络延迟或超时,这将在某些情况下难以恢复操作。 不幸的是,这在大型表上运行速度很慢,因为 MySQL JDBC 驱动程序不支持游标,并且驱动程序会尝试将所有数据加载到内存中 我正在使用 postgressql 作为数据库,但它没有帮助。仍然 OOM。 检查您使用的驱动程序是否支持此功能。想想其他可能的原因(堆大小是多少?您要在内存中放入多少数据?)。【参考方案2】:

虽然它可能不是最佳的,但您的解决方案似乎对于一次性数据库清理例程来说应该没问题。运行这样的查询并获得结果不应该花那么长时间(我假设因为它是一个关闭几秒钟就可以了)。可能的问题 -

您的网络(或至少您与 mysql 的连接)是否很慢?如果是这样,您可以尝试在 mysql 机器上本地运行该进程,或者更好地连接。

表结构中是否存在导致它的原因?为每一行拉下 10k 的数据? 200 个字段?根据非索引行计算要获取的 id 值?您可以尝试找到一种对数据库更友好的方式来提取数据(例如,仅包含您需要的列,具有数据库聚合值等)

如果您没有通过第二个增量,那么确实有问题 - 效率与否,在运行的 JVM 上将 2000 或 20,000 行转储到内存中应该没有任何问题。也许您正在冗余地存储数据或极其低效地存储数据?

【讨论】:

感谢您的建议。我相信主要问题是我没有以最佳方式使用 JDBC API。我现在能够以 10k-20k 的增量相对快速地获取我的数据。很好的建议,尽管只拉取必要的列而不是执行 SELECT *。【参考方案3】:

对我有帮助的一件事是Statement.setFetchSize(Integer.MIN_VALUE)。我从Jason's blog 得到这个想法。这将执行时间减少了一半以上。消耗的内存急剧下降(因为一次只读取一行。)

不过,此技巧不适用于 PreparedStatement

【讨论】:

2000 的获取大小对我来说已经很有效了。较大的值没有改变任何东西。

以上是关于使用 JDBC 迭代大表的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

从大表的子集中对随机行进行最快查询 - postgresql

使用对象和键迭代 NSArray 的最快方法

迭代文件系统的最快方法

在 Javascript 中迭代 JSON 字符串的最快方法

迭代 Pandas DataFrame 并插入行的最快方法

在 Java Spark 中迭代大型数据集的最快且有效的方法