Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z zapytaniem i brak pomysłu na jego optymalizacje...
Forum PHP.pl > Forum > Bazy danych > MySQL
sniver
Najchętniej to w takim momentach był zrobił to: sciana.gif

Mam zapytanie i baze, niby wszystko ok, ale wykonuje sie troche długo bo baza produktów troche w EroBAY urosła...

Zapytanie jest z wyszukiwarki, a konkretnie przyporządkowuje kategorie produktów względem znalezionych w bazie danych...

Oto query:

  1. SELECT
  2. `c`.`CAT_Id` AS `id`,
  3. `c`.`PARENT_Id` AS `parent`,
  4. `c`.`CAT_Name` AS `name`,
  5. `c`.`CAT_Url` AS `url`,
  6. (
  7. SELECT
  8. COUNT(1)
  9. FROM
  10. `products` AS `p`
  11. JOIN `productsdescription` AS `pd` ON (`pd`.`PRD_Id` = `p`.`PRD_Id`)
  12. WHERE
  13. (`p`.`CAT_Id` IN (
  14. SELECT
  15. `c2`.`CAT_Id`
  16. FROM
  17. `categories` AS `c2`
  18. WHERE
  19. (
  20. (`c2`.`CAT_Id` = `c`.`CAT_Id`)
  21. OR (`c2`.`CAT_Ip` LIKE CONCAT(`c`.`CAT_Id`,'.%'))
  22. )
  23. AND (
  24. (`c2`.`CAT_Active` = 1)
  25. AND (`c2`.`CAT_Counter` > 0)
  26. )
  27. )
  28. )
  29. AND (MATCH(`pd`.`PRD_Name`, `pd`.`PRD_Description`) AGAINST ('kostium' IN BOOLEAN MODE))
  30. ) AS `licznik`
  31.  
  32. FROM
  33. `categories` AS `c`
  34.  
  35. WHERE
  36. (
  37. (`c`.`CAT_Active` = 1)
  38. AND (`c`.`CAT_Counter` > 0)
  39. )
  40. AND (
  41. (`c`.`CAT_Id` = 61)
  42. OR (`c`.`PARENT_Id` = 61)
  43. OR (`c`.`CAT_Ip` LIKE CONCAT(`c`.`CAT_Id`,'.%'))
  44. OR (`c`.`PARENT_Id` = 3)
  45. )
  46.  
  47. GROUP BY `c`.`CAT_Id`
  48.  
  49. HAVING
  50. (`licznik` > 0)
  51.  
  52. ORDER BY `c`.`PARENT_Id` ASC, `c`.`CAT_Sort` ASC


Problem znajduje się w subzapytaniu zwracającym wartość licznik, a konkretnie w kolejnym zagnierzdzeniu które wpisuje do IN podkategorie..

Może ktoś ma jakiś fajny pomysł jak to ugryźć...
Noidea
Z tego co widzę to drzewko kategorii jest zrobione w "sprytny" sposób przez zapisanie ID w stringu ( "2.34.232.3422" ). Nazwanie kolumny CAT_Ip i oddzielanie liczb kropkami nie sprawia, że rozwiązanie jest bardziej profesjonalne, równie dobrze można oddzielać je przecinkami.
Taką strukturę stosują ludzie, którym bardziej zależy na łatwości zapisania zapytania ( WHERE ip LIKE id + '.%' ) niż na wydajności - czyli masz to co chciałeś smile.gif

Najlepsze rozwiązanie to google -> mysql category tree, przeanalizować kilka rozwiązań, wybrać najlepsze, przerobić strukturę bazy.


Rozwiązania doraźne:
Widzę, że w podzapytaniu zakładasz, że CAT_Id jest zawsze na początku CAT_Ip. Może da się to wykorzystać, wstawić jakąś dodatkową kolumnę do tabeli categories z powtórzonymi danymi, zamienić skorelowane podzapytanie na JOINa, cokolwiek. Tylko najpierw muszę wiedzieć co jest w kolumnie CAT_Ip. A dokładnie to ID której kategorii jest na samym początku.
sniver
CAT_Ip to tz. IP kategorii :-)
w takim formacie jak to napisałeś ;>

właśnie pomyślałem o tym że do każdej kategorii mogę dodać pole (jak wspomniałeś) i tam zapisać wszystkie dzieci i dzieci, dzieci jakiejś kategorii

Przeanalizowałem kilka metod na robienie drzewa IP. Powyższa metoda została wykorzystana na www.erobay.pl - więc wiadome do czego to ma być.
W/g waszego doświadczenia jaka struktura drzewa kategorii może być najbardziej optymalna?
Pilsener
Cytat
Taką strukturę stosują ludzie, którym bardziej zależy na łatwości zapisania zapytania ( WHERE ip LIKE id + '.%' ) niż na wydajności
- nie sądzę. Pokaż mi bardziej wydajną metodę pozwalającą pobierać, przenosić, usuwać wybrane gałęzie. Poza tym pola "IP" czy depth dodawane są pomocniczo właśnie w tym celu.

Proponuję zrobić explain i utworzyć odpowiednie indeksy, powinno pomóc. Jeżeli problemem jest rozmiar drzewa to można je podzielić na kilka mniejszych.

P.S. > Możesz też poeksperymentować z modelem nested set, ale jak patrzę na te pętle w zapytaniach to nie wiem, czy to będzie wygodne i wydajne...
sniver
Dodałem dodatkowe pole. Pole o dzwięcznej nazwie "Collection" - a konkretnie CAT_Collection, czyli zbiór :-)

Każda z kategorii ma swoje dzieci (a dzieci mają dzieci). System każdorazowo musi odpytywać bazę o to które to dzieci należą do danej kategorii, w tym fragmencie:

  1. [...]
  2. (`p`.`CAT_Id` IN (
  3. SELECT
  4. `c2`.`CAT_Id`
  5. FROM
  6. `categories` AS `c2`
  7. WHERE
  8. (
  9. (`c2`.`CAT_Id` = `c`.`CAT_Id`)
  10. OR (`c2`.`CAT_Ip` LIKE CONCAT(`c`.`CAT_Id`,'.%'))
  11. )
  12. AND (
  13. (`c2`.`CAT_Active` = 1)
  14. AND (`c2`.`CAT_Counter` > 0)
  15. )
  16. )
  17. )
  18.  
  19. [...]


Powyższe rozwiązanie zamieniłem na dodanie informacji o spisie kategorii do pola: 'CAT_Collection', a w nim informacje w stylu 5, 94, 115, 116

Teraz gotowy zbiór potomków wpisuję do tego warunku i wygląda tak: (`p`.`CAT_Id` IN (`c`.`CAT_Collection`)) - różnica w działaniu? Piorunująca :]
Czy to dobre czy nie - dam znać za tydzień jak przybędzie odwiedzających i baza produktów sie zwiększy na EroBAY.pl :-)
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.