2014-08-28 3 views
0

J'ai plusieurs tables que j'essaie de rejoindre. J'ai ajouté des index aux tables pour augmenter la vitesse mais prend encore longtemps pour se joindre. Je suppose que c'est prévu mais je me demandais s'il y avait un moyen plus efficace de créer une jointure avec plusieurs tables. J'ai également mis le net_read_timeout = à 150 puisque j'obtenais une erreur de connexion perdue. Ma requête ressemble à:optimisation pour joindre plusieurs tables dans mysql

set net_read_timeout = 150; 
ALTER TABLE wspeed2 ADD INDEX (speed,roadtypeID) --For all the tables 

SELECT a.month,a.roadTypeID,a.speed,a.pid, a.or, b.pid, b.or, c.pid, c.or, d.pid, d.or, 
     e.pid, e.or, f.pid, f.or, g.pid, g.or, h.pid, h.or, i.pid, i.or, j.pid, j.or, 
     k.pid, k.or, l.pid, l.or, m.pid, m.or, n.pid, n.or, o.pid, o.or, p.pid, p.or, 
     q.pid, q.or, r.pid, r.or, s.pid, s.or, t.pid, t.or, u.pid, u.or, v.pid, v.or 
FROM wspeed2 a, wspeed3 b, wspeed20 c, wspeed24 d, wspeed25 e, wspeed26 f, wspeed27 g, wspeed63 h, wspeed65 i, wspeed68 j, 
    wspeed69 k, wspeed70 l, wspeed71 m, wspeed72 n, wspeed73 o, wspeed74 p, wspeed75 q, wspeed76 r, wspeed77 s, wspeed78 t, wspeed81 u, wspeed82 v 
WHERE a.speed = b.speed and b.speed = c.speed and c.speed = d.speed and d.speed = e.speed and e.speed = f.speed and f.speed = g.speed and g.speed = h.speed 
    and h.speed = i.speed and i.speed = j.speed and j.speed = k.speed and k.speed = l.speed and l.speed = m.speed and m.speed = n.speed and n.speed = o.speed 
    and o.speed = p.speed and p.speed = q.speed and q.speed = r.speed and r.speed = s.speed and s.speed = t.speed and t.speed = u.speed and u.speed = v.speed 
GROUP BY a.speed; 
+0

Je viens de Microsoft fond; cependant, en général, j'utiliserais la table temporaire ou d'autres tables de transfert quand j'ai plus de 5 tables à joindre. –

+0

Ceci est le principal problème avec les bases de données SQL. Il n'y a pas de meilleure façon de le faire que je suis au courant de – ControlAltDel

Répondre

0

Bien que la requête elle-même semble simple mais étrange, ici c'est avec les jointures. Note ... Puisque vous aviez a = bb = cc = d etc ... cela veut aussi dire a = ra = sa = t etc ... Donc, au lieu de tous les compter sur l'alias devant, il pourrait aider le moteur doit avoir toutes les autres tables de vitesse directement liées à l'alias de niveau "a" racine comme je l'ai ci-dessous. Cela dit, vous joignez 21 tables différentes, si une ou plusieurs tables n'ont pas d'enregistrement pour la vitesse correspondante dans le tableau "a", elles n'apparaîtront PAS dans le jeu de résultats. Si vous voulez ALL sans tenir compte d'une correspondance dans l'autre table, changez-les tous à LEFT JOIN à la place. Maintenant, en regardant votre tableau "a", vous êtes basé sur un type de route et un mois par vitesse. La colonne de vitesse est-elle une colonne unique? Je pense que c'est, mais pas positif. Si l'une des tables sous-jacentes jointes a plus d'un enregistrement par la même valeur de vitesse, vous obtiendrez un résultat cartésien et pourrait étouffer votre requête.

De plus, vous aviez un groupe par, mais pas de colonnes de fonctions d'agrégation telles qu'un SUM (quelque chose), count(), avg(), min(), max(), alors quel est le point du groupe . Vous porterez plutôt qu'il a ordonné par quelque chose (de préférence quelque chose avec un index sur la « une » table

