Using filesort
niekoniecznie jest złą rzeczą. Nazwa jest nieco myląca. Chociaż zawiera "plik", nie oznacza to, że dane są zapisywane w dowolnym miejscu na dysku twardym. Nadal jest tylko przetwarzany w pamięci.
Z podręcznika :
Rozumiesz, dlaczego tak się dzieje w Twoim zapytaniu, prawda? Używanie tego rodzaju podzapytań jest złym stylem, ponieważ jest zależne podzapytanie. Dla każdego wiersza w Twojej app
tabela podzapytanie jest wykonywane. Bardzo źle. Przepisz zapytanie z join
.
select app.id,
gp.dateup
from app
join gamesplatform_pricehistory gp on gp.id_app = app.id
where app.id > 0
and gp.country = 1
and gp.dateup = (SELECT MAX(dateup) FROM gamesplatform_pricehistory smgp WHERE smgp.id_app = gp.id_app AND smgp.country = 1)
;
To nadal używa zależnego podzapytania, ale explain
wygląda znacznie lepiej:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|--------------------|-------|-------|---------------|---------|---------|----------------------------|------|--------------------------|
| 1 | PRIMARY | app | index | PRIMARY | PRIMARY | 4 | (null) | 2 | Using where; Using index |
| 1 | PRIMARY | gp | ref | id_app | id_app | 5 | db_2_034bc.app.id,const | 1 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | smgp | ref | id_app | id_app | 5 | db_2_034bc.gp.id_app,const | 1 | Using index |
Innym sposobem na przepisanie tego byłoby to:
select app.id,
gp.dateup
from app
LEFT join
(SELECT id_app, MAX(dateup) AS dateup
FROM gamesplatform_pricehistory
WHERE country = 1
GROUP BY id_app
)gp on gp.id_app = app.id
where app.id > 0
;
Wyjaśnienie wygląda jeszcze lepiej:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|-------------|----------------------------|-------|---------------|---------|---------|--------|------|--------------------------|
| 1 | PRIMARY | app | index | PRIMARY | PRIMARY | 4 | (null) | 2 | Using where; Using index |
| 1 | PRIMARY | <derived2> | ALL | (null) | (null) | (null) | (null) | 2 | |
| 2 | DERIVED | gamesplatform_pricehistory | index | (null) | id_app | 13 | (null) | 2 | Using where; Using index |
A oto wersja, w której nie masz żadnego zależnego podzapytania:
select app.id,
gp.dateup
from app
left join gamesplatform_pricehistory gp on gp.id_app = app.id and country = 1
left join gamesplatform_pricehistory gp2 on gp.id_app = app.id and country = 1 and gp.dateup < gp2.dateup
where app.id > 0
and gp2.dateup is null
;
Działa to tak:Kiedy gp.dateup
osiąga maksimum, nie ma gp2.dateup
.