¿Dos índices de una sola columna frente a un índice de dos columnas en MySQL?

113

Me enfrento a lo siguiente y no estoy seguro de cuál es la mejor práctica.

Considere la siguiente tabla (que se agrandará):

id PK | giver_id FK | destinatario_id FK | fecha

Estoy usando InnoDB y, por lo que tengo entendido, crea índices automáticamente para las dos columnas de clave externa. Sin embargo, también haré muchas consultas en las que necesito hacer coincidir una combinación particular de:

SELECT...WHERE giver_id = x AND recipient_id = t.

Cada una de estas combinaciones será única en la tabla.

¿Existe algún beneficio al agregar un índice de dos columnas sobre estas columnas, o los dos índices individuales en teoría serían suficientes / iguales?

Tom
fuente
1
Si la combinación de las dos columnas es única, puede crear un índice de dos columnas con una característica única que no solo aumentará la velocidad de su consulta sino que también agregará consistencia a su tabla.
sguven
"MySQL puede usar índices de varias columnas para consultas que prueban todas las columnas del índice, o consultas que prueban solo la primera columna, las dos primeras columnas, las tres primeras columnas, etc. Si especifica las columnas en el lado derecho orden en la definición del índice, un solo índice compuesto puede acelerar varios tipos de consultas en la misma tabla ". - Índices de columnas múltiples
AlikElzin-kilaka
Para extrapolar en @ user1585784; Si la combinación de las dos columnas es única, creo que se debe usar una clave única para ellas. De hecho, si uno quiere hacer cumplir la singularidad en el nivel de la base de datos, una clave única es la forma más fácil de hacerlo ...
Erk

Respuestas:

132

Si tiene dos índices de una sola columna, solo uno de ellos se usará en su ejemplo.

Si tiene un índice con dos columnas, la consulta puede ser más rápida (debe medir). Un índice de dos columnas también se puede utilizar como índice de una sola columna, pero solo para la columna que se enumera primero.

A veces puede resultar útil tener un índice en (A, B) y otro en (B). Esto agiliza las consultas que utilizan una o ambas columnas, pero, por supuesto, también utiliza más espacio en disco.

Al elegir los índices, también debe tener en cuenta el efecto de insertar, eliminar y actualizar. Más índices = actualizaciones más lentas.

Mark Byers
fuente
1
"MySQL puede usar índices de varias columnas para consultas que prueban todas las columnas del índice, o consultas que prueban solo la primera columna, las dos primeras columnas, las tres primeras columnas, etc. Si especifica las columnas en el lado derecho orden en la definición del índice, un solo índice compuesto puede acelerar varios tipos de consultas en la misma tabla ". - Índices de columnas múltiples
AlikElzin-kilaka
33

Un índice de cobertura como:

ALTER TABLE your_table ADD INDEX (giver_id, recipient_id);

... significaría que el índice podría usarse si se hace referencia a una consulta giver_id, o una combinación de giver_idy recipient_id. Tenga en cuenta que los criterios de índice se basan en el extremo izquierdo: una consulta que se refiera solo recipient_idno podría usar el índice de cobertura en la declaración que proporcioné.

Además, MySQL solo puede usar un índice por SELECT, por lo que un índice de cobertura sería el mejor medio para optimizar sus consultas.

Ponis dios mio
fuente
10
MySQL can only use one index per SELECTesto ya no es cierto, sería bueno si editara su respuesta para actualizarla.
Davor
¿Le importaría explicar por qué el índice de cobertura no podría ser utilizado por recipient_id?
Ivo Pereira
2
@IvoPereira Los índices de columnas múltiples en MySQL le permiten usar todos los campos en el índice de izquierda a derecha. Por ejemplo, si tiene un INDEX (col1, col2, col3, col4), el índice se aplicará a las búsquedas con una WHEREcláusula como col1 = 'A'o col1 = 'A' AND col2 = 'B'o col1 = 'A' AND col2 ='B' AND col3 = 'C' AND col4 = 'D', pero este índice en particular no se usará para nada como WHERE col2 = 'B'o WHERE col3 = 'C' AND col4 = 'D'porque los campos de búsqueda no se dejan en la mayoría de la definición del índice. Tendría que agregar índices adicionales para cubrir esos campos.
Slicktrick
"un índice por SELECCIONAR" , ¿sigue siendo cierto para mariadb 10.1?
oldboy
1
@Anthony: No. vea el comentario de Davor arriba.
kapad
4

Si uno de los índices de clave externa ya es muy selectivo, entonces el motor de la base de datos debería usar ese para la consulta que especificó. La mayoría de los motores de base de datos utilizan algún tipo de heurística para poder elegir el índice óptimo en esa situación. Si ninguno de los índices es muy selectivo por sí mismo, probablemente tenga sentido agregar el índice creado en ambas claves, ya que dice que usará mucho ese tipo de consulta.

Otra cosa a considerar es si puede eliminar el campo PK en esta tabla y definir el índice de clave primaria en los campos giver_idy recipient_id. Dijo que la combinación es única, por lo que posiblemente funcionaría (dadas muchas otras condiciones que solo usted puede responder). Sin embargo, por lo general, creo que la complejidad adicional que agrega no vale la pena.

Mark Wilkins
fuente
Gracias Mark, una de las claves es muy selectiva, por lo que debería estar bien. Opté por mantener los dos índices (automáticos) en su lugar y ver cómo funciona con el tiempo. También pensé en una clave principal combinada de donante: destinatario, pero como cada campo también debe poder buscarse individualmente, solo agregaría una sobrecarga de php. Además, la nueva clave sería una cadena (más larga) en lugar de un entero (más corto).
Tom
2

Otra cosa a considerar es que las características de desempeño de ambos enfoques se basarán en el tamaño y cardinalidad del conjunto de datos. Puede encontrar que el índice de 2 columnas solo se vuelve más eficaz en un determinado umbral de tamaño del conjunto de datos, o exactamente lo contrario. Nada puede sustituir las métricas de rendimiento para su escenario exacto.

Andrés
fuente
¿Podría vincular a alguna documentación sobre esto? Gracias.
kapad