Raj*_*ngh 10 sql postgresql greatest-n-per-group postgresql-performance postgresql-13
有两个表conversations和messages,我想获取对话及其最新消息的内容。
conversations- id(主键)、名称、创建时间
messages- id、内容、created_at、conversation_id
目前我们正在运行此查询来获取所需的数据
SELECT
conversations.id,
m.content AS last_message_content,
m.created_at AS last_message_at
FROM
conversations
INNER JOIN messages m ON conversations.id = m.conversation_id
AND m.id = (
SELECT
id
FROM
messages _m
WHERE
m.conversation_id = _m.conversation_id
ORDER BY
created_at DESC
LIMIT 1)
ORDER BY
last_message_at DESC
LIMIT 15
OFFSET 0
Run Code Online (Sandbox Code Playgroud)
上面的查询返回有效数据,但其性能随着行数的增加而降低。有没有其他方法可以提高性能来编写此查询?例如附加小提琴。
http://sqlfiddle.com/#!17/2decb/2
还尝试了已删除答案之一中的建议:
SELECT DISTINCT ON (c.id)
c.id,
m.content AS last_message_content,
m.created_at AS last_message_at
FROM conversations AS c
INNER JOIN messages AS m
ON c.id = m.conversation_id
ORDER BY c.id, m.created_at DESC
LIMIT 15 OFFSET 0
Run Code Online (Sandbox Code Playgroud)
http://sqlfiddle.com/#!17/2decb/5
但这个查询的问题是它不按 排序m.created_at。我希望结果集按以下顺序排序m.created_at DESC
由于结果中除了对话中的 id 之外没有选择任何列,因此您只能查询消息表以减少时间(查询 1)。如果可能存在conversation_id对话表中不可用的任何消息,并且您不想选择这些消息,那么您可以使用第二个查询。
架构和插入语句:
CREATE TABLE conversations
(
id INT,
name VARCHAR(200),
created_at DATE
);
INSERT INTO conversations VALUES (1, 'CONV1', '1 DEC 2021');
INSERT INTO conversations VALUES (2, 'CONV2', '1 DEC 2021');
CREATE TABLE messages
(
id INT,
content VARCHAR(200),
created_at DATE,
conversation_id INT
);
INSERT INTO messages VALUES (1, 'TEST 3', '12 DEC 2021', 1);
INSERT INTO messages VALUES (2, 'TEST 2', '11 DEC 2021', 1);
INSERT INTO messages VALUES (3, 'TEST 1', '10 DEC 2021', 1);
INSERT INTO messages VALUES (4, 'TEST CONV2 1', '10 DEC 2021', 2);
Run Code Online (Sandbox Code Playgroud)
询问:
WITH Latest_Conversation_Messages AS
(
SELECT
conversation_id, content, created_at,
ROW_NUMBER() OVER (PARTITION BY conversation_id ORDER BY created_at DESC) rn
FROM
messages
)
SELECT
conversation_id, content AS last_message_content,
created_at AS last_message_at
FROM
Latest_Conversation_Messages
WHERE
rn = 1
Run Code Online (Sandbox Code Playgroud)
输出:
| 对话id | 最后消息内容 | 最后一条消息的时间 |
|---|---|---|
| 1 | 测试3 | 2021-12-12 |
| 2 | 测试转换器2 1 | 2021-12-10 |
查询2:
WITH Latest_Conversation_Messages AS
(
SELECT
conversation_id, content, created_at ,
ROW_NUMBER() OVER (PARTITION BY conversation_id ORDER BY created_at DESC) rn
FROM
messages m
WHERE
EXISTS (SELECT 1 FROM conversations c
WHERE c.id = m.conversation_id)
)
SELECT
conversation_id, content AS last_message_content,
created_at AS last_message_at
FROM
Latest_Conversation_Messages
WHERE
rn = 1
Run Code Online (Sandbox Code Playgroud)
输出:
| 对话id | 最后消息内容 | 最后一条消息的时间 |
|---|---|---|
| 1 | 测试3 | 2021-12-12 |
| 2 | 测试转换器2 1 | 2021-12-10 |
db<>在这里摆弄
您是否尝试过横向连接?
SELECT
conversations.id,
m.content AS last_message_content,
m.created_at AS last_message_at
FROM "conversations"
INNER JOIN LATERAL (
SELECT content, created_at
FROM messages m
WHERE conversations.id = m.conversation_id
ORDER BY created_at DESC
FETCH FIRST 1 ROW ONLY
) m ON TRUE
ORDER BY last_message_at DESC
LIMIT 15 OFFSET 0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
373 次 |
| 最近记录: |