2009-06-15 6 views
1

alors disons que je construis ce système de gestion de contacts. Il existe une table USER et une table CONTACT_INFO. Pour chaque USER, je peux avoir zéro ou plusieurs enregistrements CONTACT_INFO. La façon dont je l'ai défini, j'ai configuré une clé étrangère dans ma table CONTACT_INFO pour pointer vers l'enregistrement USER correspondant.Créer une requête optimale pour trouver les enregistrements qui sont dans un seul tableau

Je voudrais rechercher tous les enregistrements USER qui n'ont pas d'enregistrements CONTACT_INFO.

Je pense que cela pourrait se faire:

SELECT * FROM user u WHERE u.user_id NOT IN (SELECT DISTINCT c.user_id FROM CONTACT_INFO); 

Ma préoccupation est que les tables se développent, les performances de cette requête peut se dégrader de manière significative.

Une idée avec laquelle je joue est d'ajouter une colonne dans la table USER qui indique si elle a des enregistrements CONTACT_INFO ou non. Aussi, je me demandais, si en insérant un enregistrement dans CONTACT_INFO, le SGBD doit vérifier que l'enregistrement existe, il accèderait déjà à cet enregistrement pour des raisons de vérification et donc de mise à jour, quand je mets à jour un enregistrement CONTACT_INFO ne devrait pas être C'est coûteux, performant.

Comme toujours, les commentaires sont appréciés.

+1

Vous devriez essayer plusieurs des options ci-dessous, puis déterminer le plan de requête et les performances pour chacun d'entre eux et choisir le meilleur. –

+0

De quels SGBD parlons-nous? – AakashM

Répondre

2

De mes tests, ce qui suit est plus rapide que la méthode de BradC:

select (...) 
from user u 
where not exists (select null from CONTACT_INFO c where u.user_id = c.user_id) 

Cela peut être parce que le compilateur ne faire la conversion elle-même, je ne sais pas. Le Dorfier a raison en principe, cependant: si vous avez configuré vos index directement sur la base de données (les deux colonnes user_id doivent être indexées), votre réponse et la plupart de ces réponses seront extrêmement rapides, peu importe combien d'enregistrements vous avez dans votre base de données.

Soit dit en passant, si vous cherchez un moyen d'obtenir une requête qui répertorie les utilisateurs avec une valeur booléenne « HasContactInfo », vous pouvez faire quelque chose comme ceci:

select u.(...), 
    (case when exists (select null from CONTACT_INFO c where c.user_id = u.user_id) then 1 
     else null 
     end) has_contact_info 
from user u 

Cette deuxième solution ne peut pas être utile dans votre cas, mais je l'ai trouvé beaucoup plus rapide que certaines requêtes plus simples que j'avais supposé être optimisées automatiquement.

3

plus simple est:

SELECT (...) 
FROM user u 
LEFT OUTER JOIN CONTACT_INFO c 
ON u.user_id = c.user_id 
WHERE c.user_id IS NULL 

Il semble plus difficile à manier, mais devrait évoluer mieux.

+0

Les optimiseurs que j'ai testés traitent cela de la même manière qu'un simple NOT EXISTS.(Mais c'est une bonne technique pour beaucoup de cas de toute façon, et légèrement plus portable, ce qui signifie qu'il fonctionne dans les anciennes versions de MySQL.) – dkretz

1

Avez-vous des raisons de penser que les performances vont se dégrader? C'est l'un des types de requête les plus efficaces en SQL. Mais déposez le DISTINCT.

+0

pourquoi devrais-je supprimer le DISTINCT? – Irwin

+0

Parce qu'il peut effectivement calculer la liste de valeurs agrégées. Tout ce qu'il faut vraiment faire est de regarder sur l'index et voir s'il y a une valeur à tous - il suffit de trouver le premier. – dkretz

1

Au moins dans l'oracle, j'obtenir de meilleures performances en utilisant

où 0 = (select count (*) à partir CONTACT_INFO c où ...)

au lieu de NOT IN clause.

Questions connexes