运营要「最近一单」,同事写了 select * from orders order by create_time desc limit 1,在 200 万行的表上跑了六秒。explain 一看,type 是 ALL,create_time 上根本没有索引。

按自增主键取,几乎不花钱

如果业务上的最新就是最后插入的那条,直接按主键倒序。聚簇索引末尾的一条,走反向扫描,几十毫秒就回来,这是最省的一招。

SELECT * FROM orders ORDER BY id DESC LIMIT 1;

按时间字段排,先把索引补上

用 create_time 排序时给这个字段建索引,最好做成 create_time 加 id 的联合索引,排序和回表都能用上。只建单列也能去掉 filesort,但回表的开销省不掉。

SELECT * FROM orders ORDER BY create_time DESC, id DESC LIMIT 1;

id 要一起写进 order by,create_time 相同的两条记录,谁排前面是不确定的,分页时容易重复或漏行。

每组取最新,别拿 max 硬套

按用户分组取每人最后一单,常见写法是先查最大 id 再关联回去。数据量不大时够用,子查询会被物化成临时表,行数一多就开始慢。

SELECT o.* FROM orders o JOIN (SELECT user_id, MAX(id) AS mid FROM orders GROUP BY user_id) t ON o.id = t.mid;

MySQL 8 可以直接用窗口函数,逻辑清楚得多,代价是多扫一遍数据。

SELECT * FROM (SELECT o.*, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY id DESC) AS rn FROM orders o) x WHERE rn = 1;

我的判断是:取单条最新就用 order by 加 limit,成本最低;分组取最新在千万级表上别指望一条 SQL 解决,加一个标记字段维护起来更省心。