| Bellacosa Mainframe e a modelagem de dados para o db2 |
☕ Um Café no Bellacosa Mainframe
Viagem ao Fundo dos Dados — O Dia em que o Programador COBOL Entrou no Db2 e Descobriu um IMS Morando no Porão
Ou: por que trocar segmentos por tabelas não elimina a hierarquia, como diferenciar QSAM, VSAM, IMS e banco relacional, e o que Edgar Codd diria ao encontrar uma chave de 47 bytes carregando toda a árvore genealógica do cliente
Prólogo — A entrada para o mundo subterrâneo
O professor Otto Lidenbrock encontrou um manuscrito misterioso escondido dentro de um livro antigo. O documento indicava uma passagem para o centro da Terra através da cratera de um vulcão islandês. Um programador COBOL iniciante, por sua vez, encontrou algo igualmente inquietante: uma tabela Db2 com uma chave composta por empresa, filial, departamento, cliente, contrato, produto, parcela e sequência.
Não havia runas. Havia um copybook de 1989.
Na primeira página, alguém escrevera:
01 CHAVE-MESTRA.
05 CD-EMPRESA PIC 9(03).
05 CD-FILIAL PIC 9(04).
05 NR-CLIENTE PIC 9(09).
05 NR-CONTRATO PIC 9(12).
05 NR-PARCELA PIC 9(03).O sistema utilizava uma versão moderna do Db2, possuía SQL, índices, tablespaces, packages e planos. Mesmo assim, para chegar a uma parcela, o programa precisava conhecer empresa, filial, cliente e contrato. Qualquer consulta começava pela raiz e descia pelos mesmos túneis. As tabelas pareciam segmentos. Os cursores pareciam GN. Algumas rotinas faziam tantos SELECT encadeados que quase se podia ouvir um distante GNP ecoando nas cavernas.
Foi então que surgiu a pergunta que leva muitos veteranos do mainframe a desconfiar do chão sob seus pés:
Se estou usando Db2, por que ainda sinto que os dados são IMS/DL/I?
A resposta curta é: porque tecnologia relacional e pensamento relacional não são a mesma coisa. É possível colocar dados num SGBD relacional e continuar projetando, navegando e mantendo tudo como se fosse uma velha hierarquia. A placa na entrada diz Db2, mas a planta dos túneis continua sendo IMS.
Vamos descer.
1. Hierarquia não é pecado; prisão de caminho é outra história
A realidade está cheia de hierarquias legítimas:
uma empresa contém departamentos;
um pedido contém itens;
uma conta recebe lançamentos;
um funcionário pode responder a um gerente;
um produto pode ser formado por componentes;
um país possui estados, que possuem municípios.
Portanto, encontrar relações pai-filho dentro de um Db2 não prova que a modelagem esteja errada. O modelo relacional representa hierarquias perfeitamente bem. A questão decisiva é saber se a hierarquia descreve o negócio ou aprisiona o acesso ao dado.
No banco hierárquico, o caminho é parte essencial da estrutura. Imagine:
CLIENTE
└── CONTA
└── LANÇAMENTOPara alcançar determinado lançamento, a navegação tradicional começa no cliente, localiza a conta e finalmente desce ao lançamento. O programador não faz apenas uma pergunta sobre os dados; ele informa ou conhece o caminho para encontrá-los.
No modelo relacional, o lançamento pode ser encontrado diretamente por sua identidade:
SELECT *
FROM LANCAMENTO
WHERE ID_LANCAMENTO = 987654;Também pode ser encontrado pela conta:
SELECT *
FROM LANCAMENTO
WHERE ID_CONTA = 12345;Ou relacionado ao cliente:
SELECT L.*
FROM CLIENTE C
JOIN CONTA A
ON A.ID_CLIENTE = C.ID_CLIENTE
JOIN LANCAMENTO L
ON L.ID_CONTA = A.ID_CONTA
WHERE C.ID_CLIENTE = 100;O dado não deixa de ter parentes. Ele apenas deixa de possuir um único roteiro obrigatório de visitação.
Essa é uma das diferenças mais importantes entre os dois mundos: no modelo hierárquico, pensamos em percorrer caminhos; no relacional, pensamos em combinar conjuntos de fatos.
2. IMS — a caverna desenhada antes da expedição
O IMS organiza dados em segmentos. Existe um segmento raiz e, abaixo dele, segmentos dependentes. Um desenho simplificado poderia ser:
CLIENTE
├── ENDEREÇO
├── TELEFONE
└── CONTA
└── LANÇAMENTOCada ocorrência de CONTA vive sob determinado CLIENTE; cada LANÇAMENTO vive sob determinada CONTA. A aplicação percorre essa estrutura usando chamadas DL/I como:
GU— Get Unique;GN— Get Next;GNP— Get Next Within Parent;ISRT— Insert;REPL— Replace;DLET— Delete.
É uma lógica navegacional. Ela se parece com a expedição de Júlio Verne: entre pela cratera correta, atravesse a galeria indicada, contorne o lago subterrâneo e procure a passagem depois da rocha marcada. Se você quiser chegar ao mesmo ponto por outro lado, talvez precise de outro índice, outro caminho lógico ou uma nova solução estrutural.
Isso não torna o IMS primitivo. Muito pelo contrário. O IMS continua sendo uma tecnologia poderosa, madura e extremamente eficiente em cargas com caminhos previsíveis. Possui índices secundários, logical relationships e diversos recursos que tornam o modelo muito mais sofisticado do que uma árvore escolar desenhada no quadro.
Suas qualidades aparecem quando:
o relacionamento pai-filho é estável;
os caminhos de acesso são conhecidos;
o volume transacional é elevado;
a previsibilidade é valiosa;
a estrutura combina naturalmente com o negócio.
As dificuldades aparecem quando consultas novas exigem atravessar a árvore de maneiras não previstas, quando muitos-para-muitos se multiplicam ou quando alterar a estrutura obriga muitos programas a reaprender o mapa subterrâneo.
3. Db2 — a pergunta lógica e o caminho escolhido pelo otimizador
No modelo relacional, uma tabela representa uma relação: um conjunto de fatos do mesmo tipo. Cada linha deveria afirmar algo claro sobre o mundo.
Uma tabela CLIENTE pode declarar:
Existe um cliente identificado por este código, com este nome e esta data de nascimento.
Uma tabela CONTA pode declarar:
Existe uma conta identificada por este código e relacionada a determinado cliente.
O relacionamento não deveria morar apenas na memória do analista ou numa condição dentro do COBOL. Ele pode ser declarado ao SGBD:
ALTER TABLE CONTA
ADD CONSTRAINT FK_CONTA_CLIENTE
FOREIGN KEY (ID_CLIENTE)
REFERENCES CLIENTE (ID_CLIENTE);Quando a regra existe somente no programa, temos uma convenção. Quando é declarada como constraint, temos uma regra protegida pelo banco para todos os programas autorizados a alterar aqueles dados.
No Db2, escrevemos o que desejamos obter. O otimizador decide como alcançar o resultado, considerando estatísticas, índices, cardinalidades, custos e alternativas de acesso. Pode escolher a ordem dos joins e diferentes estratégias físicas sem exigir que a regra de negócio seja reescrita.
É como pedir:
Quero todos os fósseis encontrados por expedições islandesas entre duas datas.
Em vez de ordenar:
Entre pelo túnel A, caminhe 300 metros, vire à esquerda, abra a terceira caixa e leia registro por registro.
Essa separação entre intenção lógica e acesso físico é uma das grandes conquistas do modelo relacional.
4. Quando o Db2 usa gravata, mas pensa em DL/I
Existem sintomas clássicos de que o sistema migrou de tecnologia sem migrar de pensamento.
4.1 Chaves que contêm todo o caminho dos ancestrais
Imagine estas chaves:
CLIENTE
CD_EMPRESA + CD_FILIAL + NR_CLIENTE
CONTA
CD_EMPRESA + CD_FILIAL + NR_CLIENTE + NR_CONTA
LANÇAMENTO
CD_EMPRESA + CD_FILIAL + NR_CLIENTE + NR_CONTA + DT_MOVIMENTO + SEQUENCIAUma chave composta não é automaticamente ruim. Em muitos casos, a composição representa a verdadeira identidade do negócio. O problema começa quando o filho transporta toda a ancestralidade apenas porque antigamente o caminho físico precisava estar embutido na chave.
Uma possibilidade mais independente seria:
CLIENTE
ID_CLIENTE PK
CONTA
ID_CONTA PK
ID_CLIENTE FK
LANCAMENTO
ID_LANCAMENTO PK
ID_CONTA FKAgora, cada entidade tem identidade própria. O relacionamento continua existindo, mas não se confunde com a identidade completa do registro.
Não existe mandamento dizendo “usarás sempre chave artificial”. O bom projetista pergunta: a chave é estável? É curta? Tem significado duradouro? Pode mudar por correção cadastral ou legislação? Expõe informação sensível? Realmente identifica a entidade ou simplesmente reproduz a trilha de acesso?
4.2 O programa que faz uma excursão linha a linha
Outro sinal é o programa que seleciona clientes e, para cada cliente, abre uma consulta de contas; para cada conta, consulta lançamentos; para cada lançamento, busca informações complementares.
Em espírito:
SELECT CLIENTE
SELECT CONTA
SELECT LANCAMENTO
SELECT TIPO_LANCAMENTOÉ uma navegação hierárquica reconstruída com SQL. Também pode produzir o conhecido problema de muitas consultas repetitivas.
Uma abordagem relacional tenta formular o conjunto desejado:
SELECT C.ID_CLIENTE,
A.ID_CONTA,
SUM(L.VALOR) AS TOTAL
FROM CLIENTE C
JOIN CONTA A
ON A.ID_CLIENTE = C.ID_CLIENTE
JOIN LANCAMENTO L
ON L.ID_CONTA = A.ID_CONTA
GROUP BY C.ID_CLIENTE,
A.ID_CONTA;Não significa transformar qualquer processamento COBOL em um SQL gigantesco e impossível de manter. Significa reconhecer quando o SGBD pode trabalhar eficientemente com conjuntos, evitando que o programa imite um explorador abrindo cada caixote individualmente.
4.3 Relações protegidas apenas pelo COBOL
Alguns programas verificam se o pai existe antes de inserir o filho:
EXEC SQL
SELECT COUNT(*)
INTO :WS-COUNT
FROM CLIENTE
WHERE ID_CLIENTE = :WS-ID-CLIENTE
END-EXECDepois, se WS-COUNT for maior que zero, inserem a conta. Além de duplicar a regra em diferentes programas, essa estratégia pode sofrer com concorrência: a realidade pode mudar entre a verificação e a inserção.
Uma foreign key expressa diretamente a regra. O COBOL continua tratando o retorno SQL e produzindo a mensagem apropriada, mas o Db2 assume a proteção central da integridade.
4.4 A ordem “natural” da tabela
Uma tabela relacional não possui ordem lógica garantida. Este comando:
SELECT * FROM CLIENTE;não promete retornar clientes por código, nome, horário de inclusão nem posição física. Se a ordem importa, ela deve ser declarada:
SELECT *
FROM CLIENTE
ORDER BY NOME, ID_CLIENTE;Programa que depende da ordem observada sem ORDER BY está tratando a tabela como arquivo sequencial. Pode funcionar por anos e mudar depois de uma reorganização, alteração de índice ou novo access path. O monstro não nasceu naquele dia; naquele dia alguém apenas acendeu a lanterna.
5. QSAM — a longa estrada em linha reta
QSAM é associado ao acesso sequencial a registros bloqueados e aparece diariamente em processamento batch. É natural encontrá-lo em entradas, saídas, relatórios, interfaces, cargas, descargas e arquivos de erros.
No COBOL:
READ ARQ-CLIENTES
AT END
SET FIM-ARQUIVO TO TRUE
END-READO layout pode estar num copybook:
01 REG-CLIENTE.
05 REG-ID PIC 9(09).
05 REG-NOME PIC X(40).
05 REG-STATUS PIC X(01).Para o mecanismo de acesso, existem registros e bytes. O significado “as posições 10 a 49 representam o nome” está no layout conhecido pela aplicação.
QSAM é como uma ferrovia subterrânea: excelente quando se deseja seguir do primeiro ao último vagão. Para processar quarenta milhões de registros numa passada, uma leitura sequencial pode ser exatamente a solução correta.
Entretanto, QSAM não oferece por si só joins, foreign keys ou integridade referencial entre diferentes datasets. Se um arquivo de contas contém o código do cliente, cabe aos programas garantir que esse cliente exista no arquivo correspondente.
Eis uma curiosidade importante para o iniciante: dataset é um termo amplo no z/OS. QSAM não é “um tipo de banco”; é um método de acesso normalmente empregado com datasets sequenciais. Confundir dataset, organização e método de acesso é como chamar toda criatura subterrânea de dinossauro. Algumas nem sequer viveram no mesmo período.
6. VSAM — as galerias com placas e atalhos
VSAM é uma família de organizações e serviços de acesso. O mais famoso no universo COBOL é o KSDS, que permite acesso por chave e também processamento sequencial.
READ ARQ-CLIENTE
KEY IS WS-ID-CLIENTE
INVALID KEY
CONTINUE
END-READAs organizações mais conhecidas incluem:
KSDS — registros acessíveis por chave e em sequência de chave;
ESDS — registros mantidos conforme a ordem de entrada, com acesso por endereço relativo;
RRDS — registros associados a números relativos;
LDS — espaço linear, utilizado em cenários específicos e por componentes que gerenciam sua própria estrutura.
Um KSDS possui entradas indexadas e pode encontrar rapidamente um registro. Ainda assim, o fato de dois clusters terem campos com o mesmo código não cria automaticamente um relacionamento protegido entre eles.
Se o arquivo CONTA contém ID-CLIENTE, um programa pode excluir o cliente e deixar contas órfãs, a menos que as aplicações e os processos impeçam isso. O VSAM não interpreta espontaneamente aquela igualdade como uma foreign key.
VSAM também não é “inferior” ao Db2. Há problemas para os quais sua simplicidade, previsibilidade e acesso direto são excelentes. A pergunta madura não é “qual tecnologia é mais moderna?”, mas “qual semântica, integridade, concorrência e padrão de acesso este problema exige?”.
7. O mapa comparativo da expedição
| Tecnologia | Visão predominante | Relacionamentos | Acesso típico | Quem conhece grande parte da semântica? |
|---|---|---|---|---|
| QSAM | sequência de registros | mantidos pela aplicação | leitura/gravação sequencial | copybook e programa |
| VSAM KSDS | registros indexados por chave | mantidos principalmente pela aplicação | chave ou sequência | definição do cluster, copybook e programa |
| IMS | segmentos numa hierarquia | pai-filho estruturado pelo banco | navegação DL/I | DBD, PSB/PCB e aplicação |
| Db2 | conjuntos de fatos relacionados | PK, FK, constraints e valores | SQL declarativo | catálogo, modelo e aplicação |
O ponto não é dizer que apenas o Db2 conhece regras. Todos esses ambientes podem formar sistemas sólidos. A diferença está em onde a estrutura e a integridade são declaradas e quanto o programa precisa conhecer sobre o percurso físico ou lógico.
8. O que caracteriza uma boa modelagem relacional
Uma boa modelagem começa quando conseguimos terminar esta frase sem hesitar:
Cada linha desta tabela representa...
“Um cliente” é claro. “Uma conta” também. “A participação de um cliente numa conta durante certo período” pode justificar uma tabela associativa. Já “cliente, contrato, endereço atual, última cobrança e alguns campos reservados” revela vários conceitos presos no mesmo fóssil.
8.1 Identidade clara
Cada linha deve ser distinguível. Uma tabela pode usar uma chave técnica e, ao mesmo tempo, proteger a chave natural:
CREATE TABLE CLIENTE (
ID_CLIENTE BIGINT NOT NULL,
NOME VARCHAR(100) NOT NULL,
CPF CHAR(11),
CONSTRAINT PK_CLIENTE
PRIMARY KEY (ID_CLIENTE),
CONSTRAINT UK_CLIENTE_CPF
UNIQUE (CPF)
);ID_CLIENTE fornece identidade técnica estável; CPF expressa uma possível regra de unicidade do negócio. O modelo real ainda precisa decidir como tratar estrangeiros, dados provisórios, correções e valores ausentes.
8.2 Relacionamentos declarados
Uma conta pode exigir um cliente existente:
CREATE TABLE CONTA (
ID_CONTA BIGINT NOT NULL,
ID_CLIENTE BIGINT NOT NULL,
DATA_ABERTURA DATE NOT NULL,
SITUACAO CHAR(1) NOT NULL,
CONSTRAINT PK_CONTA
PRIMARY KEY (ID_CONTA),
CONSTRAINT FK_CONTA_CLIENTE
FOREIGN KEY (ID_CLIENTE)
REFERENCES CLIENTE (ID_CLIENTE),
CONSTRAINT CK_CONTA_SITUACAO
CHECK (SITUACAO IN ('A', 'B', 'E'))
);O DDL passa a documentar e proteger identidade, obrigatoriedade, relacionamento e domínio.
8.3 Um fato em seu devido lugar
Se o limite de crédito pertence à conta, não deveria estar em CLIENTE apenas porque hoje cada cliente possui uma única conta. Se o preço depende do produto e da data de vigência, talvez não pertença simplesmente a PRODUTO.
A pergunta de ouro é:
Este atributo depende de quê?
Se depende da chave, da chave inteira e de nada além da chave, provavelmente está no lugar correto. Eis, em linguagem prática, a alma da normalização.
8.4 Muitos-para-muitos sem colunas numeradas
Um cliente pode participar de várias contas e uma conta pode ter vários titulares. Criar ID_CLIENTE_1, ID_CLIENTE_2 e ID_CLIENTE_3 estabelece um limite artificial e espalha lógica condicional.
O modelo apropriado pode usar:
CLIENTE
ID_CLIENTE
CONTA
ID_CONTA
CONTA_TITULAR
ID_CONTA
ID_CLIENTE
TIPO_TITULARIDADE
DATA_INICIO
DATA_FIMCONTA_TITULAR não é apenas uma ponte técnica. Ela representa um fato do negócio: determinada pessoa participa de determinada conta, com certo papel e durante certo intervalo.
8.5 Repetições viram linhas, não colunas numeradas
Uma tabela com TELEFONE_1, TELEFONE_2 e TELEFONE_3 carrega uma pergunta inevitável: o que acontecerá com o quarto telefone?
Uma tabela CLIENTE_TELEFONE permite zero, um ou muitos números, cada um com tipo, preferência, validade e outras regras necessárias.
8.6 NULL não é um saco de mistérios
NULL não deveria significar simultaneamente “não informado”, “não existe”, “não se aplica”, “será calculado”, “ocorreu erro” e “veio em branco no arquivo de 1997”. Esses estados podem exigir tratamentos diferentes.
O modelo precisa definir o significado da ausência. Caso contrário, cada programa inventará sua própria interpretação e o banco ganhará pequenas cavernas particulares.
8.7 O tempo precisa ser modelado
Pergunte sempre:
a data é de ocorrência, processamento ou vigência?
o dado atual substitui o anterior ou deve existir histórico?
períodos podem se sobrepor?
DATA_FIM IS NULLsignifica registro vigente?alterações retroativas são permitidas?
precisamos saber quem alterou e quando?
Muitos modelos parecem ótimos até alguém perguntar: “Como essa conta estava no fechamento do mês passado?”. Nesse instante, descobre-se que atualizar uma linha apagou a história.
9. Normalização sem transformar o Db2 num labirinto
Normalizar significa reduzir redundâncias e anomalias, não dividir o universo em centenas de tabelas minúsculas por devoção religiosa.
Na primeira forma normal, evitamos guardar listas escondidas numa coluna:
TELEFONES = "11999999999;11888888888;11777777777"Esse campo dificulta validação, pesquisa, indexação e alteração individual.
Na segunda forma normal, quando existe chave composta, cada atributo não-chave deve depender da chave inteira. Se ITEM_PEDIDO tem chave ID_PEDIDO + ID_PRODUTO, o nome do cliente não depende dessa combinação; a descrição geral do produto tampouco.
Na terceira forma normal, evitamos dependências indiretas. Se CLIENTE contém ID_CIDADE, NOME_CIDADE e UF, mas nome e UF dependem de ID_CIDADE, talvez esses atributos pertençam a CIDADE.
Entretanto, snapshots, trilhas históricas, integrações e estruturas analíticas podem duplicar dados intencionalmente. A distinção importante é esta:
redundância acidental cria várias verdades concorrentes;
redundância projetada identifica a fonte oficial, o momento da cópia e o mecanismo de reconciliação.
Desnormalizar por desempenho antes de medir é como abrir uma passagem com dinamite porque talvez exista um atalho atrás da parede. Pode existir. Também pode haver um oceano subterrâneo esperando para entrar.
10. Passo a passo para construir um bom modelo
Passo 1 — Escreva as regras em português
Antes do primeiro CREATE TABLE, registre frases como:
um cliente pode participar de várias contas;
uma conta pode ter vários titulares;
um lançamento pertence a exatamente uma conta;
uma conta pode existir sem lançamento;
a titularidade possui início, fim e tipo;
um lançamento cancelado não desaparece: ganha estado e referência de estorno.
Essas frases revelam entidades, cardinalidades, opcionalidade e tempo.
Passo 2 — Separe entidades, eventos e classificações
Entidades são coisas reconhecíveis, como cliente, conta e produto. Eventos registram algo ocorrido, como pagamento, transferência ou lançamento. Classificações descrevem categorias e estados.
Misturar tudo em TB_CADASTRO_GERAL pode parecer econômico no início, mas logo cria colunas sem sentido para metade das linhas e códigos mágicos decidindo qual formato cada registro possui.
Passo 3 — Defina as cardinalidades
Para cada relacionamento, pergunte:
a ocorrência relacionada é obrigatória?
pode existir uma ou várias?
o relacionamento muda com o tempo?
há exceções reais?
Não escolha 1:N porque o arquivo antigo parecia possuir um cabeçalho e vários detalhes. Escolha porque essa é a regra do negócio.
Passo 4 — Escolha chaves com consciência
Examine estabilidade, tamanho, privacidade e significado. Uma chave natural ótima hoje pode mudar amanhã. Uma chave artificial facilita identidade, mas não elimina a necessidade de proteger unicidades do negócio.
Passo 5 — Declare constraints
Use PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL e CHECK quando representam regras verdadeiras. Criar tudo como nullable para “facilitar a carga” apenas transfere a dificuldade para milhares de consultas futuras.
Passo 6 — Teste o ciclo de vida, não apenas o cadastro
Simule:
criação;
correção;
cancelamento;
reativação;
troca de titular;
evento retroativo;
auditoria;
anonimização;
consulta histórica;
exclusão permitida e exclusão proibida.
Um modelo que funciona somente no primeiro INSERT ainda não atravessou a primeira galeria.
Passo 7 — Valide com consultas reais
Escreva as perguntas principais que o negócio fará. Se para responder a algo básico for necessário interpretar cinco códigos obscuros e reconstruir manualmente uma sequência implícita, talvez o modelo não represente o negócio com clareza.
Passo 8 — Planeje o físico depois do lógico
Somente então avalie índices, particionamento, clustering, compressão, tablespaces, estatísticas, padrões batch, concorrência, recuperação e retenção.
Índice não corrige semântica. Ele encontra depressa aquilo que talvez tenha sido armazenado errado.
11. A fronteira que nunca parece clara nos projetos reais
Na prática, as fronteiras ficam nebulosas porque sistemas empresariais acumulam décadas de decisões:
tabelas nasceram de layouts VSAM;
segmentos IMS foram convertidos quase mecanicamente;
interfaces batch exigiram registros autocontidos;
projetos evitaram foreign keys por medo de desempenho ou dificuldade de carga;
regras ficaram duplicadas em COBOL, Java, stored procedures e ETLs;
aquisições juntaram conceitos diferentes sob nomes iguais;
cada equipe modelou apenas a parte que conhecia;
urgências transformaram exceções temporárias em arquitetura permanente.
Por isso, sua sensação não é nostalgia técnica nem impressão equivocada. Muitas instalações Db2 contêm estratos arqueológicos. Na superfície há SQL moderno; alguns metros abaixo aparecem tabelas tratadas como KSDS; mais fundo, chaves carregam caminhos de segmentos; no último nível, um programa ainda acredita que branco, zero e ausência são a mesma criatura.
Uma boa modernização começa reconhecendo esses estratos. Não é necessário demolir tudo. Pode-se:
documentar o significado real das tabelas;
identificar fontes oficiais e redundâncias;
localizar relações sem constraints;
medir órfãos e inconsistências antes de criar FKs;
encapsular legados por views e serviços;
corrigir novas extensões segundo um modelo melhor;
migrar por domínios, com reconciliação e rollback;
manter desempenho e operação envolvidos desde o desenho.
Colocar uma foreign key numa base histórica sem verificar dados existentes pode revelar milhões de órfãos. A constraint não criou o problema; ela apenas encontrou os esqueletos.
12. Checklist do explorador relacional
Ao examinar uma tabela, pergunte:
Cada linha representa exatamente o quê?
Qual regra torna uma linha única?
A chave representa identidade ou caminho de navegação?
Quais foreign keys deveriam existir?
Há registros órfãos?
Existem listas dentro de colunas?
Há colunas numeradas como
ENDERECO_1,ENDERECO_2eENDERECO_3?O mesmo fato aparece em várias tabelas?
Qual delas é a fonte oficial?
O programa depende da ordem sem
ORDER BY?Existem sequências de
SELECTque imitam pai-filho-neto?As regras vivem no banco ou espalhadas por programas?
É possível reconstruir o passado?
Branco, zero e
NULLpossuem significados definidos?Alterar um relacionamento exige alterar a identidade do registro?
Se muitas respostas causarem desconforto, provavelmente existe um IMS, um VSAM ou um QSAM conceitual vivendo por baixo das tabelas. Isso não condena o sistema, mas indica onde começar a investigação.
Epílogo — O centro da Terra não era o fim da viagem
Depois de atravessar galerias de QSAM, atalhos de VSAM, árvores de IMS e salões relacionais do Db2, nosso programador COBOL finalmente entendeu que nenhuma dessas tecnologias é vilã.
QSAM pode ser perfeito para uma grande varredura batch. VSAM pode oferecer o acesso direto e previsível de que determinada aplicação necessita. IMS pode processar hierarquias estáveis com eficiência extraordinária. Db2 pode representar conjuntos relacionados, proteger integridade e permitir múltiplos caminhos lógicos de consulta.
O erro não está em conservar tecnologia antiga quando ela resolve bem o problema. O erro está em usar uma tecnologia sem compreender seu modelo — ou esperar que a simples migração física transforme automaticamente a maneira de pensar.
Uma boa modelagem relacional apresenta:
conceitos com fronteiras compreensíveis;
linhas com identidade clara;
fatos colocados onde realmente pertencem;
relacionamentos declarados e protegidos;
cardinalidades fiéis ao negócio;
ausência e tempo com significado definido;
redundância consciente, quando necessária;
independência entre a pergunta lógica e o caminho físico;
capacidade de evoluir sem obrigar cada programa a memorizar a árvore inteira.
No final de Viagem ao Centro da Terra, os exploradores não retornam pelo mesmo caminho: são expelidos por outro vulcão, muito longe do ponto de entrada. É um belo easter egg relacional. Num mundo governado por caminhos hierárquicos, a saída deveria repetir a rota conhecida. Num mundo relacional, diferentes caminhos podem alcançar o mesmo conjunto de fatos.
E se Edgar F. Codd estivesse sentado numa poltrona do Bellacosa Mainframe, tomando café enquanto examinava aquela chave de 47 bytes, talvez dissesse com toda a elegância britânica:
Meu caro, isto não é uma relação. É uma árvore genealógica tentando passar pela catraca do Db2.
O programador olharia novamente para o copybook, respiraria fundo e abriria o catálogo.
A expedição verdadeira estaria apenas começando.