2013-07-29 43 views
5

Ho avuto questa query per iniziare con:Come rendere JOINS più veloce?

SELECT DISTINCT spentits.* 
FROM `spentits` 
WHERE (spentits.user_id IN 
     (SELECT following_id 
      FROM `follows` 
      WHERE `follows`.`follower_id` = '44' 
      AND `follows`.`accepted` = 1) 
     OR spentits.user_id = '44') 
ORDER BY id DESC 
LIMIT 15 OFFSET 0 

Questa query richiede 10ms da eseguire.

Ma una volta aggiungo un semplice unirsi:

SELECT DISTINCT spentits.* 
FROM `spentits` 
LEFT JOIN wishlist_items ON wishlist_items.user_id = 44 AND wishlist_items.spentit_id = spentits.id 
WHERE (spentits.user_id IN 
     (SELECT following_id 
      FROM `follows` 
      WHERE `follows`.`follower_id` = '44' 
      AND `follows`.`accepted` = 1) 
     OR spentits.user_id = '44') 
ORDER BY id DESC 
LIMIT 15 OFFSET 0 

Questa volta l'esecuzione aumentato di 11x. Ora ci vuole circa 120ms da eseguire. La cosa interessante è che se rimuovo la clausola oORDER BY id DESC, il tempo torna a 10ms.

Sono nuovo ai database quindi non lo capisco. Perché rimuovere una di queste clausole lo accelera 11x? E come posso mantenerlo così com'è ma renderlo più veloce?

Ho indici su spentits.user_id, follows.follower_id, follows.accepted e su primary ids di ogni tabella.

SPIEGARE:

1 PRIMARY spentits index index_spentits_on_user_id PRIMARY 4 NULL 15 Using where; Using temporary 
1 PRIMARY wishlist_items ref index_wishlist_items_on_user_id,index_wishlist_items_on_spentit_id index_wishlist_items_on_spentit_id 5 spentit.spentits.id 1 Using where; Distinct 
2 SUBQUERY follows index_merge index_follows_on_follower_id,index_follows_on_following_id,index_follows_on_accepted 

index_follows_on_follower_id,index_follows_on_accepted 5,2 NULL 566 Using intersect(index_follows_on_follower_id,index_follows_on_accepted); Using where 
+1

Cosa mostra EXPLAIN PLAN? –

+0

@DavidJashi aggiornato con EXPLAIN – 0xSina

risposta

2

Si dovrebbe avere indice anche su:

wishlist_items.spentit_id

Perché si stanno unendo sopra la colonna

+0

Whoops, ho dimenticato di elencarlo, ma l'ho indicizzato. – 0xSina

0

Il SINISTRA L'ISCRIZIONE è facile y per spiegare: viene prodotto un prodotto incrociato di tutte le voci rispetto a tutte le altre voci. Le condizioni del join (nel tuo caso: prendi tutte le voci a sinistra e trova quelle a destra) vengono applicate successivamente. Quindi, se la tabella degli spenditsits è grande, richiederà un po 'di tempo al server. Ti suggerirei di sbarazzarti della tua subquery e fare tre join. Inizia con la tabella più piccola per evitare grandi quantità di dati.

+1

'Viene prodotto un prodotto incrociato di tutte le voci rispetto a tutte le altre voci' - Questo è CROSS JOIN, non SINISTRA JOIN –

+0

Inoltre, facendo 2 JOINS (join on segue invece os subquery) uccide la performance. Ci vogliono circa 350 ms per eseguire. – 0xSina

0

Nel 2 ° esempio, la sottoselezione viene eseguita per ogni utente spendits.user.

Se si scrive è come questo sarà più veloce perché la selezione secondaria viene eseguito una volta:

SELECT DISTINCT spentits.* 
FROM `spentits`, (SELECT following_id 
      FROM `follows` 
      WHERE `follows`.`follower_id` = '44' 
      AND `follows`.`accepted` = 1) 
     OR spentits.user_id = '44') as `follow` 
LEFT JOIN wishlist_items ON wishlist_items.user_id = 44 AND wishlist_items.spentit_id = spentits.id 
WHERE (spentits.user_id IN 
     (follow) 
ORDER BY id DESC 
LIMIT 15 OFFSET 0 

Come si può vedere la subselect spostato nella FROM-parte della query e crea una tabel immaginario (o vista). Questo tabel immaginario è una vista in linea.

JOIN e le viste in linea sono più veloci ogni volta che una sottoselezione nella parte WHERE.

+0

Ottenere "colonna sconosciuta" segui "in" clausola where "" – 0xSina

+0

Hai ragione. C'è un errore con un '(' e l'operatore IN non combacia con i tabel. – Shockergnomm

+0

Prova questo per favore: SELEZIONA spentits DISTINTI * da 'spentits', (SELECT following_id FROM' follows' dove 'follows'.'follower_id' = '44' E' follows'.'accepted' = 1.) OR spentits.user_id = '44') come 'follow' LEFT JOIN wishlist_items ON wishlist_items.user_id = 44 AND wishlist_items.spentit_id = spentits.id WHERE spentits.user_id = follow.following_id ORDER BY id DESC LIMIT 15 OFFSET 0 – Shockergnomm

Problemi correlati