2

针对大型 PostgreSQL 表运行以下代码,NpgsqlDataReader 对象会阻塞,直到获取所有数据。

NpgsqlCommand cmd = new NpgsqlCommand(strQuery, _conn);
NpgsqlDataReader reader = cmd.ExecuteReader(); // <-- takes 30 seconds

我怎样才能让它表现得不预取所有数据?我想逐行遍历结果集,而不是一次将所有 15 GB 提取到内存中。

我知道在 Npgsql 1.x 中存在此类问题,但我使用的是 2.0。这是针对 XP/Vista/7 上的 PostgreSQL 8.3 数据库的。我的连接字符串中也没有任何时髦的“强制 Npgsql 预取”内容。我完全不知道为什么会这样。

4

2 回答 2

3

我很惊讶驱动程序没有提供执行此操作的方法——但您可以手动执行 SQL 语句来声明一个游标,打开它并分批从中获取。即(这段代码非常可疑,因为我不是 C# 人):

new PgsqlCommand("DECLARE cur_data NO SCROLL CURSOR AS "
                 + strQuery, _conn).ExecuteNonQuery();
do {
   NpgsqlDataReader reader = new NpgsqlCommand("FETCH 100 FROM cur_data", _conn)
                                           .ExecuteReader();
   int rows = 0;
   // read data from reader, incrementing "rows" for each row
} while (rows > 0);
new PgsqlCommand("CLOSE cur_data", _conn).ExecuteNonQuery();

注意:

  • 您需要在事务块内才能使用游标,除非您在声明它时指定“HOLD”选项,在这种情况下,服务器会将结果假脱机到服务器端临时文件(您不必传输虽然这一切都是一次)
  • cursor_tuple_fraction设置可能会导致在通过游标执行查询时使用不同的计划,而不是在立即模式下。您可能想要在声明游标之前执行“SET cursor_tuple_fraction=1”,因为您实际上打算获取所有游标的输出。
于 2010-06-06T12:27:13.680 回答
1

您使用的是哪个 Npgsql 版本?我们不久前添加了对大表的支持。事实上,Postgresql 协议版本 3 支持在不使用游标的情况下对大型结果集进行分页。不幸的是,我们还没有实现它。对此感到抱歉。

请尝试使用 Npgsql 2.0.9 并让我知道您是否仍有问题。

于 2010-06-16T14:32:46.040 回答