Question

J'ai une question qui ressemble à ceci:

select
id
, int1
, int2
, (select count(*) from big_table_with_millions_of_rows 
    where id between t.int1 and t.int2)
from myTable t
where
....

select renvoie exactement une ligne. L'identifiant utilisé dans la ligne sélectionner est une colonne indexée (clé primaire). Si je remplace t.int1 et t.int2 avec les valeurs de INT1 / INT2 retourné par cette seule ligne, la requête complète en millisecondes. Si j'exécute la requête comme ci-dessus - à savoir avec des références à INT1 / INT2, il faut environ 10 minutes. Quand je lance profileur et regarde ce qui se passe en fait, je vois que 99% du temps, le moteur est occupé de renvoyer des données de la requête en ligne. Il semble que MySql fonctionne réellement le

select ... from big_table_with_millions_of_rows 

bit de la requête en ligne une fois avant d'appliquer la

where id between t.int1 and t.int2

bit au résultat. Cela peut-il être vrai? Sinon, ce qui se passe? Je l'avais toujours pensé que SELECTs inline étaient potentiellement dangereux, car ils sont exécutés ligne par ligne que le dernier élément de la requête, mais pour des situations comme celle-ci, où le SELECT initial est en effet très sélectif, il peut être très efficace. Quelqu'un peut-il nous éclairer à ce sujet?

EDIT: grâce à la rétroaction jusqu'à présent. Ce qui me préoccupe est pas tant sur la nature ligne par ligne de la requête en ligne, mais le fait qu'il semble incapable d'utiliser l'index de clé primaire face à des variables plutôt que (les mêmes) valeurs codées en dur. Je pense que si serait ANALYSER n'a pas été exécuté récemment, l'optimiseur suppose qu'il doit faire un scan de table car il n'a aucune connaissance sur la distribution des données. Mais ne devrait pas le fait que la recherche de gamme se fait sur la clé primaire ne compense pas cela?

Était-ce utile?

La solution

Si la sous-requête est corrélative pas optimisé bien, essayez cette requête:

select
  t.id
, t.int1
, t.int2
, count(*)
from myTable t
left outer join big_table_with_millions_of_rows b
  on (b.id between t.int1 and t.int2)
where
....
group by t.id

Cela devrait optimiser beaucoup mieux.


Re votre question mise à jour: droit, MySQL n'est pas SGBDR les plus sophistiqués sur le marché en termes d'optimisation. Ne soyez pas surpris quand MySQL ne peut pas optimiser les cas d'angle comme celui-ci.

Je suis un fan de MySQL pour sa facilité d'utilisation et open source et toutes ces bonnes choses, mais la vérité est que ses concurrents sont en avance de MySQL en termes de technologie. Chaque SGBDR a quelques « points aveugles », mais MySQL semble être de plus.

Vérifiez également que vous utilisez la dernière version de MySQL. Ils améliorent l'optimiseur dans chaque version, donc vous pourriez obtenir de meilleurs résultats avec une version plus récente.

Autres conseils

Essayez d'éviter les sous-requêtes en utilisant REJOIGNEZ corrélées si vous le pouvez.

Regardez cette superbe vidéo sur les performances de MySQL sur youtube . Aller à 31:00 minutes. Le président Jay Pipes parle à éviter les sous-requêtes corrélées.

Si une des références de champs sous-requêtes de la requête contenant, la sous-requête doit être ré-exécuter par chaque ligne de la requête contenant, car les champs mentionnés peuvent être différents dans chaque ligne. Si elle est complètement autonome, il peut être exécuté une seule fois avant que la requête externe commence le traitement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top