Mysql
 sql >> Base de données >  >> RDS >> Mysql

La sous-requête MySQL fait toujours le tri des fichiers

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 .