Индекси
Създайте индекси на x.id
и y.id
- които вероятно вече имате, ако това са вашите първични ключове.
Индекс с няколко колони също може да помогне, особено с сканира само за индекс
в стр. 9.2+:
CREATE INDEX y_mult_idx ON y (id DESC, val)
Въпреки това, в моите тестове, този индекс не беше използван в началото. Трябваше да добавя (иначе безсмислено) val
към ORDER BY
за да убеди планиращия заявки, че редът на сортиране съвпада. Вижте запитване 3 .
Индексът прави малка разлика в тази синтетична настройка. Но за таблици с повече колони, извличане на val
от таблицата става все по-скъп, което прави "покриващия" индекс по-привлекателен.
Заявки
1) Просто
SELECT DISTINCT ON (x.id)
x.id, y.val
FROM x
JOIN y ON y.id <= x.id
ORDER BY x.id, y.id DESC;
Повече обяснение за техниката с DISTINCT
в този свързан отговор:
Проведох някои тестове, защото имах подозрения, че първата заявка няма да се мащабира добре. Бързо е с малка маса, но не е добро с по-големи маси. Postgres не оптимизира плана и започва с (ограничено) кръстосано свързване с цена O(N²)
.
2) Бързо
Тази заявка все още е доста проста и се мащабира отлично:
SELECT x.id, y.val
FROM x
JOIN (SELECT *, lead(id, 1, 2147483647) OVER (ORDER BY id) AS next_id FROM y) y
ON x.id >= y.id
AND x.id < y.next_id
ORDER BY 1;
Прозоречната функция lead()
е инструментален. Използвам опцията за предоставяне по подразбиране, за да покрия ъгловия регистър на последния ред:2147483647
е най-голямото възможно цяло число
. Адаптиране към вашия тип данни.
3) Много просто и почти толкова бързо
SELECT x.id
,(SELECT val FROM y WHERE id <= x.id ORDER BY id DESC, val LIMIT 1) AS val
FROM x;
Обикновено свързани подзаявки са склонни да бъдат бавни. Но този може просто да избере стойност от (покриващия) индекс и иначе е толкова прост, че може да се конкурира.
Допълнителният ORDER BY
елемент val
(удебелено подчертаване) изглежда безсмислено. Но добавянето му убеждава планиращия заявки, че е добре да се използва индексът с няколко колони y_mult_idx
отгоре, защото редът на сортиране съвпада. Обърнете внимание на
в EXPLAIN
изход.
Тестов случай
След оживен дебат и множество актуализации събрах всички запитвания, публикувани досега, и направих тестов случай за бърз преглед. Използвам само 1000 реда, така че SQLfiddle не изчаква с по-бавните заявки. Но първите 4 (Erwin 2, Clodoaldo, a_horse, Erwin 3) се мащабират линейно във всичките ми локални тестове. Актуализиран още веднъж, за да включва най-новото ми допълнение, подобряване на формата и подреждане по ефективност сега:
Голям SQL Fiddle сравняване на ефективността.