| Bellacosa Mainframe e o sql sem misterios |
☕ Um Café no Bellacosa Mainframe
SQL sem Mistérios
O Guia Definitivo para um Programador COBOL Padawan Entender por que Performance Não Está no SQL — Está na Forma Como o Banco de Dados Pensa
"No IBM Z aprendemos uma lição muito cedo: escrever um programa COBOL correto é apenas metade do trabalho. A outra metade é fazer com que ele execute milhões de vezes por dia consumindo o mínimo possível de CPU, memória, I/O e tempo de resposta. O mesmo vale para SQL. O segredo nunca esteve apenas na consulta. O segredo sempre esteve no plano de execução."
Introdução
Existe uma ideia que acompanha praticamente todo programador iniciante.
"Se meu SQL está correto, ele será rápido."
Infelizmente isso quase nunca é verdade.
Na realidade, dois comandos SQL visualmente parecidos podem apresentar diferenças de desempenho de centenas ou até milhares de vezes.
O curioso é que ambos retornam exatamente o mesmo resultado.
Como isso é possível?
Porque SQL é uma linguagem declarativa.
Você não diz como o banco deve executar.
Você apenas informa o que deseja obter.
Quem decide como chegar ao resultado é o Query Optimizer, talvez um dos componentes mais sofisticados já criados na Engenharia de Software.
É exatamente nesse ponto que muitos desenvolvedores COBOL descobrem uma das maiores diferenças entre programar aplicações e construir sistemas corporativos de missão crítica.
No Mainframe, especialmente no Db2 for z/OS, performance nunca foi um detalhe.
Ela sempre foi parte da regra de negócio.
Um banco que processa milhões de transações por hora não pode desperdiçar CPU apenas porque alguém escreveu um SQL aparentemente "bonito".
A maior mentira sobre SQL
Quando alguém pergunta:
"Como faço um SQL mais rápido?"
A pergunta correta deveria ser:
"Como faço o otimizador escolher um plano de execução melhor?"
Essa pequena mudança muda completamente a forma de pensar.
O SQL é apenas uma descrição lógica.
Quem faz o trabalho pesado é o banco.
Imagine pedir um táxi.
Você informa:
"Quero ir do aeroporto até o hotel."
Você não diz:
qual avenida utilizar;
qual velocidade manter;
qual ponte atravessar;
onde abastecer.
Quem decide isso é o motorista.
Com SQL acontece exatamente a mesma coisa.
Você informa o destino.
O banco decide o caminho.
E esse caminho chama-se:
Execution Plan
O verdadeiro inimigo chama-se I/O
Quando começamos em COBOL normalmente pensamos que CPU é o maior problema.
Depois de alguns anos trabalhando em bancos descobrimos outra realidade.
O maior inimigo geralmente é:
DISCO
Mais precisamente:
I/O
Toda vez que o Db2 precisa buscar páginas em disco, existe um custo.
Imagine uma tabela.
CLIENTES
500 milhões de registros
Você deseja apenas:
CPF = 123456789
Existem dois caminhos.
Primeiro.
Ler
500 milhões
↓
encontrar registro
Segundo.
ÍNDICE
↓
posição
↓
registro
A diferença entre essas duas estratégias pode representar minutos versus milissegundos.
É exatamente isso que o otimizador tenta resolver.
O cérebro invisível do banco de dados
Muita gente acredita que o SQL é executado exatamente como foi escrito.
Na realidade acontece algo muito mais interessante.
Primeiro o banco interpreta.
Depois calcula estatísticas.
Depois verifica índices.
Depois estima custos.
Depois compara algoritmos.
Depois escolhe um plano.
Só então executa.
Na prática ele faz algo semelhante a isto:
SQL
↓
Parser
↓
Optimizer
↓
Statistics
↓
Execution Plan
↓
Runtime
Ou seja...
Antes de executar uma única linha, o banco já simulou diversos cenários.
Esse processo acontece milhares de vezes por segundo.
O pensamento de um especialista IBM Z
Existe uma diferença enorme entre um programador iniciante e um especialista.
O iniciante pergunta:
Meu SQL funciona?
O especialista pergunta:
Quantos GETPAGEs ele gera?
Quantas páginas serão lidas?
Qual Buffer Pool será utilizada?
Existe Table Scan?
O índice é Matching?
Existe Sort?
O Join utilizará Hash?
Há paralelismo?
O RUNSTATS está atualizado?
Qual é o custo estimado?
Perceba.
A preocupação deixa de ser o SQL.
Ela passa a ser o comportamento interno do banco.
Primeira regra: reduza trabalho
Uma consulta lenta quase sempre faz trabalho demais.
Veja um erro extremamente comum.
SELECT *
FROM CLIENTES;
Parece inofensivo.
Mas imagine a tabela:
CPF
NOME
EMAIL
ENDEREÇO
TELEFONE
FOTO
OBSERVAÇÃO
SCORE
RENDA
LIMITE
NASCIMENTO
Seu programa COBOL utiliza apenas:
CPF
NOME
Então por que pedir todo o restante?
Cada coluna representa:
mais páginas;
mais memória;
mais tráfego;
mais CPU.
O primeiro princípio da engenharia de performance é extremamente simples.
Nunca leia aquilo que você não utilizará.
O índice não é mágica
Outro grande mito.
Muitos acreditam que basta criar índices.
Na prática isso pode piorar tudo.
Cada índice precisa ser atualizado em:
INSERT
UPDATE
DELETE
Quanto mais índices,
mais escrita,
mais manutenção,
mais espaço,
mais CPU.
Por isso especialistas projetam índices observando o comportamento das consultas.
Não existe índice perfeito.
Existe índice adequado para determinada carga de trabalho.
O poder dos índices compostos
Imagine este SQL.
WHERE CPF=?
AND STATUS='A'
Qual índice é melhor?
CPF
ou
CPF
STATUS
O segundo.
Porque acompanha exatamente o padrão utilizado pela consulta.
Esse conceito chama-se:
Composite Index.
No Db2 isso pode eliminar milhares de leituras desnecessárias.
Covering Index: quando a tabela deixa de ser necessária
Poucos conceitos impressionam tanto um programador COBOL quanto este.
Imagine:
SELECT NOME
FROM CLIENTES
WHERE CPF=?
Se existir um índice contendo:
CPF
NOME
o Db2 pode responder utilizando apenas o índice.
A tabela sequer será acessada.
Isso reduz:
I/O;
CPU;
tempo de resposta.
É uma das maiores vitórias do otimizador.
SARGable: a palavra que todo Padawan deveria decorar
Ela parece complicada.
Mas a ideia é simples.
Observe.
Errado.
WHERE YEAR(DATA)=2025
Agora o banco precisa calcular YEAR para milhões de linhas.
O índice praticamente perde sua utilidade.
Agora veja.
WHERE DATA
BETWEEN
'2025-01-01'
AND
'2025-12-31'
Aqui o índice pode ser percorrido diretamente.
Esse conceito chama-se:
Search Argument Able
ou simplesmente
SARGable.
Sempre que possível, permita que o banco utilize diretamente seus índices.
EXISTS x IN
Outro assunto clássico.
Muitos iniciantes perguntam:
"Qual é mais rápido?"
A resposta correta é:
"Depende."
Mas existe uma tendência.
Em conjuntos muito grandes,
EXISTS costuma interromper a busca assim que encontra a primeira ocorrência.
Já IN pode exigir estratégias diferentes dependendo do plano escolhido.
O importante não é decorar regras.
É analisar o plano.
Filtrar antes de juntar
Imagine duas tabelas.
CLIENTES
120 milhões
PEDIDOS
800 milhões
Sem filtro:
120 milhões
×
800 milhões
Agora imagine aplicar:
STATUS='ATIVO'
antes do JOIN.
Talvez restem apenas:
2 milhões
×
8 milhões
O banco trabalhará muito menos.
Essa simples mudança pode reduzir drasticamente o custo de execução.
DISTINCT é caro
DISTINCT parece elegante.
Mas por trás dele normalmente existe:
SORT
COMPARAÇÃO
ELIMINAÇÃO
MEMÓRIA
CPU
Em muitos projetos ele aparece apenas para esconder um JOIN incorreto.
O especialista não remove duplicidade.
Ele evita produzi-la.
UNION ou UNION ALL?
Outro clássico.
UNION precisa descobrir registros repetidos.
Para isso geralmente ocorre:
SORT
COMPARE
REMOVE
UNION ALL simplesmente concatena.
Tabela A
+
Tabela B
Sem ordenar.
Sem comparar.
Sem remover.
Em processos ETL isso faz enorme diferença.
O plano de execução é o mapa do tesouro
Imagine um médico sem raio-X.
É exatamente isso que faz quem tenta otimizar SQL sem olhar o plano.
No Db2 utilizamos:
EXPLAIN
PLAN_TABLE
Visual Explain
No PostgreSQL:
EXPLAIN ANALYZE
No SQL Server:
Actual Execution Plan
No Oracle:
EXPLAIN PLAN
O plano revela tudo.
Table Scan
Index Scan
Nested Loop
Merge Join
Hash Join
Sort
Temporary
Parallel
Sem ele praticamente toda otimização é tentativa e erro.
O verdadeiro papel do RUNSTATS
Existe uma armadilha muito comum.
O SQL está perfeito.
Os índices existem.
Mesmo assim o desempenho é ruim.
O problema pode estar nas estatísticas.
No Db2, o utilitário RUNSTATS informa ao otimizador:
quantidade de linhas;
cardinalidade;
distribuição dos valores;
quantidade de páginas;
fator de clusterização;
informações sobre índices.
Sem essas estatísticas, o otimizador toma decisões com base em estimativas imprecisas, aumentando a chance de escolher um plano inadequado.
Partition Pruning: lendo apenas o necessário
Imagine uma tabela dividida por ano.
2021
2022
2023
2024
2025
2026
Sua consulta busca apenas 2026.
Se o particionamento for bem utilizado, o banco ignora todas as demais partições.
Em vez de ler bilhões de linhas, lê apenas a fração necessária.
É uma das técnicas mais importantes para bases corporativas de grande porte.
Os algoritmos invisíveis dos JOINs
Quando você escreve:
JOIN
o Db2 ainda precisa decidir como unir as tabelas.
As principais estratégias são:
Nested Loop Join, ideal para poucos registros e bons índices.
Merge Join, eficiente quando os dados já estão ordenados.
Hash Join, excelente para grandes volumes e junções sem índices seletivos.
A escolha depende de estatísticas, cardinalidade e custo estimado. O mesmo SQL pode gerar algoritmos diferentes conforme os dados evoluem.
O que um Padawan COBOL pode aprender com tudo isso?
Existe um paralelo interessante entre COBOL e SQL.
Quando escrevemos um programa COBOL, evitamos ler um arquivo inteiro se conhecemos a chave do registro.
Não percorremos um VSAM KSDS sequencialmente para localizar uma única conta quando podemos usar a chave primária.
Da mesma forma, no Db2 não devemos obrigar o banco a fazer um table scan quando um índice seletivo resolveria o problema com muito menos trabalho.
A lógica é a mesma: reduzir operações desnecessárias e aproveitar as estruturas de acesso disponíveis.
A Filosofia Bellacosa Mainframe
Ao longo de décadas trabalhando com IBM Z, uma lição se repetiu inúmeras vezes.
Os sistemas mais rápidos raramente eram aqueles escritos pelos programadores mais "geniais".
Eram aqueles escritos por profissionais que entendiam como a infraestrutura pensava.
Eles compreendiam que:
CPU custa dinheiro.
I/O custa tempo.
Memória é finita.
Locks geram contenção.
Sorts desperdiçam recursos.
Estatísticas influenciam decisões.
Índices precisam de estratégia.
Cada GETPAGE representa trabalho.
Cada plano de execução conta uma história.
No universo Mainframe, performance nunca foi um luxo. Sempre foi um requisito funcional.
Palavra Final
Se existe uma única mensagem que este artigo pretende deixar para todo Programador COBOL Padawan, é esta:
Você não otimiza apenas uma instrução SQL. Você otimiza a forma como o banco de dados raciocina sobre ela.
Quando você escreve uma consulta, está apenas descrevendo um objetivo. Quem realmente faz o trabalho é o otimizador, escolhendo índices, algoritmos de JOIN, estratégias de acesso, ordenações e caminhos de execução.
Os grandes especialistas em Db2 para IBM Z não decoram truques. Eles estudam estatísticas, analisam planos de execução, compreendem o comportamento do otimizador e medem continuamente CPU, I/O, GETPAGEs, uso de Buffer Pools e contenção. Eles sabem que um ganho de poucos milissegundos por transação pode representar milhões de operações economizadas ao longo de um ano.
Como ensinamos no Bellacosa Mainframe: o SQL é apenas a pergunta; o plano de execução é a resposta do banco. Quando você aprende a ler essa resposta, deixa de ser apenas um programador que escreve consultas e passa a pensar como um verdadeiro engenheiro de software para sistemas de missão crítica.
No fim das contas, o objetivo não é criar um SQL elegante. É construir aplicações capazes de processar milhões de transações com eficiência, previsibilidade e confiabilidade — exatamente como os grandes ambientes IBM Z fazem há décadas. Esse é o verdadeiro caminho para evoluir de Padawan a Mestre na arte da performance em bancos de dados.