Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP]Architektura rozbudowanego drzewa kategorii a szybkość odpowiedzi z DB
Forum PHP.pl > Forum > Przedszkole
JamalBIG
Witam

W jaki sposób rozwiązać problem rozbudowanego drzewa kategorii w skrypcie tak aby zapytania do DB nie trwały zbyt długo i same zapytania były krótkie? Np. serwis allegro ma bardzo rozbudowane drzewo kategorii a mimo tego całość działa płynnie.
Obecnie mam to rozwiązanie dość abstrakcyjnie przez co przy rozbudowanym drzewie kategorii zapytanie trwa bardzo długo.

Obecna struktura tabeli:
id | nazwa | lewa_id | poziom | pozycja | lista
lewa_id - id kategorii nadrzędnej;
poziom - poziom zagłębienia kategorii;
pozycja - pozycja do sortowania przy wyświetlaniu;
lista - lista wszystkich podległych kategorii (np. 23,31,75);

Z góry dzięki za propozycje rozwiązań
Pozdrawiam
b4rt3kk
Cytat(JamalBIG @ 23.03.2015, 15:08:18 ) *
Witam

W jaki sposób rozwiązać problem rozbudowanego drzewa kategorii w skrypcie tak aby zapytania do DB nie trwały zbyt długo i same zapytania były krótkie? Np. serwis allegro ma bardzo rozbudowane drzewo kategorii a mimo tego całość działa płynnie.
Obecnie mam to rozwiązanie dość abstrakcyjnie przez co przy rozbudowanym drzewie kategorii zapytanie trwa bardzo długo.

Obecna struktura tabeli:
id | nazwa | lewa_id | poziom | pozycja | lista
lewa_id - id kategorii nadrzędnej;
poziom - poziom zagłębienia kategorii;
pozycja - pozycja do sortowania przy wyświetlaniu;
lista - lista wszystkich podległych kategorii (np. 23,31,75);

Z góry dzięki za propozycje rozwiązań
Pozdrawiam


To zależy od tego, czy musisz mieć naraz rozwinięte wszystkie kategorie, czy np. dopiero po kliknięciu na daną kategorię. W drugim przypadku sprawa będzie prostsza.
Forti
Category

- id
- title
- parent_id
- level
- root

i teraz masz tak:

- telefony (1, telefony, null, 1, 1)
-- lg (2, lg, 1, 2, 1)
--- coś_tam (5, coś_tam, 2, 3, 1)
-- samsung (3, samsung, 1, 2, 1)
-- sony (4, sony, 1, 2, 1)

- inna (6, inna, null, 1, 2)
itp.

Powinieneś załapać z czasem, Jest jeszcze left | right, ale to już "wyższa szkoła jazdy"

Za kwestie zapytań odpowiada optymalizacja kodu, bazy, indexy a w przypadku np. allegro ilość serwerów wink.gif
Pyton_000
nested set
b4rt3kk
Aha, polecałbym jeszcze cache. Drzewo kategorii to nie jest coś co często się zmienia.
JamalBIG
Samo wyświtlanie drzewa działa ok, bo wyświetlane są tylko dwa 'poziomy' czyli kategorie i podkategorie ale w jaki sposób 'sklecić' zapytanie do DB aby wyświetlić wszystkie treści które zostały przyporządkowane do kategorii najniższego rzędu - np. w kategorii 'Telefony' mam 200 podkategorii do których jest możliwe dodanie 'treści' - czy zapytanie musi wyglądać tak:
  1. SELECT * FROM ...... WHERE cat_id IN(1,2,3,4,5....., 200)

W takim przypadku zapytanie jest tak długie, że 'serwer się gotuje'
Forti
Masz źle zbudowane baze. Nie masz mieć mole "children" tylko pole "parent" i potem zapytaniem pobierasz wszystkie kategorie które mają parent = ? lub jedno zapytanie o kategorie główne, czyli np. parent = null i leftjoin parent = :id. Rozumiesz? ;>
b4rt3kk
Cytat(JamalBIG @ 23.03.2015, 15:42:55 ) *
Samo wyświtlanie drzewa działa ok, bo wyświetlane są tylko dwa 'poziomy' czyli kategorie i podkategorie ale w jaki sposób 'sklecić' zapytanie do DB aby wyświetlić wszystkie treści które zostały przyporządkowane do kategorii najniższego rzędu - np. w kategorii 'Telefony' mam 200 podkategorii do których jest możliwe dodanie 'treści' - czy zapytanie musi wyglądać tak:
  1. SELECT * FROM ...... WHERE cat_id IN(1,2,3,4,5....., 200)

