[pgsql] Losowy rekord - jak najszybciej?
ethanak - 10-09-2006 00:16
[pgsql] Losowy rekord - jak najszybciej?
Witam
Od razu na wstępie: jestem po przejrzeniu archiwum i coś już tam wyczytałem.
Mam takie trzy tabelki:
create table a(klucz text);
create table b(klucz text references a(klucz),... reszta nieważna);
create table c(klucz text references a(klucz), typ text, kiedy date, ...reszta nieważna);
Chodzi mi o wyciągnięcie losowo wybranego klucza dla podanego typu spełniającego następujące założenia:
a) klucz musi występować w tabeli b; b) para klucz - typ nie występuje w tabeli c, lub w przypadku gdy występuje należy wybrać dowolny klucz z najstarszym 'kiedy' pod warunkiem że jest to nie później niż przedwczoraj.
(mam nadzieję że jasno się wyraziłem)
Przewidywane rozmiary tabel: a - max. 100000; b - mniej więcej rozmiaru a; c - 10 x wielkość a;
Jak na razie moje próby przy kilku tysiącach rekordów nie napawająmnie zbytnim optymizmem :(
No i pytania dwa:
a) jak to zrobić aby było najszybciej?
b) czy nie lepiej rozbić to na dwa zapytania (pierwsze dla elementów które nie występują w c, drugie dla wybrania najstarszego).
Dodam, że dane w tabeli c zmieniają się dość często (tzn. praktycznie jednemu wykonaniu powyższego zapytania odpowiada jedna modyfikacja tabeli c)
ethanak -- mailto=window.atob('ZXRoYW5ha0Bwb2xpcC5jb20=');
Michał Zaborowski - 10-09-2006 00:16
Najszybciej to zrobić tabel 'with oids' i oprzeć generowanie losowych wartości na oidach. To jest też chyba najprostsze rozwiązanie.
-- Pozdrawiam, Michał Zaborowski (TeXXaS)
ethanak - 10-09-2006 00:16
Michał Zaborowski napisał(a): > Najszybciej to zrobić tabel 'with oids' i oprzeć > generowanie losowych wartości na oidach. To jest > też chyba najprostsze rozwiązanie. > Tylko że w tym przypadku dwa egzemplarze aplikacji łączące się z bazą dostaną te same rekordy - a ja chcę żeby dostały w miarę możliwości różne. W tej chwili rozwiązuję to poprzez ustawienie seeda z poziomu aplikacji na podstawie /dev/urandom i to akurat działa...
ethanak -- mailto=window.atob('ZXRoYW5ha0Bwb2xpcC5jb20='); /* Pisze człowiek ambitnie, a tu przychodzi prostak i wszystko rozumie. To jest ewidentna bezczelność! S. Friedmann/J. Kofta */
Michał Zaborowski - 10-09-2006 00:16
No to sporo się wyjaśniło - przynajmniej dla mnie. ;) Mówię o 'najszybciej' w tytule. To random z PG zwraca te same dane? AFAIR działa i to bardzo dobrze - można więc zrobić zapytanie 'select' o losowy rekord. Nie ma potrzeby przewalania danych i odpytywania się o losowy wiersz. OID jest po to, żeby można było zrobić losowanie na poziomie WHERE a nie w OFFSET, albo z podzapytaniem.
-- Pozdrawiam, Michał Zaborowski (TeXXaS)
ethanak - 10-09-2006 00:16
Michał Zaborowski napisał(a): [...] > To random z PG zwraca te same dane? AFAIR działa i to > bardzo dobrze - można więc zrobić zapytanie 'select' o > losowy rekord.
No kur... zabij nie wiem czemu ale wczoraj uparcie zwracał mi to samo - pewnie jakiś błąd w aplikacji (teraz nie do sprawdzenia bo wczorajszych kodów raczej nie mam). Ale to akurat nieważne.
> Nie ma potrzeby przewalania danych i > odpytywania się o losowy wiersz. OID jest po to, żeby > można było zrobić losowanie na poziomie WHERE a nie w > OFFSET, albo z podzapytaniem.
OK, dobra, to powiedz jak bo nie bardzo mogę sobie to wyobrazić?
ethanak -- mailto=window.atob('ZXRoYW5ha0Bwb2xpcC5jb20='); /* Pisze człowiek ambitnie, a tu przychodzi prostak i wszystko rozumie. To jest ewidentna bezczelność! S. Friedmann/J. Kofta */
Michał Zaborowski - 10-09-2006 00:16
ethanak napisał(a): > Michał Zaborowski napisał(a): > [...] >> To random z PG zwraca te same dane? AFAIR działa i to >> bardzo dobrze - można więc zrobić zapytanie 'select' o >> losowy rekord. > > No kur... zabij nie wiem czemu ale wczoraj uparcie zwracał mi to samo - > pewnie jakiś błąd w aplikacji (teraz nie do sprawdzenia bo wczorajszych > kodów raczej nie mam). Ale to akurat nieważne. > CVS, SVN? To pierwsze mniejsze to drugie potężniejsze :)
>> Nie ma potrzeby przewalania danych i >> odpytywania się o losowy wiersz. OID jest po to, żeby >> można było zrobić losowanie na poziomie WHERE a nie w >> OFFSET, albo z podzapytaniem. > Dobra, co do podzapytania to trochę przesadziłem... ;)
> OK, dobra, to powiedz jak bo nie bardzo mogę sobie to wyobrazić? > ? Tak myślałem, że się do tego sprawadzi, ale zawsze można mieć nadzieję...
Zapytanie może wyglądać np. tak: select oid from tbl where oid = (random() * (select max(oid) from tbl))::int4
Można też przyspieszyć zapamiętując max(oid), ale od 8.1 PG używa tu indeksu i za wiele się nie zyska.
-- Pozdrawiam, Michał Zaborowski (TeXXaS)
ethanak - 10-09-2006 00:16
On 2006-09-05 14:24, Michał Zaborowski wrote: [...] >> wczorajszych kodów raczej nie mam). Ale to akurat nieważne. >> > CVS, SVN? To pierwsze mniejsze to drugie potężniejsze :)
A po ciężki puhw mi źródła niedziałającego programu? Ani bloga sobie nie założyłem, ani zeszyciku z króliczkiem na okładce nie mam...
[...] >> OK, dobra, to powiedz jak bo nie bardzo mogę sobie to wyobrazić? >> > ? Tak myślałem, że się do tego sprawadzi, ale zawsze > można mieć nadzieję...
Tak - można mieć nadzieję że gość co się zajmuje programowaniem zupełnie innych rzeczy w C tudzież pewnymi wybranymi aspektami projektowania stron WWW nagle zostanie mistrzem w Postgresie.
> > Zapytanie może wyglądać np. tak: > select oid > from tbl > where oid = (random() * (select max(oid) from tbl))::int4
Przykro - does not work. Ilość wierszy zero nie jest specjalnie interesująca.
Ergo: albo chcesz mi pomóc, albo powiedz po prostu że się nie znam i jako lejek mam nie wpierdalać się w rozmowy Wielkich Specjalistów.
ethanak -- mailto=window.atob('ZXRoYW5ha0Bwb2xpcC5jb20=');
hubert depesz lubaczewski - 10-09-2006 00:16
On 2006-09-05, ethanak <sweethanak@buziaczek.pl> wrote: > create table a(klucz text); > create table b(klucz text references a(klucz),... reszta nieważna); > create table c(klucz text references a(klucz),
1. fatalnie, że to tekst. 2. nie dałyś rady dołożyć primary keya na int'cie? 3. jak często robisz delete? insert i update mnie nie interesuje.
depesz
-- http://www.depesz.com/index.php/2006...udzi-do-pracy/
hubert depesz lubaczewski - 10-09-2006 00:59
On 2006-09-07, ethanak <sweethanak@buziaczek.pl> wrote: > On 2006-09-06 19:40, hubert depesz lubaczewski wrote: > [...] >> pomogło? > > Pewnie by pomogło gdyby nie jeden drobiazg. > > Ten sposób pozwala na wyciągnięcie losowego rekordu z całej tabelki. > Tymczasem ja potrzebuję wyciągnięcia losowego rekordu z tabelki > spełniającego jakiśtam warunek, przy czym może zaistnieć sytuacja że > taki rekord w ogóle nie istnieje, albo jest tylko jeden w tabeli mającej > 100k rekordów... > > W wersji roboczej mam "order by random() limit 1" (wyczytane w archiwum > właśnie) ale to mi się niespecjalnie podoba :( > > A tak przy okazji: czy wykonanie setval('randomizer_seq',0) przed > "update tabelka..." nie oszczędziłoby jednego zapytania w random_id()?
nie za bardzo. bo i tak nie można nigdy zakładać, że to się nie zmieni.
a select min w postgresach nowych jest szybciutki.
depesz
-- http://www.depesz.com/index.php/2006...udzi-do-pracy/
ethanak - 10-09-2006 00:59
hubert depesz lubaczewski napisał(a): [...] >>A tak przy okazji: czy wykonanie setval('randomizer_seq',0) przed >>"update tabelka..." nie oszczędziłoby jednego zapytania w random_id()? > > > nie za bardzo. bo i tak nie można nigdy zakładać, że to się nie zmieni. > > a select min w postgresach nowych jest szybciutki.
W sumie racja.
BTW problem rozwiązałem na poziomie aplikacji (tzn. nie dokładnie tak jak chciałem, ale do moich celów wystarczający).
ethanak -- mailto=window.atob('ZXRoYW5ha0Bwb2xpcC5jb20='); /* Pisze człowiek ambitnie, a tu przychodzi prostak i wszystko rozumie. To jest ewidentna bezczelność! S. Friedmann/J. Kofta */
zanotowane.pldoc.pisz.plpdf.pisz.pleffulla.pev.pl
|
[ms sql] =?ISO-8859-2?Q?wy=B6wietlenie_pierwszych_5_rekord?==?ISO-8859-2?Q?=F3w_z_zapytania_=3F_odpowiednik_ROWNUM_w_o?== ?ISO-8859-2?Q?raclu_dla_MS_SQL=27a?=
[MySQL] =?ISO-8859-2?Q?Wy=B6wietlenie_kolejnej_pozycji=2C_?==?ISO-8859-2?Q?jak=B1_mia=B3by_dany_rekord=2C_gdybym_czyta=B3 _?==?ISO-8859-2?Q?wg_konkretnych_kryteri=F3w=2E_Da_si=EA_=3F?=
=?ISO-8859-2?Q?Narz=EAdzie_do_budowania_zapyta=F1_SQL=2C?==?I SO-8859-2?Q?_PL/PgSQL=2C_PL/SQL=2C_T-SQL?=
Jak =?ISO-8859-2?Q?zamieni=E6_dwa_pola_jednej_kolumny_?==?ISO-8859-2?Q?w_dw=F3ch_rekordach_za_pomoc=B1_jednego_zapyt? ==?ISO-8859-2?Q?ania=3F?=
[mysql/php] jak =?ISO-8859-2?Q?zliczy=E6_ilo=B6=E6_unikalnyc?==?ISO-8859-2?Q?h_rekord=F3w_w_jednym_zapytaniu=3F?=
=?ISO-8859-2?Q?WY=B6wietlenie_rekord=F3w_pocz=B1wszy_od_?==?I SO-8859-2?Q?danej_litery=2E=2E=2E?=
=?iso-8859-2?Q?=5BMySQL=5D_Wy=B6wietlenie_wszystkich_rekordow _zawierajacy?==?iso-8859-2?Q?ch_duplikat_a__moze_inna_struktura_bazy_danych ?=
[postgresql] kilka =?ISO-8859-2?Q?rekord=F3w_subquery_jako_?==?ISO-8859-2?Q?string?=
[mysql] Wyszukanie =?ISO-8859-2?Q?rekord=F3w=28powiazane_tabel?==?ISO-8859-2?Q?e=29?=
[MySQL]: Dodanie zliczania =?ISO-8859-2?Q?rekord=F3w_do_rozb?==?ISO-8859-2?Q?udowanego_zapytania?=
zanotowane.pldoc.pisz.plpdf.pisz.plradioaktywni.htw.pl
Cytat
Decede mihi sole - nie zasłaniaj mi słonca. Gdy kogoś kochasz, jesteś jak stworzyciel świata - na cokolwiek spojrzysz, nabiera to kształtu, wypełnia się barwą, światłem. Powietrze przytula się do ciebie, choćby był mróz, a ty masz w sobie tyle radości, że musisz ją rozdawać wokoło, bo się w tobie nie mieści Hoc fac - tak czyń. A tergo - od tyłu; z tyłu. I czarne włosy posiwieją. Safona |
|