哪个查询更有效?内部加入vs子查询?总和案例与

时间:2015-04-05 09:20:08

标签: sql database postgresql query-optimization

我正在使用PostgreSql 9.我有一个简单的问题。 哪个查询更有效?

SELECT users_sessions.session_id, users_sessions.series 
FROM users_sessions 
WHERE users_sessions.user_id = 8 
AND users_sessions.session_id IN (
    SELECT session_id 
    FROM sessions_history 
    GROUP BY sessions_history.session_id 
    HAVING SUM(CASE WHEN sessions_history.action = 2 THEN 1 END) = 0
) 

VS

SELECT US8.session_id,Us8.series

FROM

( SELECT us.session_id as S_ID, us.series 
        FROM users_sessions as US
        WHERE US.user_id = 8 ) AS US8
INNER JOIN
(SELECT SH.session_id as SH_ID
        FROM session_history as SH
        WHERE SH.action <> 2) AS SH2    
ON US8.session_id = SH2.session_id 

4 个答案:

答案 0 :(得分:1)

您的第二个查询 在语法上无效。您无法在SELECT子句中的HAVING列表(&#34;输出列&#34;)中引用列别名。

无论哪种方式,两个查询都不好。如果您确实想要找到不存在的(user_id, action)组合,请尝试改为:

SELECT t.*, 0 AS s
FROM  (SELECT 8 AS user_id, 2 AS action) t
LEFT  JOIN (
            users_sessions  us
       JOIN session_history sh USING (session_id)
           ) USING (user_id, action)
WHERE  sh.session_id IS NULL;

我将子查询tLEFT JOIN中的单行的派生表引入到两个基表的组合中。如果组合,则仅返回一行。 假设列名user_idaction在两个表中只出现一次。否则,对第二个连接使用更明确的条件:

ON t.user_id = us.user_id AND t.action = sh.action

详细说明:

替代

可能更快,但是:

SELECT t.*, 0 AS s
FROM  (SELECT 8 AS user_id, 2 AS action) t
LEFT   JOIN users_sessions  us USING (user_id)
LEFT   JOIN session_history sh USING (action, session_id)
WHERE  sh.session_id IS NULL;

在此示例中,USING构造是安全的。

答案 1 :(得分:1)

另一种解决方案使用NOT EXISTS,它是您似乎要求的精确翻译:

给我没有行动2的会议:

SELECT session_id, series 
FROM users_sessions as us
WHERE users_sessions.user_id = 8 
AND NOT EXISTS
 (  SELECT * 
    FROM sessions_history as sh
    WHERE action = 2
    AND us.session_id = sh.session_id 
 ) 

答案 2 :(得分:1)

我的值得一提;

我可以用两种不同的方式解释你的意图,并为每个提供不同的解决方案(我的首选解决方案在每种情况下都是第一个);


至少有一条历史记录的会话,其中的操作&lt;&gt; 2
(而不关心有多少历史记录,其中action = 2)

SELECT
    us.session_id,
    us.series
FROM
    users_sessions   AS us
INNER JOIN
    session_history  AS sh
        ON  sh.session_id  = us.session_id
        AND sh.action     <> 2
WHERE
    us.user_id = 8
GROUP BY
    us.session_id,
    us.series

SELECT
    us.session_id,
    us.series
FROM
    users_sessions   AS us
WHERE
        us.user_id = 8
    AND EXISTS (SELECT *
                  FROM session_history  AS sh
                 WHERE sh.session_id  = us.session_id
                   AND sh.action     <> 2
               )

SELECT
    us.session_id,
    us.series
FROM
    users_sessions   AS us
INNER JOIN
(
    SELECT
        session_id
    FROM
        session_history
    WHERE
        sh.action <> 2
    GROUP BY
        session_id
)
    AS sh
        ON  sh.session_id  = us.session_id
WHERE
    us.user_id = 8


没有历史记录的会话记录where action = 2
(但可以有其他历史记录)

SELECT
    us.session_id,
    us.series
FROM
    users_sessions   AS us
LEFT JOIN
    session_history  AS sh
        ON  sh.session_id = us.session_id
        AND sh.action     = 2
WHERE
        us.user_id     = 8
    AND sh.session_id IS NULL

-- No GROUP BY needed this time

SELECT
    us.session_id,
    us.series
FROM
    users_sessions   AS us
WHERE
        us.user_id = 8
    AND NOT EXISTS (SELECT *
                     FROM session_history  AS sh
                     WHERE sh.session_id = us.session_id
                       AND sh.action     = 2
                   )

答案 3 :(得分:0)

您如何看待这个?

SELECT US8.session_id,Us8.series

FROM

( SELECT us.session_id as S_ID, us.series 
        FROM users_sessions as US
        WHERE US.user_id = 8 ) AS US8
INNER JOIN
(SELECT SH.session_id as SH_ID
        FROM session_history as SH
        WHERE SH.action <> 2) AS SH2    
ON US8.session_id = SH2.session_id