为什么PostgreSQL不立即返回行?

7 投票
2 回答
1447 浏览
提问于 2025-04-15 17:47

下面的查询会立即返回数据:

SELECT time, value from data order by time limit 100;

如果没有限制条件,服务器在开始返回数据之前会花很长时间:

SELECT time, value from data order by time;

我在使用查询工具(psql)和通过API查询时都观察到了这一点。

问题/疑问:

  • 服务器在开始返回数据之前需要做的工作量,对于这两个查询应该是一样的,对吧?
  • 如果是这样,为什么第二种情况会有延迟呢?
  • 我是不是对关系型数据库管理系统(RDBMS)有什么基本的误解?
  • 有没有办法让我在第二种情况下也能让PostgreSQL立即开始返回结果,而不需要等待?
  • 编辑(见下文)。看起来setFetchSize是解决这个问题的关键。在我的情况下,我是通过Python执行查询,使用的是SQLAlchemy。我该如何为单个查询(通过session.execute执行)设置这个选项?我使用的是psycopg2驱动。

顺便提一下,time列是主键。

编辑:

我相信这段摘自JDBC驱动文档的内容描述了这个问题,并暗示了一个解决方案(我仍然需要帮助 - 请看上面的最后一条问题):

默认情况下,驱动程序会一次性收集查询的所有结果。这对于大型数据集来说可能不太方便,因此JDBC驱动提供了一种基于数据库游标的方式,只获取少量行。

还有:

将代码更改为游标模式只需将语句的获取大小设置为适当的值。将获取大小设置回0将导致所有行被缓存(这是默认行为)。

// make sure autocommit is off
conn.setAutoCommit(false);
Statement st = conn.createStatement();

// Turn use of the cursor on.
st.setFetchSize(50);

2 个回答

0

理论上来说,因为你的排序是根据主键进行的,所以结果不需要再排序,数据库其实可以直接按主键顺序返回数据。

我觉得一个优秀的数据库应该能意识到这一点,并进行优化。但看起来PGSQL(PostgreSQL)并没有做到这一点。*耸肩*

如果你使用LIMIT 100,你不会感觉到什么影响,因为从数据库中提取这100条结果非常快,即使在提取之前先把它们整理和排序,你也不会感觉到延迟。

我建议你试着去掉ORDER BY。很有可能你的结果本来就会按时间正确排序(根据你的主键,可能还有一些标准或规范要求这样),这样你可能会更快得到结果。

4

psycopg2这个数据库驱动在返回任何数据之前,会先把整个查询结果都缓存在内存里。这意味着如果你想逐步获取结果,就需要使用服务器端游标。关于SQLAlchemy的相关信息,可以查看文档中的服务器端游标,如果你在使用ORM(对象关系映射),可以参考Query.yield_per()方法

目前,SQLAlchemy没有为单个查询设置这个选项,但有一个相关的工单,里面有实现这个功能的补丁

撰写回答