Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sortowanie tabel

0 views
Skip to first unread message

Lucek B

unread,
Aug 4, 2006, 12:40:39 PM8/4/06
to
Witam
Przepraszam z góry za pytanie początkującego , dopiero poznaję zagadnienia
zwiazane z bazami.
Mam pytanie projektowe . Moja baza bedzie zaawierała kilka nieskomplikowanych
tabel z kilkoma polami.Uzytkownik bedzie mial program ktorego elementem jest
tabela ktora pozwala mu na przewijanie co N rekordow w partiach np co 10 (np od
20 do 30).Bedzie tez mogl posortowac wedlug kazdej kategorii ale juz globalnie
np po kolei znowu transzami co 10 jednak wyniki beda posortowane np malejaco.
I tak po kazdej kategorii.
I tu mam pytanie.Otoz rekordow bedzie nie mniej niz 5000 i oczywiscie nie moge
sobie pozowolic na "przestoj". Jak to powinienem wykonac ? CZy gdy user wykona
sortowanie to mam wykonac SELECT , posortowac , zwrocic porcje danych ?
Wyglada mi to na 100% marnowanie pamieci i czasu.Prosze o podpowiedz.
Czy w bazami sa zwiazane jakies ogolno dostepne desing patterny ? Jezeli tak
to prosze o namiary.
Z góry dzieki.

Pozdrawiam Lucek

--
Wysłano z serwisu OnetNiusy: http://niusy.onet.pl

Artur Gancarz

unread,
Aug 4, 2006, 2:16:44 PM8/4/06
to
Użytkownik Lucek B napisał:
Niestety nie jestem expertem i nie jestem pewien, czy zrozumiałem Twoje
pytanie, ale:
1) jeśli chcesz posortować wyniki otrzymywane z bazy to np.:
select * from tabela order by nazwa_kolumny_sortowanej;
Zwróci wtedy posortowane wiersze wg podanej nazwy kolumny.

2) jeśli chcesz np. otrzymać na podstawie poprzedniego zapytania rekordy
np. od 21 do 30 (dokładnie 10 szt.) to trzeba na końcu dopisać:
select * from tabela order by nazwa_kolumny_sortowanej limit 20,10;

Oznacza to mniej więcej to, że ma pominąć 20 szt. z początku, a
następnie wyświetlić 10 następnych (tutaj: od 21 do 30)
i tak dalej:
select * from tabela order by nazwa_kolumny_sortowanej limit 0,10;
wyświetli rekordy od 1 do 10 (pominie ZERO)

select * from tabela order by nazwa_kolumny_sortowanej limit 120,10;
wyświetli rekordy od 121 do 130

Czy o to chodziło?
pozdrawiam
Artur

lbo...@vp.pl

unread,
Aug 4, 2006, 3:30:35 PM8/4/06
to

> Niestety nie jestem expertem i nie jestem pewien, czy zrozumiałem Twoje
> pytanie, ale:
> 1) jeśli chcesz posortować wyniki otrzymywane z bazy to np.:
> select * from tabela order by nazwa_kolumny_sortowanej;
> Zwróci wtedy posortowane wiersze wg podanej nazwy kolumny.
>
> 2) jeśli chcesz np. otrzymać na podstawie poprzedniego zapytania rekordy
> np. od 21 do 30 (dokładnie 10 szt.) to trzeba na końcu dopisać:
> select * from tabela order by nazwa_kolumny_sortowanej limit 20,10;
>
> Oznacza to mniej więcej to, że ma pominąć 20 szt. z początku, a
> następnie wyświetlić 10 następnych (tutaj: od 21 do 30)
> i tak dalej:
> select * from tabela order by nazwa_kolumny_sortowanej limit 0,10;
> wyświetli rekordy od 1 do 10 (pominie ZERO)
>
> select * from tabela order by nazwa_kolumny_sortowanej limit 120,10;
> wyświetli rekordy od 121 do 130
>
> Czy o to chodziło?
> pozdrawiam
> Artur

Dzieki za odpowiedz.
Widziałem to rozwiązanie jednak rozwazam je w kontekscie sortowania
globalnego czyli wszystkich rekordów w bazie.Podany kod posortuje
te 10 wierszy(dobrze rozumuje?)a nie o tym mysle.
Przedstawie to na przykladzie np prosta gra ktora posiada unikalne id
ze skojarzonym wynikiem w pewnej grze internetowej

id score
1 222
.
2 233

55 23
.
355 3235
Teraz ktos posiada tabele w ktorej moze ogladnac 10 wynikow naraz
Pobiera wyniki od 20 do 30. Szuka po id gry. Po chwili chce dostac
posortowane wyniki ale nie ta porcje 10 tylko globalnie cala tabele czyli
kto ma najwiecej punktow .Ja to widze tak - trzeba posortowac cala tabel
w jednym zapytaniu i dostane wszystkie wiersze w dobrej kolejnosci , potem
zeby nie wykonywac kolejnego zapytania zachowam to w pamieci przez pewien okres
czasu i klient bedzie mogl odpytywac tak posortowane dane.Jest to jednak
bardzo pamieciozerne i nieefektywne zatem zle zaprojektowlem.Jak to powinno
wygladac ?? Ten przyklad to nie to co robie , bede mial rowniez porownanie
ciagu znakow zatem posortowanie tego bedzie trwac znacznie dluzej.
Moje pytanie wiec brzmi jak sie mam do tego porzadnie zabrac ???
Bardzo prosze o podpowiedz

