¿Cómo agrego índices a las tablas de MySQL?

407

Tengo una tabla MySQL muy grande con aproximadamente 150,000 filas de datos. Actualmente, cuando intento ejecutar

SELECT * FROM table WHERE id = '1';

el código funciona bien ya que el campo ID es el índice primario. Sin embargo, para un desarrollo reciente en el proyecto, tengo que buscar en la base de datos por otro campo. Por ejemplo:

SELECT * FROM table WHERE product_id = '1';

Este campo no fue indexado previamente; sin embargo, he agregado uno, por lo que mysql ahora indexa el campo, pero cuando intento ejecutar la consulta anterior, se ejecuta muy lentamente. Una consulta EXPLAIN revela que no hay índice para el campo product_id cuando ya he agregado uno, y como resultado la consulta tarda entre 20 minutos y 30 minutos en devolver una sola fila.

Mis resultados completos de EXPLAIN son:

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

Puede ser útil tener en cuenta que acabo de echar un vistazo, y el campo ID se almacena como INT, mientras que el campo PRODUCT_ID se almacena como VARCHAR. ¿Podría ser esta la fuente del problema?

Miguel
fuente
1
¿Puedes publicar los EXPLAINresultados completos ? ¿Estás seguro de que no hay índice? ¿O el índice está allí, pero MySQL está eligiendo no usarlo?
VoteyDisciple
169
Una tabla grande tendría 150,000,000 de registros. Una tabla muy grande tiene 15,000,000,000 de registros. Una tabla de tamaño promedio tiene 150,000. Para futura referencia.
usumoio
44
Tenga en cuenta que 'OR' puede hacer que MySql no use índices. Tuve una consulta con 3 OR. Cada uno combinó un índice y se ejecutó en 15 ms. Todos juntos tardaron entre 25 segundos y el tiempo de espera. Así que realicé 3 consultas y las uní, y también tardé 15 ms en 500,000 filas.
Leif Neland
Considere el tipo de datos que está almacenando. El rendimiento puede cambiar según el tipo de datos que esté comparando. Como dijo que PRODUCT_ID es un tipo de datos VARCHAR, intente cambiarlo a INT e indexe la columna.
Gilbertdim

Respuestas:

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

Nunca te compares integercon stringsMySQL. Si ides así int, elimine las comillas.

zerkms
fuente
Ya he agregado el índice usando ese SQL exacto, pero parece que no se ha "aplicado" a los datos y la consulta EXPLAIN muestra que no hay índice para el campo.
Michael
1
¿Le gustaría revisar el índice con una MOSTRAR MESA CREAR, o ya lo hizo?
Escrito el
33
Use SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html para verificar si se han agregado los índices
Timo Huovinen
66
Hoy tuve el problema exacto que describe @Michael, y la solución fue "Nunca comparar números enteros con cadenas en mysql". Gracias.
user12345
@Wrikken Agregué mi índice y usé su comando MOSTRAR ÍNDICES DESDE SU TABLA. Aparece pero no creo que se use mientras consulto mi tabla. ¿Tengo que cambiar la consulta de selección cuando uso un índice?
Ced
148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);
pabloferraz
fuente
97
En MySQL, si se utiliza ALTER TABLE tbl ADD INDEX (col)en lugar de ALTER TABLE tbl ADD INDEX col (col), a continuación, utilizando ALTER TABLE tbl ADD INDEX (col)más de una vez, seguir añadiendo índices nombrados col_2, col_3, ... cada vez. Mientras que usando la ALTER TABLE tbl ADD INDEX col (col)2da vez, dará ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza
82

Puede usar esta sintaxis para agregar un índice y controlar el tipo de índice (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;

Puede obtener información sobre las diferencias entre los índices BTREE y HASH aquí: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html

Hieu Vo
fuente
1
Hash convertido a btree cuando veo usando índices de show.
RN Kushwaha
1
¿Cuál será el valor predeterminado de Hash y BTree, si no especifico ninguno?
Bhavuk Mathur
2
@RNKushwaha porque InnoDB y MyIsam no admiten HASH, AFAIK, solo los motores de almacenamiento Memory y NDB lo admiten
Hieu Vo
60

Vale la pena señalar que múltiples índices de campo pueden mejorar drásticamente el rendimiento de su consulta. Entonces, en el ejemplo anterior, asumimos que ProductID es el único campo para buscar, pero si la consulta dijera ProductID = 1 AND Category = 7, entonces ayuda un índice de múltiples columnas. Esto se logra con lo siguiente:

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

Además, el índice debe coincidir con el orden de los campos de consulta. En mi ejemplo extendido, el índice debería ser (ProductID, Category) y no al revés.

Antonio
fuente
1
Agradable, nombrar explícitamente el índice permite una reversión fácil.
Sam Berry
¿Puedes citar la fuente de the index should match the order of the query fields?
Bishwas Mishra
58

Se pueden agregar índices de dos tipos: cuando define una clave primaria, MySQL la tomará como índice de forma predeterminada.

Explicación

Clave primaria como índice

Considere que tiene una tbl_studenttabla y desea student_idcomo clave principal:

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

La declaración anterior agrega una clave primaria, lo que significa que los valores indexados deben ser únicos y no pueden ser NULL.

Especificar nombre de índice

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

La declaración anterior creará un índice ordinario con student_indexnombre.

Crear índice único

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

Aquí, student_unique_indexes el nombre de índice asignado a student_id y crea un índice para el que los valores deben ser únicos (aquí se puede aceptar nulo).

Opción de texto completo

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

La declaración anterior creará el nombre del índice de texto completo con el student_fulltext_indexque necesita MyISAM Mysql Engine.

¿Cómo eliminar índices?

DROP INDEX `student_index` ON `tbl_student`

¿Cómo verificar los índices disponibles?

SHOW INDEX FROM `tbl_student`
Jazzzzzz
fuente
17

Dices que tienes un índice, la explicación dice lo contrario. Sin embargo, si realmente lo hace, así es como continuar:

Si tiene un índice en la columna y MySQL decide no usarlo, puede ser porque:

  1. Hay otro índice en la consulta que MySQL considera más apropiado de usar, y solo puede usar uno. La solución suele ser un índice que abarca varias columnas si su método normal de recuperación es por valor de más de una columna.
  2. MySQL decide que hay muchas filas coincidentes, y cree que un escaneo de tabla es probablemente más rápido. Si ese no es el caso, a veces ANALYZE TABLEayuda.
  3. En consultas más complejas, decide no usarlo en base a un vudú de pensamiento extremadamente inteligente en el plan de consulta que por alguna razón simplemente no se ajusta a sus requisitos actuales.

En el caso de (2) o (3), puede convencer a MySQL para que use el índice mediante la sintaxis de pista de índice , pero si lo hace, asegúrese de ejecutar algunas pruebas para determinar si realmente mejora el rendimiento para usar el índice tal como lo indica. .

Wrikken
fuente