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

含50万行messages表的MySQL查询耗时超15秒,求优化方案

MySQL慢查询优化方案

原查询耗时高核心原因

  • 嵌套相关子查询逐行执行:外层每返回1条role_users符合条件的数据,就要对50万行的messages表执行2次独立查询,外层如果返回N条数据,总共要执行2*N次messages表扫描,IO开销极高
  • 缺少必要的覆盖索引,关联过滤字段无索引时每次查询都会触发全表扫描
  • 多余的DISTINCT关键字:如果role_users表的id是主键/唯一键,DISTINCT完全多余,反而会增加排序去重的额外开销

第一步:新增覆盖索引(必做)

直接在对应表添加联合索引,让查询可以直接走索引无需回表读数据:

-- 覆盖最新消息时间查询逻辑,匹配OR条件两端的关联字段+排序字段
CREATE INDEX idx_messages_from_to_created ON messages(from_role_user_id, to_role_user_id, created_at DESC);
-- 覆盖未读消息计数查询逻辑,包含所有过滤条件字段
CREATE INDEX idx_messages_unread_count ON messages(from_role_user_id, to_role_user_id, is_read);
-- 覆盖外层角色用户表的过滤条件
CREATE INDEX idx_role_users_filter ON role_users(is_deleted, chat_status, user_name, role_id);
-- 覆盖角色表关联和名称过滤
CREATE INDEX idx_roles_name ON roles(name, id);

第二步:改写SQL逻辑,替换相关子查询为预聚合JOIN

将原本逐行执行的子查询改为提前一次性聚合messages表数据,仅扫描2次messages表即可完成所有计算:

SELECT 
    ur.id, ur.user_name AS name, ur.online, ur.chat_status,
    ur.updated_at, ur.profile_image, ur.role_id,
    msg_agg.last_msg_at AS message_at,
    COALESCE(unread_agg.unread_count, 0) AS count,
    r.name AS role
FROM role_users ur
LEFT JOIN roles r ON r.id = ur.role_id
-- 预聚合所有用户的最新消息时间
LEFT JOIN (
    SELECT 
        user_id,
        MAX(created_at) AS last_msg_at
    FROM (
        SELECT from_role_user_id AS user_id, created_at FROM messages
        UNION ALL
        SELECT to_role_user_id AS user_id, created_at FROM messages
    ) t
    GROUP BY user_id
) msg_agg ON msg_agg.user_id = ur.id
-- 预聚合所有发给用户1的未读消息计数
LEFT JOIN (
    SELECT 
        from_role_user_id AS user_id,
        COUNT(*) AS unread_count
    FROM messages
    WHERE to_role_user_id = 1 AND is_read = 0
    GROUP BY from_role_user_id
) unread_agg ON unread_agg.user_id = ur.id
WHERE 
    ur.id != 1
    AND r.name IN ('superadmin', 'candidate', 'admin', 'manager', 'business_unit','client')
    AND ur.chat_status != 'offline'
    AND ur.is_deleted = 0
    AND ur.user_name IS NOT NULL
ORDER BY message_at DESC
LIMIT 10;

优化效果说明

优化后messages表的扫描次数从2*N次降低到固定2次,配合覆盖索引可以完全避免回表,查询耗时通常可以降到1秒以内,逻辑和原查询完全一致。

内容的提问来源于stack exchange,提问作者Nijesh W

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 02:06:04