CORAZZA.DEV

Estação #03

Capa de Álgebra Relacional e Bancos de Dados

Álgebra Relacional e Bancos de Dados

Marcos Corazza | 29 junho 2026
#data-science#algebra#fundamentos

Na Estação 3, decodificamos a Álgebra Relacional e os fundamentos de Banco de Dados. Antes de escrever queries complexas em SQL ou manipular DataFrames no Pandas, é vital entender a matemática revolucionária de Edgar F. Codd que transformou dados caóticos em tabelas organizadas. Exploramos as operações essenciais (Seleção, Projeção, União, Produto Cartesiano) e como elas garantem a independência dos dados. Descubra a teoria matemática que sustenta a extração de dados no mundo moderno.

RESUMO
Palavras:~1.860
Leitura:9 min
Linha01 Fundamentos
Progresso:16.7% [■■---------]

Até agora, em nossa jornada, construímos uma base matemática para entender as transformações de dados (Álgebra Linear) e exploramos as estruturas de baixo nível que os computadores usam para armazenar e buscar informações na memória (Árvores Binárias e Hashes). Mas, no dia a dia, um Cientista de Dados raramente interage diretamente com ponteiros de memória ou implementa funções de hash do zero. Nós interagimos com Bancos de Dados.

Nesta terceira estação, vamos elevar o nosso nível de abstração. Vamos descobrir como a humanidade resolveu o problema de organizar, consultar e garantir a integridade de montanhas de informações comerciais. Para isso, precisamos voltar à década de 1970, nos laboratórios da IBM, onde um matemático chamado Edgar F. Codd publicou um artigo que mudaria a computação para sempre, introduzindo o Modelo Relacional e sua linguagem matemática subjacente: a Álgebra Relacional.

Pode parecer contraintuitivo estudar álgebra para aprender sobre bancos de dados, mas não se engane: toda consulta SQL que você escreve, e toda filtragem que você faz no Pandas, é executada nos bastidores como uma equação de Álgebra Relacional. Compreender essa matemática é obter a planta arquitetônica de como os dados fluem dentro de uma corporação.

1. Do Caos à Ordem: O Paradigma Relacional

Antes do modelo relacional, os sistemas de banco de dados eram um pesadelo logístico. Eles usavam modelos de navegação hierárquica ou em rede. O que isso significa na prática? Significava que a forma como o dado era consultado dependia estritamente de como ele estava gravado no disco físico. Se o engenheiro mudasse a estrutura do disco, todos os programas de consulta quebravam. Não havia independência de dados.

Codd revolucionou isso aplicando a Teoria dos Conjuntos (da matemática) aos dados de negócios. Ele propôs que o usuário não precisaria saber onde ou como os dados estavam armazenados fisicamente. O usuário apenas declararia o que ele queria, operando sobre estruturas lógicas simples e bidimensionais.

O Vocabulário Relacional

No mercado de trabalho, usamos termos práticos, mas na academia e nos motores de banco de dados, o vocabulário é rigorosamente matemático. É vital conhecer essa tradução:

  • Relação (Relation): No mundo prático, chamamos de Tabela. É a estrutura bidimensional principal. Um banco de dados relacional é simplesmente uma coleção de relações.

  • Tupla (Tuple): No dia a dia, chamamos de Linha ou Registro. Representa uma única entidade no mundo real (ex: um cliente específico).

  • Atributo (Attribute): Na prática, é a Coluna. Descreve as propriedades de uma relação (ex: "Nome", "Idade", "CPF").

  • Domínio (Domain): É o conjunto de valores atômicos válidos para um atributo. O domínio é o que chamamos de Tipagem de Dados. Se o atributo é "Idade", o domínio são números inteiros positivos. Você não pode armazenar a string "João" na coluna de idade.

Essa separação rígida impõe uma ordem estrutural (o schema) que garante a integridade e a consistência da informação, evitando que os dados se transformem em um pântano inútil.

2. A Álgebra Relacional: A Matemática das Tabelas

A Álgebra Relacional é uma linguagem de consulta procedimental. Ela consiste em um conjunto de operações que recebem uma ou mais relações (tabelas) como entrada e produzem uma nova relação como saída.

Como a saída de uma operação é sempre uma tabela, podemos encadear essas operações infinitamente, assim como na álgebra básica podemos resolver (2+3)×4(2 + 3) \times 4. Vamos dissecar as operações fundamentais que suportam todo o processamento analítico.

2.1 Seleção (Selection - σ\sigma)

A Seleção é usada para escolher um subconjunto de tuplas (linhas) de uma relação que satisfaçam uma condição específica. Ela filtra os dados horizontalmente.

Na matemática, usamos a letra grega Sigma (σ\sigma). A sintaxe é σcondic\ca~o(Relac\ca~o)\sigma_{condição}(Relação).

Exemplo Lógico: Imagine uma tabela chamada ClientesClientes. Queremos apenas os clientes com idade superior a 30 anos.

