🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.bazy-danych
Article #194318

Re: PostgreSQL - jak zbudować optymalne zapytanie?

#194318
From: M.M.
Date: Fri, 13 Mar 2015 04:54
191 lines
9435 bytes
On Thursday, March 12, 2015 at 4:14:39 PM UTC+1, nk...@toya.net.pl wrote:
> W dniu czwartek, 12 marca 2015 13:22:41 UTC+1 użytkownik M.M. napisał:
> > On Thursday, March 12, 2015 at 8:48:10 AM UTC+1, nk...@toya.net.pl wrote:
> > > W dniu poniedziałek, 9 marca 2015 12:23:28 UTC+1 użytkownik M.M. napisał:
> > > > 
> > > > Sorki, ale nadal nie kumam.
> > > > Testujesz najpierw:
> > > > where x < 5;
> > > > A potem:
> > > > where x < 5 AND x < 6 OR x < 5;
> > > > 
> > > > Wyszły Ci czasy t1 i t2. Załóżmy że t1<t2 to co wywnioskujesz? I na
> > > > odwrót, że t1>t2.
> > >  
> > > Po prostu sprawdzasz czy system poprzestaje na sprawdzeniu
> > > pierwszego członu warunku i dalej już nie sprawdza np.:
> > > 
> > > if (p1<>NULL and p2=p3)  czas wykonania ~0,03 sek
> > > if (p2=p3 and p1<>NULL) czas wykonania ~0,08 sek
> > > 
> > > 
> > > to co to oznacza? 
> > Problem w tym, że to może oznaczać bardzo dużo. Zobacz jak
> > dużo dzieje się w trakcie takiego głupiego zapytania. Najpierw
> > połączenie z bazą po TCP-IP. Zobacz jak dużo dzieje się na
> > tym poziomie: uprawnienia, firewalle, szyfrowanie, kompresja,
> > korekcja błędów. Potem zapytanie dostaje się do bazy, i znowu:
> > parsowanie, uprawnienia, silnik bazy danych musi sprawdzić czy 
> > chociaż są w bazie tabele o podanych nazwach. Potem pracuje
> > kompilator i optymalizator zapytania. Optymalizator może
> > czasami gromadzić statystyczne dane. Potem bufor systemu
> > plików i bufor silnika bazy danych. Sorki, ale ja nadal nie
> > umiem wyciągnąć żadnych wniosków z tego co przedstawiłeś.
> > Pokazałeś że jeden czas jest krótszy od drugiego, intuicja
> > podpowiada, aby wybrać ten krótszy - pomijam fakt że
> > trzykrotna różnica w czasach, z powodu samej zmiany kolejności 
> > wyrażeń, już jest podejrzana. Potem do bazy dodaję
> > jeden rekord, albo nawet tę samą bazę odtwarzam z kopii 
> > zapasowej i co może się stać? Czasy mogą się zupełnie zmienić,
> > prawda?
> > 
> > 
> > > Do testowania najlepiej używać najwolniejszego komputera
> > > bo wtedy te czasy są bardzo widoczne, 
> > Nie zgodzę się, najlepiej użyć warunków najbardziej podobnych do
> > tych, w jakich baza będzie pracowała. 
> > 
> > > no i testowane pola
> > > nie powinny mieć indeksów (sprawdzasz tu tylko warunek).
> > Ale dlaczego w ogóle taki test wykonywać, jeśli potem w
> > realnym działaniu można indeks założyć?
> > 
> > 
> > Pozdrawiam
> 
> Dlatego od pewnego czasu dałem sobie spokój z czasami wykonywania
> bo są tak krótkie, że taka walka trochę mija się z celem.
> Te testy wykonywałem za czasów krasnala i wówczas było o co walczyć
> bo mój wypasiony komp miał ok 600 MHz na procku.
Ja może spokoju sobie nie dałem, ale nie liczę na odnalezienie 
jakiejś reguły. Często sprawdzam 2-3 wersje jakiegoś zapytania, ale
zwykle jestem zdziwiony czasami zapytań. Kiedyś, gdy bardzo dużo
optymalizowałem w języku C/C++, to wyrobiłem sobie intucję i
z reguły odgadywałem, które rozwiązanie przyspieszy o 0.5%.
Robiłem 20 poprawek w kodzie i zyskiwałem łączne przyspieszenie 
rzędu 10-30%. A w bazach danych to chyba zawsze jest loteria.
Mam w przybliżeniu takie zapytanie:
select
 tabela.pole1,
 tabela.pole2,
 podzapytanie1,
 podzapytanie2,
 podzapytanie3
