12 julio, 2025

En muchos sitios web que usan MySQL, sobre todo aquellos que manejan nombres en español o portugués, es común tener problemas con búsquedas. Por ejemplo, un usuario busca “camion" y no encuentra “camión“, o escribe “cafetera" y no aparece “cafétera“.

En este artículo aprenderás cómo configurar tu base de datos y tu código PHP para que las búsquedas:

  • Sean insensibles a acentos y mayúsculas
  • Usen FULLTEXT para mayor velocidad
  • Funcionen en bases de datos grandes

📦 Escenario: catálogo de productos

Supongamos que tenemos una tabla productos así:

CREATE TABLE productos (
  id INT AUTO_INCREMENT PRIMARY KEY,
  nombre VARCHAR(255) NOT NULL,
  descripcion TEXT,
  categoria VARCHAR(100),
  precio DECIMAL(10,2),
  FULLTEXT(nombre, descripcion)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;

Problema: búsqueda con MATCH ... AGAINST no encuentra “camión” si buscas “camion”


🚨 ¿Por qué sucede?

Aunque utf8mb3_unicode_ci es insensible a acentos para comparaciones con LIKE, no garantiza lo mismo para FULLTEXT. Este índice crea un diccionario de términos tal como están escritos, por lo que “camión” y “camion” son palabras distintas.


✅ Solución 1: Migrar a utf8mb4_unicode_ci

El primer paso ideal es actualizar la tabla a utf8mb4, que tiene mejor soporte para unicode y búsqueda:

ALTER TABLE productos CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Luego, recrea el índice FULLTEXT para asegurarte de que se ajuste a la nueva codificación:

ALTER TABLE productos 
  DROP INDEX nombre,
  ADD FULLTEXT(nombre, descripcion);

✅ Solución 2: Preprocesar el término de búsqueda en PHP

A pesar de tener la collation correcta, MySQL no siempre trata acentos como equivalentes en FULLTEXT. Entonces, también debes normalizar el término de búsqueda desde el lado del servidor. En PHP:

function quitarAcentos($cadena) {
    return iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $cadena);
}

$terminoBusqueda = 'camion'; // viene del usuario
$normalizado = quitarAcentos($terminoBusqueda);

🔍 Consulta optimizada con FULLTEXT + prioridad de categoría

Supongamos que quieres que los resultados de categoría "ofertas" salgan primero:

SELECT id, nombre, descripcion, categoria, precio
FROM productos
WHERE MATCH(nombre, descripcion) AGAINST(:busqueda IN BOOLEAN MODE)
ORDER BY (categoria = 'ofertas') DESC, precio ASC
LIMIT 20;

Esto ordena los productos donde la categoría es 'ofertas' primero, y luego por precio ascendente.


🧪 Alternativa sin FULLTEXT (cuando hay pocos datos)

Si tu tabla es pequeña o temporalmente necesitas algo rápido, puedes usar LIKE (aunque es más lento):

SELECT * FROM productos
WHERE nombre LIKE '%camion%' OR descripcion LIKE '%camion%';

Y puedes duplicar eso para considerar las versiones con y sin acento si no estás normalizando:

WHERE nombre LIKE '%camión%' OR nombre LIKE '%camion%'

📌 Conclusión

Para una búsqueda moderna y amigable:

  1. Usa utf8mb4_unicode_ci para buena compatibilidad internacional.
  2. Usa FULLTEXT para rendimiento.
  3. Normaliza los términos con PHP (iconv) para ignorar acentos.
  4. Ajusta el ORDER BY según tus necesidades de negocio.

¡Así mejoras tanto la experiencia del usuario como el rendimiento de tu aplicación!


¿Qué opinas de esta solución? ¿La conocías?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *