Índices MySQL: ¿cuáles son las mejores prácticas?

208

He estado usando índices en mis bases de datos MySQL durante un tiempo, pero nunca aprendí correctamente sobre ellos. Generalmente pongo un índice en cualquier campo que buscaré o seleccionaré usando una WHEREcláusula, pero a veces no parece tan en blanco y negro.

¿Cuáles son las mejores prácticas para los índices MySQL?

Ejemplos de situaciones / dilemas:

  • Si una tabla tiene seis columnas y todas se pueden buscar, ¿debo indexarlas todas o ninguna?

  • ¿Cuáles son los impactos negativos en el rendimiento de la indexación?

  • Si tengo una columna VARCHAR 2500 que se puede buscar desde partes de mi sitio, ¿debo indexarla?

Haroldo
fuente
55
Probablemente deberías volver a plantear la pregunta. La elección de índices es una parte importante para la optimización de cualquier modelo de base de datos. Y a mi punto de vista no relacionado con php.
VGE

Respuestas:

242

Definitivamente deberías pasar un tiempo leyendo sobre indexación, hay mucho escrito al respecto y es importante entender lo que está sucediendo.

En términos generales, un índice impone un orden en las filas de una tabla.

Por simplicidad, imagine que una tabla es solo un gran archivo CSV. Cada vez que se inserta una fila, se inserta al final . Por lo tanto, el orden "natural" de la tabla es solo el orden en que se insertaron las filas.

Imagine que tiene ese archivo CSV cargado en una aplicación de hoja de cálculo muy rudimentaria. Todo lo que hace esta hoja de cálculo es mostrar los datos y numerar las filas en orden secuencial.

Ahora imagine que necesita encontrar todas las filas que tienen algún valor "M" en la tercera columna. Dado lo que tiene disponible, solo tiene una opción. Escanea la tabla verificando el valor de la tercera columna para cada fila. Si tiene muchas filas, ¡este método (un "escaneo de tabla") puede llevar mucho tiempo!

Ahora imagine que además de esta tabla, tiene un índice. Este índice particular es el índice de valores en la tercera columna. El índice enumera todos los valores de la tercera columna, en un orden significativo (por ejemplo, alfabéticamente) y para cada uno de ellos, proporciona una lista de números de fila donde aparece ese valor.

Ahora tiene una buena estrategia para encontrar todas las filas donde el valor de la tercera columna es "M". Por ejemplo, puede realizar una búsqueda binaria ! Mientras que el escaneo de la tabla requiere que busque N filas (donde N es el número de filas), la búsqueda binaria solo requiere que observe las entradas de índice log-n, en el peor de los casos. ¡Vaya, eso es mucho más fácil!

Por supuesto, si tiene este índice y agrega filas a la tabla (al final, ya que así es como funciona nuestra tabla conceptual), debe actualizar el índice cada vez. Así que trabajas un poco más mientras escribes nuevas filas, pero ahorras un montón de tiempo cuando buscas algo.

Entonces, en general, la indexación crea una compensación entre la eficiencia de lectura y la eficiencia de escritura. Sin índices, las inserciones pueden ser muy rápidas: el motor de la base de datos simplemente agrega una fila a la tabla. A medida que agrega índices, el motor debe actualizar cada índice mientras realiza la inserción.

Por otro lado, las lecturas se vuelven mucho más rápidas.

Con suerte, eso cubre sus dos primeras preguntas (como han respondido otros, debe encontrar el equilibrio correcto).

Tu tercer escenario es un poco más complicado. Si usa LIKE, los motores de indexación generalmente lo ayudarán con su velocidad de lectura hasta el primer "%". En otras palabras, si está SELECCIONANDO DONDE la columna COMO 'foo% bar%', la base de datos usará el índice para encontrar todas las filas donde la columna comienza con "foo", y luego deberá escanear ese conjunto de filas intermedio para encontrar el subconjunto que contiene "barra". SELECCIONAR ... DONDE la columna COMO '% bar%' no puede usar el índice. Espero que puedas ver por qué.

Finalmente, debe comenzar a pensar en los índices en más de una columna. El concepto es el mismo y se comporta de manera similar al material LIKE: esencialmente, si tiene un índice en (a, b, c), el motor continuará usando el índice de izquierda a derecha lo mejor que pueda. Entonces, una búsqueda en la columna a podría usar el índice (a, b, c), como lo haría uno en (a, b). Sin embargo, el motor necesitaría hacer un escaneo completo de la tabla si estuviera buscando DONDE b = 5 AND c = 1)