Pozdrawiam Luccek

Bartosz Feński aka fEnIo

unread,
Aug 4, 2006, 3:47:34 PM8/4/06
to
W artykule lbo...@vp.pl napisał(a):

>> Niestety nie jestem expertem i nie jestem pewien, czy zrozumiałem Twoje
>> pytanie, ale:
>> 1) jeśli chcesz posortować wyniki otrzymywane z bazy to np.:
>> select * from tabela order by nazwa_kolumny_sortowanej;
>> Zwróci wtedy posortowane wiersze wg podanej nazwy kolumny.
>>
>> 2) jeśli chcesz np. otrzymać na podstawie poprzedniego zapytania rekordy
>> np. od 21 do 30 (dokładnie 10 szt.) to trzeba na końcu dopisać:
>> select * from tabela order by nazwa_kolumny_sortowanej limit 20,10;
>>
>> Oznacza to mniej więcej to, że ma pominąć 20 szt. z początku, a
>> następnie wyświetlić 10 następnych (tutaj: od 21 do 30)
>> i tak dalej:
>> select * from tabela order by nazwa_kolumny_sortowanej limit 0,10;
>> wyświetli rekordy od 1 do 10 (pominie ZERO)
>>
>> select * from tabela order by nazwa_kolumny_sortowanej limit 120,10;
>> wyświetli rekordy od 121 do 130
>>
>> Czy o to chodziło?

> Dzieki za odpowiedz.
> Widziałem to rozwiązanie jednak rozwazam je w kontekscie sortowania
> globalnego czyli wszystkich rekordów w bazie.Podany kod posortuje
> te 10 wierszy(dobrze rozumuje?)a nie o tym mysle.

Źle rozumujesz.

> Przedstawie to na przykladzie np prosta gra ktora posiada unikalne id
> ze skojarzonym wynikiem w pewnej grze internetowej
>
> id score
> 1 222
> .
> 2 233
>
> 55 23
> .
> 355 3235
> Teraz ktos posiada tabele w ktorej moze ogladnac 10 wynikow naraz
> Pobiera wyniki od 20 do 30. Szuka po id gry. Po chwili chce dostac
> posortowane wyniki ale nie ta porcje 10 tylko globalnie cala tabele czyli
> kto ma najwiecej punktow .

Tak właśnie się stanie po zapytaniu, które przytoczył Ci poprzednik.

>Ja to widze tak - trzeba posortowac cala tabel

> w jednym zapytaniu i dostane wszystkie wiersze w dobrej kolejnosci, potem


> zeby nie wykonywac kolejnego zapytania zachowam to w pamieci przez pewien okres
> czasu i klient bedzie mogl odpytywac tak posortowane dane.Jest to jednak
> bardzo pamieciozerne i nieefektywne zatem zle zaprojektowlem.

Nigdy nie wyciągaj wszystkich rekordów. W 99% jest to błąd.

> Jak to powinno
> wygladac ?? Ten przyklad to nie to co robie , bede mial rowniez porownanie
> ciagu znakow zatem posortowanie tego bedzie trwac znacznie dluzej.
> Moje pytanie wiec brzmi jak sie mam do tego porzadnie zabrac ???
> Bardzo prosze o podpowiedz

Bazy danych zostały zaprojektowane do takiego przetwarzania, by było one
jak najbardziej optymalne i szybkie. Po prostu dobrze dobierz zapytanie tak
by baza zwróciła taką ilość danych jaką chcesz w danym momencie wyświetlić.

Przetwarzanie tych danych dopiero po wyciągnięciu z bazy jest często gęsto
nieporozumieniem i jest wolniejsze.

pozdr,
fEnIo

--
,''`. Bartosz Fenski | mailto:fe...@debian.org | pgp:0x13fefc40 | irc:fEnIo
: :' : 32-050 Skawina - Glowackiego 3/15 - malopolskie v. - Poland
`. `' phone:+48602383548 | proud Debian maintainer and user
`- http://skawina.eu.org | jid:fe...@jabber.org | rlu:172001

lbo...@vp.pl

unread,
Aug 4, 2006, 3:54:01 PM8/4/06
to

>
> Bazy danych zostały zaprojektowane do takiego przetwarzania, by było one
> jak najbardziej optymalne i szybkie. Po prostu dobrze dobierz zapytanie tak
> by baza zwróciła taką ilość danych jaką chcesz w danym momencie wyświetlić.
>
> Przetwarzanie tych danych dopiero po wyciągnięciu z bazy jest często gęsto
> nieporozumieniem i jest wolniejsze.
>
> pozdr,
> fEnIo
>
> --

