Atualizando a chave primária do MySQL

103

Tenho uma tabela user_interactionscom 4 colunas:

 user_1
 user_2
 type
 timestamp

A chave primária é (user_1,user_2,type)
e eu quero mudar para(user_2,user_1,type)

Então o que eu fiz foi:

drop primary key ...  
add primary key (user_2,user_1,type)...

e voila ...

O problema é que o banco de dados está ativo em um servidor.

Portanto, antes que eu pudesse atualizar a chave primária, muitas duplicatas já se insinuaram e estão continuamente entrando.

O que fazer?

O que quero fazer agora é remover as duplicatas e manter as que estão com as mais recentes timestamp(que é uma coluna da tabela).

E então, de alguma forma, atualize a chave primária novamente.

simplfuzz
fonte
16
De repente, me sinto mal por cada DBA que xinguei baixinho ...
Ignacio Vazquez-Abrams
5
da próxima vez, adicione uma chave exclusiva com as mesmas colunas da chave primária e, em seguida, atualize a chave primária
knittl
1
@Ignacio, está ativo em um servidor, mas é um servidor de backup-backup :-). Não sou um DBA, mas não tentarei fazer isso em um servidor REALMENTE
ativo
1
@knittl, sim, foi o que pensei agora, embora muito tarde :-)
simplfuzz
4
@pixeline: É uma chave primária composta.
Ignacio Vazquez-Abrams

Respostas:

231

Da próxima vez, use uma única instrução "alter table" para atualizar a chave primária.

alter table xx drop primary key, add primary key(k1, k2, k3);

Para consertar as coisas:

create table fixit (user_2, user_1, type, timestamp, n, primary key( user_2, user_1, type) );
lock table fixit write, user_interactions u write, user_interactions write;

insert into fixit 
select user_2, user_1, type, max(timestamp), count(*) n from user_interactions u 
group by user_2, user_1, type
having n > 1;

delete u from user_interactions u, fixit 
where fixit.user_2 = u.user_2 
  and fixit.user_1 = u.user_1 
  and fixit.type = u.type 
  and fixit.timestamp != u.timestamp;

alter table user_interactions add primary key (user_2, user_1, type );

unlock tables;

O bloqueio deve impedir que novas atualizações entrem enquanto você estiver fazendo isso. Quanto tempo isso leva obviamente depende do tamanho da sua mesa.

O principal problema é se você tem algumas duplicatas com o mesmo carimbo de data / hora.

Martin
fonte
11

Se a chave primária for um valor de incremento automático, você deve remover o incremento automático, então descartar a chave primária e então adicionar novamente o incremento automático

ALTER TABLE `xx`
MODIFY `auto_increment_field` INT, 
DROP PRIMARY KEY, 
ADD PRIMARY KEY (new_primary_key);

em seguida, adicione de volta o incremento automático

ALTER TABLE `xx` ADD INDEX `auto_increment_field` (auto_increment_field),
MODIFY `auto_increment_field` int auto_increment;

em seguida, defina o incremento automático de volta ao valor anterior

ALTER TABLE `xx` AUTO_INCREMENT = 5;
Frazras
fonte
2

Você também pode usar a IGNOREpalavra-chave, por exemplo:

 update IGNORE table set primary_field = 'value'...............
Sarfraz
fonte