Espero que esto ayude a arrojar un poco de luz, pero debo reiterar que es mejor pasar unas horas buscando buenos artículos que expliquen estas cosas en profundidad. También es una buena idea leer la documentación de su servidor de base de datos particular. La forma en que los planificadores de consultas implementan y utilizan los índices puede variar bastante.

timdev
fuente
10
¿Qué pasa con los FULLTEXTíndices? ¿Pueden ayudar con condiciones como LIKE '%bar%'?
Septagram
2
@Septagram: FULLTEXTpuede ayudar con esa consulta si bar es una "palabra". FULLTEXTmaneja palabras, no subcadenas arbitrarias (como lo LIKEhace).
Rick James
@timdev explícitamente, ¿en qué parte se respondió la primera pregunta? Puedo detectar la segunda y tercera preguntas respondidas en la primera y segunda parte (antes y después de Esperemos que cubra sus dos primeras preguntas ) de su valiosa respuesta
Manuel Jordan
1
@ManuelJordan: no hay una respuesta simple a la primera pregunta. Depende de cómo desee equilibrar las compensaciones en el contexto del uso anticipado (o incluso mejor, observado).
timdev
57

Echa un vistazo a presentaciones como Más Dominio del arte de la indexación .

Actualización 12/2012: He publicado una nueva presentación mía: Cómo diseñar índices, de verdad . Lo presenté en octubre de 2012 en ZendCon en Santa Clara, y en diciembre de 2012 en Percona Live London.

Diseñar los mejores índices es un proceso que tiene que coincidir con las consultas que ejecuta en su aplicación.

Es difícil recomendar reglas de propósito general sobre qué columnas son mejores para indexar, o si debe indexar todas las columnas, sin columnas, qué índices deben abarcar varias columnas, etc. Depende de las consultas que necesite ejecutar.

Sí, hay algunos gastos generales, por lo que no debe crear índices innecesariamente. Pero debe crear los índices que brinden beneficios a las consultas que necesita para ejecutarse rápidamente. La sobrecarga de un índice generalmente es mucho mayor que su beneficio.

Para una columna que es VARCHAR (2500), probablemente desee utilizar un índice FULLTEXT o un índice de prefijo:

CREATE INDEX i ON SomeTable(longVarchar(100));

Tenga en cuenta que un índice convencional no puede ayudar si está buscando palabras que pueden estar en el medio de ese varchar largo. Para eso, use un índice de texto completo.

Bill Karwin
fuente
3
Muchas gracias. slideshare.net/matsunobu/… fue realmente muy útil.
Bishal Paudel
1
Excelente presentación de slideshare.net/billkarwin/how-to-design-indexes-really
Manuel Jordan
1
Presentación increíble (la de 2012), realmente entendió todo el punto de los índices.
DarkteK
46

No repetiré algunos de los buenos consejos en otras respuestas, pero agregaré:

Índices compuestos

Puede crear índices compuestos, un índice que incluye varias columnas. MySQL puede usarlos de izquierda a derecha . Entonces si tienes:

Table A
Id
Name
Category
Age
Description

Si tiene un índice compuesto que incluye Nombre / Categoría / Edad en ese orden, estas cláusulas WHERE usarían el índice:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

pero

WHERE Category='A' and Age > 18

no usaría ese índice porque todo tiene que usarse de izquierda a derecha.

Explique

Use Explain / Explain Extended para comprender qué índices están disponibles para MySQL y cuál realmente selecciona. MySQL solo usará UNA clave por consulta .

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

Registro de consulta lenta

Active el registro de consultas lentas para ver qué consultas se ejecutan lentamente.

Columnas anchas

Si tiene una columna ancha donde la MAYOR parte de la distinción ocurre en los primeros caracteres, puede usar solo los primeros N caracteres en su índice. Ejemplo: tenemos una columna ReferenceNumber definida como varchar (255) pero el 97% de los casos, el número de referencia es de 10 caracteres o menos. Cambié el índice para mirar solo los primeros 10 caracteres y mejoré bastante el rendimiento.

Eric J.
fuente
Tengo una pregunta sobre la última parte. Leí en alguna parte que si creas una columna con VARCHAR, siempre debes establecerla en 255. Ahora dijiste que un índice establecido para este tipo de columna podría limitarse a mirar solo los primeros 10 caracteres. ¿Cómo puedes hacer eso exactamente?
AlexioVay
20

Si una tabla tiene seis columnas y todas pueden buscarse, ¿debo indexarlas todas o ninguna?

