Один из вариантов был таким:
SELECT DISTINCT t1.*
FROM logs t1
JOIN logs t2
ON t1.id > t2.id AND t1.dt < t2.dt;
⚠️Но посмотрим на план запроса (читаем снизу вверх, смотрим на cost):
HashAggregate (cost=92291..92294)
Group Key: t1.id, t1.dt
-> Nested Loop (cost=0..89454)
Join Filter
-> Seq Scan on logs t1 (cost=0..33)
-> Materialize
-> Seq Scan on logs t2
Здесь очень дорогой Nested Loop Join, который увеличил косты с 33 до 90к.
✅Что ожидалось увидеть?
Используем lag/lead и сравниваем разницу айдишников с предыдущим и последующим:
WITH diffs AS (
SELECT
*,
id - LAG(id) OVER(ORDER BY dt) prev_diff,
id - LEAD(id) OVER(ORDER BY dt) next_diff
FROM logs
)
SELECT id, dt
FROM diffs
WHERE prev_diff > 1 or next_diff > 1;
План запроса:
Subquery Scan on diffs (cost=159..249)
Filter
-> WindowAgg
-> Sort
Sort Key: logs.dt
-> Seq Scan on logs
В первом случае примерные косты были 90к, во втором 250 => в 370 раз меньше.
✨Также нам необязательно знать все id поздних записей, достаточно найти границы диапазонов✨