12
votes

MySQL n'utilise pas d'index lorsque la déclaration "non in" est présente

La structure de la table est la suivante:

1   SIMPLE  test    index_merge PRIMARY,one,two,three,four  one,two 5,5     30  Using sort_union(one,two); Using where; Using filesort


9 commentaires

Quelle est la taille de votre table? Et pourriez-vous essayer d'utiliser index de force (primaire) pour voir s'il y a un gain de performance?


Avez-vous essayé d'utiliser NOT_EXIST ()?


Stackoverflow.com/Questions/6120100/MYSQL-NOT-IN -Query-optim ize


@Mani environ 4 millions d'enregistrements


@Alec sont les valeurs 204177, 214518, 231429, 242739, 243834, 244354, 244644, 244690 Différent chaque fois que la requête s'exécute, ou constante? Si différent, à quelle fréquence le get est-il exécuté?


C'est une requête très inhabituelle d'exécuter à plusieurs reprises. Comment as-tu fini ici? Il existe peut-être une autre approche de stockage de données qui pourrait atténuer la solution.


Combien d'enregistrements récupérez-vous après avoir utilisé pas dans la condition ? En l'aperçu, votre pas dans court-circuits votre autre "gros" conditions , ce qui vous laisse avec 2 ou Conditions qui sont minuscules. Ayant utilisé direction qui semble avoir une cardinalité faible, cela oblige MySQL à numériser toutes les lignes pour satisfaire vos conditions de 2 ou . C'est mes 2 cents, je sais que cela n'aide pas vraiment mais votre sont vraiment, vraiment laid :)


@Bohemian Les valeurs changent à chaque fois


@alec Il est trop tard pour répondre maintenant, après la fin de la prime, si vous voulez de meilleures réponses. Vous devriez surveiller le site pour commentaires / questions, surtout s'il y a une prime en jeu


6 Réponses :


4
votes

Si votre version MySQL est inférieure à 5.0.7, le problème MySQL peut être une raison

regarder ce billet dans MySQL Bug suivi https://bugs.mysql.com /bug.php?id=10561


0 commentaires

4
votes

Mélange et et ou causerait souvent un plan de requête étrange sur MySQL, dans mon expérience. Je n'ai pas assez de données sur la table pour tester, mais j'essaierais de réécrire votre requête en utilisant Union tout . Après tout, ou dans est fondamentalement union .

L'idée est de le casser sur des conditions plus petites afin que mysql puisse utiliser différents index optimisé pour chaque partie plutôt que par opposition à la barrage ensemble. xxx


0 commentaires

4
votes

Il serait bon d'avoir une vidange de données d'échantillonnage à tester, mais j'ai créé certains de moi-même. Ensuite, j'ai divisé chacun des quatre extérieurs dans des sous-requêtes, les syndiquées et déplacé la commande à l'ensemble de résultats final.

J'ai eu des problèmes avec des index lors de l'utilisation complexe où les clauses et pour moi il ressemble à vous Avoir une application de chat / messagerie et essayez d'obtenir des messages vers et depuis un utilisateur particulier dans une seule requête. Personnellement, je les scinderais en requêtes individuelles pour simplifier le code / les requêtes.

Voici ma requête: xxx


0 commentaires

5
votes

Je ne suis pas sûr de savoir pourquoi cela ne fonctionne pas correctement. Qu'est-ce que je manque dans les index? P>

Je suis sûr que le planificateur de requête fonctionne parfaitement, vous ne manquez rien dans les index qui aideraient dans ce cas. Le planificateur de requêtes a décidé qu'il serait plus rapide d'utiliser un index différent car les deux requêtes sont très différentes. P>

Nous pouvons rendre l'optimiseur à utiliser une union des index pour nous qui le rendra considérablement plus rapide. Vous pouvez conserver le pas dans code> et ne pas modifier l'une des déclarations ou code>. J'ai dirigé des repères de base de la méthode que j'ai utilisée contre la méthode de l'Union. Les mises en garde s'appliquent car votre configuration de DB peut être très différente du mien. Exécution de la requête A 1000 fois et cela 3 fois, j'ai pris le meilleur temps pour chaque requête ... p>

requête optimisée indiquée ci-dessous b> p> xxx Pré>

réécrit comme un ensemble de syndicions b> p> xxx pré>

pense comme l'optimiseur et travaillez avec moins de données forte > p>

Le SQL suivant est plusieurs commandes de grandeur plus rapidement dans les tests sur une base de données d'environ 4 millions de lignes. Le changement de clé est la ligne suivante p> xxx pré>

Cette ligne est vaste, réduisant énormément l'ensemble de données que MySQL doit fonctionner car nous utilisons dans code> de pas dans code>. Ceci est la nouvelle requête, j'ai essayé de ne pas trop changer la requête d'origine. P>

1. I don't want these 10 items from a 1,000,000 records I need the other 999,990, this reads the whole index.
2. I only want these 10 from a 1,000,000 records. This might only require one disk seek.


1 commentaires

Heureux d'avoir pu aider. Si vous voulez d'autres idées sur la façon de syntoniser ce qui précède, il y a de meilleurs indices que vous pouvez utiliser. Vous ne gagnerez pas grand chose, mais si l'optimiseur leur choisit, il y a une forte probabilité qu'ils soient plus optimales. Ils sont plus petits que les indices actuels et cela pourrait être le plus gros gain.




1
votes

commencez par ce xxx pré>

supposer que la sous-requête a beaucoup moins de lignes que test code>, cela peut fonctionner plus rapidement. P>

maintenant, pour Utilisez "Evaluation paresseuse" pour accélérer plus: P>

PRIMARY KEY(id)
INDEX(from, id)
INDEX(to,   id)


4 commentaires

Oui. Cela fait longtemps. (Vous avez une requête méchante ici. La vraie solution peut impliquer de repenser le schéma.)


Je sais que c'est méchant mais je pense que l'OP sait que aussi, il a suffisamment de représentant que je suppose qu'il sait ce qu'il fait. La question pose pourquoi le pas dans cause des problèmes et j'ai essayé de résoudre ce problème. La requête / schéma peut être abordée de nombreuses manières. Je serai de retour dans quelques heures, c'est un petit monde. J'étais à Ysports et j'aimais là-bas.


@Harry Oui, au courant de la requête Nasty :(


Comme déjà mentionné, ou est un tueur de couple qui conduit effectivement à des analyses de table. pas dans (Sélectionnez ...) est beaucoup pire que pas dans (1,2,3) en raison des appels répétés à la sous-requête.