MySQL no permite la indexación de un valor total de BLOB
, TEXT
y largas columnas VARCHAR
porque los datos que contienen puede ser enorme, e implícitamente índice de base de datos será grande, lo que significa ningún beneficio de índice.
MySQL requiere que defina los primeros N caracteres para indexar, y el truco consiste en elegir un número N que sea lo suficientemente largo como para dar una buena selectividad, pero lo suficientemente corto como para ahorrar espacio. El prefijo debe ser lo suficientemente largo como para que el índice sea tan útil como lo sería si hubiera indexado toda la columna.
Antes de ir más allá, déjenos definir algunos términos importantes. La selectividad del índice es la proporción de los valores indizados distintos totales y el número total de filas. Aquí está un ejemplo de tabla de prueba:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Si índice sólo el primer carácter (N = 1), entonces la mesa de índice se parecerá a la siguiente tabla:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
En este caso, el índice la selectividad 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 es = 2/3 = 0,66 lo que significa que mayor selectividad índice, pero también hemos aumentado el tamaño de índice. El truco es encontrar el número mínimo N que resultará en una selectividad de índice máxima.
Existen dos métodos para hacer cálculos para la tabla de la base de datos. Haré una demostración en el this database dump.
Digamos que queremos añadir la columna last_name en la tabla empleados al índice, y queremos definir el número más pequeño N que producirá la mejor selectividad índice.
Primera permitió establecer las 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 se puede ver, el último nombre de Baba es la más frecuente. Ahora vamos a encontrar los prefijos de last_name 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 mucho más ocurrencias de cada prefijo, que significa que tenemos para aumentar el número N hasta que los valores son casi los mismos que en el ejemplo anterior.
Aquí hay 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í hay 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 un índice en la columna last_name
con indexación de los primeros 10 caracteres. En la definición de tabla, la columna 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, es alrededor de 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 mi publicación Prefixed indexes in MySQL.
Una tabla no puede tener varias claves principales. ¿Quiere decir que tiene una clave primaria compuesta (que incluye más de una columna) o tiene varias claves 'ÚNICAS'? – Quassnoi
En mi caso, por algún motivo, tenía un tipo de TEXTO para una columna de correo electrónico en lugar de VARCHAR. – Kris