¿Está buscando campo por campo o algunas búsquedas utilizan múltiples campos? Los campos que están más que se busca en? ¿Cuáles son los tipos de campo? (El índice funciona mejor en INT que en VARCHAR por ejemplo) ¿Ha intentado usar EXPLAIN en las consultas que se están ejecutando?

¿Cuáles son los impactos negativos en el rendimiento de la indexación?

ACTUALIZACIONES e INSERTOS serán más lentos. También hay requisitos adicionales de espacio de almacenamiento, pero eso no es habitual en estos días.

Si tengo una columna VARCHAR 2500 que se puede buscar desde partes de mi sitio, ¿debería indexarla?

No, a menos que sea ÚNICO (lo que significa que ya está indexado) o solo busque coincidencias exactas en ese campo (sin usar LIKE o la búsqueda de texto completo de mySQL).

Generalmente pongo un índice en cualquier campo que buscaré o seleccionaré usando una cláusula WHERE

Normalmente indexaría los campos que son los más consultados, y luego los INT / BOOLEAN / ENUM en lugar de los campos que son VARCHARS. No olvide, a menudo necesita crear un índice en campos combinados, en lugar de un índice en un campo individual. Use EXPLAIN y verifique el registro lento.

Pete
fuente
11

Cargue datos de manera eficiente : los índices aceleran las recuperaciones pero ralentizan las inserciones y eliminaciones, así como las actualizaciones de valores en columnas indexadas. Es decir, los índices ralentizan la mayoría de las operaciones que implican escritura. Esto ocurre porque escribir una fila requiere escribir no solo la fila de datos, también requiere cambios en cualquier índice. Cuantos más índices tenga una tabla, más cambios deben realizarse y mayor es la degradación del rendimiento promedio. La mayoría de las tablas reciben muchas lecturas y pocas escrituras, pero para una tabla con un alto porcentaje de escrituras, el costo de la actualización del índice puede ser significativo.

Evite los índices : si no necesita un índice particular para que las consultas funcionen mejor, no lo cree.

Espacio en disco : un índice ocupa espacio en disco, y varios índices ocupan correspondientemente más espacio. Esto podría hacer que alcance un límite de tamaño de tabla más rápidamente que si no hubiera índices. Evite los índices siempre que sea posible.

Para llevar: no sobrepasar el índice

Srikar Doddi
fuente
5

En general, los índices ayudan a acelerar la búsqueda en la base de datos, teniendo la desventaja de usar espacio extra en el disco y ralentizar las consultas INSERT/ UPDATE/ DELETE. Use EXPLAINy lea los resultados para saber cuándo MySQL usa sus índices.

Si una tabla tiene seis columnas y todas pueden buscarse, ¿debo indexarlas todas o ninguna?

La indexación de las seis columnas no siempre es la mejor práctica.

(a) ¿Va a utilizar alguna de esas columnas cuando busque información específica?

(b) ¿Cuál es la selectividad de esas columnas (cuántos valores distintos hay almacenados, en comparación con la cantidad total de registros en la tabla)?

MySQL utiliza un optimizador basado en costos, que intenta encontrar la ruta "más barata" al realizar una consulta. Y los campos con baja selectividad no son buenos candidatos.

¿Cuáles son los impactos negativos en el rendimiento de la indexación?

Ya respondió: espacio extra en disco, menor rendimiento durante la inserción - actualización - eliminación.

Si tengo una columna VARCHAR 2500 que se puede buscar desde partes de mi sitio, ¿debo indexarla?

Pruebe el índice FULLTEXT .

Un hacha
fuente
4

1/2) Los índices aceleran ciertas operaciones de selección, pero ralentizan otras operaciones como insertar, actualizar y eliminar. Puede ser un buen equilibrio.

3) use un índice de texto completo o quizás una esfinge

Paul Creasey
fuente
Para evitarlo slow down other operations like insert, update and deletes, puede usar el START TRANSACTION; YOUR CODE HERE; COMMIT cual puede ayudar a evitar slowing downlas otras operaciones, ya que solo verificará una vez las restricciones. PRECAUCIÓN: Si usa REPLACE INTOy su SQL_MODE<> STRICT_ALL_TABLESO TRADITIONALEl Bulk Loadignorará el reemplazo e insertará duplicados.
JayRizzo
Las transacciones no son compatibles con todos los motores MySQL. AFAIK, las transacciones ralentizan las operaciones de DB, incluso si se usan solo implícitamente. Lo que necesitamos diseñar en función del rendimiento real es una forma semiautomática de perfilar (medir el rendimiento) de varias opciones de optimización, incluidos los índices y las transacciones.
David Spector