Invisible Columns no MySQL

Como usar o atributo INVISIBLE do MySQL para adicionar ou remover colunas de uma tabela em produção sem quebrar código legado que faz SELECT *.

Adicionar uma coluna nova a uma tabela em produção sempre traz um risco escondido: qualquer código que faça SELECT * — e ainda existe muito código assim por aí — passa a receber uma coluna a mais sem ter sido avisado, o que pode quebrar ORMs, serializadores de JSON ou testes que comparam o número de campos retornados. Desde o MySQL 8.0.23, o atributo INVISIBLE resolve esse problema: uma coluna marcada como invisível continua existindo normalmente na tabela, mas desaparece de SELECT * e de INSERT sem lista explícita de colunas, só aparecendo quando referenciada pelo nome.

Como funciona

Por padrão toda coluna é VISIBLE. Para criar uma coluna já invisível, basta acrescentar a palavra-chave na definição:

CREATE TABLE produtos (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(120) NOT NULL,
    preco DECIMAL(10,2) NOT NULL,
    margem_interna DECIMAL(5,2) INVISIBLE DEFAULT 0
);

Consultando a tabela normalmente, margem_interna simplesmente não aparece:

SELECT * FROM produtos;
-- retorna apenas: id, nome, preco

SELECT id, nome, margem_interna FROM produtos;
-- retorna: id, nome, margem_interna (a coluna existe e pode ser referenciada)

O mesmo vale para INSERT: sem listar as colunas explicitamente, a coluna invisível é ignorada e recebe seu valor DEFAULT:

INSERT INTO produtos (nome, preco) VALUES ('Teclado', 199.90);
-- margem_interna recebe o DEFAULT (0)

INSERT INTO produtos (nome, preco, margem_interna) VALUES ('Mouse', 89.90, 15.5);
-- funciona normalmente quando referenciada explicitamente

Tornando uma coluna existente invisível

Não é preciso recriar a tabela: um ALTER TABLE muda a visibilidade de uma coluna já existente. Há mais de uma sintaxe equivalente para isso:

ALTER TABLE produtos ALTER COLUMN margem_interna SET INVISIBLE;
ALTER TABLE produtos ALTER COLUMN margem_interna SET VISIBLE;

-- Formas equivalentes, redeclarando o tipo da coluna
ALTER TABLE produtos MODIFY COLUMN margem_interna DECIMAL(5,2) INVISIBLE;
ALTER TABLE produtos CHANGE COLUMN margem_interna margem_interna DECIMAL(5,2) VISIBLE;

Como é só uma mudança de metadado, essas alterações são praticamente instantâneas, mesmo em tabelas grandes — nenhuma linha precisa ser reescrita.

Migração de schema em duas etapas

O uso mais comum é reduzir o risco de adicionar ou remover colunas em produção sem coordenar um deploy perfeitamente sincronizado com o código da aplicação:

-- 1. Adiciona a coluna já invisível: nenhum SELECT * existente é afetado
ALTER TABLE produtos ADD COLUMN peso_kg DECIMAL(8,3) INVISIBLE DEFAULT 0;

-- 2. Depois que o código da aplicação já sabe referenciar peso_kg explicitamente,
--    a coluna pode virar visível sem nenhum outro impacto
ALTER TABLE produtos ALTER COLUMN peso_kg SET VISIBLE;

O caminho inverso funciona para descontinuar uma coluna: torná-la invisível primeiro, observar se algo quebra, e só depois removê-la de fato com DROP COLUMN depois de um tempo tranquilo.

Verificando quais colunas estão invisíveis

A visibilidade aparece na coluna EXTRA de INFORMATION_SCHEMA.COLUMNS (e também no resultado de SHOW COLUMNS):

SELECT COLUMN_NAME, EXTRA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'meu_banco'
  AND TABLE_NAME = 'produtos';
-- margem_interna aparece com EXTRA = 'INVISIBLE'

Quando usar

Cuidados

Invisibilidade não é controle de acesso: qualquer usuário com permissão de leitura na tabela pode consultar uma coluna invisível referenciando-a pelo nome — o atributo só afasta a coluna de consultas genéricas, não a esconde de quem sabe que ela existe. Uma tabela também precisa ter pelo menos uma coluna visível; tentar tornar todas as colunas invisíveis resulta em erro. Vale atenção especial a colunas invisíveis com NOT NULL e sem DEFAULT: um INSERT sem lista de colunas vai falhar nesse caso, já que o MySQL não tem como preencher a coluna automaticamente. E como já é usado internamente pelo próprio MySQL — a chave my_row_id criada por Generated Invisible Primary Keys nada mais é que uma coluna invisível —, é uma boa prática evitar nomear colunas próprias como my_row_id para não colidir com esse mecanismo.

Compatibilidade

O atributo INVISIBLE está disponível desde o MySQL 8.0.23 (fevereiro de 2021), continua funcionando da mesma forma no MySQL 8.4 LTS e nas versões 9.x, e vale tanto para colunas de tabelas InnoDB quanto de outras engines.

documentação oficial

Conclusão

Colunas invisíveis não mudam o que é possível fazer em SQL, mas dão uma ferramenta simples para evoluir o schema de uma tabela sem depender de uma coordenação perfeita com todo o código que a consulta. Para times que não controlam 100% dos lugares que fazem SELECT * num banco, vale usar INVISIBLE como etapa intermediária de qualquer migração que adicione ou remova colunas.

Tecnologia:
mysql

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.