Mettre à jour la clé primaire MySQL

103

J'ai une table user_interactionsavec 4 colonnes:

 user_1
 user_2
 type
 timestamp

La clé primaire est (user_1,user_2,type)
et je veux changer en(user_2,user_1,type)

Donc ce que j'ai fait était:

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

et voila ...

Le problème est que la base de données est en direct sur un serveur.

Donc, avant que je puisse mettre à jour la clé primaire, de nombreux doublons se sont déjà glissés et ils s'infiltrent continuellement.

Que faire?

Ce que je veux faire maintenant, c'est supprimer les doublons et conserver ceux avec le dernier timestamp(qui est une colonne dans le tableau).

Et puis, d'une manière ou d'une autre, mettez à nouveau à jour la clé primaire.

simplfuzz
la source
16
Je me sens soudainement mal pour chaque DBA que j'ai maudit dans mon souffle ...
Ignacio Vazquez-Abrams
5
la prochaine fois, ajoutez une clé unique avec les mêmes colonnes que la clé primaire, puis mettez à jour la clé primaire
knittl
1
@Ignacio, c'est en direct sur un serveur, mais c'est un serveur de sauvegarde-sauvegarde :-). Je ne suis pas un DBA, mais je n'essaierai pas cette chose sur un serveur VRAIMENT en direct :-)
simplfuzz
1
@knittl, oui c'est ce que je pensais maintenant, très tard cependant :-)
simplfuzz
4
@pixeline: C'est une clé primaire composée.
Ignacio Vazquez-Abrams

Réponses:

231

La prochaine fois, utilisez une seule instruction "alter table" pour mettre à jour la clé primaire.

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

Pour réparer les choses:

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;

Le verrou devrait arrêter les mises à jour supplémentaires pendant que vous faites cela. Le temps que cela prend dépend évidemment de la taille de votre table.

Le problème principal est si vous avez des doublons avec le même horodatage.

Martin
la source
11

Si la clé primaire est une valeur auto_increment, vous devez supprimer l'incrémentation automatique, puis supprimer la clé primaire puis rajouter l'incrémentation automatique

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

puis rajoutez l'incrémentation automatique

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

puis remettez l'incrémentation automatique à la valeur précédente

ALTER TABLE `xx` AUTO_INCREMENT = 5;
frazras
la source
2

Vous pouvez également utiliser le IGNOREmot - clé, par exemple:

 update IGNORE table set primary_field = 'value'...............
Sarfraz
la source