σidade>30(Clientes)\sigma_{idade > 30}(Clientes)

O resultado é uma nova tabela que mantém todas as colunas originais, mas contém apenas as linhas onde a condição é verdadeira.

2.2 Projeção (Projection - π\pi)

Enquanto a Seleção filtra as linhas (horizontalmente), a Projeção filtra os atributos (verticalmente). Ela escolhe colunas específicas e descarta o resto. O símbolo utilizado é a letra grega Pi (π\pi). A sintaxe é πcoluna1,coluna2(Relac\ca~o)\pi_{coluna1, coluna2}(Relação).

Exemplo Lógico: Queremos apenas os nomes e os emails da nossa tabela de Clientes, ignorando seus CPFs, endereços e idades.

πnome,email(Clientes)\pi_{nome, email}(Clientes)

Nota matemática vital: Como a Álgebra Relacional é baseada na teoria dos conjuntos, um conjunto não pode ter itens duplicados. Portanto, a operação de projeção remove automaticamente qualquer linha inteiramente duplicada no resultado.

2.3 Combinando Operações (Composição)

Na vida real, queremos filtrar linhas e colunas ao mesmo tempo. Podemos aninhar as fórmulas:

πnome,email(σidade>30(Clientes))\pi_{nome, email}(\sigma_{idade > 30}(Clientes))

Lê-se de dentro para fora: Primeiro, encontre os clientes com mais de 30 anos (Seleção). Do resultado dessa operação, extraia apenas os nomes e emails (Projeção).

2.4 União (Union - \cup)

Permite juntar as tuplas de duas relações diferentes. Para que a união seja possível, as tabelas precisam ser compatíveis em esquema (mesmo número de colunas e os mesmos domínios/tipos de dados na mesma ordem).

Exemplo Lógico: Você tem uma tabela Clientes_SPClientes\_SP e outra Clientes_RJClientes\_RJ. Para obter a lista nacional:

Clientes_SPClientes_RJClientes\_SP \cup Clientes\_RJ

Novamente, duplicatas exatas são eliminadas automaticamente.

2.5 Diferença de Conjuntos (Set Difference - -)

Retorna as tuplas que estão presentes na primeira relação, mas não estão na segunda. Também requer que as tabelas sejam compatíveis.

Exemplo Lógico: Você tem uma tabela Todos_UsuariosTodos\_Usuarios e uma tabela Usuarios_CanceladosUsuarios\_Cancelados. Para encontrar os usuários ativos:

Todos_UsuariosUsuarios_CanceladosTodos\_Usuarios - Usuarios\_Cancelados

2.6 Produto Cartesiano (Cartesian Product - ×\times)

Esta é a operação mais perigosa e poderosa. O Produto Cartesiano combina cada tupla de uma relação com todas as tuplas da outra relação.

Se a Tabela A tem 100 linhas e a Tabela B tem 1000 linhas, A×BA \times B gerará uma monstruosidade de 100.000 linhas, combinando tudo com tudo. Isolado, o produto cartesiano raramente tem utilidade analítica, mas ele é a base matemática fundamental para a operação de Join, que dissecaremos profundamente na Estação 4.

2.7 Renomeação (Rename - ρ\rho)

Muitas vezes, após várias operações, os nomes das colunas ficam confusos ou se chocam. A operação Rho (ρ\rho) permite alterar o nome de atributos ou de relações inteiras. Ela não altera os dados, apenas os rótulos de apresentação (o famoso AS no SQL).

3. A Ponte: Da Álgebra para o SQL

Por que nós não digitamos πnome(σidade>30(Clientes))\pi_{nome}(\sigma_{idade>30}(Clientes)) no teclado hoje em dia?

Porque nos anos 70, criar teclados com letras gregas e treinar analistas de negócios para escrever fórmulas matemáticas complexas era inviável. Então, a IBM desenvolveu a Structured Query Language (SQL).

O SQL foi desenhado para parecer com a sintaxe do idioma inglês, mas, por baixo dos panos, o Otimizador de Consultas (Query Optimizer) do banco de dados traduz imediatamente seu código SQL de volta para a Álgebra Relacional.

Veja a correspondência direta:

  • A Relação \rightarrow FROM tabela

  • A Seleção (σ\sigma) \rightarrow WHERE condição

  • A Projeção (π\pi) \rightarrow SELECT coluna1, coluna2

Portanto, a fórmula matemática πnome,email(σidade>30(Clientes))\pi_{nome, email}(\sigma_{idade > 30}(Clientes)) é literalmente:

SELECT nome, email FROM Clientes WHERE idade > 30;

A grande diferença de paradigma é que a Álgebra Relacional é procedimental (você especifica a ordem dos passos matemáticos), enquanto o SQL é declarativo (você descreve o que quer, e o Otimizador do banco de dados usa heurísticas e Estatísticas para descobrir qual é a ordem algébrica mais rápida para chegar lá usando as Árvores Binárias dos índices).

