Un message ici sur dba.stackexchange ( Quelles sont les meilleures pratiques pour les déclencheurs pour maintenir un numéro de révision sur les enregistrements? ) a engendré une question intéressante (du moins, intéressante pour moi) en ce qui concerne la performance dans MySQL.
Le contexte est que nous souhaitons insérer un enregistrement dans une table pour chaque ligne mise à jour. Avant la mise à jour de la ligne, nous souhaitons stocker une valeur précédente, puis incrémenter l'une des colonnes (une colonne "Version").
Si nous le faisons dans un déclencheur, cela fonctionne bien. Pour MySQL, les déclencheurs sont rangée à la ligne , ce serait donc une solution facile. Sélectionnez les données actuellement dans le tableau, insérez-la dans la table de journalisation et la mise à jour de la colonne "Version" dans les nouvelles données.
Cependant, il est possible de déplacer cette logique à une procédure stockée. Si vous faites cela, vous effectuez l'insert, puis incrémentez la colonne "Version" de la table. Toute la chose serait définie basée.
Donc, lorsqu'il s'agit d'effectuer cet insert, cela serait-il plus performant pour utiliser l'approche de procédure stockée à base d'ensemble ou une approche basée sur la gâchette?
Cette question est destinée à MySQL (puisqu'il a des déclencheurs à ligne à ligne), bien qu'il puisse s'appliquer à d'autres SGDD de déclenchement de ligne à ligne.
Par souci de simplicité, les déclencheurs sont la voie à suivre pour mettre en œuvre tout type de suivi des changements de base de données. Cependant, vous devez être conscient de ce qui se passe sous la cagoule lorsque vous utilisez des déclencheurs.
Selon Programmation de la procédure stockée MySQL , page 256 Sous la tête "Tenghoth Overhead", indique ce qui suit:
Il est important de se rappeler que, par nécessité, des déclencheurs ajoutent des frais généraux à la déclaration DML auxquelles ils s'appliquent. La quantité réelle de frais généraux dépendra de la nature de la gâchette, mais --- Comme tous les déclencheurs MySQL exécutent pour chaque rangée - les frais généraux peuvent s'accumuler rapidement pour des déclarations qui traitent un grand nombre de lignes. Vous devez donc éviter de placer des déclarations de SQL coûteuses ou du code de procédure dans les déclencheurs.
Une explication élargie des frais de déclenchement est donnée aux pages 529-531. Le point de conclusion de cette section indique les éléments suivants:
La leçon ici est la suivante: puisque le code de déclenchement exécutera une fois pour chaque ligne affectée par une instruction DML, la gâchette peut facilement devenir le facteur le plus important dans la performance DML. Le code à l'intérieur de l'organisme de déclenchement doit être aussi léger que possible et - en particulier - toute instruction SQL dans la gâchette doit être prise en charge par des index dans la mesure du possible.
Non mentionné dans le livre est un autre facteur lorsque vous utilisez des déclencheurs: en ce qui concerne la journalisation d'audit, soyez conscient de ce que vous enregistrez les données. Je dis cela parce que vous devez choisir de vous connecter à une table myisam, chaque insertion dans une table Myisam produit une serrure de table complète pendant l'insert. Cela peut devenir un goulot d'étranglement sérieux dans un environnement de grande transaction élevé. De plus, si la gâchette est contre une table InnoDb et que vous connectez des modifications de Myisam à partir de la gâchette, cela désactivait secrètement la conformité des acides (c'est-à-dire réduire les transactions de blocs au comportement automatique), ce qui n'est pas impossible de roulement.
Lorsque vous utilisez des déclencheurs sur des tables innovées et des changements de journalisation
De cette manière, les journaux d'audit peuvent bénéficier de validation/de restauration, tout comme les tables principales.
En ce qui concerne l'utilisation de procédures stockées, vous devez appeler minutieusement la procédure stockée à chaque point de DML contre la table suivie. On pourrait facilement manquer des changements de journalisation face aux dizaines de milliers de lignes de code d'application. Placer ce code dans une gâchette élimine la recherche de toutes ces déclarations DML.
CAVEAT
En fonction de la complexité de la gâchette, cela peut encore être un goulot d'étranglement. Si vous souhaitez réduire les goulots d'étranglement dans la journalisation d'audit, vous pouvez faire quelque chose. Cependant, cela nécessitera un peu de changement d'infrastructure.
Utilisation du matériel de base, créez deux autres serveurs de DB
Cela permettra au serveur de réduire l'écriture d'E/S sur la base de données principale (MD) en raison de la journalisation d'audit. Voici comment vous pouvez y accomplir:
Étape 01) Activez la journalisation binaire dans la base de données principale.
Étape 02) Utilisation d'un serveur peu coûteux, SETUP MYSQL (la même version que MD) avec la journalisation binaire activée. Ce sera DM. Réplication de configuration de MD à DM.
Étape 03) Utilisation d'un second serveur peu coûteux, configuration MySQL (la même version que MD) avec la journalisation binaire désactivée. Configurez chaque table d'audit à utiliser - Replicat-do-table . Ce sera au. Réplication de configuration de DM à l'UA.
Étape 04) MySqldump Les structures de table de MD et le chargent en DM et AU.
Étape 05) Convertir toutes les tables d'audit dans MD pour utiliser le moteur de stockage Blackhole
Étape 06) Convertir toutes les tables in DM et AU pour utiliser le moteur de stockage Blackhole
Étape 07) Convertissez toutes les tables d'audit en UA pour utiliser le moteur de stockage MyISAM
Lorsque vous avez terminé
Ce que cela ne stocke stocke des informations d'audit sur un serveur DB distinct et réduisez également toute dégradation d'E/S écriture que MD aurait normalement.
Voici une approche pour effectuer cette mise à jour en vrac.
Pour cet exemple
Pour créer TABLY_A_KEYS2UPDATE, procédez comme suit:
CREATE TABLE table_A_Keys2Update SELECT id FROM table_A;
ALTER TABLE table_A_Keys2Update ADD PRIMARY KEY (id);
Après avoir peuplé de table_a_keys2update avec les ID dont le numéro de révision doit être incrémenté, effectuez la jette de mise à jour suivante Joindre à l'incrément de révision Numéro de toutes les lignes dont l'ID est dans Table_a et Table_A_Keys2UPDate:
UPDATE table_A A INNER JOIN table_A_Keys2Update B USING (id)
SET A.revision = A.revision + 1;
Cette requête d'une ligne peut remplacer une gâchette et une procédure stockée.
En option, vous pouvez placer cette question dans une procédure stockée et l'appeler si vous le souhaitez.