游标和获取如何在PostgreSQL中工作

时间:2018-12-31 13:41:50

标签: postgresql cursor

我想知道CURSORFETCHPostgreSQL内部如何工作。

首先,我认为

  1. 使用CURSOR语句声明select时,DB将执行select语句,然后将结果存储在DB内存中。

  2. FETCH上调用CURSOR时,DB只会读取在CURSOR上移动的结果。

  3. 关闭CURSOR后,存储的结果将从内存中删除。

如果我的假设正确,则FETCH的响应时间应该短,而不管select语句的复杂程度如何。

但是,当我测试时,FETCH的响应时间比我预期的要差,就像它做了我没想到的事情。

它们如何工作?

---------编辑---------

以下是我用实际数据库表进行测试时得到的结果。 (select语句包含3个表的join子句,其中一个表具有300万行)

(   8sec) DECLARE “123" NO SCROLL CURSOR WITH HOLD FOR SELECT .....
(0.04sec) FETCH FORWARD 2 FROM "123";
(   4sec) FETCH FORWARD 10000 FROM "123";

---------编辑---------

FETCH FORWARD 10000 FROM "123"中4秒钟的响应时间似乎是由于我使用的pgcli(PostgreSQL客户端工具)造成的。

我不知道为什么,但是更改客户端工具后,速度显然可以达到0.04秒。

1 个答案:

答案 0 :(得分:1)

SQL Commands: DECLARE

  

在当前实现中,由保留的游标表示的行   被复制到临时文件或存储区中,以便它们保留   可用于后续交易。

这取决于您是使用单个交易中的游标还是使用“保持”和多个交易。

如果使用“ WITH HOLD”,则在名为“ DECLARE”的事务的“ COMMIT”上,将使用来自游标的所有数据创建一个临时表。如果数据量很大,则表会保存到磁盘,因此获取起来会有些慢。但这并不慢,因为这应该是对一定数量的行进行顺序扫描。

tometzky=> begin;
BEGIN
Time: 0.301 ms
tometzky=> declare c no scroll cursor with hold for select pg_sleep(1) from generate_series(1,6);
DECLARE CURSOR
Time: 1.140 ms
tometzky=> commit;
COMMIT
Time: 6007.180 ms (00:06.007)
tometzky=> fetch forward 3 from c;
 pg_sleep 
----------



(3 rows)

Time: 0.384 ms
tometzky=> fetch forward 3 from c;
 pg_sleep 
----------



(3 rows)

Time: 0.336 ms
tometzky=> fetch forward 3 from c;
 pg_sleep 
----------
(0 rows)

Time: 0.338 ms

当您使用来自称为DECLARE的同一事务中的游标时,每个FETCH将在请求的行数可用时立即返回:

tometzky=> begin;
BEGIN
Time: 0.301 ms
tometzky=> declare c no scroll cursor for select pg_sleep(1) from generate_series(1,6);
DECLARE CURSOR
Time: 1.225 ms
tometzky=> fetch forward 3 from c;
 pg_sleep 
----------



(3 rows)

Time: 3004.041 ms (00:03.004)
tometzky=> fetch forward 3 from c;
 pg_sleep 
----------



(3 rows)

Time: 3003.855 ms (00:03.004)
tometzky=> fetch forward 3 from c;
 pg_sleep 
----------
(0 rows)

Time: 0.229 ms
tometzky=> commit;
COMMIT
Time: 0.444 ms

但是,例如,如果您所使用的查询要求在最后一步进行排序,则无论如何必须首先获取所有行以对其进行排序。