Esecuzione di un trigger rispetto a una stored procedure in MySQL


11

Un post qui su DBA.StackExchange ( Quali sono le migliori pratiche per i trigger per mantenere un numero di revisione sui record? ) Ha generato una domanda interessante (almeno, interessante per me) per quanto riguarda le prestazioni in MySQL.

Il contesto è che vogliamo inserire un record in una tabella per ogni riga che viene aggiornata. Prima di aggiornare la riga, vogliamo memorizzare un valore precedente e quindi incrementare una delle colonne (una colonna "versione").

Se lo facciamo all'interno di un trigger, funziona bene. Per MySQL, i trigger sono riga per riga , quindi sarebbe una soluzione semplice. Selezionare i dati attualmente nella tabella, inserirli nella tabella di registrazione e aggiornare la colonna "versione" nei nuovi dati.

Tuttavia, è possibile spostare questa logica in una stored procedure. Se lo fai, stai eseguendo l'inserimento, quindi incrementando la colonna "versione" nella tabella. L'intera cosa verrebbe impostata in base.

Quindi, quando si tratta di eseguire questo inserto, sarebbe più efficace utilizzare l'approccio basato su set di procedure memorizzate o un approccio basato su trigger?

Questa domanda è per MySQL (dal momento che ha trigger riga per riga), sebbene possa applicarsi ad altri DBMS trigger riga per riga.


1
Una cosa da tenere a mente per quanto riguarda l'inoltro della logica di controllo delle versioni a una procedura memorizzata: quanto sarà complicato quando qualcuno, in qualche modo, scrive direttamente sul tavolo bypassando il meccanismo di controllo?
billinkc,

Sono d'accordo. Ma dall'altra parte della scala, forse si desidera bypassare intenzionalmente questa registrazione in determinate circostanze. Certo, questa è una domanda completamente diversa . Sono davvero solo curioso delle implicazioni sulle prestazioni.
Richard,

Risposte:


7

Per semplicità, i trigger sono la strada da percorrere per implementare qualsiasi tipo di tracciamento delle modifiche al database. Tuttavia, è necessario essere consapevoli di ciò che accade sotto il cofano quando si utilizzano i trigger.

Secondo MySQL Stored Procedure Programming , la pagina 256 sotto la voce "Trigger Overhead" dice quanto segue:

È importante ricordare che, per necessità, i trigger generano un sovraccarico dell'istruzione DML a cui si applicano. la quantità effettiva di overhead dipenderà dalla natura del trigger, ma --- poiché tutti i trigger MySQL vengono eseguiti PER OGNI FILA --- l'overhead può accumularsi rapidamente per le istruzioni che elaborano un numero elevato di righe. Dovresti quindi evitare di inserire costose istruzioni SQL o codici procedurali nei trigger.

Una spiegazione estesa del sovraccarico del trigger è riportata alle pagine 529-531. Il punto di conclusione di quella sezione indica quanto segue:

La lezione qui è questa: poiché il codice trigger verrà eseguito una volta per ogni riga interessata da un'istruzione DML, il trigger può facilmente diventare il fattore più significativo nelle prestazioni DML. Il codice all'interno del corpo del trigger deve essere il più leggero possibile e, in particolare, qualsiasi istruzione SQL nel trigger deve essere supportata da indici ogni volta che è possibile.

Non menzionato nel libro è un altro fattore quando si usano i trigger: quando si tratta della registrazione di controllo, si prega di essere consapevoli di ciò in cui si accedono i dati. Dico questo perché se dovessi scegliere di accedere a una tabella MyISAM, ogni INSERT in una tabella MyISAM produce un blocco completo della tabella durante INSERT. Questo può diventare un serio collo di bottiglia in un ambiente ad alto traffico e transazioni elevate. Inoltre, se il trigger si trova su una tabella InnoDB e si registrano le modifiche in MyISAM dall'interno del trigger, ciò disabiliterà segretamente la conformità ACID (ovvero, ridurrà le transazioni di blocco al comportamento di autocommit), che non può essere ripristinato.

Quando si usano i trigger su tabelle InnoDB e si registrano le modifiche

  • La tabella a cui accedi è anche InnoDB
  • L'autocommit è disattivato
  • Configura a fondo i blocchi INIZIA TRANSAZIONE ... COMMIT / ROLLBACK

