Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Drzewiasta struktura oraz INDEX na pole typu TEXT
Forum PHP.pl > Forum > PHP
Sajrox
Witam,

Chciałbym podyskutować o pewnym rozwiązaniu dotyczącym tworzenia drzewka kategorii.

Otóż mam przykladowe drzewo kategorii

Komputery(id: 1) 
-> Monitory(id: 2) 
-> -> Lcd (id: 3) 
-> -> -> 24 cale (id: 4)

W bazie mam pola ID | PARENT_ID | NAME | PATH_UP | DEPTH

Pole PATH_UP trzyma identyfikatory kategorii w górę (odzielone kropką), czyli np kategoria "Lcd" będzie miała w tym polu: "1.2.3"
Kiedy będę chciał znaleść wszystkie kategorie na niższym poziomie, tworze zapytanie:
  1. SELECT * FROM categories WHERE path_up LIKE '1.2.3.%'


Dla kategorii Monitory:
  1. SELECT * FROM categories WHERE path_up LIKE '1.2.%'


Pytanie czy LIKE w tym wypadku będzie efektywny i wydajny ?
Pole path_up jest typu TEXT i posiada nałozony index.

I ogólnie czy takie rozwiązanie jest wydajne i sensowne?


EDIT:
Jednak na TEXT nie można załozyć indexu wiec zmieniłem typ na VARCHAR(1000) i widze że indeks działa. Jednak dalej mam pytanie czy trakie rozwiazanie drzewa jest dobre według Was?

Myślę też by dla identyfikatorów któe podaję po kropce w polu parh_up stworzyć osobną tabelę i tak trzymać polaczenia jeden do wielu (CATEGORIES_ID | CATEGORIES_ID_UP)
czyli dla naszej kategorii LCD wynik będzie wyglądał tak:

CATEGORIES_ID | CATEGORIES_ID_UP
3 | 1
3 | 2


Kategoria LCD:
CATEGORIES_ID | CATEGORIES_ID_UP
4 | 1
4 | 2
4 | 3
phpion
Nie wiem jak MySQL, ale PostgreSQL w takim przypadku użyłby indeksu. Domyślam się więc, że i MySQL go użyje. Najlepiej sprawdź to sobie sam: poprzedź zapytanie SELECT słowiem kluczowym EXPLAIN, czyli EXPLAIN SELECT * FROM...
Kocurro
Witam,

takie rozwiązanie nei jest zbyt dobre a to dlatego, że jesteś zmuszony używać konstrukcji LIKE ... ja bym tą konstrukcję przerobił chociaż na SUBSTR = bo to już lepiej podziała. Jednakże bardziej polecam zmianę struktury drzewa na strukturę z lewymi i prawymi extentami smile.gif

Pozdrawiam,
Łukasz
Sajrox
Co do lewych i prawych stron kategorii to wacham się dlatego że gdy będę miał np 200 000 kategorii to wraz z dodanienm nowej kategorii będe musiał zmieniać pole left lub right w bardzo duzej ilości kategorii co może być cięzkie dla bazy :/
Kocurro
Jest to o wiele lżejsze niż like ...

Pozwolę sobie linka wstawić by było wiadomo o czym mówię:

http://artykuly.zyxist.com/czytaj.php/drzewa_w_php_i_mysql
wry
like skorzysta z indexu jesli szukany string nie zaczyna sie od znaku dopasowania, tak jak mowil kocurro dobrym rozwiazanim jest uzyc nested tree
http://dev.mysql.com/tech-resources/articl...hical-data.html
btw dodanie nowej kategorii to kwestia wsadzenia jej do bazy z left = max(right) + 1 right = max(right) +2, zabawa zaczyna sie kiedy zdzialasz z podkategoriami, ale i tak jest to chyba najwydajnieszy ssposob przechowywania drzewa bo pozwala ci jednym zapytaniem wyswietlic potrzebne informacje
Sajrox
Jednak uzyję "Nested Set" aby ograniczyć ilość operacji w momencie dodania/usunięcia kategorii (chodzi o każdorazowe przesuwanie znacznika right) podziele swoje drzewko na kategorie główne oraz jej wszystkie podkategorie.

W przypadku dodania liścia kategorii lub jego usunięcia zmianiam znaczniki right/left tylko dla kategorii gównej na 1 poziomie w której wprowadzamy zmiany.
Wszystkie inne kategorie na 1 poziomie nie będą ruszane.

W celu wyświetlenia odpowiedniej porcji podkategorii dodam jeszcze pole parent_id. Znajdie się tutaj ID kategorii głównej na 1 poziomie.

Screen



W momencie dodania podkategorii do drzewa od polu parent_id = 1 przesuwam znaczniki tylko d drzewie od parent_id = 1. Wszystkie pozostałe pozostają bez zmian.

Co o tym sądzicie ?
Kocurro
Za dużo kombinujesz. Baza danych da sobie spokojnie radę bez takiego kombinowania, jak jest dobrze skonfigurowana to nie masz o co się bać. Ale jeśli już bardzo chcesz to możesz tak zrobić smile.gif
Sajrox
Jednak zdecydowałem się na standardowe Nested Set bez żadnych udziwnień. Jednak dfo szczęscią brakuje mi jednej rzeczy.
Przy przenoszeniu węzła musze zastosować na zapytania UPDATE. Jednak gdy wykonuje je po kolei, po po wykonaniu pierwszego UPDATE kolejny już nie ma sensu. Potrzebuje wykonać 2 update jednocześnie aby efekty były widoczne dopiero po ich wykonaniu. A nie że drugi update widzi zmiany dokonane przez pierwszy.
Sądziłenm że Transakcje załatwią sprawę a jednak nie sad.gif


Co o tym sądzicie ?
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.