對齊日期用 self-join,對齊前後順序用視窗函數
「跟前一筆比」這種需求有兩種完全不同的語意,選錯工具會安靜地算出錯的答案——問題不是效能,是語意。
兩種語意
- 絕對值對齊(前一天、上一個月、某個特定 id)→ self-join。
ON a.d = b.d + 1是拿日期數值去對齊,中間漏掉的那天就 join 不上。要的就是「沒有前一天的資料就不算」時,這個漏接是正確行為。 - 前後順序對齊(上一筆、下一筆,不管中間隔多久)→ 視窗函數。
LAG(x) OVER (ORDER BY d)撈的是排序後的相鄰列,不看數值差距。用 self-join 做這件事根本寫不出來——你不知道該+1還是+3。
先問「中間漏一天時,這兩筆該不該被視為相鄰」,答案直接決定用哪個。
順帶的成本差異
- self-join 的本質是把一張表當兩張配對:join 欄位有索引時很快,沒索引會退化成 O(n²)(JOIN 貴在每一列都要去另一張表配對)。
LAG/LEAD只需掃描 + 排序一次,約 O(n log n),在大表無索引時反而穩。
但別讓成本先決定語意:語意錯的快答案沒有價值。語意允許兩種寫法時,再拿索引狀況和資料量來挑,跟 同一個寫法在互動式列表沒事,在全量掃描必爆 是同一種判斷順序。
其他優點
self-join 是最老的語法,舊版資料庫 100% 支援、優化器對它的索引利用也最成熟;視窗函數需要 MySQL 8+ 之類的較新環境。