In questo modo, i registri di controllo possono beneficiare di COMMIT / ROLLBACK come le tabelle principali.

Per quanto riguarda l'utilizzo delle stored procedure, è necessario chiamare scrupolosamente la stored procedure in ogni punto del DML rispetto alla tabella da tracciare. Si potrebbero facilmente perdere le modifiche alla registrazione di fronte a decine di migliaia di righe di codice dell'applicazione. Inserire tale codice in un trigger elimina la ricerca di tutte quelle istruzioni DML.

AVVERTIMENTO

A seconda della complessità del trigger, può comunque essere un collo di bottiglia. Se si desidera ridurre i colli di bottiglia nella registrazione di controllo, è possibile fare qualcosa. Tuttavia, richiederà un piccolo cambiamento di infrastruttura.

Utilizzando l'hardware delle materie prime, creare altri due server DB

Questo servirà a ridurre l'I / O di scrittura sul database principale (MD) a causa della registrazione di controllo. Ecco come puoi realizzarlo:

Passaggio 01) Attiva la registrazione binaria nel database principale.

Passaggio 02) Utilizzando un server economico, configurare MySQL (stessa versione di MD) con la registrazione binaria abilitata. Questo sarà DM. Replica dell'installazione da MD a DM.

Passaggio 03) Utilizzando un secondo server economico, configurare MySQL (stessa versione di MD) con la registrazione binaria disabilitata. Imposta ogni tabella di controllo per usare --replicate-do-table . Questo sarà AU. Replica dell'installazione da DM a AU.

Step 04) mysqldump le strutture della tabella da MD e caricale in DM e AU.

Passaggio 05) Convertire tutte le tabelle di controllo in MD per utilizzare il motore di archiviazione BLACKHOLE

Passaggio 06) Convertire tutte le tabelle in DM e AU per utilizzare il motore di archiviazione BLACKHOLE

Passaggio 07) Convertire tutte le tabelle di controllo in AU per utilizzare il motore di archiviazione MyISAM

Quando fatto

  • DM replicherà da MD e registrerà le cose solo nel suo registro binario
  • Con il filtro --replicate-do-table su tutte le tabelle di controllo, AU si replicherà da DM

Ciò che fa è archiviare le informazioni di controllo su un server DB separato e ridurre anche qualsiasi degrado di I / O in scrittura che MD avrebbe normalmente.


Risposta eccezionale +++ 1
b_dubb

1

Ecco un approccio per eseguire questo aggiornamento in blocco.

Per questo esempio

  • table_A ha un ID PRIMARY KEY
  • Si crea una tabella denominata table_A_Keys2Update con solo id come PRIMARY KEY
  • Popoli table_A_Keys2Update con gli ID di table_A che sai che devono essere aggiornati

Per creare table_A_Keys2Update, procedi come segue:

CREATE TABLE table_A_Keys2Update SELECT id FROM table_A;
ALTER TABLE table_A_Keys2Update ADD PRIMARY KEY (id);

Dopo aver popolato table_A_Keys2Update con gli ID il cui numero di revisione deve essere incrementato, eseguire il seguente UPDATE JOIN per incrementare il numero di revisione di tutte le righe il cui ID è sia in table_A che table_A_Keys2Update:

UPDATE table_A A INNER JOIN table_A_Keys2Update B USING (id)
SET A.revision = A.revision + 1;

Questa query a una riga può sostituire un trigger e una stored procedure.

Facoltativamente, è possibile inserire questa query in una stored procedure e chiamarla se lo si desidera.


È davvero l'inserto di cui sono curioso. Se INSERISCI IN Audit SELEZIONA <qualunque> DA <primary_table> DOVE <parametri dalla procedura memorizzata> puoi eseguire l'inserimento in blocco. Nel trigger, dovresti semplicemente INSERIRE IN VALORI di controllo <dati dalla riga aggiornata> . Quindi, l'inserto a riga singola, riga per riga, sarebbe più veloce dell'inserto bulk?
Richard,

Per semplicità, il trigger sarebbe molto meglio 1) a condizione che la tabella principale non abbia mai avuto inserimenti di massa nel mezzo di qualsiasi ora di punta, 2) le informazioni di controllo devono essere lette su richiesta in qualsiasi momento e 3) il tuo sito è a basso traffico.
RolandoMySQLDBA,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.