Performances d'un déclencheur par rapport à une procédure stockée dans MySQL

11

Un article 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 suscité une question intéressante (au moins, intéressante pour moi) concernant les performances dans MySQL.

Le contexte est que nous voulons insérer un enregistrement dans une table pour chaque ligne mise à jour. Avant la mise à jour de la ligne, nous voulons stocker une valeur précédente, puis incrémenter une des colonnes (une colonne "version").

Si nous le faisons à l'intérieur d'un déclencheur, cela fonctionne bien. Pour MySQL, les déclencheurs sont ligne par ligne , donc ce serait une solution facile. Sélectionnez les données actuellement dans la table, insérez-les dans la table de journalisation et mettez à jour la colonne "version" dans les nouvelles données.

Cependant, il est possible de déplacer cette logique vers une procédure stockée. Si vous faites cela, vous effectuez l'insertion, puis incrémentez la colonne "version" dans le tableau. Le tout serait réglé en fonction.

Donc, quand il s'agit de réaliser cet insert, cela serait-il plus performant d'utiliser l'approche de procédure stockée basée sur un ensemble ou une approche basée sur un déclencheur?

Cette question est pour MySQL (car il a des déclencheurs ligne par ligne), bien qu'elle puisse s'appliquer à d'autres SGBD de déclenchement ligne par ligne.

Richard
la source
1
Une chose à garder à l'esprit en ce qui concerne le transfert de la logique de gestion des versions à une procédure stockée - à quel point allez-vous être bossé quand quelqu'un, d'une manière ou d'une autre, écrit directement sur la table en contournant votre mécanisme d'audit?
billinkc
Je suis d'accord. Mais à l'autre bout de l'échelle, vous pouvez peut-être contourner intentionnellement cette journalisation dans certaines circonstances. Bien sûr, c'est une question entièrement différente . Je suis vraiment curieux de connaître les implications en termes de performances.
Richard

Réponses:

7

Dans un souci de simplicité, les déclencheurs sont la voie à suivre pour implémenter tout type de suivi des modifications de la base de données. Cependant, vous devez être conscient de ce qui se passe sous le capot lorsque vous utilisez des déclencheurs.

Selon MySQL Stored Procedure Programming , la page 256 sous la rubrique "Trigger Overhead" dit ce qui suit:

Il est important de se rappeler que, par nécessité, les déclencheurs ajoutent une surcharge à l'instruction DML à laquelle ils s'appliquent. la quantité réelle de surcharge dépendra de la nature du déclencheur, mais --- comme tous les déclencheurs MySQL s'exécutent POUR CHAQUE RANG --- la surcharge peut rapidement s'accumuler pour les instructions qui traitent un grand nombre de lignes. Vous devez donc éviter de placer des instructions SQL ou du code procédural coûteux dans les déclencheurs.

Une explication détaillée de la surcharge de déclenchement est donnée aux pages 529-531. Le point de conclusion de cette section indique ce qui suit:

La leçon à tirer est la suivante: étant donné que le code de déclenchement s'exécutera une fois pour chaque ligne affectée par une instruction DML, le déclencheur peut facilement devenir le facteur le plus important des performances DML. Le code à l'intérieur du corps du déclencheur doit être aussi léger que possible et - en particulier - toutes les instructions SQL dans le déclencheur doivent être prises en charge par des index chaque fois que possible.

