Sql Postgres复杂的完全外部联接,使空值与;关于;柱

Sql Postgres复杂的完全外部联接,使空值与;关于;柱,sql,postgresql,join,Sql,Postgresql,Join,我已经编写了一个PostgresSQL查询,它在规模上的性能相对较好,并提供了我想要的数据集,但我想知道这是否是编写查询的最简单/最好的方法。似乎应该有一个更简单的连接操作来满足我需要的条件 编辑:我确实需要在大型表上执行此操作。在下面给出的例子中,宠物是1.5亿行,食物大约是10万行。我在底部的解决方案以大约0.6ms的速度计时。这两个表都有一个id和用户id索引。食品表还包括一个宠物id索引 我的系统中有两个相关的表,它们有一个保证共享的属性-user_id。下面的示例本质上说明了我的问题:

我已经编写了一个PostgresSQL查询,它在规模上的性能相对较好,并提供了我想要的数据集,但我想知道这是否是编写查询的最简单/最好的方法。似乎应该有一个更简单的连接操作来满足我需要的条件

编辑:我确实需要在大型表上执行此操作。在下面给出的例子中,宠物是1.5亿行,食物大约是10万行。我在底部的解决方案以大约0.6ms的速度计时。这两个表都有一个id和用户id索引。食品表还包括一个宠物id索引

我的系统中有两个相关的表,它们有一个保证共享的属性-user_id。下面的示例本质上说明了我的问题:

宠物

+------+-------+---------+
|  id  | type  | user_id |
+------+-------+---------+
| 1234 | dog   |       1 |
| 1235 | cat   |       1 |
| 1236 | gecko |       1 |
+------+-------+---------+
+------+------+
| p.id | f.id |
+------+------+
| NULL | 4321 |  --no pet, hamburger
| 1234 | 4322 |  --dog, dog food
| 1235 | 4323 |  --cat, cat food
| 1236 | NULL |  --gecko, no food
+------+------+
食物

+------+-----------+---------+--------+
|  id  |   name    | user_id | pet_id |
+------+-----------+---------+--------+
| 4321 | hamburger |       1 | NULL   |
| 4322 | dog food  |       1 | 1234   |
| 4323 | cat food  |       1 | 1235   |
+------+-----------+---------+--------+
期望的结果

+------+-------+---------+
|  id  | type  | user_id |
+------+-------+---------+
| 1234 | dog   |       1 |
| 1235 | cat   |       1 |
| 1236 | gecko |       1 |
+------+-------+---------+
+------+------+
| p.id | f.id |
+------+------+
| NULL | 4321 |  --no pet, hamburger
| 1234 | 4322 |  --dog, dog food
| 1235 | 4323 |  --cat, cat food
| 1236 | NULL |  --gecko, no food
+------+------+
现在,通过一个例子,我将确定结果是什么。结果包含来自两侧的所有属于我的user_id的行(假设该表可能包含数千个不属于user_id 1的其他行)。我希望这些结果行只包含与另一个表匹配的每一行的一个副本

我尝试使其工作的完整外部联接示例:

SELECT p.id, f.id
FROM pets p FULL OUTER JOIN food f ON p.user_id = f.user_id
WHERE p.user_id = 1;
这个查询有点问题,因为

  • 它从查询的左侧排除
    NULL
    s。我需要这些
  • 因为user_id在这里基本上是常量,所以我得到了大量的重复项,因为它与user_id匹配。左侧的每一行都与右侧的每一行匹配。不是我需要的。我需要一对一的比赛
  • 我可以通过在
    的WHERE
    过滤器中包含
    来修复#1:

    SELECT p.id, f.id
    FROM pets p FULL OUTER JOIN food f ON p.user_id = f.user_id
    WHERE p.user_id = 1 OR f.user_id = 1;
    
    由于我不能完全确定的原因,这使得查询花费了很长时间。在我们的系统中,两个表都有一个关于用户id的索引,因此并不缺少索引

    为了解决我的问题,我使用了以下查询(实际上是两个查询的组合):


    所以我的问题是:有没有一种更简单的方法可以将其作为一个查询来执行?

    您只是想得有点过头了。您想在
    P.ID=F.PET\u ID
    加入:

    SELECT P.ID, F.ID
    FROM PETS P
    FULL OUTER JOIN FOOD F ON P.ID = F.PET_ID
                          AND P.USER_ID = F.USER_ID
                          AND P.USER_ID = 1 --optional                          
    ORDER BY P.ID
    

    SELECT p.id, f.id
    FROM pets p 
    FULL OUTER JOIN food f 
      ON p.user_id = f.user_id
     AND p.id = f.pet_id
     AND p.user_id = 1;
    
    输出

    |     id |     id |
    |--------|--------|
    |   1234 |   4322 |
    |   1235 |   4323 |
    |   1236 | (null) |
    | (null) |   4321 |
    
    注意:


    您应该在两个表的
    (user\u id,pet\u id)
    上添加一个复合索引。

    您是否分别尝试了这两个查询?性能问题应包括
    EXPLAIN ANALYZE
    和一些关于表大小、索引、当前时间性能、期望时间等的信息。
    Slow
    是一个相对术语,我们需要一个实际值进行比较。感谢您的反馈!我确实分别尝试了这两个查询。它们的运行速度要快一点(加起来约0.3毫秒,而union为0.6毫秒)。我正在尝试将数据集返回到我的应用程序,以保存数据的后期处理/缝合。我在顶部稍微编辑了一下这个问题,添加了一个关于表大小和当前时间性能的注释。期望的性能将类似于当前的性能。我只是想知道我是否错过了一个更直接的方法来实现同样的效果。非常感谢你的回答。不幸的是,这在我看来有点慢。我对问题进行了编辑,以便更清楚地了解这一点。我尝试了这个查询,花了122057毫秒(对两个表进行了顺序扫描)。@JustinR。请参见下面Juan的评论-复合索引应该可以加快速度。您需要在两个表的
    (user\u id,pet\u id)
    上创建一个复合索引。我认为这最好地回答了我的问题,包括了这个索引评论。介意把评论移到你的答案中,然后我会投票并标记为已接受吗?如果我留下评论,你会收到通知。如果我只是编辑答案,你不会。那么现在有多快?