Temat: [postgresql] Problem z indeksami
Marcin Frątczak:
Michał Z.:
Pierwsza sprawa... Kolejność kolumn wymienionych w indeksie ma znaczenie. Powiem więcej - ma podstawowe znaczenie. Ogólna zasada jest taka, że zaczyna się od kolumn, których wartości mają największy rozrzut.
Druga sprawa. Do optymalizacji liczników najlepiej sprawdza się kolumna z zestawem triggerów. Podejrzewam, że zestaw warunków jest dość standardowy i 2,3 kolumny w tabelce z kategoriami rozwiążą problem. Można dodać tabelkę w relacji 1:1, żeby zmieniać, tego co już działa. W ten sposób można "obskoczyć" to co jest najczęściej używane. Jak to jest zewnętrzny soft można "instead of" wrzucić dla zapytań, które wpadają do bazy. No, ale z tym to trzeba uważać.
Kolejnosc ktorych wartosci maja najwiekszy rozrzut czyli nie np wartosci boolean, tylko np kategorie typu integer gdzie kolumna moze miec wiele wartosci, tak?
Celem jest to, żeby zamiast bobrować po tabelce wyciągnąć potrzebne
dane - po to powstały indeksy. Problem jest taki, że wyciągnięcie
30% tabelki przez indeks jest o wiele droższe niż proste jej
przejrzenie seqscanem. PG ma tak, że jak uzna, że wyciągnie mniej
jak 2% danych to używa indeksu - jak nie - jedzie seqscanem. Dlatego
właśnie stawianie indeksu na kolumnie z True/False nie bardzo ma
sens. W ogólności... Jak indeks ma wiele kolumn to PG indeksuje je
jedna po drugiej. Czyli najpierw buduje indeks dla pierwszej kolumny,
potem dla danych, które odpowiadają poszczególnym wartościom z
pierwszej budowane są kolejne indeksy... Na przykładzie - mam klucz
obcy do kategorii i parę kolumn true/false - dla ustalenia uwagi:
active, block, stick. Jak dam boole najpierw zbuduje kolosalne
indeksy na każdym poziomie... i na koniec zrobi indeks dla
kategorii. Z grubsza podzieli tabelę na dwie części. Każdą wartość
z obu części musi pamiętać, bo przecież o to chodzi. Dalej dla
każdej części zrobi indeks dla kolejnego boola... Masakra. :) Jak
najpierw dam kategorię - pierwszy indeks potnie dane na drobne
kawałki, które potem będzie można w prosty sposób dodatkowo
poindeksować tymi boolami. Po co w ogóle robić indeks na boolach?
No bo skoro i tak jedzie po indeksie to szybciej mu będzie zrobić
ten krok, niż przeglądać dane sekwencyjnie. Tak, w ogólności :)
Inne rozwiązanie to indeks częściowy. Czyli indeksujemy tylko część
danych, spełniających warunek - np. active=true and blocked=false.
W ten sposób indeks będzie mniejszy, co jest plusem, poindeksowane
dane z założenia będą spełniać w/w warunek. Mam nadzieję, że nie
zanudziłem ;)
Ja wszystkie mozliwe kombinacje ile ogloszen jest wg danych warunkow zapisuje w innej tabeli. Przechowywana jest tam ilosc ogloszen wg kryteriow: state, type, category
Jak to ugryzc trigerem ? Aktualnie tabele z cachem licznika ma 18k rekordow. (Tyle kombinacji wyszlo)
Memcache to jest rozwiązanie. No, ale po restarcie system trochę
muli :) Triggerów robi się 3 - insert, update, delete. Są pola old
i new... Jest tylko jeden myk. Ważne, żeby w update zmieniać dane
w ściśle określonej kolejności. Najpierw zmieniany ma być rekord o
mniejszym id. Inaczej może być dead-lock i to taki parszywy, ciężki
do wytropienia. Ja bym zrobił osobną tabelę na te dane. Wrzuciłbym
te wszystkie rzeczy po których ma być wyliczany count i niech
jedzie. Triggery byłyby na ogłoszeniach. No, chyba że coś jeszcze
się zmienia. Nie wiem tylko, czy takie pełne liczniki są niezbędne.
Z doświadczenia wiem, że jest spora szansa, że ktoś tak sobie
powiedział tylko. W rzeczywistości liczba aktywnych, nie
skasowanych wiadomości w kategorii ma znaczenie. Pewnie jest coś,
czego nie wiem... chodzi mi o to, żeby się dobrze temu przyjrzeć,
bo koszty są spore, a znaczenie biznesowe - raczej niewielkie.
Jest jeszcze jedna rzecz. Jak baza liczy county to wtedy plus jest
taki, że jest jedno miejsce w systemie, gdzie są poprawne dane.
Minus jest taki, że to zwykle najbardziej obciążone miejsce i
wyciąganie jest kosztowne. Można aktualizować co jakiś czas. Typy,
kategorie raczej się nie zmieniają za często. Mogą siedzieć w
memcache. Aplikacja i tak wie kiedy dodaje, kasuje kategorię, więc
można sobie ze zmianami poradzić. Do tego coś co raz na 5 minut
aktualizuje ostatnio zmienione kategorie. Te triggery mogą wpisać
czas ostatniej zmiany - potem wystarczy wyciągnąć to co się zmieniło
od ostatniej aktualizacji. Można też zrobić wyjątek dla małych
kategorii - dla nich wyciągać co i raz. Zależy od założeń...
No to chyba tyle.