2010-11-11 11 views
1

Comment puis-je éviter d'utiliser une table temporaire pour cette requête tout en atteignant toujours le même objectif?Comment éviter d'utiliser une table temporaire pour cette requête simple

EXPLAIN EXTENDED 
SELECT DISTINCT id, view_count 
    FROM 
     screenshot_udb_affect_assoc 
    INNER JOIN 
     screenshot ON id = screenshot_id 
    WHERE unit_id = 110 LIMIT 0, 6 

id select_type table type possible_keys key key_len ref rows filtered Extra 
1 SIMPLE screenshot_udb_affect_assoc ref screenshot_id,unit_id unit_id 4 const 34 100.00 Using temporary 
1 SIMPLE screenshot eq_ref PRIMARY PRIMARY 4 source_core.screenshot_udb_affect_assoc.screenshot... 1 100.00 

J'ai mis à jour la requête de ne pas utiliser plus RAND() et au lieu de la LIMIT sera aléatoire via PHP. Bien qu'il montre encore qu'il est en utilisant une table temporaire

+0

Est-ce que 'unit_id' appartient à' screensho't? Combien de captures d'écran y a-t-il avec 'unit_id = 110'? Combien de 'screenshot_udb_affect_assoc' par' screenshot'? – Quassnoi

+0

Environ 150 captures d'écran pour une unité donnée, probablement 12-15 unités par capture d'écran – Webnet

+0

Pourriez-vous donner un exemple de la nouvelle requête que vous produisez (de préférence avec un EXPLAIN aussi)? –

Répondre

2
SELECT rnd_id, rnd_value 
FROM (
     SELECT @cnt := COUNT(*) + 1, 
       @lim := 6 
     FROM screenshot 
     JOIN screenshot_udb_affect_assoc 
     ON  screenshot_id = id 
     WHERE unit_id = 110 
     ) vars 
STRAIGHT_JOIN 
     (
     SELECT r.*, 
       @lim := @lim - 1 
     FROM (
       SELECT id, view_count 
       FROM screenshot 
       JOIN screenshot_udb_affect_assoc 
       ON  screenshot_id = id 
       WHERE unit_id = 110 
       ) r 
     WHERE (@cnt := @cnt - 1) 
       AND RAND() < @lim/@cnt 
     ) i 

expliqués plus en détail dans cet article:

Cela a encore besoin de deux scans sur toutes les lignes répondant à la requête, mais pas filesort.

Créer les indices suivants:

screenshot (unit_id) 
screenshot_udb_affect_assoc (screenshot_id) 
+0

Je déteste ne pas utiliser cela, mais si cela nécessite deux scans, je veux vraiment essayer de descendre à 1 scan si je peux. – Webnet

+0

@Webnet: vous pouvez remplacer le 'COUNT (*)' par l'estimation approximative. Le caractère aléatoire en souffrira un peu, mais il se terminera en un seul balayage. – Quassnoi

2

ORDER BY RAND() provoque automatiquement une table temporaire à créer.

Il fonctionne en créant une table temporaire avec une nouvelle colonne qui est remplie avec des nombres aléatoires. Il effectue ensuite la requête sur la table temporaire à l'aide de ORDER BY. Pour éviter d'utiliser une table temporaire, vous devrez trouver une nouvelle méthode de sélection des nombres aléatoires.

La solution que j'ai utilisée auparavant (qui repose sur les lignes qui ne sont pas supprimées) consiste à faire un SELECT COUNT sur la table, puis à sélectionner des nombres aléatoires dans cette plage et à ne sélectionner que ces lignes.

Il existe un certain nombre d'autres solutions, mais ORDER BY RAND() n'est pas une bonne solution.

Questions connexes