O MySQL permite que você defina o índice prefixado, o que significa que você define os primeiros N caracteres da string original a ser indexada, e o truque é escolher um número N que seja longo o suficiente para oferecer boa seletividade, mas curto o suficiente para economizar espaço. O prefixo deve ser longo o suficiente para tornar o índice quase tão útil quanto seria se você tivesse indexado a coluna inteira.
Antes de prosseguirmos, vamos definir alguns termos importantes. A seletividade do índice é a razão entre o total de valores indexados distintos e o número total de linhas . Aqui está um exemplo para a tabela de teste:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Se indexarmos apenas o primeiro caractere (N = 1), a tabela de índice será semelhante à seguinte:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
Nesse caso, a seletividade do índice é igual a IS = 1/3 = 0,33.
Vamos agora ver o que acontecerá se aumentarmos o número de caracteres indexados para dois (N = 2).
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
Nesse cenário, IS = 2/3 = 0,66, o que significa que aumentamos a seletividade do índice, mas também aumentamos o tamanho do índice. O truque é encontrar o número mínimo N que resultará na seletividade máxima do índice .
Existem duas abordagens que você pode fazer cálculos para sua tabela de banco de dados. Farei uma demonstração no despejo deste banco de dados .
Digamos que desejemos adicionar a coluna last_name nos funcionários da tabela ao índice e queremos definir o menor número N que produzirá a melhor seletividade do índice.
Primeiro, vamos identificar os sobrenomes mais frequentes:
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)
Como você pode ver, o sobrenome Baba é o mais frequente. Agora, vamos encontrar os prefixos last_name mais frequentes , começando com prefixos de cinco letras.
+-----+--------+
| 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)
Há muito mais ocorrências de cada prefixo, o que significa que precisamos aumentar o número N até que os valores sejam quase os mesmos que no exemplo anterior.
Aqui estão os resultados para 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 |
+-----+-----------+
Aqui estão os resultados para 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)
São resultados muito bons. Isso significa que podemos criar um índice na coluna last_name, indexando apenas os 10 primeiros caracteres. Na definição da tabela, a coluna last_name é definida como VARCHAR(16)
, e isso significa que salvamos 6 bytes (ou mais, se houver caracteres UTF8 no sobrenome) por entrada. Nesta tabela, existem 1637 valores distintos multiplicados por 6 bytes e cerca de 9 KB, e imagine como esse número aumentaria se nossa tabela contivesse milhões de linhas.
Você pode ler outras maneiras de calcular o número de N em meus índices pré-fixados no MySQL .
Usar as funções MD5 e SHA1 para gerar valores que devem ser indexados também não é uma boa abordagem . Por quê? Leia no post Como escolher o tipo de dados correto para uma chave primária no banco de dados MySQL