mysql取最新一条数据
昨天同事问我:“MySQL里怎么取最新的最新一条数据?”他有个订单表,想查某个用户最近一笔订单。条数这问题看着简单,最新但真写起来,条数坑不少。最新 最直觉的条数写法是 所以稳妥点: 如果表数据量不大,比如几千行,上面写法随便跑。但订单表动辄千万级, 还有一种情况:要取每个用户的最新一条。这就不是简单 这相关子查询在MySQL 5.7里性能堪忧,每行都要执行一次。MySQL 8.0可以用窗口函数: 窗口函数写法清晰,但执行时仍要排序全表。数据量大时,更实际的做法是建一张“用户最新订单”的冗余表,用触发器或应用层双写维护。牺牲一点写入性能,换查询的极致速度。很多电商系统就这么干的。 另外提个醒: 这语句在 我自己的习惯:单用户取最新一条,永远写 写SQL跟写代码一样,能跑和跑得对是两码事。尤其“最新一条”这种需求,边界情况比想象中多。多花五分钟想清楚排序字段的唯一性,比事后查数据错乱强。ORDER BY create_time DESC LIMIT 1。没错,最新大部分场景这就够了。条数可如果create_time只精确到秒,最新同一秒内有两笔订单呢?条数你拿到的可能是任意一条。MySQL不保证相同排序值的最新返回顺序,除非你再加个id DESC做二级排序。条数我见过线上事故就是最新这么来的——用户投诉“最近订单显示错了”,查半天发现是条数时间戳精度问题。ORDER BY create_time DESC,最新 id DESC LIMIT 1。id是自增主键的话,它天然反映了插入顺序。这招在分页场景也常用,叫“游标分页”或者“seek method”,比OFFSET高效得多。不过这是另一个话题了。ORDER BY加LIMIT如果没走对索引,就是全表扫描加文件排序。我试过一张八百万行的表,没索引时查一次要四秒多。加了(user_id, create_time)联合索引后,降到几毫秒。注意索引列顺序——WHERE user_id = ? ORDER BY create_time DESC,索引得是(user_id, create_time),反过来不行。LIMIT能解决的了。常见写法是子查询:SELECT * FROM orders o WHERE o.id = ( SELECT id FROM orders WHERE user_id = o.user_id ORDER BY create_time DESC, id DESC LIMIT 1 );SELECT * FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY create_time DESC, id DESC ) AS rn FROM orders ) t WHERE rn = 1;GROUP BY配合MAX(create_time)是经典错误写法。SELECT user_id, MAX(create_time), order_no FROM orders GROUP BY user_id;ONLY_FULL_GROUP_BY模式下直接报错。就算关掉这个模式,order_no也不保证来自create_time最大的那行。MySQL文档明确说了,非聚合列的值是不确定的。别赌运气。ORDER BY create_time DESC, id DESC LIMIT 1,并且确认WHERE条件能命中索引。批量取最新,优先考虑窗口函数,数据量再大就上冗余表。至于GROUP BY加MAX,见到就改,没商量。
-
上一篇
-
下一篇