Domanda

Sto incontrando uno strano comportamento di MySQL. Query esecuzione (cioè l'utilizzo di indici come dimostrato da spiegare [QUERY]) e dei tempi di esecuzione sono dipendenti dagli elementi della clausola dove.

Ecco una query in cui si verifica il problema:

select distinct
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1, ent_leng el1, rel_c r1, _tax_c t1, rel_c r2, _tax_c t2
where el1.fk_ent=e1.idx
and r1.fk_ent=e1.idx and ((r1.fk_cat=43) or (r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43))
and r2.fk_ent=e1.idx and ((r2.fk_cat=10) or (r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))

La corrispondente spiegare uscita è:

| id | select_type | table | type   | possible_keys           | key     | key_len | ref           | rows  | Extra                       
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
|  1 | SIMPLE      | el1   | index  | fk_ent                  | fk_ent  | 4       | NULL          | 15002 | Using index; Using temporary
|  1 | SIMPLE      | e1    | eq_ref | PRIMARY                 | PRIMARY | 4       | DB.el1.fk_ent |     1 | Using index
|  1 | SIMPLE      | r1    | ref    | fk_ent,fk_cat,fks       | fks     | 4       | DB.e1.idx     |     1 | Using where; Using index
|  1 | SIMPLE      | r2    | ref    | fk_ent,fk_cat,fks       | fks     | 4       | DB.el1.fk_ent |     1 | Using index
|  1 | SIMPLE      | t1    | index  | fk_cat1,fk_cat2,fk_cats | fk_cats | 8       | NULL          |    69 | Using where; Using index; Distinct; 
|    |             |       |        |                         |         |         |               |       | Using join buffer
|  1 | SIMPLE      | t2    | index  | fk_cat1,fk_cat2,fk_cats | fk_cats | 8       | NULL          |    69 | Using where; Using index; Distinct;  
                                                                                                          | Using join buffer

Come si può vedere un indice di una colonna ha lo stesso nome della colonna a cui appartiene. Ho anche aggiunto alcuni indici inutili insieme a quelli usati, solo per vedere se cambiano l'esecuzione (che non lo fanno).

L'esecuzione si ~ 4,5 secondi.

Quando aggiungo l'entl1.name colonna alla parte di selezione (niente altro è cambiato), l'indice in fk_ent EL1 non può essere più utilizzato:

| id | select_type | table | type   | possible_keys           | key     | key_len | ref           | rows  | Extra                       
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
|  1 | SIMPLE      | el1   | ALL    | fk_ent                  |  NULL   | NULL    | NULL          | 15002 | Using temporary

L'esecuzione avviene ora ~ 8,5 secondi.

Ho sempre pensato che la parte di selezione di una query non influenza l'utilizzo di indici dal motore e non influisce sulle prestazioni in questo modo.

Tralasciando l'attributo non è una soluzione, e ci sono ancora più attributi che devo selezionare. Ancora peggio, la query nella forma utilizzata è anche un po 'più complessa e che rende il problema di prestazioni un grosso problema.

Quindi le mie domande sono le seguenti: 1) Qual è il motivo di questo strano comportamento? 2) Come posso risolvere il problema di prestazioni?

Grazie per il vostro aiuto! Gred

È stato utile?

Soluzione

E 'la restrizione DISTINCT. Si può pensare che, come un'altra restrizione WHERE. Quando si modifica la lista di selezione, si sta davvero cambiando la clausola WHERE per la restrizione DISTINCT, e ora l'ottimizzatore decide che ha a che fare una scansione di tabella in ogni caso, quindi potrebbe anche non utilizzare l'indice.

Modifica

Non sono sicuro se questo aiuta, ma se mi sto capendo i vostri dati in modo corretto, penso che si può eliminare la restrizione DISTINCT in questo modo:

select
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1
  Inner Join ent_leng el1 ON el1.fk_ent=e1.idx
  Inner Join rel_c r1 ON r1.fk_ent=e1.idx
  Inner Join rel_c r2 ON r2.fk_ent=e1.idx
where 
 ((r1.fk_cat=43) or Exists(Select 1 From _tax_c t1 Where r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43)) 
 and 
 ((r2.fk_cat=10) or Exists(Select 1 From _tax_c t2 Where r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))

Altri suggerimenti

MySQL restituire i dati da un indice se possibile, salvare l'intera riga venga caricato. In questo modo, le colonne selezionate possono influenzare la selezione dell'indice.

Con questo in mente, si può molto più efficiente per aggiungere tutte le colonne necessarie a un indice, specialmente nel caso di selezione solo un piccolo sottoinsieme di colonne.

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