Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Wydajność zapytani sub select
kris2
post
Post #1





Grupa: Zarejestrowani
Postów: 150
Pomógł: 3
Dołączył: 15.08.2007

Ostrzeżenie: (0%)
-----


Mam taki zestaw tabel:

użytkownik (z uzytkownikami systemu)

grupy (grupy do ktorych moze zapisac sie uzytkownik) (np A, B, C , D , E ...)

uzytkownicy_grupa (relacjz zawierająca informacje o grupac do ktorych jest zapisany użytkownik)

załóżmy że użytkowników jest milion a grup 10-20 więc wydajność ma znaczenie.

schamt jest taki

użytkownik 1 - N użytkownicy_grupa N <- 1 grupy

Jak najwydajniej zapytać się o użytkowników należących do grupy A, B i C:
Przychodzą mi do głowy 3 rozwiązania

po 1: - totalnie lame
- umieścic w tabeli użytkownicy spis grup po przecinku i użyć LIKE

po 2: - wykorzystanie zmiennej typu array
- to też nie wygląda na idealne rozwiązanie ponieważ jest ograniczenie przy przeszukiwaniu zmiennych array, można jedynie użyć any lub all
(+ na PostgreSQL napisano
Tip: Arrays are not sets; searching for specific array elements may be a sign of database misdesign. Consider using a separate table with a row for each item that would be an array element. This will be easier to search, and is likely to scale up better to large numbers of elements.
)

po 3: - używanie subselecta na zasadzie
  1. SELECT * FROM u&#380;ytkownik u WHERE (SELECT * FROM grupa g WHERE u.użytkownik_id=g.użytkownik_id AND (g.grupa=A or g.grupa=B or g.grupa=C))=3


Ma ktoś jakieś lepsze rozwiązania lub umie uzasadnić które wybrać i dlaczego?

Ten post edytował kris2 21.08.2007, 19:40:38
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
osiris
post
Post #2





Grupa: Zarejestrowani
Postów: 121
Pomógł: 15
Dołączył: 19.07.2007

Ostrzeżenie: (0%)
-----


Jedna uwaga. Do moich zapytan podanych we wczesniejszym poscie wkradl sie blad. Ponizsze zapytanie jest zle:
  1. SELECT * FROM uzytkownicy WHERE (grupy & $grupy) > 0

powinno byc:
  1. SELECT * FROM uzytkownicy WHERE (grupy & $grupy) = $grupy


W pierwszym przypadku zostana znalezieni wszyscy uzytkownicy ktorzy naleza do przynajmniej jednej z grup (a nie wszystkich)!

Ciekaw bylem wydajnosci takiego rozwiazania i sam zrobilem troche testow.

Stworzylem przykladowa tabele:
  1. CREATE TABLE `users` (
  2. `id` mediumint(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `name` varchar(20) collate utf8_polish_ci NOT NULL,
  4. `pass` varchar(40) collate utf8_polish_ci NOT NULL,
  5. `groups` int(10) UNSIGNED NOT NULL DEFAULT '0',
  6. `homedir` varchar(30) collate utf8_polish_ci NOT NULL,
  7. `active` tinyint(1) NOT NULL DEFAULT '0',
  8. PRIMARY KEY (`id`),
  9. KEY `groups` (`groups`)
  10. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci

i wypelnilem je przypadkowymi danymi. Jesli chodzi o name, pass i homedir, dane te pobralem czytajac plik avi (IMG:http://forum.php.pl/style_emoticons/default/tongue.gif) , groups byly losowo generowane, active co druga jest 1.

Wstawilem 1,5 mln rekordow. Tabela zajmuje:170MB, z indeksami prawie 200MB.

Co sie okazalo to to ze dlugosc wyszukiwania uzytkownikow nalezacych do wybranych grup zalezy od tego ile grup chcemy sprawdzic. Nie wiem czemu tak sie dzieje, moze ktos ma jakis pomysl.

Testy przeprowadzilem w nastepujacy sposob:
dla kazdej mozliwej liczby bitow(1-31) wykonywalem 10 zapytan:
  1. SELECT SQL_NO_CACHE * FROM users WHERE groups & $liczba = $liczba LIMIT 30

gdzie $liczba to losowo wygenerowana liczba w ktorej n bitow jest zapalonych (to tak jakbysmy szukali user wsrod n losowo wybranych grup),

mierzylem czas wykonywania tych zapytan i potem obliczylem srednia.
Oto wyniki:
Kod
Ilosc bitow        Sredni czas(s)
---------------------------------
1               0.00074770450592
2               0.000751495361328
3               0.000946569442749
4               0.0039412021637
5               0.0040956735611
6               0.00505304336548
7               0.00831155776978
8               0.0105215072632
9               0.0200308084488
10              0.0367336988449
11              0.0835324525833
12              0.147039031982
13              0.276187181473
14              0.507218337059
15              1.06423690319
16              1.53951747417
17              1.59646685123
18              1.64317190647
19              1.67781071663
20              1.71348867416
21              1.56421909332
22              1.59005527496
23              1.62178874016
24              1.64297554493
25              1.67281501293
26              1.65174326897
27              1.57270855904
28              1.6054520607
29              1.62569227219
30              1.66454772949
31              1.6705922842


Jak widac czas wykonywania zapytania na poczatku rosnie wykladniczo. Pozniej najprawdopodobniej zaczely coraz lepiej dzialac mechanizmy cacheujace linux'a.

Testy przeprowadzalem na kompie:
AMD Sempron 2500+
pamiec 1GB RAM
dysk 160GB SATA 8MB Cache
OS: Kubuntu 7.04

W czasie wykonywania testu zajetosc czasu procesora byla maksymalna.

Komp sluzy do uzytku domowego, wiec w czasie testow bylo otwartych sporo innych aplikacji, ale staralem sie wtedy nic nie robic (nawet nie ruszalem myszka) wiec wyniki powinny byc w miare wiarygodne.

Nie wiem czy to jest optymalne rozwiazanie, warto by jeszcze sprawdzic jak sie sprawdzi moje wczesniejsze rozwiazanie (z grupowaniem) i jakie beda osiaga przy wykorzystaniu pola typu BITFIELD.

Ten post edytował osiris 23.08.2007, 15:09:16
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 5.10.2025 - 15:20