代码之家  ›  专栏  ›  技术社区  ›  ROBERT RICHARDSON

循环中的游标vs select语句

  •  1
  • ROBERT RICHARDSON  · 技术社区  · 6 年前

    我刚刚在另一个stackoverflow问题中看到了一个简单的例子,这个问题使用一个游标循环遍历一个表。我只需循环查看select查询的结果,而不是将select查询包装在游标中。使用光标有什么好处?

    (我不能在这里包括这个例子,因为stackoverflow认为我的问题主要是代码,需要更多的细节。我以前遇到过这种讨厌的限制。如果我能用几句话清楚地问我的问题,我应该能够。我会看看是否能找到这个问题的链接,如果可以,我会在这里添加链接。)

    这里是 original question 我看到光标用的地方。

    2 回复  |  直到 6 年前
        1
  •  3
  •   klin    6 年前

    使用光标有什么好处?

    唯一的好处是你必须写更多的代码(如果他们付钱给你每行代码)。

    do $$
    declare
        rec record;
        cur cursor for select i from generate_series(1, 3) i;
    begin
        open cur;
        loop
            fetch cur into rec;
            exit when rec is null;
            raise notice '%', rec.i;
        end loop;
        close cur;
    end
    $$;
    

    A loop through query results 只需打开(虚拟)光标,获取行,检查范围,需要时退出并为您关闭光标。

    do $$
    declare
        rec record;
    begin
        for rec in select i from generate_series(1, 3) i
        loop
            raise notice '%', rec.i;
        end loop;
    end
    $$;
    
        2
  •  3
  •   Laurenz Albe    6 年前

    有几种方法:

    1. 在pl/pgsql中使用显式游标并循环遍历它并处理每个结果行。

      例子:

      OPEN c FOR SELECT id FROM a WHERE ok;
      LOOP
         UPDATE b SET a_ok = TRUE WHERE a_id = c.id;
      END LOOP;
      
    2. 使用A FOR r IN SELECT ... LOOP 在pl/pgsql中。这实际上与1相同。更清晰的语法。

      例子:

      FOR c IN SELECT id FROM a WHERE ok LOOP
         UPDATE b SET a_ok = TRUE WHERE a_id = c.id;
      END LOOP;
      
    3. 运行一个 SELECT 不带游标的查询并在客户端处理每个结果行,可能为每个结果发出一个数据库查询。

      示例(伪代码):

      resultset := db_exec('SELECT id FROM a WHERE ok');
      while (resultset.next()) {
          db_exec('UPDATE b SET a_ok = TRUE WHERE a_id = ' || resultset.get('id'));
      }
      
    4. 使用A JOIN .

      例子:

      UPDATE b SET a_ok = TRUE
      FROM a
      WHERE a.id = b.a_id AND a.ok;
      

    方法3。是解决这个问题最糟糕的方法,因为它会导致大量的客户机-服务器往返,并且让数据库解析大量语句。 唉,这常常是sql新手们解决问题的方式。我称之为 自制嵌套循环连接 . 除此之外,客户端软件通常会将第一次查询的完整结果集捕获到内存中,这会导致另一个问题。

    方法1。2。是相等的,除了2。更优雅。它节省了往返行程,并在引擎盖下使用了准备好的语句,因此 UPDATE 不需要一直分析。尽管如此,执行器必须运行多次,而且众所周知,pl/pgsql不是特别快。它也是一种自制的嵌套循环连接。

    方法4就是方法。不仅所有东西都在一个查询中运行,而且postgresql还可以使用更有效的连接策略(如果这样做更好的话)。