← Voltar ao blog
Ciência e Tecnologia 23 de setembro de 2026 12 min de leitura

Migrar de Oracle para PostgreSQL: custos e armadilhas reais

O roteiro de uma migração que dá certo: inventário, avaliação de PL/SQL, conversão de tipos, carga com CDC, corte com janela curta — e a lista das armadilhas que estouram cronograma.

Migrar de Oracle para PostgreSQL: custos e armadilhas reais

Migração de banco não falha por causa de dado. Falha por causa de código, de prazo e de gente. Já participei de algumas que correram bem e de pelo menos duas que viraram história de terror — e a diferença nunca esteve na ferramenta.

Dados fluindo de um servidor para outro através de uma ponte de migração
Os dados atravessam fácil. O que estava escrito em volta deles, não.

Fase 1: inventário honesto (1 a 3 semanas)

Antes de qualquer promessa de prazo, meça o que existe:

-- Volume de codigo no banco: o principal fator de esforco
SELECT type, COUNT(*) AS objetos, SUM(line) AS linhas
FROM   dba_source
WHERE  owner NOT IN ('SYS','SYSTEM','XDB','DBSNMP','OUTLN')
GROUP  BY type ORDER BY 3 DESC;

-- Recursos especificos do Oracle usados no codigo
SELECT name, type, COUNT(*)
FROM   dba_source s, (SELECT 'CONNECT BY' t FROM dual UNION ALL
                      SELECT 'DBMS_SCHEDULER' FROM dual UNION ALL
                      SELECT 'PRAGMA AUTONOMOUS' FROM dual UNION ALL
                      SELECT 'BULK COLLECT' FROM dual UNION ALL
                      SELECT 'UTL_FILE' FROM dual) x
WHERE  UPPER(s.text) LIKE '%'||x.t||'%'
GROUP  BY name, type;

-- Tamanho e maiores tabelas (define a estrategia de carga)
SELECT segment_name, ROUND(bytes/1024/1024/1024,1) gb
FROM   dba_segments WHERE segment_type='TABLE'
ORDER  BY bytes DESC FETCH FIRST 20 ROWS ONLY;

Regra de bolso que uso para estimar: até 5 mil linhas de PL/SQL, migração é projeto de meses. Acima de 50 mil, é programa de anos ou candidato a reescrita da aplicação junto.

Fase 2: esquema e tipos

O ora2pg faz o grosso e gera até relatório de esforço estimado (ora2pg -t SHOW_REPORT --estimate_cost). Mas revise o mapeamento de tipos à mão:

OraclePostgreSQLCuidado
NUMBER(p,s)numeric(p,s)Se for inteiro, use int/bigint: bem mais rápido
NUMBER sem precisãonumericVerifique o uso real antes
VARCHAR2(n)varchar(n) ou textn em bytes x caracteres
DATEtimestamp(0)DATE do Oracle tem hora; o do Postgres não
CLOB / BLOBtext / byteabytea grande pede Large Object
ROWIDctid (não use)Se a aplicação usa ROWID, vai doer

Fase 3: as armadilhas que estouram cronograma

  1. String vazia é NULL no Oracle. No PostgreSQL não é. Consultas com WHERE campo IS NULL passam a devolver resultados diferentes. Esta é, de longe, a fonte número um de bug silencioso.
  2. Ordenação. O Oracle ordena por binário por padrão; o PostgreSQL usa a collation do locale. Relatórios "mudam de ordem" e o usuário abre chamado.
  3. Divisão por zero e conversões implícitas. O Oracle é permissivo com '123' + 1; o PostgreSQL não.
  4. Transação autônoma. Muito usada para log de auditoria. No Postgres exige dblink ou repensar o design.
  5. Hints. Não existem no PostgreSQL (fora pg_hint_plan). Query afinada na marra volta a depender de estatísticas — leia o query planner imprevisível.
  6. Jobs. DBMS_SCHEDULER vira pg_cron ou agendador externo, com semântica diferente.
  7. VACUUM. Sua rotina operacional muda. Ignorar isso derruba a performance três meses depois do go-live — VACUUM e bloat em escala.

Fase 4: carga e corte

Para bases pequenas, dump e restore numa janela de fim de semana resolve. Acima de algumas centenas de gigabytes, ou com janela curta, o caminho é carga inicial mais CDC:

1. Carga inicial completa (ora2pg COPY ou Debezium snapshot)
2. CDC continuo do Oracle para o Postgres (Debezium/GoldenGate)
3. Rodar em paralelo: aplicacao lendo do Oracle, comparando com o Postgres
4. Corte: congela escrita, espera lag zerar, vira a string de conexao
5. Manter o Oracle de pe por semanas, com rollback ensaiado

Depois da carga, sempre:

ANALYZE;                       -- sem estatisticas, o planner erra feio
REINDEX DATABASE producao;     -- se houve carga fora de ordem
SELECT * FROM pg_stat_user_tables WHERE n_live_tup = 0;  -- tabela vazia = carga falhou

Quanto custa

ItemObservação
Consultoria / time de migraçãoMaior item; proporcional às linhas de PL/SQL
Testes e homologaçãoCostuma ser 40% do projeto; nunca corte aqui
Operação em paraleloVocê paga os dois bancos por alguns meses
Suporte comercial PostgreSQLOpcional, uma fração do suporte Oracle
Treinamento do timeBarato e com o melhor retorno do projeto

Compare esse total com dez anos de suporte Oracle — os números de referência estão em custo real e licenciamento. Se a conta não fechar, ainda resta reduzir para Standard Edition 2.

O conselho que eu daria a mim mesmo há vinte anos

Não migre tudo de uma vez. Escolha um sistema periférico, de baixo risco e com dono interessado. Faça ele inteiro, do inventário ao pós-corte. O time aprende, a organização ganha confiança e você descobre as suas armadilhas específicas com um sistema que, se cair, não para a empresa.

Depois disso, o segundo é metade do trabalho. E o terceiro, rotina.


Sobre o autor: Alexandre Almeida atua com bancos de dados há mais de 25 anos, foi instrutor oficial de Oracle e MySQL para mais de 1.000 alunos e escreveu Aprendendo MySQL: Prática, Teoria e Laboratórios. Veja também os treinamentos.

Fontes: documentação do ora2pg; PostgreSQL Documentation — Data Types, Logical Replication e Routine Vacuuming; Oracle Database SQL Language Reference 19c; documentação do Debezium.