Performance do ORM vs SQL: O que é melhor para seu projeto Node.js?

image.png Acho que todo mundo já passou por aquele momento em que está desenvolvendo um projeto, querendo fazer tudo de forma otimizada, mas se pergunta: “Será que o ORM está fazendo o meu banco de dados ficar lento?”. Eu já passei por isso e, sinceramente, não sabia se deveria continuar usando o ORM ou partir para o SQL puro. E fui pesquisar, no final, decidi trazer algumas respostas para quem, como eu, também fica nessa dúvida. Neste artigo, vamos bater um papo sobre a performance do ORM e do SQL puro, com foco em como isso impacta os projetos em Node.js. No final das contas, o que realmente importa é: qual das duas opções vai dar conta do recado no seu projeto e, claro, como você pode tirar o máximo de performance de cada uma delas.

O que é um ORM e como isso afeta a performance?

Se você é desenvolvedor Node.js e já trabalhou com bancos de dados relacionais, provavelmente já usou algum ORM. Mas o que é isso exatamente? ORM (Object-Relational Mapping) é um tipo de ferramenta que "mapeia" as tabelas do banco de dados para objetos na linguagem de programação. Ou seja, com o ORM, você não precisa escrever SQL para buscar dados, manipular registros ou fazer consultas. A ferramenta faz tudo isso para você. No ecossistema Node, temos vários ORMs populares, como Sequelize, Prisma e TypeORM. Exemplo com Sequelize: carbon.png Exemplo com Prisma: carbon (1).png

Vantagens do ORM:

  1. Facilidade de uso: ORMs abstraem a complexidade do SQL, tornando mais rápido o desenvolvimento.
  2. Manutenção simplificada: Mudanças no esquema do banco de dados podem ser gerenciadas por migrations.
  3. Portabilidade: O mesmo código ORM pode funcionar com diferentes bancos de dados com poucas ou nenhuma modificação.

Desvantagens do ORM:

  1. Performance: Para operações complexas, ORMs podem gerar queries ineficientes.
  2. Curva de aprendizado: Algumas ferramentas possuem APIs complexas e exigem conhecimento específico.
  3. Overhead: O custo adicional de abstrações pode impactar a performance em cenários de alto volume.

🆚

SQL Puro: O controle total sobre as consultas

Agora, se você opta por SQL puro, é como se estivesse conversando diretamente com o banco de dados. Você escreve suas consultas, otimiza elas da forma que achar melhor, e tem o controle total de como os dados são recuperados. Isso é ótimo quando a performance é prioridade.

Vantagens do SQL Puro:

  1. Performance otimizada: Consultas ajustadas manualmente tendem a ser mais rápidas.
  2. Flexibilidade: Você tem acesso total aos recursos do banco, como índices personalizados e stored procedures.
  3. Controle absoluto: Pode lidar melhor com casos de uso complexos.

Desvantagens do SQL Puro:

  1. Manutenção: Consultas complexas podem ser difíceis de entender e atualizar.
  2. Maior risco de erros: Sem abstrações, erros de sintaxe e SQL injection tornam-se mais comuns.
  3. Maior esforço inicial: Escrever e otimizar SQL exige mais conhecimento e tempo.

Benchmarking: ORM vs SQL Puro

Agora vamos dar uma olhada em benchmarks que mostram a diferença de performance entre ORM e SQL puro. Se você acessar o benchmark publicado no AprendaGolang, vai ver que, em operações complexas, SQL puro pode ser até 40% mais rápido que ORMs, dependendo da consulta. Por exemplo:

  • Com ORM (Sequelize): Uma consulta simples pode levar algo em torno de 100ms devido ao overhead de abstração.
  • Com SQL puro: A mesma consulta no banco pode ser otimizada e levar apenas 50ms. Ou seja, em aplicações com grandes volumes de dados ou consultas complexas, o SQL puro geralmente se sai melhor. Mas para operações mais simples ou quando o foco é agilidade no desenvolvimento, o ORM é um verdadeiro aliado.

Quando usar ORM ou SQL puro?

Use ORM quando:

  • O time está focado em entregar rápido e precisa de uma solução mais simples para interação com o banco.
  • O projeto tem requisitos de performance moderados (por exemplo, um sistema que não vai lidar com milhões de registros por segundo).
  • O time tem pouca experiência com SQL e não quer lidar com a complexidade de escrever queries manuais.

Use SQL puro quando:

  • A performance é crítica e você precisa de total controle sobre as consultas.
  • Seu sistema precisa lidar com consultas complexas, como JOINs, subqueries, ou consultas analíticas.
  • O projeto envolve grandes volumes de dados e você precisa otimizar ao máximo o tempo de resposta. image.png

O melhor dos dois mundos?

Depois de olhar para os prós e contras de cada abordagem, uma coisa fica clara: o ideal é avaliar cada caso e, quando possível, usar o melhor dos dois mundos. Em muitos projetos, você pode usar o ORM para as consultas mais simples e o SQL puro quando a performance for realmente um requisito crítico. Por exemplo, você pode usar Sequelize ou Prisma para as consultas simples de CRUD, mas para aquelas queries pesadas que envolvem muitos dados ou operações complexas, dar preferência ao SQL puro pode fazer toda a diferença. Em resumo, o que deu para perceber é que não existe uma única resposta. O que realmente importa é entender os requisitos do seu projeto e escolher a ferramenta certa para o trabalho. Às vezes, uma mistura dos dois pode ser a escolha mais inteligente.