Powiem szczerze iz nie spodziewalem się tego W takim razie ogromny ukłon w
strone autorów tych rozwiazan i Was za odpowiedzi na moje pytanie.Dzieki

Pozdrawiam Lucek

lost

unread,
Aug 4, 2006, 4:57:00 PM8/4/06
to
> Powiem szczerze iz nie spodziewalem się tego W takim razie ogromny ukłon w
> strone autorów tych rozwiazan i Was za odpowiedzi na moje pytanie.Dzieki
>
> Pozdrawiam Lucek
>
Jeszcze jedno wyjaśnienie,. w bazie nie zachodzi żadne sortowanie,
to wynik zapytania jest sortowany i wycinasz z niego tyle rekordów
ile potrzeba.
Tablice w bazie są takie jak były.

--


Łukasz

unread,
Aug 6, 2006, 5:48:12 AM8/6/06
to
Użytkownik "Artur Gancarz" <eins...@agh.edu.pl> napisał w wiadomości
news:eb02tk$nug$1...@news.agh.edu.pl...

>
> 2) jeśli chcesz np. otrzymać na podstawie poprzedniego zapytania rekordy
> np. od 21 do 30 (dokładnie 10 szt.) to trzeba na końcu dopisać:
> select * from tabela order by nazwa_kolumny_sortowanej limit 20,10;
>
> Oznacza to mniej więcej to, że ma pominąć 20 szt. z początku, a
> następnie wyświetlić 10 następnych (tutaj: od 21 do 30)
> i tak dalej:
> select * from tabela order by nazwa_kolumny_sortowanej limit 0,10;
> wyświetli rekordy od 1 do 10 (pominie ZERO)
>
> select * from tabela order by nazwa_kolumny_sortowanej limit 120,10;
> wyświetli rekordy od 121 do 130
>

Witam,

Dołączę się do wątku bo mam podobny problem.
Chcę sortować po LAST_NAME, FIRST_NAME i dla unikalności ID.

Dla samego LAST_NAME, FIRST_NAME worzyłem zapytania w stylu
WHERE (LAST_NAME>X OR (LAST_NAME=X AND FIRST_NAME>Y)
oczywiscie po dodaniu ID to się odpowiednio rozbuduje.
Niestety Postgres 'głupiał' i nie wykorzystywał indeksu, dlatego utworzyłem
indeks na LAST_NAME||' '||FIRST_NAME i uniknąłem OR w klauzuli WHERE.

Niestety po dodaniu "ID" dla uzyskania unikalności zapytania problem znów
wrócił. Nie chcę tworzyć indeksów na LAST_NAME||' '||FIRST_NAME||' '||ID bo
uważam takie konstrukcje za koszmarne, poza tym wiążę w ten sposób
uporządkowania z indeksami, chciałbym w związku z tym przekonstruować
zapytanie.

Konstrukcja LIMIT OFFSET niestety nie wygląda na wydajną dla większych
zbiorów:
EXPLAIN
SELECT "LAST_NAME","FIRST_NAME" FROM CONTACT
WHERE "COMPANY_ID" = 48
ORDER BY "LAST_NAME"||' '||"FIRST_NAME"
LIMIT 20 OFFSET 30000;
----------------------
Limit (cost=19899.24..19899.29 rows=20 width=20)
-> Sort (cost=19824.24..19907.55 rows=33327 width=20)
Sort Key: ((("LAST_NAME")::text || ' '::text) ||
("FIRST_NAME")::text)
-> Bitmap Heap Scan on contact (cost=209.64..16846.87 rows=33327
widt
h=20)
Recheck Cond: ("COMPANY_ID" = 48)
-> Bitmap Index Scan on contact_index_company
(cost=0.00..209.6
4 rows=33327 width=0)
Index Cond: ("COMPANY_ID" = 48)
(7 rows)

W porównaniu z:
EXPLAIN
SELECT "LAST_NAME","FIRST_NAME" FROM CONTACT
WHERE "COMPANY_ID" = 48
ORDER BY "LAST_NAME"||' '||"FIRST_NAME"
LIMIT 20;
----------------------------
Limit (cost=0.00..75.27 rows=20 width=20)
-> Index Scan using company_index_company_lfname on contact
(cost=0.00..125
431.28 rows=33327 width=20)
Index Cond: ("COMPANY_ID" = 48)
(3 rows)

Dla nieunikalnego uporządkowania rozwiązanie jest proste:
warunek WHERE "LAST_NAME"||' '||"FIRST_NAME">'X Y', ale po dodaniu do ORDER
BY kolumny ID wszystko się wywala...

Będę bardzo wdzięczny jeśli ktoś zaproponuje jakąś konstrukcję która nie
korzysta z OFFSET i umożliwia Postgresowi wykorzystanie indeksu na częśc
uporządkowania

Pozdrawiam,
Łukasz


0 new messages