Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [mySQL] Sortowanie wg kolumny COUNT
starcode
post
Post #1





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 18.06.2006

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


Witam.

Borykam się ostatnio z wydajnością zapytania, w którym występuje złączenie dwóch dużych tabel (pierwsza 2mln rekordów, druga 4mln rekordów).

Zapytanie podstawowo wygląda tak:
  1. SELECT * , p.`product_id` AS `product_id` , COUNT( DISTINCT (o.`store_id` ) ) AS `liczba_produktow` , MIN( o.`product_offer_price` ) AS `cena`
  2. FROM `products` p INNER JOIN `products_offers` o ON ( o.`product_id` = p.`product_id` AND o.`product_offer_status` = '1' )
  3. WHERE p.`product_navi_3` = '1158'
  4. GROUP BY p.`product_id`
  5. ORDER BY `liczba_produktow` DESC
  6. LIMIT 0 , 100


Na wszelkie pola biorące udział w warunkach zapytania (czyli product_id, store_id, product_offer_status, product_navi_3) są nałożone indeksy (indeksu nie ma jedynie na kolumnie ceny - product_offer_price). Ale nie to jest problemem. Z przeprowadzonych testów, spowolnienie (czy raczej zasobożerność) zwiększa klauzula ORDER BY.
Gdy klauzuli ORDER BY nie ma (tj. sortowanie nie odbywa się po kolumnie `liczba_produktow` lub `cena`) mySQL przegląda jedynie rekordy, które spełniają warunek WHERE (czyli product_navi_3 = 1158), w momencie gdy ORDER BY jest - mysql przegląda wszystkie rekordy w tabeli (2mln!).
Dzieje się tak dlatego, że nie ma indeksów na sortowanych kolumnach - ale nie ma (chyba?) możliwości nałożenia indeksu na kolumny, które są obliczane w "locie".

Dlatego też wykombinowałem SELECT z SELECT'a, który wygląda mniej więcej tak:
  1. SELECT *
  2. FROM (
  3. SELECT p.`product_name` , p.`product_id` , COUNT( DISTINCT (o.`store_id` ) ) AS `liczba_produktow` , MIN( o.`product_offer_price` ) AS `cena`
  4. FROM `products` p INNER JOIN `products_offers` o ON ( o.`product_id` = p.`product_id` AND o.`product_offer_status` = '1' AND p.`product_navi_1` = '1154' )
  5. GROUP BY p.`product_id`
  6. LIMIT 0 , 5000
  7. )res
  8. ORDER BY res.`liczba_produktow` DESC
  9. LIMIT 0 , 100


Zapytanie zagnieżdzone pobiera tylko tyle rekordów ile jest w limicie (tj. nie przeszukuje całej tabeli). Wyszedłem z założenia, że mogę pobrać wszystkie rekordy i dopiero je posortować - w danym indeksie (kategorii zazwyczaj nie ma więcej niż 5000 rekordów), więc stosunkowo małe porcje danych są pobierane.
Niestety w zapytaniu dalej, dodanie ORDER BY powoduje, że mimo wszystko pobierane (przeglądane) są wszystkie dane z tabeli.

Czy jest jakieś rozwiązanie, aby mySQL na siłę nie próbował pobierać wszystkich danych ponownie, tylko wykonał sortowanie na tym mniejszym już zbiorze (z zagnieżdzonego selecta)?

Z góry dzięki za pomoc...

Ten post edytował starcode 2.05.2013, 12:18:53
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
starcode
post
Post #2





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 18.06.2006

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


Usunięcie DISTINCT nie wpłynie na to, że będzie pobieranych mniej rekordów z bazy - a jednocześnie informuje mnie ile jest produktów z RÓŻNYCH sklepów.
Tak samo pomijam, fakt, że może się zdarzyć, że 5001 produkt będzie tym najliczniejszym.

Zależy mi na tym, aby pobrać dane nie przeglądając całej tabeli. Nie wiem czemu mysql - mimo, że ma zawęzić sie tylko do produktów z danej kategorii - przegląda wszystkie rekordy.
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: 13.10.2025 - 22:45