web-dev-qa-db-fra.com

Mysql sélectionner où ne figure pas dans le tableau

J'ai 2 tables (A et B) avec les mêmes clés primaires. Je veux sélectionner toutes les lignes qui sont en A et non en B. Les travaux suivants:

select * from A where not exists (select * from B where A.pk=B.pk);

mais cela semble assez mauvais (~ 2 sec sur seulement 100k lignes en A et 3-10k de moins en B)

Existe-t-il une meilleure façon de gérer cela? Peut-être en tant que joint gauche?

select * from A left join B on A.x=B.y where B.y is null;

Sur mes données, cela semble fonctionner un peu plus vite (~ 10%) mais qu'en est-il en général?

52
BCS

J'utilise des requêtes au format de votre deuxième exemple. Une jointure est généralement plus évolutive qu'une sous-requête corrélée.

35
Bill Karwin

Je pense que votre dernière déclaration est la meilleure façon. Vous pouvez aussi essayer

SELECT A.*    
from A left join B on 
    A.x = B.y
    where B.y is null
55
Nick Berardi

Les jointures sont généralement plus rapides (dans MySQL), mais vous devriez également considérer votre schéma d'indexation si vous constatez qu'il se déplace toujours lentement. Généralement, toute configuration de champ en tant que clé étrangère (à l'aide d'INNODB) aura déjà un ensemble d'index. Si vous utilisez MYISAM, assurez-vous que toutes les colonnes de l'instruction ON sont indexées et envisagez également d'ajouter des colonnes dans la clause WHERE à la fin de l'index, pour en faire un index de couverture. Cela permet au moteur d'avoir accès à toutes les données nécessaires dans l'index, supprimant la nécessité de faire un deuxième aller-retour vers les données d'origine. Gardez à l'esprit que cela aura un impact sur la vitesse des insertions/mises à jour/suppressions, mais peut considérablement augmenter la vitesse de la requête.

2
ChoNuff

J'utilise également des jointures gauches avec un critère de type "où table2.id est nul".

Semble certainement être plus efficace que l'option de requête imbriquée.

2
Dave Rix