Conclusão

No final das contas, tanto o ORM quanto o SQL puro têm seus pontos fortes e fracos. Sequelize, Prisma e TypeORM são excelentes para produtividade e flexibilidade, mas, como vimos, quando a performance é crucial, o SQL puro ainda tem sua vantagem. Em fim, como deu para perceber, o ideal é avaliar as necessidades do projeto e, muitas vezes, combinar os dois. Se você ainda está em dúvida, talvez o melhor seja começar com o ORM e, conforme o projeto evolui, otimizar algumas consultas para SQL puro quando for necessário. Afinal, quem não ama uma boa consultinha otimizada, né?

Referências

Com ORM (Sequelize): Uma consulta simples pode levar algo em torno de 100ms devido ao overhead de abstração.

Não sei coo acontece no Node, não sou especialista nele, porém eu uso todo o poder do EloquentORM do Laravel e acompanho todas as queries pelo Laravel DebugBar para otimizá-las e evitar duplicação.

A minha query mais rápida leva 1.6 milisegundos, enquanto a mais lenta leva 5.9ms. Não sei do funcionamento em outras linguagens se o ORM é melhor ou pior, mas com PHP não tenho a necessidade nenhuma de utilizar SQL puro, inclusive é bem capaz da minha consulta sair menos otimizada do que a do Eloquent rsrs. Então esses 100ms estão pouco altos, não acha? Acredito que a infra seja mais preponderante nesse quesito do que o uso de ORMs.

Faz tempo, mas já utilizava o Eloquent, e de fato dava para perceber que as aplicações feitas com Laravel eram mais rápidas nesse quesito. Os ORMs para Node.js criam uma abstração a mais entre o Node e o banco, gerando várias operações para uma consulta simples, e é por isso que deixa as consultas lentas. Não sei como é no php.

Acho que vai pelo que você falou, as vezes é melhor fazer um app usando apenas o adapador do banco e gerando as queries na mão, e as vezes é melhor usar o ORM pra simplificar as coisas e garantir algumas coisas como proteção a SQL Injection. Não adianta fazer tudo em sqlpuro se o sistema é um backoffice que vai ser usado no máximo por umas 20 pessoas assim como um relatório complexo ou uma api que recebe milhões de transações por minuto e performance é um ponto critico não é o ideal forçar um ORM se o sql puro resolve melhor. Fora isso bom artigo.

muito o obrigado. E exatamente isso. ...entendo o que aplicação precisa e usar. Mas em geral gosto muito das migrations dos ORMs, principalmente quando trabalha co. um time.
Esse também é um ponto pra se considerar, manter a versão das tabelas acaba sendo muito útil. Porém, já trabalhei em lugares que havia um app usando alembic (Python) que era o responsável por gerar as tabelas ai a maior parte dos serviços não usava o ORM por que tinha um projeto só pra isso.
Que massa! Eu não conhecia essa solução. Estava analisando agora e percebi que ela resolve todos os meus problemas relacionados à migração de banco. Vou começar a recomendá-la! Apesar de ser mais focado em Node.js, gosto muito de Python e acredito que os dois podem ser usados juntos sem problemas.

Uma abordagem interessante para o melhor dos dois mundos é transformar seus dados diretamente no banco, preparando-os para serem mapeados pela linguagem com uma view ou função que retorna exatamente o que o ORM precisa. Junto com triggers para lidar com operações de update ou insert. Dessa forma, o ORM continua cuidando da integração com a linguagem, mas é o SQL puro que faz o trabalho pesado de verdade!

Para seguir essa abordagem, é necessario ter em mente o lugar onde você vai concentrar a carga bruta do seu processento e a escalabilidade da solução. A logica no banco é bem mais difícil e custosa de escalar do que em uma aplicação node. Hoje eu prefiro evitar esse tipo de solução.
Perfeito, Marcelo e Jonatas! Como toda decisão em computação, envolve avaliar os trade-offs. Obrigado pelos exemplos, porque é exatamente isso que vejo: quase sempre uma instância parruda de um SQL Server, MySQL ou PostgreSQL consegue segurar a barra sem muito estresse. De fato, escalar horizontalmente o banco é um desafio que deve ser evitado, mas, mesmo concentrando uma boa parte do processamento no banco, se feito da maneira certa, não costuma ser um problema.
Isso é legal só ter cuidado com overhead, nos lugares que trabalhei muitas vezes esse recurso foi abusado a ponto que o banco rodava numa instancia de 64 cpus e 128gb de ram e sofria em horário de pico. Mas, isso é importante eu cheguei a conclusão na ultima rinha, que passar toda a responsabilidade das transações e validações pro banco melhorava a performance significativamente.
É uma boa ideia. Agora uma dúvida, como fazer a migração de ORM para SQL puro?
Não sei se tem opção melhor, mas já fiz com script.

