Publicado en

ORM vs SQL directo: cómo el backend accede a los datos

Comparación de la misma consulta escrita en SQL directo y en ORM sobre fondo oscuro

El backend necesita hablar con la base de datos. La pregunta es cómo. Hay dos enfoques principales: escribir el SQL a mano o usar una capa de abstracción que lo genere automáticamente. Esa capa es un ORM, y elegir entre uno y otro tiene consecuencias prácticas en rendimiento, productividad y mantenimiento.

SQL directo

Con SQL directo el desarrollador escribe las queries manualmente y las ejecuta usando el driver nativo del gestor de base de datos. El resultado llega como filas de datos que el código procesa según necesite.

-- La query viaja exactamente como la escribes
SELECT u.nombre, COUNT(p.id) AS pedidos
FROM usuarios u
LEFT JOIN pedidos p ON u.id = p.id_usuario
WHERE u.activo = 1
GROUP BY u.id
ORDER BY pedidos DESC
LIMIT 10;

Lo que ves es exactamente lo que ejecuta la base de datos. Sin intermediarios, sin traducciones, sin sorpresas.

ORM: Object-Relational Mapper

Un ORM (Object-Relational Mapper) es una capa de software que mapea las tablas de la base de datos a clases o modelos del lenguaje de programación. En lugar de escribir SQL, interactúas con objetos y el ORM genera las queries por ti.

// La misma consulta con un ORM (pseudo-código)
Usuario.findAll({
  atributos: ['nombre', [COUNT('p.id'), 'pedidos']],
  include:   [{ model: Pedido }],
  where:     { activo: true },
  group:     ['id'],
  order:     [['pedidos', 'DESC']],
  limit:     10
})

El ORM genera el SQL, lo ejecuta y devuelve los resultados como objetos del modelo. También gestiona las relaciones: usuario.pedidos es un array de objetos Pedido, no un JOIN que tienes que escribir tú. Ejemplos conocidos son Hibernate (Java), SQLAlchemy (Python), Eloquent (PHP/Laravel) o Sequelize (Node.js).

Pros y contras

Tabla comparativa de ventajas e inconvenientes de SQL directo y ORM: SQL directo tiene más control y rendimiento, ORM tiene más productividad y portabilidad

La decisión no es técnica sino contextual. SQL directo gana en control y rendimiento; ORM gana en velocidad de desarrollo y abstracción. Los problemas de ORM no son insuperables, pero hay que conocerlos.

El problema N+1

El problema más habitual con los ORMs es el N+1: cuando pides una lista de registros y luego accedes a una relación de cada uno, el ORM ejecuta una query por cada elemento de la lista en lugar de una sola query que lo traiga todo.

El problema N+1: sin eager loading se ejecutan 101 queries para 100 usuarios, con eager loading se resuelve con solo 2 queries

La solución es el eager loading: indicarle al ORM que cargue las relaciones en la misma operación, lo que genera una query con JOIN o dos queries con IN en lugar de N+1 queries individuales. En la mayoría de ORMs se indica con una opción de include o with.

El problema no es el ORM en sí, sino no conocerlo bien. Un ORM mal usado puede generar consultas mucho peores que SQL manual. Hay que entender el SQL que genera.

El punto intermedio: query builders

Entre SQL directo y ORM existe un enfoque intermedio: los query builders. Son librerías que ofrecen una API fluida para construir queries sin escribir SQL en texto plano, pero sin el mapeo objeto-tabla completo de un ORM.

// Query builder (pseudo-código, similar a Knex.js)
db('usuarios')
  .select('u.nombre', db.raw('COUNT(p.id) AS pedidos'))
  .leftJoin('pedidos AS p', 'u.id', 'p.id_usuario')
  .where('u.activo', 1)
  .groupBy('u.id')
  .orderBy('pedidos', 'desc')
  .limit(10)

La sintaxis es más próxima al SQL real y el desarrollador sigue teniendo control sobre la estructura de la query. La ventaja sobre SQL directo es que es portable entre gestores (el query builder genera el dialecto correcto para MySQL, PostgreSQL o SQLite) y más legible que concatenar strings.

Cuándo usar cada uno

  • ORM: proyectos nuevos con operaciones CRUD estándar, cuando el equipo prefiere trabajar con objetos, cuando las migraciones automáticas ahorran tiempo, o cuando la portabilidad entre gestores importa.
  • SQL directo: consultas complejas con múltiples JOINs, subconsultas o funciones específicas del gestor, cuando el rendimiento es crítico y cada milisegundo importa, o cuando trabajas sobre una base de datos legacy con un esquema que no encaja bien en un ORM.
  • Query builder: buen equilibrio para la mayoría de proyectos. Más control que un ORM completo sin la verbosidad de SQL en strings.

En la práctica, muchos proyectos combinan los tres: ORM para las operaciones habituales, query builder para los casos intermedios y SQL directo para las queries de analítica o rendimiento crítico que el ORM no puede expresar bien.

Con la autenticación, los tokens y el acceso a datos cubiertos, queda un último mecanismo de comunicación que los artículos anteriores no han tocado: qué pasa cuando el servidor necesita hablar con el cliente sin que este lo pida primero.