萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL GROUP BY 排序陷阱:子查詢法獲取各組最新記錄

問題現場

表 posts(id, tid, subject, message, dateline),需查每個主題(tid)的最新回覆(dateline 最大)。

直覺寫法:

SELECT * FROM posts GROUP BY tid LIMIT 10;

錯誤結果:返回每組**第一行**(最早回覆),非最新。

原因分析

MySQL GROUP BY 不保證組內行順序,預設取組內第一行(通常是最早插入)。ORDER BY 在 GROUP BY 之後執行,無法影響組內選取。

正確解法

方法一:子查詢先排序再分組(最直觀)

SELECT * FROM (
    SELECT * FROM posts ORDER BY dateline DESC
) AS p
GROUP BY tid
ORDER BY dateline DESC
LIMIT 10;

原理:內層按時間倒序,外層 GROUP BY 取每組第一行即最新。

方法二:聚合函數配合 JOIN(效能較好)

SELECT p.* FROM posts p
JOIN (
    SELECT tid, MAX(dateline) AS max_dt FROM posts GROUP BY tid
) latest ON p.tid = latest.tid AND p.dateline = latest.max_dt
ORDER BY p.dateline DESC
LIMIT 10;

方法三:窗口函數(MySQL 8.0+ 推薦)

WITH ranked AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY tid ORDER BY dateline DESC) AS rn
    FROM posts
)
SELECT * FROM ranked WHERE rn = 1 ORDER BY dateline DESC LIMIT 10;

效能對比建議

方法適用版本效能備註
子查詢法所有版本中大表需覆蓋索引 (tid, dateline)
JOIN 聚合所有版本較好利用索引掃描,推薦 5.7
窗口函數8.0+最佳語法清晰,優化器支援好

索引建議

CREATE INDEX idx_tid_dateline ON posts(tid, dateline DESC);

延伸:錯誤 GROUP BY + ORDER BY 寫法

-- 錯誤:order by 作用於分組後結果,不影響組內選取
SELECT * FROM posts GROUP BY tid ORDER BY dateline DESC;

-- 正確:用聚合函數
SELECT * FROM posts GROUP BY tid ORDER BY MAX(dateline) DESC;
copyright © 萬盛學電腦網 all rights reserved