Non mentionné dans le livre est un autre facteur lors de l'utilisation de déclencheurs: en ce qui concerne la journalisation d'audit, veuillez être conscient de ce dans quoi vous vous connectez. Je dis cela parce que si vous choisissez de vous connecter à une table MyISAM, chaque INSERT dans une table MyISAM produit un verrou de table complet pendant l'insertion. Cela peut devenir un goulot d'étranglement sérieux dans un environnement à trafic élevé et à transactions élevées. De plus, si le déclencheur est contre une table InnoDB et que vous enregistrez les modifications dans MyISAM à partir du déclencheur, cela désactivera secrètement la conformité ACID (c'est-à-dire, réduira les transactions de bloc au comportement de validation automatique), qui ne peut pas être annulée.

Lors de l'utilisation de déclencheurs sur des tables InnoDB et des modifications de journalisation

  • La table à laquelle vous vous connectez est également InnoDB
  • Vous avez désactivé la validation automatique
  • Vous configurez soigneusement les blocs START TRANSACTION ... COMMIT / ROLLBACK

De cette façon, les journaux d'audit peuvent bénéficier de COMMIT / ROLLBACK comme les tables principales.

En ce qui concerne l'utilisation des procédures stockées, vous devrez appeler minutieusement la procédure stockée à chaque point de DML par rapport à la table en cours de suivi. On pourrait facilement manquer des changements de journalisation face à des dizaines de milliers de lignes de code d'application. Placer un tel code dans un déclencheur élimine la recherche de toutes ces instructions DML.

CAVEAT

Selon la complexité du déclencheur, il peut toujours s'agir d'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 petit changement d'infrastructure.

En utilisant du matériel standard, créez deux autres serveurs DB

Cela servira à réduire les E / S d'écriture sur la base de données principale (MD) en raison de la journalisation d'audit. Voici comment vous pouvez y parvenir:

Étape 01) Activez la journalisation binaire dans la base de données principale.

Étape 02) À l'aide d'un serveur peu coûteux, configurez MySQL (même version que MD) avec la journalisation binaire activée. Ce sera DM. Configurez la réplication de MD vers DM.

Étape 03) À l'aide d'un deuxième serveur peu coûteux, configurez MySQL (même version que MD) avec la journalisation binaire désactivée. Configurez chaque table d'audit pour utiliser --replicate-do-table . Ce sera AU. Configurez la réplication de DM vers AU.

Étape 04) mysqldump les structures de table de MD et chargez-les dans DM et AU.

Étape 05) Convertissez toutes les tables d'audit dans MD pour utiliser le moteur de stockage BLACKHOLE

Étape 06) Convertissez toutes les tables en DM et AU pour utiliser le moteur de stockage BLACKHOLE

Étape 07) Convertissez toutes les tables d'audit en AU pour utiliser le moteur de stockage MyISAM

Lorsque vous avez terminé

  • DM répliquera à partir du MD et enregistrera les éléments dans son journal binaire uniquement
  • Avec le filtre --replicate-do-table sur toutes les tables d'audit, AU répliquera à partir de DM

Cela permet de stocker les informations d'audit sur un serveur de base de données distinct et de réduire également toute dégradation des E / S d'écriture que MD aurait normalement.

RolandoMySQLDBA
la source
Réponse énorme +++ 1
b_dubb
1

Voici une approche pour effectuer cette mise à jour en masse.

Pour cet exemple

  • table_A a un identifiant PRIMARY KEY
  • Vous créez une table appelée table_A_Keys2Update avec juste id comme PRIMARY KEY
  • Vous remplissez table_A_Keys2Update avec les identifiants de table_A dont vous savez qu'ils doivent être mis à jour

Pour créer table_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 rempli table_A_Keys2Update avec les identifiants dont le numéro de révision doit être incrémenté, effectuez la mise à jour UPDATE JOIN suivante pour incrémenter le numéro de révision de toutes les lignes dont l'ID se trouve à la fois 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 un déclencheur et une procédure stockée.

Facultativement, vous pouvez placer cette seule requête dans une procédure stockée et l'appeler si vous le souhaitez.

RolandoMySQLDBA
la source
C'est vraiment l'insert qui m'intéresse. Si vous INSÉREZ dans l'audit, sélectionnez SELECT <n'importe quoi> DE <table_principale> OERE <paramètres de la procédure stockée> vous pouvez effectuer l'insertion en bloc. Dans le déclencheur, vous insérez simplement des valeurs d'audit <données de la ligne mise à jour> . Ainsi, l'insertion ligne par ligne serait-elle plus rapide que l'insertion en bloc?
Richard
Par souci de simplicité, le déclencheur serait bien meilleur 1) à condition que la table primaire ne subisse jamais d'insertions groupées au milieu des heures de pointe, 2) les informations d'audit doivent être lues à la demande à tout moment, et 3) votre site est peu fréquenté.
RolandoMySQLDBA