La respuesta de @Alden Quimby es correcta hasta donde llega, pero hay más en la historia, porque MySQL solo intenta para elegir el índice óptimo, y su capacidad para tomar esa determinación está limitada debido a la forma en que los índices de texto completo interactúan con el optimizador.
Lo que realmente sucede es esto:
Si el id_usuario especificado existe en 0 o 1 filas coincidentes en la tabla, el optimizador se dará cuenta de esto y elegirá id_usuario como índice para esa consulta. Rápida ejecución.
De lo contrario, el optimizador elegirá el índice de texto completo, filtrando cada fila que coincida con el índice de texto completo para eliminar las filas que no contengan un ID de usuario que coincida con la cláusula WHERE. No tan rápido.
Así que no es realmente el camino "óptimo". Es más como texto completo, con una buena optimización para evitar la búsqueda de texto completo con la única condición de que sabemos que no tenemos casi nada de interés en la tabla.
La razón por la que esto falla es que un índice de texto completo no devuelve ninguna estadística significativa al optimizador. Simplemente dice "sí, creo que esa consulta probablemente solo debería requerir que verifique 1 fila"... lo que, por supuesto, agrada mucho al optimizador, por lo que el índice de texto completo gana la oferta por el costo más bajo, a menos que el índice con el número entero el valor también viene en comparativamente bajo o más bajo.
Aún así, eso no significa que no lo intentaría de esta manera primero.
Hay otra opción, que funcionaría mejor con consultas de texto completo IN BOOLEAN MODE
y eso es para crear otra columna que rellenaría con algo como CONCAT('user_id_',user_id) o algo similar, y luego declarar un índice de texto completo de 2 columnas.
filter_string VARCHAR(48) # populated with CONCAT('user_id_',user_id);
....
FULLTEXT KEY (message,filter_string)
Luego especifique todo en la consulta.
SELECT ...
WHERE user_id = 500 AND
MATCH (message,filter_string) AGAINST ('+kittens +puppies +user_id_500' IN BOOLEAN MODE);
Ahora, el índice de texto completo será responsable de hacer coincidir solo aquellas filas donde aparezcan gatitos, cachorros y "user_id_500" en el índice de texto completo combinado de las dos columnas, pero aún querrá tener el filtro de enteros allí también para asegurarse de que los resultados finales están restringidos a pesar de cualquier aparición aleatoria de "user_id_500" en el mensaje.