Banco de dados em produção costuma dar problema em horários ruins: a aplicação trava porque uma consulta segurou um lock, o disco enche de madrugada, alguém rodou um UPDATE sem WHERE. Nessas horas, saber o comando certo de cabeça (ou saber onde procurar) faz toda a diferença.
Este artigo reúne situações reais, organizadas por tema, com os comandos para PostgreSQL, MySQL, SQL Server, MongoDB e Redis. No final há uma tabela completa para consulta rápida. Para entender os conceitos por trás (transações, índices, isolamento, NoSQL), leia o guia completo de banco de dados.
Alterando dados sem medo
Conferir antes de rodar um UPDATE ou DELETE
-- 1. Veja exatamente o que será afetado
SELECT id, status FROM pedidos WHERE status = 'pendente' AND criado_em < '2026-01-01';
-- 2. Rode dentro de uma transação
BEGIN;
UPDATE pedidos SET status = 'expirado'
WHERE status = 'pendente' AND criado_em < '2026-01-01';
-- o cliente mostra: UPDATE 42 → era o número esperado?
-- 3. Confirme ou desfaça
COMMIT; -- ou ROLLBACK;No SQL Server, BEGIN TRANSACTION e SELECT @@ROWCOUNT logo após o comando.
Rodei um UPDATE sem WHERE
Se ainda está dentro da transação: ROLLBACK; e respire. Se já confirmou (ou estava em autocommit), o caminho é restaurar a partir de backup:
- PostgreSQL: restaure o último backup numa base separada e copie de volta os dados afetados; com arquivamento de WAL configurado, dá para voltar a um instante exato (point-in-time recovery).
- MySQL: restaure o backup e reaplique o binary log até um pouco antes do comando (
mysqlbinlog --stop-datetime). - SQL Server: com modelo de recuperação FULL e backups de log,
RESTORE ... WITH STOPAT = '2026-09-24 14:32:00'restaura até o momento anterior.
Prevenção: no MySQL, SET SQL_SAFE_UPDATES = 1; recusa UPDATE/DELETE sem WHERE pela chave.
Apagar em lotes para não travar a tabela
-- PostgreSQL: apaga de 10 mil em 10 mil
DELETE FROM logs
WHERE id IN (SELECT id FROM logs WHERE criado_em < now() - INTERVAL '90 days' LIMIT 10000);
-- MySQL
DELETE FROM logs WHERE criado_em < NOW() - INTERVAL 90 DAY LIMIT 10000;
-- SQL Server
DELETE TOP (10000) FROM logs WHERE criado_em < DATEADD(DAY, -90, GETDATE());Repita até não sobrar linhas. Um DELETE de milhões de linhas numa única transação segura locks, cresce o log e pode derrubar a replicação.
Dados duplicados
Encontrar duplicados
SELECT email, COUNT(*) AS vezes
FROM clientes
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY vezes DESC;Apagar duplicados mantendo o registro mais antigo
-- PostgreSQL e SQL Server (e MySQL 8 com CTE em DELETE via JOIN)
WITH ranqueados AS (
SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS n
FROM clientes
)
DELETE FROM clientes WHERE id IN (SELECT id FROM ranqueados WHERE n > 1);Depois, impeça que volte a acontecer: ALTER TABLE clientes ADD CONSTRAINT clientes_email_unico UNIQUE (email);.
A aplicação travou: locks e sessões
Quem está rodando o quê agora
-- PostgreSQL
SELECT pid, usename, state, now() - query_start AS duracao, left(query, 80) AS consulta
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY duracao DESC;
-- MySQL
SHOW FULL PROCESSLIST;
-- SQL Server
SELECT session_id, status, blocking_session_id, wait_type, total_elapsed_time
FROM sys.dm_exec_requests
WHERE session_id > 50;Quem está bloqueando quem
-- PostgreSQL
SELECT pid, pg_blocking_pids(pid) AS bloqueado_por, left(query, 80)
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;
-- SQL Server
SELECT session_id, blocking_session_id, wait_type, wait_time
FROM sys.dm_exec_requests
WHERE blocking_session_id <> 0;
-- MySQL 8
SELECT * FROM sys.innodb_lock_waits;Encerrar a consulta ou a sessão problemática
-- PostgreSQL
SELECT pg_cancel_backend(12345); -- cancela só a consulta (mais gentil)
SELECT pg_terminate_backend(12345); -- derruba a conexão
-- MySQL
KILL QUERY 123; -- cancela a consulta
KILL 123; -- derruba a conexão
-- SQL Server
KILL 57;Uma transação aberta e esquecida (idle in transaction no PostgreSQL) é a causa mais comum de locks eternos. No PostgreSQL, idle_in_transaction_session_timeout encerra essas sessões automaticamente.
Limitar quanto tempo uma consulta pode rodar
SET statement_timeout = '30s'; -- PostgreSQL, na sessão
SET SESSION max_execution_time = 30000; -- MySQL, em ms (só SELECT)O banco ficou lento
Ver o plano de execução
EXPLAIN ANALYZE SELECT * FROM pedidos WHERE cliente_id = 42; -- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM pedidos WHERE cliente_id = 42; -- MySQL 8.0.18+
SET STATISTICS IO, TIME ON; -- SQL Server (e ative o plano no SSMS)Seq Scan (PostgreSQL), type: ALL (MySQL) ou Table Scan (SQL Server) numa tabela grande indicam falta de índice.
As consultas mais pesadas
-- PostgreSQL (precisa da extensão pg_stat_statements)
SELECT calls, round(total_exec_time) AS ms_total, round(mean_exec_time) AS ms_media, left(query, 80)
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
-- SQL Server
SELECT TOP 10 qs.total_elapsed_time / qs.execution_count AS media, qs.execution_count,
SUBSTRING(st.text, 1, 100) AS consulta
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY media DESC;No MySQL, ative o slow query log: SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;.
Criar índice sem travar a tabela
CREATE INDEX CONCURRENTLY idx_pedidos_cliente ON pedidos (cliente_id); -- PostgreSQL
ALTER TABLE pedidos ADD INDEX idx_cliente (cliente_id), ALGORITHM=INPLACE, LOCK=NONE; -- MySQL
CREATE INDEX idx_cliente ON pedidos (cliente_id) WITH (ONLINE = ON); -- SQL Server (edições que suportam)Estatísticas desatualizadas
ANALYZE pedidos; -- PostgreSQL
ANALYZE TABLE pedidos; -- MySQL
UPDATE STATISTICS pedidos; -- SQL ServerO otimizador escolhe o plano com base em estatísticas. Depois de uma carga grande de dados, elas podem estar velhas e gerar planos ruins.
Índices que ninguém usa (e só atrasam as escritas)
-- PostgreSQL
SELECT relname AS tabela, indexrelname AS indice, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;No SQL Server, compare user_seeks + user_scans com user_updates em sys.dm_db_index_usage_stats.
Espaço em disco
Tamanho dos bancos e das maiores tabelas
-- PostgreSQL
SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database;
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total
FROM pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;
-- MySQL
SELECT table_name, ROUND((data_length + index_length) / 1024 / 1024) AS mb
FROM information_schema.tables
WHERE table_schema = 'loja'
ORDER BY mb DESC LIMIT 10;
-- SQL Server
EXEC sp_spaceused;
EXEC sp_spaceused 'pedidos';O log de transações do SQL Server não para de crescer
DBCC SQLPERF(LOGSPACE); -- quanto do log está em uso
SELECT name, recovery_model_desc, log_reuse_wait_desc FROM sys.databases;Se o modelo é FULL e log_reuse_wait_desc mostra LOG_BACKUP, faltam backups de log: agende BACKUP LOG regularmente. Encolher o arquivo sem resolver a causa só adia o problema.
PostgreSQL: tabela inchada depois de muitos UPDATE/DELETE
VACUUM (VERBOSE, ANALYZE) pedidos; -- limpa versões mortas e reaproveita espaçoO VACUUM FULL devolve espaço ao sistema operacional, mas trava a tabela inteira durante a execução; prefira ferramentas como pg_repack em produção.
Backups e restores de emergência
# PostgreSQL
pg_dump -U postgres -d loja -F c -f loja_$(date +%F).dump
pg_restore -U postgres -d loja_restaurada loja_2026-09-24.dump
pg_dump -U postgres -d loja -t pedidos -F c -f pedidos.dump # uma tabela só
# MySQL
mysqldump -u root -p --single-transaction --routines loja > loja.sql
mysql -u root -p loja_restaurada < loja.sql-- SQL Server
BACKUP DATABASE Loja TO DISK = 'C:\bk\loja.bak' WITH COPY_ONLY, COMPRESSION;
RESTORE VERIFYONLY FROM DISK = 'C:\bk\loja.bak';
RESTORE DATABASE Loja_Teste FROM DISK = 'C:\bk\loja.bak'
WITH MOVE 'Loja' TO 'C:\data\Loja_Teste.mdf', MOVE 'Loja_log' TO 'C:\data\Loja_Teste.ldf';COPY_ONLY faz um backup avulso sem bagunçar a sequência de backups diferenciais. Os nomes lógicos usados no MOVE saem de RESTORE FILELISTONLY.
Exportar uma consulta para CSV
\copy (SELECT * FROM pedidos WHERE status = 'pago') TO 'pagos.csv' CSV HEADER -- psqlmysql -u root -p -e "SELECT * FROM loja.pedidos" --batch > pedidos.tsv # MySQL (separado por tab)Usuários e acesso
Criar um usuário só de leitura
-- PostgreSQL
CREATE ROLE relatorios LOGIN PASSWORD 'troque-esta-senha';
GRANT CONNECT ON DATABASE loja TO relatorios;
GRANT USAGE ON SCHEMA public TO relatorios;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO relatorios;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO relatorios;
-- MySQL
CREATE USER 'relatorios'@'%' IDENTIFIED BY 'troque-esta-senha';
GRANT SELECT ON loja.* TO 'relatorios'@'%';
-- SQL Server
CREATE LOGIN relatorios WITH PASSWORD = 'Troque-Esta-Senha1';
CREATE USER relatorios FOR LOGIN relatorios;
ALTER ROLE db_datareader ADD MEMBER relatorios;Usuário órfão depois de restaurar no SQL Server
ALTER USER app WITH LOGIN = app;Religa o usuário do banco ao login da instância (substitui o antigo sp_change_users_login).
"Too many connections"
SHOW max_connections; -- PostgreSQL
SELECT count(*) FROM pg_stat_activity;
SHOW VARIABLES LIKE 'max_connections'; -- MySQL
SHOW STATUS LIKE 'Threads_connected';A solução raramente é aumentar o limite: use um pool de conexões na aplicação (ou PgBouncer no PostgreSQL) e procure conexões vazando.
MongoDB em apuros
O que está rodando e o que está lento
db.currentOp({ secs_running: { $gt: 5 } }) // operações há mais de 5 s
db.killOp(12345) // encerra uma operação
db.setProfilingLevel(1, { slowms: 100 }) // registra consultas acima de 100 ms
db.system.profile.find().sort({ ts: -1 }).limit(5)Consulta sem índice
db.pedidos.find({ clienteId: 42 }).explain("executionStats")
// "COLLSCAN" no plano = varreu a coleção inteira
db.pedidos.createIndex({ clienteId: 1, criadoEm: -1 })Encontrar e remover duplicados
db.clientes.aggregate([
{ $group: { _id: "$email", ids: { $push: "$_id" }, total: { $sum: 1 } } },
{ $match: { total: { $gt: 1 } } }
])Depois, remova os extras e crie db.clientes.createIndex({ email: 1 }, { unique: true }).
Tamanho e backup
db.stats() // tamanho do banco
db.pedidos.stats().size // tamanho da coleção em bytesmongodump --uri="mongodb://localhost:27017/loja" --out=backup/
mongorestore --uri="mongodb://localhost:27017" backup/
mongoexport --db=loja --collection=pedidos --type=csv --fields=_id,total --out=pedidos.csvRedis em apuros
Está vivo? Quanto de memória usa?
redis-cli PING # PONG = ok
redis-cli INFO memory # used_memory_human e maxmemory
redis-cli INFO stats # hits, misses, conexões
redis-cli DBSIZE # quantidade de chavesAchar as maiores chaves sem travar o servidor
redis-cli --bigkeys # amostra as maiores chaves por tipo
redis-cli --scan --pattern "sessao:*" | head
redis-cli MEMORY USAGE nome:da:chaveNunca use KEYS * em produção: ele percorre tudo numa única thread e bloqueia o Redis.
Comandos lentos e clientes conectados
redis-cli SLOWLOG GET 10 # os 10 comandos mais lentos recentes
redis-cli CLIENT LIST # quem está conectado
redis-cli CLIENT KILL ID 42 # derruba um clienteApagar muitas chaves por padrão
redis-cli --scan --pattern "cache:produtos:*" | xargs -L 100 redis-cli UNLINKUNLINK libera a memória em segundo plano, sem bloquear como o DEL em chaves grandes.
A memória acabou
Defina limite e política de despejo, para que o Redis remova chaves antigas em vez de recusar escritas:
redis-cli CONFIG SET maxmemory 512mb
redis-cli CONFIG SET maxmemory-policy allkeys-lruPara cache, allkeys-lru é o padrão sensato. Se o Redis guarda dados que não podem sumir, prefira volatile-lru (só remove chaves com expiração) e mais memória.
Tabela completa: bancos de dados em emergências
SQL e NoSQL: comandos que salvam sua vida
PostgreSQL, MySQL, SQL Server, MongoDB e Redis.
Alterações seguras
Antes de mexer em produção
Sessões e locks
Quando a aplicação trava
Lentidão
Encontre e corrija o gargalo
Espaço em disco
Quem está ocupando o disco
Backup e restore
Tenha sempre um caminho de volta
Acesso
Usuários e conexões
MongoDB
No mongosh e no terminal
Redis
No redis-cli
Referências
- Documentação do PostgreSQL: referência completa, inclusive das views de monitoramento.
- Manual de referência do MySQL: documentação oficial do MySQL.
- Referência do Transact-SQL (Microsoft): documentação do SQL Server.
- Manual do MongoDB: documentação oficial do MongoDB.
- Documentação do Redis: comandos, memória e persistência.
- SQL Server First Responder Kit: scripts gratuitos de diagnóstico.



