之前可能已经提出过这个问题,但谷歌搜索“IN”这样的关键字效果不佳。
这是我的疑问:
UPDATE tblCustomer SET type = 2
WHERE idcustomer
IN (SELECT fidcustomer1
FROM tblorder
UNION
SELECT fidcustomer2
FROM tblorder
)
要将其分解:我想将所有客户的类型(只是一个int)设置为2,对于出现在order-table中的所有客户,在任一列中。
在我的测试数据中,这些表中没有一行包含超过几百行,但查询运行了很多分钟(即使没有UNION,这似乎没有太大区别),显然是重做客户中每行一次的内部查询。我显然可以将它重写为单个SELECT DISTINCT(id),然后是几百个单行更新,并使用我用于ODBC访问的任何语言来执行逻辑,但这只是一个黑客攻击。
如何正确地重写?
附录:我要更新的表包含很多相对较大的BYTEA blob,每行几MB。它们被设置为Storage External或Extended,但我想知道这是否会使顺序扫描变慢。所有更新似乎都需要很长时间,而不仅仅是这一次。
答案 0 :(得分:5)
我建议采用一种更简单的方法:
UPDATE tblCustomer c
SET type = 2
FROM tblorder o
WHERE c.idcustomer IN (o.fidcustomer1, o.fidcustomer2)
AND c.type IS DISTINCT FROM 2 -- optional, to avoid empty updates
除非tblorder
中有重复,否则您采用的方法与您的方法类似:
UPDATE tblCustomer c
SET type = 2
FROM (
SELECT fidcustomer1 AS cust FROM tblorder
UNION
SELECT fidcustomer2 FROM tblorder
) o
WHERE c.idcustomer = o.cust
AND c.type IS DISTINCT FROM 2;
无论哪种方式,在PostgreSQL中,加入表定期执行比IN
表达更好。
答案 1 :(得分:4)
-------------------------------
-- Use two EXISTS:
-------------------------------
UPDATE tblCustomer tc
SET type = 2
WHERE EXISTS (
SELECT *
FROM tblorder ex
WHERE ex.fidcustomer1 = tc.idcustomer
)
OR EXISTS (
SELECT *
FROM tblorder ex
WHERE ex.fidcustomer2 = tc.idcustomer
);
-------------------------------
-- or combine the two EXISTS::
-------------------------------
UPDATE tblCustomer tc
SET type = 2
WHERE EXISTS (
SELECT *
FROM tblorder ex
WHERE ex.fidcustomer1 = tc.idcustomer
OR ex.fidcustomer2 = tc.idcustomer
);
我的直觉是第一个版本(存在两个独立的版本)会表现得更好,因为如果其中一个存在会产生True
,执行者可以短路。这将避免重复删除阶段(可能是排序),这是UNION构造所固有的。