如何从巨大的表中读取所有行?

我有一个处理数据库(PostgreSQL)的所有行的问题。 我得到一个错误: org.postgresql.util.PSQLException: Ran out of memory retrieving query results. 我认为我需要读小块的所有行,但它不工作 – 它只读取100行(下面的代码)。 怎么做?

  int i = 0; Statement s = connection.createStatement(); s.setMaxRows(100); // bacause of: org.postgresql.util.PSQLException: Ran out of memory retrieving query results. ResultSet rs = s.executeQuery("select * from " + tabName); for (;;) { while (rs.next()) { i++; // do something... } if ((s.getMoreResults() == false) && (s.getUpdateCount() == -1)) { break; } } 

在PostgreSQL中使用CURSOR或让JDBC驱动程序为您处理 。

处理大型数据集时LIMIT和OFFSET会变慢。

简短版本是,调用stmt.setFetchSize(50);conn.setAutoCommitMode(false); 避免将整个ResultSet读入内存。

以下是文档所说的内容:

根据游标获取结果

默认情况下,驱动程序一次收集查询的所有结果。 这对于大数据集可能不方便,所以JDBC驱动程序提供了一种将ResultSet放在数据库游标上的方法,并且只提取less量的行。

less量的行被caching在连接的客户端,当耗尽时,通过重新定位游标来检索下一行的行。

注意:

  • 基于游标的ResultSets不能在所有情况下使用。 有很多限制,这会使得驱动程序无声无息地恢复到一次提取整个ResultSet的状态。

  • 与服务器的连接必须使用V3协议。 这是服务器版本7.4和更高版本的默认设置(并且仅受其支持)。

  • 连接不能处于自动提交模式。 后端在事务结束时closures游标,所以在自动提交模式下,后端将closures游标,之后可以从中取出任何东西。

  • 该语句必须使用ResultSettypes的ResultSet.TYPE_FORWARD_ONLY创build。 这是默认的,所以不需要重写代码来利用这个优点,但是这也意味着你不能向后滚动或者在ResultSet中跳转。

  • 给定的查询必须是单个语句,而不是用分号串在一起的多个语句。

例5.2。 设置获取大小以打开和closures游标。

将代码更改为光标模式非常简单,只需将语句的获取大小设置为适当的大小即可。 将读取大小设置回0将导致所有行被caching(默认行为)。

 // make sure autocommit is off conn.setAutoCommit(false); Statement st = conn.createStatement(); // Turn use of the cursor on. st.setFetchSize(50); ResultSet rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("a row was returned."); } rs.close(); // Turn the cursor off. st.setFetchSize(0); rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("many rows were returned."); } rs.close(); // Close the statement. st.close(); 

我认为你的问题类似于这个线程: JDBC分页包含你的需要的解决scheme。

特别是对于PostgreSQL,您可以在请求中使用LIMIT和OFFSET关键字: http : //www.petefreitag.com/item/451.cfm

PS:在Java代码中,我build议您使用PreparedStatement而不是简单的语句: http : //download.oracle.com/javase/tutorial/jdbc/basics/prepared.html

我做了如下。 不是我想的最好的方式,但它的作品:)

  Connection c = DriverManager.getConnection("jdbc:postgresql://...."); PreparedStatement s = c.prepareStatement("select * from " + tabName + " where id > ? order by id"); s.setMaxRows(100); int lastId = 0; for (;;) { s.setInt(1, lastId); ResultSet rs = s.executeQuery(); int lastIdBefore = lastId; while (rs.next()) { lastId = Integer.parseInt(rs.getObject(1).toString()); // ... } if (lastIdBefore == lastId) { break; } } 

至less在我的情况下,问题是在试图获取结果的客户端上。

想要得到一个.csv所有的结果。

我通过使用find了解决scheme

 psql -U postgres -d dbname -c "COPY (SELECT * FROM T) TO STDOUT WITH DELIMITER ','" 

(其中dbname是db的名称…)并redirect到一个文件。