Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [mySQL] Sortowanie wg kolumny COUNT
starcode
post 2.05.2013, 12:18:13
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

Posty w temacie


Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 14.08.2025 - 08:10