Uma ideia interessante seria fazer um comparativo com o próprio TabNews que utiliza SQL puro, testar contra as queries complexas de cálculo de TabCoins e TabCash, ou a própria consulta para trazer os comentários do post.

Excelente ideia, nao dúvida que o curso.dev chega a ter uma aula sobre isso. hehehe

Eu gosto de SQL puro, mas nunca me identifiquei com o estilo de abstração da maioria dos ORMs, mesmo gostando muito do conceito.

Nessa brincadeira cheguei até a criar um ORM pra MySQL com Node.js e gosto bastante dele. A ideia é ser algo bem minimalista e que, principalmente, lembre a sintaxe original do SQL ao ler e escrever a abstração.

Por exemplo, inserindo duas tabelas:

await pool.insert({
  table: 'test',
  values: [
    {
      column1: 'foo',
      column2: 1,
    },
    {
      column1: 'bar',
      column2: 2,
    },
  ],
});

Que nada mais é que uma abstração para:

INSERT INTO `test` (`column1`, `column2`) VALUES (?, ?), (?, ?)
-- params: ['foo', 1,  'bar', 2]

A vantagem aqui é que fica muito mais fácil inserir múltiplas linhas dinamicamente com uma única query, independente do tamanho da lista dos valores, além de oferecer mais segurança por preparar os parâmetros automaticamente.

Já se fosse pra inserir um único valor, acabaria escrevendo mais com o ORM que com SQL puro. Com isso em mente, eu permito o uso do SQL puro para aproveitar a conexão do ORM sem a obrigação de fazer abstrações pra tudo (essa mesma ideia vale para queries extremamente complexas).

Geralmente a gente precisa apenas de: INSERT UPDATE DELETE SELECT SELECT (com 1 innerJOIN às vezes)
[RodrigoSchio](https://www.tabnews.com.br/RodrigoSchio), é bem nessa ideia mesmo:
Screenshot 2024-11-19 at 15 41 58 Screenshot 2024-11-19 at 15 40 37
- O uso de operadores é opcional e alguns dos nomes são inspirados no **Sequelize**.

Usar ORM é ter que aprender duas vezes: a primeira é o próprio ORM e a segunda é o SQL. Só usam bem um ORM quem entende de SQL. Dizer pra novatos que não precisam aprender SQL é dar um péssimo conselho pra eles, ainda mais se tratando de backend.

recomendo muito o drizzle porque ele é basicamente sql dentro de funções typescript. e se isso nao é suficiente, voce pode usar generics dentro das queries puras. sinceramente o melhor pra esse caso de queries pesadas. só é chatinho de criar tabela nele ou criar migrações mas isso é o de menos

Tai uma briga boa.

Como sou muito old school, prefiro SQL - lembrando ainda que trabalhando direto no SQL voce pode fazer umas magias negras, como determinar o indice que deseja utilizar em uma pesquisa, indices que nao devem ser utilizados, criacao de tabelas fantasmas, views otimizadas, nested subqueries, stored procedures e triggers para agilizar funcoes e por ai vai.

Alias, otimizacao de SQL eh uma escola a parte - depende tantos dos dados, das tabelas, dos indices, das tablespaces, um bom DBA consegue fazer coisas bem sinistras.

Mas tambem eh verdade que 80% das queries sao arroz-com-feijao - o problema justamente eh que nos 20% restante ficam as queries cabeludas.

Como fica ? Meus dois cents:

ORM para o dia-a-dia, entregar o sistema o mais rapipdo possivel (e garantir a papinha das criancas ou o pack de cerveja dos marmanjos)

Quando chegar naqueles pontos-chave, ai da uma parada, respira fundo e faz o SQL na mao e compara com o gerado pelo ORM e usa o que for mais performatico - porque ninguem merece sistema lento por preguica do dev.

Lembrando que tudo isso cai por terra quando o dev sequer sabe escrever uma query direito e sai metendo * em tudo pq é só isso que ele sabe fazer.

Melhor um ORM do que uma query mal escrita, comelona e insegura.

Eu sempre uso sql puro,isso te da mais autonomia,pode ser mais trabalhoso mas te da menos dor de cabeça na hora de manutenção e atualização.

Concordo que terar maior autonomia, sql puro permitir otimizar melhor as queries. Mas sobre a questção de "menos dor de cabeça na hora de manutenção e atualização", isso ja não acho tanto. Mesmo com um script excelente, pode ser difícil para outro desenvolvedor entender exatamente o aquela query com 3 ou 4 relacionamentos e alguns filtros está fazendo. Claro que

São pontos realmente muito bons a considerar. Eu, gosto de usar SQL à medida que o modelo entidade-relacionamento fica complexo. Fica impossível usar a abstração do ORM à medida que o MER fica mais complexo. A diferença de performance vai se refletir em um bom MER e no uso correto dos SGBDs, independente do uso de ORM/SQL.

Sim, estou começando a adotar essa abordagem nos meus projetos futuros. Também gosto muito de montar queries e pretendo utilizá-las apenas para regras de negócios complexas ou para melhorar a performance de algumas consultas.