5

如果我有类似的查询

SELECT date_trunc('day', assigndate)e,
       count(CASE WHEN a.assigneeid = 65548
             AND a.assigneeid IN
               (SELECT userid
                FROM groupmembers
                WHERE groupid = 65553) THEN 1 ELSE NULL END) assigned,
       count(CASE WHEN a.assigneeid = 65548
             AND a.completedtime IS NOT NULL
             AND a.assigneeid IN
               (SELECT userid
                FROM groupmembers
                WHERE groupid = 65553) THEN 1 ELSE NULL END) completed
FROM ASSIGNMENT a
WHERE assigndate > CURRENT_TIMESTAMP - interval '20 days'
GROUP BY date_trunc('day',assigndate);

有问题的子查询是

SELECT userid
                FROM groupmembers
                WHERE groupid = 65553

那么由于子查询是not co-related针对父查询的,因此它将只执行一次并使用缓存的结果。但是由于子查询存在于查询中的 2 个位置,因此根据SQL plan,它被评估两次。有没有办法获得cache该子查询的结果并在两个位置都使用它?

子查询不能转换为连接,因为没有要连接的单个字段(也不能是无条件连接,因为计数会出错)

4

2 回答 2

12

您可以使用公用表 express ( WITH)

with cte as 
(
     SELECT userid FROM groupmembers WHERE groupid = 65553
)
SELECT 
    date_trunc('day', assigndate)e,  
    count(CASE WHEN a.assigneeid = 65548 AND a.assigneeid IN  
           (SELECT userid from cte) then 1 else null end) assigned,
...
于 2012-10-22T12:46:12.353 回答
1

您应该重写查询以消除子查询:

SELECT date_trunc('day', assigndate)e,
       sum(CASE WHEN a.assigneeid = 65548 and gm.userid is not null then 1 else 0
           end) as assigned,
       sum(CASE WHEN a.assigneeid = 65548 and a.completedtime IS NOT NULL and gm.userid is not null
                then 1 else 0
           end) as completed
FROM ASSIGNMENT a left outer join
     (select distinct userid
      from groupmembers
      where groupid = 65553
     ) gm
     on a.assigneeid = gm.userid
WHERE assigndate > CURRENT_TIMESTAMP - interval '20 days'
GROUP BY date_trunc('day',assigndate)
order by 1

一般来说,我认为在FROM(or WITH) 子句中保留表引用是一种很好的做法。很难遵循SELECT子句中子查询的逻辑。在这种情况下,子查询是如此相似,以至于它们实际上是在乞求组合成一个语句。

于 2012-10-22T14:03:14.010 回答