Toda tabela InnoDB precisa de uma chave primária para funcionar bem — é ela que define a ordem física das linhas em disco e é usada internamente pelo replication baseado em linha (row-based replication) para identificar cada registro. Antes do MySQL 8.0.30, uma tabela criada sem PRIMARY KEY explícita simplesmente não tinha uma, e o InnoDB recorria a um índice interno oculto e ineficiente para as operações que dependiam dele. A partir do MySQL 8.0.30, o recurso de Generated Invisible Primary Keys (GIPK) resolve isso: o próprio servidor cria uma chave primária de verdade, do tipo BIGINT UNSIGNED com AUTO_INCREMENT, sempre que uma tabela InnoDB é criada sem chave primária — e essa coluna fica invisível, sem aparecer em SELECT *.
O problema das tabelas sem chave primária
Antes do GIPK, criar uma tabela assim era perfeitamente válido, mas deixava a tabela em desvantagem:
CREATE TABLE eventos (
tipo VARCHAR(50),
payload JSON,
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP
);
Sem chave primária, o InnoDB cria um índice clustered interno baseado em um ROW_ID de 6 bytes, compartilhado entre todas as tabelas sem chave — o que é ineficiente e não pode ser referenciado por SQL. Pior ainda: ferramentas de replicação em grupo (Group Replication) e clusters como o InnoDB Cluster e o NDB Cluster exigem que toda tabela tenha uma chave primária para funcionar corretamente, e rejeitavam (ou avisavam sobre) tabelas sem uma.
Como o GIPK funciona
Com a variável de sessão sql_generate_invisible_primary_key ativada, a mesma instrução CREATE TABLE passa a gerar uma chave primária automaticamente:
SET sql_generate_invisible_primary_key = ON;
CREATE TABLE eventos (
tipo VARCHAR(50),
payload JSON,
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP
);
Consultando a estrutura da tabela, aparece uma coluna nova, my_row_id, que não foi declarada:
SHOW CREATE TABLE eventos;
CREATE TABLE `eventos` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT INVISIBLE,
`tipo` varchar(50) DEFAULT NULL,
`payload` json DEFAULT NULL,
`criado_em` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`my_row_id`)
) ENGINE=InnoDB;
O nome da coluna e da chave é sempre my_row_id, e ela é marcada como INVISIBLE — o mesmo mecanismo de colunas invisíveis introduzido no MySQL 8.0.23, usado aqui para que a chave gerada não polua o resultado de consultas existentes.
Invisível, mas não escondida
Uma coluna invisível não aparece em SELECT * nem em INSERT sem lista de colunas, mas continua acessível quando referenciada explicitamente pelo nome:
SELECT * FROM eventos;
-- retorna: tipo, payload, criado_em (sem my_row_id)
SELECT my_row_id, tipo FROM eventos;
-- retorna: my_row_id, tipo
INSERT INTO eventos (tipo, payload) VALUES ('login', '{"usuario": 42}');
-- funciona normalmente; my_row_id é preenchido pelo AUTO_INCREMENT
INSERT INTO eventos (my_row_id, tipo, payload) VALUES (1000, 'logout', '{}');
-- também funciona, se o valor for informado explicitamente
Isso preserva a compatibilidade com código existente que não sabia da existência da chave gerada, ao mesmo tempo em que permite usá-la quando necessário — por exemplo, para paginação eficiente ou como alvo de uma JOIN.
Habilitando globalmente
Em vez de ativar por sessão, o mais comum é configurar a variável no arquivo de configuração do servidor, para que toda tabela nova sem chave primária já nasça com GIPK:
-- my.cnf
[mysqld]
sql_generate_invisible_primary_key=ON
Ou dinamicamente, para a sessão global sem reiniciar o servidor:
SET GLOBAL sql_generate_invisible_primary_key = ON;
O padrão de fábrica é OFF: é preciso habilitar explicitamente para o recurso entrar em ação. A configuração afeta apenas tabelas InnoDB — outras engines (MyISAM, MEMORY etc.) ignoram essa variável.
Identificando tabelas com GIPK
Para auditar quais tabelas de um banco têm uma chave gerada automaticamente, o dicionário de dados expõe essa informação diretamente:
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'meu_banco'
AND CREATE_OPTIONS LIKE '%GENERATED_KEY%';
Quando usar
- Bancos que ingerem tabelas geradas por ferramentas de terceiros (ETL, migração de outro SGBD) que às vezes não definem chave primária.
- Ambientes com MySQL Group Replication, InnoDB Cluster ou replicação baseada em linha, onde toda tabela precisa de uma chave primária para replicar de forma confiável e eficiente.
- Simplificar scripts de criação de tabelas de staging ou temporárias que antes exigiam adicionar manualmente um
id BIGINT AUTO_INCREMENT PRIMARY KEYsó para satisfazer essas exigências. - Evitar o índice clustered interno baseado em
ROW_ID, que é menos eficiente que uma chave primária real.
Cuidados
O nome my_row_id é fixo — não é possível escolher outro nome para a coluna gerada. Se a tabela já tiver uma coluna chamada my_row_id (mesmo sem ser chave), o GIPK não é aplicado e a tabela continua sem chave primária, silenciosamente. Além disso, uma vez que a chave é criada, ela não é removida automaticamente se depois for adicionada uma chave primária "de verdade" à tabela — nesse caso é preciso remover manualmente a coluna my_row_id com ALTER TABLE ... DROP COLUMN my_row_id. Ferramentas que fazem SELECT * e esperam receber todas as colunas físicas da tabela (como alguns ORMs de introspecção de schema) podem não enxergar my_row_id a menos que consultem INFORMATION_SCHEMA.COLUMNS diretamente.
Compatibilidade
Generated Invisible Primary Keys foram introduzidas no MySQL 8.0.30 (julho de 2022), exigem a engine InnoDB e seguem disponíveis e habilitáveis da mesma forma no MySQL 8.4 LTS e nas versões 9.x. O recurso depende do mecanismo de colunas invisíveis, disponível desde o MySQL 8.0.23.
Conclusão
GIPK não muda como se escreve consultas do dia a dia, mas elimina uma classe inteira de problemas causados por tabelas sem chave primária — desde ineficiência de armazenamento até incompatibilidade com replicação em cluster. Vale habilitar sql_generate_invisible_primary_key globalmente em ambientes que não controlam 100% do DDL que chega ao banco, como uma rede de segurança contra tabelas criadas sem chave.
0 Comentário
Deixe seu Comentário!
Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.