Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Optymalizacja zapytania + indeksy
Walian
post
Post #1





Grupa: Zarejestrowani
Postów: 124
Pomógł: 1
Dołączył: 13.07.2009

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


Mam takie zapytanie:
  1. SELECT
  2. SQL_CALC_FOUND_ROWS
  3. a.article_id,
  4. a.article_status,
  5. a.article_views,
  6. a.article_date_added,
  7. a.article_date_modified,
  8. a.article_desc,
  9. a.article_adder,
  10. a.article_last_changer,
  11. a.article_name,
  12. (
  13. SELECT
  14. m.member_level
  15. FROM
  16. members AS `m`
  17. WHERE
  18. LOWER(m.member_username)=LOWER(a.article_adder)
  19. ) AS `adder_level`,
  20. (
  21. SELECT
  22. m.member_level
  23. FROM
  24. members AS `m`
  25. WHERE
  26. LOWER(m.member_username)=LOWER(a.article_last_changer)
  27. ) AS `last_changer_level`
  28. FROM
  29. articles AS `a`
  30. WHERE
  31. a.article_category_id=1 -- tu odpowiednie Id
  32. ORDER BY
  33. a.article_date_added DESC
  34. LIMIT 0,20;


Służy do wylistowania / wyszukania artykułów dla danej kategorii.
Dodatkowo zwraca mi dodatkowe informacje o dodającym oraz o osobie, która jako ostatnia edytowała artykuł (edytować może autor lub administrator), m.in to czy dodający lub ostatni edytujący jest administratorem, czy też zwykłym użytkownikiem. Oczywiście zamiast tego zera przy limicie pojawia się odpowiedni offset (IMG:style_emoticons/default/winksmiley.jpg)

Dla testu dodałem ok. 1000 artykułów do bazy.
Niestety zapytanie zbyt długo się wykonuje, a i tak testuję to tylko na localhoście.
Czas więc zoptymalizować składnię zapytania o ile się da no i dodać indeksy.

Tabela artykułów:
  1. CREATE TABLE `articles` (
  2. `article_id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `article_category_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0,
  4. `article_status` tinyint(3) UNSIGNED NOT NULL DEFAULT 0,
  5. `article_views` int(11) UNSIGNED NOT NULL DEFAULT 0,
  6. `article_date_added` datetime NOT NULL,
  7. `article_date_modified` datetime NOT NULL,
  8. `article_desc` tinytext COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  9. `article_content` mediumtext COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  10. `article_adder` varchar(12) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  11. `article_last_changer` varchar(12) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  12. `article_name` varchar(64) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  13. `article_safe_name` varchar(64) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  14. PRIMARY KEY (`article_id`),
  15. UNIQUE KEY `article_name` (`article_name`),
  16. UNIQUE KEY `article_safe_name` (`article_safe_name`)
  17. ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci;

Pole member_username w tabeli members:
  1. `member_username` varchar(12) COLLATE utf8_polish_ci NOT NULL DEFAULT '',


I pytanie tak na marginesie - stosować słówko AS w zapytaniach czy lepiej skrócony zapis bez tego słowa kluczowego?
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
Walian
post
Post #2





Grupa: Zarejestrowani
Postów: 124
Pomógł: 1
Dołączył: 13.07.2009

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


Ok dzięki Mchl.
Złączenia już wykorzystywałem kilka razy, jednak w tym wypadku nie udawało mi się uzyskać pożądanych efektów więc tymczasowo zastosowałem podzapytania.
Co prawda musiałem zmienić w Twoim zapytaniu INNER JOIN-y na LEFT JOIN-y bo nie dostawałem wyników, ale teraz już jest OK.
Tak w ogóle to masz literówkę w:
Cytat
alc.member.level


Cytat("gothye")
skoro wyszukujesz po
  1. article_category_id

to czemu tutaj klucza nie zastosowałeś ?

Bo kategorii będzie bardzo niewiele, na początku ok. 15, maksymalnie myślę, że około 30.

Mam jeszcze jeden mały problem.
W menu mam wylistowane kategorie i chcę by obok każdej w nawiasie pokazało ile przypada widocznych artykułów dla danej kategorii.
O tym czy artykuł jest widoczny decyduje jego status z zakresu od 0 do 6.
Widoczne są tylko te ze statusem od 0 do 2 lub ze statusem 6.
Kategorie też mają swoje statusy, ale tylko od 0 do 3 i widoczne są wszystkie ze statusem mniejszym niż 3.

Tabela kategorii:
  1. CREATE TABLE `articles_categories` (
  2. `category_id` tinyint(3) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `category_sort_order` tinyint(3) UNSIGNED NOT NULL DEFAULT 0,
  4. `category_status` tinyint(3) UNSIGNED NOT NULL DEFAULT 0,
  5. `category_visible_articles` mediumint(8) UNSIGNED NOT NULL DEFAULT 0,
  6. `category_date_added` datetime NOT NULL,
  7. `category_date_modified` datetime NOT NULL,
  8. `category_adder` varchar(12) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  9. `category_last_changer` varchar(12) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  10. `category_name` varchar(32) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  11. `category_safe_name` varchar(32) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  12. `category_title` varchar(255) COLLATE utf8_polish_ci NOT NULL DEFAULT '',
  13. PRIMARY KEY (`category_id`),
  14. UNIQUE KEY `category_name` (`category_name`),
  15. UNIQUE KEY `category_safe_name` (`category_safe_name`),
  16. UNIQUE KEY `category_title` (`category_title`)
  17. ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci;


Na razie najlepsze zapytanie jakie udało mi się wymyślić ma taką postać:
  1. SELECT
  2. ac.category_id,
  3. ac.category_status,
  4. ac.category_name,
  5. ac.category_title,
  6. COUNT(a.article_id) AS `articles_count`
  7. FROM
  8. articles_categories AS `ac`
  9. LEFT JOIN
  10. articles AS `a`
  11. ON
  12. (a.article_category_id=ac.category_id) AND ((a.article_status < 3) OR (a.article_status = 6))
  13. WHERE
  14. (ac.category_status < 3)
  15. GROUP BY
  16. ac.category_id;


Dla ok. 1000 artykułów zapytanie wykonuje się średnio w 0.45 s, czyli chyba za długo.
Indeksów chyba nie ma sensu zakładać na pola id i status prawda?

Jak sami widzicie zapytanie mocno kombinowane :/
Zapytanie musi mi zwrócić również kategorie nieposiadające artykułów (0 w nawiasie).

Ten post edytował Walian 20.02.2010, 22:32:54
Go to the top of the page
+Quote Post
Mchl
post
Post #3





Grupa: Zarejestrowani
Postów: 855
Pomógł: 145
Dołączył: 17.07.2008
Skąd: High Memory Area

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


Cytat(Walian @ 20.02.2010, 22:27:40 ) *
Bo kategorii będzie bardzo niewiele, na początku ok. 15, maksymalnie myślę, że około 30.


No to co? Ważne po ile będzie artykułów w każdej kategorii.

Spróbuj tak:

Kod
SELECT
   ac.category_id,
   ac.category_status,
   ac.category_name,
   ac.category_title,
   a.articles_count
FROM
   articles_categories AS `ac`
LEFT JOIN (
   SELECT
      article_category_id
      COUNT(*) AS articles_count
   FROM
      articles AS `a`
   WHERE
      (a.article_status < 3) OR (a.article_status = 6)
   GROUP BY
      article_category_id
) AS a
ON
   (a.article_category_id=ac.category_id)
WHERE
   (ac.category_status < 3)


Ten post edytował Mchl 20.02.2010, 22:48:14
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: 7.10.2025 - 17:12