Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Wyświetlanie kategorii z użyciem cache w Laravel - optymalizacja
Forum PHP.pl > Forum > Przedszkole
trifek
Witajcie.
Mam zagwozdkę. Mam stronę wykorzystującą https://www.jstree.com oraz Laravel 7 z wykorzystaniem https://packagist.org/packages/kalnoy/nestedset

Mam tabelę z kategoriami (164574 rekordów) - która zajmuje około 22,3 MB (po zrzucie z phpmyadmin). Kategorie są praktycznie niezmienne.

Mój model i migracja wyglądają następująco:
  1. class Category extends Model
  2. {
  3. use ScopeActiveTrait;
  4. use NodeTrait;
  5. use HasSlug;
  6.  
  7. /**
  8.   * Get the options for generating the slug.
  9.   */
  10. public function getSlugOptions() : SlugOptions
  11. {
  12. return SlugOptions::create()
  13. ->generateSlugsFrom('category_name')
  14. ->slugsShouldBeNoLongerThan(160)
  15. ->saveSlugsTo('slug');
  16. }
  17.  
  18. protected $guarded = ['id'];
  19. protected $fillable = ['category_name', 'description', 'keywords', 'content', 'enable', 'photo', 'order', 'slug', '_lft', '_rgt', 'parent_id'];
  20. public $timestamps = false;
  21.  
  22. }
  23.  
  24. Schema::create('categories', function (Blueprint $table) {
  25. $table->bigIncrements('id');
  26. $table->string('category_name', 155);
  27. $table->string('description', 155)->nullable();
  28. $table->string('keywords', 155)->nullable();
  29. $table->longText('content')->nullable();
  30. $table->char('enable', 1)->default(0);
  31. $table->string('photo', 155)->nullable();
  32. $table->bigInteger('order')->default(0);
  33. $table->string('slug', 160)->nullable();
  34. NestedSet::columns($table);
  35. $table->engine = "InnoDB";
  36. $table->charset = 'utf8mb4';
  37. $table->collation = 'utf8mb4_unicode_ci';
  38. });
  39.  



Założenie:
1. wyświetlić drzewko kategorii
2. zaznaczyć na drzewku wybrane kategorie


Do zapisu wybranych kategorii mam:
  1. Schema::create('selected_product_categories', function (Blueprint $table) {
  2. $table->id();
  3. $table->bigInteger('product_id')->unsigned()->default(0);
  4. $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
  5. $table->bigInteger('category_id')->unsigned()->default(0);
  6. $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
  7. $table->timestamps();
  8. });
  9.  
  10. class SelectedProductCategory extends Model
  11. {
  12. protected $fillable = ['product_id', 'category_id'];
  13. protected $guarded = ['id'];
  14. }
  15.  

Mój kod do wyświetlania wygląda następująco:

  1. <div id="ajax" class="ajax"></div>
  2. <script>
  3. $(function () {
  4. $('#ajax').jstree({
  5. "checkbox": {
  6. "keep_selected_style": false
  7. },
  8. "plugins": [
  9. "checkbox",
  10. ],
  11. 'core': {
  12. 'data': {
  13. "url": "domain.com/products/categoryTree",
  14. "dataType": "json"
  15. }
  16. }
  17. }).on('changed.jstree', function (e, data) {
  18. var checked_ids = [];
  19. var selectedNodes = $('#ajax').jstree("get_selected", true);
  20. $.each(selectedNodes, function () {
  21. checked_ids.push(this.id);
  22. });
  23. $('.categoryTree').val(checked_ids);
  24. });
  25. });
  26.  
  27. </script>
  28.  
  29.  
  30.  
  31. public function categoryTree(Category $category, SelectedProductCategory $selectedProductCategory, Request $request)
  32. {
  33. $tree = Cache::remember('categories', 31536000, function () use ($category) {
  34. return $category->select(['id', 'category_name', 'parent_id', 'order', '_lft', '_rgt'])->active()->orderBy('order', 'ASC')->get();
  35. });
  36.  
  37. $nodes = $this->generateJsTree($tree->toTree(), ($request->exists('id')) ? $selectedProductCategory->where('product_id', $request->input('id'))->orderBy('id', 'ASC')->get() : null);
  38. return $nodes;
  39.  
  40. }
  41.  
  42.  
  43. private function generateJsTree($nodes, $selectedCategories): array
  44. {
  45. $categoryArray = array();
  46. $traverse = function ($categories, $prefix = '-') use (&$traverse, &$categoryArray, $selectedCategories) {
  47. foreach ($categories as $category) {
  48. $selected = false;
  49. if (!is_null($selectedCategories)) {
  50. $selected = $selectedCategories->contains('category_id', $category->id) ? true : false;
  51. }
  52.  
  53. $categoryArray[] = ['id' => $category->id, 'text' => $category->category_name, 'parent' => $category->parent_id questionmark.gif '#', 'state' => ['opened' => false, 'selected' => $selected]];
  54. $traverse($category->children, $prefix . '-');
  55. }
  56. };
  57. $traverse($nodes);
  58. return $categoryArray;
  59. }


