Curso de MySQL
FULLTEXT en MySQL: búsqueda de texto completo
Por Víctor Peña · Publicado el

Hola, ¿cómo están? Continuando con el curso de MySQL, hoy veremos FULLTEXT: la forma correcta de implementar un buscador dentro de tu sistema.
¡Empecemos!
El problema con LIKE
Para buscar texto, lo primero que se le ocurre a todo el mundo es esto:
SELECT * FROM citas WHERE diagnostico LIKE '%dolor%';
Funciona, pero tiene tres limitaciones serias:
No usa índices. Como vimos, el comodín al inicio obliga a recorrer toda la tabla. Con un millón de registros, cada búsqueda es un escaneo completo.
Busca coincidencias literales. «dolor» no encuentra «dolores», y buscar «dolor cabeza» no encuentra «dolor de cabeza», porque la frase exacta no aparece.
No ordena por relevancia. Un texto que menciona la palabra ocho veces y otro que la menciona una vez pesan igual.
FULLTEXT resuelve los tres.
Qué es un índice FULLTEXT
Es un tipo especial de índice que analiza el texto y guarda las palabras que contiene, junto con dónde aparecen y con qué frecuencia.
En vez de guardar la frase completa, guarda algo parecido al índice de términos de un libro. Por eso puede responder «dame los registros que contengan esta palabra» sin leer los textos uno por uno.
Crear el índice
ALTER TABLE citas ADD FULLTEXT INDEX ft_diagnostico (diagnostico);
O al crear la tabla:
CREATE TABLE articulos (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
titulo VARCHAR(255) NOT NULL,
contenido TEXT NOT NULL,
FULLTEXT INDEX ft_articulo (titulo, contenido)
) ENGINE=InnoDB;
Fíjate en que puede cubrir varias columnas a la vez: buscará tanto en el título como en el contenido.
Requisitos: las columnas deben ser CHAR, VARCHAR o TEXT, e InnoDB lo soporta desde MySQL 5.6.
Buscar con MATCH AGAINST
SELECT id, diagnostico
FROM citas
WHERE MATCH(diagnostico) AGAINST('dolor');
Dos reglas al escribirlo:
- Las columnas del
MATCHdeben coincidir exactamente con las del índice. Si el índice cubre(titulo, contenido), hay que escribirMATCH(titulo, contenido). - Si no coinciden, MySQL da error.
Modo natural
Es el modo por defecto. Busca las palabras y ordena por relevancia:
SELECT
id,
diagnostico,
MATCH(diagnostico) AGAINST('dolor cabeza') AS relevancia
FROM citas
WHERE MATCH(diagnostico) AGAINST('dolor cabeza')
ORDER BY relevancia DESC;
La relevancia es un número: cuanto más alto, mejor coincidencia. Un texto que contiene ambas palabras varias veces puntúa más que uno que menciona una sola vez.
Poder pedir la relevancia como columna es lo que permite construir un buscador de verdad, con los mejores resultados arriba.
Modo booleano
Da control preciso sobre la búsqueda:
SELECT id, diagnostico
FROM citas
WHERE MATCH(diagnostico) AGAINST('+dolor -espalda' IN BOOLEAN MODE);
Los operadores disponibles:
| Operador | Significado |
|---|---|
+palabra |
Debe aparecer |
-palabra |
No debe aparecer |
palabra* |
Empieza con esa raíz |
"frase exacta" |
Esa secuencia literal |
>palabra |
Aumenta su relevancia |
<palabra |
La reduce |
(a b) |
Agrupa términos |
Algunos ejemplos:
-- Debe contener "dolor", y "cabeza" suma relevancia
AGAINST('+dolor cabeza' IN BOOLEAN MODE)
-- Palabras que empiecen por "cardio"
AGAINST('cardio*' IN BOOLEAN MODE)
-- La frase exacta
AGAINST('"dolor de cabeza"' IN BOOLEAN MODE)
-- Con "control" pero sin "rutinario"
AGAINST('+control -rutinario' IN BOOLEAN MODE)
El modo booleano es el que querrás para un buscador con filtros. Además, funciona aunque no exista índice FULLTEXT, solo que entonces será lento.
La longitud mínima de palabra
Este detalle desconcierta a mucha gente: por defecto, InnoDB ignora las palabras de menos de 3 caracteres.
SHOW VARIABLES LIKE 'innodb_ft_min_token_size';
Si necesitas buscar términos cortos —códigos, siglas—, hay que cambiar esa variable en la configuración del servidor y reconstruir el índice. No es un cambio que puedas hacer sobre la marcha.
Las palabras vacías
MySQL mantiene una lista de palabras demasiado comunes para ser útiles, que ignora al indexar. En inglés incluye artículos y preposiciones.
El problema para nosotros: esa lista está pensada para el inglés, así que palabras españolas frecuentes como «de», «la» o «para» sí se indexan y ensucian los resultados.
Se puede definir una lista propia:
CREATE TABLE mis_stopwords (value VARCHAR(30)) ENGINE=InnoDB;
INSERT INTO mis_stopwords VALUES ('de'), ('la'), ('el'), ('para'), ('con');
Y apuntar la configuración del servidor a esa tabla. Requiere reiniciar y reconstruir los índices, así que conviene decidirlo al principio del proyecto.
Combinar con otros filtros
FULLTEXT se lleva bien con el resto de la consulta:
SELECT
c.fecha,
c.diagnostico,
CONCAT(p.nombre, ' ', p.apellido) AS paciente,
MATCH(c.diagnostico) AGAINST('dolor') AS relevancia
FROM citas c
JOIN pacientes p ON c.paciente_id = p.id
WHERE MATCH(c.diagnostico) AGAINST('dolor')
AND c.estado = 'atendida'
AND c.fecha >= '2026-01-01'
ORDER BY relevancia DESC
LIMIT 20;
Búsqueda de texto, filtros normales y ordenación por relevancia en una sola consulta.
FULLTEXT o LIKE
LIKE |
FULLTEXT |
|
|---|---|---|
| Usa índice | Solo sin % inicial |
Sí |
| Ordena por relevancia | No | Sí |
| Busca varias palabras | Torpe | Natural |
| Coincidencias parciales | Sí, %tex% |
Solo por prefijo |
| Palabras cortas | Sí | Mínimo 3 caracteres |
Usa LIKE para búsquedas por prefijo en campos cortos: autocompletar un apellido, filtrar por código.
Usa FULLTEXT para buscar en textos largos: descripciones, artículos, diagnósticos, comentarios.
Cuándo se te queda corto
Seamos honestos sobre los límites. FULLTEXT es excelente para un buscador interno, pero no maneja bien:
- Errores de escritura. Buscar «cardilogía» no encuentra «cardiología».
- Sinónimos. «doctor» no encuentra «médico».
- Raíces de palabra. «corriendo» no encuentra «correr».
Si necesitas eso, la herramienta adecuada es un motor de búsqueda especializado como Elasticsearch o Meilisearch, que se integran junto a la base de datos.
Pero para la mayoría de los sistemas, FULLTEXT sobra: es gratis, ya está instalado y no añade una pieza más que mantener.
Un buscador completo
Juntando todo, así se vería el buscador de un sistema:
SELECT
c.id,
c.fecha,
LEFT(c.diagnostico, 150) AS resumen,
CONCAT(p.nombre, ' ', p.apellido) AS paciente,
ROUND(MATCH(c.diagnostico) AGAINST('+dolor +cabeza' IN BOOLEAN MODE), 2) AS relevancia
FROM citas c
JOIN pacientes p ON c.paciente_id = p.id
WHERE MATCH(c.diagnostico) AGAINST('+dolor +cabeza' IN BOOLEAN MODE)
ORDER BY relevancia DESC
LIMIT 20;
Ese LEFT(diagnostico, 150) devuelve solo un extracto, que es lo que muestras en la lista de resultados.
Desde PHP, recuerda pasar el término de búsqueda como parámetro, nunca concatenado.
Errores comunes
- Columnas del
MATCHdistintas de las del índice. - Buscar palabras de menos de 3 letras sin cambiar la configuración.
- Esperar coincidencias parciales en medio de la palabra:
FULLTEXTsolo hace prefijos. - Seguir usando
LIKE '%texto%'en tablas grandes. - No ordenar por relevancia, desaprovechando la principal ventaja.
Para cerrar
FULLTEXT es la respuesta correcta cuando alguien pide «un buscador» en el sistema. Resuelve el problema de rendimiento del LIKE y añade algo que este no puede dar: ordenar por qué tan bien coincide cada resultado.
Con esta lección cerramos el recorrido principal del curso de MySQL. Lo que viene son cinco temas complementarios que no cubrimos y que aparecen en cualquier proyecto real.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp