【问题标题】:Postgres JOIN on multiple possible columns with OR statementPostgres JOIN 在多个可能的列上使用 OR 语句
【发布时间】:2021-03-28 10:52:33
【问题描述】:

我有两个表要连接在一起:

contracts:

id customer_id_1 customer_id_2 customer_id_3 date
1 MAIN1 TRAN1 TRAN2 20201101
2 MAIN2 20201001
3 MAIN3 TRAN5 20200901
4 MAIN4 TRAN7 TRAN8 20200801

customers:

id customer_id info date
1 MAIN1 blah 20200930
2 TRAN2 blah 20200929
3 TRAN5 blah 20200831
4 TRAN7 blah 20200801

在我的contracts 表中,每一行代表与客户的合同,在customers 表中,他们可能有1 个或多个不同的ID。在customers 表中,我有关于客户的信息(可以是每个客户在不同日期的零个或多个记录)。我想执行从contractscustomers 的联接,以便在记录合同时获得有关客户的最新信息,而忽略合同日期之后可能可用的任何潜在客户信息。我也对没有客户信息的合同不感兴趣。这里的主要问题是,在customers 中,每个客户记录都可以引用可能存在的 3 个 ID 中的任何一个。

我目前有以下查询,它按预期执行任务,但问题是在 50-100k 行范围内的数据上运行时 非常 很慢。如果我删除 INNER JOIN 中的 OR 语句并仅加入第一个 ID,则查询会在几秒钟内执行,而不是大约半小时。

SELECT 
  DISTINCT ON (ctr.id) 
  ctr.id, 
  ctr.customer_id_1, 
  ctr.date AS contract_date, 
  cst.info, 
  cst.date AS info_date
FROM 
  contracts ctr
  INNER JOIN customers cst ON (
    cst.customer_id = ctr.customer_id_1
    OR cst.customer_id = ctr.customer_id_2
    OR cst.customer_id = ctr.customer_id_3
  )
  AND ctr.date >= cst.date
ORDER BY
  ctr.id,
  cst.date DESC

结果:

id customer_id_1 contract_date info info_date
1 MAIN1 20201101 blah 20200930
3 MAIN3 20200901 blah 20200831
4 MAIN4 20200801 blah 20200801

似乎JOINs 中的OR 语句不是很常见(我几乎没有在网上找到任何示例),我认为这是因为必须有更好的方法来做到这一点。所以我的问题是,如何优化?

【问题讨论】:

    标签: sql postgresql datetime inner-join greatest-n-per-group


    【解决方案1】:

    OR 通常是 SQL 谓词中的性能杀手。

    加入前的另一种反透视:

    select distinct on (ctr.id) 
        ctr.id, 
        ctr.customer_id_1, 
        ctr.date as contract_date, 
        cst.info, 
        cst.date as info_date
    from contracts ctr
    cross join lateral (values 
        (ctr.customer_id_1), (ctr.customer_id_2), (ctr.customer_id_3)
    ) as ctx(customer_id)
    inner join customers cst on cst.customer_id = ctx.customer_id and ctr.date >= cst.date
    order by  ctr.id, cst.date desc
    

    使用这种技术可以极大地改进数据模型:合同和客户之间的关系应该存储在单独的表中,每个客户/合同元组位于单独的行中 - 本质上,查询的作用是在横向连接中虚拟构建派生表。

    【讨论】:

    • 感谢@GMB!你绝对是正确的数据模型 - 不幸的是我无法控制它!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 2016-05-02
    • 2017-11-16
    相关资源
    最近更新 更多