如何阻止NpgsqlDataReader阻止?

时间:2010-06-06 06:03:39

标签: .net postgresql npgsql

对大型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预取”内容。我完全不知道为什么会这样。

2 个答案:

答案 0 :(得分: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”,因为您实际上打算获取所有游标的输出。

答案 1 :(得分:1)

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

请尝试使用Npgsql 2.0.9,如果您还有问题,请告诉我。