sql >> Database >  >> RDS >> Mysql

Mysql-subquery doet altijd filesort

Using filesort is niet noodzakelijk een slechte zaak. De naam is een beetje misleidend. Hoewel het "bestand" bevat, betekent dit niet dat de gegevens overal op de harde schijf worden geschreven. Het wordt nog steeds gewoon in het geheugen verwerkt.

Uit de handleiding :

Je begrijpt waarom dit in je query gebeurt, toch? Het gebruik van dit soort subquery's is een slechte stijl omdat het een afhankelijk . is subquery. Voor elke rij in je app tabel wordt de subquery uitgevoerd. Heel slecht. Herschrijf de query met een 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)
;

Dit gebruikt nog steeds een afhankelijke subquery, maar de explain ziet er veel beter uit:

| 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 |

Een andere manier om het te herschrijven is als volgt:

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
;

De uitleg ziet er nog beter uit:

| 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 |

En hier is een versie waarin je helemaal geen afhankelijke subquery hebt:

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
;

Het werkt als volgt:Wanneer gp.dateup maximaal is, is er geen gp2.dateup .



  1. MYSQL OR vs IN-prestaties

  2. Op MySQL gebaseerde web-app:gemakkelijkste manier voor gebruikers om een ​​bestelling of items te kiezen?

  3. lege string in orakel

  4. Kies uit meerdere partities tegelijk