在 MySQL 中LEFT JOIN默认会匹配 B 表中所有符合条件的记录导致结果集膨胀一对多。如果你只想关联 B 表中的第一条记录通常指按某个字段排序后的第一条如时间最新或 ID 最小有几种实现方案取决于你的 MySQL 版本和对“第一条”的定义。假设场景A 表(id,name)B 表(id,a_id,create_time,content)目标A 表左连接 B 表每个 A 只对应 B 中create_time最新的那一条。方案一使用窗口函数ROW_NUMBER()(推荐MySQL 8.0)这是最标准、性能最好且语义最清晰的方法。通过子查询给 B 表数据打排行号只取排名第 1 的。SELECT a.*, b.content, b.create_time FROM table_a a LEFT JOIN ( SELECT *, ROW_NUMBER() OVER (PARTITION BY a_id ORDER BY create_time DESC) as rn FROM table_b ) b ON a.id b.a_id AND b.rn 1;原理PARTITION BY a_id表示按 A 表 ID 分组ORDER BY create_time DESC表示组内按时间倒序rn 1即取最新的一条。优点逻辑严密性能优秀。要求MySQL 8.0 及以上版本。方案二子查询 二次关联 (兼容 MySQL 5.7 及以下)老版本 MySQL 不支持窗口函数。通常的做法是先在子查询中找出每个a_id对应的 B 表主键 ID如最大 ID 或最早时间对应的 ID然后再关联 B 表获取详细信息。SELECT a.*, b.content, b.create_time FROM table_a a LEFT JOIN ( -- 第一步找出每个 a_id 对应的目标 B 表 ID (这里假设 ID 越大时间越新) SELECT a_id, MAX(id) as b_id FROM table_b GROUP BY a_id ) tmp ON a.id tmp.a_id LEFT JOIN table_b b ON tmp.b_id b.id;原理先通过GROUP BY缩小 B 表范围到“每个 A 对应一条 B 的 ID再根据 ID 关联回 B 表拿详情。注意如果“第一条”不是由主键 ID 决定的比如是按create_time子查询里需要用SUBSTRING_INDEX(GROUP_CONCAT(...))或者关联查询来定 ID但那样性能较差。通常建议业务上保证 ID 自增且与时间正相关。优点兼容性好所有 MySQL 版本可用。方案三如果不关心具体哪一条只要任意一条 (MySQL 5.7)如果你不需要特定的排序比如不需要最新的只要是 B 表里的某一条就行可以使用ANY_VALUE配合GROUP BY。SELECT a.id, a.name, ANY_VALUE(b.content) as content, -- 任意取一个值 ANY_VALUE(b.create_time) as time FROM table_a a LEFT JOIN table_b b ON a.id b.a_id GROUP BY a.id;原理强制将结果按 A 表 ID 分组ANY_VALUE告诉 MySQL 从 B 的多条记录中随便选一个不报错。优点写法最简单通常性能最快。缺点数据不确定每次查询可能取到不同的 B 记录。方案四关联子查询 (不推荐用于大数据量)直接在ON或WHERE中使用子查询限制。SELECT a.*, b.* FROM table_a a LEFT JOIN table_b b ON a.id b.a_id AND b.id ( SELECT id FROM table_b WHERE a_id a.id ORDER BY create_time DESC LIMIT 1 );缺点这是相关子查询对于 A 表的每一行B 表都要执行一次查询。数据量大时性能极差N1 问题生产环境慎用。总结与建议首选如果你的数据库是MySQL 8.0请务必使用方案一 (ROW_NUMBER)。兼容如果是MySQL 5.7且“第一条”可以通过主键 ID 大小判断使用方案二。性能优化确保 B 表的关联字段a_id和排序字段create_time或id上有索引。例如ALTER TABLE table_b ADD INDEX idx_a_id_time (a_id, create_time DESC);这对方案一和方案二都有极大帮助。示例索引创建-- 针对方案一和方案二的优化索引 CREATE INDEX idx_b_aid_ontime ON table_b (a_id, create_time DESC);