O problema do N+1
Exemplo de Cursos x Pré-requisito
Um curso pode ter vários cursos como pré-requisito.
Exemplo:
- Para fazer Cálculo 1: precisa de Matemática
- Para fazer Cálculo 2: precisa de Matemática e Cálculo 1
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 SQLExercícios extras
- Crie um banco chamado no_trabalho
- Crie tabela pessoa: nome, e-mail, id único
- Crie tabela modelo_celular: nome, modelo, descrição, data de fabricação
- Adicione à pessoa: cep, endereço, número, complemento, lat, lng
- Adicione o CEP:
'05373-020'
e veja se o zero ficou à esquerda 😄