Contenido de esta guía
Respuesta rápida
Un índice sobre expresión guarda claves derivadas de una expresión calculada a partir de las columnas de la fila. Sirve cuando la consulta repite esa misma transformación en WHERE u ORDER BY.
CREATE INDEX idx_clientes_email_lower
ON clientes(lower(email));
SELECT id, nombre, email
FROM clientes
WHERE lower(email) = 'ana@example.test';El índice no cambia el valor almacenado en email. Mantiene una estructura adicional con el resultado de lower(email) para que el motor pueda localizar coincidencias sin recalcular y revisar toda la tabla cuando el planificador considere útil el índice.
Modelo mental: indexa la forma en la que realmente buscas
Un índice convencional sobre email contiene el valor de la columna. Si tu condición siempre aplica lower(email), la expresión consultada ya no es simplemente email. Un índice funcional permite indexar esa forma derivada.
No es una mejora automática. Cada índice ocupa espacio y debe mantenerse en inserciones y actualizaciones. Créalo porque una consulta real y frecuente lo necesita, no porque exista una función que puedas indexar.
Ejemplo comprobado: búsqueda de email sin distinguir mayúsculas
Sobre la base educativa, el siguiente índice y consulta fueron comprobados dentro de una transacción y revertidos después de la prueba:
CREATE INDEX idx_clientes_email_lower_demo
ON clientes(lower(email));
EXPLAIN QUERY PLAN
SELECT id, nombre, email
FROM clientes
WHERE lower(email) = 'ana@example.test';| detail |
|---|
| SEARCH clientes USING INDEX idx_clientes_email_lower_demo (<expr>=?) |
El plan confirma que SQLite reconoce el índice para la expresión consultada. La consulta devuelve a Ana Torres con ana@example.test.
La expresión de la consulta debe encajar con la indexada
SQLite documenta una regla especialmente estricta: el planificador no hace álgebra para demostrar que dos expresiones equivalentes son la misma. Si indexas x + y y consultas y + x, puede no usar el índice aunque la suma sea matemáticamente equivalente.
En la práctica, conserva una forma estable para las expresiones indexadas y comprueba el plan real con EXPLAIN o la herramienta equivalente del motor.
Crear el índice y asumir que toda variante lo usará
Un índice disponible no obliga al optimizador a elegirlo. Además de la expresión, influyen selectividad, tamaño de tabla, estadísticas y coste estimado. Verifica la consulta que importa.
Diferencias entre motores
- PostgreSQL:
CREATE INDEXacepta expresiones y exige que las funciones y operadores usados en la definición sean inmutables. - SQLite: permite índices sobre expresiones deterministas y exige una coincidencia muy cercana entre la expresión del índice y la de la consulta.
- MySQL 8.4: admite functional key parts; la expresión se escribe entre paréntesis adicionales, por ejemplo
CREATE INDEX idx ON tabla ((LOWER(columna))), y hereda restricciones de columnas generadas. - SQL Server: el patrón habitual es definir una columna calculada que cumpla requisitos de determinismo/precisión y crear el índice sobre esa columna.
Por eso «índice funcional» describe una intención común, pero la sintaxis exacta no es portable entre los cuatro motores.
Cuándo merece la pena
- Filtros frecuentes por
LOWER(columna)u otra normalización estable. - Ordenaciones repetidas por una expresión calculada.
- Reglas de unicidad sobre una transformación cuando el motor lo permite y la semántica está bien definida.
No lo confundas con un índice compuesto, que combina varias claves, ni con un índice parcial/filtrado, que incluye solo las filas que cumplen un predicado. Un índice puede combinar varias ideas, pero cada una resuelve un problema distinto.
Práctica: indexa una búsqueda normalizada por ciudad
Prepara un índice para LOWER(ciudad)
Escribe un índice sobre lower(ciudad) y una consulta que busque 'madrid' usando exactamente la misma expresión. Después comprueba el plan en tu motor.
CREATE INDEX.lower(ciudad) en el WHERE.Solución razonada para SQLite/PostgreSQL
CREATE INDEX idx_clientes_ciudad_lower
ON clientes(lower(ciudad));
SELECT id, nombre, ciudad
FROM clientes
WHERE lower(ciudad) = 'madrid'
ORDER BY id;La consulta y el índice comparten la misma transformación. En MySQL y SQL Server adapta primero la definición al mecanismo documentado por el motor.
Qué debes recordar
- Indexa una expresión cuando las consultas reales filtran u ordenan por esa expresión.
- La forma de la consulta debe ser compatible con la forma indexada.
- Comprueba el plan: que el índice exista no garantiza su uso.
- La sintaxis y las restricciones cambian bastante entre motores.
Conceptos relacionados
Fuentes técnicas consultadas
Las referencias oficiales se usaron para verificar sintaxis, restricciones y comportamiento del planificador.