Das Binärlog enthält Informationen über SQL-Anweisungen, die Datenbankinhalte ändern. Diese Informationen werden in Form von „Ereignissen“ gespeichert, welche die Modifikationen beschreiben. Das Binärlog dient zwei wichtigen Zwecken:
Für die Replikation sendet der Master-Server die Ereignisse, die in seinem Binärlog stehen, an seine Slaves. Diese führen die Ereignisse dann aus, um die Datenänderungen nachzuvollziehen, die auf dem Master stattgefunden haben. Siehe Abschnitt 6.2, „Replikation: Implementation“.
Für bestimmte Datenwiederherstellungsoperationen muss das Binärlog genutzt werden. Nach der Wiederherstellung einer Sicherungsdatei werden aus dem Binärlog die Ereignisse, die nach Erstellung der Sicherungsdatei eintraten, erneut ausgeführt. Diese Ereignisse bringen die Datenbank von dem Zeitpunkt der Sicherung auf den neuesten Stand. Siehe auch Abschnitt 5.10.2.2, „Verwenden von Datensicherungen zur Wiederherstellung“.
Dieser Abschnitt beschreibt, wie MySQL 5.1 das Binärlogging für gespeicherte Routinen (Prozeduren und Funktionen) und Trigger behandelt. Es wird beschrieben, welche Bedingungen die Implementierung zurzeit an die Verwendung gespeicherter Routinen knüpft, und diese Bedingungen werden auch begründet.
Die hier beschriebenen Probleme gründen im Wesentlichen auf die Tatsache, dass Binärlogging auf SQL-Anweisungsebene stattfindet. In einem künftigen Release von MySQL soll auch Binärlogging auf Zeilenebene eingeführt werden, wobei die Änderungen protokolliert werden, die bei der Ausführung von SQL-Anweisungen in den einzelnen Zeilen stattfinden.
Soweit nichts anderes gesagt wird, gehen wir in den nachfolgenden
Bemerkungen davon aus, dass Sie Binärlogging durch Hochfahren des
Servers mit der Option --log-bin
eingeschaltet
haben. (Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.) Wenn das
Binärlog nicht eingeschaltet ist, ist weder eine Replikation
möglich noch steht das Binärlog für die Wiederherstellung von
Daten zur Verfügung.
Die derzeit gültigen Bedingungen für die Nutzung gespeicherter Funktionen in MySQL 5.1 werden im Folgenden zusammengefasst. Diese Bedingungen gelten nicht für gespeicherte Prozeduren, und sie gelten auch ansonsten nur dann, wenn das Binärlogging auch eingeschaltet ist.
Um eine gespeicherte Funktion anzulegen oder zu ändern,
benötigen Sie das SUPER
-Recht zusätzlich
zu dem normalerweise erforderlichen CREATE
ROUTINE
- oder ALTER
ROUTINE
-Recht.
Wenn Sie eine gespeicherte Funktion erstellen, müssen Sie sie entweder als deterministisch deklarieren oder festlegen, dass sie keine Daten modifiziert. Andernfalls kann sie für die Datenwiederherstellung oder Replikation Unsicherheiten bergen.
Zur Lockerung der obigen Bedingungen für die Erstellung einer
Funktion (obligatorisches SUPER
-Recht und
das Erfordernis, entweder eine deterministische Funktion oder
eine Funktion, die keine Daten ändert, zu deklarieren)
können Sie die globale Systemvariable
log_bin_trust_function_creators
auf 1
setzen. Diese Variable hat den Standardwert 0, lässt sich
aber folgendermaßen umstellen:
mysql> SET GLOBAL log_bin_trust_function_creators = 1;
Sie können diese Variable auch einstellen, indem Sie beim
Starten des Servers die Option
--log-bin-trust-function-creators
einstellen.
Wenn Binärlogging nicht aktiviert ist, ist
log_bin_trust_function_creators
unwirksam
und das SUPER
-Recht ist nicht erforderlich,
um eine Funktion anzulegen.
Da Trigger gespeicherten Funktionen ähneln, gelten diese
Ausführungen zu Funktionen auch für Trigger, allerdings mit der
folgenden Einschränkung: Da CREATE TRIGGER
kein optionales DETERMINISTIC
-Merkmal hat, geht
man davon aus, dass Trigger immer deterministisch sind. Doch diese
Grundannahme muss nicht immer gelten. So ist beispielsweise die
Funktion UUID()
nichtdeterministisch (und wird
auch nicht repliziert). Solche Funktionen sollten Sie in Triggern
nur mit Vorsicht benutzen.
Da Trigger Tabellen ändern können, kommen im Zusammenhang mit
CREATE TRIGGER
ähnliche Fehlermeldungen wie
bei gespeicherten Funktionen vor, wenn Sie nicht das
SUPER
-Recht haben und
log_bin_trust_function_creators
den Wert 0 hat.
Im Folgenden erfahren Sie mehr über die Logging-Implementierung und ihre Implikationen.
Der Server schreibt CREATE PROCEDURE
-,
CREATE FUNCTION
-, ALTER
PROCEDURE
-, ALTER FUNCTION
-,
DROP PROCEDURE
- und DROP
FUNCTION
-Anweisungen in das Binärlog.
Der Aufruf einer gespeicherten Funktion wird als
DO
-Anweisung protokolliert, wenn die
Funktion Daten ändert und in einer Anweisung auftritt, die
ansonsten nicht protokolliert würde. Dadurch wird verhindert,
dass Datenänderungen, die durch die Verwendung von
gespeicherten Funktionen in nichtprotokollierten Anwendungen
auftreten, nicht repliziert werden. So werden beispielsweise
SELECT
-Anweisungen nicht in das Binärlog
geschrieben, aber ein SELECT
kann eine
gespeicherte Funktion aufrufen, die Datenänderungen
hervorruft. Um damit umzugehen, wird eine DO
-Anweisung in
das Binärlog geschrieben, wenn die Funktion eine Änderung
vornimmt. Angenommen, folgende Funktionen werden auf dem
Master ausgeführt:
func_name
()
CREATE FUNCTION f1(a INT) RETURNS INT BEGIN IF (a < 3) THEN INSERT INTO t2 VALUES (a); END IF; END; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); SELECT f1(a) FROM t1;
Wenn die SELECT
-Anweisung ausgeführt wird,
wird die Funktion f1()
dreimal aufgerufen.
Zwei der Aufrufe fügen eine Zeile ein und MySQL schreibt für
jede von ihnen eine DO
-Anweisung in das
Log. Somit hält MySQL folgende Anweisungen im Binärlog fest:
DO f1(1); DO f1(2);
Der Server protokolliert auch eine
DO
-Anweisung für einen Aufruf einer
gespeicherten Funktion, wenn die Funktion eine gespeicherte
Prozedur aufruft, die einen Fehler verursacht. In diesem Fall
schreibt der Server die DO
-Anweisung
zusammen mit dem erwarteten Fehlercode in das Log. Wenn auf
dem Slave derselbe Fehler auftritt, ist dies das erwartete
Resultat und die Replikation läuft weiter. Andernfalls bricht
die Replikation ab.
Wenn anstelle von Anweisungen, die eine Funktion ausführt, Aufrufe gespeicherter Funktionen protokolliert werden, hat dies Folgen für die Sicherheit der Replikation. Dafür sind zwei Faktoren verantwortlich:
Es ist möglich, dass eine Funktion auf dem Master und den Slave-Servern unterschiedliche Ausführungspfade einschlägt.
Anweisungen, die auf einem Slave ausgeführt werden, werden von dem SQL-Thread des Slaves verarbeitet, der volle Berechtigungen hat.
Die Folge davon ist, dass zwar jeder Benutzer für die
Erstellung einer Funktion das CREATE
ROUTINE
-Recht benötigt. Doch damit könnte er eine
Funktion schreiben, die eine gefährliche Anweisung enthält,
die nur auf dem Slave ausgeführt wird, da sie dort von dem
SQL-Thread ausgeführt wird, der über volle Berechtigungen
verfügt. Wenn beispielsweise der Master-Server die Server-ID
1 und der Slave-Server die Server-ID 2 hätte, könnte ein
Benutzer auf dem Master-Server eine unsichere Funktion namens
unsafe_func()
folgendermaßen erstellen und
aufrufen:
mysql>delimiter //
mysql>CREATE FUNCTION unsafe_func () RETURNS INT
->BEGIN
->IF @@server_id=2 THEN
->dangerous_statement
; END IF;RETURN 1;
->END;
->//
mysql>delimiter ;
mysql>INSERT INTO t VALUES(unsafe_func());
Da die CREATE FUNCTION
- und die
INSERT
-Anweisung in das Binärlog
geschrieben werden, führt der Slave sie aus. Und da der
Slave-SQL-Thread wiederum über so umfassende Berechtigungen
verfügt, wird er die gefährliche Anweisung auch befolgen.
Somit hat der Funktionsaufruf auf dem Master andere Folgen als
auf dem Slave und ist nicht replikationssicher.
Um Server, auf denen das Binärlogging eingeschaltet ist, vor
dieser Gefahr zu schützen, benötigen die Erzeuger
gespeicherter Funktionen zusätzlich zu dem üblichen
CREATE ROUTINE
-Recht, das ohnehin notwendig
ist, auch das SUPER
-Recht. Ebenso darf
ALTER FUNCTION
nur benutzen, wer
zusätzlich zu dem ALTER ROUTINE
-Recht auch
das SUPER
-Recht besitzt. Fehlt die
SUPER
-Berechtigung, wird ein Fehler
ausgelöst:
ERROR 1419 (HY000): You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
Wenn Sie von den Erzeugern von Funktionen nicht verlangen
möchten, dass sie das SUPER
-Recht besitzen
(zum Beispiel, wenn in Ihrem System alle Benutzer, die das
CREATE ROUTINE
-Recht haben, erfahrene
Anwendungsentwickler sind), dann können Sie die globale
Systemvariable
log_bin_trust_function_creators
auf 1
setzen. Das können Sie auch tun, indem Sie beim Serverstart
die Option --log-bin-trust-function-creators
einstellen. Wenn kein Binärlogging aktiviert ist, ist
log_bin_trust_function_creators
wirkungslos
und zum Anlegen von Funktionen ist kein
SUPER
-Recht erforderlich.
Wenn eine Funktion, die Änderungen vornimmt, nichtdeterministisch ist, so ist sie auch nicht wiederholbar. Dies kann zwei unangenehme Folgen haben:
Ein Slave entspricht nicht mehr dem Master.
Wiederhergestellte Daten entsprechen nicht mehr den Originaldaten.
Um diese Probleme in den Griff zu bekommen, stellt MySQL folgende Anforderung: Auf einem Master-Server ist die Erzeugung und Änderung einer Funktion nur möglich, wenn diese als deterministisch deklariert ist oder keine Daten ändert. Hierbei kommen zwei Arten von Funktionsmerkmalen ins Spiel:
Die Merkmale DETERMINISTIC
und
NOT DETERMINISTIC
zeigen an, ob eine
Funktion für dieselben Eingabewerte auch immer dieselben
Ergebnisse produziert. Da die Standardeinstellung, wenn
nichts anderes angegeben wird, NOT
DETERMINISTIC
lautet, müssen Sie explizit das
Merkmal DETERMINISTIC
angeben, um
klarzustellen, dass eine Funktion deterministisch ist.
Durch Verwendung der Funktion NOW()
(oder ihrer Synonyme) oder RAND()
wird
eine Funktion nicht unbedingt deterministisch. Für
NOW()
zeichnet das Binärlog den
Zeitstempel auf und repliziert richtig. Die Funktion
RAND()
repliziert ebenfalls korrekt,
sofern sie in einer Funktion nicht mehrmals aufgerufen
wird. (Den Ausführungs-Zeitstempel der Funktion und den
Zufallszahlen-Seedwert können Sie als implizite Eingaben
betrachten, die bei Master und Slave identisch sind.)
Die Merkmale CONTAINS SQL
, NO
SQL
, READS SQL DATA
und
MODIFIES SQL DATA
geben Informationen
darüber, ob die Funktion Daten liest oder schreibt.
NO SQL
oder READS SQL
DATA
zeigt an, dass eine Funktion keine Daten
ändert, aber Sie müssen eines dieser Merkmale explizit
angeben, da ansonsten der Standardwert CONTAINS
SQL
ist.
Damit eine CREATE FUNCTION
-Anweisung
akzeptiert wird, muss nach Voreinstellung
DETERMINISTIC
bzw. entweder NO
SQL
oder READS SQL DATA
explizit
angegeben werden. Andernfalls tritt ein Fehler auf:
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
Wenn Sie log_bin_trust_function_creators
auf 1 setzen, wird nicht mehr gefordert, dass Funktionen
entweder deterministisch sind oder keine Daten ändern.
Wie die Natur einer Funktion eingeschätzt wird, hängt von
der „Ehrlichkeit“ ihres Erzeugers ab: MySQL
prüft nicht, ob eine als DETERMINISTIC
deklarierte Funktion auch tatsächlich keine Anweisungen
enthält, die nichtdeterministische Ergebnisse produzieren.
Aufrufe an gespeicherte Prozeduren werden auf Anweisungs-
statt auf CALL
-Ebene protokolliert. Das
bedeutet, dass der Server nicht die
CALL
-Anweisung protokolliert, sondern
diejenigen Anweisungen der Prozedur, die tatsächlich
ausgeführt werden. Dadurch treten auf den Slave-Servern
dieselben Änderungen wie auf dem Master ein. So werden
Probleme vermieden, die entstehen könnten, wenn eine Prozedur
auf verschiedenen Rechnern verschiedene Ausführungspfade hat.
Im Allgemeinen werden Anweisungen, die in einer gespeicherten Prozedur ausgeführt werden, nach denselben Regeln in das Binärlog geschrieben, die auch für eigenständig ausgeführte Anweisungen gelten. Die Protokollierung von Prozeduranweisungen wird besonders vorsichtig gehandhabt, da die Ausführung von Anweisungen innerhalb einer Prozedur nicht dasselbe ist wie außerhalb einer Prozedur:
Eine zu protokollierende Anweisung könnte Verweise auf lokale Prozedurvariablen enthalten. Da diese Variablen außerhalb des Prozedurkontextes gar nicht vorhanden sind, kann eine Anweisung, die eine solche Variable benutzt, nicht wörtlich protokolliert werden. Stattdessen wird für das Log jede Referenz auf eine lokale Variable durch das folgende Konstrukt ersetzt:
NAME_CONST(var_name
,var_value
)
var_name
ist der Name der
lokalen Variablen und var_value
eine Konstante, die den Wert der Variablen zum Zeitpunkt
der Protokollierung der Anweisung anzeigt.
NAME_CONST()
hat den Wert
var_value
und den
„Namen“ var_name
.
Somit erhalten Sie folgendes Ergebnis, wenn Sie diese
Funktion direkt aufrufen:
mysql> SELECT NAME_CONST('myname', 14);
+--------+
| myname |
+--------+
| 14 |
+--------+
NAME_CONST()
ermöglicht es, eine
selbstständige Anweisung auf einem Slave so auszuführen,
dass sie denselben Effekt hat wie die Originalanweisung,
die innerhalb einer gespeicherten Prozedur auf dem
Master-Server ausgeführt wurde.
Eine zu protokollierende Anweisung könnte Referenzen auf
benutzerdefinierte Variablen enthalten. Also schreibt
MySQL eine SET
-Anweisung in das
Binärlog, um zu gewährleisten, dass die Variable auf dem
Slave mit demselben Wert wie auf dem Master existiert.
Wenn beispielsweise eine Anweisung die Variable
@my_var
benutzt, steht vor dieser
Anweisung im Binärlog folgende Anweisung, wobei
value
der Wert ist, den
@my_var
auf dem Master hat:
SET @my_var = value
;
Prozeduraufrufe können in einer committeten oder
zurückgerollten Transaktion auftreten. Früher wurden
CALL
-Anweisungen auch dann
protokolliert, wenn sie in einer zurückgerollten
Transaktion vorkamen. Seit MySQL 5.0.12 wird der
Transaktionskontext berücksichtigt, sodass die
transaktionsbedingten Aspekte der Prozedurausführung
korrekt repliziert werden. Das bedeutet, dass der Server
in der Prozedur nur diejenigen Anweisungen protokolliert,
die auch tatsächlich ausgeführt werden und Daten
ändern. Nach Bedarf protokolliert er darüber hinaus auch
BEGIN
-, COMMIT
- und
ROLLBACK
-Anweisungen. Wenn
beispielsweise eine Prozedur nur Transaktionstabellen
ändert und innerhalb einer Transaktion ausgeführt wird,
die zurückgerollt wird, werden solche Änderungen nicht
ins Log geschrieben. Tritt die Prozedur hingegen in einer
committeten Transaktion auf, werden
BEGIN
- und
COMMIT
-Anweisungen mit den Updates
protokolliert. Die Anweisungen einer in einer
zurückgerollten Transaktion ausgeführten Prozedur werden
nach denselben Regeln protokolliert, die auch gelten
würden, wenn die Anweisungen selbstständig ausgeführt
worden wären:
Änderungen an Transaktionstabellen werden nicht protokolliert.
Änderungen an anderen Tabellen werden protokolliert, weil sie durch ein Rollback nicht rückgängig gemacht werden.
Änderungen an einem Mix von Transaktionstabellen und
anderen Tabellen werden innerhalb eines
BEGIN
-ROLLBACK
Blocks protokolliert, damit die Slaves dieselben
Änderungen und Rollbacks wie der Master vornehmen.
Ein Aufruf einer gespeicherten Prozedur wird
nicht auf Anweisungsebene in das
Binärlog geschrieben, wenn die Prozedur innerhalb einer
gespeicherten Funktion aufgerufen wird. In einem solchen Fall
wird lediglich die Anweisung protokolliert, welche die
Funktion aufruft, (wenn diese innerhalb einer protokollierten
Anweisung benutzt wird), oder eine
DO
-Anweisung (wenn sie in einer Anweisung
benutzt wird, die nicht protokolliert wird). Daher sollten Sie
vorsichtig mit gespeicherten Funktionen sein, die eine
Prozedur aufrufen, selbst wenn die Prozedur ansonsten sicher
ist.
Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.