J'écris souvent des datascrubs qui mettent à jour des millions de lignes de données. Les données résident dans une base de données MySQL OLTP 24x7x365 utilisant InnoDB. Les mises à jour peuvent nettoyer chaque ligne de la table (dans laquelle la base de données finit par acquérir un verrou au niveau de la table) ou peuvent simplement nettoyer 10% des lignes d'une table (ce qui peut toujours être dans les millions).Mise à jour de l'instruction MySQL UPDATE pour éviter les tailles TRX massives
Pour éviter de créer des tailles de transaction massives et de minimiser les conflits, je finis généralement par essayer de décomposer mon instruction UPDATE massive en une série de transactions UPDATE plus petites. Donc, je finis par écrire une construction de boucle qui limite ma clause de UPDATE WHERE comme ceci:
(avertissement: c'est juste pseudo-code pour obtenir le point à travers)
@batch_size=10000;
@max_primary_key_value = select max(pk) from table1
for (int i=0; i<[email protected]_primary_key_value; [email protected]_size)
{
start transaction;
update IGNORE table1
set col2 = "flag set"
where col2 = "flag not set"
and pk > i
and pk < [email protected];
commit;
}
Cette approche juste suce simplement pour si de nombreuses raisons.
Je souhaite émettre une instruction UPDATE sans que la base de données tente de regrouper tous les enregistrements en cours de mise à jour dans une seule unité de transaction. Je ne veux pas que la mise à jour réussisse ou échoue en tant qu'unité de travail unique. Si la moitié des lignes ne parviennent pas à mettre à jour ... pas de problème, faites le moi savoir. Essentiellement, chaque ligne est sa propre unité de travail, mais le traitement par lots ou la mise en cursus est la seule façon de comprendre comment représenter cela dans le moteur de base de données.
J'ai regardé la définition des niveaux d'isolation pour ma session, mais cela ne semble pas m'aider dans ce cas particulier.
D'autres idées?
Approche intéressante Eric. J'aime l'idée, mais elle est limitée aux mises à jour qui modifient réellement les valeurs de champs définies dans la clause WHERE (comme l'exemple que j'ai donné). Cependant, j'ai le même problème avec de grandes mises à jour qui ne correspondent pas à ce modèle (par exemple, set col1 = "foo" où col2 = "bar"). –
@Matthew - Si c'est le cas, vous pouvez toujours modifier votre requête pour qu'elle soit quelque chose comme "set col1 = 'foo' où col2 = 'bar' et col1! '' Foo '" ce qui éviterait la sortie d'un lot de non -modification des mises à jour vous mettant hors de la boucle. –