W takim przypadku zapytanie jest tak długie, że 'serwer się gotuje'


Dodaj LIMIT i paginator.
JamalBIG
Cytat(Forti @ 23.03.2015, 15:56:47 ) *
Masz źle zbudowane baze. Nie masz mieć mole "children" tylko pole "parent" i potem zapytaniem pobierasz wszystkie kategorie które mają parent = ? lub jedno zapytanie o kategorie główne, czyli np. parent = null i leftjoin parent = :id. Rozumiesz? ;>

Możesz podać to na przykładzie? Z paginatorem i limitem bez zmian bo chyba problem leży w długości zapytania do DB...
Pyton_000
Czy ktoś mnie w ogóle słucha? Do dużych drzew w których modyfikacja jest rzadka a bardzo dużo odczytów najlepiej nadaje się nested set, bo jednym zapytaniem można pobierać różne cuda i to bez skomplikowanych zapytań. Jest trudna w ogólnej obsłudze (dodawanie, usuwanie itp.) ale już wybieranie kategorii jest banalnie proste.
Forti
Co rozumiesz przez duże drzewo? Używałem doctrine tree dla 1800 kategorii z 6 level i bylo to wyciąganie armat na wróbla:P Mysle ze kolega ma mniejsze drzewo
JamalBIG
Cytat(Forti @ 23.03.2015, 18:12:15 ) *
Co rozumiesz przez duże drzewo? Używałem doctrine tree dla 1800 kategorii z 6 level i bylo to wyciąganie armat na wróbla:P Mysle ze kolega ma mniejsze drzewo

Chętnie wyciągnę armaty, biorę pod uwagę najgorsze warianty czli kilka/kilkadziesiąt kategorii i kilka/kilkanaście leveli. Tak jak pisałem, sama obsługa kategorii i tabeli z nimi nie jest problemem, problem jest z zapytaniem do DB kiedy chce wywołać treści przyporządkowane do kategorii ostatniego levelu
Forti
Robisz to zle. Zamiast pobierać IN() itp. To może lepiej pobierz całość i zmapuj w php w pętlach Itp. Po za tym co rozumiesz przez długie zapytania? Samo in() nie jest niczym wolnym czy cos. Leftjoin tak samo. Chcesz optymalizować a mówisz ze chetnie wyciągniesz armaty...
JamalBIG
Cytat(Forti @ 23.03.2015, 21:01:27 ) *
Robisz to zle. Zamiast pobierać IN() itp. To może lepiej pobierz całość i zmapuj w php w pętlach Itp. Po za tym co rozumiesz przez długie zapytania? Samo in() nie jest niczym wolnym czy cos. Leftjoin tak samo. Chcesz optymalizować a mówisz ze chetnie wyciągniesz armaty...

To może źle zrozumiałem 'armaty' wink.gif
Pobieranie całości nie wiem czy jest dobrym pomysłem jeżeli będzie tam kilka tysięcy wpisów przykorządkowanych do konkretnych kategorii...
b4rt3kk
Cytat(JamalBIG @ 23.03.2015, 21:06:43 ) *
To może źle zrozumiałem 'armaty' wink.gif
Pobieranie całości nie wiem czy jest dobrym pomysłem jeżeli będzie tam kilka tysięcy wpisów przykorządkowanych do konkretnych kategorii...


Pobieranie całości to najgorszy pomysł jaki może być.

Jeśli chodzi o pobieranie wyników dorzuć zwyczajnie zwykłego limita:

  1. SELECT * FROM products WHERE id_cat IN (1,2,20) LIMIT 50 OFFSET 0;


Dobrym pomysłem byłoby też założenie indexu na id_cat.

Gdyby to był postgres mógłbyś też zrobić tabele dziedziczące z warunkiem WITH (no ale niestety nie jest).

Zwróć też uwagę jakie kolumny pobierasz, ogranicz się do minimum, tzn. bierz tylko te, które potrzebujesz. Jeśli np. w którejś przechowujesz spory blok tekstu lub nawet obrazek to wiadomo, że pobranie zawartości musi zająć dłuższą chwilę. Więc zamiast SELECT *, zastosuj SELECT col1, col2, itd.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.