代码之家  ›  专栏  ›  技术社区  ›  Swingline Rage

如何阻止NPGSQLDataReader阻塞?

  •  2
  • Swingline Rage  · 技术社区  · 14 年前

    对一个大的PostgreSQL表运行以下代码,npgsqldatareader对象将一直阻塞,直到获取所有数据。

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

    我如何才能让它的行为不预取所有数据?我想一行一行地遍历结果集,而不想让它一次将所有15GB的数据都提取到内存中。

    我知道NPGSql1.x中存在这种问题,但我现在使用的是2.0。这是针对xp/vista/7上的PostgreSQL 8.3数据库的。我的连接字符串中也没有任何时髦的“强制NPGSQL预取”内容。我完全不知道为什么会发生这种事。

    2 回复  |  直到 14 年前
        1
  •  3
  •   araqnid    14 年前

    我很惊讶驱动程序没有提供这样做的方法——但是您可以手动执行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 设置可能会导致在通过光标执行查询时使用不同的计划,而不是直接模式。在声明光标之前,您可能需要执行“设置光标元组分数=1”,因为您实际上打算获取光标的所有输出。
        2
  •  1
  •   Francisco Junior    14 年前

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

    请尝试一下NPGSQL2.0.9,如果您还有问题,请告诉我。