2012-02-28 5 views
3

je la requête SQL suivante:mysql jointure gauche prend trop de temps

SELECT 
    upd.*, 
    usr.username AS `username`, 
    usr.profile_picture AS `profile_picture` 
FROM 
    updates AS upd 
LEFT JOIN 
    subscribers AS sub ON upd.uid=sub.suid 
LEFT JOIN 
    users AS usr ON upd.uid=usr.uid 
WHERE 
    upd.deleted='0' && (upd.uid='118697835834' || sub.uid='118697835834') 
GROUP BY upd.id 
ORDER BY upd.date DESC 
LIMIT 0, 15 

où je reçois tous les utilisateurs (118697835834) mises à jour, sa photo de profil d'une autre table en utilisant jointure gauche et aussi tous ses utilisateurs d'abonnement mises à jour afin puis-je les montrer dans son fil d'actualité.

Cependant, comme les mises à jour deviennent de plus en plus que la requête prend plus de temps pour charger ... dès maintenant en utilisant Profiler Codeigniter je peux voir que la requête prend 1,3793 ...

En ce moment j'ai créé autour de 18k comptes factices et souscrits de moi et vice versa afin que je puisse tester le temps d'exécution ... les temps que je reçois sont tragiques compte tenu que je suis dans localhost ...

J'ai aussi quelques index où je suppose besoin de plus dans la table des utilisateurs (nom d'utilisateur et uid comme unique), mise à jour de la table (update_id comme unique et uid comme index)

Je suppose que je suis en train de faire quelque chose de mal à obtenir des résultats si mauvais ...

EDIT: Exécution EXPLIQUER Résultat Etendu:

Array 
(
    [0] => stdClass Object 
     (
      [id] => 1 
      [select_type] => SIMPLE 
      [table] => upd 
      [type] => ALL 
      [possible_keys] => i2 
      [key] => 
      [key_len] => 
      [ref] => 
      [rows] => 22 
      [filtered] => 100.00 
      [Extra] => Using where; Using temporary; Using filesort 
     ) 

    [1] => stdClass Object 
     (
      [id] => 1 
      [select_type] => SIMPLE 
      [table] => sub 
      [type] => ALL 
      [possible_keys] => 
      [key] => 
      [key_len] => 
      [ref] => 
      [rows] => 18244 
      [filtered] => 100.00 
      [Extra] => Using where 
     ) 

    [2] => stdClass Object 
     (
      [id] => 1 
      [select_type] => SIMPLE 
      [table] => usr 
      [type] => eq_ref 
      [possible_keys] => uid 
      [key] => uid 
      [key_len] => 8 
      [ref] => site.upd.uid 
      [rows] => 1 
      [filtered] => 100.00 
      [Extra] => 
     ) 

) 

EDIT2: SHOW CREATE des tableaux Table des utilisateurs:

CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`uid` bigint(20) NOT NULL, 
`username` varchar(20) COLLATE utf8_unicode_ci NOT NULL, 
`email` text CHARACTER SET latin1 NOT NULL, 
`password` text CHARACTER SET latin1 NOT NULL, 
`profile_picture_full` text COLLATE utf8_unicode_ci NOT NULL, 
`profile_picture` text COLLATE utf8_unicode_ci NOT NULL, 
`date_registered` datetime NOT NULL, 
`activated` tinyint(1) NOT NULL, 
`closed` tinyint(1) NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `uid` (`uid`), 
UNIQUE KEY `username` (`username`) 
) ENGINE=MyISAM AUTO_INCREMENT=23521 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

table abonnés:

CREATE TABLE `subscribers` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`sid` bigint(20) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`suid` bigint(20) NOT NULL, 
`date` datetime NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=18255 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

Tableau Mises à jour:

CREATE TABLE `updates` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`update_id` bigint(19) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`type` text COLLATE utf8_unicode_ci NOT NULL, 
`update` text COLLATE utf8_unicode_ci NOT NULL, 
`date` datetime NOT NULL, 
`total_likes` int(11) NOT NULL, 
`total_comments` int(11) NOT NULL, 
`total_favorites` int(11) NOT NULL, 
`category` bigint(20) NOT NULL, 
`deleted` tinyint(1) NOT NULL, 
`deleted_date` datetime NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `i1` (`update_id`), 
KEY `i2` (`uid`), 
KEY `deleted_index` (`deleted`) 
) ENGINE=MyISAM AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 
+2

