我正在使用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_flag
到table_all
的批量复制。有没有办法做到这一点?
答案 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,你有一个基本的误解。索引可以提供很多帮助,但无论如何都必须处理所有行。
您应该更改工作流程,以便能够选择要更新的几行。即使使用改进的查询,您当前的方法效率也非常低。