from
 tabela
where
 tabela.id > parametr
order by 
 tabela.id
limit 1000.

Dodam, że podzapytania są skomplikowane, np. mają kolejne 
podzapytania. Zapytaniem tym, zwiększając parametr w każdej
iteracji, wyciągam z bazy po 1000 'rekordów'. Zapytanie
działa rewlacyjnie około 20 razy. 20 zapytań, czyli wyciągnięcie
20tys rekordów, trwa może 20 sekund. Potem nagle zapytanie 21
trwa np. 120 sekund. I nie mam pojęcia co zrobić.

W drugim rozwiązaniu dałem coś takiego:
select
 tabela.pole1,
 tabela.pole2,
 podzapytanie1,
 podzapytanie2,
 podzapytanie3
from
 tabela
where
 tabela.id in (id1,id2,...id1000)

Działało wolniej niż pierwsze, ale nie było tego nagłego 120
sekundowego laga. Potem spróbowałem jeszcze jedną wersję:

select
 tabela.pole1,
 tabela.pole2,
 podzapytanie1,
 podzapytanie2,
 podzapytanie3
from
 tabela
where
 tabela.id <= max AND tabela.id > min
 
To ostatnie działa najlepiej. Oczywiście to i powyższe 
zapytanie wymaga dodatkowego zapytania które wyciągnie z
bazy ograniczenia na tabela.id.

Ta ostatnia wersja wymaga mniej/więcej:

select
 max(tabela.id),
from (
select
 tabela.id,
from
 tabela
where
 tabela.id > prev_max
order by 
 tabela.id
limit 1000.
);

Czyli ta ostatnia wersja to nic innego, jak rozbicie jednego
dużego zapytania na dwa małe. A jednak nie ma tego nagłego
spowolnienia o 60 razy! Mnie ręce opadają, dlaczego baza
sobie nie radzi?



> Pytanie dotyczyło właśnie o kolejność członów w warunku WHERE
> i tu moja podpowiedź - od nakrótszego do najwolniejszego oczywiście
> jeśli system tak działa, że po nie spełnieniu pierwszego członu
> dajmy na to "p1 IS NOT NULL" dalszych już nie sprawdza bo po co.
> Kolega pisał, że aż 90% rekordów ma NULLe to chyba lepiej jak
> już na wstępie system zrezygnuje ze sprawdzania dalszych członów.
W sumie racja, jeśli pola w danym silniku są zorganizowane jako 
tabele kolumnowe, to nie musi dociągać pozostałych danych. Można
obliczenia wykonywane w klauzuli where przyspieszyć ze 1.5 raza.
A to w niektórych przypadkach może dać zysku z 10% na całym
zapytaniu. Pytanie czy warto się bić o te 10%?


> Tu testowanie nie dotyczy pracy sieci ale pracy systemu bazodanowego
> na serwerze www. Im sprawniejszy system bazodanowy tym więcej zapytań
> obsłuży. Każde zapytanie blokuje bazę na czas jego wykonania.
Tak, ale zobacz. Operacje na danych trwają np. 0.1 sekundy. A nawiązanie
polączenia, transfer, parsering zapytania, testy uprawnień, logowanie,
budowanie statystyk przez optymalizator, trwa np. 1s. Czyli łączny
czas to 1.1s. Przyspieszysz operację na danych o 10%, czyli całość
trwa 1.09s. Więc przyspieszenie jakie w praktyce widzisz to 1%. Pytanie
czy w ogóle warto się brać za próbę takiego przyspieszania? 

Druga sprawa, baza danych to nie jest asembler wykonywany na określonym
CPU. W każdej chwili, np. po dodaniu nowej kolumny, albo wręcz po
dodaniu nowego rekordu, optymalizator może zapytanie wykonać 
zupełnie inaczej. W wyniku tego, ciężko uzyskane przyspieszenie, nagle
zamieni się w spowolnienie. Generalnie z Tobą się zgadzam, ale 
mam wątpliwości, czy w ogóle warto się brać za taki tuning?


> Tu kolega Marek chciałby aby to user decydował o warunkach w WHERE
> i jest pytanie czy sprawdzać programowo zapytanie na obecność
> flodów czy nie ma takiej potrzeby bo parser i tak odrzuci powtórzenia.
To wiedzą tylko osoby które znają silnik bazy od podszewki. Myślę, że
optymalizator raz zachowa się tak, a drugi raz inaczej. A po wgraniu
nowej wersji silnika, albo po użyciu dysku SSD, może wszystko
ulec kolejnej zmianie.


