2012-11-26 11 views
5

Se creo le seguenti due indiciesL'ordine in cui vengono creati gli indici influisce su quale indice sceglierà Query Optimizer?

ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address); 
ALTER TABLE requests ADD INDEX is_cached(exec_date, cached); 

L'uscita show index from requests è la seguente

Table  Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
requests 1   daily_ips 1    exec_date A   413   NULL NULL YES BTREE  
requests 1   daily_ips 2    ip_address A   218334  NULL NULL YES BTREE  
requests 1   is_cached 1    exec_date A   165   NULL NULL YES BTREE  
requests 1   is_cached 2    cached  A   165   NULL NULL YES BTREE  

Ho la seguente domanda

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes 
FROM requests 
GROUP BY exec_date; 

id select_type table type possible_keys key   key_len ref rows Extra 
1 SIMPLE requests index NULL   daily_ips 263 NULL 436695 

Tuttavia desidero forzare la query ottimizzatore per utilizzare l'indice is_cached anziché l'indice daily_ips.

Se rimuovo l'indice daily_ips e aggiungi di nuovo

ALTER TABLE requests DROP INDEX daily_ips; 
ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address); 

quindi eseguire la stessa EXPLAIN dichiarazione, query optimizer sceglie l'indice is_cached.

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE requests index NULL is_cached 6 NULL 440493 Using index 

E 'un comportamento previsto per l'ottimizzatore delle query di scegliere un indice in base all'ordine è stato aggiunto?

Come si comunica a Query Optimizer quale indice utilizzare?

+0

Credo che l'indice venga utilizzato solo per eseguire una scansione della tabella. Se si desidera utilizzare effettivamente l'indice, è necessario ristrutturare la query in due query che eseguono un conteggio con una condizione where su cache. (Anche se la cache dovrebbe essere la prima chiave nell'indice, ovviamente.) Fondamentalmente, CASE sta causando una scansione della tabella. – Corbin

+1

Avevo aggiornato la mia risposta per verificare che –

+0

@Corbin non sono sicuro di aver capito come farei a fare la query che mi consiglia. In che modo posso ristrutturare esattamente la query in 2 query (qualsiasi codice di esempio sarebbe molto apprezzato)? – user784637

risposta

2

È possibile specificare quale indice sholud utilizzare per eseguire la query.

Prova questo:

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes 
FROM requests USE INDEX(is_cached) 
GROUP BY exec_date; 

differnce tra USE INDEX e FORCE INDEX:

Specificando USO INDEX (index_list), si può dire a MySQL di utilizzare solo uno degli indici di nome per trovare le righe della tabella . La sintassi alternativa IGNORE INDEX (index_list) può essere usata per dire a MySQL di non usare alcuni indici o indici particolari. Questi suggerimenti sono utili se EXPLAIN mostra che MySQL sta usando l'indice sbagliato dall'elenco di possibili indici.

È inoltre possibile utilizzare FORCE INDEX, che funziona come USE INDEX (index_list) ma con l'aggiunta che si presuppone che una scansione della tabella sia molto costosa. In altre parole, una scansione della tabella viene utilizzata solo se non è possibile utilizzare uno degli indici indicati per trovare le righe nella tabella.

UPDATE

Prova questa ricerca:

SELECT exec_date, 
     100 * SUM(IF(cached = 0, 1, 0))/SUM(1) cached_no, 
     100 * SUM(IF(cached = 1, 1, 0))/SUM(1) cached_yes 
FROM (SELECT exec_date, IF(cached = 'no', 0, 1) cached 
     FROM requests GROUP BY exec_date) AS A 
+1

Grazie! Qualche differenza tra 'USE INDEX' e' FORCE INDEX'? – user784637

+1

Controllare la mia risposta aggiornata –

+0

Se si è soddisfatti della risposta, accettare la risposta e svuotarla. –

2

Per forzare un indice sopra anothe è possibile utilizzare FORCE INDEX direttiva:

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes FROM requests FORCE INDEX(`is_cached`) GROUP BY exec_date; 

MySQL ottimizzatore seleziona indice che restituisce meno righe a scansione, nel tuo caso questo conteggio è molto vicino per entrambi gli indici (436695 vs 440493).

Problemi correlati