Domanda

Ho una query piuttosto complessa con circa 100 KB di righe.

La query viene eseguita in 13 secondi in SQL Server Express (esegui sulla mia casella di sviluppo)

La stessa query con la stessa indicizzazione e tabelle richiede più di 15 minuti per l'esecuzione su MySQL 5.1 (esegui sulla mia casella di produzione - molto più potente e testata con risorse al 100%) E a volte la query si arresta in modo anomalo con un errore di memoria.

Cosa sto facendo di sbagliato in MySQL? Perché ci vuole così tanto tempo?

select e8.*
from table_a e8
inner join (
    select max(e6.id) as id, e6.category, e6.entity, e6.service_date
    from (
        select e4.* 
        from table_a e4
        inner join (
            select max(e2.id) as id, e3.rank, e2.entity, e2.provider_id, e2.service_date
            from table_a e2
            inner join (
                select min(e1.rank) as rank, e1.entity, e1.provider_id, e1.service_date
                from table_a e1
                where e1.site_id is not null
                group by e1.entity, e1.provider_id, e1.service_date 
            ) as e3
            on e2.rank= e3.rank
            and e2.entity = e3.entity
            and e2.provider_id = e3.provider_id
            and e2.service_date = e3.service_date
            and e2.rank= e3.rank
            group by e2.entity, e2.provider_id, e2.service_date, e3.rank
        ) e5
        on e4.id = e5.id
        and e4.rank= e5.rank                            
    ) e6
    group by e6.category, e6.entity, e6.service_date 
) e7
on e8.id = e7.id and e7.category = e8.category
È stato utile?

Soluzione

Questa risposta inizialmente ho tentato di pubblicare sulla tua domanda eliminata che non indicava che si trattava di un problema con MySQL. Vorrei ancora andare avanti e utilizzare SQL Server per il refactoring della query utilizzando i CTE e quindi riconvertire in query nidificate (se presenti). Mi dispiace per la formattazione, Jeff Atwood mi ha inviato il testo originale pubblicato e ho dovuto riformattarlo di nuovo.

È difficile fare a meno di dati, risultati attesi e nomi validi, ma vorrei convertire tutte le query nidificate in CTE, raggrupparle, denominarle in modo significativo e refactoring, iniziando con l'esclusione delle colonne che non si stanno utilizzando. La rimozione delle colonne non comporterà miglioramenti, perché l'ottimizzatore è piuttosto intelligente, ma ti darà la possibilità di migliorare la tua query, probabilmente prendendo in considerazione alcuni o tutti i CTE. Non sono sicuro di cosa stia facendo il tuo codice, ma potresti trovare utili le nuove funzioni di tipo RANK (), perché sembra che tu stia utilizzando un tipo di modello di ricerca con tutti questi self-join.

Quindi inizia da qui invece. Ho esaminato i miglioramenti di e7 per te, le colonne inutilizzate da e7 potrebbero indicare un difetto o un pensiero incompleto sulle possibilità di raggruppamento, ma se quelle colonne sono davvero superflue, questo potrebbe tornare indietro attraverso la tua logica in e6, e5 ed e3. Se il raggruppamento in e7 è corretto, puoi eliminare tutto tranne max (id) nei risultati e nel join. Non riesco a capire perché dovresti avere più MAX (id) per categoria, perché ciò moltiplicherebbe i tuoi risultati quando ti iscrivi, quindi il MAX (id) deve essere univoco all'interno della categoria, nel qual caso la categoria è ridondante nel join.

WITH e3 AS (
select min(e1.rank) as rank,
e1.entity,
e1.provider_id,
e1.service_date
from table_a e1
where e1.site_id is not null
group by e1.entity, e1.provider_id, e1.service_date
)

,e5 AS (
select max(e2.id) as id,
e3.rank,
e2.entity,
e2.provider_id,
e2.service_date
from table_a e2
inner join e3
on e2.rank= e3.rank
and e2.entity = e3.entity
and e2.provider_id = e3.provider_id
and e2.service_date = e3.service_date
and e2.rank= e3.rank
group by e2.entity, e2.provider_id, e2.service_date, e3.rank
)

,e6 AS (
select e4.* -- switch from * to only the columns you are actually using
from table_a e4
inner join e5
on e4.id = e5.id
and e4.rank= e5.rank
)

,e7 AS (
select max(e6.id) as id, e6.category -- unused, e6.entity, e6.service_date
from e6
group by e6.category, e6.entity, e6.service_date
-- This instead
-- select max(e6.id) as id
-- from e6
-- group by e6.category, e6.entity, e6.service_date
)

select e8.*
from table_a e8
inner join e7
on e8.id = e7.id
and e7.category = e8.category
-- THIS INSTEAD on e8.id = e7.id

Altri suggerimenti

100.000 righe non dovrebbero richiedere 13 secondi se fossero disponibili indici efficienti. Sospetto che la differenza sia dovuta al fatto che SQL Server ha un Query Optimizer molto più robusto di MySQL. Ciò che MySQL ha è più nell'ordine di un parser SQL che di un ottimizzatore.

Dovrai fornire molte più informazioni: schemi completi di tutte le tabelle partecipanti e un elenco completo di indici su ciascuna, per cominciare.

Quindi qualche idea di cosa trattano i dati e di cosa intende produrre la query. Qualcosa nell'ordine di un caso d'uso.

Sarebbe interessante SPIEGARE PIANO con entrambi per vedere quali fossero le differenze. Non sono sicuro che si tratti di un confronto tra mela e arancia, ma sarei curioso.

Non so se questo può aiutare , ma questo è stato il primo successo nella ricerca di " mysql query optimizer " ;.

Ecco un altro potrebbe essere utile.

L'unico database open source che conosco che ha CTE è Firebird ( http : //www.firebirdsql.org/rlsnotesh/rlsnotes210.html#rnfb210-cte )

Postgres avrà in 8.4 penso

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top