2010-01-18 5 views
0

Je lance une requête quotidienne pour compiler des statistiques - mais cela semble vraiment inefficace. Ceci est la requête:Optimisation de requête de sous-sélection Mysql

SELECT a.id, tstamp, label_id, (SELECT author_id FROM b WHERE b.tid = a.id ORDER BY b.tstamp DESC LIMIT 1) AS author_id 
FROM a, b 
WHERE (status = '2' OR status = '3') 
AND category != 6 
AND a.id = b.tid 
AND (b.type = 'C' OR b.type = 'R') 
AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end} 
ORDER BY b.tstamp DESC 
LIMIT 500 

Cette requête semble être très lente. Toutes mes excuses pour le nom de merde - On m'a demandé de ne pas révéler les noms des tables.

La raison pour laquelle il y a un sous-select est parce que le select externe obtient une ligne de la table a et il obtient une ligne de la table b. Mais aussi besoin de connaître le dernier author_id de la table b, donc je lance une sous-sélection pour retourner celle-là. Je ne veux pas lancer un autre select à l'intérieur d'une boucle php - car c'est aussi inefficace.

Cela fonctionne correctement - j'ai juste besoin de trouver un moyen beaucoup plus rapide d'obtenir cet ensemble de données.

+0

@Matt: Vous devriez essayer les réponses fournies, upvote utile et accepter celui qui a résolu votre problème. Si aucun d'entre eux ne l'a fait, pensez à modifier votre question pour fournir plus d'informations. –

Répondre

2

Si b.tstamp est unique dans b.tid, prenez la solution OMG Poneys.

Sinon, vous pouvez essayer cette solution. Il trie le résultat entier par b.tstamp DESC et ajoute un classement par author_id. Les sélections externes prend seulement la ligne avec rank = 1, qui est celle avec le plus grand tstamp par author_id.

SELECT id, tstamp, label_id, author_id 
    FROM (SELECT id, 
       tstamp, 
       label_id, 
       author_id, 
       CASE 
       WHEN @author_id != author_id THEN @row_num := 1 
       ELSE @row_num := @row_num + 1 
       END AS rank, 
       @author_id := b.author_id 
      FROM a, 
       b, 
       (SELECT @row_num := 0, @author_id := NULL) y 
      WHERE a.id = b.tid 
      AND (status = '2' OR status = '3') 
      AND category != 6 
      AND (b.type = 'C' OR b.type = 'R') 
      AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end} 
      ORDER BY b.author_id, b.tstamp DESC 
) x 
WHERE x.rank = 1 
LIMIT 500 

Je ne l'ai pas essayé, donc s'il vous plaît commenter si cela ne fonctionne pas.

2

Essayez:

SELECT a.id, 
     b.tstamp, 
     label_id, 
     y.author_id 
    FROM TABLE_A a 
    JOIN TABLE_B b ON b.tid = a.id 
    JOIN (SELECT b.tid, 
       MAX(b.tstamp) 'm_tstamp' 
      FROM TABLE_B b 
     GROUP BY b.tid) x ON x.tid = a.id 
    JOIN (SELECT b.tid, 
       b.author_id, 
       b.tstamp 
      FROM TABLE_B b 
     GROUP BY b.tid) y ON y.tid = a.id 
         AND y.tstamp = x.m_tstamp 
    WHERE status IN ('2', '3') 
    AND b.type IN ('C', 'R') 
    AND category != 6 
    AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end} 
ORDER BY b.tstamp DESC 
    LIMIT 500 
+0

@Peter Lang: Merci! Corrigée. –