Logo InWork WhatsApp Logo

O problema do N+1

Exemplo de Cursos x Pré-requisito

Um curso pode ter vários cursos como pré-requisito.

Exemplo:

CREATE DATABASE minhabase;
USE minhabase;

CREATE TABLE cursos (
cur_id INT(8) PRIMARY KEY AUTO_INCREMENT,
cur_nome VARCHAR(50) NOT NULL
);

INSERT cursos (cur_nome) VALUES ('Matemática Básica'), ('Cálculo 1'), ('Cálculo 2');

CREATE TABLE curso_req (
cur_id INT(8) NOT NULL,
cur_id_req INT(8) NOT NULL,
CONSTRAINT fk_curso_req FOREIGN KEY (cur_id) REFERENCES cursos (cur_id),
CONSTRAINT fk_cursos_0 FOREIGN KEY (cur_id_req) REFERENCES cursos (cur_id)
);

INSERT curso_req (cur_id, cur_id_req) VALUES
(2, 1), -- Cálculo 1 → Matemática
(3, 1), -- Cálculo 2 → Matemática
(3, 2); -- Cálculo 2 → Cálculo 1

Visualizando dependências com JOIN

SELECT 
    cursos.cur_nome AS Curso_Desejado,
    curso_pre.cur_nome AS Pre_requisito
FROM curso_req
    INNER JOIN cursos AS curso_pre ON curso_req.cur_id_req = curso_pre.cur_id
    INNER JOIN cursos ON curso_req.cur_id = cursos.cur_id;

O problema do N+1

Exemplo PHP para ilustrar:

<?php

// Retorna informação de um curso.
function getClassFromId(int $id): array {
   $stmt = $db->prepare("SELECT cur_id, cur_nome from cursos where cur_id = ?");
   $stmt->execute($id);
   return $stmt->fetch(PDO::FETCH_OBJ);
}

// Retorna todos os cursos obrigatorios
function getAllRequiredClassFromClassId(int $curId): array {
   $stmt = $db->prepare("SELECT cur_id, cur_id_req from curso_req where cur_id = ?");
   $stmt->execute($curId);
   return $stmt->fetchAll(PDO::FETCH_OBJ);
}

// Vamos retornar todos os cursos obrigatorios para Cálculo 2 (Vai retornar: Matemática + Cálculo 1s).
$getAllRequiredClass = getAllRequiredClassFromClassId(3);
foreach($getAllRequiredClass as $requiredClass) {
   print getClassFromId($requiredClass->cur_id)->cur_nome . "\n";
}

Esse código faz 3 queries (1 + N), o que é ineficiente. Melhor resolver com JOIN.

Exemplo com JOIN para evitar N+1:

SELECT 
cursos.cur_nome,
COUNT(cursos_req.cur_id) AS qnt_materias_pre    
FROM cursos
LEFT JOIN cursos_req ON cursos_req.cur_id = cursos.cur_id
GROUP BY cursos.cur_id;

🚀 Quer dominar SQL de verdade?

Aprenda banco de dados na prática com meu eBook SQL Descomplicado. Com exercícios, explicações claras e exemplos reais, ele vai te ajudar a sair do básico rapidamente.

👉 QUERO APRENDER SQL

Exercícios extras

  1. Crie um banco chamado no_trabalho
  2. Crie tabela pessoa: nome, e-mail, id único
  3. Crie tabela modelo_celular: nome, modelo, descrição, data de fabricação
  4. Adicione à pessoa: cep, endereço, número, complemento, lat, lng
  5. Adicione o CEP: '05373-020' e veja se o zero ficou à esquerda 😄