3

以前可能有人问过这个问题,但是在谷歌上搜索“IN”之类的关键字效果并不好。

这是我的查询:

UPDATE tblCustomer SET type = 2 
WHERE idcustomer                                
IN (SELECT fidcustomer1
    FROM tblorder                   
     UNION                      
    SELECT fidcustomer2
    FROM tblorder                   
   )                                

将其分解:我想将出现在订单表中的所有客户的所有客户的类型(只是一个 int)设置为 2,位于任一列中。

在我的测试数据中,这些表中没有一个包含超过几百行,但是查询运行了很多分钟(即使没有 UNION,这似乎也没有太大区别),显然是重新执行内部查询在客户中每行一次。我显然可以将它重写为一个 SELECT DISTINCT(id),然后进行几百次单行更新,并以我用于 ODBC 访问的任何语言执行逻辑,但这只是一个 hack。

我怎样才能正确地重写它?

附录:我要更新的表包含很多相对较大的 BYTEA blob,每行几 MB。它们设置为外部存储或扩展,但我想知道这是否会使顺序扫描变慢。所有更新似乎都需要很长时间,而不仅仅是这个。

4

2 回答 2

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表达式执行得更好。

于 2012-11-14T11:16:13.270 回答
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 构造固有的删除重复阶段(可能还有排序)。

于 2012-11-14T11:43:00.180 回答