Mysql
 sql >> Base de données >  >> RDS >> Mysql

La mise à jour en masse de SQLalchemy dans MySQL fonctionne très lentement

Vous pouvez accélérer les opérations de mise à jour en masse avec une astuce, même si le serveur de base de données (comme dans votre cas) a une très mauvaise latence. Au lieu de mettre à jour votre table directement, vous utilisez une stage-table pour insérer vos nouvelles données très rapidement, puis effectuez une mise à jour conjointe de la table de destination . Cela présente également l'avantage de réduire considérablement le nombre de déclarations que vous devez envoyer à la base de données.

Comment cela fonctionne-t-il avec les UPDATE ?

Disons que vous avez une table entries et vous avez de nouvelles données qui arrivent tout le temps, mais vous ne voulez mettre à jour que celles qui ont déjà été stockées. Vous créez une copie de votre table de destination entries_stage avec uniquement les champs pertinents :

entries = Table('entries', metadata,
    Column('id', Integer, autoincrement=True, primary_key=True),
    Column('value', Unicode(64), nullable=False),
)

entries_stage = Table('entries_stage', metadata,
    Column('id', Integer, autoincrement=False, unique=True),
    Column('value', Unicode(64), nullable=False),
)

Ensuite, vous insérez vos données avec un bulk-insert. Cela peut être encore plus rapide si vous utilisez la syntaxe d'insertion de valeurs multiples de MySQL, qui n'est pas prise en charge nativement par SQLAlchemy, mais peut être construite sans trop de difficulté.

INSERT INTO enries_stage (`id`, `value`)
VALUES
(1, 'string1'), (2, 'string2'), (3, 'string3'), ...;

Au final, vous mettez à jour les valeurs de la destination-table avec les valeurs de la stage-table comme ceci :

 UPDATE entries e
 JOIN entries_stage es ON e.id = es.id
 SET e.value = es.value;

Ensuite, vous avez terminé.

Qu'en est-il des encarts ?

Cela fonctionne également pour accélérer les insertions bien sûr. Comme vous avez déjà les données dans le stage-table , tout ce que vous avez à faire est d'émettre un INSERT INTO ... SELECT déclaration, avec les données qui ne sont pas dans destination-table encore.

INSERT INTO entries (id, value)
SELECT FROM entries_stage es
LEFT JOIN entries e ON e.id = es.id
HAVING e.id IS NULL;

La bonne chose à ce sujet est que vous n'avez pas à faire INSERT IGNORE , REPLACE ou ON DUPLICATE KEY UPDATE , qui incrémentera votre clé primaire, même si elles ne feront rien .