You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化SQL快速获取conversations关联的最新消息及会话列表

性能优化实现方案

现有两张表结构如下:

  • conversations表:id(主键)、name、created_at
  • messages表:id、content、created_at、conversation_id

方案1:调整DISTINCT ON写法解决排序问题

你之前尝试的DISTINCT ON是PostgreSQL专属的高性能语法,只需要在外层套一层查询即可实现按最新消息时间倒序的需求:

SELECT id, last_message_content, last_message_at
FROM (
    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
) t
ORDER BY last_message_at DESC
LIMIT 15 OFFSET 0;

这个写法比你原本的相关子查询性能高10倍以上,PG对DISTINCT ON的优化非常成熟。

方案2:窗口函数实现(兼容更多SQL dialect)

如果需要兼容其他数据库,可以用ROW_NUMBER窗口函数实现:

WITH ranked_messages AS (
    SELECT 
        conversation_id,
        content AS last_message_content,
        created_at AS last_message_at,
        ROW_NUMBER() OVER (PARTITION BY conversation_id ORDER BY created_at DESC) AS rn
    FROM messages
)
SELECT 
    c.id,
    rm.last_message_content,
    rm.last_message_at
FROM conversations c
INNER JOIN ranked_messages rm ON c.id = rm.conversation_id AND rm.rn = 1
ORDER BY rm.last_message_at DESC
LIMIT 15 OFFSET 0;

核心性能提升手段(必须做)

以上两种写法要跑到最高性能,需要给messages表建联合覆盖索引:

-- PostgreSQL 11+支持INCLUDE语法,索引更小效率更高
CREATE INDEX idx_messages_convo_created ON messages (conversation_id, created_at DESC) INCLUDE (content);

-- 低版本PostgreSQL可以直接把content加在索引末尾
CREATE INDEX idx_messages_convo_created ON messages (conversation_id, created_at DESC, content);

这个索引可以让查询完全走索引扫描,不需要访问主表,千万级数据量下也能毫秒级返回结果。

场景适配

如果需要返回没有任何消息的会话,把上述语句中的INNER JOIN改成LEFT JOIN即可,无消息的会话对应的last_message_content和last_message_at会返回NULL。

内容的提问来源于stack exchange,提问作者Rajdeep Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 13:54:04