我想知道CURSOR
和FETCH
在PostgreSQL
内部如何工作。
首先,我认为
使用CURSOR
语句声明select
时,DB将执行select
语句,然后将结果存储在DB内存中。
在FETCH
上调用CURSOR
时,DB只会读取在CURSOR
上移动的结果。
关闭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秒。
答案 0 :(得分:1)
在当前实现中,由保留的游标表示的行 被复制到临时文件或存储区中,以便它们保留 可用于后续交易。
这取决于您是使用单个交易中的游标还是使用“保持”和多个交易。
如果使用“ 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
但是,例如,如果您所使用的查询要求在最后一步进行排序,则无论如何必须首先获取所有行以对其进行排序。