Un desarrollador de Magento cambió 300 llamadas individuales a ProductRepositoryInterface::getById() por una única consulta de colección. Las peticiones a la base de datos bajaron de 300 a 1, y la página de categoría cargó notablemente más rápido. ¿El inconveniente? Algunos productos desaparecieron de la tienda, desconcertando a clientes y propietarios.

El problema N+1 en una página de categoría de Magento

La página mostraba 300 productos. Para cada uno, el código obtenía dos atributos personalizados mediante el método getById() del repositorio, generando una consulta por producto: el clásico patrón N+1. Reemplazar esas cargas individuales por una colección que extrae todas las filas necesarias en una sola consulta redujo drásticamente el número de consultas. La latencia del front-end mejoró, pero la lista de productos ahora omitía artículos que antes aparecían.

Por qué la colección oculta los artículos sin stock

El módulo CatalogInventory de Magento añade automáticamente un filtro de "en stock" a cualquier colección de productos creada para el frontend. El filtro se activa cuando la configuración de la tienda Display Out of Stock Products está desactivada, una opción común para los comerciantes que no desean mostrar artículos no disponibles.

Por el contrario, el repositorio nunca aplica un filtro de stock. Simplemente comprueba que un producto existe y lo devuelve, independientemente del nivel de inventario. Cuando el código pasó de llamadas al repositorio a una colección, el filtro de stock eliminó silenciosamente cada producto cuya cantidad fuera cero. No se registró ningún error; la colección simplemente devolvió menos filas de las que el desarrollador esperaba.

Qué significa esto para los comerciantes

Una tienda que elimina silenciosamente los SKU sin stock crea varios problemas:

  • Los componentes del front-end reciben entradas faltantes, lo que produce etiquetas vacías o precios incorrectos.
  • La depuración se vuelve más difícil porque el síntoma (la falta de productos) no genera advertencias.

Debido a que la mayoría de las pruebas automatizadas utilizan fixtures de productos con stock, el error suele permanecer oculto hasta que el sitio funciona con inventario real.

Cómo mantener la velocidad sin ocultar el inventario

  1. Omitir el filtro de stock por defecto – Elimine explícitamente el filtro de la colección si necesita todos los productos, independientemente de su disponibilidad. Magento ofrece métodos para desactivar o reemplazar el plugin de stock por cada consulta.
  2. Usar el repositorio cuando la precisión sea importante – El repositorio garantiza que se devuelva cada ID de producto solicitado, incluso si no tiene stock. Cachee los resultados o cargue solo los IDs que necesite para controlar las consultas adicionales.
  3. Emplear un resource model o SQL puro – Consulte la tabla de productos directamente para obtener los atributos requeridos. Esto evita todos los plugins de la colección y le otorga control total sobre qué filas se incluyen.

Velocidad frente a corrección

Cambiar un bucle N+1 ruidoso por una única consulta de colección parece natural; la reducción de la latencia es tangible. Sin embargo, una consulta más rápida que devuelve el conjunto incorrecto de productos es un defecto, no una optimización. Los desarrolladores deben sopesar la velocidad bruta frente al riesgo de mostrar un catálogo incompleto.

Qué vigilar a continuación

  • Desviación de la configuración – Verifique que la bandera Display Out of Stock Products coincida con el comportamiento previsto de cualquier código de colección personalizado.
  • Efectos secundarios de los plugins – Otros módulos pueden añadir sus propios filtros a las colecciones. Revise la pila de plugins cada vez que cambie las estrategias de consulta.

La lección es clara: solucionar un problema N+1 con una colección solo es un éxito si también audita los filtros por defecto de la colección. Ignorar el filtro de stock integrado de Magento puede podar silenciosamente su catálogo, convirtiendo una mejora de rendimiento en una pérdida de ingresos.