2009-02-20 5 views
23

Diciamo che ho una semplice tabella molti-a-molti tra le tabelle "table1" e "table2" che consiste di due campi int: "table1-id" e "table2-id". Come dovrei indicizzare questa tabella di collegamento?Come indicizzare correttamente una tabella di collegamento per la connessione many-to-many in MySQL?

Ho usato solo un indice primario composito (table1-id, table2-id), ma ho letto che questo indice potrebbe non funzionare se si modifica l'ordine dei campi nella query. Quindi qual è la soluzione ottimale allora - creare indici indipendenti per ogni campo senza un indice primario?

Grazie.

risposta

25

Dipende da come si cerca.

se si cerca in questo modo:

/* 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 

allora avete bisogno:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_1, table_2) 

In questo caso, table1 guiderà nella NESTED LOOPS e l'indice sarà utilizzabile solo quando table1 è indicizzato prima .

Se si cerca in questo modo:

/* 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 

allora avete bisogno:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_2, table_1) 

per i motivi di cui sopra.

Non hai bisogno di indici indipendenti qui. Un indice composito può essere utilizzato ovunque sia possibile utilizzare un indice semplice sulla prima colonna. Se si utilizzano gli indici indipendenti, non sarà in grado di cercare in modo efficiente per entrambi i valori:

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

Per una query come questo, avrete bisogno di almeno un indice su entrambe le colonne.

Non è mai male avere un indice aggiuntivo per il secondo 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) 

chiave primaria verrà utilizzato per le ricerche on both values e per le ricerche in base al valore di table_1, indice aggiuntivo saranno utilizzati per le ricerche basate su valore di table_2.

+0

Grazie per la risposta dettagliata, ma cosa succede se cerco in entrambi i modi? Inoltre sto usando Hibernate quindi non sono nemmeno sicuro di quale sia il suo utilizzo. – serg

+2

SE cerchi in entrambi i modi, avrai bisogno di DUE indici: un composito per il PRIMARY KEY e uno per la colonna che è il secondo nel PRIMARY KEY. È in fondo al mio post. – Quassnoi

+0

Grande risposta, grazie per il dettaglio –

4

Finché si specificano entrambe le chiavi nella query, non importa quale ordine hanno nella query, né importa quale ordine le si specifica nell'indice.

Tuttavia, non è improbabile che a volte si abbia solo l'una o l'altra chiave. Se a volte hai solo id_1, allora dovrebbe essere il primo (ma hai ancora bisogno di un solo indice).

Se a volte ne avete uno, a volte l'altro, a volte entrambi, avrete bisogno di un indice con entrambe le chiavi e un secondo indice (non univoco) con un campo - il più selettivo dei due tasti - e il l'indice composito primario dovrebbe iniziare con l'altra chiave.

+0

Mi piace la tua risposta, ma non ho la competenza per verificarlo. – jpierson

+0

Cosa intendi con "più selettivo"? –

+2

Una parola più tecnica è "cardinalità". Significa quanti valori diversi ci sono per il campo. Ad un estremo, alta cardinalità, ogni valore è unico. D'altra parte, alcuni campi potrebbero avere solo alcuni valori distinti, nel qual caso un indice non risparmia molto sulla lettura dei dischi. – dkretz

0

@Quassnoi, nella tua prima query stai effettivamente utilizzando solo la chiave tt.table_1 come possiamo vedere dalla clausola WHERE: WHERE t1.id = @id. E nella seconda query - solo tt.table_2.

Quindi l'indice multi-colonna potrebbe essere utile solo nella terza query a causa di WHERE table_1 = @id1 AND table_2 = @id2. Se le query di questo tipo non verranno utilizzate, pensi che valga la pena utilizzare due indici separati a una colonna?