En los últimos meses me he enfrentado a un caso muy interesante con una empresa que, tras muchos años de evolución, tenía una base de datos MySQL extraordinariamente bien diseñada… pero que ya no aguantaba el ritmo.
Algunos informes tardaban más de 15 minutos en ejecutarse.
Y no era por negligencia:
- Tenían foreign keys bien definidos.
- Los índices estaban perfectamente pensados.
- El diseño relacional era de manual.
Pero después de años acumulando datos y complejidad, algunas consultas simplemente se habían vuelto imposibles de ejecutar de forma interactiva. Literalmente, los usuarios se lo pensaban dos o tres veces antes de pulsar “Generar informe”.
Diagnóstico: cuando todo está bien, pero ya no basta
Analicé el entorno con cuidado:
- No era un problema de diseño.
- No era un problema de infraestructura.
- No era falta de caching.
El problema real era que el sistema relacional, por muy optimizado que estuviera, no estaba hecho para búsquedas dinámicas, parciales y con condiciones cambiantes sobre volúmenes tan masivos de datos.
La solución: Elasticsearch y Logstash, en modo batch
Decidí introducir Elasticsearch como capa de búsqueda secundaria, sin sustituir el sistema relacional, pero sí liberándolo de las consultas más pesadas e interactivas.
Búsqueda rápida, sin necesidad de frescura absoluta
Una de las primeras conversaciones con el equipo fue sobre cuán frescos necesitaban los datos.
La respuesta fue clara: “Si la búsqueda tiene un desfase de una o dos horas, nos da igual. Lo importante es que funcione rápido”.
Eso fue clave. Hacer una indexación en tiempo real habría sido muy complejo: Los datos cambiaban todo el tiempo, y casi cualquier entidad estaba involucrada en esas consultas. Detectar deltas y actualizar solo lo modificado era arriesgado y costoso.
Así que adoptamos un enfoque por lotes, mucho más simple y robusto.
Logstash como generador de documentos
Al final diseñe una imagen Docker personalizada con Logstash, que hacía lo siguiente:
- Ejecuta una query SQL compleja contra la base de datos original.
- Transforma los resultados en documentos preparados para Elasticsearch.
- Los envía directamente a un índice optimizado para búsqueda.
Cada ejecución es autónoma y efímera. El proceso completo vive dentro de una tarea Fargate en AWS ECS: se levanta, hace el trabajo, y muere.
Un cronjob lanza esta tarea cada dos horas, y eso es suficiente.
El equipo ha ganado velocidad sin comprometer la lógica ni la estabilidad del sistema.
Index templates bien hechos
El índice de Elasticsearch usa un index template muy cuidado, con:
- Análisis con ngram para permitir búsquedas parciales desde el tercer carácter.
- Reconocimiento de palabras y normalización.
- Configuración precisa para campos específicos (fechas, códigos, nombres, etc.).
El resultado es una experiencia de búsqueda tipo “autocomplete avanzado”: A medida que vas escribiendo, los resultados aparecen casi al instante, incluso en datasets enormes.
De cuello de botella a herramienta diaria
Gracias a esta solución:
- Las consultas han pasado de 15 minutos a ~150 milisegundos.
- La búsqueda se ha convertido en un commodity dentro de la herramienta interna.
- Lo que antes era un informe con miedo, ahora es parte del flujo natural de trabajo.
Muchas veces, cuando las bases de datos empiezan a flaquear, el instinto es añadir complejidad: particionado, replicación cruzada, materialized views cada vez más específicas…
Pero en muchos casos, la solución más sensata y sostenible es separar responsabilidades:
- La base de datos guarda y protege los datos.
- Elasticsearch los sirve exactamente como lo necesita la aplicación.
Este patrón (guardar en la base de datos, leer desde Elasticsearch) no solo simplifica, sino que escala muy bien. Y además, es fácil de implementar si se hace con cabeza.