Jak zmusić Postgresa do korzystania z indeksu, jeśli w przeciwnym razie nalegałby na skanowanie sekwencyjne?
sql
postgresql
indexing
mikrofon
źródło
źródło
Odpowiedzi:
Zakładając, że pytasz o typową funkcję „podpowiedzi do indeksu”, którą można znaleźć w wielu bazach danych, PostgreSQL nie zapewnia takiej funkcji. To była świadoma decyzja podjęta przez zespół PostgreSQL. Dobry przegląd tego, dlaczego i co można zamiast tego zrobić, można znaleźć tutaj . Powody są po prostu takie, że jest to hack wydajnościowy, który zwykle powoduje więcej problemów później, gdy zmieniają się dane, podczas gdy optymalizator PostgreSQL może ponownie ocenić plan na podstawie statystyk. Innymi słowy, to, co dziś może być dobrym planem zapytań, prawdopodobnie nie będzie dobrym planem zapytań na zawsze, a wskazówki dotyczące indeksu wymuszają określony plan zapytań na zawsze.
Jako bardzo tępy młotek, przydatny do testowania, możesz użyć parametrów
enable_seqscan
ienable_indexscan
. Widzieć:enable_
parametrySą to nie nadaje się do ciągłego użytku produkcyjnego . Jeśli masz problemy z wyborem planu zapytań, powinieneś zapoznać się z dokumentacją dotyczącą śledzenia problemów z wydajnością zapytań . Nie ustawiaj parametrów
enable_
i nie odchodź.Jeśli nie masz bardzo dobrego powodu do korzystania z indeksu, Postgres może dokonywać właściwego wyboru. Czemu?
Zobacz także ten stary post na grupie dyskusyjnej .
źródło
Prawdopodobnie jedyny ważny powód do używania
jest wtedy, gdy piszesz zapytania i chcesz szybko sprawdzić, jaki byłby plan zapytań, gdyby w tabelach były duże ilości danych. Lub oczywiście, jeśli chcesz szybko potwierdzić, że Twoje zapytanie nie korzysta z indeksu tylko dlatego, że zbiór danych jest zbyt mały.
źródło
set enable_seqscan=false
, uruchom zapytanie, a następnie szybko uruchom,set enable_seqscan=true
aby przywrócić poprawne zachowanie postgresql (i oczywiście nie rób tego na produkcji, tylko w fazie rozwoju!)SET SESSION enable_seqscan=false
aby wpływać tylko na siebieCzasami PostgreSQL nie dokonuje najlepszego wyboru indeksów dla określonego warunku. Na przykład załóżmy, że istnieje tabela transakcji z kilkoma milionami wierszy, których jest kilkaset na dany dzień, a tabela ma cztery indeksy: identyfikator_transakcji, identyfikator_klienta, datę i opis. Chcesz uruchomić następujące zapytanie:
PostgreSQL może zdecydować się na użycie indeksu transaction_description_idx zamiast transaction_date_idx, co może spowodować, że zapytanie zajmie kilka minut zamiast mniej niż jednej sekundy. W takim przypadku możesz wymusić korzystanie z indeksu w dniu, modyfikując warunek w następujący sposób:
źródło
your_wanted_index
, może być tak, że silnik postgresql po prostu wykona zamiast tego skanowanie sekwencji / klucza podstawowego. Wniosek - nie ma w 100% niezawodnej metody na wymuszenie użycia indeksu na serwerze PostgreSql.where
warunku, ale są dwie tabele lub połączone, a Postgres nie może pobrać indeksu.Krótka odpowiedź
Ten problem zwykle występuje, gdy szacowany koszt skanowania indeksu jest zbyt wysoki i nie odzwierciedla prawidłowo rzeczywistości. Może być konieczne obniżenie
random_page_cost
parametru konfiguracyjnego, aby to naprawić. Z dokumentacji Postgres :Możesz sprawdzić, czy niższa wartość faktycznie spowoduje, że Postgres użyje indeksu (ale używaj go tylko do testowania ):
Możesz przywrócić wartość domyślną
SET random_page_cost = DEFAULT;
ponownie za pomocą .tło
Skanowanie indeksu wymaga niesekwencyjnego pobierania stron z dysku. Postgres używa
random_page_cost
do oszacowania kosztu takich niesekwencyjnych pobrań w stosunku do kolejnych pobrań. Wartość domyślna to4.0
, zakładając zatem średnią współczynnik kosztu wynosi 4 w porównaniu do pobierania sekwencyjnego (biorąc pod uwagę efekty buforowania).Problem polega jednak na tym, że ta wartość domyślna jest nieodpowiednia w następujących ważnych scenariuszach z życia wziętych:
1) Dyski półprzewodnikowe
Jak przyznaje dokumentacja:
Zgodnie z ostatnim punktem tego slajdu z przemówienia na PostgresConf 2018,
random_page_cost
powinno być ustawione na coś pomiędzy1.0
a2.0
dla dysków półprzewodnikowych.2) Dane w pamięci podręcznej
Jeśli wymagane dane indeksu są już buforowane w pamięci RAM, skanowanie indeksu będzie zawsze znacznie szybsze niż skanowanie sekwencyjne. Dokumentacja mówi:
Problem polega na tym, że oczywiście nie możesz łatwo dowiedzieć się, czy odpowiednie dane są już w pamięci podręcznej. Jeśli jednak często zadawane są zapytania o określony indeks, a system ma wystarczającą ilość pamięci RAM, dane prawdopodobnie zostaną zapisane w pamięci podręcznej i
random_page_cost
powinny mieć niższą wartość. Będziesz musiał eksperymentować z różnymi wartościami i zobaczyć, co działa w Twoim przypadku.Możesz także chcieć użyć rozszerzenia pg_prewarm do jawnego buforowania danych.
źródło
Pytanie samo w sobie jest bardzo niepoprawne. Wymuszanie (na przykład przez wykonanie enable_seqscan = off) jest bardzo złym pomysłem. Warto sprawdzić, czy będzie szybszy, ale kod produkcyjny nigdy nie powinien wykorzystywać takich sztuczek.
Zamiast tego - wyjaśnij analizę swojego zapytania, przeczytaj je i dowiedz się, dlaczego PostgreSQL wybiera zły (Twoim zdaniem) plan.
Istnieją narzędzia w internecie, że pomoc przy czytaniu wyjaśnić analizować wyjście - jeden z nich jest explain.depesz.com - napisany przeze mnie.
Inną opcją jest dołączenie do kanału #postgresql w sieci irc freenode i rozmowa z gośćmi, którzy mogą Ci pomóc - ponieważ optymalizacja zapytania nie polega na „zadaniu pytania, uzyskaj odpowiedź, bądź szczęśliwy”. bardziej przypomina rozmowę, w której trzeba sprawdzić wiele rzeczy, wiele się nauczyć.
źródło
Istnieje sztuczka polegająca
OFFSET 0
na tym, aby popchnąć postgres, aby preferował seqscan, dodając a w podzapytaniuJest to przydatne do optymalizacji żądań łączących duże / ogromne tabele, gdy potrzebujesz tylko n pierwszych / ostatnich elementów.
Powiedzmy, że szukasz pierwszych / ostatnich 20 elementów obejmujących wiele tabel zawierających 100 tys. (Lub więcej) wpisów, nie ma sensu budować / łączyć całego zapytania ze wszystkimi danymi, gdy to, czego szukasz, znajduje się w pierwszych 100 lub 1000 wpisy. Na przykład w tym scenariuszu okazuje się, że skanowanie sekwencyjne przebiega ponad 10 razy szybciej.
zobacz Jak mogę uniemożliwić Postgresowi wstawianie podzapytania?
źródło