MySQL le permite definir un índice prefijado, lo que significa que define los primeros N caracteres de la cadena original a indexar, y el truco consiste en elegir un número N que sea lo suficientemente largo como para proporcionar una buena selectividad, pero lo suficientemente corto como para ahorrar espacio. El prefijo debe ser lo suficientemente largo como para que el índice sea casi tan útil como lo sería si indexara toda la columna.
Antes de continuar, definamos algunos términos importantes. La selectividad del índice es la relación del total de valores indexados distintos y el número total de filas . Aquí hay un ejemplo para la tabla de prueba:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Si indexamos solo el primer carácter (N = 1), la tabla de índice se verá como la siguiente tabla:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
En este caso, la selectividad del índice es igual a IS = 1/3 = 0.33.
Veamos ahora qué sucederá si aumentamos el número de caracteres indexados a dos (N = 2).
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
En este escenario IS = 2/3 = 0.66, lo que significa que aumentamos la selectividad del índice, pero también hemos aumentado el tamaño del índice. El truco consiste en encontrar el número mínimo N que dará como resultado una selectividad de índice máxima .
Hay dos enfoques que puede hacer cálculos para su tabla de base de datos. Haré una demostración en el volcado de esta base de datos .
Digamos que queremos agregar la columna last_name en la tabla de empleados al índice, y queremos definir el número N más pequeño que produzca la mejor selectividad del índice.
Primero identifiquemos los apellidos más frecuentes:
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 puede ver, el apellido Baba es el más frecuente. Ahora vamos a encontrar los prefijos de apellido más frecuentes , comenzando con los prefijos 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)
Hay muchas más ocurrencias de cada prefijo, lo que significa que tenemos que aumentar el número N hasta que los valores sean casi los mismos que en el ejemplo anterior.
Aquí están los 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 |
+-----+-----------+
Aquí están los 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)
Estos son muy buenos resultados. Esto significa que podemos hacer que el índice en la columna last_name indexe solo los primeros 10 caracteres. En la columna de definición de tabla, last_name se define como VARCHAR(16)
, y esto significa que hemos guardado 6 bytes (o más si hay caracteres UTF8 en el apellido) por entrada. En esta tabla hay 1637 valores distintos multiplicados por 6 bytes que son aproximadamente 9 KB, e imagine cómo crecería este número si nuestra tabla contiene millones de filas.
Puede leer otras formas de calcular el número de N en mis índices indexados en MySQL .
Usar las funciones MD5 y SHA1 para generar valores que deberían indexarse tampoco es un buen enfoque . ¿Por qué? Léalo en la publicación Cómo elegir el tipo de datos correcto para una clave primaria en la base de datos MySQL