4. O Impacto Direto em Data Science

Por que um Cientista de Dados não pode simplesmente ignorar isso e baixar tudo como CSV para ler no Python?

  1. Volume Intratável: Bases de dados modernas têm Terabytes, às vezes Petabytes. Tentar puxar tudo para a memória RAM do Python via rede vai travar sua máquina e o servidor.

  2. Pushdown Computation: O conhecimento profundo da Álgebra Relacional permite que você empurre (pushdown) a computação para o banco de dados. Um Cientista de Dados Sênior usa as operações de seleção (σ\sigma) e projeção (π\pi) no SQL para extrair apenas a matriz exata necessária para o modelo preditivo, aproveitando o poder de processamento distribuído e os índices O(log n) do banco de dados.

  3. Fundamento do Pandas/Spark: O pacote Pandas em Python e o Apache Spark são, na sua essência, motores de Álgebra Relacional processados em memória. Compreender a teoria dos conjuntos garante que você manipule DataFrames sem criar explosões combinatórias que consomem toda a sua memória.

5. Resumo e Próximos Passos

O modelo relacional retirou a navegação física do controle dos programadores e a entregou para a matemática dos conjuntos, criando sistemas resilientes, seguros e flexíveis. Compreendemos a Seleção (cortar na horizontal), a Projeção (cortar na vertical) e as operações de conjunto (União e Diferença).

No entanto, o verdadeiro poder dos bancos de dados não está em uma tabela isolada, mas na relação entre elas. Como conectamos Vendas, Clientes e Produtos de forma eficiente? Na Estação 4, mergulharemos fundo na evolução direta do Produto Cartesiano: Os Joins (Inner, Outer, Cross e Theta).

Antes de seguir em frente, vamos traduzir essas teorias matemáticas abstratas para o código Python que você rodará todos os dias em seus notebooks Jupyter.

Mão na Massa: Álgebra Relacional com Pandas

Embora o SQL seja a linguagem oficial dos bancos de dados, os Cientistas de Dados realizam as exatas mesmas operações de Álgebra Relacional usando a biblioteca pandas em Python. O Pandas abstrai as tabelas como DataFrames.

Abaixo, simulamos um banco de dados na memória do Python e executamos as operações matemáticas fundamentais que vimos na teoria.

import pandas as pd dados_clientes = { 'cliente_id': [1, 2, 3, 4, 5], 'nome': ['Ana', 'Bruno', 'Carlos', 'Diana', 'Eduardo'], 'idade': [28, 35, 42, 29, 55], 'cidade': ['SP', 'RJ', 'MG', 'SP', 'RS'] } dados_novos_clientes = { 'cliente_id': [6, 7, 1], 'nome': ['Fernanda', 'Gustavo', 'Ana'], 'idade': [31, 22, 28], 'cidade': ['PR', 'SC', 'SP'] } df_clientes = pd.DataFrame(dados_clientes) df_novos = pd.DataFrame(dados_novos_clientes) # ------------------------------------- # RELAÇÃO ORIGINAL (TABELA CLIENTES) # ------------------------------------- print(df_clientes, "\n") # --------------------------------------- # SELEÇÃO (Sigma - Filtragem de Linhas) # --------------------------------------- # SQL: SELECT * FROM df_clientes WHERE idade > 30 selecao = df_clientes[df_clientes['idade'] > 30] print(selecao, "\n") # -------------------------------------- # PROJEÇÃO (Pi - Filtragem de Colunas) # -------------------------------------- # SQL: SELECT nome, cidade FROM df_clientes projecao = df_clientes[['nome', 'cidade']] print(projecao, "\n") # --------------------------------------- # COMPOSIÇÃO (Seleção e Projeção Juntas) # --------------------------------------- composicao = df_clientes[df_clientes['cidade'] == 'SP'][['nome', 'idade']] print(composicao, "\n") # ---------------------------------- # UNIÃO (Union - Juntar Conjuntos) # ---------------------------------- uniao = pd.concat([df_clientes, df_novos]).drop_duplicates(subset=['cliente_id']) print(uniao, "\n") # ----------------------------------------- # DIFERENÇA DE CONJUNTOS (Set Difference) # ----------------------------------------- diferenca_merge = df_novos.merge(df_clientes, on='cliente_id', how='left', indicator=True) diferenca = diferenca_merge[diferenca_merge['_merge'] == 'left_only'] diferenca = diferenca[['cliente_id', 'nome_x', 'idade_x', 'cidade_x']].rename( columns={'nome_x': 'nome', 'idade_x': 'idade', 'cidade_x': 'cidade'} ) print(diferenca, "\n") # ---------------------------------------- # PRODUTO CARTESIANO (Cartesian Product) # ---------------------------------------- produto_cartesiano = df_clientes.merge(df_novos, how='cross', suffixes=('_orig', '_novo')) print(f"Número de linhas geradas: {len(produto_cartesiano)}") print(produto_cartesiano.head(5))