MySQL ti consente di definire un indice prefissato, il che significa che devi definire i primi N caratteri dalla stringa originale da indicizzare, e il trucco è scegliere un numero N che sia abbastanza lungo da dare una buona selettività, ma abbastanza corto da risparmiare spazio. Il prefisso dovrebbe essere abbastanza lungo da rendere l'indice quasi utile quanto lo sarebbe se indicizzassi l'intera colonna.
Prima di andare oltre, definiamo alcuni termini importanti. La selettività dell'indice è il rapporto tra i valori indicizzati distinti totali e il numero totale di righe . Ecco un esempio per la tabella di test:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Se indicizziamo solo il primo carattere (N = 1), la tabella dell'indice sarà simile alla seguente tabella:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
In questo caso, la selettività dell'indice è uguale a IS = 1/3 = 0,33.
Vediamo ora cosa accadrà se aumentiamo il numero di caratteri indicizzati a due (N = 2).
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
In questo scenario IS = 2/3 = 0,66 significa che abbiamo aumentato la selettività dell'indice, ma abbiamo anche aumentato la dimensione dell'indice. Il trucco è trovare il numero minimo N che porterà alla massima selettività dell'indice .
Esistono due approcci che è possibile eseguire calcoli per la tabella del database. Farò dimostrazione su questo dump del database .
Supponiamo di voler aggiungere all'indice la colonna last_name negli impiegati della tabella e vogliamo definire il numero N più piccolo che produrrà la migliore selettività dell'indice.
Innanzitutto cerchiamo di identificare i cognomi più frequenti:
select count(*) as cnt, last_name from employees group by employees.last_name order by cnt
+-----+-------------+
| cnt | last_name |
+-----+-------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Farris |
| 222 | Sudbeck |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Neiman |
| 218 | Mandell |
| 218 | Masada |
| 217 | Boudaillier |
| 217 | Wendorf |
| 216 | Pettis |
| 216 | Solares |
| 216 | Mahnke |
+-----+-------------+
15 rows in set (0.64 sec)
Come puoi vedere, il cognome Baba è il più frequente. Ora troveremo i prefissi last_name che si verificano più frequentemente , iniziando con i prefissi a cinque lettere.
+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa |
| 758 | Mande |
| 711 | Schwa |
| 562 | Angel |
| 561 | Gecse |
| 555 | Delgr |
| 550 | Berna |
| 547 | Peter |
| 543 | Cappe |
| 539 | Stran |
| 534 | Canna |
| 485 | Georg |
| 417 | Neima |
| 398 | Petti |
| 398 | Duclo |
+-----+--------+
15 rows in set (0.55 sec)
Ci sono molte più occorrenze di ogni prefisso, il che significa che dobbiamo aumentare il numero N fino a quando i valori sono quasi gli stessi dell'esempio precedente.
Ecco i risultati per N = 9
select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;
+-----+-----------+
| cnt | prefix |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudailli |
| 216 | Cummings |
| 216 | Pettis |
+-----+-----------+
Ecco i risultati per N = 10.
+-----+------------+
| cnt | prefix |
+-----+------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudaillie |
| 216 | Cummings |
| 216 | Pettis |
| 216 | Solares |
+-----+------------+
15 rows in set (0.56 sec)
Questi sono ottimi risultati. Ciò significa che possiamo creare un indice sulla colonna last_name indicizzando solo i primi 10 caratteri. Nella colonna della definizione della tabella, last_name è definito come VARCHAR(16)
, e questo significa che abbiamo salvato 6 byte (o più se ci sono caratteri UTF8 nel cognome) per voce. In questa tabella ci sono 1637 valori distinti moltiplicati per 6 byte è di circa 9 KB e immagina come questo numero aumenterebbe se la nostra tabella contiene milioni di righe.
Puoi leggere altri modi per calcolare il numero di N nel mio post Indici prefissati in MySQL .
Anche l'uso delle funzioni MD5 e SHA1 per generare valori che dovrebbero essere indicizzati non è un buon approccio . Perché? Leggilo per posta Come scegliere il giusto tipo di dati per una chiave primaria nel database MySQL