2009-12-25 11 views
2

J'effectue une requête qui recherche des valeurs dans une table qui ne sont pas dans une autre. Par exemple:Optimisation de requête MySQL

SELECT id FROM table1 WHERE id NOT IN (SELECT id FROM table2); 

Les deux tableaux ont environ 1 million de lignes, mais seulement quelques centaines qui ne correspondent pas à des valeurs qui sont retournées dans le jeu de résultats. La requête prend environ 35 secondes. Faire un profil d'exposition sur la requête montre que mysql passe la plupart du temps dans l'état de "préparation". Des idées sur comment je peux optimiser cet état ou ce qui se passe réellement pendant la "préparation"?

La valeur d'identifiant dans les deux tables est indexée et de même type et taille.

Le profil complet de la requête est:

+--------------------------------+----------+ 
| Status       | Duration | 
+--------------------------------+----------+ 
| (initialization)    | 0  | 
| checking query cache for query | 0  | 
| Opening tables     | 0.13  | 
| System lock     | 0  | 
| Table lock      | 0  | 
| init       | 0.01  | 
| optimizing      | 0  | 
| statistics      | 0  | 
| preparing      | 0  | 
| executing      | 0  | 
| Sending data     | 0  | 
| optimizing      | 0  | 
| statistics      | 0  | 
| preparing      | 34.83 | 
| end       | 0  | 
| query end      | 0  | 
| freeing items     | 0  | 
| closing tables     | 0  | 
| logging slow query    | 0  | 
+--------------------------------+----------+ 

Des conseils sont appréciés.

Merci.

Répondre

3

Je devais quitter la table2 sur l'ID où ID est null. Cela vous donnera un retour beaucoup plus rapide des données.

select 
    a.id 
from 
    table1 a 
    left join table2 b on a.id = b.id and b.id is null 
+0

heureux que vous chnaged qui se joignent droit à une gauche! –

+0

Devrait-il être là et où b.id est nul? –

+0

il est préférable de spécifier cela dans la clause where; mais l'optimiseur devrait produire des plans identiques. –

1
SELECT id FROM table1 
LEFT JOIN table2 ON table1.id = table2.id 
WHERE table2.id IS NULL; 
+0

La requête prend encore environ 30 secondes mais pour ce" show profile " " la plupart du temps est dans "Envoi de données". Est-ce juste le temps qu'il faut à mysql pour lancer la requête ou y at-il quelque chose que je puisse faire pour l'accélérer? –

+0

cela dépendra des index que vous avez définis ... –

2

Il n'y a rien à optimiser - NOT IN produit un plan de requête équivalente à LEFT JOIN/IS NULL dans MySQL. Quote:

Cependant, ces trois méthodes génèrent trois plans différents qui sont exécutés par trois morceaux de code différents. Le code qui exécute le prédicat EXISTS est environ 30% moins efficace que ceux qui exécutent index_subquery et LEFT JOIN optimisé pour utiliser la méthode Not exists. C'est pourquoi la meilleure façon de rechercher des valeurs manquantes dans MySQL est d'utiliser un LEFT JOIN/IS NULL ou NOT IN plutôt que NOT EXISTS.

Pour plus d'informations, consultez NOT IN vs. NOT EXISTS vs. LEFT JOIN/IS NULL: MySQL

+0

'table2.id' devrait être indexé bien sûr pour produire la requête équivalente. Mais à partir de son nom (qui ressemble à un «PK») et du fait que la requête prend «35» secondes pour des «1,000,000» lignes, nous pouvons conclure qu'il est indexé. – Quassnoi