Using filesort
n'est pas forcément une mauvaise chose. Le nom est un peu trompeur. Bien qu'il contienne un "fichier", cela ne signifie pas que les données sont écrites n'importe où sur le disque dur. Il est encore juste traité en mémoire.
À partir du manuel :
Vous comprenez pourquoi cela se produit dans votre requête, n'est-ce pas ? L'utilisation de ce type de sous-requêtes est un mauvais style car il s'agit d'une dépendante sous-requête. Pour chaque ligne de votre app
table la sous-requête est exécutée. Très mauvais. Réécrivez la requête avec une 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)
;
Cela utilise toujours une sous-requête dépendante, mais le explain
ça a l'air beaucoup mieux :
| 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 |
Une autre façon de le réécrire serait ceci :
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
;
L'explication est encore meilleure :
| 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 |
Et voici une version où vous n'avez aucune sous-requête dépendante :
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
;
Cela fonctionne comme ceci :Lorsque gp.dateup
est à son maximum, il n'y a pas de gp2.dateup
.