Comparação de Comportamento de Bloqueio ao Adicionar Campos em Grandes Tabelas em Oracle, MySQL e PostgreSQL
Este artigo analisa o impacto de bloqueios ao adicionar colunass em tabelas de alto volume em três sistemas de bancos de dados: Oracle, MySQL e PostgreSQL. A comparação abrange tipos de bloqueio, duração e efeitos em operações DML e consultas.
Ambiente de Teste
Os testes foram conduzidos com 50.000 registros nas seguintes versões:
| Banco de Dados |
Versão |
Conjunto de Dados |
| Oracle |
23.26.1.2.0 (26ai) |
50.000 linhas |
| MySQL |
8.0.45 |
50.000 linhas |
| PostgreSQL |
16.13 |
50.000 linhas |
Resumo dos Resultados
Tempo de Execução para Adicionar Colunas
| Banco de Dados |
Sem Valor Padrão |
Com Valor Padrão |
Notas |
| Oracle |
~50ms |
~40ms |
Atualização de metadados apenas |
| MySQL 8.0+ |
~1s |
<1ms |
Algoritmo INSTANT |
| PostgreSQL 11+ |
~2ms |
~2ms |
Recurso de valor padrão rápido |
Tipos de Bloqueio
| Banco de Dados |
Tipo de Bloqueio durante Adição de Coluna |
| Oracle |
Bloqueio DDL Exclusivo |
| MySQL |
Bloqueio MDL WRITE |
| PostgreSQL |
Bloqueio ACCESS EXCLUSIVE |
Detalhes para Oracle
Resultados do Teste
Adicionar coluna sem valor padrão:
Início: 00:43:39.004
Fim: 00:43:39.054
Duração: aproximadamente 50ms
Adicionar coluna com valor padrão:
Início: 00:43:39.055
Fim: 00:43:39.095
Duração: aproximadamente 40ms
Mecanismo de Bloqueio do Oracle
| Tipo de Bloqueio |
Descrição |
| Bloqueio DDL Exclusivo |
Impede outras operações DDL durante a adição |
| Row-X (SX) |
Bloqueio de linha exclusivo, mas permite consultas |
Impacto em DML e Consultas
| Tipo de Operação |
Efeito |
| SELECT |
Sem bloqueio (leitura consistente) |
| INSERT |
Bloqueio temporário durante DDL |
| UPDATE |
Bloqueio temporário durante DDL |
| DELETE |
Bloqueio temporário durante DDL |
Recursos do Oracle
-- No Oracle 11g+, adicionar colunas com valor padrão usa atualização de metadados
-- Atualização física completa ocorre apenas quando necessário
ALTER TABLE tabela_grande ADD (campo_novo VARCHAR2(50) DEFAULT 'valor');
-- Requer atualização completa se:
-- 1. Valor padrão + restrição NOT NULL
-- 2. Coluna adicionada com NOT NULL explícito
Detalhes para MySQL
Resultados do Teste
Adicionar coluna sem valor padrão:
Início: 2026-03-24 00:39:15
Fim: 2026-03-24 00:39:16
Duração: aproximadamente 1s
Adicionar coluna com valor padrão (algoritmo INSTANT):
Início: 2026-03-24 00:39:16
Fim: 2026-03-24 00:39:16
Duração: <1ms (conclusão instantânea)
Mecanismo de Bloqueio do MySQL
| Tipo de Bloqueio |
Descrição |
| Bloqueio MDL WRITE |
Bloqueio de metadados para escrita, impede DML durante DDL |
| Bloqueio MDL READ |
Bloqueio de metadados para leitura, adquirido por SELECT |
Algoritmo INSTANT no MySQL 8.0
-- MySQL 8.0.12+ suporta o algoritmo INSTANT para adicionar colunas
-- Apenas metadados são modificados, sem alterar dados existentes
ALTER TABLE tabela_grande ADD COLUMN nova_coluna VARCHAR(50) DEFAULT 'valor';
-- Condições para uso do INSTANT:
-- 1. Coluna adicionada no final da tabela
-- 2. Com valor padrão ou permitindo NULL
-- 3. Sem operações complexas adicionais
Impacto em DML e Consultas
| Tipo de Operação |
MySQL 5.7 |
MySQL 8.0 (INSTANT) |
| SELECT |
Bloqueado |
Sem bloqueio |
| INSERT |
Bloqueado |
Sem bloqueio |
| UDPATE |
Bloqueado |
Sem bloqueio |
| DELETE |
Bloqueado |
Sem bloqueio |
Comparação entre Versões do MySQL
| Versão |
Algoritmo para Adicionar Coluna |
Descrição |
| 5.6 e anteriores |
COPY |
Cópia completa da tabela, bloqueio prolongado |
| 5.7 |
INPLACE |
Atualização no local, ainda requer bloqueio de tabela |
| 8.0.12+ |
INSTANT |
Apenas metadados modificados, conclusão imediata |
Detalhes para PostgreSQL
Resultados do Teste
Adicionar coluna sem valor padrão:
Início: 2026-03-24 00:43:37.398548
Fim: 2026-03-24 00:43:37.400639
Duração: aproximadamente 2ms
Adicionar coluna com valor padrão:
Início: 2026-03-24 00:43:37.401066
Fim: 2026-03-24 00:43:37.403055
Duração: aproximadamente 2ms
Mecanismo de Bloqueio do PostgreSQL
| Tipo de Bloqueio |
Descrição |
| Bloqueio ACCESS EXCLUSIVE |
Nível mais alto de bloqueio, impede todas as operações na tabela |
Recurso de Valor Padrão Rápido no PostgreSQL 11+
-- PostgreSQL 11+ suporta valores padrão rápidos ao adicionar colunas
-- Apenas metadados são atualizados, sem reescrever a tabela
ALTER TABLE tabela_grande ADD COLUMN nova_coluna VARCHAR(50) DEFAULT 'valor';
-- Condições:
-- 1. Valor padrão é uma expressão constante
-- 2. Não envolve funções voláteis
Impacto em DML e Consultas
| Tipo de Operação |
PostgreSQL 10 e anteriores |
PostgreSQL 11+ |
| SELECT |
Bloqueado |
Bloqueio temporário |
| INSERT |
Bloqueado |
Bloqueio temporário |
| UPDATE |
Bloqueado |
Bloqueio temporário |
| DELETE |
Bloqueado |
Bloqueio temporário |
Níveis de Blqoueio no PostgreSQL
Níveis de bloqueio (do menor para o maior):
1. ACCESS SHARE - SELECT
2. ROW SHARE - SELECT FOR UPDATE
3. ROW EXCLUSIVE - INSERT/UPDATE/DELETE
4. SHARE UPDATE EXCLUSIVE - VACUUM, ANALYZE
5. SHARE - CREATE INDEX
6. SHARE ROW EXCLUSIVE - CREATE TRIGGER
7. EXCLUSIVE - REFRESH MATERIALIZED VIEW
8. ACCESS EXCLUSIVE - ALTER TABLE, DROP TABLE
Duração do Bloqueio Comparada
Duração ao Adicionar Colunas
| Banco de Dados |
Duração do Bloqueio |
Área de Impacto |
| Oracle |
Milissegundos |
Apenas durante operação DDL |
| MySQL 8.0 INSTANT |
<1ms |
Praticamente sem impacto |
| MySQL 5.7 INPLACE |
Segundos a minutos |
Requer verificação completa da tabela |
| PostgreSQL 11+ |
Milissegundos |
Apenas durante operação DDL |
Impacto em Cenários com Grandes Volumes de Dados
| Volume de Dados |
Oracle |
MySQL 8.0 |
PostgreSQL 11+ |
| 100.000 linhas |
~50ms |
<1ms |
~2ms |
| 1.000.000 linhas |
~50ms |
<1ms |
~2ms |
| 10.000.000 linhas |
~50ms |
<1ms |
~2ms |
| 100.000.000 linhas |
~50ms |
<1ms |
~2ms |
Recomendações de Boas Práticas
Para Oracle
-- Recomendado: usar valor padrão para evitar atualizações futuras
ALTER TABLE tabela_grande ADD (campo_novo VARCHAR2(50) DEFAULT 'valor');
-- Evitar: adicionar restrição NOT NULL (requer atualização completa)
ALTER TABLE tabela_grande ADD (campo_novo VARCHAR2(50) NOT NULL); -- Não recomendado
-- Alternativa: adicionar NOT NULL em etapas
ALTER TABLE tabela_grande ADD (campo_novo VARCHAR2(50) DEFAULT 'valor');
-- Após atualização pela aplicação
ALTER TABLE tabela_grande MODIFY (campo_novo VARCHAR2(50) NOT NULL);
Para MySQL
-- Recomendado: usar algoritmo INSTANT (MySQL 8.0.12+)
ALTER TABLE tabela_grande ADD COLUMN nova_coluna VARCHAR(50) DEFAULT 'valor';
-- Verificar uso do INSTANT
ALTER TABLE tabela_grande ADD COLUMN nova_coluna VARCHAR(50), ALGORITHM=INSTANT;
-- Evitar: adicionar coluna no meio da tabela (não suporta INSTANT)
ALTER TABLE tabela_grande ADD COLUMN nova_coluna VARCHAR(50) AFTER id; -- Requer COPY
-- Listar suporte de algoritmo
SHOW CREATE TABLE tabela_grande;
Para PostgreSQL
-- Recomendado: usar valor padrão rápido (PostgreSQL 11+)
ALTER TABLE tabela_grande ADD COLUMN nova_coluna VARCHAR(50) DEFAULT 'valor';
-- Evitar: usar funções voláteis como valor padrão
ALTER TABLE tabela_grande ADD COLUMN nova_coluna TIMESTAMP DEFAULT now(); -- Requer reescrita da tabela
-- Alternativa: usar valor constante
ALTER TABLE tabela_grande ADD COLUMN nova_coluna TIMESTAMP DEFAULT '2024-01-01';
-- Monitorar bloqueios
SELECT * FROM pg_locks WHERE relation = 'tabela_grande'::regclass;