2017-02-03 1 views
1

J'ai une table (T1) avec ca. 500000 enregistrements en double non:Connexion optimale dans deux tables MySQL

ID1 Relation ID2 
4  Rel4  13 
5  Rel5  4 
13  Rel13  16 
16  Rel16  5 

J'ai la table des propriétés T1_Prop:

ID Entity  
4  Ent4  
5  Ent5 
13 Ent13 
16 Ent16 

Je veux rejoindre ces deux tables (basé sur id: 4) de manière efficace comme suit:

Entity Relation Entity 
Ent4  Rel4  Ent13 
Ent5  Rel5  EntEnt4 

J'ai conçu cette instruction select incluant JOIN qui fonctionne correctement. Cependant, je ne sais pas si ce la meilleure façon de le faire:

select 
    a.entity, 
    r.relation, 
    b.entity 
from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 AND (r.ID1=4 OR r.ID2=4) 
INNER JOIN T1_Prop as b ON b.ID=r.ID2; 
+1

des questions sur http://codereview.stackexchange.com/ appartiennent Optimisation – Sirko

+0

meilleur en termes de quoi? – Shadow

+0

En terme d'efficacité.Je veux juste utiliser MySQL comme son et je ne cherche pas à l'améliorer avec certaines bibliothèques exernal ou alors – StaOver

Répondre

0

C'est une belle utilisation de SQL. Il est construit pour ce genre de requête.

Vous aurez besoin de deux index de couverture pour accélérer ce processus, le T1. Ils sont:

(ID1, ID2, relation) 

et

(ID2, ID1, relation) 

Les deux indices sont pour le traitement de la clause OR. C'est le seul problème de performance potentiel que je vois, et c'est juste parce que les opérations OR parfois tromper le planificateur de requêtes pour faire trop d'analyse de table. Essayez de refactoriser votre requête afin de rendre plus visible votre sélection de valeurs d'ID.

select a.entity, r.relation, b.entity 
    from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 
INNER JOIN T1_Prop as b ON b.ID=r.ID2 
WHERE (r.ID1=4 OR r.ID2=4) 

Ensuite, si vous avez des problèmes avec des performances, après avoir créé la couverture des index, factoriser encore à

select a.entity, r.relation, b.entity 
    from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 
INNER JOIN T1_Prop as b ON b.ID=r.ID2 
WHERE r.ID1=4 
UNION 
select a.entity, r.relation, b.entity 
    from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 
INNER JOIN T1_Prop as b ON b.ID=r.ID2 
WHERE r.ID2=4 
+0

Faites ce 'UNION ALL', qui sera plus efficace que le dédoublonnage inutile de la valeur par défaut. –

0

Votre requête ressemble bien à l'exception de la première clause ON. La condition (r.ID1=4 OR r.ID2=4) n'est pas une règle pour laquelle enregistrer à partir de T1_Prop joindre à l'enregistrement T1. C'est plutôt une condition, quels enregistrements T1 à considérer et appartient par conséquent dans la clause WHERE.

select 
    a.entity AS entity1, 
    r.relation, 
    b.entity AS entity2 
FROM t1 AS r 
INNER JOIN t1_prop AS a ON a.id = r.id1 
INNER JOIN t1_prop AS b ON b.id = r.id2 
WHERE r.id1 = 4 OR r.id2 = 4; 

Ceci ne changera pas le plan d'exécution; le SGBD l'exécutera exactement de la même manière. Mais il est plus lisible car il montre l'intention réelle: obtenir des relations où l'un des ID est 4 et joindre les entités à ces relations.

Une autre option pour afficher cette intention est:

select 
    a.entity AS entity1, 
    r.relation, 
    b.entity AS entity2 
FROM (SELECT * FROM t1 WHERE r.id1 = 4 OR r.id2 = 4) AS r 
INNER JOIN t1_prop AS a ON a.id = r.id1 
INNER JOIN t1_prop AS b ON b.id = r.id2; 

Certains considèrent les sous-requêtes dans de moins lisible, mais, bien, d'autres ne le font pas. Et quand les requêtes deviennent plus complexes et disent que vous avez même affaire à des agrégats provenant de différentes tables, c'est souvent le moyen de créer une requête propre.

Aucune des requêtes ci-dessus n'est réellement meilleure ou pire que l'autre.

+0

La sous-requête nécessite un effort supplémentaire inutile. –

+0

@Rick James: Lequel? Le SGBD doit arriver au même plan d'exécution pour les deux requêtes, à condition que son optimiseur fonctionne bien. Si MySQL ne le fait pas encore, tout dépend de son implémentation actuelle qui pourrait mieux supporter la première ou la deuxième requête. Peut-être que MySQL a des problèmes avec les tables dérivées dans sa version actuelle; Je ne sais pas. Mais même si c'est le cas, il peut déjà être différent dans la prochaine version :-) –

+0

'EXPLAIN SELECT ...' pour les deux devrait dire si l'optimiseur est devenu plus intelligent. Ce _might_ soit quelque chose qui s'est amélioré dans environ 5.7. –