Czy REINDEX jest niebezpieczny?

17

Próbowałem COUNT(*)uzyskać tabelę ze 150 000 wierszy z kluczem podstawowym. Narzędzie to trwa około 5 minut, więc zorientowałem się, że jest to problem z indeksowaniem.

Powołując się na instrukcję PostgreSQL :

REINDEX jest podobny do upuszczania i ponownego tworzenia indeksu, ponieważ zawartość indeksu jest odbudowywana od zera. Jednak względy blokowania są raczej różne. REINDEX blokuje zapisy, ale nie odczytuje tabeli nadrzędnej indeksu. Pobiera także wyłączną blokadę na konkretnym przetwarzanym indeksie, który blokuje odczyty, które próbują użyć tego indeksu (...) Kolejne polecenie UTWÓRZ INDEKS blokuje zapisy, ale nie odczytuje; ponieważ indeksu nie ma, żaden odczyt nie będzie próbował go użyć, co oznacza, że ​​nie będzie blokowania, ale odczyty mogą zostać wymuszone na drogie sekwencyjne skany.

Czy na podstawie własnego doświadczenia potrafisz powiedzieć:

  • jest REINDEXINGniebezpieczny? Czy może to zaszkodzić spójności danych?
  • Czy to może zająć dużo czasu?
  • Czy to prawdopodobne rozwiązanie mojego scenariusza?

Aktualizacja:

Rozwiązaniem, które działało dla nas, było odtworzenie tego samego indeksu o innej nazwie, a następnie usunięcie starego indeksu.

Tworzenie indeksu jest bardzo szybkie i zmniejszyliśmy rozmiar indeksu z 650 MB do 8 MB. Używanie COUNT(*)z betweenzajmuje tylko 3 sekundy.

Adam Matan
źródło

Odpowiedzi:

15

Ponowne indeksowanie nie jest niebezpieczne i nie może zaszkodzić spójności danych. Jeśli jednak masz czas krytyczny, możesz stracić dane, jeśli tabela jest zablokowana, a DML jest przerywany.

Ponowne indeksowanie nie powinno zająć dużo czasu, ale zwykle wymaga odczytywania całej tabeli, sortowania pól indeksu i pisania nowego indeksu. Biorąc pod uwagę czas COUNT(*), prawdopodobnie zajmie to pięć minut lub więcej.

Jest mało prawdopodobne, że jest to problem z indeksowaniem. COUNT(*)powinien użyć skanowania tabeli, w którym to przypadku nie jest odczytywany indeks. Spodziewałbym się, że masz jakiś problem z IO.

Spróbuj użyć COUNT(1)lub, COUNT(pk_field)który może korzystać z indeksu.

Jeśli korzystasz z platformy Unix lub Linux, możesz chcieć monitorować aktywność dysku sar. Być może masz wadliwy dysk, który może znacznie obniżyć stawki IO.

Tabele z dużymi obiektami mogą również znacznie zwiększyć IO, aby utworzyć rekordy dla COUNT (*).

BillThor
źródło
2
Według wiki.postgresql.org COUNT(*)jest najlepszym wyborem:If you are using count(*), the database is free to use any column to count, which means it can pick the smallest covering index to scan (note that this is why count(*) is much better than count(some_field), as long as you don't care if null values of some_field are counted). Since indexes often fit entirely in memory, this means count(*) is often very fast.
orange80
1

Nie jestem pewien najlepszej odpowiedzi dla ciebie. Jednak ten wątek wydaje się oferować kilka dobrych sugestii: n http://postgresql.1045698.n5.nabble.com/count-performance-issue-td2067873.html

Jedna uwaga jest taka, że ​​można zaimplementować WYZWALACZ, aby zachować liczbę wierszy w osobnej tabeli (jeśli aplikacje będą wywoływać COUNT (*)).

Kilka odpowiedzi sugeruje, że jest to objaw bazy danych, która nie została ostatnio wystarczająco odkurzona (sugerując, że autovacuum jest wyłączone na twoim serwerze lub w szczególności dla tej bazy danych)?

Inna sugestia wygląda następująco:

ANALYZE tablename;
SELECT reltuple FROM pg_class WHERE relname = 'tablename';

A ktoś zidentyfikowany jako A. Kretschmer zauważa:

Nie. Bieżąca implementacja indeksu nie zawiera informacji o widoczności wierszy w bieżącej transakcji. Musisz zeskanować całą tabelę danych, aby sprawdzić, czy bieżący wiersz jest widoczny w bieżącej transakcji.

... popierając mój komentarz o uprawnieniach na poziomie wiersza, które są problemem dotyczącym wydajności.

Moje wyszukiwanie pokazało również WikiVS: MySQL vs. PostgreSQL: COUNT (*) .

Możesz przejrzeć inne wyniki, które znalazłem, używając Google: wydajność licznika postgresql (*)

Jim Dennis
źródło