【发布时间】: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 表中,我有关于客户的信息(可以是每个客户在不同日期的零个或多个记录)。我想执行从contracts 到customers 的联接,以便在记录合同时获得有关客户的最新信息,而忽略合同日期之后可能可用的任何潜在客户信息。我也对没有客户信息的合同不感兴趣。这里的主要问题是,在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