¿Es posible tener un índice basado en funciones en MySQL?

Recuerdo que en Oracle es posible indexar en función de una función, por ejemplo SUBSTRING(id,1,8) .

¿MySQL soporta esto? Si no, ¿hay alguna alternativa?

No, no en un sentido general, no creo que incluso 5.6 tenga esta funcionalidad. Es posible usar solo la parte delantera de una columna (esta funcionalidad ha existido durante mucho tiempo), pero no una que comience en el segundo o siguientes caracteres ni en ninguna otra función más compleja.

Por ejemplo, lo siguiente crea un índice usando los primeros cinco caracteres de un nombre:

 create index name_first_five on cust_table (name(5)); 

Para expresiones más complejas, puede lograr un efecto similar al tener otra columna con los datos indexables, y luego usar los activadores de inserción / actualización para asegurarse de que esté lleno correctamente.

Aparte del espacio desperdiciado para datos redundantes, eso es más o menos lo mismo.

Y, aunque técnicamente infringe 3NF, eso se mitiga mediante el uso de desencadenantes para mantener los datos sincronizados (esto es algo que a menudo se hace para obtener un mayor rendimiento).

MySQL no es compatible con esto, pero hay una alternativa.

1. Desde MySQL 5.7.6

Puede usar una columna generada automáticamente para contener la subcadena con un índice:

 CREATE TABLE SomeTable ( id CHAR(10), sub_id CHAR(8) AS SUBSTRING(id, 1, 8) STORED, INDEX(sub_id) ) 

Como señaló Benjamin , InnoDB admite índices secundarios en columnas virtuales, por lo que se puede omitir la palabra clave ALMACENADA. De hecho, los índices secundarios en columnas virtuales pueden ser preferibles. Más información aquí: Índices secundarios y columnas generadas

2. Antes de MySQL 5.7.6

Puede usar una columna actualizada por un desencadenador con un índice:

 CREATE TABLE SomeTable ( id CHAR(10), sub_id CHAR(8) , INDEX(sub_id) ); CREATE TRIGGER TR_SomeTable_INSERT_sub_id BEFORE INSERT ON SomeTable FOR EACH ROW SET NEW.sub_id = SUBSTRING(NEW.id, 1, 8); CREATE TRIGGER TR_SomeTable_UPDATE_sub_id BEFORE UPDATE ON SomeTable FOR EACH ROW SET NEW.sub_id = SUBSTRING(NEW.id, 1, 8); 

Esto es posible a partir de MySQL 5.7.5 utilizando las nuevas Columnas generadas .