2016-03-21 23 views
16

To pytanie dotyczy funkcji first_value(), używając innej funkcji lub obejścia problemu.Najlepsza wydajność w powtarzaniu próbkowania z kolumny zgrupowanej

Chodzi również o "niewielki wzrost wydajności" w dużych tabelach. Aby użyć np. max() w wyjaśnianym kontekście poniżej, wymaga fałszywych porównań. Nawet jeśli jest szybki, nakłada dodatkowe koszty.


Ten typowy zapytania

SELECT x, y, count(*) as n 
FROM t 
GROUP BY x, y; 

potrzeby powtórzyć wszystkie kolumny w GROUP BY wrócić więcej niż jedną kolumnę. Syntaktyczna cukier to zrobić, jest użycie referencji pozycyjnych:

SELECT x, y, count(*) as n 
FROM t 
GROUP BY x, 2 -- imagine that 2, 3, etc. are repeated with x 

Czasami potrzebuje nie tylko cukier, ale także niektóre semantyczny zrozumieć skomplikowany kontekst:

SELECT x, COALESCE(y,z), count(*) as n 
FROM t 
GROUP BY x, y, z -- y and z are not "real need" grouping clauses? 

Mogę sobie wyobrazić wiele innych złożonych kontekstów. Zobaczymy typowe rozwiązania:

SELECT x, max(y) as y, count(*) as n 
FROM t 
GROUP BY x -- best semantic! no need for other columns here 

gdzie max() funkcja może być każdy „próbka()” (na przykład pierwsza lub ostatnia wartość.). Działanie czegoś, co nie robi nic, jest lepsze niż max(), np. agregująca funkcja first_value(), ale potrzebuje ona WINDOW, więc straciła wydajność. Istnieją pewne stare sugestie: to implement first/last agg functions in C.

Czy istnieje funkcja agregująca "uzyskaj dowolną wartość szybko" o lepszej wydajności niż max() lub GROUP BY X,2,...?
Być może jakiś nowy element w najnowszym wydaniu?

+1

proszę [edytuj] Twoje pytanie i dodać kilka przykładowych danych i oczekiwaną produkcję w oparciu o te dane. 'max()' będzie dość szybkie, jeśli masz indeks na kolumnach. Możesz zajrzeć do 'limit' lub' distinct on() 'Również jeśli * nie * masz powolne zapytania, podaj zapytania, pełną definicję tabeli i plan wykonania używając' explain (analyze, verbose) ' –

+0

I don zrozumiałe, co masz na myśli przez funkcję 'max()' może być dowolną "próbką()". Czy chodziło Ci o "funkcję agregującą"? Również jeśli chodzi o to, jak sprawić, by funkcje agregujące były szybsze, co ma wspólnego z tym wprowadzenie do syntaktycznego cukru? –

+0

Istnieje sposób na emulację luźnego skanowania indeksu na postgresie, który byłby najszybszy https://wiki.postgresql.org/wiki/Loose_indexscan – Mihai

Odpowiedz

5

Nie jest oficjalnym źródłem, ale niektóre myśli an pytanie postrzegane jako raczej ogólna:

Ogólnie agregatorów neeed przetwarzać wszystkie pasujące wiersze. Z tekstu pytania możesz skierować agregatory, które próbują zidentyfikować określone wartości (maks., Min, pierwszy, ostatni, n-ty, itd.). Mogą one korzystać z baz danych, które zachowują właściwe wartości dla konkretnego takiego agregatora. Następnie "wybierając" tę wartość można przyspieszyć drastycznie.
E.g. niektóre bazy danych śledzą wartości maksymalne i minimalne kolumn.
Możesz zobaczyć to wsparcie jako wysoko wyspecjalizowane wewnętrzne indeksy, które są obsługiwane przez sam system, a nie pod (bezpośrednią) kontrolą użytkownika.

Teraz postgresql koncentruje się bardziej na pomocy, która pomaga w ulepszaniu zapytań w ogóle, a nie tylko w specjalnych przypadkach. W ten sposób unikają wysiłku w celu przyspieszenia specjalnych przypadków, które w oczywisty sposób nie przynoszą korzyści szerokiemu zakresowi zastosowań.

Powrót do przyspieszenia agregatorów wartości próbnych.

Z agregatory konieczności przetworzyć wszystkie wiersze w ogólnym przypadku nie hving ogólną strategię, która pozwala zwarcia że wymóg agregatory, które próbują identying konkretne wartości (agregatorów próbka rzeczowe dla teraz), to jest oczywiste, że wszelkie zmiany składu z kwerendy która nie prowadzi do zredukowanego zestawu wierszy, które muszą zostać przetworzone, zajmie podobny czas do zakończenia.

Do przyspieszenia takich zapytań poza przetwarzaniem wszystkich wierszy potrzebujesz bazy danych pomocniczych. W przypadku baz danych jest to zwykle udostępniane w formie indeksu.

Można również skorzystać ze specjalnych operacji wykonywania, które pozwalają zmniejszyć liczbę wierszy do odczytania.

