Indeksy
Twórz indeksy na x.id
i y.id
- które prawdopodobnie już masz, jeśli są to twoje klucze podstawowe.
Indeks wielokolumnowy też może pomóc, szczególnie z skanowania tylko do indeksowania
na stronie 9.2+:
CREATE INDEX y_mult_idx ON y (id DESC, val)
Jednak w moich testach ten wskaźnik nie był początkowo używany. Musiałem dodać (inaczej bez sensu) val
do ORDER BY
aby przekonać planistę zapytań, że kolejność sortowania jest zgodna. Zobacz zapytanie 3 .
Indeks nie ma większego znaczenia w tej syntetycznej konfiguracji. Ale w przypadku tabel z większą liczbą kolumn pobieranie val
z tabeli staje się coraz droższy, dzięki czemu indeks „pokrywania” staje się bardziej atrakcyjny.
Zapytania
1) Prosty
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;
Więcej wyjaśnień techniki z DISTINCT
w tej powiązanej odpowiedzi:
Przeprowadziłem kilka testów, ponieważ miałem podejrzenia, że pierwsze zapytanie nie będzie się dobrze skalować. Jest szybki przy małym stole, ale nie jest dobry przy większych stołach. Postgres nie optymalizuje planu i zaczyna od (ograniczonego) połączenia krzyżowego, którego koszt to O(N²)
.
2) Szybko
To zapytanie jest nadal dość proste i doskonale skaluje się:
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;
Funkcja okna lead()
jest instrumentalny. Korzystam z opcji, aby zapewnić domyślną osłonę narożnej wielkości ostatniego wiersza:2147483647
to największa możliwa liczba całkowita
. Dostosuj się do swojego typu danych.
3) Bardzo proste i prawie tak samo szybkie
SELECT x.id
,(SELECT val FROM y WHERE id <= x.id ORDER BY id DESC, val LIMIT 1) AS val
FROM x;
Zwykle skorelowane podzapytania są powolne. Ale ten może po prostu wybrać wartość z indeksu (pokrywającego), a poza tym jest tak prosty, że może konkurować.
Dodatkowe ORDER BY
element val
(wytłuszczone podkreślenie) wydaje się bezcelowe. Jednak dodanie go przekonuje planistę zapytań, że można użyć indeksu wielokolumnowego y_mult_idx
z góry, ponieważ kolejność sortowania jest zgodna. Zwróć uwagę na
w EXPLAIN
wyjście.
Przypadek testowy
Po ożywionej debacie i wielu aktualizacjach zebrałem wszystkie wysłane do tej pory zapytania i stworzyłem przypadek testowy do szybkiego przeglądu. Używam tylko 1000 wierszy, więc SQLfiddle nie przekracza limitu czasu przy wolniejszych zapytaniach. Ale top 4 (Erwin 2, Clodoaldo, a_horse, Erwin 3) skaluje się liniowo we wszystkich moich lokalnych testach. Zaktualizowano jeszcze raz, aby uwzględnić mój najnowszy dodatek, poprawić format i kolejność według wydajności:
Wielkie skrzypce SQL porównywanie wydajności.