• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Optymalizacja zapytania

Object Storage Arubacloud
0 głosów
204 wizyt
pytanie zadane 6 stycznia 2019 w SQL, bazy danych przez Muhin Gaduła (4,120 p.)
edycja 6 stycznia 2019 przez Muhin

Cześć,

Mam takie zapytanie:

SELECT serieses_list.id,
(AVG(sr.story) + AVG(sr.graphics) + AVG(sr.music) + AVG(sr.characters)) / 4 AS middle
FROM serieses_list
JOIN serieses_tags ON serieses_tags.series_id = serieses_list.id
LEFT JOIN serieses_ratings AS sr ON sr.series_id = serieses_list.id
GROUP BY serieses_tags.series_id, serieses_tags.tag_id, sr.series_id, sr.user_id
HAVING SUM(IF(serieses_tags.tag_id = 1, 1, 0)) > 0
AND SUM(IF(serieses_tags.tag_id = 3, 1, 0)) > 0
AND SUM(IF(serieses_tags.tag_id = 6, 1, 0)) > 0
ORDER BY middle ASC
LIMIT 10 OFFSET 0
serieses_list
id name description cover type episode_number episode_length emission_statuas
serieses_tags
id tag_id series_id
serieses_ratings
id series_id user_id story graphics music characters
1 16 1 8 7 9 6

Explain:

 

na ten moment w tabeli serieses_ratings jest ~28000 wierszy. Wykonanie tego zapytania trwa jakieś 1,5 sekundy. Co można zrobić żeby to jakoś zoptymalizować?

Edit: Poczytałem trochę o GROUP BY i udało mi się zbić czas wykonania do 900 ms

1 odpowiedź

+1 głos
odpowiedź 6 stycznia 2019 przez rafal.budzis Szeryf (85,260 p.)
wybrane 6 stycznia 2019 przez Muhin
 
Najlepsza
1 ) podaj strukture tabel ;-)

2 ) pomyśl czy nie mozna dodać indeksow

3 ) pokaz wynik wynik zapytania EXPLAIN

Mogę w ciemno powiedzieć ze tabela serieses_list nie jest ci potrzebna w zapytaniu bo nie pobierasz z niej żadnych danych oprócz ID do złaczenia. Może jesteś w stanie wykorzystać dwie tabeli i zrobić JOIN w taki sposób ?

ON serieses_tags.series_id = serieses_ratings.series_id

Zastanawia mnie też sama klauzula HAVING dziwnie dość wygląda. Napiszesz mi dlaczego jest zapisane to w taki sposób ?
komentarz 6 stycznia 2019 przez Muhin Gaduła (4,120 p.)
Rzeczywiście, tabela serieses_list  jest tutaj zbędna, choć to nic nie zmieniło.

W edycji posta dodałem informacje o które prosiłeś.
komentarz 6 stycznia 2019 przez Muhin Gaduła (4,120 p.)

@rafal612b,

Dlatego, że tylko w taki sposób jestem w stanie wyszukiwać wierszy na podstawie wielu tagów z innej tabeli.

komentarz 6 stycznia 2019 przez rafal.budzis Szeryf (85,260 p.)

hmmm można by też spróbować zrobić mniejsze pod zapytanie ;) Zamiast tego HAVING

SELECT series_id,

(AVG(sr.story) + AVG(sr.graphics) + AVG(sr.music) + AVG(sr.characters)) / 4 AS middle

FROM

( SELECT tag_id, series_id from serieses_tags WHERE serieses_tags.tag_id in [1,3,6])

LEFT JOIN serieses_ratings AS sr ON sr.series_id = series_id
GROUP BY serieses_tags.series_id, serieses_tags.tag_id, sr.series_id, sr.user_id

ORDER BY middle ASC

LIMIT 10 OFFSET 0

PS. nie jestem pewny czy dobrze napisałem podzapytanie bo dawno tego nie pisałem ;)

komentarz 6 stycznia 2019 przez rafal.budzis Szeryf (85,260 p.)
Must have w twoim problemie jest dodanie indeksów z tego co widać po EXPLAIN tabelka serieses_tags nie ma żadnych posible_index dodaj dwa indeksy do tabeli serieses_tags Pierwszy na dwie kolumny (tag_id, series_id) a drugi odwrotny ( series_id, tag_id). Sprawdź czy przyśpieszy ;) Potem EXPLAIN powie ci który indeks jest lepszy i który jest używany.
komentarz 6 stycznia 2019 przez Muhin Gaduła (4,120 p.)
Może to pytanie zabrzmi głupio, ale o jakie indexy chodzi?
komentarz 6 stycznia 2019 przez Muhin Gaduła (4,120 p.)

Dobra, udało mi się znacznie zbić czas wykonania tego zapytania.

Generalnie kod który podałeś zmienił logikę tego zapytania, ale na jego podstawie napisałem to:

SELECT DISTINCT(s.series_id),
(AVG(sr.story) + AVG(sr.graphics) + AVG(sr.music) + AVG(sr.characters)) / 4 AS middle
FROM
(
	SELECT series_id, tag_id
	FROM serieses_tags
	GROUP BY series_id
	HAVING SUM(CASE WHEN tag_id = 1 THEN 1 ELSE 0 END) > 0
	AND SUM(CASE WHEN tag_id = 3 THEN 1 ELSE 0 END) > 0
	AND SUM(CASE WHEN tag_id = 6 THEN 1 ELSE 0 END) > 0
) AS s
JOIN serieses_list ON serieses_list.id = s.series_id
LEFT JOIN serieses_ratings AS sr ON sr.series_id = s.series_id
GROUP BY s.series_id, s.tag_id, sr.series_id
ORDER BY middle DESC

Ten kod nie dość, że działa to jego wykonanie trwa 0.032s.

Podobne pytania

0 głosów
1 odpowiedź 218 wizyt
pytanie zadane 9 kwietnia 2020 w SQL, bazy danych przez wsnofi Bywalec (2,680 p.)
0 głosów
3 odpowiedzi 359 wizyt
0 głosów
1 odpowiedź 463 wizyt
pytanie zadane 11 listopada 2018 w PHP przez Śmieszek_;3 Użytkownik (780 p.)

92,573 zapytań

141,423 odpowiedzi

319,648 komentarzy

61,959 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...