Skrypt generuje mi plik z cache (~250MB) na serwerze, jednak drzewko wyświetla się baaaardzo wolno (po 3-5min).

W momencie gdy wkleję link z html do przeglądarki: domain.com/products/categoryTree to wygenerowanie danych zajmuje mu parę minut.

Co może być przyczyną takiego długiego wczytywania?
Co można lepiej zoptymalizować? Bardzo proszę o pomoc smile.gif

nospor
Ponad 160tys kategorii i te je wszystkie naraz wyswietlasz uzytkownikowi.... Co mozna zoptymalizowac sie jeszcze pytasz? WYwal to. Nie generuje sie takiej ilosci danych na raz to chyba logiczne
Masz generowac pierwszy poziom kategorii a po kliknieciu w ktorys masz ajaxem leciec po podkategorie dla tego poziomu. Ale tez tylko z jednego poziomu nizej a nie ze wszystkich
trifek
Tak, ale w momencie gdy ktoś doda produkt do np. 15 różnych kategorii (mam 7 poziomów "w głąb"), to jak w edycji pokazać takie drzewko?Musi być wczytane całe i rozłożone żeby użytkownik mógł znaleść co dodał.... Chyba że masz jakiś inny pomysł? smile.gif

Używam tego drzewka: https://www.jstree.com/docs/json/
nospor
Co to w ogole za kategorie ze moze ich byc 160tys?

- Samochod
--- Samochod z jednymi drzwiamu
------ Z jedna klamka
------ Z dwoma klamkami
--- Samochod z dwoma drzwiami
....
--- Samochod z 10 drzwiami


Moze poprostu przedobrzyles ze szczegolowoscia kategorii?
Nie mozesz pokazac wszystkich tylu kategorii i tyle w temacie. Albo wiec otwieraj to drzewko tylko dla wybranych kategorii zeby user widzial co wybral - to nadal nie bedzie 160tys albo kategorie wybrane wyswietlaj podspodem i tyle
gino
Cytat
Tak, ale w momencie gdy ktoś doda produkt do np. 15 różnych kategorii...


pomijając już co napisał @nospor pozwalasz użytkownikowi na coś takiego? Czyli mogę wrzucić kosiarkę do kategorii dajmy na to noże i nożyczki jak i do pojazdy samochodowe i narzędzia piekarskie? Ładny kocioł w tym sklepie.

gino
trifek
Sklep motoryzacyjny.
Produkt - przykładowo płyn do chłodnic może być w Volksvagen Golf 1, 2, 3, 4, 5, 6, 7, 8 + Seat Leon 1, 2, 3..., Skoda Octavia 1, 2, 3 itp....
Założenie jest takie że 1 produkt może być w wielu miejscach

Cytat(nospor @ 1.09.2020, 18:55:06 ) *
Co to w ogole za kategorie ze moze ich byc 160tys?

- Samochod
--- Samochod z jednymi drzwiamu
------ Z jedna klamka
------ Z dwoma klamkami
--- Samochod z dwoma drzwiami
....
--- Samochod z 10 drzwiami


Moze poprostu przedobrzyles ze szczegolowoscia kategorii?
Nie mozesz pokazac wszystkich tylu kategorii i tyle w temacie. Albo wiec otwieraj to drzewko tylko dla wybranych kategorii zeby user widzial co wybral - to nadal nie bedzie 160tys albo kategorie wybrane wyswietlaj podspodem i tyle


technicznie rzecz biorąc, to nie jest tak, że jak mam plik z cache to powinien być błyskawicznie przekazany do przeglądarki przez php?

Wydaje mi się że to wszystko "klęka" przez to:

  1. private function generateJsTree($nodes, $selectedCategories): array
  2. {
  3. $categoryArray = array();
  4. $traverse = function ($categories, $prefix = '-') use (&$traverse, &$categoryArray, $selectedCategories) {
  5. foreach ($categories as $category) {
  6. $selected = false;
  7. if (!is_null($selectedCategories)) {
  8. $selected = $selectedCategories->contains('category_id', $category->id) ? true : false;
  9. }
  10.  
  11. $categoryArray[] = ['id' => $category->id, 'text' => $category->category_name, 'parent' => $category->parent_id questionmark.gif '#', 'state' => ['opened' => false, 'selected' => $selected]];
  12. $traverse($category->children, $prefix . '-');
  13. }
  14. };
  15. $traverse($nodes);
  16. return $categoryArray;
  17. }
  18.  


Bez tego odznaczania działa to sporo szybciej
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.