2009-02-20 15 views
23

Digamos que tengo una tabla de muchos a muchos entre las tablas "tabla1" y "tabla2" que consta de dos campos int: "tabla1-id" y "tabla2-id". ¿Cómo debería indexar esta tabla de enlaces?¿Cómo indexar correctamente una tabla de vinculación para la conexión de muchos a muchos en MySQL?

Solía ​​hacer un índice compuesto primario (table1-id, table2-id), pero he leído que este índice podría no funcionar si cambia el orden de los campos en la consulta. Entonces, ¿cuál es la solución óptima? ¿Hacer índices independientes para cada campo sin un índice primario?

Gracias.

Respuesta

25

Depende de cómo busque.

si se busca de esta manera:

/* Given a value from table1, find all related values from table2 */ 
SELECT * 
FROM table1 t1 
JOIN table_table tt ON (tt.table_1 = t1.id) 
JOIN table2 t2 ON (t2.id = tt.table_2) 
WHERE t1.id = @id 

entonces usted necesita:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_1, table_2) 

En este caso, table1 estará al frente de NESTED LOOPS y su índice será útil sólo cuando table1 se indexa primero .

Si usted busca la siguiente manera:

/* Given a value from table2, find all related values from table1 */ 
SELECT * 
FROM table2 t2 
JOIN table_table tt ON (tt.table_2 = t2.id) 
JOIN table1 t1 ON (t1.id = tt.table_1) 
WHERE t2.id = @id 

entonces usted necesita:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_2, table_1) 

por las razones anteriores.

No necesita índices independientes aquí. Un índice compuesto se puede usar en cualquier lugar donde se pueda usar un índice simple en la primera columna. Si utiliza índices independientes, que no será capaz de buscar de manera eficiente para ambos valores:

/* Check if relationship exists between two given values */ 
SELECT 1 
FROM table_table 
WHERE table_1 = @id1 
    AND table_2 = @id2 

Para una consulta de este tipo, se necesitan al menos un índice en ambas columnas.

Nunca es malo tener un índice adicional para el segundo campo:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 PRIMARY KEY (table_1, table_2) 
CREATE INDEX ix_table2 ON table_table (table_2) 

Clave primaria será utilizado para las búsquedas on both values y para las búsquedas basadas en el valor de table_1, índice adicionales se utilizarán para búsquedas basadas en valor de table_2.

+0

Gracias por la respuesta detallada, pero ¿y si busco en ambos sentidos? También estoy usando Hibernate, así que no estoy seguro de qué manera lo está usando. – serg

+2

SI busca en ambos sentidos, necesitará DOS índices: un compuesto para la LLAVE PRIMARIA y uno simple para la columna que es el segundo en la LLAVE PRINCIPAL. Está en el final de mi publicación. – Quassnoi

+0

Gran respuesta gracias por el detalle –

4

Mientras especifiques ambas claves en la consulta, no importa el orden que tengan en la consulta, ni importa el orden en que las especifiques en el índice.

Sin embargo, no es poco probable que a veces solo tenga una u otra de las claves. Si a veces solo tiene id_1, entonces debería ser el primero (pero aún así solo necesita un índice).

Si a veces tiene una, a veces la otra, a veces ambas, necesitará un índice con ambas claves, y un segundo índice (no único) con un campo, la más selectiva de las dos, y la el índice compuesto primario debe comenzar con la otra clave.

+0

Me gusta su respuesta lo mejor, pero no tengo la experiencia para verificarlo. – jpierson

+0

¿Qué quiere decir con "más selectivo"? –

+2

Una palabra más técnica es "cardinalidad". Significa cuántos valores diferentes hay para el campo. En un extremo, alta cardinalidad, cada valor es único. Por otro lado, algunos campos pueden tener solo algunos valores distintos, en cuyo caso un índice no ahorra mucho en forma de lecturas de disco. – dkretz

0

@Quassnoi, en su primera consulta, en realidad está utilizando solo la clave tt.table_1 como podemos ver en la cláusula WHERE: WHERE t1.id = @id. Y en la segunda consulta, solo tt.table_2.

Por lo tanto, el índice de varias columnas podría ser útil solo en la tercera consulta debido a WHERE table_1 = @id1 AND table_2 = @id2. Si las consultas de este tipo no van a ser utilizadas, ¿cree que vale la pena usar dos índices separados de una columna?

Cuestiones relacionadas