CURSOR vs select语句在循环中

时间:2018-07-30 14:49:10

标签: postgresql plpgsql

我刚刚在另一个StackOverflow问题中看到了一个简单的示例,该问题使用游标在表中循环。我只会遍历选择查询的结果,而不是将选择查询包装在光标中。使用游标有什么优势?

(我无法在此处包括示例,因为StackOverflow认为我的问题主要是代码,并且需要更多详细信息。我之前遇到过这种令人讨厌的限制。如果我可以用几句话就可以清楚地问我的问题,应该能够。我将查看是否可以找到该问题的链接,如果可以,我将在此处添加该链接。)

这是我看到使用CURSOR的original question

2 个答案:

答案 0 :(得分:3)

  

使用游标有什么好处?

唯一的优点是您必须编写更多的代码(如果他们为每行代码付费)。

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
$$;

答案 1 :(得分:3)

有几种方法:

  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. 在PL / pgSQL中使用FOR r IN SELECT ... LOOP。实际上,这与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. 使用JOIN

    示例:

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

方法3是最容易想到的解决问题的方法,因为它导致大量的客户端-服务器往返,并使数据库解析大量的语句。 las,这通常是SQL新手解决问题的方式。我称它为“ 本地嵌套循环连接” 。 最重要的是,客户端软件通常会将第一个查询的完整结果集存储到内存中,这会导致另一个问题。

方法1.和2.是等效的,除了2.更优雅。它节省了往返行程,并在后台使用了准备好的语句,因此UPDATE不必一直都在分析。仍然,执行程序必须运行很多次,并且PL / pgSQL并不是特别快。这也是一种自家的嵌套循环联接。

方法4是可行的方法。不仅所有内容都可以在单个查询中运行,而且PostgreSQL可以使用更有效的联接策略(如果更好)。