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

Oracle ou PostgreSQL: comparativo técnico sem torcida

O PostgreSQL é o substituto mais próximo do Oracle: PL/pgSQL, tipos ricos, particionamento nativo e extensões. Onde ele empata, onde ainda perde, e o que muda no bolso e na operação.

Oracle ou PostgreSQL: comparativo técnico sem torcida

De todos os bancos livres, o PostgreSQL é o que chega mais perto do Oracle em vocabulário e em ambição. Não é coincidência: os dois vieram da mesma linhagem acadêmica de banco objeto-relacional. Por isso ele é o destino natural de quem quer sair do Oracle sem reescrever a aplicação inteira.

Mas "mais perto" não é "igual". Vamos aos pontos onde a diferença aparece de verdade.

Dois bancos de dados lado a lado em comparação, um deles com o elefante do PostgreSQL
Vocabulário parecido, mecânica interna bem diferente.

Quadro comparativo

CritérioOraclePostgreSQL
Linguagem proceduralPL/SQL (packages, tipos, bulk collect)PL/pgSQL, além de Python, Perl, JavaScript
Versionamento MVCCUndo segments; sem bloat de tabelaVersões na própria tabela; exige VACUUM
ParticionamentoOpção paga no EENativo e gratuito (declarativo desde o 10)
ParalelismoMuito maduroBom, porém menos agressivo
Cluster ativo-ativoRACNão existe equivalente nativo
ExtensibilidadeFechadaExtensões: PostGIS, pgvector, TimescaleDB…
CustoLicença + 22% ao anoZero de licença; suporte opcional

PL/SQL e PL/pgSQL: 80% igual, 20% sofrido

A estrutura é reconhecível na hora:

-- Oracle (PL/SQL)
CREATE OR REPLACE PROCEDURE aplica_desconto(p_id NUMBER, p_pct NUMBER) AS
  v_valor NUMBER;
BEGIN
  SELECT valor INTO v_valor FROM pedidos WHERE id = p_id FOR UPDATE;
  UPDATE pedidos SET valor = v_valor * (1 - p_pct/100) WHERE id = p_id;
  COMMIT;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20001, 'Pedido inexistente');
END;
/

-- PostgreSQL (PL/pgSQL)
CREATE OR REPLACE PROCEDURE aplica_desconto(p_id bigint, p_pct numeric)
LANGUAGE plpgsql AS $
DECLARE v_valor numeric;
BEGIN
  SELECT valor INTO STRICT v_valor FROM pedidos WHERE id = p_id FOR UPDATE;
  UPDATE pedidos SET valor = v_valor * (1 - p_pct/100) WHERE id = p_id;
  COMMIT;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RAISE EXCEPTION 'Pedido inexistente';
END $;

Os 20% que doem: não existe PACKAGE (usa-se schema como agrupador), transação autônoma exige dblink ou extensão, bulk collect e FORALL têm equivalentes diferentes, hierarquia com CONNECT BY vira WITH RECURSIVE, e sequences se comportam de forma distinta. Nada impossível; tudo trabalhoso quando são dez mil linhas.

Diferenças de comportamento que pegam DBA experiente

  • String vazia. No Oracle, '' é NULL. No PostgreSQL, é string vazia. Isso muda o resultado de consultas antigas silenciosamente.
  • DDL transacional. No PostgreSQL você faz BEGIN; ALTER TABLE ...; ROLLBACK; e nada aconteceu. No Oracle, DDL dá commit implícito. A favor do Postgres, e delicioso.
  • MVCC e lixo. O Oracle guarda a versão antiga no undo; o PostgreSQL guarda na própria tabela e precisa de VACUUM. É a maior mudança de rotina operacional — detalhes em VACUUM e bloat.
  • Case das identificadores. Oracle guarda em maiúsculas; PostgreSQL em minúsculas. Aspas duplas viram armadilha permanente.
  • NUMBER x numeric. Mapear tudo para numeric funciona, mas custa performance; onde couber bigint ou int, use.

O que o PostgreSQL ainda não tem

  1. RAC. Escrita ativa em vários nós com storage compartilhado não existe nativamente. Patroni resolve failover, não escrita simultânea — veja alta disponibilidade e replicação.
  2. Flashback Database. Existe PITR, mas não o "desfaz" instantâneo.
  3. Ferramental unificado. AWR, ADDM e RMAN têm equivalentes espalhados (pg_stat_statements, pgBackRest, auto_explain) e não integrados.
  4. Suporte de fornecedor único. Existe suporte comercial excelente, mas é um mercado de vários players, não um número de telefone só.

O que o PostgreSQL tem e o Oracle não

Extensões. Um mesmo banco que faz OLTP, guarda geometria com PostGIS, embeddings com pgvector e série temporal com TimescaleDB — tudo em uma transação, um backup, um conjunto de permissões. E tipos nativos que você passa a usar todo dia:

-- Intervalo temporal com restricao de sobreposicao: uma linha faz o trabalho
CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE reservas (
  sala_id  int NOT NULL,
  periodo  tstzrange NOT NULL,
  EXCLUDE USING gist (sala_id WITH =, periodo WITH &&)
);

-- Array e JSONB indexavel, sem tabela auxiliar
CREATE INDEX idx_doc_tags ON documentos USING gin (tags);

A conclusão prática

Para OLTP corporativo, relatórios, aplicações internas e sistemas novos, o PostgreSQL faz o serviço e devolve o orçamento de suporte para o time. Para ERP certificado, RAC obrigatório ou uma base madura de PL/SQL crítico, o Oracle continua defensável — e o caminho é reduzir edição em vez de sair.

Se a decisão for sair, leia antes migrar de Oracle para PostgreSQL: custos e armadilhas. O panorama de custo está em Oracle: custo real, licenciamento e alternativas, e a operação do lado Postgres em guia definitivo de PostgreSQL em produção.


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. Exemplos validados em Oracle 19c e PostgreSQL 16/17.

Fontes: Oracle Database PL/SQL Language Reference 19c; PostgreSQL Documentation — PL/pgSQL, Partitioning, Constraints e Extensions; Oracle Database Licensing Information User Manual.