Z pg masz możliwość zapewnienia własnej realizacji indeksu. Możesz więc dodać implementację, która najlepiej obsługuje specjalny rodzaj agregatora, który Cię interesuje. (Przynajmniej w przypadkach, gdy często trzeba uruchamiać takie zapytania).

Również operacje wykonawcze, takie jak indeks , skanują tylko lub leniwy ewaluacji z zapytaniami rekursywnymi może pozwolić na pisanie określonego zapytania w sposób, który przyspiesza w porównaniu do "prostego" kodowania.

Jeśli bardziej celujesz w swoje pytanie w ogólne podejście, możesz lepiej skonsultować się z badaczem w takich kwestiach, jak ten, to jest ponad wszystko, co SO ma zamiar zapewnić.

Jeśli masz konkretne (zestaw) zapytania, które wymagają poprawy, podanie jednoznacznych pytań może pomóc społeczności w zidentyfikowaniu potencjalnych optymalizacji. Próba optymalizacji bez dobrej bazy danych pomiarowych prowadzi do nikąd, ponieważ to, co daje doskonały wynik w jednym przypadku, może zabić wydajność w innym.

+0

Dzięki @rpy! czy możesz zilustrować przykładami kodu SQL? (lub cytowanie kontekstów według moich przykładów) –

+0

Naprawdę nie jestem przekonany, że pokazanie przykładów będzie pomocne w nieznanym scenariuszu. E.f mając indeks na 'kolumnie' przyspieszy zapytanie' select max (column) ... 'z powodu skanowania (tylko) indeksu. (Jedyna część ma zastosowanie tylko wtedy, gdy w tabeli jest więcej kolumn). Zmiana zapytania nieznacznie, aby uwzględnić warunek, np. 'Wybierz max (kolumna) z tabeli, w której inna kolumna = SOMEVALUE' może spowodować, że indeks będzie bezużyteczny. Wtedy może być potrzebne posiadanie 2 oddzielnych indeksów na dwóch kolumnach lub mających połączony indeks na "innej kolumnie, kolumnie". – rpy

+0

Cała sytuacja stanie się bardziej złożona, jak tylko sprzężenia zostaną wprowadzone do zapytania. Więc nie oczekuj ogólnej reguły, jeśli chcesz dobrej wydajności z SOMEAGGREGATE(), a następnie wykonaj następujące czynności ... __. Spójrz na swoje zapytanie, sprawdź plany zapytań, możesz określić rozkłady skorelowanych wartości (nie są dostępne ze statystyk pg), a następnie rozpocznij optymalizację. – rpy

7

Jeśli naprawdę nie obchodzi których członkiem zestawu jest zrywane, a jeśli nie trzeba obliczyć dodatkowych agregatów (jak liczyć), jest szybka i prosta alternatywa z DISTINCT ON (x)bezORDER BY:

SELECT DISTINCT ON (x) x, y, z FROM t; 

x, y i z są z tego samego rzędu, ale rząd jest dowolna wybrać z każdego zestawu wierszy z tym samym x.

Jeśli jednak potrzebujesz zliczenia, twoje opcje dotyczące wydajności są ograniczone, ponieważ cała tabela musi zostać odczytana w obu przypadkach. Mimo to, można połączyć go z funkcji okna w tym samym SELECT:

SELECT DISTINCT ON (x) x, y, z, count(*) OVER (PARTITION BY x) AS x_count FROM t; 

Rozważmy sekwencję zdarzeń w SELECT zapytania:

W zależności od wymagań, nie może być szybszym sposobem na uzyskanie zliczeń:

W połączeniu z GROUP BY jedyną realistyczną opcją widzę zdobyć wydajność jest first_last_agg extension. Ale nie oczekuj zbyt wiele.

Dla innych przypadków użycia bez liczenia (w tym prosty przypadek na górze), istnieją szybsze rozwiązania, w zależności od konkretnego przypadku użycia. W szczególności, aby uzyskać "pierwszą" lub "ostatnią" wartość każdego zestawu. Emuluj luźne skanowanie indeksu.(Podobnie jak @Mihai commented):

+0

Jeszcze raz dziękuję. Testuję [first_last_agg] (http://pgxn.org/dist/first_last_agg/), wydaje mi się, czego potrzebuję (!) ... Wtedy wrócę tu (za kilka dni), aby skomentować to i twoją dyskusję. –

+1

... Jestem [czekają na pierwszą recenzję w Github] (https://github.com/wulczer/first_last_agg/issues/2) ... Ale zrób trochę pracy domowej: 'DISTINCT ON' nie jest bezpośrednim rozwiązaniem, ponieważ, jak skomentowałeś i [testowałem] (http://dba.stackexchange.com/q/133520/90651), nie optymalizuję "GROUP BY", ani nie usuwam kolumn z klauzuli. Idealnym rozwiązaniem był [cytowany przez Craiga] (http://stackoverflow.com/a/8373384/287948), jest "ANY_VALUE()" zdefiniowany w MySQL 5.7+, który oferuje poprawną semantyczną dla tego zadania (i SQL parser decyduje, czy użyje pierwszego, czy ostatniego jako próbki). –

+0

@PeterKrauss: Dodałem opcję łączenia agregatów z 'DISTINCT ON'. –

Powiązane problemy