Come faccio ad aggiungere indici alle tabelle MySQL?


407

Ho una tabella MySQL molto grande con circa 150.000 righe di dati. Attualmente, quando provo a correre

SELECT * FROM table WHERE id = '1';

il codice funziona bene poiché il campo ID è l'indice primario. Tuttavia, per uno sviluppo recente nel progetto, devo cercare nel database da un altro campo. Per esempio:

SELECT * FROM table WHERE product_id = '1';

Questo campo non era precedentemente indicizzato; tuttavia, ne ho aggiunto uno, quindi mysql ora indicizza il campo, ma quando provo a eseguire la query sopra, funziona molto lentamente. Una query EXPLAIN rivela che non esiste alcun indice per il campo product_id quando ne ho già aggiunto uno e, di conseguenza, la query impiega da 20 minuti a 30 minuti per restituire una singola riga.

I miei risultati completi EXPLAIN sono:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

Potrebbe essere utile notare che ho appena dato un'occhiata e il campo ID è memorizzato come INT mentre il campo PRODUCT_ID è memorizzato come VARCHAR. Potrebbe essere questa la fonte del problema?


1
Puoi pubblicare i EXPLAINrisultati completi ? Sei certo è che non c'è nessun indice? O l'indice è lì, ma MySQL sta scegliendo di non usarlo?
VoteyDisciple

169
Una grande tabella avrebbe 150.000.000 di record. Una tabella molto grande ha 15.000.000.000 di record. Una tabella di dimensioni medie ha 150.000. Per riferimento futuro.
usumoio,

4
Ricorda che "OR" può impedire a MySql di utilizzare gli indici. Ho avuto una query con 3 OR. Ciascuno ha elaborato un indice e ha funzionato in 15ms. Tutti insieme hanno impiegato tra 25sec e timeout. Così ho fatto 3 query e UNION le ha riunite insieme, ci sono voluti anche 15ms su 500.000 righe.
Leif Neland,

Considera il tipo di dati che stai memorizzando. Le prestazioni possono variare in base al tipo di dati che si sta confrontando. Come hai detto, PRODUCT_ID è un tipo di dati VARCHAR, prova a cambiarlo in INT e indicizza la colonna.
Gilbertdim,

Risposte:


606
ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)

Non confrontare mai integera stringsin MySQL. Se idè int, rimuovere le virgolette.


Ho già aggiunto l'indice usando quell'esatto SQL ma sembra che non sia stato "applicato" ai dati e la query EXPLAIN mostra che non esiste un indice per il campo.
Michael,

1
Vuoi controllare l'indice con SHOW CREATE TABLE o l'hai già fatto?
Wrikken,

33
Utilizzare SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html per verificare se gli indici sono stati aggiunti
Timo Huovinen

6
Oggi ho avuto il problema esatto descritto da @Michael e la soluzione era "Non confrontare mai numeri interi con stringhe in mysql". Grazie.
user12345

@Wrikken Ho aggiunto il mio indice e ho usato il comando MOSTRA INDICI DAL TUO TABELLA. Viene visualizzato ma non penso che venga utilizzato mentre eseguo una query sulla mia tabella. Devo modificare la query di selezione quando si utilizza un indice?
Ced

148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

97
In MySQL, se si utilizza ALTER TABLE tbl ADD INDEX (col)invece che ALTER TABLE tbl ADD INDEX col (col), quindi utilizzando ALTER TABLE tbl ADD INDEX (col)più di una volta non mancherà di tenere l'aggiunta di indici di nome col_2, col_3... ogni volta. Considerando che usando la ALTER TABLE tbl ADD INDEX col (col)seconda volta, darà ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza,

82

È possibile utilizzare questa sintassi per aggiungere un indice e controllare il tipo di indice (HASH o BTREE).

create index your_index_name on your_table_name(your_column_name) using HASH;
or
create index your_index_name on your_table_name(your_column_name) using BTREE;

Puoi conoscere le differenze tra gli indici BTREE e HASH qui: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html


1
Hash convertito in btree quando vedo l'utilizzo di show index.
RN Kushwaha,

1
Quale sarà l'impostazione predefinita da Hash e BTree, se non ne specifico nessuno?
Bhavuk Mathur,

2
@RNKushwaha perché InnoDB e MyIsam non supportano HASH, AFAIK, solo i motori di archiviazione Memory e NDB lo supportano
Hieu Vo

60

Vale la pena notare che più indici di campo possono migliorare drasticamente le prestazioni della query. Quindi nell'esempio sopra si assume che ProductID sia l'unico campo da cercare, ma se la query dicesse ProductID = 1 AND Category = 7, allora un indice a più colonne aiuta. Ciò si ottiene con quanto segue:

ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)

Inoltre, l'indice deve corrispondere all'ordine dei campi della query. Nel mio esempio esteso l'indice dovrebbe essere (ProductID, Categoria) e non viceversa.


1
Bello, denominare esplicitamente l'indice consente una facile inversione.
Sam Berry,

Puoi citare la fonte di the index should match the order of the query fields?
Bishwas Mishra il

58

È possibile aggiungere indici di due tipi: quando si definisce una chiave primaria, MySQL la prenderà come indice per impostazione predefinita.

Spiegazione

Chiave primaria come indice

Considera di avere una tbl_studenttabella e desideri student_idcome chiave primaria:

ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)

L'istruzione precedente aggiunge una chiave primaria, il che significa che i valori indicizzati devono essere univoci e non possono essere NULL.

Specifica il nome dell'indice

ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)

L'istruzione precedente creerà un indice ordinario con student_indexnome.

Crea un indice univoco

ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)

Qui, student_unique_indexè il nome dell'indice assegnato a student_id e crea un indice per i quali i valori devono essere univoci (qui è possibile accettare null).

Opzione full-text

ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)

L'istruzione precedente creerà il nome dell'indice Fulltext con student_fulltext_index, per il quale è necessario MyISAM Mysql Engine.

Come rimuovere gli indici?

DROP INDEX `student_index` ON `tbl_student`

Come controllare gli indici disponibili?

SHOW INDEX FROM `tbl_student`

17

Dici di avere un indice, spiega altrimenti. Tuttavia, se lo fai davvero, ecco come continuare:

Se hai un indice sulla colonna e MySQL decide di non usarlo, potrebbe essere perché:

  1. C'è un altro indice nella query che MySQL ritiene più appropriato da usare e può utilizzarne solo uno. La soluzione è di solito un indice che si estende su più colonne se il loro normale metodo di recupero è in valore di più di una colonna.
  2. MySQL decide che ci sono molte righe corrispondenti e pensa che un tablecan sia probabilmente più veloce. In caso contrario, a volte ANALYZE TABLEaiuta.
  3. Nelle query più complesse, decide di non utilizzarlo sulla base di un voodoo elaborato estremamente intelligente nel piano di query che per qualche motivo non si adatta ai requisiti attuali.

Nel caso di (2) o (3), potresti convincere MySQL a utilizzare l'indice tramite la sintassi del suggerimento sull'indice , ma se lo fai, assicurati di eseguire alcuni test per determinare se effettivamente migliora le prestazioni per utilizzare l'indice mentre lo accenni .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.