SELECT 
     a.month, a.roadTypeID, a.speed, 
     a.pid, a.or, b.pid, b.or, c.pid, c.or, d.pid, d.or, 
     e.pid, e.or, f.pid, f.or, g.pid, g.or, h.pid, h.or, 
     i.pid, i.or, j.pid, j.or, k.pid, k.or, l.pid, l.or, 
     m.pid, m.or, n.pid, n.or, o.pid, o.or, p.pid, p.or, 
     q.pid, q.or, r.pid, r.or, s.pid, s.or, t.pid, t.or, 
     u.pid, u.or, v.pid, v.or 
    FROM 
     wspeed2 a 
     JOIN wspeed3 b on a.speed = b.speed 
     JOIN wspeed20 c on a.speed = c.speed 
     JOIN wspeed24 d on a.speed = d.speed 
     JOIN wspeed25 e on a.speed = e.speed 
     JOIN wspeed26 f on a.speed = f.speed 
     JOIN wspeed27 g on a.speed = g.speed 
     JOIN wspeed63 h on a.speed = h.speed 
     JOIN wspeed65 i on a.speed = i.speed 
     JOIN wspeed68 j on a.speed = j.speed 
     JOIN wspeed69 k on a.speed = k.speed 
     JOIN wspeed70 l on a.speed = l.speed 
     JOIN wspeed71 m on a.speed = m.speed 
     JOIN wspeed72 n on a.speed = n.speed 
     JOIN wspeed73 o on a.speed = o.speed 
     JOIN wspeed74 p on a.speed = p.speed 
     JOIN wspeed75 q on a.speed = q.speed 
     JOIN wspeed76 r on a.speed = r.speed 
     JOIN wspeed77 s on a.speed = s.speed 
     JOIN wspeed78 t on a.speed = t.speed 
     JOIN wspeed81 u on a.speed = u.speed 
     JOIN wspeed82 v on a.speed = v.speed 

Si cela ne fonctionne pas, peut-être ajouter mot-clé MySQL « STRAIGHT » pourrait aider, par exemple:.

sélectionnez STRAIGHT_JOIN [reste de requête]

+0

@Daniel, heureux que cela semble fonctionner pour vous. Pourriez-vous me faire part de l'amélioration des performances de la requête? Cela pourrait être bon pour d'autres avec des données réelles et des jointures multiples similaires. Connaître avant/après les temps passés sur ces requêtes et futures est bon à savoir. – DRapp

+0

Ouais, pas de problème. Après avoir vu et essayé votre structure de requête, j'ai décidé d'inclure également pk pour toutes les tables qui correspondraient à toutes. Dans ce cas les pk étaient composés de monthid, roadtype et speed. Lorsque vous faites la jointure avec cette structure et le pk en place, la vitesse de la requête est améliorée de 5 min à une seconde. –

0

en utilisant la jointure interne et gauche/droite vous donnera une meilleure performance. Essayez de réécrire la requête de cette façon -

select ... from t1 
innerjoin t2 on t1.pk=t2.fk 
leftjoin t3 on t1.pk=t3.fk 
+1

Je ne vois pas pourquoi MySQL n'optimiserait pas les jointures implicites et explicites pour produire le même chemin d'exécution. Pourquoi pensez-vous que des jointures explicites donneraient de meilleures performances? –

+0

si 3 tables ont chacune 100 lignes. Dans la méthode "FROM t1, t2", il créera d'abord 1000000 lignes, puis filtrera. mais dans "FROM t1 join t2 ON ..", il créera uniquement des lignes correspondantes. –

+1

@Biswajit, êtes-vous sûr de ça? C'est une optimisation assez basique. J'ai du mal à croire que MySQL soit inconscient. –

0