Utilisez EXPLAIN afin que vous puissiez voir comment la requête est en cours d'exécution –

+0

avez-vous fait 'EXPLAIN EXTENDED' (ajoutez-le à votre requête) –

+0

avez-vous indexé tout ce que vous recherchez et joindre? –

Répondre

2

Essayez celui-ci (sans GROUP BY):

SELECT 
    upd.*, 
    usr.username AS `username`, 
    usr.profile_picture AS `profile_picture` 
FROM 
     updates AS upd 
    LEFT JOIN 
     users AS usr 
      ON upd.uid = usr.uid 
WHERE 
    upd.deleted='0' 
    AND 
    (upd.uid='118697835834' 
    OR EXISTS 
     (SELECT * 
     FROM subscribers AS sub 
     WHERE upd.uid = sub.suid 
      AND sub.uid = '118697835834' 
    ) 
    ) 
ORDER BY upd.date DESC 
LIMIT 0, 15 

Au moins, les colonnes qui sont utilisées dans les jointures doivent être indexées: updates.uid, users.uid et subscribers.suid. Je voudrais également ajouter un index sur subscribers.uid.

+0

c'est en effet plus rapide ... il faut maintenant indexer correctement pour espérer de meilleures performances – fxuser

+2

@fxuser: Editez votre question et ajoutez les descriptions de vos tables (types de données de colonnes, index et PK, FKs). –

+0

J'ai ajouté tout le spectacle créé de 3 tables – fxuser

0

ne devrait pas prendre trop de temps pour courir; avez-vous un index sur 'supprimé'? Que fait le 'GROUP BY id'? Devrait-il être UID? Peut-il sortir, si ID est en fait juste un incrément automatique, ID unique? (Ce qui serait coûteux et aussi inutile)

+0

ajouté un index sur supprimé, rien n'a changé. GROUP BY id est nécessaire pour que la requête affiche toutes les mises à jour car, en la supprimant, elle continuera à afficher 1 à plusieurs reprises. – fxuser

1

Essayez:

SELECT 
    upd.*, 
    usr.username AS `username`, 
    usr.profile_picture AS `profile_picture` 
FROM 
    updates AS upd 
LEFT JOIN 
    subscribers AS sub ON upd.uid=sub.suid 
LEFT JOIN 
    users AS usr ON upd.uid=usr.uid 
WHERE 
    upd.deleted=0 and upd.uid in (118697835834,118697835834) 
GROUP BY upd.id 
ORDER BY upd.date DESC 
LIMIT 0, 15 

Notez que ' a été retiré de valeurs numériques et les opérateurs binaires changé aux opérateurs conventionnels.

+0

Toujours le même temps de chargement – fxuser

0

Je pense que vous feriez mieux de séparer cette requête en un select sur la table des utilisateurs, puis d'unir ces résultats avec le select sur la table des abonnés.

+0

Commencez également par la table des utilisateurs, puis joignez les mises à jour. Il est probable que votre table de mise à jour sera beaucoup plus grande que vos utilisateurs. – Luc

1

ne pas utiliser les jointures, essayez celui-ci:

select *, 
     (select username from users where uid = upd.uid) as username, 
     (select profile_picture from users where uid = upd.uid) as profile_picture, 
from updates as upd 
WHERE 
    upd.deleted='0' && upd.uid='118697835834' 

(non testé!)

peut-être vous devez vérifier s'il existe un abonné dans la clause where avec un autre sous-sélection .

Une autre façon serait de faire une jointure sur des sous-sélections et non sur toute la table. Cela peut également augmenter vos performances.

+0

Et la raison d'éviter 'JOIN' est? Pouvez-vous poster un plan 'EXPLAIN' de votre requête qui est meilleur que celui de' JOIN'ed? – Naltharial

+0

vous semblez manquer table des abonnés ici ... – fxuser

+0

@Naltharial: Je n'ai pas mis en place la base de données, donc je n'ai pas EXPLAIN. Mais j'ai souvent augmenté la performance en évitant les «jointures» dans mes projets. – user1027167