2015-10-08 11 views
6

Nel manuale MySQL c'è una pagina su index hinting che indica che è possibile specificare l'indicizzazione dell'indice per parti specifiche della query.Come funziona Index Scope in Mysql?

È possibile specificare l'ambito di un suggerimento indice aggiungendo una clausola FOR al suggerimento. Ciò fornisce un controllo più dettagliato sulla selezione dell'ottimizzatore di un piano di esecuzione per varie fasi dell'elaborazione della query. Per influenzare solo gli indici utilizzati quando MySQL decide come trovare le righe nella tabella e come elaborare i join, utilizzare FOR JOIN. Per influenzare l'utilizzo dell'indice per l'ordinamento o il raggruppamento di righe, utilizzare FOR ORDER BY o FOR GROUP BY.

Tuttavia, ci sono poche o nessuna informazione su come funziona o cosa fa effettivamente nell'ottimizzatore MySQL. Inoltre, in pratica sembra essere trascurabile nel migliorare effettivamente qualsiasi cosa.

Ecco una query di prova e che cosa spiegare dice sulla query:

SELECT 
    `property`.`primary_id` AS `id` 
FROM `California` `property` 

USE INDEX FOR JOIN (`Zipcode Bedrooms`) 
USE INDEX FOR ORDER BY (`Zipcode Bathrooms`) 

INNER JOIN `application_zipcodes` `az` 
    ON `az`.`application_id` = '18' 
    AND `az`.`zipcode` = `property`.`zipcode` 

WHERE `property`.`city` = 'San Jose' 
AND `property.`zipcode` = '95133' 
AND `property`.property_type` = 'Residential' 
AND `property`.`style` = 'Condominium' 
AND `property`.`bedrooms` = '3' 
ORDER BY `property`.`bathrooms` ASC 
LIMIT 15 
; 

spiego:

EXPLAIN SELECT `property`.`primary_id` AS `id` FROM `California` `property` USE INDEX FOR JOIN (`Zipcode Bedrooms`) USE INDEX FOR ORDER BY (`Zipcode Bathrooms`) INNER JOIN `application_zipcodes` `az` ON `az`.`application_id` = '18' AND `az`.`zipcode` = `property`.`zipcode` WHERE `property`.`city` = 'San Jose' AND `property.`zipcode` = '95133' AND `property`.property_type` = 'Residential' AND `property`.`style` = 'Condominium' AND `property`.`bedrooms` = '3' ORDER BY `property`.`bathrooms` ASC LIMIT 15\g 
+------+-------------+----------+--------+---------------+---------+---------+------------------------------------+------+----------------------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref        | rows | Extra            | 
+------+-------------+----------+--------+---------------+---------+---------+------------------------------------+------+----------------------------------------------------+ 
| 1 | SIMPLE  | Property | ref | Zip Bed  | Zip Bed | 17  | const,const      | 2364 | Using index condition; Using where; Using filesort | 
| 1 | SIMPLE  | az  | eq_ref | PRIMARY  | PRIMARY | 7  | const,Property.zipcode    | 1 | Using where; Using index       | 
+------+-------------+----------+--------+---------------+---------+---------+------------------------------------+------+----------------------------------------------------+ 
2 rows in set (0.01 sec) 

Quindi, per riassumere sto fondamentalmente chiedo come la portata indice è stato pensato per essere usato, in quanto ciò non sembra fare nulla quando aggiungo o rimuovo la riga USE INDEX FOR ORDER BY (Zipcode Bathrooms).

risposta

1

Devo ancora capire come utilizzare più suggerimenti. MySQL non utilizzerà quasi mai più di un indice per SELECT. L'unica eccezione che conosco è con "index merge", che non è rilevante nel tuo esempio.

L'ottimizzatore di solito si concentra sulla ricerca di un buon indice per la clausola WHERE. Se copre interamente lo WHERE, senza "intervalli", quindi controlla se ci sono campi GROUP BY e ORDER BY, nell'ordine corretto, da utilizzare. Se è in grado di gestire tutto il WHERE, GROUP BY, and ORDER BY, allora può effettivamente ottimizzare il LIMIT (ma non OFFSET).

Se l'Ottimizzatore non può consumare tutto il WHERE, può raggiungere il ORDER BY nella speranza di evitare il "fileort" che richiede ORDER BY.

Niente di ciò consente indici diversi per clausole diverse. Un singolo suggerimento può incoraggiare l'uso di uno dei suddetti casi (sopra) rispetto all'altra; Non lo so.

Non utilizzare utf8 per zipcode; rende le cose più voluminose del necessario (3 byte per carattere). In generale, ridurre le dimensioni del tavolo aiuterà le prestazioni. Oppure, se si dispone di un set di dati enorme, può essere di grande aiuto. (Evitare l'I/O è molto importante.)

Bathrooms non è molto selettivo; non c'è molto da guadagnare anche se sarebbe possibile.

az.application_id è la chiave inglese grande nella query; che cos'è?

+0

Essenzialmente era un modo per creare una relazione uno a molti tra un elenco di codici di avviamento postale che avevo. [Hai effettivamente commentato quel problema che stavo avendo e questo risultato sembra essere il risultato più veloce.] (Http: // StackOverflow.it/questions/32256402/sql-performance-using-or-is-slow-than-in-quando-using-order-by) Questa query nella domanda è in realtà piuttosto veloce se sta usando l'indice corretto, tuttavia l'ottimizzatore prova a scegliere quello sbagliato, causando un filesort. Inoltre non riesco a rimuovere nessuno degli indici poiché sono entrambi necessari per l'ordinamento. – Dbeazy

+0

Non è stato possibile modificare nuovamente il mio ultimo commento. Hai detto: "I bagni non sono molto selettivi; non c'è molto da guadagnare anche se sarebbe possibile. Anche se questo è vero in un caso di dichiarazione where, ci sono molte righe, quindi usarlo come indice per l'ordine è molto più veloce di quanto sarebbe quando usando un indice su 'Bedrooms'. Volevo anche notare che ho anche provato ad usare un gigantesco Union All per i codici di avviamento postale, ed era davvero veloce, ma questo doveva essere gestibile da altri sviluppatori diversi da me, quindi ho pensato che l'astrazione contorta per un minore aumento di velocità rispetto alla corrente fosse non ne vale la pena. – Dbeazy