Come funzionano veramente i join MySQL?

2

Nel mio caso, unire la tabella all'interno della sottoquery o all'esterno della subquery dà pochissime differenze con COUNT

CASO 1: a circa 6202 righe.
In questo caso, table_c viene aggiunto all'interno del sottoquery, ma viene aggiunto solo (Nessuna altra azione per la tabella, non viene selezionato alcun dato o il filtro dell'intera query con quella tabella).

CASO 2: a circa 6235 righe.
In questo caso la tabella viene unita al di fuori della sottoquery, ma la chiave di join ( groupCol ) è la stessa.

Ecco la mia query MySQL autoesplicativa:

SELECT 
    COUNT(*)
FROM (
    SELECT
          a.*
        , b.some
        # no c columns
    # main table
    FROM table_a      AS a

    # no mention this
    LEFT JOIN table_b AS b
    ON a.col = b.bcol

    #### CASE 1 ###
    # this is left joined, this is matter
    # this is only joined, does nothing more
    LEFT JOIN table_c AS c
    ON c.col = a.groupCol
    #### CASE 1 ###

 WHERE 
    *** SOME statements *** 
    # c table not participating in WHERE, or GROUP-ing clause
 GROUP BY a.groupCol 
 ORDER BY a.dateCol
) AS subSelect 


#### CASE 2 : table_c is joined outside of subquery ###
LEFT JOIN table_c AS c
ON c.col = subSelect.groupCol
#### CASE 2 ###

WHERE 
    *** SOME statements *** 
    # table_c still not participating of course

So anche come funziona MySQL LEFT JOIN : se i dati non vengono trovati nella seconda tabella, i campi corrispondenti di riga da quella tabella sono impostati su null.

Che cosa succede realmente qui non riesco a capire.

Anche il caso 1 è più veloce del caso 2.
Perché? Sicuramente, l'unione nel caso 1, contiene almeno il doppio di righe. Nel caso 2 viene prima filtrato e poi unito.
Ho pensato che dovrebbe essere più veloce ...

    
posta George Garchagudashvili 20.12.2013 - 10:10
fonte

2 risposte

5

Ho eseguito due query in MySQL durante l'utilizzo di EXPLAIN.

Il primo è il seguente:

select count(*) from parent
left outer join child on child.parent_id = id;

Il secondo è il seguente:

select count(*) from (
    select * from parent p
    left outer join child c on c.parent_id = p.id
) count;

Entrambi hanno restituito 68 record, il che implica che se stai ottenendo qualcosa di diverso, è a causa di un filtro che stai utilizzando, non del modo in cui viene eseguita la query.

Quando corro spiegare sulla prima query ottengo il seguente:

'1', 'SIMPLE', 'parent', 'index', NULL, 'FK8338B25AD02D715A', '9', NULL, '15', 'Using index'
'1', 'SIMPLE', 'child', 'ref', 'PRIMARY,FKAFAB561391AEEB78', 'FKAFAB561391AEEB78', '8', 'db.parent.id', '2', 'Using index'

E quando eseguo la seconda query ottengo il seguente:

'1', 'PRIMARY', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Select tables optimized away'
'2', 'DERIVED', 'p', 'ALL', NULL, NULL, NULL, NULL, '15', ''
'2', 'DERIVED', 'c', 'ref', 'PRIMARY,FKAFAB561391AEEB78', 'FKAFAB561391AEEB78', '8', 'db.p.id', '2', 'Using index'

Il DERIVED significa semplicemente che ho usato alias per le tabelle che erano necessarie nella seconda query per funzionare correttamente. Altrimenti, noterai che sono molto simili. Noterai che l'unica altra grande differenza è una riga aggiuntiva "Seleziona tabelle ottimizzate". Questa è un'ottimizzazione eseguita da MySQL per ridurre le query e renderla più semplice.

In altre parole, la seconda query richiede solo l'ottimizzazione di MySQL oltre alla query effettiva, quindi può essere solo più lenta e fornire gli stessi risultati della prima. Se il tuo conteggio non è coerente tra queste due query, è probabile che stia succedendo qualcos'altro che probabilmente è un filtro di qualche tipo.

Spero che ti aiuti!

    
risposta data 20.12.2013 - 11:04
fonte
1

Dopo 20 minuti di pausa ho scoperto cosa sta succedendo:

Nel primo caso quando entri nella subquery, GROUP -ing ha fatto il lavoro, ma quando si è unito all'esterno sarebbe GROUP -ed di nuovo, certo che sarebbe stupido ma ...

Sembra che abbia entrate doppie in table_c che moltiplica alcune delle righe.

Grazie anche a @Neil

    
risposta data 20.12.2013 - 13:16
fonte

Leggi altre domande sui tag