MongoDB: Guia Completo do Banco de Dados NoSQL Mais Popular
Entenda como MongoDB revolucionou persistência de dados com seu modelo de documentos flexível, perfeito para aplicações modernas que exigem agilidade e escala.
Descubra por que PostgreSQL é a escolha preferida de desenvolvedores para aplicações que exigem confiabilidade, performance e recursos avançados.
Equipe Arkanus
27/10/2025
PostgreSQL não é apenas mais um banco de dados SQL - é um sistema de gerenciamento de banco de dados objeto-relacional (ORDBMS) de código aberto que combina mais de 35 anos de evolução com inovação contínua. É a escolha de empresas como Apple, Instagram, Spotify e Twitch quando confiabilidade e recursos avançados são essenciais.
PostgreSQL (ou "Postgres") é um sistema de banco de dados relacional open-source conhecido por sua robustez, conformidade com SQL standards e extensibilidade incomparável. Nascido na Universidade da Califórnia (Berkeley) em 1986, evoluiu para se tornar o banco de dados relacional mais avançado disponível hoje.
PostgreSQL
MySQL
PostgreSQL é "MySQL feito certo" - mais rigoroso, mais poderoso, mais correto.
PostgreSQL é o banco mais conforme com SQL standard. Se está no standard SQL, Postgres provavelmente implementa.
ACID Guarantee:
-- Transação ACID completa
BEGIN;
UPDATE contas SET saldo = saldo - 100 WHERE id = 1;
UPDATE contas SET saldo = saldo + 100 WHERE id = 2;
-- Se qualquer erro, ROLLBACK automático
COMMIT;
-- JSON/JSONB nativo
CREATE TABLE eventos (
id SERIAL PRIMARY KEY,
dados JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO eventos (dados) VALUES
('{"user_id": 123, "action": "login", "metadata": {"ip": "192.168.1.1"}}');
-- Query JSON diretamente
SELECT dados->>'action' as acao,
dados->'metadata'->>'ip' as ip
FROM eventos
WHERE dados->>'user_id' = '123';
-- Arrays nativos
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
tags TEXT[] NOT NULL
);
INSERT INTO posts (tags) VALUES
(ARRAY['postgresql', 'database', 'sql']);
SELECT * FROM posts WHERE 'postgresql' = ANY(tags);
-- UUID
CREATE TABLE usuarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL
);
-- Range Types
CREATE TABLE reservas (
id SERIAL PRIMARY KEY,
periodo TSRANGE NOT NULL,
sala_id INT,
EXCLUDE USING GIST (sala_id WITH =, periodo WITH &&)
);
-- Previne overlapping reservations automaticamente!
-- Geometric Types
CREATE TABLE locais (
id SERIAL PRIMARY KEY,
nome VARCHAR(100),
localizacao POINT
);
SELECT * FROM locais
WHERE localizacao <-> point(40.7128, -74.0060) < 10; -- 10 km radius
-- Criar índice de texto completo
CREATE TABLE artigos (
id SERIAL PRIMARY KEY,
titulo TEXT,
conteudo TEXT,
tsv TSVECTOR GENERATED ALWAYS AS (
to_tsvector('portuguese', titulo || ' ' || conteudo)
) STORED
);
CREATE INDEX idx_artigos_fts ON artigos USING GIN(tsv);
-- Buscar com ranking
SELECT titulo, ts_rank(tsv, query) as rank
FROM artigos, to_tsquery('portuguese', 'postgresql & database') query
WHERE tsv @@ query
ORDER BY rank DESC;
Common Table Expressions (CTEs):
-- CTE Recursivo para hierarquia
WITH RECURSIVE organizacao AS (
-- Base case
SELECT id, nome, gerente_id, 1 as nivel
FROM funcionarios
WHERE gerente_id IS NULL
UNION ALL
-- Recursive case
SELECT f.id, f.nome, f.gerente_id, o.nivel + 1
FROM funcionarios f
JOIN organizacao o ON f.gerente_id = o.id
)
SELECT * FROM organizacao ORDER BY nivel, nome;
Window Functions:
-- Ranking e análise
SELECT
nome,
departamento,
salario,
RANK() OVER (PARTITION BY departamento ORDER BY salario DESC) as rank_dept,
AVG(salario) OVER (PARTITION BY departamento) as media_dept,
SUM(salario) OVER (ORDER BY data_admissao ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as soma_movel
FROM funcionarios;
PostGIS - Dados geoespaciais:
CREATE EXTENSION postgis;
-- Armazenar geometria
CREATE TABLE cidades (
nome VARCHAR(100),
localizacao GEOGRAPHY(POINT, 4326)
);
-- Calcular distância
SELECT nome,
ST_Distance(localizacao, 'POINT(-74.0060 40.7128)'::geography) / 1000 as km
FROM cidades
ORDER BY km
LIMIT 10;
pg_trgm - Fuzzy search:
CREATE EXTENSION pg_trgm;
-- Busca por similaridade
SELECT nome, similarity(nome, 'João Silva') as sim
FROM usuarios
WHERE nome % 'Joao Silv' -- % = similar operator
ORDER BY sim DESC
LIMIT 5;
UUID generation:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SELECT uuid_generate_v4();
B-Tree (default):
CREATE INDEX idx_usuarios_email ON usuarios(email);
Hash (igualdade apenas):
CREATE INDEX idx_usuarios_cpf ON usuarios USING HASH(cpf);
GIN (arrays, JSON, full-text):
CREATE INDEX idx_posts_tags ON posts USING GIN(tags);
CREATE INDEX idx_eventos_dados ON eventos USING GIN(dados);
GiST (geometric, range):
CREATE INDEX idx_reservas_periodo ON reservas USING GIST(periodo);
BRIN (grandes tabelas sequenciais):
CREATE INDEX idx_logs_timestamp ON logs USING BRIN(timestamp);
EXPLAIN ANALYZE:
EXPLAIN ANALYZE
SELECT u.nome, COUNT(p.id) as total_posts
FROM usuarios u
LEFT JOIN posts p ON u.id = p.usuario_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.id, u.nome
HAVING COUNT(p.id) > 10;
Índices Parciais:
-- Índice apenas para registros ativos
CREATE INDEX idx_usuarios_ativos ON usuarios(email)
WHERE status = 'ativo';
Índices Covering:
-- Índice contém todos os dados necessários
CREATE INDEX idx_usuarios_login ON usuarios(email)
INCLUDE (nome, ultimo_login);
-- Query pode usar index-only scan
SELECT nome, ultimo_login FROM usuarios WHERE email = 'user@example.com';
-- Tabela particionada por range
CREATE TABLE vendas (
id SERIAL,
data DATE NOT NULL,
valor DECIMAL(10,2),
produto_id INT
) PARTITION BY RANGE (data);
-- Partições
CREATE TABLE vendas_2024_q1 PARTITION OF vendas
FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');
CREATE TABLE vendas_2024_q2 PARTITION OF vendas
FOR VALUES FROM ('2024-04-01') TO ('2024-07-01');
-- Queries automaticamente usam partição correta
SELECT SUM(valor) FROM vendas WHERE data BETWEEN '2024-01-01' AND '2024-03-31';
-- View materializada (pré-computada)
CREATE MATERIALIZED VIEW vendas_por_mes AS
SELECT
DATE_TRUNC('month', data) as mes,
COUNT(*) as total_vendas,
SUM(valor) as receita
FROM vendas
GROUP BY mes;
CREATE INDEX ON vendas_por_mes(mes);
-- Refresh quando necessário
REFRESH MATERIALIZED VIEW CONCURRENTLY vendas_por_mes;
Acesse dados externos como tabelas PostgreSQL:
CREATE EXTENSION postgres_fdw;
CREATE SERVER servidor_remoto
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'outro-servidor.com', dbname 'analytics', port '5432');
CREATE FOREIGN TABLE vendas_remotas (...)
SERVER servidor_remoto
OPTIONS (schema_name 'public', table_name 'vendas');
-- Query normalmente
SELECT * FROM vendas_remotas WHERE data > '2024-01-01';
Replicação seletiva e cross-version:
-- No publisher
CREATE PUBLICATION minha_pub FOR TABLE usuarios, posts;
-- No subscriber
CREATE SUBSCRIPTION minha_sub
CONNECTION 'host=publisher.com dbname=prod user=replicator'
PUBLICATION minha_pub;
CREATE TABLE documentos (
id SERIAL PRIMARY KEY,
titulo TEXT,
conteudo TEXT,
usuario_id INT
);
ALTER TABLE documentos ENABLE ROW LEVEL SECURITY;
-- Usuários só veem seus próprios documentos
CREATE POLICY documentos_policy ON documentos
FOR ALL
USING (usuario_id = current_setting('app.user_id')::INT);
-- Setar contexto na aplicação
SET app.user_id = 123;
-- Usuário 123 só vê seus documentos
SELECT * FROM documentos;
-- Criar roles
CREATE ROLE readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
CREATE ROLE app_user LOGIN PASSWORD 'senha_forte';
GRANT readonly TO app_user;
-- Revoke permissões
REVOKE DELETE ON usuarios FROM app_user;
CREATE EXTENSION IF NOT EXISTS "pgaudit";
-- Log todas operações em tabelas sensíveis
ALTER DATABASE mydb SET pgaudit.log = 'write, ddl';
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Usuario {
id Int @id @default(autoincrement())
email String @unique
nome String
posts Post[]
createdAt DateTime @default(now())
@@index([email])
}
model Post {
id Int @id @default(autoincrement())
titulo String
conteudo String
publicado Boolean @default(false)
autor Usuario @relation(fields: [autorId], references: [id])
autorId Int
tags String[]
@@index([autorId])
@@index([publicado])
}
// Usar Prisma Client
const usuario = await prisma.usuario.create({
data: {
email: 'user@example.com',
nome: 'João',
posts: {
create: [
{ titulo: 'Meu primeiro post', conteudo: '...' }
]
}
},
include: { posts: true }
});
@Entity()
export class Usuario {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ unique: true })
email: string;
@Column()
nome: string;
@Column('text', { array: true, default: [] })
tags: string[];
@Column('jsonb', { nullable: true })
metadata: Record<string, any>;
@OneToMany(() => Post, post => post.autor)
posts: Post[];
@CreateDateColumn()
createdAt: Date;
}
# Backup completo
pg_dump -U postgres -d mydb -F c -f backup.dump
# Backup com compressão
pg_dump -U postgres -d mydb -F c -Z 9 -f backup.dump.gz
# Restore
pg_restore -U postgres -d mydb_novo backup.dump
# Backup contínuo (Point-in-Time Recovery)
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'cp %p /backups/wal/%f'
# Restore para ponto específico no tempo
pg_basebackup -D /backup/base -F tar -z -P
# recovery.conf
restore_command = 'cp /backups/wal/%f %p'
recovery_target_time = '2024-10-27 10:30:00'
-- Queries lentas
SELECT pid, now() - query_start as duration, query
FROM pg_stat_activity
WHERE state = 'active' AND now() - query_start > interval '5 seconds'
ORDER BY duration DESC;
-- Tamanho de tabelas
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 20;
-- Cache hit ratio
SELECT
sum(blks_hit)*100/sum(blks_hit+blks_read) as cache_hit_ratio
FROM pg_stat_database;
-- Conexões ativas
SELECT count(*) FROM pg_stat_activity WHERE state = 'active';
Use PgBouncer para gerenciar conexões eficientemente:
[databases]
mydb = host=localhost dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20
Aplicação conecta a PgBouncer (6432), não diretamente ao Postgres (5432).
AWS RDS PostgreSQL:
AWS Aurora PostgreSQL:
Google Cloud SQL:
Azure Database for PostgreSQL:
Supabase:
Aplicações Web/Mobile: Persistência confiável para apps modernos
Data Warehousing: Análises complexas com window functions e CTEs
Geoespacial: PostGIS para aplicações de mapas e localização
Time-Series: TimescaleDB extension para séries temporais
Full-Text Search: Search engine integrado sem Elasticsearch
Multi-Tenant SaaS: Row-level security para isolamento de tenants
PostgreSQL é mais que um banco de dados - é uma plataforma de dados completa que combina:
✅ Confiabilidade absoluta (ACID completo) ✅ Recursos avançados (JSON, Arrays, Full-Text Search) ✅ Extensibilidade incomparável ✅ Performance excepcional ✅ Open-source sem vendor lock-in ✅ Comunidade ativa e engajada
Na Arkanus, PostgreSQL é nosso banco de dados relacional preferido para:
Se você quer um banco de dados que cresce com seu projeto, PostgreSQL é a escolha certa - e podemos ajudar você a aproveitá-lo ao máximo.
Precisa de ajuda com PostgreSQL? Nossa equipe tem expertise em design de schemas, otimização de queries e migração. Entre em contato.

Equipe Arkanus
Equipe Arkanus escreve sobre tecnologia, transformação digital e engenharia de software na Arkanus.
Entenda como MongoDB revolucionou persistência de dados com seu modelo de documentos flexível, perfeito para aplicações modernas que exigem agilidade e escala.
Node.js revolucionou o desenvolvimento backend com JavaScript. Descubra por que empresas como Netflix, PayPal e Uber confiam nesta tecnologia.
Python não é só para cientistas de dados. Descubra como esta linguagem versátil pode transformar seus processos de negócio, desde automação até inteligência artificial.