Si la colonne speed est pas unique dans ces tableaux (et probablement ce n'est pas, étant donné que vous avez dit que vous avez ajouté un index avec speed comme colonne principale ...

Si t Dans ces tableaux, il y a plusieurs lignes avec la même valeur de speed, alors votre requête pourrait créer un immense ensemble.

Faisons quelques calculs simples. S'il y a deux lignes dans chaque table qui ont la même valeur de vitesse, alors les opérations JOIN entre a et b créeront 4 lignes pour cette vitesse. Lorsque nous ajoutons la jointure à c, avec deux autres lignes, cela représente un total de 8 lignes. Quand nous obtenons toutes les 22 tables jointes, chacune avec deux lignes, nous sommes à 2^22 ou plus de 4 millions de lignes. Et puis cet ensemble de lignes, avec la même valeur pour speed, doit être traité dans une opération GROUP BY pour éliminer les doublons.

(Bien sûr, si l'une des tables n'a pas de ligne de cette même valeur speed, la requête produirait aucune ligne pour cette speed.)

Personnellement, je l'ancien fossé Syntaxe de virgule pour l'opération JOIN et utilisez le mot clé JOIN à la place. Et je déplacerais les prédicats de jointure de la clause WHERE vers la clause ON appropriée.

Je ferais également de l'une des tables le "pilote" pour toutes les jointures, j'utiliserais une référence à la même table dans chacune des jointures. (Nous savons que si a=b et b=c, puis a=c. Mais je ne suis pas sûr de l'optimiseur MySQL, si cela fait une différence si nous spécifions a=b and a=c à la place de a=b and b=c.

S'il y a un nombre relativement peu de valeurs distinctes de speed dans chacune des tables, mais beaucoup de lignes avec la même valeur, je considérerais en utilisant des vues en ligne pour obtenir une seule rangée pour chaque vitesse de chacune des tables MySQL peut utiliser un index approprié pour optimiser le GROUPE PAR l'opération sur chaque table individuelle ... J'opterais pour un index de couverture ... par exemple

ON wspeed20 (speed, pid, `or`) 
ON wspeed24 (speed, pid, `or`) 

Unfor En règle générale, la table dérivée (résultat d'une requête de vue en ligne) n'est pas indexée, de sorte que les opérations JOIN peuvent être coûteuses (pour un grand nombre de lignes de chaque requête de vue en ligne).

SELECT a.month,a.roadTypeID,a.speed,a.pid,a.or, b.pid, b.or, c.pid, c.or, d.pid, d.or, 
    e.pid, e.or, f.pid, f.or, g.pid, g.or, h.pid, h.or, i.pid, i.or, j.pid, j.or, 
    k.pid, k.or, l.pid, l.or, m.pid, m.or, n.pid, n.or, o.pid, o.or, p.pid, p.or, 
    q.pid, q.or, r.pid, r.or, s.pid, s.or, t.pid, t.or, u.pid, u.or, v.pid, v.or 

    FROM (SELECT speed, pid, `or` FROM wspeed2 GROUP BY speed) a 
    JOIN (SELECT speed, pid, `or` FROM wspeed3 GROUP BY speed) b ON b.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed20 GROUP BY speed) c ON c.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed24 GROUP BY speed) d ON d.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed25 GROUP BY speed) e ON e.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed26 GROUP BY speed) f ON f.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed27 GROUP BY speed) g ON g.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed63 GROUP BY speed) h ON h.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed65 GROUP BY speed) i ON i.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed68 GROUP BY speed) j ON j.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed69 GROUP BY speed) k ON k.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed70 GROUP BY speed) l ON l.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed71 GROUP BY speed) m ON m.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed72 GROUP BY speed) n ON n.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed73 GROUP BY speed) o ON o.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed74 GROUP BY speed) p ON p.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed75 GROUP BY speed) q ON q.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed76 GROUP BY speed) r ON r.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed77 GROUP BY speed) s ON s.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed78 GROUP BY speed) t ON t.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed81 GROUP BY speed) u ON u.speed = a.speed 
    JOIN (SELECT speed, pid, `or` FROM wspeed82 GROUP BY speed) v ON v.speed = a.speed 

qui a le potentiel de réduire le nombre de lignes à joindre (à nouveau, s'il y a un grand nombre de valeurs en double pour speed, et un petit nombre de valeurs distinctes pour speed.) Mais , encore une fois, les opérations JOIN entre les tables dérivées n'auront aucun index disponible. (Au moins, pas dans les versions de MySQL jusqu'à 5.6.)