代码之家  ›  专栏  ›  技术社区  ›  SangminKim

PostgreSQL中的cursor和fetch是如何工作的

  •  2
  • SangminKim  · 技术社区  · 5 年前

    我想知道怎么做 CURSOR FETCH 在内部工作 PostgreSQL .

    起初,我以为

    1. 什么时候? 光标 声明时使用 select 语句,db将执行 选择 语句,然后将结果存储在数据库内存中。

    2. 什么时候? 在上调用 光标 ,db将只读取移动到 光标 .

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

    如果我的假设是正确的, 应该有很短的响应时间,不管 选择 语句很复杂。

    但是,当我测试的时候, 表现出比我预期的差的响应时间,就像它做了一些我没有预料到的事情。

    它们是如何工作的?

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

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

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

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

    4秒响应时间 FETCH FORWARD 10000 FROM "123" 似乎是因为 pgcli (PostgreSQL客户机工具)我用过。

    我不知道为什么,但在更改客户机工具后,它显然快到了0.04秒。

    1 回复  |  直到 5 年前
        1
  •  1
  •   Tometzky    5 年前

    SQL Commands: DECLARE :

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

    这取决于您是从单个事务使用光标,还是使用“保留”和多个事务。

    如果使用“WITHHOLD”,那么在调用“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的同一事务中的光标时,一旦请求的行数可用,每个提取都将返回:

    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
    

    但是,例如,如果您使用的查询最后一步需要排序,那么无论如何,它必须先获取所有行才能对它们进行排序。