如何在有序的sql列上执行批量更新?

时间:2014-05-26 22:12:03

标签: sql postgresql sql-update

我正在使用PostgreSQL,并有一个名为table_all的表,有500万行和这种结构:

id|source_id|destination_id|some_flag
1 | 12      |  13          |  NULL
2 | 12      |  14          |  NULL
...

另一个表table_flag具有相同的行数和以下结构:

id|some_flag
1 | true
2 | false
...

我需要使用some_flag中的值在table_all中设置table_flag。如果我发表如下声明:

UPDATE table_all set some_flag = table_flag.some_flag 
from table_flag 
where table_all.id = table_flag.id

需要几个小时,我需要经常执行此操作。这两个表按id排序,这是唯一的,两个表都有所有id。直觉上,在some_flag中使用table_all中的值设置table_flag只需执行从table_flagtable_all的批量复制。有没有办法做到这一点?

3 个答案:

答案 0 :(得分:0)

如果该标志确实是一个布尔列,我建议使用默认值和子查询的组合,如:

UPDATE table_all SET some_flag = True WHERE id IN (SELECT id FROM table_flag WHERE some_flag=True)

编辑:删除语句“table_all上的非聚集索引(id,some_flag)可能会有所帮助。”因为安德鲁指出,索引bool列不是一个好主意。

答案 1 :(得分:0)

如果您的更新是 incremental (例如,主表中的大多数标志不为空),请使用此查询:

update table_all 
set some_flag = table_flag.some_flag 
from table_flag 
where 
    table_all.id = table_flag.id
    and (table_all.some_flag isnull
        or table_all.some_flag <> table_flag.some_flag);

如果主表中的所有(或主要部分)标志为空,您可以尝试使用游标:

do $$
declare  
    cur cursor for select id, some_flag from table_flag;
    rec record;
begin
    for rec in cur loop
        update table_all 
        set some_flag = rec.some_flag 
        where 
            table_all.id = rec.id
            and (table_all.some_flag isnull
                or table_all.some_flag <> rec.some_flag);
    end loop;
end $$;

答案 2 :(得分:0)

防止实际上没有改变任何东西的“空更新”,但同样昂贵,因为Postgres无论如何都需要插入新的行版本。

UPDATE table_all a
SET    some_flag = f.some_flag 
FROM   table_flag f
WHERE  a.id = f.id
AND    a.some_flag IS DISTINCT FROM f.some_flag;

对于可以为NULL的列,请使用IS DISTINCT FROM 对于已定义的列,NOT NULL <> 就足够了。

另外,there is no "order" in a database table,你有一个基本的误解。索引可以提供很多帮助,但无论如何都必须处理所有行。

您应该更改工作流程,以便能够选择要更新的几行。即使使用改进的查询,您当前的方法效率也非常低。