> Na indeksach warunki działają tak samo, indeksy przyspieszają
> wyszukiwanie ale tak jak pisałem, czy teraz przy tak krótkich czasach
> ma to sens.
Moim zdaniem nie działają tak samo. Jeśli indeks pasuje do warunku, to
warunek w ogóle nie jest sprawdzany. W wyniku przeszukiwania b-tree
od razu dochodzimy do rekordów spełniających warunek. W przypadku
indeksu w ogóle nie ma sensu testowanie kolejności - przynajmniej
ja bym nie testował.

Pozdrawiam
Technical Details
Message-ID: <a1d9f705-3bd5-4e94-88b7-11dbb5b3b1f7@googlegroups.com>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!newsfeed.fsmpi.rwth-aachen.de!newsfeed.straub-nv.de!proxad.net!feeder1-2.proxad.net!209.85.213.215.MISMATCH!hl2no7695940igb.0!news-out.google.com!db6ni50316igc.0!nntp.google.com!hl2no11044888igb.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail
References: <mci51m$dju$1@news.icm.edu.pl> <fk06sb-jtf.ln1@depesz.com> <mctd2q$q6k$1@news.icm.edu.pl> <5bb452da-87e3-46b6-bbe4-51cd8e95fc73@googlegroups.com> <c57ea06e-2252-4f0c-ad4b-a2a2fed94ac4@googlegroups.com> <ef9d0ff9-dc2b-4ce1-845d-2f080e919ebd@googlegroups.com> <27b8c3e2-f0d5-4667-a74a-09a11cbeb915@googlegroups.com> <2330ae3c-1ffb-4e8a-8327-3a7cb9cebc0b@googlegroups.com> <6a2452a5-2772-4d96-af45-9858c4435913@googlegroups.com> <bd8c25b1-9d49-44a0-987f-4370401878a8@googlegroups.com>

Show Full Headers
Complete Article Headers
X-Received: by 10.140.235.83 with SMTP id g80mr46532135qhc.5.1426222488375;        Thu, 12 Mar 2015 21:54:48 -0700 (PDT)
X-Received: by 10.140.34.168 with SMTP id l37mr739127qgl.20.1426222488328; Thu, 12 Mar 2015 21:54:48 -0700 (PDT)
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!newsfeed.fsmpi.rwth-aachen.de!newsfeed.straub-nv.de!proxad.net!feeder1-2.proxad.net!209.85.213.215.MISMATCH!hl2no7695940igb.0!news-out.google.com!db6ni50316igc.0!nntp.google.com!hl2no11044888igb.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail
Newsgroups: pl.comp.bazy-danych
Date: Thu, 12 Mar 2015 21:54:47 -0700 (PDT)
In-Reply-To: <bd8c25b1-9d49-44a0-987f-4370401878a8@googlegroups.com>
Complaints-To: groups-abuse@google.com
Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=178.36.122.220; posting-account=xjvq9QoAAAATMPC2X3btlHd_LkaJo_rj
NNTP-Posting-Host: 178.36.122.220
References: <mci51m$dju$1@news.icm.edu.pl> <fk06sb-jtf.ln1@depesz.com> <mctd2q$q6k$1@news.icm.edu.pl> <5bb452da-87e3-46b6-bbe4-51cd8e95fc73@googlegroups.com> <c57ea06e-2252-4f0c-ad4b-a2a2fed94ac4@googlegroups.com> <ef9d0ff9-dc2b-4ce1-845d-2f080e919ebd@googlegroups.com> <27b8c3e2-f0d5-4667-a74a-09a11cbeb915@googlegroups.com> <2330ae3c-1ffb-4e8a-8327-3a7cb9cebc0b@googlegroups.com> <6a2452a5-2772-4d96-af45-9858c4435913@googlegroups.com> <bd8c25b1-9d49-44a0-987f-4370401878a8@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <a1d9f705-3bd5-4e94-88b7-11dbb5b3b1f7@googlegroups.com>
Subject: Re: PostgreSQL - jak zbudować optymalne zapytanie?
From: "M.M." <mmarszik@gmail.com>
Injection-Date: Fri, 13 Mar 2015 04:54:48 +0000
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit