MySQL 5.1 Referenzhandbuch

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.

Copyright 1997-2006 MySQL AB

Diese Dokumentation wird NICHT unter der GPL-Lizenz vertrieben. Die Benutzung dieser Dokumentation unterliegt folgenden Bedingungen: Sie dürfen diese Dokumentation ausschließich für private Zwecke ausdrucken. Eine Umwandlung in andere Formate ist gestattet, solange die ursprünglichen Inhalte nicht verändert oder in sonstiger Weise editiert werden. Sie dürfen diese Dokumentation weder veröffentlichen noch in sonstiger Form auf irgendeinem Medium vertreiben, außer wenn Sie die Dokumentation in ähnlicher Form wie MySQL selbst verteilen (das heißt elektronisch zum Download auf einer Website zusammen mit der Software) oder auf einer CD-ROM oder einem ähnlichen Medium, vorausgesetzt, dass die Dokumentation zusammen mit der Software auf diesem Medium verteilt wird. Jeder sonstige Gebrauch, beispielsweise die Verteilung gedruckter Exemplare, oder die Verwendung dieser Dokumentation in Gänze oder in Teilen in irgendeiner anderen Publikation bedarf der vorherigen schriftlichen Zustimmung eines dazu berechtigten Vertreters von MySQL AB. MySQL AB behält sich sämtliche Rechte an dieser Dokumentation vor, die nicht weiter oben ausdrücklich eingeräumt wurden.

Wenn Sie an weiteren Informationen interessiert sind oder eine Übersetzung durchführen wollen, schreiben Sie bitte an .

Zusammenfassung

Das ist das MySQL-Referenzhandbuch. Es dokumentiert MySQL 5.1 bis 5.1.5-alpha.

Dokument erzeugt am: 2006-10-11 (revision: 349)


Inhaltsverzeichnis

Vorwort
1. Allgemeine Informationen über MySQL
1.1. Über dieses Handbuch
1.2. Konventionen in diesem Handbuch
1.3. Was ist MySQL AB?
1.4. Was ist MySQL?
1.4.1. Geschichte von MySQL
1.4.2. Die wichtigsten Features von MySQL
1.4.3. Wie stabil ist MySQL?
1.4.4. Wie groß können MySQL-Tabellen sein?
1.4.5. Jahr-2000-Konformität
1.5. Überblick über das Datenbanksystem MaxDB
1.5.1. Was ist MaxDB?
1.5.2. Geschichte von MaxDB
1.5.3. Features von MaxDB
1.5.4. Lizenzierung und Support
1.5.5. Unterschiede zwischen MaxDB und MySQL
1.5.6. Interoperabilität zwischen MaxDB und MySQL
1.5.7. Links zu MaxDB
1.6. MySQL-Roadmap
1.6.1. Was ist neu in MySQL 5.1?
1.7. Informationsquellen zu MySQL
1.7.1. Die MySQL-Mailinglisten
1.7.2. MySQL-Community-Support in den MySQL-Foren
1.7.3. Unterstützung für die MySQL-Community auf Internet Relay Chat (IRC)
1.8. Wie man Bugs oder Probleme meldet
1.9. Wie kompatibel zum SQL-Standard ist MySQL?
1.9.1. An welche Standards hält sich MySQL?
1.9.2. Auswahl der SQL-Modi
1.9.3. MySQL im ANSI-Modus laufen lassen
1.9.4. MySQL-Erweiterungen zu ANSI SQL92
1.9.5. MySQL: Unterschiede im Vergleich zu ANSI SQL92
1.9.6. Wie MySQL mit Constraints umgeht
2. Installation von MySQL
2.1. Allgemeines zur Installation
2.1.1. Betriebssysteme, die von MySQL unterstützt werden
2.1.2. Welche MySQL-Version Sie benutzen sollten
2.1.3. Woher man MySQL bekommt
2.1.4. Bestätigen der Paketintegrität mittels MD5-Prüfsummen oder GnuPG
2.1.5. Installationslayouts
2.2. Schnelle Standardinstallation von MySQL
2.3. Installation von MySQL unter Windows
2.3.1. Systemvoraussetzungen für Windows
2.3.2. Auswahl eines Installationspakets
2.3.3. Installation von MySQL mit dem automatischen Installer
2.3.4. Verwendung des MySQL-Installations-Assistenten
2.3.5. Verwendung des Konfigurations-Assistenten
2.3.6. Installation von MySQL aus einem Noinstall-Zip-Archiv
2.3.7. Entpacken des Installationsarchivs
2.3.8. Anlegen einer Optionsdatei
2.3.9. Auswahl des MySQL Server-Typs
2.3.10. Erstmaliges Starten des Servers
2.3.11. Starten von MySQL von der Windows-Befehlszeile
2.3.12. Starten von MySQL als Windows-Dienst
2.3.13. Test der MySQL-Installation
2.3.14. Troubleshooting einer MySQL-Installation unter Windows
2.3.15. Upgrade von MySQL unter Windows
2.3.16. MySQL unter Windows im Vergleich zu MySQL unter Unix
2.4. MySQL unter Linux installieren
2.5. Installation von MySQL unter Mac OS X
2.6. Installation von MySQL unter NetWare
2.7. Installation von MySQL auf anderen Unix-ähnlichen Systemen
2.8. Installation der Quelldistribution
2.8.1. Schnellinstallation, Überblick
2.8.2. Typische configure-Optionen
2.8.3. Installation vom Entwicklungs-Source-Tree
2.8.4. Probleme beim Kompilieren?
2.8.5. Anmerkungen zu MIT-pthreads
2.8.6. Windows-Quelldistribution
2.8.7. MySQL-Clients auf Windows kompilieren
2.9. Einstellungen und Tests nach der Installation
2.9.1. Nach der Installation unter Windows durchzuführende Schritte
2.9.2. Schritte nach der Installation unter Unix
2.9.3. Einrichtung der anfänglichen MySQL-Berechtigungen
2.10. MySQL aktualisieren (Upgrade/Downgrade)
2.10.1. Upgrade von MySQL 5.0
2.10.2. Upgrade auf eine andere Architektur
2.11. Downgrade von MySQL
2.12. Betriebssystemspezifische Anmerkungen
2.12.1. Linux (alle Linux-Versionen)
2.12.2. Anmerkungen zu Mac OS X
2.12.3. Anmerkungen zu Solaris
2.12.4. Anmerkungen zu BSD
2.12.5. Anmerkungen zu anderen Unixen
2.12.6. Anmerkungen zu OS/2
2.13. Anmerkungen zur Perl-Installation
2.13.1. Installation von Perl unter Unix
2.13.2. Installation von ActiveState-Perl unter Windows
2.13.3. Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
3. Einführung in MySQL: ein MySQL-Tutorial
3.1. Verbindung zum Server herstellen und trennen
3.2. Anfragen eingeben
3.3. Eine Datenbank erzeugen und benutzen
3.3.1. Eine Datenbank erzeugen und auswählen
3.3.2. Eine Tabelle erzeugen
3.3.3. Daten in Tabellen einladen
3.3.4. Informationen aus einer Tabelle abfragen
3.4. Informationen über Datenbanken und Tabellen
3.5. mysql im Stapelbetrieb
3.6. Beispiele gebräuchlicher Abfragen
3.6.1. Der höchste Wert einer Spalte
3.6.2. Die Zeile, die den höchsten Wert einer bestimmten Spalte enthält
3.6.3. Höchster Wert einer Spalte pro Gruppe
3.6.4. Die Zeilen, die das gruppenweise Maximum eines bestimmten Felds enthalten
3.6.5. Wie Benutzervariablen verwendet werden
3.6.6. Wie Fremdschlüssel verwendet werden
3.6.7. Über zwei Schlüssel suchen
3.6.8. Besuche pro Tag berechnen
3.6.9. Verwendung von AUTO_INCREMENT
3.7. Anfragen aus dem Zwillingsprojekt
3.7.1. Alle nicht verteilten Zwillinge finden
3.7.2. Eine Tabelle über den Zustand von Zwillingspaaren zeigen
3.8. MySQL mit Apache verwenden
4. Benutzung von MySQL-Programmen
4.1. Überblick über MySQL-Programme
4.2. Aufruf von MySQL-Programmen
4.3. Angabe von Programmoptionen
4.3.1. Befehlszeilenoptionen für mysqld
4.3.2. my.cnf-Optionsdateien
4.3.3. Verwendung von Umgebungsvariablen für die Angabe von Optionen
4.3.4. Verwendung von Optionen zum Setzen von Programmvariablen
5. Datenbankverwaltung
5.1. Überblick über serverseitige Programme und Dienstprogramme
5.2. mysqld — Der MySQL-Server
5.2.1. Befehlsoptionen für mysqld
5.2.2. Server-Systemvariablen
5.2.3. Verwendung von Server-Systemvariablen
5.2.4. Server-Statusvariablen
5.2.5. Der SQL-Modus des Servers
5.2.6. Herunterfahren des MySQL Servers
5.3. mysqld-max, ein erweiterter mysqld-Server
5.4. Startprogramme für den MySQL-Server
5.4.1. mysqld_safe — Startskript für den MySQL-Server
5.4.2. mysql.server — Startskript für den MySQL-Server
5.4.3. mysqld_multi — Verwalten mehrerer MySQL-Server
5.5. mysqlmanager — Der MySQL Instance Manager
5.5.1. MySQL Instance Manager: MySQL-Server starten
5.5.2. MySQL Instance Manager: Verbinden und Anlegen von Benutzerkonten
5.5.3. MySQL Instance Manager: Befehlsoptionen
5.5.4. MySQL Instance Manager: Konfigurationsdateien
5.5.5. MySQL Instance Manager: Unterstützte Befehle
5.6. mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen
5.7. Absichern von MySQL gegen Angreifer
5.7.1. Allgemeine Sicherheitsrichtlinien
5.7.2. Absichern von MySQL gegen Angreifer
5.7.3. Startoptionen für mysqld in Bezug auf Sicherheit
5.7.4. Sicherheitsprobleme mit LOAD DATA LOCAL
5.7.5. Wie man MySQL als normaler Benutzer laufen läßt
5.8. Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem
5.8.1. Was das Berechtigungssystem macht
5.8.2. Wie das Berechtigungssystem funktioniert
5.8.3. Von MySQL zur Verfügung gestellte Berechtigungen
5.8.4. Verbinden mit dem MySQL-Server
5.8.5. Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
5.8.6. Zugriffskontrolle, Phase 2: Anfrageüberprüfung
5.8.7. Wann Berechtigungsänderungen wirksam werden
5.8.8. Gründe für Access denied-Fehler
5.8.9. Kennwort-Hashing ab MySQL 4.1
5.9. MySQL-Benutzerkontenverwaltung
5.9.1. MySQL-Benutzernamen und -Kennwörter
5.9.2. Hinzufügen neuer MySQL-Benutzer
5.9.3. Entfernen von Benutzerkonten in MySQL
5.9.4. Begrenzen von Benutzer-Ressourcen
5.9.5. Kennwörter einrichten
5.9.6. Wie Sie Ihre Kennwörter sicher halten
5.9.7. Verwendung sicherer Verbindungen
5.10. Datensicherung und Wiederherstellung
5.10.1. Datenbank-Datensicherungen
5.10.2. Beispielhaftes Vorgehen zur Datensicherung und Wiederherstellung
5.10.3. Zeitpunktbezogene Wiederherstellung
5.10.4. Benutzung von myisamchk für Tabellenwartung und Absturzreparatur
5.11. Lokalisierung und internationaler Gebrauch von MySQL
5.11.1. Der für Daten und zum Sortieren benutzte Zeichensatz
5.11.2. Nicht englische Fehlermeldungen
5.11.3. Einen neuen Zeichensatz hinzufügen
5.11.4. Die Zeichendefinitionsarrays
5.11.5. Unterstützung für String-Vergleiche
5.11.6. Unterstützung für Multi-Byte-Zeichen
5.11.7. Probleme mit Zeichensätzen
5.11.8. Zeitzonen-Unterstützung des MySQL-Servers
5.12. Die MySQL-Logdateien
5.12.1. Die Fehler-Logdatei
5.12.2. Die allgemeine Anfragen-Logdatei
5.12.3. Die binäre Update-Logdatei
5.12.4. Die Logdatei für langsame Anfragen
5.12.5. Wartung und Pflege der Logdateien
5.13. Mehrere MySQL-Server auf derselben Maschine laufen lassen
5.13.1. Mehrere Server unter Windows verwenden
5.13.2. Mehrere MySQL-Server unter Unix laufen lassen
5.13.3. Verwendung von Client-Programmen in einer Mehrserverumgebung
5.14. MySQL-Anfragen-Cache
5.14.1. Wie der Anfragen-Cache funktioniert
5.14.2. Anfragen-Cache-Optionen in SELECT
5.14.3. Konfiguration des Anfragen-Cache
5.14.4. Anfragen-Cache-Status und -Wartung
6. Replikation bei MySQL
6.1. Einführung in die Replikation
6.2. Replikation: Implementation
6.3. Zeilenbasierte Replikation
6.4. Replikation: Implementationsdetails
6.4.1. Thread-Zustände des Replikationsmasters
6.4.2. I/O-Thread-Zustände von Replikationsslaves
6.4.3. SQL-Thread-Zustände von Replikationsslaves
6.4.4. Relay- und Statusdateien bei der Replikation
6.5. Wie man eine Replikation aufsetzt
6.6. Replikation: Kompatibilität zwischen MySQL-Versionen
6.7. Upgrade eines Replikationssetups
6.7.1. Replikation: Upgrade auf 5.0
6.8. Replikation: Features und bekannte Probleme
6.9. Replikationsoptionen in my.cnf
6.10. Wie Server Replikationsregeln auswerten
6.11. Replikation: häufig gestellte Fragen
6.12. Vergleich zwischen anweisungsbasierter und zeilenbasierter Replikation
6.13. Replikation: Problemlösungen
6.14. Berichten von Replikationsfehlern und -problemen
6.15. Auto-Increment in der Multi-Master-Replikation
7. Optimierung
7.1. Überblick über die Optimierung
7.1.1. MySQL: konzeptionelle Einschränkungen
7.1.2. Applikationskonzepte unter Beachtung von Portabilitätsaspekten
7.1.3. Wofür benutzen wir MySQL?
7.1.4. Die MySQL-Benchmark-Reihe
7.1.5. Wie Sie Ihre eigenen Benchmarks benutzen
7.2. SELECT-Anweisungen und andere Anfragen optimieren
7.2.1. EXPLAIN-Syntax (Informationen über ein SELECT erhalten)
7.2.2. Anfragenperformance abschätzen
7.2.3. Geschwindigkeit von SELECT-Anweisungen
7.2.4. Optimierungen der WHERE-Klausel
7.2.5. Bereichsoptimierung
7.2.6. Optimierung durch Indexverschmelzung
7.2.7. IS NULL-Optimierung
7.2.8. Optimierung von DISTINCT
7.2.9. Optimierung von LEFT JOIN und RIGHT JOIN
7.2.10. Optimierung verschachtelter Joins
7.2.11. Vereinfachungsmöglichkeit für äußere Joins
7.2.12. ORDER BY-Optimierung
7.2.13. GROUP BY-Optimierung
7.2.14. LIMIT-Optimierung
7.2.15. Vermeidung von Tabellenscans
7.2.16. Geschwindigkeit von INSERT-Anweisungen
7.2.17. Geschwindigkeit von UPDATE-Anweisungen
7.2.18. Geschwindigkeit von DELETE-Anfragen
7.2.19. Weitere Optimierungstipps
7.3. Probleme mit Sperren
7.3.1. Wie MySQL Tabellen sperrt
7.3.2. Themen, die Tabellensperren betreffen
7.3.3. Gleichzeitige Einfügevorgänge
7.4. Optimierung der Datenbankstruktur
7.4.1. Überlegungen zum Datenbankdesign
7.4.2. Wie Sie Ihre Daten so klein wie möglich bekommen
7.4.3. Spaltenindizes
7.4.4. Mehrspaltige Indizes
7.4.5. Wie MySQL Indizes benutzt
7.4.6. Der MyISAM-Schlüssel-Cache
7.4.7. Sammlung von MyISAM-Indexstatistiken
7.4.8. Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
7.4.9. Warum gibt es so viele offene Tabellen?
7.5. Optimierung des MySQL Servers
7.5.1. System/Kompilierzeitpunkt und Tuning der Startparameter
7.5.2. Serverparameter feineinstellen
7.5.3. Leistung des Abfragenoptimierers steuern
7.5.4. Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
7.5.5. Wie MySQL Speicher benutzt
7.5.6. Wie MySQL DNS benutzt
7.6. Festplatte, Anmerkungen
7.6.1. Symbolische Verknüpfungen
8. Client- und Hilfsprogramme
8.1. Überblick über Client- und Hilfsprogramme
8.2. myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM
8.2.1. Allgemeine Optionen für myisamchk
8.2.2. Prüfoptionen für myisamchk
8.2.3. Reparaturoptionen für myisamchk
8.2.4. Weitere Optionen für myisamchk
8.2.5. Speicherbenutzung von myisamchk
8.3. myisamlog — Anzeige von MyISAM-Logdateiinhalten
8.4. myisampack — Erzeugung komprimierter, schreibgeschützter MyISAM Tabellen
8.5. mysql — Das MySQL-Befehlszeilenwerkzeug mysql
8.5.1. mysql Optionen
8.5.2. mysql-Befehle
8.5.3. Wie SQL-Befehle aus einer Textdatei geladen werden
8.5.4. mysql: Tipps
8.6. mysqlaccess — Client für die Überprüfung von Zugriffsberechtigungen
8.7. mysqladmin — Client für die Verwaltung eines MySQL Servers
8.8. mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien
8.9. mysqlcheck — Hilfsprogramm für die Wartung und Reparatur von Tabellen
8.10. mysqldump — Programm zur Datensicherung
8.11. mysqlhotcopy — Backup-Programm für Datenbanken
8.12. mysqlimport — Programm zum Datenimport
8.13. mysqlshow — Anzeige von Informationen über Datenbanken, Tabellen und Spalten
8.14. mysqlslap — Client zur Lastemulation
8.15. mysql_zap — Prozesse beenden, die einem Muster entsprechen
8.16. perror — Erklärung der Fehlercodes
8.17. replace — Hilfsprogramm für String-Ersetzungen
9. Sprachstruktur
9.1. Literale: wie Strings und Zahlen geschrieben werden
9.1.1. Strings
9.1.2. Zahlen
9.1.3. Hexadezimale Werte
9.1.4. Boolesche Werte
9.1.5. Bitfeldwerte
9.1.6. NULL-Werte
9.2. Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
9.2.1. Qualifikatoren für Bezeichner
9.2.2. Groß-/Kleinschreibung in Namen
9.3. Benutzerdefinierte Variablen
9.4. Kommentar
9.5. Ist MySQL pingelig hinsichtlich reservierter Wörter?
10. Zeichensatz-Unterstützung
10.1. Zeichensätze und Sortierfolgen im Allgemeinen
10.2. Zeichensätze und Sortierfolgen in MySQL
10.3. Festlegen von Zeichensätzen und Sortierfolgen
10.3.1. Serverzeichensatz und -sortierfolge
10.3.2. Datenbankzeichensatz und -sortierfolge
10.3.3. Tabellenzeichensatz und -sortierfolge
10.3.4. Spaltenzeichensatz und -sortierfolge
10.3.5. Zeichensatz und Sortierfolge literaler Strings
10.3.6. Nationaler Zeichensatz
10.3.7. Beispiele für die Zuordnung von Zeichensatz und Sortierfolge
10.3.8. Kompatibilität mit anderen Datenbanksystemen
10.4. Verbindungszeichensatz und -sortierfolge
10.5. Probleme mit Sortierfolgen
10.5.1. Verwendung von COLLATE in SQL-Anweisungen
10.5.2. Rangfolgen von COLLATE-Klauseln
10.5.3. Der BINARY-Operator
10.5.4. Spezialfälle, in denen die Festlegung der Sortierfolge problematisch ist
10.5.5. Sortierfolgen müssen für den richtigen Zeichensatz angegeben werden
10.5.6. Beispiel für die Auswirkung von Sortierfolgen
10.6. Operationen, auf die sich die Zeichensatzunterstützung auswirkt
10.6.1. Ergebnis-Strings
10.6.2. CONVERT() und CAST()
10.6.3. SHOW-Anweisungen und INFORMATION_SCHEMA
10.7. Unicode-Unterstützung
10.8. UTF8 für Metadaten
10.9. Zeichensätze und Sortierfolgen, die MySQL unterstützt
10.9.1. Unicode-Zeichensätze
10.9.2. Westeuropäische Zeichensätze
10.9.3. Mitteleuropäische Zeichensätze
10.9.4. Zeichensätze für Südeuropa und den Mittleren Osten
10.9.5. Baltische Zeichensätze
10.9.6. Kyrillische Zeichensätze
10.9.7. Asiatische Zeichensätze
11. Datentypen
11.1. Überblick über Datentypen
11.1.1. Überblick über numerische Datentypen
11.1.2. Überblick über Datums- und Zeittypen
11.1.3. Überblick über String-Typen
11.1.4. Vorgabewerte von Datentypen
11.2. Numerische Datentypen
11.3. Datums- und Zeittypen
11.3.1. Die DATETIME-, DATE- und TIMESTAMP-Typen
11.3.2. Der TIME-Typ
11.3.3. Der YEAR-Typ
11.3.4. Jahr-2000-Probleme und Datumstypen
11.4. String-Typen
11.4.1. Die CHAR- und VARCHAR-Typen
11.4.2. Die BINARY- und VARBINARY-Typen
11.4.3. Die Spaltentypen BLOB und TEXT
11.4.4. Der Spaltentyp ENUM
11.4.5. Der Spaltentyp SET
11.5. Speicherbedarf von Spaltentypen
11.6. Auswahl des richtigen Datentyps für eine Spalte
11.7. Verwendung von Datentypen anderer Datenbanken
12. Funktionen für die Benutzung in SELECT- und WHERE-Klauseln
12.1. Operatoren
12.1.1. Rangfolge von Operatoren
12.1.2. Typumwandlung bei der Auswertung von Ausdrücken
12.1.3. Vergleichsoperatoren
12.1.4. Logische Operatoren
12.2. Ablaufsteuerungsfunktionen
12.3. String-Funktionen
12.3.1. String-Vergleichsfunktionen
12.4. Numerische Funktionen
12.4.1. Arithmetische Operationen
12.4.2. Mathematische Funktionen
12.5. Datums- und Zeitfunktionen
12.6. Welchen Kalender benutzt MySQL?
12.7. MySQL-Volltextsuche
12.7.1. Boolesche Volltextsuche
12.7.2. Volltextsuche mit Abfragenerweiterung
12.7.3. Stoppwörter in der Volltextsuche
12.7.4. Beschränkungen der Volltextsuche
12.7.5. MySQL-Volltextsuche feineinstellen
12.8. Cast-Funktionen und Operatoren
12.9. XML-Funktionen
12.10. Weitere Funktionen
12.10.1. Bitfunktionen
12.10.2. Verschlüsselungs- und Kompressionsfunktionen
12.10.3. Informationsfunktionen
12.10.4. Verschiedene Funktionen
12.11. Funktionen und Modifizierer für die Verwendung in GROUP BY-Klauseln
12.11.1. Funktionen zur Benutzung in GROUP BY-Klauseln
12.11.2. GROUP BY-Modifizierer
12.11.3. GROUP BY mit versteckten Feldern
13. SQL-Anweisungssyntax
13.1. Datendefinition: CREATE, DROP, ALTER
13.1.1. ALTER DATABASE
13.1.2. ALTER TABLE
13.1.3. CREATE DATABASE
13.1.4. CREATE INDEX
13.1.5. CREATE TABLE
13.1.6. DROP DATABASE
13.1.7. DROP INDEX
13.1.8. DROP TABLE
13.1.9. RENAME TABLE
13.2. Datenmanipulation: SELECT, INSERT, UPDATE, DELETE
13.2.1. DELETE
13.2.2. DO
13.2.3. HANDLER
13.2.4. INSERT
13.2.5. LOAD DATA INFILE
13.2.6. REPLACE
13.2.7. SELECT
13.2.8. Syntax von Unterabfragen
13.2.9. TRUNCATE
13.2.10. UPDATE
13.3. Grundlegende Befehle des MySQL-Dienstprogramms für Benutzer
13.3.1. DESCRIBE (Informationen über Spalten abrufen)
13.3.2. USE
13.4. Transaktionale und Sperrbefehle von MySQL
13.4.1. BEGIN/COMMIT/ROLLBACK
13.4.2. Statements können nicht zurückgerollt werden
13.4.3. Anweisungen, die implizite Commits verursachen
13.4.4. SAVEPOINT und ROLLBACK TO SAVEPOINT
13.4.5. LOCK TABLES und UNLOCK TABLES
13.4.6. SET TRANSACTION
13.4.7. XA-Transaktionen
13.5. Anweisungen zur Datenbankadministration
13.5.1. Anweisungen zur Benutzerkontenverwaltung
13.5.2. Anweisungen für die Tabellenwartung
13.5.3. SET
13.5.4. SHOW
13.5.5. Weitere Verwaltungsanweisungen
13.6. SQL-Befehle in Bezug auf Replikation
13.6.1. SQL-Anweisungen für die Steuerung von Master-Servern
13.6.2. SQL-Anweisungen für die Steuerung von Slave-Servern
13.7. SQL-Syntax für vorbereitete Anweisungen
14. Speicher-Engines und Tabellentypen
14.1. Die MyISAM-Speicher-Engine
14.1.1. MyISAM-Startoptionen
14.1.2. Für Indizes benötigter Speicherplatz
14.1.3. MyISAM-Tabellenformate
14.1.4. MyISAM-Tabellenprobleme
14.2. InnoDB-Tabellen
14.2.1. Überblick über InnoDB-Tabellen
14.2.2. Kontaktinformationen
14.2.3. Konfiguration
14.2.4. InnoDB: Startoptionen und Systemvariablen
14.2.5. InnoDB-Tablespace erzeugen
14.2.6. InnoDB-Tabellen erzeugen
14.2.7. Hinzufügen und Entfernen von InnoDB-Daten- und -Logdateien
14.2.8. Sichern und Wiederherstellen einer InnoDB-Datenbank
14.2.9. Eine InnoDB-Datenbank auf eine andere Maschine verschieben
14.2.10. InnoDB-Transaktionsmodell
14.2.11. Tipps zur Leistungssteigerung
14.2.12. Implementierung der Multiversionierung
14.2.13. Tabellen- und Indexstrukturen
14.2.14. Verwaltung von Speicherplatz für Dateien und von Festplattenein- und -ausgaben
14.2.15. InnoDB-Fehlerbehandlung
14.2.16. Beschränkungen von InnoDB-Tabellen
14.2.17. InnoDB-Troubleshooting
14.3. Die MERGE-Speicher-Engine
14.3.1. MERGE-Tabellenprobleme
14.4. Die MEMORY-Speicher-Engine
14.5. Die BDB-Speicher-Engine
14.5.1. Betriebssysteme, die von BDB unterstützt werden
14.5.2. BDB installieren
14.5.3. BDB-Startoptionen
14.5.4. Kennzeichen von BDB-Tabellen
14.5.5. Einschränkungen bei Verwendung von BDB-Tabellen
14.5.6. Fehler, die bei der Benutzung von BDB-Tabellen auftreten können
14.6. Die EXAMPLE-Speicher-Engine
14.7. Die FEDERATED-Speicher-Engine
14.7.1. Beschreibung der FEDERATED-Speicher-Engine
14.7.2. Benutzung von FEDERATED-Tabellen
14.7.3. Beschränkungen der FEDERATED-Speicher-Engine
14.8. Die ARCHIVE-Speicher-Engine
14.9. Die CSV-Speicher-Engine
14.10. Die BLACKHOLE-Speicher-Engine
15. Erstellung einer eigenen Speicher-Engine
15.1. Einführung
15.2. Überblick
15.3. Quelldateien für Speicher-Engines erstellen
15.4. Erstellung des Handlerton
15.5. Die Erzeugung von Handlern
15.6. Definiton von Dateierweiterungen
15.7. Tabellen anlegen
15.8. Tabellen öffnen
15.9. Einfaches Tabellenscanning implementieren
15.9.1. Implementierung der Funktion store_lock()
15.9.2. Implementierung der Funktion external_lock()
15.9.3. Implementierung der Funktion rnd_init()
15.9.4. Implementierung der Funktion info()
15.9.5. Implementierung der Funktion extra()
15.9.6. Implementierung der Funktion rnd_next()
15.10. Tabellen schließen
15.11. INSERT-Unterstützung für Speicher-Engines
15.12. UPDATE-Unterstützung für Speicher-Engines
15.13. DELETE-Unterstützung für Speicher-Engines
15.14. Unterstützung für nichtsequenzielle Leseoperationen
15.14.1. Implementierung der Funktion position()
15.14.2. Implementierung der Funktion rnd_pos()
15.15. Unterstützung für Indizes
15.15.1. Überblick über Indizes
15.15.2. Indexinformationen während CREATE TABLE-Operationen erhalten
15.15.3. Erzeugen von Indexschlüsseln
15.15.4. Schlüsselinformationen parsen
15.15.5. Indexinformationen an den Optimierer liefern
15.15.6. Nutzung des Indexes vorbereiten mit index_init()
15.15.7. Aufräumen mit index_end()
15.15.8. Implementierung der Funktion index_read()
15.15.9. Implementierung der Funktion index_read_idx()
15.15.10. Implementierung der Funktion index_next()
15.15.11. Implementierung der Funktion index_prev()
15.15.12. Implementierung der Funktion index_first()
15.15.13. Implementierung der Funktion index_last()
15.16. Unterstützung für Transaktionen
15.16.1. Überblick über Transaktionen
15.16.2. Eine Transaktion starten
15.16.3. Implementierung von ROLLBACK
15.16.4. Implementierung von COMMIT
15.16.5. Unterstützung für Savepoints
15.17. Die API-Referenz
15.17.1. bas_ext
15.17.2. close
15.17.3. create
15.17.4. delete_row
15.17.5. delete_table
15.17.6. external_lock
15.17.7. extra
15.17.8. index_end
15.17.9. index_first
15.17.10. index_init
15.17.11. index_last
15.17.12. index_next
15.17.13. index_prev
15.17.14. index_read_idx
15.17.15. index_read
15.17.16. info
15.17.17. open
15.17.18. position
15.17.19. records_in_range
15.17.20. rnd_init
15.17.21. rnd_next
15.17.22. rnd_pos
15.17.23. start_stmt
15.17.24. store_lock
15.17.25. update_row
15.17.26. write_row
16. MySQL Cluster
16.1. MySQL Cluster: Überblick
16.2. MySQL Cluster: grundlegende Konzepte
16.2.1. MySQL Cluster: Knoten, Knotengruppen, Repliken und Partitionen
16.3. Einfache Schritt-für-Schritt-Anleitung für mehrere Computer
16.3.1. Hardware, Software und Netzwerk
16.3.2. Installation auf mehreren Computern
16.3.3. Konfiguration im Mehrcomputerbetrieb
16.3.4. Erster Start
16.3.5. Beispieldaten einladen und Abfragen ausführen
16.3.6. Sicheres Herunterfahren und Neustarten
16.4. MySQL Cluster: Konfiguration
16.4.1. MySQL Cluster vom Quellcode bauen
16.4.2. Installation der Software
16.4.3. Schnelle Testeinrichtung von MySQL Cluster
16.4.4. Konfigurationsdatei
16.5. Prozessverwaltung in MySQL Cluster
16.5.1. Verwendung des MySQL Server-Prozesses für MySQL Cluster
16.5.2. ndbd, der Speicher-Engine-Node-Prozess
16.5.3. ndb_mgmd, der Management-Server-Prozess
16.5.4. ndb_mgm, der Management-Client-Prozess
16.5.5. Befehlsoptionen für MySQL Cluster-Prozesse
16.6. Management von MySQL Cluster
16.6.1. MySQL Cluster: Startphasen
16.6.2. Befehle des Management-Clients
16.6.3. Ereignisberichte, die MySQL Cluster erzeugt
16.6.4. Einbenutzermodus
16.6.5. Online-Backup eines MySQL Clusters
16.7. Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster
16.7.1. Konfiguration von MySQL Cluster für SCI Sockets
16.7.2. Auswirkungen der Cluster-Interconnects verstehen
16.8. Bekannte Beschränkungen von MySQL Cluster
16.9. MySQL Cluster: Roadmap für die Entwicklung
16.9.1. MySQL Cluster: Änderungen in MySQL 5.0
16.9.2. MySQL 5.1 Roadmap für die Entwicklung von MySQL Cluster
16.10. MySQL Cluster: FAQ
16.11. MySQL Cluster: Glossar
17. Partitionierung
17.1. Überblick über die Partitionierung in MySQL
17.2. Partitionstypen
17.2.1. RANGE-Partitionierung
17.2.2. LIST-Partitionierung
17.2.3. HASH-Partitionierung
17.2.4. KEY-Partitionierung
17.2.5. Unterpartitionen
17.2.6. Wie die MySQL-Partitionierung NULL-Werte handhabt
17.3. Partitionsverwaltung
17.3.1. Verwaltung von RANGE- und LIST-Partitionen
17.3.2. Verwaltung von HASH- und KEY-Partitionen
17.3.3. Wartung von Partitionen
17.3.4. Abruf von Informationen über Partitionen
17.4. Beschränkungen und Grenzen der Partitionierung
18. Raumbezogene Erweiterungen in MySQL
18.1. Einführung in die raumbezogenen Funktionen von MySQL
18.2. Das OpenGIS-Geometriemodell
18.2.1. Hierarchie der Geometrieklassen
18.2.2. Die Klasse Geometry
18.2.3. Die Klasse Point
18.2.4. Die Klasse Curve
18.2.5. Die Klasse LineString
18.2.6. Die Klasse Surface
18.2.7. Die Klasse Polygon
18.2.8. Die Klasse GeometryCollection
18.2.9. Die Klasse MultiPoint
18.2.10. Die Klasse MultiCurve
18.2.11. Die Klasse MultiLineString
18.2.12. Die Klasse MultiSurface
18.2.13. Die Klasse MultiPolygon
18.3. Unterstützte raumbezogene Datenformate
18.3.1. Well-Known Text(WKT)-Format
18.3.2. Well-Known Binary(WKB)-Format
18.4. Erzeugen einer MySQL-Datenbank mit raumbezogenen Werten
18.4.1. Raumbezogene Datentypen in MySQL
18.4.2. Erzeugung raumbezogener Werte
18.4.3. Erzeugung raumbezogener Spalten
18.4.4. Füllen raumbezogener Spalten
18.4.5. Abfragen raumbezogener Daten
18.5. Analyse raumbezogener Informationen
18.5.1. Umwandlungsfunktionen für das Geometrieformat
18.5.2. Geometry-Funktionen
18.5.3. Funktionen, die neue geometrische Objekte aus bestehenden erzeugen
18.5.4. Funktionen zum Testen raumbezogener Beziehungen zwischen geometrischen Objekten
18.5.5. Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
18.5.6. Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
18.6. Optimierung der raumbezogenen Analyse
18.6.1. Erzeugung raumbezogener Indizes
18.6.2. Verwendung eines raumbezogenen Indizes
18.7. MySQL-Konformität und Kompatibilität
19. Gespeicherte Prozeduren und Funktionen
19.1. Gespeicherte Routinen und die Berechtigungstabellen
19.2. Syntax gespeicherter Prozeduren
19.2.1. CREATE PROCEDURE und CREATE FUNCTION
19.2.2. ALTER PROCEDURE und ALTER FUNCTION
19.2.3. DROP PROCEDURE und DROP FUNCTION
19.2.4. Syntax der CALL-Anweisung
19.2.5. BEGIN ... END-Syntax für komplexe Anweisungen
19.2.6. Syntax der DECLARE-Anweisung
19.2.7. Variablen in gespeicherten Routinen
19.2.8. Bedingungen und Handler
19.2.9. Cursor
19.2.10. Konstrukte für die Ablaufsteuerung
19.3. Gespeicherte Prozeduren, Funktionen, Trigger und Replikation: häufig gestellte Fragen
19.4. Binärloggen gespeicherter Routinen und Trigger
20. Trigger
20.1. CREATE TRIGGER
20.2. DROP TRIGGER
20.3. Verwendung von Triggern
21. Views
21.1. ALTER VIEW
21.2. CREATE VIEW
21.3. DROP VIEW
21.4. SHOW CREATE VIEW
22. Die Datenbank INFORMATION_SCHEMA
22.1. Die Tabelle INFORMATION_SCHEMA SCHEMATA
22.2. Die Tabelle INFORMATION_SCHEMA TABLES
22.3. Die Tabelle INFORMATION_SCHEMA COLUMNS
22.4. Die Tabelle INFORMATION_SCHEMA STATISTICS
22.5. Die Tabelle INFORMATION_SCHEMA USER_PRIVILEGES
22.6. Die Tabelle INFORMATION_SCHEMA SCHEMA_PRIVILEGES
22.7. Die Tabelle INFORMATION_SCHEMA TABLE_PRIVILEGES
22.8. Die Tabelle INFORMATION_SCHEMA COLUMN_PRIVILEGES
22.9. Die Tabelle INFORMATION_SCHEMA CHARACTER_SETS
22.10. Die Tabelle INFORMATION_SCHEMA COLLATIONS
22.11. Die Tabelle INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY
22.12. Die Tabelle INFORMATION_SCHEMA TABLE_CONSTRAINTS
22.13. Die Tabelle INFORMATION_SCHEMA KEY_COLUMN_USAGE
22.14. Die Tabelle INFORMATION_SCHEMA ROUTINES
22.15. Die Tabelle INFORMATION_SCHEMA VIEWS
22.16. Die Tabelle INFORMATION_SCHEMA TRIGGERS
22.17. Die Tabelle INFORMATION_SCHEMA PLUGINS
22.18. Die Tabelle INFORMATION_SCHEMA ENGINES
22.19. Die Tabelle INFORMATION_SCHEMA PARTITIONS
22.20. Die Tabelle INFORMATION_SCHEMA EVENTS
22.21. Weitere INFORMATION_SCHEMA-Tabellen
22.22. Erweiterungen der SHOW-Anweisungen
23. Präzisionsberechnungen
23.1. Typen numerischer Werte
23.2. Änderungen beim Datentyp DECIMAL
23.3. Behandlung von Ausdrücken
23.4. Rundungsverhalten
23.5. Beispiele für Präzisionsberechnungen
24. APIs und Bibliotheken
24.1. libmysqld, die eingebettete MySQL Server-Bibliothek
24.1.1. Überblick über die eingebettete MySQL Server-Bibliothek
24.1.2. Programme mit libmysqld kompilieren
24.1.3. Einschränkungen bei der Benutzung des eingebetteten MySQL Servers
24.1.4. Optionen des eingebetteten Servers
24.1.5. Ein einfaches Embedded Server-Beispiel
24.1.6. Lizenzierung des eingebetteten Servers
24.2. MySQL-C-API
24.2.1. C-API: Datentypen
24.2.2. C-API: Funktionsüberblick
24.2.3. C-API: Funktionsbeschreibungen
24.2.4. C-API: Prepared Statements
24.2.5. C-API: Prepared Statement-Datentypen
24.2.6. C-API Prepared Statements: Funktionsüberblick
24.2.7. C-API Prepared Statements: Funktionsbeschreibungen
24.2.8. C-API: Probleme bei Prepared Statements
24.2.9. C-API: Behandlung der Ausführung mehrerer Anweisungen
24.2.10. C-API: Behandlung von Datums- und Zeitwerten
24.2.11. C-Threaded-Funktionsbeschreibungen
24.2.12. C Embedded Server: Funktionsbeschreibungen
24.2.13. Häufige Fragen und Probleme bei der Benutzung der C-API
24.2.14. Clientprogramme bauen
24.2.15. Wie man einen Thread-Client herstellt
24.3. MySQLs PHP-API
24.3.1. Allgemeine Probleme mit MySQL und PHP
24.4. MySQLs Perl-API
24.5. MySQL-C++-APIs
24.5.1. Borland C++
24.6. MySQL-Python-APIs
24.7. MySQL-Tcl-APIs
24.8. MySQL-Eiffel-Wrapper
24.9. MySQL-Hilfsprogramme für die Programmentwicklung
24.9.1. msql2mysql — Umwandeln von mSQL-Programmen für die Benutzung mit MySQL
24.9.2. mysql_config — Kompilieroptionen zum Kompilieren von Clients erhalten
25. Connectors
25.1. MySQL Connector/ODBC
25.1.1. Einführung in MyODBC
25.1.2. Installation von MyODBC
25.1.3. MyODBC: Konfiguration
25.1.4. MyODBC-Beispiele
25.1.5. MyODBC-Referenz
25.1.6. Hinweise und Tipps zu MyODBC
25.1.7. MyODBC-Support
25.2. Connector/NET
25.2.1. Versionen von Connector/NET
25.2.2. Installation von Connector/NET
25.2.3. Hinweise und Tipps zu Connector/NET
25.2.4. Support für Connector/NET
25.3. MySQL Connector/J
25.3.1. Connector/J-Versionen
25.3.2. Installation von Connector/J
25.3.3. Connector/J-Beispiele
25.3.4. Connector/J (JDBC)-Referenz
25.3.5. Hinweise und Tipps zu Connector/J
25.3.6. Support für Connector/J
25.4. MySQL Connector/MXJ
25.4.1. Einführung in Connector/MXJ
25.4.2. Installation von Connector/MXJ
25.4.3. Konfiguration von Connector/MXJ
25.4.4. Referenz zu Connector/MXJ
25.4.5. Hinweise und Tipps zu Connector/MXJ
25.4.6. Support für Connector/MXJ
26. MySQL erweitern
26.1. Hinzufügen neuer Funktionen zu MySQL
26.1.1. MySQL-Threads
26.1.2. MySQL-Testsystem
26.2. Die MySQL-Plug-In-Schnittstelle
26.2.1. Charakteristiken der Plug-In-Schnittstelle
26.2.2. Volltext-Parser-Plug-Ins
26.2.3. INSTALL PLUGIN
26.2.4. UNINSTALL PLUGIN
26.2.5. Schreiben von Plug-Ins
26.3. Hinzufügen neuer Funktionen zu MySQL
26.3.1. Features der Schnittstelle für benutzerdefinierte Funktionen (UDF)
26.3.2. CREATE FUNCTION/DROP FUNCTION
26.3.3. DROP FUNCTION
26.3.4. Hinzufügen einer neuen benutzerdefinierten Funktion
26.3.5. Hinzufügen einer neuen nativen Funktion
26.4. Hinzufügen neuer Prozeduren zu MySQL
26.4.1. PROCEDURE ANALYSE
26.4.2. Schreiben einer Prozedur
A. Probleme und häufig auftretende Fehler
A.1. Wie man feststellt, was Probleme verursacht
A.2. Einige häufige Fehler bei der Benutzung von MySQL
A.2.1. Access denied-Fehler
A.2.2. Can't connect to [local] MySQL server-Fehler
A.2.3. Client does not support authentication protocol
A.2.4. Interaktive Kennworteingabe schlägt fehl
A.2.5. Host '...' is blocked-Fehler
A.2.6. Too many connections-Fehler
A.2.7. No free memory-Fehler
A.2.8. MySQL server has gone away-Fehler
A.2.9. Packet too large-Fehler
A.2.10. Kommunikationsfehler/abgebrochene Verbindung
A.2.11. The table is full-Fehler
A.2.12. Can't create/write to file-Fehler
A.2.13. Command out of sync-Fehler in Client
A.2.14. User ignored-Fehler
A.2.15. Table 'xxx' doesn't exist-Fehler
A.2.16. Can't initialize charset xxx-Fehler
A.2.17. Datei nicht gefunden
A.3. Installationsbezogene Themen
A.3.1. Probleme beim Linken mit der MySQL-Clientbibliothek
A.3.2. Probleme mit Dateirechten
A.4. Administrationsbezogene Themen
A.4.1. Wie ein vergessenes Kennwort zurückgesetzt wird
A.4.2. Was zu tun ist, wenn MySQL andauernd abstürzt
A.4.3. Wie MySQL mit vollen Festplatten umgeht
A.4.4. Wohin MySQL temporäre Dateien speichert
A.4.5. Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern
A.4.6. Probleme mit Zeitzonen
A.5. Anfragenbezogene Themen
A.5.1. Groß-/Kleinschreibung beim Suchen
A.5.2. Probleme bei der Benutzung von DATE-Spalten
A.5.3. Probleme mit NULL-Werten
A.5.4. Probleme mit alias
A.5.5. Rollback schlägt bei nichttransaktionssicheren Tabellen fehl
A.5.6. Zeilen aus verwandten Tabellen löschen
A.5.7. Lösung von Problemen mit nicht übereinstimmenden Zeilen
A.5.8. Probleme mit Fließkommavergleichen
A.6. Probleme im Zusammenhang mit dem Optimierer
A.7. Tabellendefinitionsbezogene Themen
A.7.1. Probleme mit ALTER TABLE
A.7.2. Wie man die Reihenfolge der Spalten in einer Tabelle ändert
A.7.3. Probleme mit TEMPORARY TABLE
A.8. Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL
A.8.1. Offene Probleme in MySQL
B. Fehlercodes und -meldungen
B.1. Fehlercodes und -meldungen des Servers
B.2. Fehlercodes und -meldungen der Clients
C. Danksagungen
C.1. Entwickler bei MySQL AB
C.2. Kontributoren zu MySQL
C.3. Redakteure und Übersetzer
C.4. Von MySQL benutzte und mit MySQL ausgelieferte Bibliotheken
C.5. Pakete, die MySQL unterstützen
C.6. Werkzeuge, die zum Herstellen von MySQL benutzt werden
C.7. Unterstützer von MySQL
D. MySQL-Änderungsverlauf (Change History)
D.1. Änderungen in Release 5.1.x (Entwicklung)
D.1.1. Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)
D.1.2. Änderungen in Release 5.1.5 (10. Januar 2006)
D.1.3. Änderungen in Release 5.1.4 (21. Dezember 2005)
D.1.4. Änderungen in Release 5.1.3 (29. November 2005)
D.1.5. Änderungen in Release 5.1.2 (Nicht veröffentlicht)
D.1.6. Änderungen in Release 5.1.1 (Nicht veröffentlicht)
D.2. Änderungen in MyODBC
D.2.1. Änderungen in MyODBC 3.51.13
D.2.2. Änderungen in MyODBC 3.51.12
D.2.3. Änderungen in MyODBC 3.51.11
D.3. MySQL Connector/J Change History
D.3.1. Changes in MySQL Connector/J 5.0.3 (26 July 2006)
D.3.2. Changes in MySQL Connector/J 5.0.2-beta (11 July 2006)
D.3.3. Changes in MySQL Connector/J 5.0.1-beta (Not Released)
D.3.4. Changes in MySQL Connector/J 5.0.0-beta (22 December 2005)
D.3.5. Changes in MySQL Connector/J 3.1.14 (not yet released)
D.3.6. Changes in MySQL Connector/J 3.1.13 (26 May 2006)
D.3.7. Changes in MySQL Connector/J 3.1.12 (30 November 2005)
D.3.8. Changes in MySQL Connector/J 3.1.11-stable (07 October 2005)
D.3.9. Changes in MySQL Connector/J 3.1.10-stable (23 June 2005)
D.3.10. Changes in MySQL Connector/J 3.1.9-stable (22 June 2005)
D.3.11. Changes in MySQL Connector/J 3.1.8-stable (14 April 2005)
D.3.12. Changes in MySQL Connector/J 3.1.7-stable (18 February 2005)
D.3.13. Changes in MySQL Connector/J 3.1.6-stable (23 December 2004)
D.3.14. Changes in MySQL Connector/J 3.1.5-gamma (02 December 2004)
D.3.15. Changes in MySQL Connector/J 3.1.4-beta (04 September 2004)
D.3.16. Changes in MySQL Connector/J 3.1.3-beta (07 July 2004)
D.3.17. Changes in MySQL Connector/J 3.1.2-alpha (09 June 2004)
D.3.18. Changes in MySQL Connector/J 3.1.1-alpha (14 February 2004)
D.3.19. Changes in MySQL Connector/J 3.1.0-alpha (18 February 2003)
D.3.20. Changes in MySQL Connector/J 3.0.17-ga (23 June 2005)
D.3.21. Changes in MySQL Connector/J 3.0.16-ga (15 November 2004)
D.3.22. Changes in MySQL Connector/J 3.0.15-production (04 September 2004)
D.3.23. Changes in MySQL Connector/J 3.0.14-production (28 May 2004)
D.3.24. Changes in MySQL Connector/J 3.0.13-production (27 May 2004)
D.3.25. Changes in MySQL Connector/J 3.0.12-production (18 May 2004)
D.3.26. Changes in MySQL Connector/J 3.0.11-stable (19 February 2004)
D.3.27. Changes in MySQL Connector/J 3.0.10-stable (13 January 2004)
D.3.28. Changes in MySQL Connector/J 3.0.9-stable (07 October 2003)
D.3.29. Changes in MySQL Connector/J 3.0.8-stable (23 May 2003)
D.3.30. Changes in MySQL Connector/J 3.0.7-stable (08 April 2003)
D.3.31. Changes in MySQL Connector/J 3.0.6-stable (18 February 2003)
D.3.32. Changes in MySQL Connector/J 3.0.5-gamma (22 January 2003)
D.3.33. Changes in MySQL Connector/J 3.0.4-gamma (06 January 2003)
D.3.34. Changes in MySQL Connector/J 3.0.3-dev (17 December 2002)
D.3.35. Changes in MySQL Connector/J 3.0.2-dev (08 November 2002)
D.3.36. Changes in MySQL Connector/J 3.0.1-dev (21 September 2002)
D.3.37. Changes in MySQL Connector/J 3.0.0-dev (31 July 2002)
D.3.38. Changes in MySQL Connector/J 2.0.14 (16 May 2002)
D.3.39. Changes in MySQL Connector/J 2.0.13 (24 April 2002)
D.3.40. Changes in MySQL Connector/J 2.0.12 (07 April 2002)
D.3.41. Changes in MySQL Connector/J 2.0.11 (27 January 2002)
D.3.42. Changes in MySQL Connector/J 2.0.10 (24 January 2002)
D.3.43. Changes in MySQL Connector/J 2.0.9 (13 January 2002)
D.3.44. Changes in MySQL Connector/J 2.0.8 (25 November 2001)
D.3.45. Changes in MySQL Connector/J 2.0.7 (24 October 2001)
D.3.46. Changes in MySQL Connector/J 2.0.6 (16 June 2001)
D.3.47. Changes in MySQL Connector/J 2.0.5 (13 June 2001)
D.3.48. Changes in MySQL Connector/J 2.0.3 (03 December 2000)
D.3.49. Changes in MySQL Connector/J 2.0.1 (06 April 2000)
D.3.50. Changes in MySQL Connector/J 2.0.0pre5 (21 February 2000)
D.3.51. Changes in MySQL Connector/J 2.0.0pre4 (10 January 2000)
D.3.52. Changes in MySQL Connector/J 2.0.0pre (17 August 1999)
D.3.53. Changes in MySQL Connector/J 1.2b (04 July 1999)
D.3.54. Changes in MySQL Connector/J 1.2a (14 April 1999)
D.3.55. Changes in MySQL Connector/J 1.1i (24 March 1999)
D.3.56. Changes in MySQL Connector/J 1.1h (08 March 1999)
D.3.57. Changes in MySQL Connector/J 1.1g (19 February 1999)
D.3.58. Changes in MySQL Connector/J 1.1f (31 December 1998)
D.3.59. Changes in MySQL Connector/J 1.1b (03 November 1998)
D.3.60. Changes in MySQL Connector/J 1.1 (02 September 1998)
D.3.61. Changes in MySQL Connector/J 1.0 (24 August 1998)
D.3.62. Changes in MySQL Connector/J 0.9d (04 August 1998)
D.3.63. Changes in MySQL Connector/J 0.9 (28 July 1998)
D.3.64. Changes in MySQL Connector/J 0.8 (06 July 1998)
D.3.65. Changes in MySQL Connector/J 0.7 (01 July 1998)
D.3.66. Changes in MySQL Connector/J 0.6 (21 May 1998)
E. Anmerkungen zur Portierung auf andere Systeme
E.1. Einen MySQL-Server debuggen
E.1.1. MySQL zum Debuggen kompilieren
E.1.2. Trace-Dateien erzeugen
E.1.3. mysqld unter gdb debuggen
E.1.4. Einen Stack-Trace benutzen
E.1.5. Logdateien benutzen, um Ursachen für Fehler in mysqld zu finden
E.1.6. Erzeugen eines Testfalls, wenn Sie Tabellenbeschädigung feststellen
E.2. Einen MySQL-Client debuggen
E.3. Das DBUG-Paket
E.4. Anmerkungen zu RTS-Thread
E.5. Unterschiede zwischen verschiedenen Thread-Paketen
F. Umgebungsvariablen
G. Beschreibung der MySQL-Syntax für reguläre Ausdrücke
H. Beschränkungen in MySQL
H.1. Beschränkungen von Joins
I. Feature-Beschränkungen
I.1. Beschränkungen bei gespeicherten Routinen und Triggern
I.2. Beschränkungen von serverseitigen Cursorn
I.3. Beschränkungen von Unterabfragen
I.4. Beschränkungen bei Views
I.5. Beschränkungen bei XA-Transaktionen
J. GNU General Public License
K. MySQL FLOSS License Exception
Stichwortverzeichnis

Abbildungsverzeichnis

15.1. MySQL-Architektur

Beispiele

25.1. Eine Verbindung vom DriverManager erhalten
25.2. Mit java.sql.Statement eine SELECT-Anfrage ausführen
25.3. Gespeicherte Prozeduren
25.4. Using Connection.prepareCall()
25.5. Registrierung von Ausgabeparametern
25.6. Einstellung von CallableStatement-Eingabeparametern
25.7. Abruf von Ergebnissen und Ausgabeparameterwerten
25.8. AUTO_INCREMENT-Spaltenwerte mit Statement.getGeneratedKeys() abrufen
25.9. Abruf von AUTO_INCREMENT-Spaltenwerten mit SELECT LAST_INSERT_ID()
25.10. Retrieving AUTO_INCREMENT column values in Updatable ResultSets
25.11. Verwendung eines Verbindungspools mit einem J2EE-Anwendungsserver
25.12. Beispiel einer Transaktion mit Retry-Logik

Vorwort

Dieses Referenzhandbuch für das MySQL-Datenbanksystem behandelt die MySQL-Serie 5.1 bis Version 5.1.5-alpha. Wegen vieler funktionaler und sonstiger Unterschiede ist es nicht explizit für ältere (oder neuere) Versionen von MySQL-Software vorgesehen. Wenn Sie eine solche Version verwenden, schauen Sie bitte nach, ob es eine ältere oder neuere Übersetzung des Referenzhandbuchs gibt. Sollte das nicht der Fall sein, verwenden Sie bitte die englischsprachige Originalversion.

Die Namen beteiligter Personen sind unverändert aus dem englischen Original entnommen. Bei Namen, die ursprünglich in kyrillischer Schrift geschrieben sind, wurde ebenfalls die englische Transkription verwendet. Der Grund für einen Verzicht auf deutsche Transkription besteht darin, dass die Namen solcher Personen häufig in Changeset-Kommentaren oder im Quelltext auftauchen. (Es gibt auch ein „Osterei“, SHOW AUTHORS, das die Namen der MySQL-Entwickler auflistet.) Eine Übertragung in die deutsche Schreibweise hätte die Nachvollziehbarkeit in dieser Hinsicht erschwert.

Kapitel 1. Allgemeine Informationen über MySQL

Die MySQL®-Software ist ein sehr schneller und robuster SQL-Datenbankserver (Structured Query Language, strukturierte Abfragesprache), der Multi-Threading und Mehrbenutzerbetrieb unterstützt. MySQL Server ist für unternehmenskritische Produktionssysteme mit hoher Beanspruchung ebenso vorgesehen wie für die Einbettung in Software, die flächendeckend eingesetzt wird. MySQL ist ein eingetragenes Warenzeichen von MySQL AB.

Die MySQL-Software ist dual lizenziert: Der Benutzer kann wählen, ob er die MySQL-Software als Open-Source-Produkt gemäß der GNU General Public License (http://www.fsf.org/licenses/) verwenden oder eine kommerzielle Standardlizenz bei MySQL AB erwerben will. Weitere Informationen zu unseren Lizenzierungsrichtlinien erhalten Sie unter http://www.mysql.com/company/legal/licensing/.

Die folgende Liste beschreibt einige wesentliche Abschnitte dieses Handbuchs:

Wichtig:

Um Fehler (häufig auch als „Bugs“ bezeichnet) zu melden, besuchen Sie die Seite http://bugs.mysql.com. Siehe auch Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

Wenn Sie einen kritischen Sicherheitsfehler in MySQL Server festgestellt haben, teilen Sie uns dies bitte umgehend via E-Mail an mit.

1.1. Über dieses Handbuch

Dies ist das Referenzhandbuch zum MySQL-Datenbanksystem, Version 5.1 bis einschließlich Release 5.1.5-alpha. Aufgrund der zahlreichen funktionalen und auch sonstigen Unterschiede zwischen MySQL 5.1 und vorherigen Versionen ist dieses Handbuch nicht für die Verwendung mit älteren Versionen der MySQL-Software vorgesehen. Wenn Sie ein älteres Release der MySQL-Software verwenden, finden Sie weitere Informationen im MySQL 5.0 Reference Manual, wo die 5.0-Serie der MySQL-Releases behandelt wird, oder im MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1, wo die Serien 3.23, 4.0 und 4.1 der MySQL-Software beschrieben werden. Unterschiede zwischen den Unterversionen von MySQL 5.1 sind unter Angabe der Release-Nummern (5.1.x) im vorliegenden Text enthalten.

Da dieses Handbuch als Referenzhandbuch dient, finden Sie hier keine allgemeinen Hinweise zu SQL oder zu Konzepten relationaler Datenbanken. Ebenso wenig wird beschrieben, wie Sie Ihr Betriebssystem oder einen Befehlszeilen-Interpreter verwenden.

Die MySQL-Datenbanksoftware wird fortlaufend weiterentwickelt. Auch das Referenzhandbuch wird häufig aktualisiert. Die aktuelle Version des Handbuchs ist in durchsuchbarer Form online unter http://dev.mysql.com/doc/ verfügbar. Weitere Formate wie HTML, PDF oder CHM (Windows-Hilfeformat) sind ebenfalls erhältlich.

Die Quelldateien des Referenzhandbuchs sind im Format DocBook XML verfasst. Die HTML-Version und weitere Versionen werden automatisch erzeugt. Dabei kommen in erster Linie die DocBook XSL-Stylesheets zum Einsatz. Informationen zu DocBook finden Sie unter http://docbook.org/.

Haben Sie Anmerkungen zu Ergänzungen oder Fehlerkorrekturen in diesem Handbuch, dann senden Sie bitte eine E-Mail an das Dokumentationsteam ().

Dieses Handbuch wurde ursprünglich verfasst von David Axmark und Michael „Monty“ Widenius. Es wird vom MySQL-Dokumentationsteam gepflegt, zu dem Paul DuBois, Stefan Hinz, Mike Hillyer und Jon Stephens gehören. Die Namen zahlreicher weiterer Mitwirkender finden Sie unter Anhang C, Danksagungen.

Die Urheberrechte für dieses Handbuch liegen bei dem schwedischen Unternehmen MySQL AB. MySQL® und das MySQL-Logo sind eingetragene Warenzeichen von MySQL AB. Weitere in diesem Handbuch verwendete Warenzeichen und eingetragene Warenzeichen sind Eigentum der jeweiligen Besitzer und dienen lediglich erläuternden Zwecken.

1.2. Konventionen in diesem Handbuch

Dieses Handbuch verwendet folgende typografische Konventionen:

  • Text in diesem Stil wird für SQL-Anweisungen sowie für Datenbank-, Tabellen- und Spaltennamen verwendet, darüber hinaus für Listings, Quellcode und Umgebungsvariablen. Beispiel: „Um die Berechtigungstabellen neu einzuladen, benutzen Sie die Anweisung FLUSH PRIVILEGES.

  • Text in diesem Stil bezeichnet Eingaben, die Sie in Beispielen eintippen.

  • Text in diesem Stil bezeichnet die Namen ausführbarer Programme und Skripte, beispielsweise mysql (das MySQL-Befehlszeilen-Clientprogramm) und mysqld (die ausführbare MySQL Server-Datei).

  • Text in diesem Stil wird für variable Eingaben verwendet, bei denen Sie einen Wert Ihrer Wahl eingeben.

  • Datei- und Verzeichnisnamen werden wie folgt geschrieben: „Die globale Optionsdatei my.cnf befindet sich im Verzeichnis /etc.

  • Zeichenfolgen werden so geschrieben: „Um einen Platzhalter anzugeben, verwenden Sie das Zeichen ‘%’.

  • Text in diesem Stil wird für Hervorhebungen verwendet.

  • Text in diesem Stil wird für Tabellenüberschriften und für besonders starke Hervorhebung verwendet.

Wenn Befehle dargestellt werden, die innerhalb eines bestimmten Programms eingegeben werden sollen, gibt die Eingabeaufforderung am Zeilenbeginn das zu verwendende Programm an. Beispielsweise gibt shell> einen Befehl an, der von einer Login-Shell ausgeführt werden soll. mysql> gibt eine Anweisung an, die innerhalb des Clientprogramms mysql ausgeführt wird.

shell> geben Sie hier einen Shell-Befehl ein
mysql> geben Sie hier eine MySQL-Anweisung ein

Die „Shell“ ist Ihr Befehlszeilen-Interpreter. Unter Unix ist das typischerweise ein Programm wie sh, csh oder bash. Unter Windows ist das entsprechende Programm command.com oder cmd.exe, die typischerweise in einem Eingabefenster ausgeführt werden.

Wenn Sie einen Befehl oder eine Anweisung aus einem Beispiel eingeben, geben Sie bitte nicht die Eingabeaufforderung (den Prompt) ein, die in dem Beispiel angegeben ist.

Innerhalb von Anweisungen müssen Datenbank-, Tabellen- und Spaltennamen oftmals ersetzt werden. Das Handbuch verwendet zum Kenntlichmachen, dass eine Ersetzung notwendig ist, db_name, tbl_name und col_name. Beispielsweise könnten Sie folgende Anweisung finden:

mysql> SELECT col_name FROM db_name.tbl_name;

Das bedeutet, dass Sie bei Eingabe einer ähnlichen Anweisung Ihre eigenen Namen für Datenbank, Tabelle und Spalten angeben sollen, beispielsweise so:

mysql> SELECT author_name FROM biblio_db.author_list;

SQL-Schlüsselwörter sind unabhängig von der verwendeten Groß- und Kleinschreibung. Dieses Handbuch verwendet ausschließlich zur besseren Kenntlichmachung Großschreibung.

In Syntaxbeschreibungen geben eckige Klammern (‘[’ und ‘]’) optionale Wörter oder Klauseln an. In folgender Anweisung beispielsweise ist IF EXISTS optional:

DROP TABLE [IF EXISTS] tbl_name

Wenn ein Syntaxelement eine Anzahl von Alternativen hat, werden diese durch vertikale Striche (‘|’) getrennt. Wenn ein Element ausgewählt werden kann, aber nicht muss, werden die Alternativen in eckigen Klammern (‘[’ und ‘]’) angegeben:

TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)

Wenn ein Element ausgewählt werden muss, werden die Alternativen in geschweiften Klammern (‘{’ und ‘}’) angegeben:

{DESCRIBE | DESC} tbl_name [col_name | wild]

Eine Auslassung () gibt an, dass ein Abschnitt einer Anweisung weggelassen wurde, normalerweise, um eine kürzere Version einer komplexeren Syntax darzustellen. Beispielsweise ist INSERT … SELECT die Abkürzung der Form der INSERT-Anweisung, bei der eine SELECT-Anweisung folgt.

Eine Auslassung kann darüber hinaus angeben, dass das vorhergehende Syntaxelement einer Anweisung wiederholt werden kann. Im folgenden Beispiel können mehrere reset_option-Werte angegeben werden, wobei jedem Wert nach dem ersten ein Komma vorangestellt wird:

RESET reset_option [,reset_option] ...

Befehle zum Setzen von Shell-Variablen werden in der Syntax der Bourne-Shell dargestellt, wie beispielsweise die Folge zum Setzen der Umgebungsvariablen CC und der Ausführung des Befehls configure:

shell> CC=gcc ./configure

Wenn Sie csh oder tcsh verwenden, müssen Sie die Befehle etwas anders eingeben:

shell> setenv CC gcc
shell> ./configure

1.3. Was ist MySQL AB?

MySQL AB ist das Unternehmen der Gründer und Hauptentwickler von MySQL. MySQL AB wurde ursprünglich in Schweden von David Axmark, Allan Larsson und Michael „Monty“ Widenius gegründet.

Wir entwickeln die MySQL-Datenbanksoftware mit viel Engagement und machen sie unseren Benutzern bekannt. MySQL AB gehört das Copyright am MySQL-Quellcode, das MySQL-Logo und (eingetragene) Warenzeichen und dieses Handbuch. Siehe auch Abschnitt 1.4, „Was ist MySQL?“.

Die Kernwerte von MySQL zeugen von unserem Engagement für MySQL und Open Source.

Diese Kernwerte bestimmen, wie MySQL AB mit der MySQL Server-Software verfährt:

  • Sie soll die beste und meistgenutzte Datenbank der Welt sein,

  • allen verfügbar und für alle erschwinglich,

  • leicht zu benutzen,

  • ständig in Verbesserung begriffen, jedoch stets schnell und sicher,

  • frei von Bugs und

  • es soll Spaß machen, sie zu benutzen.

Die Kernwerte des Unternehmens MySQL AB und seiner Angestellten sind:

  • Wir sind der Open-Source-Philosophie verpflichtet und unterstützen die Open-Source-Gemeinschaft,

  • versuchen, stets gute Bürger zu sein,

  • arbeiten vorzugsweise mit Partnern zusammen, die unsere Werte und Geisteshaltung teilen,

  • beantworten E-Mails und stellen Support zur Verfügung,

  • sind ein virtuelles Unternehmen, das mit anderen Netzwerkverbunde bildet, und

  • arbeiten gegen Softwarepatente.

Die MySQL-Website (http://www.mysql.com/) enthält stets die neuesten Informationen über MySQL und MySQL AB.

Nebenbei bemerkt ist das „AB“ im Firmennamen die Abkürzung für das schwedische Wort „aktiebolag“, was „Aktiengesellschaft“ bedeutet. In anderen Ländern verwenden wir stattdessen „MySQL, Inc.“ oder „MySQL GmbH“ (für regionale Niederlassungen). Diese befinden sich in den USA beziehungsweise in Deutschland.

1.4. Was ist MySQL?

MySQL, das populärste quelloffene SQL-Datenbankmanagementsystem der Welt, wird von MySQL AB entwickelt, vertrieben und supportet. MySQL AB ist ein kommerzielles, von den MySQL-Entwicklern gegründetes Unternehmen. Es ist ein Open-Source-Unternehmen der zweiten Generation, das die Werte und Methodik von Open Source mit einem erfolgreichen Geschäftsmodell verbindet.

Die MySQL-Website (http://www.mysql.com/) enthält die neuesten Informationen über MySQL-Software und MySQL AB.

  • MySQL ist ein Datenbankmanagementsystem.

    Eine Datenbank ist eine strukturierte Sammlung von Daten. Das kann alles von einer einfachen Einkaufsliste über eine Bildergalerie bis zu riesigen Informationsmengen in einem Firmennetzwerk sein. Um Daten in einer Computerdatenbank hinzuzufügen, auf sie zuzugreifen oder um sie zu verarbeiten, wird ein Datenbankmanagementsystem wie der MySQL Server benötigt. Weil Computer in der Handhabung großer Datenmengen sehr gut sind, spielen Datenbankmanagementsysteme eine zentrale Rolle beim Einsatz von Computern, sowohl als selbstständige Hilfsprogramme als auch als Teile anderer Anwendungen.

  • MySQL ist ein relationales Datenbankmanagementsystem.

    Eine relationale Datenbank speichert Daten in separaten Tabellen, statt alle Daten in einem einzigen großen Speicherraum abzulegen. Das sorgt für Vorteile hinsichtlich Geschwindigkeit und Flexibilität. Das „SQL“ in „MySQL“ steht für „Structured Query Language“ (strukturierte Abfragesprache). SQL ist die gebräuchlichste standardisierte Sprache, die für den Zugriff auf Datenbanken eingesetzt wird. Sie ist im ANSI/ISO-SQL-Standard festgelegt. Dieser, kurz SQL-Standard genannt, hat sich seit 1986 entwickelt. Es existieren verschiedene Versionen. In diesem Handbuch bezieht sich „SQL-92“ auf den im Jahre 1992 veröffentlichten Standard, „SQL:1999“ auf den 1999 veröffentlichten und „SQL:2003“ auf die aktuelle Version des Standards. Wir benutzen die Bezeichnung „der SQL-Standard“ für die aktuelle Version des SQL-Standards.

  • MySQL-Software ist quelloffene (Open Source) Software.

    Open Source bedeutet, dass es für jeden möglich ist, die Software zu benutzen und zu verändern. Jeder kann sie vom Internet herunterladen und ohne Bezahlung verwenden. Wenn man will, kann man sich den Quellcode ansehen und diesen nach den eigenen Wünschen abwandeln. MySQL verwendet die Lizenz GPL (GNU General Public License), http://www.fsf.org/licenses/. Diese legt fest, was man in unterschiedlichen Fällen mit der Software machen darf und was nicht. Wenn Ihnen ein Gebrauch unter der GPL nicht zusagt oder Sie MySQL in eine kommerzielle Applikation einbetten wollen, können Sie von uns eine kommerzielle Version erwerben. Weitere Informationen zur Lizenz finden Sie auf unserer Website (http://www.mysql.com/company/legal/licensing/).

  • Der MySQL-Datenbankserver ist sehr schnell, zuverlässig und einfach zu benutzen.

    Wenn es das ist, wonach Sie suchen, sollten Sie MySQL ausprobieren. MySQL Server hat darüber hinaus viele praktische Features, die in enger Zusammenarbeit mit unseren Benutzern entwickelt wurden. Einen Leistungsvergleich zwischen MySQL Server und anderen Datenbanksystemen finden Sie auf unserer Benchmark-Seite unter Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“.

    MySQL Server wurde ursprünglich für den Zweck entwickelt, große Datenbanken sehr viel schneller als bestehende Lösungen zu handhaben. Er ist seit Jahren in äußerst anspruchsvollen Produktionsumgebungen im Einsatz. Obwohl er ständig weiterentwickelt wird, bietet MySQL Server schon heute ein reiches Set von Funktionen. Flexible Anbindungsmöglichkeiten, Geschwindigkeit und Sicherheit machen MySQL Server äußerst geeignet für den Zugriff auf Datenbanken im Internet.

  • MySQL Server arbeitet als Client-Server-Version und in eingebetteten Systemen.

    Die MySQL-Datenbanksoftware ist ein Client-Server-System, das aus einem Mehr-Thread-SQL-Server besteht, der verschiedene Backends sowie diverse Clientprogramme und -bibliotheken und Verwaltungswerkzeuge unterstützt und mittels vieler verschiedener Programmierschnittstellen (API) angesprochen werden kann.

    MySQL Server ist auch als eingebettete Mehr-Thread-Bibliothek verfügbar, die Sie in Ihre Applikationen einlinken können, um ein schnelles, kleines und leicht zu verwaltendes Einzelprodukt zu erhalten.

  • Es gibt eine große Zahl von Dritten beigesteuerter Software.

    Es ist recht wahrscheinlich, dass Ihre Lieblingsapplikation oder -sprache bereits den MySQL-Datenbankserver unterstützt.

Die offizielle Aussprache von „MySQL“ ist „Mai Es Ku Ell“ (nicht „Mai Sie Quell“).

1.4.1. Geschichte von MySQL

Unsere Absicht war ursprünglich, den mSQL-Code zu benutzen, um unsere eigenen Tabellen anzusprechen, wobei wir unsere eigenen schnellen Low-Level-Routinen (ISAM) benutzten. Nach einigem Testen gelangten wir allerdings zu der Überzeugung, dass mSQL weder schnell noch flexibel genug wäre, um unsere Anforderungen abzudecken. Dies resultierte in einer neuen SQL-Schnittstelle zu unserer Datenbank, allerdings mit fast derselben API-Schnittstelle, wie sie mSQL benutzt. Diese API wurde gewählt, weil sie es erlaubte, Code von Drittanbietern einfach zu portieren.

Die Entstehung des Namens MySQL ist nicht völlig geklärt. Unser Basisverzeichnis und eine große Anzahl unserer Bibliotheken und Werkzeuge hatten immer schon das Präfix „my“ während mehr als 10 Jahren. Wie auch immer, auch die Tochter von Monty Widenius, einem der Gründer von MySQL, heißt My. Welcher der beiden Umstände MySQL den Namen gab, ist immer noch ein Rätsel, sogar für uns.

Der Name des MySQL-Delphins (unseres Logos) ist „Sakila“. Er wurde von den Gründern von MySQL AB aus einer riesigen Liste mit Vorschlägen unserer Benutzer im Rahmen des „Name the Dolphin“-Wettbewerbs gewählt. Der Name wurde von Ambrose Twebaze, einem Open-Source-Software-Entwickler aus Swasiland, Afrika, eingereicht. Nach Ambrose hat der weibliche Vorname Sakila seine Wurzeln in Siswati, der Sprache von Swasiland. Sakila ist darüber hinaus der Name einer Stadt in Arusha, Tansania, die in der Nähe von Ambroses Herkunftsland, Uganda, liegt.

1.4.2. Die wichtigsten Features von MySQL

Die folgende Liste beschreibt einige wichtige Charakteristika von MySQL. Weitere Informationen sind unter Abschnitt 1.6, „MySQL-Roadmap“, zu finden.

Interna und Portabilität:

  • Geschrieben in C und C++.

  • Getestet mit einer großen Anzahl unterschiedlicher Compiler.

  • Läuft auf vielen Plattformen, siehe Abschnitt 2.1.1, „Betriebssysteme, die von MySQL unterstützt werden“.

  • Benutzt aus Gründen der Portabilität GNU Automake, Autoconf und Libtool.

  • APIs für C, C++, Eiffel, Java, Perl, PHP, Python, Ruby und Tcl stehen zur Verfügung, siehe Kapitel 24, APIs und Bibliotheken.

  • Voll multithread-fähig unter Benutzung von Kernel-Threads. Das bedeutet, dass Sie sehr einfach mehrere Prozessoren benutzen können, falls verfügbar.

  • Enthält transaktionale und nichttransaktionale Speicher-Engines.

  • Verwendet sehr schnelle B-Baum-Festplatten-Tabellen (MyISAM) mit Indexkompression.

  • Es ist verhältnismäßig einfach, neue Speicher-Engines hinzuzufügen. Das ist praktisch, wenn man beispielsweise einer Inhouse-Datenbank eine SQL-Schnittstelle hinzufügen möchte.

  • Ein sehr schnelles thread-basiertes Speicherzuordnungssystem.

  • Sehr schnelle Joins durch Benutzung eines optimierten Multi-Joins in einem Durchgang.

  • Im Arbeitsspeicher gehaltene Hash-Tabellen, die als temporäre Tabellen benutzt werden.

  • SQL-Funktionen sind durch eine hochoptimierte Klassenbibliothek implementiert und sollten so schnell sein, wie es überhaupt geht. Üblicherweise gibt es keinerlei Speicherzuordnung nach der Initialisierung von Anfragen.

  • Keine Speicherlecks (memory leaks). MySQL wird mit Purify getestet, einem kommerziellen Werkzeug zur Entdeckung von Speicherlecks, und mit Valgrind, einem GPL-Werkzeug (http://developer.kde.org/~sewardj/).

  • Der Server ist als separates Programm verfügbar, das in einer vernetzten Client-Server-Umgebung arbeitet. Es ist auch als Bibliothek erhältlich, die in Einzelanwendungen eingebettet werden kann. Solche Applikationen können isoliert oder in Umgebungen eingesetzt werden, in denen kein Netzwerk zur Verfügung steht.

Datentypen:

  • Viele Datentypen: vorzeichenbehaftete und vorzeichenlose Integers, die 1, 2, 3, 4 und 8 Byte lang sein können, FLOAT, DOUBLE, CHAR, VARCHAR, TEXT, BLOB, DATE, TIME, DATETIME, TIMESTAMP, YEAR, SET, ENUM und OpenGIS-Typen (raumbezogene Daten). Siehe Kapitel 11, Datentypen.

  • Datensätze fester und variabler Länge.

Anweisungen und Funktionen:

  • Volle Operator- und Funktionsunterstützung in SELECT- und WHERE-Klauseln von Abfragen. Beispiel:

    mysql> SELECT CONCAT(first_name, ' ', last_name)
        -> FROM citizen
        -> WHERE income/dependents > 10000 AND age > 30;
    
  • Volle Unterstützung der SQL-Klauseln GROUP BY und ORDER BY. Unterstützung von Gruppierungsfunktionen (COUNT(), COUNT(DISTINCT ...), AVG(), STD(), SUM(), MAX(), MIN() und GROUP_CONCAT()).

  • Unterstützung von LEFT OUTER JOIN und RIGHT OUTER JOIN sowohl mit Standard-SQL- als auch mit ODBC-Syntax.

  • Unterstützung für Aliase auf Tabellen und Spalten, wie im SQL-Standard verlangt.

  • DELETE, INSERT, REPLACE und UPDATE geben die Anzahl der geänderten (betroffenen) Zeilen zurück. Durch Setzen eines Flags beim Verbinden mit dem Server lässt sich stattdessen die Anzahl der übereinstimmenden Zeilen zurückgeben.

  • Die MySQL-spezifische Anweisung SHOW kann zum Abruf von Informationen über Datenbanken, Speicher-Engines, Tabellen und Indizes verwendet werden.

    Mit der Anweisung EXPLAIN lässt sich feststellen, wie der Optimierer eine Abfrage auflöst.

  • Funktionsnamen vertragen sich mit Tabellen- und Spaltennamen. Beispielsweise ist ABS ein gültiger Spaltenname. Als einzige Einschränkung dürfen bei einem Funktionsaufruf dem Funktionsnamen keine Leerzeichen folgen, siehe Abschnitt 9.5, „Ist MySQL pingelig hinsichtlich reservierter Wörter?“.

  • Ab MySQL 3.22 können Tabellen in unterschiedlichen Datenbanken in einer Abfrage verwendet werden.

Sicherheit:

  • MySQL besitzt ein sehr flexibles und sicheres Berechtigungs- und Kennwortsystem, das Host-basierte Überprüfung unterstützt. Kennwörter sind sicher, weil jegliche Übermittlung beim Verbinden mit dem Server verschlüsselt erfolgt.

Skalierbarkeit und Grenzen:

  • Handhabt große Datenbanken. Wir selbst benutzen Datenbanken mit mehr als 50 Millionen Datensätzen und kennen Benutzer, die MySQL Server mit 60.000 Tabellen und über 5 Milliarden Zeilen benutzen.

  • Pro Tabelle sind bis zu 64 Indizes erlaubt (32 vor MySQL 4.1.2). Jeder Index kann aus 1 bis 16 Spalten oder Spaltenteilen bestehen. Die größte Indexweite beträgt 1.000 Byte (500 vor MySQL 4.1.2). Indizes können Präfixe einer Spalte bei folgenden Spaltentypen verwenden: CHAR, VARCHAR, BLOB und TEXT.

Konnektivität:

  • Clients können sich mit dem MySQL Server über TCP/IP-Sockets verbinden. Das ist auf jeder Plattform möglich. Auf Windows-Systemen der NT-Serie (NT, 2000, XP, 2003, Vista) können sich Clients mittels Named Pipes verbinden. Auf Unix-ähnlichen Systemen können Clients Unix-Domain-Socketdateien verwenden.

  • Ab MySQL 4.1 werden unter Windows auch Shared-Memory-Verbindungen unterstützt, wenn der Server mit der Option --shared-memory gestartet wurde. Clients können sich über Shared Memory mit der Option --protocol=memory verbinden.

  • Die Schnittstelle Connector/ODBC (MyODBC) stellt MySQL-Unterstützung für Clientprogramme zur Verfügung, die ODBC (Open Database Connectivity) benutzen. Beispielsweise können sie damit von MS Access auf MySQL Server zugreifen. Clients können unter Windows und Unix laufen. Der Quellcode von MyODBC ist offen. Alle Funktionen von ODBC 2.5 werden unterstützt sowie darüber hinaus viele weitere, siehe Kapitel 25, Connectors.

  • Die Schnittstelle Connector/J stellt MySQL-Unterstützung für Java-Clientprogramme zur Verfügung, die JDBC-Verbindungen benutzen. Clients können unter Windows und Unix laufen. Der Quellcode von Connector/J ist offen. Siehe Kapitel 25, Connectors.

  • Mit MySQL Connector/NET können Entwickler auf einfache Art .NET-Applikationen entwickeln, die sichere, hochperformante Datenverbindungen mit MySQL benötigen. Es enthält die erforderlichen ADO.NET-Schnittstellen und lässt sich in Werkzeuge einbinden, die ADO.NET-kompatibel sind. Entwickler können Applikationen mit der .NET-Sprache ihrer Wahl herstellen. MySQL Connector/NET ist ein voll verwalteter ADO.NET-Treiber, der zu 100 % in C# geschrieben wurde, siehe Kapitel 25, Connectors.

Lokalisierung:

  • Der Server kann Clients Fehlermeldungen in vielen Sprachen ausgeben, siehe Abschnitt 5.11.2, „Nicht englische Fehlermeldungen“.

  • Volle Unterstützung für diverse Zeichensätze, beispielsweise latin1 (cp1252), german, big5, ujis. In Tabellen- und Spaltennamen sind beispielsweise die Zeichen ‘å’, ‘ä’ und ‘ö’ zulässig. Ab MySQL 4.1 wird Unicode unterstützt.

  • Alle Daten werden mit dem ausgewählten Zeichensatz gespeichert. Alle Vergleiche für normale String-Spalten unterscheiden nicht nach Groß- und Kleinschreibung.

  • Sortierungen werden mit dem ausgewählten Zeichensatz durchgeführt, wobei die schwedische Sortierfolge als Vorgabe ausgewählt ist. Das lässt sich beim Start des MySQL Servers ändern. Schauen Sie sich als Beispiel einer fortgeschrittenen Sortierfolge den tschechischen Sortiercode an. MySQL Server unterstützt viele verschiedene Zeichensätze, die beim Kompilieren von MySQL sowie zur Laufzeit angegeben werden können.

Clients und Werkzeuge:

  • MySQL Server hat eingebaute SQL-Anweisungen zum Prüfen, Optimieren und Reparieren von Tabellen. Diese Anweisungen sind auch von der Befehlszeile aus zugänglich, über das Clientprogramm mysqlcheck. Darüber hinaus enthält MySQL myisamchk, ein sehr schnelles Hilfsprogramm zum Durchführen dieser Operationen auf MyISAM-Tabellen, siehe Kapitel 5, Datenbankverwaltung.

  • Alle MySQL-Programme können mit den Optionen --help und -? aufgerufen werden, die direkte Hilfestellungen anzeigen.

1.4.3. Wie stabil ist MySQL?

Dieser Abschnitt beschäftigt sich mit den Fragen „Wie stabil ist MySQL?“ und „Kann ich mich auf MySQL bei diesem Projekt verlassen?“. Wir werden versuchen, einige Dinge klarzustellen und einige der wichtigeren Fragen zu beantworten, die offensichtlich viele Leute beschäftigen. Dieser Abschnitt wurde aus Informationen zusammengestellt, die aus den Mailinglisten gesammelt wurden, die sehr aktiv beim Berichten von Problemen und Nutzungsbeispielen sind.

Der ursprüngliche Code stammt aus den frühen 1980er Jahren. Er stellt eine stabile Codebasis zur Verfügung, und das Tabllenformat ISAM, das von der ursprünglichen Speicher-Engine verwendet wurde, ist immer noch abwärtskompatibel. Bei TcX funktioniert MySQL ohne jegliche Probleme in unseren Projekten seit Mitte 1996. Als MySQL einer breiteren Öffentlichkeit zugänglich gemacht wurde, fiel uns auf, dass es einige Teile von ungetestetem Code gab, die schnell von neuen Benutzern gefunden wurden, die Anfragen machten, die von unseren eigenen abwichen. Seitdem hat jedes neue Release weniger Portabilitätsprobleme als das vorhergehende, obwohl jedes viele neue Features hat.

Jedes Release von MySQL war benutzbar. Probleme gab es nur, wenn Benutzer anfingen, Code aus den „Grauzonen“ zu benutzen. Natürlich wissen Benutzer von außerhalb nicht, was diese Grauzonen sind, daher versucht dieser Abschnitt, die momentan bekannten aufzuzeigen. Die Beschreibungen hier beziehen sich auf Version 3.23 von MySQL. Alle bekannten und berichteten Bugs werden in der letzten Version behoben, mit Ausnahme der Bugs, die im Bugs-Abschnitt aufgelistet sind und auf das Design zurückzuführen sind. Siehe Abschnitt A.8, „Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL“.

MySQL ist in mehreren Ebenen mit unabhängigen Modulen geschrieben. Diese Module sind im Folgenden aufgeführt, wobei angezeigt wird, wie gut getestet jedes von ihnen ist:

  • Replikation (stabil)

    Große Gruppen von Servern, die Replikation verwenden, sind im Produktionseinsatz, mit guten Ergebnissen. Die Entwicklung erweiterter Replikationsfeatures wird fortgesetzt.

  • InnoDB-Tabellen (stabil)

    Die transaktionale Speicher-Engine InnoDB ist seit Version 3.23.49 stabil. InnoDB wird in großen Hochlast-Produktionssystemen eingesetzt.

  • Volltextsuche (stabil)

    Die Volltextsuche wird viel verwendet. Wichtige Detailverbesserungen wurden in MySQL 4.0 und 4.1 hinzugefügt.

  • MyODBC 3.51 (stabil)

    MyODBC 3.51 verwendet ODBC SDK 3.51 und ist im breiten Produktionseinsatz. Einige Probleme scheinen applikationsbedingt zu sein und unabhängig vom ODBC-Treiber oder den zugrunde liegenden Datenbanken.

1.4.4. Wie groß können MySQL-Tabellen sein?

MySQL Version 3.22 hatte eine Begrenzung auf 4 Gbyte bei der Tabellengröße. Mit der Speicher-Engine MyISAM in MySQL Version 3.23 wurde die maximale Tabellengröße auf 65.536 Terabyte (2567 – 1 Byte) erhöht. Das bedeutet, dass die maximale effektive Tabellengröße von MySQL-Datenbanken normalerweise durch Beschränkungen des Betriebssystems hinsichtlich Dateigrößen festgelegt ist, nicht durch MySQL-interne Grenzen.

Die Speicher-Engine InnoDB hält InnoDB-Tabellen in einem Tablespace, der aus mehreren Dateien bestehen kann. Hierdurch ist es möglich, dass eine Tabelle die maximale Größe einer einzelnen Datei überschreitet. Der Tablespace kann auch rohe Festplattenpartitionen beinhalten, wodurch extrem große Tabellen möglich werden. Die maximale Größe des Tablespaces beträgt 64 Terabyte.

Im Folgenden sind einige Beispiele für Dateigrößen aufgeführt, die durch Betriebssysteme veranlasst sind. Die Tabelle soll nur als Anhaltspunkt dienen. Sie ist in keiner Weise auf Vollständigkeit bedacht. Die aktuellsten Informationen erhalten Sie in der Dokumentation Ihres Betriebssystems.

BetriebssystemMaximale Dateigröße
Linux 2.2-Intel 32-bit2 Gbyte (LFS: 4 Gbyte)
Linux 2.4+(mit Dateisystem ext3) 4 Tbyte
Solaris 9/1016 Tbyte
NetWare w/NSS Dateisystem8 Tbyte
Win32 w/ FAT/FAT322 Gbyte/4 Gbyte
Win32 w/ NTFS2 Tbyte (möglicherweise mehr)
Mac OS X w/ HFS+2 Tbyte

Unter Linux 2.2 können Sie MyISAM-Tabellen mit mehr als 2 Gbyte erzeugen, indem Sie den Large File Support(LFS)-Patch für das Dateisystem ext2 einspielen. Unter Linux 2.4 bestehen Patches für ReiserFS, die Unterstützung für große Dateien bieten (bis zu 2 Tbyte). Die meisten aktuellen Linux-Distributionen basieren auf Kernel 2.4 oder höher und enthalten sämtliche erforderlichen LFS-Patches. Mit JFS und XFS sind unter Linux Dateien im Petabytebereich und darüber hinaus möglich. Die maximal erreichbare Dateigröße hängt jedoch immer noch von mehreren Faktoren ab, unter anderem vom Dateisystem, auf dem MySQL-Tabellen gespeichert werden.

Einen detaillierten Überblick über LFS unter Linux bietet die Seite Large File Support in Linux von Andreas Jäger, die Sie hier finden: http://www.suse.de/~aj/linux_lfs.html.

Wichtiger Hinweis für Windows-Benutzer: FAT und VFAT (FAT32) sind nicht für den Produktionseinsatz von MySQL geeignet. Benutzen Sie stattdessen NTFS.

Standardmäßig erzeugt MySQL MyISAM-Tabellen mit einer internen Struktur, die eine maximale Größe von 4 Gbyte erlaubt. Sie können die maximale Tabellengröße einer MyISAM-Tabelle mit der Anweisung SHOW TABLE STATUS oder mittels myisamchk -dv tbl_name feststellen. Siehe Abschnitt 13.5.4, „SHOW.

Wenn Sie eine MyISAM-Tabelle brauchen, die größer als 4 Gbyte ist, und Ihr Betriebssystem große Dateien unterstützt, können Sie in der CREATE TABLE-Anweisung die Optionen AVG_ROW_LENGTH und MAX_ROWS verwenden, siehe Abschnitt 13.1.5, „CREATE TABLE. Sie können diese Optionen auch mit ALTER TABLE ändern, um die maximale Tabellengröße zu verändern, nachdem die Tabelle erzeugt wurde, siehe Abschnitt 13.1.2, „ALTER TABLE.

Darüber hinaus gibt es weitere Möglichkeiten, die Dateigrößenbeschränkung von MyISAM-Tabellen zu umgehen:

1.4.5. Jahr-2000-Konformität

Der MySQL Server selbst hat keine Probleme mit der Jahr-2000-Konformität:

  • MySQL benutzt Unix-Zeitfunktionen und hat keine Probleme mit Datumsangaben bis 2069. Alle zweistelligen Jahresangaben werden als Angaben zwischen 1970 und 2069, betrachtet, was bedeutet, dass, wenn Sie 01 in einer Spalte speichern, MySQL dies als 2001 behandelt.

  • Alle MySQL-Datumsfunktionen sind in einer Datei sql/time.cc gespeichert und sehr sorgfältig kodiert, um Jahr-2000-sicher zu sein.

  • AB MySQL Version 3.22 kann der Spaltentyp YEAR das Jahr 0 und den Bereich von 1901 bis 2155 in einem Byte speichern und sie mit 2 oder 4 Ziffern anzeigen.

Das folgende einfache Beispiel demonstriert, dass MySQL Server keine Probleme mit DATE- oder DATETIME-Werten bis zum Jahr 9999 und keine Probleme mit TIMESTAMP-Werten bis ins Jahr 2030 hat:

mysql> DROP TABLE IF EXISTS y2k;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE y2k (date DATE,
    ->                   date_time DATETIME,
    ->                   time_stamp TIMESTAMP);
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO y2k VALUES
    -> ('1998-12-31','1998-12-31 23:59:59','1998-12-31 23:59:59'),
    -> ('1999-01-01','1999-01-01 00:00:00','1999-01-01 00:00:00'),
    -> ('1999-09-09','1999-09-09 23:59:59','1999-09-09 23:59:59'),
    -> ('2000-01-01','2000-01-01 00:00:00','2000-01-01 00:00:00'),
    -> ('2000-02-28','2000-02-28 00:00:00','2000-02-28 00:00:00'),
    -> ('2000-02-29','2000-02-29 00:00:00','2000-02-29 00:00:00'),
    -> ('2000-03-01','2000-03-01 00:00:00','2000-03-01 00:00:00'),
    -> ('2000-12-31','2000-12-31 23:59:59','2000-12-31 23:59:59'),
    -> ('2001-01-01','2001-01-01 00:00:00','2001-01-01 00:00:00'),
    -> ('2004-12-31','2004-12-31 23:59:59','2004-12-31 23:59:59'),
    -> ('2005-01-01','2005-01-01 00:00:00','2005-01-01 00:00:00'),
    -> ('2030-01-01','2030-01-01 00:00:00','2030-01-01 00:00:00'),
    -> ('2040-01-01','2040-01-01 00:00:00','2040-01-01 00:00:00'),
    -> ('9999-12-31','9999-12-31 23:59:59','9999-12-31 23:59:59');
Query OK, 14 rows affected, 2 warnings (0.00 sec)
Records: 14  Duplicates: 0  Warnings: 2

mysql> SELECT * FROM y2k;
+------------+---------------------+---------------------+
| date       | date_time           | time_stamp          |
+------------+---------------------+---------------------+
| 1998-12-31 | 1998-12-31 23:59:59 | 1998-12-31 23:59:59 |
| 1999-01-01 | 1999-01-01 00:00:00 | 1999-01-01 00:00:00 |
| 1999-09-09 | 1999-09-09 23:59:59 | 1999-09-09 23:59:59 |
| 2000-01-01 | 2000-01-01 00:00:00 | 2000-01-01 00:00:00 |
| 2000-02-28 | 2000-02-28 00:00:00 | 2000-02-28 00:00:00 |
| 2000-02-29 | 2000-02-29 00:00:00 | 2000-02-29 00:00:00 |
| 2000-03-01 | 2000-03-01 00:00:00 | 2000-03-01 00:00:00 |
| 2000-12-31 | 2000-12-31 23:59:59 | 2000-12-31 23:59:59 |
| 2001-01-01 | 2001-01-01 00:00:00 | 2001-01-01 00:00:00 |
| 2004-12-31 | 2004-12-31 23:59:59 | 2004-12-31 23:59:59 |
| 2005-01-01 | 2005-01-01 00:00:00 | 2005-01-01 00:00:00 |
| 2030-01-01 | 2030-01-01 00:00:00 | 2030-01-01 00:00:00 |
| 2040-01-01 | 2040-01-01 00:00:00 | 0000-00-00 00:00:00 |
| 9999-12-31 | 9999-12-31 23:59:59 | 0000-00-00 00:00:00 |
+------------+---------------------+---------------------+
14 rows in set (0.00 sec)

Die letzten beiden TIMESTAMP-Spaltenwerte sind null, weil die Jahreswerte (2040, 9999) das Maximum für TIMESTAMP überschreiten. Der Datentyp TIMESTAMP, der zur Speicherung der aktuellen Zeit verwendet wird, unterstützt Werte im Bereich zwischen '1970-01-01 00:00:00' und '2030-01-01 00:00:00' (auf 32-Bit-Maschinen; vorzeichenbehafteter Wert). Auf 64-Bit-Maschinen kann TIMESTAMP Werte bis zum Jahr 2106 (vorzeichenloser Wert) handhaben.

Obgleich MySQL Server selbst Jahr-2000-sicher ist, kann es Probleme mit Applikationen geben, die nicht Jahr-2000-konform sind. Beispielsweise speichern oder behandeln viele alte Applikationen Jahreswerte als zweistellige Zahlen (was uneindeutig ist). Dieses Problem wird durch Applikationen verschlimmert, die Werte wie 00 oder 99 als „fehlende“ Wertangaben betrachten. Solcherlei Probleme können schwer zu beheben sein.

Obwohl also MySQL Server keine Jahr-2000-Probleme aufweist, ist es die Aufgabe der Applikation, eindeutige Werte einzugeben. Siehe Abschnitt 11.3.4, „Jahr-2000-Probleme und Datumstypen“, hier sind die Regeln aufgeführt, die MySQL Server zur Handhabung uneindeutiger Datumseingaben mit zweistelligen Jahreswerten verwendet.

1.5. Überblick über das Datenbanksystem MaxDB

MaxDB ist eine Hochlast-Datenbank für den Unternehmenseinsatz. Das System ist SAP-zertifiziert.

MaxDB ist der neue Name des Datenbankverwaltungssystems, das vormals SAP DB hieß. Im Jahr 2003 schlossen sich SAP AG und MySQL AB zu einer Partnerschaft zusammen und gaben das Datenbanksystem unter dem neuen Markennamen MaxDB heraus. Die Entwicklung von MaxDB wurde seitdem wie gehabt durch das SAP-Entwicklungsteam fortgesetzt.

MySQL AB arbeitet eng mit dem MaxDB-Team bei SAP zusammen, um Verbesserungen in das Produkt MaxDB einzubringen. Beispielsweise werden zusammen neue native Treiber entwickelt, die eine effizientere Nutzung von MaxDB in der Open-Source-Community erlauben. Die Dokumentation wurde auf den MaxDB-Seiten verfügbar gemacht. Als gleichermaßen wichtig werden Features für das Zusammenspiel zwischen MySQL und MaxDB erachtet. Der neu entwickelte Synchronisationsmanager von MaxDB beispielsweise unterstützt die Synchronisation von Daten zwischen MaxDB und MySQL.

Das MaxDB-Datenbankverwaltungssystem hat eine andere Codebasis als das MySQL-Datenbankverwaltungssystem. MaxDB und MySQL sind voneinander unabhängige Produkte, die beide von MySQL AB angeboten werden.

MySQL AB bietet eine Vielzahl professioneller Dienstleistungen für MaxDB an.

1.5.1. Was ist MaxDB?

MaxDB ist ein zu ANSI SQL-92 (entry level) konformes relationales Datenbankverwaltungssystem (RDBMS) der SAP AG, das auch von MySQL AB vertrieben wird. MaxDB erfüllt alle Ansprüche an den Gebrauch im Unternehmen: Sicherheit, Skalierbarkeit, Nichtsequenzialität (Gleichzeitigkeit von Zugriffen) und Performanz. Es läuft auf allen größeren Betriebssystemen. Im Laufe der Jahre hat es unter Beweis gestellt, dass es in der Lage ist, SAP R/3 und Terabytes von Daten im Rund-um-die-Uhr-Betrieb zu unterstützen.

Die Datenbankentwicklung begann 1977 als Forschungsprojekt an der Technischen Universität Berlin. In den frühen 1980er Jahren wurde es zu einem Datenbankprodukt, das nacheinander Nixdort, Siemens Nixdorf, der Software AG und dann (bis heute) der SAP AG gehörte. Im Verlauf dieser Zeit wurde es VDN, Reflex, Supra 2, DDB/4, Entire SQL-DB-Server sowie ADABAS D genannt. 1997 übernahm SAP die Software von der Software AG und benannte sie in SAP DB um. Seit Oktober 2000 sind die SAP DB-Quellcodes unter der GNU General Public-Lizenz (siehe Anhang J, GNU General Public License) veröffentlicht.

Im Jahre 2003 gründeten die SAP AG und MySQL AB eine Partnerschaft und benannten das Datenbanksystem in MaxDB um.

1.5.2. Geschichte von MaxDB

Die Geschichte von MaxDB geht zurück auf SAP DB, das Datenbanksystem der SAP AG. MaxDB ist also die umbenannte und erweiterte Version von SAP DB. Seit vielen Jahren wird MaxDB in kleinen, mittleren und großen Installationen der mySAP-Business-Suite und anderen anspruchsvollen SQL-Anwendungen verwendet, die ein unternehmenstaugliches Datenbanksystem hinsichtlich Anzahl der Benutzer, transaktionaler Arbeitslast und Größe der Datenbank benötigen.

SAP DB war als Alternative zu Datenbanken von Drittanbietern wie Oracle oder Microsoft SQL Server sowie DB2 von IBM gedacht. Im Oktober 2000 veröffentlichte die SAP AG SAP DB unter der Lizenz GNU GPL (siehe Anhang J, GNU General Public License) und machte es damit zu quelloffener (Open Source) Software.

Heute kommt MaxDB in über 3500 SAP-Kundeninstallationen auf der ganzen Welt zum Einsatz. Darüber hinaus setzt die Mehrzahl aller Datenbankinstallationen unter Unix und Linux innerhalb der IT-Abteilung von SAP auf MaxDB auf. MaxDB ist optimiert auf Hochlast-Online-Transaction-Processing (OLTP) mit mehreren Tausend Benutzern und Datenbankgrößen zwischen mehreren hundert Gbytes und mehreren Tbytes.

Im Jahre 2003 begründeten SAP und MySQL eine Partnerschaft und eine Entwicklungskooperation. Im Rahmen dieser Zusammenarbeit wurde das System SAP DB der SAP AG unter dem Namen MaxDB by MySQL veröffentlicht. Das erste Release unter diesem Namen war 7.5 (November 2003).

Version 7.5 von MaxDB ist eine direkte Weiterentwicklung auf der Codebasis von SAP DB 7.4. Daher kann MaxDB 7.5 direkt als Upgrade von früheren SAP DB-Versionen ab 7.2.04 verwendet werden.

Das bestehende SAP-DB-Entwicklungsteam bei der SAP AG ist nach wie vor verantwortlich für die Entwicklung und den Support von MaxDB. MySQL AB und das MaxDB-Team bei SAP arbeiten an Verbesserungen am Produkt MaxDB eng zusammen; siehe Abschnitt 1.5, „Überblick über das Datenbanksystem MaxDB“. Sowohl die SAP AG als auch MySQL AB wickeln Verkauf und Auslieferung von MaxDB ab. Die Weiterentwicklung von MaxDB und MySQL Server setzt Synergien frei, die beiden Produktlinien zugute kommen.

MaxDB unterliegt dem kompletten Qualitätssicherungsprozess der SAP AB, bevor das Produkt mit SAP-Lösungen ausgeliefert oder zum Download auf der MySQL-Website zur Verfügung gestellt wird.

1.5.3. Features von MaxDB

MaxDB ist eine SAP-zertifizierte, quelloffene Hochlast-Datenbank für OLTP- und OLAP-Einsatzzwecke, die hohe Zuverlässigkeit und Verfügbarkeit sowie Skalierbarkeit und ein sehr umfangreiches Set von Features bietet. MaxDB ist auf große mySAP-Business-Suite-Umgebungen und sonstige Applikationen, die höchste Unternehmensfunktionalität benötigen, zugeschnitten und ergänzt somit den MySQL-Datenbankserver.

MaxDB arbeitet als Client-Server-Produkt. Es wurde hinsichtlich der Anforderungen von OLTP und Data Warehouse/OLAP/Entscheidungsunterstützung entwickelt und bietet folgende Vorteile:

  • Einfache Konfiguration und Verwaltung: Ein grafischer Installationsmanager sowie ein Datenbankmanager als einziges Verwaltungswerkzeug für sämtliche DBMS-Operationen

  • Rund-um-die-Uhr-Betrieb, keine geplanten Stillstandszeiten, keine ständige Beobachtung erforderlich: Automatische Verwaltung des Speicherplatzes ohne Notwendigkeit von Neuorganisationen

  • Ausgefeilte Sicherungs- und Wiederherstellungsoptionen: Online-Backups und inkrementelle Sicherungen sowie Wiederherstellungsassistenten, die Sie durch das Recovery-Szenario führen

  • Unterstützt eine große Zahl gleichzeitiger Benutzer, Datenbankgrößen im Terabytebereich und anspruchsvolle Arbeitslasten: Ausgereifte Zuverlässigkeit, Performanz und Skalierbarkeit

  • Hochverfügbarkeit: Clusterunterstützung, Standby-Konfiguration, Hot-Standby-Konfiguration

1.5.4. Lizenzierung und Support

MaxDB kann unter denselben Lizenzen benutzt werden, die für andere von MySQL AB vertriebene Produkte gelten. Es ist daher unter der Lizenz GNU General Public License sowie einer kommerziellen Lizenz erhältlich. Weitere Informationen zur Lizenzierung finden Sie unter http://www.mysql.com/company/legal/licensing/.

MySQL AB bietet technischen Support für Nicht-SAP-Kunden. Der Support ist in verschiedenen Stufen erhältlich (Basic, Silver, Gold), die vom unbegrenzten E-Mail- und Web-Support bis hin zum 24×7-Telefon-Support für geschäftskritische Anwendungen reichen.

MySQL AB bietet auch Lizenzen und Support für MaxDB an, wenn es mit SAP-Applikationen wie SAP NetWeaver und der mySAP-Business-Suite eingesetzt wird. Für weitere Informationen zu Lizenzen und Support gemäß Ihren Anforderungen setzen Sie sich bitte mit MySQL AB in Verbindung (http://www.mysql.com/company/contact/).

Consulting und Schulungen sind ebenfalls erhältlich. MySQL gibt in regelmäßigen Abständen Kurse. Eine Liste finden Sie unter http://www.mysql.com/training/.

1.5.5. Unterschiede zwischen MaxDB und MySQL

MaxDB ist die SAP-zertifizierte Datenbank von MySQL AB. Der MaxDB-Datenbankserver ergänzt das Produktport von MySQL AB. Einige Features von MaxDB sind bei MySQL Server nicht erhältlich und umgekehrt.

Folgende Liste fasst die Hauptunterschiede zwischen MaxDB und MySQL zusammen, wobei kein Anspruch auf Vollständigkeit besteht:

  • MaxDB läuft als Client-Server-System, während MySQL darüber hinaus auch als eingebettetes System laufen kann.

  • MaxDB läuft nicht auf allen von MySQL unterstützten Plattformen.

  • MaxDB verwendet ein proprietäres Netzwerkprotokoll für die Client-Server-Kommunikation. MySQL benutzt entweder TCP/IP (mit oder ohne SSL-Verschlüsselung), Sockets (unter Unix-ähnlichen Systemen) oder Named Pipes und Shared Memory (unter Systemen der Windows-NT-Familie).

  • MaxDB unterstützt gespeicherte Prozeduren und Funktionen. MySQL unterstützt diese ab Version 5.0 ebenfalls. MaxDB unterstützt die Programmierung von Triggern über eine SQL-Erweiterung. MySQL unterstützt Trigger ab Version 5.0. MaxDB enthält einen Debugger für Stored-Procedure-Sprachen, kann Trigger verschachteln und unterstützt mehrere Trigger pro Aktion und Zeile.

  • MaxDB wird mit textbasierten, grafischen und webbasierten Benutzerschnittstellen ausgeliefert. MySQL wird nur mit textbasierten Schnittstellen ausgeliefert, während grafische Benutzerwerkzeuge wie MySQL Query Browser und MySQL Administrator getrennt von den Hauptdistributionen zur Verfügung stehen. Webbasierte Schnittstellen für MySQL werden von Drittanbietern zur Verfügung gestellt.

  • MaxDB unterstützt eine Reihe von Programmierschnittstellen, die auch von MySQL unterstützt werden. Zur Entwicklung mit MaxDB stehen folgende Schnittstellen zur Verfügung: Der MaxDB ODBC-Treiber, SQL Database Connectivity (SQLDBC), JDBC-Treiber, Perl- und Python-Module und eine MaxDB PHP-Extension, die den Zugriff auf MaxDB mittels PHP erlaubt. Schnittstellen von Drittanbietern: Unterstützung für OLE DB, ADO, DAO, RDO und .NET über ODBC. MaxDB unterstützt eingebettetes SQL mit C/C++.

  • MaxDB enthält Verwaltungsfeatures, die MySQL nicht hat: Auftragsplanung nach Zeit (in MySQL ab Version 5.1 enthalten), Ereignis und Alarm sowie das Senden von Nachrichten an einen Datenbankverwalter, geregelt durch Alarmschwellen (Thresholds).

1.5.6. Interoperabilität zwischen MaxDB und MySQL

MaxDB und MySQL sind unabhängige Datenbankverwaltungssysteme. Beide Systeme können über Datenaustausch interagieren. Um Daten zwischen MaxDB und MySQL auszutauschen, können Sie entweder die jeweiligen Export- und Importwerkzeuge der Systeme oder den Synchronisationsmanager von MaxDB verwenden. Die Verwendung der Import- und Exportwerkzeuge ist für gelegentlichen, manuell durchgeführten Datenabgleich gedacht. Der Synchronisationsmanager von MaxDB dagegen bietet schnelle, automatische Datentransfer-Möglichkeiten.

Der MaxDB Loader kann zum Export von Daten und Objektdefinitionen verwendet werden. Der Loader kann Daten im MaxDB-internen, im binären oder im Textformat (CSV) exportieren. Ins Textformat exportierte Daten können in MySQL mittels des Clientprogramms mysqlimport importiert werden. Um Daten aus MySQL zu exportieren, können Sie entweder mysqldump verwenden, um INSERT-Anweisungen zu erzeugen, oder SELECT ... INTO OUTFILE, um eine Textdatei (CSV) zu schreiben. Diese Daten können dann mit dem MaxDB Loader importiert werden.

Objektdefinitionen können zwischen den Systemen mittels MaxDB Loader und dem MySQL-Werzeug mysqldump ausgetauscht werden. Weil die SQL-Dialekte beider Systeme sich leicht unterscheiden und MaxDB Features aufweist, die momentan von MySQL nicht unterstützt werden (beispielsweise SQL-Constraints), empfehlen wir, Definitionsdateien per Hand abzugleichen. Das Werkzeug mysqldump stellt die Option --compatible=maxdb zur Verfügung, die Ausgaben erzeugt, die sich leichter nach MaxDB portieren lassen.

Der Synchronisationsmanager von MaxDB steht ab Version 7.6 zur Verfügung. Er unterstützt das Erzeugen von asynchronen Replikationsszenarien zwischen mehreren MaxDB-Instanzen. Es sind jedoch auch darüber hinausgehende Features zur Interoperabilität geplant, die es dem Synchronisationsmanager erlauben sollen, zu und von einem MySQL Server zu replizieren.

1.5.7. Links zu MaxDB

Die Hauptseite für Informationen zu MaxDB ist http://www.mysql.com/products/maxdb. Hier finden Sie detaillierte Informationen zu den Features des MaxDB- Datenbanksystems und Links zur verfügbaren Dokumentation.

Das MySQL Referenzhandbuch enthält keinerlei MaxDB-Dokumentation mit Ausnahmen der in diesem Abschnitt gegebenen Einführung. MaxDB hat seine eigene Dokumentation, genannt MaxDB-Bibliothek, die sich hier befindet: http://dev.mysql.com/doc/maxdb/index.html.

MySQL AB unterhält eine Community-Mailingliste zu MaxDB: http://lists.mysql.com/maxdb, auf der sich neben lebhaften Beiträgen der Community auch Postings der Kernentwickler finden. Produktankündigungen werden ebenfalls an diese Liste geschickt.

Ein Webforum zu MaxDB ist verfügbar unter http://forums.mysql.com/. Im Forum werden vorrangig Fragen zu MaxDB angesprochen, die sich nicht auf SAP-Applikationen beziehen.

1.6. MySQL-Roadmap

Dieser Abschnitt enthält eine Momentaufnahme des MySQL-Entwicklungsfahrplans einschließlich verschiedener wichtiger Funktionen, die in diversen MySQL-Releases implementiert wurden bzw. für diese vorgesehen sind. Nachfolgend finden Sie Informationen zu allen Release-Serien.

Die aktuelle Release-Serie ist MySQL 5.0. Die für den Einsatz in Produktionsumgebungen erforderliche Stabilität wurde für MySQL 5.0.15 (Freigabe im Oktober 2005) festgestellt. Die vorherige Release-Serie war MySQL 4.1. Die für den Einsatz in Produktionsumgebungen erforderliche Stabilität wurde für MySQL 4.1.7 (Freigabe im Oktober 2004) festgestellt. „Produktionsstatus“ bedeutet, dass die Entwicklung bei den Versionen 5.0 und 4.1 zukünftig auf die Fehlerbereinigung beschränkt ist. Bei den älteren MySQL-Serien 4.0 und 3.23 werden nur noch kritische Fehler behoben.

Die aktive MySQL-Entwicklung betrifft derzeit die MySQL-Release-Serien 5.0 und 5.1. Neue Funktionen werden lediglich bei Version 5.1 implementiert.

Bevor Sie von einer Release-Serie auf die nächste aktualisieren, beachten Sie die Hinweise in Abschnitt 2.10, „MySQL aktualisieren (Upgrade/Downgrade)“.

Die meistgewünschten Funktionen und die Versionen, in denen sie implementiert werden bzw. für die ihre Implementierung vorgesehen ist, werden in folgender Tabelle zusammengefasst.

FunktionMySQL-Serie
Fremdschlüssel3.23 (für die InnoDB-Speicher-Engine)
Unions4.0
Unterabfragen4.1
R-Trees4.1 (für die MyISAM-Speicher-Engine)
Gespeicherte Prozeduren5.0
Sichten5.0
Cursor5.0
XA-Transaktionen5.0
Fremdschlüssel5.2 (implementiert in 3.23 für InnoDB)
Trigger5.0 und 5.1
Partitionierung5.1
Pluggable Storage Engine-API5.1
Datensatzbasierte Replikation5.1

1.6.1. Was ist neu in MySQL 5.1?

Die folgenden Funktionen wurden in MySQL 5.1 implementiert. Weitere Detailinformationen werden wir im Zuge der Weiterentwicklung von MySQL 5.1 ergänzen.

  • Partitionierung: Diese Funktionalität erlaubt die Verteilung von Teilen einzelner Tabellen über ein Dateisystem. Die entsprechenden Regeln können bei Erstellung der Tabelle konfiguriert werden. Verschiedene Teile einer Tabelle werden also als separate Tabellen an verschiedenen Positionen abgelegt, die partitionierte Tabelle präsentiert sich dem Benutzer jedoch weiterhin als eine einzige Tabelle. Weitere Informationen zu dieser Funktionalität finden Sie in Kapitel 17, Partitionierung (Autor: Mikael Ronström).

  • Plug-In-API: MySQL 5.1 unterstützt eine sehr flexible Plug-In-API, die das Laden und Entladen verschiedener Komponenten während der Laufzeit gestattet, ohne dass der Server neu gestartet werden müsste. Zwar sind die Arbeiten daran noch nicht abgeschlossen, aber die Plug-In-Volltext-Parser sind ein erster Schritt in diese Richtung. Hiermit können Benutzer eigene Eingabefilter für indizierten Text implementieren und so eine Volltextsuche für beliebige Daten (z. B. PDF-Dateien oder andere Dokumentformate) ermöglichen. Ein dem Parser vorgeschaltetes Volltext-Plug-In führt die eigentliche Verarbeitung und Extraktion des Texts durch und übergibt diesen dann an die in MySQL integrierte Volltextsuche (Autor: Sergey Vojtovich).

  • Der Instanzen-Manager (IM) bietet nun einige neue Funktionen:

    • SHOW instance_name LOG FILES listet alle von der Instanz verwendeten Logdateien auf (Autor: Petr Chardin).

    • SHOW instance_name LOG {ERROR | SLOW | GENERAL} size ruft einen Teil der angegebenen Logdatei ab (Autor: Petr Chardin).

    • SET instance_name.option_name=option_value setzt eine Option auf den angegebenen Wert und schreibt sie in die Konfigurationsdatei. Weitere Informationen zu diesen neuen Befehlen finden Sie unter Abschnitt 5.5, „mysqlmanager — Der MySQL Instance Manager“ (Autor: Petr Chardin).

1.7. Informationsquellen zu MySQL

Dieser Abschnitt listet zusätzliche Informationsquellen auf, die für Sie hilfreich sein können. Dies sind etwa die MySQL-Mailinglisten und Benutzerforen sowie IRC-Kanäle.

1.7.1. Die MySQL-Mailinglisten

Dieser Abschnitt stellt die MySQL-Mailinglisten vor und enthält Hinweise zur Benutzung dieser Listen. Wenn Sie eine Mailingliste bestellen, erhalten Sie alle Beiträge zu dieser Liste als E-Mails. Sie können auch eigene Fragen (und Antworten) an die Liste schicken.

Um eine der in diesem Abschnitt aufgeführten Listen zu bestellen bzw. zu kündigen, besuchen Sie die Seite http://lists.mysql.com/. Bei den meisten Listen können Sie die reguläre Version, bei der jeder Beitrag einzeln als Mail gesendet wird, oder eine Digest-Version auswählen, wobei Sie einmal täglich eine lange Mail mit allen Beiträgen des Tages erhalten.

Bitte senden Sie bei Fragen zu Bestellung oder Kündigung einer Liste keine Mitteilungen an die Liste selbst, denn auch diese werden automatisch an tausende anderer Benutzer weitergeschickt.

An Ihrem Standort haben vielleicht schon viele Benutzer eine MySQL-Mailingliste abonniert. Sollte dies der Fall sein, dann wird am Standort womöglich eine lokale Mailingliste betrieben, sodass Mitteilungen, die von lists.mysql.com an Ihren Standort geschickt werden, an diese lokale Liste weitergeleitet werden. Wenden Sie sich in diesem Fall an Ihren Systemadministrator, damit dieser Sie zur lokalen MySQL-Liste hinzufügt bzw. aus dieser entfernt.

Wenn Sie wollen, dass die Daten einer Mailingliste in Ihrem E-Mail-Programm in ein anderes Postfach geleitet werden, erstellen Sie einen Filter, der eingehende Mails nach den Kopfdaten (Headern) sortiert. Sie können die Header List-ID: oder Delivered-To: zur Identifizierung von Mitteilungen einer MySQL-Liste verwenden.

Die folgenden MySQL-Mailinglisten sind vorhanden:

  • announce

    Diese Liste ist für Ankündigungen neuer MySQL-Versionen und zugehöriger Programme vorgesehen. Das Aufkommen ist bei dieser Liste gering. Sie sollte von allen MySQL-Benutzern abonniert werden.

  • mysql

    Dies ist die wichtigste Liste für allgemeine Diskussionen zu MySQL. Bitte beachten Sie, dass einige Themen besser in den spezialisierteren Listen behandelt werden. Wenn Sie eine Mitteilung an die falsche Liste schicken, erhalten Sie unter Umständen keine Antwort.

  • bugs

    Diese Liste ist für Benutzer vorgesehen, die bezüglich aller Probleme, die seit dem letzten MySQL-Release gemeldet wurden, auf dem neuesten Stand bleiben oder sich aktiv an der Suche und Behebung von Bugs beteiligen wollen. Siehe auch Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

  • internals

    Diese Liste ist für Benutzer vorgesehen, die am MySQL-Code arbeiten. Sie ist auch das Forum für Diskussionen zur MySQL-Entwicklung und zur Verbreitung von Patches.

  • mysqldoc

    Diese Liste ist für Benutzer vorgesehen, die an der MySQL-Dokumentation arbeiten. Dies sind beispielsweise Mitarbeiter von MySQL AB oder Übersetzer.

  • benchmarks

    Diese Liste ist für jeden gedacht, der sich für Fragen der Leistungsfähigkeit interessiert. Die Diskussionen drehen sich in erster Linie um die Leistung von Datenbanken (wobei man sich nicht auf MySQL beschränkt), aber auch andere Kategorien – z. B. die Leistungsfähigkeit von Kerneln, Datei- oder Festplattensystemen usw. – werden hier behandelt.

  • packagers

    Diese Liste ist für Diskussionen gedacht, bei denen es um das Packen und Vertreiben von MySQL geht. Dies ist das Forum, in dem für die Distribution Zuständige Ideen zum Packen von MySQL und zu der Frage austauschen können, wie man gewährleistet, dass „Look and Feel“ von MySQL auf allen unterstützten Plattformen und Betriebssystemen so ähnlich wie möglich sind.

  • java

    Diese Liste ist für Diskussionen über den MySQL Server und Java vorgesehen. Hier werden meistens JDBC-Treiber wie etwa MySQL Connector/J diskutiert.

  • win32

    Diese Liste ist für alle Themen reserviert, die den Betrieb der MySQL-Software auf Microsoft-Betriebssystemen wie Windows 9x, Me, NT, 2000, XP und 2003 betreffen.

  • myodbc

    Diese Liste behandelt Themen im Zusammenhang mit der Verbindungsherstellung zum MySQL Server über ODBC.

  • gui-tools

    Diese Liste ist für alle Themen vorgesehen, die GUI-Tools (grafische Oberflächen) für MySQL bereitstellen, z. B. MySQL Administrator und MySQL Query Browser.

  • cluster

    Bei dieser Liste dreht sich alles um MySQL Cluster.

  • dotnet

    Diese Liste ist für Diskussionen über den MySQL Server und die .NET-Plattform vorgesehen. Es geht dabei in erster Linie um MySQL Connector/Net.

  • plusplus

    Diese Liste behandelt alle Themen in Zusammenhang mit der Programmierung unter Verwendung der C++-API für MySQL.

  • perl

    Dies ist eine Liste, bei der Themen zum Bereich der Perl-Unterstützung für MySQL mit DBD::mysql diskutiert werden.

Wenn Sie über eine MySQL-Mailingliste oder ein Forum keine befriedigende Antwort auf Ihre Frage erhalten, besteht eine weitere Option im kostenpflichtigen Support durch MySQL AB. Auf diese Weise erhalten Sie direkten Kontakt zu den MySQL-Entwicklern.

Die folgende Tabelle enthält einige MySQL-Mailinglisten in anderen Sprachen als Englisch. Diese Listen werden jedoch nicht von MySQL AB betrieben.

  • Eine französischsprachige Mailingliste.

  • Eine koreanischsprachige Mailingliste. Sie bestellen sie, indem Sie den Befehl subscribe mysql ihre@email.adresse in einer Mail an die Liste schicken.

  • Eine deutschsprachige Mailingliste. Sie bestellen sie, indem Sie den Befehl subscribe mysql-de ihre@email.adresse in einer Mail an die Liste schicken. Weitere Informationen zu dieser Mailingliste finden Sie unter http://www.4t2.com/mysql/.

  • Eine portugiesischsprachige Mailingliste. Sie bestellen sie, indem Sie den Befehl subscribe mysql-br ihre@email.adresse in einer Mail an die Liste schicken.

  • Eine spanischsprachige Mailingliste. Sie bestellen sie, indem Sie den Befehl subscribe mysql ihre@email.adresse in einer Mail an die Liste schicken.

1.7.1.1. Richtlinien für die Benutzung der MySQL-Mailinglisten

Bitte senden Sie keine Mails mit aktiviertem HTML-Modus aus Ihrem Browser. Viele Benutzer lesen ihre Mails nicht mit einem Browser.

Wenn Sie eine Frage beantworten, die an die Mailingliste gesendet wurde, und der Ansicht sind, dass die Antwort von allgemeinem Interesse ist, dann sollten Sie sie an die Liste schicken, statt dem Fragesteller direkt zu schreiben. Formulieren Sie Ihre Antwort allgemein genug, sodass auch andere Benutzer als der Fragesteller davon profitieren können. Bevor Sie einen Beitrag an die Liste schicken, vergewissern Sie sich, dass es sich nicht um eine Wiederholung einer bereits vorhandenen Antwort handelt.

Versuchen Sie, die wesentlichen Aspekte der Frage in der Antwort zusammenzufassen. Sie sind nicht verpflichtet, die gesamte Frage in ihrer ursprünglichen Form zu zitieren.

Wenn Antworten direkt an Sie und nicht an die Mailingliste geschrieben werden, gilt es als lobenswert, die Antworten in zusammengefasster Form an die Liste zu schicken, sodass auch andere Benutzer von den Antworten profitieren können, mit deren Hilfe Sie das Problem beheben konnten.

1.7.2. MySQL-Community-Support in den MySQL-Foren

Die Foren unter http://forums.mysql.com sind eine wichtige Quelle für die Benutzergemeinschaft. Es gibt eine ganze Reihe von Foren, die in die folgenden Kategorien fallen:

  • Migration

  • MySQL verwenden

  • MySQL Connectors

  • Programmiersprachen

  • Tools

  • Anwendungen von Drittanbietern

  • Speicher-Engines

  • MySQL-Technologie

  • SQL-Standards

  • Business

1.7.3. Unterstützung für die MySQL-Community auf Internet Relay Chat (IRC)

Neben den verschiedenen MySQL-Mailinglisten und -Foren finden Sie erfahrene Mitglieder der Gemeinschaft im Internet Relay Chat (IRC). Die folgenden Netzwerke und Kanäle sind die besten, die wir derzeit kennen:

freenode (Serverinformationen unter http://www.freenode.net/)

  • #mysql ist in erster Linie für MySQL-spezifische Fragen gedacht, aber auch allgemeine Fragen zum SQL-Komplex sind willkommen. Auch Fragen zu PHP, Perl oder C in Verbindung mit MySQL sind hier häufig zu finden.

Wenn Sie nach einer IRC-Clientsoftware suchen, um eine Verbindung mit einem IRC-Netzwerk herzustellen, dann werfen Sie einen Blick auf xChat (http://www.xchat.org/). X-Chat (unter GPL-Lizenz) ist für Unix und für Windows-Plattformen erhältlich. (Einen kostenlosen Build von X-Chat finden Sie unter http://www.silverex.org/download/.)

1.8. Wie man Bugs oder Probleme meldet

Bevor Sie einen Bugreport zu einem Problem einreichen, stellen Sie zunächst sicher, dass es sich wirklich um einen Bug handelt und dass dieser nicht bereits gemeldet wurde:

  • Beginnen Sie mit der Suche im MySQL-Online-Manual unter http://dev.mysql.com/doc/. Wir versuchen, das Manual aktuell zu halten, indem wir es häufig mit Lösungen zu neu gefundenen Problemen aktualisieren. Die Änderungshistorie (http://dev.mysql.com/doc/mysql/en/news.html) kann besonders nützlich sein, da es durchaus möglich ist, dass eine neuere Version eine Lösung zu Ihrem Problem enthält.

  • Wenn beim Parsen einer SQL-Anweisung ein Fehler auftritt, überprüfen Sie Ihre Syntax bitte sorgfältig. Wenn Sie keinen Fehler erkennen können, ist es sehr wahrscheinlich, dass Ihre gegenwärtige Version von MySQL Server die verwendete Syntax nicht unterstützt. Wenn Sie die aktuelle Version verwenden und das Manual die von Ihnen verwendete Syntax nicht behandelt, dann unterstützt MySQL Server Ihre Anweisung nicht. In diesem Fall bestehen Ihre Möglichkeiten darin, die Syntax selbst zu implementieren oder eine E-Mail an zu senden und darin um ein Angebot für eine Implementierung zu bitten.

    Wenn das Manual die von Ihnen verwendete Syntax behandelt, aber Sie mit einer älteren Version von MySQL Server arbeiten, überprüfen Sie in der MySQL-Änderungshistorie, wann die Syntax implementiert wurde. In diesem Fall können Sie auf eine neuere Version von MySQL Server aktualisieren.

  • Informationen zur Lösung einiger häufiger Probleme finden Sie unter Anhang A, Probleme und häufig auftretende Fehler.

  • Durchsuchen Sie die Bugdatenbank unter http://bugs.mysql.com/ und überprüfen Sie, ob der Bug gemeldet und ggf. behoben wurde.

  • Durchsuchen Sie die Archive der MySQL-Mailinglisten unter http://lists.mysql.com/. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

  • Sie können auch über http://www.mysql.com/search/ alle Webseiten (einschließlich des Manuals) durchsuchen, die sich auf der Website von MySQL AB befinden.

Wenn Sie im Manual, der Bugdatenbank oder den Archiven der Mailinglisten keine Antwort finden, wenden Sie sich an Ihren lokalen MySQL-Fachmann. Erhalten Sie auch dort keine Antwort auf Ihre Frage, dann melden Sie den Bug bitte unter Beachtung der folgenden Verhaltensregeln.

Die normale Vorgehensweise zur Meldung von Bugs besteht in einem Besuch auf http://bugs.mysql.com/. Dies ist die Adresse unserer Bugdatenbank. Diese Datenbank ist öffentlich und kann von jedem gelesen und durchsucht werden. Wenn Sie sich am System anmelden, können Sie neue Meldungen eingeben. Haben Sie keinen Webzugang, dann können Sie mit dem Skript mysqlbug einen Bugreport erstellen. Das Skript ist am Ende dieses Abschnitts beschrieben.

Bugs, die in die Bugdatenbank unter http://bugs.mysql.com/ eingetragen sind und in einem gegebenen Release behoben wurden, sind in der Änderungshistorie vermerkt.

Wenn Sie einen sensiblen Sicherheitsbug in MySQL gefunden haben, können Sie eine E-Mail an schicken.

Wenn Sie Probleme mit anderen Benutzern diskutieren wollen, können Sie zu diesem Zweck eine der MySQL-Mailinglisten verwenden. Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

Das Verfassen eines Bugreports erfordert Geduld. Wenn Sie dies aber zuallererst tun, sparen Sie sowohl sich selbst als auch uns Zeit. Ein guter Bugreport enthält einen vollständigen Testfall für den Bug, welcher es uns mit hoher Wahrscheinlichkeit ermöglichen wird, ihn bereits im nächsten Release zu beheben. Dieser Abschnitt soll Ihnen dabei helfen, Ihren Bugreport korrekt zu formulieren, sodass Sie keine Zeit mit Dingen verschwenden, die uns nur wenig oder gar nicht helfen. Bitte lesen Sie diesen Abschnitt aufmerksam durch und stellen Sie sicher, dass alle hier beschriebenen Angaben in Ihrem Report enthalten sind.

Sie sollten das Problem bevorzugt mit der aktuellen Produktions- oder Entwicklungsversion von MySQL Server überprüfen, bevor Sie den Report absenden. Der Bug sollte sich problemlos reproduzieren lassen, indem einfach der Befehl mysql test < script_file für Ihren Testfall ausgeführt oder das Shell- oder Perl-Skript gestartet wird, das Sie dem Bugreport hinzufügen. Für jeden Bug, den wir reproduzieren können, stehen die Chancen einer Behebung im nächsten MySQL-Release gut.

Am hilfreichsten ist es, wenn eine gute Beschreibung des Problems dem Bugreport beiliegt. Das bedeutet: Geben Sie ein gutes Beispiel für alles an, was Sie taten, als das Problem auftrat, und beschreiben Sie möglichst detailliert das Problem selbst. Die besten Reports sind diejenigen, die eine vollständige Beschreibung enthalten, wie der Bug oder das Problem reproduziert werden können. Siehe auch Abschnitt E.1.6, „Erzeugen eines Testfalls, wenn Sie Tabellenbeschädigung feststellen“.

Bedenken Sie, dass wir zwar einen Report bearbeiten können, der zu viele Angaben enthält, nicht aber einen solchen, der zu wenig Informationen umfasst. Es kommt häufig vor, dass Tatsachen weggelassen werden, weil der Einreicher annimmt, dass wir das Problem kennen und die Details keine Rolle spielen. Eine Faustregel, der Sie folgen können, lautet: Wenn Sie im Zweifel sind, ob Sie etwas angeben wollen, dann geben Sie es lieber an. Es geht schneller und ist weniger mühsam, ein paar Zeilen mehr in Ihren Report zu schreiben, als länger auf die Antwort warten zu müssen, weil wir bei Ihnen Angaben erfragen müssen, die im eingereichten Bugreport nicht enthalten waren.

Die meistgemachten Fehler in Bugreports bestehen darin, dass (a) die Versionsnummer der verwendeten MySQL-Distribution nicht enthalten und (b) die Plattform, auf der der MySQL Server installiert ist, nicht vollständig (einschließlich der Angaben zu Typ und Versionsnummer der Plattform) beschrieben ist. Dies sind extrem wichtige Informationen, und in 99 von 100 Fällen ist der Bugreport ohne sie wertlos. Sehr oft erhalten wir Fragen wie „Warum funktioniert das bei mir nicht?“. Dann stellen wir fest, dass die angeforderte Funktionalität in der betreffenden MySQL-Version gar nicht implementiert war oder dass ein in einem Report beschriebener Bug in einer neueren MySQL-Version bereits behoben ist. Fehler sind häufig plattformspezifisch. In solchen Fällen ist es praktisch unmöglich für uns, irgendetwas zu beheben, wenn wir weder das Betriebssystem noch die Versionsnummer der Plattform kennen.

Wenn Sie MySQL aus dem Quellcode kompiliert haben, denken Sie bitte auch daran, Angaben zu Ihrem Compiler hinzuzufügen, sofern dies für das Problem relevant ist. Häufig finden Benutzer Bugs in Compilern und glauben dann, dass das Problem MySQL-spezifisch ist. Die meisten Compiler werden fortlaufend weiterentwickelt und von Version zu Version besser. Um zu ermitteln, ob Ihr Problem von Ihrem Compiler abhängt, müssen wir wissen, welchen Compiler Sie verwendet haben. Beachten Sie, dass jedes Kompilierungsproblem als Bug betrachtet und entsprechend gemeldet werden sollte.

Wenn ein Programm eine Fehlermeldung erzeugt, ist es sehr wichtig, auch diese Meldung in Ihrem Report zu erwähnen. Wenn wir versuchen, Erkundigungen in den Archiven einzuziehen, dann ist es am besten, wenn Sie die Fehlermeldung exakt so angeben, wie das Programm sie erzeugt hat. (Beachten Sie im Zweifelsfall auch die Groß-/Kleinschreibung.) Am besten kopieren Sie die gesamte Fehlermeldung über die Zwischenablage in Ihren Report. Versuchen Sie bitte nicht, die Fehlermeldung aus dem Gedächtnis zu rekonstruieren.

Wenn Sie ein Problem in Zusammenhang mit Connector/ODBC (MyODBC) haben, versuchen Sie bitte, eine Trace-Datei zu erzeugen, und schicken diese mit Ihrem Report. Siehe auch Abschnitt 25.1.7.2, „Melden von MyODBC-Problemen und -Fehlern“.

Wenn Ihr Report lange Abfrageausgabezeilen aus Testfällen enthält, die Sie mit dem Befehlszeilen-Tool mysql ausgeführt haben, dann können Sie die Leserlichkeit der Ausgabe mit der Option --vertical oder dem Abschlusszeichen \G erhöhen. Das weiter unten folgende Beispiel für EXPLAIN SELECT demonstriert die Verwendung von \G.

Bitte legen Sie Ihrem Report die folgenden Angaben bei:

  • Die Versionsnummer der von Ihnen verwendeten MySQL-Distribution (z. B. MySQL 5.0.19). Die Versionsnummer ermitteln Sie durch Ausführen von mysqladmin version. Das Programm mysqladmin finden Sie im Verzeichnis bin im MySQL-Installationsverzeichnis.

  • Den Hersteller und das Modell des Computers, auf dem das Problem aufgetreten ist.

  • Name und Version des Betriebssystems. Wenn Sie mit Windows arbeiten, erhalten Sie Namen und Versionsnummer, indem Sie auf das Arbeitsplatz-Symbol doppelklicken und dann den Eintrag „Hilfe/Über Windows“ auswählen. Bei den meisten UNIX-Derivaten gelangen Sie an diese Angaben, indem Sie den Befehl uname -a ausführen.

  • In bestimmten Fällen ist die Menge des (physischen und virtuellen) Speichers relevant. Geben Sie diese Werte im Zweifelsfall auch an.

  • Wenn Sie eine Quelldistribution der MySQL-Software verwenden, geben Sie Namen und Versionsnummer des verwendeten Compilers an. Im Falle einer Binärdistribution nennen Sie den Distributionsnamen.

  • Tritt das Problem während der Kompilierung auf, dann fügen Sie die exakten Fehlermeldungen sowie ein paar Zeilen Kontext im Bereich des problematischen Codes in der Datei hinzu, in dem der Fehler auftritt.

  • Wenn mysqld abstürzt, sollten Sie auch die Anweisung angeben, mit der mysqld zum Absturz gebracht wurde. Diese Information erhalten Sie normalerweise, wenn Sie mysqld mit aktiviertem Abfragelog starten und die Logdatei überprüfen, nachdem mysqld abgestürzt ist. Siehe auch Abschnitt E.1.5, „Logdateien benutzen, um Ursachen für Fehler in mysqld zu finden“.

  • Wenn eine Datenbanktabelle mit dem Problem in Zusammenhang steht, geben Sie die Ausgabe der Anweisung SHOW CREATE TABLE db_name.tbl_name im Bugreport an. Dies stellt eine sehr einfache Möglichkeit dar, die Definition einer beliebigen Tabelle in der Datenbank zu ermitteln. Mithilfe dieser Information können wir die Situation, in der das Problem bei Ihnen auftrat, auf unseren Systemen nachstellen.

  • Bei leistungsspezifischen Bugs oder Problemen mit SELECT-Anweisungen sollten Sie außerdem die Ausgabe von EXPLAIN SELECT ... und zumindest die Anzahl der Datensätze angeben, die die SELECT-Anweisung erzeugt. Ferner hinzufügen sollten Sie die Ausgabe von SHOW CREATE TABLE tbl_name für jede betroffene Tabelle. Je mehr Angaben Sie über die Umstände machen, desto größer ist die Wahrscheinlichkeit, dass wir Ihnen helfen können.

    Nachfolgend finden Sie ein Beispiel für einen sehr guten Bugreport. Die Anweisungen werden mit dem Befehlszeilen-Tool mysql ausgeführt. Beachten Sie die Verwendung des Abschlusszeichens \G bei Anweisungen, die andernfalls sehr lange, schwierig zu lesende Ausgabezeilen erzeugen würden.

    mysql> SHOW VARIABLES; mysql> SHOW COLUMNS FROM ...\G <output from SHOW COLUMNS> mysql> EXPLAIN SELECT ...\G <output from EXPLAIN> mysql> FLUSH STATUS; mysql> SELECT ...; <A short version of the output from SELECT, including the time taken to run the query> mysql> SHOW STATUS; <output from SHOW STATUS>
  • Wenn während der Ausführung von mysqld ein Bug oder Problem auftritt, dann versuchen Sie, ein Eingabeskript hinzuzufügen, welches die Anomalie reproduziert. Dieses Skript sollte alle erforderlichen Quellcodedateien enthalten. Je exakter das Skript die betreffende Situation reproduzieren kann, umso besser. Wenn Sie einen reproduzierbaren Test erstellen können, sollten Sie diesen als Anhang an den Bugreport anhängen.

    Können Sie kein Skript erstellen, dann sollten Sie Ihrem Report zumindest die Ausgabe von mysqladmin variables extended-status processlist hinzufügen, damit wir einige Anhaltspunkte dazu erhalten, wie Ihr System arbeitet.

  • Können Sie keinen Testfall mit nur wenigen Datensätzen erstellen oder ist die Testtabelle zu groß, um in den Bugreport eingefügt werden zu können (d. h., sie umfasst mehr als zehn Datensätze), dann sollten Sie Ihre Tabellen mit mysqldump speichern und eine README-Datei erstellen, die Ihr Problem beschreibt. Erstellen Sie ein komprimiertes Archiv Ihrer Dateien mithilfe von tar und gzip oder zip und übertragen Sie das Archiv dann via FTP an ftp://ftp.mysql.com/pub/mysql/upload/. Tragen Sie das Problem danach in unsere Bugdatenbank unter http://bugs.mysql.com/ ein.

  • Wenn Sie der Ansicht sind, dass der MySQL Server ein merkwürdiges Ergebnis für die Anweisung erzeugt, fügen Sie nicht nur dieses, sondern auch Ihre Ansicht bezüglich des von Ihnen erwarteten Ergebnisses und eine Beschreibung der Grundlage dieser Ansicht hinzu.

  • Wenn Sie ein Beispiel des Problems angeben, sollten Sie am besten Tabellennamen, Variablennamen usw. verwenden, die in Ihrer tatsächlichen Situation zum Einsatz kommen, statt neue Namen einzuführen. Das Problem könnte auch mit dem Namen einer Tabelle oder Variablen zusammenhängen. Solche Fälle mögen selten sein, aber besser ist es, auf der sicheren Seite zu stehen. Schließlich sollte es für Sie einfacher sein, ein Beispiel anzugeben, das Ihre tatsächlichen Umstände verwendet, und für uns ist dies in jedem Fall besser. Wenn Sie wollen, dass bestimmte Daten im Bugreport für Dritte unsichtbar bleiben, können Sie ihn via FTP an ftp://ftp.mysql.com/pub/mysql/upload/ übertragen. Sind die Daten wirklich derart geheim, dass Sie sie noch nicht einmal uns zeigen wollen, dann können Sie auch ein Beispiel unter Verwendung anderer Namen erstellen; dies stellt allerdings nur den letzten Ausweg dar.

  • Fügen Sie, sofern möglich, alle Optionen an, die Sie für die betreffenden Programme angegeben hatten. Geben Sie etwa die Optionen an, die Sie beim Start des Servers mysqld verwenden, sowie auch solche, die Sie bei der Ausführung von MySQL-Clientprogrammen verwendet haben. Die Optionen für Programme wie mysqld und mysql sowie für das Skript configure sind für die Behebung von Problemen häufig unentbehrlich, und es kann nie schaden, sie hinzuzufügen. Wenn Ihr Problem in Zusammenhang mit einem Programm steht, das in einer Sprache wie Perl oder PHP geschrieben ist, fügen Sie bitte die Versionsnummer des Sprachprozessors sowie die Versionen aller Module an, die das Programm verwendet. Setzen Sie beispielsweise ein Perl-Skript ein, das die Module DBI und DBD::mysql benutzt, dann müssen Sie die Versionsnummern von Perl, DBI und DBD::mysql angeben.

  • Bezieht sich Ihre Frage auf das Berechtigungssystem, dann führen Sie bitte die Ausgaben von mysqlaccess und mysqladmin reload sowie alle Fehlermeldungen an, die Sie beim Verbindungsversuch erhalten. Wenn Sie Ihre Berechtigungen testen, sollten Sie zunächst mysqlaccess ausführen. Nachfolgend starten Sie mysqladmin reload version und versuchen, eine Verbindung mit dem problematischen Programm herzustellen. Das Programm mysqlaccess finden Sie im Verzeichnis bin im MySQL-Installationsverzeichnis.

  • Wenn Sie einen Patch für einen Bug haben, fügen Sie ihn hinzu. Gehen Sie aber nicht davon aus, dass wir lediglich diesen Patch benötigen oder dass wir ihn verwenden können, wenn Sie bestimmte Angaben wie etwa Testfälle weglassen, die den Bug demonstrieren, den Sie mit Ihrem Patch beheben. Unter Umständen stellen wir Probleme bei Ihrem Patch fest oder verstehen ihn überhaupt nicht. In diesem Fall können wir ihn natürlich nicht verwenden.

    Wenn wir den Zweck des Patches nicht exakt verifizieren können, verwenden wir ihn auch nicht. In diesem Fall sind Testfälle sehr hilfreich. Zeigen Sie, dass der Patch das Problem in allen Situationen behebt, die auftreten können. Können wir einen (ggf. auch seltenen) Fall ermitteln, in dem der Patch nicht funktioniert, dann ist er möglicherweise nutzlos.

  • Mutmaßungen bezüglich des Wesens, der Ursache oder der Abhängigkeiten eines Bugs sind in der Regel falsch. Sogar das MySQL-Team kann solche Dinge nicht erraten, sondern muss zunächst einmal mit einem Debugger die wirkliche Ursache des Bugs ermitteln.

  • Geben Sie in Ihrem Bugreport an, dass Sie das Referenzmaterial und das Mailarchiv überprüft haben, damit andere wissen, dass Sie zunächst versucht haben, das Problem selbst zu lösen.

  • Wenn das Problem darin besteht, dass Ihre Daten beschädigt zu sein scheinen oder Sie Fehler erhalten, wenn Sie auf eine bestimmte Tabelle zugreifen, dann sollten Sie Ihre Tabellen zuerst überprüfen und dann versuchen, sie zu reparieren. Hierzu verwenden Sie CHECK TABLE und REPAIR TABLE oder aber myisamchk. Siehe auch Kapitel 5, Datenbankverwaltung.

    Wenn Sie Windows verwenden, überprüfen Sie bitte den Wert von lower_case_table_names mit dem Befehl SHOW VARIABLES LIKE 'lower_case_table_names'. Diese Variable beeinflusst, wie der Server die Groß-/Kleinschreibung von Datenbank- und Tabellennamen behandelt. Die Auswirkung auf einen gegebenen Wert sollte so sein wie in Abschnitt 9.2.2, „Groß-/Kleinschreibung in Namen“, beschrieben.

  • Wenn Fälle beschädigter Tabellen bei Ihnen häufig auftreten, sollten Sie herausfinden, wann und warum dies passiert. In diesem Fall enthält das Fehlerlog im MySQL-Datenverzeichnis unter Umständen Informationen dazu, was geschehen ist. (Es handelt sich um die Datei mit dem Suffix .err im Dateinamen.) Siehe auch Abschnitt 5.12.1, „Die Fehler-Logdatei“. Bitte fügen Sie alle relevanten Angaben aus dieser Datei in Ihrem Bugreport an. Normalerweise sollte mysqld eine Tabelle niemals zum Absturz bringen, sofern es nicht während eines laufenden Updates terminiert wurde. Wenn Sie erkennen können, warum mysqld terminiert wird, dann ist es für uns viel einfacher, Ihnen einen Fix für dieses Problem zur Verfügung zu stellen. Siehe auch Abschnitt A.1, „Wie man feststellt, was Probleme verursacht“.

  • Laden Sie, sofern möglich, die aktuellste Version von MySQL Server herunter und installieren Sie sie. Überprüfen Sie dann, ob Ihr Problem auf diese Weise gelöst wird. Alle Versionen der MySQL-Software wurden umfassend getestet und sollten problemlos funktionieren. Wir achten bei unseren Entwicklungen auf größtmögliche Abwärtskompatibilität, d. h., Sie sollten problemlos zwischen verschiedenen MySQL-Versionen wechseln können. Siehe auch Abschnitt 2.1.2, „Welche MySQL-Version Sie benutzen sollten“.

Wenn Sie keinen Webzugang haben und einen Bug nicht auf http://bugs.mysql.com/ melden können, erzeugen Sie mit dem Skript mysqlbug einen Bugreport (oder einen Report zu einem beliebigen anderen Problem). mysqlbug unterstützt Sie bei der Erzeugung eines Reports, denn ein Großteil der erforderlichen Informationen wird automatisch ermittelt. Sollte jedoch etwas fehlen, dann fügen Sie es Ihrer Meldung bitte hinzu. mysqlbug finden Sie im Verzeichnis scripts (Quelldistribution) bzw. im Verzeichnis bin unter Ihrem MySQL-Installationsverzeichnis (Binärdistribution).

1.9. Wie kompatibel zum SQL-Standard ist MySQL?

Dieser Abschnitt beschreibt das Verhältnis von MySQL zu den SQL-Standards von ANSI und ISO. MySQL weist eine Reihe von Erweiterungen gegenüber dem SQL-Standard auf; hier finden Sie Informationen darüber, welche Erweiterungen dies sind und wie Sie sie benutzen. Ferner sind Informationen zu den Funktionalitäten, die in MySQL fehlen, und dazu enthalten, wie Sie einige dieser Unterschiede umgehen können.

Der SQL-Standard wird seit 1986 fortlaufend entwickelt, und es existieren verschiedene Versionen. In diesem Handbuch bezeichnet „SQL-92“ den im Jahr 1992 veröffentlichten Standard, „SQL:1999“ die 1999 veröffentlichte Version und„SQL:2003“ die aktuelle Variante des Standards. Wendungen wie „der SQL-Standard“ oder „Standard-SQL“ werden generell zur Bezeichnung der aktuellen Version des SQL-Standards verwendet.

Eines unserer wichtigsten Anliegen in Bezug auf das Produkt besteht darin, die Kompatibilität mit dem SQL-Standard zu optimieren, ohne dabei Geschwindigkeit oder Zuverlässigkeit von MySQL zu opfern. Wir scheuen nicht davor zurück, SQL mit Erweiterungen zu ergänzen oder Nicht-SQL-Funktionalitäten zu unterstützen, wenn dies den Nutzen von MySQL Server für einen Großteil unserer Benutzer erheblich steigert. Die HANDLER-Schnittstelle ist ein Beispiel für diese Strategie. Siehe auch Abschnitt 13.2.3, „HANDLER.

Wir werden auch weiterhin sowohl transaktionale als auch nichttransaktionale Datenbanken unterstützen, damit der unternehmenskritische Einsatz rund um die Uhr wie auch eine hohe Beanspruchung im Web- oder Protokollierungseinsatz möglich sind.

MySQL Server wurde ursprünglich für die Arbeit mit mittelgroßen Datenbanken (10 bis 100 Millionen Datensätze bzw. 100 Mbyte pro Tabelle) auf Kleincomputern entwickelt. Heute hingegen werden mit MySQL Server terabytegroße Datenbanken verarbeitet. Der Code kann aber auch in einer reduzierten Version kompiliert werden, die für mobile oder integrierte Geräte geeignet ist. Die kompakte Struktur des MySQL Servers ermöglicht Weiterentwicklungen in beiden Richtungen, ohne dass es im Source-Tree zu Konflikten kommt.

Derzeit streben wir keine Echtzeitunterstützung an, obwohl die Replikationsmerkmale von MySQL die wesentlichen Funktionalitäten bieten.

MySQL unterstützt Clustering für Hochverfügbarkeitsdatenbanken mithilfe der NDBCluster-Speicher-Engine. Siehe auch Kapitel 16, MySQL Cluster.

Die XML-Funktionalität wird ab MySQL 5.1 implementiert. Diese Version unterstützt den W3C XPath-Standard bereits weitgehend. Im Zuge der Fortentwicklung von MySQL planen wir, die XML-Unterstützung weiter zu optimieren.

1.9.1. An welche Standards hält sich MySQL?

Unser Ziel ist es, die SQL-Standards von ANSI und ISO vollständig zu unterstützen, ohne Zugeständnisse bezüglich der Geschwindigkeit oder der Qualität des Codes zu machen.

1.9.2. Auswahl der SQL-Modi

Der MySQL Server kann in verschiedenen SQL-Modi betrieben werden und diese Modi auf unterschiedliche Weise für verschiedene Clients anwenden. Diese Funktionalität erlaubt es jeder Anwendung, den Betriebsmodus des Servers an die eigenen Anforderungen anzupassen.

Die SQL-Modi steuern Aspekte des Serverbetriebs, z. B. welche SQL-Syntax MySQL unterstützen soll und welche Art der Datengültigkeitsprüfungen durchzuführen ist. Dies erleichtert die Verwendung von MySQL in verschiedenen Umgebungen und in Verbindung mit anderen Datenbankservern.

Sie können den SQL-Standardmodus einstellen, indem Sie mysqld mit der Option --sql-mode="mode_value" starten. Ab MySQL 4.1 können Sie den Modus auch während der Laufzeit ändern, indem Sie die Systemvariable sql_mode mit der Anweisung SET [SESSION|GLOBAL] sql_mode='mode_value' einstellen.

Weitere Informationen zur Einstellung des SQL-Modus finden Sie in Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

1.9.3. MySQL im ANSI-Modus laufen lassen

Sie können mysqld mithilfe der Startoption --ansi zur Ausführung im ANSI-Modus anweisen. Die Ausführung des Servers im ANSI-Modus entspricht dem Serverstart mit den folgenden Optionen:

--transaction-isolation=SERIALIZABLE --sql-mode=ANSI

Ab MySQL 4.1.1 können Sie den gleichen Effekt während der Laufzeit erzielen, indem Sie die folgenden beiden Anweisungen ausführen:

SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET GLOBAL sql_mode = 'ANSI';

Sie können wie folgt überprüfen, dass das Einstellen der Systemvariablen sql_modeauf 'ANSI' alle für den ANSI-Modus relevanten SQL-Modusoptionen aktiviert:

mysql> SET GLOBAL sql_mode='ANSI';
mysql> SELECT @@global.sql_mode;
        -> 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI'

Beachten Sie, dass die Ausführung des Servers im ANSI-Modus mithilfe der Option --ansi nicht ganz zum gleichen Ergebnis führt wie die Einstellung 'ANSI' für den SQL-Modus. Die Option --ansi betrifft den SQL-Modus und stellt ferner die Stufe der Transaktionsisolierung ein. Vom Einstellen des SQL-Modus auf 'ANSI' hingegen ist die Isolierungsstufe nicht betroffen.

Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld, und Abschnitt 1.9.2, „Auswahl der SQL-Modi“.

1.9.4. MySQL-Erweiterungen zu ANSI SQL92

MySQL Server unterstützt einige Erweiterungen, die Sie in anderen Datenbankmanagementsystemen wahrscheinlich nicht finden werden. Beachten Sie in jedem Fall, dass, wenn Sie diese Erweiterungen verwenden, Ihr Code nicht auf andere SQL-Server portierbar ist. In manchen Fällen können Sie Code schreiben, der MySQL-Erweiterungen enthält, aber trotzdem portierbar ist; Sie müssen dann Kommentare in der folgenden Form verwenden:

/*! MySQL-specific code */

In diesem Fall verarbeitet MySQL Server den Code innerhalb des Kommentars wie normale SQL-Anweisungen; andere SQL-Server hingegen ignorieren die Erweiterungen. So erkennt MySQL Server beispielsweise anders als andere Server das Schlüsselwort STRAIGHT_JOIN in der folgenden Anweisung:

SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...

Wenn Sie nach dem Zeichen ‘!’ die Versionsnummer angeben, wird die Syntax nur ausgeführt, wenn die betreffende oder eine neuere MySQL-Version verwendet wird. Das Schlüsselwort TEMPORARY im folgenden Kommentar wird nur von Servern ausgeführt, auf denen MySQL 3.23.02 oder höher läuft:

CREATE /*!32302 TEMPORARY */ TABLE t (a INT);

Die folgenden Beschreibungen listen MySQL-Erweiterungen nach Kategorie sortiert auf.

  • Organisation der Daten auf der Festplatte

    MySQL Server ordnet jede Datenbank einem Unterverzeichnis des MySQL-Datenverzeichnisses zu. Tabellen innerhalb einer Datenbank entsprechen den Dateinamen im Datenbankverzeichnis. Dies hat einige Auswirkungen:

    • Die Groß-/Kleinschreibung bei Datenbank- und Tabellennamen in MySQL Server wird bei solchen Betriebssystemen unterschieden, die auch eine Unterscheidung der Groß-/Kleinschreibung bei den Dateinamen vornehmen (also etwa die Mehrzahl der Unix-Systeme). Siehe auch Abschnitt 9.2.2, „Groß-/Kleinschreibung in Namen“.

    • Sie können Standardsystembefehle zum Sichern, Umbenennen, Verschieben, Löschen und Kopieren von Tabellen verwenden, die von der MyISAM-Speicher-Engine verwaltet werden. So können Sie eine MyISAM-Tabelle etwa umbenennen, indem Sie die Namen der .MYD-, .MYI- und .frm-Dateien ändern, denen die Tabelle entspricht. (Nichtsdestoweniger ist die Verwendung von RENAME TABLE bzw. ALTER TABLE ... RENAME und die Umbenennung der Dateien durch den Server vorzuziehen.)

    Datenbank- und Tabellennamen dürfen keine Pfadtrennzeichen (‘/’, ‘\’) enthalten.

  • Allgemeine Sprachsyntax

    • Standardmäßig dürfen Strings von den Zeichen ‘"’ oder ‘'’ umschlossen sein und nicht nur von ‘'’. (Wenn der SQL-Modus ANSI_QUOTES aktiviert ist, dürfen die Strings nur vom Zeichen ‘'’ umfasst sein; Strings, die von ‘"’ umfasst sind, interpretiert der Server als Bezeichner.)

    • Verwendung von ‘\’ als Escape-Zeichen in Strings.

    • In SQL-Anweisungen können Sie mithilfe der Syntax db_name.tbl_name auf Tabellen aus anderen Datenbanken zugreifen. Einige SQL-Server bieten die gleiche Funktionalität, nennen dies aber User-Space. MySQL Server unterstützt Tabellenräume, wie sie etwa in der folgenden Anweisung verwendet werden, nicht: CREATE TABLE ralph.my_table...IN my_tablespace.

  • SQL-Anweisungssyntax

    • Die Anweisungen ANALYZE TABLE, CHECK TABLE, OPTIMIZE TABLE und REPAIR TABLE.

    • Die Anweisungen CREATE DATABASE, DROP DATABASE und ALTER DATABASE. Siehe auch Abschnitt 13.1.3, „CREATE DATABASE, Abschnitt 13.1.6, „DROP DATABASE, und Abschnitt 13.1.1, „ALTER DATABASE.

    • Die Anweisung DO.

    • EXPLAIN SELECT ruft eine Beschreibung dazu auf, wie Tabellen durch die Abfrageoptimierung verarbeitet werden.

    • Die Anweisungen FLUSH und RESET.

    • Die Anweisung SET. Siehe auch Abschnitt 13.5.3, „SET.

    • Die Anweisung SHOW. Siehe auch Abschnitt 13.5.4, „SHOW. Ab MySQL 5.0 lassen sich die Angaben, die von vielen der MySQL-spezifischen SHOW-Anweisungen erzeugt werden, auf standardkonformere Weise durch Verwendung von SELECT zur Abfrage von INFORMATION_SCHEMA erhalten. Siehe auch Kapitel 22, Die Datenbank INFORMATION_SCHEMA.

    • Verwenden von LOAD DATA INFILE. In vielen Fällen ist die Syntax kompatibel mit Oracles LOAD DATA INFILE. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

    • Verwendung von RENAME TABLE. Siehe auch Abschnitt 13.1.9, „RENAME TABLE.

    • Verwendung von REPLACE anstelle der Kombination DELETE und INSERT. Siehe auch Abschnitt 13.2.6, „REPLACE.

    • Verwendung von CHANGE col_name, DROP col_name oder DROP INDEX, IGNORE oder RENAME in ALTER TABLE-Anweisungen. Verwendung mehrerer ADD-, ALTER-, DROP- oder CHANGE-Klauseln in einer ALTER TABLE-Anweisung. Siehe auch Abschnitt 13.1.2, „ALTER TABLE.

    • Verwendung von Indexnamen, Indizes für das Präfix einer Spalte und Verwendung von INDEX oder KEY in CREATE TABLE-Anweisungen. Siehe auch Abschnitt 13.1.5, „CREATE TABLE.

    • Verwendung von TEMPORARY oder IF NOT EXISTS mit CREATE TABLE.

    • Verwendung von IF EXISTS mit DROP TABLE und DROP DATABASE.

    • Die Möglichkeit, mehrere Tabellen mit einer einzigen DROP TABLE-Anweisung zu löschen.

    • Die Klauseln ORDER BY und LIMIT der Anweisungen UPDATE und DELETE.

    • Die Syntax INSERT INTO ... SET col_name = ....

    • Die Klausel DELAYED der Anweisungen INSERT und REPLACE.

    • Die Klausel LOW_PRIORITY der Anweisungen INSERT, REPLACE, DELETE und UPDATE.

    • Verwendung von INTO OUTFILE oder INTO DUMPFILE in SELECT-Anweisungen. Siehe auch Abschnitt 13.2.7, „SELECT.

    • Optionen wie STRAIGHT_JOIN oder SQL_SMALL_RESULT in SELECT-Anweisungen.

    • In der Klausel GROUP BY müssen Sie nicht alle gewählten Spalten benennen. Hierdurch erhalten Sie eine bessere Leistung bei einigen sehr speziellen, aber trotzdem recht häufig auftretenden Abfragen. Siehe auch Abschnitt 12.11, „Funktionen und Modifizierer für die Verwendung in GROUP BY-Klauseln“.

    • Sie können ASC und DESC mit GROUP BY und nicht nur mit ORDER BY festlegen.

    • Die Möglichkeit, Variablen in einer Anweisung mit dem Zuweisungsoperator := festzulegen:

      mysql> SELECT @a:=SUM(total),@b=COUNT(*),@a/@b AS avg
          -> FROM test_table;
      mysql> SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
      
  • Datentypen

    • Die Datentypen MEDIUMINT, SET und ENUM sowie die verschiedenen BLOB- und TEXT-Datentypen.

    • Die Datentypattribute AUTO_INCREMENT, BINARY, NULL, UNSIGNED und ZEROFILL.

  • Funktionen und Operatoren

    • Um Benutzern anderer SQL-Umgebungen den Umstieg auf MySQL zu erleichtern, unterstützt MySQL Server Aliase für eine Reihe von Funktionen. So unterstützen etwa alle String-Funktionen sowohl die Standard-SQL- als auch die ODBC-Syntax.

    • MySQL Server fasst die Operatoren || und && als logisches ODER bzw. UND auf, wie man es von der Programmiersprache C her kennt. In MySQL Server sind || und OR Synonyme; Gleiches gilt für && und AND. Aufgrund dieser praktischen syntaktischen Eigenschaften unterstützt MySQL Server den Standard-SQL-Operator || für die String-Verkettung nicht; verwenden Sie stattdessen CONCAT(). Da CONCAT() eine beliebige Anzahl von Argumenten entgegennimmt, ist es ganz einfach, die Verwendung des Operators || in MySQL Server nachzubilden.

    • Verwendung von COUNT(DISTINCT value_list), wobei value_list mehr als ein Element aufweist.

    • Standardmäßig wird bei String-Vergleichen die Groß-/Kleinschreibung unterschieden, wobei die Sortierreihenfolge vom aktuellen Zeichensatz bestimmt wird; dieser ist vorgabeseitig latin1 (cp1252 West European). Wenn Sie das nicht wollen, sollten Sie Ihre Spalten mit dem Attribut BINARY deklarieren oder BINARY zur Umwandlung verwenden, was Vergleiche auf der Basis des zugrunde liegenden Zeichensatzes (statt der lexikalischen Anordnung) ermöglicht.

    • Der Operator % ist ein Synonym zu MOD(). Infolgedessen ist N % M gleichbedeutend mit MOD(N,M). % wird für C-Programmierer und aus Gründen der Kompatibilität mit PostgreSQL unterstützt.

    • Die Operatoren =, <>, <=,<, >=,>, <<, >>, <=>, AND, OR und LIKE können in Ausdrücken in der Ausgabespaltenliste (links von FROM) in SELECT-Anweisungen verwendet werden. Ein Beispiel:

      mysql> SELECT col1=1 AND col2=2 FROM my_table;
      
    • Die Funktion LAST_INSERT_ID() gibt den aktuellen AUTO_INCREMENT-Wert zurück. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.

    • LIKE ist für numerische Werte zulässig.

    • Die Operatoren REGEXP and NOT REGEXP für erweiterte reguläre Ausdrücke.

    • CONCAT() oder CHAR() mit einem oder mehr als zwei Argumenten. (In MySQL Server können diese Funktionen eine variable Anzahl von Argumenten entgegennehmen.)

    • Die Funktionen BIT_COUNT(), CASE, ELT(), FROM_DAYS(), FORMAT(), IF(), PASSWORD(), ENCRYPT(), MD5(), ENCODE(), DECODE(), PERIOD_ADD(), PERIOD_DIFF(), TO_DAYS() und WEEKDAY().

    • Verwendung von TRIM() zum Zurechtschneiden von Teil-Strings. Standard-SQL unterstützt nur die Entfernung einzelner Zeichen.

    • Die GROUP BY-Funktionen STD(), BIT_OR(), BIT_AND(), BIT_XOR() und GROUP_CONCAT(). Siehe auch Abschnitt 12.11, „Funktionen und Modifizierer für die Verwendung in GROUP BY-Klauseln“.

Eine priorisierte Liste mit Angaben dazu, wann MySQL Server durch neue Erweiterungen ergänzt wird, finden Sie im MySQL-Entwicklungsfahrplan unter http://dev.mysql.com/doc/mysql/en/roadmap.html.

1.9.5. MySQL: Unterschiede im Vergleich zu ANSI SQL92

Wir versuchen, MySQL Server möglichst nah an die ANSI-SQL- und ODBC-SQL-Standards zu halten. Allerdings führt MySQL Server manche Operationen in bestimmten Fällen anders aus:

  • Bei VARCHAR-Spalten werden führende Leerzeichen beim Speichern des Werts entfernt (dies wurde in MySQL 5.0.3 behoben). Siehe auch Abschnitt A.8, „Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL“.

  • In manchen Fällen werden CHAR-Spalten stillschweigend in VARCHAR-Spalten konvertiert, wenn Sie eine Tabelle definieren oder ihre Struktur ändern (dies wurde in MySQL 5.0.3 behoben).

  • Es gibt eine Reihe von Unterschieden zwischen den Berechtigungssystemen von MySQL und Standard-SQL. Beispielsweise werden in MySQL Berechtigungen für eine Tabelle nicht automatisch widerrufen, wenn Sie die Tabelle löschen. Um die Berechtigungen für die Tabelle zu widerrufen, müssen Sie explizit eine REVOKE-Anweisung absetzen. Weitere Informationen finden Sie unter Abschnitt 13.5.1.5, „REVOKE.

  • Die Funktion CAST() unterstützt die Umwandlung in REAL oder BIGINT nicht. Siehe auch Abschnitt 12.8, „Cast-Funktionen und Operatoren“.

  • Standard-SQL setzt voraus, dass eine HAVING-Klausel in einer SELECT-Anweisung auf Spalten in der GROUP BY-Klausel verweist. Dies ist erst ab MySQL 5.0.2 möglich.

1.9.5.1. Unterstützung für Unterabfragen

MySQL 4.1 und höher unterstützen Unterabfragen und abgeleitete Tabellen. Eine „Unterabfrage“ ist eine SELECT-Anweisung, die mit einer anderen Anweisung verschachtelt ist. Eine „abgeleitete Tabelle“ (eine unbenannte Sicht) ist eine Unterabfrage in der FROM-Klausel einer anderen Anweisung. Siehe auch Abschnitt 13.2.8, „Syntax von Unterabfragen“.

Bei MySQL-Versionen vor 4.1 können die meisten Unterabfragen mithilfe von Joins oder anderer Methoden umformuliert werden. Beispiele zu dieser Vorgehensweise finden Sie unter Abschnitt 13.2.8.11, „Umschreiben von Unterabfragen in Joins für frühere MySQL-Versionen“.

1.9.5.2. SELECT INTO TABLE

MySQL Server unterstützt die Sybase SQL-Erweiterung SELECT ... INTO TABLE nicht. Stattdessen verwendet MySQL Server die Standard-SQL-Syntax INSERT INTO ... SELECT, mit der im Wesentlichen das Gleiche erreicht werden kann. Siehe auch Abschnitt 13.2.4.1, „INSERT ... SELECT. Ein Beispiel:

INSERT INTO tbl_temp2 (fld_id)
    SELECT tbl_temp1.fld_order_id
    FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

Alternativ können Sie auch SELECT ... INTO OUTFILE oder CREATE TABLE ... SELECT verwenden.

Ab MySQL 5.0 können Sie SELECT ... INTO mit benutzerdefinierten Variablen verwenden. Die gleiche Syntax kann ebenfalls in gespeicherten Routinen mithilfe von Cursorn und lokalen Variablen eingesetzt werden. Siehe auch Abschnitt 19.2.7.3, „SELECT ... INTO-Anweisung“.

1.9.5.3. Transaktionen

Die Versionen 3.23-max und alle Versionen ab 4.0 von MySQL Server unterstützen Transaktionen mit transaktionalen InnoDB- und BDB-Speicher-Engines. InnoDB bietet vollständige ACID-Konformität. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen. Informationen zu InnoDB-spezifischen Unterschieden zu Standard-SQL bezüglich der Behandlung von Transaktionsfehlern finden Sie in Abschnitt 14.2.15, „InnoDB-Fehlerbehandlung“.

Die anderen nichttransaktionalen Speicher-Engines in MySQL Server (wie etwa MyISAM) folgen einem anderen Muster der Datenintegrität, welches „atomare Operationen“ genannt wird. Aus transaktionaler Sicht arbeiten MyISAM-Tabellen quasi immer im Modus AUTOCOMMIT=1. Atomare Operationen bieten häufig vergleichbare Integrität bei besserer Leistung.

Da MySQL Server beide Muster unterstützt, können Sie selbst entscheiden, ob Ihre Anwendungen besser mit der Geschwindigkeit atomarer Operationen oder der Verwendung der Transaktionsfunktionalität bedient sind. Diese Auswahl lässt sich pro Tabelle treffen.

Wie bereits angemerkt, fällt die Entscheidung zwischen transaktionalen und nichttransaktionalen Speicher-Engines in erster Linie aufgrund von Leistungsanforderungen. Transaktionale Tabellen haben einen wesentlich höheren Bedarf an Speicher- und Festplattenkapazität und benötigen zudem mehr Prozessorleistung. Andererseits bieten transaktionale Speicher-Engines wie InnoDB auch viele wesentliche Vorteile. Der modulare Aufbau von MySQL Server erlaubt die gleichzeitige Nutzung verschiedener Speicher-Engines zur Erfüllung unterschiedlicher Bedürfnisse und für optimale Leistung in allen Situationen.

Wie aber nutzen Sie nun die Funktionen von MySQL Server zur Aufrechterhaltung einer strikten Integrität auch bei nichttransaktionalen MyISAM-Tabellen, und wie stehen diese Funktionen im Vergleich mit transaktionalen Speicher-Engines da?

  • Wenn Ihre Anwendungen so geschrieben sind, dass sie in kritischen Situationen von der Fähigkeit zum Aufruf von ROLLBACK anstelle von COMMIT abhängen, dann sind Transaktionen praktischer. Mit Transaktionen lässt sich auch sicherstellen, dass nicht abgeschlossene Updates oder beschädigende Aktionen nicht in die Datenbank übertragen werden; der Server hat die Möglichkeit, einen automatischen Rollback durchzuführen, und Ihre Datenbank ist gerettet.

    Wenn Sie nichttransaktionale Tabellen verwenden, gestattet Ihnen MySQL Server in fast allen Fällen die Lösung potenzieller Probleme durch Integrierung einfacher Prüfungen vor Updates und Ausführung simpler Skripten, die die Datenbank auf Inkonsistenzen untersuchen und diese ggf. automatisch reparieren bzw. Warnmeldungen anzeigen. Beachten Sie, dass Sie Tabellen normalerweise mithilfe der MySQL-Logdatei oder einer zusätzlichen Logdatei reparieren, ohne dass die Datenintegrität hiervon beeinträchtigt würde.

  • In der Mehrzahl der Fälle lassen sich kritische transaktionale Updates so umformulieren, dass sie atomar sind. Allgemein gesprochen lassen sich alle Integritätsprobleme, die sich mit Transaktionen lösen lassen, mit LOCK TABLES oder atomaren Updates beseitigen. Hierdurch ist sichergestellt, dass ein Vorgang serverseitig nicht abgebrochen wird – ein Problem, welches bei transaktionalen Datenbanksystemen häufig auftritt.

  • Um unabhängig davon, ob Sie transaktionale Tabellen verwenden, mit MySQL Server sicher arbeiten zu können, müssen Sie nur über Backups verfügen und die binäre Protokollierung aktiviert haben. Sind diese Voraussetzungen erfüllt, dann können Sie wie bei anderen transaktionalen Datenbanksystemen einen fehlerlosen Zustand jederzeit wiederherstellen. Sicherungskopien sollten immer vorhanden sein – egal, welches Datenbanksystem Sie verwenden.

Das transaktionale Muster hat Vor- und Nachteile. Viele Benutzer und Anwendungsentwickler wissen die Einfachheit zu schätzen, sich um Probleme „herumzuprogrammieren“, bei denen ein Abbruch erforderlich ist oder erforderlich zu sein scheint. Doch sogar dann, wenn Sie mit dem atomaren Operationsmuster noch nicht oder mit Transaktionen recht gut vertraut sind, sollten Sie den Geschwindigkeitsvorteil berücksichtigen, den nicht transaktionale Tabellen bieten; immerhin liegt die Verarbeitungsgeschwindigkeit drei- bis fünfmal höher als bei optimal programmierten transaktionalen Tabellen.

In Situationen, in denen die Integrität eine entscheidende Rolle spielt, bietet MySQL Server die Zuverlässigkeit und Integrität transaktionaler Tabellen auch für nichttransaktionale Tabellen. Wenn Sie Tabellen mit LOCK TABLES sperren, werden alle Updates so lange angehalten, bis die Integritätsprüfungen durchgeführt wurden. Wenn Sie eine READ LOCAL-Sperre (im Gegensatz zur Schreibsperre) für eine Tabelle setzen, die gleichzeitiges Einfügen am Tabellenende gestattet, ist das Lesen ebenso möglich wie das Einfügen durch andere Clients. Der Client, für den die Lesesperre gesetzt ist, sieht die neu hinzugefügten Datensätze erst, wenn die Sperre aufgehoben wird. Mit INSERT DELAYED können Sie Einfügungen schreiben, die in eine lokale Warteschlange aufgenommen werden, bis die Sperren aufgehoben wurden. In diesem Fall muss der Client nicht warten, bis der Einfügevorgang abgeschlossen ist. Siehe auch Abschnitt 7.3.3, „Gleichzeitige Einfügevorgänge“, und Abschnitt 13.2.4.2, „INSERT DELAYED.

Atomar“, wie wir es hier verstehen, hat nichts mit Zauberei zu tun. Damit ist lediglich gemeint, dass gewährleistet ist, dass, solange ein bestimmtes Update durchgeführt wird, dieses von keinem anderen Benutzer unterbrochen werden kann und dass es keinen automatischen Rollback gibt (was bei transaktionalen Tabellen immer möglich ist, wenn Sie nicht mit extremer Sorgfalt vorgehen). MySQL Server garantiert außerdem, dass es nicht zur Dirty Reads kommt.

Die folgende Liste erläutert ein paar Methoden für die Arbeit mit nichttransaktionalen Tabellen:

  • Schleifen, die Transaktionen erfordern, lassen sich normalerweise mithilfe von LOCK TABLES kopieren. Sie benötigen keine Cursor, um Datensätze direkt zu aktualisieren.

  • Um die Verwendung von ROLLBACK zu umgehen, können Sie die folgende Strategie verwenden:

    1. Sperren Sie alle Tabellen, auf die Sie zugreifen wollen, mit LOCK TABLES.

    2. Prüfen Sie die Bedingungen, die wahr sein müssen, bevor Sie das Update durchführen.

    3. Sind alle Bedingungen erfüllt, dann führen Sie das Update durch.

    4. Heben Sie die Sperrungen Ihrer Tabellen mit UNLOCK TABLES auf.

    Wenn auch nicht immer, so funktioniert dies in der Regel doch wesentlich schneller als die Verwendung von Transaktionen mit möglichen Rollbacks. Die einzige Situation, die mit dieser Lösung nicht bereinigt werden kann, liegt vor, wenn jemand die Threads während eines Updates beendet. In diesem Fall werden alle Sperren aufgehoben, aber unter Umständen wurden manche Updates nicht ausgeführt.

  • Sie können auch Funktionen zur Aktualisierung von Datensätzen in einer einzigen Operation verwenden. Mithilfe der folgenden Methode erhalten Sie eine sehr effiziente Anwendung:

    • Ändern Sie die Spalten relativ zum aktuellen Wert.

    • Aktualisieren Sie nur solche Spalten, die tatsächlich geändert wurden.

    Wenn wir beispielsweise Kundendaten aktualisieren, dann aktualisieren wir nur diejenigen Kundendaten, die sich auch geändert haben, und überprüfen nachfolgend lediglich, ob sich geänderte Daten oder Daten, die von den geänderten Daten abhängen, verglichen mit dem ursprünglichen Datensatz geändert haben. Die Überprüfung auf geänderte Daten erfolgt mit der WHERE-Klausel in der UPDATE-Anweisung. Wurde der Datensatz nicht aktualisiert, dann erhält der Client folgende Mitteilung: „Some of the data you have changed has been changed by another user.“ („Einige Daten, die Sie geändert haben, wurden von einem anderen Benutzer geändert.“) Dann werden der alte und der neue Datensatz in einem Fenster zu Vergleichszwecken angezeigt, damit der Benutzer entscheiden kann, welche Version des Kundendatensatzes zukünftig verwendet werden soll.

    Auf diese Weise erhalten wir etwas, dass der Sperrung einer Spalte ähnelt, tatsächlich aber noch besser ist, da nur einige Spalten mithilfe von Werten aktualisiert werden, die relativ zu den aktuellen Werten sind. Dies wiederum bedeutet, dass eine typische UPDATE-Anweisung etwa so aussieht:

    UPDATE tablename SET pay_back=pay_back+125;
    
    UPDATE customer
      SET
        customer_date='current_date',
        address='new address',
        phone='new phone',
        money_owed_to_us=money_owed_to_us-125
      WHERE
        customer_id=id AND address='old address' AND phone='old phone';
    

    Dies ist sehr effizient und funktioniert auch dann, wenn ein anderer Client die Werte in den Spalten pay_back oder money_owed_to_us geändert hat.

  • In vielen Fällen wünschten sich Benutzer LOCK TABLES oder ROLLBACK, um eindeutige Bezeichner verwalten zu können. Dies lässt sich jedoch weitaus effizienter ohne Sperrung oder Rollback realisieren, indem man eine AUTO_INCREMENT-Spalte und entweder die SQL-Funktion LAST_INSERT_ID() oder die C-API-Funktion mysql_insert_id() verwendet. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“, und Abschnitt 24.2.3.36, „mysql_insert_id().

    Sie können die Notwendigkeit, eine Sperrung auf Datensatzebene vorzunehmen, im Allgemeinen durch entsprechende Programmierung umgehen. In manchen Situationen jedoch ist diese Sperrung erforderlich, und InnoDB-Tabellen unterstützen sie auch. Andernfalls können Sie bei MyISAM-Tabellen eine Flag-Spalte verwenden und etwa Folgendes machen:

    UPDATE tbl_name SET row_flag=1 WHERE id=ID;
    

    MySQL gibt 1 als Anzahl der betroffenen Datensätze zurück, wenn der Datensatz gefunden wurde und row_flag im ursprünglichen Datensatz nicht 1 war. Sie können sich das so vorstellen, als ob MySQL Server die obige Anweisung wie folgt geändert hätte:

    UPDATE tbl_name SET row_flag=1 WHERE id=ID AND row_flag <> 1;
    

1.9.5.4. Gespeicherte Prozeduren und Trigger

Gespeicherte Prozeduren und Funktionen sind ab MySQL 5.0 implementiert. Siehe auch Kapitel 19, Gespeicherte Prozeduren und Funktionen.

Die grundlegende Trigger-Funktionalität ist ab MySQL 5.0.2 implementiert. Die Weiterentwicklung ist für MySQL 5.1 vorgesehen. Siehe auch Kapitel 20, Trigger.

1.9.5.5. Fremdschlüssel

Ab MySQL Server 3.23.44 unterstützt die InnoDB-Speicher-Engine die Überprüfung von Fremdschlüsselbeschränkungen einschließlich CASCADE, ON DELETE und ON UPDATE. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

Bei anderen Speicher-Engines als InnoDB verarbeitet MySQL Server zwar die FOREIGN KEY-Syntax in CREATE TABLE-Anweisungen, verwendet oder speichert sie aber nicht. Zukünftig wird die Implementierung auf die Speicherung dieser Information in der Tabellenspezifikationsdatei erweitert, sodass sie mit mysqldump und ODBC abgerufen werden kann. Zu einem späteren Zeitpunkt werden Fremdschlüsselbeschränkungen auch für MyISAM-Tabellen implementiert werden.

Die Durchsetzung von Fremdschlüsseln bietet Datenbankentwicklern verschiedene Vorteile:

  • Setzt man einen guten Entwurf der Beziehungen voraus, dann erschweren Fremdschlüsselbeschränkungen es dem Programmierer, Inkonsistenzen in die Datenbank einzubringen.

  • Die zentralisierte Überprüfung der Beschränkungen durch den Datenbankserver macht eine Durchführung dieser Überprüfungen auf Anwendungsseite unnötig. Auf diese Weise wird die Möglichkeit beseitigt, dass verschiedene Anwendungen unter Umständen nicht alle Beschränkungen auf gleiche Weise überprüfen.

  • Dank der Verwendung kaskadierender Updates und Löschungen kann der Anwendungscode vereinfacht werden.

  • Korrekt entworfene Fremdschlüsselregeln unterstützen Sie bei der Dokumentation von Beziehungen zwischen Tabellen.

Denken Sie in jedem Fall daran, dass diese Vorteile auf Kosten einer zusätzlichen Belastung des Datenbankservers entstehen, da dieser die erforderlichen Überprüfungen durchführen muss. Weitere Überprüfungen durch den Server beeinträchtigen die Leistungsfähigkeit in so hohem Maße, dass sie für bestimmte Anwendungen vermieden werden sollten, sofern dies möglich ist. (Aus diesem Grund ist die Fremdschlüssellogik bei einigen größeren kommerziellen Anwendungen auch auf Anwendungsebene programmiert.)

MySQL stellt Datenbankprogrammierern die Auswahl des zu verwendenden Ansatzes frei. Wenn Sie keine Fremdschlüssel benötigen und die Mehrbelastung des Servers bei der Durchsetzung der referenziellen Integrität vermeiden wollen, können Sie stattdessen eine andere Speicher-Engine wie etwa MyISAM auswählen. (Die MyISAM-Engine bietet eine sehr gute Performance für Anwendungen, die nur INSERT- und SELECT-Operationen durchführen. In solchen Fällen weist die Tabelle keine Löcher in der Mitte auf, und das Einfügen und Abrufen von Daten kann gleichzeitig erfolgen. Siehe auch Abschnitt 7.3.2, „Themen, die Tabellensperren betreffen“.)

Wenn Sie sich dafür entscheiden, die Vorteile der Überprüfung der referenziellen Integrität nicht zu nutzen, dann sollten Sie die folgenden Gesichtspunkte in Ihre Überlegungen mit einbeziehen:

  • Fehlt die serverseitige Überprüfung der Fremdschlüsselbeziehung, dann muss die Anwendung sich selbst um die Aspekte der Beziehung kümmern. Sie muss beispielsweise dafür sorgen, dass Datensätze in der korrekten Reihenfolge in Tabellen eingetragen werden und dass keine verwaisten Unterdatensätze erstellt werden. Ferner muss sie in der Lage sein, Fehler, die bei Einfügevorgängen für mehrere Datensätze auftreten, beheben zu können.

  • Wenn ON DELETE die einzige referenzielle Integritätsfunktion ist, die eine Anwendung benötigt, dann können Sie ab MySQL Server 4.0 einen ähnlichen Effekt erzielen, indem Sie DELETE-Anweisungen über mehrere Tabellen verwenden; so können Sie Datensätze aus mehreren Tabellen mit nur einer Anweisung löschen. Siehe auch Abschnitt 13.2.1, „DELETE.

  • Ein Workaround für das Fehlen von ON DELETE besteht darin, die passenden DELETE-Anweisungen in Ihrer Anwendung hinzuzufügen, wenn Sie Datensätze aus einer Tabelle löschen, die einen Fremdschlüssel beinhaltet. In der Praxis kann dies häufig ebenso schnell sein wie die Verwendung von Fremdschlüsseln – und ist zudem besser portierbar.

Denken Sie daran, dass der Einsatz von Fremdschlüsseln unter Umständen zu Problemen führen kann:

  • Die Unterstützung von Fremdschlüsseln beseitigt eine Reihe von Schwierigkeiten bei der referenziellen Integrität, aber es ist nach wie vor erforderlich, Schlüsselbeziehungen mit Sorgfalt zu erstellen, damit zirkulare Regeln oder falsche Kombinationen kaskadierender Löschungen ausgeschlossen werden.

  • Es kommt häufig vor, dass ein Datenbankadministrator eine Beziehungstopologie erstellt, die die Wiederherstellung einzelner Tabellen aus einem Backup erschwert. (MySQL schwächt dieses Problem ab, indem es Ihnen die temporäre Deaktivierung von Fremdschlüsselüberprüfungen gestattet, wenn Sie eine Tabelle neu laden, die von anderen Tabellen abhängt. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“. Ab MySQL 4.1.1 erzeugt mysqldump Speicherauszugsdateien, die diesen Vorteil automatisch nutzen, wenn sie neu geladen werden.)

Beachten Sie, dass Fremdschlüssel in SQL zur Überprüfung und Durchsetzung der referenziellen Integrität verwendet werden, nicht jedoch zur Verknüpfung von Tabellen. Wenn Sie mit einer SELECT-Abfrage Ergebnisse aus mehreren Tabellen abrufen wollen, tun Sie dies mithilfe eines Joins dieser Tabellen:

SELECT * FROM t1, t2 WHERE t1.id = t2.id;

Siehe auch Abschnitt 13.2.7.1, „JOIN, und Abschnitt 3.6.6, „Wie Fremdschlüssel verwendet werden“.

Die FOREIGN KEY-Syntax ohne ON DELETE ... wird von ODBC-Anwendungen häufig zur Erzeugung automatischer WHERE-Klauseln verwendet.

1.9.5.6. Sichten (Views)

Views (einschließlich aktualisierbarer Views) sind ab MySQL Server 5.0.1 implementiert. Siehe auch Kapitel 21, Views.

Views sind praktisch, wenn es darum geht, Benutzern den Zugriff auf einen Satz von Beziehungen (Tabellen) so zu gestatten, als ob es sich nur um eine einzige Tabelle handeln würde, und ihren Zugriff auf diesen Satz zu beschränken. Views können auch zur Beschränkung des Zugriffs auf Datensätze (d. h. auf eine Teilmenge einer bestimmten Tabelle) verwendet werden. Für die Steuerung des Spaltenzugriffs können Sie auch das pfiffige Berechtigungssystem in MySQL Server benutzen. Siehe auch Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“.

Bei der Entwicklung der Views-Implementierung war und ist es unser ehrgeiziges Ziel, in den Grenzen von SQL eine möglichst vollständige Konformität mit „Codds Regel Nr. 6“ für relationale Datenbanksysteme zu erzielen, die da besagt: „Alle Views, die theoretisch aktualisierbar sind, sollten auch in der Praxis aktualisierbar sein“.

1.9.5.7. '--' als Beginn eines Kommentars

Standard-SQL verwendet die C-Syntax /* This is a Comment */ für Kommentare, und auch MySQL Server unterstützt diese Syntax. Ferner unterstützt MySQL Erweiterungen dieser Syntax, die die Einbettung MySQL-spezifischen SQL-Codes in den Kommentar gestatten. Siehe auch Abschnitt 9.4, „Kommentar“.

Als Startkommentarsequenz benutzt Standard-SQL ‘--’. MySQL Server setzt hingegen ‘#’ als Startkommentarzeichen. MySQL Server 3.23.3 und höher unterstützen zudem eine Variante des Kommentarstils ‘--’. Das bedeutet, dass der Startkommentarsequenz ‘--’ ein Leerzeichen (oder ein Steuerzeichen wie etwa der Zeilenwechsel) folgen muss. Das Leerzeichen ist erforderlich, um Probleme mit automatisch erzeugten SQL-Abfragen zu vermeiden, die Konstrukte wie das folgende verwenden, in dem wir in !payment! automatisch eine Rechnungssumme einsetzen:

UPDATE account SET credit=credit-!payment!

Überlegen Sie einmal, was passieren würde, wenn payment einen negativen Wert wie etwa -1 hätte:

UPDATE account SET credit=credit--1

credit--1 ist in SQL ein zulässiger Ausdruck, aber ‘--’ wird als Start eines Kommentars interpretiert – ein Teil des Ausdrucks wird also verworfen! Das Ergebnis ist eine Anweisung, die eine vollständig andere Bedeutung hat als ursprünglich vorgesehen:

UPDATE account SET credit=credit

Diese Anweisung erzeugt überhaupt keine Werteänderung! So lässt sich veranschaulichen, dass es erhebliche Folgen haben könnte, wenn man ‘--’ als Startkommentarsequenz zulassen würde.

Wenn man unsere in MySQL 3.23.3 und höher vorhandene Implementierung verwendet, bei der auf ‘--’ zwingend ein Leerzeichen folgen muss, damit die Startkommentarsequenz als solche erkannt wird, ist credit--1 tatsächlich sicher.

Eine weiteres Sicherheitsmerkmal besteht darin, dass der Befehlszeilenclient mysql Zeilen ignoriert, die mit ‘--’ beginnen.

Die nachfolgenden Informationen sind nur von Bedeutung, wenn Sie eine MySQL-Version vor 3.23.3 verwenden:

Wenn Sie ein SQL-Skript, das Kommentare des Typs ‘--’ enthält, als Textdatei gespeichert haben, dann sollten Sie das Utility replace wie folgt verwenden, um die Kommentare so umzuwandeln, dass Sie das Zeichen ‘#’ verwenden, bevor Sie das Skript ausführen:

shell> replace " --" " #" < text-file-with-funny-comments.sql \
         | mysql db_name

Dies ist sicherer, als das Skript auf übliche Weise auszuführen:

shell> mysql db_name < text-file-with-funny-comments.sql

Sie können die Skriptdatei auch „an Ort und Stelle“ bearbeiten, damit die Kommentare des Typs ‘--’ in ‘#’-Kommentare umgewandelt werden:

shell> replace " --" " #" -- text-file-with-funny-comments.sql

Mit folgendem Befehl machen Sie die Änderung rückgängig:

shell> replace " #" " --" -- text-file-with-funny-comments.sql

Siehe auch Abschnitt 8.17, „replace — Hilfsprogramm für String-Ersetzungen“.

1.9.6. Wie MySQL mit Constraints umgeht

MySQL erlaubt Ihnen die Verwendung sowohl von transaktionalen Tabellen, die Rollbacks unterstützen, als auch von nichttransaktionalen Tabellen ohne Rollback. Aus diesem Grund unterscheidet sich der Umgang mit Constraints in MySQL ein wenig von dem in anderen Datenbanksystemen. Wir müssen den Fall beschreiben, der vorliegt, wenn Sie eine große Menge von Datensätzen in einer nichttransaktionalen Tabelle, bei der im Fehlerfall kein Rollback möglich ist, eingefügt oder aktualisiert haben.

Die Grundphilosophie besteht darin, dass MySQL Server versucht, einen Fehler für alle Probleme zu generieren, die während der Verarbeitung einer auszuführenden Anweisung erkannt wurden; gleichzeitig wird versucht, den fehlerfreien Status in Bezug auf alle Fehler wiederherzustellen, die während der Ausführung der Anweisung auftreten. Das lässt sich in den meisten, jedoch nicht in allen Fällen realisieren.

Wenn ein Fehler auftritt, hat MySQL zwei Optionen: Es kann die Ausführung der Anweisung abbrechen oder das Problem bestmöglich beheben und dann fortfahren. Standardmäßig verfolgt der Server die zweite Option. Dies bedeutet beispielsweise, dass der Server unzulässige Werte automatisch auf die nächstgelegenen zulässigen Werte verschiebt.

Es gibt mehrere SQL-Modusoptionen, die eine bessere Kontrolle der Handhabung unzulässiger Datenwerte und der Frage gestatten, ob die Ausführung einer Anweisung im Fehlerfall fortgeführt oder abgebrochen werden soll. Mithilfe dieser Optionen können Sie MySQL Server so konfigurieren, dass es auf eine traditionellere Weise agiert, die anderen Datenbanksystemen ähnelt, bei denen unzulässige Eingaben nicht angenommen werden. Der SQL-Modus kann global beim Serverstart eingestellt werden und betrifft dann alle Clients. Einzelne Clients können den SQL-Modus während der Laufzeit einstellen; auf diese Weise kann jeder Client das Verhalten auswählen, welches für seine speziellen Anforderungen am geeignetsten ist. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Die folgenden Abschnitte beschreiben, wie MySQL Server verschiedene Arten von Constraints handhabt.

1.9.6.1. PRIMARY KEY- und UNIQUE-Index-Constraints

Normalerweise tritt ein Fehler auf, wenn Sie versuchen, einen Datensatz mit INSERT bzw. UPDATE einzufügen oder zu aktualisieren, und dadurch eine Unvereinbarkeit bezüglich eines Primärschlüssels, eines eindeutigen Schlüssels oder eines Fremdschlüssels erfolgen würde. Verwenden Sie eine transaktionale Speicher-Engine wie InnoDB, dann macht MySQL die Anweisung automatisch rückgängig. Nutzen Sie hingegen eine nichttransaktionale Speicher-Engine, dann beendet MySQL die Verarbeitung der Anweisung bei dem Datensatz, an dem der Fehler aufgetreten ist, und lässt alle nachfolgenden Datensätze unverändert.

Für den Fall, dass Sie solche Unvereinbarkeiten ignorieren wollen, unterstützt MySQL das Schlüsselwort IGNORE für INSERT und UPDATE. In diesem Fall ignoriert MySQL sämtliche Schlüsselunvereinbarkeiten und fährt mit der Verarbeitung des nächsten Datensatzes fort. Siehe auch Abschnitt 13.2.4, „INSERT, und Abschnitt 13.2.10, „UPDATE.

Informationen zur Anzahl der tatsächlich eingefügten oder aktualisierten Datensätze erhalten Sie über die C-API-Funktion mysql_info(). Ab MySQL 4.1 können Sie auch die Anweisung SHOW WARNINGS verwenden. Siehe auch Abschnitt 24.2.3.34, „mysql_info(), und Abschnitt 13.5.4.25, „SHOW WARNINGS.

Derzeit unterstützen nur InnoDB-Tabellen Fremdschlüssel. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“. Die Fremdschlüsselunterstützung in MyISAM-Tabellen ist zur Implementierung in MySQL 5.2 vorgesehen. Siehe auch Abschnitt 1.6, „MySQL-Roadmap“.

1.9.6.2. Constraints auf ungültigen Daten

Vor MySQL 5.0.2 verzeiht MySQL unzulässige oder unzutreffende Dateneingaben und setzt diese nach der Eingabe auf zulässige Werte. Bei MySQL 5.0.2 und höher bleibt dies zwar auch das Standardverhalten, aber Sie können den SQL-Modus des Servers so ändern, dass ein traditionellerer Umgang mit solchen Daten gewählt wird: Der Server kann sie dann auch abweisen und die Anweisung abbrechen, in der sie auftreten. Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Dieser Abschnitt beschreibt das (nachsichtige) Standardverhalten von MySQL und den neueren strikten SQL-Modus sowie die Unterschiede zwischen diesen Modi.

Wenn Sie den strikten Modus nicht verwenden, dann wird, wann immer Sie einen „falschen“ Wert in eine Spalte einsetzen (z. B. eine NULL in eine NOT NULL-Spalte oder einen zu großen numerischen Wert in eine numerische Spalte), MySQL die Spalte auf den „bestmöglichen“ Wert setzen, statt einen Fehler zu erzeugen. Die folgenden Regeln beschreiben genauer, wie dies funktioniert:

  • Wenn Sie versuchen, einen Wert außerhalb des zulässigen Bereichs in einer numerischen Spalte zu speichern, dann speichert MySQL Server stattdessen null, den kleinstmöglichen oder den größtmöglichen Wert – abhängig davon, welcher gültige Wert am nächsten liegt.

  • Bei Strings speichert MySQL entweder den Leer-String oder den Teil des Strings, der sich in der Spalte speichern lässt.

  • Wenn Sie in einer numerischen Spalte einen String speichern wollen, der nicht mit einer Zahl beginnt, dann speichert MySQL Server 0.

  • Mit ungültigen Werten für ENUM- und SET-Spalten wird wie in Abschnitt 1.9.6.3, „ENUM- und SET-Constraints“, beschrieben verfahren.

  • MySQL gestattet die Speicherung bestimmter unzulässiger Werte in DATE- und DATETIME-Spalten (z. B. '2000-02-31' oder '2000-02-00'). Der Grundgedanke dahinter ist der, dass es nicht Aufgabe des SQL-Servers sein kann, Datumsangaben auszuwerten. Wenn MySQL einen Datumswert speichern und den exakt gleichen Wert wieder abrufen kann, dann speichert MySQL ihn auch wie eingegeben. Ist das Datum jedoch völlig falsch (d. h., es kann nicht vom Server gespeichert werden), dann wird stattdessen der spezielle „Nulldatumswert'0000-00-00' in der Spalte abgelegt.

  • Wenn Sie NULL in einer Spalte speichern wollen, die keine NULL-Werte akzeptiert, dann erscheint bei INSERT-Anweisungen für einzelne Datensätze ein Fehler. Bei INSERT-Anweisungen für mehrere Datensätze oder INSERT INTO ... SELECT-Anweisungen hingegen speichert MySQL Server den impliziten Vorgabewert für den Datentyp der Spalte. In der Regel ist dies 0 bei numerischen Typen, der Leer-String ('') bei String-Typen und der „Nullwert“ für Datums- und Uhrzeittypen. Implizite Vorgabewerte werden in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, behandelt.

  • Wenn eine INSERT-Anweisung keinen Wert für eine Spalte angibt, fügt MySQL den Vorgabewert ein, sofern die Spaltendefinition eine explizite DEFAULT-Klausel enthält. Ist eine solche DEFAULT-Klausel nicht in der Definition enthalten, dann fügt MySQL den impliziten Vorgabewert für den Datentyp der Spalte ein.

Der Grund für die Verwendung obiger Regeln im nicht strikten Modus ist, dass wir diese Bedingungen erst nach Beginn der Ausführung der betreffenden Anweisung überprüfen können. Tritt nach der Aktualisierung einiger Datensätze ein Problem auf, dann können wir nicht einfach einen Rollback durchführen, da die Speicher-Engine Rollbacks unter Umständen nicht unterstützt. Die Option, die Anweisung einfach zu beenden, wäre nachteilig; in diesem Fall wäre die Aktualisierung nämlich nur „zur Hälfte“ erfolgt, was das wohl schlimmste vorstellbare Szenario wäre. In einem solchen Fall ist es besser, das „Bestmögliche“ zu tun und dann fortzufahren, so als ob nichts gewesen wäre.

In MySQL 5.0.2 und höher können Sie eine strengere Behandlung der Eingabewerte mithilfe der SQL-Modi STRICT_TRANS_TABLES oder STRICT_ALL_TABLES auswählen:

SET sql_mode = 'STRICT_TRANS_TABLES';
SET sql_mode = 'STRICT_ALL_TABLES';

STRICT_TRANS_TABLES aktiviert den strikten Modus für transaktionale Speicher-Engines und bis zu einem gewissen Grad auch für nichttransaktionale Engines. Das funktioniert wie folgt:

  • Bei transaktionalen Speicher-Engines wird bei Auftreten unzulässiger Werte in einer Anweisung die Ausführung dieser Anweisung abgebrochen und ein Rollback durchgeführt.

  • Bei nichttransaktionalen Speicher-Engines wird die Anweisung abgebrochen, wenn der Fehler beim ersten einzufügenden bzw. zu aktualisierenden Datensatz auftritt. (Tritt der Fehler beim ersten Datensatz auf, dann kann die Anweisung wie bei transaktionalen Tabellen abgebrochen werden, ohne dass Änderungen in der Tabelle erfolgt wären.) Fehler in nachfolgenden Datensätzen brechen die Anweisung nicht ab, denn in der Tabelle wurden bereits Änderungen vorgenommen. Stattdessen werden unzulässige Datensätze korrigiert und Warnungen (anstelle von Fehlern) erzeugt. Mit anderen Worten: Bei STRICT_TRANS_TABLES hat ein falscher Wert zur Folge, dass MySQL einen Rollback aller bereits durchgeführten Aktualisierungen vornimmt, sofern dies ohne Änderungen in der Tabelle möglich ist. Wurde die Tabelle jedoch bereits geändert, dann führen weitere Fehler zu Korrekturen und Warnungen.

Für eine noch striktere Prüfung aktivieren Sie STRICT_ALL_TABLES. Dies entspricht weitgehend STRICT_TRANS_TABLES, nur führen Fehler bei nichttransaktionalen Speicher-Engines hier dazu, dass die Anweisung auch bei unzulässigen Daten im zweiten oder allen folgenden Datensätzen abgebrochen wird. Das bedeutet, dass, wenn bei einer nichttransaktionalen Tabelle im Verlauf einer Einfüge- oder Aktualisierungsoperation für mehrere Datensätze ein Fehler auftritt, nur eine Teilaktualisierung erfolgt. Datensätze vor Auftreten des Fehlers werden eingefügt bzw. aktualisiert, Datensätze nach dem Fehler jedoch nicht. Um dieses Verhalten bei nicht transaktionalen Tabellen zu vermeiden, verwenden Sie entweder Anweisungen für einzelne Datensätze oder aber STRICT_TRANS_TABLES, sofern Konvertierungswarnungen (statt Fehlern) akzeptabel sind. Um Probleme bereits im Vorfeld zu vermeiden, sollten Sie zur Überprüfung des Spalteninhalts nicht MySQL verwenden. Es ist sicherer (und oft auch schneller), wenn die Anwendung sicherstellt, dass sie nur zulässige Werte an die Datenbank übermittelt.

Bei Auswahl eines strikten Modus können Sie die Behandlung von Fehlern als Warnungen vorsehen, indem Sie INSERT IGNORE bzw. UPDATE IGNORE statt INSERT oder UPDATE ohne IGNORE verwenden.

1.9.6.3. ENUM- und SET-Constraints

ENUM- und SET-Spalten stellen eine effiziente Möglickeit dar, Spalten zu definieren, die nur eine festgelegte Wertemenge aufnehmen können. Siehe auch Abschnitt 11.4.4, „Der Spaltentyp ENUM, und Abschnitt 11.4.5, „Der Spaltentyp SET. Allerdings ermöglichen ENUM- und SET-Spalten vor MySQL 5.0.2 keine echten Constraints bei der Eingabe ungültiger Daten:

  • ENUM-Spalten haben immer einen Vorgabewert. Wenn Sie keinen Vorgabewert angeben, dann ist er NULL für Spalten, die NULL unterstützen, andernfalls der erste Aufzählungswert in der Spaltendefinition.

  • Fügen Sie einen falschen Wert in eine ENUM-Spalte ein oder erzwingen einen Wert in einer ENUM-Spalte mithilfe von IGNORE, dann wird dieser auf den reservierten Aufzählungswert 0 gesetzt, der als Leer-String im String-Kontext angezeigt wird.

  • Wenn Sie einen falschen Wert in eine SET-Spalte einfügen, wird dieser falsche Wert ignoriert. Kann die Spalte beispielsweise die Werte 'a', 'b' und 'c' enthalten, dann würde der Versuch, 'a,x,b,y' zuzuweisen, den Wert 'a,b' zur Folge haben.

Ab MySQL 5.0.2 können Sie den Server so konfigurieren, dass er den strikten SQL-Modus verwendet. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“. Ist der strikte Modus aktiviert, dann fungiert die Definition einer ENUM- oder SET-Spalte als Beschränkung für Werte, die in die Spalte eingegeben werden. Bei Werten, die die folgenden Bedingungen nicht erfüllen, tritt ein Fehler auf:

  • Ein ENUM-Wert muss zu der Wertemenge gehören, die in der Spaltendefinition aufgelistet ist, oder ein internes numerisches Äquivalent eines Werts in der Wertemenge sein. Der Wert darf nicht der Fehlerwert (also 0 oder der Leer-String) sein. Bei einer Spalte, die als ENUM('a','b','c') definiert ist, sind Werte wie etwa '', 'd' oder 'ax' unzulässig und werden abgewiesen.

  • Ein SET-Wert muss der Leer-String oder ein Wert sein, der nur aus den in der Spaltendefinition aufgeführten Werten besteht, die durch Kommata getrennt sind. Bei einer Spalte, die als SET('a','b','c') definiert ist, sind Werte wie etwa 'd' oder 'a,b,c,d' unzulässig und werden abgewiesen.

Fehler aufgrund ungültiger Werte können im strikten Modus unterdrückt werden, indem Sie INSERT IGNORE bzw. UPDATE IGNORE verwenden. In diesem Fall wird statt eines Fehlers eine Warnung erzeugt. Bei ENUM wird der Wert als Fehlermitglied (0) eingefügt. Bei SET wird der Wert wie vorgegeben eingefügt, sofern nicht vorhandene ungültige Teil-Strings gelöscht werden. So führt etwa 'a,x,b,y' zum Wert 'a,b'.

Kapitel 2. Installation von MySQL

Inhaltsverzeichnis

2.1. Allgemeines zur Installation
2.1.1. Betriebssysteme, die von MySQL unterstützt werden
2.1.2. Welche MySQL-Version Sie benutzen sollten
2.1.3. Woher man MySQL bekommt
2.1.4. Bestätigen der Paketintegrität mittels MD5-Prüfsummen oder GnuPG
2.1.5. Installationslayouts
2.2. Schnelle Standardinstallation von MySQL
2.3. Installation von MySQL unter Windows
2.3.1. Systemvoraussetzungen für Windows
2.3.2. Auswahl eines Installationspakets
2.3.3. Installation von MySQL mit dem automatischen Installer
2.3.4. Verwendung des MySQL-Installations-Assistenten
2.3.5. Verwendung des Konfigurations-Assistenten
2.3.6. Installation von MySQL aus einem Noinstall-Zip-Archiv
2.3.7. Entpacken des Installationsarchivs
2.3.8. Anlegen einer Optionsdatei
2.3.9. Auswahl des MySQL Server-Typs
2.3.10. Erstmaliges Starten des Servers
2.3.11. Starten von MySQL von der Windows-Befehlszeile
2.3.12. Starten von MySQL als Windows-Dienst
2.3.13. Test der MySQL-Installation
2.3.14. Troubleshooting einer MySQL-Installation unter Windows
2.3.15. Upgrade von MySQL unter Windows
2.3.16. MySQL unter Windows im Vergleich zu MySQL unter Unix
2.4. MySQL unter Linux installieren
2.5. Installation von MySQL unter Mac OS X
2.6. Installation von MySQL unter NetWare
2.7. Installation von MySQL auf anderen Unix-ähnlichen Systemen
2.8. Installation der Quelldistribution
2.8.1. Schnellinstallation, Überblick
2.8.2. Typische configure-Optionen
2.8.3. Installation vom Entwicklungs-Source-Tree
2.8.4. Probleme beim Kompilieren?
2.8.5. Anmerkungen zu MIT-pthreads
2.8.6. Windows-Quelldistribution
2.8.7. MySQL-Clients auf Windows kompilieren
2.9. Einstellungen und Tests nach der Installation
2.9.1. Nach der Installation unter Windows durchzuführende Schritte
2.9.2. Schritte nach der Installation unter Unix
2.9.3. Einrichtung der anfänglichen MySQL-Berechtigungen
2.10. MySQL aktualisieren (Upgrade/Downgrade)
2.10.1. Upgrade von MySQL 5.0
2.10.2. Upgrade auf eine andere Architektur
2.11. Downgrade von MySQL
2.12. Betriebssystemspezifische Anmerkungen
2.12.1. Linux (alle Linux-Versionen)
2.12.2. Anmerkungen zu Mac OS X
2.12.3. Anmerkungen zu Solaris
2.12.4. Anmerkungen zu BSD
2.12.5. Anmerkungen zu anderen Unixen
2.12.6. Anmerkungen zu OS/2
2.13. Anmerkungen zur Perl-Installation
2.13.1. Installation von Perl unter Unix
2.13.2. Installation von ActiveState-Perl unter Windows
2.13.3. Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl

Dieses Kapitel beschreibt, wie Sie sich MySQL beschaffen und installieren. Zunächst folgt eine Zusammenfassung der Vorgehensweise; die Details werden dann im weiteren Verlauf beschrieben. Wenn Sie MySQL nicht zum ersten Mal installieren, sondern eine vorhandene MySQL-Version auf eine neuere Version aktualisieren wollen, dann finden Sie weitere Informationen zur Vorgehensweise und zu Gesichtspunkten, die vor dem Upgrade beachtet werden müssen, in Abschnitt 2.10, „MySQL aktualisieren (Upgrade/Downgrade)“.

  1. Ermitteln Sie, ob Ihre Plattform unterstützt wird. Bitte beachten Sie, dass nicht alle unterstützten Systeme gleichermaßen zur Ausführung von MySQL geeignet sind. Auf manchen Plattformen arbeitet MySQL robuster und effizienter als auf anderen. Weitere Informationen finden Sie in Abschnitt 2.1.1, „Betriebssysteme, die von MySQL unterstützt werden“.

  2. Wählen Sie die zu installierende Distribution. Es sind verschiedene MySQL-Versionen verfügbar, die meisten davon in unterschiedlichen Distributionsformaten. Sie können zwischen fertig gepackten Distributionen mit binären (vorkompilierten) Programmen und dem Quellcode wählen. Entscheiden Sie sich im Zweifelsfall für eine binäre Distribution. Für Benutzer, die unsere aktuellsten Entwicklungen sehen und uns beim Testen des neuesten Codes helfen wollen, bieten wir auch einen öffentlichen Zugang zum aktuellen Source-Tree. Wie Sie bestimmen, welche Version und welchen Distributionstyp Sie verwenden sollten, erfahren Sie in Abschnitt 2.1.2, „Welche MySQL-Version Sie benutzen sollten“.

  3. Laden Sie die Distribution herunter, die Sie installieren wollen. Informationen zur Vorgehensweise finden Sie in Abschnitt 2.1.3, „Woher man MySQL bekommt“. Um die Integrität der Distribution zu überprüfen, gehen Sie vor wie in Abschnitt 2.1.4, „Bestätigen der Paketintegrität mittels MD5-Prüfsummen oder GnuPG, beschrieben.

  4. Installieren Sie die Distribution. Um MySQL aus einer binären Distribution zu installieren, gehen Sie vor wie in Abschnitt 2.2, „Schnelle Standardinstallation von MySQL“, beschrieben. Wenn Sie MySQL hingegen aus einer Quelldistribution oder aus dem aktuellen Entwicklungs-Source-Tree installieren, gehen Sie vor wie in Abschnitt 2.8, „Installation der Quelldistribution“, beschrieben.

    Wenn Sie bei der Installation Probleme haben, finden Sie plattformspezifische Hinweise zu deren Beseitigung in Abschnitt 2.12, „Betriebssystemspezifische Anmerkungen“.

  5. Führen Sie die nach der Installation erforderlichen Konfigurationsarbeiten durch. Lesen Sie nach der Installation von MySQL Abschnitt 2.9, „Einstellungen und Tests nach der Installation“. Dieser Abschnitt enthält wichtige Informationen dazu, wie Sie den einwandfreien Betrieb des MySQL Servers sicherstellen. Ferner ist dort beschrieben, wie Sie die bei der Installation erstellten MySQL-Benutzerkonten, die anfangs keine Passwörter aufweisen, bis zur Konfiguration von Passwörtern sichern. Die in diesem Abschnitt enthaltenen Informationen gelten unabhängig davon, ob Sie MySQL mithilfe einer Binär- oder einer Quelldistribution installieren.

  6. Wenn Sie die MySQL-Benchmark-Skripten ausführen wollen, muss der Perl-Support für MySQL eingerichtet sein. Siehe auch Abschnitt 2.13, „Anmerkungen zur Perl-Installation“.

2.1. Allgemeines zur Installation

Vor der Installation von MySQL müssen Sie Folgendes tun:

  1. Ermitteln Sie, ob MySQL auf Ihrer Plattform läuft.

  2. Wählen Sie die zu installierende Distribution aus.

  3. Laden Sie die Distribution herunter und überprüfen Sie die Integrität.

Dieser Abschnitt enthält Informationen, die für die Ausführung dieser Schritte erforderlich sind. Danach können Sie die Anweisungen in den nachfolgenden Abschnitten des Kapitels zur Installation der von Ihnen gewählten Distribution verwenden.

2.1.1. Betriebssysteme, die von MySQL unterstützt werden

Dieser Abschnitt listet die Betriebssysteme auf, auf denen MySQL ausgeführt können werden sollte.

Wir verwenden GNU Autoconf, weswegen eine Portierung von MySQL auf alle modernen Systeme möglich ist, die einen C++-Compiler und eine funktionsfähige Implementierung von POSIX-Threads enthalten. (Die Thread-Unterstützung wird für den Server benötigt. Wenn Sie nur den Clientcode kompilieren wollen, benötigen Sie lediglich den C++-Compiler.) Wir selbst verwenden und entwickeln die Software in erster Linie auf Systemen unter Linux (SuSE und Red Hat), FreeBSD und Sun Solaris (Versionen 8 und 9).

Berichten zufolge lässt sich MySQL erfolgreich auf den nachfolgend aufgeführten Kombinationen aus Betriebssystem und Thread-Paket kompilieren. Beachten Sie, dass die native Thread-Unterstützung bei vielen Betriebssystemen nur in den jeweils aktuellsten Versionen funktioniert.

Nicht alle Plattformen sind für die Ausführung von MySQL gleichermaßen geeignet. Die Eignung einer Plattform für einen unternehmenskritischen, stark beanspruchten MySQL Server wird von den folgenden Faktoren bestimmt:

  • Allgemeine Stabilität der Thread-Bibliothek. Auch auf Plattformen, die ansonsten einen exzellenten Ruf genießen, ist MySQL nur so stabil wie die aufgerufene Thread-Bibliothek – und zwar auch dann, wenn alles andere perfekt ist.

  • Die Funktionalität des Kernels und der Thread-Bibliothek bezüglich der optimalen Nutzung von SMP-Systemen (symmetrischen Multiprozessorsystemen). Mit anderen Worten: Wenn ein Prozess einen Thread erstellt, sollte dieser auf einem anderen Prozessor laufen können als der ursprüngliche Prozess.

  • Die Fähigkeit von Kernel und Thread-Bibliothek, mehrere Threads auszuführen, die häufig ein Mutex für einen kurzen kritischen Bereich ohne umfassende Kontextschalter setzen, und aufzuheben. Wenn die Implementierung von pthread_mutex_lock() zu zurückhaltend bei der Bereitstellung von Prozessorzeit ist, wird MySQL hierdurch empfindlich gestört. Wird dieser Aspekt nicht berücksichtigt, dann macht das Ergänzen zusätzlicher Prozessoren MySQL tatsächlich langsamer.

  • Allgemeine Stabilität und Leistungsfähigkeit des Dateisystems.

  • Wenn Ihre Tabellen sehr groß werden, steht und fällt die Leistung mit der Fähigkeit des Dateisystems, mit großen Dateien nicht nur überhaupt, sondern sogar effizient umgehen zu können.

  • Unser eigenes Fachwissen hier bei MySQL AB bezüglich des jeweiligen Betriebssystems. Kennen wir eine Plattform gut, dann können wir plattformspezifische Optimierungen und Fehlerbehebungen bei der Kompilierung aktivieren. Außerdem können wir Informationen zur optimalen Konfiguration Ihres Systems für MySQL vermitteln.

  • Der Umfang der Tests, die wir intern für ähnliche Konfigurationen durchgeführt haben.

  • Die Anzahl der Benutzer, die MySQL erfolgreich auf Plattformen mit ähnlichen Konfigurationen verwenden. Ist diese Zahl groß, dann ist die Wahrscheinlichkeit plattformspezifischer Überraschungen eher gering.

Basierend auf diesen Kriterien sind die derzeit am besten für die Ausführung von MySQL geeigneten Plattformen x86 mit SuSE Linux (Kernel 2.4 oder 2.6) und ReiserFS (oder jede ähnliche Linux-Distribution) und SPARC mit Solaris (2.7 bis 2.9). An dritter Stelle kommt FreeBSD; wir hoffen aber, es in den Kreis der Favoriten aufnehmen zu können, sobald die Thread-Bibliothek optimiert wurde. Außerdem sind wir natürlich zuversichtlich, irgendwann alle anderen Plattformen, auf denen MySQL derzeit kompiliert und ausgeführt werden kann, aber noch nicht mit derselben hohen Stabilität und Leistungsfähigkeit läuft, in diese Runde aufnehmen zu können. Dies erfordert einigen Aufwand unsererseits in Zusammenarbeit mit den Entwicklern der Betriebssysteme und Bibliothekskomponenten, auf die MySQL angewiesen ist. Wenn Sie an der Optimierung einer dieser Komponenten interessiert sind, Einfluss auf deren Entwicklung ausüben können und detailliertere Angaben dazu benötigen, was MySQL für eine bessere Ausführung benötigt, dann senden Sie eine E-Mail an die MySQL-Mailingliste internals. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

Bitte beachten Sie, dass es nicht Zweck des obigen Vergleichs ist, festzustellen, dass ein Betriebssystem generell besser oder schlechter ist als ein anderes. Die Rede ist hier ausschließlich von der Auswahl eines Betriebssystems für den ganz speziellen Zweck, MySQL auszuführen. Wenn man andere Schwerpunkte setzen würde, würde das Ergebnis des Vergleichs sicher auch anders ausfallen. In bestimmten Fällen besteht der Grund dafür, dass ein Betriebssystem für die Ausführung von MySQL besser geeignet ist als ein anderes, schlicht und einfach darin, dass wir mehr Aufwand in Tests und Optimierung einer bestimmten Plattform gesteckt haben. Wir geben hier unsere Beobachtungen wieder, um Ihnen bei der Entscheidung zu helfen, eine geeignete Plattform für MySQL auszuwählen.

2.1.2. Welche MySQL-Version Sie benutzen sollten

Wenn Sie die Installation von MySQL vorbereiten, sollten Sie entscheiden, welche Version Sie benutzen. Die Entwicklung von MySQL erfolgt in mehreren Release-Serien, von denen Sie sich die für Ihre Zwecke geeignetste auswählen können. Wenn Sie sich für eine Version entschieden haben, können Sie ein Distributionsformat auswählen. Releases sind im Binär- und im Quellformat verfügbar.

2.1.2.1. Auswahl der bestgeeigneten Version von MySQL

Die erste zu treffende Entscheidung ist die, ob Sie einen (stabilen) Produktions-Release oder aber einen Entwicklungs-Release verwenden wollen. Im MySQL-Entwicklungsprozess koexistieren mehrere Release-Serien miteinander, die sich alle durch ihren Grad der Ausgereiftheit voneinander unterscheiden:

  • MySQL 5.1 ist die nächste Entwicklungs-Release-Serie. In ihr werden neue Funktionen implementiert. Alpha-Releases sind derzeit verfügbar und erlauben umfassende Tests durch interessierte Benutzer.

  • MySQL 5.0 ist die aktuelle Release-Serie für Produktionsumgebungen. Neue Releases erscheinen nur bei Vorhandensein von Bugfixes; neue Funktionalitäten werden nicht ergänzt, da sie die Stabilität beeinträchtigen könnten.

  • MySQL 4.1 ist die vorherige Release-Serie für Produktionsumgebungen. Neue Releases erscheinen hier, wenn kritische Bugs und Sicherheitslücken behoben werden. Bei dieser Serie werden keine wesentlichen neuen Funktionen mehr hinzugefügt.

  • MySQL 4.0 und 3.23 sind die alten stabilen Release-Serien für Produktionsumgebungen. Diese Versionen sind nun stillgelegt, d. h., neue Releases erscheinen nur, wenn extrem kritische, vorzugsweise sicherheitsrelevante Bugs behoben werden.

Wir halten ein endgültiges Einfrieren von Codes nicht für machbar, da dies Bugfixes und andere Fehlerbereinigungen, die erforderlich sind, unmöglich machen würde. Das von uns bevorzugte „Teileinfrieren“ erlaubt uns das Ergänzen von Kleinigkeiten, die sich nicht auf die Einsatzfähigkeit eines Produktions-Releases auswirken sollten. Natürlich pflanzen sich wesentliche Bugfixes in früheren Serien auch auf ihre jeweiligen Nachfolger fort.

Wenn Sie MySQL zum ersten Mal verwenden oder es auf ein System portieren wollen, für das keine binäre Distribution verfügbar ist, empfehlen wir Ihnen normalerweise, die Produktions-Release-Serie zu verwenden. Derzeit ist dies MySQL 5.0. Alle MySQL-Releases – auch die der Entwicklungsserie – werden vor der Veröffentlichung mit den MySQL-Benchmarks und der umfangreichen Testsuite überprüft.

Wenn Sie ein älteres System verwenden und ein Upgrade durchzuführen beabsichtigen, gleichzeitig aber verhindern wollen, dass es während der Aktualisierung zu Problemen kommt, dann sollten Sie auf die aktuelle Version derselben Release-Serie aktualisieren, die Sie bereits verwenden (hierbei ist nur der letzte Teil der Versionsnummer höher als bei der von Ihnen verwendeten Version). Wir haben lediglich versucht, kritische Bugs zu beheben und kleine, relativ „sichere“ Änderungen an dieser Version vorzunehmen.

Wenn Sie neue Funktionen verwenden wollen, die nicht in der Produktions-Release-Serie vorhanden sind, können Sie sich auch für eine Version aus der Entwicklungsserie entscheiden. Beachten Sie, dass die Entwicklungs-Releases nicht so stabil sind wie die Produktions-Releases.

Wollen Sie die allerneuesten Quellcodes mit allen aktuellen Patches und Bugfixes einsetzen, dann können Sie eines unserer BitKeeper-Repositorys verwenden. Dies sind nicht „Releases“ im eigentlichen Sinne, sondern Vorabversionen des Codes, auf dem zukünftige Releases basieren werden.

Das MySQL-Benennungsschema verwendet Release-Namen, die aus drei Zahlen und einem Suffix bestehen. Dies kann etwa so aussehen: mysql-5.0.12-beta. Die Zahlen im Release-Namen sind wie folgt zu interpretieren:

  • Die erste Zahl (5) ist die Hauptversion und beschreibt das Dateiformat. Alle MySQL 5-Releases haben das gleiche Dateiformat.

  • Die zweite Zahl (0) ist der Release-Level. Zusammengefasst bilden Hauptversion und Release-Level die Nummer der Release-Serie.

  • Die dritte Zahl (12) ist die Versionsnummer innerhalb der Release-Serie. Diese wird bei jedem neuen Release um den Wert 1 erhöht. In der Regel sollten Sie immer die neueste Version in der von Ihnen gewählten Serie verwenden.

Bei kleineren Updates wird jeweils die letzte Zahl im Versions-String hochgezählt. Liegen wesentliche Neuerungen bei den Merkmalen oder kleinere Inkompatibilitäten mit vorherigen Versionen vor, dann wird die zweite Zahl im Versions-String hochgezählt. Ändert sich schließlich das Dateiformat, dann wird die erste Zahl erhöht.

Release-Namen enthalten auch ein Suffix, welches die Stabilitätsstufe für den Release angibt. Releases innerhalb einer Serie durchschritten eine bestimmte Abfolge von Suffixen, die jeweils anzeigen, wie sich die Stabilität erhöht. Mögliche Suffixe sind die folgenden:

  • alpha zeigt an, dass der Release neue Funktionen enthält, die noch nicht umfassend getestet wurden. Bekannte Bugs sollten im Abschnitt „News“ dokumentiert sein. Siehe auch Anhang D, MySQL-Änderungsverlauf (Change History). Die meisten Alpha-Releases implementieren neue Befehle und Erweiterungen. Die aktive Entwicklung, die auch umfassende Änderungen am Code beinhalten kann, erfolgt in der Alphaphase. Allerdings werden vor der Veröffentlichung eines Releases Tests durchgeführt.

  • beta bedeutet, dass der Release funktionsseitig abgeschlossen ist und der gesamte neue Code getestet wurde. Es werden keine wesentlichen neuen Funktionen und Merkmale mehr hinzugefügt. Es sollten auch keine kritischen Bugs mehr vorhanden sein. Eine Version wechselt vom Alpha- in den Betastatus, wenn mindestens einen Monat lang keine schweren Bugs mehr für die Alphaversion gemeldet wurden und wir nicht beabsichtigen, neue Merkmale hinzuzufügen, die die Zuverlässigkeit der zuvor implementierten Funktionen beeinträchtigen könnten.

    Bei zukünftigen Beta-, Release-Candidate- oder Produktions-Releases erfolgen keine Änderungen mehr an APIs, extern sichtbaren Strukturen und Spalten für SQL-Anweisungen.

  • rc ist ein Release-Candidate, d. h. eine Betaversion, die bereits seit einiger Zeit verfügbar ist und offensichtlich stabil arbeitet. Es werden nur noch kleinere Fehlerkorrekturen vorgenommen (deswegen entspricht der Release-Candidate auch dem, was man früher als Gamma-Release bezeichnete).

  • Ist kein Suffix vorhanden, dann bedeutet dies, dass die Version bereits seit einiger Zeit an vielen verschiedenen Standorten läuft, ohne dass kritische nachvollziehbare Bugs gemeldet wurden (Ausnahme: plattformspezifische Bugs). Bei solchen Releases werden nur kritische Bugfixes implementiert. Eine solche Version nennen wir Produktions-Release (stabilen Release) oder auch „GA-Release“ (General Availability, allgemeine Verfügbarkeit).

MySQL verwendet ein Benennungsschema, welches sich geringfügig von dem anderer Produkte unterscheidet. In der Regel können Sie problemlos jede Version einsetzen, die bereits seit ein paar Wochen verfügbar ist, ohne durch eine neue Version innerhalb derselben Release-Serie ersetzt worden zu sein.

Alle MySQL-Releases werden mit unseren Standardtests und Benchmarks überprüft, damit gewährleistet ist, dass ihr Einsatz relativ sicher ist. Da die Standardtests im Laufe der Zeit so erweitert werden, dass alle zuvor gefundenen Bugs berücksichtigt werden, wird unsere Testsuite immer besser.

Alle Releases wurden zumindest mit den folgenden Tools getestet:

  • Einer internen Testsuite.

    Das Verzeichnis mysql-test enthält ein umfangreiches Set mit Testfällen. Wir führen diese Tests an praktisch jeder Serverbinärdatei durch. Weitere Informationen zur Testsuite finden Sie in Abschnitt 26.1.2, „MySQL-Testsystem“.

  • MySQL-Benchmarks.

    Diese Reihe führt eine Anzahl gängiger Abfragen aus. Ferner ermöglicht sie zu bestimmen, ob der letzte Optimierungsstapel den Code tatsächlich beschleunigt hat. Siehe auch Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“.

  • Crash-Me-Test.

    Dieser Test versucht zu ermitteln, welche Funktionen die Datenbank unterstützt und welche Fähigkeiten und Einschränkungen vorhanden sind. Siehe auch Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“.

Wir testen außerdem die neueste MySQL-Version immer auf zumindest einem System in unserer internen Produktionsumgebung. Dabei stehen uns mehr als 100 Gbyte Daten zum Arbeiten zur Verfügung.

2.1.2.2. Auswahl eines Distributionsformats

Nachdem Sie die zu installierende MySQL-Version gewählt haben, müssen Sie noch festlegen, ob eine binäre oder eine Quelldistribution für die Installation verwendet werden soll. In den meisten Fällen werden Sie sich wahrscheinlich für die Binärdistribution entscheiden, sofern es für Ihre Plattform eine solche gibt. Binärdistributionen sind für viele Plattformen im nativen Format verfügbar, z. B. RPM-Dateien für Linux oder DMG-Pakete für Mac OS X. Distributionen sind außerdem als ZIP-Archive oder komprimierte tar-Dateien erhältlich.

Die folgenden Gründe sprechen für die Verwendung einer Binärdistribution:

  • Binärdistributionen sind in der Regel einfacher zu installieren als Quelldistributionen.

  • Um unterschiedliche Benutzeranforderungen zu erfüllen, bieten wir zwei verschiedene Binärversionen an: eine kompilierte Fassung mit der Kernfunktionalität und eine weitere (MySQL-Max) mit einem erweiterten Feature-Set. Beide Versionen werden aus derselben Quelldistribution kompiliert. Alle nativen MySQL-Clients können mit Servern aus beiden MySQL-Versionen Verbindungen herstellen.

    Die erweiterte MySQL-Binärdistribution ist am Suffix -max zu erkennen und mit den gleichen Optionen konfiguriert wie mysqld-max. Siehe auch Abschnitt 5.3, „mysqld-max, ein erweiterter mysqld-Server“.

    Wenn Sie bei RPM-Distributionen die RPM-Datei MySQL-Max verwenden wollen, müssen Sie zuerst das Standard-RPM MySQL-server installieren.

Unter bestimmten Umständen kann es auch von Vorteil sein, MySQL aus einer Quelldistribution heraus zu installieren:

  • Sie wollen MySQL an einer expliziten Position installieren. Die Standardbinärdistributionen lassen sich an jeder Installationsposition ausführen, aber unter Umständen benötigen Sie noch mehr Flexibilität, um MySQL-Komponenten an jeder beliebigen Stelle abzulegen.

  • Sie wollen mysqld konfigurieren, um sicherzustellen, dass Funktionen, die unter Umständen nicht in den Standardbinärdistributionen enthalten sind, in jedem Fall vorhanden sind. Es folgt eine Liste der meistbenötigten Zusatzoptionen, die Sie verwenden können, um die Verfügbarkeit von Funktionen zu gewährleisten:

    • --with-innodb

    • --with-berkeley-db (nicht auf allen Plattformen verfügbar)

    • --with-libwrap

    • --with-named-z-libs (erfolgt für einige der Binärdistributionen)

    • --with-debug[=full]

  • Sie wollen mysqld ohne bestimmte Funktionen konfigurieren, die in den Standardbinärdistributionen enthalten sind. So werden Distributionen beispielsweise mit der Unterstützung für alle Zeichensätze kompiliert. Wenn Sie einen kleineren MySQL Server wünschen, können Sie diesen so kompilieren, dass nur die erforderlichen Zeichensätze unterstützt werden.

  • Sie haben einen speziellen Compiler (z. B. pgcc) oder wollen Compiler-Optionen nutzen, die für Ihren Prozessor besser optimiert sind. Binärdistributionen werden mit Optionen kompiliert, die auf einer Vielzahl von Prozessoren derselben Prozessorfamilie funktionieren sollten.

  • Sie wollen die aktuellsten Quelltexte aus einem der BitKeeper-Repositorys verwenden, um Zugang zu allen aktuellen Bugfixes zu haben. Wenn Sie beispielsweise einen Bug gefunden und diesen dem MySQL-Entwicklerteam gemeldet haben, dann wird der Bugfix in das Quellcode-Repository geschrieben, und Sie können dann dort darauf zugreifen. Der Bugfix erscheint in einem Release erst, wenn dieser tatsächlich veröffentlicht wird.

  • Sie wollen den C- oder C++-Code lesen (oder ändern), aus dem MySQL besteht. Zu diesem Zweck sollten Sie sich eine Quelldistribution besorgen, denn der Quellcode ist immer das ultimative Handbuch.

  • Quelldistributionen enthalten mehr Tests und Beispiele als Binärdistributionen.

2.1.2.3. Wann und wie Updates veröffentlicht werden

MySQL entwickelt sich ziemlich schnell, und neue Entwicklungen wollen wir anderen MySQL-Benutzern möglichst umgehend bereitstellen. Deswegen erstellen wir immer dann einen neuen Release, wenn wir neue und nützliche Funktionen integriert haben, die auch für andere Benutzer nützlich oder notwendig sein könnten.

Außerdem versuchen wir Benutzern zu helfen, die nach Funktionen fragen, welche leicht zu implementieren sind. Wir achten darauf, was unsere lizenzierten Benutzer – und insbesondere die Kunden unseres Supports – wollen, und versuchen ihnen in dieser Hinsicht zu helfen.

Niemand ist gezwungen, einen neuen Release herunterzuladen. Der Abschnitt „News“ soll Ihnen dabei helfen zu ermitteln, ob im neuen Release etwas dabei ist, was Sie wirklich brauchen. Siehe auch Anhang D, MySQL-Änderungsverlauf (Change History).

Bei der Aktualisierung von MySQL halten wir uns an die folgenden Richtlinien:

  • Releases werden innerhalb jeder Serie veröffentlicht. Bei jedem Release ist die letzte Zahl in der Versionsnummer um 1 höher als beim vorherigen Release in der Serie.

  • Stabile Produktions-Releases erscheinen in der Regel ein- bis zweimal jährlich. Werden jedoch kleine Bugs gefunden, dann wird ein Release nur mit Bugfixes veröffentlicht.

  • Arbeits-Releases und Bugfixes für ältere Releases erscheinen normalerweise alle vier bis acht Wochen.

  • Binärdistributionen für bestimmte Plattformen werden von uns für Haupt-Releases erstellt. Binärdistributionen für andere Systeme werden von Dritten angefertigt, dies aber wahrscheinlich weniger häufig.

  • Bugfixes werden bereitgestellt, sobald kleine oder unkritische, aber ärgerliche Bugs erkannt und korrigiert wurden. Dieses Fixes sind in den BitKeeper-Repositorys sofort verfügbar und außerdem Bestandteil des nächsten Releases.

  • Wird durch Zufall ein schwerwiegender Bug in einem Release gefunden, dann ist es unser Grundsatz, diesen in einem neuen Release schnellstmöglich zu beheben. (Wir wünschten uns, andere Unternehmen würden das auch so handhaben!)

2.1.2.4. Release-Philosophie: keine bekannten Bugs in Releases

Wir verwenden viel Zeit und Mühe darauf, unsere Releases fehlerfrei zu machen. Bislang haben wir nicht eine einzige MySQL-Version veröffentlicht, die einen bekannten nachvollziehbaren schweren Bug aufwies (ein „schwerer“ Bug ist ein Umstand, der dazu führt, dass MySQL bei normaler Verwendung abstürzt, falsche Antworten für normale Abfragen erzeugt oder ein Sicherheitsproblem aufweist).

Wir haben alle offenen Probleme, Bugs und Streitfragen dokumentiert, die von strukturellen Entscheidungen abhängen. Siehe auch Abschnitt A.8, „Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL“.

Unser Ziel ist es, alle Bugs zu beheben, die behebbar sind, ohne eine stabile MySQL-Version weniger stabil machen zu müssen. In bestimmten Fällen bedeutet dies, dass wir ein Problem in den Entwicklungsversionen, nicht aber in der stabilen Produktionsversion beheben können. Natürlich dokumentieren wir solche Probleme, damit sie den Benutzern bekannt sind.

Es folgt eine Beschreibung unserer Vorgehensweise:

  • Wir überwachen das Auftreten von Bugs mithilfe unserer Kundensupportliste, der Bugdatenbank unter http://bugs.mysql.com/ und der externen MySQL-Mailinglisten.

  • Alle gemeldeten Bugs für die aktiven Versionen werden in die Bugdatenbank eingegeben.

  • Wenn wir einen Bug beheben, dann versuchen wir immer, einen Testfall dafür zu erstellen und diesen in unser Testsystem einzufügen, damit gewährleistet ist, dass der Bug nie wieder auftreten kann, ohne sofort erkannt zu werden. (Solche Testfälle gibt es für ca. 90 Prozent aller behobenen Bugs.)

  • Wir erstellen Testfälle für alle neuen Funktionen, die wir in MySQL ergänzen.

  • Bevor wir mit der Erstellung eines neuen MySQL-Releases beginnen, stellen wir sicher, dass alle gemeldeten nachvollziehbaren Bugs der betreffenden MySQL-Version (3.23.x, 4.0.x, 4.1.x, 5.0.x, 5.1.x usw.) behoben sind. Wenn ein Fehler aufgrund interner Strukturentscheidungen in MySQL nicht behoben werden kann, wird dies im Handbuch dokumentiert. Siehe auch Abschnitt A.8, „Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL“.

  • Wir erstellen einen Build für alle Plattformen, für die Binärdistributionen unterstützt werden, und verarbeiten alle mit unserer Testsuite und der Benchmark-Reihe.

  • Schlagen Testsuite oder Benchmark-Reihe bei einer Plattform fehl, dann wird hierfür keine Binärdistribution veröffentlicht. Ist das Problem in einem allgemeinen Fehler im Quellcode begründet, dann beheben wir es und erstellen den Build einschließlich aller Tests auf allen Systemen von Grund auf neu.

  • Erstellungs- und Testvorgänge benötigen etwa eine Woche. Erhalten wir während dieses Zeitraums eine Meldung zu einem schweren Bug (z. B. einem Bug, der einen Speicherauszug verursacht), dann beheben wir das Problem und starten die Erstellung von Neuem.

  • Wenn die Binärdistributionen auf http://dev.mysql.com/ veröffentlicht wurden, senden wir eine Bekanntmachung an die Mailinglisten mysql und announce. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“. Die Bekanntmachung enthält eine Liste aller Änderungen am und aller bekannten Probleme mit dem Release. Der Abschnitt Known Problems (Bekannte Probleme) in den Versionshinweisen wurde bislang nur bei einer Hand voll Releases benötigt.

  • Damit unsere Benutzer möglichst umgehend auf die aktuellsten MySQL-Funktionen zugreifen können, versuchen wir, alle vier bis acht Wochen einen neuen MySQL-Release anzufertigen. Momentaufnahmen des Quellcodes werden täglich erstellt und sind unter http://downloads.mysql.com/snapshots.php verfügbar.

  • Wenn wir trotz aller Bemühungen nach der Freigabe eines Releases die Meldung erhalten, dass ein kritisches Problem für den Build einer bestimmten Plattform vorliegt, dann beheben wir dieses sofort und erstellen einen neuen 'a'-Release für die betreffende Plattform. Weil so viele Leute MySQL benutzen, sind Probleme schnell gefunden und behoben.

  • Unsere Leistungen bei der Erstellung stabiler Releases sind recht gut. Unter den letzten 150 Releases waren es weniger als zehn, für die wir einen neuen Build erstellen mussten. In drei dieser Fälle wurde der Bug von einer fehlerhaften glibc-Bibliothek auf einem unserer Erstellungssysteme verursacht, die ausfindig zu machen uns recht viel Zeit gekostet hat.

2.1.2.5. MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden

Eine der Dienstleistungen von MySQL AB besteht in der Bereitstellung von MySQL-Binärdistributionen, die entweder auf unseren eigenen Systemen oder aber auf Systemen kompiliert wurden, bei denen uns Unterstützer von MySQL freundlicherweise Zugang zu ihren Computern gewährt haben.

Neben den Binärdateien in den plattformspezifischen Paketformaten bieten wir für eine Anzahl von Plattformen auch Binärdistributionen in Form komprimierter tar-Dateien (.tar.gz-Dateien) an. Siehe auch Abschnitt 2.2, „Schnelle Standardinstallation von MySQL“.

Die RPM-Distributionen für MySQL 5.1-Releases, die wir über die Website bereitstellen, werden von MySQL AB angefertigt.

Informationen zu Windows-Distributionen finden Sie in Abschnitt 2.3, „Installation von MySQL unter Windows“.

Diese Distributionen werden mithilfe des Skripts Build-tools/Do-compile erzeugt, das den Quellcode kompiliert und das Binärarchiv tar.gz mithilfe von scripts/make_binary_distribution erstellt.

Diese Binärdateien werden mit den folgenden Compilern und Optionen konfiguriert und erstellt. Diese Informationen können Sie auch abrufen, indem Sie die Variablen COMP_ENV_INFO und CONFIGURE_LINE im Skript bin/mysqlbug jeder tar-Binärdistributionsdatei abfragen.

Sollten Sie optimalere Optionen für einen der folgenden configure-Befehle haben, dann schicken Sie diese an die MySQL-Mailingliste internals. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

Wollen Sie eine Debugversion von MySQL kompilieren, dann sollten Sie die Option--with-debug oder --with-debug=full zu den folgenden configure-Befehlen hinzufügen und ggf. vorhandene -fomit-frame-pointer-Optionen entfernen.

Die folgenden Binärdateien werden auf den Entwicklungssystemen von MySQL AB erstellt:

  • Linux 2.4.xx x86 mit gcc 2.95.3:

    CFLAGS="-O2 -mcpu=pentiumpro" CXX=gcc CXXFLAGS="-O2 -mcpu=pentiumpro
    -felide-constructors" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --enable-assembler --disable-shared
    --with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static
    
  • Linux 2.4.x x86 mit icc (Intel C++ Compiler 8.1 oder höhere Releases):

    CC=icc CXX=icpc CFLAGS="-O3 -unroll2 -ip -mp -no-gcc -restrict"
    CXXFLAGS="-O3 -unroll2 -ip -mp -no-gcc -restrict" ./configure
    --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --enable-assembler
    --disable-shared --with-client-ldflags=-all-static
    --with-mysqld-ldflags=-all-static --with-embedded-server --with-innodb
    

    Beachten Sie, dass Version 8.1 und höher des Intel-Compilers separate Treiber für „reines“ C (icc) und C++ (icpc) aufweisen; wenn Sie icc Version 8.0 oder älter zur Erstellung von MySQL verwenden, müssen Sie die Einstellung CXX=icc vornehmen.

  • Linux 2.4.xx Intel Itanium 2 mit ecc (Intel C++ Itanium Compiler 7.0):

    CC=ecc CFLAGS="-O2 -tpp2 -ip -nolib_inline" CXX=ecc CXXFLAGS="-O2
    -tpp2 -ip -nolib_inline" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile
    
  • Linux 2.4.xx Intel Itanium mit ecc (Intel C++ Itanium Compiler 7.0):

    CC=ecc CFLAGS=-tpp1 CXX=ecc CXXFLAGS=-tpp1 ./configure
    --prefix=/usr/local/mysql --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile
    
  • Linux 2.4.xx alpha mit ccc (Compaq C V6.2-505/Compaq C++ V6.3-006):

    CC=ccc CFLAGS="-fast -arch generic" CXX=cxx CXXFLAGS="-fast -arch
    generic -noexceptions -nortti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-mysqld-ldflags=-non_shared
    --with-client-ldflags=-non_shared --disable-shared
    
  • Linux 2.x.xx ppc mit gcc 2.95.4:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --localstatedir=/usr/local/mysql/data --libexecdir=/usr/local/mysql/bin
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared --with-embedded-server
    --with-innodb
    
  • Linux 2.4.xx s390 mit gcc 2.95.3:

    CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors" ./configure
    --prefix=/usr/local/mysql --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --disable-shared
    --with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static
    
  • Linux 2.4.xx x86_64 (AMD64) mit gcc 3.2.1:

    CXX=gcc ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared
    
  • Sun Solaris 8 x86 mit gcc 3.2.3:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --localstatedir=/usr/local/mysql/data --libexecdir=/usr/local/mysql/bin
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared --with-innodb
    
  • Sun Solaris 8 SPARC mit gcc 3.2:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --enable-assembler --with-named-z-libs=no
    --with-named-curses-libs=-lcurses --disable-shared
    
  • Sun Solaris 8 SPARC (64-Bit) mit gcc 3.2:

    CC=gcc CFLAGS="-O3 -m64 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -m64 -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-named-z-libs=no
    --with-named-curses-libs=-lcurses --disable-shared
    
  • Sun Solaris 9 SPARC mit gcc 2.95.3:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --enable-assembler --with-named-curses-libs=-lcurses
    --disable-shared
    
  • Sun Solaris 9 SPARC mit cc-5.0 (Sun Forte 5.0):

    CC=cc-5.0 CXX=CC ASFLAGS="-xarch=v9" CFLAGS="-Xa -xstrconst -mt
    -D_FORTEC_ -xarch=v9" CXXFLAGS="-noex -mt -D_FORTEC_ -xarch=v9"
    ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --enable-assembler
    --with-named-z-libs=no --enable-thread-safe-client --disable-shared
    
  • IBM AIX 4.3.2 ppc mit gcc 3.2.3:

    CFLAGS="-O2 -mcpu=powerpc -Wa,-many " CXX=gcc CXXFLAGS="-O2
    -mcpu=powerpc -Wa,-many -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-named-z-libs=no --disable-shared
    
  • IBM AIX 4.3.3 ppc mit xlC_r (IBM Visual Age C/C++ 6.0):

    CC=xlc_r CFLAGS="-ma -O2 -qstrict -qoptimize=2 -qmaxmem=8192"
    CXX=xlC_r CXXFLAGS ="-ma -O2 -qstrict -qoptimize=2 -qmaxmem=8192"
    ./configure --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --with-named-z-libs=no
    --disable-shared --with-innodb
    
  • IBM AIX 5.1.0 ppc mit gcc 3.3:

    CFLAGS="-O2 -mcpu=powerpc -Wa,-many" CXX=gcc CXXFLAGS="-O2 -mcpu=powerpc
    -Wa,-many -felide-constructors -fno-exceptions -fno-rtti" ./configure
    --prefix=/usr/local/mysql --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --with-named-z-libs=no
    --disable-shared
    
  • IBM AIX 5.2.0 ppc mit xlC_r (IBM Visual Age C/C++ 6.0):

    CC=xlc_r CFLAGS="-ma -O2 -qstrict -qoptimize=2 -qmaxmem=8192"
    CXX=xlC_r CXXFLAGS="-ma -O2 -qstrict -qoptimize=2 -qmaxmem=8192"
    ./configure --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --with-named-z-libs=no
    --disable-shared --with-embedded-server --with-innodb
    
  • HP-UX 10.20 pa-risc1.1 mit gcc 3.1:

    CFLAGS="-DHPUX -I/opt/dce/include -O3 -fPIC" CXX=gcc CXXFLAGS="-DHPUX
    -I/opt/dce /include -felide-constructors -fno-exceptions -fno-rtti
    -O3 -fPIC" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-pthread --with-named-thread-libs=-ldce
    --with-lib-ccflags=-fPIC --disable-shared
    
  • HP-UX 11.00 pa-risc mit aCC (HP ANSI C++ B3910B A.03.50):

    CC=cc CXX=aCC CFLAGS=+DAportable CXXFLAGS=+DAportable ./configure
    --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --disable-shared
    --with-embedded-server --with-innodb
    
  • HP-UX 11.11 pa-risc2.0 64-Bit mit aCC (HP ANSI C++ B3910B A.03.33):

    CC=cc CXX=aCC CFLAGS=+DD64 CXXFLAGS=+DD64 ./configure
    --prefix=/usr/local/mysql --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --disable-shared
    
  • HP-UX 11.11 pa-risc2.0 32-Bit mit aCC (HP ANSI C++ B3910B A.03.33):

    CC=cc CXX=aCC CFLAGS="+DAportable" CXXFLAGS="+DAportable" ./configure
    --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --disable-shared
    --with-innodb
    
  • HP-UX 11.22 ia64 64-Bit mit aCC (HP aC++/ANSI C B3910B A.05.50):

    CC=cc CXX=aCC CFLAGS="+DD64 +DSitanium2" CXXFLAGS="+DD64 +DSitanium2"
    ./configure --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile --disable-shared
    --with-embedded-server --with-innodb
    
  • Apple Mac OS X 10.2 powerpc mit gcc 3.1:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared
    
  • FreeBSD 4.7 i386 mit gcc 2.95.4:

    CFLAGS=-DHAVE_BROKEN_REALPATH ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --enable-assembler --with-named-z-libs=not-used
    --disable-shared
    
  • FreeBSD 4.7 i386 mit LinuxThreads mit gcc 2.95.4:

    CFLAGS="-DHAVE_BROKEN_REALPATH -D__USE_UNIX98 -D_REENTRANT
    -D_THREAD_SAFE -I/usr/local/include/pthread/linuxthreads"
    CXXFLAGS="-DHAVE_BROKEN_REALPATH -D__USE_UNIX98 -D_REENTRANT
    -D_THREAD_SAFE -I/usr/local/include/pthread/linuxthreads" ./configure
    --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data
    --libexecdir=/usr/local/mysql/bin --enable-thread-safe-client
    --enable-local-infile --enable-assembler
    --with-named-thread-libs="-DHAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
    -D_THREAD_SAFE -I /usr/local/include/pthread/linuxthreads
    -L/usr/local/lib -llthread -llgcc_r" --disable-shared
    --with-embedded-server --with-innodb
    
  • QNX Neutrino 6.2.1 i386 mit gcc 2.95.3qnx-nto 20010315:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared
    

Die folgenden Binärdistributionen wurden auf Systemen von Dritten erstellt, die MySQL AB freundlicherweise von anderen Benutzern zur Verfügung gestellt wurden. Diese werden aus Gefälligkeit bereitgestellt; MySQL AB hat keine vollständige Kontrolle über diese Systeme, weswegen wir für Binärdistributionen, die auf ihnen erstellt wurden, nur eingeschränkten Support bieten können.

  • SCO Unix 3.2v5.0.7 i386 mit gcc 2.95.3:

    CFLAGS="-O3 -mpentium" LDFLAGS=-static CXX=gcc CXXFLAGS="-O3 -mpentium
    -felide-constructors" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-named-z-libs=no --enable-thread-safe-client
    --disable-shared
    
  • SCO UnixWare 7.1.4 i386 mit CC 3.2:

    CC=cc CFLAGS="-O" CXX=CC ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-named-z-libs=no --enable-thread-safe-client
    --disable-shared --with-readline
    
  • SCO OpenServer 6.0.0 i386 mit CC 3.2:

    CC=cc CFLAGS="-O" CXX=CC ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --with-named-z-libs=no --enable-thread-safe-client
    --disable-shared --with-readline
    
  • Compaq Tru64 OSF/1 V5.1 732 alpha mit cc/cxx (Compaq C V6.3-029i/DIGITAL C++ V6.1-027):

    CC="cc -pthread" CFLAGS="-O4 -ansi_alias -ansi_args -fast -inline
    speed -speculate all" CXX="cxx -pthread" CXXFLAGS="-O4 -ansi_alias
    -fast -inline speed -speculate all -noexceptions -nortti" ./configure
    --prefix=/usr/local/mysql --with-extra-charsets=complex
    --enable-thread-safe-client --enable-local-infile
    --with-named-thread-libs="-lpthread -lmach -lexc -lc" --disable-shared
    --with-mysqld-ldflags=-all-static
    
  • SGI Irix 6.5 IP32 mit gcc 3.0.1:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared
    
  • FreeBSD/sparc64 5.0 mit gcc 3.2.1:

    CFLAGS=-DHAVE_BROKEN_REALPATH ./configure --prefix=/usr/local/mysql
    --localstatedir=/usr/local/mysql/data --libexecdir=/usr/local/mysql/bin
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --disable-shared --with-innodb
    

Die folgenden Kompilierungsoptionen wurden für Binärpakete verwendet, die MySQL AB in der Vergangenheit bereitgestellt hat. Diese Binärdistributionen werden nicht mehr aktualisiert. Die Kompilierungsoptionen werden zu Referenzzwecken an diese Stelle aufgelistet.

  • Linux 2.2.xx SPARC mit egcs 1.1.2:

    CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc CXXFLAGS="-O3
    -fno-omit-frame-pointer -felide-constructors -fno-exceptions
    -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex --enable-thread-safe-client
    --enable-local-infile --enable-assembler --disable-shared
    
  • Linux 2.2.x mit x686 mit gcc 2.95.2:

    CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro
    -felide-constructors -fno-exceptions -fno-rtti" ./configure
    --prefix=/usr/local/mysql --enable-assembler
    --with-mysqld-ldflags=-all-static --disable-shared
    --with-extra-charsets=complex
    
  • SunOS 4.1.4 2 sun4c mit gcc 2.7.2.1:

    CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors" ./configure
    --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex
    --enable-assembler
    
  • SunOS 5.5.1 (und höher) sun4u mit egcs 1.0.3a oder 2.90.27 oder gcc 2.95.2 und höher:

    CC=gcc CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors
    -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql
    --with-low-memory --with-extra-charsets=complex --enable-assembler
    
  • SunOS 5.6 i86pc mit gcc 2.8.1:

    CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
    --with-low-memory --with-extra-charsets=complex
    
  • BSDI BSD/OS 3.1 i386 mit gcc 2.7.2.1:

    CC=gcc CXX=gcc CXXFLAGS=-O ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex
    
  • BSDI BSD/OS 2.1 i386 mit gcc 2.7.2:

    CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex
    
  • AIX 4.2 mit gcc 2.7.2.2:

    CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
    --with-extra-charsets=complex
    

2.1.3. Woher man MySQL bekommt

Informationen zur aktuellen MySQL-Version und Hinweise zum Download finden Sie auf unserer Downloadseite unter http://dev.mysql.com/downloads/. Eine vollständige und aktuelle Liste der Spiegelserver für den MySQL-Download finden Sie unter http://dev.mysql.com/downloads/mirrors.html. Dort erhalten Sie auch Hinweise dazu, wie Sie selbst einen MySQL-Spiegelserver anbieten können und wie Sie ausgefallene oder veraltete Spiegelserver melden.

Der Hauptspiegelserver ist über http://mirrors.sunsite.dk/mysql/ erreichbar.

2.1.4. Bestätigen der Paketintegrität mittels MD5-Prüfsummen oder GnuPG

Wenn Sie das für Ihre Zwecke geeignete MySQL-Paket heruntergeladen haben, sollten Sie, bevor Sie die Installation starten, sicherstellen, dass es intakt ist und nicht verändert wurde. Für diese Integritätsprüfung bietet MySQL drei Methoden an:

  • MD5-Prüfsummen

  • Kryptografiesignaturen unter Verwendung von GnuPG (GNU Privacy Guard)

  • die eingebaute RPM-Integritätsprüfmethode für RPM-Pakete

Die folgenden Abschnitte beschreiben, wie diese Methoden verwendet werden.

Wenn Sie feststellen, dass MD5-Prüfsumme oder GPG-Signaturen nicht übereinstimmen, probieren Sie zunächst, das betreffende Paket noch einmal von einem anderen Spiegelserver herunterzuladen. Wenn Sie die Integrität des Pakets mehrfach nicht erfolgreich verifizieren können, teilen Sie uns dies unter Angabe des vollständigen Paketnamens und des verwendeten Downloadservers via E-Mail an die Adresse oder mit. Bitte melden Sie Probleme mit dem Download nicht über das Bugmeldesystem.

2.1.4.1. Verifizieren der MD5-Prüfsumme

Wenn Sie ein MySQL-Paket heruntergeladen haben, sollten Sie sicherstellen, dass die zugehörige MD5-Prüfsumme mit der auf den MySQL-Downloadseiten angegebenen Prüfsumme übereinstimmt. Jedes Paket weist eine individuelle Prüfsumme auf, die Sie mithilfe des folgenden Befehls abfragen können (hierbei ist package_name der Name des heruntergeladenen Pakets):

shell> md5sum package_name

Beispiel:

shell> md5sum mysql-standard-5.1.5-alpha-linux-i686.tar.gz
aaab65abbec64d5e907dcd41b8699945  mysql-standard-5.1.5-alpha-linux-i686.tar.gz

Vergewissern Sie sich, dass die resultierende Prüfsumme (der angezeigte Hexadezimal-String) mit der Angabe übereinstimmt, die auf der Downloadseite unmittelbar unter dem betreffenden Paket angegeben ist.

Hinweis: Sie müssen die Prüfsumme der Archivdatei (d. h. der .zip- oder .tar.gz-Datei) verifizieren, nicht die Prüfsumme der Dateien, die im Archiv gespeichert sind.

Beachten Sie, dass nicht alle Betriebssysteme den Befehl md5sum unterstützen. Bei manchen heißt er einfach md5, bei anderen ist er überhaupt nicht enthalten. Bei Linux ist er Teil des Pakets GNU Text Utilities, das für eine Vielzahl von Plattformen verfügbar ist. Sie können den Quellcode auch unter http://www.gnu.org/software/textutils/ herunterladen. Wenn Sie OpenSSL installiert haben, können Sie stattdessen den Befehl openssl md5 package_name verwenden. Eine Windows-Implementierung des Befehls md5 ist unter http://www.fourmilab.ch/md5/ verfügbar. winMd5Sum ist ein grafisches MD5-Prüfwerkzeug, das Sie sich unter http://www.nullriver.com/index/products/winmd5sum beschaffen können.

2.1.4.2. Signaturüberprüfung mit GnuPG

Eine andere Methode zur Überprüfung der Integrität und Authentizität eines Pakets besteht in der Verwendung kryptografischer Signaturen. Diese sind zuverlässiger, aber arbeitsaufwändiger als MD5-Prüfsummen.

Wir von MySQL AB signieren MySQL-Pakete für den Download mit GnuPG (GNU Privacy Guard). GnuPG ist eine Open-Source-Alternative zum bekannten Pretty Good Privacy (PGP) von Phil Zimmermann. Weitere Informationen zu GnuPG sowie zu dessen Download und Installation auf Ihrem System finden Sie unter http://www.gnupg.org/. Die meisten Linux-Distributionen werden mit standardmäßig installiertem GnuPG ausgeliefert. Weitere Informationen zu GnuPG finden Sie unter http://www.openpgp.org/.

Um die Signatur für ein bestimmtes Paket zu überprüfen, müssen Sie sich zunächst eine Kopie des GPG-Build-Schlüssels von MySQL AB beschaffen. Diese können Sie unter http://www.keyserver.net/ herunterladen. Der erforderliche Schlüssel heißt build@mysql.com. Alternativ können Sie den Schlüssel aus dem folgenden Text kopieren und direkt einfügen:

Key ID:
pub  1024D/5072E1F5 2003-02-03
     MySQL Package signing key (www.mysql.com) <build@mysql.com>
Fingerprint: A4A9 4068 76FC BD3C 4567  70C8 8C71 8D3B 5072 E1F5

Public Key (ASCII-armored):

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

mQGiBD4+owwRBAC14GIfUfCyEDSIePvEW3SAFUdJBtoQHH/nJKZyQT7h9bPlUWC3
RODjQReyCITRrdwyrKUGku2FmeVGwn2u2WmDMNABLnpprWPkBdCk96+OmSLN9brZ
fw2vOUgCmYv2hW0hyDHuvYlQA/BThQoADgj8AW6/0Lo7V1W9/8VuHP0gQwCgvzV3
BqOxRznNCRCRxAuAuVztHRcEAJooQK1+iSiunZMYD1WufeXfshc57S/+yeJkegNW
hxwR9pRWVArNYJdDRT+rf2RUe3vpquKNQU/hnEIUHJRQqYHo8gTxvxXNQc7fJYLV
K2HtkrPbP72vwsEKMYhhr0eKCbtLGfls9krjJ6sBgACyP/Vb7hiPwxh6rDZ7ITnE
kYpXBACmWpP8NJTkamEnPCia2ZoOHODANwpUkP43I7jsDmgtobZX9qnrAXw+uNDI
QJEXM6FSbi0LLtZciNlYsafwAPEOMDKpMqAK6IyisNtPvaLd8lH0bPAnWqcyefep
rv0sxxqUEMcM3o7wwgfN83POkDasDbs3pjwPhxvhz6//62zQJ7Q7TXlTUUwgUGFj
a2FnZSBzaWduaW5nIGtleSAod3d3Lm15c3FsLmNvbSkgPGJ1aWxkQG15c3FsLmNv
bT6IXQQTEQIAHQUCPj6jDAUJCWYBgAULBwoDBAMVAwIDFgIBAheAAAoJEIxxjTtQ
cuH1cY4AnilUwTXn8MatQOiG0a/bPxrvK/gCAJ4oinSNZRYTnblChwFaazt7PF3q
zIhMBBMRAgAMBQI+PqPRBYMJZgC7AAoJEElQ4SqycpHyJOEAn1mxHijft00bKXvu
cSo/pECUmppiAJ41M9MRVj5VcdH/KN/KjRtW6tHFPYhMBBMRAgAMBQI+QoIDBYMJ
YiKJAAoJELb1zU3GuiQ/lpEAoIhpp6BozKI8p6eaabzF5MlJH58pAKCu/ROofK8J
Eg2aLos+5zEYrB/LsrkCDQQ+PqMdEAgA7+GJfxbMdY4wslPnjH9rF4N2qfWsEN/l
xaZoJYc3a6M02WCnHl6ahT2/tBK2w1QI4YFteR47gCvtgb6O1JHffOo2HfLmRDRi
Rjd1DTCHqeyX7CHhcghj/dNRlW2Z0l5QFEcmV9U0Vhp3aFfWC4Ujfs3LU+hkAWzE
7zaD5cH9J7yv/6xuZVw411x0h4UqsTcWMu0iM1BzELqX1DY7LwoPEb/O9Rkbf4fm
Le11EzIaCa4PqARXQZc4dhSinMt6K3X4BrRsKTfozBu74F47D8Ilbf5vSYHbuE5p
/1oIDznkg/p8kW+3FxuWrycciqFTcNz215yyX39LXFnlLzKUb/F5GwADBQf+Lwqq
a8CGrRfsOAJxim63CHfty5mUc5rUSnTslGYEIOCR1BeQauyPZbPDsDD9MZ1ZaSaf
anFvwFG6Llx9xkU7tzq+vKLoWkm4u5xf3vn55VjnSd1aQ9eQnUcXiL4cnBGoTbOW
I39EcyzgslzBdC++MPjcQTcA7p6JUVsP6oAB3FQWg54tuUo0Ec8bsM8b3Ev42Lmu
QT5NdKHGwHsXTPtl0klk4bQk4OajHsiy1BMahpT27jWjJlMiJc+IWJ0mghkKHt92
6s/ymfdf5HkdQ1cyvsz5tryVI3Fx78XeSYfQvuuwqp2H139pXGEkg0n6KdUOetdZ
Whe70YGNPw1yjWJT1IhMBBgRAgAMBQI+PqMdBQkJZgGAAAoJEIxxjTtQcuH17p4A
n3r1QpVC9yhnW2cSAjq+kr72GX0eAJ4295kl6NxYEuFApmr1+0uUq/SlsQ==
=YJkx
-----END PGP PUBLIC KEY BLOCK-----

Um den Schlüssel in Ihren eigenen öffentlichen GPG-Schlüsselbund zu importieren, verwenden Sie gpg --import. Haben Sie den Schlüssel beispielsweise unter dem Dateinamen mysql_pubkey.asc gespeichert, dann sieht der Importbefehl wie folgt aus:

shell> gpg --import mysql_pubkey.asc

Nachdem Sie den öffentlichen Schlüssel heruntergeladen und importiert haben, laden Sie das gewünschte MySQL-Paket und die entsprechende Signatur herunter (diese steht ebenfalls auf der Downloadseite zur Verfügung). Die Signaturdatei hat den gleichen Namen wie die Distributionsdatei und trägt die Erweiterung .asc. Ein Beispiel:

Distributionsdateimysql-standard-5.1.5-alpha-linux-i686.tar.gz
Signaturdateimysql-standard-5.1.5-alpha-linux-i686.tar.gz.asc

Stellen Sie sicher, dass beide Dateien im gleichen Verzeichnis gespeichert sind, und führen Sie dann den folgenden Befehl aus, um die Signatur der Distributionsdatei zu verifizieren:

shell> gpg --verify package_name.asc

Beispiel:

shell> gpg --verify mysql-standard-5.1.5-alpha-linux-i686.tar.gz.asc
gpg: Signature made Tue 12 Jul 2005 23:35:41 EST using DSA key ID 5072E1F5
gpg: Good signature from "MySQL Package signing key (www.mysql.com) <build@mysql.com>"

Die Meldung Good signature (Signatur korrekt) zeigt an, dass alles in Ordnung ist. Sie können alle Warnungen vom Typ insecure memory ignorieren, die unter Umständen angezeigt werden.

Weitere Informationen zum Umgang mit öffentlichen Schlüsseln finden Sie in der GPG-Dokumentation.

2.1.4.3. Signaturüberprüfung mit RPM

Bei RPM-Paketen ist keine separate Signatur vorhanden. RPM-Pakete enthalten vielmehr eine integrierte GPG-Signatur und eine MD5-Prüfsumme. Sie können ein Paket durch Ausführen des folgenden Befehls verifizieren:

shell> rpm --checksig package_name.rpm

Beispiel:

shell> rpm --checksig MySQL-server-5.1.5-alpha-0.i386.rpm
MySQL-server-5.1.5-alpha-0.i386.rpm: md5 gpg OK

Hinweis: Wenn Sie RPM 4.1 verwenden und die Meldung (GPG) NOT OK (MISSING KEYS: GPG#5072e1f5) erhalten, obwohl Sie den öffentlichen MySQL-Schlüssel zuerst in Ihren eigenen GPG-Schlüsselbund importiert haben, dann müssen Sie den Schlüssel zuerst in Ihren RPM-Schlüsselbund importieren. RPM 4.1 verwendet nicht länger den GPG-Schlüsselbund (oder GPG selbst). Stattdessen arbeitet es mit einem eigenen Schlüsselbund, da es eine systemweite Anwendung ist, während der öffentliche GPG-Schlüsselbund eine benutzerspezifische Datei ist. Um den öffentlichen MySQL-Schlüssel in den RPM-Schlüsselbund zu importieren, besorgen Sie sich den Schlüssel zunächst wie in Abschnitt 2.1.4.2, „Signaturüberprüfung mit GnuPG, beschrieben. Nachfolgend verwenden Sie den Befehl rpm --import für den Schlüsselimport. Haben Sie den öffentlichen Schlüssel beispielsweise unter dem Dateinamen mysql_pubkey.asc gespeichert, dann sieht der Importbefehl wie folgt aus:

shell> rpm --import mysql_pubkey.asc

Wie Sie sich den öffentlichen MySQL-Schlüssel beschaffen, lesen Sie in Abschnitt 2.1.4.2, „Signaturüberprüfung mit GnuPG.

2.1.5. Installationslayouts

Dieser Abschnitt beschreibt die standardmäßige Struktur der Verzeichnisse, die bei der Installation der von MySQL AB bereitgestellten Binär- oder Quelldistributionen erstellt werden. Distributionen anderer Anbieter verwenden unter Umständen andere Strukturen als die hier beschriebenen.

Bei MySQL 5.1 unter Windows heißt das Standardinstallationsverzeichnis C:\Programme\MySQL\MySQL Server 5.1. (Manche Windows-Benutzer ziehen eine Installation in C:\mysql vor, da dieses Verzeichnis früher einmal der Standardpfad war. Allerdings bleibt auch in diesem Fall die Struktur der Unterverzeichnisse dieselbe.) Das Installationsverzeichnis hat die folgenden Unterverzeichnisse:

VerzeichnisVerzeichnisinhalt
binClientprogramme und der mysqld-Server
dataLogdateien, Datenbanken
DocsDokumentation
examplesBeispielprogramme und -skripten
includeInclude-Dateien (Header-Dateien)
libBibliotheken
scriptsHilfsprogrammskripten
shareFehlermeldungsdateien

Installationen, die mit den Linux-RPM-Dateien von MySQL AB erstellt werden, erzeugen Dateien in den folgenden Systemverzeichnissen:

VerzeichnisVerzeichnisinhalt
/usr/binClientprogramme und -skripten
/usr/sbinDer mysqld-Server
/var/lib/mysqlLogdateien, Datenbanken
/usr/share/doc/packagesDokumentation
/usr/include/mysqlInclude-Dateien (Header-Dateien)
/usr/lib/mysqlBibliotheken
/usr/share/mysqlFehlermeldungs- und Zeichensatzdateien
/usr/share/sql-benchBenchmarks

Unter Unix wird eine tar-Binärdistributionsdatei installiert, indem sie an der gewählten Installationsposition (meist /usr/local/mysql) entpackt wird. Dabei werden die folgenden Unterverzeichnisse erstellt:

VerzeichnisVerzeichnisinhalt
binClientprogramme und der mysqld-Server
dataLogdateien, Datenbanken
docsDokumentation, ChangeLog
includeInclude-Dateien (Header-Dateien)
libBibliotheken
scriptsmysql_install_db
share/mysqlFehlermeldungsdateien
sql-benchBenchmarks

Eine Quelldistribution wird installiert, nachdem Sie sie konfiguriert und kompiliert haben. Standardmäßig werden bei der Installation Dateien in den folgenden Unterverzeichnissen von /usr/local erstellt:

VerzeichnisVerzeichnisinhalt
binClientprogramme und -skripten
include/mysqlInclude-Dateien (Header-Dateien)
infoDokumentation im Info-Format
lib/mysqlBibliotheken
libexecDer mysqld-Server
share/mysqlFehlermeldungsdateien
sql-benchBenchmarks und der Crash-Me-Test
varDatenbanken und Logdateien

Innerhalb des Installationsverzeichnisses unterscheidet sich die Struktur einer Quelldistribution wie folgt von der einer Binärdistribution:

  • Der mysqld-Server wird im Verzeichnis libexec statt im Verzeichnis bin installiert.

  • Das Datenverzeichnis ist var und nicht data.

  • mysql_install_db wird im Verzeichnis bin installiert, nicht im Verzeichnis scripts.

  • Die Header-Datei- und Bibliotheksverzeichnisse sind include/mysql und lib/mysql statt include und lib.

Sie können Ihre eigene Binärdistribution aus einer kompilierten Quelldistribution erstellen, indem Sie das Skript scripts/make_binary_distribution aus dem Stammverzeichnis der Quelldistribution ausführen.

2.2. Schnelle Standardinstallation von MySQL

Die nachfolgenden Abschnitte behandeln die Installation von MySQL auf Plattformen, für die wir Pakete im nativen Paketformat der jeweiligen Plattform anbieten. (Dies wird auch als Durchführung einer „Binärinstallation“ bezeichnet.) Binärdistributionen von MySQL sind allerdings auch für viele andere Plattformen verfügbar. In Abschnitt 2.7, „Installation von MySQL auf anderen Unix-ähnlichen Systemen“, finden Sie allgemeine Installationsanweisungen für diese Pakete, die für alle Plattformen gelten.

In Abschnitt 2.1, „Allgemeines zur Installation“, finden Sie weitere Informationen dazu, welche anderen Binärdistributionen verfügbar sind und wie Sie diese erhalten.

2.3. Installation von MySQL unter Windows

Eine native Windows-Distribution von MySQL wird von MySQL AB seit Version 3.21 angeboten. Der Anteil dieser Distributionen an den täglichen MySQL-Downloads ist beträchtlich. In diesem Abschnitt beschreiben wir die Vorgehensweise bei der MySQL-Installation unter Windows.

Das Installationsprogramm der Windows-Version von MySQL installiert in Verbindung mit einem grafischen Konfigurations-Assistenten automatisch MySQL, erstellt eine Optionsdatei, startet den Server und sichert die voreingestellten Benutzerkonten ab.

Wenn Sie eine vorhandene Installation von MySQL aktualisieren, die älter als MySQL 4.1.5 ist, dann müssen Sie die folgenden Schritte durchführen:

  1. Besorgen Sie sich die Distribution und installieren Sie sie.

  2. Konfigurieren Sie, sofern erforderlich, eine Optionsdatei.

  3. Wählen Sie den zu verwendenden Server aus.

  4. Starten Sie den Server.

  5. Konfigurieren Sie Passwörter für die vorgabeseitigen MySQL-Konten.

Diese Vorgehensweise muss auch bei neueren MySQL-Installationen beachtet werden, wenn Sie ein Installationspaket verwenden, das kein Installationsprogramm enthält.

MySQL für Windows ist in verschiedenen Distributionsformaten erhältlich:

  • Es sind Binärdistributionen verfügbar, die ein Setup-Programm enthalten, das alles Erforderliche installiert, sodass Sie den Server sofort starten können. Ein anderes Binärdistributionsformat enthält ein Archiv, das Sie einfach an der Installationsposition entpacken und dann selbst konfigurieren. Detaillierte Informationen finden Sie in Abschnitt 2.3.2, „Auswahl eines Installationspakets“.

  • Die Quelldistribution enthält den gesamten Code und alle Supportdateien zur Erstellung der ausführbaren Dateien mithilfe des Compiler-Systems Visual Studio 2003.

Im Allgemeinen sollten Sie die Binärdistribution verwenden. Sie ist einfacher zu verwenden als die übrigen, und Sie benötigen keine zusätzlichen Tools, um MySQL zum Laufen zu bringen.

Im folgenden Abschnitt wird beschrieben, wie MySQL unter Windows mithilfe einer Binärdistribution installiert wird. Informationen zur Installation einer Quelldistribution finden Sie in Abschnitt 2.8.6, „Windows-Quelldistribution“.

2.3.1. Systemvoraussetzungen für Windows

Um MySQL unter Windows auszuführen, benötigen Sie Folgendes:

  • Ein 32-Bit-Windows-Betriebssystem wie Windows 9x, Me, NT, 2000, XP oder Windows Server 2003.

    Windows NT-basierte Betriebssysteme (NT, 2000, XP, 2003) gestatten Ihnen die Ausführung des MySQL Servers als Dienst. Die Verwendung eines Windows NT-basierten Betriebssystems wird dringend empfohlen. Siehe auch Abschnitt 2.3.12, „Starten von MySQL als Windows-Dienst“.

    Sie sollten MySQL unter Windows generell mithilfe eines Kontos erstellen, das über Administratorrechte verfügt. Andernfalls kann es bei bestimmten Operationen wie der Bearbeitung der Umgebungsvariablen PATH oder dem Zugriff auf den Service Control Manager zu Problemen kommen.

  • TCP/IP-Protokollunterstützung.

  • Eine Kopie der MySQL-Binärdistribution für Windows. Diese kann unter http://dev.mysql.com/downloads/ heruntergeladen werden. Siehe auch Abschnitt 2.1.3, „Woher man MySQL bekommt“.

    Hinweis: Wenn Sie die Distribution via FTP herunterladen, empfehlen wir Ihnen die Verwendung eines geeigneten FTP-Clients mit Wiederaufnahmefunktion für den Download, um eine Dateibeschädigung während des Downloads auszuschließen.

  • Zum Entpacken der Distributionsdatei ein Programm, das .zip-Dateien lesen kann.

  • Ausreichend viel Speicherplatz auf Ihrer Festplatte, um MySQL entpacken und installieren und die Datenbanken entsprechend Ihren Anforderungen erstellen zu können (mindestens 200 Mbyte empfohlen).

Je nachdem, wie Sie MySQL einsetzen wollen, können auch weitere Anforderungen vorliegen:

  • Wenn Sie die Verbindung zum MySQL Server via ODBC herstellen wollen, benötigen Sie einen Connector/ODBC-Treiber. Siehe auch Abschnitt 25.1, „MySQL Connector/ODBC“.

  • Wenn Sie Tabellen benötigen, die größer als 4 Gbyte sind, installieren Sie MySQL auf NTFS oder einem neueren Dateisystem. Vergessen Sie nicht, bei der Erstellung von Tabellen MAX_ROWS und AVG_ROW_LENGTH zu verwenden. Siehe auch Abschnitt 13.1.5, „CREATE TABLE.

2.3.2. Auswahl eines Installationspakets

Bei MySQL 5.1 können Sie zwischen drei Installationspaketen für MySQL unter Windows auswählen. Die folgenden Pakete sind verfügbar:

  • Das Essentials-Paket: Dieses Paket erkennen Sie am Dateinamen mit dem Aufbau mysql-essential-5.1.5-alpha-win32.msi. Es enthält die für die Installation von MySQL unter Windows mindestens erforderlichen Dateien einschließlich des Konfigurations-Assistenten. Nicht enthalten sind optionale Komponenten wie der eingebettete Server und die Benchmark-Reihe.

  • Das Complete-Paket: Dieses Paket erkennen Sie am Dateinamen mit dem Aufbau mysql-5.1.5-alpha-win32.zip. Es enthält alle Dateien, die für eine vollständige Windows-Installation erforderlich sind, einschließlich des Konfigurations-Assistenten. Ferner enthalten sind optionale Komponenten wie der eingebettete Server und die Benchmark-Reihe.

  • Das Noinstall-Archiv: Dieses Paket erkennen Sie am Dateinamen mit dem Aufbau mysql-noinstall-5.1.5-alpha-win32.zip. Es enthält alle im Complete-Paket enthaltenen Dateien mit Ausnahme des Konfigurations-Assistenten. Das Paket umfasst kein automatisiertes Installationsprogramm, muss also manuell installiert und konfiguriert werden.

Für die meisten Benutzer wird das Essentials-Paket empfohlen.

Welches Paket Sie auswählen, wirkt sich auf den nachfolgenden Installationsvorgang aus. Entscheiden Sie sich für das Essentials- oder Complete-Paket, dann finden Sie weitere Informationen in Abschnitt 2.3.3, „Installation von MySQL mit dem automatischen Installer“. Wollen Sie MySQL hingegen aus dem Noinstall-Archiv installieren, dann fahren Sie fort mit Abschnitt 2.3.6, „Installation von MySQL aus einem Noinstall-Zip-Archiv“.

2.3.3. Installation von MySQL mit dem automatischen Installer

Neue MySQL-Benutzer können den MySQL-Installations-Assistenten und den MySQL-Konfigurations-Assistenten zur Installation von MySQL unter Windows verwenden. Diese Assistenten sind so aufgebaut, dass die MySQL-Installation und -Konfiguration neuen Benutzern den sofortigen Einsatz von MySQL ermöglicht.

Die MySQL-Installations- und MySQL-Konfigurations-Assistenten sind Bestandteil des Essentials- und des Complete-Pakets von MySQL. Sie werden für die meisten MySQL-Standardinstallationen empfohlen. Ausnahmen betreffen Benutzer, die mehrere MySQL-Instanzen auf demselben Serverhost installieren wollen, und fortgeschrittene Benutzer, die volle Kontrolle über die Serverkonfiguration wünschen.

2.3.4. Verwendung des MySQL-Installations-Assistenten

2.3.4.1. Einführung in den Installations-Assistenten

Der MySQL-Installations-Assistent ist ein Installationsprogramm für den MySQL Server, das die aktuellen Installer-Technologien von Microsoft Windows nutzt. In Verbindung mit dem MySQL-Konfigurations-Assistenten ermöglicht der MySQL-Installations-Assistent einem Benutzer die Installation und Konfiguration eines MySQL Servers, der direkt nach der Installation einsatzbereit ist.

Der MySQL-Installations-Assistent ist das Standardinstallationsprogramm für alle MySQL Server-Distributionen ab Version 4.1.5. Benutzer vorheriger MySQL-Versionen müssen ihre vorhandenen MySQL-Installationen manuell herunterfahren und entfernen, bevor sie MySQL mit dem MySQL-Installations-Assistenten installieren. In Abschnitt 2.3.4.7, „Upgrade von MySQL mit dem Installations-Assistenten“, finden Sie weitere Informationen zur Aktualisierung einer früheren Version.

In den aktuellen Windows-Versionen hat Microsoft eine verbesserte Version von MSI (Microsoft Windows Installer) implementiert. In Windows 2000, Windows XP und Windows Server 2003 ist MSI der De-facto-Standard für die Anwendungsinstallation. Der MySQL-Installations-Assistent nutzt diese Technologie, um den Installationsprozess reibungsloser und flexibler zu gestalten.

Die MSI-Engine wurde mit der Veröffentlichung von Windows XP aktualisiert. Wenn Sie eine vorherige Windows-Version einsetzen, finden Sie in dem Microsoft Knowledge Base-Artikel unter der Adresse http://support.microsoft.com/default.aspx?scid=kb;EN-US;292539 Informationen zum Upgrade auf die aktuelle Version der MSI-Engine.

Ferner hat Microsoft kürzlich das WiX-Toolkit (Windows Installer XML) vorgestellt. Hierbei handelt es sich um das erste offizielle Open-Source-Projekt von Microsoft. Wir verwenden WiX nun auch, denn erstens ist es ein Open-Source-Projekt, und zweitens gestattet es die Handhabung des gesamten Windows-Installationsvorgangs auf flexible Weise unter Verwendung von Skripten.

Die Optimierung des MySQL-Installations-Assistenten steht und fällt mit der Unterstützung und dem Feedback solcher Benutzer wie Ihnen. Wenn Sie feststellen, dass im MySQL-Installations-Assistenten etwas fehlt, das für Sie sehr wichtig wäre, oder einen Bug entdecken, melden Sie dies bitte in unserer Bugdatenbank. Hinweise hierzu finden Sie in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

2.3.4.2. Download und Start des MySQL-Installations-Assistenten

Die MySQL-Installationspakete können unter http://dev.mysql.com/downloads/ heruntergeladen werden. Wenn das von Ihnen heruntergeladene Paket in einem ZIP-Archiv gespeichert ist, müssen Sie dieses zunächst entpacken.

Der Vorgang zum Starten des Assistenten hängt vom Inhalt des heruntergeladenen Installationspakets ab. Enthält dieses eine Datei namens setup.exe, dann doppelklicken Sie darauf, um den Installationsvorgang zu starten. Enthält das Paket hingegen eine .msi-Datei, dann doppelklicken Sie darauf, um den Installationsvorgang zu starten.

2.3.4.3. Auswahl eines Installationstyps

Es sind drei Installationstypen vorhanden: Typical (Standard), Complete (Vollständig) und Custom (Benutzerdefiniert).

Bei der Installationsmethode Typical werden der MySQL Server, der Befehlszeilenclient mysql und die befehlszeilenbasierten Hilfsprogramme installiert. Zu den Befehlszeilenclients und Hilfsprogrammen gehören mysqldump, myisamchk und verschiedene weitere Programme zur Verwaltung des MySQL Servers.

Die Installationsmethode Complete installiert alle Komponenten, die im Installationspaket enthalten sind. Das vollständige Installationspaket umfasst Komponenten wie die eingebettete Serverbibliothek, die Benchmark-Reihe, Support-Skripten und die Dokumentation.

Bei der Installationsmethode Custom haben Sie vollständige Kontrolle darüber, welche Pakete installiert werden und wie der Installationspfad aussieht. Weitere Informationen zur benutzerdefinierten Installation finden Sie unter Abschnitt 2.3.4.4, „Der Dialog zur benutzerspezifischen Installation“.

Wenn Sie sich für die Installationsmethode Typical oder Complete entschieden haben und auf die Schaltfläche Next klicken, wird ein Fenster angezeigt, in dem Sie die gewählten Optionen überprüfen und die Installation dann starten können. Wenn Sie hingegen die Methode Custom auswählen und dann auf die Schaltfläche Next klicken, wird nachfolgend das Dialogfeld für die benutzerdefinierte Installation aufgerufen, welches in Abschnitt 2.3.4.4, „Der Dialog zur benutzerspezifischen Installation“, beschrieben wird.

2.3.4.4. Der Dialog zur benutzerspezifischen Installation

Wenn Sie den Installationspfad oder bestimmte Komponenten ändern wollen, die vom MySQL-Installations-Assistenten installiert werden, wählen Sie die Installationsmethode Custom.

Alle verfügbaren Komponenten werden dann in einer Baumstruktur links im Installationsdialog angezeigt. Komponenten, die nicht installiert werden, sind durch ein rotes X gekennzeichnet, während für die Installation gewählten Komponenten ein graues Symbol aufweisen. Um den Installationsstatus einer Komponente umzuschalten, klicken Sie auf das Symbol der betreffenden Komponente und wählen die gewünschte Option aus der erscheinenden Dropdown-Liste.

Sie können den vorgegebenen Installationspfad ändern, indem Sie auf die Schaltfläche Change... rechts neben dem angezeigten Installationspfad klicken.

Wenn Sie die zu installierenden Komponenten und den Pfad gewählt haben, klicken Sie auf die Schaltfläche Next, um den Bestätigungsdialog anzuzeigen.

2.3.4.5. Der Bestätigungsdialog

Wenn Sie eine Installationsmethode und ggf. die zu installierenden Komponenten gewählt haben, schreiten Sie fort zum Bestätigungsdialog. Installationsmethode und Pfad werden nun zur Bestätigung angezeigt.

Wenn die angezeigten Einstellungen korrekt sind, klicken Sie auf die Schaltfläche Install, um MySQL zu installieren. Wenn Sie Ihre Einstellungen noch einmal ändern wollen, klicken Sie auf die Schaltfläche Back. Um den MySQL-Installations-Assistenten zu verlassen, ohne MySQL zu installieren, klicken Sie auf die Schaltfläche Cancel.

Wenn die Installation abgeschlossen ist, können Sie sich auf der MySQL-Website registrieren. Wenn Sie registriert sind, können Sie Mitteilungen an die MySQL-Foren unter forums.mysql.com schicken, Bugs unter bugs.mysql.com melden und unseren Newsletter abonnieren. Der Abschlussbildschirm des Installationsprogramms zeigt eine Zusammenfassung der Installation und erlaubt Ihnen den Aufruf des MySQL-Konfigurations-Assistenten, mit dem Sie eine Konfigurationsdatei erstellen, den MySQL-Dienst installieren und die Sicherheitseinstellungen konfigurieren können.

2.3.4.6. Änderungen, die der MySQL-Installations-Assistent durchführt

Wenn Sie auf die Schaltfläche Install klicken, startet der MySQL-Installations-Assistent den Installationsvorgang und nimmt bestimmte Änderungen an Ihrem System vor, die in den nachfolgenden Abschnitten beschrieben sind.

Änderungen in der Registrierung

Der MySQL-Installations-Assistent erstellt bei Auswahl der Standardinstallation einen Schlüssel in der Windows-Registrierung. Dieser befindet sich unter HKEY_LOCAL_MACHINE\SOFTWARE\MySQL AB.

Der MySQL-Installations-Assistent richtet einen Schlüssel ein, der nach der Hauptversion des installierten Servers benannt ist (z. B. MySQL Server 5.1). Dieser enthält zwei Zeichenfolgenwerte namens Location und Version. Die Zeichenfolge Location enthält den Pfad zum Installationsverzeichnis. Bei einer Standardinstallation heißt der Wert C:\Programme\MySQL\MySQL Server 5.1\. Die Zeichenfolge Version enthält die Release-Nummer. Wird etwa MySQL Server 5.1.5-alpha installiert, dann enthält der Schlüssel den Wert 5.1.5-alpha.

Diese Registrierungsschlüssel ermöglichen es externen Programmen, das Installationsverzeichnis des MySQL Servers zu ermitteln; hierdurch wird eine zeitaufwändige vollständige Durchsuchung der Festplatte zur Ermittlung des Installationspfads des MySQL Servers unnötig. Die Registrierungsschlüssel sind für die Ausführung des Servers nicht erforderlich und werden, wenn Sie MySQL aus dem Noinstall-Archiv installieren, auch nicht erstellt.

Änderungen im Startmenü

Der MySQL-Installations-Assistent erstellt im Windows-Menü Start einen neuen Eintrag in einem MySQL-Menü, welches nach der installierten MySQL-Hauptversion benannt ist. Installieren Sie beispielsweise MySQL 5.1, dann erstellt der Installations-Assistent einen Abschnitt namens MySQL Server 5.1 im Menü Start.

In diesem neuen Abschnitt im Menü Start werden die folgenden Einträge eingerichtet:

  • MySQL Command Line Client: Dies ist eine Verknüpfung mit dem Befehlszeilenclient mysql, die so konfiguriert ist, dass eine Verbindung als Benutzer root hergestellt wird. Beim Aufruf fordert die Verknüpfung die Eingabe eines root-Benutzerpassworts an, wenn Sie eine Verbindung herstellen.

  • MySQL Server Instance Config Wizard: Dies ist eine Verknüpfung zum MySQL-Konfigurations-Assistenten. Verwenden Sie diese Verknüpfung zur Konfiguration eines neu installierten oder zur Neukonfiguration eines vorhandenen Servers.

  • MySQL Documentation: Dies ist eine Verknüpfung zur Dokumentation zum MySQL Server, die lokal im Installationsverzeichnis des MySQL Servers gespeichert ist. Die Option ist nicht verfügbar, wenn der MySQL Server aus dem Essentials-Paket installiert wurde.

Änderungen am Dateisystem

Der MySQL-Installations-Assistent installiert den MySQL 5.1 Server standardmäßig im Verzeichnis C:\Programme\MySQL\MySQL Server 5.1. Hierbei ist Programme das Standardverzeichnis für Anwendungen auf Ihrem System und 5.1 die Hauptversion Ihres MySQL Servers. Dies ist das empfohlene Verzeichnis für den MySQL Server. Es ersetzt die vormalige Standardposition C:\mysql.

Standardmäßig werden alle MySQL-Anwendungen in einem gemeinsamen Verzeichnis in C:\Programme\MySQL gespeichert. Hierbei ist Programme in Ihrer Windows-Installation das Standardverzeichnis für Anwendungen. Bei einer typischen MySQL-Installation auf einem Entwicklersystem könnte dies wie folgt aussehen:

C:\Programme\MySQL\MySQL Server 5.1
C:\Programme\MySQL\MySQL Administrator 1.0
C:\Programme\MySQL\MySQL Query Browser 1.0

Dieser Ansatz erleichtert Verwaltung und Pflege aller auf einem System installierten MySQL-Anwendungen.

2.3.4.7. Upgrade von MySQL mit dem Installations-Assistenten

Der MySQL-Installations-Assistent kann Server-Upgrades automatisch mithilfe der MSI-Aktualisierungsfunktionen durchführen. Das bedeutet, dass Sie eine vorhandene Installation nicht mehr manuell entfernen müssen, bevor Sie einen neuen Release installieren. Das Installationsprogramm beendet und entfernt den vorhandenen MySQL-Dienst selbsttätig, bevor die neue Version installiert wird.

Automatische Upgrades sind nur dann verfügbar, wenn Sie Aktualisierungen zwischen Installationen durchführen, die die gleiche Haupt- und Unterversionsnummern aufweisen. So kann etwa ein automatisches Upgrade von MySQL 4.1.5 auf MySQL 4.1.6 erfolgen, nicht jedoch von MySQL 5.0 auf MySQL 5.1.

Siehe auch Abschnitt 2.3.15, „Upgrade von MySQL unter Windows“.

2.3.5. Verwendung des Konfigurations-Assistenten

2.3.5.1. Einführung in den Konfigurations-Assistenten

Der MySQL-Konfigurations-Assistent hilft Ihnen bei der Automatisierung der Serverkonfiguration unter Windows. Der Konfigurations-Assistent erstellt eine benutzerdefinierte Datei my.ini. Hierzu stellt er Ihnen eine Reihe von Fragen und verknüpft Ihre Antworten dann mit einer Vorlage, um eine Datei my.ini zu erzeugen, die für Ihre Installation maßgeschneidert ist.

Der MySQL-Konfigurations-Assistent ist Bestandteil des MySQL 5.1-Servers und derzeit nur für Windows-Benutzer verfügbar.

Der MySQL-Konfigurations-Assistent ist zu einem Großteil Ergebnis des Feedbacks, das MySQL AB über viele Jahre hinweg von Benutzern erhalten hat. Sollten Sie feststellen, dass eine für Sie wesentliche Funktionalität fehlt, dann melden Sie dies bitte in unserer Bugdatenbank. Hinweise zur Vorgehensweise finden Sie in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

2.3.5.2. Start des MySQL-Konfigurations-Assistenten

Der MySQL-Konfigurations-Assistent wird normalerweise über den MySQL-Installations-Assistenten gestartet, wenn dieser beendet wird. Sie können den Konfigurations-Assistenten aber auch durch Auswahl des Eintrags MySQL Server Instance Config Wizard im Abschnitt MySQL des Windows-Menüs Start aufrufen.

Alternativ navigieren Sie zum Verzeichnis bin Ihrer MySQL-Installation und rufen die Datei MySQLInstanceConfig.exe direkt auf.

2.3.5.3. Auswahl einer Wartungsoption

Wenn der MySQL-Konfigurations-Assistent eine vorhandene Datei my.ini erkennt, können Sie wahlweise den vorhandenen Server umkonfigurieren oder die Serverinstanz durch Löschen von my.ini entfernen und den MySQL-Dienst beenden und entfernen.

Wenn Sie den vorhandenen Server umkonfigurieren wollen, wählen Sie die Option Re-configure Instance und klicken dann auf die Schaltfläche Next. Ihre vorhandene Datei my.ini wird nun in mytimestamp.ini.bak umbenannt, wobei timestamp ein Zeitstempel mit dem Datum und der Uhrzeit des Zeitpunkts ist, an dem die vorhandene my.ini erstellt worden ist. Wenn Sie die vorhandene Serverinstanz entfernen wollen, wählen Sie die Option Remove Instance und klicken dann auf die Schaltfläche Next.

Wählen Sie die Option Remove Instance, dann wird ein Bestätigungsfenster aufgerufen. Klicken Sie auf die Schaltfläche Execute. Der MySQL-Konfigurations-Assistent beendet und entfernt nun den MySQL-Dienst. Nachfolgend löscht er die Datei my.ini. Die Serverinstallation und ihr Ordner data werden nicht entfernt.

Wenn Sie die Option Re-configure Instance auswählen, wird das Dialogfeld Configuration Type angezeigt. Hier können Sie den Installationstyp auswählen, den Sie konfigurieren wollen.

2.3.5.4. Auswahl eines Konfigurationstyps

Wenn Sie den MySQL-Konfigurations-Assistenten für eine neue MySQL-Installation aufrufen oder die Option Re-configure Instance für eine vorhandene Installation auswählen, wird das Dialogfeld Configuration Type aufgerufen.

Es stehen zwei Konfigurationsmethoden zur Verfügung: Detailed Configuration und Standard Configuration. Die Option Standard Configuration ist für Neubenutzer vorgesehen, die direkt mit MySQL arbeiten wollen, ohne sich vorher Gedanken zur Serverkonfiguration machen zu müssen. Die Option Detailed Configuration ist hingegen für fortgeschrittene Benutzer gedacht, die eine exaktere Kontrolle über die Serverkonfiguration wünschen.

Wenn Sie noch nicht mit MySQL gearbeitet haben und einen Server benötigen, der als Entwicklersystem für genau einen Benutzer vorgesehen ist, dann ist Standard Configuration die richtige Wahl für Ihre Bedürfnisse. Wenn Sie die Option Standard Configuration wählen, stellt der MySQL-Konfigurations-Assistent alle Konfigurationsoptionen mit Ausnahme von Service Options (Dienstoptionen) und Security Options (Sicherheitsoptionen) automatisch ein.

Unter Umständen werden bei Auswahl von Standard Configuration Optionseinstellungen vorgenommen, die mit Systemen, auf denen bereits MySQL-Installationen vorhanden sind, nicht kompatibel sind. Ist auf dem System, auf dem Sie eine MySQL-Installation konfigurieren wollen, bereits eine andere MySQL-Installation vorhanden, dann wird die Auswahl Detailed Configuration empfohlen.

Um die Auswahl Standard Configuration fertig zu stellen, lesen Sie bitte die Abschnitte zu Service Options und Security Options in Abschnitt 2.3.5.11, „Der Dialog zu Dienstoptionen“, bzw. Abschnitt 2.3.5.12, „Der Dialog zu Sicherheitsoptionen“.

2.3.5.5. Der Dialog zum Servertyp

Sie können zwischen drei verschiedenen Servertypen wählen. Welchen Servertyp Sie wählen, wirkt sich auf die Entscheidungen aus, die der MySQL-Konfigurations-Assistent in den Bereichen Speicher-, Festplatten- und Prozessornutzung trifft.

  • Developer Machine: Diese Option ist die beste Wahl für eine normale Desktop-Workstation, auf der MySQL nur für den privaten Einsatz vorgesehen ist. Es wird vorausgesetzt, dass viele andere Desktopanwendungen ausgeführt werden. Der MySQL Server wird deswegen für eine minimale Nutzung der Systemressourcen konfiguriert.

  • Server Machine: Wählen Sie diese Option für ein Serversystem, bei dem der MySQL Server gemeinsam mit anderen Serveranwendungen wie FTP-, Mail- oder Webservern ausgeführt wird. Der MySQL Server wird in diesem Fall für eine moderate Nutzung der Systemressourcen konfiguriert.

  • Dedicated MySQL Server Machine: Die Option wählen Sie bei einem Serversystem, auf dem ausschließlich der MySQL Server läuft. Es wird vorausgesetzt, dass keine anderen Anwendungen ausgeführt werden. Der MySQL Server wird deswegen für die Nutzung aller Systemressourcen konfiguriert.

2.3.5.6. Der Dialog zur Datenbankverwendung

Das Dialogfeld Database Usage erlaubt Ihnen die Angabe von Speicher-Engines, die Sie bei der Erstellung von MySQL-Tabellen voraussichtlich verwenden werden. Die hier gewählte Option bestimmt, ob die InnoDB-Speicher-Engine verfügbar ist und welcher Anteil der Serverressourcen für InnoDB bereitgestellt wird.

  • Multifunctional Database: Diese Option aktiviert sowohl die InnoDB- als auch die MyISAM-Speicher-Engine und teilt die verfügbaren Ressourcen gleichmäßig zwischen diesen beiden auf. Die Option ist für Benutzer empfehlenswert, die beide Speicher-Engines regelmäßig verwenden.

  • Transactional Database Only: Diese Option aktiviert sowohl die InnoDB- als auch die MyISAM-Speicher-Engine, reserviert den überwiegenden Teil der Serverressourcen jedoch für die InnoDB-Engine. Diese Option ist für Benutzer gedacht, die InnoDB fast ausschließlich verwenden und MyISAM nur in sehr seltenen Fällen einsetzen.

  • Non-Transactional Database Only: Diese Option deaktiviert die InnoDB-Speicher-Engine vollständig und weist die gesamten Serverressourcen der MyISAM-Engine zu. Sie wird Benutzern empfohlen, die InnoDB überhaupt nicht verwenden.

2.3.5.7. Der InnoDB-Tablespace-Dialog

Manche Benutzer wollen die InnoDB-Tablespace-Dateien an einer anderen Position als im MySQL Serverdatenverzeichnis speichern. Dies kann wünschenswert sein, wenn Ihr System über ein Speichergerät mit höherer Kapazität oder mehr Leistung verfügt (z. B. ein RAID-Speichersystem).

Um die Standardposition der InnoDB-Tablespace-Dateien zu ändern, wählen Sie ein anderes Laufwerk aus der Dropdown-Liste mit den Laufwerksbuchstaben aus und stellen dann in der Dropdown-Liste mit den Pfaden einen anderen Pfad ein. Um einen benutzerdefinierten Pfad zu erstellen, klicken Sie auf die Schaltfläche ....

Wenn Sie die Konfiguration eines vorhandenen Servers modifizieren, müssen Sie auf die Schaltfläche Modify klicken, bevor Sie den Pfad ändern. In dieser Situation müssen Sie die vorhandenen Tablespace-Dateien manuell an die neue Position verschieben, bevor Sie den Server starten.

2.3.5.8. Der Dialog zu gleichzeitigen Verbindungen

Um zu verhindern, dass der Server keine Ressourcen mehr zugewiesen bekommt, ist es wichtig, die Anzahl gleichzeitiger Verbindungen zum MySQL Server zu begrenzen. Das Dialogfeld Concurrent Connections ermöglicht Ihnen die Angabe der erwarteten Auslastung Ihres Servers und stellt die Anzahl gleichzeitiger Verbindungen entsprechend ein. Es ist ferner möglich, die Anzahl gleichzeitiger Verbindungen manuell zu ändern.

  • Decision Support (DSS)/OLAP: Wählen Sie diese Option, wenn Ihr Server keine hohe Anzahl gleichzeitiger Verbindungen unterstützen muss. Die maximale Anzahl von Verbindungen wird in diesem Fall auf 100 gesetzt, wobei ein Durchschnitt von 20 Verbindungen erwartet wird.

  • Online Transaction Processing (OLTP): Wählen Sie diese Option, wenn Ihr Server eine große Zahl gleichzeitiger Verbindungen unterstützen muss. Die maximale Anzahl der Verbindungen wird hier auf 500 festgelegt.

  • Manual Setting: Wählen Sie diese Option, wenn Sie die maximale Anzahl gleichzeitiger Verbindungen zum Server manuell einstellen wollen. Wählen Sie die Anzahl gleichzeitiger Verbindungen über die Dropdown-Liste aus oder geben Sie den gewünschten Wert direkt in das Dropdown-Feld ein, sofern er nicht in der Liste enthalten ist.

2.3.5.9. Der Dialog zu Netzwerk- und Strict-Modus-Optionen

Im Dialogfeld Networking Options aktivieren oder deaktivieren Sie die TCP/IP-Netzwerkunterstützung und konfigurieren die Portnummer, die zur Verbindung mit dem MySQL Server verwendet wird.

Standardmäßig ist die TCP/IP-Netzwerkunterstützung aktiviert. Um sie zu deaktivieren, entfernen Sie die Markierung des Kontrollkästchen Enable TCP/IP Networking.

Standardmäßig ist Port 3306 gewählt. Um den für den MySQL-Zugriff verwendeten Port zu ändern, wählen Sie im Dropdown-Feld eine neue Portnummer aus und geben die gewünschte Nummer direkt in das Dropdown-Feld ein. Wird die eingetragene Portnummer bereits verwendet, dann werden Sie aufgefordert, Ihre Eingabe zu bestätigen.

Über Server SQL Mode können Sie den strikten SQL-Servermodus aktivieren oder deaktivieren. Bei aktiviertem striktem Modus (Standard) verhält sich MySQL ähnlich wie andere Datenbankmanagementsysteme. Wenn Sie Anwendungen ausführen, die auf das vorherige „nachsichtige“ Verhalten von MySQL angewiesen sind, müssen Sie diese Anwendungen entweder anpassen oder den strikten Modus deaktivieren. Weitere Informationen finden Sie in Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

2.3.5.10. Der Zeichensatzdialog

Der MySQL Server unterstützt mehrere Zeichensätze. In diesem Zusammenhang ist es möglich, einen Standardzeichensatz einzustellen, der für alle Tabellen, Spalten und Datenbanken verwendet wird, soweit nichts anderes explizit festgelegt ist. Im Dialogfeld Character Set können Sie den Standardzeichensatz des MySQL Servers ändern.

  • Standard Character Set: Wählen Sie diese Option, wenn Sie latin1 als Standardzeichensatz verwenden wollen. latin1 wird für Englisch und viele westeuropäische Sprachen verwendet.

  • Best Support For Multilingualism: Wählen Sie diese Option, wenn Sie utf8 als Standardzeichensatz verwenden wollen. Dies ist ein Unicode-Zeichensatz, der Zeichen vieler verschiedener Sprachen enthält.

  • Manual Selected Default Character Set/ Collation: Wählen Sie diese Option, wenn Sie den Standardzeichensatz des Servers manuell einstellen wollen. Wählen Sie den gewünschten Zeichensatz aus der angezeigten Dropdown-Liste.

2.3.5.11. Der Dialog zu Dienstoptionen

Auf Windows NT-basierten Plattformen kann der MySQL Server als Windows-Dienst installiert werden. Wenn der Server auf diese Weise installiert wird, kann er beim Systemstart automatisch gestartet werden. Zudem ist auch ein automatischer Neustart des Dienstes durch Windows nach einem Ausfall möglich.

Der MySQL-Konfigurations-Assistent installiert den MySQL Server standardmäßig als Dienst mit dem Dienstnamen MySQL. Wollen Sie den Dienst nicht installieren, dann deaktivieren Sie das Kontrollkästchen Install As Windows Service . Sie können den Namen des Dienstes ändern, indem Sie einen anderen Namen im vorhandenen Dropdown-Feld auswählen oder einen neuen Dienstnamen direkt in das Feld eintragen.

Um den MySQL Server als Dienst zu installieren, der aber beim Systemstart nicht automatisch gestartet wird, deaktivieren Sie das Kontrollkästchen Launch the MySQL Server Automatically .

2.3.5.12. Der Dialog zu Sicherheitsoptionen

Es wird dringend empfohlen, ein root-Passwort für Ihren MySQL Server einzurichten. Der MySQL-Konfigurations-Assistent fordert Sie standardmäßig dazu auf. Wollen Sie kein root-Passwort erstellen, dann deaktivieren Sie das Kontrollkästchen Modify Security Settings .

Um das root-Passwort einzurichten, geben Sie das gewünschte Passwort in die Felder New root password und Confirm ein. Wenn Sie einen vorhandenen Server umkonfigurieren, müssen Sie das vorhandene root-Passwort in das Feld Current root password eingeben.

Um root-Anmeldungen über das Netzwerk zu verhindern, markieren Sie das Kontrollkästchen Root may only connect from localhost. Dies erhöht die Sicherheit Ihres root-Kontos.

Um ein anonymes Benutzerkonto einzurichten, markieren Sie das Kontrollkästchen Create An Anonymous Account . Die Erstellung eines solchen Kontos kann die Serversicherheit verringern und Probleme mit der Anmeldung und mit Berechtigungen verursachen. Aus diesem Grund wird davon abgeraten.

2.3.5.13. Der Bestätigungsdialog

Das letzte Dialogfeld im MySQL-Konfigurations-Assistent ist Confirmation Dialog. Um den Konfigurationsvorgang zu starten, klicken Sie auf die Schaltfläche Execute. Wenn Sie zu einem der vorherigen Dialogfelder zurückkehren wollen, klicken Sie auf die Schaltfläche Back. Um den MySQL-Konfigurations-Assistenten zu verlassen, ohne MySQL zu konfigurieren, klicken Sie auf die Schaltfläche Cancel.

Wenn Sie auf die Schaltfläche Execute geklickt haben, führt der MySQL-Konfigurations-Assistent eine Reihe von Aufgaben aus, deren Fortschritt auf dem Bildschirm angezeigt wird.

Der MySQL-Konfigurations-Assistent ermittelt zunächst die Konfigurationsdateioptionen basierend auf Ihren Einstellungen. Hierzu verwendet er eine Vorlage, die von Entwicklern und Technikern bei MySQL AB erstellt wurde. Diese Vorlage heißt my-template.ini und befindet sich in Ihrem Serverinstallationsverzeichnis.

Der Konfigurations-Assistent schreibt diese Optionen dann in eine Datei namens my.ini. Die endgültige Position von my.ini wird neben der Aufgabe Write configuration file angezeigt.

Wenn Sie angegeben haben, dass ein Dienst für den MySQL Server eingerichtet werden soll, erstellt und startet der MySQL-Konfigurations-Assistent diesen Dienst. Konfigurieren Sie einen vorhandenen Dienst um, dann startet der MySQL-Konfigurations-Assistent den Dienst neu, um Ihre Konfigurationsänderungen anzuwenden.

Haben Sie angegeben, dass ein root-Passwort eingerichtet werden soll, dann stellt der MySQL-Konfigurations-Assistent eine Verbindung mit dem Server her, richtet Ihr neues root-Passwort ein und übernimmt ggf. weitere von Ihnen gewählte Sicherheitseinstellungen.

Wenn der MySQL-Konfigurations-Assistent seine Aufgaben abgeschlossen hat, wird eine Zusammenfassung angezeigt. Klicken Sie auf die Schaltfläche Finish, um den MySQL-Konfigurations-Assistenten zu beenden.

2.3.5.14. Speicherort der Datei my.ini

Der MySQL-Konfigurations-Assistent legt die Datei my.ini im Installationsverzeichnis des MySQL Servers ab. Dies erleichtert die Zuordnung von Konfigurationsdateien zu bestimmten Serverinstanzen.

Um sicherzustellen, dass der MySQL Server weiß, wo er nach der Datei my.ini suchen muss, wird im Zuge der Dienstinstallation ein Argument ähnlich dem folgenden an den MySQL Server übergeben: --defaults-file="C:\Programme\MySQL\MySQL Server 5.1\my.ini". Hierbei wird C:\Programme\MySQL\MySQL Server 5.1 durch den Installationspfad des MySQL Servers ersetzt.

Die Option --defaults-file weist den MySQL Server an, beim Start die Konfigurationsoptionen aus der angegebenen Datei auszulesen.

2.3.5.15. Editieren der Datei my.ini

Um die Datei my.ini zu ändern, öffnen Sie sie mit einem Texteditor und nehmen die erforderlichen Änderungen vor. Sie können die Serverkonfiguration auch mit dem Hilfsprogramm MySQL Administrator bearbeiten.

MySQL-Clients und Hilfsprogramme wie die Befehlszeilenclients mysql und mysqldump können die Datei my.ini im Serverinstallationsverzeichnis nicht lokalisieren. Um die Client- und Hilfsanwendungen zu konfigurieren, erstellen Sie eine neue Datei my.ini im Verzeichnis C:\WINDOWS bzw. C:\WINNT (je nachdem, welches Verzeichnis für Ihre Windows-Version gültig ist).

2.3.6. Installation von MySQL aus einem Noinstall-Zip-Archiv

Benutzer, die eine Installation aus dem Noinstall-Paket vornehmen, können die Anweisungen in diesem Abschnitt zur manuellen Installation von MySQL verwenden. Die Installation von MySQL aus einem ZIP-Archiv erfolgt mit den nachfolgenden Schritten:

  1. Extrahieren Sie das Archiv in das gewünschte Installationsverzeichnis.

  2. Erstellen Sie die Optionsdatei.

  3. Wählen Sie den MySQL Server-Typ aus.

  4. Starten Sie den MySQL Server.

  5. Schützen Sie die standardmäßig eingerichteten Benutzerkonten.

Die Abläufe werden in den nachfolgenden Abschnitten beschrieben.

2.3.7. Entpacken des Installationsarchivs

So installieren Sie MySQL manuell:

  1. Wenn Sie ein Upgrade von einer vorherigen Version durchführen wollen, lesen Sie bitte Abschnitt 2.3.15, „Upgrade von MySQL unter Windows“, bevor Sie den Upgradevorgang beginnen.

  2. Verwenden Sie ein Windows NT-basiertes Betriebssystem (z. B. Windows NT, Windows 2000, Windows XP oder Windows Server 2003), dann stellen Sie sicher, dass Sie als Benutzer mit Administratorrechten angemeldet sind.

  3. Wählen Sie ein Installationsverzeichnis aus. Traditionell wird der MySQL Server im Verzeichnis C:\mysql installiert. Der MySQL-Installations-Assistent installiert MySQL hingegen in C:\Programme\MySQL. Wenn Sie MySQL nicht in C:\mysql installieren, müssen Sie den Pfad zum Installationsverzeichnis während des Systemstarts oder in einer Optionsdatei angeben. Siehe auch Abschnitt 2.3.8, „Anlegen einer Optionsdatei“.

  4. Verwenden Sie ein ZIP-kompatibles Programm, um das Installationsarchiv in das gewählte Verzeichnis zu extrahieren. Bei Verwendung bestimmter Programme wird das Archiv in einen Ordner im Installationsverzeichnis extrahiert. Sollte dies bei Ihrem Programm der Fall sein, dann verschieben Sie den gesamten Inhalt des Unterordners in das gewählte Installationsverzeichnis.

2.3.8. Anlegen einer Optionsdatei

Wenn Sie für die Ausführung des Servers bestimmte Startoptionen angeben wollen, können Sie dies über die Befehlszeile tun oder sie in einer Optionsdatei ablegen. Sollen die Optionen bei jedem Serverstart verwendet werden, dann ist die Verwendung einer Optionsdatei zur Angabe Ihrer MySQL-Konfiguration praktischer. Dies gilt insbesondere unter den folgenden Umständen:

  • Die Positionen von Installations- oder Datenverzeichnis unterscheiden sich von den Standardvorgaben (C:\Programme\MySQL\MySQL Server 5.1 und C:\Programme\MySQL\MySQL Server 5.1\data).

  • Sie müssen die Servereinstellungen optimieren.

Wenn der MySQL Server unter Windows gestartet wird, sucht er in zwei Dateien nach Optionseinstellungen: in der Datei my.ini im Windows-Verzeichnis und der Datei C:\my.cnf. Das Windows-Verzeichnis heißt normalerweise C:\WINDOWS, C:\WINNT o. ä. Sie können die exakte Position der Umgebungsvariable WINDIR entnehmen. Hierzu geben Sie den folgenden Befehl ein:

C:\> echo %WINDIR%

MySQL sucht zunächst in der Datei my.ini und nachfolgend in my.cnf nach Optionseinstellungen. Allerdings sollten Sie, um Verwirrung zu vermeiden, am besten nur eine Datei verwenden. Verwendet Ihr PC einen Boot-Loader, bei dem C: nicht das Startlaufwerk ist, dann können Sie ohnehin nur die Datei my.ini benutzen. Unabhängig von der gewählten Option muss es sich in jedem Fall um eine unverschlüsselte Textdatei handeln.

Sie können auch die Beispieloptionsdateien verwenden, die zum Umfang Ihrer MySQL-Distribution gehören. Suchen Sie im Installationsverzeichnis nach Dateien wie my-small.cnf, my-medium.cnf, my-large.cnf und my-huge.cnf, die Sie umbenennen und als Grundlage für Ihre Konfigurationsdatei in das passende Verzeichnis kopieren können.

Eine Optionsdatei kann mit jedem Texteditor (z. B. dem Windows-Editor) erstellt und bearbeitet werden. Ist MySQL beispielsweise in E:\mysql installiert und befindet sich das Datenverzeichnis in E:\mydata\data, dann können Sie eine Optionsdatei erstellen, die einen Abschnitt [mysqld] enthält. In diesem geben Sie die folgenden Werte für die Parameter basedir und datadir an:

[mysqld]
# set basedir to your installation path
basedir=E:/mysql
# set datadir to the location of your data directory
datadir=E:/mydata/data

Beachten Sie, dass Windows-Pfadnamen in Optionsdateien nicht mit Backslashs, sondern mit normalen Schrägstrichen angegeben werden. Wenn Sie Backslashs (umgekehrte Schrägstriche) verwenden, müssen Sie sie doppelt angeben:

[mysqld]
# set basedir to your installation path
basedir=E:\\mysql
# set datadir to the location of your data directory
datadir=E:\\mydata\\data

Unter Windows legt das MySQL-Installationsprogramm das Datenverzeichnis direkt im Installationsverzeichnis von MySQL ab. Wenn Sie das Datenverzeichnis an eine andere Position verschieben wollen, sollten Sie den gesamten Inhalt des Verzeichnisses data an die neue Position kopieren. Befindet sich MySQL etwa in C:\Programme\MySQL\MySQL Server 5.1, dann ist das Datenverzeichnis standardmäßig C:\Programme\MySQL\MySQL Server 5.1\data. Wollen Sie stattdessen E:\mydata als Datenverzeichnis verwenden, dann müssen Sie zweierlei tun:

  1. Sie verschieben das gesamte Verzeichnis data und alle darin enthaltenen Daten von C:\Programme\MySQL\MySQL Server 5.1\data nach E:\mydata.

  2. Sie verwenden die Option --datadir, um die neue Position des Datenverzeichnisses bei jedem Serverstart anzugeben.

2.3.9. Auswahl des MySQL Server-Typs

Die folgende Tabelle zeigt die in MySQL 5.1 für Windows verfügbaren Server:

BinärdateiBeschreibung
mysqld-debugMit allen Debugging-Funktionen und automatischer Überprüfung der Speicherzuordnung kompiliert. Unterstützt auch InnoDB- und BDB-Tabellen.
mysqldOptimierte Binärdatei mit InnoDB-Unterstützung.
mysqld-ntOptimierte Binärdatei für Windows NT/2000/XP mit Unterstützung von Named Pipes.
mysqld-maxOptimierte Binärdatei mit Unterstützung für InnoDB- und BDB-Tabellen.
mysqld-max-ntWie mysqld-max, aber mit Unterstützung für Named Pipes kompiliert.

Alle genannten Binärdateien sind für moderne Intel-Prozessoren optimiert, sollten aber auf allen Intel i386-Prozessoren oder höher funktionieren.

Alle Windows-MySQL 5.1 Server unterstützen symbolische Verknüpfungen von Datenbankverzeichnissen.

MySQL unterstützt TCP/IP auf allen Windows-Plattformen. Die Server mysqld-nt und mysql-max-nt unterstützen Named Pipes unter Windows NT, 2000, XP und 2003. Allerdings wird TCP/IP standardmäßig unabhängig von der Plattform verwendet. (Named Pipes sind in vielen Windows-Konfigurationen langsamer als TCP/IP.)

Die Verwendung von Named Pipes hängt von folgenden Bedingungen ab:

  • Named Pipes werden nur aktiviert, wenn Sie den Server mit der Option --enable-named-pipe starten. Diese Option muss explizit angegeben werden, da einige Benutzer Schwierigkeiten mit dem Herunterfahren des MySQL Servers hatten, wenn Named Pipes verwendet wurden.

  • Named-Pipe-Verbindungen sind nur bei den Servern mysqld-nt und mysqld-max-nt und nur dann zulässig, wenn der Server unter einer Windows-Version läuft, die Named Pipes auch unterstützt (NT, 2000, XP, 2003).

  • Diese Server können auch auf Computern unter Windows 98 oder ME laufen, aber dann muss TCP/IP installiert sein; Named-Pipe-Verbindungen sind in diesem Fall nicht möglich.

  • Unter Windows 95 laufen die Server nicht.

Hinweis: Die meisten Beispiele in diesem Handbuch verwenden mysqld als Servername. Wenn Sie einen anderen Server (z. B. mysqld-nt) auswählen, nehmen Sie bei den in den Beispielen gezeigten Befehlen die erforderlichen Änderungen vor.

2.3.10. Erstmaliges Starten des Servers

In diesem Abschnitt finden Sie einen allgemeinen Überblick zum Start des MySQL Servers. Die nachfolgenden Abschnitte enthalten spezielle Informationen zum Starten des MySQL Servers von der Befehlszeile oder als Windows-Dienst.

Die hier enthaltenen Informationen gelten in erster Linie, wenn Sie MySQL aus dem Noinstall-Paket heraus installiert haben oder MySQL manuell (statt unter Verwendung der grafischen Oberflächen) konfigurieren und testen wollen.

Die Beispiele in diesem und den folgenden Abschnitten setzen voraus, dass MySQL im Standardverzeichnis C:\Programme\MySQL\MySQL Server 5.1 installiert wurde. Haben Sie MySQL an anderer Stelle installiert, dann müssen Sie die in den Beispielen gezeigten Pfadnamen entsprechend abändern.

Auf NT-basierten Systemen wie Windows NT, 2000, XP oder 2003 haben Clients zwei Optionen: Sie können entweder TCP/IP verwenden oder eine Named Pipe nutzen, sofern der Server Named-Pipe-Verbindungen unterstützt. Damit MySQL TCP/IP unter Windows NT 4.0 nutzen kann, muss das Service Pack 3 (oder höher) installiert sein.

Unter Windows 95/98/ME müssen MySQL-Clients die Serververbindung immer über TCP/IP herstellen. (Auf diese Weise kann jeder Rechner in Ihrem Netzwerk eine Verbindung zum MySQL Server herstellen.) Aus diesem Grund müssen Sie sicherstellen, dass die TCP/IP-Unterstützung auf Ihrem Computer installiert ist, bevor Sie MySQL starten. Sie finden TCP/IP auf Ihrer Windows-CD-ROM.

Beachten Sie, dass Sie, wenn Sie einen frühen Windows 95-Release (z. B. OSR2) verwenden, wahrscheinlich ein veraltetes Winsock-Paket verwenden; MySQL erfordert jedoch Winsock 2. Sie finden die aktuelle Winsock-Version auf der Website http://www.microsoft.com/. Windows 98 enthält die neue Winsock 2-Bibliothek bereits, d. h., diese muss nicht aktualisiert werden.

MySQL für Windows unterstützt auch Verbindungen mit gemeinsam genutztem Speicher, sofern beim Start die Option --shared-memory angegeben wurde. Clients können durch Verwendung der Option --protocol=memory eine Verbindung über gemeinsamen Speicher herstellen.

Informationen zur zu startenden Serverbinärdatei finden Sie in Abschnitt 2.3.9, „Auswahl des MySQL Server-Typs“.

Tests führen Sie am besten über die Eingabeaufforderung in einem Konsolenfenster (oder „DOS-Fenster“) aus. So kann der Server Statusmeldungen im Fenster anzeigen, wo sie leicht zu sehen sind. Funktioniert bei der Konfiguration etwas nicht einwandfrei, dann können Sie Probleme mithilfe dieser Meldungen erkennen und beheben.

Um den Server zu starten, geben Sie folgenden Befehl ein:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld" --console

Bei Servern, die die InnoDB-Unterstützung enthalten, sollten Sie folgende Mitteilungen beim Serverstart sehen:

InnoDB: The first specified datafile c:\ibdata\ibdata1 did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file c:\ibdata\ibdata1 size to 209715200
InnoDB: Database physically writes the file full: wait...
InnoDB: Log file c:\iblogs\ib_logfile0 did not exist: new to be created
InnoDB: Setting log file c:\iblogs\ib_logfile0 size to 31457280
InnoDB: Log file c:\iblogs\ib_logfile1 did not exist: new to be created
InnoDB: Setting log file c:\iblogs\ib_logfile1 size to 31457280
InnoDB: Log file c:\iblogs\ib_logfile2 did not exist: new to be created
InnoDB: Setting log file c:\iblogs\ib_logfile2 size to 31457280
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: creating foreign key constraint system tables
InnoDB: foreign key constraint system tables created
011024 10:58:25  InnoDB: Started

Wenn der Server seine Startsequenz beendet, sollten Sie eine Meldung in der Art der folgenden sehen (hierdurch wird angezeigt, dass der Server nun zur Annahme von Clientverbindungen bereit ist):

mysqld: ready for connections
Version: '5.1.5-alpha'  socket: ''  port: 3306

Nachfolgend schreibt der Server weiterhin alle erzeugten Diagnoseausgaben in die Konsole. Sie können ein neues Konsolenfenster öffnen, in dem Clientprogramme ausgeführt werden.

Wenn Sie die Option --console weglassen, schreibt der Server die gesamte Diagnoseausgabe in das Fehlerlog im Datenverzeichnis (standardmäßig C:\Programme\MySQL\MySQL Server 5.1\data). Das Fehlerlog ist die Datei mit der Erweiterung .err.

Hinweis: Für die in den MySQL-Grant-Tabellen aufgeführten Konten gibt es zunächst noch keine Passwörter. Wenn Sie den Server gestartet haben, sollten Sie entsprechend der in Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, beschriebenen Verfahrensweise Passwörter für diese Konten einrichten.

2.3.11. Starten von MySQL von der Windows-Befehlszeile

Der MySQL Server kann manuell über die Befehlszeile gestartet werden. Dies ist bei jeder Windows-Version möglich.

Um dem Server mysqld von der Befehlszeile zu starten, öffnen Sie ein Konsolenfenster („Eingabeaufforderung“) und geben folgenden Befehl ein:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld"

Der in obigem Beispiel verwendete Pfad kann abhängig vom MySQL-Installationsverzeichnis auf Ihrem System anders aussehen.

Bei Nicht-NT-Versionen von Windows wird hierdurch mysqld im Hintergrund gestartet. Das bedeutet, dass nach dem Serverstart eine andere Eingabeaufforderung angezeigt wird. Wenn Sie den Server auf diese Weise unter Windows NT, 2000, XP oder 2003 starten, läuft der Server im Vordergrund; bis zur Beendigung des Servers erscheint keine Eingabeaufforderung. Aus diesem Grund müssen Sie ein anderes Konsolenfenster öffnen, um Clientprogramme ausführen zu können, während der Server läuft.

Sie können den MySQL Server mit folgendem Befehl beenden:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqladmin" -u root shutdown

Hinweis: Wenn das MySQL-Benutzerkonto root ein Passwort aufweist, müssen Sie mysqladmin mit der Option -p aufrufen und das Passwort auf Aufforderung angeben.

Mit diesem Befehl rufen Sie das MySQL-Administrationshilfsprogramm mysqladmin auf, welches eine Verbindung zum Server herstellt und das Herunterfahren auslöst. Der Befehl stellt die Verbindung als MySQL-Benutzer root her. Dies ist das standardmäßige Administratorenkonto im MySQL-Grant-System. Beachten Sie, dass Benutzer im MySQL-Grant-System nichts mit den Benutzerkonten zu tun haben, über die man sich am Windows-System anmeldet.

Wenn mysqld nicht startet, kontrollieren Sie, ob der Server im Fehlerlog Meldungen eingetragen hat, die auf die Ursache des Problems schließen lassen. Das Fehlerlog befindet sich im Verzeichnis C:\Programme\MySQL\MySQL Server 5.1\data. Es handelt sich um die Datei mit der Erweiterung .err. Sie können auch versuchen, den Server als mysqld --console zu starten; in diesem Fall erhalten Sie unter Umständen über den Bildschirm einige nützliche Informationen, die bei der Beseitigung des Problems helfen können.

Die letzte Option ist der Start von mysqld mit den Optionen --standalone und --debug. In diesem Fall schreibt mysqld eine Logdatei namens C:\mysqld.trace, die die Ursache dafür angeben sollte, dass mysqld nicht gestartet wird. Siehe auch Abschnitt E.1.2, „Trace-Dateien erzeugen“.

Verwenden Sie mysqld --verbose --help, um alle Optionen anzuzeigen, die mysqld versteht.

2.3.12. Starten von MySQL als Windows-Dienst

Bei der Windows NT-Familie (Windows NT, 2000, XP, 2003) besteht die empfohlene Methode zur Ausführung von MySQL in der Installation als Dienst, wobei MySQL automatisch mit Windows gestartet und beendet wird. Ein MySQL Server, der als Dienst installiert ist, lässt sich mithilfe von NET über die Befehlszeile oder über das grafische Hilfsprogramm Dienste steuern.

Das Hilfsprogramm Dienste (der Service Control Manager von Windows) lässt sich über die Windows-Systemsteuerung aufrufen (Abschnitt Verwaltung bei Windows 2000, XP und Server 2003). Um Konflikte zu vermeiden, ist es ratsam, das Hilfsprogramm Dienste während der Serverinstallation oder Löschaktionen über die Befehlszeile zu schließen.

Bevor Sie MySQL als Windows-Dienst installieren, sollten Sie zunächst mit dem folgenden Befehl den aktuellen Server beenden, sofern dieser ausgeführt wird:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqladmin" -u root shutdown

Hinweis: Wenn das MySQL-Benutzerkonto root ein Passwort aufweist, müssen Sie mysqladmin mit der Option -p aufrufen und das Passwort auf Aufforderung angeben.

Mit diesem Befehl rufen Sie das MySQL-Administrationshilfsprogramm mysqladmin auf, welches eine Verbindung zum Server herstellt und das Herunterfahren auslöst. Der Befehl stellt die Verbindung als MySQL-Benutzer root her. Dies ist das standardmäßige Administratorenkonto im MySQL-Grant-System. Beachten Sie, dass Benutzer im MySQL-Grant-System nichts mit den Benutzerkonten zu tun haben, über die man sich am Windows-System anmeldet.

Installieren Sie den Server mit dem folgenden Befehl als Dienst:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld" --install

Mit dem Befehl zur Dienstinstallation wird der Server nicht gestartet. Hinweise zum Start finden Sie in einem späteren Abschnitt.

Um den Aufruf von MySQL-Programmen zu erleichtern, können Sie den Pfadnamen des MySQL-Verzeichnisses bin zur Umgebungsvariable PATH Ihres Windows-Systems hinzufügen:

  • Klicken Sie auf dem Windows-Desktop mit der rechten Maustaste auf das Symbol Arbeitsplatz und wählen Sie Eigenschaften.

  • Wählen Sie nun im angezeigten Fenster Systemeigenschaften die Registerkarte Erweitert und klicken Sie auf die Schaltfläche Umgebungsvariablen.

  • Unter Systemvariablen wählen Sie Path und klicken dann auf die Schaltfläche Bearbeiten. Das Dialogfeld Systemvariable bearbeiten erscheint.

  • Setzen Sie den Cursor an das Ende des im Feld Wert der Variablen gezeigten Texts (betätigen Sie die Taste Ende, um sicherzustellen, dass der Cursor tatsächlich ans Ende des Textes in diesem Textfeld gesetzt wird). Geben Sie nun den vollständigen Pfadnamen Ihres MySQL-Verzeichnisses bin ein (beispielsweise C:\Programme\MySQL\MySQL Server 5.1\bin). Achten Sie dabei darauf, dass dieser Pfad durch ein Semikolon von den übrigen Werten in diesem Feld abgetrennt ist. Bestätigen Sie nun alle angezeigten Dialogfelder nacheinander durch Anklicken der jeweiligen Schaltflächen OK, bis keine offenen Dialogfelder mehr angezeigt werden. Sie sollten jetzt aus jedem beliebigen Verzeichnis heraus jedes ausführbare MySQL-Programm durch Eingabe seines Namens an der DOS-Eingabeaufforderung starten können, ohne den vollständigen Pfad angeben zu müssen. Dies betrifft die Server, den mysql-Client und alle befehlszeilenbasierten MySQL-Hilfsprogramme wie mysqladmin und mysqldump.

    Wenn Sie mehrere MySQL Server auf Ihrem System betreiben, sollten Sie das MySQL-Verzeichnis bin nicht der Windows-Umgebungsvariablen PATH hinzufügen.

Warnung: Bei der manuellen Editierung der Umgebungsvariablen PATH müssen Sie größte Vorsicht walten lassen: Wenn Sie einen Teil des Werts von PATH versehentlich löschen oder ändern, kann das System instabil oder sogar unbrauchbar werden.

Bei der Installation des Dienstes können die folgenden zusätzlichen Argumente in MySQL 5.1 verwendet werden:

  • Sie können unmittelbar auf die Option --install einen Dienstnamen angeben. Der Standardname für den Dienst lautet MySQL.

  • Wird ein Name für den Dienst angegeben, so kann genau eine weitere Option folgen. Konventionsgemäß ist dies --defaults-file=file_name; hierdurch wird der Name einer Optionsdatei angegeben, die der Server beim Start auslesen soll.

    Sie können statt --defaults-file auch eine beliebige andere Option angeben, doch dies wird nicht empfohlen. --defaults-file ist flexibler, da es Ihnen die Festlegung einer Vielzahl von Startoptionen für den Server gestattet, die einfach in der spezifizierten Optionsdatei abgelegt werden.

  • Sie können auch eine Option --local-service gefolgt vom Dienstnamen angeben. In diesem Fall wird der Server über das Windows-Konto LocalService ausgeführt, welches über eingeschränkte Systemberechtigungen verfügt. Dieses Konto ist nur unter Windows XP oder höher vorhanden. Werden beide Optionen --defaults-file und --local-service auf den Dienstnamen folgend angegeben, dann ist die Reihenfolge unerheblich.

Bei einem MySQL Server, der als Windows-Dienst installiert ist, bestimmen die folgenden Grundsätze den Dienstnamen und die vom Server verwendeten Optionsdateien:

  • Wenn der Dienstinstallationsbefehl keinen Dienstnamen oder den Vorgabenamen (MySQL) gefolgt von der Option --install angibt, dann verwendet der Server den Dienstnamen MySQL und liest seine Optionen aus dem Abschnitt [mysqld] der Standardoptionsdateien aus.

  • Wurde im Dienstinstallationsbefehl ein anderer Dienstname als MySQL gefolgt von der Option --install angegeben, dann verwendet der Server diesen anderen Namen. Die Optionen werden dann aus dem Abschnitt in den Standardoptionsdateien ausgelesen, der den gleichen Namen hat wie der Dienst selbst.

    Außerdem liest der Server auch den Abschnitt [mysqld] in den Standardoptionsdateien aus. Sie können den Abschnitt [mysqld] also für diejenigen Optionen verwenden, die allen MySQL-Diensten gemeinsam sind, und zusätzlich einen Abschnitt mit dem Namen eines bestimmten Dienstes konfigurieren, der dann von dem Server benutzt wird, der mit diesem Dienstnamen installiert wurde.

  • Wenn im Dienstinstallationsbefehl die Option --defaults-file auf den Dienstnamen folgend angegeben wird, liest der Server nur die Optionen im Abschnitt [mysqld] der angegebenen Datei aus und ignoriert die Standardoptionsdateien.

Nehmen wir einmal den folgenden Befehl als ein etwas komplexeres Beispiel:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld"
          --install MySQL --defaults-file=C:\my-opts.cnf

Hier wird der Standarddienstname (MySQL) auf die Option --install folgend angegeben. Wäre keine Option --defaults-file vorhanden, dann würde dieser Befehl dafür sorgen, dass der Server den Abschnitt [mysqld] in den Standardoptionsdateien ausliest. Da allerdings die Option --defaults-file angegeben ist, liest der Server die Optionen im Abschnitt [mysqld] der spezifizierten Datei.

Sie können Optionen auch als Startparameter im Windows-Hilfsprogramm Dienste festlegen, bevor Sie den MySQL-Dienst starten.

Wurde ein MySQL Server als Dienst installiert, dann startet Windows den Dienst automatisch beim Systemstart. Der Dienst lässt sich auch direkt aus dem Hilfsprogramm Dienste oder mithilfe des Befehls NET START MySQL starten. Der NET-Befehl unterscheidet hierbei keine Groß-/Kleinschreibung.

Wenn mysqld als Dienst ausgeführt wird, hat es keinen Zugriff auf ein Konsolenfenster; insofern werden keine Meldungen angezeigt. Wenn mysqld nicht startet, kontrollieren Sie, ob der Server im Fehlerlog Meldungen eingetragen hat, die auf die Ursache des Problems schließen lassen. Das Fehlerlog befindet sich im MySQL-Datenverzeichnis (z. B. C:\Programme\MySQL\MySQL Server 5.1\data). Es handelt sich um die Datei mit der Erweiterung .err.

Wenn ein MySQL Server als Dienst installiert wurde und dieser Dienst ausgeführt wird, beendet Windows ihn automatisch beim Herunterfahren. Der Server kann auch manuell im Hilfsprogramm Dienste, mit dem Befehl NET STOP MySQL oder dem Befehl mysqladmin shutdown beendet werden.

Außerdem haben Sie die Möglichkeit, den Server als manuellen Dienst zu installieren, wenn Sie nicht wollen, dass der Dienst beim Hochfahren automatisch gestartet wird. Verwenden Sie zu diesem Zweck die Option --install-manual statt --install:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld" --install-manual

Um einen Server zu entfernen, der als Dienst installiert ist, beenden Sie ihn zunächst, sofern er noch ausgeführt wird; hierzu verwenden Sie den Befehl NET STOP MYSQL. Danach entfernen Sie ihn mit der Option --remove:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld" --remove

Wenn mysqld nicht als Dienst ausgeführt wird, können Sie ihn über die Befehlszeile starten. Informationen zur Vorgehensweise finden Sie in Abschnitt 2.3.11, „Starten von MySQL von der Windows-Befehlszeile“.

Bitte schlagen Sie in Abschnitt 2.3.14, „Troubleshooting einer MySQL-Installation unter Windows“, nach, wenn Sie bei der Installation Probleme haben sollten.

2.3.13. Test der MySQL-Installation

Ob der MySQL Server funktioniert, können Sie durch Ausführen eines der folgenden Befehle leicht überprüfen:

C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqlshow"
C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqlshow" -u root mysql
C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqladmin" version status proc
C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysql" test

Wenn mysqld nur langsam auf TCP/IP-Verbindungen von Clientprogrammen reagiert, liegt wahrscheinlich ein DNS-Problem vor. Starten Sie in einem solchen Fall mysqld mit der Option --skip-name-resolve und verwenden Sie nur localhost und IP-Nummern in der Spalte Host der MySQL-Grant-Tabellen.

Sie können die Verwendung einer Named-Pipe-Verbindung (statt einer TCP/IP-Verbindung) erzwingen, indem Sie die Optionen --pipe oder --protocol=PIPE verwenden oder den Punkt . als Hostnamen angeben. Verwenden Sie die Option --socket, um den Namen der Pipe anzugeben, sofern Sie nicht den Namen der Standard-Pipe verwenden wollen.

2.3.14. Troubleshooting einer MySQL-Installation unter Windows

Wenn Sie MySQL zum ersten Mal installieren und ausführen, können bestimmte Fehler auftreten, die verhindern, dass der MySQL Server gestartet wird. Dieser Abschnitt soll Ihnen dabei helfen, einige dieser Fehler zu diagnostizieren und zu beheben.

Ihre erste Ressource bei der Fehlersuche ist das Fehlerlog. Der MySQL Server verwendet das Fehlerlog zur Aufzeichnung von Daten zu dem Fehler, der verhindert, dass der Server gestartet werden kann. Das Fehlerlog befindet sich im Datenverzeichnis, das in Ihrer Datei my.ini angegeben ist. Die Standardposition des Datenverzeichnisses ist C:\Programme\MySQL\MySQL Server 5.1\data. Siehe auch Abschnitt 5.12.1, „Die Fehler-Logdatei“.

Eine andere Informationsquelle zu möglichen Fehlern sind die Konsolenmeldungen, die beim Starten des MySQL-Dienstes angezeigt werden. Verwenden Sie den Befehl NET START mysql an der Befehlszeile, nachdem Sie mysqld als Dienst installiert haben, um Fehlermeldungen anzuzeigen, die beim Start des MySQL Servers als Dienst erzeugt werden. Siehe auch Abschnitt 2.3.12, „Starten von MySQL als Windows-Dienst“.

Die folgenden Beispiele zeigen weitere häufig auftretende Fehlermeldungen, die bei der Installation von MySQL und dem ersten Start des Servers angezeigt werden können:

  • Wenn der MySQL Server die mysql-Berechtigungsdatenbank oder andere kritische Dateien nicht finden kann, erscheinen Meldungen folgenden Typs:

    System error 1067 has occurred.
    Fatal error: Can't open privilege tables: Table 'mysql.host' doesn't exist
    

    Solche Meldungen treten häufig auf, wenn das MySQL-Datenbank- oder das MySQL-Datenverzeichnis nicht an der Standardposition (C:\Programme\MySQL\MySQL Server 5.1 bzw. C:\Programme\MySQL\MySQL Server 5.1\data) installiert wurde.

    Die Situation entsteht, wenn MySQL aktualisiert und in einem neuen Verzeichnis installiert, aber die Konfigurationsdatei nicht an die geänderte Umgebung angepasst wurde. Außerdem kann es zu Konflikten zwischen alten und neuen Konfigurationsdateien kommen. Benennen Sie alte Konfigurationsdateien in jedem Fall um oder löschen Sie sie, bevor Sie MySQL aktualisieren.

    Wenn Sie MySQL in ein anderes Verzeichnis als C:\Programme\MySQL\MySQL Server 5.1 installiert haben, müssen Sie sicherstellen, dass dies dem MySQL Server bekannt ist. Hierzu verwenden Sie die Konfigurationsdatei my.ini. Die Datei mit dem Namen my.ini muss in Ihrem Windows-Verzeichnis gespeichert sein (normalerweise C:\WINDOWS oder C:\WINNT). Sie können die exakte Position der Umgebungsvariable WINDIR entnehmen. Hierzu geben Sie den folgenden Befehl an der Befehlszeile ein:

    C:\> echo %WINDIR%
    

    Eine Optionsdatei kann mit jedem Texteditor (z. B. dem Windows-Editor) erstellt und bearbeitet werden. Ist MySQL beispielsweise in E:\mysql installiert und befindet sich das Datenverzeichnis in D:\MySQLdata, dann können Sie eine Optionsdatei erstellen, die einen Abschnitt [mysqld] enthält. In diesem geben Sie die folgenden Werte für die Parameter basedir und datadir an:

    [mysqld]
    # set basedir to your installation path
    basedir=E:/mysql
    # set datadir to the location of your data directory
    datadir=D:/MySQLdata
    

    Beachten Sie, dass Windows-Pfadnamen in Optionsdateien nicht mit Backslashs, sondern mit normalen Schrägstrichen angegeben werden. Wenn Sie Backslashs (umgekehrte Schrägstriche) verwenden, müssen Sie sie doppelt angeben:

    [mysqld]
    # set basedir to your installation path
    basedir=C:\\Program Files\\MySQL\\MySQL Server 5.1
    # set datadir to the location of your data directory
    datadir=D:\\MySQLdata
    

    Wenn Sie den Wert datadir in Ihrer MySQL-Konfigurationsdatei ändern, müssen Sie den Inhalt des vorhandenen MySQL-Datenverzeichnisses verschieben, bevor Sie den MySQL Server neu starten.

    Siehe auch Abschnitt 2.3.8, „Anlegen einer Optionsdatei“.

  • Wenn Sie MySQL neu installieren oder aktualisieren, ohne den vorhandenen MySQL-Dienst zu beenden und zu entfernen, und zur Installation den MySQL-Konfigurations-Assistenten verwenden, dann wird unter Umständen folgende Fehlermeldung angezeigt:

    Error: Cannot create Windows service for MySql. Error: 0
    

    Dies passiert, wenn der Konfigurations-Assistent einen Dienst zu installieren versucht und einen anderen Dienst gleichen Namens vorfindet.

    Eine Lösung dieses Problems besteht darin, bei Verwendung des Konfigurations-Assistenten einen anderen Dienstnamen als mysql auszuwählen. Hierdurch wird der neue Dienst korrekt installiert. Allerdings bleibt dann ein veralteter Dienst zurück. Dies ist an sich zwar unproblematisch, aber trotzdem sollten alte Dienste, die nicht mehr erforderlich sind, korrekt entfernt werden.

    Um den alten mysql-Dienst permanent zu entfernen, führen Sie den folgenden Befehl als Benutzer mit Administratorrechten an der Befehlszeile aus:

    C:\> sc delete mysql
    [SC] DeleteService SUCCESS
    

    Wenn das Hilfsprogramm sc bei Ihrer Windows-Version nicht vorhanden ist, laden Sie das Hilfsprogramm delsrv unter http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/delsrv-o.asp herunter und verwenden Sie die Syntax delsrv mysql.

2.3.15. Upgrade von MySQL unter Windows

Dieser Abschnitt listet einige der Schritte auf, die bei der Aktualisierung von MySQL unter Windows erforderlich sind.

  1. Lesen Sie Abschnitt 2.10, „MySQL aktualisieren (Upgrade/Downgrade)“. Sie finden dort weitere, nicht Windows-spezifische Informationen zum Upgrade von MySQL.

  2. Fertigen Sie immer eine Sicherung Ihrer aktuellen MySQL-Installation an, bevor Sie ein Upgrade durchführen. Siehe auch Abschnitt 5.10.1, „Datenbank-Datensicherungen“.

  3. Laden Sie die aktuelle Windows-Distribution von MySQL unter http://dev.mysql.com/downloads/ herunter.

  4. Vor Durchführung des Upgrades müssen Sie den Server beenden. Ist der Server als Dienst installiert, dann beenden Sie ihn durch Eingabe des folgenden Befehls an der Befehlszeile:

    C:\> NET STOP MYSQL
    

    Wird der MySQL Server nicht als Dienst ausgeführt, dann beenden Sie ihn mit dem folgenden Befehl:

    C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqladmin" -u root shutdown
    

    Hinweis: Wenn das MySQL-Benutzerkonto root ein Passwort aufweist, müssen Sie mysqladmin mit der Option -p aufrufen und das Passwort auf Aufforderung angeben.

  5. Wenn Sie von einer MySQL-Version vor 4.1.5 auf MySQL 5.1 aktualisieren oder ein Upgrade von einer MySQL-Version, die aus einem ZIP-Archiv installiert wurde, auf eine mit dem MySQL-Installations-Assistenten zu installierende Version durchführen, dann müssen Sie die vorherige Installation und den MySQL-Dienst (sofern der Server als Dienst installiert ist) manuell entfernen.

    Verwenden Sie den folgenden Befehl, um den MySQL-Dienst zu entfernen:

    C:\> C:\mysql\bin\mysqld --remove
    

    Wenn Sie den vorhandenen Dienst nicht entfernen, kann der MySQL-Installations-Assistent den neuen MySQL-Dienst unter Umständen nicht korrekt installieren.

  6. Wenn Sie den MySQL-Installations-Assistenten verwenden, starten Sie den Assistenten wie in Abschnitt 2.3.4, „Verwendung des MySQL-Installations-Assistenten“, beschrieben.

  7. Wenn Sie MySQL aus einem ZIP-Archiv installieren, extrahieren Sie das Archiv. Sie können die vorhandene MySQL-Installation entweder überschreiben (diese befindet sich normalerweise im Verzeichnis C:\mysql) oder es in ein anderes Verzeichnis (z. B. C:\mysql4) installieren. Wir empfehlen das Überschreiben der vorhandenen Installation.

  8. Wenn Sie MySQL als Windows-Dienst ausführen und Sie den Dienst zu einem früheren Zeitpunkt dieses Vorgangs deinstallieren mussten, installieren Sie ihn jetzt neu. (Siehe auch Abschnitt 2.3.12, „Starten von MySQL als Windows-Dienst“.)

  9. Starten Sie den Server neu. Verwenden Sie beispielsweise NET START MySQL, wenn Sie MySQL als Dienst ausführen, oder rufen Sie mysqld auf andere Weise direkt auf.

  10. Wenn Fehler auftreten, finden Sie weitere Informationen in Abschnitt 2.3.14, „Troubleshooting einer MySQL-Installation unter Windows“.

2.3.16. MySQL unter Windows im Vergleich zu MySQL unter Unix

MySQL für Windows hat sich als sehr stabil erwiesen. Die Windows-Version von MySQL hat dieselben Merkmale wie die entsprechende Unix-Version. Es gibt jedoch folgende Ausnahmen:

  • Windows 95 und Threads

    Pro erstelltem Thread verliert Windows 95 durch ein Speicherleck etwa 200 Byte Hauptspeicher. Jede Verbindung in MySQL erstellt einen neuen Thread, weswegen man mysqld nicht für längere Zeit unter Windows 95 ausführen sollte, wenn Ihr Server mehrere Verbindungen verwaltet! Neuere Windows-Versionen weisen diesen Bug nicht auf.

  • Eingeschränkte Anzahl von Ports

    Windows-Systeme stellen für Clientverbindungen etwa 4000 Ports bereit. Wird eine Verbindung über einen Port beendet, dann dauert es zwei bis vier Minuten, bis der Port wieder verwendet werden kann. In Situationen, in denen Clients sehr schnell Verbindungen mit dem Server herstellen und diese wieder trennen, ist es unter Umständen möglich, dass alle verfügbaren Ports verbraucht sind, bevor bereits geschlossene Ports wieder verfügbar werden. In diesem Fall scheint der MySQL Server stehen geblieben zu sein, obwohl er tatsächlich nach wie vor ausgeführt wird. Beachten Sie, dass unter Umständen auch andere auf dem System laufenden Anwendungen Ports beanspruchen; in diesem Fall ist die Anzahl der für MySQL verfügbaren Ports noch geringer.

    Weitere Informationen zu diesem Problem finden Sie unter http://support.microsoft.com/default.aspx?scid=kb;en-us;196271.

  • Gleichzeitige Leseoperationen

    MySQL ist auf die Systemaufrufe pread() und pwrite() angewiesen, um INSERT und SELECT miteinander kombinieren zu können. Zurzeit verwenden wir Mutexe zur Emulation von pread() und pwrite(). Wir beabsichtigen, diese Schnittstelle auf Dateiebene in der Zukunft durch eine virtuelle Schnittstelle zu ersetzen, damit wir die Schnittstellen readfile()/writefile() unter Windows NT, Windows 2000 und Windows XP verwenden und so eine höhere Geschwindigkeit erzielen können. Die aktuelle Implementierung beschränkt die Anzahl der von MySQL 5.1 verwendbaren offenen Dateien auf 2048, d. h., Sie können unter Windows NT/2000/XP/Server 2003 nicht so viele gleichzeitige Threads ausführen wie unter Unix.

  • Sperrleseoperationen

    MySQL verwendet für jede Verbindung eine Sperrleseoperation. Dies hat die folgenden Auswirkungen, wenn Named-Pipe-Verbindungen aktiviert sind:

    • Eine Verbindung wird – anders als bei MySQL für Unix – nicht automatisch nach acht Stunden getrennt.

    • Hängt eine Verbindung, dann ist es nicht möglich, diese zu unterbrechen, ohne MySQL zu terminieren.

    • mysqladmin kill funktioniert bei hängenden Verbindungen nicht.

    • mysqladmin shutdown kann MySQL nicht herunterfahren, solange eine Verbindung hängt.

    Wir beabsichtigen, dieses Problem in der Zukunft zu lösen.

  • ALTER TABLE

    Während Sie eine ALTER TABLE-Anweisung ausführen, ist die betreffende Tabelle für die Benutzung durch andere Threads gesperrt. Dies hängt mit der Tatsache zusammen, dass Sie eine Datei unter Windows nicht löschen können, solange sie von einem anderen Thread verwendet wird. Wir hoffen, für dieses Problem in der Zukunft einen Workaround zu finden.

  • DROP TABLE

    Die Ausführung von DROP TABLE für eine Tabelle, die von einer MERGE-Tabelle verwendet wird, funktioniert unter Windows nicht, da der MERGE-Handler die Tabellenzuordnung vor der übergeordneten Schicht von MySQL verborgen vornimmt. Da Windows das Löschen geöffneter Dateien nicht gestattet, müssen Sie zunächst alle MERGE-Tabellen (mit FLUSH TABLES) neu laden oder die MERGE-Tabelle löschen, bevor Sie die gewünschte Tabelle tatsächlich löschen können.

  • DATA DIRECTORY und INDEX DIRECTORY

    Die Optionen DATA DIRECTORY und INDEX DIRECTORY für CREATE TABLE werden unter Windows ignoriert, da Windows keine symbolischen Verknüpfungen unterstützt. Außerdem werden diese Optionen auf Systemen ignoriert, bei denen der Aufruf realpath() nicht funktioniert.

  • DROP DATABASE

    Sie können eine Datenbank, die gerade von einem Thread verwendet wird, nicht löschen.

  • MySQL aus dem Task-Manager heraus terminieren

    Unter Windows 95 können Sie MySQL nicht aus dem Task-Manager heraus oder mit dem Ausschalt-Utility terminieren. Sie müssen MySQL vielmehr mit dem Befehl mysqladmin shutdown beenden.

  • Irrelevante Groß-/Kleinschreibung bei Namen

    Da die Groß-/Kleinschreibung bei Dateinamen unter Windows nicht unterschieden wird, ist auch die Schreibweise der Namen von MySQL-Datenbanken und -Tabellen unter Windows irrelevant. Die einzige Einschränkung besteht darin, dass die Datenbank- und Tabellennamen unter Verwendung derselben Schreibweise (Groß- oder Kleinschreibung) in einer gegebenen Anweisung festgelegt werden müssen. Siehe auch Abschnitt 9.2.2, „Groß-/Kleinschreibung in Namen“.

  • Das Pfadtrennzeichen ‘\

    Unter Windows werden die Bestandteile von Pfaden durch das Zeichen ‘\’ voneinander getrennt, welches gleichzeitig das Escape-Zeichen von MySQL ist. Wenn Sie LOAD DATA INFILE oder SELECT ... INTO OUTFILE verwenden, verwenden Sie Dateinamen im Unix-Stil mit ‘/’-Zeichen:

    mysql> LOAD DATA INFILE 'C:/tmp/skr.txt' INTO TABLE skr;
    mysql> SELECT * INTO OUTFILE 'C:/tmp/skr.txt' FROM skr;
    

    Alternativ müssen Sie das Zeichen ‘\’ doppelt verwenden:

    mysql> LOAD DATA INFILE 'C:\\tmp\\skr.txt' INTO TABLE skr;
    mysql> SELECT * INTO OUTFILE 'C:\\tmp\\skr.txt' FROM skr;
    
  • Probleme mit Pipes

    An der Windows-Eingabeaufforderung funktionieren Pipes nicht zuverlässig. Wenn eine Pipe das Zeichen ^Z/CHAR(24) enthält, meint Windows ein Dateiende zu erkennen und bricht das Programm ab.

    Dies ist in erster Linie ein Problem, wenn Sie wie folgt eine binäre Logdatei anzuwenden versuchen:

    C:\> mysqlbinlog binary_log_file | mysql --user=root
    

    Wenn Sie bei der Anwendung des Logs Probleme haben und das Zeichen ^Z/CHAR(24) für die Ursache halten, dann können Sie den folgenden Workaround verwenden:

    C:\> mysqlbinlog binary_log_file --result-file=/tmp/bin.sql
    C:\> mysql --user=root --execute "source /tmp/bin.sql"
    

    Der untere Befehl kann auch verwendet werden, um zuverlässig in einer beliebigen SQL-Datei zu lesen, die unter Umständen Binärdateien enthält.

  • Fehler Access denied for user

    Wenn MySQL Ihren Hostnamen nicht korrekt auflösen kann, erhalten Sie unter Umständen folgende Fehlermeldung, sobald Sie versuchen, ein MySQL-Clientprogramm auszuführen, um eine Verbindung mit dem auf dem gleichen Computer laufenden Server herzustellen:

    Access denied for user 'some_user'@'unknown'
    to database 'mysql'
    

    Um dieses Problem zu beheben, sollten Sie eine Datei namens \windows\hosts erstellen, die die folgenden Informationen enthält:

    127.0.0.1       localhost
    

2.4. MySQL unter Linux installieren

Die empfohlene Vorgehensweise zur Installation von MySQL unter Linux besteht in der Verwendung von RPM-Paketen. Die MySQL-RPMs werden derzeit auf einem SuSE Linux 7.3-System erstellt, sollten aber unter den meisten Linux-Versionen funktionieren, die rpm unterstützen und glibc verwenden. Wie Sie sich die RPM-Pakete beschaffen, lesen Sie in Abschnitt 2.1.3, „Woher man MySQL bekommt“.

MySQL AB bietet eine Reihe plattformspezifischer RPMs an. Der Unterschied zwischen einem plattformspezifischen und einem generischen RPM besteht darin, dass ein plattformspezifisches RPM auf der Zielplattform erstellt und dynamisch verknüpft wurde, wohingegen ein generisches RPM statisch mit LinuxThreads verknüpft ist.

Hinweis: RPM-Distributionen von MySQL werden häufig von anderen Anbietern bereitgestellt. Beachten Sie, dass Merkmale und Funktionsumfang sich von den Versionen unterscheiden können, die von MySQL AB angeboten werden, und dass die Angaben in diesem Handbuch nicht unbedingt für deren Installation gelten. Ziehen Sie im Zweifelsfall die Dokumentation des Anbieters zu Rate.

Wenn Sie Probleme mit einer RPM-Datei haben (also etwa, wenn die Fehlermeldung Sorry, the host 'xxxx' could not be looked up angezeigt wird), finden Sie weitere Informationen in Abschnitt 2.12.1.2, „Anmerkungen zur Binärdistribution (Linux)“.

In den meisten Fällen müssen Sie nur die Pakete MySQL-server und MySQL-client installieren, um eine lauffähige MySQL-Installation zu erhalten. Die übrigen Pakete sind für eine Standardinstallation nicht erforderlich. Wenn Sie einen MySQL-Max-Server mit Zusatzfunktionen verwenden wollen, sollten Sie auch das RPM MySQL-Max installieren. Allerdings sollten Sie dies erst nach der Installation des MySQL-server-RPM durchführen. Siehe auch Abschnitt 5.3, „mysqld-max, ein erweiterter mysqld-Server“.

Wenn Sie bei dem Versuch, MySQL-Pakete zu installieren, einen Abhängigkeitsfehler erhalten (z. B. error: removing these packages would break dependencies: libmysqlclient.so.10 is needed by ...), dann sollten Sie auch das Paket MySQL-shared-compat installieren, denn dieses enthält die beiden gemeinsamen Bibliotheken für die Abwärtskompatibilität (libmysqlclient.so.12 für MySQL 4.0 und libmysqlclient.so.10 für MySQL 3.23) .

Einige Linux-Distributionen werden immer noch mit MySQL 3.23 ausgeliefert und verknüpfen Anwendungen gewöhnlich dynamisch, um Festplattenkapazität zu sparen. Befinden sich diese gemeinsamen Bibliotheken in einem separaten Paket (z. B. MySQL-shared), dann reicht es aus, dieses Paket einfach installiert zu lassen und nur die MySQL Server- und -Clientpakete zu aktualisieren (diese sind statisch verknüpft und hängen nicht von den gemeinsamen Bibliotheken ab). Bei Distributionen, in denen die gemeinsamen Bibliotheken im selben Paket enthalten sind wie der MySQL Server (z. B. Red Hat Linux), können Sie entweder unser MySQL-shared-RPM für Version 3.23 installieren oder stattdessen das Paket MySQL-shared-compat verwenden.

Die folgenden RPM-Pakete sind verfügbar:

  • MySQL-server-VERSION.i386.rpm

    Das ist der MySQL Server. Sie benötigen ihn in jedem Fall, sofern Sie nicht lediglich eine Verbindung mit einem MySQL Server herstellen wollen, der auf einem anderen Computer ausgeführt wird. Hinweis: Server-RPM-Dateien hießen vor MySQL 4.0.10 MySQL-VERSION.i386.rpm (d. h., der Zusatz -server war im Namen nicht enthalten).

  • MySQL-Max-VERSION.i386.rpm

    Das ist der MySQL Max-Server. Dieser Server verfügt über zusätzliche Fähigkeiten, die der Server im RPM MySQL-server nicht aufweist. Sie müssen das RPM MySQL-server jedoch zuerst installieren, da es für MySQL-Max erforderlich ist.

  • MySQL-client-VERSION.i386.rpm

    Die MySQL-Standardclientprogramme. Dieses Paket sollten Sie immer installieren.

  • MySQL-bench-VERSION.i386.rpm

    Tests und Benchmarks. Erfordert Perl und das Modul DBD::mysql.

  • MySQL-devel-VERSION.i386.rpm

    Die Bibliotheken und Include-Dateien, die erforderlich sind, wenn Sie andere MySQL-Clients (z. B. die Perl-Module) kompilieren wollen.

  • MySQL-shared-VERSION.i386.rpm

    Dieses Paket enthält die gemeinsamen Bibliotheken (libmysqlclient.so*), die bestimmte Sprachen und Anwendungen benötigen, um MySQL dynamisch laden und verwenden zu können.

  • MySQL-shared-compat-VERSION.i386.rpm

    Dieses Paket enthält die gemeinsamen Bibliotheken für MySQL 3.23 und MySQL 4.0. Installieren Sie es statt MySQL-shared, wenn Sie Anwendungen haben, die dynamisch mit MySQL 3.23 verknüpft sind, Sie aber auf MySQL 4.0 aktualisieren wollen, ohne die Bibliotheksabhängigkeiten zu durchbrechen. Das Paket ist ab MySQL 4.0.13 verfügbar.

  • MySQL-embedded-VERSION.i386.rpm

    Dies ist die eingebettete MySQL Server-Bibliothek (verfügbar ab MySQL 4.0).

  • MySQL-VERSION.src.rpm

    Dieses Paket enthält den Quellcode aller zuvor aufgeführten Pakete. Es kann auch zur Neuerstellung der RPMs auf anderen Architekturen (z. B. Alpha oder SPARC) verwendet werden.

Um alle in einem RPM-Paket (z. B. einem MySQL-server-RPM) enthaltenen Dateien anzuzeigen, führen Sie den folgenden Befehl aus:

shell> rpm -qpl MySQL-server-VERSION.i386.rpm

Wollen Sie eine minimale Standardinstallation durchführen, dann installieren Sie die Server- und Client-RPMs:

shell> rpm -i MySQL-server-VERSION.i386.rpm
shell> rpm -i MySQL-client-VERSION.i386.rpm

Wenn Sie nur die Clientprogramme benötigen, dann installieren Sie lediglich das Client-RPM:

shell> rpm -i MySQL-client-VERSION.i386.rpm

Das RPM-Format bietet eine Funktion zur Überprüfung der Integrität und Authentifizierung von Paketen vor der Installation. Wenn Sie mehr zu dieser Funktion erfahren wollen, lesen Sie Abschnitt 2.1.4, „Bestätigen der Paketintegrität mittels MD5-Prüfsummen oder GnuPG.

Das Server-RPM legt Daten im Verzeichnis /var/lib/mysql ab. Außerdem richtet das RPM ein Anmeldekonto für einen Benutzer namens mysql (sofern nicht bereits vorhanden) ein, über das der MySQL Server ausgeführt wird, und erstellt die entsprechenden Einträge in /etc/init.d/, um den Server automatisch mit dem System zu starten. (Dies bedeutet, dass Sie, wenn Sie zuvor bereits eine Installation durchgeführt und Änderungen an deren Startskript vorgenommen haben, eine Kopie des Skripts erstellen sollten, damit es bei der Installation eines neueren RPM nicht verloren geht.) Weitere Informationen dazu, wie MySQL automatisch mit dem System gestartet werden kann, finden Sie in Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.

Wenn Sie das MySQL-RPM auf älteren Linux-Distributionen installieren wollen, die Initialisierungsskripten in /etc/init.d noch nicht (direkt oder über eine symbolische Verknüpfung) unterstützen, dann sollten Sie eine symbolische Verknüpfung erstellen, die auf die Position verweist, an der Ihre Initialisierungsskripten tatsächlich installiert sind. Heißt die Position etwa /etc/rc.d/init.d, dann geben Sie vor der Installation des RPM die folgenden Befehle ein, um /etc/init.d als symbolische Verknüpfung zu erstellen, die darauf verweist:

shell> cd /etc
shell> ln -s rc.d/init.d .

Allerdings sollten die aktuellen Versionen aller wichtigen Linux-Distributionen das neue Verzeichnislayout unterstützen, das /etc/init.d verwendet, da es für die LSB-Kompatibilität (Linux Standard Base) erforderlich ist.

Wenn zu den RPM-Dateien, die Sie installieren, MySQL-server gehört, dann sollte der Server mysqld nach der Installation einwandfrei funktionieren. Sie sollten ihn mithilfe von MySQL starten können.

Klappt etwas nicht, dann erhalten Sie weitere Informationen im Abschnitt zur Installation von Binärdistributionen. Siehe auch Abschnitt 2.7, „Installation von MySQL auf anderen Unix-ähnlichen Systemen“.

Hinweis: Für die in den MySQL-Grant-Tabellen aufgeführten Konten gibt es zunächst noch keine Passwörter. Wenn Sie den Server gestartet haben, sollten Sie entsprechend der in Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, beschriebenen Verfahrensweise Passwörter für diese Konten einrichten.

2.5. Installation von MySQL unter Mac OS X

Sie können MySQL unter Mac OS X 10.2.x („Jaguar“) oder höher mithilfe eines Mac OS X-Binärpakets im PKG-Format anstelle der binären Tar-Distribution installieren. Bitte beachten Sie, dass ältere Mac OS X-Versionen (z. B. 10.1.x) nicht durch dieses Paket unterstützt werden.

Das Paket befindet sich in einer Festplattenimagedatei (.dmg), die Sie zunächst einbinden müssen. Doppelklicken Sie im Finder auf das zugehörige Symbol. Danach binden Sie das Image ein und zeigen seinen Inhalt an.

Wie Sie sich MySQL beschaffen, lesen Sie in Abschnitt 2.1.3, „Woher man MySQL bekommt“.

Hinweis: Bevor Sie mit der Installation fortfahren, müssen Sie alle laufenden MySQL Server-Instanzen herunterfahren. Dies tun Sie entweder mit der MySQL-Manager-Anwendung (unter Mac OS X Server) oder mithilfe von mysqladmin shutdown an der Befehlszeile.

Um nun die MySQL-PGK-Datei zu installieren, doppelklicken Sie auf das Paketsymbol. Nun wird das Installationsprogramm für das Mac OS X-Paket gestartet. Dieses Programm geleitet Sie durch die Installation von MySQL.

Aufgrund eines Bugs im Mac OS X-Paketinstallationsprogramm wird bei Anzeige des Dialogfelds zur Auswahl des Ziellaufwerks unter Umständen die folgende Fehlermeldung angezeigt:

You cannot install this software on this disk. (null)

Klicken Sie in diesem Fall einmal auf die Schaltfläche Go Back, um zum vorherigen Bildschirm zurückzukehren. Klicken Sie dann auf Continue, um das Dialogfeld zur Auswahl des Ziellaufwerks erneut aufzurufen. Nun sollten Sie das Ziellaufwerk problemlos auswählen können. Wir haben diesen Bug Apple bereits gemeldet. Das Problem wird dort untersucht.

Das Mac OS X-PKG von MySQL installiert sich im Verzeichnis /usr/local/mysql-VERSION. Ferner wird eine symbolische Verknüpfung /usr/local/mysql eingerichtet, die ebenfalls auf die neue Position verweist. Ist ein Verzeichnis namens /usr/local/mysql bereits vorhanden, dann wird dieses zunächst in /usr/local/mysql.bak umbenannt. Außerdem erstellt das Installationsprogramm die Grant-Tabellen in der mysql-Datenbank. Hierzu führt es den Befehl mysql_install_db aus.

Das Installationslayout ähnelt dem einer tar-Binärdistribution: Alle MySQL-Binärdateien befinden sich im Verzeichnis /usr/local/mysql/bin. Die MySQL-Socketdatei wird standardmäßig als /tmp/mysql.sock erstellt. Siehe auch Abschnitt 2.1.5, „Installationslayouts“.

Für die MySQL-Installation ist ein Mac OS X-Benutzerkonto mit dem Namen mysql erforderlich. Unter Mac OS X 10.2 und höher sollte ein solches Konto standardmäßig vorhanden sein.

Wenn Sie Mac OS X Server ausführen, sollte eine MySQL-Version bereits installiert sein. Die folgende Tabelle zeigt die MySQL-Versionen, die mit den verschiedenen Versionen von Mac OS X Server ausgeliefert werden.

Mac OS X Server-VersionMySQL-Version
10.2–10.2.23.23.51
10.2.3–10.2.63.23.53
10.34.0.14
10.3.24.0.16
10.4.04.1.10a

Dieses Handbuch behandelt nur die Installation des offiziellen MySQL-PKG für Mac OS X. Lesen Sie in jedem Fall Apples Hilfeinformationen zur Installation von MySQL: Starten Sie die Anwendung „Hilfeanzeige“ und wählen Sie die Hilfe für „Mac OS X-Server“. Suchen Sie dann nach dem Begriff „MySQL“ und lesen Sie das Thema „MySQL installieren“.

Beachten Sie bei vorinstallierten MySQL-Versionen auf Mac OS X Server insbesondere, dass Sie mysqld mit dem Befehl safe_mysqld statt mysqld_safe starten müssen, wenn die betreffende MySQL-Version älter ist als 4.0.

Haben Sie zuvor MySQL-Pakete für Mac OS X von Marc Liyanage verwendet (http://www.entropy.ch), dann können Sie die auf den dortigen Seiten beschriebenen Aktualisierungsanweisungen für Pakete einfach unter Verwendung der dort bezeichneten Installationsstruktur für Binärdistributionen befolgen.

Aktualisieren Sie von Marcs Versionen 3.23.xx oder von der Mac OS X Server-Version von MySQL auf das offizielle MySQL-PKG, dann müssen Sie die vorhandenen MySQL-Berechtigungstabellen ebenfalls in das aktuelle Format konvertieren, da einige neue Sicherheitsberechtigungen hinzugefügt worden sind. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Wenn Sie wollen, dass MySQL während des Systemstarts automatisch gestartet wird, müssen Sie auch das MySQL-Startobjekt installieren. Es ist auf dem Mac OS X-Installationsmedium als separates Installationspaket enthalten. Doppelklicken Sie einfach auf das Symbol MySQLStartupItem.pkg und folgen Sie dann den Anweisungen am Bildschirm.

Beachten Sie, dass das Startobjekt nur einmal installiert werden darf! Es ist nicht notwendig, das Startobjekt bei jeder späteren Aktualisierung des MySQL-Pakets vorzunehmen.

Das Startobjekt für MySQL wird in /Library/Startobjekte/MySQLCOM installiert. (Vor MySQL 4.1.2 hieß das Verzeichnis /Library/StartupItems/MySQL, aber dies führt zu einem Konflikt mit dem MySQL-Startobjekt, das von Mac OS X Server installiert wurde.) Bei der Startobjektinstallation wird eine Variable MYSQLCOM=-YES- in der Systemkonfigurationsdatei /etc/hostconfig ergänzt. Wenn Sie den automatischen Start von MySQL deaktivieren wollen, ändern Sie einfach den Wert der Variablen wie folgt: MYSQLCOM=-NO-.

Unter Mac OS X Server verwendet die MySQL-Standardinstallation die Variable MYSQL in der Datei /etc/hostconfig. Das Startobjekt-Installationsprogramm von MySQL AB deaktiviert diese Variable (MYSQL=-NO-). Hierdurch werden beim Systemstart Konflikte mit der Variablen MYSQLCOM vermieden, die vom MySQL AB-Startobjekt verwendet wird. Allerdings wird dabei ein laufender MySQL Server nicht heruntergefahren. Dies müssen Sie selbst erledigen.

Nach der Installation können Sie MySQL mithilfe der folgenden Befehle in einem Terminal-Fenster ausführen. Um diesen Vorgang durchzuführen, benötigen Sie Administratorrechte.

Wenn Sie das Startobjekt installiert haben, verwenden Sie folgenden Befehl:

shell> sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
(Enter your password, if necessary)
(Press Control-D or enter "exit" to exit the shell)

Wenn Sie das Startobjekt hingegen nicht installiert haben, geben Sie diese Befehlsfolge ein:

shell> cd /usr/local/mysql
shell> sudo ./bin/mysqld_safe
(Enter your password, if necessary)
(Press Control-Z)
shell> bg
(Press Control-D or enter "exit" to exit the shell)

Sie sollten nun in der Lage sein, eine Verbindung zum MySQL Server herzustellen. Hierzu können Sie etwa /usr/local/mysql/bin/mysql ausführen.

Hinweis: Für die in den MySQL-Grant-Tabellen aufgeführten Konten gibt es zunächst noch keine Passwörter. Wenn Sie den Server gestartet haben, sollten Sie entsprechend der in Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, beschriebenen Verfahrensweise Passwörter für diese Konten einrichten.

Sie sollten in der Ressourcendatei Ihrer Shell Aliase ergänzen, um den Zugriff auf häufig verwendete Programme wie mysql und mysqladmin über die Befehlszeile zu erleichtern. Die Syntax für bash lautet:

alias mysql=/usr/local/mysql/bin/mysql
alias mysqladmin=/usr/local/mysql/bin/mysqladmin

Für tcsh verwenden Sie Folgendes:

alias mysql /usr/local/mysql/bin/mysql
alias mysqladmin /usr/local/mysql/bin/mysqladmin

Noch vorteilhafter ist es, /usr/local/mysql/bin zur Umgebungsvariablen PATH hinzuzufügen. Fügen Sie beispielsweise die folgende Zeile zu Ihrer Datei $HOME/.bashrc hinzu, wenn Sie bash als Shell verwenden:

PATH=${PATH}:/usr/local/mysql/bin

Fügen Sie folgende Zeile zu Ihrer Datei $HOME/.tcshrc hinzu, wenn Sie tcsh als Shell verwenden:

setenv PATH ${PATH}:/usr/local/mysql/bin

Wenn weder .bashrc noch .tcshrc in Ihrem Homeverzeichnis vorhanden sind, erstellen Sie die Datei mit einem Texteditor.

Aktualisieren Sie eine vorhandene Installation, dann beachten Sie, dass, wenn Sie ein neues MySQL-PKG installieren, das Verzeichnis der alten Installation nicht entfernt wird. Leider bietet das Mac OS X-Installationsprogramm noch nicht die Funktionalität, die zur korrekten Aktualisierung zuvor installierter Pakete erforderlich ist.

Um Ihre vorhandenen Datenbanken mit der neuen Installation verwenden zu können, müssen Sie den Inhalt des alten Datenverzeichnisses in das neue Datenverzeichnis kopieren. Stellen Sie sicher, dass weder der alte noch der neue Server laufen, während Sie diesen Kopiervorgang durchführen. Haben Sie die MySQL-Datenbankdateien der alten Installation kopiert und den neuen Server erfolgreich gestartet, dann können Sie die alten Installationsdateien entfernen, um Festplattenspeicher zu sparen. Ebenfalls entfernen sollten Sie ältere Versionen der Package-Receipt-Verzeichnisse in /Library/Receipts/mysql-VERSION.pkg.

2.6. Installation von MySQL unter NetWare

Die Portierung von MySQL auf NetWare wurde von Novell gezielt unterstützt. Kunden von Novell werden erfreut sein zu erfahren, dass NetWare 6.5 im Bündel mit MySQL-Binärdateien ausgeliefert wird – komplett mit einer automatischen Lizenz zur kommerziellen Nutzung, gültig für alle Server, auf denen diese NetWare-Version läuft.

MySQL für NetWare wird mithilfe einer Kombination aus Metrowerks CodeWarrior for NetWare und speziellen Versionen der GNU-Autotools zur Cross-Kompilierung kompiliert.

Die aktuellen Binärpakete für NetWare erhalten Sie unter http://dev.mysql.com/downloads/. Siehe auch Abschnitt 2.1.3, „Woher man MySQL bekommt“.

Ein NetWare-Server, auf dem MySQL laufen soll, muss die folgenden Anforderungen erfüllen:

  • Das aktuelle Support Pack für NetWare 6.5 muss installiert sein.

  • Das System muss die Mindestanforderungen erfüllen, die Novell für die Ausführung der betreffenden NetWare-Version stellt.

  • MySQL-Daten und die Programmbinärdateien müssen auf einem NSS-Volume installiert sein (traditionelle Volumes werden nicht unterstützt).

Gehen Sie wie folgt vor, um MySQL für NetWare zu installieren:

  1. Wenn Sie eine vorhandene Installation aktualisieren, beenden Sie den MySQL Server. Hierzu geben Sie den folgenden Befehl an der Serverkonsole ein:

    SERVER:  mysqladmin -u root shutdown
    

    Hinweis: Wenn das MySQL-Benutzerkonto root ein Passwort aufweist, müssen Sie mysqladmin mit der Option -p aufrufen und das Passwort auf Aufforderung angeben.

  2. Melden Sie sich am Zielserver über einen Clientcomputer an, der Zugriff auf das Verzeichnis hat, in dem Sie MySQL installieren wollen.

  3. Extrahieren Sie die ZIP-Datei mit dem Binärpaket auf den Server. Stellen Sie dabei sicher, dass die in der ZIP-Datei gespeicherten Pfade verwendet werden. Am sichersten ist das einfache Entpacken nach SYS:\.

    Wenn Sie eine vorhandene Installation aktualisieren, müssen Sie unter Umständen das Datenverzeichnis (beispielsweise SYS:MYSQL\DATA) kopieren. Gleiches gilt für die Datei my.cnf, sofern Sie diese an Ihre Bedürfnisse angepasst haben. Danach können Sie die alte Kopie von MySQL löschen.

  4. Sie sollten dem Verzeichnis einen anderen, konsistenteren und einfacher zu handhabenden Namen geben. In den Beispielen dieses Handbuchs verwenden wir SYS:MYSQL als Bezeichnung für das Installationsverzeichnis.

    Beachten Sie, dass die MySQL-Installation unter NetWare nicht erkennt, ob eine MySQL-Version außerhalb des NetWare-Releases bereits vorhanden ist. Haben Sie also etwa die aktuelle MySQL-Version (ab MySQL 4.1 oder höher) aus dem Web in SYS:\MYSQL installiert, dann müssen Sie den Ordner umbenennen, bevor Sie den NetWare-Server aktualisieren; andernfalls werden in SYS:\MySQL vorhandene Dateien, die im NetWare Support Pack abgelegt sind, mit der MySQL-Version überschrieben.

  5. Fügen Sie an der Serverkonsole einen Suchpfad für das Verzeichnis hinzu, welches die MySQL-NLMs enthält. Ein Beispiel:

    SERVER:  SEARCH ADD SYS:MYSQL\BIN
    
  6. Initialisieren Sie ggf. das Datenverzeichnis und die Grant-Tabellen, indem Sie mysql_install_db an der Serverkonsole ausführen.

  7. Starten Sie den MySQL Server mit mysqld_safe an der Serverkonsole.

  8. Um die Installation abzuschließen, sollten Sie auch die folgenden Befehle in der Datei autoexec.ncf ergänzen. Wenn Ihre MySQL-Installation beispielsweise in SYS:MYSQL abgelegt ist und Sie MySQL automatisch starten wollen, fügen Sie folgende Befehle hinzu:

    #Starts the MySQL 5.1.x database server
    SEARCH ADD SYS:MYSQL\BIN
    MYSQLD_SAFE
    

    Führen Sie MySQL unter NetWare 6.0 aus, dann empfehlen wir Ihnen dringend die Verwendung der Option --skip-external-locking in der Befehlszeile:

    #Starts the MySQL 5.1.x database server
    SEARCH ADD SYS:MYSQL\BIN
    MYSQLD_SAFE --skip-external-locking
    

    Ferner ist es notwendig, CHECK TABLE und REPAIR TABLE anstelle von myisamchk zu verwenden, da myisamchk externe Sperren verwendet. Die externe Sperrung bereitet bei NetWare 6.0 bekanntermaßen Probleme. Diese wurden jedoch in NetWare 6.5 beseitigt.

    mysqld_safe stellt unter NetWare eine Bildschirmpräsenz bereit. Wenn Sie das NLM mysqld_safe entladen (herunterfahren), verschwindet der Bildschirm standardmäßig nicht. Stattdessen wird eine Benutzereingabe angefordert:

    *<NLM has terminated; Press any key to close the screen>*
    

    Wenn Sie hingegen wollen, dass NetWare den Bildschirm automatisch schließt, dann verwenden Sie die Option --autoclose für mysqld_safe. Ein Beispiel:

    #Starts the MySQL 5.1.x database server
    SEARCH ADD SYS:MYSQL\BIN
    MYSQLD_SAFE --autoclose
    
  9. Wenn Sie MySQL installieren – sei es zum ersten Mal oder im Zuge der Aktualisierung von einer vorherigen Version –, dann müssen Sie das aktuellste passende Perl-Modul und die geeigneten PHP-Erweiterungen für NetWare herunterladen:

Das Verhalten von mysqld_safe unter NetWare wird in Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“, detailliert beschrieben.

War auf dem NetWare-Server bereits eine MySQL-Installation vorhanden, dann müssen Sie in jedem Fall in der Datei autoexec.ncf nach MySQL-Startbefehlen suchen und diese nach Bedarf bearbeiten oder löschen.

Hinweis: Für die in den MySQL-Grant-Tabellen aufgeführten Konten gibt es zunächst noch keine Passwörter. Wenn Sie den Server gestartet haben, sollten Sie entsprechend der in Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, beschriebenen Verfahrensweise Passwörter für diese Konten einrichten.

2.7. Installation von MySQL auf anderen Unix-ähnlichen Systemen

Dieser Abschnitt behandelt die Installation der MySQL-Binärdistributionen, die für die verschiedenen Plattformen in Form komprimierter tar-Dateien (d. h. Dateien mit der Erweiterung .tar.gz) vorliegen. Eine detaillierte Liste finden Sie in Abschnitt 2.1.2.5, „MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden“.

Wie Sie sich MySQL beschaffen, lesen Sie in Abschnitt 2.1.3, „Woher man MySQL bekommt“.

Eine tar-Datei mit einer Binärdistribution weist einen Namen mit dem Aufbau mysql-VERSION-OS.tar.gz auf. Hierbei ist VERSION eine Zahl (z. B. 5.1.5-alpha), während OS das Betriebssystem bezeichnet, für das die Distribution vorgesehen ist (beispielsweise pc-linux-i686).

Neben diesen Universalpaketen bieten wir für ausgewählte Plattformen auch Binärdateien in plattformspezifischen Paketformaten an. Weitere Informationen zur Installation dieser Pakete finden Sie in Abschnitt 2.2, „Schnelle Standardinstallation von MySQL“.

Um eine MySQL-Binärdistribution in einer tar-Datei zu installieren, benötigen Sie die folgenden Tools:

  • GNU gunzip zum Dekomprimieren der Distribution.

  • Ein anständiges tar zum Entpacken der Distribution. GNU tar funktioniert bekanntermaßen. Bestimmte Betriebssysteme enthalten eine vorinstallierte Version von tar, die aber offenbar problematisch ist. Beispielsweise haben die tar-Varianten von Mac OS X und Sun Probleme mit langen Dateinamen. Unter Mac OS X können Sie das vorinstallierte Programm gnutar verwenden. Auf anderen Systemen mit fehlerhaften tar-Anwendungen sollten Sie zunächst GNU tar installieren.

Sollten Sie auf Probleme stoßen und einen Fehlerbericht speichern wollen, dann gehen Sie vor wie in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschrieben.

Die wichtigsten Befehle, die bei der Installation und Verwendung einer MySQL-Binärdistribution ausgeführt werden müssen, sind die folgenden:

shell> groupadd mysql
shell> useradd -g mysql mysql
shell> cd /usr/local
shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
shell> ln -s full-path-to-mysql-VERSION-OS mysql
shell> cd mysql
shell> scripts/mysql_install_db --user=mysql
shell> chown -R root  .
shell> chown -R mysql data
shell> chgrp -R mysql .
shell> bin/mysqld_safe --user=mysql &

Hinweis: Beim folgenden Vorgang werden keine Passwörter für MySQL-Konten eingerichtet. Wenn Sie den Vorgang abgeschlossen haben, fahren Sie fort bei Abschnitt 2.9, „Einstellungen und Tests nach der Installation“.

Hier nun eine detailliertere Version der vorangegangenen Beschreibung zur Installation einer Binärdistribution:

  1. Fügen Sie einen Anmeldebenutzer und eine Gruppe hinzu, unter denen mysqld ausgeführt wird:

    shell> groupadd mysql
    shell> useradd -g mysql mysql
    

    Diese Befehle fügen die Gruppe mysql und den Benutzer mysql hinzu. Die Syntax für useradd und groupadd kann bei den verschiedenen Unix-Varianten etwas anders aussehen. Auch können die Befehlsnamen selbst variieren (z. B. adduser und addgroup).

    Unter Umständen wollen Sie dem Benutzer und der Gruppe einen anderen Namen als mysql zuweisen. In diesem Fall müssen Sie in den folgenden Schritten den entsprechenden Namen einsetzen.

  2. Wählen Sie das Verzeichnis aus, in das Sie die Distribution entpacken wollen, und rufen Sie dieses auf. Im folgenden Beispiel entpacken wir die Distribution in /usr/local. (Die folgenden Anweisungen setzen deswegen auch voraus, dass Sie Berechtigungen zum Erstellen von Dateien und Verzeichnissen in /usr/local haben. Ist das Verzeichnis geschützt, dann müssen Sie die Installation als root durchführen.)

    shell> cd /usr/local
    
  3. Beschaffen Sie sich wie in Abschnitt 2.1.3, „Woher man MySQL bekommt“, beschrieben eine Distributionsdatei. Die Binärdistributionen für alle Plattformen werden innerhalb eines Releases aus derselben MySQL-Quelldistribution erstellt.

  4. Entpacken Sie die Distribution. Hierdurch wird das Installationsverzeichnis erstellt. Erstellen Sie dann eine symbolische Verknüpfung zu diesem Verzeichnis:

    shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
    shell> ln -s full-path-to-mysql-VERSION-OS mysql
    

    Der Befehl tar erstellt ein Verzeichnis namens mysql-VERSION-OS. Der Befehl ln legt eine symbolische Verknüpfung zu diesem Verzeichnis an. Auf diese Weise können Sie das Installationsverzeichnis einfacher aufrufen als über /usr/local/mysql.

    Bei GNU tar ist kein separater Aufruf von gunzip erforderlich. Sie können die erste Zeile mit dem folgenden Alternativbefehl ersetzen, um die Distribution zu dekomprimieren und zu entpacken:

    shell> tar zxvf /path/to/mysql-VERSION-OS.tar.gz
    
  5. Wechseln Sie nun in das Installationsverzeichnis:

    shell> cd mysql
    

    Sie werden im Verzeichnis mysql verschiedene Dateien und Unterverzeichnisse vorfinden. Die für die Installation wichtigsten Elemente sind die Unterverzeichnisse bin und scripts:

    • Das Verzeichnis bin enthält Clientprogramme und den Server. Sie sollten den vollständigen Pfadnamen dieses Verzeichnisses zu Ihrer Umgebungsvariablen PATH hinzufügen, damit Ihre Shell die MySQL-Programme korrekt findet. Siehe auch Anhang F, Umgebungsvariablen.

    • Das Verzeichnis scripts enthält das Skript mysql_install_db, welches zur Initialisierung der mysql-Datenbank mit den Grant-Tabellen verwendet wird, in denen die Serverzugriffsberechtigungen gespeichert sind.

  6. Wenn Sie MySQL vorher noch nicht installiert hatten, müssen Sie die MySQL-Grant-Tabellen erstellen:

    shell> scripts/mysql_install_db --user=mysql
    

    Wenn Sie den Befehl als root ausführen, müssen Sie wie gezeigt die Option --user verwenden. Als Wert der Option sollte der Name des Anmeldekontos eingetragen werden, das Sie im ersten Schritt zur Verwendung für die Ausführung des Servers angegeben haben. Wenn Sie den Befehl ausführen, während Sie als dieser Benutzer angemeldet sind, können Sie die Option --user weglassen.

    Nach Erstellung oder Aktualisierung der Grant-Tabellen müssen Sie den Server manuell neu starten.

  7. Weisen Sie als neuen Besitzer der Programmbinärdateien root und als neuen Besitzer des Datenverzeichnisses den Benutzer zu, unter dessen Konto Sie mysqld ausführen. Wenn Sie sich etwa im Installationsverzeichnis (/usr/local/mysql) befinden, sieht der Befehl wie folgt aus:

    shell> chown -R root  .
    shell> chown -R mysql data
    shell> chgrp -R mysql .
    

    Der erste Befehl setzt das Besitzerattribut der Dateien auf den Benutzer root. Der zweite setzt das Besitzerattribut des Datenverzeichnisses auf den Benutzer mysql. Der dritte schließlich setzt das Gruppenattribut auf die Gruppe mysql.

  8. Wenn Sie wollen, dass MySQL beim Starten des Computers automatisch startet, können Sie support-files/mysql.server in das Verzeichnis kopieren, in dem sich die Startdateien Ihres Systems befinden. Weitere Informationen finden Sie im Skript support-files/mysql.server selbst und in Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.

  9. Neue Konten können Sie mit dem Skript bin/mysql_setpermission einrichten, wenn Sie die Perl-Module DBI und DBD::mysql installieren. Informationen zur Vorgehensweise finden Sie in Abschnitt 2.13, „Anmerkungen zur Perl-Installation“.

  10. Wenn Sie mysqlaccess verwenden wollen und Ihre MySQL-Distribution in einem anderen als dem Standardverzeichnis abgelegt ist, müssen Sie die Position ändern, an der mysqlaccess den mysql-Client vorzufinden erwartet. Bearbeiten Sie das Skript bin/mysqlaccess im Bereich von Zeile 18. Suchen Sie nach einer Zeile ähnlich der folgenden:

    $MYSQL     = '/usr/local/bin/mysql';    # path to mysql executable
    

    Ändern Sie den Pfad so ab, dass er die Position wiedergibt, an der mysql tatsächlich auf Ihrem System gespeichert ist. Andernfalls wird die Fehlermeldung Broken Pipe angezeigt, wenn Sie mysqlaccess ausführen.

Nachdem alles entpackt und installiert wurde, sollten Sie Ihre Distribution testen. Verwenden Sie den folgenden Befehl, um den MySQL Server zu starten:

shell> bin/mysqld_safe --user=mysql &

Wenn der Befehl sofort fehlschlägt und die Meldung mysqld ended ausgibt, finden Sie unter Umständen hilfreiche Informationen in der Datei host_name.err im Datenverzeichnis.

Weitere Informationen zu mysqld_safe können Sie Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“, entnehmen.

Hinweis: Für die in den MySQL-Grant-Tabellen aufgeführten Konten gibt es zunächst noch keine Passwörter. Wenn Sie den Server gestartet haben, sollten Sie entsprechend der in Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, beschriebenen Verfahrensweise Passwörter für diese Konten einrichten.

2.8. Installation der Quelldistribution

Bevor Sie mit einer Installation aus einer Quelldistribution fortfahren, überprüfen Sie zunächst, ob nicht für Ihre Plattform eine Binärdatei von uns angeboten wird, die für Ihre Belange geeignet sein könnte. Wir haben viel Aufwand betrieben, um zu gewährleisten, dass unsere Binärdateien mit den optimalen Optionen erstellt werden.

Wie Sie sich eine MySQL-Quelldistribution beschaffen, erfahren Sie in Abschnitt 2.1.3, „Woher man MySQL bekommt“.

MySQL-Quelldistributionen werden als komprimierte tar-Archive bereitgestellt. Der Dateiname hat den folgenden Aufbau: mysql-VERSION.tar.gz. Hierbei ist VERSION eine Zahl wie beispielsweise 5.1.5-alpha.

Zur Installation von MySQL aus einer Quelldistribution benötigen Sie die folgenden Tools:

  • GNU gunzip zum Dekomprimieren der Distribution.

  • Ein anständiges tar zum Entpacken der Distribution. GNU tar funktioniert bekanntermaßen. Bestimmte Betriebssysteme enthalten eine vorinstallierte Version von tar, die aber offenbar problematisch ist. Beispielsweise haben die tar-Varianten von Mac OS X und Sun Probleme mit langen Dateinamen. Unter Mac OS X können Sie das vorinstallierte Programm gnutar verwenden. Auf anderen Systemen mit fehlerhaften tar-Anwendungen sollten Sie zunächst GNU tar installieren.

  • Einen funktionsfähigen ANSI C++-Compiler. gcc 2.95.2 oder höher, egcs 1.0.2 oder höher oder egcs 2.91.66, SGI C++ und SunPro C++ sind Compiler, die offensichtlich problemlos funktionieren. libg++ wird bei der Verwendung von gcc nicht benötigt. gcc 2.7.x weist einen Fehler auf, der die Kompilierung bestimmter, hundertprozentig zulässiger C++-Dateien wie etwa sql/sql_base.cc unmöglich macht. Wenn Sie nur gcc 2.7.x haben, müssen Sie Ihr gcc so aktualisieren, dass es MySQL kompilieren kann. Auch gcc 2.8.1 weist bekanntermaßen Probleme auf bestimmten Plattformen auf, sollte also ebenfalls außen vor gelassen werden, sofern auf der betreffenden Plattform ein neuerer Compiler verfügbar ist.

    gcc 2.95.2 oder höher wird zur Kompilierung von MySQL 3.23.x empfohlen.

  • Ein gutes make-Programm. GNU make wird immer empfohlen und ist unter Umständen sogar erforderlich. Wenn Sie Probleme haben, dann empfehlen wir GNU make 3.75 oder höher.

Benutzen Sie eine Version von gcc, die neu genug ist, um die Option -fno-exceptions zu kennen, dann ist es extrem wichtig, diese Option auch zu verwenden. Andernfalls kompilieren Sie unter Umständen eine Binärdatei, die zu unvorhersagbaren Zeitpunkten abstürzt. Ferner empfehlen wir die Verwendung von -felide-constructors und -fno-rtti mit -fno-exceptions. Im Zweifelsfall tun Sie Folgendes:

CFLAGS="-O3" CXX=gcc CXXFLAGS="-O3 -felide-constructors \
       -fno-exceptions -fno-rtti" ./configure \
       --prefix=/usr/local/mysql --enable-assembler \
       --with-mysqld-ldflags=-all-static

Auf den meisten Systemen erhalten Sie so eine schnelle und stabile Binärdatei.

Sollten Sie auf Probleme stoßen und einen Fehlerbericht speichern wollen, dann gehen Sie vor wie in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschrieben.

2.8.1. Schnellinstallation, Überblick

Die wichtigsten Befehle, die bei der Installation und Verwendung einer MySQL-Quelldistribution ausgeführt werden müssen, sind die folgenden:

shell> groupadd mysql
shell> useradd -g mysql mysql
shell> gunzip < mysql-VERSION.tar.gz | tar -xvf -
shell> cd mysql-VERSION
shell> ./configure --prefix=/usr/local/mysql
shell> make
shell> make install
shell> cp support-files/my-medium.cnf /etc/my.cnf
shell> cd /usr/local/mysql
shell> bin/mysql_install_db --user=mysql
shell> chown -R root  .
shell> chown -R mysql var
shell> chgrp -R mysql .
shell> bin/mysqld_safe --user=mysql &

Wenn Sie von einem Quell-RPM ausgehen, tun Sie Folgendes:

shell> rpmbuild --rebuild --clean MySQL-VERSION.src.rpm

Auf diese Weise wird ein Binär-RPM erstellt, das Sie installieren können. Bei älteren RPM-Versionen müssen Sie unter Umständen den Befehl rpmbuild durch rpm ersetzen.

Hinweis: Beim folgenden Vorgang werden keine Passwörter für MySQL-Konten eingerichtet. Wenn Sie den Vorgang abgeschlossen haben, fahren Sie fort mit Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, wo Konfiguration und Tests nach der Installation beschrieben sind.

Hier nun eine detailliertere Version der vorangegangenen Beschreibung zur MySQL-Installation aus einer Quelldistribution:

  1. Fügen Sie einen Anmeldebenutzer und eine Gruppe hinzu, unter denen mysqld ausgeführt wird:

    shell> groupadd mysql
    shell> useradd -g mysql mysql
    

    Diese Befehle fügen die Gruppe mysql und den Benutzer mysql hinzu. Die Syntax für useradd und groupadd kann bei den verschiedenen Unix-Varianten etwas anders aussehen. Auch können die Befehlsnamen selbst variieren (z. B. adduser und addgroup).

    Unter Umständen wollen Sie dem Benutzer und der Gruppe einen anderen Namen als mysql zuweisen. In diesem Fall müssen Sie in den folgenden Schritten den entsprechenden Namen einsetzen.

  2. Wählen Sie das Verzeichnis aus, in das Sie die Distribution entpacken wollen, und rufen Sie dieses auf.

  3. Beschaffen Sie sich wie in Abschnitt 2.1.3, „Woher man MySQL bekommt“, beschrieben eine Distributionsdatei.

  4. Entpacken Sie die Distribution in das aktuelle Verzeichnis:

    shell> gunzip < /path/to/mysql-VERSION.tar.gz | tar xvf -
    

    Dieser Befehl erstellt ein Verzeichnis namens mysql-VERSION.

    Bei GNU tar ist kein separater Aufruf von gunzip erforderlich. Alternativ verwenden Sie den folgenden Befehl zum Dekomprimieren und Entpacken der Distribution:

    shell> tar zxvf /path/to/mysql-VERSION-OS.tar.gz
    
  5. Wechseln Sie nun in das Stammverzeichnis der entpackten Distribution:

    shell> cd mysql-VERSION
    

    Beachten Sie, dass Sie MySQL derzeit nur von diesem Stammverzeichnis aus installieren können. Sie können es nicht in einem anderen Verzeichnis erstellen.

  6. Konfigurieren Sie den Release und kompilieren Sie alles:

    shell> ./configure --prefix=/usr/local/mysql
    shell> make
    

    Wenn Sie configure ausführen, sollten Sie weitere Optionen festlegen. Führen Sie ./configure --help aus, um eine Liste der Optionen anzuzeigen. Abschnitt 2.8.2, „Typische configure-Optionen“, beschreibt einige der nützlicheren Optionen.

    Wenn Sie eine E-Mail an eine MySQL-Mailingliste senden, weil configure fehlgeschlagen ist und Sie Hilfe benötigen, fügen Sie bitte alle ggf. in der Datei config.log vorhandenen Zeilen hinzu, von denen Sie annehmen, dass sie zur Problembehebung beitragen können. Ferner sollten Sie die letzten paar Zeilen der Ausgabe von configure aufführen. Verwenden Sie zum Übermitteln eines Fehlerberichts die in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschriebenen Anweisungen.

    Schlägt die Kompilierung fehl, dann finden Sie hilfreiche Informationen in Abschnitt 2.8.4, „Probleme beim Kompilieren?“.

  7. Installieren Sie die Distribution:

    shell> make install
    

    Wenn Sie eine Optionsdatei konfigurieren wollen, verwenden Sie eine der im Verzeichnis support-files vorhandenen Dateien als Vorlage. Ein Beispiel:

    shell> cp support-files/my-medium.cnf /etc/my.cnf
    

    Sie müssen diese Befehle unter Umständen als root ausführen.

    Wenn Sie die Unterstützung für InnoDB-Tabellen konfigurieren wollen, sollten Sie die Datei /etc/my.cnf bearbeiten, das Zeichen # vor den Optionszeilen entfernen, die mit innodb_... beginnen, und die Optionswerte nach Bedarf ändern. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“, und Abschnitt 14.2.3, „Konfiguration“.

  8. Wechseln Sie nun in das Installationsverzeichnis:

    shell> cd /usr/local/mysql
    
  9. Wenn Sie MySQL vorher noch nicht installiert hatten, müssen Sie die MySQL-Grant-Tabellen erstellen:

    shell> bin/mysql_install_db --user=mysql
    

    Wenn Sie den Befehl als root ausführen, sollten Sie wie gezeigt die Option --user verwenden. Als Wert der Option sollte der Name des Anmeldekontos eingetragen werden, das Sie im ersten Schritt zur Verwendung für die Ausführung des Servers angegeben haben. Wenn Sie den Befehl ausführen, während Sie als dieser Benutzer angemeldet sind, können Sie die Option --user weglassen.

    Wenn Sie die Grant-Tabellen mit mysql_install_db erstellt haben, müssen Sie den Server manuell neu starten. Wie dies mit dem Befehl mysqld_safe geht, wird in einem späteren Schritt erläutert.

  10. Weisen Sie als neuen Besitzer der Programmbinärdateien root und als neuen Besitzer des Datenverzeichnisses den Benutzer zu, unter dessen Konto Sie mysqld ausführen. Wenn Sie sich etwa im Installationsverzeichnis (/usr/local/mysql) befinden, sieht der Befehl wie folgt aus:

    shell> chown -R root  .
    shell> chown -R mysql var
    shell> chgrp -R mysql .
    

    Der erste Befehl setzt das Besitzerattribut der Dateien auf den Benutzer root. Der zweite setzt das Besitzerattribut des Datenverzeichnisses auf den Benutzer mysql. Der dritte schließlich setzt das Gruppenattribut auf die Gruppe mysql.

  11. Wenn Sie wollen, dass MySQL beim Starten des Computers automatisch startet, können Sie support-files/mysql.server in das Verzeichnis kopieren, in dem sich die Startdateien Ihres Systems befinden. Weitere Informationen finden Sie im Skript support-files/mysql.server selbst und in Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.

  12. Neue Konten können Sie mit dem Skript bin/mysql_setpermission einrichten, wenn Sie die Perl-Module DBI und DBD::mysql installieren. Informationen zur Vorgehensweise finden Sie in Abschnitt 2.13, „Anmerkungen zur Perl-Installation“.

Nachdem alles installiert wurde, sollten Sie Ihre Distribution testen. Verwenden Sie den folgenden Befehl, um den MySQL Server zu starten:

shell> /usr/local/mysql/bin/mysqld_safe --user=mysql &

Wenn der Befehl sofort fehlschlägt und die Meldung mysqld ended ausgibt, finden Sie unter Umständen hilfreiche Informationen in der Datei host_name.err im Datenverzeichnis.

Weitere Informationen zu mysqld_safe können Sie Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“, entnehmen.

Hinweis: Für die in den MySQL-Grant-Tabellen aufgeführten Konten gibt es zunächst noch keine Passwörter. Wenn Sie den Server gestartet haben, sollten Sie entsprechend der in Abschnitt 2.9, „Einstellungen und Tests nach der Installation“, beschriebenen Verfahrensweise Passwörter für diese Konten einrichten.

2.8.2. Typische configure-Optionen

Das Skript configure bietet Ihnen umfassende Kontrolle darüber, wie Sie Ihre MySQL-Quelldistribution konfigurieren. Normalerweise werden Sie dies mithilfe der Optionen von configure an der Befehlszeile tun. Sie können configure auch über bestimmte Umgebungsvariablen beeinflussen. Siehe auch Anhang F, Umgebungsvariablen. Eine Liste der Optionen, die von configure unterstützt werden, erhalten Sie nach Ausführen des folgenden Befehls:

shell> ./configure --help

In der Folge wollen wir einige der häufiger verwendeten Optionen von configure beschreiben:

  • Um nur die Clientbibliotheken und -programme von MySQL (und nicht den Server) zu kompilieren, verwenden Sie die Option --without-server:

    shell> ./configure --without-server
    

    Wenn Sie keinen C++-Compiler haben, kann mysql nicht kompiliert werden (dies ist das einzige Clientprogramm, das C++ erfordert). In diesem Fall können Sie den Code, der das Vorhandensein des C++-Compilers prüft, aus configure entfernen und dann ./configure mit der Option --without-server ausführen. In diesem Fall wird bei der Kompilierung zwar versucht, mysql zu erstellen, aber Sie können alle Warnungen bezüglich mysql.cc ignorieren. (Wenn make stehen bleibt, geben Sie make -k ein, um das System anzuweisen, die Erstellung auch bei Auftreten von Fehlern abzuschließen.)

  • Wenn Sie die eingebettete MySQL-Bibliothek (libmysqld.a) erstellen wollen, verwenden Sie die Option --with-embedded-server.

  • Wenn Sie nicht wollen, dass Ihre Logdateien und die Datenbankverzeichnisse in /usr/local/var abgelegt werden, verwenden Sie configure in der Art wie folgt:

    shell> ./configure --prefix=/usr/local/mysql
    shell> ./configure --prefix=/usr/local \
               --localstatedir=/usr/local/mysql/data
    

    Der erste Befehl ändert das Installationspräfix, sodass alles in /usr/local/mysql (statt wie standardmäßig vorgesehen in /usr/local) installiert wird. Der zweite Befehl belässt das Installationsstandardpräfix zwar, ersetzt aber die Standardposition der Datenbankverzeichnisse (normalerweise /usr/local/var) durch /usr/local/mysql/data.

    Sie können die Positionen auch zum Zeitpunkt des Serverstarts angeben, indem Sie sie in die MySQL-Optionsdatei eintragen. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

  • Wenn Sie Unix verwenden und die MySQL-Socketdatei an einer anderen Position als im Standardverzeichnis (normalerweise /tmp oder /var/run) ablegen wollen, verwenden Sie den configure-Befehl wie folgt:

    shell> ./configure \
               --with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock
    

    Der Socketdateiname muss ein absoluter Pfadname sein. Sie können die Position von mysql.sock mithilfe einer Optionsdatei auch zum Zeitpunkt des Serverstarts einstellen. Siehe auch Abschnitt A.4.5, „Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern“.

  • Wenn Sie statisch verknüpfte Programme kompilieren wollen, um etwa eine Binärdistribution zu erstellen, die Leistung zu optimieren oder Probleme mit bestimmten Red Hat Linux-Distributionen zu umgehen, dann führen Sie configure wie folgt aus:

    shell> ./configure --with-client-ldflags=-all-static \
               --with-mysqld-ldflags=-all-static
    
  • Wenn Sie gcc einsetzen und libg++ oder libstdc++ nicht installiert haben, können Sie configure anweisen, gcc als C++-Compiler zu verwenden:

    shell> CC=gcc CXX=gcc ./configure
    

    Verwenden Sie gcc als C++-Compiler, dann wird keine Verknüpfung mit libg++ oder libstdc++ probiert. Dies kann auch dann von Vorteil sein, wenn Sie die betreffenden Bibliotheken installiert haben. In Verbindung mit einigen Versionen dieser Bibliotheken sind bei MySQL-Benutzern in der Vergangenheit nicht nachvollziehbare Probleme aufgetreten.

    Die folgende Liste führt einige Compiler auf. Ferner aufgelistet sind die zugehörigen Einstellungen für Umgebungsvariablen.

    • gcc 2.7.2:

      CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors"
      
    • egcs 1.0.3a:

      CC=gcc CXX=gcc CXXFLAGS="-O3 -felide-constructors \
      -fno-exceptions -fno-rtti"
      
    • gcc 2.95.2:

      CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro \
      -felide-constructors -fno-exceptions -fno-rtti"
      
    • pgcc 2.90.29 oder höher:

      CFLAGS="-O3 -mpentiumpro -mstack-align-double" CXX=gcc \
      CXXFLAGS="-O3 -mpentiumpro -mstack-align-double \
      -felide-constructors -fno-exceptions -fno-rtti"
      

    In den meisten Fällen erhalten Sie eine vernünftig optimierte MySQL-Binärdatei, wenn Sie die Optionen der vorangegangenen Tabelle verwenden und die folgenden Optionen in der configure-Befehlszeile hinzufügen:

    --prefix=/usr/local/mysql --enable-assembler \
    --with-mysqld-ldflags=-all-static
    

    Mit anderen Worten: Die vollständige configure-Zeile würde bei allen aktuellen gcc-Versionen ungefähr wie folgt aussehen:

    CFLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro \
    -felide-constructors -fno-exceptions -fno-rtti" ./configure \
    --prefix=/usr/local/mysql --enable-assembler \
    --with-mysqld-ldflags=-all-static
    

    Alle von uns auf der MySQL-Website unter http://dev.mysql.com/downloads/ bereitgestellten Binärdateien wurden mit optimalen Einstellungen kompiliert und sollten für die meisten Benutzer perfekt geeignet sein. Siehe auch Abschnitt 2.1.2.5, „MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden“. Es gibt einige Konfigurationseinstellungen, durch deren Optimierung Sie eine noch schnellere Binärdatei erstellen können. Diese Einstellungen sind jedoch nur für fortgeschrittene Benutzer geeignet. Siehe auch Abschnitt 7.5.4, „Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst“.

    Schlägt die Erstellung fehl und werden Fehlermeldungen erzeugt, weil Ihr Compiler oder Linker die gemeinsame Bibliothek libmysqlclient.so.N nicht erstellen konnte (wobei N eine Versionsnummer ist), dann können Sie dieses Problem umgehen, indem Sie die Option --disable-shared für configure ergänzen. In diesem Fall erstellt configure die gemeinsame Bibliothek libmysqlclient.so.N nicht.

  • Standardmäßig verwendet MySQL den Zeichensatz latin1 (cp1252 West European). Um den Standardzeichensatz zu ändern, verwenden Sie die Option --with-charset:

    shell> ./configure --with-charset=CHARSET
    

    CHARSET kann einen der folgenden Werte annehmen: big5, cp1251, cp1257, czech, danish, dec8, dos, euc_kr, gb2312, gbk, german1, hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, latin2, sjis, swe7, tis620, ujis, usa7 oder win1251ukr. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

    Die Standardsortierung kann ebenfalls angegeben werden. Standardmäßig verwendet MySQL die Sortierung latin1_swedish_ci. Um diese Sortierung zu ändern, verwenden Sie die Option --with-collation:

    shell> ./configure --with-collation=COLLATION
    

    Wollen Sie Zeichensatz und Sortierung gleichzeitig ändern, dann verwenden Sie einfach beide Optionen --with-charset und --with-collation. Die Sortierung muss für den gewählten Zeichensatz zulässig sein. (Mit der Anweisung SHOW COLLATION können Sie die für den jeweiligen Zeichensatz zulässige Sortierung ermitteln.)

    Wenn Sie Zeichen zwischen Server und Client konvertieren wollen, dann sollten Sie einen Blick auf die Anweisung SET NAMES werfen. Siehe auch Abschnitt 13.5.3, „SET, und Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.

    Warnung: Wenn Sie den Zeichensatz ändern, nachdem Sie bereits Tabellen erstellt haben, müssen Sie myisamchk -r -q --set-collation=collation_name für jede Tabelle ausführen. Andernfalls werden Ihre Indizes unter Umständen falsch sortiert. Dies kann passieren, wenn Sie MySQL installieren, einige Tabellen erstellen und nachfolgend MySQL so umkonfigurieren, dass ein anderer Zeichensatz verwendet wird, und dann neu installieren.

    Mit der configure-Option --with-extra-charsets=LIST können Sie definieren, welche zusätzlichen Zeichensätze in den Server einkompiliert werden sollen. LIST hat dabei einen der folgenden Werte:

    • eine Liste von Zeichensatznamen, die durch Leerzeichen getrennt sind

    • complex, wenn alle Zeichensätze enthalten sein sollen, die sich nicht dynamisch laden lassen

    • all, wenn grundsätzlich alle Zeichensätze in den Binärdateien enthalten sein sollen

  • Um MySQL mit Debugging-Code zu konfigurieren, verwenden Sie die Option --with-debug:

    shell> ./configure --with-debug
    

    Auf diese Weise wird eine sichere Speicherzuweisung in die Konfiguration integriert, die in der Lage ist, bestimmte Fehler zu finden und Informationen zu den Abläufen zu vermitteln. Siehe auch Abschnitt E.1, „Einen MySQL-Server debuggen“.

  • Wenn Ihre Clientprogramme Threads verwenden, müssen Sie eine Thread-sichere Version der MySQL-Clientbibliothek mit der Konfigurationsoption --enable-thread-safe-client erstellen. Auf diese Weise wird eine Bibliothek libmysqlclient_r angelegt, mit der Sie Ihre Thread-basierten Anwendungen verknüpfen sollten. Siehe auch Abschnitt 24.2.15, „Wie man einen Thread-Client herstellt“.

  • Es ist möglich, MySQL mit Unterstützung für große Tabellen zu erstellen. Hierzu verwenden Sie die Option --with-big-tables.

    Diese Option sorgt dafür, dass die Variablen, die die Ergebnisse der Datensatzzählungen enthalten, als unsigned long long statt als unsigned long gespeichert werden. Sie erlaubt Tabellen die Aufnahme von ca. 1,844E+19 ((232)2) Datensätzen statt 232 (ca. 4,295E+09) Datensätzen. Zuvor war es notwendig gewesen, -DBIG_TABLES manuell an den Compiler zu übergeben, um diese Funktion zu aktivieren.

  • Optionen, die spezifisch für bestimmte Betriebssysteme sind, finden Sie in den jeweiligen Abschnitten dieses Handbuchs. Siehe auch Abschnitt 2.12, „Betriebssystemspezifische Anmerkungen“.

2.8.3. Installation vom Entwicklungs-Source-Tree

Vorsicht: Sie sollten diesen Abschnitt nur lesen, wenn Sie Interesse daran haben, uns beim Testen unseres neuen Codes behilflich zu sein. Wenn Sie MySQL lediglich in funktionsfähiger Form auf Ihrem System einrichten wollen, sollten Sie einen Standard-Release (entweder als Binär- oder als Quelldistribution) verwenden.

Um unseren aktuellsten Entwicklungs-Source-Tree zu bekommen, laden Sie zunächst den kostenlosen BitKeeper-Client herunter, sofern Sie ihn noch nicht haben, und installieren ihn. Sie erhalten den Client unter http://www.bitmover.com/bk-client.shar.

Zur Installation des BitKeeper-Clients unter Unix verwenden Sie die folgenden Befehle:

shell> sh bk-client.shar
shell> cd bk_client-1.1
shell> make all
shell> PATH=$PWD:$PATH

Zur Installation des BitKeeper-Clients unter Windows gehen Sie wie folgt vor:

  1. Laden Sie Cygwin von http://cygwin.com herunter und installieren Sie es.

  2. Vergewissern Sie sich, dass gcc und make unter Cygwin installiert wurden. Sie können dies überprüfen, indem Sie die Befehle which gcc und which make absetzen. Ist eines der Programme nicht installiert, dann führen Sie den Paket-Manager von Cygwin aus, wählen gcc und/oder make und führen die Installation aus.

  3. Führen Sie dann unter Cygwin die folgenden Befehle aus:

    shell> sh bk-client.shar
    shell> cd bk_client-1.1
    

    Nachfolgend bearbeiten Sie das Makefile und ändern die Zeile $(CC) $(CFLAGS) -o sfio -lz sfio.c wie folgt:

    $(CC) $(CFLAGS) -o sfio sfio.c -lz
    

    Nun führen Sie den Befehl make aus und stellen den Pfad ein:

    shell> make all
    shell> PATH=$PWD:$PATH
    

Der kostenlose BitKeeper-Client wird mit seinem Quellcode ausgeliefert. Dieser Quellcode ist auch die einzige Dokumentation, die für den kostenlosen Client verfügbar ist.

Nachdem Sie den BitKeeper-Client installiert haben, können Sie auf den MySQL-Entwicklungs-Source-Tree zugreifen:

  1. Wechseln Sie in das Verzeichnis, das als Arbeitsverzeichnis vorgesehen ist, und erstellen Sie mit dem folgenden Befehl eine lokale Kopie des Zweigs von MySQL 5.1:

    shell> sfioball -r+ bk://mysql.bkbits.net/mysql-5.1-new mysql-5.1
    

    In obigem Beispiel wird der Source-Tree im Unterverzeichnis mysql-5.1/ Ihres aktuellen Verzeichnisses eingerichtet.

    Der erste Download des Source-Trees kann je nach Geschwindigkeit Ihrer Verbindung eine Weile dauern. Haben Sie bitte Geduld.

  2. Sie benötigen GNU make, autoconf 2.58 (oder höher), automake 1.8, libtool 1.5 und m4, um die nächste Befehlsgruppe auszuführen. Zwar werden viele Betriebssysteme mit eigener Implementierung von make ausgeliefert, aber die Wahrscheinlichkeit, dass der Kompilierungsvorgang mit merkwürdigen Fehlermeldungen abbricht, ist doch recht hoch. Aus diesem Grund wird dringend empfohlen, stattdessen GNU make (das manchmal auch als gmake bezeichnet wird) zu verwenden.

    Glücklicherweise wird eine große Anzahl von Betriebssystemen mit vorinstallierten GNU-Tools ausgeliefert oder enthält deren Installationspakete. In jedem Fall können Sie sie auch unter den folgenden Adressen herunterladen:

    Um MySQL 5.1 zu konfigurieren, benötigen Sie ferner GNU bison 1.75 oder höher. Ältere Versionen von bison zeigen unter Umständen folgenden Fehler an:

    sql_yacc.yy:#####: fatal error: maximum table size (32767) exceeded
    

    Hinweis: Die maximale Tabellengröße wurde mitnichten überschritten; vielmehr wird der Fehler von Bugs in älteren bison-Versionen ausgelöst.

    Das folgende Beispiel zeigt die typischen Befehle, die zur Konfiguration eines Source-Trees erforderlich sind. Der erste Befehl cd wechselt in das oberste Verzeichnis des Trees. Hierbei ist mysql-5.1 durch den korrekten Verzeichnisnamen zu ersetzen.

    shell> cd mysql-5.1
    shell> aclocal; autoheader
    shell> libtoolize --automake --force
    shell> automake --force --add-missing; autoconf
    shell> (cd storage/innobase; aclocal; autoheader; autoconf; automake)
    shell> (cd storage/bdb/dist; sh s_all)
    shell> ./configure  # Add your favorite options here
    shell> make
    

    Alternativ verwenden Sie BUILD/autorun.sh als Abkürzung für die folgende Befehlssequenz:

    shell> aclocal; autoheader
    shell> libtoolize --automake --force
    shell> automake --force --add-missing; autoconf
    shell> (cd storage/innobase; aclocal; autoheader; autoconf; automake)
    shell> (cd storage/bdb/dist; sh s_all)
    

    Die Befehlszeilen, die in die Verzeichnisse storage/innobase bzw. storage/bdb/dist wechseln, dienen der Konfiguration der InnoDB- und Berkeley DB(BDB)-Speicher-Engines. Sie können diese Befehlszeilen weglassen, wenn Sie Unterstützung für InnoDB bzw. BDB nicht benötigen.

    Hinweis: Ab MySQL 5.1 wird Code, der spezifisch für bestimmte Speicher-Engines ist, in ein storage-Verzeichnis verschoben. So liegt beispielsweise InnoDB-Code jetzt in storage/innobase und NDBCluster-Code in storage/ndb.

    Wenn Ihnen in dieser Phase seltsame Fehler angezeigt werden, dann vergewissern Sie sich, dass libtool wirklich installiert wurde.

    Eine Sammlung unserer Standardkonfigurationsskripten befindet sich im Unterverzeichnis BUILD/. Unter Umständen finden Sie es praktischer, statt der vorangegangenen Gruppe von Shell-Befehlen das Skript BUILD/compile-pentium-debug zu verwenden. Um auf einer anderen Architektur zu kompilieren, ändern Sie das Skript ab, indem Sie Pentium-spezifische Flags entfernen.

  3. Wenn die Erstellung abgeschlossen ist, führen Sie make install aus. Auf einem Produktionssystem sollten Sie dies allerdings mit Vorsicht tun: Es besteht die Möglichkeit, dass der Befehl die aktuelle Release-Installation überschreibt. Wenn bereits eine MySQL-Installation vorhanden ist, empfehlen wir die Ausführung von ./configure unter Zuweisung anderer als der für den Produktionsserver verwendeten Werte für die Optionen --prefix, --with-tcp-port und --unix-socket-path.

  4. Prüfen Sie Ihre neue Installation auf Herz und Nieren und versuchen Sie, die neuen Funktionen zum Absturz zu bringen. Führen Sie zunächst make test aus. Siehe auch Abschnitt 26.1.2, „MySQL-Testsystem“.

  5. Wenn Sie es bis zur make-Phase geschafft haben, aber die Distribution sich nicht kompilieren lässt, dann geben Sie das Problem in unsere Fehlerdatenbank ein. Beachten Sie hierzu die Anweisungen in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“. Haben Sie die aktuellen Versionen der erforderlichen GNU-Tools installiert und stürzen diese bei der Verarbeitung unserer Konfigurationsdateien ebenfalls ab, dann teilen Sie uns bitte auch dies mit. Wenn Sie allerdings aclocal ausführen und die Fehlermeldung command not found o. ä. erhalten, melden Sie dies bitte nicht. Überprüfen Sie stattdessen, ob alle notwendigen Tools installiert sind und Ihre Variable PATH korrekt eingestellt ist, damit Ihre Shell sie finden kann.

  6. Wenn Sie das Repository mit sfioball kopiert haben, um den Source-Tree zu erhalten, sollten Sie regelmäßig update ausführen, um Ihre lokale Kopie zu aktualisieren. Zu diesem Zweck können Sie nach der Konfiguration des Repositorys jederzeit den folgenden Befehl verwenden:

    shell> update bk://mysql.bkbits.net/mysql-5.1-new
    
  7. Sie können die Änderungshistorie des Trees mit allen Diffs überprüfen, indem Sie die Datei BK/ChangeLog im Source-Tree anzeigen und nach den dort aufgelisteten ChangeSet-Beschreibungen suchen. Um ein bestimmtes Changeset zu untersuchen, müssten Sie mit dem Befehl sfioball zwei bestimmte Revisionen des Source-Trees extrahieren und dann einen externen diff-Befehl aufrufen, um den Vergleich durchzuführen. Wenn Sie über ein paar spaßige Diffs oder über Code stolpern, zu dem Sie Fragen haben, schicken Sie einfach eine E-Mail an die MySQL-Mailingliste internals. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“. Auch wenn Sie eine gute Idee haben, wie man etwas vielleicht besser lösen könnte, schicken Sie ruhig eine E-Mail mit einem Patch an die Liste.

Changesets, Anmerkungen und Quellcode können Sie auch online durchsuchen. Um die entsprechenden Informationen für MySQL 5.1 anzuzeigen, besuchen Sie http://mysql.bkbits.net:8080/mysql-5.1.

2.8.4. Probleme beim Kompilieren?

Alle MySQL-Programme lassen sich bei uns mit gcc sauber und ohne Warnungen unter Solaris oder Linux kompilieren. Auf anderen Systemen werden aufgrund von Unterschieden in den systemspezifischen Include-Dateien unter Umständen Warnungen angezeigt. Informationen dazu, welche Warnungen bei der Verwendung von MIT-pthreads angezeigt werden können, finden Sie in Abschnitt 2.8.5, „Anmerkungen zu MIT-pthreads“. Informationen zu anderen Problemen entnehmen Sie der folgenden Liste.

Die Lösung zahlreicher Probleme erfordert eine Umkonfiguration. Wenn Sie eine Umkonfiguration durchführen müssen, beachten Sie bitte die folgenden Hinweise:

  • Wird configure nach einem vorherigen Aufruf erneut ausgeführt, dann werden unter Umständen Daten zugrunde gelegt, die während des vorherigen Aufrufs ermittelt worden waren. Diese Informationen sind in der Datei config.cache abgelegt. Nach dem Start prüft configure auf das Vorhandensein dieser Datei und liest ihren Inhalt ggf. aus – davon ausgehend, dass die Daten nach wie vor korrekt sind. Dies ist allerdings bei einer Umkonfigurierung nicht mehr der Fall.

  • Jedes Mal, wenn Sie configure ausführen, müssen Sie zur Neukompilierung auch make erneut ausführen. Allerdings sollten Sie alte Objektdateien aus vorherigen Builds entfernen, da diese mit abweichenden Konfigurationsoptionen erstellt wurden.

Um die Verwendung veralteter Konfigurationsdaten oder Objektdateien zu verhindern, führen Sie die folgenden Befehle aus, bevor Sie configure erneut aufrufen:

shell> rm config.cache
shell> make clean

Alternativ können Sie auch make distclean ausführen.

Die folgende Liste enthält die bei der Kompilierung von MySQL am häufigsten auftretenden Probleme:

  • Wenn Sie bei der Kompilierung von sql_yacc.cc Fehler wie die hier aufgeführten erhalten, ist offensichtlich nicht genug Arbeits- oder Auslagerungsspeicher vorhanden.

    Internal compiler error: program cc1plus got fatal signal 11
    Out of virtual memory
    Virtual memory exhausted
    

    Das Problem besteht darin, dass gcc zur Kompilierung von sql_yacc.cc mit Inline-Funktionen eine gewaltige Menge Speicher benötigt. Versuchen Sie in diesem Fall, configure mit der Option --with-low-memory auszuführen:

    shell> ./configure --with-low-memory
    

    Diese Option ergänzt die Kompilierungszeile um den Eintrag -fno-inline, wenn Sie gcc verwenden, bzw. um -O0 bei Verwendung eines anderen Tools. Sie sollten die Option --with-low-memory auch dann verwenden, wenn Sie der Ansicht sind, dass so viel Arbeits- und Auslagerungsspeicher vorhanden ist, dass ein Speichermangel nicht wahrscheinlich ist. Dieses Problem wurde sogar schon auf Systemen mit wirklich großzügigen Hardwarekonfigurationen beobachtet und konnte stets mit der Option --with-low-memory behoben werden.

  • Standardmäßig wählt configure c++ als Compiler-Namen aus, und GNU c++ verknüpft sich mit -lg++. Wenn Sie gcc verwenden, dann kann dieses Verhalten während der Konfiguration zu Problemen wie dem folgenden führen:

    configure: error: installation or configuration problem:
    C++ compiler cannot create executables.
    

    Ferner könnten Sie während der Kompilierung Probleme in Bezug auf g++, libg++ oder libstdc++ beobachten.

    Eine Ursache dieser Probleme besteht darin, dass Sie g++ entweder nicht haben oder dass Sie g++, nicht jedoch libg++ oder libstdc++ haben. Werfen Sie einen Blick in die Datei config.log. Sie sollten den Grund dafür, dass Ihr C++-Compiler nicht funktioniert, exakt angeben. Um derartige Probleme zu vermeiden, können Sie gcc als C++-Compiler verwenden. Setzen Sie die Umgebungsvariable CXX versuchsweise auf "gcc -O3". Ein Beispiel:

    shell> CXX="gcc -O3" ./configure
    

    Dies funktioniert, weil gcc C++-Quelldateien ebenso kompiliert, wie es g++ tut, jedoch standardmäßig keine Verknüpfung mit libg++ oder libstdc++ herstellt.

    Eine andere Möglichkeit, diese Probleme zu beheben, besteht in der Installation von g++, libg++ und libstdc++. Allerdings raten wir von der Verwendung von libg++ oder libstdc++ mit MySQL ab, da hierdurch nur die mysqld-Binärdatei vergrößert wird – Vorteile ergeben sich ansonsten keine. In Verbindung mit einigen Versionen dieser Bibliotheken sind bei MySQL-Benutzern in der Vergangenheit nicht nachvollziehbare Probleme aufgetreten.

  • Bricht Ihre Kompilierung mit Fehlern wie dem folgenden ab, dann müssen Sie Ihre make-Version auf GNU make aktualisieren:

    making all in mit-pthreads
    make: Fatal error in reader: Makefile, line 18:
    Badly formed macro assignment
    

    Oder:

    make: file `Makefile' line 18: Must be a separator (:
    

    Oder:

    pthread.h: No such file or directory
    

    Es ist bekannt, dass Solaris und FreeBSD problematische make-Programme umfassen.

    GNU make 3.75 funktioniert erfahrungsgemäß.

  • Wenn Sie Flags für die Verwendung durch Ihre C- oder C++-Compiler definieren wollen, sollten Sie dies tun, indem Sie die Flags den Umgebungsvariablen CFLAGS und CXXFLAGS hinzufügen. Sie können auf diese Weise auch die Compiler-Namen über CC und CXX angeben. Ein Beispiel:

    shell> CC=gcc
    shell> CFLAGS=-O3
    shell> CXX=gcc
    shell> CXXFLAGS=-O3
    shell> export CC CFLAGS CXX CXXFLAGS
    

    In Abschnitt 2.1.2.5, „MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden“, finden Sie eine Liste der Flag-Definitionen, die sich bei verschiedenen Systemen als nützlich erwiesen haben.

  • Wenn Sie bei der Kompilierung von mysqld Fehlermeldungen wie die nachfolgend gezeigte erhalten, hat configure den Typ des letzten Arguments von accept(), getsockname() oder getpeername() nicht korrekt erkannt:

    cxx: Error: mysqld.cc, line 645: In this statement, the referenced
         type of the pointer value ''length'' is ''unsigned long'',
         which is not compatible with ''int''.
    new_sock = accept(sock, (struct sockaddr *)&cAddr, &length);
    

    Um dieses Problem zu beheben, bearbeiten Sie die Datei config.h (diese wird durch configure erzeugt). Suchen Sie dort nach den folgenden Zeilen:

    /* Define as the base type of the last arg to accept */
    #define SOCKET_SIZE_TYPE XXX
    

    Setzen Sie XXX je nach Betriebssystem auf size_t oder int. (Sie müssen dies bei jeder Ausführung von configure tun, da configure config.h immer neu erstellt.)

  • Die Datei sql_yacc.cc wird aus sql_yacc.yy erstellt. Normalerweise muss bei der Erstellung keine Datei sql_yacc.cc erzeugt werden, da MySQL bereits eine vorab generierte Kopie enthält. Sofern Sie sie aber trotzdem neu erstellen müssen, könnte unter Umständen folgende Fehlermeldung angezeigt werden:

    "sql_yacc.yy", line xxx fatal: default action causes potential ...
    

    Dies weist darauf hin, dass Ihre Version von yacc fehlerhaft ist. Sie müssen stattdessen wahrscheinlich bison (die GNU-Variante von yacc) installieren und verwenden.

  • Unter Debian Linux 3.0 müssen Sie gawk anstelle des standardmäßigen mawk installieren, wenn Sie MySQL mit Berkeley DB-Unterstützung kompilieren wollen.

  • Wenn Sie mysqld oder einen MySQL-Client debuggen müssen, führen Sie configure mit der Option --with-debug aus. Kompilieren Sie Ihre Clients dann neu und verknüpfen Sie sie mit der neuen Clientbibliothek. Siehe auch Abschnitt E.2, „Einen MySQL-Client debuggen“.

  • Unter Umständen erhalten Sie unter Linux (z. B. bei SuSE Linux 8.1 oder Red Hat Linux 7.3) einen Kompilierungsfehler ähnlich dem folgenden:

    libmysql.c:1329: warning: passing arg 5 of `gethostbyname_r' from
    incompatible pointer type
    libmysql.c:1329: too few arguments to function `gethostbyname_r'
    libmysql.c:1329: warning: assignment makes pointer from integer
    without a cast
    make[2]: *** [libmysql.lo] Error 1
    

    Standardmäßig versucht das configure-Skript, die korrekte Anzahl der Argumente mithilfe des GNU C++-Compilers g++ zu ermitteln. Dieser Test führt zu falschen Ergebnissen, wenn g++ nicht installiert ist. Es gibt zwei Möglichkeiten, dieses Problem zu umgehen:

    • Stellen Sie sicher, dass der GNU-C++-Compiler g++ installiert ist. Bei manchen Linux-Distributionen heißt das erforderliche Paket gpp, bei anderen gcc-c++.

    • Verwenden Sie gcc als C++-Compiler, indem Sie die Umgebungsvariable CXX auf gcc setzen:

      export CXX="gcc"
      

    Welche Änderungen Sie auch immer durchgeführt haben, nachfolgend müssen Sie configure erneut ausführen.

2.8.5. Anmerkungen zu MIT-pthreads

In diesem Abschnitt werden einige Probleme in Zusammenhang mit MIT-pthreads angesprochen.

Unter Linux sollten Sie MIT-pthreads nicht verwenden. Benutzen Sie stattdessen die installierte LinuxThreads-Implementierung. Siehe auch Abschnitt 2.12.1, „Linux (alle Linux-Versionen)“.

Wenn Ihr System keine native Thread-Unterstützung bietet, sollten Sie MySQL mithilfe des MIT-pthreads-Pakets erstellen. Dies gilt für ältere FreeBSD-Systeme, SunOS 4.x, Solaris 2.4 und früher sowie einige andere. Siehe auch Abschnitt 2.1.1, „Betriebssysteme, die von MySQL unterstützt werden“.

MIT-pthreads ist nicht in der Quelldistribution von MySQL 5.1 enthalten. Wenn Sie dieses Paket benötigen, müssen Sie es unter http://dev.mysql.com/Downloads/Contrib/pthreads-1_60_beta6-mysql.tar.gz separat herunterladen.

Extrahieren Sie das Quellarchiv nach dem Download in das oberste MySQL-Quellverzeichnis. Hierdurch wird ein neues Unterverzeichnis namens mit-pthreads erstellt.

  • Auf den meisten Systemen können Sie die Verwendung von MIT-pthreads erzwingen, indem Sie configure mit der Option --with-mit-threads ausführen:

    shell> ./configure --with-mit-threads
    

    Die Erstellung eines Nichtquellverzeichnisses wird bei der Verwendung von MIT-pthreads nicht unterstützt, da wir unsere Änderungen an diesem Code minimieren wollen.

  • Die Tests, mit denen ermittelt wird, ob MIT-pthreads verwendet werden soll, finden nur während derjenigen Phase des Konfigurationsvorgangs statt, in der der Servercode bearbeitet wird. Haben Sie die Distribution mit der Option --without-server konfiguriert, um nur den Clientcode zu erstellen, dann wissen die Clients nicht, ob MIT-pthreads verwendet wird oder nicht; deswegen verwenden sie standardmäßig die Unix-Socketdatei. Da Unix-Socketdateien jedoch auf bestimmten Plattformen unter MIT-pthreads nicht funktionieren, bedeutet dies, dass Sie -h oder --host mit einem anderen Wert als localhost verwenden müssen, wenn Sie Clientprogramme ausführen.

  • Wird MySQL mit MIT-pthreads kompiliert, dann wird die Systemsperrung zum Zweck der Leistungsoptimierung standardmäßig deaktiviert. Mit der Option --external-locking können Sie den Server anweisen, die Systemsperre zu verwenden. Dies ist aber nur erforderlich, wenn Sie zwei MySQL Server ausführen, die auf die gleichen Datendateien zugreifen (hiervon sei aber ohnehin abgeraten).

  • Manchmal schlägt beim pthread-Befehl bind() der Versuch fehl, eine Bindung an den Server vorzunehmen – und dies, ohne dass (zumindest bei Solaris) eine Fehlermeldung erzeugt wird. Nachfolgend schlagen alle Verbindungen zu diesem Server fehl. Ein Beispiel:

    shell> mysqladmin version
    mysqladmin: connect to server at '' failed;
    error: 'Can't connect to mysql server on localhost (146)'
    

    Die Lösung dieses Problems besteht in Terminierung und Neustart des Servers mysqld. Dies ist bei uns nur aufgetreten, wenn wir den Server zwangsweise beendet und unmittelbar darauf neu gestartet haben.

  • Bei MIT-pthreads ist der Systemaufruf sleep() nicht durch SIGINT (Pause) zu unterbrechen. Dies macht sich nur bemerkbar, wenn Sie mysqladmin --sleep ausführen. Sie müssen warten, bis der Aufruf sleep() abgeschlossen ist, bevor der Interrupt bedient und der Prozess angehalten wird.

  • Beim Verknüpfen erhalten Sie (wiederum zumindest unter Solaris) unter Umständen Warnmeldungen wie die folgende, die Sie aber getrost ignorieren können:

    ld: warning: symbol `_iob' has differing sizes:
        (file /my/local/pthreads/lib/libpthread.a(findfp.o) value=0x4;
    file /usr/lib/libc.so value=0x140);
        /my/local/pthreads/lib/libpthread.a(findfp.o) definition taken
    ld: warning: symbol `__iob' has differing sizes:
        (file /my/local/pthreads/lib/libpthread.a(findfp.o) value=0x4;
    file /usr/lib/libc.so value=0x140);
        /my/local/pthreads/lib/libpthread.a(findfp.o) definition taken
    
  • Bestimmte andere Warnungen können ebenfalls ignoriert werden:

    implicit declaration of function `int strtoll(...)'
    implicit declaration of function `int strtoul(...)'
    
  • Wir haben es nicht geschafft, die Verwendung von readline mit MIT-pthreads zu ermöglichen. (Das ist zwar auch nicht notwendig, mag für manchen aber von Interesse sein.)

2.8.6. Windows-Quelldistribution

Diese Anweisungen beschreiben, wie man unter Windows Binärdateien aus dem Quellcode von MySQL 5.1 erstellt. Die Anweisungen beziehen sich auf die Erstellung von Binärdateien aus einer Standardquelldistribution oder aus dem BitKeeper-Tree, der den aktuellen Entwicklungsquellcode enthält.

Hinweis: Die Angaben in diesem Abschnitt sind ausschließlich für Benutzer vorgesehen, die ein der aktuellen Quelldistribution oder dem BitKeeper-Tree entstammendes MySQL unter Windows testen wollen. Von der Verwendung eines aus dem Quellcode selbsterstellten MySQL Servers in Produktionsumgebungen rät MySQL AB ausdrücklich ab. In der Regel ist es am besten, vorkompilierte MySQL-Binärdistributionen zu verwenden, die von MySQL AB gezielt für optimale Leistung unter Windows erstellt wurden. Anweisungen zur Installation einer Binärdistribution finden Sie in Abschnitt 2.3, „Installation von MySQL unter Windows“.

Um MySQL unter Windows aus dem Quellcode zu erstellen, benötigen Sie die folgenden Compiler und Ressourcen auf Ihrem Windows-System:

  • Visual Studio 2003-Compilersystem (VC++ 7.0)

  • Zwischen 3 und 5 Gbyte Festplattenspeicher

  • Windows 2000 oder höher

Die exakten Systemvoraussetzungen finden Sie hier: http://msdn.microsoft.com/vstudio/productinfo/sysreqs/default.aspx

Außerdem brauchen Sie eine MySQL-Quelldistribution für Windows. Es gibt zwei Möglichkeiten, eine Quelldistribution zu erhalten:

  1. Besorgen Sie sich eine von MySQL AB gepackte Quelldistribution. Diese finden Sie unter http://dev.mysql.com/downloads/.

  2. Sie können sich auch selbst eine Quelldistribution aus dem aktuellen BitKeeper-Entwicklungs-Source-Tree packen. In diesem Fall müssen Sie das Paket auf einem Unix-System erstellen und dann auf Ihr Windows-System übertragen. (Das liegt daran, dass einige Konfigurations- und Erstellungsschritte Tools erfordern, die nur unter Unix funktionieren.) Insofern benötigen Sie für die BitKeeper-Variante Folgendes:

Wenn Sie eine Windows-Quelldistribution verwenden, können Sie direkt bei Abschnitt 2.8.6.1, „Bauen von MySQL mit VC++“, fortfahren. Um die Distribution aus dem BitKeeper-Tree zu erstellen, fahren Sie fort bei Abschnitt 2.8.6.2, „Erzeugen eines Windows-Quellpakets aus dem neusten Entwicklungsbaum“.

Wenn Sie feststellen, dass etwas nicht erwartungsgemäß funktioniert, oder Vorschläge zur Verbesserung des derzeitigen Erstellungsvorgangs unter Windows haben, senden Sie bitte eine Mitteilung an die Mailingliste win32. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

2.8.6.1. Bauen von MySQL mit VC++

Hinweis: VC++-Arbeitsbereichsdateien für MySQL 4.1 und höher sind kompatibel mit den Microsoft Visual Studio 2003-Editionen und wurden von MySQL AB-Mitarbeitern vor der Freigabe getestet.

Gehen Sie wie folgt vor, um MySQL zu erstellen:

  1. Erstellen Sie ein Arbeitsverzeichnis (z. B. C:\workdir).

  2. Entpacken Sie die Quelldistribution mit WinZip oder einem anderen Windows-Tool, das .zip-Dateien lesen kann, in das gerade erstellte Verzeichnis.

  3. Starten Sie Visual Studio.

  4. Wählen Sie im Menü Datei den Eintrag Arbeitsbereich öffnen.

  5. Öffnen Sie den Arbeitsbereich mysql.dsw, den Sie im Arbeitsverzeichnis finden.

  6. Wählen Sie im Menü Erstellen den Eintrag Aktive Konfiguration festlegen.

  7. Klicken Sie auf der anderen Seite des Bildschirms auf mysqld - Win32 Debug und dann auf die Schaltfläche OK.

  8. Betätigen Sie F7, um die Erstellung des Debugservers, der Bibliotheken und einiger Clientanwendungen zu starten.

  9. Kompilieren Sie die Release-Version auf gleiche Weise.

  10. Debugversionen der Programme und Bibliotheken befinden sich in den Verzeichnissen client_debug und lib_debug. Release-Versionen der Programme und Bibliotheken befinden sich in den Verzeichnissen client_release und lib_release. Beachten Sie, dass Sie, wenn Sie sowohl Debug- als auch Release-Versionen erstellen wollen, die Option Alles erstellen im Menü Erstellen auswählen können.

  11. Testen Sie den Server. Der Server, den Sie gerade erstellt haben, erwartet die Standardwerte für das MySQL-Basisverzeichnis und das Datenverzeichnis (C:\mysql bzw. C:\mysql\data). Wenn Sie Ihren Server unter Verwendung des Source-Tree-Stammverzeichnisses und -Datenverzeichnisses als Stamm- bzw. Datenverzeichnis testen wollen, müssen Sie dem Server die entsprechenden Pfadnamen mitteilen. Sie können dies entweder über die Befehlszeile mit den Optionen --basedir und --datadir tun, oder indem Sie die entsprechenden Optionen in einer Optionsdatei ablegen. (Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.) Wenn Sie ein anderes, bereits an anderer Stelle vorhandenes Datenverzeichnis verwenden sollen, können Sie stattdessen auch diesen Pfadnamen angeben.

  12. Starten Sie Ihren Server aus dem Verzeichnis client_release oder client_debug (dies hängt vom zu verwendenden Server ab). Die allgemeinen Anweisungen zum Starten des Servers finden Sie in Abschnitt 2.3, „Installation von MySQL unter Windows“. Sie müssen die Anweisung entsprechend anpassen, wenn Sie ein anderes Basis- oder Datenverzeichnis verwenden wollen.

  13. Wenn der Server je nach Ihrer Konfiguration als Anwendung oder Dienst ausgeführt wird, versuchen Sie, mit ihm über das interaktive Befehlszeilen-Hilfsprogramm mysql eine Verbindung herzustellen. Sie finden es in Ihrem Verzeichnis client_release oder client_debug.

Wenn Sie zu der Ansicht gekommen sind, dass die von Ihnen erstellten Programme korrekt laufen, beenden Sie den Server. Installieren Sie nun wie folgt MySQL:

  1. Erstellen Sie die Verzeichnisse, in die Sie MySQL installieren wollen. Um etwa MySQL im Verzeichnis C:\mysql zu installieren, verwenden Sie die folgenden Befehle:

    C:\> mkdir C:\mysql
    C:\> mkdir C:\mysql\bin
    C:\> mkdir C:\mysql\data
    C:\> mkdir C:\mysql\share
    C:\> mkdir C:\mysql\scripts
    

    Wenn Sie andere Clients kompilieren und diese mit MySQL verknüpfen wollen, sollten Sie mehrere zusätzliche Verzeichnisse erstellen:

    C:\> mkdir C:\mysql\include
    C:\> mkdir C:\mysql\lib
    C:\> mkdir C:\mysql\lib\debug
    C:\> mkdir C:\mysql\lib\opt
    

    Wenn Sie Benchmarks für MySQL erstellen wollen, legen Sie das folgende Verzeichnis an:

    C:\> mkdir C:\mysql\sql-bench
    

    Für Benchmark-Tests benötigen Sie die Perl-Unterstützung. Siehe auch Abschnitt 2.13, „Anmerkungen zur Perl-Installation“.

  2. Kopieren Sie die folgenden Verzeichnisse aus dem Verzeichnis workdir in das Verzeichnis C:\mysql:

    C:\> cd \workdir
    C:\workdir> copy client_release\*.exe C:\mysql\bin
    C:\workdir> copy client_debug\mysqld.exe C:\mysql\bin\mysqld-debug.exe
    C:\workdir> xcopy scripts\*.* C:\mysql\scripts /E
    C:\workdir> xcopy share\*.* C:\mysql\share /E
    

    Wenn Sie andere Clients kompilieren und diese mit MySQL verknüpfen wollen, sollten Sie außerdem verschiedene Bibliotheken und Header-Dateien erstellen:

    C:\workdir> copy lib_debug\mysqlclient.lib C:\mysql\lib\debug
    C:\workdir> copy lib_debug\libmysql.* C:\mysql\lib\debug
    C:\workdir> copy lib_debug\zlib.* C:\mysql\lib\debug
    C:\workdir> copy lib_release\mysqlclient.lib C:\mysql\lib\opt
    C:\workdir> copy lib_release\libmysql.* C:\mysql\lib\opt
    C:\workdir> copy lib_release\zlib.* C:\mysql\lib\opt
    C:\workdir> copy include\*.h C:\mysql\include
    C:\workdir> copy libmysql\libmysql.def C:\mysql\include
    

    Wenn Sie Benchmarks für MySQL erstellen wollen, sollten Sie auch Folgendes tun:

    C:\workdir> xcopy sql-bench\*.* C:\mysql\bench /E
    

Konfigurieren und starten Sie den Server auf die gleiche Weise wie bei einer Windows-Distribution. Siehe auch Abschnitt 2.3, „Installation von MySQL unter Windows“.

2.8.6.2. Erzeugen eines Windows-Quellpakets aus dem neusten Entwicklungsbaum

Um ein Windows-Quellcodepaket aus dem BitKeeper-Source-Tree zu erstellen, verwenden Sie die nachfolgenden Anweisungen. Dieser Vorgang muss auf einem System unter Unix oder einem Unix-Derivat durchgeführt werden, da einige der Konfigurations- und Erstellungsschritte das Vorhandensein von Tools voraussetzen, die nur unter Unix laufen. Die folgende Vorgehensweise funktioniert etwa unter Linux einwandfrei.

  1. Kopieren Sie den BitKeeper-Source-Tree für MySQL 5.1. Hinweise hierzu finden Sie in Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“.

  2. Konfigurieren und erstellen Sie die Distribution, um eine Serverbinärdatei zu erhalten, mit der Sie arbeiten können. Eine Möglichkeit hierzu besteht im Ausführen des folgenden Befehls im obersten Verzeichnis Ihres Source-Trees:

    shell> ./BUILD/compile-pentium-max
    
  3. Wenn Sie sich davon überzeugt haben, dass der Erstellungsprozess erfolgreich abgeschlossen wurde, führen Sie das folgende Hilfsskript im obersten Verzeichnis Ihres Source-Trees aus:

    shell> ./scripts/make_win_src_distribution
    

    Das Skript erstellt ein Windows-Quellpaket zur Verwendung auf Ihrem Windows-System. Sie können je nach Bedarf unterschiedliche Optionen für das Skript angeben. Die folgenden Optionen werden akzeptiert:

    • --help

      Zeigt eine Hilfemeldung an.

    • --debug

      Druckt Informationen zu Skriptoperationen (das Paket wird nicht erstellt).

    • --tmp

      Gibt das Temporärverzeichnis an.

    • --suffix

      Suffixname des Pakets.

    • --dirname

      Name des Verzeichnisses, in das die Dateien temporär kopiert werden.

    • --silent

      Die Liste der verarbeiteten Dateien wird nicht ausgegeben.

    • --tar

      Erstellt ein tar.gz- statt eines .zip-Pakets.

    Standardmäßig legt make_win_src_distribution ein Archiv im ZIP-Format mit dem Namen mysql-VERSION-win-src.zip an. Hierbei steht VERSION für die Version Ihres MySQL-Source-Trees.

  4. Kopieren Sie das soeben erstellte Windows-Quellpaket auf Ihren Windows-Computer bzw. laden Sie es hoch. Verwenden Sie zur Kompilierung die Anweisungen in Abschnitt 2.8.6.1, „Bauen von MySQL mit VC++“.

2.8.7. MySQL-Clients auf Windows kompilieren

In Ihren Quelldateien sollten Sie my_global.h vor mysql.h einsetzen:

#include <my_global.h>
#include <mysql.h>

my_global.h enthält alle Dateien, die für die Windows-Kompatibilität erforderlich sind (z. B. windows.h), wenn Sie Ihr Programm unter Windows kompilieren.

Sie können Ihren Code entweder mit der dynamischen Bibliothek libmysql.lib, die nichts anderes als ein Wrapper zum Einladen bei Bedarf in libmysql.dll ist, oder mit der statischen Bibliothek mysqlclient.lib verknüpfen.

Die MySQL-Clientbibliotheken werden als Bibliotheken mit Threads kompiliert, d. h., Sie sollten Ihren Code mit Multithread-Unterstützung kompilieren.

2.9. Einstellungen und Tests nach der Installation

Nach der Installation von MySQL gibt es einige Aspekte, die beachtet werden sollten. So sollten Sie etwa unter Unix das Datenverzeichnis initialisieren und die MySQL-Grant-Tabellen erstellen. Bei allen Plattformen besteht ein erhebliches Sicherheitsrisiko darin, dass die bei der Installation in den Grant-Tabellen eingerichteten Konten keine Passwörter aufweisen. Sie sollten Passwörter zuweisen, um unautorisierten Zugriff auf den MySQL Server zu verhindern. Optional können Sie Zeitzonentabellen erstellen, um die Erkennung benannter Zeitzonen zu ermöglichen.

Die folgenden Abschnitte erhalten Angaben zu Maßnahmen nach Abschluss der Installation, die speziell auf Windows- bzw. Unix-Systeme zugeschnitten sind. In Abschnitt 2.9.2.3, „Probleme mit dem Start des MySQL Servers“, finden Sie zudem Informationen, die für alle Plattformen gelten. Dort wird beschrieben, was Sie tun können, wenn Sie Probleme mit dem Starten des Servers haben. Auch Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“, betrifft alle Plattformen. Sie sollten den Anweisungen folgen, um zu gewährleisten, dass Ihre MySQL-Konten durch Konfiguration von Passwörtern angemessen geschützt sind.

Wenn Sie so weit sind, dass Sie weitere Benutzerkonten erstellen wollen oder müssen, finden Sie Informationen zum MySQL-Zugriffssteuerungssystem und zur Kontenverwaltung in Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“, und Abschnitt 5.9, „MySQL-Benutzerkontenverwaltung“.

2.9.1. Nach der Installation unter Windows durchzuführende Schritte

Unter Windows müssen Datenverzeichnis und Grant-Tabellen nicht erstellt werden. Windows-Distributionen von MySQL enthalten bereits Grant-Tabellen mit vorinitialisierten Konten in der mysql-Datenbank im Datenverzeichnis. Insofern ist es nicht notwendig, das Skript mysql_install_db auszuführen, das unter Unix obligatorisch ist. Was Passwörter betrifft, so haben Sie diese unter Umständen bereits für die Konten vergeben, sofern Sie MySQL mit dem Windows-Installations-Assistenten installiert haben. (Siehe auch Abschnitt 2.3.4, „Verwendung des MySQL-Installations-Assistenten“.) Andernfalls müssen Sie die in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“, beschriebene Vorgehensweise zur Vergabe von Passwörtern befolgen.

Bevor Sie Passwörter konfigurieren, sollten Sie einige Clientprogramme ausführen, um sicherzustellen, dass sich Serververbindungen herstellen lassen und einwandfrei arbeiten. Vergewissern Sie sich, dass der Server läuft (siehe Abschnitt 2.3.10, „Erstmaliges Starten des Servers“), und geben Sie dann die folgenden Befehle ein, um nachzuprüfen, ob Sie Daten vom Server abrufen können. Die Ausgabe sollte ähnlich wie nachfolgend aufgeführt aussehen:

C:\> C:\mysql\bin\mysqlshow
+-----------+
| Databases |
+-----------+
| mysql     |
| test      |
+-----------+

C:\> C:\mysql\bin\mysqlshow mysql
Database: mysql
+---------------------------+
|          Tables           |
+---------------------------+
| columns_priv              |
| db                        |
| func                      |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| host                      |
| proc                      |
| procs_priv                |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+

C:\> C:\mysql\bin\mysql -e "SELECT Host,Db,User FROM db" mysql
+------+-------+------+
| host | db    | user |
+------+-------+------+
| %    | test% |      |
+------+-------+------+

Wenn Sie eine Windows-Version verwenden, die Dienste unterstützt, und Sie wollen, dass der MySQL Server beim Start von Windows automatisch gestartet wird, finden Sie Informationen in Abschnitt 2.3.12, „Starten von MySQL als Windows-Dienst“.

2.9.2. Schritte nach der Installation unter Unix

Nachdem Sie MySQL unter Unix installiert haben, müssen Sie die Grant-Tabellen initialisieren, den Server starten und sicherstellen, dass dieser korrekt arbeitet. Ferner sollten Sie das automatische Starten und Beenden des Servers beim Starten bzw. Herunterfahren des Systems konfigurieren. Zudem sind Passwörter für die Konten in den Grant-Tabellen zu erstellen.

Unter Unix werden die Grant-Tabellen durch das Programm mysql_install_db eingerichtet. Bei einigen Installationsmethoden wird dieses Programm für Sie automatisch ausgeführt:

  • Wenn Sie MySQL unter Linux mithilfe von RPM-Distributionen installieren, startet das Server-RPM mysql_install_db.

  • Wenn Sie MySQL unter Mac OS X mithilfe einer PKG-Distribution installieren, startet das Installationsprogramm mysql_install_db.

In allen anderen Fällen müssen Sie mysql_install_db selbst ausführen.

Die nachfolgende Vorgehensweise beschreibt, wie man die Grant-Tabellen initialisiert (soweit dies noch nicht geschehen ist) und dann den Server startet. Ferner werden einige Befehle vorgeschlagen, mit denen Sie testen können, ob der Server zugänglich ist und korrekt arbeitet. Informationen zum automatischen Starten und Beenden des Servers finden Sie in Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.

Wenn Sie den Vorgang abgeschlossen haben und der Server läuft, sollten Sie für die von mysql_install_db erstellten Konten Passwörter erstellen. Eine Anleitung hierzu finden Sie in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“.

In den nachfolgenden Beispielen läuft der Server unter der Benutzer-ID des Anmeldekontos mysql. Dies setzt natürlich voraus, dass dieses Konto auch existiert. Ist dies nicht der Fall, dann müssen Sie das Konto entweder erstellen oder den Namen eines anderen vorhandenen Anmeldekontos ersetzen, das Sie für die Ausführung des Servers verwenden wollen.

  1. Wechseln Sie in das oberste Verzeichnis Ihrer MySQL-Installation (dieses wird hier als BASEDIR dargestellt):

    shell> cd BASEDIR
    

    BASEDIR ist dabei so etwas wie /usr/local/mysql oder /usr/local. Die folgenden Schritte setzen voraus, dass Sie in dieses Verzeichnis gewechselt sind.

  2. Sofern notwendig, führen Sie mysql_install_db aus, um die vorgabeseitigen MySQL-Grant-Tabellen mit den Berechtigungen einzurichten, die bestimmen, wie Benutzer mit dem Server Verbindungen herstellen können. Sie müssen das tun, wenn Sie einen Distributionstyp verwendet haben, bei dessen Installation das Programm nicht automatisch ausgeführt wird.

    Normalerweise muss mysql_install_db nur bei der Erstinstallation von MySQL ausgeführt werden; Sie können diesen Schritt also überspringen, wenn Sie eine vorhandene Installation aktualisieren. Allerdings überschreibt mysql_install_db keine vorhandenen Berechtigungstabellen, kann also in allen Situationen problemlos ausgeführt werden.

    Um die Grant-Tabellen zu initialisieren, verwenden Sie einen der folgenden Befehle (je nachdem, ob sich mysql_install_db im Verzeichnis bin oder scripts befindet):

    shell> bin/mysql_install_db --user=mysql
    shell> scripts/mysql_install_db --user=mysql
    

    Das Skript mysql_install_db erstellt das Datenverzeichnis des Servers. In diesem Datenverzeichnis werden Verzeichnisse für die mysql-Datenbank, die alle Datenbankberechtigungen enthält, und die test-Datenbank erstellt, die Sie zum Testen von MySQL verwenden können. Das Skript erstellt außerdem Einträge für root-Konten und Konten für anonyme Benutzer in den Berechtigungstabellen. Diese Konten haben anfangs kein Passwort. Eine Beschreibung ihrer Ausgangsberechtigungen finden Sie in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“. Kurz gesagt, ermöglichen diese Berechtigungen dem MySQL-root-Benutzer alles und erlauben jedem Benutzer zudem die Erstellung und Verwendung von Datenbanken mit dem Namen test oder einem Namen, der mit test_ beginnt.

    Es ist wichtig sicherzustellen, dass die Datenbankverzeichnisse und -dateien im Besitz des Kontos mysql sind, damit der Server bei der späteren Ausführung Lese- und Schreibzugriff darauf hat. Um dies zu gewährleisten, sollte die Option --user wie nachfolgend gezeigt verwendet werden, wenn Sie mysql_install_db als root ausführen. Andernfalls sollten Sie das Skript ausführen, während Sie als mysql angemeldet sind; in diesem Fall können Sie die Option --user in dem Befehl weglassen.

    mysql_install_db erstellt eine Reihe von Tabellen in der mysql-Datenbank, darunter u. a. user, db, host, tables_priv, columns_priv und func. Eine vollständige Auflistung und Beschreibung dieser Tabellen finden Sie in Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“.

    Wenn Sie die test-Datenbank nicht brauchen, können Sie sie nach dem Starten des Servers mit dem Befehl mysqladmin -u root drop test entfernen.

    Sollten Sie an dieser Stelle Probleme mit mysql_install_db haben, dann finden Sie weitere Informationen in Abschnitt 2.9.2.1, „Probleme mit mysql_install_db.

  3. Starten Sie den MySQL Server:

    shell> bin/mysqld_safe --user=mysql &
    

    Es ist wichtig, dass der MySQL Server über ein berechtigungsloses Anmeldekonto (d. h. kein root-Konto) ausgeführt wird. Um dies zu gewährleisten, sollte die Option --user wie nachfolgend gezeigt verwendet werden, wenn Sie mysql_safe als root ausführen. Andernfalls sollten Sie das Skript ausführen, während Sie als mysql am System angemeldet sind; in diesem Fall können Sie die Option --user in dem Befehl weglassen.

    Weitere Anweisungen zur Ausführung von MySQL als berechtigungsloser Benutzer finden Sie in Abschnitt 5.7.5, „Wie man MySQL als normaler Benutzer laufen läßt“.

    Wenn Sie vor Durchführung dieses Schritts vergessen haben, die Grant-Tabellen zu erstellen, dann erscheint die folgende Meldung im Fehlerlog, wenn Sie den Server starten:

    mysqld: Can't find file: 'host.frm'
    

    Bei Auftreten anderer Probleme während des Serverstarts finden Sie Informationen in Abschnitt 2.9.2.3, „Probleme mit dem Start des MySQL Servers“.

  4. Stellen Sie mit mysqladmin sicher, dass der Server ausgeführt wird. Die folgenden Befehle ermöglichen einfache Tests, um zu prüfen, ob der Server aktiv ist und auf Verbindungen reagiert:

    shell> bin/mysqladmin version
    shell> bin/mysqladmin variables
    

    Die Ausgabe von mysqladmin version kann je nach Plattform und MySQL-Version variieren, sollte aber der nachfolgend abgebildeten ähneln:

    shell> bin/mysqladmin version
    mysqladmin  Ver 14.12 Distrib 5.1.5-alpha, for pc-linux-gnu on i686
    Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
    This software comes with ABSOLUTELY NO WARRANTY. This is free software,
    and you are welcome to modify and redistribute it under the GPL license
    
    Server version          5.1.5-alpha-Max
    Protocol version        10
    Connection              Localhost via UNIX socket
    UNIX socket             /var/lib/mysql/mysql.sock
    Uptime:                 14 days 5 hours 5 min 21 sec
    
    Threads: 1  Questions: 366  Slow queries: 0  
    Opens: 0  Flush tables: 1  Open tables: 19  
    Queries per second avg: 0.000
    

    Wenn Sie wissen wollen, was Sie mit mysqladmin noch machen können, rufen Sie es mit der Option --help auf.

  5. Überprüfen Sie nun, ob Sie den Server herunterfahren können:

    shell> bin/mysqladmin -u root shutdown
    
  6. Als Nächstes prüfen Sie, ob Sie den Server neu starten können. Hierzu verwenden Sie mysqld_safe oder rufen mysqld direkt auf. Ein Beispiel:

    shell> bin/mysqld_safe --user=mysql --log &
    

    Schlägt mysqld_safe fehl, dann lesen Sie Abschnitt 2.9.2.3, „Probleme mit dem Start des MySQL Servers“.

  7. Führen Sie einige einfache Tests durch, um sicherzustellen, dass Sie Daten am Server abrufen können. Die Ausgabe sollte ähnlich wie nachfolgend aufgeführt aussehen:

    shell> bin/mysqlshow
    +-----------+
    | Databases |
    +-----------+
    | mysql     |
    | test      |
    +-----------+
    
    shell> bin/mysqlshow mysql
    Database: mysql
    +---------------------------+
    |          Tables           |
    +---------------------------+
    | columns_priv              |
    | db                        |
    | func                      |
    | help_category             |
    | help_keyword              |
    | help_relation             |
    | help_topic                |
    | host                      |
    | proc                      |
    | procs_priv                |
    | tables_priv               |
    | time_zone                 |
    | time_zone_leap_second     |
    | time_zone_name            |
    | time_zone_transition      |
    | time_zone_transition_type |
    | user                      |
    +---------------------------+
    
    shell> bin/mysql -e "SELECT Host,Db,User FROM db" mysql
    +------+--------+------+
    | host | db     | user |
    +------+--------+------+
    | %    | test   |      |
    | %    | test_% |      |
    +------+--------+------+
    
  8. Im Verzeichnis sql-bench (dieses befindet sich im MySQL-Installationsverzeichnis) befindet sich eine Benchmark-Reihe, die Sie verwenden können, um die Leistungsfähigkeit von MySQL auf verschiedenen Plattformen zu vergleichen. Diese Benchmark-Reihe ist in Perl geschrieben. Sie erfordert das Perl-DBI-Modul, welches eine datenbankunabhängige Schnittstelle zu verschiedenen Datenbanken bereitstellt, sowie einige weitere Perl-Module:

    DBI
    DBD::mysql
    Data::Dumper
    Data::ShowTable
    

    Diese Module erhalten Sie bei CPAN (http://www.cpan.org/). Siehe auch Abschnitt 2.13.1, „Installation von Perl unter Unix“.

    Das Verzeichnis sql-bench/Results enthält die Ergebnisse vieler Testläufe mit unterschiedlichen Datenbanken und Plattformen. Um alle Tests durchzuführen, setzen Sie die folgenden Befehle ab:

    shell> cd sql-bench
    shell> perl run-all-tests
    

    Wenn das Verzeichnis sql-bench bei Ihnen nicht vorhanden ist, haben Sie MySQL wahrscheinlich aus anderen RPM-Dateien als dem Quell-RPM installiert. (Das Quell-RPM enthält das Benchmark-Verzeichnis sql-bench.) In diesem Fall müssen Sie die Benchmark-Reihe zunächst installieren, bevor Sie sie verwenden können. Es gibt separate Benchmark-RPMs namens mysql-bench-VERSION-i386.rpm, die den Benchmark-Code und die Daten enthalten.

    Wenn Sie mit einer Quelldistribution arbeiten, finden Sie in deren Unterverzeichnis tests weitere Tests, die Sie ausführen können. Um etwa auto_increment.tst auszuführen, setzen Sie den folgenden Befehl im obersten Verzeichnis Ihrer Quelldistribution ab:

    shell> mysql -vvf test < ./tests/auto_increment.tst
    

    Die erwarteten Testergebnisse finden Sie in der Datei ./tests/auto_increment.res.

  9. An dieser Stelle sollte der Server bereits laufen. Allerdings verfügt keines der vorgabeseitigen MySQL-Konten über ein Passwort. Weisen Sie deswegen Passwörter zu wie in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“, beschrieben.

Der Installationsvorgang für MySQL 5.1 erstellt Zeitzonentabellen in der Datenbank mysql. Sie müssen die Tabellen allerdings manuell ausfüllen; wie das geht, steht in Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“.

2.9.2.1. Probleme mit mysql_install_db

Der Zweck des Skripts mysql_install_db besteht in der Generierung neuer MySQL-Berechtigungstabellen. Hierbei werden vorhandene MySQL-Berechtigungstabellen nicht überschrieben, und auch andere Daten werden nicht beeinträchtigt.

Wollen Sie Ihre Berechtigungstabellen neu erstellen, dann beenden Sie zunächst den mysqld-Server, sofern dieser läuft. Benennen Sie das Verzeichnis mysql im Datenverzeichnis dann um, um es zu speichern, und führen Sie nachfolgend mysql_install_db aus. Nehmen wir an, Ihr aktuelles Verzeichnis ist das MySQL-Installationsverzeichnis, mysql_install_db befindet sich im Verzeichnis bin und das Datenverzeichnis heißt data. Um die mysql-Datenbank umzubenennen und mysql_install_db erneut auszuführen, verwenden Sie die folgenden Befehle:

shell> mv data/mysql data/mysql.old
shell> bin/mysql_install_db --user=mysql

Wenn Sie mysql_install_db ausführen, können die folgenden Probleme auftreten:

  • mysql_install_db kann die Grant-Tabellen nicht installieren.

    Unter Umständen stellen Sie fest, dass mysql_install_db die Grant-Tabellen nicht installieren kann und nach Anzeige der folgenden Meldungen beendet wird:

    Starting mysqld daemon with databases from XXXXXX
    mysqld ended
    

    In diesem Fall sollten Sie die Fehlerlogdatei sehr aufmerksam lesen. Das Fehlerlog sollte sich im Verzeichnis XXXXXX befinden (dieses ist nach der Fehlermeldung benannt) und angeben, warum mysqld nicht gestartet wurde. Wenn Sie nicht verstehen, was geschehen ist, hängen Sie das Log an, wenn Sie einen Bugreport einsenden. Siehe auch Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

  • Ein mysqld-Prozess wird ausgeführt.

    Dies weist darauf hin, dass der Server läuft und die Grant-Tabellen wahrscheinlich bereits erstellt wurden. In diesem Fall müssen Sie mysql_install_db überhaupt nicht ausführen, da es nur einmal gestartet werden muss (nämlich dann, wenn Sie MySQL zum ersten Mal installieren).

  • Die Installation eines zweiten mysqld-Servers schlägt fehl, wenn ein Server bereits läuft.

    Dies kann passieren, wenn eine MySQL-Installation bereits vorhanden ist, Sie aber eine neue Installation an einer anderen Position ablegen wollen. So haben Sie vielleicht eine Produktionsinstallation, wollen aber eine zweite Installation zu Testzwecken einrichten. Meist tritt dieses Problem auf, wenn Sie einen zweiten Server ausführen wollen, der auf eine Netzwerkschnittstelle zuzugreifen versucht, die bereits vom ersten Server verwendet wird. In diesem Fall werden Sie eine der folgenden Fehlermeldungen sehen:

    Can't start server: Bind on TCP/IP port:
    Address already in use
    Can't start server: Bind on unix socket ...
    

    Anweisungen zur Einrichtung mehrerer Server finden Sie in Abschnitt 5.13, „Mehrere MySQL-Server auf derselben Maschine laufen lassen“.

  • Sie haben keinen Schreibzugriff auf das Verzeichnis /tmp.

    Wenn Sie keinen Schreibzugriff erhalten, um Temporärdateien oder eine Unix-Socketdatei im Standardverzeichnis (/tmp) zu erstellen, dann tritt ein Fehler auf, wenn Sie mysql_install_db oder den mysqld-Server ausführen wollen.

    Sie können verschiedene Positionen für das Temporärverzeichnis und die Unix-Socketdatei angeben, indem Sie die folgenden Befehle vor dem Starten von mysql_install_db oder mysqld ausführen (hierbei ist some_tmp_dir der vollständige Pfadname eines Verzeichnisses, für das Sie Schreibzugriff haben):

    shell> TMPDIR=/some_tmp_dir/
    shell> MYSQL_UNIX_PORT=/some_tmp_dir/mysql.sock
    shell> export TMPDIR MYSQL_UNIX_PORT
    

    Danach sollten Sie in der Lage sein, mysql_install_db mit den folgenden Befehlen auszuführen und den Server zu starten:

    shell> bin/mysql_install_db --user=mysql
    shell> bin/mysqld_safe --user=mysql &
    

    Wenn sich mysql_install_db im Verzeichnis scripts befindet, ändern Sie den ersten Befehl zu scripts/mysql_install_db.

    Siehe auch Abschnitt A.4.5, „Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern“, und Anhang F, Umgebungsvariablen.

Es gibt einige Alternativen zur Ausführung des Skripts mysql_install_db, welches Bestandteil der MySQL-Distribution ist:

  • Wenn Sie wollen, dass die Ausgangsberechtigungen sich von den Standardwerten unterscheiden, können Sie mysql_install_db vor der Ausführung bearbeiten. Allerdings bietet es sich eher an, mit GRANT und REVOKE die Berechtigungen zu ändern, nachdem die Grant-Tabellen eingerichtet wurden. Mit anderen Worten, Sie können mysql_install_db ausführen und dann mithilfe von mysql -u root mysql eine Verbindung zum Server als MySQL-root-Benutzer herstellen, damit Sie die erforderlichen GRANT- und REVOKE-Anweisungen absetzen können.

    Wenn Sie MySQL auf mehreren Computern mit denselben Berechtigungen installieren wollen, können Sie die GRANT- und REVOKE-Anweisungen auch in einer Datei ablegen und diese Datei mithilfe von mysql als Skript ausführen, nachdem Sie mysql_install_db gestartet haben. Ein Beispiel:

    shell> bin/mysql_install_db --user=mysql
    shell> bin/mysql -u root < your_script_file
    

    Auf diese Weise müssen Sie die Anweisungen nicht manuell auf jedem einzelnen Computer eingeben.

  • Es ist möglich, die Grant-Tabellen nach ihrer Erstellung vollständig neu zu erstellen. Dies müssen Sie unter Umständen tun, wenn Sie gerade erst lernen, wie man GRANT und REVOKE verwendet, und nach der Ausführung von mysql_install_db derart viele Änderungen vorgenommen haben, dass Sie die Tabellen komplett löschen und von vorn beginnen wollen.

    Um die Grant-Tabellen neu zu erstellen, entfernen Sie alle .frm-, .MYI- und .MYD-Dateien im Datenbankverzeichnis mysql. Danach führen Sie das Skript mysql_install_db erneut aus.

  • Sie können mysqld manuell mithilfe der Option --skip-grant-tables starten und die Berechtigungsdaten selbst unter Verwendung von mysql hinzufügen:

    shell> bin/mysqld_safe --user=mysql --skip-grant-tables &
    shell> bin/mysql mysql
    

    Von mysql führen Sie die in mysql_install_db enthaltenen SQL-Befehle manuell aus. In jedem Fall müssen Sie danach mysqladmin flush-privileges oder mysqladmin reload ausführen, um dem Server mitzuteilen, dass er die Grant-Tabellen neu laden muss.

    Beachten Sie, dass Sie, wenn Sie mysql_install_db nicht benutzen, die Grant-Tabellen nicht nur manuell ausfüllen, sondern sie zuvor auch noch erstellen müssen.

2.9.2.2. MySQL automatisch starten und anhalten

Normalerweise starten Sie den mysqld-Server unter Verwendung einer der folgenden Möglichkeiten:

  • Durch direkten Aufruf von mysqld. Das funktioniert auf allen Plattformen.

  • Durch Ausführung des MySQL Servers als Windows-Dienst. Dies ist unter Windows-Versionen möglich, die Dienste unterstützen (also NT, 2000, XP und 2003). Der Dienst kann entweder so konfiguriert werden, dass der Server automatisch mit Windows startet, oder als manueller Dienst, den Sie manuell starten müssen. Informationen zur Vorgehensweise finden Sie in Abschnitt 2.3.12, „Starten von MySQL als Windows-Dienst“.

  • Durch Aufruf von mysqld_safe. Hierbei wird versucht, die passenden Optionen für mysqld zu ermitteln und es dann mit diesen Optionen zu starten. Dieses Skript wird unter Unix und Unix-ähnlichen Systemen verwendet. Siehe auch Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“.

  • Durch den Aufruf von mysql.server. Dieses Skript wird in erster Linie beim Starten und Beenden von Systemen verwendet, die Ausführungsverzeichnisse im System V-Stil verwenden, wo es normalerweise unter dem Namen mysql installiert ist. Das Skript mysql.server startet den Server, indem es mysqld_safe aufruft. Siehe auch Abschnitt 5.4.2, „mysql.server — Startskript für den MySQL-Server“.

  • Unter Mac OS X können Sie ein separates MySQL-Startobjektpaket installieren, um den automatischen Start von MySQL beim Systemstart zu aktivieren. Das Startobjekt startet den Server durch Aufruf von mysql.server. Weitere Informationen finden Sie in Abschnitt 2.5, „Installation von MySQL unter Mac OS X“.

Die Skripten mysqld_safe und mysql.server und das Mac OS X-Startobjekt können für den manuellen Start des Servers oder für seinen automatischen Start beim Systemstart verwendet werden. mysql.server und das Startobjekt erlauben zudem das Beenden des Servers.

Um den Server mit mysql.server manuell zu starten oder zu beenden, rufen Sie es mit dem Argument start bzw. stop auf:

shell> mysql.server start
shell> mysql.server stop

Bevor mysql.server den Server startet, wechselt es in das MySQL-Installationsverzeichnis und ruft dann mysqld_safe auf. Wenn Sie wollen, dass der Server als ein bestimmter Benutzer ausgeführt wird, fügen Sie die entsprechende Option user im Abschnitt [mysqld] der Optionsdatei /etc/my.cnf hinzu. Eine Erklärung erhalten Sie im weiteren Verlauf dieses Abschnitts. (Unter Umständen müssen Sie mysql.server bearbeiten, wenn Sie eine Binärdistribution von MySQL in einem anderen als dem Standardverzeichnis installiert haben. Ändern Sie es so, dass es via cd in das korrekte Verzeichnis wechselt, bevor es mysqld_safe ausführt. Beachten Sie allerdings, dass Ihre geänderte Version von mysql.server bei einem zukünftigen MySQL-Upgrade überschrieben werden könnte; deswegen sollten Sie eine Kopie der editierten Version erstellen, die Sie bei Bedarf neu installieren können.)

mysql.server stop beendet den Server, indem es ein Signal an ihn schickt. Sie können den Server auch manuell beenden, indem Sie mysqladmin shutdown ausführen.

Um MySQL automatisch auf Ihrem Server zu starten und zu beenden, müssen Sie Start- und Stoppbefehle an den entsprechenden Stellen Ihrer /etc/rc*-Dateien einfügen.

Wenn Sie das Linux-Server-RPM-Paket (MySQL-server-VERSION.rpm) verwenden, wird das Skript mysql.server im Verzeichnis /etc/init.d unter dem Namen mysql installiert. Sie müssen die Installation also nicht manuell vornehmen. Weitere Informationen zu Linux-RPM-Paketen finden Sie in Abschnitt 2.4, „MySQL unter Linux installieren“.

Manche Anbieter stellen RPM-Pakete bereit, die ein Startskript unter einem anderen Namen wie etwa mysqld installieren.

Wenn Sie MySQL aus einer Quelldistribution installieren oder ein Binärdistributionsformat verwenden, das mysql.server nicht automatisch installiert, können Sie es manuell installieren. Sie finden das Skript im Verzeichnis support-files, das sich im MySQL-Installationsverzeichnis befindet, oder in einem MySQL-Source-Tree.

Um mysql.server manuell zu installieren, kopieren Sie es unter dem Namen mysql in das Verzeichnis /etc/init.d und machen es dann ausführbar. Dies tun Sie, indem Sie in das entsprechende Verzeichnis wechseln, in dem sich mysql.server befindet, und dann die folgenden Befehle ausführen:

shell> cp mysql.server /etc/init.d/mysql
shell> chmod +x /etc/init.d/mysql

Ältere Red Hat-Systeme verwenden das Verzeichnis /etc/rc.d/init.d statt /etc/init.d. In diesem Fall müssen Sie die obigen Befehle entsprechend ändern. Alternativ erstellen Sie zunächst /etc/init.d als symbolische Verknüpfung, die auf /etc/rc.d/init.d verweist:

shell> cd /etc
shell> ln -s rc.d/init.d .

Nach der Installation des Skripts hängt der Befehl, der zur Aktivierung der Ausführung beim Systemstart erforderlich ist, von Ihrem Betriebssystem ab. Unter Linux können Sie chkconfig verwenden:

shell> chkconfig --add mysql

Unter manchen Linux-Systemen scheint auch der folgende Befehl notwendig zu sein, um das Skript mysql vollständig zu aktivieren:

shell> chkconfig --level 345 mysql on

Unter FreeBSD sollten Startskripten generell in /usr/local/etc/rc.d/ abgelegt werden. Die Manpage rc(8) gibt an, dass Skripten in diesem Verzeichnis nur dann ausgeführt werden, wenn ihr Basisname dem Shell-Muster für Dateinamen *.sh entspricht. Alle anderen Dateien oder Verzeichnisse, die in diesem Verzeichnis vorhanden sind, werden stillschweigend ignoriert. Mit anderen Worten: Unter FreeBSD müssen Sie das Skript mysql.server als /usr/local/etc/rc.d/mysql.server.sh installieren, um den automatischen Start zu aktivieren.

Als Alternative zur obigen Konfiguration verwenden manche Betriebssysteme auch /etc/rc.local oder /etc/init.d/boot.local, um zusätzliche Dienste beim Systemstart zu starten. Um MySQL auf diese Weise zu starten, könnten Sie einen Befehl wie den folgenden an die entsprechende Startdatei anhängen:

/bin/sh -c 'cd /usr/local/mysql; ./bin/mysqld_safe --user=mysql &'

Bei anderen Systemen lesen Sie in der Dokumentation zu Ihrem Betriebssystem nach, um zu erfahren, wie Startskripten installiert werden.

Sie können Optionen für mysql.server in einer globalen Datei /etc/my.cnf ablegen. Eine /etc/my.cnf-Datei sieht normalerweise so aus:

[mysqld]
datadir=/usr/local/mysql/var
socket=/var/tmp/mysql.sock
port=3306
user=mysql

[mysql.server]
basedir=/usr/local/mysql

Das Skript mysql.server versteht die folgenden Optionen: basedir, datadir und pid-file. Sofern angegeben, müssen diese in einer Optionsdatei und nicht an der Befehlszeile abgelegt sein. mysql.server versteht nur start und stop als Befehlszeilenargumente.

Die folgende Tabelle zeigt, welche Optionsgruppen der Server und die jeweiligen Startskripten aus den Optionsdateien auslesen:

SkriptAbschnitte in der Optionsdatei
mysqld[mysqld], [server], [mysqld-major_version]
mysqld_safe[mysqld], [server], [mysqld_safe]
mysql.server[mysqld], [mysql.server], [server]

[mysqld-major_version] bedeutet, dass Abschnitte mit Namen wie [mysqld-5.0] und [mysqld-5.1] von Servern der Versionen 5.0.x, 5.1.x usw. ausgelesen werden. Diese Funktion kann verwendet werden, um Optionen anzugeben, die nur von Servern einer bestimmten Release-Serie ausgelesen werden können.

Zwecks Abwärtskompatibilität liest mysql.server auch den Abschnitt [mysql_server] und mysqld_safe den Abschnitt [safe_mysqld] aus. Allerdings sollten Sie Ihre Optionsdateien so aktualisieren, dass sie stattdessen die Abschnitte [mysql.server] und [mysqld_safe] auslesen, wenn Sie MySQL 5.1 verwenden.

Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

2.9.2.3. Probleme mit dem Start des MySQL Servers

Dieser Abschnitt enthält Vorschläge zur Fehlersuche, wenn unter Unix Probleme beim Start des Servers auftreten. Wenn Sie Windows verwenden, finden Sie Informationen in Abschnitt 2.3.14, „Troubleshooting einer MySQL-Installation unter Windows“.

Haben Sie Probleme beim Starten des Servers, dann probieren Sie folgende Schritte:

  • Suchen Sie im Fehlerlog nach Ursachen dafür, dass der Server nicht startet.

  • Geben Sie alle Sonderoptionen an, die von den von Ihnen verwendeten Speicher-Engines benötigt werden.

  • Stellen Sie sicher, dass der Server die Position des Datenverzeichnisses kennt.

  • Stellen Sie auch sicher, dass der Server auf das Datenverzeichnis zugreifen kann. Besitzrechte und Berechtigungen für das Datenverzeichnis und seine Inhalte müssen so konfiguriert sein, dass der Server sie lesen und ändern kann.

  • Überprüfen Sie, ob die Netzwerkschnittstellen, die der Server verwenden will, vorhanden sind.

Einige Speicher-Engines haben Optionen, die ihr Verhalten steuern. Sie können eine Datei my.cnf erstellen und darin die Startoptionen der Engines angeben, die Sie zu verwenden beabsichtigen. Wenn Sie Speicher-Engines verwenden wollen, die transaktionssichere Tabellen (InnoDB, BDB, NDB) unterstützen, dann vergewissern Sie sich, dass diese wie gewünscht konfiguriert sind, bevor Sie den Server starten:

Speicher-Engines verwenden, sofern keine Optionswerte definiert sind, die Vorgabewerte. Wir empfehlen deswegen, die verfügbaren Optionen zu prüfen und explizite Werte für diejenigen Optionen anzugeben, bei denen die Vorgabewerte nicht für Ihre Installation geeignet sind.

Wenn der mysqld-Server startet, wechselt er in das Datenverzeichnis. In diesem Verzeichnis erwartet er das Vorhandensein der Datenbanken, und hier wird er auch seine Logdateien speichern. Auch die PID-Datei (Process ID, Prozesskennung) wird im Datenverzeichnis abgelegt.

Das Datenverzeichnis wird bei der Kompilierung des Servers fest zugeordnet. Standardmäßig sucht der Server deswegen an der angegebenen Position nach diesem Verzeichnis. Befindet sich das Datenverzeichnis in Ihrem System an anderer Stelle, dann funktioniert der Server nicht einwandfrei. Durch Aufruf des Befehls mysqld mit den Optionen --verbose und --help können Sie die Vorgaben für die Pfadeinstellungen ermitteln.

Wenn die Standardpositionen dem MySQL-Installationslayout auf Ihrem System nicht entsprechen, können Sie sie durch Angabe von Optionen für mysqld oder mysqld_safe auf der Befehlszeile oder in einer Optionsdatei außer Kraft setzen.

Um die Position des Datenverzeichnisses explizit anzugeben, verwenden Sie die Option --datadir. Allerdings können Sie mysqld die Position des Basisverzeichnisses angeben, in dem MySQL installiert ist; mysqld wird dann in diesem Verzeichnis nach dem Datenverzeichnis suchen. Die Angabe erfolgt mit der Option --basedir.

Um die Auswirkungen der Optionen zur Pfadangabe zu überprüfen, rufen Sie mysqld mit diesen Optionen auf, gefolgt von den Optionen --verbose und --help. Wenn Sie beispielsweise in das Verzeichnis wechseln, in dem mysqld installiert ist, und dann den folgenden Befehl ausführen, werden die Auswirkung des Serverstarts bei einem Basisverzeichnis /usr/local angezeigt:

shell> ./mysqld --basedir=/usr/local --verbose --help

Sie können auch andere Optionen wie --datadir spezifizieren; beachten Sie aber, dass --verbose und --help jeweils als letzte Optionen aufzuführen sind.

Wenn Sie die gewünschten Pfadeinstellungen ermittelt haben, starten Sie den Server ohne --verbose und --help.

Wird mysqld gerade ausgeführt, dann können Sie die verwendeten Pfadeinstellungen durch Absetzen des folgenden Befehls ermitteln:

shell> mysqladmin variables

Oder:

shell> mysqladmin -h host_name variables

host_name ist der Name des MySQL Server-Hosts.

Erhalten Sie beim Starten von mysqld die Fehlermeldung Errcode 13 (Permission denied, Berechtigung verweigert), dann gestatten die Berechtigungen des Datenverzeichnisses oder seiner Inhalte keinen Serverzugriff. In diesem Fall ändern Sie die Berechtigungen für die betreffenden Dateien und Verzeichnisse so, dass der Server das Recht hat, sie zu verwenden. Sie können den Server auch als root starten, wovon aus sicherheitstechnischer Sicht jedoch dringend abgeraten wird.

Wechseln Sie unter Unix in das Datenverzeichnis und überprüfen Sie die Besitzrechte für das Datenverzeichnis und seinen Inhalt, um den Serverzugriff zu gewährleisten. Verwenden Sie etwa folgenden Befehl, wenn das Datenverzeichnis /usr/local/mysql/var ist:

shell> ls -la /usr/local/mysql/var

Wenn die Besitzrechte für das Datenverzeichnis oder seine Unterverzeichnisse nicht bei dem Anmeldekonto liegen, das Sie zur Ausführung des Servers verwenden, dann müssen Sie die Besitzrechte für diese Ressourcen dem Konto zuweisen. Heißt das Konto mysql, dann verwenden Sie folgende Befehle:

shell> chown -R mysql /usr/local/mysql/var
shell> chgrp -R mysql /usr/local/mysql/var

Wenn der Server nicht korrekt startet, prüfen Sie das Fehlerlog. Logdateien befinden sich im Datenverzeichnis (unter Windows normalerweise C:\Programme\MySQL\MySQL Server 5.1\data, bei Unix-Binärdistributionen in /usr/local/mysql/data und bei Unix-Quelldistributionen in /usr/local/var). Suchen Sie im Datenverzeichnis nach Dateien mit Namen des Typs host_name.err und host_name.log, wobei host_name der Name des Serverhosts ist. Überprüfen Sie nun die letzten paar Zeilen dieser Dateien. Unter Unix können Sie sie mit tail anzeigen:

shell> tail host_name.err
shell> tail host_name.log

Das Fehlerlog sollte Informationen dazu enthalten, warum der Server nicht starten konnte. Beispielsweise könnte das Log etwa Folgendes enthalten:

000729 14:50:10  bdb:  Recovery function for LSN 1 27595 failed
000729 14:50:10  bdb:  warning: ./test/t1.db: No such file or directory
000729 14:50:10  Can't init databases

Das bedeutet, dass Sie mysqld nicht mit der Option --bdb-no-recover gestartet haben; Berkeley DB hat dann, als es versuchte, Ihre Datenbanken wiederherzustellen, Ungereimtheiten in Bezug auf die eigenen Logdateien erkannt. Um fortzufahren, sollten Sie die alten Berkeley DB-Logdateien aus dem Datenbankverzeichnis an einen anderen Ort verschieben, wo Sie sie später untersuchen können. Die BDB-Logdateien werden in chronologischer Reihenfolge beginnend mit log.0000000001 benannt; die Zahl im Namen wird dabei stets erhöht.

Wenn Sie mysqld mit Unterstützung für BDB-Tabellen ausführen und beim Start von mysqld ein Speicherauszug auftritt, könnte dies auf Probleme in Verbindung mit dem BDB-Wiederherstellungslog hinweisen. In diesem Fall können Sie versuchen, mysqld mit der Option --bdb-no-recover zu starten. Wenn das klappt, sollten Sie alle BDB-Logdateien aus dem Datenverzeichnis entfernen und dann versuchen, mysqld ohne die Option --bdb-no-recover neu zu starten.

Tritt einer der folgenden Fehler auf, dann bedeutet dies, dass ein anderes Programm (vielleicht ein anderer mysqld-Server) den TCP/IP-Port bzw. die Unix-Socketdatei verwendet, die mysqld für sich beansprucht:

Can't start server: Bind on TCP/IP port: Address already in use
Can't start server: Bind on unix socket ...

Ermitteln Sie mit dem Befehl ps, ob ein anderer mysqld-Server ausgeführt wird. Ist dies der Fall, dann fahren Sie den Server herunter, bevor Sie mysqld erneut starten. (Wenn ein anderer Server ausgeführt wird und Sie tatsächlich mehrere Server gleichzeitig betreiben wollen, finden Sie Informationen zur Vorgehensweise in Abschnitt 5.13, „Mehrere MySQL-Server auf derselben Maschine laufen lassen“.)

Läuft kein anderer Server, dann führen Sie den Befehl telnet your_host_name tcp_ip_port_number aus. (Die Standardportnummer von MySQL ist 3306.) Betätigen Sie dann mehrfach die Eingabetaste. Erhalten Sie keine Fehlermeldung in der Art von telnet: Unable to connect to remote host: Connection refused, dann verwendet ein anderes Programm den TCP/IP-Port, den mysqld nutzen will. Sie müssen dann ermitteln, welches Programm dies ist, und es deaktivieren; alternativ können Sie mysqld mit der Option --port auch anweisen, an einem anderen Port zu lauschen. In diesem Fall müssen Sie auch die Portnummer für Clientprogramme angeben, die über TCP/IP eine Verbindung mit dem Server herstellen wollen.

Ein anderer Grund, warum kein Zugriff auf den Port möglich ist, könnte eine laufende Firewall sein, die Verbindungen zu diesem Port unterbindet. In diesem Fall müssen Sie die Firewall-Einstellungen so abändern, dass ein Zugriff möglich ist.

Wenn der Server startet, Sie aber keine Verbindung zu ihm herstellen können, dann sollten Sie sicherstellen, dass ein Eintrag wie der folgende in /etc/hosts vorhanden ist:

127.0.0.1       localhost

Dieses Problem tritt nur bei Systemen auf, die über keine funktionierende Thread-Bibliothek verfügen und für die MySQL zur Verwendung von MIT-pthreads konfiguriert sein muss.

Wenn Sie mysqld nicht zum Laufen bringen, können Sie versuchen, unter Verwendung der Option --debug eine Trace-Datei zu erstellen, um das Problem zu ermitteln. Siehe auch Abschnitt E.1.2, „Trace-Dateien erzeugen“.

2.9.3. Einrichtung der anfänglichen MySQL-Berechtigungen

Eine wesentliche Komponente des MySQL-Installationsprozesses ist die Einrichtung der mysql-Datenbank, die die Grant-Tabellen enthält:

  • Windows-Distributionen enthalten vorinitialisierte Grant-Tabellen, die automatisch installiert werden.

  • Unter Unix werden die Grant-Tabellen durch das Programm mysql_install_db ausgefüllt. Einige Installationsmethoden führen dieses Programm für Sie aus. Andere wiederum erfordern eine manuelle Ausführung. Detaillierte Informationen finden Sie in Abschnitt 2.9.2, „Schritte nach der Installation unter Unix“.

Die Grant-Tabellen definieren die vorgabeseitigen MySQL-Benutzerkonten und deren Zugriffsberechtigungen. Diese Konten werden wie folgt eingerichtet:

  • Es werden Konten mit dem Benutzernamen root erstellt. Dies sind Superuser-Konten, die alles dürfen. Anfänglich sind die Passwörter der root-Konten leer, d. h., jeder kann als rootohne Passwort — eine Verbindung mit dem MySQL Server herstellen und erhält alle Berechtigungen.

    • Unter Windows wird genau ein root-Konto erstellt. Dieses erlaubt nur eine Verbindung über den lokalen Host. Das Windows-Installationsprogramm erstellt optional ein Konto, welches Verbindung von beliebigen Hosts ermöglicht. Dieses Konto wird jedoch nur dann angelegt, wenn die Option Enable root access from remote machines während der Installation gewählt wurde.

    • Unter Unix sind beide root-Konten für Verbindungen vom lokalen Host vorgesehen. Verbindungen vom lokalen Host müssen unter Angabe von localhost für das eine Konto bzw. des tatsächlichen Hostnamens oder der IP-Nummer für das andere Konto hergestellt werden.

  • Es werden zwei Konten für anonyme Benutzer erstellt; bei beiden ist der Benutzername leer. Die anonymen Konten haben kein Passwort, d. h., jeder kann über sie eine Verbindung zum MySQL Server herstellen.

    • Unter Windows wird ein anonymes Konto für Verbindungen vom lokalen Host eingerichtet. Es hat ebenso wie die root-Konten alle Berechtigungen. Das andere Konto ist für Verbindungen von beliebigen Hosts vorgesehen und hat alle Berechtigungen für die test-Datenbank und für alle Datenbanken, deren Name auf test beginnt.

    • Unter Unix sind beide anonymen Konten für Verbindungen vom lokalen Host vorgesehen. Verbindungen vom lokalen Host müssen unter Angabe von localhost für das eine Konto bzw. des tatsächlichen Hostnamens oder der IP-Nummer für das andere Konto hergestellt werden. Diese Konten haben alle Berechtigungen für die Datenbank test und für alle Datenbanken, deren Name mit test_ beginnt.

Wie bereits angemerkt, hat keines der Vorgabekonten ein Passwort. Das bedeutet, dass Ihre MySQL-Installation nicht geschützt ist, bis Sie etwas Entsprechendes unternehmen:

  • Wenn Sie verhindern wollen, dass Clients sich ohne Angabe eines Passworts als anonyme Benutzer anmelden können, sollten Sie entweder für jedes anonyme Konto ein Passwort einrichten oder die Konten ganz entfernen.

  • Allen MySQL-root-Konten sollten Sie Passwörter zuweisen.

Die folgenden Angaben erläutern, wie Sie Passwörter für die vorgegebenen MySQL-Konten erstellen – erst für die anonymen Konten und dann für die root-Konten. Ersetzen Sie „ newpwd “ in den Beispielen durch das Passwort, welches Sie verwenden wollen. Die Erläuterungen behandeln auch die Frage, wie Sie die anonymen Konten entfernen können, wenn Sie anonymen Zugriff überhaupt nicht gestatten wollen.

Sie sollten die Einstellung der Passwörter auf einen späteren Zeitpunkt verschieben, damit Sie sie nicht angeben müssen, wenn Sie weitere Konfigurations- oder Testschritte durchführen. Achten Sie allerdings darauf, sie einzurichten, bevor Sie Ihre Installation für Produktionszwecke einsetzen.

Um Passwörter für anonyme Konten zu konfigurieren, stellen Sie als root eine Verbindung zum Server her und stellen das Passwort entweder mit SET PASSWORD ein oder führen eine UPDATE-Anweisung aus. In beiden Fällen müssen Sie das Passwort mit der PASSWORD()-Funktion verschlüsseln.

SET PASSWORD verwenden Sie unter Windows wie folgt:

shell> mysql -u root
mysql> SET PASSWORD FOR ''@'localhost' = PASSWORD('newpwd');
mysql> SET PASSWORD FOR ''@'%' = PASSWORD('newpwd');

SET PASSWORD verwenden Sie unter Unix wie folgt:

shell> mysql -u root
mysql> SET PASSWORD FOR ''@'localhost' = PASSWORD('newpwd');
mysql> SET PASSWORD FOR ''@'host_name' = PASSWORD('newpwd');

In der zweiten SET PASSWORD-Anweisung ersetzen Sie host_name durch den Namen des Serverhosts. Es handelt sich dabei um den Namen, den Sie in der Spalte Host desjenigen root-Datensatzes in der Tabelle user angegeben haben, der nicht mit localhost verknüpft wird. Wenn Sie diesen Hostnamen nicht kennen, setzen Sie die folgende Anweisung vor der Verwendung von SET PASSWORD ab:

mysql> SELECT Host, User FROM mysql.user;

Suchen Sie nach dem Datensatz, bei dem root in der Spalte User und etwas anderes als localhost in der Spalte Host steht. Verwenden Sie dann diesen Host-Wert in der zweiten SET PASSWORD-Anweisung.

Die andere Möglichkeit, Passwörter für anonyme Konten zuzuweisen, ist die Verwendung von UPDATE zur direkten Modifizierung der Tabelle user. Stellen Sie als root eine Verbindung zum Server her und setzen Sie eine UPDATE-Anweisung ab, die in der Spalte Password der betreffenden Datensätze in der Tabelle user einen Wert hinzufügt. Der Vorgang ist bei Windows und Unix identisch. Die folgende UPDATE-Anweisung weist beiden anonymen Konten gleichzeitig ein Passwort zu:

shell> mysql -u root
mysql> UPDATE mysql.user SET Password = PASSWORD('newpwd')
    ->     WHERE User = '';
mysql> FLUSH PRIVILEGES;

Wenn Sie die Passwörter in der Tabelle user mit UPDATE direkt aktualisieren, müssen Sie den Server mit FLUSH PRIVILEGES anweisen, die Grant-Tabellen neu einzulesen. Andernfalls werden Ihre Änderungen erst umgesetzt, wenn Sie den Server neu starten.

Wenn Sie die anonymen Konten stattdessen ganz entfernen wollen, gehen Sie wie folgt vor:

shell> mysql -u root
mysql> DELETE FROM mysql.user WHERE User = '';
mysql> FLUSH PRIVILEGES;

Die DELETE-Anweisung gilt für Windows und Unix gleichermaßen. Wenn Sie unter Windows nur das anonyme Konto entfernen wollen, das die gleichen Berechtigungen wie root hat, geben Sie stattdessen Folgendes ein:

shell> mysql -u root
mysql> DELETE FROM mysql.user WHERE Host='localhost' AND User='';
mysql> FLUSH PRIVILEGES;

Dieses Konto gewährt anonymen Zugriff, verfügt aber über Vollzugriff; insofern verbessern Sie die Sicherheit, wenn Sie es entfernen.

Sie können den root-Konten Passwörter auf mehreren unterschiedlichen Wegen zuweisen. Im Folgenden wollen wir drei Methoden demonstrieren:

  • Verwenden der SET PASSWORD-Anweisung

  • Verwenden des befehlszeilenbasierten Clientprogramms mysqladmin

  • Verwenden der UPDATE-Anweisung

Um Passwörter mit SET PASSWORD zuzuweisen, stellen Sie als root eine Verbindung zum Server her und setzen zwei SET PASSWORD-Anweisungen ab. Beachten Sie dabei, dass Sie das Passwort mit der PASSWORD()-Funktion verschlüsseln müssen.

Unter Windows geben Sie Folgendes ein:

shell> mysql -u root
mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpwd');
mysql> SET PASSWORD FOR 'root'@'%' = PASSWORD('newpwd');

Unter Unix geben Sie Folgendes ein:

shell> mysql -u root
mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpwd');
mysql> SET PASSWORD FOR 'root'@'host_name' = PASSWORD('newpwd');

In der zweiten SET PASSWORD-Anweisung ersetzen Sie host_name durch den Namen des Serverhosts. Dies ist derselbe Hostname, den Sie bei der Zuweisung der Passwörter für die anonymen Konten verwendet haben.

Um für die root-Konten Passwörter mit mysqladmin zu konfigurieren, führen Sie folgende Befehle aus:

shell> mysqladmin -u root password "newpwd"
shell> mysqladmin -u root -h host_name password "newpwd"

Diese Befehle gelten für Windows und Unix gleichermaßen. Im zweiten Befehl ersetzen Sie host_name durch den Namen des Serverhosts. Die doppelten Anführungszeichen, die das Passwort umgeben, sind nicht immer erforderlich; Sie sollten sie aber verwenden, wenn das Passwort Leerzeichen oder andere Zeichen enthält, die Ihr Befehls-Interpreter als Sonderzeichen interpretiert.

Sie können auch mithilfe von UPDATE die Tabelle user direkt bearbeiten. Die folgende UPDATE-Anweisung weist beiden root-Konten gleichzeitig ein Passwort zu:

shell> mysql -u root
mysql> UPDATE mysql.user SET Password = PASSWORD('newpwd')
    ->     WHERE User = 'root';
mysql> FLUSH PRIVILEGES;

Die UPDATE-Anweisung gilt für Windows und Unix gleichermaßen.

Nachdem die Passwörter konfiguriert wurden, müssen Sie immer, wenn Sie eine Serververbindung herstellen, das Passwort angeben. Wollen Sie also etwa mysqladmin zum Herunterfahren des Servers verwenden, dann tun Sie das mit folgendem Befehl:

shell> mysqladmin -u root -p shutdown
Enter password: (enter root password here)

Hinweis: Wenn Sie Ihr root-Passwort nach der Konfiguration vergessen haben, finden Sie in Abschnitt A.4.1, „Wie ein vergessenes Kennwort zurückgesetzt wird“, Informationen dazu, wie Sie das Passwort zurücksetzen.

Um weitere Konten einzurichten, können Sie die Anweisung GRANT verwenden. Informationen zur Vorgehensweise finden Sie in Abschnitt 5.9.2, „Hinzufügen neuer MySQL-Benutzer“.

2.10. MySQL aktualisieren (Upgrade/Downgrade)

Generell empfehlen wir, Upgrades nur von einer Release-Serie zur nächsten durchzuführen und keine Serien auszulassen. Wenn Sie beispielsweise derzeit MySQL 4.0 verwenden und dann auf eine neuere Serie aktualisieren wollen, führen Sie ein Upgrade auf MySQL 4.1 und nicht auf 5.0 oder 5.1 durch.

Die folgende Checkliste sollten Sie immer überprüfen, wenn Sie ein Upgrade durchführen:

  • Vor der Aktualisierung von MySQL 5.0 auf 5.1 lesen Sie Abschnitt 2.10.1, „Upgrade von MySQL 5.0“, und Anhang D, MySQL-Änderungsverlauf (Change History). Dort finden Sie Informationen zu Funktionen, die bei MySQL 5.1 neu sind oder sich von jenen in MySQL 5.0 unterscheiden. Wenn Sie von einer Release-Serie vor MySQL 5.0 aus ein Upgrade durchführen wollen, sollten Sie nacheinander von Release-Serie zu Release-Serie aktualisieren, bis Sie MySQL 5.0 erreicht haben; danach können Sie auf MySQL 5.1 aktualisieren. Informationen zu Upgrades von MySQL 5.0 finden Sie im MySQL 5.0 Reference Manual. MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1 enthält die entsprechenden Angaben zu früheren Releases.

  • Bevor Sie das Upgrade durchführen, sichern Sie Ihre Datenbanken einschließlich der mysql-Datenbank, die Ihre Grant-Tabellen enthält.

  • Einige Releases von MySQL enthalten Änderungen an der Struktur der Grant-Tabellen, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Upgrade auf eine neue MySQL-Version durchführen, sollten Sie Ihre Grant-Tabellen aktualisieren, damit sichergestellt ist, dass diese auf der aktuellen Struktur basieren und auf diese Weise neue Funktionalitäten nutzen können. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

  • Wenn Sie MySQL Server unter Windows betreiben, lesen Sie Abschnitt 2.3.15, „Upgrade von MySQL unter Windows“.

  • Wenn Sie die Replikation nutzen, finden Sie in Abschnitt 6.7, „Upgrade eines Replikationssetups“, weitere Informationen zur Aktualisierung Ihrer Replikationskonfiguration.

  • Haben Sie zuvor bereits eine MySQL-Max-Distribution installiert, die einen Server namens mysqld-max enthält, und wollen nun auf eine Nicht-Max-Version von MySQL aktualisieren, dann beachten Sie, dass mysqld_safe nach wie vor versucht, den alten Server mysqld-max auszuführen. Wenn Sie ein Upgrade durchführen, sollten Sie den alten mysqld-max-Server manuell entfernen, um sicherzustellen, dass mysqld_safe den neuen Server mysqld ausführt.

Sie können die Format- und Datendateien von MySQL jederzeit zwischen verschiedenen Versionen derselben Architektur hin- und herschieben, solange Sie die Release-Serie nicht wechseln. Wenn Sie den Zeichensatz bei der Ausführung von MySQL ändern, dann müssen Sie myisamchk -r -q --set-collation=collation_name für alle MyISAM-Tabellen ausführen. Andernfalls werden Ihre Indizes unter Umständen nicht korrekt sortiert, weil sich bei einer Änderung des Zeichensatzes auch die Sortierreihenfolge ändern kann.

Wenn Sie in Bezug auf neue Versionen eher vorsichtig sind, können Sie Ihr vorhandenes mysqld immer umbenennen, bevor Sie eine neue Version installieren. Verwenden Sie beispielsweise MySQL 5.0.13 und wollen auf 5.1.10 aktualisieren, dann benennen Sie Ihren aktuellen Server von mysqld zu mysqld-5.0.13 um. Tut Ihr neuer Server mysqld dann etwas Unerwartetes, dann können Sie ihn einfach herunterfahren und mit Ihrem alten mysqld neu starten.

Wenn Sie nach Durchführung eines Upgrades auf Probleme in Zusammenhang mit neu kompilierten Clientprogrammen (z. B. die Fehlermeldung Commands out of sync) stoßen oder unerwartete Speicherauszüge auftreten, dann haben Sie bei der Kompilierung Ihrer Programme wahrscheinlich alte Header- oder Bibliotheksdateien angegeben. In diesem Fall sollten Sie das Datum Ihrer Datei mysql.h und der Bibliothek libmysqlclient.a überprüfen, um sicherzustellen, dass diese der aktuellen MySQL-Distribution entstammen. Andernfalls müssen Sie Ihre Programme mit den neuen Headern und Bibliotheken neu kompilieren.

Wenn Probleme in der Art auftreten, dass der neue mysqld-Server nicht startet oder Sie ohne Passwort keine Verbindung herstellen können, dann schauen Sie nach, ob Sie nicht noch eine alte my.cnf-Datei von Ihrer vorherigen Installation verwenden. Diese Überprüfung können Sie mithilfe der Option --print-defaults vornehmen (z. B. mysqld --print-defaults). Wenn dieser Befehl etwas anderes als den Programmnamen anzeigt, dann beeinträchtigt eine aktive my.cnf den Server- oder Clientbetrieb.

Wenn Sie einen neuen MySQL-Release installieren, bietet es sich immer an, das Perl-Modul DBD::mysql neu zu erstellen und zu installieren. Gleiches gilt auch für die anderen MySQL-Schnittstellen wie die PHP-Erweiterung mysql und das Python-Modul MySQLdb.

2.10.1. Upgrade von MySQL 5.0

Wenn Sie von einer 5.0-Installation auf 5.0.10 oder höher aktualisieren, beachten Sie, dass es unumgänglich ist, Ihre Grant-Tabellen zu aktualisieren. Andernfalls wird die Erstellung gespeicherter Prozeduren und Funktionen unter Umständen nicht funktionieren. Die entsprechende Vorgehensweise ist in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“, beschrieben.

Hinweis: Es ist gängige Praxis, Ihre Daten vor der Installation einer neuen Softwareversion zu sichern. Auch wenn MySQL mit Eifer daran arbeitet, ein möglichst hohes Qualitätsniveau zu erzielen, sollten Sie Ihre Daten immer schützen, indem Sie eine Sicherungskopie erstellen. MySQL empfiehlt in der Regel, dass Sie Ihre Tabellen aus vorherigen Versionen speichern und dann neu laden, um auf 5.1 zu aktualisieren.

Generell sollten Sie beim Upgrade von MySQL 5.0 auf 5.1 Folgendes tun:

  • Überprüfen Sie die Einträge in den weiter unten in diesem Abschnitt vorhandenen Änderungslisten darauf, ob Ihre Anwendungen hierdurch auf irgendeine Weise betroffen sein könnten. Achten Sie dabei insbesondere auf solche Änderungen, die mit dem Vermerk Inkompatible Änderung versehen sind. Diese führen zu Inkompatibilitäten mit früheren MySQL-Versionen und können Ihre Aufmerksamkeit bereits vor Durchführung des Upgrades erfordern.

  • Lesen Sie die Änderungshistorie von MySQL 5.1 im Hinblick auf die wesentlichen neuen Funktionen, die Sie in Version 5.1 verwenden können. Siehe auch Abschnitt D.1, „Änderungen in Release 5.1.x (Entwicklung)“.

  • Wenn Sie MySQL Server unter Windows betreiben, lesen Sie Abschnitt 2.3.15, „Upgrade von MySQL unter Windows“.

  • Wenn Sie die Replikation nutzen, finden Sie in Abschnitt 6.7, „Upgrade eines Replikationssetups“, weitere Informationen zur Aktualisierung Ihrer Replikationskonfiguration.

Die nachfolgenden Listen beschreiben Änderungen, die unter Umständen Anwendungen betreffen können und die Sie beachten sollten, wenn Sie auf Version 5.1 aktualisieren.

Änderungen beim Server:

  • Inkompatible Änderung: MySQL 5.1 implementiert die Unterstützung einer sehr flexiblen Plug-In-API, die das Laden und Entladen verschiedener Komponenten während der Laufzeit gestattet, ohne dass der Server neu gestartet werden müsste. Siehe auch Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“. Die Plug-In-API benötigt die Tabelle mysql.plugin. Wenn Sie von einer älteren MySQL-Version aktualisieren, sollten Sie den Befehl mysql_fix_privilege_tables ausführen, um diese Tabelle zu erstellen. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

    Plug-Ins werden in das Verzeichnis installiert, welches in der Systemvariablen plugin_dir spezifiziert ist. Diese Variable steuert auch die Position, von der der Server benutzerdefinierte Funktionen (User-Defined Functions, UDFs) lädt; dies stellt eine Änderung zu früheren Versionen von MySQL dar. Mithin müssen alle UDF-Bibliotheksdateien von jetzt an in das Plug-In-Verzeichnis installiert werden. Wenn Sie von einer älteren MySQL-Version aktualisieren, müssen Sie Ihre UDF-Dateien in das Plug-In-Verzeichnis migrieren.

  • Die Systemvariable table_cache wurde umbenannt in table_open_cache. Skripten, die table_cache verwenden, sollten so angepasst werden, dass sie den neuen Namen benutzen.

  • Inkompatible Änderung: Die Struktur der FULLTEXT-Indizes wurde in MySQL 5.1.6 geändert. Nach der Aktualisierung auf MySQL 5.1.6 oder höher müssen Sie die REPAIR TABLE-Anweisung für jede Tabelle aufrufen, die FULLTEXT-Indizes enthält.

SQL-Änderungen

  • Inkompatible Änderung: Der Namespace für Trigger wurde in MySQL 5.0.10 geändert. Vorher mussten Trigger-Namen je Tabelle eindeutig sein. Nun muss eine Eindeutigkeit innerhalb des Schemas (Datenbank) gegeben sein. Eine Auswirkung dieser Änderung besteht darin, dass die Syntax DROP TRIGGER nun statt eines Tabellennamens einen Schemanamen verwendet (wobei dieser Schemaname optional ist; wird er weggelassen, dann wird das aktuelle Schema verwendet).

    Wenn Sie von einer vorherigen Version von MySQL 5 auf MySQL 5.0.10 oder höher aktualisieren, müssen Sie alle Trigger löschen und sie neu erstellen; andernfalls wird DROP TRIGGER nach dem Upgrade nicht funktionieren. Gehen Sie am besten wie folgt vor:

    1. Aktualisieren Sie auf MySQL 5.0.10 oder höher, um auf die Trigger-Daten in der Tabelle INFORMATION_SCHEMA.TRIGGERS zugreifen zu können. (Dies sollte auch für Trigger aus Versionen vor 5.0.10 funktionieren.)

    2. Speichern Sie alle Trigger-Definitionen mithilfe der folgenden SELECT-Anweisung:

      SELECT CONCAT('CREATE TRIGGER ', t.TRIGGER_SCHEMA, '.', t.TRIGGER_NAME,
                    ' ', t.ACTION_TIMING, ' ', t.EVENT_MANIPULATION, ' ON ',
                    t.EVENT_OBJECT_SCHEMA, '.', t.EVENT_OBJECT_TABLE,
                    ' FOR EACH ROW ', t.ACTION_STATEMENT, '//' )
      INTO OUTFILE '/tmp/triggers.sql'
      FROM INFORMATION_SCHEMA.TRIGGERS AS t;
      

      Die Anweisung verwendet INTO OUTFILE, d. h., Sie müssen die Berechtigung FILE haben. Die Datei wird auf dem Serverhost erstellt; wenn Sie wollen, können Sie einen anderen Dateinamen verwenden. Um hundertprozentig sicher zu sein, überprüfen Sie die Trigger-Definitionen in der Datei triggers.sql und fertigen unter Umständen eine Sicherung der Datei an.

    3. Beenden Sie den Server und löschen Sie alle Trigger, indem Sie sämtliche .TRG-Dateien in Ihren Datenbankverzeichnissen entfernen. Wechseln Sie dann in Ihr Datenverzeichnis und setzen Sie folgenden Befehl ab:

      shell> rm */*.TRG
      
    4. Starten Sie den Server und erstellen Sie alle Trigger mithilfe der triggers.sql-Datei neu: In meinem Fall sah dies beispielsweise so aus:

      mysql> delimiter // ;
      mysql> source /tmp/triggers.sql //
      
    5. Vergewissern Sie sich, dass alle Trigger mit der SHOW TRIGGERS-Anweisung erfolgreich erstellt wurden.

  • Inkompatible Änderung: MySQL 5.1.6 hat die Berechtigung TRIGGER neu eingeführt. Zuvor benötigte man die Berechtigung SUPER zum Erstellen oder Löschen von Triggern. Jetzt ist für derartige Vorgänge die Berechtigung TRIGGER erforderlich. Dies ist eine Sicherheitsoptimierung, da Sie Benutzern nun nicht länger die Berechtigung SUPER gewähren müssen, damit diese Trigger erstellen können. Allerdings wurde die Anforderung, dass das Konto, welches in der DEFINER-Klausel eines Triggers genannt wird, die Berechtigung SUPER haben muss, dadurch ersetzt, dass das Konto nun die Berechtigung TRIGGER erfordert. Wenn Sie von einer früheren MySQL 5-Version auf MySQL 5.1.6 oder höher aktualisieren, sollten Sie überprüfen, welche Konten in der DEFINER-Klausel vorhandener Trigger aufgeführt sind, und sicherstellen, dass diese Konten die Berechtigung TRIGGER haben. Andernfalls werden sie bei Aktivierung fehlschlagen. Mit der folgenden Anweisung können Sie ermitteln, welche Konten in den DEFINER-Klauseln aufgeführt sind:

    SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.TRIGGERS;
    

    Wenn Sie diesen Konten die Berechtigung TRIGGER gewährt haben, können Sie die Berechtigung SUPER für diejenigen Konten widerrufen, die Sie nicht anderweitig benötigen.

  • Einige Schlüsselwörter sind in MySQL 5.1 reserviert, bei denen dies in MySQL 5.0 nicht der Fall war. Siehe auch Abschnitt 9.5, „Ist MySQL pingelig hinsichtlich reservierter Wörter?“.

  • Die Anweisungen INSTALL PLUGIN und UNINSTALL PLUGIN, die für die Plug-In-API verwendet werden, sind neu. Gleiches gilt für die Klausel WITH PARSER der FULLTEXT-Indexerstellung, die ein Parser-Plug-In mit einem Volltextindex verknüpft. Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“.

2.10.2. Upgrade auf eine andere Architektur

Sie können die .frm-, .MYI- und .MYD-Dateien für MyISAM-Tabellen zwischen verschiedenen Architekturen kopieren, die dasselbe Fließkommaformat unterstützen. (MySQL sorgt automatisch für das erforderliche Austauschen von Bytes.) Siehe auch Abschnitt 14.1, „Die MyISAM-Speicher-Engine“.

In Fällen, in denen Sie Datenbanken zwischen verschiedenen Architekturen transferieren müssen, können Sie mit mysqldump eine Datei mit SQL-Anweisungen erstellen. Danach übertragen Sie die Datei auf das andere System und verwenden es dort als Eingabe für den mysql-Client.

Mit mysqldump --help erfahren Sie, welche Optionen vorhanden sind. Wenn Sie die Daten auf eine neuere Version von MySQL verschieben, sollten Sie mysqldump --opt verwenden, denn so profitieren Sie von allen Optimierungen, die zu einer kleineren Speicherdatei führen, welche sich auch schneller verarbeiten lässt.

Die einfachste (wenn auch nicht schnellste) Möglichkeit, eine Datenbank zwischen zwei Computern zu verschieben, besteht darin, die folgenden Befehle auf dem Rechner auszuführen, auf dem die Datenbank sich befindet:

shell> mysqladmin -h 'other_hostname' create db_name
shell> mysqldump --opt db_name | mysql -h 'other_hostname' db_name

Wollen Sie eine Datenbank von einem entfernten Computer über ein langsames Netzwerk kopieren, dann können Sie die folgenden Befehle verwenden:

shell> mysqladmin create db_name
shell> mysqldump -h 'other_hostname' --opt --compress db_name | mysql db_name

Sie können die Daten auch in einer Datei ablegen, diese auf den Zielcomputer übertragen und dann dort in die Datenbank einladen. So können Sie etwa eine Datenbank wie folgt in einer komprimierten Datei auf dem Quellcomputer speichern:

shell> mysqldump --quick db_name | gzip > db_name.gz

Übertragen Sie die Datei mit den Datenbankinhalten auf den Zielcomputer und führen Sie dort folgende Befehle aus:

shell> mysqladmin create db_name
shell> gunzip < db_name.gz | mysql db_name

Sie können auch mysqldump und mysqlimport zur Übertragung der Datenbank verwenden. Bei großen Tabellen ist das wesentlich schneller als die einfache Verwendung von mysqldump. Bei den folgenden Befehlen steht DUMPDIR für den vollständigen Pfadnamen des Verzeichnisses, in dem Sie die Ausgabe von mysqldump speichern.

Zunächst erstellen Sie das Verzeichnis für die Ausgabedateien und speichern dann die Datenbank:

shell> mkdir DUMPDIR
shell> mysqldump --tab=DUMPDIR db_name

Danach übertragen Sie die Dateien im Verzeichnis DUMPDIR in das entsprechende Verzeichnis auf dem Zielcomputer und laden die Dateien dann dort in MySQL ein:

shell> mysqladmin create db_name           # create database
shell> cat DUMPDIR/*.sql | mysql db_name   # create tables in database
shell> mysqlimport db_name DUMPDIR/*.txt   # load data into tables

Vergessen Sie nicht, die mysql-Datenbank zu kopieren, da darin die Grant-Tabellen gespeichert sind. Unter Umständen müssen Sie die Befehle auf dem neuen Computer als MySQL-root-Benutzer ausführen, bis Ihre mysql-Datenbank vor Ort ist.

Nachdem Sie die mysql-Datenbank auf dem neuen System importiert haben, führen Sie mysqladmin flush-privileges aus, damit der Server die Grant-Tabelle-Daten neu lädt.

2.11. Downgrade von MySQL

Dieser Abschnitt erläutert, was Sie tun sollten, um in dem unwahrscheinlichen Fall, dass eine ältere MySQL-Version besser funktionierte als eine neue Version, ein Downgrade durchzuführen.

Führen Sie das Downgrade innerhalb derselben Release-Serie durch (z. B. von 5.0.13 auf 5.0.12), dann müssen Sie in der Regel nur die neuen Binärdateien über die alten installieren. Mit den Datenbanken müssen Sie nichts machen. Allerdings empfiehlt es sich wie immer auch hier, ein Backup zu erstellen.

Die folgende Checkliste sollten Sie immer überprüfen, wenn Sie ein Downgrade durchführen:

  • Lesen Sie den Abschnitt zur Aktualisierung auf die Release-Serie, von der aus Sie das Downgrade durchführen, um sicherzustellen, dass diese nicht bestimmte Funktionen enthält, die Sie doch benötigen. Siehe Abschnitt 2.10, „MySQL aktualisieren (Upgrade/Downgrade)“.

  • Wenn für die betreffende Version ein Abschnitt zum Downgrade vorhanden ist, sollten Sie diesen ebenfalls sorgfältig lesen.

In den meisten Fällen können Sie die Format- und Datendateien von MySQL zwischen verschiedenen Versionen derselben Architektur hin- und herschieben, solange Sie die Release-Serie nicht wechseln.

Wenn Sie das Downgrade von einer Release-Serie auf eine andere durchführen, kann es bei den Speicherformaten der Tabellen zu Inkompatibilitäten kommen. In diesem Fall können Sie Ihre Tabellen vor dem Downgrade mithilfe von mysqldump speichern. Laden Sie nach Abschluss des Downgrades die Speicherauszugsdatei mit mysql oder mysqlimport, um die Tabellen neu zu erstellen. Beispiele finden Sie in Abschnitt 2.10.2, „Upgrade auf eine andere Architektur“.

Das offensichtlichste Symptom bei Downgrade-Inkompatibilitäten des Tabellenformats besteht darin, dass Sie Tabellen nicht öffnen können. Gehen Sie in diesem Fall wie folgt vor:

  1. Beenden Sie den älteren MySQL Server, auf den Sie das Downgrade durchführen.

  2. Starten Sie den neueren MySQL Server, von dem aus Sie das Downgrade durchführen.

  3. Speichern Sie alle Tabellen, auf die der ältere Server nicht zugreifen konnte, mithilfe von mysqldump, um eine Speicherauszugsdatei zu erstellen.

  4. Beenden Sie den neueren MySQL Server und starten Sie den älteren neu.

  5. Laden Sie die Speicherauszugsdatei in den älteren Server. Nun sollten Sie auf Ihre Tabellen zugreifen können.

2.12. Betriebssystemspezifische Anmerkungen

2.12.1. Linux (alle Linux-Versionen)

Dieser Abschnitt beschreibt Probleme, die unter Linux aufgetreten sind. Die ersten Teilabschnitte schildern dabei betriebssystemspezifische Probleme allgemeiner Art, Probleme in Bezug auf die Verwendung von Binär- oder Quelldistributionen und Probleme nach Abschluss der Installation. Im Weiteren werden Probleme erläutert, die unter Linux auf bestimmten Plattformen auftreten.

Beachten Sie, dass die meisten dieser Probleme unter älteren Linux-Versionen auftreten. Wenn Sie eine neuere Version verwenden, werden Sie wahrscheinlich gar nichts bemerken.

2.12.1.1. Anmerkungen zum Betriebssystem Linux

MySQL setzt die Linux-Version 2.0 oder höher voraus.

Warnung: Auf SMP-Systemen sind merkwürdige Probleme bei der Kombination Linux 2.2.14 und MySQL aufgetreten. Ferner haben uns einige MySQL-Benutzer mitgeteilt, dass sie schwerwiegende Stabilitätsprobleme bei der Verwendung von MySQL mit dem Kernel 2.2.14 hatten. Wenn Sie diesen Kernel verwenden, sollten Sie auf die Kernel-Version 2.2.19 (oder höher) oder auf Version 2.4 aktualisieren. Bei Multiprozessorsystemen sollten Sie die Verwendung der Kernel-Version 2.4 in jedem Fall in Betracht ziehen, da Sie dadurch einen erheblichen Geschwindigkeitszuwachs erfahren werden. Außerdem wird sich so die Stabilität Ihres Systems erhöhen.

Wenn Sie LinuxThreads verwenden, sollten mindestens drei laufende mysqld-Prozesse angezeigt werden. Das sind tatsächlich Threads. Ein Thread ist für den LinuxThreads-Manager, ein weiterer zur Verwaltung der Verbindungen und der dritte zur Verwaltung von Alarmmeldungen und Signalen.

2.12.1.2. Anmerkungen zur Binärdistribution (Linux)

Die MySQL-Binär- und -RPM-Releases für die Linux-Intel-Kombination sind für optimale Geschwindigkeit konfiguriert. Wir versuchen immer, den schnellsten stabilen Compiler zu finden, der verfügbar ist.

Der Binär-Release wird mit -static verknüpft, d. h., Sie müssen sich in der Regel keine Gedanken darüber machen, welche Version der Systembibliotheken Sie haben. Sie müssen auch LinuxThreads nicht installieren. Ein mit -static verknüpftes Programm ist ein wenig größer als ein dynamisch verknüpftes Programm, aber auch ein bisschen schneller (ca. 3 bis 5 Prozent). Allerdings besteht ein Problem bei statisch verknüpften Programmen darin, dass Sie keine UDFs (User-Defined Functions, benutzerdefinierte Funktionen) verwenden können. Wenn Sie UDFs schreiben oder verwenden wollen (dies ist nur etwas für C- oder C++-Programmierer), dann müssen Sie MySQL selbst mit dynamischer Verknüpfung kompilieren.

Ein bekanntes Problem bei Binärdistributionen besteht darin, dass auf älteren Linux-Systemen, die libc verwenden (also z. B. Red Hat 4.x oder Slackware), gelegentlich Schwierigkeiten in Verbindung mit der Auflösung der Hostnamen auftreten (diese sind jedoch nicht schwerwiegend). Verwendet Ihr System libc statt glibc2, dann werden Sie wahrscheinlich Probleme in Verbindung mit der Hostnamensauflösung und getpwnam() haben. Diese treten auf, weil glibc (leider) auf einige externe Bibliotheken angewiesen ist, um die Namensauflösung und getpwent() implementieren zu können – und zwar auch dann, wenn mit der Option -static kompiliert wurde. Diese Probleme äußern sich auf zweierlei Weise:

  • Bei der Ausführung von mysql_install_db erhalten Sie die folgende Fehlermeldung:

    Sorry, the host 'xxxx' could not be looked up
    

    Sie können dieses Problem beheben, indem Sie mysql_install_db --force ausführen, was dazu führt, dass der Test resolveip in mysql_install_db nicht ausgeführt wird. Der Nachteil besteht darin, dass Sie Hostnamen nicht in Grant-Tabellen verwenden können; mit Ausnahme von localhost müssen Sie dann immer die entsprechenden IP-Adressen angeben. Wenn Sie eine alte MySQL-Version verwenden, die --force nicht unterstützt, dann müssen Sie den Test resolveip in mysql_install manuell mit einem Texteditor entfernen.

  • Unter Umständen erhalten Sie auch die folgende Fehlermeldung, wenn Sie versuchen, mysqld mit der Option --user auszuführen:

    getpwnam: No such file or directory
    

    Um dieses Problem zu umgehen, starten Sie mysqld mit dem Befehl su statt durch Angabe der Option --user. Auf diese Weise ändert das System die Benutzerkennung des mysqld-Prozesses selbst, d. h. mysqld muss dies nicht erledigen.

Eine andere Lösung, die beide Probleme behebt, besteht darin, keine Binärdistribution zu verwenden. Beschaffen Sie sich eine MySQL-Quelldistribution (im RPM- oder tar.gz-Format) und installieren Sie diese stattdessen.

Bei manchen Linux 2.2-Versionen erhalten Sie unter Umständen die Fehlermeldung Resource temporarily unavailable, wenn Clients über TCP/IP sehr schnell viele neue Verbindungen mit einem mysqld-Server herstellen. Das Problem besteht darin, dass bei Linux zwischen dem Moment, zu dem ein TCP/IP-Socket von Ihnen geschlossen wird, und dem Zeitpunkt der tatsächlichen Freigabe des Sockets eine Verzögerung auftritt. Es ist nur für eine endliche Anzahl von TCP/IP-Slots Platz vorhanden; deswegen sind zu wenig Ressourcen vorhanden, wenn Clients innerhalb kurzer Zeit zu viele neue TCP/IP-Verbindungen anfordern. Beispielsweise tritt dieser Fehler auf, wenn Sie den MySQL-Benchmark test-connect über TCP/IP ausführen.

Wir haben dieses Problem einige Male auf verschiedenen Linux-Mailinglisten beschrieben, konnten aber niemals eine geeignete Lösung finden. Der einzige bekannte „Fix“ besteht darin, dass Clients Permanentverbindungen verwenden oder Sie, wenn Sie den Datenbankserver und die Clients auf demselben Rechner ausführen, Verbindungen via Unix-Socketdatei statt TCP/IP-Verbindungen einsetzen.

2.12.1.3. Anmerkungen zur Linux-Quelldistribution

Die folgenden Anmerkungen zu glibc betreffen Sie nur, wenn Sie MySQL selbst erstellen. Wenn Sie Linux auf einem x86-Computer ausführen, sollten Sie in den meisten Fällen besser unsere Binärdistribution verwenden. Wir verknüpfen unsere Binärdateien zur jeweils am besten gepatchten Version von glibc, die wir finden können, und mit den bestmöglichen Compiler-Einstellungen, um sie so für hochbeanspruchte Server zu optimieren. Für normale Benutzer ist unsere Binärdistribution auch in Setups mit vielen gleichzeitigen Verbindungen oder Tabellen, die die 2-Gbyte-Grenze sprengen, in den meisten Fällen erste Wahl. Wenn Sie nach der Lektüre des folgenden Texts nicht genau wissen, wie Sie vorgehen sollen, probieren Sie zunächst unsere Binärdatei aus, um zu ermitteln, ob diese für Ihre Anforderungen geeignet ist. Sollten Sie feststellen, dass dies nicht der Fall ist, dann sollten Sie eine selbsterstellte Version erproben. In diesem Fall würden wir uns freuen, wenn Sie uns dies mitteilen würden, damit wir beim nächsten Mal eine bessere Binärdistribution erstellen können.

MySQL verwendet LinuxThreads unter Linux. Wenn Sie eine alte Linux-Version verwenden, die glibc2 nicht enthält, dann müssen Sie LinuxThreads installieren, bevor Sie MySQL zu kompilieren versuchen. Sie bekommen LinuxThreads unter http://dev.mysql.com/downloads/os-linux.html.

Beachten Sie, dass glibc-Versionen bis einschließlich 2.1.1 beim Umgang mit pthread_mutex_timedwait(), welches beim Absetzen von INSERT DELAYED-Anweisungen verwendet wird, einen schweren Bug aufweisen. Wir empfehlen Ihnen, INSERT DELAYED erst nach der Aktualisierung von glibc zu verwenden.

Beachten Sie, dass der Linux-Kernel und die LinuxThread-Bibliothek standardmäßig maximal 1024 Threads verwalten können. Wenn Sie mehr als 1000 gleichzeitige Verbindungen vorsehen, dann müssen Sie wie folgt ein paar Änderungen an LinuxThreads vornehmen:

  • Erhöhen Sie den Wert PTHREAD_THREADS_MAX in sysdeps/unix/sysv/linux/bits/local_lim.h auf 4096 und verringern Sie STACK_SIZE in linuxthreads/internals.h auf 256 Kbyte. Die Pfade sind relativ zum Stammverzeichnis von glibc. (Beachten Sie, dass MySQL bei 600 bis 1000 Verbindungen nicht stabil läuft, wenn STACK_SIZE auf der Vorgabe von 2 Mbyte belassen wird.)

  • Kompilieren Sie LinuxThreads erneut, um eine neue libpthread.a-Bibliothek zu erzeugen, und verknüpfen Sie MySQL dann wieder damit.

Weitere Informationen dazu, wie Sie Thread-Beschränkungen in LinuxThreads umgehen, finden Sie unter http://www.volano.com/linuxnotes.html.

Es gibt noch ein weiteres Problem, dass die Performance von MySQL insbesondere auf SMP-Systemen erheblich beeinträchtigt. glibc 2.1 weist eine sehr schwache Mutex-Implementierung in LinuxThreads für Programme mit vielen Threads auf, die das Mutex nur für eine kurze Zeit halten. Die Folgen sind paradox: Wenn Sie MySQL mit einer nicht modifizierten LinuxThreads-Version verbinden, können Sie die Leistungsfähigkeit von MySQL in vielen Fällen verbessern, indem Sie Prozessoren aus dem SMP entfernen! Wir haben für glibc 2.1.3 unter http://dev.mysql.com/Downloads/Linux/linuxthreads-2.1-patch einen Patch bereitgestellt, um dieses Verhalten zu korrigieren.

Bei glibc 2.2.2 verwendet MySQL das adaptive Mutex, welches wesentlich besser ist als bei glibc 2.1.3 (auch in der gepatchten Version). Wir wollen aber darauf hinweisen, dass der aktuelle Mutex-Code in glibc 2.2.2 gelegentlich zu viel des Guten tut, wodurch die MySQL-Performance wieder beeinträchtigt wird. Die Wahrscheinlichkeit, dass ein solches Verhalten auftritt, kann dadurch verringert werden, dass man dem Prozess mysqld die höchste Priorität zuweist. Wir konnten das Problem zudem ebenfalls mit einem Patch beheben, den Sie unter http://dev.mysql.com/Downloads/Linux/linuxthreads-2.2.2.patch finden. Dieser Patch korrigiert alle drei hier beschriebenen Probleme: das STACK_SIZE-Problem, das Problem der Thread-Beschränkung und das Mutex-Problem. Er muss im Verzeichnis linuxthreads mit patch -p0 </tmp/linuxthreads-2.2.2.patch angewendet werden. Wir hoffen, dass er in irgendeiner Form in zukünftigen Releases von glibc 2.2 enthalten sein wird. In jedem Fall müssen Sie bei der Verknüpfung mit glibc 2.2.2 STACK_SIZE und PTHREAD_THREADS_MAX korrigieren. Wir hoffen, dass die Standardeinstellungen in Zukunft auf Werte korrigiert werden, die für hochbeanspruchte MySQL Server geeigneter sind; in diesem Fall ließen sich die Befehle zur Erstellung eines eigenen Builds auf ./configure; make; make install beschränken.

Wir empfehlen Ihnen, diese Patches zur Erstellung einer speziellen statischen Version von libpthread.a zu verwenden und diese dann nur für die statische Verknüpfung mit MySQL zu verwenden. Wir wissen, dass diese Patches in Verbindung mit MySQL einwandfrei funktionieren und die Leistungsfähigkeit erheblich verbessern, können jedoch nichts zu ihren Auswirkungen auf andere Anwendungen sagen. Wenn Sie andere Anwendungen verknüpfen, die LinuxThreads mit einer anderen als der gepatchten statischen Version der Bibliothek benötigen, oder eine gepatchte gemeinsame Version erstellen und diese auf Ihrem System installieren, dann tun Sie dies auf eigenes Risiko.

Sollten während der Installation von MySQL merkwürdige Probleme auftreten oder bestimmte gängige Hilfsprogramme stehen bleiben, dann ist dies mit hoher Wahrscheinlichkeit durch die Bibliothek oder den Compiler verursacht. Wenn dies der Fall ist, dann können Sie diese Probleme mithilfe unserer Binärdistribution lösen.

Wenn Sie eigene MySQL-Clientprogramme verknüpfen, dann wird unter Umständen die folgende Fehlermeldung zur Laufzeit angezeigt:

ld.so.1: fatal: libmysqlclient.so.#:
open failed: No such file or directory

Dieses Problem lässt sich auf eine der folgenden Weisen lösen:

  • Verknüpfen Sie die Clients mit dem Flag -Wl,r/full/path/to/libmysqlclient.so statt mit -Lpath.

  • Kopieren Sie libmysqclient.so nach /usr/lib.

  • Fügen Sie den Pfadnamen des Verzeichnisses, in dem sich libmysqlclient.so befindet, der Umgebungsvariablen LD_RUN_PATH hinzu, bevor Sie den Client ausführen.

Wenn Sie den Fujitsu-Compiler (fcc/FCC) verwenden, treten unter Umständen Probleme bei der Kompilierung von MySQL auf, weil die Linux-Header-Dateien sehr stark auf gcc ausgerichtet sind. Der folgende configure-Befehl sollte auch für fcc/FCC funktionieren:

CC=fcc CFLAGS="-O -K fast -K lib -K omitfp -Kpreex -D_GNU_SOURCE \
    -DCONST=const -DNO_STRTOLL_PROTO" \
CXX=FCC CXXFLAGS="-O -K fast -K lib \
    -K omitfp -K preex --no_exceptions --no_rtti -D_GNU_SOURCE \
    -DCONST=const -Dalloca=__builtin_alloca -DNO_STRTOLL_PROTO \
    '-D_EXTERN_INLINE=static __inline'" \
./configure \
    --prefix=/usr/local/mysql --enable-assembler \
    --with-mysqld-ldflags=-all-static --disable-shared \
    --with-low-memory

2.12.1.4. Anmerkungen zu Linux: nach der Installation

mysql.server finden Sie im Verzeichnis support-files, das sich im MySQL-Installationsverzeichnis befindet, oder in einem MySQL-Source-Tree. Sie können es als /etc/init.d/mysql installieren, um MySQL automatisch zu starten und zu beenden. Siehe auch Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.

Wenn MySQL nicht genügend Dateien oder Verbindungen öffnen kann, haben Sie Linux möglicherweise nicht so konfiguriert, dass es genug Dateien verwalten kann.

Unter Linux 2.2 und höher können Sie die Anzahl zugewiesener Datei-Handles wie folgt überprüfen:

shell> cat /proc/sys/fs/file-max
shell> cat /proc/sys/fs/dquot-max
shell> cat /proc/sys/fs/super-max

Wenn Sie mehr als 16 Mbyte Speicher haben, sollten Sie Ihre Skripten durch einen Zusatz in der Art des folgenden ergänzen (z. B. /etc/init.d/boot.local unter SuSE Linux):

echo 65536 > /proc/sys/fs/file-max
echo 8192 > /proc/sys/fs/dquot-max
echo 1024 > /proc/sys/fs/super-max

Sie können die echo-Befehle auf der Befehlszeile auch als root ausführen, aber diese Einstellungen gehen beim nächsten Neustart Ihres Computers verloren.

Alternativ stellen Sie diese Parameter für den Start mithilfe des Tools sysctl ein, welches von vielen Linux-Distributionen (einschließlich SuSE Linux 8.0 und höher) verwendet wird. Tragen Sie die folgenden Werte in eine Datei namens /etc/sysctl.conf ein:

# Increase some values for MySQL
fs.file-max = 65536
fs.dquot-max = 8192
fs.super-max = 1024

Außerdem sollten Sie Folgendes in /etc/my.cnf ergänzen:

[mysqld_safe]
open-files-limit=8192

Auf diese Weise konfigurieren Sie für den Server eine Gesamtbeschränkung der Verbindungen und offenen Dateien auf 8192.

Die Konstante STACK_SIZE in LinuxThreads steuert das Spacing von Thread-Stapeln im Adressraum. Dieses muss groß genug sein, um genügend Raum für jeden einzelnen Thread-Stapel bereitzustellen, aber auch klein genug, um zu verhindern, dass der Stapel bestimmter Threads mit den globalen mysqld-Daten kollidiert. Leider trennt, wie wir durch Experimentieren festgestellt haben, die Linux-Implementierung von mmap() einen bereits zugeordneten Bereich wieder auf, wenn Sie sie anweisen, die Zuordnung einer derzeit verwendeten Adresse aufzulösen: Es wird kein Fehler zurückgegeben, sondern alle Daten auf der gesamten Seite werden auf null gesetzt. Insofern hängt die Sicherheit von mysqld und allen anderen Thread-basierten Anwendungen vom „wohlwollenden“ Verhalten des Codes ab, der die Threads erstellt. Der Benutzer muss Maßnahmen ergreifen, um sicherzustellen, dass die Anzahl laufender Threads jederzeit so niedrig ist, dass es nicht zum Konflikt zwischen den Thread-Stapeln und dem globalen Bereich kommt. Bei mysqld sollten Sie dieses Verhalten erzwingen, indem Sie der Variablen max_connections einen sinnvollen Wert zuweisen.

Wenn Sie MySQL selbst erstellen, können Sie LinuxThreads für eine bessere Stapelnutzung patchen. Siehe auch Abschnitt 2.12.1.3, „Anmerkungen zur Linux-Quelldistribution“. Wenn Sie LinuxThreads aber nicht patchen wollen, sollten Sie max_connections auf einen Wert von maximal 500 setzen. Arbeiten Sie mit einem großen Schlüsselpuffer, großen Heap-Tabellen oder anderen Materialien, die zu einer umfassenden Speicherzuweisung durch mysqld führen, oder verwenden Sie die Kernel-Version 2.2 mit einem 2-Gbyte-Patch, dann sollte der Wert noch kleiner sein. Wenn Sie unsere Binär- oder RPM-Version verwenden, können Sie max_connections beruhigt auf 1500 setzen, sofern Sie weder große Schlüsselpuffer noch datenintensive Heap-Tabellen benutzen. Je stärker Sie STACK_SIZE in LinuxThreads verringern, desto mehr Threads können Sie gefahrlos erstellen. Wir empfehlen Werte zwischen 128 und 256 Kbyte.

Wenn Sie zahlreiche nebenläufige Verbindungen verwenden, können Sie einem „Feature“ im Kernel 2.2 zum Opfer fallen, das Fork-Bomb-Angriffe verhindern soll, indem Prozesse, die untergeordnete Prozesse aufspalten oder klonen, eine Strafe erhalten. Hierdurch wird die Skalierbarkeit zunehmend beeinträchtigt, je größer die Anzahl nebenläufiger Clients ist. Auf Systemen mit nur einem Prozessor manifestiert sich dies unseren Beobachtungen zufolge in einer sehr langsamen Thread-Erstellung: Die Verbindungsherstellung mit MySQL kann sehr lange (bis zu einer Minute) dauern; Gleiches gilt für das Abbauen der Verbindung. Auf Multiprozessorsystemen haben wir bei steigender Clientanzahl eine allmähliche Abnahme der Abfragegeschwindigkeit feststellen können. Im Zuge der Lösung dieses Problems haben wir von einem unserer Benutzer einen Kernel-Patch erhalten, der seinen Angaben zufolge auf seiner Site geholfen haben soll. Dieser Patch ist unter http://dev.mysql.com/Downloads/Patches/linux-fork.patch verfügbar. Wir haben den Patch sowohl in Entwicklungs- als auch in Produktionssystemen umfassend getestet und festgestellt, dass sich die MySQL-Performance hierdurch erheblich verbessert, ohne dass es zu Problemen kommt. Deswegen empfehlen wir Benutzern, die hochbeanspruchte Server mit Kernel-Version 2.2 betreiben, seine Anwendung.

In der Kernel-Version 2.4 wurde das Problem behoben; wenn Sie also nicht mit der aktuellen Leistungsfähigkeit Ihres Systems zufrieden sind, ist es unter Umständen einfacher, ein Upgrade auf Version 2.4 durchzuführen, statt Ihren 2.2-Kernel zu patchen. Auf SMP-Systemen erhalten Sie neben der Problembehandlung zusätzlich noch eine beträchtliche SMP-Steigerung.

Wir haben MySQL mit dem Kernel 2.4 auf einem System mit zwei Prozessoren getestet und festgestellt, dass sich MySQL wesentlich besser skalieren lässt. Es gab im gesamten Testbereich bis 1000 Clients praktisch keine Verringerung des Abfragedurchsatzes, und der MySQL-Skalierungsfaktor (berechnet als Verhältnis des maximalen Durchsatzes zum Durchsatz pro Client) lag bei 180 %. Ähnliche Ergebnisse konnten wir auf einem System mit vier CPUs beobachten: praktisch keine Verlangsamung, während die Anzahl der Clients auf 1000 erhöht wurde, und dazu ein Skalierungsfaktor von 300 %. Basierend auf diesen Ergebnissen empfehlen wir für hochbeanspruchte SMP-Server mit dem Kernel 2.2 derzeit in jedem Fall eine Aktualisierung auf Kernel 2.4.

Unseren Beobachtungen zufolge ist es unumgänglich, den Prozess mysqld unter dem Kernel 2.4 mit höchstmöglicher Priorität auszuführen, um maximale Leistung zu erzielen. Dies ist möglich, indem der Befehl renice -20 $$ zu mysqld_safe hinzugefügt wird. Bei unseren Tests mit einem 4-CPU-Rechner haben wir eine 60-prozentige Durchsatzsteigerung bei 400 Clients erzielt.

Ferner versuchen wir derzeit auch, weitere Informationen dazu zu sammeln, wie gut MySQL mit dem Kernel 2.4 auf 4-Wege- und 8-Wege-Systemen funktioniert. Wenn Sie Zugang zu einem solchen System haben und einige Benchmarks erstellt haben, möchten wir Sie bitten, eine E-Mail mit den Ergebnissen an zu senden. Wir werden diese prüfen und ggf. in das Handbuch aufnehmen.

Wenn Sie einen abgestürzten mysqld-Serverprozess mit ps erkennen, dann weist dies normalerweise darauf hin, dass Sie einen Bug in MySQL entdeckt haben oder eine Tabelle beschädigt ist. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

Um, wenn mysqld mit einem SIGSEGV-Signal abstürzt, unter Linux einen Speicherauszug zu erhalten, können Sie mysqld mit der Option --core-file starten. Beachten Sie, dass Sie wahrscheinlich auch die Größe der Speicherauszugsdatei erhöhen müssen, indem Sie ulimit -c 1000000 zu mysqld_safe hinzufügen oder mysqld_safe mit --core-file-size=1000000 starten. Siehe auch Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“.

2.12.1.5. Anmerkungen zu Linux x86

MySQL erfordert libc 5.4.12 oder höher. Bekanntermaßen funktioniert es mit libc 5.4.46. glibc 2.0.6 und höher sollten ebenfalls keine Probleme bereiten. Es hat in der Vergangenheit einige Probleme mit den glibc-RPMs von Red Hat gegeben. Prüfen Sie also bei Auftreten von Problemen, ob Updates vorhanden sind. Die glibc-RPMs 2.0.7-19 und 2.0.7-29 RPMs funktionieren ebenfalls einwandfrei.

Wenn Sie Red Hat 8.0 oder eine neue glibc 2.2.x-Bibliothek verwenden, werden Sie unter Umständen feststellen, dass sich mysqld in gethostbyaddr() aufhängt. Dies geschieht, weil die neue glibc-Bibliothek eine Stapelgröße von mehr als 128 Kbyte für diesen Aufruf benötigt. Um das Problem zu beheben, starten Sie mysqld mit der Option --thread-stack=192K. (Verwenden Sie -O thread_stack=192K bei MySQL vor Version 4.) Diese Stapelgröße ist bei MySQL 4.0.10 und höher voreingestellt, weswegen das Problem bei diesen Versionen nicht auftreten sollte.

Wenn Sie zur Kompilierung von MySQL gcc 3.0 und höher verwenden, müssen Sie die Bibliothek libstdc++v3 vor der MySQL-Kompilierung installieren, da Sie andernfalls bei der Verknüpfung eine Fehlermeldung zu einem fehlenden __cxa_pure_virtual-Symbol erhalten.

Bei einigen älteren Linux-Distributionen erzeugt configure unter Umständen einen Fehler wie den folgenden:

Syntax error in sched.h. Change _P to __P in the
/usr/include/sched.h file.
See the Installation chapter in the Reference Manual.

Tun Sie einfach, was die Fehlermeldung vorschlägt: Ergänzen Sie den Makronamen _P, der nur einen Unterstrich aufweist, um einen weiteren Unterstrich und probieren Sie es dann erneut.

Bei der Kompilierung werden unter Umständen Warnungen angezeigt. Die folgenden können dabei ignoriert werden:

mysqld.cc -o objs-thread/mysqld.o
mysqld.cc: In function `void init_signals()':
mysqld.cc:315: warning: assignment of negative value `-1' to
`long unsigned int'
mysqld.cc: In function `void * signal_hand(void *)':
mysqld.cc:346: warning: assignment of negative value `-1' to
`long unsigned int'

Wenn mysqld beim Start immer einen Speicherauszug erzeugt, kann dies möglicherweise durch eine veraltete /lib/libc.a verursacht worden sein. Versuchen Sie sie umzubenennen, entfernen Sie sql/mysqld, führen Sie ein neues make install durch und probieren Sie es dann erneut. Dieses Problem wurde für einige Slackware-Installationen gemeldet.

Wenn Sie die folgende Fehlermeldung beim Verknüpfen von mysqld erhalten, ist Ihre libg++.a nicht korrekt installiert:

/usr/lib/libc.a(putc.o): In function `_IO_putc':
putc.o(.text+0x0): multiple definition of `_IO_putc'

Sie können die Verwendung von libg++.a vermeiden, indem Sie configure wie folgt ausführen:

shell> CXX=gcc ./configure

2.12.1.6. Anmerkungen zu Linux SPARC

Bei einigen Implementierungen ist readdir_r() fehlerhaft. Das Symptom besteht darin, dass die SHOW DATABASES-Anweisung immer eine leere Menge zurückgibt. Dies lässt sich durch Entfernen von HAVE_READDIR_R aus der Datei config.h nach der Konfiguration, aber vor der Kompilierung durchführen.

2.12.1.7. Anmerkungen zu Linux Alpha

Wir haben MySQL 5.1 unter Linux Alpha mit unseren Benchmarks und unserer Testsuite getestet, und es scheint gut zu funktionieren.

Derzeit erstellen wir die MySQL-Binärpakete unter SuSE Linux 7.0 für AXP, Kernel 2.4.4-SMP, Compaq C-Compiler (V6.2-505) und Compaq C++-Compiler (V6.3-006) auf einem Compaq DS20-Computer mit einem Alpha EV6-Prozessor.

Sie finden die genannten Compiler unter http://www.support.compaq.com/alpha-tools/. Durch Verwendung dieser Compiler anstelle von gcc erhalten wir eine um ca. 9 bis 14 Prozent bessere MySQL-Performance.

Bei MySQL unter Alpha verwenden wir das Flag -arch generic für unsere Kompilierungsoptionen. Hierdurch ist sichergestellt, dass die Binärdatei auf allen Alpha-Prozessoren läuft. Wir kompilieren auch statisch, um Probleme mit Bibliotheken zu vermeiden. Der configure-Befehl sieht wie folgt aus:

CC=ccc CFLAGS="-fast -arch generic" CXX=cxx \
CXXFLAGS="-fast -arch generic -noexceptions -nortti" \
./configure --prefix=/usr/local/mysql --disable-shared \
    --with-extra-charsets=complex --enable-thread-safe-client \
    --with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared

Wenn Sie egcs benutzen wollen, funktioniert unserer Erfahrung nach folgende configure-Zeile:

CFLAGS="-O3 -fomit-frame-pointer" CXX=gcc \
CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors \
    -fno-exceptions -fno-rtti" \
./configure --prefix=/usr/local/mysql --disable-shared

Es gibt ein paar bekannte Probleme bei der Ausführung von MySQL unter Linux-Alpha:

  • Das Debugging von Thread-basierten Anwendungen wie MySQL funktioniert mit gdb 4.18 nicht. Verwenden Sie stattdessen gdb 5.1.

  • Wenn Sie versuchen, mysqld bei der Verwendung von gcc statisch zu verknüpfen, dann tritt beim Start des resultierenden Images ein Speicherauszug auf. Anders gesagt: Verwenden Sie keinesfalls --with-mysqld-ldflags=-all-static mit gcc.

2.12.1.8. Anmerkungen zu Linux PowerPC

MySQL sollte auf MkLinux mit dem neuesten glibc-Paket funktionieren (getestet mit glibc 2.0.7).

2.12.1.9. Anmerkungen zu Linux MIPS

Um MySQL auf Qube2 (Linux Mips) zum Laufen zu bringen, benötigen Sie die neuesten glibc-Bibliotheken. glibc-2.0.7-29C2 funktioniert bekanntermaßen. Sie müssen ferner den C++-Compiler egcs verwenden (egcs 1.0.2-9, gcc 2.95.2 oder höher).

2.12.1.10. Anmerkungen zu Linux IA-64

Um MySQL unter Linux IA-64 kompilieren zu können, verwenden wir den folgenden configure-Befehl zur Erstellung mit gcc 2.96:

CC=gcc \
CFLAGS="-O3 -fno-omit-frame-pointer" \
CXX=gcc \
CXXFLAGS="-O3 -fno-omit-frame-pointer -felide-constructors \
    -fno-exceptions -fno-rtti" \
    ./configure --prefix=/usr/local/mysql \
    "--with-comment=Official MySQL binary" \
    --with-extra-charsets=complex

Unter IA-64 verwenden die MySQL-Clientbinärdateien gemeinsame Bibliotheken. Das bedeutet, dass Sie, wenn Sie unsere Binärdistribution in einem anderen Verzeichnis als /usr/local/mysql installieren, den Pfad des Verzeichnisses, in dem libmysqlclient.so installiert ist, entweder der Datei /etc/ld.so.conf oder dem Wert der Umgebungsvariablen LD_LIBRARY_PATH hinzufügen müssen.

Siehe auch Abschnitt A.3.1, „Probleme beim Linken mit der MySQL-Clientbibliothek“.

2.12.2. Anmerkungen zu Mac OS X

Unter Mac OS X kann tar lange Dateinamen nicht verarbeiten. Wenn Sie eine .tar.gz-Distribution entpacken müssen, verwenden Sie stattdessen gnutar.

2.12.2.1. Mac OS X 10.x (Darwin)

MySQL sollte unter Mac OS X 10.x (Darwin) ohne größere Probleme funktionieren.

Die folgenden Probleme sind bekannt:

  • Die Verbindungszeiten (wait_timeout, interactive_timeout und net_read_timeout) werden nicht beachtet.

    Dies ist wahrscheinlich ein Signalverwaltungsproblem in der Thread-Bibliothek, wo das Signal eine anhängige Leseoperation nicht unterbricht. Wir hoffen, dass ein künftiges Update der Thread-Bibliotheken dieses Problem beheben wird.

Unsere Binärdatei für Mac OS X wird unter Darwin 6.3 mit der folgenden configure-Zeile kompiliert:

CC=gcc CFLAGS="-O3 -fno-omit-frame-pointer" CXX=gcc \
CXXFLAGS="-O3 -fno-omit-frame-pointer -felide-constructors \
    -fno-exceptions -fno-rtti" \
    ./configure --prefix=/usr/local/mysql \
    --with-extra-charsets=complex --enable-thread-safe-client \
    --enable-local-infile --disable-shared

Siehe auch Abschnitt 2.5, „Installation von MySQL unter Mac OS X“.

2.12.2.2. Mac OS X Server

Bei aktuellen Versionen von Mac OS X Server sind vor der Kompilierung keine Betriebssystemänderungen erforderlich. Die Kompilierung für die Serverplattform ist mit der für die Clientversion von Mac OS X identisch.

Bei älteren Versionen (Mac OS X Server 1.2, auch bekannt als „Rhapsody“) müssen Sie zunächst ein pthread-Paket installieren, bevor Sie MySQL konfigurieren können.

Siehe auch Abschnitt 2.5, „Installation von MySQL unter Mac OS X“.

2.12.3. Anmerkungen zu Solaris

Unter Solaris haben Sie möglicherweise schon die ersten Probleme, bevor Sie die MySQL-Distribution überhaupt entpacken können, denn tar unter Solaris kann mit langen Dateinamen nicht umgehen. Dies bedeutet, dass Ihnen unter Umständen Fehler angezeigt werden, wenn Sie MySQL entpacken.

In diesem Fall müssen Sie GNU tar (gtar) zum Entpacken der Distribution verwenden. Sie finden eine vorkompilierte Kopie für Solaris unter http://dev.mysql.com/downloads/os-solaris.html.

Native Sun-Threads funktionieren erst ab Solaris 2.5. Bis Solaris 2.4 verwendet MySQL automatisch MIT-pthreads. Siehe auch Abschnitt 2.8.5, „Anmerkungen zu MIT-pthreads“.

Wenn die folgende Fehlermeldung bei Ausführung von configure angezeigt wird, stimmt etwas mit Ihrer Compiler-Installation nicht:

checking for restartable system calls... configure: error can not
run test programs while cross compiling

In diesem Fall sollten Sie den Compiler auf eine neuere Version aktualisieren. Sie können das Problem möglicherweise auch beheben, indem Sie die folgende Zeile in die Datei config.cache einfügen:

ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'}

Wenn Sie Solaris auf einem SPARC-System verwenden, wird gcc 2.95.2 oder 3.2 als Compiler empfohlen. Sie finden ihn unter http://gcc.gnu.org/. Beachten Sie, dass egcs 1.1.1 und gcc 2.8.1 auf SPARC nicht zuverlässig arbeiten.

Die empfohlene configure-Zeile sieht bei Verwendung von gcc 2.95.2 wie folgt aus:

CC=gcc CFLAGS="-O3" \
CXX=gcc CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti" \
./configure --prefix=/usr/local/mysql --with-low-memory \
    --enable-assembler

Bei Verwendung eines UltraSPARC-Systems erhalten Sie eine um 4 Prozent bessere Performance, wenn Sie -mcpu=v8 -Wa,-xarch=v8plusa zu den Umgebungsvariablen CFLAGS und CXXFLAGS hinzufügen.

Wenn Sie den Forte-Compiler 5.0 oder höher von Sun einsetzen, können Sie configure wie folgt ausführen:

CC=cc CFLAGS="-Xa -fast -native -xstrconst -mt" \
CXX=CC CXXFLAGS="-noex -mt" \
./configure --prefix=/usr/local/mysql --enable-assembler

Um eine 64-Bit-Binärdatei mit Sun Forte zu erstellen, verwenden Sie die folgenden Konfigurationsoptionen:

CC=cc CFLAGS="-Xa -fast -native -xstrconst -mt -xarch=v9" \
CXX=CC CXXFLAGS="-noex -mt -xarch=v9" ASFLAGS="-xarch=v9" \
./configure --prefix=/usr/local/mysql --enable-assembler

Wenn Sie eine 64-Bit-Solaris-Binärdatei mit gcc erstellen wollen, ergänzen Sie -m64 in CFLAGS und CXXFLAGS und entfernen Sie --enable-assembler aus der configure-Zeile.

In den MySQL-Benchmarks erhielten wir auf UltraSPARC bei der Verwendung von Forte 5.0 im 32-Bit-Modus im Vergleich zu gcc 3.2 mit dem Flag -mcpu einen Geschwindigkeitszuwachs von 4 Prozent.

Wenn Sie eine 64-Bit-mysqld-Binärdatei erstellen, ist diese um 4 Prozent langsamer als die 32-Bit-Binärdatei, kann aber mehr Threads und Speicher verwalten.

Wenn Sie Solaris 10 für x86_64 einsetzen, sollten Sie alle Dateisysteme einbinden, auf denen Sie InnoDB-Dateien mit der Option forcedirectio speichern wollen. (Standardmäßig erfolgt die Einbindung ohne diese Option.) Andernfalls entsteht ein erheblicher Leistungseinbruch, wenn die InnoDB-Speicher-Engine auf dieser Plattform verwendet wird.

Wenn Sie auf ein Problem mit fdatasync oder sched_yield stoßen, können Sie es beheben, indem Sie LIBS=-lrt zur configure-Zeile hinzufügen.

Bei Versionen des WorkShop-Compilers vor 5.3 müssen Sie eventuell das Skript configure bearbeiten. Die Zeile

#if !defined(__STDC__) || __STDC__ != 1

ändern Sie wie folgt:

#if !defined(__STDC__)

Wenn Sie __STDC__ mit der Option -Xc aktivieren, kann der Sun-Compiler keine Kompilierung mit der pthread.h-Header-Datei von Solaris durchführen. Dies ist ein Sun-spezifischer Bug (beschädigter Compiler oder beschädigte Include-Datei).

Wenn mysqld die folgende Fehlermeldung bei der Ausführung ausgibt, haben Sie versucht, MySQL mit dem Sun-Compiler zu kompilieren, ohne die Multithread-Option -mt zu aktivieren:

libc internal error: _rmutex_unlock: rmutex not held

Fügen Sie -mt zu CFLAGS und CXXFLAGS hinzu und kompilieren Sie neu.

Wenn Sie die SFW-Version von gcc verwenden (in Solaris 8 enthalten), dann müssen Sie /opt/sfw/lib zur Umgebungsvariablen LD_LIBRARY_PATH hinzufügen, bevor Sie configure ausführen.

Verwenden Sie das auf sunfreeware.com verfügbare gcc, dann werden Sie eine Menge Probleme haben. Um dies zu vermeiden, sollten Sie gcc und GNU binutils auf dem Computer kompilieren, auf dem sie auch ausgeführt werden sollen.

Wenn Sie bei der Kompilierung von MySQL mit gcc folgende Fehlermeldung erhalten, ist Ihr gcc nicht für Ihre Solaris-Version konfiguriert:

shell> gcc -O3 -g -O2 -DDBUG_OFF  -o thr_alarm ...
./thr_alarm.c: In function `signal_hand':
./thr_alarm.c:556: too many arguments to function `sigwait'

In diesem Fall besteht die richtige Lösung einzig und allein darin, sich die neueste Version von gcc zu besorgen und sie mit Ihrem aktuellen gcc-Compiler zu kompilieren. Zumindest bei Solaris 2.5 enthalten praktisch alle Binärversionen von gcc alte, unbrauchbare Include-Dateien, die Thread-basierte (und wohl auch weitere) Programme beschädigen.

Solaris bietet keine statischen Versionen aller Systembibliotheken (libpthreads und libdl) an, d. h., Sie können MySQL nicht mit --static kompilieren. Wenn Sie es dennoch versuchen, erhalten Sie eine der folgenden Fehlermeldungen:

ld: fatal: library -ldl: not found
undefined reference to `dlopen'
cannot find -lrt

Wenn Sie eigene MySQL-Clientprogramme verknüpfen, dann wird unter Umständen die folgende Fehlermeldung zur Laufzeit angezeigt:

ld.so.1: fatal: libmysqlclient.so.#:
open failed: No such file or directory

Dieses Problem lässt sich auf eine der folgenden Weisen lösen:

  • Verknüpfen Sie die Clients mit dem Flag -Wl,r/full/path/to/libmysqlclient.so statt mit -Lpath.

  • Kopieren Sie libmysqclient.so nach /usr/lib.

  • Fügen Sie den Pfadnamen des Verzeichnisses, in dem sich libmysqlclient.so befindet, der Umgebungsvariablen LD_RUN_PATH hinzu, bevor Sie den Client ausführen.

Wenn Sie Probleme haben, configure mit -lz zu verknüpfen, weil zlib nicht installiert ist, dann haben Sie zwei Möglichkeiten:

  • Wenn Sie das komprimierte Kommunikationsprotokoll einsetzen können wollen, müssen Sie zlib bei ftp.gnu.org herunterladen und installieren.

  • Sie führen configure mit der Option --with-named-z-libs=no aus, wenn Sie MySQL erstellen.

Wenn Sie gcc verwenden und Probleme beim Einladen von UDFs (User-Defined Functions, benutzerdefinierte Funktionen) in MySQL haben, ergänzen Sie die Verknüpfungszeile für die UDF um -lgcc.

Wollen Sie, dass MySQL automatisch startet, dann können Sie support-files/mysql.server in das Verzeichnis /etc/init.d kopieren und eine symbolische Verknüpfung namens /etc/rc3.d/S99mysql.server zu ihr erstellen.

Wenn zu viele Prozesse innerhalb kurzer Zeit eine Verbindung mit mysqld herstellen wollen, werden Sie die folgende Fehlermeldung im MySQL-Log finden:

Error in accept: Protocol error

Dieses Problem können Sie unter Umständen beheben, indem Sie den Server mit der Option --back_log=50 starten. (Bei MySQL vor Version 4 verwenden Sie -O back_log=50.)

Solaris unterstützt Core-Dateien für setuid()-Anwendungen nicht, d. h., Sie können keine Core-Datei von mysqld erhalten, wenn Sie die Option --user verwenden.

2.12.3.1. Anmerkungen zu Solaris 2.7/2.8

Normalerweise können Sie eine Binärdatei für Solaris 2.6 auch unter Solaris 2.7 oder 2.8 verwenden. Auch betreffen Probleme, die für Solaris 2.6 gelistet sind, meist ebenfalls Solaris 2.7 und 2.8.

MySQL sollte neue Versionen von Solaris automatisch erkennen können und für die im Folgenden beschriebenen Probleme Workarounds aktivieren.

Solaris 2.7 und 2.8 haben einige Bugs bei den Include-Dateien. Bei Verwendung von gcc erhalten Sie unter Umständen folgende Fehlermeldung:

/usr/include/widec.h:42: warning: `getwc' redefined
/usr/include/wchar.h:326: warning: this is the location of the previous
definition

In diesem Fall können Sie das Problem beheben, indem Sie /usr/include/widec.h nach .../lib/gcc-lib/os/gcc-version/include kopieren. Die Zeile 41

#if     !defined(lint) && !defined(__lint)

ändern Sie wie folgt:

#if     !defined(lint) && !defined(__lint) && !defined(getwc)

Alternativ können Sie /usr/include/widec.h auch direkt editieren. Wenn Sie das Problem auf eine der beschriebenen Weisen behoben haben, sollten Sie config.cache entfernen und configure erneut ausführen.

Wenn Sie bei der Ausführung von make die folgenden Fehlermeldungen erhalten, liegt das daran, dass configure die Datei curses.h nicht erkannt hat (wahrscheinlich aufgrund des Fehlers in /usr/include/widec.h):

In file included from mysql.cc:50:
/usr/include/term.h:1060: syntax error before `,'
/usr/include/term.h:1081: syntax error before `;'

Dieses Problem lässt sich auf mehreren Wegen lösen:

  • Konfigurieren Sie mit CFLAGS=-DHAVE_CURSES_H CXXFLAGS=-DHAVE_CURSES_H ./configure.

  • Bearbeiten Sie /usr/include/widec.h wie im vorherigen Abschnitt beschrieben und führen Sie configure erneut aus.

  • Entfernen Sie die Zeile #define HAVE_TERM aus der Datei config.h und führen Sie make erneut aus.

Wenn Ihr Linker beim Verknüpfen von Clientprogrammen -lz nicht finden kann, besteht das Problem wahrscheinlich darin, dass Ihre Datei libz.so in /usr/local/lib installiert ist. Dieses Problem lässt sich auf eine der folgenden Weisen lösen:

  • Fügen Sie /usr/local/lib zu LD_LIBRARY_PATH hinzu.

  • Fügen Sie von /lib aus eine Verknüpfung zu libz.so hinzu.

  • Wenn Sie Solaris 8 verwenden, können Sie die optionale zlib von Ihrer Solaris 8-Distributions-CD installieren.

  • Sie führen configure mit der Option --with-named-z-libs=no aus, wenn Sie MySQL erstellen.

2.12.3.2. Anmerkungen zu Solaris x86

Unter Solaris 8 auf x86 erzeugt mysqld einen Speicherauszug, wenn Sie die Debugsymbole mithilfe von strip entfernen.

Wenn Sie gcc oder egcs unter Solaris x86 verwenden und bei hoher Belastung Probleme mit Speicherauszügen haben, sollten Sie folgenden configure-Befehl verwenden:

CC=gcc CFLAGS="-O3 -fomit-frame-pointer -DHAVE_CURSES_H" \
CXX=gcc \
CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors \
    -fno-exceptions -fno-rtti -DHAVE_CURSES_H" \
./configure --prefix=/usr/local/mysql

Hierdurch vermeiden Sie Probleme mit der Bibliothek libstdc++ und mit C++-Ausnahmefehlern.

Sollte dies nicht helfen, dann sollten Sie eine Debugversion kompilieren und diese mit einer Trace-Datei oder unter gdb ausführen. Siehe auch Abschnitt E.1.3, „mysqld unter gdb debuggen“.

2.12.4. Anmerkungen zu BSD

In diesem Abschnitt erhalten Sie Informationen zur Verwendung von MySQL unter Varianten von BSD Unix.

2.12.4.1. Anmerkungen zu FreeBSD

FreeBSD 4.x oder neuer wird für die Ausführung von MySQL empfohlen, da das Thread-Paket wesentlich besser integriert ist. Um ein sicheres und stabiles System zu erhalten, sollten Sie nur FreeBSD-Kernels verwenden, die mit -RELEASE gekennzeichnet sind.

Die einfachste (und deswegen empfohlene) Vorgehensweise zur Installation von MySQL besteht in der Verwendung der mysql-server- und mysql-client-Ports, die unter http://www.freebsd.org/ verfügbar sind. Die Verwendung dieser Ports hat die folgenden Vorteile:

  • Sie erhalten ein funktionsfähiges MySQL, bei dem alle Optimierungen, die unter Ihrer FreeBSD-Version bekanntermaßen funktionieren, bereits aktiviert sind.

  • Konfiguration und Erstellung werden automatisch durchgeführt.

  • Startskripten sind in /usr/local/etc/rc.d installiert.

  • Sie können mit pkg_info -L überprüfen, welche Dateien installiert sind.

  • Sie können ferner mit pkg_delete MySQL entfernen, wenn Sie es auf Ihrem Rechner nicht mehr benötigen.

Wir empfehlen die Verwendung von MIT-pthreads unter FreeBSD 2.x und von nativen Threads unter FreeBSD 3 und höher. Zwar können auch spätere Versionen von Release 2.2.x mit nativen Threads betrieben werden, aber dann kann es zu Problemen beim Herunterfahren von mysqld kommen.

Leider sind bestimmte Funktionsaufrufe unter FreeBSD noch nicht vollständig Thread-sicher. Dies betrifft vor allem die Funktion gethostbyname(), die von MySQL zur Umwandlung von Hostnamen in IP-Adressen verwendet wird. Unter bestimmten Umständen verursacht der Prozess mysqld unvermittelt eine Prozessorauslastung von 100 Prozent und reagiert nicht mehr. Wenn dieses Problem auftritt, versuchen Sie MySQL mit der Option --skip-name-resolve zu starten.

Alternativ können Sie MySQL unter FreeBSD 4.x mit der LinuxThreads-Bibliothek verknüpfen, wodurch einige der Probleme vermieden werden, die die native Thread-Implementierung von FreeBSD hat. Einen sehr guten Vergleich von LinuxThreads und nativen Threads finden Sie in Jeremy Zawodnys Artikel FreeBSD or Linux for your MySQL Server? unter http://jeremy.zawodny.com/blog/archives/000697.html.

Es gibt ein bekanntes Problem bei der Verwendung von LinuxThreads unter FreeBSD:

  • Die Verbindungszeiten (wait_timeout, interactive_timeout und net_read_timeout) werden nicht beachtet. Auffälliges Symptom ist, dass Permanentverbindungen für eine sehr lange Zeit hängen, ohne abgebaut zu werden, und dass eine Terminierung des Threads erst Erfolg hat, wenn der Thread einem neuen Befehl zugeordnet wird.

    Dies ist wahrscheinlich ein Signalverwaltungsproblem in der Thread-Bibliothek, wo das Signal eine anhängige Leseoperation nicht unterbricht. Das Problem wird voraussichtlich in FreeBSD 5.0 behoben.

Damit der MySQL-Erstellungsprozess funktioniert, ist GNU make (gmake) erforderlich. Wenn GNU make nicht vorhanden ist, müssen Sie es vor der Kompilierung von MySQL installieren.

Die empfohlene Vorgehensweise zur Kompilierung und Installation von MySQL unter FreeBSD mit gcc (2.95.2 und höher) ist die folgende:

CC=gcc CFLAGS="-O2 -fno-strength-reduce" \
    CXX=gcc CXXFLAGS="-O2 -fno-rtti -fno-exceptions \
    -felide-constructors -fno-strength-reduce" \
    ./configure --prefix=/usr/local/mysql --enable-assembler
gmake
gmake install
cd /usr/local/mysql
bin/mysql_install_db --user=mysql
bin/mysqld_safe &

Wenn Sie feststellen, dass configure MIT-pthreads verwendet, lesen Sie die Anmerkungen zu MIT-pthreads. Siehe auch Abschnitt 2.8.5, „Anmerkungen zu MIT-pthreads“.

Wenn make install die Fehlermeldung ausgibt, dass es /usr/include/pthreads nicht finden kann, dann hat configure nicht erkannt, dass Sie MIT-pthreads benötigen. Um dieses Problem zu beheben, entfernen Sie config.cache und führen configure dann erneut mit der Option --with-mit-threads aus.

Achten Sie darauf, dass Ihre Namensauflösung korrekt ist. Andernfalls werden Verzögerungen oder Fehler bei der Auflösung auftreten, wenn Sie die Verbindung mit mysqld herzustellen versuchen. Ferner müssen Sie sicherstellen, dass der Eintrag localhost in der Datei /etc/hosts korrekt ist. Am Anfang der Datei sollte eine Zeile ähnlich der folgenden stehen:

127.0.0.1       localhost localhost.your.domain

FreeBSD hat bekanntermaßen einen sehr niedrigen Standardwert für Datei-Handles. Siehe auch Abschnitt A.2.17, „Datei nicht gefunden“. Starten Sie den Server unter Verwendung der Option --open-files-limit für mysqld_safe oder heben Sie den Wert für den Benutzer mysqld in /etc/login.conf an und erstellen Sie die Datei dann mit cap_mkdb /etc/login.conf neu. Achten Sie außerdem darauf, die passende Klasse für diesen Benutzer in der Passwortdatei zu konfigurieren, sofern Sie die Vorgabe nicht verwenden (benutzen Sie chpass mysqld-user-name). Siehe auch Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“.

FreeBSD beschränkt die Größe eines Prozesses auch dann auf 512 Mbyte, wenn auf Ihrem System wesentlich mehr Arbeitsspeicher vorhanden ist. Insofern kann ein Fehler wie der folgende auftreten:

Out of memory (Needed 16391 bytes)

Bei den aktuellen Versionen von FreeBSD (mindestens seit 4.x) können Sie den Grenzwert auch anheben, indem Sie die folgenden Einträge in der Datei /boot/loader.conf hinzufügen und den Computer neu starten (diese Einstellungen lassen sich nicht zur Laufzeit mit dem Befehl sysctl ändern):

kern.maxdsiz="1073741824" # 1GB
kern.dfldsiz="1073741824" # 1GB
kern.maxssiz="134217728" # 128MB

Bei älteren FreeBSD-Versionen müssen Sie Ihren Kernel neu kompilieren, um die maximale Datensegmentgröße für einen Prozess zu ändern. In diesem Fall sollten Sie sich die Option MAXDSIZ in der Konfigurationsdatei LINT näher ansehen, um weitere Informationen zu erhalten.

Wenn es Probleme mit dem aktuellen Daten in MySQL gibt, sollte eine Einstellung der Variablen TZ Abhilfe leisten können. Siehe auch Anhang F, Umgebungsvariablen.

2.12.4.2. Anmerkungen zu NetBSD

Zur Kompilierung unter NetBSD benötigen Sie GNU make. Andernfalls schlägt der Erstellungsprozess fehl, wenn make versucht, lint für C++-Dateien auszuführen.

2.12.4.3. Anmerkungen zu OpenBSD

Unter OpenBSD 2.5 können Sie MySQL mit nativen Threads kompilieren. Hierzu verwenden Sie die folgenden Optionen:

CFLAGS=-pthread CXXFLAGS=-pthread ./configure --with-mit-threads=no

2.12.4.4. Anmerkungen zu BSD/OS

Wenn Sie die folgende Fehlermeldung bei der Kompilierung von MySQL erhalten, ist der Wert ulimit für den virtuellen Speicher auf Ihrem System zu niedrig:

item_func.h: In method
`Item_func_ge::Item_func_ge(const Item_func_ge &)':
item_func.h:28: virtual memory exhausted
make[2]: *** [item_func.o] Error 1

Verwenden Sie beispielsweise ulimit -v 80000 und führen Sie make erneut aus. Funktioniert dies nicht und Sie verwenden bash, dann probieren Sie stattdessen csh oder sh aus. Einige BSDI-Benutzer haben Probleme mit bash und ulimit gemeldet.

Wenn Sie gcc einsetzen, müssen Sie unter Umständen auch das Flag --with-low-memory verwenden, damit configure sql_yacc.cc kompilieren kann.

Wenn es Probleme mit den aktuellen Daten in MySQL gibt, sollte eine Einstellung der Variablen TZ Abhilfe leisten können. Siehe auch Anhang F, Umgebungsvariablen.

2.12.4.5. Anmerkungen zu BSD/OS Version 3.x

Aktualisieren Sie auf BSD/OS 3.1. Sollte dies nicht möglich sein, dann installieren Sie BSDIpatch M300-038.

Verwenden Sie den folgenden Befehl zur Konfiguration von MySQL:

env CXX=shlicc++ CC=shlicc2 \
./configure \
    --prefix=/usr/local/mysql \
    --localstatedir=/var/mysql \
    --without-perl \
    --with-unix-socket-path=/var/mysql/mysql.sock

Auch die folgende Variante funktioniert bekanntermaßen:

env CC=gcc CXX=gcc CXXFLAGS=-O3 \
./configure \
    --prefix=/usr/local/mysql \
    --with-unix-socket-path=/var/mysql/mysql.sock

Sie können die Verzeichnispositionen auf Wunsch ändern oder die Voreinstellungen übernehmen (hierzu geben Sie einfach keine Positionen an).

Sollten Leistungsprobleme unter starker Belastung auftreten, dann probieren Sie die Option --skip-thread-priority für mysqld. Hierdurch werden alle Threads mit derselben Priorität ausgeführt. Unter BSDI 3.1 können Sie auf diese Weise die Performance verbessern – zumindest so lange, bis BSDI den Thread-Scheduler in Ordnung bringt.

Wird bei der Kompilierung die Fehlermeldung virtual memory exhausted angezeigt, dann sollten Sie ulimit -v 80000 ausprobieren und make erneut ausführen. Funktioniert dies nicht und Sie verwenden bash, dann probieren Sie stattdessen csh oder sh aus. Einige BSDI-Benutzer haben Probleme mit bash und ulimit gemeldet.

2.12.4.6. Anmerkungen zu BSD/OS Version 4.x

BSDI 4.x weist einige Bugs in Bezug auf Threads auf. Wenn Sie MySQL hierunter verwenden wollen, sollten Sie alle Thread-spezifischen Patches installieren. Dis gilt zumindest für M400-023.

Auf einigen BSDI 4.x-Systemen treten Probleme mit gemeinsamen Bibliotheken auf. Sie erkennen dies daran, dass Sie keine Clientprogramme wie etwa mysqladmin ausführen können. In diesem Fall müssen Sie das System so umkonfigurieren, dass es keine gemeinsamen Bibliotheken verwendet; dies tun Sie mit der Option --disable-shared für configure.

Ferner haben Kunden Probleme unter BSDI 4.0.1 damit gehabt, dass die Binärdatei mysqld nach einer Weile keine Tabellen mehr öffnen konnte. Ursache hierfür ist ein bibliotheks- oder systembezogener Bug, aufgrund dessen mysqld das aktuelle Verzeichnis wechselt, ohne hierfür zuvor eine Bestätigung angefordert zu haben.

Sie beseitigen das Problem, indem Sie entweder MySQL auf Version 3.23.34 oder höher aktualisieren oder nach der Ausführung von configure die Zeile #define HAVE_REALPATH aus der Datei config.h entfernen, bevor Sie make starten.

Beachten Sie, dass dies bedeutet, dass Sie in diesem Fall unter BSDI keine symbolischen Verknüpfungen zwischen Datenbankverzeichnissen oder von einer Tabelle zu einer anderen Datenbank erstellen können. (Symbolische Verknüpfungen zu anderen Festplatten hingegen sind unproblematisch.)

2.12.5. Anmerkungen zu anderen Unixen

2.12.5.1. Anmerkungen zu HP-UX Version 10.20

Wenn Sie MySQL unter HP-UX kompilieren, gibt es ein paar kleinere Probleme. Wir empfehlen die Verwendung von gcc anstelle des nativen Compilers von HP-UX, da gcc einen besseren Code erzeugt.

Verwenden Sie unter HP-UX am besten gcc 2.95. Verwenden Sie keine Hochoptimierungsflags (wie etwa -O6), da dies unter Umständen unter HP-UX nicht sicher ist.

Der folgende configure-Befehl sollte für gcc 2.95 funktionieren:

CFLAGS="-I/opt/dce/include -fpic" \
CXXFLAGS="-I/opt/dce/include -felide-constructors -fno-exceptions \
-fno-rtti" \
CXX=gcc \
./configure --with-pthread \
    --with-named-thread-libs='-ldce' \
    --prefix=/usr/local/mysql --disable-shared

Der folgende configure-Befehl sollte für gcc 3.1 funktionieren:

CFLAGS="-DHPUX -I/opt/dce/include -O3 -fPIC" CXX=gcc \
CXXFLAGS="-DHPUX -I/opt/dce/include -felide-constructors \
    -fno-exceptions -fno-rtti -O3 -fPIC" \
./configure --prefix=/usr/local/mysql \
    --with-extra-charsets=complex --enable-thread-safe-client \
    --enable-local-infile  --with-pthread \
    --with-named-thread-libs=-ldce --with-lib-ccflags=-fPIC
    --disable-shared

2.12.5.2. Anmerkungen zu HP-UX Version 11.x

Aufgrund einiger kritischer Bugs in den HP-UX-Standardbibliotheken sollten Sie die folgenden Patches installieren, bevor Sie MySQL unter HP-UX 11.0 ausführen:

PHKL_22840 Streams cumulative
PHNE_22397 ARPA cumulative

Hierdurch können Sie das Problem beheben, EWOULDBLOCK aus recv() und EBADF aus accept() in Thread-basierten Anwendungen zu erhalten.

Wenn Sie gcc 2.95.1 auf einem nicht gepatchten HP-UX 11.x-System einsetzen, wird unter Umständen die folgende Fehlermeldung angezeigt:

In file included from /usr/include/unistd.h:11,
                 from ../include/global.h:125,
                 from mysql_priv.h:15,
                 from item.cc:19:
/usr/include/sys/unistd.h:184: declaration of C function ...
/usr/include/sys/pthread.h:440: previous declaration ...
In file included from item.h:306,
                 from mysql_priv.h:158,
                 from item.cc:19:

Das Problem besteht darin, dass HP-UX pthreads_atfork() nicht konsistent definiert. Es liegt ein Prototypkonflikt in /usr/include/sys/unistd.h:184 und /usr/include/sys/pthread.h:440 vor.

Eine Lösung besteht darin, /usr/include/sys/unistd.h nach mysql/include zu kopieren und unistd.h so zu editieren, dass es zur Definition in pthread.h passt. Suchen Sie nach der folgenden Zeile:

extern int pthread_atfork(void (*prepare)(), void (*parent)(),
                                          void (*child)());

Ändern Sie sie wie folgt ab:

extern int pthread_atfork(void (*prepare)(void), void (*parent)(void),
                                          void (*child)(void));

Wenn Sie die Änderung vorgenommen haben, sollte die folgende configure-Zeile funktionieren:

CFLAGS="-fomit-frame-pointer -O3 -fpic" CXX=gcc \
CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -O3" \
./configure --prefix=/usr/local/mysql --disable-shared

Verwenden Sie den HP-UX-Compiler, dann können Sie den folgenden Befehl verwenden (dieser wurde mit cc B.11.11.04 getestet):

CC=cc CXX=aCC CFLAGS=+DD64 CXXFLAGS=+DD64 ./configure \
    --with-extra-character-set=complex

Sie können alle Fehler des folgenden Typs ignorieren:

aCC: warning 901: unknown option: `-3': use +help for online
documentation

Wenn die folgende Fehlermeldung von configure ausgegeben wird, dann stellen Sie sicher, dass der Pfad zum K&R-Compiler nicht vor dem Pfad zum HP-UX-C- und C++-Compiler steht:

checking for cc option to accept ANSI C... no
configure: error: MySQL requires an ANSI C compiler (and a C++ compiler).
Try gcc. See the Installation chapter in the Reference Manual.

Ein anderer Grund dafür, dass eine Kompilierung nicht möglich ist, besteht darin, dass Sie die +DD64-Flags nicht wie eben beschrieben definiert haben.

Eine andere Möglichkeit für HP-UX 11 besteht darin, die unter http://dev.mysql.com/downloads/ verfügbaren MySQL-Binärdateien zu verwenden, die wir selbst erstellt und getestet haben. Ferner wurde uns mitgeteilt, dass die von MySQL angebotenen Binärdateien für HP-UX 10.20 auch unter HP-UX 11 erfolgreich ausgeführt werden können. Wenn Sie hierbei auf Probleme treffen, sollten Sie überprüfen, ob HP-UX-Patches verfügbar sind.

2.12.5.3. Anmerkungen zu IBM-AIX

Die automatische Erkennung von xlC fehlt bei Autoconf. Aus diesem Grund muss eine Reihe von Variablen eingestellt werden, bevor configure ausgeführt wird. Das folgende Beispiel verwendet den IBM-Compiler:

export CC="xlc_r -ma -O3 -qstrict -qoptimize=3 -qmaxmem=8192 "
export CXX="xlC_r -ma -O3 -qstrict -qoptimize=3 -qmaxmem=8192"
export CFLAGS="-I /usr/local/include"
export LDFLAGS="-L /usr/local/lib"
export CPPFLAGS=$CFLAGS
export CXXFLAGS=$CFLAGS

./configure --prefix=/usr/local \
                --localstatedir=/var/mysql \
                --sbindir='/usr/local/bin' \
                --libexecdir='/usr/local/bin' \
                --enable-thread-safe-client \
                --enable-large-files

Obige Optionen werden zur Kompilierung der MySQL-Distribution verwendet, die unter http://www-frec.bull.com/ verfügbar ist.

Wenn Sie in obiger configure-Zeile die Option -O3 auf -O2 setzen, müssen Sie auch die Option -qstrict entfernen. Dies ist eine Einschränkung des C-Compilers von IBM.

Wenn Sie gcc oder egcs zur Kompilierung von MySQL verwenden, müssen Sie das Flag -fno-exceptions benutzen, weil die Fehlerbehandlung in gcc/egcs nicht Thread-sicher ist! (Dies wurde mit egcs 1.1 getestet.) Es gibt ferner einige bekannte Probleme mit dem IBM-Assembler, die in Verbindung mit gcc zu fehlerhaftem Code führen können.

Wir empfehlen die folgende configure-Zeile bei egcs und gcc 2.95 unter AIX:

CC="gcc -pipe -mcpu=power -Wa,-many" \
CXX="gcc -pipe -mcpu=power -Wa,-many" \
CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti" \
./configure --prefix=/usr/local/mysql --with-low-memory

Die Option -Wa,-many ist erforderlich, damit die Kompilierung erfolgreich verläuft. Bei IBM ist dieses Problem bekannt, man sieht sich aber mit der Behebung nicht unter Zeitdruck, da ein Workaround verfügbar ist. Wir wissen nicht, ob -fno-exceptions bei gcc 2.95 erforderlich ist, aber weil MySQL keine Ausnahmen verwendet und die Option einen schnelleren Code erzeugt, empfehlen wir ihre generelle Verwendung bei egcs und gcc.

Wenn ein Problem mit dem Assemblercode auftritt, versuchen Sie die Option -mcpu=xxx so zu ändern, dass sie zu Ihrer CPU passt. Normalerweise müssen power2, power oder powerpc verwendet werden. Möglicherweise müssen Sie aber auch 604 oder 604e einsetzen. Wir wissen es nicht genau, nehmen aber an, dass power mit hoher Wahrscheinlichkeit in den meisten Fällen sicher ist (und zwar auch auf power2-Systemen).

Wenn Sie nicht wissen, welchen Prozessor Sie haben, führen Sie den Befehl uname -m aus. Er erzeugt einen String, der etwa so aussieht: 000514676700. Das Format ist xxyyyyyymmss, wobei xx und ss immer 00, yyyyyy eine eindeutige Systemkennung und mm die Kennung des CPU-Planars sind. Eine Übersicht über diese Werte finden Sie unter http://www16.boulder.ibm.com/pseries/en_US/cmds/aixcmds5/uname.htm.

Dort erhalten Sie Angaben zu Rechnertyp und -modell, auf deren Basis Sie die CPU in Ihrem Rechner ermitteln können.

Wenn Sie Probleme mit Signalen haben (weil sich MySQL unter hoher Belastung unerwartet aufhängt), haben Sie unter Umständen einen Betriebssystembug bei den Threads oder Signalen gefunden. In diesem Fall können Sie MySQL wie folgt anweisen, Signale nicht zu verwenden:

CFLAGS=-DDONT_USE_THR_ALARM CXX=gcc \
CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti \
-DDONT_USE_THR_ALARM" \
./configure --prefix=/usr/local/mysql --with-debug \
    --with-low-memory

Hierdurch wird die Leistungsfähigkeit von MySQL nicht beeinträchtigt; ein Nebeneffekt besteht aber darin, dass Sie Clients, die an einer Verbindung „schlafen“, mit mysqladmin kill oder mysqladmin shutdown nicht terminieren können. Stattdessen hängt sich der Client auf, wenn er den nächsten Befehl absetzt.

Bei einigen Versionen von AIX führt eine Verknüpfung mit libbind.a bei getservbyname() zu einem Speicherauszug. Dies ist ein AIX-Bug, der IBM gemeldet werden sollte.

Bei AIX 4.2.1 und gcc müssen Sie die folgenden Änderungen vornehmen.

Bearbeiten Sie nach der Konfiguration config.h und include/my_config.h. Die Zeile

#define HAVE_SNPRINTF 1

ändern Sie wie folgt:

#undef HAVE_SNPRINTF

Schließlich müssen Sie in mysqld.cc noch einen Prototyp für initgroups() hinzufügen.

#ifdef _AIX41
extern "C" int initgroups(const char *,int);
#endif

Wenn Sie dem Prozess mysqld viel Speicher zuweisen müssen, reicht es nicht aus, einfach ulimit -d unlimited zu verwenden. Sie müssen vielmehr auch mysqld_safe mit einer Zeile wie der folgenden ergänzen:

export LDR_CNTRL='MAXDATA=0x80000000'

Weitere Informationen zur Verwendung einer großen Menge Speicher finden Sie unter http://publib16.boulder.ibm.com/pseries/en_US/aixprggd/genprogc/lrg_prg_support.htm.

Benutzer von AIX 4.3 sollten gmake statt des in AIX enthaltenen make-Hilfsprogramms verwenden.

2.12.5.4. Anmerkungen zu SunOS 4

Unter SunOS 4 ist MIT-pthreads zur Kompilierung von MySQL erforderlich. Das wiederum bedeutet, dass Sie GNU make benötigen.

Einige SunOS 4-Systeme haben Probleme mit dynamischen Bibliotheken und libtool. Dieses Problem können Sie mit der folgenden configure-Zeile beheben:

./configure --disable-shared --with-mysqld-ldflags=-all-static

Wenn Sie readline kompilieren, erhalten Sie unter Umständen Warnungen zu Doppeldefinitionen. Diese können Sie getrost ignorieren.

Wenn Sie mysqld kompilieren, erscheinen einige Warnungen des Typs implicit declaration of function. Diese können Sie getrost ignorieren.

2.12.5.5. Anmerkungen zu Alpha-DEC-UNIX (Tru64)

Wenn Sie egcs 1.1.2 unter Digital Unix verwenden, sollten Sie auf gcc 2.95.2 aktualisieren, weil egcs unter DEC einige schwerwiegende Bugs aufweist!

Wenn Sie Thread-basierte Programme unter Digital Unix kompilieren, empfiehlt die Dokumentation die Verwendung der Option -pthread für cc und cxx und die -lmach -lexc-Bibliotheken (zusätzlich zu -lpthread). Sie sollten configure etwa wie folgt ausführen:

CC="cc -pthread" CXX="cxx -pthread -O" \
./configure --with-named-thread-libs="-lpthread -lmach -lexc -lc"

Wenn Sie mysqld kompilieren, werden unter Umständen einige Warnungen wie die folgenden angezeigt:

mysqld.cc: In function void handle_connections()':
mysqld.cc:626: passing long unsigned int *' as argument 3 of
accept(int,sockadddr *, int *)'

Diese können Sie getrost ignorieren. Sie erscheinen, weil configure nur Fehler, nicht jedoch Warnungen erkennen kann.

Wenn Sie den Server direkt über die Befehlszeile starten, kann es bei der Abmeldung zu Abstürzen kommen. (Wenn Sie sich abmelden, erhalten Ihre ausstehenden Prozesse ein SIGHUP-Signal.) Versuchen Sie, den Server wie folgt zu starten:

nohup mysqld [options] &

nohup sorgt dafür, dass der Befehl, der darauf folgt, alle ggf. vom Terminal gesendeten SIGHUP-Signale ignoriert. Alternativ starten Sie den Server durch Ausführung von mysqld_safe. Hierdurch wird mysqld unter Verwendung von nohup für Sie aufgerufen. Siehe auch Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“.

Wenn ein Problem bei der Kompilierung von mysys/get_opt.c auftritt, entfernen Sie einfach die Zeile #define _NO_PROTO am Anfang dieser Datei.

Wenn Sie den CC-Compiler von Compaq einsetzen, sollte die folgende configure-Zeile problemlos funktionieren:

CC="cc -pthread"
CFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all -arch host"
CXX="cxx -pthread"
CXXFLAGS="-O4 -ansi_alias -ansi_args -fast -inline speed all \
    -arch host -noexceptions -nortti"
export CC CFLAGS CXX CXXFLAGS
./configure \
    --prefix=/usr/local/mysql \
    --with-low-memory \
    --enable-large-files \
    --enable-shared=yes \
    --with-named-thread-libs="-lpthread -lmach -lexc -lc"
gnumake

Tritt ein Problem mit libtool auf, wenn Sie wie gerade gezeigt mit gemeinsamen Bibliotheken kompilieren und mysql verknüpfen, sollten Sie dieses durch Absetzen der folgenden Befehle umgehen können:

cd mysql
/bin/sh ../libtool --mode=link cxx -pthread  -O3 -DDBUG_OFF \
    -O4 -ansi_alias -ansi_args -fast -inline speed \
    -speculate all \ -arch host  -DUNDEF_HAVE_GETHOSTBYNAME_R \
    -o mysql  mysql.o readline.o sql_string.o completion_hash.o \
    ../readline/libreadline.a -lcurses \
    ../libmysql/.libs/libmysqlclient.so  -lm
cd ..
gnumake
gnumake install
scripts/mysql_install_db

2.12.5.6. Anmerkungen zu Alpha-DEC-OSF1

Wenn Sie Probleme beim Kompilieren haben und DEC CC und gcc installiert sind, probieren Sie einmal, configure wie folgt auszuführen:

CC=cc CFLAGS=-O CXX=gcc CXXFLAGS=-O3 \
./configure --prefix=/usr/local/mysql

Treten Probleme in Verbindung mit der Datei c_asm.h auf, dann können Sie wie folgt eine Dummyversion von c_asm.h erstellen:

touch include/c_asm.h
CC=gcc CFLAGS=-I./include \
CXX=gcc CXXFLAGS=-O3 \
./configure --prefix=/usr/local/mysql

Beachten Sie, dass die folgenden Probleme beim Programm ld sich durch den Download des aktuellen DEC-(Compaq-)Patch-Kits beheben lassen. Dieses finden Sie unter http://ftp.support.compaq.com/public/unix/.

Unter OSF/1 V4.0D tritt bei Verwendung des Compilers "DEC C V5.6-071 on Digital Unix V4.0 (Rev. 878)" ein seltsames Verhalten auf (undefinierte asm-Symbole). /bin/ld scheint ebenfalls beschädigt zu sein (Probleme mit _exit undefined-Fehlern, die beim Verknüpfen von mysqld auftreten). Es ist uns gelungen, MySQL auf diesem System mit der folgenden configure-Zeile zu kompilieren, nachdem wir /bin/ld durch die Version aus OSF 4.0C ersetzt haben:

CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql

Beim Digital-Compiler "C++ V6.1-029" sollte Folgendes funktionieren:

CC=cc -pthread
CFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed \
       -speculate all -arch host
CXX=cxx -pthread
CXXFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed \
         -speculate all -arch host -noexceptions -nortti
export CC CFLAGS CXX CXXFLAGS
./configure --prefix=/usr/mysql/mysql \
            --with-mysqld-ldflags=-all-static --disable-shared \
            --with-named-thread-libs="-lmach -lexc -lc"

Bei einigen Versionen von OSF/1 ist die Funktion alloca() beschädigt. Dieses Problem können Sie beheben, indem Sie die Zeile in config.h entfernen, die 'HAVE_ALLOCA' definiert.

Die Funktion alloca() weist unter Umständen auch einen falschen Prototyp in /usr/include/alloca.h auf. Sich hierauf beziehende Warnmeldungen können Sie ignorieren.

configure verwendet die folgenden Thread-Bibliotheken automatisch: --with-named-thread-libs="-lpthread -lmach -lexc -lc".

Wenn Sie gcc verwenden, können Sie auch versuchen, configure wie folgt auszuführen:

CFLAGS=-D_PTHREAD_USE_D4 CXX=gcc CXXFLAGS=-O3 ./configure ...

Wenn Sie Probleme mit Signalen haben (weil sich MySQL unter hoher Belastung unerwartet aufhängt), haben Sie unter Umständen einen Betriebssystembug bei den Threads oder Signalen gefunden. In diesem Fall können Sie MySQL wie folgt anweisen, Signale nicht zu verwenden:

CFLAGS=-DDONT_USE_THR_ALARM \
CXXFLAGS=-DDONT_USE_THR_ALARM \
./configure ...

Hierdurch wird die Leistungsfähigkeit von MySQL nicht beeinträchtigt; ein Nebeneffekt besteht aber darin, dass Sie Clients, die an einer Verbindung „schlafen“, mit mysqladmin kill oder mysqladmin shutdown nicht terminieren können. Stattdessen hängt sich der Client auf, wenn er den nächsten Befehl absetzt.

Bei gcc 2.95.2 erhalten Sie möglicherweise den folgenden Kompilierungsfehler:

sql_acl.cc:1456: Internal compiler error in `scan_region',
at except.c:2566
Please submit a full bug report.

Um dies zu beheben, sollten Sie in das Verzeichnis sql wechseln und dort die letzte gcc-Zeile ausschneiden und einfügen, die Option -O3 dabei jedoch zu -O0 ändern (oder -O0 direkt nach gcc hinzufügen, wenn Ihre compile-Zeile gar keine -O-Option enthält). Danach können Sie wieder zum obersten Verzeichnis wechseln und make erneut ausführen.

2.12.5.7. Anmerkungen zu SGI Irix

Wenn Sie Irix 6.5.3 oder höher verwenden, kann mysqld Threads nur dann erstellen, wenn Sie es als Benutzer mit CAP_SCHED_MGT-Berechtigungen (z. B. als root) ausführen oder dem Server mysqld diese Berechtigung mit dem folgenden Shell-Befehl zuweisen:

chcap "CAP_SCHED_MGT+epi" /opt/mysql/libexec/mysqld

Unter Umständen müssen Sie die Definitionen einiger Symbole in config.h nach der Ausführung von configure, aber vor der Kompilierung aufheben.

Bei einigen Irix-Implementierungen ist die Funktion alloca() beschädigt. Wenn der mysqld-Server sich bei einigen SELECT-Anweisungen aufhängt, entfernen Sie die Zeilen aus config.h, die HAVE_ALLOC und HAVE_ALLOCA_H definieren. Funktioniert mysqladmin create nicht, dann entfernen Sie die Zeile aus config.h, die HAVE_READDIR_R definiert. Möglicherweise müssen Sie auch die Zeile HAVE_TERM_H entfernen.

SGI empfiehlt, alle Patches auf der folgenden Seite auf einmal zu installieren: http://support.sgi.com/surfzone/patches/patchset/6.2_indigo.rps.html.

Sie sollten zumindest das jeweils letzte Kernel-, rld- und libc-Rollup installieren.

Für die pthreads-Unterstützung benötigen Sie in jedem Fall alle POSIX-Patches auf der folgenden Seite:

http://support.sgi.com/surfzone/patches/patchset/6.2_posix.rps.html

Möglicherweise erhalten Sie bei der Kompilierung von mysql.cc eine Fehlermeldung ähnlich der folgenden:

"/usr/include/curses.h", line 82: error(1084):
invalid combination of type

Geben Sie in diesem Fall Folgendes im obersten Verzeichnis Ihres MySQL-Source-Trees ein:

extra/replace bool curses_bool < /usr/include/curses.h > include/curses.h
make

Gemeldet wurden ferner Zeitplanungsprobleme. Wird nur ein Thread ausgeführt, dann ist die Performance schwach. Dies können Sie vermeiden, indem Sie einen anderen Client starten. Dies hat unter Umständen eine zwei- bis zehnfache Steigerung der Ausführungsgeschwindigkeit für den anderen Thread zur Folge. Dieses Problem mit Irix-Threads ist schlecht nachvollziehbar: Bis es behoben ist, müssen Sie wohl improvisieren, um geeignete Lösungen zu finden.

Wenn Sie mit gcc kompilieren, können Sie den folgenden configure-Befehl verwenden:

CC=gcc CXX=gcc CXXFLAGS=-O3 \
./configure --prefix=/usr/local/mysql --enable-thread-safe-client \
    --with-named-thread-libs=-lpthread

Unter Irix 6.5.11 mit nativen Irix-C- und -C++-Compilern der Version 7.3.1.2 funktioniert Angaben zufolge auch Folgendes:

CC=cc CXX=CC CFLAGS='-O3 -n32 -TARG:platform=IP22 -I/usr/local/include \
-L/usr/local/lib' CXXFLAGS='-O3 -n32 -TARG:platform=IP22 \
-I/usr/local/include -L/usr/local/lib' \
./configure --prefix=/usr/local/mysql --with-innodb --with-berkeley-db \
    --with-libwrap=/usr/local \
    --with-named-curses-libs=/usr/local/lib/libncurses.a

2.12.5.8. Anmerkungen zu SCO UNIX und OpenServer 5.0.x

Die aktuelle Portierung wird nur auf Systemen unter sco3.2v5.0.5, sco3.2v5.0.6 und sco3.2v5.0.7 getestet. Die Portierung auf sco3.2v4.2 ist ebenfalls weit fortgeschritten. Open Server 5.0.8 (Legend) bietet native Threads und unterstützt Dateien, die größer sind als 2 Gbyte. Das aktuelle Limit bei der Dateigröße liegt bei 2 Gbyte.

Wir konnten MySQL mit dem folgenden configure-Befehl unter OpenServer mit gcc 2.95.3 kompilieren.

CC=gcc CXX=gcc ./configure --prefix=/usr/local/mysql \
    --enable-thread-safe-client --with-innodb \
    --with-openssl --with-vio --with-extra-charsets=complex

gcc erhalten Sie unter ftp://ftp.sco.com/pub/openserver5/opensrc/gnutools-5.0.7Kj.

Dieses Entwicklungssystem erfordert das OpenServer Execution Environment Supplement oss646B unter OpenServer 5.0.6 und oss656B und die in gwxlibs enthaltenen OpenSource-Bibliotheken. Alle OpenSource-Tools befinden sich im Verzeichnis opensrc. Sie finden sie unter ftp://ftp.sco.com/pub/openserver5/opensrc/.

Wir empfehlen die Verwendung des aktuellen Produktions-Releases von MySQL.

SCO stellt Betriebssystem-Patches unter ftp://ftp.sco.com/pub/openserver5 für OpenServer 5.0.[0-6] und unter ftp://ftp.sco.com/pub/openserverv5/507 für OpenServer 5.0.7 bereit.

Informationen zu behobenen Sicherheitslücken bietet SCO unter ftp://ftp.sco.com/pub/security/OpenServer für OpenServer 5.0.x an.

Die maximale Dateigröße auf einem OpenServer 5.0.x-System beträgt 2 Gbyte.

Die Gesamtmenge an Speicher, der für Stream-Puffer, CLISTs und Sperrdatensätze zugewiesen wird, darf unter OpenServer 5.0.x einen Wert von 60 Mbyte nicht überschreiten.

Stream-Puffer werden in Einheiten von 4096 Byte großen Seiten zugewiesen, CLISTs haben jeweils 70 Byte, und Sperrdatensätze sind je 64 Byte groß. Hieraus ergibt sich:

(NSTRPAGES * 4096) + (NCLIST * 70) + (MAX_FLCKREC * 64) <= 62914560

Gehen Sie wie folgt vor, um die Option Database Services zu konfigurieren. Wenn Sie nicht genau wissen, ob eine Anwendung dies erfordert, schlagen Sie in der Dokumentation dieser Anwendung nach.

  1. Melden Sie sich als root an.

  2. Aktivieren Sie den SUDS-Treiber, indem Sie die Datei /etc/conf/sdevice.d/suds bearbeiten. Ändern Sie das N im zweiten Feld zu Y.

  3. Aktivieren Sie mithilfe von mkdev aio oder des Hardware/Kernel-Managers die Unterstützung für asynchrone Eingabe/Ausgabe und verknüpfen Sie den Kernel neu. Damit Benutzer Speicher für die Verwendung mit diesem E/A-Typ verriegeln können, aktualisieren Sie die Datei aiomemlock(F). Diese Datei sollte mit den Namen der Benutzer, die AIO verwenden dürfen, und der maximalen Speichermenge aktualisiert werden, die diese Benutzer sperren dürfen.

  4. Viele Anwendungen verwenden setuid-Binärdateien, d. h., Sie müssen nur einen Benutzer angeben. Konsultieren Sie die Dokumentation zur fraglichen Anwendung, um zu ermitteln, ob dies bei dieser Anwendung der Fall ist.

Nachdem Sie den Vorgang abgeschlossen haben, starten Sie das System neu, um einen neuen Kernel zu erstellen, der diese Änderungen beinhaltet.

Standardmäßig haben die Einträge in /etc/conf/cf.d/mtune folgende Einstellungen:

Value           Default         Min             Max
-----           -------         ---             ---
NBUF            0               24              450000
NHBUF           0               32              524288
NMPBUF          0               12              512
MAX_INODE       0               100             64000
MAX_FILE        0               100             64000
CTBUFSIZE       128             0               256
MAX_PROC        0               50              16000
MAX_REGION      0               500             160000
NCLIST          170             120             16640
MAXUP           100             15              16000
NOFILES         110             60              11000
NHINODE         128             64              8192
NAUTOUP         10              0               60
NGROUPS         8               0               128
BDFLUSHR        30              1               300
MAX_FLCKREC     0               50              16000
PUTBUFSZ        8000            2000            20000
MAXSLICE        100             25              100
ULIMIT          4194303         2048            4194303
* Streams Parameters
NSTREAM         64              1               32768
NSTRPUSH        9               9               9
NMUXLINK        192             1               4096
STRMSGSZ        16384           4096            524288
STRCTLSZ        1024            1024            1024
STRMAXBLK       524288          4096            524288
NSTRPAGES       500             0               8000
STRSPLITFRAC    80              50              100
NLOG            3               3               3
NUMSP           64              1               256
NUMTIM          16              1               8192
NUMTRW          16              1               8192
* Semaphore Parameters
SEMMAP          10              10              8192
SEMMNI          10              10              8192
SEMMNS          60              60              8192
SEMMNU          30              10              8192
SEMMSL          25              25              150
SEMOPM          10              10              1024
SEMUME          10              10              25
SEMVMX          32767           32767           32767
SEMAEM          16384           16384           16384
* Shared Memory Parameters
SHMMAX          524288          131072          2147483647
SHMMIN          1               1               1
SHMMNI          100             100             2000
FILE            0               100             64000
NMOUNT          0               4               256
NPROC           0               50              16000
NREGION         0               500             160000

Wir empfehlen die Einstellung folgender Werte:

NOFILES sollte 4096 oder 2048 sein.

MAXUP sollte 2048 sein.

Um Änderungen am Kernel vorzunehmen, wechseln Sie in das Verzeichnis /etc/conf/bin und nehmen die erforderlichen Änderungen mit ./idtune name parameter vor. Um beispielsweise SEMMS auf 200 zu setzen, führen Sie folgende Befehle als root aus:

# cd /etc/conf/bin
# ./idtune SEMMNS 200

Wir empfehlen eine Optimierung des Systems. Welche Parameterwerte allerdings hierzu geeignet sind, hängt von der Anzahl der Benutzer, die auf die Anwendung oder Datenbank zugreifen, und von der Größe der Datenbank selbst (d. h. dem verwendeten Pufferpool) ab. Das Folgende betrifft die Kernel-Parameter, die in /etc/conf/cf.d/stune definiert sind:

SHMMAX (Einstellempfehlung: 128 Mbyte) und SHMSEG (Einstellempfehlung: 15). Diese Parameter beeinflussen die MySQL-Datenbank-Engine bei der Erstellung der Benutzerpufferpools.

NOFILES und MAXUP sollten auf mindestens 2048 gesetzt werden.

MAXPROC sollte (abhängig von der Anzahl der Benutzer) auf mindestens 3000/4000 gesetzt werden.

Ferner wird die Verwendung der folgenden Formel zur Berechnung der Werte für SEMMSL, SEMMNS und SEMMNU empfohlen:

SEMMSL = 13

13 hat sich als optimaler Wert sowohl für Progress als auch für MySQL erwiesen.

SEMMNS = SEMMSL × Anzahl der auf dem System ausgeführten Server

Setzen Sie SEMMNS auf den Wert von SEMMSL multipliziert mit der maximalen Anzahl der Datenbankserver, die gleichzeitig auf Ihrem System ausgeführt werden.

SEMMNU = SEMMNS

SEMMNU setzen Sie dann auf den gleichen Wert wie SEMMNS. Wahrscheinlich würde hier auch ein Wert von 75 Prozent von SEMMNS ausreichen, aber dies ist eine konservative Schätzung.

Sie müssen zumindest die "SCO OpenServer Linker and Application Development Libraries" oder das OpenServer Development System installieren, um gcc verwenden zu können. Das GCC Dev-System können Sie nicht nutzen, ohne mindestens eine dieser Komponenten zu installieren.

Zunächst sollten Sie sich jedoch das FSU-Pthreads-Paket beschaffen und es installieren. Sie finden es unter http://moss.csc.ncsu.edu/~mueller/ftp/pub/PART/pthreads.tar.gz. Eine vorkompilierte Fassung finden Sie unter ftp://ftp.zenez.com/pub/zenez/prgms/FSU-threads-3.14.tar.gz.

FSU-Pthreads kann mit SCO Unix 4.2 mit tcpip oder aber mithilfe von OpenServer 3.0 oder Open Desktop 3.0 (OS 3.0 ODT 3.0) mit installiertem SCO Development System kompiliert werden, wobei eine gute Portierung von GCC 2.5.x zum Einsatz kommen sollte. Für ODT oder OS 3.0 benötigen Sie eine gute Portierung von GCC 2.5.x. Ohne eine solche gute Portierung können eine Menge Probleme entstehen. Die Portierung für dieses Produkt erfordert das SCO Unix Development-System. Ohne dieses fehlen Ihnen die Bibliotheken und der erforderliche Linker. Ferner benötigen Sie SCO-3.2v4.2-includes.tar.gz. Diese Datei enthält die Änderungen an den Include-Dateien des SCO Development Systems, die für die Erstellung von MySQL benötigt werden. Sie müssen die vorhandenen System-Include-Dateien durch diese modifizierten Header-Dateien ersetzen. Sie erhalten sie unter ftp://ftp.zenez.com/pub/zenez/prgms/SCO-3.2v4.2-includes.tar.gz.

Um FSU-Pthreads auf Ihrem System zu erstellen, sollten Sie nichts weiteres tun müssen, als GNU make auszuführen. Das Makefile in FSU-threads-3.14.tar.gz ist so konfiguriert, dass es FSU-threads erstellt.

Sie können ./configure im Verzeichnis threads/src ausführen und die Option SCO OpenServer auswählen. Dieser Befehl kopiert Makefile.SCO5 nach Makefile. Danach führen Sie make aus.

Zur Installation in das Standardverzeichnis /usr/include melden Sie sich als root und wechseln dann in das Verzeichnis thread/src. Dort führen Sie make install aus.

Denken Sie daran, GNU make zur Erstellung von MySQL zu verwenden.

Hinweis: Wenn Sie mysqld_safe nicht als root starten, erhalten Sie nur die standardmäßig vorgesehenen 110 offenen Dateien pro Prozess. mysqld schreibt eine entsprechende Anmerkung in die Logdatei.

Bei SCO 3.2V4.2 sollten Sie FSU-Pthreads Version 3.14 oder höher verwenden. Der folgende configure-Befehl sollte funktionieren:

CFLAGS="-D_XOPEN_XPG4" CXX=gcc CXXFLAGS="-D_XOPEN_XPG4" \
./configure \
    --prefix=/usr/local/mysql \
    --with-named-thread-libs="-lgthreads -lsocket -lgen -lgthreads" \
    --with-named-curses-libs="-lcurses"

Unter Umständen treten Probleme mit einigen Include-Dateien auf. In diesem Fall finden Sie neue SCO-spezifische Include-Dateien unter ftp://ftp.zenez.com/pub/zenez/prgms/SCO-3.2v4.2-includes.tar.gz.

Sie sollten diese Datei in das Verzeichnis include Ihres MySQL-Source-Trees entpacken.

Anmerkungen zur SCO-Entwicklung:

  • MySQL sollte FSU-Pthreads automatisch erkennen und mysqld mit -lgthreads -lsocket -lgthreads verknüpfen.

  • Die SCO-Entwicklungsbibliotheken sind in FSU-Pthreads mehrfach aufrufbar. SCO behauptet, dass seine Bibliothek mehrfach aufrufbar ist, mithin muss sie also auch bei FSU-Pthreads mehrfach aufrufbar sein. FSU-Pthreads unter OpenServer versucht, mithilfe des SCO-Schemas mehrfach aufrufbare Bibliotheken zu erstellen.

  • FSU-Pthreads wird mit GNU malloc verknüpft ausgeliefert (zumindest gilt dies für die Version unter ftp::/ftp.zenez.com). Wenn Probleme mit der Speichernutzung auftreten, vergewissern Sie sich, dass gmalloc.o in libgthreads.a und libgthreads.so enthalten ist.

  • In FSU-Pthreads erkennen die folgenden Systemaufrufe das Vorhandensein von pthreads: read(), write(), getmsg(), connect(), accept(), select() und wait().

  • Der Patch CSSA-2001-SCO.35.2, der üblicherweise als Sicherheits-Patch erg711905-dscr_remap (version 2.0.0) gelistet ist, beschädigt FSU-Threads und macht mysqld instabil. Wenn Sie mysqld auf einem System unter OpenServer 5.0.6 verwenden wollen, müssen Sie diesen Patch entfernen.

  • Setzen Sie SCO OpenServer 5 ein, dann müssen Sie unter Umständen FSU-Pthreads mit -DDRAFT7 in CFLAGS neu kompilieren. Andernfalls hängt sich InnoDB beim Start von mysqld auf.

  • SCO bietet Betriebssystem-Patches unter ftp://ftp.sco.com/pub/openserver5 für OpenServer 5.0.x.

  • Fehlerbehebungen für Sicherheitslücken und libsocket.so.2 bietet SCO unter ftp://ftp.sco.com/pub/security/OpenServer und ftp://ftp.sco.com/pub/security/sse für OpenServer 5.0.x an.

  • Sicherheitsrelevante Fehlerbehebungen für OpenServer vor OSR506 und den Bugfix für telnetd finden Sie unter ftp://stage.caldera.com/pub/security/openserver/ oder ftp://stage.caldera.com/pub/security/openserver/CSSA-2001-SCO.10/ als libsocket.so.2 und libresolv.so.1 mit Anweisungen zur Installation auf Systemen vor OSR506.

    Es empfiehlt sich wohl, diese Patches vor der Kompilierung und Verwendung von MySQL zu installieren.

Ab Legend/OpenServer 6.0.0 gibt es native Threads, und die Beschränkung der Dateigröße auf 2 Gbyte entfällt.

2.12.5.9. Anmerkungen zu SCO OpenServer 6.0.x

OpenServer 6 enthält die folgenden wesentlichen Verbesserungen:

  • Unterstützung für Dateien bis zu 1 Tbyte

  • Multiprozessorunterstützung für bis zu 32 Prozessoren

  • verbesserte Speicherunterstützung für bis zu 64 Gbyte

  • Leistungserweiterung von UnixWare auf OpenServer 6

  • drastische Leistungssteigerungen

OpenServer 6.0.0-Befehle sind wie folgt organisiert:

  • /bin ist für Befehle vorgesehen, die sich exakt so verhalten wie unter OpenServer 5.0.x.

  • /u95/bin ist für Befehle vorgesehen, die eine erhöhte Standardkonformität aufweisen. Hierzu gehört z. B. die LFS-Unterstützung (Large File System).

  • /udk/bin ist für Befehle vorgesehen, die sich exakt so verhalten wie unter UnixWare 7.1.4. Standardmäßig wird LFS unterstützt.

Nachfolgend erhalten Sie eine Anleitung zur Einstellung von PATH unter OpenServer 6. Wenn der Benutzer das traditionelle Verhalten von OpenServer 5.0.x wünscht, sollte PATH zunächst /bin sein. Wünscht der Benutzer LFS-Unterstützung, dann sollte der Pfad /u95/bin:/bin sein. Benötigt der Benutzer zunächst UnixWare 7-Unterstützung, dann wäre der korrekte Pfad /udk/bin:/u95/bin:/bin:.

Wir empfehlen die Verwendung des aktuellen Produktions-Releases von MySQL.

Wir konnten MySQL mit dem folgenden configure-Befehl unter OpenServer 6.0.x kompilieren.

CC="cc" CFLAGS="-I/usr/local/include" \
CXX="CC" CXXFLAGS="-I/usr/local/include" \
./configure --prefix=/usr/local/mysql \
    --enable-thread-safe-client --with-berkeley-db=./bdb \
    --with-innodb --with-openssl --with-extra-charsets=complex \
    --enable-readline

Wenn Sie gcc verwenden wollen, müssen Sie gcc 2.95.3 oder höher einsetzen.

CC=gcc CXX=g++ ./configure --prefix=/usr/local/mysql

Die Version von Berkeley DB, die Bestandteil von UnixWare 7.1.4 wie auch von OpenServer 6.0.0 ist, wird bei der Erstellung von MySQL nicht eingesetzt. Stattdessen verwendet MySQL seine eigene Version von Berkeley DB. Der Befehl configure muss sowohl eine statische als auch eine dynamische Bibliothek in src_directory/bdb/build_unix/ erstellen, aber dies nicht mit MySQLs eigener BDB-Version. Der Workaround sieht wie folgt aus:

  1. Führen Sie die normalen für MySQL erforderlichen Konfigurationsarbeiten durch.

  2. cd bdb/build_unix/

  3. cp -p Makefile to Makefile.sav

  4. Führen Sie unter Verwendung derselben Optionen ../dist/configure aus.

  5. Führen Sie gmake aus.

  6. cp -p Makefile.sav Makefile

  7. Wechseln Sie in das oberste Quellverzeichnis und führen Sie gmake aus.

Auf diese Weise lassen sich sowohl die statischen als auch die dynamischen Bibliotheken erstellen und zum Laufen bringen. OpenServer 6.0.0 erfordert auch, dass Patches für den MySQL-Source-Tree und der Patch für config.guess auf bdb/dist/config.guess angewendet werden. Sie können die Patches unter ftp://ftp.zenez.com/pub/zenez/prgms/mysql-4.1.12-osr6-patches.tar.gz bzw. ftp://ftp.zenez.com/pub/zenez/prgms/mysql-4.x.x-osr6-patches herunterladen. Lesen Sie die beigefügte Datei README, um Hilfe zu erhalten.

SCO stellt Betriebssystem-Patches für OpenServer 6 unter ftp://ftp.sco.com/pub/openserver6 bereit.

Informationen zu behobenen Sicherheitslücken bietet SCO unter ftp://ftp.sco.com/pub/security/OpenServer.

Standardmäßig beträgt die maximale Dateigröße auf einem OpenServer 6.0.0-System 1 Tbyte. Einige Betriebssystem-Hilfsprogramme weisen eine Beschränkung auf 2 Gbyte auf. Die maximale Dateigröße unter UnixWare 7 beträgt 1 Tbyte mit VXFS oder HTFS.

Standardmäßig haben die Einträge in /etc/conf/cf.d/mtune folgende Einstellungen:

Value           Default         Min             Max
-----           -------         ---             ---
SVMMLIM         0x9000000       0x1000000       0x7FFFFFFF
HVMMLIM         0x9000000       0x1000000       0x7FFFFFFF
SSTKLIM         0x1000000       0x2000          0x7FFFFFFF
HSTKLIM         0x1000000       0x2000          0x7FFFFFFF

Wir empfehlen die Einstellung folgender Werte:

SDATLIM 0x7FFFFFFF
HDATLIM 0x7FFFFFFF
SSTKLIM 0x7FFFFFFF
HSTKLIM 0x7FFFFFFF
SVMMLIM 0x7FFFFFFF
HVMMLIM 0x7FFFFFFF
SFNOLIM 2048
HFNOLIM 2048

Wir empfehlen eine Optimierung des Systems. Welche Parameterwerte allerdings hierzu geeignet sind, hängt von der Anzahl der Benutzer, die auf die Anwendung oder Datenbank zugreifen, und von der Größe der Datenbank selbst (d. h. dem verwendeten Pufferpool) ab. Das Folgende betrifft die Kernel-Parameter, die in /etc/conf/cf.d/stune definiert sind:

SHMMAX (Einstellempfehlung: 128 Mbyte) und SHMSEG (Einstellempfehlung: 15). Diese Parameter beeinflussen die MySQL-Datenbank-Engine bei der Erstellung der Benutzerpufferpools.

SFNOLIM und HFNOLIM sollten auf maximal 2048 gesetzt werden.

NPROC sollte (abhängig von der Anzahl der Benutzer) auf mindestens 3000/4000 gesetzt werden.

Ferner wird die Verwendung der folgenden Formel zur Berechnung der Werte für SEMMSL, SEMMNS und SEMMNU empfohlen:

SEMMSL = 13

13 hat sich als optimaler Wert sowohl für Progress als auch für MySQL erwiesen.

SEMMNS = SEMMSL × Anzahl der auf dem System ausgeführten Server

Setzen Sie SEMMNS auf den Wert von SEMMSL multipliziert mit der maximalen Anzahl der Datenbankserver, die gleichzeitig auf Ihrem System ausgeführt werden.

SEMMNU = SEMMNS

SEMMNU setzen Sie dann auf den gleichen Wert wie SEMMNS. Wahrscheinlich würde hier auch ein Wert von 75 Prozent von SEMMNS ausreichen, aber dies ist eine konservative Schätzung.

2.12.5.10. Anmerkungen zu SCO UnixWare 7.1.x und OpenUNIX 8.0.0

Wir empfehlen die Verwendung des aktuellen Produktions-Releases von MySQL.

Wir konnten MySQL mit dem folgenden configure-Befehl unter UnixWare 7.1.x kompilieren.

CC="cc" CFLAGS="-I/usr/local/include" \
CXX="CC" CXXFLAGS="-I/usr/local/include" \
./configure --prefix=/usr/local/mysql \
    --enable-thread-safe-client --with-berkeley-db=./bdb \
    --with-innodb --with-openssl --with-extra-charsets=complex

Wenn Sie gcc verwenden wollen, müssen Sie gcc 2.95.3 oder höher einsetzen.

CC=gcc CXX=g++ ./configure --prefix=/usr/local/mysql

Die Version von Berkeley DB, die Bestandteil von UnixWare 7.1.4 wie auch von OpenServer 6.0.0 ist, wird bei der Erstellung von MySQL nicht eingesetzt. Stattdessen verwendet MySQL seine eigene Version von Berkeley DB. Der Befehl configure muss sowohl eine statische als auch eine dynamische Bibliothek in src_directory/bdb/build_unix/ erstellen, aber dies nicht mit MySQLs eigener BDB-Version. Der Workaround sieht wie folgt aus:

  1. Führen Sie die normalen für MySQL erforderlichen Konfigurationsarbeiten durch.

  2. cd bdb/build_unix/

  3. cp -p Makefile to Makefile.sav

  4. Führen Sie unter Verwendung derselben Optionen ../dist/configure aus.

  5. Führen Sie gmake aus.

  6. cp -p Makefile.sav Makefile

  7. Wechseln Sie in das oberste Quellverzeichnis und führen Sie gmake aus.

Auf diese Weise lassen sich sowohl die statischen als auch die dynamischen Bibliotheken erstellen und zum Laufen bringen.

SCO bietet Betriebssystem-Patches unter ftp://ftp.sco.com/pub/unixware7 für UnixWare 7.1.1, unter ftp://ftp.sco.com/pub/unixware7/713/ für UnixWare 7.1.3, unter ftp://ftp.sco.com/pub/unixware7/714/ für UnixWare 7.1.4 und unter ftp://ftp.sco.com/pub/openunix8 für OpenUNIX 8.0.0 an.

Informationen zu behobenen Sicherheitslücken bietet SCO unter ftp://ftp.sco.com/pub/security/OpenUNIX für OpenUNIX und unter ftp://ftp.sco.com/pub/security/UnixWare für UnixWare an.

Standardmäßig beträgt die maximale Dateigröße auf einem UnixWare 7.1.1-System 1 Gbyte, bei UnixWare 7.1.4 ist die Größe hingegen auf 1 Tbyte mit VXFS beschränkt. Einige Betriebssystem-Hilfsprogramme weisen eine Beschränkung auf 2 Gbyte auf. Die maximal mögliche Dateigröße unter UnixWare 7 beträgt 1 Tbyte mit VXFS.

Unter UnixWare 7.1.4 müssen Sie nichts tun, um in den Genuss der Unterstützung großer Dateien zu kommen. Bei Versionen vor UnixWare 7.1.x müssen Sie zu diesem Zweck fsadm ausführen.

# fsadm -Fvxfs -o largefiles /
# fsadm /         * Note
# ulimit unlimited
# cd /etc/conf/bin
# ./idtune SFSZLIM 0x7FFFFFFF     ** Note
# ./idtune HFSZLIM 0x7FFFFFFF     ** Note
# ./idbuild -B

* This should report "largefiles".
** 0x7FFFFFFF represents infinity for these values.

Starten Sie das System mit shutdown neu.

Standardmäßig haben die Einträge in /etc/conf/cf.d/mtune folgende Einstellungen:

Value           Default         Min             Max
-----           -------         ---             ---
SVMMLIM         0x9000000       0x1000000       0x7FFFFFFF
HVMMLIM         0x9000000       0x1000000       0x7FFFFFFF
SSTKLIM         0x1000000       0x2000          0x7FFFFFFF
HSTKLIM         0x1000000       0x2000          0x7FFFFFFF

Wir empfehlen die Einstellung folgender Werte:

SDATLIM 0x7FFFFFFF
HDATLIM 0x7FFFFFFF
SSTKLIM 0x7FFFFFFF
HSTKLIM 0x7FFFFFFF
SVMMLIM 0x7FFFFFFF
HVMMLIM 0x7FFFFFFF
SFNOLIM 2048
HFNOLIM 2048

Wir empfehlen eine Optimierung des Systems. Welche Parameterwerte allerdings hierzu geeignet sind, hängt von der Anzahl der Benutzer, die auf die Anwendung oder Datenbank zugreifen, und von der Größe der Datenbank selbst (d. h. dem verwendeten Pufferpool) ab. Das Folgende betrifft die Kernel-Parameter, die in /etc/conf/cf.d/stune definiert sind:

SHMMAX (Einstellempfehlung: 128 Mbyte) und SHMSEG (Einstellempfehlung: 15). Diese Parameter beeinflussen die MySQL-Datenbank-Engine bei der Erstellung der Benutzerpufferpools.

SFNOLIM und HFNOLIM sollten auf maximal 2048 gesetzt werden.

NPROC sollte (abhängig von der Anzahl der Benutzer) auf mindestens 3000/4000 gesetzt werden.

Ferner wird die Verwendung der folgenden Formel zur Berechnung der Werte für SEMMSL, SEMMNS und SEMMNU empfohlen:

SEMMSL = 13

13 hat sich als optimaler Wert sowohl für Progress als auch für MySQL erwiesen.

SEMMNS = SEMMSL × Anzahl der auf dem System ausgeführten Server

Setzen Sie SEMMNS auf den Wert von SEMMSL multipliziert mit der maximalen Anzahl der Datenbankserver, die gleichzeitig auf Ihrem System ausgeführt werden.

SEMMNU = SEMMNS

SEMMNU setzen Sie dann auf den gleichen Wert wie SEMMNS. Wahrscheinlich würde hier auch ein Wert von 75 Prozent von SEMMNS ausreichen, aber dies ist eine konservative Schätzung.

2.12.6. Anmerkungen zu OS/2

MySQL verwendet eine ganze Menge offener Dateien. Aus diesem Grund sollten Sie Ihre Datei CONFIG.SYS um etwas in der Art des Folgenden ergänzen:

SET EMXOPT=-c -n -h1024

Andernfalls könnte der folgende Fehler auftreten:

File 'xxxx' not found (Errcode: 24)

Wenn Sie MySQL mit OS/2 Warp 3 verwenden, benötigen Sie FixPack 29 oder höher. Bei OS/2 Warp 4 ist FixPack 4 oder höher erforderlich. Dies ist eine Anforderung der Pthreads-Bibliothek. MySQL muss auf einer Partition eines Typs installiert sein, der lange Dateinamen benutzt (also etwa HPFS, FAT32 usw.).

Das Skript INSTALL.CMD muss aus der OS/2-eigenen CMD.EXE ausgeführt werden und funktioniert unter Ersatz-Shells wie 4OS2.EXE unter Umständen nicht.

Das Skript scripts/mysql-install-db wurde umbenannt. Es heißt install.cmd und ist ein REXX-Skript, das die Standardsicherheitseinstellungen von MySQL einrichtet und die WorkPlace-Shell-Symbole für MySQL erstellt.

Dynamische Module sind einkompiliert, wurden aber nicht vollständig getestet. Dynamische Module sollten mit der Pthreads-Laufzeitbibliothek kompiliert werden.

gcc -Zdll -Zmt -Zcrtdll=pthrdrtl -I../include -I../regex -I.. \
    -o example udf_example.cc -L../lib -lmysqlclient udf_example.def
mv example.dll example.udf

Hinweis: Aufgrund der Beschränkungen in OS/2 dürfen UDF-Modulnamenstämme nicht länger als acht Zeichen sein. Module werden im Verzeichnis /mysql2/udf gespeichert, welches vom Skript safe-mysqld.cmd in der Umgebungsvariablen BEGINLIBPATH abgelegt wird. Wenn Sie UDF-Module verwenden, werden die angegebenen Erweiterungen ignoriert (es wird davon ausgegangen, dass diese ohnehin immer .udf lauten). Beispielsweise kann das gemeinsame Modul unter Unix example.so heißen; eine Funktion daraus würden Sie dann wie folgt laden:

mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME 'example.so';

Bei OS/2 hieße das Modul example.udf, aber Sie würden die Modulerweiterung nicht angeben:

mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME 'example';

2.13. Anmerkungen zur Perl-Installation

Die Perl-Unterstützung für MySQL erfolgt mithilfe der DBI-/DBD-Clientschnittstelle. Die Schnittstelle erfordert Perl 5.6.1 oder höher. Sie funktioniert nicht, wenn Sie eine ältere Perl-Version einsetzen.

Wenn Sie Transaktionen mit Perl DBI verwenden wollen, brauchen Sie DBD::mysql in der Version 1.2216 oder höher. Empfohlen wird DBD::mysql 2.9003 oder höher.

Sofern Sie MySQL 4.1 oder eine neuere Clientbibliothek verwenden, müssen Sie DBD::mysql 2.9003 oder höher in jedem Fall einsetzen.

Die Perl-Unterstützung ist nicht in den MySQL-Distributionen enthalten. Die erforderlichen Module für Unix erhalten Sie unter http://search.cpan.org bzw. für Windows durch Verwendung des ActiveState-Programms ppm. Die folgenden Abschnitte beschreiben die erforderlichen Abläufe.

Wenn Sie die MySQL-Benchmark-Skripten ausführen wollen, muss der Perl-Support für MySQL installiert sein. Siehe auch Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“.

2.13.1. Installation von Perl unter Unix

Die Perl-Unterstützung durch MySQL setzt voraus, dass Sie die Unterstützung für die MySQL-Clientprogrammierung (Bibliotheken und Header-Dateien) installiert haben. Bei den meisten Installationsmethoden werden die notwendigen Dateien installiert. Haben Sie MySQL allerdings aus RPM-Dateien für Linux installiert, dann vergewissern Sie sich, dass Sie das Entwickler-RPM zur Installation verwendet haben. Die Clientprogramme befinden sich im Client-RPM, die Unterstützung für die Clientprogrammierung jedoch im Entwickler-RPM.

Wenn Sie die Perl-Unterstützung installieren wollen, erhalten Sie die erforderlichen Dateien beim CPAN (Comprehensive Perl Archive Network) unter http://search.cpan.org.

Die einfachste Möglichkeit, Perl-Module unter Unix zu installieren, besteht in der Verwendung des CPAN-Moduls. Ein Beispiel:

shell> perl -MCPAN -e shell
cpan> install DBI
cpan> install DBD::mysql

Die DBD::mysql-Installation führt eine Anzahl von Tests durch. Bei diesen Tests wird versucht, unter Angabe der Standardwerte für Benutzername und Passwort eine Verbindung zum lokalen MySQL Server herzustellen. (Der Standardbenutzername ist unter Unix Ihr Anmeldename und unter Windows ODBC. Das Standardpasswort heißt „no password“.) Wenn Sie mit diesen Einstellungen keine Verbindung zum Server herstellen können, weil beispielsweise Ihr Konto ein Passwort hat, dann schlagen die Tests fehl. Sie können force install DBD::mysql verwenden, um fehlgeschlagene Tests zu ignorieren.

DBI benötigt das Modul Data::Dumper. Dieses ist unter Umständen bereits installiert, andernfalls sollten Sie es vor der Installation von DBI installieren.

Es ist auch möglich, die Moduldistributionen in Form komprimierter tar-Archive herunterzuladen und die Module manuell zu erstellen. Um beispielsweise eine DBI-Distribution zu entpacken und zu erstellen, verwenden Sie folgende Vorgehensweise:

  1. Entpacken Sie die Distribution in das aktuelle Verzeichnis:

    shell> gunzip < DBI-VERSION.tar.gz | tar xvf -
    

    Dieser Befehl erstellt ein Verzeichnis namens DBI-VERSION.

  2. Wechseln Sie nun in das Stammverzeichnis der entpackten Distribution:

    shell> cd DBI-VERSION
    
  3. Erstellen Sie die Distribution und kompilieren Sie alles:

    shell> perl Makefile.PL
    shell> make
    shell> make test
    shell> make install
    

Der Befehl make test ist wichtig, da mit ihm die Funktionsfähigkeit des Moduls verifiziert wird. Beachten Sie, dass der MySQL Server laufen muss, wenn Sie diesen Befehl während der DBD::mysql-Installation absetzen, um den Schnittstellencode auszuführen; andernfalls schlägt der Test fehl.

Sie sollten die DBD::mysql-Distribution bei jeder Installation eines neuen MySQL-Releases neu erstellen und installieren. Dies gilt insbesondere, wenn Sie beispielsweise feststellen, dass all Ihre DBI-Skripten nach der Aktualisierung von MySQL nicht mehr funktionieren.

Wenn Sie nicht die erforderlichen Berechtigungen zur Installation von Perl-Modulen im Systemverzeichnis haben oder lokale Perl-Module installieren wollen, ist die folgende Referenz für Ihre Belange vielleicht recht nützlich: http://servers.digitaldaze.com/extensions/perl/modules.html#modules

Lesen Sie dort das Kapitel „Installing New Modules that Require Locally Installed Modules“.

2.13.2. Installation von ActiveState-Perl unter Windows

Unter Windows müssen Sie Folgendes tun, um das DBD-Modul mit ActiveState-Perl zu installieren:

  1. Beschaffen Sie sich ActiveState Perl unter http://www.activestate.com/Products/ActivePerl/ und installieren Sie es.

  2. Öffnen Sie ein Konsolenfenster („Eingabeaufforderung“).

  3. Stellen Sie ggf. die Variable HTTP_proxy ein. So kann etwa folgende Einstellung erforderlich sein:

    set HTTP_proxy=my.proxy.com:3128
    
  4. Starten Sie das PPM-Programm:

    C:\> C:\perl\bin\ppm.pl
    
  5. Installieren Sie DBI, sofern Sie dies nicht bereits getan haben:

    ppm> install DBI
    
  6. Führen Sie, wenn alles geklappt hat, folgenden Befehl aus:

    install \
    ftp://ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd
    

Diese Vorgehensweise sollte bei ActiveState Perl 5.6 oder höher funktionieren.

Klappt dies nicht, dann sollten Sie stattdessen den MyODBC-Treiber installieren und über ODBC eine Verbindung zum MySQL Server herstellen:

use DBI;
$dbh= DBI->connect("DBI:ODBC:$dsn",$user,$password) ||
  die "Got error $DBI::errstr when connecting to $dsn\n";

2.13.3. Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl

Wenn Perl meldet, dass das Modul ../mysql/mysql.so nicht gefunden werden kann, dann liegt das wahrscheinlich daran, dass Perl die gemeinsame Bibliothek libmysqlclient.so nicht findet. Sie sollten dieses Problem auf eine der folgenden Weisen lösen können:

  • Kompilieren Sie die Distribution DBD::mysql mit perl Makefile.PL -static -config statt mit perl Makefile.PL.

  • Kopieren Sie libmysqlclient.so in das Verzeichnis, in dem sich Ihre anderen gemeinsamen Bibliotheken befinden (dies ist wahrscheinlich /usr/lib oder /lib).

  • Ändern Sie die -L-Optionen zur Kompilierung von DBD::mysql so ab, dass die tatsächliche Position von libmysqlclient.so berücksichtigt wird.

  • Unter Linux können Sie den Pfadnamen des Verzeichnisses, in dem sich libmysqlclient.so befindet, zur Datei /etc/ld.so.conf hinzufügen.

  • Fügen Sie den Pfadnamen des Verzeichnisses, in dem sich libmysqlclient.so befindet, der Umgebungsvariablen LD_RUN_PATH hinzu. Einige Systeme verwenden stattdessen LD_LIBRARY_PATH.

Beachten Sie, dass Sie möglicherweise auch die -L-Optionen ändern müssen, wenn auch andere Bibliotheken vom Linker nicht gefunden werden. Kann der Linker beispielsweise libc nicht finden, weil sich die Datei in /lib befindet, der Verknüpfungsbefehl aber -L/usr/lib angibt, dann ändern Sie die Option -L zu -L/lib oder fügen -L/lib zum vorhandenen Verknüpfungsbefehl hinzu.

Wenn Sie die folgenden Fehler von DBD::mysql erhalten, verwenden Sie wahrscheinlich gcc (oder eine alte Binärdatei, die mit gcc kompiliert wurde):

/usr/bin/perl: can't resolve symbol '__moddi3'
/usr/bin/perl: can't resolve symbol '__divdi3'

Fügen Sie -L/usr/lib/gcc-lib/... -lgcc zum Verknüpfungsbefehl hinzu, wenn die Bibliothek mysql.so erstellt wird (überprüfen Sie die Ausgabe von make bezüglich mysql.so, wenn Sie den Perl-Client kompilieren). Die -L-Option sollte den Pfadnamen des Verzeichnisses angeben, in dem libgcc.a auf Ihrem System gespeichert ist.

Eine andere Ursache dieses Problems könnte sein, dass nicht sowohl Perl als auch MySQL mit gcc kompiliert wurden. In diesem Fall können Sie die Nichtübereinstimmung beheben, indem Sie beide mit gcc kompilieren.

Wenn Sie die Tests ausführen, gibt DBD::mysql unter Umständen die folgende Fehlermeldung aus:

t/00base............install_driver(mysql) failed:
Can't load '../blib/arch/auto/DBD/mysql/mysql.so' for module DBD::mysql:
../blib/arch/auto/DBD/mysql/mysql.so: undefined symbol:
uncompress at /usr/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169.

Dies bedeutet, dass Sie die Komprimierungsbibliothek -lz in der Verknüpfungszeile hinzufügen müssen. Dies können Sie tun, indem Sie in der Datei lib/DBD/mysql/Install.pm die Zeile

$sysliblist .= " -lm";

wie folgt ändern:

$sysliblist .= " -lm -lz";

Danach müssen Sie make realclean ausführen und nachfolgend von vorne mit der Installation beginnen.

Wenn Sie DBI unter SCO installieren wollen, müssen Sie Makefile in DBI-xxx und allen Unterverzeichnissen bearbeiten. Beachten Sie, dass das Folgende gcc 2.95.2 oder höher voraussetzt:

OLD:                                  NEW:
CC = cc                               CC = gcc
CCCDLFLAGS = -KPIC -W1,-Bexport       CCCDLFLAGS = -fpic
CCDLFLAGS = -wl,-Bexport              CCDLFLAGS =

LD = ld                               LD = gcc -G -fpic
LDDLFLAGS = -G -L/usr/local/lib       LDDLFLAGS = -L/usr/local/lib
LDFLAGS = -belf -L/usr/local/lib      LDFLAGS = -L/usr/local/lib

LD = ld                               LD = gcc -G -fpic
OPTIMISE = -Od                        OPTIMISE = -O1

OLD:
CCCFLAGS = -belf -dy -w0 -U M_XENIX -DPERL_SCO5 -I/usr/local/include

NEW:
CCFLAGS = -U M_XENIX -DPERL_SCO5 -I/usr/local/include

Diese Änderungen sind erforderlich, weil der Perl-Dynaloader die DBI-Module nicht lädt, wenn diese mit icc oder cc kompiliert wurden.

Wollen Sie das Perl-Modul auf einem System verwenden, das keine dynamischen Verknüpfungen unterstützt (wie z. B. SCO), dann können Sie eine statische Perl-Version erzeugen, die DBI und DBD::mysql enthält. Dies funktioniert so, dass Sie eine Perl-Version mit verknüpftem DBI-Code erzeugen und diese über Ihre aktuelle Perl-Installation installieren. Dieses verwenden Sie dann zur Erstellung einer Perl-Version, die zusätzlich den verknüpften DBD-Code beinhaltet und die Sie dann installieren.

Unter SCO müssen Sie zuvor die folgenden Umgebungsvariablen einstellen:

LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/usr/progressive/lib

Oder:

LD_LIBRARY_PATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:\
    /usr/progressive/lib:/usr/skunk/lib
LIBPATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:\
    /usr/progressive/lib:/usr/skunk/lib
MANPATH=scohelp:/usr/man:/usr/local1/man:/usr/local/man:\
    /usr/skunk/man:

Sie erstellen zunächst eine Perl-Version, die ein statisch verknüpftes DBI-Modul enthält. Dies tun Sie durch Ausführen der folgenden Befehle in dem Verzeichnis, in dem Ihre DBI-Distribution gespeichert ist:

shell> perl Makefile.PL -static -config
shell> make
shell> make install
shell> make perl

Danach müssen Sie das neue Perl installieren. Die Ausgabe von make perl gibt den exakten make-Befehl an, den Sie ausführen müssen, um die Installation durchzuführen. Unter SCO heißt der Befehl make -f Makefile.aperl inst_perl MAP_TARGET=perl.

Als Nächstes verwenden Sie das gerade erstellte Perl zur Erstellung eines anderen Perl, welches auch ein statisch verknüpftes DBD::mysql enthält. Hierzu führen Sie die folgenden Befehle in dem Verzeichnis aus, in dem sich Ihre DBD::mysql-Distribution befindet:

shell> perl Makefile.PL -static -config
shell> make
shell> make install
shell> make perl

Abschließend sollten Sie dieses neue Perl installieren. Auch hier zeigt die Ausgabe von make perl den zu verwendenden Befehl an.

Kapitel 3. Einführung in MySQL: ein MySQL-Tutorial

Dieses Kapitel enthält eine Einführung in MySQL. Hier wird erläutert, wie mithilfe des mysql-Clientprogramms eine einfache Datenbank erstellt und verwendet wird. mysql (das manchmal auch als „Terminalmonitor“ oder einfach als „Monitor“ bezeichnet wird) ist ein interaktives Programm, das es Ihnen ermöglicht, Verbindungen mit einem MySQL Server herzustellen, Abfragen auszuführen und die Ergebnisse anzuzeigen. mysql kann auch im Stapelbetrieb verwendet werden: Sie legen Ihre Abfragen im Voraus in einer Datei ab und weisen mysql dann an, den Inhalt dieser Datei auszuführen. Wir werden hier beide Methoden der Verwendung von mysql behandeln.

Um eine Liste der Optionen anzuzeigen, die mysql bietet, rufen Sie es mit der Option --help auf:

shell> mysql --help

Dieses Kapitel setzt voraus, dass mysql auf Ihrem Computer installiert ist und dass ein MySQL Server verfügbar ist, mit dem Sie eine Verbindung herstellen können. Sollte dies nicht der Fall sein, dann wenden Sie sich an Ihren MySQL-Administrator. (Wenn Sie selbst der Administrator sind, lesen Sie die erforderlichen Abschnitte dieses Handbuchs, z. B. Kapitel 5, Datenbankverwaltung.)

Dieses Kapitel beschreibt den gesamten Vorgang der Einrichtung und Verwendung einer Datenbank. Wenn Sie nur am Zugriff auf eine vorhandene Datenbank interessiert sind, können Sie die Abschnitte überspringen, die beschreiben, wie Datenbanken und die darin enthaltenen Tabellen erstellt werden.

Da dieses Kapitel lediglich ein Tutorial ist, werden natürlich viele Detailangaben weggelassen. Um mehr zu den hier behandelten Themen zu erfahren, lesen Sie die einschlägigen Abschnitte dieses Handbuchs.

3.1. Verbindung zum Server herstellen und trennen

Um eine Verbindung mit dem Server herzustellen, müssen Sie beim Aufruf von mysql normalerweise einen MySQL-Benutzernamen und in aller Regel auch ein Passwort angeben. Wird der Server auf einem anderen System als demjenigen ausgeführt, an dem Sie sich anmelden, dann müssen Sie auch einen Hostnamen angeben. Wenden Sie sich an Ihrem Administrator, um zu erfahren, welche Parameter (Host- und Benutzernamen sowie Passwort) Sie für die Verbindung angeben müssen. Wenn Sie die korrekten Anmeldeinformationen kennen, sollten Sie wie folgt eine Verbindung herstellen können:

shell> mysql -h host -u user -p
Enter password: ********

host und user stehen für den Namen des Hosts, auf dem Ihr MySQL Server ausgeführt wird, bzw. den Benutzernamen Ihres MySQL-Kontos. Ersetzen Sie die Werte wie für Ihre Konfiguration erforderlich. Hierbei repräsentiert ******** Ihr Passwort; geben Sie dieses ein, wenn mysql die Aufforderung Enter password: anzeigt.

Funktioniert alles wie erwartet, dann werden ein paar einleitende Informationen gefolgt von der Eingabeaufforderung mysql> angezeigt:

shell> mysql -h host -u user -p
Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 25338 to server version: 5.1.5-alpha-standard

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>

Die Eingabeaufforderung mysql> zeigt an, dass mysql nun zur Entgegennahme von Befehlen bereit ist.

Wenn Sie sich an dem Computer angemeldet haben, auf dem auch MySQL ausgeführt wird, dann können Sie den Hostnamen weglassen und einfach Folgendes eingeben:

shell< mysql -u user -p

Wenn Sie beim Anmeldeversuch eine Fehlermeldung wie etwa ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) erhalten, bedeutet dies, dass der MySQL Server-Daemon (unter Unix) bzw. der MySQL Server-Dienst (unter Windows) nicht ausgeführt wird. Wenden Sie sich an den Administrator oder lesen Sie den für Ihr Betriebssystem vorgesehenen Abschnitt in Kapitel 2, Installation von MySQL.

Hilfe bei anderen Problemen, die beim Anmelden häufig auftreten, finden Sie in Abschnitt A.2, „Einige häufige Fehler bei der Benutzung von MySQL“.

Einige MySQL-Installationen gestatten Benutzern die Herstellung einer Verbindung zum auf dem lokalen Host laufenden Server als anonymer (d. h. nicht benannter) Benutzer. Sollte dies bei Ihrem System der Fall sein, dann sollten Sie eine Verbindung herstellen können, indem Sie mysql einfach ohne weitere Optionen aufrufen:

shell> mysql

Wenn Sie erfolgreich eine Verbindung hergestellt haben, können Sie diese jederzeit trennen, indem Sie QUIT (oder einfach \q) an der Eingabeaufforderung mysql> eingeben:

mysql> QUIT
Bye

Unter Unix können Sie die Trennung auch mit der Tastenkombination Strg+D durchführen.

Die meisten Beispiele in den nachfolgenden Abschnitten setzen voraus, dass Sie mit dem Server verbunden sind. Dieses wird durch die Eingabeaufforderung mysql> angezeigt.

3.2. Anfragen eingeben

Stellen Sie zunächst wie im vorhergehenden Abschnitt beschrieben eine Verbindung zum Server her. Durch diesen Vorgang wird noch keine Datenbank ausgewählt, was aber noch nicht problematisch ist. Wir wollen erst einmal sehen, wie man Abfragen absetzt, statt gleich mit den eigentlichen Datenbankfunktionen – dem Erstellen von Tabellen und dem Einladen von Daten in bzw. Abrufen dieser Daten aus den Tabellen – anzufangen. Dieser Abschnitt erläutert die Grundprinzipien der Befehlseingabe mithilfe verschiedener Abfragen, die Sie ausprobieren können, um sich mit der Funktionsweise von mysql vertraut zu machen.

Hier zunächst ein einfacher Befehl, der den Server bittet, seine Versionsnummer und das aktuelle Datum anzugeben. Geben Sie den Befehl wie hier gezeigt an der Eingabeaufforderung mysql> ein und betätigen Sie dann die Eingabetaste:

mysql> SELECT VERSION(), CURRENT_DATE;
+-----------------+--------------+
| VERSION()       | CURRENT_DATE |
+-----------------+--------------+
| 5.1.2-alpha-log | 2005-10-11   |
+-----------------+--------------+
1 row in set (0.01 sec)
mysql>

Diese Abfrage veranschaulicht mehrere Aspekte von mysql:

  • Ein Befehl besteht normalerweise aus einer SQL-Anweisung gefolgt von einem Semikolon. (Es gibt eine Reihe von Ausnahmen, bei denen das Semikolon weggelassen werden kann. Ein Beispiel ist das bereits weiter oben erwähnte QUIT; weitere werden folgen.)

  • Wenn Sie einen Befehl absetzen, sendet mysql ihn zur Ausführung an den Server und zeigt die Ergebnisse an. Darauf folgt wieder eine neue Eingabeaufforderung mysql>, mit der angezeigt wird, dass nun ein neuer Befehl eingegeben werden kann.

  • mysql zeigt die Abfrageausgabe in Tabellenform (d. h. als Zeilen und Spalten) an. Die erste Zeile enthält die Spaltenüberschriften. Alle nachfolgenden Zeilen sind Abfrageergebnisse. Normalerweise sind Spaltenüberschriften die Namen der Spalten, die aus den Datenbanktabellen abgerufen werden. Wenn Sie den Wert eines Ausdrucks statt einer Tabellenspalte (wie im obigen Beispiel) abrufen, beschriftet mysql die Spalte mit dem Ausdruck selbst.

  • mysql zeigt an, wie viele Datensätze (Zeilen) zurückgegeben wurden und wie lange die Ausführung der Abfrage dauerte; hierdurch können Sie grob auf die Serverleistung schließen. Die Werte sind allerdings nicht sehr genau, denn sie geben nur eine normale Zeit statt der Prozessor- oder Systemzeit an, die zudem durch Faktoren wie der Serverauslastung und der Netzwerklatenz beeinflusst wird. (Aus Gründen der Übersichtlichkeit haben wir die Zeile „rows in set“ in einigen der in diesem Kapitel aufgeführten Beispiele weggelassen.)

Schlüsselwörter können in beliebiger Groß-/Kleinschreibung angegeben werden. Die folgenden Abfragen sind gleichwertig:

mysql> SELECT VERSION(), CURRENT_DATE;
mysql> select version(), current_datum;
mysql> SeLeCt vErSiOn(), current_DATE;

Es folgt eine weitere Abfrage. Sie veranschaulicht, wie man mysql als einfachen Taschenrechner verwenden kann:

mysql> SELECT SIN(PI()/4), (4+1)*5;
+------------------+---------+
| SIN(PI()/4)      | (4+1)*5 |
+------------------+---------+
| 0.70710678118655 |      25 |
+------------------+---------+
1 row in set (0.02 sec)

Die bislang gezeigten Abfragen waren vergleichsweise kurze, einzeilige Anweisungen. Sie können aber auch mehrere Anweisungen in eine Zeile schreiben. Schließen Sie sie jeweils mit einem Semikolon ab:

mysql> SELECT VERSION(); SELECT NOW();
+-----------------+
| VERSION()       |
+-----------------+
| 5.1.2-alpha-log |
+-----------------+
1 row in set (0.00 sec)

+---------------------+
| NOW()               |
+---------------------+
| 2005-10-11 15:15:00 |
+---------------------+
1 row in set (0.00 sec)

Ein Befehl muss nicht vollständig innerhalb einer einzelnen Zeile angegeben werden; insofern stellen auch längere Befehle über mehrere Zeilen kein Problem dar. mysql ermittelt das Ende Ihrer Anweisung anhand des schließenden Semikolons und nicht auf der Basis der Eingabezeile. (Anders gesagt, akzeptiert mysql frei formatierte Eingaben: Alle Eingabezeilen werden gesammelt, die Ausführung erfolgt aber erst, nachdem das Semikolon erkannt wurde.)

Hier ist eine einfache mehrzeilige Anweisung:

mysql> SELECT
    -> USER()
    -> ,
    -> CURRENT_DATE;
+---------------+--------------+
| USER()        | CURRENT_DATE |
+---------------+--------------+
| jon@localhost | 2005-10-11   |
+---------------+--------------+

Beachten Sie in diesem Beispiel, wie die Eingabeaufforderung von mysql> auf -> umschaltet, nachdem Sie die erste Zeile einer mehrzeiligen Abfrage eingegeben haben. Auf diese Weise zeigt mysql an, dass noch keine vollständige Anweisung erkannt wurde und weitere Eingaben erwartet werden. Diese Form der Eingabeaufforderung ist sehr praktisch, denn sie erlaubt Rückschlüsse auf erforderliche Eingaben. Sie wissen also immer, worauf mysql gerade wartet.

Wenn Sie einen Befehl, den Sie gerade eingeben, doch nicht ausführen wollen, können Sie ihn durch Eingabe von \c abbrechen:

mysql> SELECT
    -> USER()
    -> \c
mysql>

Beachten Sie auch hier die Eingabeaufforderung. Sie schaltet zurück auf mysql>, nachdem Sie \c eingegeben haben. So wird angezeigt, dass mysql auf einen neuen Befehl wartet.

Die folgende Tabelle zeigt alle Eingabeaufforderungen, auf die Sie treffen können, und fasst ferner zusammen, welche Rückschlüsse sie jeweils bezüglich des Zustandes von mysql erlauben.

EingabeaufforderungBedeutung
mysql>Bereit für einen neuen Befehl.
->Erwartet die nächste Zeile einer mehrzeiligen Befehlseingabe.
'>Erwartet die nächste Zeile und die Vervollständigung eines Strings, der mit einem einfachen Anführungszeichen (‘'’) begonnen wurde.
">Erwartet die nächste Zeile und die Vervollständigung eines Strings, der mit einem doppelten Anführungszeichen (‘"’) begonnen wurde.
`>Erwartet die nächste Zeile und die Vervollständigung eines Bezeichners, der mit einem Backtick (‘`’) begonnen wurde.
/*>Erwartet die nächste Zeile und die Vervollständigung eines Kommentars, der mit /* begonnen wurde.

Mehrzeilige Anweisungen treten häufig ungewollt auf, wenn Sie eigentlich nur einen einzeiligen Befehl absetzen wollen, aber das abschließende Semikolon vergessen. In diesem Fall erwartet mysql eine weitere Eingabe:

mysql> SELECT USER()
    ->

Wenn das geschieht (d. h., wenn Sie glauben, dass Sie einen vollständigen Befehl eingegeben haben, aber die Eingabeaufforderung -> erscheint), dann wartet mysql in aller Regel auf das Semikolon. Bemerken Sie nicht sofort, welche Eingabeaufforderung hier angezeigt wird, dann sitzen Sie womöglich eine Zeit lang vor dem Computer, bevor Sie feststellen, was passiert ist. Geben Sie einfach ein Semikolon ein, um die Anweisung abzuschließen – sie wird dann von mysql ausgeführt:

mysql> SELECT USER()
    -> ;
+---------------+
| USER()        |
+---------------+
| jon@localhost |
+---------------+

Die Eingabeaufforderungen '> und "> erscheinen bei der Erfassung von Strings (MySQL erwartet also die Vervollständigung eines Strings). In MySQL können Sie Strings entweder in ‘'’ oder ‘"’ setzen (z. B. 'hello' oder "goodbye"). mysql erlaubt die Eingabe von Strings, die sich über mehrere Zeilen erstrecken. Wenn Sie die Eingabeaufforderung '> oder "> sehen, bedeutet dies, dass Sie eine Zeile mit einem String eingegeben haben, der mit dem Anführungszeichen ‘'’ oder ‘"’ beginnt, diesen String aber noch nicht mit dem zugehörigen schließenden Anführungszeichen beendet haben. Hierdurch ist häufig erkennbar, dass Sie ein Anführungszeichen einzugeben vergessen haben. Ein Beispiel:

mysql> SELECT * FROM my_table WHERE name = 'Smith AND alter < 30;
    '>

Wenn Sie diese SELECT-Anweisung eingeben und dann die Eingabetaste betätigen, werden Sie eine Zeit lang warten, ohne dass etwas passiert. Wenn Sie sich wundern, warum die Verarbeitung der Abfrage so lange dauert, werden Sie bald feststellen, dass die Eingabeaufforderung '> angezeigt wird. Sie besagt, dass mysql den Rest eines nicht abgeschlossenen Strings erwartet. (Erkennen Sie den Fehler in der Anweisung? Beim String 'Smith fehlt das zweite einzelne Anführungszeichen.)

Was können Sie nun tun? Die einfachste Möglichkeit besteht darin, den Befehl abzubrechen. Sie können in diesem Fall aber nicht einfach \c eingeben, da mysql dies als Teil des Strings interpretieren würde, den Sie vermeintlich eingeben. Geben Sie stattdessen zuerst das schließende Anführungszeichen (damit mysql weiß, dass der String abgeschlossen ist) und erst dann \c ein:

mysql> SELECT * FROM my_table WHERE name = 'Smith AND alter < 30;
    '> '\c
mysql>

Die Eingabeaufforderung schaltet nun auf mysql> zurück und zeigt so an, dass mysql für einen neuen Befehl bereit ist.

Die Eingabeaufforderung `> ähnelt '> und ">, gibt aber an, dass Sie mit einem Backtick einen Bezeichner begonnen, aber noch nicht beendet haben.

Zu wissen, was die Eingabeaufforderungen '>, "> und `> bedeuten, ist wichtig, denn wenn Sie versehentlich einen nicht abgeschlossenen String eingeben, werden alle nachfolgend eingegebenen Zeilen von mysql ignoriert – einschließlich der Zeile mit dem Befehl QUIT. Dies kann insbesondere dann recht verwirrend sein, wenn Sie nicht wissen, dass Sie ein schließendes Anführungszeichen eingeben müssen, bevor Sie den aktuellen Befehl abbrechen können.

3.3. Eine Datenbank erzeugen und benutzen

Nachdem Sie nun wissen, wie Sie Befehle eingeben, sind Sie so weit, dass Sie auf eine Datenbank zugreifen können.

Angenommen, Sie halten bei sich zu Hause mehrere Haustiere (Ihre kleine „Menagerie“) und wollen nun verschiedene Informationen zu diesen Tieren verwalten. Dies können Sie tun, indem Sie Tabellen erstellen, die die gewünschten Informationen aufnehmen sollen, und diese Tabellen dann mit den erforderlichen Daten bestücken. Danach können Sie zu Ihren Tieren verschiedene Arten von Fragen beantworten, indem Sie Daten aus den Tabellen abrufen. In diesem Abschnitt erläutern wir, wie man

  • eine Datenbank erstellt,

  • eine Tabelle erstellt,

  • Daten in eine Tabelle lädt,

  • Daten auf verschiedene Weisen aus der Tabelle abruft,

  • mehrere Tabellen verwendet.

Die Menageriedatenbank ist (bewusst) einfach gehalten, aber es ist auch nicht schwierig, sich Situationen aus dem täglichen Leben vorzustellen, in denen eine ähnliche Art von Datenbank zum Einsatz kommen könnte. Eine solche Datenbank könnte etwa von einem Landwirt, der seinen Tierbestand organisieren möchte, oder von einem Tierarzt zur Patientenverwaltung verwendet werden. Eine Menageriedistribution mit einigen der in den folgenden Abschnitten verwendeten Abfragen und Beispieldaten finden Sie auf der MySQL-Website. Sie ist in komprimierter Form als tar- (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.tar.gz) und Zip-Archiv (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.zip) verfügbar.

Verwenden Sie die SHOW-Anweisung, um zu ermitteln, welche Datenbanken derzeit auf dem Server vorhanden sind:

mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql    |
| test     |
| tmp      |
+----------+

Die Liste der Datenbanken sieht auf Ihrem Computer wahrscheinlich etwas anders aus, aber die Datenbanken mysql und test sind höchstwahrscheinlich vorhanden. Die Datenbank mysql ist erforderlich, da sie die Benutzerberechtigungen beschreibt. Die Datenbank test hingegen wird häufig als Spielplatz für Benutzer verwendet, die Dinge ausprobieren möchten.

Beachten Sie, dass Ihnen unter Umständen nicht alle Datenbanken angezeigt werden, wenn Ihnen die Berechtigung SHOW DATABASES fehlt. Siehe auch Abschnitt 13.5.1.3, „GRANT und REVOKE.

Wenn die Datenbank test vorhanden ist, versuchen Sie sie aufzurufen:

mysql> USE test
Database changed

Beachten Sie, dass USE ebenso wie QUIT kein Semikolon braucht. (Sie können solche Anweisungen aber nichtsdestoweniger mit einem Semikolon abschließen – hierdurch wird kein Schaden angerichtet.) Die USE-Anweisung ist auch auf andere Weise besonders: Sie muss in einer einzigen Zeile angegeben werden.

Sie können die Datenbank test für die folgenden Beispiele verwenden (vorausgesetzt, Sie haben Zugriff darauf); beachten Sie aber, dass alles, was Sie in dieser Datenbank erstellen, von allen anderen Benutzern, die darauf zugreifen dürfen, entfernt werden kann. Aus diesem Grund sollten Sie Ihren MySQL-Administrator besser bitten, eine eigene Datenbank verwenden zu dürfen. Wenn Sie Ihre Datenbank menagerie nennen wollen, dann muss der Administrator folgenden Befehl ausführen:

mysql> GRANT ALL ON menagerie.* TO 'your_mysql_name'@'your_client_host';

Hierbei ist your_mysql_name der Ihnen zugewiesene MySQL-Benutzername und your_client_host der Name des Hosts, von dem aus Sie die Verbindung zum Server herstellen.

3.3.1. Eine Datenbank erzeugen und auswählen

Wenn Ihr Administrator beim Konfigurieren der Berechtigungen eine Datenbank für Sie erstellt hat, können Sie diese sofort nutzen. Andernfalls müssen Sie sie selbst einrichten:

mysql> CREATE DATABASE menagerie;

Unter Unix wird bei Datenbanknamen – anders als bei SQL-Schlüsselwörtern – die Groß-/Kleinschreibung unterschieden. Deswegen muss der Datenbankname immer als menagerie und nicht als Menagerie, MENAGERIE oder in einer anderen Variante angegeben werden. Gleiches gilt für Tabellennamen. (Unter Windows gilt diese Einschränkung nicht; allerdings müssen Sie innerhalb einer Abfrage eine Datenbank oder Tabelle konsistent mit derselben Schreibung bezeichnen. Wir empfehlen jedoch aus verschiedenen Gründen, immer dieselbe Schreibweise zu nutzen, die beim Einrichten der Datenbank verwendet wurde.)

Hinweis: Wenn Sie beim Erstellen einer Datenbank eine Fehlermeldung wie etwa ERROR 1044 (42000): Access denied for user 'monty'@'localhost' to database 'menagerie' erhalten, bedeutet dies, dass Ihr Benutzerkonto nicht die zur Datenbankerstellung erforderlichen Berechtigungen hat. Besprechen Sie dies mit Ihrem Administrator oder lesen Sie Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“.

Wenn Sie eine Datenbank erstellen, wird diese nicht automatisch für die Verwendung ausgewählt; Sie müssen dies ausdrücklich tun. Um menagerie also zur aktuellen Datenbank zu machen, verwenden Sie folgenden Befehl:

mysql> USE menagerie
Database changed

Ihre Datenbank muss nur einmal erstellt werden, sie muss aber jedes Mal, wenn Sie eine mysql-Sitzung beginnen, zur Verwendung ausgewählt werden. Dies tun Sie durch Absetzen einer USE-Anweisung wie im Beispiel gezeigt. Alternativ können Sie die Datenbank auch auf der Befehlszeile auswählen, wenn Sie mysql aufrufen. Geben Sie auf alle ggf. erforderlichen Verbindungsparameter folgend einfach den Datenbanknamen ein. Ein Beispiel:

shell> mysql -h host -u user -p menagerie
Enter password: ********

Beachten Sie, dass menagerie im gerade gezeigten Befehl nicht Ihr Passwort ist. Wenn Sie Ihr Passwort auf der Befehlszeile nach der Option -p angeben wollen, müssen Sie dies ohne zwischengeschaltetes Leerzeichen tun (z. B. als -pmypassword, nicht jedoch als -p mypassword). Allerdings wird von der Übermittlung des Passworts auf der Befehlszeile ohnehin abgeraten, weil es so anderen Benutzern offenbart werden könnte, die an Ihrem Computer angemeldet sind.

3.3.2. Eine Tabelle erzeugen

Das Erstellen einer Datenbank ist ganz einfach. Noch aber ist die Datenbank leer, wie Sie mit SHOW TABLES nachprüfen können:

mysql> SHOW TABLES;
Empty set (0.00 sec)

Schwieriger zu entscheiden ist hingegen, wie die Struktur der Datenbank aussehen soll: Welche Tabellen brauchen Sie? Und welche Spalten sollen in diesen Tabellen enthalten sein?

Sie brauchen eine Tabelle, die einen Datensatz für jedes Ihrer Haustiere enthält. Diese Tabelle könnte man haustier nennen; sie sollte zumindest den Namen jedes Tieres enthalten. Da der Name an sich aber nicht besonders interessant ist, sollte die Tabelle auch weitere Informationen enthalten. Wenn beispielsweise mehrere Personen in Ihrer Familie Haustiere halten, würde es sich anbieten, die Besitzer der einzelnen Tiere aufzuführen. Ferner könnten einige grundlegende Beschreibungen eingetragen werden, z. B. die Tierart und das Geschlecht.

Und das Alter der Tiere? Das könnte zwar interessant sein, die Speicherung in einer Datenbank ist jedoch problematisch. Da sich das Alter im Laufe der Zeit ändert, müssten Sie Ihre Datensätze regelmäßig aktualisieren. Stattdessen ist es besser, einen festen Wert wie etwa das Geburtsdatum zu speichern. Wann immer Sie dann das Alter eines Tieres in Erfahrung bringen wollten, müssten Sie nur die Differenz zwischen dem aktuellen Datum und dem Geburtsdatum errechnen. MySQL bietet Funktionen, die derartige Rechenaufgaben erledigen können, sodass dies nicht weiter schwierig ist. Das Speichern des Geburtsdatums statt des Alters hat aber auch weitere Vorteile:

  • Sie können die Datenbank für Aufgaben wie das automatische Erinnern an anstehende Tiergeburtstage verwenden. (Wenn Sie der Ansicht sind, dass eine solche Abfrage etwas albern ist, dann beachten Sie, dass Sie dieselbe Frage im Kontext einer Unternehmensdatenbank verwenden könnten, um Kunden zu ermitteln, denen Sie demnächst Geburtstagsgrüße senden wollen – die persönliche Note mit freundlicher Unterstützung Ihrer Datenbank.)

  • Sie können das Alter auch in Relation zu anderen als dem aktuellen Datum berechnen. Wenn Sie etwa das Sterbedatum eines Tieres in der Datenbank ablegen, können Sie ganz leicht berechnen, wie alt es bei seinem Tod war.

Sie können sich wahrscheinlich eine Reihe andere Informationstypen vorstellen, die in der Tabelle haustier von Nutzen sein könnten, aber die bisher genannten sollen fürs Erste ausreichen: Name, Besitzer, Tierart, Geschlecht, Geburts- und Sterbedatum.

Das Layout Ihrer Tabelle legen Sie mit einer CREATE TABLE-Anweisung fest:

mysql> CREATE TABLE haustier (name VARCHAR(20), besitzer VARCHAR(20),
    -> gattung VARCHAR(20), geschlecht CHAR(1), geburtstag DATE, todestag DATE);

VARCHAR ist eine geeignete Wahl für die Spalten name, besitzer und gattung, denn die Werte dieser Spalten können in der Länge variieren. Die Längen in diesen Spaltendefinitionen müssen weder identisch sein noch alle den Wert 20 haben. Sie können eine beliebige Länge zwischen 1 und 65535 eingeben – je nachdem, was Ihnen am sinnvollsten erscheint. Haben Sie jedoch eine falsche Entscheidung getroffen und es stellt sich später heraus, dass Sie ein längeres Feld benötigen, dann bietet MySQL hierfür die ALTER TABLE-Anweisung an.

Zur Auswahl des Geschlechts Ihrer Tiere bieten sich mehrere Wertetypen an, z. B. 'm' und 'w' oder auch 'männlich' und 'weiblich'. Am einfachsten ist die Verwendung der Einzelzeichen 'm' und 'w'.

Der Datentyp DATE ist offensichtlich am geeignetsten für die Spalten geburtstag und todestag.

Wenn Sie eine Tabelle erstellt haben, sollte die Anweisung SHOW TABLES eine entsprechende Ausgabe erzeugen:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| haustier            |
+---------------------+

Um zu überprüfen, dass Ihre Tabelle wie gewünscht erstellt worden ist, verwenden Sie eine DESCRIBE-Anweisung:

mysql> DESCRIBE haustier;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| name       | varchar(20) | YES  |     | NULL    |       |
| besitzer   | varchar(20) | YES  |     | NULL    |       |
| gattung    | varchar(20) | YES  |     | NULL    |       |
| geschlecht | char(1)     | YES  |     | NULL    |       |
| geburtstag | date        | YES  |     | NULL    |       |
| todestag   | date        | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+

Sie können DESCRIBE auch jederzeit aufrufen, wenn Sie die Spaltennamen Ihrer Tabelle oder die verwendeten Datentypen vergessen haben.

Weitere Informationen zu MySQL-Datentypen finden Sie in Kapitel 11, Datentypen.

3.3.3. Daten in Tabellen einladen

Nachdem Sie Ihre Tabelle erstellt haben, müssen Sie sie mit Daten füllen. Zu diesem Zweck sind die Anweisungen LOAD DATA und INSERT vorhanden.

Nehmen wir einmal an, dass sich die Angaben zu Ihren Haustieren wie in der folgenden Tabelle gezeigt zusammenfassen lassen (beachten Sie dabei, dass MySQL Datumsangaben im Format 'YYYY-MM-DD' erwartet; dies unterscheidet sich unter Umständen von dem Format, mit dem Sie vertraut sind).

namebesitzergattunggeschlechtgeburtstagtodestag
FluffyHaroldKatzew1993-02-04 
ClawsGwenKatzem1994-03-17 
BuffyHaroldHundw1989-05-13 
FangBennyHundm1990-08-27 
BowserDianeHundm1979-08-311995-07-29
ChirpyGwenVogelw1998-09-11 
WhistlerGwenVogel 1997-12-09 
SlimBennySchlangem1996-04-29 

Da wir anfangs eine leere Tabelle haben, können Sie diese zunächst ganz einfach ausfüllen, indem Sie eine Textdatei erstellen, die jeweils eine Zeile pro Tier enthält. Die Inhalte der Datei können Sie dann mit einer einzigen Anweisung in die Tabelle einladen.

Erstellen Sie also eine Textdatei namens haustier.txt mit einem Datensatz pro Zeile, bei dem die einzelnen Werte durch Tabulatorzeichen voneinander getrennt sind; die Werte müssen dabei in der Reihenfolge eingegeben werden, in der Sie in der CREATE TABLE-Anweisung aufgeführt wurden. Bei fehlenden Werten (z. B. wenn das Geschlecht nicht bekannt oder das Ableben des Tieres noch nicht erfolgt ist) können Sie NULL-Werte eingeben. Diese geben Sie als \N (Backslash, großes N) in Ihre Textdatei ein. So würde der Datensatz für Whistler, den Vogel, wie folgt aussehen (der Whitespace zwischen den Werten ist ein Tabulatorzeichen):

namebesitzergattunggeschlechtgeburtstagtodestag
WhistlerGwenVogel\N1997-12-09\N

Um die Textdatei haustier.txt in die Tabelle haustier zu laden, genügt die folgende Anweisung:

mysql> LOAD DATA LOCAL INFILE '/path/haustier.txt' INTO TABLE haustier;

Beachten Sie, dass Sie, wenn Sie die Datei unter Windows mit einem Editor erstellt haben, der \r\n als Zeilenbegrenzer verwendet, Folgendes verwenden:

mysql> LOAD DATA LOCAL INFILE '/path/haustier.txt' INTO TABLE haustier
    -> LINES TERMINATED BY '\r\n';

(Auf einem Apple Macintosh unter Mac OS X würden Sie hingegen eher LINES TERMINATED BY '\r' benutzen.)

Sie können das Trennzeichen für Spaltenwerte und den Zeilenbegrenzer bei Bedarf auch ausdrücklich in der LOAD DATA-Anweisung angeben, die Standardeinstellungen sind jedoch das Tabulator- bzw. das Zeilenvorschubzeichen. Diese Einstellungen sind zum Einlesen unserer Datei haustier.txt geeignet.

Schlägt die Anweisung fehl, dann liegt das wahrscheinlich daran, dass bei der MySQL-Installation standardmäßig nicht die Funktionalität für lokale Dateien aktiviert ist. Wie Sie dies ändern, erfahren Sie in Abschnitt 5.7.4, „Sicherheitsprobleme mit LOAD DATA LOCAL.

Zum sukzessiven Einfügen neuer Datensätze ist die INSERT-Anweisung am praktischsten. In ihrer einfachsten Form geben Sie Werte für jede Spalte in der Reihenfolge an, in der die Spalten in der CREATE TABLE-Anweisung aufgeführt waren. Nehmen wir etwa an, Diane bekommt einen neuen Hamster namens „Puffball“. Nun könnten Sie den erforderlichen neuen Datensatz wie folgt mithilfe einer INSERT-Anweisung angeben:

mysql> INSERT INTO haustier
    -> VALUES ('Puffball','Diane','Hamster','w','1999-03-30',NULL);

Beachten Sie, dass die String- und Datenwerte hier in Anführungszeichen gesetzt werden. Mit der INSERT-Anweisung können Sie NULL auch direkt eingeben, um einen fehlenden Wert darzustellen. \N würden Sie hier – anders als bei LOAD DATA – nicht verwenden.

Aus diesem Beispiel sollte klar werden, dass die Erstellung der Basisdatensätze mithilfe einzelner INSERT-Anweisungen erheblich mehr Tipparbeit bedeuten würde als die Verwendung einer einzelnen LOAD DATA-Anweisung.

3.3.4. Informationen aus einer Tabelle abfragen

Mit der SELECT-Anweisung können Sie Daten aus einer Tabelle abrufen. Die allgemeine Form dieser Anweisung sieht wie folgt aus:

SELECT what_to_select
FROM which_table
WHERE conditions_to_satisfy;

what_to_select gibt hierbei an, was Sie sehen wollen. Dies kann eine Liste mit Spalten oder alternativ * sein, wenn Sie alle Spalten anzeigen wollen. which_table gibt die Tabelle an, aus der Sie Daten abrufen wollen. Die WHERE-Klausel ist optional. Ist sie vorhanden, dann gibt conditions_to_satisfy eine oder mehrere Bedingungen an, die Datensätze erfüllen müssen, um abgerufen zu werden.

3.3.4.1. Alle Daten auswählen

Die einfachste Form von SELECT ruft alle in der Tabelle vorhandenen Daten ab:

mysql> SELECT * FROM haustier;
+----------+----------+----------+------------+------------+------------+
| name     | besitzer | gattung  | geschlecht | geburtstag | todestag   |
+----------+----------+----------+------------+------------+------------+
| Fluffy   | Harold   | Katze    | w          | 1993-02-04 | NULL       |
| Claws    | Gwen     | Katze    | m          | 1994-03-17 | NULL       |
| Buffy    | Harold   | Hund     | w          | 1989-05-13 | NULL       |
| Fang     | Benny    | Hund     | m          | 1990-08-27 | NULL       |
| Bowser   | Diane    | Hund     | m          | 1979-08-31 | 1995-07-29 |
| Chirpy   | Gwen     | Vogel    | w          | 1998-09-11 | NULL       |
| Whistler | Gwen     | Vogel    | NULL       | 1997-12-09 | NULL       |
| Slim     | Benny    | Schlange | m          | 1996-04-29 | NULL       |
| Puffball | Diane    | Hamster  | w          | 1999-03-30 | NULL       |
+----------+----------+----------+------------+------------+------------+

Diese Verwendung von SELECT ist nützlich, wenn Sie beispielsweise Ihre Tabelle überprüfen wollen, nachdem Sie gerade die ersten Daten eingeladen haben. Nehmen wir etwa an, dass Sie nicht ganz sicher sind, ob Sie für Bowser das richtige Geburtsdatum eingegeben haben. Dem Stammbaum entnehmen Sie, dass das korrekte Geburtsjahr nicht 1979, sondern 1989 lautet.

Nun gibt es zwei Möglichkeiten, den Fehler zu beheben:

  • Sie korrigieren den Datensatz in der Datei haustier.txt, leeren die Tabelle mit DELETE und laden die Daten dann mit LOAD DATA neu ein:

    mysql> DELETE FROM haustier;
    mysql> LOAD DATA LOCAL INFILE 'haustier.txt' INTO TABLE haustier;
    

    Allerdings müssen Sie bei dieser Vorgehensweise auch die Daten für Puffball neu eingeben.

  • Sie ändern nur den fehlerhaften Datensatz. Hierzu verwenden Sie eine UPDATE-Anweisung:

    mysql> UPDATE haustier SET geburtstag = '1989-08-31' WHERE name = 'Bowser';
    

    Mit UPDATE ändern Sie nur den fraglichen Datensatz – Sie müssen die Tabellendaten in diesem Fall nicht neu laden.

3.3.4.2. Bestimmte Zeilen auswählen

Wie im vorherigen Abschnitt gezeigt, ist das Abrufen der Daten einer ganzen Tabelle recht einfach. Sie lassen einfach die WHERE-Klausel in der SELECT-Anweisung weg. In der Regel wollen Sie aber nicht die gesamte Tabelle anzeigen – insbesondere dann nicht, wenn diese sehr groß ist. Stattdessen werden Sie meist an der Beantwortung einer bestimmten Frage interessiert sein. In diesem Fall müssen Sie Beschränkungen für die gewünschten Daten definieren. Betrachten wir einmal einige Auswahlabfragen dahingehend, welche Fragen diese zu Ihren Haustieren beantworten.

Sie können die Auswahl in Ihrer Tabelle auch auf bestimmte Datensätze beschränken. Wollen Sie z. B. die Änderungen am Geburtsdatum von Bowser überprüfen, dann wählen Sie den entsprechenden Datensatz wie folgt aus:

mysql> SELECT * FROM haustier WHERE name = 'Bowser';
+--------+----------+----------+------------+------------+------------+
| name   | besitzer | gattung  | geschlecht | geburtstag | todestag   |
+--------+----------+----------+------------+------------+------------+
| Bowser | Diane    | Hund     | m          | 1989-08-31 | 1995-07-29 |
+--------+----------+----------+------------+------------+------------+

Die Ausgabe bestätigt die korrekte Änderung der Jahresangabe von 1979 auf 1989.

Bei String-Vergleichen wird die Groß-/Kleinschreibung normalerweise ignoriert, weswegen Sie den Namen als 'bowser', 'BOWSER' usw. angeben können. Das Abfrageergebnis ist stets gleich.

Sie können Bedingungen aber nicht nur für name, sondern für jede beliebige Spalte angeben. Wenn Sie beispielsweise wissen wollen, welche Tiere im Jahre 1998 oder danach geboren wurden, testen Sie die Spalte geburtstag:

mysql> SELECT * FROM haustier WHERE geburtstag >= '1998-1-1';
+----------+----------+---------+-------------+------------+----------+
| name     | besitzer | gattung | geschlecht  | geburtstag | todestag |
+----------+----------+---------+-------------+------------+----------+
| Chirpy   | Gwen     | Vogel   | w           | 1998-09-11 | NULL     |
| Puffball | Diane    | Hamster | w           | 1999-03-30 | NULL     |
+----------+----------+---------+-------------+------------+----------+

Sie können auch Bedingungen kombinieren, um etwa nach weiblichen Hunden zu suchen:

mysql> SELECT * FROM haustier WHERE gattung = 'Hund' AND geschlecht = 'w';
+-------+-----------+---------+-------------+------------+----------+
| name  | besitzer  | gattung | geschlecht  | geburtstag | todestag |
+-------+-----------+---------+-------------+------------+----------+
| Buffy | Harold    | Hund    | w           | 1989-05-13 | NULL     |
+-------+-----------+---------+-------------+------------+----------+

Obige Abfrage verwendet den Operator AND (logisches Und). Es gibt analog auch einen Operator OR (logisches Oder):

mysql> SELECT * FROM haustier WHERE gattung = 'Schlange' OR gattung = 'Vogel';
+----------+----------+----------+-------------+------------+----------+
| name     | besitzer | gattung  | geschlecht  | geburtstag | todestag |
+----------+----------+----------+-------------+------------+----------+
| Chirpy   | Gwen     | Vogel    | w           | 1998-09-11 | NULL     |
| Whistler | Gwen     | Vogel    | NULL        | 1997-12-09 | NULL     |
| Slim     | Benny    | Schlange | m           | 1996-04-29 | NULL     |
+----------+----------+----------+-------------+------------+----------+

AND und OR können auch gemischt verwendet werden, wobei AND jedoch Vorrang vor OR hat. Wenn Sie beide Operatoren verwenden, bietet sich die Verwendung von Klammern an, um exakt anzugeben, wie die Bedingungen gruppiert werden sollen:

mysql> SELECT * FROM haustier WHERE (gattung = 'Katze' AND geschlecht = 'm')
    -> OR (gattung = 'Hund' AND geschlecht = 'w');
+-------+-----------+---------+-------------+------------+----------+
| name  | besitzer  | gattung | geschlecht  | geburtstag | todestag |
+-------+-----------+---------+-------------+------------+----------+
| Claws | Gwen      | Katze   | m           | 1994-03-17 | NULL     |
| Buffy | Harold    | Hund    | w           | 1989-05-13 | NULL     |
+-------+-----------+---------+-------------+------------+----------+

3.3.4.3. Bestimmte Spalten auswählen

Wenn Sie nicht die gesamten Datensätze aus Ihrer Tabelle sehen wollen, dann führen Sie in der jeweiligen Abfrage die gewünschten Spalten durch Kommata getrennt auf. Wollen Sie also etwa wissen, wann Ihre Tiere geboren wurden, dann wählen Sie die Spalten name und geburtstag:

mysql> SELECT name, geburtstag FROM haustier;
+----------+------------+
| name     | geburtstag |
+----------+------------+
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Buffy    | 1989-05-13 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Puffball | 1999-03-30 |
+----------+------------+

Um herauszufinden, wem welches Tier gehört, setzen Sie folgende Abfrage ab:

mysql> SELECT besitzer FROM haustier;
+----------+
| besitzer |
+----------+
| Harold   |
| Gwen     |
| Harold   |
| Benny    |
| Diane    |
| Gwen     |
| Gwen     |
| Benny    |
| Diane    |
+----------+

Beachten Sie, dass diese einfache Abfrage die Spalte besitzer jedes Datensatzes abruft; einige davon tauchen mehrfach auf. Um die Ausgabe zu optimieren, können Sie jeden eindeutigen Ergebnisdatensatz genau einmal ausgeben, indem Sie einfach das Schlüsselwort DISTINCT hinzufügen:

mysql> SELECT DISTINCT besitzer FROM haustier;
+----------+
| besitzer |
+----------+
| Benny    |
| Diane    |
| Gwen     |
| Harold   |
+----------+

Mithilfe einer WHERE-Klausel können Sie Datensatz- und Spaltenauswahl kombinieren. Um z. B. die Geburtsdaten von Hunden und Katzen anzuzeigen, verwenden Sie folgende Abfrage:

mysql> SELECT name, gattung, geburtstag FROM haustier
    -> WHERE gattung = 'Hund' OR gattung = 'Katze';
+--------+---------+------------+
| name   | gattung | geburtstag |
+--------+---------+------------+
| Fluffy | Katze   | 1993-02-04 |
| Claws  | Katze   | 1994-03-17 |
| Buffy  | Hund    | 1989-05-13 |
| Fang   | Hund    | 1990-08-27 |
| Bowser | Hund    | 1989-08-31 |
+--------+---------+------------+

3.3.4.4. Zeilen sortieren

Sie haben in den vorangegangenen Beispielen vielleicht bereits festgestellt, dass die Ergebnisdatensätze nicht in einer bestimmten Reihenfolge angezeigt werden. Häufig ist es jedoch einfacher, das Abfrageergebnis zu durchsuchen, wenn die Datensätze sinnvoll sortiert werden. Um ein Ergebnis zu sortieren, verwenden Sie die ORDER BY-Klausel.

Nachfolgend sind die Geburtstage der Tiere nach Datum sortiert aufgelistet:

mysql> SELECT name, geburtstag FROM haustier ORDER BY geburtstag;
+----------+------------+
| name     | geburtstag |
+----------+------------+
| Buffy    | 1989-05-13 |
| Bowser   | 1989-08-31 |
| Fang     | 1990-08-27 |
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Slim     | 1996-04-29 |
| Whistler | 1997-12-09 |
| Chirpy   | 1998-09-11 |
| Puffball | 1999-03-30 |
+----------+------------+

Bei zeichenbasierten Spalten erfolgt die Sortierung – wie bei allen anderen Vergleichsoperationen auch – normalerweise ohne Berücksichtigung der Groß-/Kleinschreibung. Das bedeutet, dass die Reihenfolge bei Spalten, die bis auf die Groß-/Kleinschreibung identisch sind, nicht definiert ist. Sie können die Sortierung einer Spalte unter Berücksichtigung der Groß-/Kleinschreibung durch Verwendung von BINARY wie folgt erzwingen: ORDER BY BINARY col_name.

Die Standardreihenfolge bei der Sortierung ist aufsteigend, d. h., die kleinsten Werte werden zuerst aufgeführt. Um in umgekehrter (absteigender) Reihenfolge zu sortieren, fügen Sie das Schlüsselwort DESC zum Namen der Spalte zu, nach der die Sortierung erfolgt:

mysql> SELECT name, geburtstag FROM haustier ORDER BY geburtstag DESC;
+----------+------------+
| name     | geburtstag |
+----------+------------+
| Puffball | 1999-03-30 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Claws    | 1994-03-17 |
| Fluffy   | 1993-02-04 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Buffy    | 1989-05-13 |
+----------+------------+

Sie können auch nach mehreren Spalten und diese jeweils mit eigener Reihenfolge sortieren. Um beispielsweise nach der Tierart in aufsteigender, dann dem Geburtsdatum innerhalb der Tierart in absteigender Reihenfolge (d. h. das jüngste Tier zuerst nennend) zu sortieren, verwenden Sie die folgende Abfrage:

mysql> SELECT name, gattung, geburtstag FROM haustier
    -> ORDER BY gattung, geburtstag DESC;
+----------+----------+------------+
| name     | gattung  | geburtstag |
+----------+----------+------------+
| Chirpy   | Vogel    | 1998-09-11 |
| Whistler | Vogel    | 1997-12-09 |
| Claws    | Katze    | 1994-03-17 |
| Fluffy   | Katze    | 1993-02-04 |
| Fang     | Hund     | 1990-08-27 |
| Bowser   | Hund     | 1989-08-31 |
| Buffy    | Hund     | 1989-05-13 |
| Puffball | Hamster  | 1999-03-30 |
| Slim     | Schlange | 1996-04-29 |
+----------+----------+------------+

Beachten Sie, dass das Schlüsselwort DESC nur für den Spaltennamen gilt, dem es direkt vorangestellt ist (geburtstag); die Sortierreihenfolge der Spalte gattung wird hiervon nicht berührt.

3.3.4.5. Datumsberechnungen

MySQL bietet eine Anzahl von Funktionen, mit denen Sie datumsbezogene Berechnungen durchführen können, um etwa Altersangaben zu ermitteln oder Teile aus Datumsangaben zu extrahieren.

Um zu bestimmen, wie alt Ihre Haustiere jeweils sind, berechnen Sie die Differenz im Jahresbestandteil des aktuellen und des Geburtsdatums und ziehen den Wert 1 ab, sofern das aktuelle Datum im Kalenderjahr vor dem Geburtsdatum liegt. Die folgende Abfrage zeigt für jedes Haustier das Geburtsdatum, das aktuelle Datum und das Alter in Jahren an.

mysql> SELECT name, geburtstag, CURDATE(),
    -> (YEAR(CURDATE())-YEAR(geburtstag))
    -> - (RIGHT(CURDATE(),5)<RIGHT(geburtstag,5))
    -> AS alter
    -> FROM haustier;
+----------+------------+------------+-------+
| name     | geburtstag | CURDATE()  | alter |
+----------+------------+------------+-------+
| Fluffy   | 1993-02-04 | 2003-08-19 |    10 |
| Claws    | 1994-03-17 | 2003-08-19 |     9 |
| Buffy    | 1989-05-13 | 2003-08-19 |    14 |
| Fang     | 1990-08-27 | 2003-08-19 |    12 |
| Bowser   | 1989-08-31 | 2003-08-19 |    13 |
| Chirpy   | 1998-09-11 | 2003-08-19 |     4 |
| Whistler | 1997-12-09 | 2003-08-19 |     5 |
| Slim     | 1996-04-29 | 2003-08-19 |     7 |
| Puffball | 1999-03-30 | 2003-08-19 |     4 |
+----------+------------+------------+-------+

Hierbei extrahiert YEAR() die Jahreszahl aus dem Datum, während mit RIGHT() die fünf Zeichen ganz rechts im Datum (MM-DD, also der Monat und der Tag) ermittelt werden. Der Teil des Ausdrucks, der die Werte MM-DD vergleicht, ist entweder 1 oder 0. Hiermit wird von der Jahresdifferenz ggf. ein Jahr abgezogen, sofern CURDATE() (das aktuelle Datum) im Kalenderjahr vor geburtstag liegt. Der gesamte Ausdruck wirkt ein wenig unübersichtlich, weswegen ein Alias (alter) verwendet wird, um die Beschriftung der Ausgabespalte sinnvoller zu gestalten.

Die Abfrage funktioniert zwar, aber das Ergebnis ließe sich einfacher erfassen, wenn die Datensätze in einer bestimmten Reihenfolge angezeigt würden. Dies ist durch Ergänzen der Klausel ORDER BY name möglich, die die Ausgaben dem Namen nach sortiert:

mysql> SELECT name, geburtstag, CURDATE(),
    -> (YEAR(CURDATE())-YEAR(geburtstag))
    -> - (RIGHT(CURDATE(),5)<RIGHT(geburtstag,5))
    -> AS alter
    -> FROM haustier ORDER BY name;
+----------+------------+------------+-------+
| name     | geburtstag | CURDATE()  | alter |
+----------+------------+------------+-------+
| Bowser   | 1989-08-31 | 2003-08-19 |    13 |
| Buffy    | 1989-05-13 | 2003-08-19 |    14 |
| Chirpy   | 1998-09-11 | 2003-08-19 |     4 |
| Claws    | 1994-03-17 | 2003-08-19 |     9 |
| Fang     | 1990-08-27 | 2003-08-19 |    12 |
| Fluffy   | 1993-02-04 | 2003-08-19 |    10 |
| Puffball | 1999-03-30 | 2003-08-19 |     4 |
| Slim     | 1996-04-29 | 2003-08-19 |     7 |
| Whistler | 1997-12-09 | 2003-08-19 |     5 |
+----------+------------+------------+-------+

Um die Ausgabe nach dem Alter statt dem Namen zu sortieren, verwenden Sie einfach eine andere ORDER BY-Klausel:

mysql> SELECT name, geburtstag, CURDATE(),
    -> (YEAR(CURDATE())-YEAR(geburtstag))
    -> - (RIGHT(CURDATE(),5)<RIGHT(geburtstag,5))
    -> AS alter
    -> FROM haustier ORDER BY alter;
+----------+------------+------------+-------+
| name     | geburtstag | CURDATE()  | alter |
+----------+------------+------------+-------+
| Chirpy   | 1998-09-11 | 2003-08-19 |     4 |
| Puffball | 1999-03-30 | 2003-08-19 |     4 |
| Whistler | 1997-12-09 | 2003-08-19 |     5 |
| Slim     | 1996-04-29 | 2003-08-19 |     7 |
| Claws    | 1994-03-17 | 2003-08-19 |     9 |
| Fluffy   | 1993-02-04 | 2003-08-19 |    10 |
| Fang     | 1990-08-27 | 2003-08-19 |    12 |
| Bowser   | 1989-08-31 | 2003-08-19 |    13 |
| Buffy    | 1989-05-13 | 2003-08-19 |    14 |
+----------+------------+------------+-------+

Eine ähnliche Abfrage kann verwendet werden, um das erreichte Alter bereits verstorbener Tiere zu bestimmen. Welche Tiere dies sind, ermitteln Sie durch die Überprüfung, ob für todestag der Wert NULL lautet. Bei denjenigen Datensätzen, bei denen der Wert nicht NULL ist, berechnen Sie die Differenz zwischen den Werten todestag und geburtstag:

mysql> SELECT name, geburtstag, todestag,
    -> (YEAR(todestag)-YEAR(geburtstag)) - (RIGHT(todestag,5)<RIGHT(geburtstag,5))
    -> AS alter
    -> FROM haustier WHERE todestag IS NOT NULL ORDER BY alter;
+--------+------------+------------+-------+
| name   | geburtstag | todestag   | alter |
+--------+------------+------------+-------+
| Bowser | 1989-08-31 | 1995-07-29 |     5 |
+--------+------------+------------+-------+

Die Abfrage verwendet todestag IS NOT NULL statt todestag <> NULL, da NULL ein Sonderwert ist, der nicht mithilfe der üblichen Vergleichsoperatoren verglichen werden kann. Wir werden später noch darauf eingehen. Siehe auch Abschnitt 3.3.4.6, „Mit NULL-Werten arbeiten“.

Was aber, wenn Sie nun wissen wollen, welche Tiere im nächsten Monat Geburtstag haben? Für diese Art der Berechnung sind Jahr und Tag irrelevant: Sie müssen lediglich den Monat aus der Spalte geburtstag extrahieren. MySQL bietet mehrere Funktionen zur Extraktion von Datumsbestandteilen, z. B. YEAR(), MONTH() und DAYOFMONTH(). MONTH() ist für unsere Belange die passende Funktion. Um zu sehen, wie sie funktioniert, führen Sie eine einfache Abfrage aus, die den Wert von geburtstag und MONTH(geburtstag) anzeigt:

mysql> SELECT name, geburtstag, MONTH(geburtstag) FROM haustier;
+----------+------------+-------------------+
| name     | geburtstag | MONTH(geburtstag) |
+----------+------------+-------------------+
| Fluffy   | 1993-02-04 |                 2 |
| Claws    | 1994-03-17 |                 3 |
| Buffy    | 1989-05-13 |                 5 |
| Fang     | 1990-08-27 |                 8 |
| Bowser   | 1989-08-31 |                 8 |
| Chirpy   | 1998-09-11 |                 9 |
| Whistler | 1997-12-09 |                12 |
| Slim     | 1996-04-29 |                 4 |
| Puffball | 1999-03-30 |                 3 |
+----------+------------+-------------------+

Das Suchen von Tieren, die nächsten Monat Geburtstag haben, ist ebenfalls ganz einfach. Nehmen wir einmal an, es wäre April. In diesem Fall ist der Monatswert 4 – Sie suchen also nach Tieren, die im Mai (d. h. im Monat 5) geboren sind. Das geht wie folgt:

mysql> SELECT name, geburtstag FROM haustier WHERE MONTH(geburtstag) = 5;
+-------+------------+
| name  | geburtstag |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+

Wenn der aktuelle Monat Dezember ist, gibt es eine kleine Komplikation. Sie können nämlich nicht einfach die Monatsnummer (12) um den Wert 1 erhöhen – die Suche nach im Monat 13 geborenen Tieren brächte kein Ergebnis, weil es diesen Monat nicht gibt. Schließlich suchen Sie nach Tieren, die im Januar (Monat 1) geboren sind.

Sie können die Abfrage so verfassen, dass sie unabhängig vom aktuellen Monat funktioniert, sodass Sie die Nummer eines bestimmten Monats gar nicht verwenden müssen. DATE_ADD() erlaubt Ihnen das Addieren eines bestimmten Zeitintervalls für ein gegebenes Datum. Wenn Sie einen Monat zum aktuellen Wert von CURDATE() hinzuaddieren wollen, extrahieren Sie den Monatsbestandteil mit MONTH(). Das Ergebnis ist der Monat, in dem Sie nach Geburtstagen suchen müssen:

mysql> SELECT name, geburtstag FROM haustier
    -> WHERE MONTH(geburtstag) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));

Eine andere Möglichkeit, diese Aufgabe zu lösen, besteht darin, 1 hinzuzuaddieren und dann den auf den aktuellen Monat folgenden Monat zu ermitteln, wobei mithilfe der Modulofunktion (MOD) der Monatswert auf 0 gesetzt wird, wenn er derzeit 12 beträgt:

mysql> SELECT name, geburtstag FROM haustier
    -> WHERE MONTH(geburtstag) = MOD(MONTH(CURDATE()), 12) + 1;

Beachten Sie, dass MONTH eine Zahl zwischen 1 und 12 zurückgibt. Ferner gibt MOD(something,12) eine Zahl zwischen 0 und 11 zurück. Insofern muss die Addition nach MOD() erfolgen, andernfalls würden wir von November (11) direkt zu Januar (1) springen.

3.3.4.6. Mit NULL-Werten arbeiten

Wenn Sie mit dem Wert NULL noch keine Erfahrung haben, kann Ihnen manche Überraschung bevorstehen. Vom Konzept her bezeichnet NULL einen „fehlenden unbekannten Wert“ und wird etwas anders behandelt als andere Werte. Um auf NULL zu prüfen, können Sie arithmetische Vergleichsoperatoren wie =, < oder <> nicht verwenden. Um dies zu demonstrieren, geben Sie einmal Folgendes ein:

mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
|     NULL |      NULL |     NULL |     NULL |
+----------+-----------+----------+----------+

Offensichtlich lassen sich aus diesen Vergleichen keine sinngebenden Ergebnisse ziehen. Verwenden Sie stattdessen die Operatoren IS NULL und IS NOT NULL:

mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
| 1 IS NULL | 1 IS NOT NULL |
+-----------+---------------+
|         0 |             1 |
+-----------+---------------+

Beachten Sie, dass 0 oder NULL in MySQL „falsch“ entspricht, während alles andere wahr ist. Der standardmäßig „wahr“ entsprechende Wert aus einer booleschen Operation ist 1.

Die Sonderbehandlung für NULL ist der Grund dafür, warum im vorherigen Abschnitt die Frage, welche Tiere nicht mehr leben, mit todestag IS NOT NULL statt mit todestag <> NULL ermittelt werden musste.

Zwei NULL in einer GROUP BY-Klausel werden als gleichberechtigt betrachtet.

Wenn Sie eine ORDER BY-Klausel verwenden, werden NULL-Werte zuerst angezeigt, sofern Sie ORDER BY ... ASC angeben; im umgekehrten Fall ORDER BY ... DESC erscheinen sie hingegen am Ende der Ergebnislisten.

Ein häufiger Fehler beim Umgang mit NULL besteht in der Annahme, dass es nicht möglich ist, eine Null oder einen Leer-String in eine Spalte einzufügen, die als NOT NULL definiert ist. Das stimmt nicht. Es handelt sich dabei vielmehr um echte Werte, während NULL die Bedeutung „kein Wert“ hat. Sie können dies ganz einfach wie folgt durch Verwendung von IS [NOT] NULL testen:

mysql> SELECT 0 IS NULL, 0 IS NOT NULL, '' IS NULL, '' IS NOT NULL;
+-----------+---------------+------------+----------------+
| 0 IS NULL | 0 IS NOT NULL | '' IS NULL | '' IS NOT NULL |
+-----------+---------------+------------+----------------+
|         0 |             1 |          0 |              1 |
+-----------+---------------+------------+----------------+

Es ist also durchaus möglich, eine Null oder einen Leer-String in eine NOT NULL-Spalte einzusetzen, denn diese Werte sind in der Tat NOT NULL. Siehe auch Abschnitt A.5.3, „Probleme mit NULL-Werten“.

3.3.4.7. Übereinstimmende Suchmuster

MySQL ermöglicht einen Mustervergleich sowohl nach SQL-Standard als auch basierend auf erweiterten regulären Ausdrücken, wie man es von Unix-Hilfsprogrammen wie vi, grep und sed her kennt.

Beim SQL-Mustervergleich können Sie ‘_’ für eine Übereinstimmung mit einzelnen Zeichen sowie ‘%’ für eine Übereinstimmung mit einer beliebigen Anzahl von Zeichen (einschließlich 0 Zeichen) verwenden. In MySQL wird bei SQL-Mustern standardmäßig keine Unterscheidung der Groß-/Kleinschreibung vorgenommen. Einige Beispiele sind hier aufgeführt. Achten Sie darauf, in Verbindung mit SQL-Mustern nicht = oder <> zu verwenden, sondern die Vergleichsoperatoren LIKE bzw. NOT LIKE.

Namen, die mit ‘b’ beginnen, finden Sie so:

mysql> SELECT * FROM haustier WHERE name LIKE 'b%';
+--------+----------+---------+------------+------------+------------+
| name   | besitzer | gattung | geschlecht | geburtstag | todestag   |
+--------+----------+---------+------------+------------+------------+
| Buffy  | Harold   | Hund    | w          | 1989-05-13 | NULL       |
| Bowser | Diane    | Hund    | m          | 1989-08-31 | 1995-07-29 |
+--------+----------+---------+------------+------------+------------+

Namen, die auf ‘fy’ enden, finden Sie so:

mysql> SELECT * FROM haustier WHERE name LIKE '%fy';
+--------+----------+---------+------------+------------+----------+
| name   | besitzer | gattung | geschlecht | geburtstag | todestag |
+--------+----------+---------+------------+------------+----------+
| Fluffy | Harold   | Katze   | w          | 1993-02-04 | NULL     |
| Buffy  | Harold   | Hund    | w          | 1989-05-13 | NULL     |
+--------+----------+---------+------------+------------+----------+

Und Namen, die ‘w’ enthalten, finden Sie so:

mysql> SELECT * FROM haustier WHERE name LIKE '%w%';
+----------+----------+---------+------------+------------+------------+
| name     | besitzer | gattung | geschlecht | geburtstag | todestag   |
+----------+----------+---------+------------+------------+------------+
| Claws    | Gwen     | Katze   | m          | 1994-03-17 | NULL       |
| Bowser   | Diane    | Hund    | m          | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen     | Vogel   | NULL       | 1997-12-09 | NULL       |
+----------+----------+---------+------------+------------+------------+

Um Namen zu ermitteln, die aus genau fünf Zeichen bestehen, verwenden Sie fünf Instanzen des Musterzeichens ‘_’:

mysql> SELECT * FROM haustier WHERE name LIKE '_____';
+-------+----------+---------+------------+------------+----------+
| name  | besitzer | gattung | geschlecht | geburtstag | todestag |
+-------+----------+---------+------------+------------+----------+
| Claws | Gwen     | Katze   | m          | 1994-03-17 | NULL     |
| Buffy | Harold   | Hund    | w          | 1989-05-13 | NULL     |
+-------+----------+---------+------------+------------+----------+

Der andere von MySQL unterstützte Mustervergleichstyp nutzt erweiterte reguläre Ausdrücke. Wenn Sie bei diesem Mustertyp auf Übereinstimmung testen, verwenden Sie die Operatoren REGEXP und NOT REGEXP (bzw. deren Synonyme RLIKE und NOT RLIKE).

Erweiterte reguläre Ausdrücke weisen u. a. die folgenden Merkmale auf:

  • .’ stimmt mit genau einem beliebigen Zeichen überein.

  • Eine Zeichenklasse ‘[...]’ führt zur Übereinstimmung bei jedem Zeichen in den Klammern. Beispielsweise liegt bei ‘[abc]’ eine Übereinstimmung mit ‘a’, ‘b’ oder ‘c’ vor. Um einen Zeichenbereich anzugeben, verwenden Sie einen Bindestrich. ‘[a-z]’ führt zur Übereinstimmung mit einem beliebigen Buchstaben, wohingegen ‘[0-9]’ einer Übereinstimmung mit jeder Ziffer entspricht.

  • *’ stimmt mit null oder mehr Instanzen des Elements überein, das ihm vorangeht. Beispielsweise liegt bei ‘x*’ eine Übereinstimmung mit einer beliebigen Anzahl von ‘x’-Zeichen vor. Gleiches gilt bei ‘[0-9]*’ für eine beliebige Anzahl von Ziffern und bei ‘.*’ für eine beliebige Anzahl eines beliebigen Elements.

  • Ein REGEXP-Mustervergleich ist erfolgreich, wenn eine Übereinstimmung des Musters an beliebiger Stelle im getesteten Wert vorliegt. (Hier liegt ein Unterschied zum LIKE-Mustervergleich, der nur erfolgreich ist, wenn das Muster mit dem gesamten Wert übereinstimmt.)

  • Um einen Anker im Muster zu setzen, sodass es mit dem Anfang oder Ende des getesteten Wertes übereinstimmen muss, verwenden Sie ‘^’ am Anfang bzw. ‘$’ am Ende des Musters.

Um zu demonstrieren, wie erweiterte reguläre Ausdrücke funktionieren, haben wir die oben gezeigten LIKE-Abfragen so umgeschrieben, dass sie REGEXP verwenden.

Um Namen zu finden, die mit ‘b’ beginnen, verwenden Sie ‘^’ für eine Übereinstimmung mit dem Namensanfang:

mysql> SELECT * FROM haustier WHERE name REGEXP '^b';
+--------+----------+---------+------------+------------+------------+
| name   | besitzer | gattung | geschlecht | geburtstag | todestag   |
+--------+----------+---------+------------+------------+------------+
| Buffy  | Harold   | Hund    | w          | 1989-05-13 | NULL       |
| Bowser | Diane    | Hund    | m          | 1989-08-31 | 1995-07-29 |
+--------+----------+---------+------------+------------+------------+

Wenn Sie einen REGEXP-Vergleich mit Unterscheidung der Groß-/Kleinschreibung wirklich erzwingen wollen, verwenden Sie das Schlüsselwort BINARY, um aus einem der Strings einen Binär-String zu machen. Bei folgender Abfrage liegt eine Übereinstimmung nur bei einem kleinen ‘b’ am Anfang des Namens vor:

mysql> SELECT * FROM haustier WHERE name REGEXP BINARY '^b';

Um Namen zu finden, die auf ‘fy’ enden, verwenden Sie ‘$’ für eine Übereinstimmung mit dem Namensende:

mysql> SELECT * FROM haustier WHERE name REGEXP 'fy$';
+--------+----------+---------+------------+------------+----------+
| name   | besitzer | gattung | geschlecht | geburtstag | todestag |
+--------+----------+---------+------------+------------+----------+
| Fluffy | Harold   | Katze   | w          | 1993-02-04 | NULL     |
| Buffy  | Harold   | Hund    | w          | 1989-05-13 | NULL     |
+--------+----------+---------+------------+------------+----------+

Namen schließlich, die ‘w’ enthalten, finden Sie mit folgender Abfrage:

mysql> SELECT * FROM haustier WHERE name REGEXP 'w';
+----------+----------+---------+------------+------------+------------+
| name     | besitzer | gattung | geschlecht | geburtstag | todestag   |
+----------+----------+---------+------------+------------+------------+
| Claws    | Gwen     | Katze   | m          | 1994-03-17 | NULL       |
| Bowser   | Diane    | Hund    | m          | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen     | Vogel   | NULL       | 1997-12-09 | NULL       |
+----------+----------+---------+------------+------------+------------+

Da ein auf einem regulären Ausdruck basierendes Muster eine Übereinstimmung liefert, wenn es an beliebiger Stelle im Wert auftaucht, ist es in dieser Abfrage nicht notwendig, ein Jokerzeichen an den beiden Seiten des Musters zu setzen (bei einem SQL-Muster wäre dies hingegen erforderlich, um eine Übereinstimmung zu erzielen).

Um Namen zu ermitteln, die aus genau fünf Zeichen bestehen, verwenden Sie ‘^’ und ‘$’ für Übereinstimmungen für Anfang und Ende des Namens und fünf Instanzen von ‘.’ dazwischen:

mysql> SELECT * FROM haustier WHERE name REGEXP '^.....$';
+-------+----------+---------+------------+------------+----------+
| name  | besitzer | gattung | geschlecht | geburtstag | todestag |
+-------+----------+---------+------------+------------+----------+
| Claws | Gwen     | Katze   | m          | 1994-03-17 | NULL     |
| Buffy | Harold   | Hund    | w          | 1989-05-13 | NULL     |
+-------+----------+---------+------------+------------+----------+

Sie könnten diese Abfrage auch mithilfe des Operators {n} („n-mal wiederholen“) schreiben:

mysql> SELECT * FROM haustier WHERE name REGEXP '^.{5}$';
+-------+----------+---------+------------+------------+----------+
| name  | besitzer | gattung | geschlecht | geburtstag | todestag |
+-------+----------+---------+------------+------------+----------+
| Claws | Gwen     | Katze   | m          | 1994-03-17 | NULL     |
| Buffy | Harold   | Hund    | w          | 1989-05-13 | NULL     |
+-------+----------+---------+------------+------------+----------+

In Anhang G, Beschreibung der MySQL-Syntax für reguläre Ausdrücke, finden Sie weitere Informationen zur Syntax regulärer Ausdrücke.

3.3.4.8. Zeilen zählen

Datenbanken werden häufig zur Beantwortung der Frage „Wie häufig taucht ein bestimmter Datentyp in einer Tabelle auf?“ verwendet. So möchten Sie vielleicht wissen, wie viele Tiere Sie oder ein anderer Besitzer haben, oder verschiedene statistische Erhebungen zu Ihren Tieren machen.

Das Zählen aller vorhandenen Tiere entspricht der Frage „Wie viele Datensätze sind in der Tabelle haustier vorhanden?“, denn es gibt genau einen Datensatz pro Tier. COUNT(*) zählt die Anzahl der Datensätze, d. h., die Abfrage zur Zählung Ihrer Tiere sieht wie folgt aus:

mysql> SELECT COUNT(*) FROM haustier;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

Weiter oben haben Sie die Namen der Leute abgerufen, die Tiere besitzen. Mit COUNT() können Sie etwa ermitteln, wie viele Tiere jeder Besitzer hat:

mysql> SELECT besitzer, COUNT(*) FROM haustier GROUP BY besitzer;
+----------+----------+
| besitzer | COUNT(*) |
+----------+----------+
| Benny    |        2 |
| Diane    |        2 |
| Gwen     |        3 |
| Harold   |        2 |
+----------+----------+

Beachten Sie, dass GROUP BY zur Gruppierung aller Datensätze für jeden Besitzer besitzer verwendet wird. Ohne diese Klausel erhalten Sie lediglich eine Fehlermeldung:

mysql> SELECT besitzer, COUNT(*) FROM haustier;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) 
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT() und GROUP BY sind praktisch, wenn Sie Ihre Daten auf verschiedene Arten charakterisieren wollen. Die folgenden Beispiele zeigen verschiedene Wege, statistische Daten zu den Tieren zu erheben.

Anzahl der Exemplare je Tierart:

mysql> SELECT gattung, COUNT(*) FROM haustier GROUP BY gattung;
+----------+----------+
| gattung  | COUNT(*) |
+----------+----------+
| Vogel    |        2 |
| Katze    |        2 |
| Hund     |        3 |
| Hamster  |        1 |
| Schlange |        1 |
+----------+----------+

Anzahl der Tiere je Geschlecht:

mysql> SELECT geschlecht, COUNT(*) FROM haustier GROUP BY geschlecht;
+------------+----------+
| geschlecht | COUNT(*) |
+------------+----------+
| NULL       |        1 |
| w          |        4 |
| m          |        4 |
+------------+----------+

(In dieser Ausgabe gibt NULL an, dass das Geschlecht unbekannt ist.)

Anzahl der Tiere je Kombination von Tierart und Geschlecht:

mysql> SELECT gattung, geschlecht, COUNT(*) FROM haustier GROUP BY gattung, geschlecht;
+----------+------------+----------+
| gattung  | geschlecht | COUNT(*) |
+----------+------------+----------+
| Vogel    | NULL       |        1 |
| Vogel    | w          |        1 |
| Katze    | w          |        1 |
| Katze    | m          |        1 |
| Hund     | w          |        1 |
| Hund     | m          |        2 |
| Hamster  | w          |        1 |
| Schlange | m          |        1 |
+----------+------------+----------+

Wenn Sie COUNT() verwenden, müssen Sie nicht die gesamte Tabelle abrufen. Die obige Abfrage beispielsweise sieht wie folgt aus, wenn Sie nur für Hunde und Katzen durchgeführt wird:

mysql> SELECT gattung, geschlecht, COUNT(*) FROM haustier
    -> WHERE gattung = 'Hund' OR gattung = 'Katze'
    -> GROUP BY gattung, geschlecht;
+---------+------------+----------+
| gattung | geschlecht | COUNT(*) |
+---------+------------+----------+
| Katze   | w          |        1 |
| Katze   | m          |        1 |
| Hund    | w          |        1 |
| Hund    | m          |        2 |
+---------+------------+----------+

Oder, wenn Sie die Anzahl der Tiere je Geschlecht nur für diejenigen Tiere anzeigen wollen, deren Geschlecht auch bekannt ist:

mysql> SELECT gattung, geschlecht, COUNT(*) FROM haustier
    -> WHERE geschlecht IS NOT NULL
    -> GROUP BY gattung, geschlecht;
+----------+------------+----------+
| gattung  | geschlecht | COUNT(*) |
+----------+------------+----------+
| Vogel    | w          |        1 |
| Katze    | w          |        1 |
| Katze    | m          |        1 |
| Hund     | w          |        1 |
| Hund     | m          |        2 |
| Hamster  | w          |        1 |
| Schlange | m          |        1 |
+----------+------------+----------+

3.3.4.9. Mehr als eine Tabelle benutzen

Die Tabelle haustier enthält Daten zu den Tieren, die Sie besitzen. Wollen Sie andere Informationen zu diesen aufzeichnen – z. B. Ereignisse wie Tierarztbesuche oder die Ankunft von Nachwuchs –, dann benötigen Sie eine zweite Tabelle. Wie sollte diese Tabelle aussehen? Folgende Angaben müssen enthalten sein:

  • Der Name des Tieres, damit Sie wissen, welches Ereignis zu welchem Tier gehört.

  • Das Ereignisdatum.

  • Ein Feld, welches das Ereignis beschreibt.

  • Ein Ereignistypfeld, das Sie zum Kategorisieren der Ereignisse benötigen.

Unter Berücksichtigung dieser Aspekte könnte die CREATE TABLE-Anweisung für die Tabelle ereignis wie folgt aussehen:

mysql> CREATE TABLE ereignis (name VARCHAR(20), datum DATE,
    -> typ VARCHAR(15), bemerkung VARCHAR(255));

Wie bei der Tabelle haustier ist es auch hier am einfachsten, die bereits bekannten Daten über eine tabulatorgetrennte Textdatei in die Tabelle einzuladen. Diese Datei soll die folgenden Informationen enthalten:

namedatumtypbemerkung
Fluffy1995-05-15Nachwuchs4 Kätzchen, 3 weiblich, 1 männlich
Buffy1993-06-23Nachwuchs5 Welpen, 2 weiblich, 3 männlich
Buffy1994-06-19Nachwuchs3 Welpen, 3 weiblich
Chirpy1999-03-21TierarztSchnabel begradigt
Slim1997-08-03Tierarztgebrochene Rippe
Bowser1991-10-12Hundepension 
Fang1991-10-12Hundepension 
Fang1998-08-28Geburtstagneues Kauspielzeug
Claws1998-03-17Geburtstagneues Flohhalsband
Whistler1998-12-09Geburtstagerster Geburtstag

Laden Sie die Datensätze wie folgt:

mysql> LOAD DATA LOCAL INFILE 'ereignis.txt' INTO TABLE ereignis;

Mit dem, was Sie bereits aus den Abfragen erlernt haben, die Sie zur Tabelle haustier abgesetzt haben, sollten Sie auch Daten aus der Tabelle ereignis abrufen können; die Prinzipien sind dieselben. Was aber, wenn Sie die Fragen, die Sie stellen, mit der Tabelle ereignis allein nicht beantworten können?

Nehmen wir an, Sie wollen herausfinden, in welchem Alter die jeweiligen Tiere Nachwuchs bekommen haben. Wir haben bereits weiter oben gesehen, wie Sie das Alter auf der Grundlage zweiter Datumsangaben berechnen. Das Datum, an dem die Mutter ihren Nachwuchs auf die Welt gebracht hat, ist in der Tabelle ereignis gespeichert, aber um das Alter der Mutter am Tag der Niederkunft zu ermitteln, benötigen Sie das Geburtsdatum, welches wiederum in der Tabelle haustier abgelegt ist. Das bedeutet, dass wir zwei Tabellen benötigen:

mysql> SELECT haustier.name,
    -> (YEAR(datum)-YEAR(geburtstag)) - (RIGHT(datum,5)<RIGHT(geburtstag,5)) AS alter,
    -> bemerkung
    -> FROM haustier, ereignis
    -> WHERE haustier.name = ereignis.name AND ereignis.typ = 'Nachwuchs';
+--------+-------+-------------------------------------+
| name   | alter | bemerkung                           |
+--------+-------+-------------------------------------+
| Fluffy |     2 | 4 Kätzchen, 3 weiblich, 1 männlich  |
| Buffy  |     4 | 5 Welpen, 2 weiblich, 3 männlich    |
| Buffy  |     5 | 3 Welpen, 3 weiblich                |
+--------+-------+-------------------------------------+

Bei dieser Abfrage fällt Verschiedenes auf:

  • Die FROM-Klausel listet zwei Tabellen auf, da die Abfrage Informationen aus beiden Tabellen abrufen muss.

  • Wenn Sie Daten aus mehreren Tabellen kombinieren (verknüpfen), dann müssen Sie angeben, wie die Datensätze der einen Tabelle denen der anderen Tabelle zugeordnet werden können. Dies ist recht einfach, da beide Tabellen eine Spalte name haben. Die Abfrage verwendet eine WHERE-Klausel zur Zuordnung von Datensätzen der beiden Tabellen basierend auf den Werten in der Spalte name.

  • Da die Spalte name in beiden Tabellen auftritt, müssen Sie bei Bezugnahme auf diese Spalte angeben, welche der beiden Tabellen Sie meinen. Dies erfolgt durch Voranstellung des Tabellennamens vor den Spaltennamen.

Um eine solche Verknüpfung – einen Join – durchzuführen, brauchen Sie keine zwei Tabellen. Manchmal ist es nützlich, eine Tabelle mit sich selbst zu verknüpfen, wenn man etwa Datensätze in einer Tabelle mit anderen Datensätzen in derselben Tabelle vergleichen will. Um beispielsweise Zuchtmöglichkeiten unter Ihren Tieren auszuloten, kann eine Verknüpfung der Tabelle haustier mit sich selbst praktisch sein, um passende Männchen und Weibchen einer Tierart zu ermitteln:

mysql> SELECT p1.name, p1.geschlecht, p2.name, p2.geschlecht, p1.gattung
    -> FROM haustier AS p1, haustier AS p2
    -> WHERE p1.gattung = p2.gattung AND p1.geschlecht = 'w' AND p2.geschlecht = 'm';
+--------+------------+--------+------------+---------+
| name   | geschlecht | name   | geschlecht | gattung |
+--------+------------+--------+------------+---------+
| Fluffy | w          | Claws  | m          | Katze   |
| Buffy  | w          | Fang   | m          | Hund    |
| Buffy  | w          | Bowser | m          | Hund    |
+--------+------------+--------+------------+---------+

In dieser Abfrage geben Sie Aliase für den Tabellennamen an, um auf die Spalten Bezug zu nehmen und klar zu machen, welcher Tabelleninstanz die Bezugnahme auf eine Spalte zuzuordnen ist.

3.4. Informationen über Datenbanken und Tabellen

Was können Sie tun, wenn Sie den Namen einer Datenbank oder Tabelle vergessen haben oder nicht mehr wissen, wie die Struktur einer gegebenen Tabelle aussieht (d. h., wie beispielsweise die Spalten heißen)? MySQL bietet zur Lösung dieses Problems eine Reihe von Anweisungen an, die Informationen zu unterstützten Datenbanken und Tabellen vermitteln.

Die Anweisung SHOW DATABASES, die die vom Server verwalteten Datenbanken auflistet, haben Sie bereits gesehen. Um herauszufinden, welche Datenbank gerade gewählt ist, verwenden Sie die Funktion DATABASE():

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie  |
+------------+

Haben Sie noch keine Datenbank ausgewählt, dann lautet das Ergebnis NULL.

Um herauszufinden, welche Tabellen die Standarddatenbank enthält (wenn Sie etwa den Namen einer Tabelle nicht mehr genau wissen), verwenden Sie diesen Befehl:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| ereignis            |
| haustier            |
+---------------------+

Wollen Sie die Struktur einer Tabelle ermitteln, dann ist der Befehl DESCRIBE praktisch, denn er zeigt Informationen zu allen Spalten einer Tabelle an:

mysql> DESCRIBE haustier;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| name       | varchar(20) | YES  |     | NULL    |       |
| besitzer   | varchar(20) | YES  |     | NULL    |       |
| gattung    | varchar(20) | YES  |     | NULL    |       |
| geschlecht | char(1)     | YES  |     | NULL    |       |
| geburtstag | date        | YES  |     | NULL    |       |
| todestag   | date        | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+

Field ist dabei der Spaltenname, Type der Datentyp der Spalte, NULL zeigt an, ob die Spalte NULL-Werte enthalten kann, Key, ob die Spalte indiziert ist, und Default bezeichnet den Standardwert der Spalte.

Wenn Sie Indizes in einer Tabelle verwenden, generiert SHOW INDEX FROM tbl_name Informationen zu diesen.

3.5. mysql im Stapelbetrieb

In obigen Abschnitten haben Sie mysql interaktiv zur Eingabe von Abfragen und zur Anzeige der Ergebnisse verwendet. Sie können mysql aber auch im Stapelbetrieb (Batch-Modus) ausführen. Zu diesem Zweck legen Sie die gewünschten Befehle in einer Datei ab und weisen mysql dann an, diese Datei auszulesen und die Befehle zu verarbeiten:

shell> mysql < batch-file

Wenn Sie mysql unter Windows ausführen und gewisse Sonderzeichen in der Datei Probleme verursachen, dann können Sie Folgendes tun:

C:\> mysql -e "source batch-file"

Müssen Sie die Verbindungsparameter auf der Befehlszeile angeben, dann könnte der Befehl so aussehen:

shell> mysql -h host -u user -p < batch-file
Enter password: ********

Wenn Sie mysql auf diese Weise verwenden, erstellen Sie eine Skriptdatei und führen das Skript dann aus.

Soll das Skript auch dann vollständig abgearbeitet werden, wenn enthaltene Anweisungen Fehler erzeugen, dann sollten Sie die Befehlszeilenoption --force verwenden.

Warum sollte man Skripten verwenden? Dafür gibt es ein paar gute Gründe:

  • Führen Sie eine Abfrage häufiger aus (beispielsweise einmal in der Woche), dann können Sie ein Skript erstellen und sich so die Tipparbeit sparen, die bei jeder Neueingabe der Abfrage anfallen würde.

  • Sie können neue Abfragen aus bereits vorhandenen ähnlichen erstellen, indem Sie Skriptdateien kopieren und bearbeiten.

  • Der Stapelbetrieb kann auch nützlich sein, wenn Sie eine Abfrage entwickeln; dies gilt insbesondere für mehrzeilige Befehle oder aus mehreren Anweisungen bestehende Befehlsabfolgen. Wenn Sie einen Fehler machen, brauchen Sie nicht alles neu einzugeben. Beheben Sie den Fehler einfach in Ihrem Skript und weisen Sie mysql dann an, es erneut auszuführen.

  • Wenn Ihre Abfrage eine umfangreiche Ausgabe erzeugt, dann können Sie diese seitenweise anzeigen lassen, statt sie am oberen Bildschirmrand verschwinden zu sehen:

    shell> mysql < batch-file | more
    
  • Zur weiteren Verarbeitung können Sie die Ausgabe auch in eine Datei leiten:

    shell> mysql < batch-file > mysql.out
    
  • Sie können Ihr Skript auch an andere Benutzer weitergeben, damit diese ebenfalls die entsprechenden Befehle ausführen können.

  • Manche Situationen erlauben keine interaktive Vorgehensweise. Dies ist etwa der Fall, wenn eine Abfrage aus einem cron-Job heraus erfolgt. In diesem Fall müssen Sie den Stapelbetrieb verwenden.

Wenn Sie mysql im Stapelbetrieb verwenden, ist das Standardausgabeformat anders (genauer gesagt, knapper) als im interaktiven Modus. Die Ausgabe von SELECT DISTINCT gattung FROM haustier etwa sieht wie folgt aus, wenn mysql interaktiv läuft:

+----------+
| gattung  |
+----------+
| Vogel    |
| Katze    |
| Hund     |
| Hamster  |
| Schlange |
+----------+

Im Stapelbetrieb hingegen sieht die Ausgabe so aus:

gattung
Vogel
Katze
Hund
Hamster
Schlange

Wenn Sie das interaktive Ausgabeformat auch im Stapelbetrieb wünschen, verwenden Sie zum Aufruf mysql -t. Damit die Ausgabe der ausgeführten Befehle angezeigt wird, verwenden Sie mysql -vvv.

Sie können auch Skripten an der mysql-Eingabeaufforderung verwenden. Hierzu dient der Befehl source bzw. \.:

mysql> source filename;
mysql> \. filename

3.6. Beispiele gebräuchlicher Abfragen

Es folgen einige Beispiele dafür, wie man häufige Probleme mit MySQL löst.

Einige dieser Beispiele verwenden die Tabelle shop, in der die Preise jedes Artikels (bzw. Artikelnummer) für bestimmte Händler aufgeführt sind. Wenn man davon ausgeht, dass jeder Händler genau einen bestimmten Festpreis für einen Artikel hat, dann ist (artikel, haendler) ein Primärschlüssel für die Datensätze.

Starten Sie das Befehlszeilen-Tool mysql und wählen Sie eine Datenbank aus:

shell> mysql your-database-name

(Bei den meisten MySQL-Installationen können Sie die Datenbank test verwenden.)

Erstellung der Beispieltabelle und Ausfüllen mit Daten erfolgen mit den folgenden Anweisungen:

mysql> CREATE TABLE shop (
    -> artikel INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
    -> haendler  CHAR(20)                 DEFAULT ''     NOT NULL,
    -> preis   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL,
    -> PRIMARY KEY(artikel, haendler));
mysql> INSERT INTO shop VALUES
    -> (1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),
    -> (3,'C',1.69),(3,'D',1.25),(4,'D',19.95);

Nachdem Sie die Anweisungen abgesetzt haben, weist die Tabelle den folgenden Inhalt auf:

mysql> SELECT * FROM shop;
+---------+----------+-------+
| artikel | haendler | preis |
+---------+----------+-------+
|    0001 | A        |  3.45 |
|    0001 | B        |  3.99 |
|    0002 | A        | 10.99 |
|    0003 | B        |  1.45 |
|    0003 | C        |  1.69 |
|    0003 | D        |  1.25 |
|    0004 | D        | 19.95 |
+---------+----------+-------+

3.6.1. Der höchste Wert einer Spalte

Welches ist die höchste Artikelnummer?

SELECT MAX(artikel) AS artikel FROM shop;

+---------+
| artikel |
+---------+
|       4 |
+---------+

3.6.2. Die Zeile, die den höchsten Wert einer bestimmten Spalte enthält

Aufgabe: Ermitteln Sie Nummer, Händler und Preis des teuersten Artikels.

Dies lässt sich recht einfach mit einer Unterabfrage bewerkstelligen:

SELECT artikel, haendler, preis
FROM   shop
WHERE  preis=(SELECT MAX(preis) FROM shop);

Eine andere Lösung besteht darin, alle Datensätze nach Preis aufsteigend zu sortieren und nur den ersten Datensatz mithilfe der MySQL-spezifischen LIMIT-Klausel abzurufen:

SELECT artikel, haendler, preis
FROM shop
ORDER BY preis DESC
LIMIT 1;

Hinweis: Wenn mehrere teuerste Artikel zum gleichen Preis vorhanden sind, dann zeigt die LIMIT-Lösung nur einen davon an.

3.6.3. Höchster Wert einer Spalte pro Gruppe

Aufgabe: Ermitteln Sie den höchsten Preis je Artikel.

SELECT artikel, MAX(preis) AS preis
FROM   shop
GROUP BY artikel

+---------+-------+
| artikel | preis |
+---------+-------+
|    0001 |  3.99 |
|    0002 | 10.99 |
|    0003 |  1.69 |
|    0004 | 19.95 |
+---------+-------+

3.6.4. Die Zeilen, die das gruppenweise Maximum eines bestimmten Felds enthalten

Aufgabe: Ermitteln Sie für jeden Artikel den oder die Händler mit dem höchsten Preis.

Dieses Problem lässt sich mit einer Unterabfrage wie der folgenden lösen:

SELECT artikel, haendler, preis
FROM   shop s1
WHERE  preis=(SELECT MAX(s2.preis)
              FROM shop s2
              WHERE s1.artikel = s2.artikel);

3.6.5. Wie Benutzervariablen verwendet werden

Sie können MySQL-Benutzervariablen verwenden, um die Ergebnisse zu vermerken, ohne sie in Temporärvariablen auf dem Client speichern zu müssen. (Siehe auch Abschnitt 9.3, „Benutzerdefinierte Variablen“.)

Um beispielsweise die Artikel mit dem höchsten und dem niedrigsten Preis zu ermitteln, können Sie Folgendes tun:

mysql> SELECT @min_preis:=MIN(preis),@max_preis:=MAX(preis) FROM shop;
mysql> SELECT * FROM shop WHERE preis=@min_preis OR preis=@max_preis;
+---------+----------+-------+
| artikel | haendler | preis |
+---------+----------+-------+
|    0003 | D        |  1.25 |
|    0004 | D        | 19.95 |
+---------+----------+-------+

3.6.6. Wie Fremdschlüssel verwendet werden

Bei MySQL unterstützen InnoDB-Tabellen die Überprüfung von Fremdschlüsselbeschränkungen. Siehe auch Abschnitt 14.2, „InnoDB-Tabellen“, und Abschnitt 1.9.5.5, „Fremdschlüssel“.

Eine Fremdschlüsselbeschränkung ist nicht erforderlich, wenn Sie lediglich zwei Tabellen miteinander verknüpfen wollen. Bei anderen Speicher-Engines als InnoDB ist dies möglich, indem eine Spalte zur Verwendung einer REFERENCES tbl_name(col_name)-Klausel definiert wird; diese hat keine eigentliche Wirkung und dient Ihnen lediglich als Erinnerung oder Anmerkung, damit Sie daran denken, dass die derzeit definierte Spalte auf eine Spalte in einer anderen Tabelle verweisen soll. Es ist bei Verwendung dieser Syntax extrem wichtig, sich zu vergegenwärtigen, dass

  • MySQL keinerlei Überprüfung durchführt, um sicherzustellen, dass col_name tatsächlich in tbl_name vorhanden ist (bzw. dass tbl_name selbst existiert),

  • MySQL keine Aktionen an tbl_name – wie etwa das Löschen von Datensätzen – als Reaktion auf Aktionen ausführt, die an Datensätzen in der von Ihnen gerade definierten Tabelle vorgenommen werden (mit anderen Worten, diese Syntax enthält keine Funktionalität wie etwa ON DELETE oder ON UPDATE; Sie können zwar eine ON DELETE- oder ON UPDATE-Klausel als Bestandteil der REFERENCES-Klausel schreiben, aber diese wird ebenfalls ignoriert),

  • diese Syntax eine Spalte erstellt (und keinerlei Index oder Schlüssel),

  • diese Syntax einen Fehler erzeugt, wenn damit eine InnoDB-Tabelle zu erzeugen versucht wird.

Sie können eine Spalte, die als Join-Spalte erstellt wurde, wie nachfolgend gezeigt verwenden:

CREATE TABLE person (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR(60) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE shirt (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
    color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
    owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
    PRIMARY KEY (id)
);

INSERT INTO person VALUES (NULL, 'Antonio Paz');

SELECT @last := LAST_INSERT_ID();

INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', @last),
(NULL, 'dress', 'white', @last),
(NULL, 't-shirt', 'blue', @last);

INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');

SELECT @last := LAST_INSERT_ID();

INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', @last),
(NULL, 'polo', 'red', @last),
(NULL, 'dress', 'blue', @last),
(NULL, 't-shirt', 'white', @last);

SELECT * FROM person;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | Antonio Paz         |
|  2 | Lilliana Angelovska |
+----+---------------------+

SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style   | color  | owner |
+----+---------+--------+-------+
|  1 | polo    | blue   |     1 |
|  2 | dress   | white  |     1 |
|  3 | t-shirt | blue   |     1 |
|  4 | dress   | orange |     2 |
|  5 | polo    | red    |     2 |
|  6 | dress   | blue   |     2 |
|  7 | t-shirt | white  |     2 |
+----+---------+--------+-------+


SELECT s.* FROM person p, shirt s
 WHERE p.name LIKE 'Lilliana%'
   AND s.owner = p.id
   AND s.color <> 'white';

+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
|  4 | dress | orange |     2 |
|  5 | polo  | red    |     2 |
|  6 | dress | blue   |     2 |
+----+-------+--------+-------+

Wenn sie auf diese Weise eingesetzt wird, wird die REFERENCES-Klausel in der Ausgabe von SHOW CREATE TABLE oder DESCRIBE nicht angezeigt:

SHOW CREATE TABLE shirt\G
*************************** 1. row ***************************
Table: shirt
Create Table: CREATE TABLE `shirt` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`style` enum('t-shirt','polo','dress') NOT NULL,
`color` enum('red','blue','orange','white','black') NOT NULL,
`owner` smallint(5) unsigned NOT NULL,
PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Die Verwendung von REFERENCES als derartigen Kommentar oder „Erinnerung“ in einer Spaltendefinition funktioniert sowohl mit MyISAM- als auch mit BerkeleyDB-Tabellen.

3.6.7. Über zwei Schlüssel suchen

Eine Suche mit OR über einen Schlüssel ist in MySQL ebenso optimal gelöst wie die Verwendung von AND.

Der einzige etwas heikle Fall ist die Suche über zwei verschiedene Schlüssel, die durch OR kombiniert sind:

SELECT field1_index, field2_index FROM test_table
WHERE field1_index = '1' OR  field2_index = '1'

Dieser Fall ist optimiert. Siehe auch Abschnitt 7.2.6, „Optimierung durch Indexverschmelzung“.

Sie können das Problem auch effizient mithilfe einer Union lösen, die die Ausgabe zweier getrennter SELECT-Anweisungen zusammenfasst. Siehe auch Abschnitt 13.2.7.2, „UNION.

Jede SELECT-Anweisung sucht nur über einen Schlüssel und kann optimiert werden:

SELECT field1_index, field2_index
    FROM test_table WHERE field1_index = '1'
UNION
SELECT field1_index, field2_index
    FROM test_table WHERE field2_index = '1';

3.6.8. Besuche pro Tag berechnen

Das folgende Beispiel zeigt, wie Sie die Bitgruppenfunktionen zur Berechnung der Anzahl von Tagen im Monat verwenden können, an denen ein Benutzer eine bestimmte Webseite besucht hat.

CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
             day INT(2) UNSIGNED ZEROFILL);
INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),
            (2000,2,23),(2000,2,23);

Die Beispieltabelle enthält Jahr/Monat/Tag-Werte, die die Besuche von Benutzern auf der Seite repräsentieren. Um zu ermitteln, an wie vielen verschiedenen Tagen in den einzelnen Monaten diese Besuche stattfanden, verwenden Sie folgende Abfrage:

SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1
       GROUP BY year,month;

Das Ergebnis sieht wie folgt aus:

+------+-------+------+
| year | month | days |
+------+-------+------+
| 2000 |    01 |    3 |
| 2000 |    02 |    2 |
+------+-------+------+

Die Abfrage berechnet, wie viele verschiedene Tage in der Tabelle für jede Jahr/Monat/Tag-Kombination erscheinen, und entfernt doppelte Einträge dabei automatisch.

3.6.9. Verwendung von AUTO_INCREMENT

Das Attribut AUTO_INCREMENT kann zur Erzeugung einer eindeutigen Kennung für neue Datensätze verwendet werden:

CREATE TABLE animals (
     id MEDIUMINT NOT NULL AUTO_INCREMENT,
     name CHAR(30) NOT NULL,
     PRIMARY KEY (id)
 );

INSERT INTO animals (name) VALUES 
    ('dog'),('cat'),('penguin'),
    ('lax'),('whale'),('ostrich');

SELECT * FROM animals;

Das Ergebnis sieht wie folgt aus:

+----+---------+
| id | name    |
+----+---------+
|  1 | dog     |
|  2 | cat     |
|  3 | penguin |
|  4 | lax     |
|  5 | whale   |
|  6 | ostrich |
+----+---------+

Sie können den aktuellen AUTO_INCREMENT-Wert mit der SQL-Funktion LAST_INSERT_ID() oder der C-API-Funktion mysql_insert_id() abrufen. Diese Funktionen sind verbindungsspezifisch, d. h., ihre Rückgabewerte werden nicht durch eine andere Verbindung beeinträchtigt, die ebenfalls Einfügeoperationen durchführt.

Hinweis: Bei mehrzeiligen Einfügeoperationen geben LAST_INSERT_ID() und mysql_insert_id() den AUTO_INCREMENT-Schlüssel des ersten eingefügten Datensatzes zurück. Auf diese Weise lassen sich mehrzeilige Einfügeoperationen auch von anderen Servern in einer Replikationskonfiguration korrekt nachvollziehen.

Bei MyISAM- und BDB-Tabellen können Sie AUTO_INCREMENT in einer Sekundärspalte eines mehrspaltigen Indexes angeben. In diesem Fall wird der erzeugte Wert der AUTO_INCREMENT-Spalte als MAX(auto_increment_column) + 1 WHERE prefix=given-prefix berechnet. Dies ist praktisch, wenn Sie Daten in sortierte Gruppen eingeben wollen.

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL,
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    name CHAR(30) NOT NULL,
    PRIMARY KEY (grp,id)
);

INSERT INTO animals (grp,name) VALUES 
    ('mammal','dog'),('mammal','cat'),
    ('Vogel','penguin'),('fish','lax'),('mammal','whale'),
    ('Vogel','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Das Ergebnis sieht wie folgt aus:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

Beachten Sie, dass in diesem Fall (wenn die AUTO_INCREMENT-Spalte Teil eines mehrspaltigen Index ist) AUTO_INCREMENT-Werte neu verwendet werden, wenn Sie den Datensatz mit dem höchsten AUTO_INCREMENT-Wert in einer beliebigen Gruppe löschen. Dies gilt auch für MyISAM-Tabellen, bei denen AUTO_INCREMENT-Werte normalerweise nicht wiederverwendet werden.

Wenn die AUTO_INCREMENT-Spalte Bestandteil mehrerer Indizes ist, erzeugt MySQL Folgewerte auf der Basis des Indexes, der mit der AUTO_INCREMENT-Spalte beginnt (sofern er vorhanden ist). Wenn also die Tabelle animals die Indizes PRIMARY KEY (grp, id) und INDEX (id) enthielte, würde MySQL den Index PRIMARY KEY bei der Erstellung von Folgewerten ignorieren. Das Ergebnis wäre eine Tabelle, die eine einzelne Folge (und nicht eine Folge pro grp-Wert) enthalten würde.

Wenn Sie bei einem anderen AUTO_INCREMENT-Wert als 1 beginnen wollen, können Sie diesen Wert mit CREATE TABLE oder ALTER TABLE wie folgt festlegen:

mysql> ALTER TABLE tbl AUTO_INCREMENT = 100;

Weitere Informationen zu AUTO_INCREMENT finden Sie hier:

3.7. Anfragen aus dem Zwillingsprojekt

Bei Analytikerna und Lentus haben wir die System- und Feldarbeiten für ein umfangreiches Forschungsprojekt durchgeführt. Dieses Projekt ist eine Zusammenarbeit zwischen dem Institut für Umweltmedizin am Karolinska Institutet in Stockholm und der Abteilung für klinische Forschung bei Altersprozessen und Psychologie an der University of Southern California.

Das Projekt umfasste u. a. ein Screening, bei dem alle in Schweden lebenden Zwillinge, die über 65 Jahre alt waren, telefonisch befragt wurden. Zwillinge, die bestimmte Kriterien erfüllten, wurden dann in eine zweite Untersuchungsphase überführt. In dieser zweiten Phase konnten sich die teilnehmenden Zwillinge auf freiwilliger Basis einer ärztlichen Untersuchung unterziehen. Zu dieser Untersuchung gehörten körperliche und neuropsychologische Tests, Labortests, Neuro-Imaging, eine Bewertung des psychologischen Zustandes und eine Erfassung der Familiengeschichte. Ferner wurden Daten zu medizinischen und umweltbedingten Risikofaktoren ermittelt.

Weitere Informationen zum Zwillingsprojekt finden Sie unter folgender Adresse: http://www.mep.ki.se/twinreg/index_en.html

Im Verlauf des Projekts kam zu Verwaltungszwecken eine Weboberfläche zum Einsatz, die in Perl und MySQL geschrieben war.

Am Ende jedes Tages wurden die Daten der Befragungen in eine MySQL-Datenbank eingetragen.

3.7.1. Alle nicht verteilten Zwillinge finden

Mit der folgenden Abfrage wurde ermittelt, wer für die zweite Phase des Projekts geeignet war:

SELECT
    CONCAT(p1.id, p1.tvab) + 0 AS tvid,
    CONCAT(p1.christian_name, ' ', p1.surname) AS Name,
    p1.postal_code AS Code,
    p1.city AS City,
    pg.abrev AS Area,
    IF(td.participation = 'Aborted', 'A', ' ') AS A,
    p1.dead AS dead1,
    l.ereignis AS event1,
    td.suspect AS tsuspect1,
    id.suspect AS isuspect1,
    td.severe AS tsevere1,
    id.severe AS isevere1,
    p2.dead AS dead2,
    l2.ereignis AS event2,
    h2.nurse AS nurse2,
    h2.doctor AS doctor2,
    td2.suspect AS tsuspect2,
    id2.suspect AS isuspect2,
    td2.severe AS tsevere2,
    id2.severe AS isevere2,
    l.finish_datum
FROM
    twin_project AS tp
    /* For Twin 1 */
    LEFT JOIN twin_data AS td ON tp.id = td.id
              AND tp.tvab = td.tvab
    LEFT JOIN informant_data AS id ON tp.id = id.id
              AND tp.tvab = id.tvab
    LEFT JOIN harmony AS h ON tp.id = h.id
              AND tp.tvab = h.tvab
    LEFT JOIN lentus AS l ON tp.id = l.id
              AND tp.tvab = l.tvab
    /* For Twin 2 */
    LEFT JOIN twin_data AS td2 ON p2.id = td2.id
              AND p2.tvab = td2.tvab
    LEFT JOIN informant_data AS id2 ON p2.id = id2.id
              AND p2.tvab = id2.tvab
    LEFT JOIN harmony AS h2 ON p2.id = h2.id
              AND p2.tvab = h2.tvab
    LEFT JOIN lentus AS l2 ON p2.id = l2.id
              AND p2.tvab = l2.tvab,
    person_data AS p1,
    person_data AS p2,
    postal_groups AS pg
WHERE
    /* p1 gets main twin and p2 gets his/her twin. */
    /* ptvab is a field inverted from tvab */
    p1.id = tp.id AND p1.tvab = tp.tvab AND
    p2.id = p1.id AND p2.ptvab = p1.tvab AND
    /* Just the screening survey */
    tp.survey_no = 5 AND
    /* Skip if partner died before 65 but allow emigration (dead=9) */
    (p2.dead = 0 OR p2.dead = 9 OR
     (p2.dead = 1 AND
      (p2.todestag_datum = 0 OR
       (((TO_DAYS(p2.todestag_datum) - TO_DAYS(p2.Geburtstag)) / 365)
        >= 65))))
    AND
    (
    /* Twin is suspect */
    (td.future_contact = 'Yes' AND td.suspect = 2) OR
    /* Twin is suspect - Informant is Blessed */
    (td.future_contact = 'Yes' AND td.suspect = 1
                               AND id.suspect = 1) OR
    /* No twin - Informant is Blessed */
    (ISNULL(td.suspect) AND id.suspect = 1
                        AND id.future_contact = 'Yes') OR
    /* Twin broken off - Informant is Blessed */
    (td.participation = 'Aborted'
     AND id.suspect = 1 AND id.future_contact = 'Yes') OR
    /* Twin broken off - No inform - Have partner */
    (td.participation = 'Aborted' AND ISNULL(id.suspect)
                                  AND p2.dead = 0))
    AND
    l.ereignis = 'Finished'
    /* Get at area code */
    AND SUBSTRING(p1.postal_code, 1, 2) = pg.code
    /* Not already distributed */
    AND (h.nurse IS NULL OR h.nurse=00 OR h.doctor=00)
    /* Has not refused or been aborted */
    AND NOT (h.status = 'Refused' OR h.status = 'Aborted'
    OR h.status = 'Died' OR h.status = 'Other')
ORDER BY
    tvid;

Hierzu ein paar Anmerkungen:

  • CONCAT(p1.id, p1.tvab) + 0 AS tvid

    Die verketteten Werte id und tvab sollen in numerischer Reihenfolge sortiert werden. Durch Hinzufügen von 0 zum Ergebnis wird MySQL dazu veranlasst, dieses Ergebnis als Zahl zu betrachten.

  • Spalte id

    Bezeichnet ein Zwillingspaar. Die Spalte wird als Schlüssel in allen Tabellen verwendet.

  • Spalte tvab

    Bezeichnet einen Zwilling in einem Paar. Der Wert ist entweder 1 oder 2.

  • Spalte ptvab

    Dies ist das Gegenstück zu tvab. Wenn tvab 1 ist, dann ist dieser Wert 2 und umgekehrt. Zweck ist die Einsparung von Tipparbeit und eine vereinfachte Optimierung der Abfrage durch MySQL.

Diese Abfrage veranschaulicht unter anderem, wie man Daten in einer Tabelle mithilfe eines Joins von derselben Tabelle aus durchführt (p1 und p2). In diesem Beispiel wird diese Methode verwendet, um zu ermitteln, ob einer von zwei Zwillingen eines Paares vor dem 65. Lebensjahr starb. Ist dies der Fall, dann wird der Datensatz nicht zurückgegeben.

Alle genannten Elemente sind in allen Tabellen mit Informationen zu den Zwillingen vorhanden. Um Abfragen zu beschleunigen, wurde ein Schlüssel sowohl auf id,tvab (alle Tabellen) als auch auf id,ptvab (person_data) erstellt.

Auf unserem Produktionssystem (UltraSPARC, 200 MHz) gibt diese Abfrage etwa 150 bis 200 Datensätze zurück und benötigt dafür weniger als eine Sekunde.

Die aktuelle Anzahl der Datensätze in den in dieser Abfrage verwendeten Tabellen sieht wie folgt aus:

TabelleDatensätze
person_data71074
lentus5291
twin_project5286
twin_data2012
informant_data663
harmony381
postal_groups100

3.7.2. Eine Tabelle über den Zustand von Zwillingspaaren zeigen

Jede Befragung resultiert in einem Statuscode, der ereignis heißt. Die nachfolgend gezeigte Abfrage wird zur Anzeige einer Tabelle über alle Zwillingspaare mit zugeordnetem Statuscode verwendet. Sie zeigt an, bei wie vielen Paaren beide Zwillinge zugelassen wurden, bei wie vielen Paaren nur ein Zwilling zugelassen (und der andere abgelehnt) wurde usw.

SELECT
        t1.ereignis,
        t2.ereignis,
        COUNT(*)
FROM
        lentus AS t1,
        lentus AS t2,
        twin_project AS tp
WHERE
        /* We are looking at one pair at a time */
        t1.id = tp.id
        AND t1.tvab=tp.tvab
        AND t1.id = t2.id
        /* Just the screening survey */
        AND tp.survey_no = 5
        /* This makes each pair only appear once */
        AND t1.tvab='1' AND t2.tvab='2'
GROUP BY
        t1.ereignis, t2.ereignis;

3.8. MySQL mit Apache verwenden

Es gibt Programme, die Ihnen die Authentifizierung Ihrer Benutzer aus einer MySQL-Datenbank gestatten und gleichzeitig das Schreiben der Logdateien in eine MySQL-Tabelle ermöglichen.

Sie können das Apache-Logformat so ändern, dass es leichter von MySQL gelesen werden kann. Hierzu fügen Sie Folgendes in Ihre Apache-Konfigurationsdatei ein:

LogFormat \
        "\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\",  \
        \"%U\",\"%{Referer}i\",\"%{User-Agent}i\""

Um eine Logdatei in diesem Format in MySQL einzuladen, können Sie etwa folgende Anweisung verwenden:

LOAD DATA INFILE '/local/access_log' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'

Die benannte Tabelle sollte so erstellt sein, dass sie Spalten aufweist, die denen entsprechen, welche die Zeile LogFormat in die Logdatei schreibt.

Kapitel 4. Benutzung von MySQL-Programmen

Dieses Kapitel vermittelt einen kurzen Überblick über die Befehlszeilenprogramme, die von MySQL AB angeboten werden, und beschreibt die allgemeine Syntax zur Angabe von Optionen bei der Ausführung dieser Programme. Die meisten Programme bieten zwar programmspezifische Optionen, aber die Optionssyntax ist bei allen Programmen ähnlich. Die nachfolgenden Kapitel enthalten detailliertere Beschreibungen einzelner Programme und der jeweiligen Optionen.

MySQL AB bietet auch drei grafikbasierte Clientprogramme zur Verwendung mit MySQL Server an:

  • MySQL Administrator: Dieses Tool dient der Administration von MySQL Servern, Datenbanken, Tabellen und Benutzerkonten.

  • MySQL Query Browser: Dieses grafische Tool von MySQL AB erlaubt das Erstellen, Ausführen und Optimieren von Abfragen über MySQL-Datenbanken.

  • MySQL Migration Toolkit: Dieses Tool erleichtert Ihnen die Migration von Schemata und Daten aus anderen Datenbanksystemen zur Verwendung mit MySQL.

Diese GUI-Programme haben jeweils eigene Handbücher, die unter http://dev.mysql.com/doc/ erhältlich sind.

4.1. Überblick über MySQL-Programme

MySQL AB bietet mehrere Programmtypen an:

  • Den MySQL Server und die Serverstartskripten:

    • mysqld ist der MySQL Server.

    • mysqld_safe, mysql.server und mysqld_multi sind Serverstartskripten.

    • mysql_install_db initialisiert das Datenverzeichnis und die Ausgangsdatenbanken.

    • Der MySQL Instance Manager überwacht und verwaltet MySQL Server-Instanzen.

    In Kapitel 5, Datenbankverwaltung, werden diese Programme eingehender behandelt.

  • Clientprogramme, die auf den Server zugreifen:

    • mysql ist ein Befehlszeilenclient zur Ausführung von SQL-Anweisungen im interaktiven Modus oder im Stapelbetrieb.

    • mysqladmin ist ein Administrationsclient.

    • mysqlcheck führt Wartungsarbeiten an den Tabellen aus.

    • mysqldump und mysqlhotcopy erstellen Datenbank-Backups.

    • mysqlimport importiert Datendateien.

    • mysqlshow zeigt Informationen zu Datenbanken und Tabellen an.

    In Kapitel 8, Client- und Hilfsprogramme, werden diese Programme eingehender behandelt.

  • Hilfsprogramme, die unabhängig vom Server laufen:

    • myisamchk führt Wartungsarbeiten an den Tabellen aus.

    • myisampack erzeugt komprimierte, schreibgeschützte Dateien.

    • mysqlbinlog ist ein Tool zur Verarbeitung binärer Logdateien.

    • perror zeigt Erläuterungen zu Fehlercodes an.

    Kapitel 5, Datenbankverwaltung, beschreibt myisamchk. Die übrigen Programme werden in Kapitel 8, Client- und Hilfsprogramme, erklärt.

Die meisten MySQL-Distributionen enthalten alle diese Programme abgesehen von denjenigen, die plattformspezifisch sind (dies gilt beispielsweise für die Serverstartskripten, die unter Windows nicht verwendet werden). Ausgenommen hiervon sind die RPM-Distributionen, denn sie sind spezialisierter: Es gibt ein RPM für den Server, ein anderes für Clientprogramme usw. Wenn Sie feststellen, dass Ihnen ein oder mehrere Programme fehlen, finden Sie in Kapitel 2, Installation von MySQL, Informationen zu Distributionstypen und deren Inhalten. Unter Umständen haben Sie eine Distribution, die nicht alle Programme enthält; Sie müssen dann möglicherweise noch andere Komponenten installieren.

4.2. Aufruf von MySQL-Programmen

Um ein MySQL-Programm über die Befehlszeile (d. h. von Ihrer Shell bzw. an der Eingabeaufforderung) aufzurufen, geben Sie den Programmnamen gefolgt von allen erforderlichen Optionen oder anderen Argumenten ein, mit denen Sie dem Programm mitteilen, was es tun soll. Die folgenden Befehle zeigen einige beispielhafte Programmaufrufe. „shell>“ stellt dabei die Eingabeaufforderung für Ihren Befehls-Interpreter dar, ist also nicht Bestandteil der Eingabe. Welche Eingabeaufforderung angezeigt wird, hängt vom verwendeten Befehls-Interpreter ab. Typische Eingabeaufforderungen sind $ bei sh oder bash, % bei csh oder tcsh und C:\> bei den Windows-Interpretern command.com oder cmd.exe.

shell> mysql -u root test
shell> mysqladmin extended-status variables
shell> mysqlshow --help
shell> mysqldump --user=root personnel

Argumente, die mit einem einzelnen oder doppelten Bindestrich (‘-’, ‘--’) beginnen, sind Optionsargumente. Optionen geben in der Regel die Art der Verbindung an, die ein Programm zum Server herstellen soll, oder betreffen den Betriebsmodus. Die Optionssyntax ist in Abschnitt 4.3, „Angabe von Programmoptionen“, beschrieben.

Nichtoptionsargumente (d. h. Argumente ohne führenden Bindestrich) übergeben zusätzliche Informationen an das Programm. So interpretiert etwa das Programm mysql das erste Nichtoptionsargument als Datenbanknamen; der Befehl mysql -u root test gibt also an, dass Sie die Datenbank test verwenden wollen.

Die nachfolgenden programmspezifischen Abschnitte geben auch an, welche Optionen das betreffende Programm versteht, und beschreiben die Bedeutung aller weiteren Nichtoptionsargumente.

Einige Optionen sind zahlreichen Programmen gemeinsam. Die häufigsten hiervon sind --host (oder -h), --user (oder -u) und --password (oder -p); sie alle dienen der Angabe von Verbindungsparametern. Angegeben werden auf diese Weise der Host, auf dem der MySQL Server ausgeführt wird, sowie der Benutzername und das Passwort Ihres MySQL-Kontos. Alle MySQL-Clientprogramme verstehen diese Optionen; sie gestatten Ihnen, festzulegen, mit welchem Server eine Verbindung hergestellt werden soll und welches Konto auf dem Server zu verwenden ist.

Sie werden möglicherweise feststellen, dass Sie beim Aufruf von MySQL-Programmen den Pfadnamen zum Verzeichnis bin angeben müssen, in dem sie installiert sind. Dies ist wahrscheinlich der Fall, wenn Sie beim Versuch, ein MySQL-Programm aus einem anderen als diesem Verzeichnis aufzurufen, die Fehlermeldung „Program not found“ erhalten. Um die Verwendung von MySQL praktischer zu gestalten, können Sie den Pfadnamen des Verzeichnisses bin zu Ihrer Umgebungsvariablen PATH hinzufügen. Danach können Sie ein Programm durch Eingabe des Programmnamens aufrufen und müssen den Pfadnamen nicht mehr angeben. Wenn Sie beispielsweise mysql in /usr/local/mysql/bin installiert haben, können Sie es nachfolgend über die Eingabe mysql; aufrufen; das Eingeben von /usr/local/mysql/bin/mysql ist dann nicht mehr notwendig.

Informationen zur Einstellung Ihrer Umgebungsvariable PATH finden Sie in der Dokumentation zu Ihrem Befehls-Interpreter. Die Syntax zur Einstellung von Umgebungsvariablen ist Interpreter-spezifisch.

4.3. Angabe von Programmoptionen

Es gibt mehrere Möglichkeiten, Optionen für MySQL-Programme anzugeben:

  • Sie listen die Optionen auf den Programmnamen folgend auf der Befehlszeile auf. Dies ist die meistverwendete Methode bei Optionen, die für eine bestimmte Art des Programmaufrufs verwendet werden.

  • Sie listen die Optionen in einer Optionsdatei auf, die das Programm beim Start ausliest. Dies bietet sich für Optionen an, die Sie bei jedem Programmstart verwenden wollen.

  • Sie listen die Optionen in Umgebungsvariablen auf. Auch diese Methode ist nützlich, wenn Sie bestimmte Optionen bei jeder Programmausführung verwenden wollen. In der Praxis werden für diesen Zweck allerdings meistens Optionsdateien verwendet. Abschnitt 5.13.2, „Mehrere MySQL-Server unter Unix laufen lassen“, beschreibt jedoch eine Situation, in der Umgebungsvariablen sehr hilfreich sein können. Dort wird eine praktische Methode erläutert, die solche Variablen zur Angabe der TCP/IP-Portnummer und der Unix-Socketdatei für Server- und Clientprogramme verwendet.

Bei der Ermittlung der angegebenen Optionen fragen MySQL-Programme zunächst die Umgebungsvariablen ab, lesen dann die Optionsdateien aus und überprüfen schließlich die Eingabe auf der Befehlszeile. Wird eine Option mehrfach angegeben, so hat das jeweils letzte Auftreten Vorrang. Das bedeutet, dass Angaben in Umgebungsvariablen die niedrigste und Befehlszeileneingaben die höchste Priorität genießen.

Sie können diese Art der Verarbeitung von Optionen durch MySQL-Programme nutzen, indem Sie Vorgabewerte in einer Optionsdatei angeben. Auf diese Weise müssen Sie sie nicht bei jeder Ausführung des Programms neu eingeben, können die Vorgabewerte bei Bedarf aber mithilfe von Optionseingaben auf der Befehlszeile außer Kraft setzen.

4.3.1. Befehlszeilenoptionen für mysqld

Auf der Befehlszeile angegebene Programmoptionen unterliegen den folgenden Regeln:

  • Optionen werden auf den Befehlsnamen folgend angegeben.

  • Ein Optionsargument beginnt abhängig davon, ob es sich um einen kurzen oder langen Optionsnamen handelt, mit einem oder zwei Bindestrichen. Für viele Optionen sind sowohl ein Kurz- als auch ein Langname vorhanden. Beispielsweise sind -? und --help die Kurz- und die Langform der Option, die ein MySQL-Programm anweist, eine Hilfemeldung anzuzeigen.

  • Bei Optionsnamen wird die Groß-/Kleinschreibung unterschieden. Das bedeutet, dass sowohl -v als auch -V zulässig sind und auch unterschiedliche Bedeutungen haben. (Es handelt sich hierbei um die Kurzformen der Optionen --verbose bzw. --version.)

  • Einige Optionen nehmen einen Wert entgegen, der auf den Optionsnamen folgt. So bezeichnet -h localhost bzw. --host=localhost den MySQL Server für ein Clientprogramm. Der Optionswert nennt dem Programm den Namen des Hosts, auf dem der MySQL Server ausgeführt wird.

  • Bei einer Option mit einem Langnamen, die einen Wert entgegennimmt, trennen Sie den Optionsnamen und den Wert durch das Zeichen ‘=’. Bei Verwendung einer Kurzform, die einen Wert entgegennimmt, kann dieser entweder direkt oder durch ein Leerzeichen getrennt auf den Optionsbuchstaben folgen: -hlocalhost und -h localhost sind gleichbedeutend. Eine Ausnahme dieser Regel ist die Option zur Angabe Ihres MySQL-Passworts. Diese Option kann in der Langform entweder als --password=pass_val oder als --password angegeben werden. Im zweiten Fall (in dem kein Passwort übergeben wird) fordert das Programm Sie danach zur Eingabe des Passworts auf. Die Passwortoption kann auch in Kurzform als -ppass_val oder als -p angegeben werden. Allerdings muss die Eingabe des Passwortwerts bei der Kurzform unmittelbar auf den Optionsbuchstaben folgend, d. h. ohne trennendes Leerzeichen, erfolgen. Der Grund hierfür ist, dass, wenn ein Leerzeichen auf den Optionsbuchstaben folgt, das Programm keine Möglichkeit hat, festzustellen, ob das nachfolgende Argument der Passwortwert oder ein anderes Argument sein soll. Hieraus ergibt sich, dass die folgenden beiden Befehle zwei völlig unterschiedliche Bedeutungen haben:

    shell> mysql -ptest
    shell> mysql -p test
    

    Der erste Befehl weist mysql an, den Passwortwert test zu verwenden, gibt aber keine Standarddatenbank an. Der zweite Befehl hingegen weist mysql an, zur Eingabe des Passworts aufzufordern und test als Standarddatenbank zu verwenden.

Einige Optionen steuern Verhaltensweisen, die sich aktivieren oder deaktivieren lassen. So unterstützt der Client mysql etwa eine Option --column-names, die bestimmt, ob zu Beginn der Abfrageergebnisse eine Zeile mit Spaltennamen angezeigt wird oder nicht. Standardmäßig ist diese Option aktiviert. Unter Umständen kann es jedoch sinnvoll sein, sie zu deaktivieren, wenn Sie beispielsweise die Ausgabe von mysql an ein anderes Programm übergeben, das nur die Daten und keine Kopfzeile erwartet.

Sie können die Spaltennamen mit jeder der folgenden Optionen deaktivieren:

--disable-column-names
--skip-column-names
--column-names=0

Die Präfixe --disable und --skip und das Suffix =0 haben den jeweils gleichen Effekt: Sie schalten die Option ab.

Um die „einschaltende“ Form der Option anzugeben, gibt es die folgenden Möglichkeiten:

--column-names
--enable-column-names
--column-names=1

Wenn einer Option das Präfix --loose vorangestellt wird, bricht ein Programm, dass die Option nicht erkennt, nicht mit einer Fehlermeldung ab, sondern setzt lediglich eine Warnung ab:

shell> mysql --loose-no-such-option
mysql: WARNING: unknown option '--no-such-option'

Das Präfix --loose kann nützlich sein, wenn Sie Programme unter mehreren MySQL-Installationen auf demselben Computer ausführen und die Optionen in einer Optionsdatei auflisten. Eine Option, die unter Umständen nicht von allen Versionen eines Programms erkannt wird, kann mithilfe des Präfixes --loose (bzw. loose in einer Optionsdatei) angegeben werden. Versionen des Programms, die die Option erkennen, werden sie dann in der Regel auch verarbeiten, während Programmversionen, die sie nicht erkennen, eine Warnung absetzen und sie ansonsten ignorieren.

Eine andere Option, die in Verbindung mit mysql gelegentlich nützlich sein kann, ist --execute oder -e. Hiermit können Sie SQL-Anweisungen an den Server übergeben. Die Anweisungen müssen in einfache oder doppelte Anführungszeichen gesetzt sein. Wenn Sie Werte in Anführungszeichen innerhalb einer Anweisung angeben wollen, sollten Sie doppelte Anführungszeichen für die Anweisung selbst und einfache Anführungszeichen für Werte innerhalb der Anweisung benutzen. Wenn Sie diese Option verwenden, führt mysql die Anweisung aus und wird dann beendet.

So können Sie beispielsweise mithilfe des folgenden Befehls eine Liste der Benutzerkonten aufrufen:

shell> mysql -u root -p --execute="SELECT User, Host FROM user" mysql
Enter password: ******
+------+-----------+
| User | Host      |
+------+-----------+
|      | gigan     |
| root | gigan     |
|      | localhost |
| jon  | localhost |
| root | localhost |
+------+-----------+
shell>

Beachten Sie, dass auf die Langform (--execute) das Gleichheitszeichen (=) folgen muss.

In obigem Beispiel wurde der Name der Datenbank mysql als separates Argument übergeben. Dieselbe Anweisung hätte auch mit dem folgenden Befehl ausgeführt werden können, der keine Standarddatenbank angibt:

mysql> mysql -u root -p --execute="SELECT User, Host FROM mysql.user"

Über die Befehlszeile lassen sich mehrere SQL-Anweisungen durch Semikola getrennt angeben:

shell> mysql -u root -p -e "SELECT VERSION();SELECT NOW()"
Enter password: ******
+-----------------+
| VERSION()       |
+-----------------+
| 5.1.5-alpha-log |
+-----------------+
+---------------------+
| NOW()               |
+---------------------+
| 2006-01-05 21:19:04 |
+---------------------+

Die Option --execute oder -e kann auch verwendet werden, um Befehle in analoger Form an ndb_mgm, den Verwaltungsclient für MySQL Cluster, zu übergeben. Ein Beispiel finden Sie in Abschnitt 16.3.6, „Sicheres Herunterfahren und Neustarten“.

4.3.2. my.cnf-Optionsdateien

Die meisten MySQL-Programme können Startoptionen aus Optionsdateien (die manchmal auch Konfigurationsdateien genannt werden) auslesen. Optionsdateien stellen eine praktische Möglichkeit dar, häufig verwendete Optionen anzugeben, damit sie nicht mehr bei jeder Ausführung eines Programms explizit eingegeben werden müssen.

Um zu ermitteln, ob ein Programm Optionsdateien ausliest, rufen Sie es mit der Option --help auf (--verbose und --help bei mysqld). Wenn das Programm Optionsdateien ausliest, zeigt die Hilfemeldung an, nach welchen Dateien sie sucht und welche Optionsabschnitte (Gruppen) sie erkennt.

Hinweis: Optionsdateien, die für MySQL Cluster-Dateien verwendet werden, werden in Abschnitt 16.4, „MySQL Cluster: Konfiguration“, behandelt.

Unter Windows lesen MySQL-Programme Startoptionen aus den folgenden Dateien aus:

DateinameZweck
WINDIR\my.iniglobale Optionen
C:\my.cnfglobale Optionen
INSTALLDIR\my.iniglobale Optionen
defaults-extra-filedie ggf. mit --defaults-extra-file=path angegebene Datei

WINDIR steht dabei für die Position Ihres Windows-Verzeichnisses. Dies ist in der Regel C:\WINDOWS oder C:\WINNT. Sie können die exakte Position der Umgebungsvariablen WINDIR entnehmen. Hierzu geben Sie den folgenden Befehl ein:

C:\> echo %WINDIR%

INSTALLDIR steht für das MySQL-Installationsverzeichnis. Dies ist normalerweise C:\PROGRAMDIR\MySQL\MySQL 5.1 Server, wobei PROGRAMDIR das Programmverzeichnis (bei deutschsprachigen Windows-Versionen üblicherweise Programme) ist, wenn MySQL 5.1 mithilfe der Installations- und Konfigurations-Assistenten eingerichtet wurde. Siehe auch Abschnitt 2.3.5.14, „Speicherort der Datei my.ini.

Unter Unix lesen MySQL-Programme Startoptionen aus den folgenden Dateien aus:

DateinameZweck
/etc/my.cnfglobale Optionen
$MYSQL_HOME/my.cnfserverspezifische Optionen
defaults-extra-filedie ggf. mit --defaults-extra-file=path angegebene Datei
~/.my.cnfbenutzerspezifische Optionen

MYSQL_HOME ist eine Umgebungsvariable, die den Pfad angibt, in dem die serverspezifische Datei my.cnf abgelegt ist.

Wenn MYSQL_HOME nicht eingestellt ist und Sie den Server mit dem Programm mysqld_safe starten, versucht mysqld_safe, MYSQL_HOME wie folgt einzustellen:

  • Dabei stehen BASEDIR und DATADIR für die Pfadnamen zum MySQL-Basis- bzw. Datenverzeichnis.

  • Ist eine Datei my.cnf in DATADIR, aber nicht in BASEDIR vorhanden, so setzt mysqld_safe MYSQL_HOME auf DATADIR.

  • Andernfalls – also wenn MYSQL_HOME nicht gesetzt und keine Datei my.cnf in DATADIR vorhanden ist – setzt mysqld_safe MYSQL_HOME auf BASEDIR.

Normalerweise ist DATADIR /usr/local/mysql/data in einer Binärinstallation bzw. /usr/local/var in einer Quellinstallation. Beachten Sie, dass dies jeweils die Position des Datenverzeichnisses ist, die zum Zeitpunkt der Konfiguration angegeben wurde, und nicht die mit der Option --datadir beim Start von mysqld spezifizierte Position. Die Verwendung von --datadir während der Laufzeit hat keinen Einfluss darauf, wo der Server nach Optionsdateien sucht, denn die Suche erfolgt vor der Verarbeitung ggf. angegebener Optionen.

MySQL sucht in der gerade beschriebenen Reihenfolge nach Optionsdateien und liest diese aus, sofern sie vorhanden sind. Ist eine Optionsdatei, die Sie verwenden wollen, nicht vorhanden, dann können Sie sie mit einem Texteditor erstellen.

Werden mehrere Instanzen einer gegebenen Option gefunden, dann hat die jeweils zuletzt gefundene Instanz immer Vorrang. Es gibt allerdings eine Ausnahme: Bei mysqld wird aus Sicherheitsgründen immer die erste Instanz der Option --user verarbeitet, damit verhindert wird, dass eine Benutzerangabe in einer Optionsdatei über die Befehlszeile außer Kraft gesetzt werden kann.

Hinweis: Auf Unix-Plattformen ignoriert MySQL Konfigurationsdateien, die für alle schreibbar („world-writable“) sind. Dies ist beabsichtigt und dient der Erhöhung der Sicherheit.

Jede Langformoption, die beim Start eines MySQL-Programms über die Befehlszeile angegeben wird, kann ebenso gut auch in einer Optionsdatei spezifiziert werden. Um eine Liste der für ein Programm verfügbaren Optionen zu erhalten, führen Sie es mit der Option --help aus.

Die Syntax zur Angabe von Optionen in einer Optionsdatei ähnelt der Befehlszeilensyntax, nur können Sie die beiden Bindestriche am Anfang weglassen. So werden etwa die Befehlszeilenoptionen --quick oder --host=localhost in einer Optionsdatei als quick bzw. host=localhost angegeben. Um eine Option des Typs --loose-opt_name in einer Optionsdatei anzugeben, schreiben Sie sie als loose-opt_name.

Leerzeilen in Optionsdateien werden ignoriert. Nichtleere Zeilen können die folgenden Formen annehmen:

  • #comment, ;comment

    Kommentarzeilen starten mit ‘#’ oder ‘;’. Ein Kommentar des Typs ‘#’ kann auch in der Mitte einer Zeile verwendet werden.

  • [group]

    group ist der Name des Programms oder Abschnitts, für den Sie die Optionen einstellen wollen. Alle auf eine Abschnittszeile folgenden Zeilen mit Optionseinstellungen gelten für den betreffenden Abschnitt, bis eine andere Abschnittszeile angegeben oder das Ende der Optionsdatei erreicht wird.

  • opt_name

    Entspricht --opt_name auf der Befehlszeile.

  • opt_name=value

    Entspricht --opt_name=value auf der Befehlszeile. In einer Optionsdatei können Sie – anders als auf der Befehlszeile – Leerzeichen um das Gleichheitszeichen ‘=’ setzen. Sie können den Wert in einzelne oder doppelte Anführungszeichen setzen, was nützlich bei Werten ist, die das Kommentarzeichen ‘#’ oder Whitespace enthalten.

Bei Optionen, die numerische Werte annehmen, kann dieser mit den Suffixen K, M oder G (in Groß- oder Kleinschreibung) angegeben werden, um einen Multiplikator von 1024, 10242 oder 10243 anzuzeigen. Der folgende Befehl beispielsweise weist mysqladmin an, 1024 Ping-Befehle im Abstand von jeweils zehn Sekunden an den Server zu senden:

mysql> mysqladmin --count=1K --sleep=10 ping

Bei Optionsnamen oder -werten werden Leerzeichen am Anfang oder Ende automatisch gelöscht. Sie können die Escape-Sequenzen ‘\b’, ‘\t’, ‘\n’, ‘\r’, ‘\\’ und ‘\s’ in Optionswerten zur Darstellung von Rückschritt-, Tabulator-, Zeilenwechsel-, Absatzschaltungs- und Leerzeichen verwenden.

Da die Escape-Sequenz ‘\\’ genau einen Backslash darstellt, müssen Sie jeden Backslash als ‘\\’ schreiben. Alternativ geben Sie den Wert unter Einsatz von ‘/’ statt ‘\’ als Trennzeichen in Pfadnamen an.

Wenn der Name eines Optionsabschnitts mit dem eines Programms identisch ist, gelten die Optionen in diesem Abschnitt speziell für dieses Programm. So betreffen beispielsweise die Abschnitte [mysqld] und [mysql] den Server mysqld bzw. das Clientprogramm mysql.

Der Optionsabschnitt [client] wird von allen Clientprogrammen (aber nicht von mysqld) ausgelesen. Auf diese Weise können Sie Optionen angeben, die für alle Clients gelten. Beispielsweise ist [client] der optimale Abschnitt zur Angabe des Passworts, mit dem Sie die Serververbindung herstellen. (Hierbei müssen Sie natürlich sicherstellen, dass nur Sie die Optionsdatei lesen und in sie schreiben können, damit Dritte Ihr Passwort nicht ermitteln können.) Beachten Sie, dass Sie eine Option nicht im Abschnitt [client] ablegen dürfen, wenn nicht gewährleistet ist, dass alle von Ihnen verwendeten Clientprogramme sie erkennen. Wenn Sie Programme starten, die eine bestimmte Option nicht verstehen, dann zeigen diese eine Fehlermeldung an und werden nachfolgend beendet.

Eine typische Datei mit globalen Optionen sieht so aus:

[client]
port=3306
socket=/tmp/mysql.sock

[mysqld]
port=3306
socket=/tmp/mysql.sock
key_buffer_size=16M
max_allowed_packet=8M

[mysqldump]
quick

Diese Optionsdatei verwendet die Syntax var_name=value für Zeilen, die die Variablen key_buffer_size und max_allowed_packet einstellen.

Eine typische Datei mit Benutzeroptionen sieht so aus:

[client]
# The following password will be sent to all standard MySQL clients
password="my_password"

[mysql]
no-auto-rehash
connect_timeout=2

[mysqlhotcopy]
interactive-timeout

Wenn Sie Optionsabschnitte erstellen wollen, die nur von mysqld-Servern einer bestimmten MySQL-Release-Serie ausgelesen werden sollen, dann sollten Sie Abschnittsnamen in der Form [mysqld-5.0], [mysqld-5.1] usw. verwenden. Der folgende Abschnitt gibt an, dass die Option --new nur von MySQL Servern der Versionsnummern 5.1.x verwendet werden soll:

[mysqld-5.1]
new

Seit MySQL 5.0.4 ist es möglich, !include-Direktiven in Optionsdateien zu verwenden, um andere Optionsdateien zu integrieren. Ebenfalls nutzbar ist !includedir; hiermit wird das Durchsuchen bestimmter Verzeichnisse nach Optionsdateien veranlasst. Um beispielsweise die Datei /home/mydir/myopt.cnf zu integrieren, können Sie die folgende Direktive verwenden:

!include /home/me/myopt.cnf

Wenn Sie das Verzeichnis /home/mydir durchsuchen und die darin vorhandenen Optionsdateien auslesen wollen, würde die Direktive wie folgt aussehen:

!includedir /home/mydir

Hinweis: Zurzeit müssen alle Dateien, die auf Unix-Betriebssystemen mithilfe der Direktive !includedir gesucht und integriert werden sollen, Dateinamen mit der Erweiterung .cnf aufweisen. Unter Windows prüft die Direktive auf Dateien mit den Erweiterungen .ini oder .cnf.

Beachten Sie, dass Optionen, die aus integrierten Dateien ausgelesen werden, im Kontext des aktuellen Optionsabschnitts angewendet werden. Nehmen wir einmal an, Sie würden die folgenden Zeilen in my.cnf ablegen:

[mysqld]
!include /home/mydir/myopt.cnf

In diesem Fall wird die Datei myopt.cnf nur für den Server verarbeitet; die Direktive !include wird von allen Clientanwendungen ignoriert. Würden Sie jedoch wie folgt formulieren, dann würde das Verzeichnis /home/mydir/my-dump-options nur von mysqldump auf Optionsdateien geprüft, nicht jedoch vom Server oder anderen Clientanwendungen:

[mysqldump]
!includedir /home/mydir/my-dump-options

Wenn Sie eine Quelldistribution verwenden, finden Sie Beispieloptionsdateien mit dem Namen my-xxxx.cnf im Verzeichnis support-files. Im Falle einer Binärdistribution schauen Sie im Verzeichnis support-files nach, welches sich im MySQL-Installationsverzeichnis befindet. Unter Windows sind die Beispieloptionsdateien unter Umständen im MySQL-Installationsverzeichnis selbst abgelegt (siehe auch weiter oben in diesem Abschnitt oder in Kapitel 2, Installation von MySQL, wenn Sie nicht wissen, wo sich dieses befindet). Derzeit sind Beispieloptionsdateien für kleine, mittelgroße, große und sehr große Systeme vorhanden. Um mit einer dieser Dateien zu experimentieren, kopieren Sie sie unter Windows als C:\my.cnf bzw. unter Unix als .my.cnf in Ihr Homeverzeichnis.

Hinweis: Unter Windows wird die Dateierweiterung .cnf unter Umständen nicht angezeigt.

Alle MySQL-Programme, die Optionsdateien unterstützen, verarbeiten die folgenden Optionen. Diese betreffen den Umgang mit Optionsdateien, müssen also über die Befehlszeile (und nicht in einer Optionsdatei) angegeben werden. Damit sie einwandfrei funktionieren, müssen die Optionen jeweils unmittelbar auf den Befehlsnamen folgen. Ausgenommen ist --print-defaults, das unmittelbar auf --defaults-file oder --defaults-extra-file angegeben werden muss.

  • --no-defaults

    Optionsdateien nicht auslesen.

  • --print-defaults

    Programmnamen und alle aus den Optionsdateien ausgelesenen Optionen anzeigen.

  • --defaults-file=file_name

    Nur die angegebene Optionsdatei verwenden. Dabei ist file_name der vollständige Pfadname zur betreffenden Datei.

  • --defaults-extra-file=file_name

    Diese Optionsdatei nach der globalen Optionsdatei, aber (unter Unix) vor der Benutzeroptionsdatei auslesen. Dabei ist file_name der vollständige Pfadname zur betreffenden Datei.

In Shell-Skripten können Sie mit dem Programm my_print_defaults die Optionsdateien durchsuchen und überprüfen, welche Optionen für ein gegebenes Programm verwendet würden. Das folgende Beispiel zeigt eine Ausgabe, die my_print_defaults erzeugen könnte, wenn es die in den Abschnitten [client] und [mysql] gefundenen Optionen anzeigen sollte:

shell> my_print_defaults client mysql
--port=3306
--socket=/tmp/mysql.sock
--no-auto-rehash

Hinweis für Entwickler: Die Verarbeitung von Optionsdateien wird in der C-Clientbibliothek implementiert, indem einfach alle Optionen in dem oder den entsprechenden Abschnitten vor den Befehlszeilenargumenten ausgelesen werden. Dies funktioniert bei Programmen, die das letzte Auftreten einer mehrfach angegebenen Option verwenden, einwandfrei. Wenn Sie jedoch ein C- oder C++-Programm haben, das zwar mehrfach angegebene Optionen verarbeitet, aber die Optionsdateien nicht ausliest, müssen Sie lediglich zwei Zeilen hinzufügen, um diese Funktionalität zu implementieren. Studieren Sie den Quellcode eines beliebigen MySQL-Standardclients, um zu erfahren, wie es gemacht wird.

Mehrere andere Sprachschnittstellen zu MySQL basieren auf der C-Clientbibliothek, und eine davon ermöglicht den Zugriff auf die Inhalte von Optionsdateien. Dies betrifft Perl und Python. Details entnehmen Sie der Dokumentation Ihrer bevorzugten Schnittstelle.

4.3.3. Verwendung von Umgebungsvariablen für die Angabe von Optionen

Um eine Option in einer Umgebungsvariablen anzugeben, stellen Sie die Variable unter Verwendung der für Ihren Befehls-Interpreter passenden Syntax ein. Unter Windows oder NetWare etwa können Sie die Variable USER zur Angabe Ihres MySQL-Kontennamens verwenden. Benutzen Sie zu diesem Zweck folgende Syntax:

SET USER=your_name

Die Unix-Syntax hängt von der verwendeten Shell ab. Nehmen wir an, Sie wollen die TCP/IP-Portnummer über die Variable MYSQL_TCP_PORT festlegen. Die typische Syntax (etwa bei sh, bash, zsh usw.) sieht so aus:

MYSQL_TCP_PORT=3306
export MYSQL_TCP_PORT

Der erste Befehl stellt die Variable ein, und der Befehl export exportiert diese dann in die Shell-Umgebung, sodass ihr Wert für MySQL und andere Prozesse verfügbar wird.

Bei csh und tcsh machen Sie die Shell-Variable mithilfe von setenv für die Umgebung verfügbar:

setenv MYSQL_TCP_PORT 3306

Die Befehle zur Einstellung von Umgebungsvariablen können Sie an der Eingabeaufforderung ausführen; sie werden dann sofort gültig, bleiben es aber nur, bis Sie sich abmelden. Damit die Einstellungen bei jeder Anmeldung übernommen werden, legen Sie den oder die entsprechenden Befehle in einer Autostartdatei ab, die Ihr Befehls-Interpreter bei jedem Start ausliest. Typische Autostartdateien sind AUTOEXEC.BAT unter Windows, .bash_profile unter bash oder .tcshrc unter tcsh. Weitere Informationen entnehmen Sie der Dokumentation zu Ihrem Befehls-Interpreter.

Anhang F, Umgebungsvariablen, listet alle Umgebungsvariablen auf, die den Betrieb von MySQL-Programmen beeinflussen.

4.3.4. Verwendung von Optionen zum Setzen von Programmvariablen

Viele MySQL-Programme haben interne Variablen, die zur Laufzeit eingestellt werden können. Programmvariablen werden auf die gleiche Weise eingestellt wie andere Langformoptionen, die einen Wert entgegennehmen. Beispielsweise hat mysql eine Variable max_allowed_packet, mit der die maximale Größe des Kommunikationspuffers eingestellt wird. Um die Variable max_allowed_packet für mysql auf einen Wert von 16 Mbyte einzustellen, können Sie einen der folgenden Befehle verwenden:

shell> mysql --max_allowed_packet=16777216
shell> mysql --max_allowed_packet=16M

Der erste Befehl gibt den Wert in Byte an, der zweite den Wert in Mbyte. Bei Variablen, die numerische Werte annehmen, kann dieser mit den Suffixen K, M oder G (in Groß- oder Kleinschreibung) angegeben werden, um einen Multiplikator von 1024, 10242 oder 10243 anzuzeigen. (Bei der Einstellung von max_allowed_packet etwa würden hiermit die Werte als Kbyte, Mbyte oder Gbyte angegeben.)

In einer Optionsdatei werden die Variableneinstellungen ohne führende Bindestriche angegeben:

[mysql]
max_allowed_packet=16777216

Oder:

[mysql]
max_allowed_packet=16M

Wenn Sie wollen, können Sie Unterstriche in einem Variablennamen als Bindestriche angeben. Die folgenden Optionsabschnitte sind gleichwertig. Beide setzen die Größe des Schlüsselpuffers am Server auf 512 Mbyte:

[mysqld]
key_buffer_size=512M

[mysqld]
key-buffer-size=512M

Hinweis: Vor MySQL 4.0.2 lautet die einzige verfügbare Syntax zur Einstellung von Programmvariablen --set-variable=option=value (bzw. set-variable=option=value in Optionsdateien). Diese Syntax wird zwar nach wie vor erkannt, findet aber seit MySQL 4.0.2 keine Akzeptanz mehr.

Viele Serversystemvariablen können auch zur Laufzeit angegeben werden. Detaillierte Informationen finden Sie in Abschnitt 5.2.3.2, „Dynamische Systemvariablen“.

Kapitel 5. Datenbankverwaltung

Inhaltsverzeichnis

5.1. Überblick über serverseitige Programme und Dienstprogramme
5.2. mysqld — Der MySQL-Server
5.2.1. Befehlsoptionen für mysqld
5.2.2. Server-Systemvariablen
5.2.3. Verwendung von Server-Systemvariablen
5.2.4. Server-Statusvariablen
5.2.5. Der SQL-Modus des Servers
5.2.6. Herunterfahren des MySQL Servers
5.3. mysqld-max, ein erweiterter mysqld-Server
5.4. Startprogramme für den MySQL-Server
5.4.1. mysqld_safe — Startskript für den MySQL-Server
5.4.2. mysql.server — Startskript für den MySQL-Server
5.4.3. mysqld_multi — Verwalten mehrerer MySQL-Server
5.5. mysqlmanager — Der MySQL Instance Manager
5.5.1. MySQL Instance Manager: MySQL-Server starten
5.5.2. MySQL Instance Manager: Verbinden und Anlegen von Benutzerkonten
5.5.3. MySQL Instance Manager: Befehlsoptionen
5.5.4. MySQL Instance Manager: Konfigurationsdateien
5.5.5. MySQL Instance Manager: Unterstützte Befehle
5.6. mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen
5.7. Absichern von MySQL gegen Angreifer
5.7.1. Allgemeine Sicherheitsrichtlinien
5.7.2. Absichern von MySQL gegen Angreifer
5.7.3. Startoptionen für mysqld in Bezug auf Sicherheit
5.7.4. Sicherheitsprobleme mit LOAD DATA LOCAL
5.7.5. Wie man MySQL als normaler Benutzer laufen läßt
5.8. Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem
5.8.1. Was das Berechtigungssystem macht
5.8.2. Wie das Berechtigungssystem funktioniert
5.8.3. Von MySQL zur Verfügung gestellte Berechtigungen
5.8.4. Verbinden mit dem MySQL-Server
5.8.5. Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
5.8.6. Zugriffskontrolle, Phase 2: Anfrageüberprüfung
5.8.7. Wann Berechtigungsänderungen wirksam werden
5.8.8. Gründe für Access denied-Fehler
5.8.9. Kennwort-Hashing ab MySQL 4.1
5.9. MySQL-Benutzerkontenverwaltung
5.9.1. MySQL-Benutzernamen und -Kennwörter
5.9.2. Hinzufügen neuer MySQL-Benutzer
5.9.3. Entfernen von Benutzerkonten in MySQL
5.9.4. Begrenzen von Benutzer-Ressourcen
5.9.5. Kennwörter einrichten
5.9.6. Wie Sie Ihre Kennwörter sicher halten
5.9.7. Verwendung sicherer Verbindungen
5.10. Datensicherung und Wiederherstellung
5.10.1. Datenbank-Datensicherungen
5.10.2. Beispielhaftes Vorgehen zur Datensicherung und Wiederherstellung
5.10.3. Zeitpunktbezogene Wiederherstellung
5.10.4. Benutzung von myisamchk für Tabellenwartung und Absturzreparatur
5.11. Lokalisierung und internationaler Gebrauch von MySQL
5.11.1. Der für Daten und zum Sortieren benutzte Zeichensatz
5.11.2. Nicht englische Fehlermeldungen
5.11.3. Einen neuen Zeichensatz hinzufügen
5.11.4. Die Zeichendefinitionsarrays
5.11.5. Unterstützung für String-Vergleiche
5.11.6. Unterstützung für Multi-Byte-Zeichen
5.11.7. Probleme mit Zeichensätzen
5.11.8. Zeitzonen-Unterstützung des MySQL-Servers
5.12. Die MySQL-Logdateien
5.12.1. Die Fehler-Logdatei
5.12.2. Die allgemeine Anfragen-Logdatei
5.12.3. Die binäre Update-Logdatei
5.12.4. Die Logdatei für langsame Anfragen
5.12.5. Wartung und Pflege der Logdateien
5.13. Mehrere MySQL-Server auf derselben Maschine laufen lassen
5.13.1. Mehrere Server unter Windows verwenden
5.13.2. Mehrere MySQL-Server unter Unix laufen lassen
5.13.3. Verwendung von Client-Programmen in einer Mehrserverumgebung
5.14. MySQL-Anfragen-Cache
5.14.1. Wie der Anfragen-Cache funktioniert
5.14.2. Anfragen-Cache-Optionen in SELECT
5.14.3. Konfiguration des Anfragen-Cache
5.14.4. Anfragen-Cache-Status und -Wartung

Dieses Kapitel behandelt Themen im Zusammenhang mit der Administration einer MySQL-Installation:

  • Server konfigurieren

  • Benutzerkonten verwalten

  • Sicherungen durchführen

  • Serverlogdateien

  • Abfrage-Cache

5.1. Überblick über serverseitige Programme und Dienstprogramme

Der MySQL-Server mysqld ist das Hauptprogramm, welches in einer MySQL-Installation die meiste Arbeit leistet. Der Server wird von mehreren zugehörigen Skripten begleitet, die bei der Einrichtung von MySQL Konfigurationsarbeiten durchführen oder Ihnen beim Starten und Beenden des Servers behilflich sind. Dieser Abschnitt vermittelt einen Überblick über den Server und zugehörige Programme. Die nachfolgenden Abschnitte beschreiben dann alle diese Programme im Detail.

Jedes MySQL-Programm akzeptiert viele verschiedene Optionen. Die meisten Programme enthalten eine Option --help, über die Sie eine Beschreibung der verschiedenen Programmoptionen erhalten können. Probieren Sie z. B. mysqld --help aus.

Sie können die Standardoptionswerte bei MySQL-Programmen außer Kraft setzen, indem Sie Optionen auf der Befehlszeile oder in einer Optionsdatei angeben. Abschnitt 4.3, „Angabe von Programmoptionen“.

Die folgende Liste stellt eine kurze Beschreibung des MySQL-Servers und der serverbezogenen Programme dar:

Es gibt noch einige andere Programme, die auf dem Serverhost ausgeführt werden.

  • make_binary_distribution

    Dieses Programm erstellt einen Binär-Release aus einer kompilierten MySQL-Distribution. Dieses für andere MySQL-Benutzer praktische Format kann dann via FTP nach /pub/mysql/upload/ auf ftp.mysql.com übertragen werden.

5.2. mysqld — Der MySQL-Server

mysqld ist der MySQL-Server. Nachfolgend werden wir folgende Themen in Zusammenhang mit der Konfiguration dieses MySQL-Servers behandeln:

  • Startoptionen, die vom Server unterstützt werden

  • Serversystemvariablen

  • Serverstatusvariablen

  • Einstellen des SQL-Modus des Servers

  • Herunterfahren des Servers

5.2.1. Befehlsoptionen für mysqld

Wenn Sie den Server mysqld starten, können Sie Programmoptionen mithilfe aller in Abschnitt 4.3, „Angabe von Programmoptionen“, beschriebenen Methoden festlegen. Die meistverwendeten Methoden sind die Angabe von Optionen in einer Optionsdatei oder über die Befehlszeile. In den meisten Fällen ist es wünschenswert, dass der Server stets die gleichen Optionen verwendet. Dies lässt sich am einfachsten gewährleisten, indem man die Optionen in einer Optionsdatei auflistet. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

mysqld liest Optionen aus den Abschnitten [mysqld] und [server] aus. mysqld_safe liest Optionen aus den Abschnitten [mysqld], [server], [mysqld_safe] und [safe_mysqld] aus. mysql.server schließlich liest Optionen aus den Abschnitten [mysqld] und [mysql.server] aus.

Ein eingebetteter MySQL-Server entnimmt seine Optionen den Abschnitten [server], [embedded] und [xxxxx_SERVER], wobei xxxxx der Name der Anwendung ist, in die der Server eingebettet ist.

mysqld akzeptiert viele Befehlsoptionen. Eine kurze Liste erhalten Sie, wenn Sie mysqld --help ausführen. Die vollständige Liste rufen Sie über mysqld --verbose --help auf.

Die folgende Liste zeigt einige der häufigsten Serveroptionen (weitere Optionen sind an anderer Stelle beschrieben):

Sie können die Werte der Serversystemvariablen auch mithilfe von Variablennamen als Optionen zuweisen. Dies wird im weiteren Verlauf dieses Abschnitts beschrieben.

  • --help, -?

    Zeigt eine kurze Hilfemeldung an und wird dann beendet. Verwenden Sie die Optionen --verbose und --help, um die vollständige Meldung zu sehen.

  • --allow-suspicious-udfs

    Diese Option bestimmt, ob UDFs (User-Defined Functions, benutzerdefinierte Funktionen), die nur ein xxx-Symbol für die Hauptfunktion aufweisen, geladen werden dürfen. Standardmäßig ist die Option deaktiviert, und es dürfen nur UDFs geladen werden, die mindestens ein Hilfssymbol aufweisen. Hierdurch soll das Laden von Funktionen aus solchen freigegebenen Objektdateien verhindert werden, die keine zulässigen UDFs enthalten. Siehe auch Abschnitt 26.3.4.6, „Vorsichtsmaßnahmen bei benutzerdefinierten Funktionen (UDF)“.

  • --ansi

    Verwendet die ANSI-konforme SQL-Standardsyntax (statt der MySQL-Syntax). Für eine genauere Steuerung des SQL-Modus des Servers verwenden Sie stattdessen die Option --sql-mode. Siehe auch Abschnitt 1.9.3, „MySQL im ANSI-Modus laufen lassen“, und Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  • --basedir=path, -b path

    Der Pfad zum MySQL-Installationsverzeichnis. Normalerweise werden alle Pfad relativ zu diesem Verzeichnis aufgelöst.

  • --bind-address=IP

    Die IP-Adresse, zu der eine Bindung hergestellt wird.

  • --binlog-format={row|statement}

    Gibt an, ob die datensatz- oder die anweisungsbasierte Replikation verwendet werden soll (die anweisungsbasierte Replikation ist die Vorgabe). Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --binlog-row-event-max-size=N

    Gibt die maximale Größe eines datensatzbasierten Binärlogereignisses in Byte an. Datensätze werden zu Ereignissen zusammengefasst, die – sofern möglich – kleiner sind als die hier angegebene Größe. Der Wert sollte ein Vielfaches von 256 sein, Standard ist 1.024. Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --both-log-formats

    Aktiviert alte und neue Logformate (Logdateien und Logtabellen). Diese Option wurde in MySQL 5.1.6 hinzugefügt.

  • --bootstrap

    Diese Option wird vom Skript mysql_install_db verwendet, um die MySQL-Berechtigungstabellen zu erstellen, ohne einen vollständigen MySQL-Server starten zu müssen.

  • --character-sets-dir=path

    Das Verzeichnis, in dem Zeichensätze installiert sind. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --character-set-client-handshake

    Zeichensatzinformationen, die vom Client übermittelt wurden, sollten nicht ignoriert werden. Um die Clientangaben zu ignorieren und den Standardzeichensatz des Servers zu benutzen, verwenden Sie --skip-character-set-client-handshake. In diesem Fall verhält sich MySQL wie MySQL 4.0.

  • --character-set-filesystem=charset_name

    Der Zeichensatz des Dateisystems. Diese Option wurde in MySQL 5.1.6 hinzugefügt.

  • --character-set-server=charset_name, -C charset_name

    Verwendet charset_name als Standardzeichensatz am Server. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --chroot=path

    Versetzt den Server mysqld während des Starts mithilfe des Systemaufrufs chroot() in eine geschlossene Umgebung. Dies ist eine empfohlene Sicherheitsmaßnahme. Beachten Sie, dass durch Verwendung dieser Option LOAD DATA INFILE und SELECT ... INTO OUTFILE in geringem Maße eingeschränkt werden.

  • --collation-server=collation_name

    Verwendet collation_name als Standardsortierung auf dem Server. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --console

    (Nur für Windows.) Schreibt Fehlerlogmeldungen auch dann in stderr und stdout, wenn --log-error angegeben ist. Wenn diese Option verwendet wird, schließt mysqld das Konsolenfenster nicht.

  • --core-file

    Schreibt eine Speicherauszugsdatei, wenn mysqld sich aufhängt. Bei einigen Systemen müssen Sie zusätzlich die Option --core-file-size für mysqld_safe angeben. Siehe auch Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“. Beachten Sie, dass auf manchen Systemen (z. B. Solaris) keine Speicherauszugsdateien geschrieben werden, wenn gleichzeitig die Option --user verwendet wird.

  • --datadir=path, -h path

    Der Pfad zum Datenverzeichnis.

  • --debug[=debug_options], -# [debug_options]

    Wird MySQL mit der Option --with-debug konfiguriert, dann können Sie mithilfe dieser Option eine Trace-Datei mit Angaben dazu erstellen, was mysqld tut. Der String debug_options heißt häufig 'd:t:o,file_name'. Standardwert ist 'd:t:i:o,mysqld.trace'. Siehe auch Abschnitt E.1.2, „Trace-Dateien erzeugen“.

  • --default-character-set=charset_name (AUSLAUFEND)

    Verwendet charset_name als Standardzeichensatz. Diese Option läuft zugunsten von --character-set-server aus. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --default-collation=collation_name

    Verwendet collation_name als Standardsortierung. Diese Option läuft zugunsten von --collation-server aus. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --default-storage-engine=type

    Stellt die standardmäßige Speicher-Engine für Tabellen ein. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

  • --default-table-type=type

    Diese Option ist synonym zu --default-storage-engine.

  • --default-time-zone=timezone

    Stellt die Standardzeitzone des Servers ein. Diese Option stellt die globale Systemvariable time_zone ein. Wird die Option nicht angegeben, dann ist die Standardzeitzone mit der Systemzeitzone identisch (diese wird durch den Wert der Systemvariablen system_time_zone bestimmt).

  • --delay-key-write[= OFF | ON | ALL]

    Legt fest, wie verzögerte Schlüsselschreiboperationen gehandhabt werden. Das verzögerte Schreiben von Schlüsseln sorgt dafür, dass Schlüsselpuffer zwischen einzelnen Schreibvorgängen für MyISAM-Tabellen neu geladen werden. OFF deaktiviert das verzögerte Schreiben von Schlüsseln, während ON es für jene Tabellen aktiviert, die mit der Option DELAY_KEY_WRITE erstellt worden sind. ALL schließlich verzögert das Schreiben der Schlüssel für alle MyISAM-Tabellen. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“, und Abschnitt 14.1.1, „MyISAM-Startoptionen“.

    Hinweis: Wenn Sie diese Variable auf ALL setzen, sollten Sie MyISAM-Tabellen nicht aus einem anderen Programm (z. B. einem anderen MySQL-Server oder myisamchk) heraus verwenden, wenn diese Tabellen bereits in Benutzung sind. Andernfalls können Indizes beschädigt werden.

  • --des-key-file=file_name

    Liest den DES-Standardschlüssel aus der angegebenen Datei aus. Diese Schlüssel werden von den Funktionen DES_ENCRYPT() und DES_DECRYPT() verwendet.

  • --enable-named-pipe

    Aktiviert die Unterstützung für Named Pipes. Diese Option betrifft nur Systeme unter Windows NT/2000/XP/2003 und kann nur für die Server mysqld-nt und mysqld-max-nt benutzt werden, die Named-Pipe-Verbindungen benutzen.

  • --event-scheduler

    Aktiviert den Ereignisplaner. Diese Option wurde in MySQL 5.1.6 hinzugefügt.

  • --exit-info[=flags], -T [flags]

    Dies ist eine Bitmaske mit verschiedenen Flags, die Sie zum Debugging des Servers mysqld verwenden können. Verwenden Sie diese Option nur, wenn Sie genau wissen, was sie tut!

  • --external-locking

    Aktiviert die externe Sperrung (Systemsperrung). Diese ist seit MySQL 4.0 standardmäßig deaktiviert. Beachten Sie, dass, wenn Sie diese Option auf einem System verwenden, auf dem lockd nicht vollständig funktioniert (z. B. unter Linux), mysqld vollständig gesperrt werden kann. Diese Option hieß früher --enable-locking.

    Hinweis: Wenn Sie diese Option verwenden, um das Aktualisieren von MyISAM-Tabellen durch mehrere MySQL-Prozesse zu ermöglichen, dann müssen Sie sicherstellen, dass die folgenden Bedingungen erfüllt sind:

    • Sie sollten den Abfrage-Cache nicht für Abfragen benutzen, die Tabellen verwenden, welche durch einen anderen Prozess aktualisiert werden.

    • Sie sollten --delay-key-write=ALL oder DELAY_KEY_WRITE=1 nicht bei gemeinsam genutzten Tabellen einsetzen.

    Die einfachste Möglichkeit, dies zu gewährleisten, besteht darin, --external-locking immer zusammen mit --delay-key-write=OFF und --query-cache-size=0 zu benutzen. (Dies wird standardmäßig nicht gemacht, weil es in vielen Konfigurationen nützlich ist, eine Mischung der vorangegangenen Optionen einzusetzen.)

  • --flush

    Schreibt nach jeder SQL-Anweisung alle Änderungen neu auf die Festplatte (Synchronisierung). Normalerweise schreibt MySQL alle Änderungen erst nach der jeweiligen SQL-Anweisung auf die Festplatte und überlässt dem Betriebssystem die Festplattensynchronisierung. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

  • --init-file=file

    Liest beim Start SQL-Anweisungen aus der angegebenen Datei aus. Jede Anweisung muss in einer eigenen Zeile stehen und darf keine Kommentare enthalten.

  • --innodb-xxx

    Die InnoDB-Optionen sind in Abschnitt 14.2.4, „InnoDB: Startoptionen und Systemvariablen“, beschrieben.

  • --language=lang_name, -L lang_name

    Gibt Clientfehlermeldungen in der angegebenen Sprache zurück. lang_name kann als Sprachname oder als vollständiger Pfadname zu dem Verzeichnis angegeben werden, in dem die Sprachdateien installiert sind. Siehe auch Abschnitt 5.11.2, „Nicht englische Fehlermeldungen“.

  • --large-pages

    Einige Hardware- und Betriebssystemarchitekturen unterstützen Speicherseiten, die größer als der Standardwert (normalerweise 4 Kbyte) sind. Die eigentliche Implementierung dieser Unterstützung hängt von der zugrundeliegenden Hardware und dem Betriebssystem ab. Anwendungen, die häufig auf den Speicher zugreifen, können leistungsseitig von der Verwendung großer Seiten profitieren, da die Anzahl von TLB-Fehlschlägen (Translation Lookaside Buffer, Übersetzungspuffer) verringert wird.

    Zurzeit unterstützt MySQL nur die Linux-Implementierung der Unterstützung für große Seiten (diese heißt in Linux HugeTLB). Wir beabsichtigen, diese Unterstützung auf FreeBSD, Solaris und möglicherweise auch andere Plattformen auszudehnen.

    Bevor unter Linux große Seiten verwendet werden können, ist es notwendig, den HugeTLB-Speicherpool zu konfigurieren. Hinweise hierzu entnehmen Sie der Datei hugetlbpage.txt im Linux-Kernel-Quellcode.

    Die Option ist standardmäßig deaktiviert.

  • --log[=file_name], -l [file_name]

    Verbindungen und SQL-Anweisungen, die von Clients empfangen werden, werden in dieser Datei protokolliert. Siehe auch Abschnitt 5.12.2, „Die allgemeine Anfragen-Logdatei“. Wenn Sie den Dateinamen weglassen, verwendet MySQL host_name.log als Dateinamen.

  • --log-bin=[base_name]

    Aktiviert das binäre Loggen. Der Server loggt alle datenändernden Anweisungen in das Binärlog, welches für Sicherungs- und Replikationszwecke verwendet wird. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

    Sofern angegeben, ist der Optionswert der Basisname der Logabfolge. Der Server erstellt Binärlogs in einer Abfolge und fügt dabei an den Basisnamen jeweils ein numerisches Suffix an. Die Angabe eines Basisnamens wird empfohlen (siehe Abschnitt A.8.1, „Offene Probleme in MySQL“ zu den Gründen). Andernfalls verwendet MySQL host_name-bin als Basisnamen.

  • --log-bin-index[=file_name]

    Dies ist die Indexdatei für Dateinamen von Binärlogs. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“. Wenn Sie den Dateinamen weglassen und auch mit --log-bin keinen Namen festgelegt haben, verwendet MySQL host_name-bin.index als Dateinamen.

  • --log-bin-trust-function-creators[={0|1}]

    Ohne Argument oder mit dem Argument 1 setzt diese Option die Systemvariable log_bin_trust_function_creators auf 1. Wird als Argument 0 übergeben, dann wird die Systemvariable auf 0 gesetzt. log_bin_trust_function_creators beeinflusst, wie MySQL Beschränkungen für die Erstellung gespeicherter Funktionen durchsetzt. Siehe auch Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“.

  • --log-error[=file_name]

    Fehler- und Startmeldungen werden in der genannten Datei protokolliert. Siehe auch Abschnitt 5.12.1, „Die Fehler-Logdatei“. Wenn Sie den Dateinamen weglassen, verwendet MySQL host_name.err. Hat der Dateiname keine Erweiterung, dann fügt der Server die Erweiterung .err hinzu.

  • --log-isam[=file_name]

    Protokolliert alle MyISAM-Änderungen an dieser Datei (wird nur zum MyISAM-Debugging verwendet).

  • --log-long-format (AUSLAUFEND)

    Schreibt Zusatzinformationen in das Update-Log, das Binärlog und das Log für langsame Abfragen, sofern diese aktiviert sind. So werden etwa der Benutzername und ein Zeitstempel für alle Abfragen protokolliert. Diese Option läuft aus, da sie mittlerweile das Standardverhalten beim Loggen darstellt. (Siehe Beschreibung zu --log-short-format.) Die Option --log-queries-not-using-indexes dient dem Loggen von Abfragen, die keine Indizes verwenden, in das Log für langsame Abfragen.

  • --log-queries-not-using-indexes

    Wenn Sie diese Option in Verbindung mit --log-slow-queries verwenden, werden Abfragen, die keine Indizes verwenden, in das Log für langsame Abfragen geschrieben. Siehe auch Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“.

  • --log-short-format

    Protokolliert weniger Informationen in das Update-Log, das Binärlog und das Log für langsame Abfragen, sofern diese aktiviert sind. So werden etwa weder Benutzername noch ein Zeitstempel für Abfragen protokolliert.

  • --log-slow-admin-statements

    Protokolliert administrative Anweisungen wie OPTIMIZE TABLE, ANALYZE TABLE und ALTER TABLE in das Log für langsame Abfragen.

  • --log-slow-queries[=file_name]

    Protokolliert alle Abfragen, deren Ausführung mehr als long_query_time Sekunden gedauert hat, in die angegebene Datei. Siehe auch Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“. Details finden Sie in den Beschreibungen zu den Optionen --log-long-format und --log-short-format.

  • --log-warnings, -W

    Schreibt Warnungen wie Aborted connection... in das Fehlerlog. Die Aktivierung dieser Option wird beispielsweise empfohlen, wenn Sie die Replikation verwenden. (Sie erhalten dann mehr Informationen zu den ablaufenden Vorgängen, z. B. Netzwerkausfälle und Neuverbindungen.) Die Option ist standardmäßig aktiviert. Sie können sie mithilfe von --skip-log-warnings deaktivieren. Unterbrochene Verbindungen werden nicht in das Fehlerlog protokolliert, sofern der Wert größer als 1 ist. Siehe auch Abschnitt A.2.10, „Kommunikationsfehler/abgebrochene Verbindung“.

  • --low-priority-updates

    Gibt tabellenändernden Operationen (INSERT, REPLACE, DELETE, UPDATE) eine niedrigere Priorität als Auswahloperationen. Dies kann auch via {INSERT | REPLACE | DELETE | UPDATE} LOW_PRIORITY ... erfolgen, um die Priorität nur einer Abfrage zu verringern. Die Priorität eines Threads können Sie mit SET LOW_PRIORITY_UPDATES=1 verringern. Siehe auch Abschnitt 7.3.2, „Themen, die Tabellensperren betreffen“.

  • --memlock

    Sperrt den mysqld-Prozess im Speicher. Dies funktioniert auf Systemen wie Solaris, die den Systemaufruf mlockall() unterstützen. Die Option kann hilfreich sein, wenn ein Problem auftritt, bei dem das Betriebssystem eine Auslagerung von mysqld auf die Festplatte verursacht. Beachten Sie, dass die Verwendung dieser Option eine Ausführung des Servers als root erfordert, wovon in der Regel aus Sicherheitsgründen abzuraten ist. Siehe auch Abschnitt 5.7.5, „Wie man MySQL als normaler Benutzer laufen läßt“.

  • --myisam-recover [=option[,option]...]]

    Stellt den Wiederherstellungsmodus der MyISAM-Speicher-Engine ein. Der Optionswert ist eine beliebige Kombination der Werte DEFAULT, BACKUP, FORCE oder QUICK. Wenn Sie mehrere Werte angeben, trennen Sie sie durch Kommata. Sie können auch den Wert "" angeben, um die Option zu deaktivieren. Wird die Option verwendet, dann prüft mysqld bei jedem Öffnen einer MyISAM-Tabelle, ob diese als abgestürzt gekennzeichnet ist oder beim letzten Mal nicht korrekt geschlossen wurde. (Die zweite Option funktioniert nur, wenn die Ausführung mit deaktivierter externer Sperrung erfolgt.) In diesem Fall führt mysqld eine Überprüfung der Tabelle durch. Ist die Tabelle tatsächlich beschädigt, dann versucht mysqld sie zu reparieren.

    Die folgenden Optionen beeinflussen die Ausführung der Reparatur:

    OptionBeschreibung
    DEFAULTIst identisch mit der Nichtangabe von Optionen für --myisam-recover.
    BACKUPSpeichert, wenn die Datendatei während der Wiederherstellung geändert wurde, eine Sicherungskopie der Datei tbl_name.MYD als tbl_name-datetime.BAK.
    FORCEFührt die Wiederherstellung auch dann durch, wenn dadurch mehr als nur ein Datensatz in der .MYD-Datei verloren geht.
    QUICKÜberprüft die Datensätze in der Tabelle nicht, wenn keine Löschblöcke vorhanden sind.

    Bevor der Server eine Tabelle automatisch repariert, schreibt er einen Hinweis zur Reparatur in das Fehlerlog. Wollen Sie die meisten Probleme durch eine Wiederherstellung ohne Benutzereingriff beseitigen, dann sollten Sie die Optionen BACKUP,FORCE angeben. Hierdurch wird die Reparatur der Tabelle auch dann erzwungen, wenn mehrere Datensätze gelöscht würden; gleichzeitig wird aber die alte Datendatei als Sicherungskopie vorgehalten, sodass Sie später untersuchen können, was passiert ist.

    Siehe auch Abschnitt 14.1.1, „MyISAM-Startoptionen“.

  • --ndb-connectstring=connect_string

    Wenn Sie die NDB-Speicher-Engine verwenden, können Sie den Managementserver angeben, der die Clusterkonfiguration verteilt. Dies tun Sie durch Einstellung der Option --ndb-connectstring. Informationen zur Syntax finden Sie in Abschnitt 16.4.4.2, „MySQL Cluster: connectstring.

  • --ndbcluster

    Wenn die Binärdatei eine Unterstützung der NDB Cluster-Speicher-Engine enthält, aktiviert diese Option die Engine (diese ist standardmäßig deaktiviert). Siehe auch Kapitel 16, MySQL Cluster.

  • --old-log-format

    Aktiviert nur das alte Logformat. Hierdurch werden Logtabellen und die SELECT-Funktionalität für Loginhalte deaktiviert. Diese Option wurde in MySQL 5.1.6 hinzugefügt.

  • --old-passwords

    Erzwingt die Erzeugung kurzer Passwort-Hashes (wie vor Version 4.1) auch für neue Passwörter. Dies kann zu Kompatibilitätszwecken erforderlich sein, wenn der Server ältere Clientprogramme unterstützen muss. Siehe auch Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“.

  • --one-thread

    Verwendet nur einen Thread (zum Debuggen unter Linux). Diese Option ist nur verfügbar, wenn der Server mit aktiviertem Debugging erstellt wurde. Siehe auch Abschnitt E.1, „Einen MySQL-Server debuggen“.

  • --open-files-limit=count

    Ändert die Anzahl der für mysqld verfügbaren Dateideskriptoren. Wenn diese Option nicht oder auf 0 gesetzt ist, verwendet mysqld den Wert, um Dateideskriptoren mit setrlimit() zu reservieren. Ist der Wert hingegen 0, dann reserviert mysqld max_connections×5 oder max_connections + table_open_cache×2 Dateien (je nachdem, welcher Wert höher ist). Versuchen Sie, diesen Wert zu erhöhen, wenn mysqld die Fehlermeldung Too many open files ausgibt.

  • --pid-file=path

    Der Pfadname der Prozesskennungsdatei. Diese Datei wird von anderen Programmen wie mysqld_safe verwendet, um die Prozesskennung des Servers zu bestimmen.

  • --port=port_num, -P port_num

    Die Portnummer, die beim Horchen auf TCP/IP-Verbindungen verwendet wird. Die Portnummer muss 1024 oder höher sein, sofern der Server nicht vom Systembenutzer root gestartet wird.

  • --port-open-timeout=num

    Bei manchen Systemen wird, wenn der Server beendet wird, der TCP/IP-Port unter Umständen nicht mehr verfügbar gemacht. Wenn der Server kurz darauf neu gestartet wird, kann der Versuch fehlschlagen, den Port neu zu öffnen. Diese Option gibt an, wie viele Sekunden der Server warten soll, bis der TCP/IP-Port wieder frei wird, sofern er nicht geöffnet werden kann. Standardmäßig gibt es keine Wartezeit. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --safe-mode

    Überspringt einige Optimierungsstufen.

  • --safe-show-database (AUSLAUFEND)

    Siehe auch Abschnitt 5.8.3, „Von MySQL zur Verfügung gestellte Berechtigungen“.

  • --safe-user-create

    Wenn diese Option aktiviert ist, kann ein Benutzer mit der GRANT-Anweisung keine neuen MySQL-Benutzer erstellen, wenn er für die Tabelle mysql.user oder eine der Spalten in dieser Tabelle nicht die Berechtigung INSERT hat.

  • --secure-auth

    Unterbindet die Authentifizierung von Clients, die Konten mit alten Passwörtern (vor Version 4.1) zu verwenden versuchen.

  • --shared-memory

    Aktiviert Verbindungen mit gemeinsamem Speicher durch lokale Clients. Diese Option ist nur unter Windows verfügbar.

  • --shared-memory-base-name=name

    Der Name des gemeinsamen Speichers, der für Verbindungen mit gemeinsamem Speicher verwendet werden soll. Diese Option ist nur unter Windows verfügbar. Der Standardname ist MYSQL. Beim Namen wird die Groß-/Kleinschreibung unterschieden.

  • --skip-bdb

    Deaktiviert die BDB-Speicher-Engine. Hierdurch wird Speicher gespart, ferner werden einige Operationen beschleunigt. Verwenden Sie die Option nicht, wenn Sie BDB-Tabellen benötigen.

  • --skip-concurrent-insert

    Schaltet die Möglichkeit ab, bei MyISAM-Tabellen gleichzeitig auszuwählen und einzufügen. (Diese Option sollte nur verwendet werden, wenn Sie das Gefühl haben, einen Bug in dieser Funktion gefunden zu haben.)

  • --skip-external-locking

    Eine externe Sperrung (Systemsperrung) wird nicht verwendet. Bei deaktivierter externer Sperrung müssen Sie den Server herunterfahren, um myisamchk verwenden zu können. (Siehe auch Abschnitt 1.4.3, „Wie stabil ist MySQL?“.) Um diese Anforderung zu umgehen, verwenden Sie die Anweisungen CHECK TABLE und REPAIR TABLE zur Überprüfung und Reparatur von MyISAM-Tabellen.

    Die externe Sperrung wird seit MySQL 4.0 standardmäßig deaktiviert.

  • --skip-grant-tables

    Diese Option sorgt dafür, dass der Server das Berechtigungssystem überhaupt nicht verwendet. Hierdurch erhalten alle Benutzer, die auf den Server zugreifen können, uneingeschränkten Zugang zu allen Datenbanken. Sie können einen laufenden Server dazu bringen, die Grant-Tabellen wieder zu verwenden, indem Sie mysqladmin flush-privileges oder mysqladmin reload über die System-Shell ausführen oder die MySQL-Anweisung FLUSH PRIVILEGES nach Herstellen einer Verbindung zum Server absetzen. Diese Option unterbindet auch das Laden von Plug-Ins und benutzerdefinierten Funktionen (UDFs).

  • --skip-host-cache

    Der interne Hostnamencache wird nicht zur schnelleren Namensauflösung verwendet. Stattdessen wird bei jeder Verbindungsherstellung durch einen Client der DNS-Server abgefragt. Siehe auch Abschnitt 7.5.6, „Wie MySQL DNS benutzt“.

  • --skip-innodb

    Deaktiviert die InnoDB-Speicher-Engine. Hierdurch wird Speicher und Festplattenkapazität gespart, ferner werden einige Operationen beschleunigt. Verwenden Sie die Option nicht, wenn Sie InnoDB-Tabellen benötigen.

  • --skip-name-resolve

    Bei der Überprüfung von Clientverbindungen werden Hostnamen nicht aufgelöst. Es werden ausschließlich IP-Nummern verwendet. Wenn Sie diese Option verwenden, müssen alle Werte in der Spalte Host der Grant-Tabellen IP-Nummern oder localhost sein. Siehe auch Abschnitt 7.5.6, „Wie MySQL DNS benutzt“.

  • --skip-ndbcluster

    Deaktiviert die NDB Cluster-Speicher-Engine. Dies ist die Standardeinstellung bei Binärdistributionen, die mit Unterstützung für die NDB Cluster-Speicher-Engine erstellt wurden. Der Server reserviert dieser Speicher-Engine nur dann Speicher und andere Ressourcen, wenn die Option --ndbcluster explizit angegeben wird. Ein Anwendungsbeispiel finden Sie in Abschnitt 16.4.3, „Schnelle Testeinrichtung von MySQL Cluster“.

  • --skip-networking

    Unterbindet das Horchen auf TCP/IP-Verbindungen ganz. Die gesamte Interaktion mit mysqld muss über Named Pipes oder gemeinsamen Speicher (unter Windows) bzw. Unix-Socketdateien (unter Unix) erfolgen. Diese Option ist für Systeme, bei denen nur lokale Clients zulässig sind, sehr empfehlenswert. Siehe auch Abschnitt 7.5.6, „Wie MySQL DNS benutzt“.

  • --standalone

    Nur unter Windows NT-basierten Systemen vorhanden. Die Option weist den MySQL-Server an, nicht als Dienst ausgeführt zu werden.

  • --symbolic-links, --skip-symbolic-links

    Aktiviert bzw. deaktiviert die Unterstützung für symbolische Verknüpfungen. Die Option hat unter Windows und Unix unterschiedliche Auswirkungen:

    • Unter Windows erlaubt Ihnen die Aktivierung symbolischer Verknüpfungen die Einrichtung einer solchen Verknüpfung zu einem Datenbankverzeichnis durch Erstellen einer Datei db_name.sym, die den Pfad zum echten Verzeichnis enthält. Siehe auch Abschnitt 7.6.1.3, „Daten unter Windows auf verschiedene Platten aufteilen“.

    • Unter Unix hat die Aktivierung symbolischer Verknüpfungen zur Folge, dass Sie eine MyISAM-Index- oder -Datendatei mit einem anderen Verzeichnis verknüpfen können. Diese Verknüpfung erfolgt mit den Optionen INDEX DIRECTORY oder DATA DIRECTORY der CREATE TABLE-Anweisung. Wenn Sie die Tabelle löschen oder umbenennen, werden die Dateien, auf die die symbolischen Verknüpfungen verweisen, ebenfalls gelöscht bzw. umbenannt. Siehe auch Abschnitt 7.6.1.2, „Benutzung symbolischer Links für Tabellen“.

  • --skip-safemalloc

    Wenn MySQL mit der Option --with-debug=full konfiguriert wird, prüfen alle MySQL-Programme bei jedem Speicherzuweisungs- und -freigabevorgang auf Speicherüberläufe. Diese Überprüfung erfolgt recht langsam, weswegen Sie sie für den Server mithilfe der Option --skip-safemalloc umgehen sollten, wenn Sie sie nicht brauchen.

  • --skip-show-database

    Bei dieser Option darf die SHOW DATABASES-Anweisung nur von Benutzern verwendet werden, die die Berechtigung SHOW DATABASES haben. Die Anweisung zeigt dann alle Datenbanknamen an. Ohne diese Option dürfen alle Benutzer SHOW DATABASES verwenden, aber die Datenbanknamen werden nur angezeigt, wenn der Benutzer die Berechtigung SHOW DATABASES oder spezifische Berechtigungen für eine Datenbank hat. Beachten Sie, dass jede globale Berechtigung als Berechtigung für die Datenbank betrachtet wird.

  • --skip-stack-trace

    Stapel-Trace-Dateien werden nicht geschrieben. Diese Option ist praktisch, wenn Sie mysqld unter einem Debugger ausführen. Bei manchen Systemen müssen Sie die Option auch verwenden, um eine Speicherauszugsdatei zu erhalten. Siehe auch Abschnitt E.1, „Einen MySQL-Server debuggen“.

  • --skip-thread-priority

    Deaktiviert die Verwendung von Thread-Prioritäten für eine schnellere Antwortzeit.

  • --socket=path

    Unter Unix gibt diese Option die Unix-Socketdatei an, die beim Horchen nach lokalen Verbindungen verwendet werden soll. Der Vorgabewert ist /tmp/mysql.sock. Unter Windows legt die Option den Pipe-Namen fest, der beim Horchen nach lokalen Verbindungen verwendet werden soll, die eine Named Pipe nutzen. Der Vorgabewert ist MySQL (keine Unterscheidung der Groß-/Kleinschreibung).

  • --sql-mode=value[,value[,value...]]

    Stellt den SQL-Modus ein. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  • --temp-pool

    Diese Option sorgt dafür, dass die meisten vom Server erstellten Temporärdateien eine kleine Menge von Namen nutzt (statt dass ein eindeutiger Name für jede neue Datei erstellt wird). Hierdurch wird ein Problem umgangen, dass der Linux-Kernel mit der Erstellung vieler neuer Dateien mit unterschiedlichen Namen hat. Beim ursprünglichen Verhalten scheint Linux ein „Speicherleck“ aufzuweisen, da der Speicher nicht dem Festplattencache, sondern dem Verzeichniseintragscache zugewiesen wird.

  • --transaction-isolation=level

    Stellt die Standardstufe für die Transaktionsisolierung ein. Der Wert level kann READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ oder SERIALIZABLE sein. Siehe auch Abschnitt 13.4.6, „SET TRANSACTION.

  • --tmpdir=path, -t path

    Der Pfad des Verzeichnisses, in dem Temporärdateien erstellt werden. Die Option kann nützlich sein, wenn Ihr /tmp-Standardverzeichnis auf einer Partition liegt, die zu klein für die Aufnahme temporärer Tabellen ist. Die Option akzeptiert mehrere Pfade, die zyklisch abwechselnd verwendet werden. Pfade sollten unter Unix durch Doppelpunkte (‘:’) und unter Windows, NetWare und OS/2 durch Semikola (‘;’) getrennt werden. Wenn der MySQL-Server als Replikations-Slave agiert, sollten Sie die Option --tmpdir nicht auf ein Verzeichnis auf einem speicherbasierten Dateisystem oder aber ein Verzeichnis verweisen lassen, welches gelöscht wird, wenn der Serverhost neu gestartet wird. Weitere Informationen zur Speicherposition temporärer Dateien finden Sie in Abschnitt A.4.4, „Wohin MySQL temporäre Dateien speichert“. Ein Replikations-Slave benötigt einen Teil seiner Temporärdateien, um einen Systemneustart so zu überstehen, dass er Temporärtabellen oder LOAD DATA INFILE-Operationen replizieren kann. Wenn Dateien in im Verzeichnis für Temporärdateien beim Serverneustart verloren gehen, schlägt die Replikation fehl.

  • --user={user_name | user_id}, -u {user_name | user_id}

    Führt den Server mysqld als Benutzer mit dem spezifizierten Benutzernamen (user_name) oder der numerischen Benutzerkennung (user_id) aus. („Benutzer“ bezeichnet in diesem Kontext ein Systemanmeldekonto und keinen in den Grant-Tabellen aufgeführten MySQL-Benutzer.)

    Diese Option zwingend erforderlich, wenn Sie mysqld als root starten. Der Server wechselt seine Benutzerkennung während der Startsequenz und wird dann als der angegebene Benutzer statt als root ausgeführt. Siehe auch Abschnitt 5.7.1, „Allgemeine Sicherheitsrichtlinien“.

    Um eine potenzielle Sicherheitslücke zu vermeiden, wenn ein Benutzer die Option --user=root in einer Datei my.cnf hinzufügt (und auf diese Weise eine Ausführung des Servers als root veranlasst), verwendet mysqld nur die erste angegebene Option --user und erzeugt eine Warnung, wenn mehrere --user-Optionen vorhanden sind. Optionen in /etc/my.cnf und $MYSQL_HOME/my.cnf werden vor eventuellen Befehlszeilenoptionen verarbeitet, weswegen empfohlen wird, eine Option --user in /etc/my.cnf einzufügen und dort einen anderen Wert als root anzugeben. Die Option in /etc/my.cnf wird vor allen anderen --user-Optionen gefunden; hierdurch ist sichergestellt, dass der Server als ein anderer Benutzer als root ausgeführt und eine Warnung erzeugt wird, wenn eine andere --user- Option gefunden wird.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

Sie können einer Serversystemvariablen einen Wert zuweisen, indem Sie eine Option der Form --var_name=value verwenden. So setzt beispielsweise --key_buffer_size=32M die Variable key_buffer_size auf einen Wert von 32 Mbyte.

Beachten Sie, dass, wenn Sie einer Variablen einen Wert zuweisen, MySQL diesen ggf. automatisch so korrigiert, dass er innerhalb eines gegebenen Bereichs bleibt, oder den Wert auf den nächstgelegenen zulässigen Wert setzt, sofern nur bestimmte Werte gestattet sind.

Wenn Sie den Höchstwert, auf den eine Variable zur Laufzeit mit SET gesetzt werden kann, beschränken wollen, definieren Sie dies unter Verwendung der Befehlszeileoption --maximum-var_name.

Es ist ferner möglich, Variablen über die Syntax --set-variable=var_name=value oder -O var_name=value einzustellen. Diese Syntax läuft jedoch aus.

Sie können die Werte der meisten Systemvariablen für einen laufenden Server mit der Anweisung SET ändern. Siehe auch Abschnitt 13.5.3, „SET.

Abschnitt 5.2.2, „Server-Systemvariablen“, bietet eine vollständige Beschreibung aller Variablen sowie weitere Informationen zu deren Einstellung beim Serverstart und zur Laufzeit. Abschnitt 7.5.2, „Serverparameter feineinstellen“, enthält Informationen zur Optimierung des Servers durch gezielte Einstellung der Systemvariablen.

5.2.2. Server-Systemvariablen

Der Server mysql verwaltet eine ganze Reihe von Systemvariablen, die angeben, wie er konfiguriert ist. Für alle diese Variablen gibt es Vorgabewerte. Diese können beim Serverstart über Optionen auf der Befehlszeile oder in Optionsdateien eingestellt werden. Die meisten Variablen lassen sich zur Laufzeit des Servers dynamisch mithilfe der SET-Anweisung ändern; auf diese Weise können Sie den Betrieb des Servers beeinflussen, ohne ihn beenden und neu starten zu müssen. Ferner können Sie die Werte auch in Ausdrücken verwenden.

Durch Absetzen der SHOW VARIABLES-Anweisung können Sie die Namen und Werte der Systemvariablen auflisten lassen.

Die meisten Systemvariablen werden an dieser Stelle beschrieben. Variablen, bei denen keine Version angegeben ist, sind in allen Releases von MySQL 5.1 vorhanden. Historische Informationen zu ihrer Implementierung finden Sie im MySQL 5.0 Reference Manual und im MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1.

Hinweise zur Syntax bei der Einstellung und Anzeige von Werten von Systemvariablen finden Sie in Abschnitt 5.2.3, „Verwendung von Server-Systemvariablen“. Abschnitt 5.2.3.2, „Dynamische Systemvariablen“, listet die Variablen auf, die zur Laufzeit eingestellt werden können. Abschnitt 14.2.4, „InnoDB: Startoptionen und Systemvariablen“, listet InnoDB-Systemvariablen auf. Informationen zur Optimierung der Systemvariablen sind in Abschnitt 7.5.2, „Serverparameter feineinstellen“, enthalten.

Hinweis: Verschiedene Systemvariablen lassen sich mit der Anweisung SET aktivieren, indem sie auf ON bzw. 1 gesetzt werden. Ähnlich können Sie sie mit SET deaktivieren, indem Sie sie auf OFF bzw. 0 setzen. Um solche Variablen über die Befehlszeile oder in Optionsdateien einstellen zu können, müssen Sie sie auf 1 oder 0 setzen (d. h. die Einstellungen ON und OFF funktionieren nicht). So führt beispielsweise auf der Befehlszeile die Option --delay_key_write=1 zum gewünschten Ergebnis – anders als --delay_key_write=ON.

Werte für Puffergrößen, Längen und Stapelgrößen sind in Byte angegeben, sofern nichts anderes festgelegt ist.

  • auto_increment_increment

    auto_increment_increment und auto_increment_offset sind zur Verwendung bei der Master-to-Master-Replikation vorgesehen und können zur Steuerung des Betriebs von AUTO_INCREMENT-Spalten eingesetzt werden. Beide Variablen können global oder lokal eingestellt werden und jeweils einen Integer-Wert zwischen 1 und 65.535 einnehmen. Wenn eine dieser Variablen auf 0 gesetzt wird, wird der Wert automatisch auf 1 umgestellt. Der Versuch, ihnen einen ganzzahligen Wert größer 65.535 oder kleiner 0 zuzuweisen, führt hingegen zur automatischen Zuweisung des Wertes 65.535. Sollten Sie versuchen, auto_increment_increment oder auto_increment_offset auf einen nicht ganzzahligen Wert zu stellen, dann wird eine Fehlermeldung ausgegeben, und der Wert der Variable bleibt unverändert.

    Diese beiden Variablen beeinflussen das Verhalten von AUTO_INCREMENT-Spalten wie folgt:

    • auto_increment_increment steuert das Intervall zwischen aufeinanderfolgenden Spaltenwerten. Zum Beispiel:

      mysql> SHOW VARIABLES LIKE 'auto_inc%';
      +--------------------------+-------+
      | Variable_name            | Value |
      +--------------------------+-------+
      | auto_increment_increment | 1     |
      | auto_increment_offset    | 1     |
      +--------------------------+-------+
      2 rows in set (0.00 sec)
      
      mysql> CREATE TABLE autoinc1
          -> (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
        Query OK, 0 rows affected (0.04 sec)
      
      mysql> SET @@auto_increment_increment=10;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> SHOW VARIABLES LIKE 'auto_inc%';
      +--------------------------+-------+
      | Variable_name            | Value |
      +--------------------------+-------+
      | auto_increment_increment | 10    |
      | auto_increment_offset    | 1     |
      +--------------------------+-------+
      2 rows in set (0.01 sec)
      
      mysql> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL);
      Query OK, 4 rows affected (0.00 sec)
      Records: 4  Duplicates: 0  Warnings: 0
      
      mysql> SELECT col FROM autoinc1;
      +-----+
      | col |
      +-----+
      |   1 |
      |  11 |
      |  21 |
      |  31 |
      +-----+
      4 rows in set (0.00 sec)
      

      (Beachten Sie, wie hier mithilfe von SHOW VARIABLES die aktuellen Werte dieser Variablen ermittelt werden.)

    • auto_increment_offset bestimmt den Startwert der Spalte AUTO_INCREMENT. Betrachten Sie folgendes Beispiel (hier wird davon ausgegangen, dass diese Anweisungen während derselben Sitzung ausgeführt werden, bei der auch obiges Beispiel für auto_increment_increment erstellt wurde):

      mysql> SET @@auto_increment_offset=5;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> SHOW VARIABLES LIKE 'auto_inc%';
      +--------------------------+-------+
      | Variable_name            | Value |
      +--------------------------+-------+
      | auto_increment_increment | 10    |
      | auto_increment_offset    | 5     |
      +--------------------------+-------+
      2 rows in set (0.00 sec)
      
      mysql> CREATE TABLE autoinc2
          -> (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
      Query OK, 0 rows affected (0.06 sec)
      
      mysql> INSERT INTO autoinc2 VALUES (NULL), (NULL), (NULL), (NULL);
      Query OK, 4 rows affected (0.00 sec)
      Records: 4  Duplicates: 0  Warnings: 0
      
      mysql> SELECT col FROM autoinc2;
      +-----+
      | col |
      +-----+
      |   5 |
      |  15 |
      |  25 |
      |  35 |
      +-----+
      4 rows in set (0.02 sec)
      

      Wenn der Wert von auto_increment_offset größer ist als der von auto_increment_increment, dann wird der Wert von auto_increment_offset ignoriert.

    Sollte eine dieser Variablen (oder beide) geändert werden und dann neue Datensätze in eine Tabelle mit einer AUTO_INCREMENT-Spalte eingefügt werden, dann könnten die Ergebnisse unlogisch erscheinen, da die Berechnung der AUTO_INCREMENT-Wertereihe ohne Berücksichtigung ggf. bereits in der Spalte vorhandener Werte erfolgt und der nächste eingefügte Wert der kleinste Wert in der Reihe ist, der größer ist als der größte vorhandene Wert in der AUTO_INCREMENT-Spalte. Mit anderen Worten wird die Reihe so berechnet:

    auto_increment_offset + N × auto_increment_increment

    Hierbei ist N ist ein positiver Integer-Wert in der Reihe [1, 2, 3, ...]. Zum Beispiel:

    mysql> SHOW VARIABLES LIKE 'auto_inc%';
    +--------------------------+-------+
    | Variable_name            | Value |
    +--------------------------+-------+
    | auto_increment_increment | 10    |
    | auto_increment_offset    | 5     |
    +--------------------------+-------+
    2 rows in set (0.00 sec)
    
    mysql> SELECT col FROM autoinc1;
    +-----+
    | col |
    +-----+
    |   1 |
    |  11 |
    |  21 |
    |  31 |
    +-----+
    4 rows in set (0.00 sec)
    
    mysql> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL);
    Query OK, 4 rows affected (0.00 sec)
    Records: 4  Duplicates: 0  Warnings: 0
    
    mysql> SELECT col FROM autoinc1;
    +-----+
    | col |
    +-----+
    |   1 |
    |  11 |
    |  21 |
    |  31 |
    |  35 |
    |  45 |
    |  55 |
    |  65 |
    +-----+
    8 rows in set (0.00 sec)
    

    Die für auto_increment_increment und auto_increment_offset angezeigten Werte erzeugen die Reihe 5 + N × 10, also [5, 15, 25, 35, 45, ...]. Der größte Wert, der vor der INSERT-Anweisung in der col-Spalte vorhanden ist, ist 31. Der nächste verfügbare Wert in der AUTO_INCREMENT-Reihe ist 35, d. h. die eingefügten Werte für col beginnen bei diesem Punkt; die Ergebnisse der SELECT-Abfrage sehen also so aus wie angezeigt.

    Es ist wichtig, sich zu vergegenwärtigen, dass es nicht möglich ist, die Wirkungen dieser zwei Variablen auf eine einzige Tabelle zu beschränken, weswegen sie nicht die Funktion von Folgen wahrnehmen, die einige andere Datenbanksysteme anbieten; die Variablen steuern vielmehr das Verhalten aller AUTO_INCREMENT-Spalten in allen Tabellen auf dem MySQL-Server. Wird eine dieser Variablen global eingestellt, dann wird die Wirkung aufrechterhalten, bis der globale Wert geändert oder durch eine lokale Einstellung außer Kraft gesetzt oder mysqld neu gestartet wird. Bei einer lokalen Einstellung wirkt sich der neue Wert auf die AUTO_INCREMENT in allen Tabellen aus, in die vom aktuellen Benutzer während der laufenden Sitzung neue Datensätze eingefügt werden, sofern die Werte nicht während dieser Sitzung geändert werden.

    Der Standardwert von auto_increment_increment ist 1. Siehe auch Abschnitt 6.15, „Auto-Increment in der Multi-Master-Replikation“.

  • auto_increment_offset

    Diese Variable hat den Vorgabewert 1. Besonderheiten entnehmen Sie der Beschreibung von auto_increment_increment.

  • back_log

    Dies ist die Anzahl der ausstehenden Verbindungsanforderungen, die bei MySQL zulässig sind. Die Option wird wichtig, wenn der MySQL-Haupt-Thread sehr viele Verbindungsanforderungen innerhalb kürzester Zeit erhält. Es dauert dann eine (wenn auch sehr kurze) Zeit, bis der Haupt-Thread die Verbindung geprüft und einen neuen Thread gestartet hat. Der Wert back_log gibt an, wie viele Anforderungen während dieser kurzen Zeit gestapelt werden können, bevor MySQL neue Anforderungen vorübergehend nicht mehr beantwortet. Sie müssen diesen Wert nur dann erhöhen, wenn Sie eine hohe Anzahl von Verbindungen innerhalb kurzer Zeit erwarten.

    Anders gesagt bestimmt der Wert die Größe der Horchwarteschlange für eingehende TCP/IP-Verbindungen. Ihr Betriebssystem hat eine eigene Begrenzung dieser Warteschlangengröße. Weitere Informationen hierzu sollten Sie auf der Manpage zum Unix-Systemaufruf listen() finden. Überprüfen Sie Ihre Betriebssystemdokumentation zu Angaben für den Maximalwert dieser Variablen. back_log darf nicht höher gesetzt sein als für das jeweilige Betriebssystem zulässig.

  • basedir

    Gibt das Basisverzeichnis der MySQL-Installation an. Die Variable kann mit der Option --basedir eingestellt werden.

  • bdb_cache_parts

    Die Anzahl der Teile, die für den BDB-Cache verwendet werden sollen. Wurde in MySQL 5.1.2 hinzugefügt.

  • bdb_cache_size

    Die Größe des Puffers, der für das Caching von Indizes und Datensätzen für BDB-Tabellen reserviert wird. Einige Systeme erlauben eine Einstellung dieser Variablen auf einen Wert von mehr als 4 Gbyte. Wenn Sie keine BDB-Tabellen verwenden, sollten Sie mysqld mit --skip-bdb starten, damit für diesen Cache kein Speicher reserviert wird.

  • bdb_home

    Dies ist das Basisverzeichnis für BDB-Tabellen. Hier sollte der gleiche Wert stehen wie bei der Variablen datadir.

  • bdb_log_buffer_size

    Gibt die Größe des Puffers an, der für das Caching von Indizes und Datensätzen für BDB-Tabellen reserviert wird. Wenn Sie keine BDB-Tabellen verwenden, sollten Sie hier 0 zuweisen oder mysqld mit --skip-bdb, damit für diesen Cache kein Speicher reserviert wird.

  • bdb_logdir

    Gibt das Verzeichnis an, in das die BDB-Speicher-Engine ihre Logdateien schreibt. Die Variable kann mit der Option --bdb-logdir eingestellt werden.

  • bdb_max_lock

    Die maximale Anzahl von Sperren, die für eine BDB-Tabelle aktiv sein können (standardmäßig 10.000). Sie sollten diesen Wert erhöhen, wenn bei der Durchführung langer Transaktionen oder dann, wenn mysqld viele Datensätze zur Berechnung einer Abfrage untersuchen muss, die folgende Fehlermeldung auftritt:

    bdb: Lock table is out of available locks
    Got error 12 from ...
    
  • bdb_region_size

    Die Größe des zugrundeliegenden Logbereichs der BDB-Umgebung. Dies ist die Größe des Speicherpools, der zur Aufzeichnung der in einer Transaktion verwendeten Dateinamen verwendet wird. Wurde in MySQL 5.1.2 hinzugefügt.

  • bdb_shared_data

    Ist ON, wenn Sie Berkeley DB mithilfe von --bdb-shared-data im Multiprozessmodus starten. (Verwenden Sie DB_PRIVATE nicht bei der Initialisierung von Berkeley DB.)

  • bdb_tmpdir

    Gibt das Verzeichnis für BDB-Temporärdateien an.

  • binlog_cache_size

    Gibt die Größe des Caches an, der die SQL-Anweisungen für das Binärlog während einer Transaktion aufnimmt. Ein Binärlog-Cache wird jedem Client zugewiesen, wenn der Server transaktionssichere Speicher-Engines unterstützt und an ihm das Binärlog aktiviert ist (Option --log-bin). Wenn Sie häufig umfangreiche, aus mehreren Anweisungen bestehende Transaktionen verwenden, können Sie diese Cachegröße erhöhen, um mehr Leistung zu erzielen. Die Statusvariablen Binlog_cache_use und Binlog_cache_disk_use können für die Optimierung dieser Variable nützlich sein. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

  • binlog_format

    Das Binärlogformat (entweder STATEMENT oder ROW). Diese Variable wird von der Option --binlog-format eingestellt. Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“.

  • bulk_insert_buffer_size

    MyISAM verwendet einen speziellen Cache mit Baumstruktur, um Masseneinfügeoperation für INSERT ... SELECT, INSERT ... VALUES (...), (...), ... und LOAD DATA INFILE beim Hinzufügen von Daten in nicht leere Tabellen zu beschleunigen. Diese Variable beschränkt die Größe der Cachebaumstruktur und ist in Byte pro Thread angegeben. Die Einstellung 0 deaktiviert diese Optimierung. Der Vorgabewert ist 8 Mbyte.

  • character_set_client

    Der Zeichensatz für Anweisungen, die vom Client kommend eintreffen.

  • character_set_connection

    Der Zeichensatz für Literale, die keine Zeichensatzeinführung aufweisen, und für die Umwandlung von Zahlen in Strings.

  • character_set_database

    Der von der Standarddatenbank verwendete Zeichensatz. Der Server stellt diese Variable immer dann ein, wenn die Standarddatenbank sich ändert. Ist keine Standarddatenbank vorhanden, dann hat die Variable denselben Wert wie character_set_server.

  • character_set_filesystem

    Der Zeichensatz des Dateisystems. Der Vorgabewert ist binary. Diese Variable wurde in MySQL 5.1.6 hinzugefügt.

  • character_set_results

    Der zur Rückgabe von Abfrageergebnissen an den Client verwendete Zeichensatz.

  • character_set_server

    Der Standardzeichensatz des Servers.

  • character_set_system

    Der vom Server zur Speicherung von Bezeichnern verwendete Zeichensatz. Der Wert ist immer utf8.

  • character_sets_dir

    Das Verzeichnis, in dem Zeichensätze installiert sind.

  • collation_connection

    Die Sortierung des Verbindungszeichensatzes.

  • collation_database

    Die von der Standarddatenbank verwendete Sortierung. Der Server stellt diese Variable immer dann ein, wenn die Standarddatenbank sich ändert. Ist keine Standarddatenbank vorhanden, dann hat die Variable denselben Wert wie collation_server.

  • collation_server

    Die Standardsortierung des Servers.

  • completion_type

    Der Transaktionsabschlusstyp:

    • Wenn der Wert 0 ist (Standardeinstellung), werden COMMIT und ROLLBACK nicht beeinflusst.

    • Ist der Wert 1, dann sind COMMIT und ROLLBACK äquivalent zu COMMIT AND CHAIN bzw. ROLLBACK AND CHAIN. (Eine neue Transaktion wird mit derselben Isolierungsstufe gestartet wie die unmittelbar zuvor beendete Transaktion.)

    • Ist der Wert 2, dann sind COMMIT und ROLLBACK äquivalent zu COMMIT RELEASE bzw. ROLLBACK RELEASE. (Der Server trennt die Verbindung nach Abschluss der Transaktion.)

  • concurrent_insert

    Wenn die Variable den Wert ON hat (Standardeinstellung), gestattet MySQL die nebenläufige Ausführung von INSERT- und SELECT-Anweisungen für MyISAM-Tabellen, die in der Mitte keine freien Blöcke aufweisen. Sie können diese Option deaktivieren, indem Sie mysqld mit --safe oder --skip-new starten.

    Diese Variable kann drei ganzzahlige Werte annehmen:

    WertBeschreibung
    0Die Funktion ist deaktiviert.
    1Dies ist die Standardeinstellung. Sie aktiviert nebenläufige Einfügeoperationen für MyISAM-Tabellen, die keine Lücken aufweisen.
    2Dieser Wert aktiviert nebenläufige Einfügeoperationen für alle MyISAM-Tabellen. Wenn eine Tabelle eine Lücke aufweist und gerade von einem anderen Thread verwendet wird, wird der neue Datensatz am Tabellenende eingefügt. Wird die Tabelle gerade nicht verwendet, dann setzt MySQL eine normale Lesesperre und fügt den neuen Datensatz in die Lücke ein.

    Siehe auch Abschnitt 7.3.3, „Gleichzeitige Einfügevorgänge“.

  • connect_timeout

    Zeit in Sekunden, während der der mysqld-Server auf ein Verbindungspaket wartet, bevor er mit der Meldung Bad handshake antwortet.

  • datadir

    Das MySQL-Datenverzeichnis. Die Variable kann mit der Option --datadir eingestellt werden.

  • date_format

    Diese Variable ist nicht implementiert.

  • datetime_format

    Diese Variable ist nicht implementiert.

  • default_week_format

    Standardmoduswert für die Funktion WEEK(). Siehe auch Abschnitt 12.5, „Datums- und Zeitfunktionen“.

  • delay_key_write

    Diese Option gilt nur für MyISAM-Tabellen. Sie kann einen der folgenden Werte annehmen und beeinflusst hierdurch die Wirkung der Tabellenoption DELAY_KEY_WRITE, die in CREATE TABLE-Anweisungen verwendet werden kann.

    OptionBeschreibung
    OFFDELAY_KEY_WRITE wird ignoriert.
    ONMySQL beachtet alle DELAY_KEY_WRITE-Optionen, die in CREATE TABLE-Anweisungen angegeben sind. Dies ist der Standardwert.
    ALLAlle neu geöffneten Tabellen werden so behandelt, als ob sie mit aktivierter Option DELAY_KEY_WRITE erstellt worden wären.

    Wenn DELAY_KEY_WRITE für eine Tabelle aktiviert ist, wird der Schlüsselpuffer der Tabelle nicht bei jeder Indexaktualisierung, sondern nur dann neu geschrieben, wenn die Tabelle geschlossen wird. Hierdurch werden Schreiboperationen für Schlüssel erheblich beschleunigt. Wenn Sie diese Funktion nutzen, sollten Sie jedoch eine automatische Überprüfung aller MyISAM-Tabellen ergänzen, indem Sie den Server mit der Option --myisam-recover starten (beispielsweise --myisam-recover=BACKUP,FORCE). Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld, und Abschnitt 14.1.1, „MyISAM-Startoptionen“.

    Beachten Sie, dass die Aktivierung der externen Sperrung mit --external-locking keinen Schutz gegen die Beschädigung von Indizes gewährleistet, deren Tabellen das verzögerte Schreiben von Schlüsseln verwenden.

  • delayed_insert_limit

    Nach dem Einfügen von mit delayed_insert_limit verzögerten Datensätzen überprüft der Handler INSERT DELAYED, ob noch SELECT-Anweisungen ausstehen. Ist dies der Fall, dann gestattet er deren Ausführung, bevor er mit dem Einfügen verzögerter Datensätze fortfährt.

  • delayed_insert_timeout

    Gibt an, wie viele Sekunden ein INSERT DELAYED-Handler auf INSERT-Anweisungen warten soll, bevor er beendet wird.

  • delayed_queue_size

    Dies ist eine tabellenspezifische Beschränkung der Anzahl von Datensätze, die bei der Verarbeitung von INSERT DELAYED-Anweisungen in der Warteschlange stehen dürfen. Wenn die Warteschlange voll wird, wartet jeder Client mit dem Absetzen einer INSERT DELAYED-Anweisung, bis wieder Platz in der Warteschlange ist.

  • div_precision_increment

    Diese Variable gibt die Anzahl der Präzisionsstellen an, um die das Ergebnis von Divisionsoperationen mit dem Operator / erweitert werden soll. Der Standardwert ist 4, der Mindestwert 0 und der Höchstwert 30. Das folgende Beispiel veranschaulicht die Wirkung einer Erhöhung des Standardwertes.

    mysql> SELECT 1/7;
    +--------+
    | 1/7    |
    +--------+
    | 0.1429 |
    +--------+
    mysql> SET div_precision_increment = 12;
    mysql> SELECT 1/7;
    +----------------+
    | 1/7            |
    +----------------+
    | 0.142857142857 |
    +----------------+
    
  • event_scheduler

    Gibt an, ob der Ereignisplaner aktiviert oder deaktiviert ist. Standardmäßig ist der Planer deaktiviert. Diese Variable wurde in MySQL 5.1.6 hinzugefügt.

  • engine_condition_pushdown

    Diese Variable betrifft NDB. Der Standardwert ist 0 (deaktiviert): Wenn Sie eine Abfrage wie SELECT * FROM t WHERE mycol = 42 ausführen, wobei mycol eine nicht indizierte Spalte ist, dann wird die Abfrage als vollständiger Tabellenscan an jedem NDB-Knoten durchgeführt. Jeder Knoten sendet jeden Datensatz an den MySQL-Server, auf dem dann die WHERE-Bedingung angewendet wird. Ist engine_condition_pushdown auf 1 gesetzt (aktiviert), dann wird die Bedingung an die Speicher-Engine „zurückverwiesen“ und an die NDB-Knoten gesendet. Jeder Knoten führt dann den Scan unter Anwendung der Bedingung durch und sendet nur diejenigen Datensätze an den MySQL-Server zurück, bei denen eine Übereinstimmung vorliegt.

  • expire_logs_days

    Die Anzahl der Tage, nach denen Binärlogs automatisch entfernt werden. Der Standardwert ist 0, d. h. es erfolgt keine automatische Entfernung. Sofern Logs entfernt werden, erfolgt dies beim Start sowie bei der Binärlogrotation.

  • flush

    Wenn aktiviert, schreibt der Server nach jeder SQL-Anweisung alle Änderungen neu auf die Festplatte (Synchronisierung). Normalerweise schreibt MySQL alle Änderungen erst nach der jeweiligen SQL-Anweisung auf die Festplatte und überlässt dem Betriebssystem die Festplattensynchronisierung. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“. Diese Variable ist aktiviert, wenn Sie mysqld mit der Option --flush starten.

  • flush_time

    Hat diese Variable einen Wert ungleich Null, dann werden alle Tabellen nach Verstreichen des durch flush_time (in Sekunden) angegebenen Zeitraums geschlossen, um Ressourcen freizugeben und nicht geschriebene Daten auf die Festplatte zu synchronisieren. Wir empfehlen die Verwendung dieser Option lediglich unter Windows 9x/Me und auf Systemen mit nur minimalen Ressourcen.

  • ft_boolean_syntax

    Die Liste der Operatoren, die bei mit der Option IN BOOLEAN MODE durchgeführter Volltextsuche unterstützt werden. Siehe auch Abschnitt 12.7.1, „Boolesche Volltextsuche“.

    Vorgabe ist '+ -><()~*:""&|'. Es gelten folgende Regeln zur Änderung des Wertes:

    • Die Operatorfunktion wird durch die Position innerhalb des Strings bestimmt.

    • Der Ersetzungswert muss 14 Zeichen umfassen.

    • Jedes Zeichen muss ein ASCII-konformes, nicht alphanumerisches Zeichen sein.

    • Das erste oder zweite Zeichen muss ein Leerzeichen sein.

    • Mit Ausnahme der Anführungszeichen für Phrasen an den Positionen 11 und 12 sind Duplikate unzulässig. Die beiden Anführungszeichen müssen nicht identisch sein, dürfen es jedoch als einzige.

    • Die Positionen 10, 13 und 14 (Standardeinstellungen: ‘:’, ‘&’ und ‘|’) sind für zukünftige Erweiterungen vorgesehen.

  • ft_max_word_len

    Die maximale Länge des Wortes, das in einem FULLTEXT-Index enthalten sein darf.

    Hinweis: Wenn Sie diese Variable ändern, müssen Sie FULLTEXT-Indizes neu erstellen. Verwenden Sie REPAIR TABLE tbl_name QUICK.

  • ft_min_word_len

    Die minimale Länge des Wortes, das in einem FULLTEXT-Index enthalten sein darf.

    Hinweis: Wenn Sie diese Variable ändern, müssen Sie FULLTEXT-Indizes neu erstellen. Verwenden Sie REPAIR TABLE tbl_name QUICK.

  • ft_query_expansion_limit

    Die Anzahl der obersten zu verwendenden Übereinstimmungen, die bei einer mit WITH QUERY EXPANSION ausgeführten Volltextsuche verwendet werden.

  • ft_stopword_file

    Datei, aus der die Liste der Stoppwörter für die Volltextsuche ausgelesen wird. Es werden alle Wörter aus der Datei verwendet; Kommentare hingegen werden nicht berücksichtigt. Standardmäßig wird eine eingebaute Liste mit Stoppwörtern (wie in der Datei myisam/ft_static.c definiert) verwendet. Wenn Sie die Variable auf den Leer-String setzen (''), wird die Ausfilterung von Stoppwörtern deaktiviert.

    Hinweis: Wenn Sie diese Variable ändern oder den Inhalt der Stoppwortdatei ändern, müssen die FULLTEXT-Indizes neu erstellt werden. Verwenden Sie REPAIR TABLE tbl_name QUICK.

  • group_concat_max_len

    Die maximal zulässige Ergebnislänge der Funktion GROUP_CONCAT(). Der Standardwert ist 1.024.

  • have_archive

    YES, wenn mysqld ARCHIVE-Tabellen unterstützt, andernfalls NO.

  • have_bdb

    YES, wenn mysqld BDB-Tabellen unterstützt. DISABLED, wenn --skip-bdb verwendet wird.

  • have_blackhole_engine

    YES, wenn mysqld BLACKHOLE-Tabellen unterstützt, andernfalls NO.

  • have_compress

    YES, wenn die Komprimierungsbibliothek zlib auf dem Server verfügbar ist, andernfalls NO. In diesem Fall können die Funktionen COMPRESS() und UNCOMPRESS() nicht verwendet werden.

  • have_crypt

    YES, wenn der Systemaufruf crypt() auf dem Server verfügbar ist, andernfalls NO. In diesem Fall kann die Funktion ENCRYPT() nicht verwendet werden.

  • have_csv

    YES, wenn mysqld ARCHIVE-Tabellen unterstützt, andernfalls NO.

  • have_example_engine

    YES, wenn mysqld EXAMPLE-Tabellen unterstützt, andernfalls NO.

    have_federated_engine

    YES, wenn mysqld FEDERATED-Tabellen unterstützt, andernfalls NO.

  • have_geometry

    YES, wenn der Server raumbezogene Datentypen unterstützt, andernfalls NO.

  • have_innodb

    YES, wenn mysqld InnoDB-Tabellen unterstützt. DISABLED, wenn --skip-innodb verwendet wird.

  • have_isam

    In MySQL 5.1 ist diese Variable nur aus Gründen der Abwärtskompatibilität vorhanden. Sie hat immer den Wert NO, da ISAM nicht mehr unterstützt werden.

  • have_ndbcluster

    YES, wenn mysqld NDB Cluster-Tabellen unterstützt. DISABLED, wenn --skip-ndbcluster verwendet wird.

  • have_partitioning

    YES, wenn mysqld die Partitionierung unterstützt. Wurde in MySQL 5.1.1 als have_partition_engine hinzugefügt und in 5.1.6 in have_partioning umbenannt.

  • have_openssl

    YES, wenn mysqld eine SSL-Verschlüsselung des Client/Server-Protokolls unterstützt, andernfalls NO.

  • have_query_cache

    YES, wenn mysqld den Abfrage-Cache unterstützt, andernfalls NO.

  • have_raid

    YES, wenn mysqld die Option RAID unterstützt, andernfalls NO.

  • have_row_based_replication

    YES, wenn der Server die Replikation unter Verwendung datensatzbasierten Binärloggens durchführen kann. Wenn der Wert NO ist, kann der Server nur anweisungsbasiertes Loggen durchführen. Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“. Diese Variable wurde in MySQL 5.1.5 hinzugefügt.

  • have_rtree_keys

    YES, wenn RTREE-Indizes verfügbar sind, andernfalls NO. (Diese werden für raumbezogene Indizes in MyISAM-Tabellen verwendet.)

  • have_symlink

    YES, wenn die Unterstützung für symbolische Verknüpfungen aktiviert ist, andernfalls NO. Diese ist unter Unix für die Unterstützung der Tabellenoptionen DATA DIRECTORY und INDEX DIRECTORY und unter Windows für die Unterstützung von symbolischen Verknüpfungen mit Datenverzeichnissen erforderlich.

  • init_connect

    Ein String, der vom Server immer dann ausgeführt wird, wenn ein Client eine Verbindung herstellt. Der String besteht aus einer oder mehreren SQL-Anweisungen. Wenn Sie mehrere Anweisungen angeben wollen, trennen Sie sie durch Semikola. So beginnt beispielsweise jeder Client bei einer Verbindung mit aktiviertem Autocommit-Modus. Es gibt keine globale Systemvariable, mit der festgelegt werden kann, dass Autocommit standardmäßig deaktiviert werden soll; mithilfe von init_connect aber können Sie genau dies realisieren:

    SET GLOBAL init_connect='SET AUTOCOMMIT=0';
    

    Diese Variable können Sie sowohl über die Befehlszeile als auch in einer Optionsdatei einstellen. Wenn Sie die Variable wie gezeigt in einer Optionsdatei einstellen wollen, ergänzen Sie die folgenden Zeilen:

    [mysqld]
    init_connect='SET AUTOCOMMIT=0'
    

    Beachten Sie, dass der Inhalt von init_connect nicht für Benutzer ausgeführt wird, die die Berechtigung SUPER haben. Zweck dieser Maßnahme ist es zu verhindern, dass ein fehlerhafter Wert für init_connect eine Verbindung zum System für alle Benutzer unmöglich macht. Wenn der Wert etwa eine Anweisung mit einem Syntaxfehler enthält, dann könnte dieser dazu führen, dass sich die Clients nicht mehr anmelden können. Da init_connect für Benutzer mit der Berechtigung SUPER nicht ausgeführt wird, können diese eine Verbindung herstellen und den Wert von init_connect korrigieren.

  • init_file

    Der Name der beim Serverstart mit der Option --init-file angegebenen Datei. Es sollte sich hierbei um eine Datei mit SQL-Anweisungen handeln, die der Server beim Start ausführen soll. Jede Anweisung muss in einer eigenen Zeile stehen und darf keine Kommentare enthalten.

  • init_slave

    Diese Variable ähnelt init_connect, es handelt sich hierbei aber um einen String, der von einem Slave-Server jedes Mal dann ausgeführt wird, wenn der SQL-Thread startet. Das Format des Strings ist identisch mit dem der Variable init_connect.

  • innodb_xxx

    InnoDB-Systemvariablen werden in Abschnitt 14.2.4, „InnoDB: Startoptionen und Systemvariablen“ beschrieben.

  • interactive_timeout

    Zeit in Sekunden, während der der Server bei einer interaktiven Verbindung auf Aktivitäten wartet, bevor er sie schließt. Ein interaktiver Client ist als Client definiert, der die Option CLIENT_INTERACTIVE für mysql_real_connect() verwendet. Siehe auch wait_timeout.

  • join_buffer_size

    Die Größe des Puffers, der für Joins benutzt wird, die keine Indizes verwenden und deswegen vollständige Tabellenscans durchführen. Normalerweise besteht die beste Möglichkeit der Realisierung schneller Joins darin, Indizes hinzuzufügen. Erhöhen Sie den Wert von join_buffer_size, um einen schnelleren vollständigen Join zu implementieren, wenn das Hinzufügen von Indizes nicht möglich ist. Für jeden vollständigen Join zwischen zwei Tabellen wird ein Join-Puffer hinzugefügt. Für einen komplexen Join zwischen mehreren Tabellen, für den Indizes nicht verwendet werden, sind unter Umständen mehrere Join-Puffer erforderlich.

  • key_buffer_size

    Indexblöcke für MyISAM-Tabellen werden gepuffert und von allen Threads gemeinsam verwendet. key_buffer_size ist die Größe des für die Indexblöcke verwendeten Puffers. Der Schlüsselpuffer heißt auch Schlüssel-Cache.

    Die maximal zulässige Größe für key_buffer_size beträgt 4 Gbyte. Das effektive Limit kann abhängig davon, wie viel physisches RAM vorhanden ist und welche RAM-spezifischen Grenzwerte je Prozess unter Ihrem Betriebssystem bzw. auf Ihrer Hardwareplattform gelten, niedriger liegen.

    Wenn Sie die Indexverwaltung (für Lese- und mehrfachen Schreiboperationen) optimieren wollen, erhöhen Sie diesen Wert so weit wie möglich. Ein Wert von 25 Prozent des gesamten Speichers auf einem System, auf dem hauptsächlich MySQL läuft, ist durchaus normal. Wenn Sie den Wert jedoch zu hoch (beispielsweise auf mehr als 50 Prozent Ihres gesamten Speichers) setzen, wird Ihr System Daten auslagern und so extrem langsam werden. Zur Durchführung des Dateisystem-Cachings für Datenleseoperationen ist MySQL auf das Betriebssystem angewiesen, d. h. Sie müssen ein wenig Platz für den Dateisystem-Cache lassen. Außerdem müssen Sie die Speicheranforderungen anderer Speicher-Engines berücksichtigen.

    Um eine noch höhere Geschwindigkeit beim Schreiben vieler Datensätze zur gleichen Zeit zu erzielen, verwenden Sie LOCK TABLES. Siehe auch Abschnitt 7.2.16, „Geschwindigkeit von INSERT-Anweisungen“.

    Sie können die Leistung des Schlüsselpuffers durch Absetzen einer SHOW STATUS-Anweisung und Überprüfung der Statusvariablen Key_read_requests, Key_reads, Key_write_requests und Key_writes verifizieren. (Siehe auch Abschnitt 13.5.4, „SHOW.) Das Verhältnis von Key_reads zu Key_read_requests sollte möglichst kleiner als 0,01 sein. Das Key_writes/Key_write_requests-Verhältnis hat normalerweise einen Wert von knapp 1, wenn Sie in erster Linie Aktualisierungs- und Löschvorgänge durchführen, kann aber wesentlich kleiner sein, wenn Sie entweder häufig Updates ausführen, die zahlreiche Datensätze gleichzeitig betreffen, oder die Tabellenoption DELAY_KEY_WRITE verwenden.

    Der Anteil des verwendeten Schlüsselpuffers kann mithilfe von key_buffer_size in Verbindung mit der Statusvariablen Key_blocks_unused und der Pufferblockgröße bestimmt werden, die über die Systemvariable key_cache_block_size verfügbar ist:

    1 - ((Key_blocks_unused × key_cache_block_size) / key_buffer_size)
    

    Dies ist lediglich ein Näherungswert, weil ein Teil des Schlüsselpuffers möglicherweise intern für Verwaltungsstrukturen reserviert ist.

    Sie können mehrere MyISAM-Schlüssel-Caches erstellen. Die Größenbeschränkung von 4 Gbyte gilt für jeden einzelnen Cache, nicht für die Summe aller Caches. Siehe auch Abschnitt 7.4.6, „Der MyISAM-Schlüssel-Cache“.

  • key_cache_age_threshold

    Dieser Wert steuert die Herabstufung von Puffern aus der heißen Unterkette eines Schlüssel-Caches in eine warme Unterkette. Niedrige Werte führen dazu, dass diese Herabstufung schneller erfolgt. Der minimale Wert ist 100, der Vorgabewert 300. Siehe auch Abschnitt 7.4.6, „Der MyISAM-Schlüssel-Cache“.

  • key_cache_block_size

    Größe der Blocks im Schlüssel-Cache in Byte. Der Standardwert ist 1.024. Siehe auch Abschnitt 7.4.6, „Der MyISAM-Schlüssel-Cache“.

  • key_cache_division_limit

    Der Trennpunkt zwischen heißen und warmen Unterketten der Schlüssel-Cache-Pufferkette. Der Wert gibt den Anteil der Pufferkette, die für die warme Unterkette benutzt wird, prozentual an. Der zulässige Wertebereich liegt zwischen 1 und 100, Vorgabewert ist 100. Siehe auch Abschnitt 7.4.6, „Der MyISAM-Schlüssel-Cache“.

  • language

    Sprache, in der Fehlermeldungen ausgegeben werden.

  • large_file_support

    Gibt an, ob mysqld mit Optionen zur Unterstützung großer Dateien kompiliert wurde.

  • large_pages

    Gibt an, ob die Unterstützung großer Seiten aktiviert wurde.

  • license

    Der Lizenztyp des Servers.

  • local_infile

    Gibt an, ob LOCAL für LOAD DATA INFILE-Anweisungen unterstützt wird. Siehe auch Abschnitt 5.7.4, „Sicherheitsprobleme mit LOAD DATA LOCAL.

  • locked_in_memory

    Gibt an, ob mysqld mit der Option --memlock im Speicher gesperrt wurde.

  • log

    Gibt an, ob das Loggen aller Anweisungen im allgemeinen Abfragelog aktiviert wurde Siehe auch Abschnitt 5.12.2, „Die allgemeine Anfragen-Logdatei“.

  • log_bin

    Gibt an, ob das Binärlog aktiviert wurde. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

  • log_bin_trust_function_creators

    Diese Variable wird angewendet, wenn das binäre Loggen aktiviert ist. Sie steuert, ob die Ersteller gespeicherter Funktionen vertrauenswürdig sind, keine gespeicherten Funktionen zu erstellen, die das Schreiben unsicherer Ereignisse in das Binärlog bewirken könnten. Wenn die Variable den Wert 0 hat (Standardeinstellung), dann dürfen Benutzer gespeicherte Routinen nur dann erstellen oder ändern, wenn sie zusätzlich zu den Berechtigungen CREATE ROUTINE oder ALTER ROUTINE die Berechtigung SUPER haben. Die Einstellung 0 implementiert auch eine Beschränkung, dass eine Funktion mit der Eigenschaft DETERMINISTIC, der Eigenschaft READS SQL DATA oder der Eigenschaft NO SQL deklariert werden muss. Hat die Variable den Wert 1, dann setzt MySQL diese Beschränkungen bei der Erstellung gespeicherter Funktionen nicht durch. Siehe auch Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“.

  • log_error

    Die Position des Fehlerlogs.

  • log_slave_updates

    Gibt an, ob Updates, die ein Slave-Server von einem Master-Server empfängt, im eigenen Binärlog des Slave-Servers aufgezeichnet werden sollen. Damit diese Variable Wirkung zeigt, muss das binäre Loggen am Slave aktiviert sein. Siehe auch Abschnitt 6.9, „Replikationsoptionen in my.cnf“.

  • log_slow_queries

    Gibt an, ob langsame Abfragen protokolliert werden sollen. „Langsam“ wird hierbei durch den Wert der Variable long_query_time bestimmt. Siehe auch Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“.

  • log_warnings

    Gibt an, ob zusätzliche Warnmeldungen erzeugt werden sollen. Die Funktion ist standardmäßig aktiviert. Unterbrochene Verbindungen werden nicht in das Fehlerlog protokolliert, sofern der Wert größer als 1 ist.

  • long_query_time

    Wenn eine Abfrage länger dauert als durch diese Variable (in Sekunden) angegeben, erhöht der Server die Statusvariable Slow_queries entsprechend. Wenn Sie die Option --log-slow-queries verwenden, wird die Abfrage in der Logdatei für langsame Abfragen protokolliert. Dieser Wert wird als Echtzeit (nicht als Prozessorzeit) gemessen, d. h. eine Abfrage, die bei einem System mit geringer Belastung den Schwellwert unterschreitet, kann bei einem stark belasteten System bereits darüber liegen. Der Mindestwert ist 1. Siehe auch Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“.

  • low_priority_updates

    Wenn diese Variable den Wert 1 hat, warten alle INSERT-, UPDATE-, DELETE- und LOCK TABLE WRITE-Anweisungen, bis keine SELECT- oder LOCK TABLE READ-Anweisungen für die betreffende Tabelle mehr anhängig sind. Diese Variable hieß früher sql_low_priority_updates.

  • lower_case_file_system

    Diese Variable beschreibt die Auswirkungen der Groß-/Kleinschreibung auf dem Dateisystem, auf dem sich das Datenverzeichnis befindet. OFF bedeutet, dass die Groß-/Kleinschreibung bei Dateinamen unterschieden wird, bei ON ist dies nicht der Fall.

  • lower_case_table_names

    Hat die Variable den Wert 1, dann werden Tabellennamen in Kleinschreibung auf der Festplatte gespeichert. Vergleiche von Tabellennamen werden dann nicht durch unterschiedliche Groß-/Kleinschreibung beeinträchtigt. Der Wert 2 führt zu einer Speicherung der Tabellennamen in der eingegebenen Form, Vergleiche erfolgen aber stets in Kleinschreibung. Diese Option gilt auch für Datenbanknamen und Tabellenaliase. Siehe auch Abschnitt 9.2.2, „Groß-/Kleinschreibung in Namen“.

    Wenn Sie InnoDB-Tabellen verwenden, sollten Sie diese Variable auf allen Plattformen auf 1 setzen. Hiermit wird die Konvertierung von Namen in die Kleinschreibung erzwungen.

    Sie sollten diese Variable keinesfalls auf 0 setzen, wenn Sie MySQL auf einem System ausführen, bei dem die Groß-/Kleinschreibung von Dateinamen nicht unterschieden wird (dies betrifft etwa Windows oder Mac OS X). Wird diese Variable beim Start nicht eingestellt und unterscheidet das Dateisystem, auf dem sich das Datenverzeichnis befindet, keine Groß-/Kleinschreibung bei Dateinamen, dann stellt MySQL lower_case_table_names automatisch auf 2.

  • max_allowed_packet

    Die maximale Größe eines Pakets oder eines erzeugten oder temporären Strings.

    Der Paketmeldungspuffer wird mit net_buffer_length Bytes initialisiert, kann aber bei Bedarf auf bis zu max_allowed_packet Bytes anwachsen. Dieser Wert ist standardmäßig niedrig, damit große (und möglicherweise falsche) Pakete abgefangen werden.

    Wenn Sie große BLOB-Spalten oder lange Strings verwenden, müssen Sie ihn erhöhen. Es sollte so groß sein wie das größte BLOB, das Sie verwenden wollen. Das Protokolllimit für max_allowed_packet beträgt 1Gbyte.

  • max_binlog_cache_size

    Wenn eine Transaktion mit mehreren Anweisungen mehr Speicher benötigt als hier angegeben, dann erzeugt der Server die Fehlermeldung Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage.

  • max_binlog_size

    Wenn eine Schreiboperation in das Binärlog bewirkt, dass die aktuelle Größe der Logdatei den Wert dieser Variable überschreitet, dann führt der Server eine Rotation der Binärlogs durch (d. h. er schließt die aktuelle Datei und öffnet die nächste). Sie können diese Variable nur auf einen Wert im Bereich zwischen 4096 Bytes und 1 Gbyte setzen. Der Vorgabewert ist 1 Gbyte.

    Eine Transaktion wird am Stück in das Binärlog geschrieben, kann also niemals auf mehrere Binärlogs verteilt werden. Deswegen kann es vorkommen, dass, wenn Transaktionen sehr groß sind, Binärlogs am Ende größer sind als mit max_binlog_size angegeben.

    Wenn max_relay_log_size 0 ist, gilt der Wert von max_binlog_size auch für Relay-Logdateien.

  • max_connect_errors

    Wenn die Anzahl unterbrochener Verbindungen zu einem Host höher liegt als durch diese Variable angegeben, dann werden weitere Verbindungen für diesen Host gesperrt. Diese Sperrung von Hosts können Sie mit FLUSH HOSTS aufheben.

  • max_connections

    Die zulässige Anzahl nebenläufiger Clientverbindungen. Wenn Sie diesen Wert erhöhen, erhöht sich auch die Anzahl der Dateideskriptoren, die mysqld benötigt. Anmerkungen zu Grenzwerten für Dateideskriptoren finden Sie in Abschnitt 7.4.8, „Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank“. Siehe auch Abschnitt A.2.6, „Too many connections-Fehler“.

  • max_delayed_threads

    Maximale Anzahl von Threads, die zur Verarbeitung von INSERT DELAYED-Anweisungen gestartet werden dürfen. Wenn Sie versuchen, Daten in eine neue Tabelle einzufügen, während alle INSERT DELAYED-Threads gerade verwendet werden, dann wird der Datensatz so eingefügt, als ob das Attribut DELAYED nicht angegeben worden wäre. Wenn Sie hier den Wert 0 angeben, erstellt MySQL in keinem Fall einen Thread zur Verarbeitung von DELAYED-Datensätzen; im Endeffekt bedeutet dies eine vollständige Deaktivierung von DELAYED.

  • max_error_count

    Die maximale Anzahl von Fehlermeldungen, Warnungen und Hinweisen, die mit SHOW ERRORS- und SHOW WARNINGS-Anweisungen zur Anzeige gespeichert werden.

  • max_heap_table_size

    Diese Variable bestimmt die maximale Größe, auf die MEMORY-Tabellen anwachsen dürfen. Der Wert der Variable wird zur Berechnung von MAX_ROWS-Werte für MEMORY-Tabellen verwendet. Die Einstellung der Variable hat keine Auswirkungen auf bereits vorhandene MEMORY-Tabellen, sofern diese nicht mit einer Anweisung wie CREATE TABLE neu erstellt oder mit ALTER TABLE oder TRUNCATE TABLE modifiziert werden.

  • max_insert_delayed_threads

    Diese Variable ist synonym zu max_delayed_threads.

  • max_join_size

    Ermöglicht das Unterbinden von SELECT-Anweisungen, die unter Umständen eine größere Anzahl von Datensätzen (bei Anweisungen für eine Tabelle) oder Datensatzkombinationen (bei Anweisungen für mehrere Tabellen) untersuchen müssen als durch max_join_size angegeben. Ebenfalls unterbunden werden SELECT-Anweisungen, bei denen mehr Festplattenzugriffe erfolgen würden als durch max_join_size angegeben. Durch Einstellen dieses Wertes können Sie SELECT-Anweisungen abfangen, bei denen Schlüssel nicht korrekt verwendet wurden und deren Verarbeitung wahrscheinlich sehr lange dauern würde. Nehmen Sie diese Einstellung vor, wenn Ihre Benutzer dazu neigen, Joins durchzuführen, bei denen entweder eine WHERE-Klausel fehlt oder die sehr lange dauern oder mehrere Millionen Datensätze zurückgeben könnten.

    Wenn Sie die Variable auf einen anderen Wert als DEFAULT setzen, wird der Wert von SQL_BIG_SELECTS auf 0 zurückgesetzt. Stellen Sie den Wert von SQL_BIG_SELECTS erneut ein, dann wird die Variable max_join_size ignoriert.

    Befindet sich ein Abfrageergebnis im Abfrage-Cache, dann wird keine Überprüfung der Ergebnisgröße durchgeführt, weil das Ergebnis zuvor bereits berechnet wurde und der Server durch den Versand des Ergebnisses nicht belastet würde.

    Diese Variable hieß früher sql_max_join_size.

  • max_length_for_sort_data

    Die Teilungsgröße bei Indexwerten. Sie bestimmt, welcher filesort-Algorithmus verwendet werden soll. Siehe auch Abschnitt 7.2.12, „ORDER BY-Optimierung“.

  • max_relay_log_size

    Wenn eine Schreiboperation durch einen Replikations-Slave in seine Relay-Logdatei bewirkt, dass die aktuelle Größe der Logdatei den Wert dieser Variable überschreitet, dann führt der Slave eine Rotation der Relay-Logs durch (d. h. er schließt die aktuelle Datei und öffnet die nächste). Wenn max_relay_log_size 0 ist, verwendet der Server max_binlog_size sowohl für das Binär- als auch für das Relay-Log. Ist max_relay_log_size größer als 0, dann wird hierdurch die Größe des Relay-Logs beschränkt. Dies ermöglicht Ihnen die Konfiguration unterschiedlicher Größen für die beiden Logdateien. Sie müssen max_relay_log_size auf einen Wert zwischen 4.096 Bytes und 1 Gbyte (jeweils einschließlich) oder auf 0 setzen. Der Standardwert ist 0. Siehe auch Abschnitt 6.4, „Replikation: Implementationsdetails“.

  • max_seeks_for_key

    Beschränkt die voraussichtliche Anzahl von Festplattenzugriffen beim schlüsselbasierten Suchen nach Datensätzen. Der MySQL-Optimierer geht davon aus, dass nicht mehr als die hier angegebene Anzahl von Schlüsselsuchvorgängen bei der Suche nach passenden Datensätzen in einer Tabelle durch einen Indexscan erforderlich ist (und zwar unabhängig von der tatsächlichen Kardinalität des Index; siehe auch Abschnitt 13.5.4.12, „SHOW INDEX). Durch Einstellen eines niedrigen Wertes (z. B. 100) können Sie MySQL dazu zwingen, Indizes statt Tabellenscans zu bevorzugen.

  • max_sort_length

    Die bei der Sortierung von BLOB- oder TEXT-Werten zu verwendende Anzahl von Bytes. Nur die ersten max_sort_length Bytes jedes Wertes werden berücksichtigt; der Rest wird ignoriert.

  • max_tmp_tables

    Die maximale Anzahl temporärer Tabellen, die ein Client zur selben Zeit offen halten darf. (Diese Option hat derzeit noch keine Auswirkungen.)

  • max_user_connections

    Die maximale Anzahl gleichzeitiger Verbindungen zu einem gegebenen MySQL-Konto. Der Wert 0 hat die Bedeutung „unbeschränkt“.

    Diese Variable hat sowohl einen globalen als auch einen (schreibgeschützten) sitzungsbezogenen Geltungsbereich. Die Sitzungsvariable hat denselben Wert wie die globale Variable, sofern das aktuelle Konto nicht eine MAX_USER_CONNECTIONS-Ressourcenbeschränkung ungleich Null hat. In diesem Fall beschreibt der Sitzungswert die kontenbezogene Beschränkung.

  • max_write_lock_count

    Nach Verstreichen der hier angegebenen Anzahl von Schreibsperren muss zunächst einmal eine Anzahl anhängiger Anforderungen für Lesesperren verarbeitet werden.

  • myisam_data_pointer_size

    Die Standardgröße (in Byte) des Zeigers, der von CREATE TABLE für MyISAM-Tabellen verwendet wird, wenn die Option MAX_ROWS nicht angegeben ist. Der Variablenwert muss zwischen 2 und 7 liegen, der Standardwert ist 6. Siehe auch Abschnitt A.2.11, „The table is full-Fehler“.

  • myisam_max_extra_sort_file_size (AUSLAUFEND)

    Hinweis: Diese Variable wird in MySQL 5.1 nicht unterstützt. Weitere Informationen finden Sie im MySQL 5.0 Reference Manual.

  • myisam_max_sort_file_size

    Die maximale Größe der Temporärdatei, die MySQL bei der Neuerstellung eines MyISAM-Indexes (bei REPAIR TABLE, ALTER TABLE oder LOAD DATA INFILE) verwenden darf. Ist die Datei größer als durch diesen Wert angegeben, dann wird der Index stattdessen unter Verwendung des Schlüssel-Caches erstellt (was allerdings langsamer ist). Der Wert wird in Byte angegeben.

  • myisam_recover_options

    Der Wert der Option --myisam-recover. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

  • myisam_repair_threads

    Wenn dieser Wert größer als 1 ist, werden Indizes von MyISAM-Tabellen parallel (d. h. jeder Index mit einem eigenen Thread) während des Prozesses Repair by sorting erstellt. Der Standardwert ist 1. Hinweis: Der Code für die Multithread-Reparatur befindet sich noch im Betastadium.

  • myisam_sort_buffer_size

    Die Größe des Puffers, der bei der Sortierung von MyISAM-Indizes bei Ausführung von REPAIR TABLE oder bei der Erstellung von Indizes mit CREATE INDEX oder ALTER TABLE zugewiesen wird.

  • myisam_stats_method

    Bestimmt, wie der Server NULL-Werte bei der Ermittlung von Statistiken zur Verteilung von Indexwerten bei MyISAM-Tabellen behandelt. Für die Variable gibt es zwei mögliche Werte: nulls_equal und nulls_unequal. Bei nulls_equal werden alle NULL-Indexwerte als gleichwertig betrachtet und bilden eine einzelne Wertegruppe, deren Größe der Anzahl der NULL-Werte entspricht. Bei nulls_unequal hingegen werden NULL-Werte nicht als gleichwertig betrachtet, und jeder NULL-Wert bildet eine eigene Wertegruppe der Größe 1.

    Die Methode, mit der Tabellenstatistiken erzeugt werden, wirkt sich darauf aus, wie der Optimierer Indizes zur Abfrageausführung auswählt. Eine Beschreibung finden Sie in Abschnitt 7.4.7, „Sammlung von MyISAM-Indexstatistiken“.

  • myisam_use_mmap

    Sorgt für die Verwendung der Speicherzuordnung zum Lesen und Schreiben von MyISAM-Tabellen. Diese Variable wurde in MySQL 5.1.4 hinzugefügt.

  • multi_read_range

    Gibt die maximale Anzahl von Bereichen an, die bei der Bereichsauswahl an eine Speicher-Engine gesendet werden. Der Standardwert beträgt 256. Das Senden mehrerer Bereiche an eine Engine ist eine Funktion, die die Leistung bestimmter Auswahloperationen drastisch optimieren kann. Dies gilt insbesondere für NDBCLUSTER: Diese Engine muss Bereichsanforderungen an alle Knoten senden, und das gleichzeitige Senden vieler derartiger Anforderungen verringert die Kommunikationskosten erheblich.

  • named_pipe

    (Nur für Windows.) Gibt an, ob der Server Verbindungen über Named Pipes unterstützt.

  • ndb_extra_logging

    Diese Variable kann auf einen Wert ungleich Null gesetzt werden, um das zusätzliche NDB-Loggen zu aktivieren. Diese Variable wurde in MySQL 5.1.6 hinzugefügt.

  • net_buffer_length

    Der Kommunikationspuffer wird zwischen SQL-Anweisungen auf diese Größe zurücksetzt. Der Wert dieser Variable sollte normalerweise nicht geändert werden. Wenn Sie aber sehr wenig Speicher haben, können Sie ihn auf die voraussichtliche Länge der von Clients gesendeten Anweisungen setzen. Überschreiten Anweisungen diese Länge, dann wird der Puffer automatisch auf bis zu max_allowed_packet Bytes vergrößert.

  • net_read_timeout

    Gibt an (in Sekunden), wie lange auf weitere Daten über eine Verbindung gewartet wird, bevor die Leseoperation abgebrochen wird. Dieser Grenzwert gilt nur für TCP/IP-Verbindungen, nicht jedoch für Verbindungen, die über Unix-Socketdateien, Named Pipes oder gemeinsamen Speicher erfolgen. Wenn der Server vom Client liest, gibt net_read_timeout den Zeitwert an, mit dem der Zeitpunkt des Abbruchs gesteuert wird. Wenn der Server hingegen auf den Client schreibt, gibt net_write_timeout den Zeitwert an, mit dem der Zeitpunkt des Abbruchs gesteuert wird. Siehe auch slave_net_timeout.

  • net_retry_count

    Wenn eine Leseoperation an einem Kommunikationsport unterbrochen wird, erfolgt die hier angegebene Anzahl von Wiederverbindungsversuchen, bevor der Vorgang endgültig abgebrochen wird. Bei FreeBSD sollte dieser Wert ziemlich hoch sein, weil interne Interrupts an alle Threads gesendet werden.

  • net_write_timeout

    Gibt an (in Sekunden), wie lange auf das Schreiben eines Blocks über eine Verbindung gewartet wird, bis die Schreiboperation abgebrochen wird. Dieser Grenzwert gilt nur für TCP/IP-Verbindungen, nicht jedoch für Verbindungen, die über Unix-Socketdateien, Named Pipes oder gemeinsamen Speicher erfolgen. Siehe auch net_read_timeout.

  • new

    Diese Variable wurde in MySQL 4.0 verwendet, um bestimmte Verhaltensweisen von Version 4.1 zu aktivieren. Sie ist aus Gründen der Abwärtskompatibilität noch vorhanden. In MySQL 5.1 ist der Wert immer OFF.

  • old_passwords

    Gibt an, ob der Server Passwörter im vor Version 4.1 verwendeten Stil benutzen soll. Siehe auch Abschnitt A.2.3, „Client does not support authentication protocol.

  • one_shot

    Dies ist keine Variable, kann aber zur Einstellung einiger Variablen verwendet werden. Eine Beschreibung finden Sie in Abschnitt 13.5.3, „SET.

  • open_files_limit

    Die Anzahl der Dateien, die mysqld nach Maßgabe des Betriebssystems öffnen darf. Dies ist der wirkliche, vom System gestattete Wert; er kann sich von dem Wert unterscheiden, den Sie mithilfe der Option --open-files-limit an mysqld bzw. mysqld_safe übergeben haben. Auf Systemen, bei denen MySQL die Anzahl offener Dateien nicht ändern kann, ist der Wert 0.

  • optimizer_prune_level

    Steuert die bei der Abfrageoptimierung angewendete Heuristik, um den Suchraum des Optimierers von wenig vielversprechenden Teilplänen zu säubern. Der Wert 0 deaktiviert die Heuristik, d. h. der Optimierer führt eine erschöpfende Suche durch. Der Wert 1 hingegen sorgt dafür, dass der Optimierer Pläne basierend auf der Anzahl der von temporären Plänen abgerufenen Datensätze entfernt.

  • optimizer_search_depth

    Die maximale Tiefe der vom Abfrageoptimierer durchgeführten Suche. Werte, die größer sind als die Anzahl der Beziehungen in einer Abfrage, führen zu besseren Abfrageplänen, benötigen aber mehr Zeit zur Erzeugung eines Ausführungsplans für eine Abfrage. Bei Werten hingegen, die kleiner sind als die Anzahl der Beziehungen in einer Abfrage, wird der Ausführungsplan schneller zurückgegeben; allerdings ist der zurückgegebene Plan unter Umständen weit davon entfernt, optimal zu sein. Wenn der Wert 0 gewählt wird, wählt das System automatisch einen sinnvollen Wert aus. Wird ein Wert zugewiesen, der der maximalen Anzahl der in einer Abfrage verwendeten Tabelle plus 2 entspricht, dann verwendet der Optimierer zur Durchführung von Suchvorgängen den in MySQL 5.0.0 (und vorher) verwendeten Algorithmus.

  • pid_file

    Der Pfadname der Prozesskennungsdatei. Die Variable kann mit der Option --pid-file eingestellt werden.

  • plugin_dir

    Der Pfadname des Plug-In-Verzeichnisses. Diese Variable wurde in MySQL 5.1.2 hinzugefügt.

  • port

    Die Nummer des Ports, auf dem der Server nach TCP/IP-Verbindungen horcht. Die Variable kann mit der Option --port eingestellt werden.

  • preload_buffer_size

    Die Größe des Puffers, der beim Vorabladen von Indizes reserviert wird.

  • protocol_version

    Die Version des vom MySQL-Server verwendeten Client/Server-Protokolls.

  • query_alloc_block_size

    Die Zuweisungsgröße von Speicherblöcken, die für Objekte reserviert sind, welche während der Verarbeitung und Ausführung von Anweisungen erstellt werden. Wenn Sie Probleme mit der Speicherfragmentierung haben, kann es hilfreich sein, diesen Wert ein wenig zu erhöhen.

  • query_cache_limit

    Es werden nur Ergebnisse zwischengespeichert, die nicht größer sind als die hier angegebene Anzahl von Bytes. Der Vorgabewert ist 1 Mbyte.

  • query_cache_min_res_unit

    Die Mindestgröße (in Byte) für Blöcke, die vom Abfrage-Cache reserviert wurden. Der Vorgabewert ist 4.096 (4 Kbyte). Informationen zur Optimierung dieser Variable finden Sie in Abschnitt 5.14.3, „Konfiguration des Anfragen-Cache“.

  • query_cache_size

    Die Menge des Speichers, der zur Zwischenspeicherung von Abfrageergebnissen reserviert wird. Der Standardwert ist 0, d. h. der Abfrage-Cache ist deaktiviert. Beachten Sie, dass die hier angegebene Speichermenge auch dann reserviert wird, wenn query_cache_type den Wert 0 hat. Weitere Informationen finden Sie in Abschnitt 5.14.3, „Konfiguration des Anfragen-Cache“.

  • query_cache_type

    Bestimmt den Typ des Abfrage-Caches. Die Einstellung des GLOBAL-Wertes legt den Typ für alle Clients fest, die sich nachfolgend anmelden. Einzelne Clients können den SESSION-Wert einstellen, um die eigene Verwendung des Abfrage-Caches zu beeinflussen. Die zulässigen Werte entnehmen Sie folgender Tabelle:

    OptionBeschreibung
    0 oder OFFErgebnisse werden nicht zwischengespeichert oder abgerufen. Beachten Sie, dass die Reservierung des Puffers für den Abfrage-Cache hierdurch nicht aufgehoben wird. Zu diesem Zweck müssen Sie query_cache_size auf 0 setzen.
    1 oder ONLegt alle Abfrageergebnisse mit Ausnahme derjenigen, die mit SELECT SQL_NO_CACHE beginnen, im Cache ab.
    2 oder DEMANDZwischengespeichert werden nur die Ergebnisse der Abfragen, die mit SELECT SQL_CACHE beginnen.

    Diese Variable hat den Standardwert ON.

  • query_cache_wlock_invalidate

    Wenn ein Client eine Schreibsperre auf eine MyISAM-Tabelle erwirkt, dann wird das Absetzen von Anweisungen anderer Clients, die aus dieser Tabelle lesen, normalerweise nicht unterbunden, wenn die Abfrageergebnisse im Abfrage-Cache vorhanden sind. Wenn Sie diese Variable auf 1 setzen, werden bei vorhandener Schreibsperre für eine Tabelle alle Abfragen im Abfrage-Cache, die auf diese Tabelle verweisen, ungültig. Hierdurch sind andere Clients, die auf diese Tabelle zugreifen wollen, zum Warten gezwungen, bis die Sperre aufgehoben wird.

  • query_prealloc_size

    Die Größe des Permanentpuffers, der zur Abarbeitung und Ausführung von Anweisungen verwendet wird. Dieser Puffer wird zwischen den Anweisungen nicht geleert. Wenn Sie komplexe Abfragen ausführen, kann ein höherer Wert für query_prealloc_size die Leistung optimieren, weil er dafür sorgt, dass der Server während der Abfrageausführung weniger Speicherreservierungen vornehmen muss.

  • range_alloc_block_size

    Die Größe der Blöcke, die bei der Bereichsoptimierung reserviert werden.

  • read_buffer_size

    Jeder Thread, der einen sequenziellen Scan durchführt, reserviert einen Puffer dieser Größe (in Byte) pro gescannter Tabelle. Wenn Sie mehrere sequenzielle Scans durchführen, sollten Sie den Wert erhöhen. Standardmäßig steht er bei 131.072.

  • read_only

    Wenn die Variable für einen Replikations-Slave-Server auf ON gesetzt ist, gestattet der Slave Updates lediglich von Slave-Threads oder von Benutzern, die die Berechtigung SUPER haben. Dies kann sinnvoll sein, um sicherzustellen, dass ein Slave-Server Updates nur von seinem Master-Server und nicht von Clients akzeptiert. Diese Variable gilt nicht für TEMPORARY-Tabellen.

  • relay_log_purge

    Aktiviert oder deaktiviert das automatische Säubern von Relay-Logdateien, sobald diese nicht mehr benötigt werden. Der Vorgabewert ist 1 (ON).

  • read_rnd_buffer_size

    Beim Lesen von Datensätzen in sortierter Reihenfolge (auf einen Schlüsselsortiervorgang folgend) werden die Datensätze über diesen Puffer gelesen, um Festplattenzugriffe zu vermeiden. Das Setzen dieser Variable auf einen hohen Wert kann die Leistung von ORDER BY erheblich verbessern. Allerdings ist dies ein Puffer, der je Client zugewiesen wird. Deswegen sollten Sie die globale Variable nicht auf einen hohen Wert setzen. Ändern Sie stattdessen die Sitzungsvariablen nur bei den Clients, die große Abfragen ausführen müssen.

  • secure_auth

    Wenn der MySQL-Server mit der Option --secure-auth gestartet wurde, sperrt er Verbindungen aller Konten, deren Passwörter im alten (d. h. vor Version 4.1 gültigen) Format gespeichert sind. In diesem Fall ist der Wert dieser Variable ON, andernfalls OFF.

    Sie sollten diese Option aktivieren, wenn Sie die Verwendung von Passwörtern im alten Format (und damit eine unsichere Kommunikation über das Netzwerk) generell unterbinden wollen.

    Der Serverstart schlägt mit einer Fehlermeldung fehl, wenn diese Option aktiviert ist, die Berechtigungstabellen jedoch das alte Format verwenden. Siehe auch Abschnitt A.2.3, „Client does not support authentication protocol.

  • server_id

    Die Serverkennung. Der Wert wird mit der Option --server-id eingestellt. Er erlaubt im Rahmen der Replikation die eindeutige Identifizierung von Master- und Slave-Servern.

  • shared_memory

    (Nur für Windows.) Gibt an, ob der Server Verbindungen mit gemeinsamem Speicher gestattet.

  • shared_memory_base_name

    (Nur für Windows.) Der Name des gemeinsamen Speichers, der für Verbindungen mit gemeinsamem Speicher verwendet werden soll. Dies ist praktisch, wenn Sie mehrere MySQL-Instanzen auf einem einzelnen physischen Computer ausführen. Der Standardname ist MYSQL. Beim Namen wird die Groß-/Kleinschreibung unterschieden.

  • skip_external_locking

    Hat den Wert OFF, wenn mysqld die externe Sperrung verwendet, bzw. ON, wenn die externe Sperrung deaktiviert ist.

  • skip_networking

    Diese Variable hat den Wert ON, wenn der Server nur lokale Verbindungen (Nicht-TCP/IP-Verbindungen) zulässt. Unter Unix verwenden lokale Verbindungen eine Unix-Socketdatei. Unter Windows nutzen lokale Verbindungen eine Named Pipe oder gemeinsamen Speicher. Unter NetWare werden nur TCP/IP-Verbindungen unterstützt; hier dürfen Sie diese Variable nicht auf ON setzen. Die Variable kann mit der Option --skip-networking auf ON gesetzt werden.

  • skip_show_database

    Diese Variable verhindert, dass Benutzer die Anweisung SHOW DATABASES verwenden, wenn sie die Berechtigung SHOW DATABASES nicht haben. Dies kann die Sicherheit erhöhen, wenn Sie es für unerwünscht halten, dass Benutzer Datenbanken sehen können, die anderen Benutzern gehören. Die Wirkung der Variable hängt von der Berechtigung SHOW DATABASES ab: Wenn der Variablenwert ON ist, darf die SHOW DATABASES-Anweisung nur von Benutzern verwendet werden, die die Berechtigung SHOW DATABASES haben. Die Anweisung zeigt dann alle Datenbanknamen an. Ist der Wert hingegen OFF, dann dürfen alle Benutzer SHOW DATABASES absetzen; angezeigt werden in diesem Fall aber nur diejenigen Datenbanken, für die der jeweilige Benutzer die Berechtigung SHOW DATABASES oder eine ähnliche Berechtigung hat.

  • slave_compressed_protocol

    Gibt an, ob eine Komprimierung des Slave/Master-Protokolls verwendet werden soll, wenn sowohl Slave als auch Master diese unterstützen.

  • slave_load_tmpdir

    Der Name des Verzeichnisses, in dem der Slave Temporärdateien zur Replikation von LOAD DATA INFILE-Anweisungen erstellt.

  • slave_net_timeout

    Gibt an (in Sekunden), wie lange auf weitere Daten über eine Master/Slave-Verbindung gewartet wird, bevor die Leseoperation abgebrochen wird. Dieser Grenzwert gilt nur für TCP/IP-Verbindungen, nicht jedoch für Verbindungen, die über Unix-Socketdateien, Named Pipes oder gemeinsamen Speicher erfolgen.

  • slave_skip_errors

    Anzahl der Replikationsfehler, die der Slave übergehen (d. h. ignorieren) soll.

  • slave_transaction_retries

    Wenn ein SQL-Thread auf einem Replikations-Slave eine Transaktion nicht ausführen kann, weil eine InnoDB-Blockade aufgetreten ist oder die Werte innodb_lock_wait_timeout von InnoDB bzw. TransactionDeadlockDetectionTimeout oder TransactionInactiveTimeout von NDBCluster überschritten wurden, erfolgt die durch slave_transaction_retries angegebene Anzahl von Neuversuchen, bevor der Vorgang mit einer Fehlermeldung beendet wird. Der Vorgabewert ist 10.

  • slow_launch_time

    Wenn die Erstellung eines Threads länger dauert als durch diese Variable (in Sekunden) angegeben, dann erhöht der Server den Wert der Statusvariablen Slow_launch_threads entsprechend.

  • socket

    Auf Unix-Plattformen bezeichnet diese Variable den Namen der Socketdatei, die für lokale Clientverbindungen verwendet wird. Der Vorgabewert ist /tmp/mysql.sock. (Bei einigen Distributionsformaten kann das Verzeichnis anders aussehen, z. B. /var/lib/mysql bei RPMs.)

    Unter Windows bezeichnet diese Variable den Namen der Named Pipe, die für lokale Clientverbindungen verwendet wird. Der Vorgabewert ist MySQL (keine Unterscheidung der Groß-/Kleinschreibung).

  • sort_buffer_size

    Jeder Thread, der eine Sortierung durchführen muss, reserviert einen Puffer dieser Größe. Erhöhen Sie den Wert, um ORDER BY- oder GROUP BY-Operationen zu beschleunigen. Siehe auch Abschnitt A.4.4, „Wohin MySQL temporäre Dateien speichert“.

  • sql_mode

    Der aktuelle SQL-Modus des Servers. Dieser kann dynamisch eingestellt werden. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  • sql_slave_skip_counter

    Die Anzahl der vom Master kommenden Ereignisse, die ein Slave-Server übergehen soll. Siehe auch Abschnitt 13.6.2.6, „SET GLOBAL SQL_SLAVE_SKIP_COUNTER.

  • storage_engine

    Die vorgabeseitige Speicher-Engine (Tabellentyp). Um die Speicher-Engine beim Serverstart einzustellen, verwenden Sie die Option --default-storage-engine. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

  • sync_binlog

    Ist der Wert dieser Variable positiv, dann synchronisiert der MySQL-Server sein Binärlog jedes Mal auf die Festplatte (unter Verwendung von fdatasync()), wenn sync_binlog in das Binärlog geschrieben wird. Beachten Sie, dass, wenn der Autocommit-Modus aktiviert ist, eine Schreiboperation pro Anweisung im Binärlog gespeichert wird; andernfalls handelt es sich um eine Schreiboperation je Transaktion. Der Standardwert ist 0, d. h. es wird keine Synchronisierung auf Festplatte durchgeführt. Der Wert 1 ist die sicherste Variante, denn im Falle eines Absturzes verlieren Sie maximal eine Anweisung bzw. eine Transaktion aus dem Binärlog. Allerdings ist diese Methode auch die langsamste (sofern die Festplatte nicht über einen batteriegestützten Cache verfügt, der die Synchronisierung extrem beschleunigt).

    Ist der Wert von sync_binlog 0 (Standardeinstellung), dann erfolgt kein zusätzliches Schreiben auf die Festplatte. Der Server ist wie bei jeder anderen Datei auch auf das Betriebssystem angewiesen, um den Dateiinhalt regelmäßig auf die Festplatte schreiben zu können.

  • sync_frm

    Wenn diese Variable auf 1 gesetzt ist, wird, wenn eine nichttemporäre Tabelle erstellt wird, deren .frm-Datei auf Festplatte synchronisiert (dies geschieht mithilfe von fdatasync()). Dies ist zwar langsamer, im Falle eines Absturzes aber sicherer. Der Standardwert ist 1.

  • system_time_zone

    Die Systemzeitzone des Servers. Wenn die Serverausführung startet, erbt sie eine Zeitzoneneinstellung von den Standardwerten des Computers, welche unter Umständen von der Umgebung des Kontos modifiziert wird, welches zur Ausführung des Servers oder Startskripts verwendet wird. Der Wert wird verwendet, um system_time_zone einzustellen. Normalerweise wird die Zeitzone durch die Umgebungsvariable TZ festgelegt. Eine Definition kann aber auch mithilfe der Option --timezone des Skripts mysqld_safe erfolgen.

    Die Variable system_time_zone unterscheidet sich von time_zone. Zwar können diese beiden Variablen denselben Wert haben, letztere wird aber zur Initialisierung der Zeitzone für die Clients verwendet, die eine Verbindung herstellen. Siehe auch Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“.

  • table_cache

    Dies ist der alte Name von table_open_cache, der vor MySQL 5.1.3 verwendet wurde. Verwenden Sie ab MySQL 5.1.3 stattdessen table_open_cache.

  • table_definition_cache

    Die Anzahl der Tabellendefinitionen, die im Definitions-Cache gespeichert werden können. Wenn Sie eine hohe Anzahl von Tabellen verwenden, können Sie einen großen Tabellendefinitions-Cache erstellen, um das Öffnen von Tabellen zu beschleunigen. Der Tabellendefinitions-Cache benötigt weniger Platz als der normale Tabellen-Cache und verwendet anders als jener keine Dateideskriptoren. Diese Variable wurde in MySQL 5.1.3 hinzugefügt.

  • table_open_cache

    Die Anzahl offener Tabellen für alle Threads. Wenn Sie diesen Wert erhöhen, erhöht sich auch die Anzahl der Dateideskriptoren, die mysqld benötigt. Wenn Sie überprüfen wollen, ob Sie den Tabellen-Cache vergrößern müssen, kontrollieren Sie die Statusvariable Opened_tables. Siehe auch Abschnitt 5.2.4, „Server-Statusvariablen“. Wenn der Wert von Opened_tables sehr groß ist und Sie FLUSH TABLES nicht sehr häufig verwenden (was nichts anderes tut, als alle Tabellen zu schließen und neu zu öffnen), dann sollten Sie den Wert von table_open_cache erhöhen. Weitere Informationen zum Tabellen-Cache finden Sie unter Abschnitt 7.4.8, „Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank“. Vor MySQL 5.1.3 hieß diese Variable table_cache.

  • table_type

    Diese Variable ist synonym zu storage_engine. Bei MySQL 5.1 ist storage_engine der bevorzugte Name.

  • thread_cache_size

    Gibt an, wie viele Threads der Server zur Neuverwendung zwischenspeichern soll. Wenn ein Client seine Verbindung trennt, dann werden die Threads dieses Clients im Cache abgelegt, sofern die Anzahl der dort vorhandenen Threads geringer als thread_cache_size ist. Thread-Anforderungen werden erfüllt, indem, sofern möglich, Threads aus dem Cache neu verwendet werden; neue Threads werden nur erstellt, wenn der Cache leer ist. Der Wert dieser Variablen kann erhöht werden, um die Leistung zu optimieren, wenn viele neue Verbindungen auftreten. (Bei einer guten Thread-Implementierung werden Sie normalerweise jedoch keine spürbare Leistungsverbesserung bemerken.) Durch Überprüfung der Differenz zwischen den Statusvariablen Connections und Threads_created können Sie die Wirksamkeit des Thread-Caches kontrollieren. Detaillierte Informationen finden Sie in Abschnitt 5.2.4, „Server-Statusvariablen“.

  • thread_concurrency

    Unter Solaris ruft mysqld thr_setconcurrency() mit diesem Wert auf. Diese Funktionen erlaubt es Anwendungen, dem Thread-System Hinweise zur gewünschten Anzahl der gleichzeitig ausgeführten Threads zukommen zu lassen.

  • thread_stack

    Die Stapelgröße für jeden Thread. Viele der vom crash-me-Test erkannten Einschränkungen hängen von diesem Wert ab. Der Standardwert ist für den normalen Betrieb ausreichend groß. Siehe auch Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“. Standardwert ist 192 Kbyte.

  • time_format

    Diese Variable ist nicht implementiert.

  • time_zone

    Die aktuelle Zeitzone. Diese Variable wird zur Initialisierung der Zeitzone für die Clients verwendet, die eine Verbindung herstellen. Standardmäßig ist der Ausgangswert 'SYSTEM' (mit der Bedeutung „Den Wert von system_time_zone verwenden“). Der Wert kann beim Serverstart mit der Option --default-time-zone explizit angegeben werden. Siehe auch Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“.

  • tmp_table_size

    Wenn eine temporäre Tabelle im Arbeitsspeicher diese Größe überschreitet, wandelt MySQL sie automatisch in eine MyISAM-Tabelle auf der Festplatte um. Erhöhen Sie den Wert von tmp_table_size, wenn Sie viele erweiterte GROUP BY-Abfragen ausführen und viel Speicher haben.

  • tmpdir

    Das für Temporärdateien und Temporärtabellen verwendete Verzeichnis. Dieser Variable kann eine Liste mit mehreren verschiedenen Pfaden zugewiesen werden, die zyklisch abwechselnd verwendet werden. Die Pfade sollten unter Unix mit Doppelpunkten (‘:’) und unter Windows, NetWare und OS/2 mit Semikola (‘;’) voneinander getrennt werden.

    Diese Multiverzeichnisfunktion kann verwendet werden, um die Last auf mehrere physische Festplatten zu verteilen. Wenn der MySQL-Server als Replikations-Slave agiert, sollten Sie tmpdir nicht auf ein Verzeichnis auf einem speicherbasierten Dateisystem oder ein Verzeichnis verweisen lassen, das gelöscht wird, wenn der Server neu startet. Ein Replikations-Slave benötigt einen Teil seiner Temporärdateien, um einen Systemneustart so zu überstehen, dass er Temporärtabellen oder LOAD DATA INFILE-Operationen replizieren kann. Wenn Dateien im Verzeichnis für Temporärdateien beim Serverneustart verloren gehen, schlägt die Replikation fehl. Wenn Sie allerdings MySQL 4.0.0 oder höher verwenden, können Sie das Temporärverzeichnis des Slaves mithilfe der Variable slave_load_tmpdir einstellen. In diesem Fall wird der Slave den globalen Wert von tmpdir nicht verwenden, und Sie können tmpdir auch auf eine nichtpermanente Position verweisen lassen.

  • transaction_alloc_block_size

    Die Menge an Bytes, um die ein Speicherpool für eine Transaktion erhöht wird, für die Speicher benötigt wird. Siehe auch die Beschreibung zu transaction_prealloc_size.

  • transaction_prealloc_size

    Es gibt für jede Transaktion einen Speicherpool, aus dem verschiedene transaktionsbezogene Reservierungen Speicher entnehmen. Die Ausgangsgröße dieses Pools entspricht der Anzahl von Bytes, die durch transaction_prealloc_size angegeben ist. Für jede Reservierung, die aus dem Pool nicht erfüllt werden kann, da zu wenig Speicher verfügbar ist, wird der Pool um die Anzahl von Bytes erhöht, die durch transaction_alloc_block_size angegeben ist. Sobald die Transaktion endet, wird der Pool wieder um die durch transaction_prealloc_size angegebene Anzahl von Bytes verringert.

    Wenn Sie dafür Sorge tragen, dass transaction_prealloc_size groß genug ist, um alle Anweisungen einer einzelnen Transaktion aufzunehmen, können Sie viele malloc()-Aufrufe vermeiden.

  • tx_isolation

    Die Standardstufe für die Transaktionsisolierung. Der Vorgabewert ist REPEATABLE-READ.

    Diese Variable wird durch die SET TRANSACTION ISOLATION LEVEL-Anweisung eingestellt. Siehe auch Abschnitt 13.4.6, „SET TRANSACTION. Wenn Sie tx_isolation direkt auf einen Isolierungsstufennamen setzen, der ein Leerzeichen enthält, dann sollte der Name in Anführungszeichen gesetzt und das Leerzeichen durch einen Bindestrich ersetzt werden. Zum Beispiel:

    SET tx_isolation = 'READ-COMMITTED';
    
  • updatable_views_with_limit

    Diese Variable steuert, ob Updates unter Verwendung einer View vorgenommen werden können, die keinen Primärschlüssel in der zugrundeliegenden Tabelle enthält, wenn das Update eine LIMIT-Klausel enthält. (Derartige Updates werden häufig von GUI-Tools erzeugt.) Ein Update ist eine UPDATE- oder DELETE-Anweisung. Unter dem Primärschlüssel versteht man hier einen PRIMARY KEY- oder einen UNIQUE-Index, bei dem keine Spalte NULL enthalten kann.

    Die Variable kann zwei Werte haben:

    • 1 oder YES: Es wird nur eine Warnung (d. h. keine Fehlermeldung) ausgegeben. Dies ist der Standardwert.

    • 0 oder NO: Das Update wird untersagt.

  • version

    Die Versionsnummer des Servers.

  • version_bdb

    Die Version der BDB-Speicher-Engine.

  • version_comment

    Das Skript configure umfasst eine Option --with-comment, die die Angabe eines Kommentars bei der Erstellung von MySQL erlaubt. Diese Variable enthält den Wert dieses Kommentars.

  • version_compile_machine

    Der Typ des Computers oder der Architektur, auf der MySQL erstellt wurde.

  • version_compile_os

    Der Typ des Betriebssystem, auf der MySQL erstellt wurde.

  • wait_timeout

    Zeit (in Sekunden), während der der Server bei einer nichtinteraktiven Verbindung auf Aktivitäten wartet, bevor er sie schließt. Dieser Grenzwert gilt nur für TCP/IP-Verbindungen, nicht jedoch für Verbindungen, die über Unix-Socketdateien, Named Pipes oder gemeinsamen Speicher erfolgen.

    Beim Thread-Start wird der Sitzungswert wait_timeout auf der Basis des globalen Wertes wait_timeout oder des globalen Wertes interactive_timeout initialisiert. Welcher Wert verwendet wird, hängt vom Clienttyp (entsprechend der Definition durch die Verbindungsoption CLIENT_INTERACTIVE von mysql_real_connect()) ab. Siehe auch interactive_timeout.

5.2.3. Verwendung von Server-Systemvariablen

Der Server mysqld arbeitet mit einer ganzen Reihe von Systemvariablen, die angeben, wie er konfiguriert ist. Für alle diese Variablen gibt es Vorgabewerte. Diese können beim Serverstart über Optionen auf der Befehlszeile oder in Optionsdateien eingestellt werden. Die meisten Variablen lassen sich zur Laufzeit des Servers dynamisch mithilfe der SET-Anweisung ändern; auf diese Weise können Sie den Betrieb des Servers beeinflussen, ohne ihn beenden und neu starten zu müssen. Ferner können Sie die Werte auch in Ausdrücken verwenden.

Hinweis: Verschiedene Systemvariablen lassen sich mit der Anweisung SET aktivieren, indem sie auf ON bzw. 1 gesetzt werden. Ähnlich können Sie sie mit SET deaktivieren, indem Sie sie auf OFF bzw. 0 setzen. Um solche Variablen über die Befehlszeile oder in Optionsdateien einstellen zu können, müssen Sie sie auf 1 oder 0 setzen (d. h. die Einstellungen ON und OFF funktionieren nicht). So führt beispielsweise auf der Befehlszeile die Option --delay_key_write=1 zum gewünschten Ergebnis – anders als --delay_key_write=ON.

Der Server verwendet zwei Arten von Systemvariablen. Globale Variablen beeinflussen den Gesamtbetrieb des Servers. Sitzungsvariablen hingegen wirken sich auf seinen Betrieb bezogen auf jeweils individuelle Clientverbindungen aus. Eine gegebene Systemvariable kann sowohl einen globalen als auch einen sitzungsbezogenen Wert haben.

Wenn der Server startet, setzt er alle globalen Variablen auf ihr jeweiligen Standardwerte. Diese Vorgaben können mithilfe von Optionen geändert werden, die in Optionsdateien oder über die Befehlszeile angegeben werden.

Wenn Sie eine Variable, die einen numerischen Wert annimmt, über eine Startoption konfigurieren, dann kann dieser Wert mit den Suffixen K, M oder G (in Groß- oder Kleinschreibung) angegeben werden, um einen Multiplikator von 1.024, 1.0242 oder 1.0243 anzuzeigen. Bei der Einstellung von key_buffer_size etwa würden hiermit die Werte als Kbyte, Mbyte oder Gbyte angegeben. Der folgende Befehl startet den Server also mit einem Abfrage-Cache, der eine Größe von 16 Mbyte hat.

mysqld --query_cache_size=16M

Die Groß-/Kleinschreibung der Suffixbuchstaben ist irrelevant: 16M und 16m sind gleichwertig.

Wenn Sie den Maximalwert, auf den eine Systemvariable zur Laufzeit mit der SET-Anweisung gesetzt werden kann, beschränken wollen, können Sie das gewünschte Maximum mithilfe einer Option des Typs --maximum-var_name beim Serverstart festlegen. Um beispielsweise eine Erhöhung des Wertes von query_cache_size auf mehr als 32 Mbyte zu verhindern, benutzen Sie die Option --maximum-query_cache_size=32M.

Wenn der Server gestartet wurde, können diejenigen Variablen, die dynamisch sind, geändert werden, indem Sie eine Verbindung mit dem Server herstellen und eine SET GLOBAL var_name = value-Anweisung absetzen. Um eine globale Variable ändern zu können, benötigen Sie die Berechtigung SUPER.

Der Server verwendet zudem einen Satz von Sitzungsvariablen für jeden Client, der eine Verbindung herstellt. Die Sitzungsvariablen des Clients werden zum Zeitpunkt der Verbindungsherstellung unter Verwendung der aktuellen Werte der entsprechenden globalen Variablen initialisiert. So wird z. B. der SQL-Modus des Clients von der Sitzungsvariable sql_mode gesteuert, die, wenn der Client die Verbindung herstellt, mit dem Wert der globalen Variable sql_mode initialisiert wird.

Sitzungsvariablen, die dynamisch sind, kann der Client durch Absetzen einer SET SESSION var_name = value-Anweisung ändern. Das Einstellen einer Sitzungsvariable erfordert keine speziellen Berechtigungen, aber ein Client kann nur seine eigenen Sitzungsvariablen einstellen, nicht jedoch die anderer Clients.

Eine Änderung einer globalen Variable ist für alle Clients sichtbar, die auf diese globale Variable zugreifen. Allerdings wirkt sich diese Änderung nur auf die entsprechenden Sitzungsvariablen derjenigen Clients aus, die nach ihrer Durchführung eine Verbindung herstellen. Änderungen an globalen Variablen haben hingegen keinen Einfluss auf die betreffende Sitzungsvariable derjenigen Clients, die bereits eine Verbindung hergestellt haben (dies gilt sogar für Clients, die die SET GLOBAL-Anweisung absetzen).

Es gibt unterschiedliche Möglichkeiten, globale und Sitzungsvariablen zur Laufzeit einzustellen. Die folgenden Beispiele verwenden sort_buffer_size als Beispiel für einen Variablennamen.

Um den Wert einer GLOBAL-Variable einzustellen, verwenden Sie eine der folgenden Syntaxen:

SET GLOBAL sort_buffer_size = value;
SET @@global.sort_buffer_size = value;

Um den Wert einer SESSION-Variable einzustellen, verwenden Sie eine der folgenden Syntaxen:

SET SESSION sort_buffer_size = value;
SET @@session.sort_buffer_size = value;
SET sort_buffer_size = value;

LOCAL ist ein Synonym für SESSION, und @@local. ist ein Synonym für @@session..

Wenn Sie beim Einstellen einer Variable keinen GLOBAL- oder SESSION-Modifikator angeben, stellt die Anweisung den Sitzungswert ein.

Um eine falsche Verwendung zu verhindern, erzeugt MySQL einen Fehler, wenn Sie SET GLOBAL für eine Variable verwenden, für die nur SET SESSION zulässig ist, oder GLOBAL (bzw. @@global.) beim Einstellen einer globalen Variable nicht angeben.

Wenn Sie einer Systemvariablen mit SET einen Wert zuweisen, dann können Sie in diesem Wert keine Suffixbuchstaben verwenden. Allerdings kann der Wert die Form eines Ausdrucks annehmen:

SET sort_buffer_size = 10 * 1024 * 1024;

Um explizit anzugeben, ob Sie die globale oder die Sitzungsvariable einstellen wollen, verwenden Sie die Modifikatoren GLOBAL oder SESSION:

SET GLOBAL sort_buffer_size = 10 * 1024 * 1024;
SET SESSION sort_buffer_size = 10 * 1024 * 1024;

Systemvariablen und ihre Werte zeigen Sie mit der SHOW VARIABLES-Anweisung an.

mysql> SHOW VARIABLES;
+---------------------------------+--------------------------------------+
| Variable_name                   | Value                                |
+---------------------------------+--------------------------------------+
| auto_increment_increment        | 1                                    |
| auto_increment_offset           | 1                                    |
| automatic_sp_privileges         | ON                                   |
| back_log                        | 50                                   |
| basedir                         | /home/jon/bin/mysql/                 |
| binlog_cache_size               | 32768                                |
| bulk_insert_buffer_size         | 8388608                              |
| character_set_client            | latin1                               |
| character_set_connection        | latin1                               |
| character_set_database          | latin1                               |
| character_set_results           | latin1                               |
| character_set_server            | latin1                               |
| character_set_system            | utf8                                 |
| character_sets_dir              | /usr/bin/mysql/share/mysql/charsets/ |
| collation_connection            | latin1_swedish_ci                    |
| collation_database              | latin1_swedish_ci                    |
| collation_server                | latin1_swedish_ci                    |
...
| innodb_additional_mem_pool_size | 1048576                              |
| innodb_autoextend_increment     | 8                                    |
| innodb_buffer_pool_awe_mem_mb   | 0                                    |
| innodb_buffer_pool_size         | 8388608                              |
| innodb_checksums                | ON                                   |
| innodb_commit_concurrency       | 0                                    |
| innodb_concurrency_tickets      | 500                                  |
| innodb_data_file_path           | ibdata1:10M:autoextend               |
| innodb_data_home_dir            |                                      |
...
| version                         | 5.1.6-alpha-log                      |
| version_comment                 | Source distribution                  |
| version_compile_machine         | i686                                 |
| version_compile_os              | suse-linux                           |
| wait_timeout                    | 28800                                |
+---------------------------------+--------------------------------------+

Um den Wert einer bestimmten GLOBAL-Variable abzurufen, geben Sie eine der folgenden Anweisungen ein:

SELECT @@global.sort_buffer_size;
SHOW GLOBAL VARIABLES like 'sort_buffer_size';

Um den Wert einer SESSION-Variable abzurufen, geben Sie eine der folgenden Anweisungen ein:

SELECT @@sort_buffer_size;
SELECT @@session.sort_buffer_size;
SHOW SESSION VARIABLES like 'sort_buffer_size';

Wenn Sie eine Variable mit SELECT @@var_name abrufen (d. h. global. oder session. nicht angeben), gibt MySQL den SESSION-Wert zurück, sofern dieser vorhanden ist, ansonsten den GLOBAL-Wert.

Wenn Sie bei SHOW VARIABLES weder GLOBAL noch SESSION angeben, gibt MySQL die SESSION-Werte zurück.

Der Grund dafür, warum das Schlüsselwort GLOBAL bei der Einstellung von Variablen angegeben werden muss, die ohnehin nur global verfügbar sind, nicht jedoch bei deren Abrufen, besteht darin, zukünftige Probleme von vornherein auszuschließen. Wenn wir in Zukunft eine SESSION-Variable entfernen müssten, die denselben Namen wie eine GLOBAL-Variable hat, würde ein Client mit der Berechtigung SUPER möglicherweise ungewollt die GLOBAL-Variable ändern – und nicht die SESSION-Variable für die eigene Verbindung. Würden wir ein SESSION-Variable mit demselben Namen hinzufügen, den auch eine GLOBAL-Variable hat, dann könnte ein Client, der eigentlich die GLOBAL-Variable ändern sollte, am Ende seine eigene SESSION-Variable modifizieren.

5.2.3.1. Strukturierte Systemvariablen

Eine Strukturvariable unterscheidet sich in zweierlei Hinsicht von einer regulären Systemvariablen:

  • Ihr Wert ist eine Struktur mit Komponenten, die Serverparameter angeben, welche als zusammengehörig zu betrachten sind.

  • Es kann mehrere Instanzen eines gegebenen Strukturvariablentyps geben. Jede Instanz hat einen anderen Namen und verweist auf eine andere Ressource, die vom Server verwaltet wird.

MySQL 5.1 unterstützt genau einen Typ von Strukturvariablen. Dieser gibt Parameter an, die den Betrieb von Schlüssel-Caches regeln. Eine Strukturvariable für Schlüssel-Caches hat die folgenden Komponenten:

  • key_buffer_size

  • key_cache_block_size

  • key_cache_division_limit

  • key_cache_age_threshold

In diesem Abschnitt beschreiben wir die Syntax, mit der Strukturvariablen referenziert werden. Schlüssel-Cache-Variablen werden zwar für Syntaxbeispiele verwendet; die einzelnen Details dazu, wie Schlüssel-Caches funktionieren, finden Sie jedoch an anderer Stelle in Abschnitt 7.4.6, „Der MyISAM-Schlüssel-Cache“.

Um eine Komponente einer Strukturvariableninstanz zu referenzieren, können Sie einen zusammengesetzten Namen des Formats instance_name.component_name verwenden. Ein paar Beispiele:

hot_cache.key_buffer_size
hot_cache.key_cache_block_size
cold_cache.key_cache_block_size

Für jede strukturierte Systemvariable ist immer eine Instanz mit dem Namen default vordefiniert. Wenn Sie eine Komponente einer Strukturvariable ohne einen Instanznamen referenzieren, wird die Instanz default verwendet. Auf diese Weise referenzieren default.key_buffer_size und key_buffer_size dieselbe Systemvariable.

Strukturvariableninstanzen und Komponenten gehorchen den folgenden Benennungsregeln:

  • Für einen gegebenen Strukturvariablentyp muss jede Instanz einen Namen haben, der innerhalb der Variablen dieses Typs eindeutig ist. Typenübergreifend hingegen müssen die Instanznamen nicht eindeutig sein. So gibt es für jede Strukturvariable eine Instanz namens default – der Name default ist also keineswegs typübergreifend eindeutig.

  • Die Namen der Komponenten jedes Strukturvariablentyps muss über alle Systemvariablennamen hinweg eindeutig sein. Wäre dies nicht der Fall (d. h. könnten zwei verschiedene Strukturvariablentypen die gleichen Mitgliedsnamen für Komponenten aufweisen), dann wäre nicht eindeutig, welche Standardstrukturvariable zur Referenzierung von Mitgliedsnamen verwendet werden sollte, die nicht durch einen Instanznamen qualifiziert wären.

  • Wenn der Namen einer Strukturvariableninstanz als Bezeichner ohne Anführungszeichen nicht zulässig ist, setzen Sie sie ihn in Backticks. So ist etwa hot-cache unzulässig – anders als `hot-cache`.

  • global, session und local sind unzulässige Instanznamen. Hierdurch wird ein Konflikt umgangen, der bei der Referenzierung nichtstrukturierter Systemvariablen auftreten kann, bei denen die Schreibung @@global.var_name zulässig ist.

Zurzeit besteht die Möglichkeit des Verstoßes gegen die ersten beiden Regeln nicht, weil der einzige Strukturvariablentyp der für die Schlüssel-Caches ist. Die Bedeutung dieser Regeln wird jedoch zunehmen, wenn zukünftig andere Typen strukturierter Variablen eingeführt werden.

Mit einer Ausnahme können Sie Komponenten von Strukturvariablen über zusammengesetzte Namen in jedem Kontext referenzieren, in dem einfache Variablennamen auftauchen können. So können Sie einer Strukturvariablen beispielsweise über eine Befehlszeilenoption einen Wert zuweisen:

shell> mysqld --hot_cache.key_buffer_size=64K

In einer Optionsdatei verwenden Sie folgende Syntax:

[mysqld]
hot_cache.key_buffer_size=64K

Wenn Sie den Server mit dieser Option starten, erstellt er einen Schlüssel-Cache namens hot_cache mit einer Größe von 64 Kbyte zusätzlich zum vorgabeseitigen Schlüssel-Cache mit der Standardgröße von 8 Mbyte.

Nehmen wir an, Sie starten den Server wie folgt:

shell> mysqld --key_buffer_size=256K \
         --extra_cache.key_buffer_size=128K \
         --extra_cache.key_cache_block_size=2048

In diesem Fall setzt der Server die Größe des vorgabeseitigen Caches auf 256 Kbyte. (Sie hätten auch --default.key_buffer_size=256K schreiben können.) Ferner erstellt der Server einen zweiten Schlüssel-Cache namens extra_cache mit einer Größe von 128 Kbyte. Bei diesem ist die Größe der Blockpuffer für die Zwischenspeicherung von Tabellenindexblöcken auf 2.048 Bytes gesetzt.

Das folgende Beispiel startet den Server mit drei verschiedenen Schlüssel-Caches, deren Größen das Verhältnis 3:1:1 aufweisen:

shell> mysqld --key_buffer_size=6M \
         --hot_cache.key_buffer_size=2M \
         --cold_cache.key_buffer_size=2M

Strukturvariablen können auch zur Laufzeit eingestellt und abgefragt werden. Um beispielsweise einen Schlüssel-Cache namens hot_cache auf eine Größe von 10 Mbyte zu setzen, verwenden Sie eine der folgenden Anweisungen:

mysql> SET GLOBAL hot_cache.key_buffer_size = 10*1024*1024;
mysql> SET @@global.hot_cache.key_buffer_size = 10*1024*1024;

Um die Cache-Größe abzufragen, tun Sie Folgendes:

mysql> SELECT @@global.hot_cache.key_buffer_size;

Die folgende Anweisung wird hingegen nicht funktionieren. Die Variable wird nicht als zusammengesetzter Name, sondern als einfacher String für einen LIKE-Mustervergleich aufgefasst:

mysql> SHOW GLOBAL VARIABLES LIKE 'hot_cache.key_buffer_size';

Dies ist die oben erwähnte Ausnahme bei der Verwendung von Strukturvariablennamen in allen Kontexten, in denen einfache Variablennamen auftreten können.

5.2.3.2. Dynamische Systemvariablen

Viele Serversystemvariablen sind dynamisch und lassen sich mit SET GLOBAL oder SET SESSION zur Laufzeit einstellen. Sie können ihre Werte auch mit SELECT abrufen. Siehe auch Abschnitt 5.2.3, „Verwendung von Server-Systemvariablen“.

Die folgende Tabelle zeigt eine vollständige Liste aller Systemvariablen. Dabei gibt die letzte Spalte für jede Variable an, ob GLOBAL oder SESSION (oder beide) gültig sind. Die Tabelle listet auch Sitzungsoptionen auf, die sich mit der SET-Anweisung einstellen lassen. Abschnitt 13.5.3, „SET, beschreibt diese Optionen.

Variablen, die vom Typ „String“ sind, nehmen einen String-Wert entgegen. Variablen, die vom Typ „numerisch“ sind, nehmen einen Zahlenwert entgegen. Variablen vom Typ „boolesch“ können die Werte 0, 1, ON und OFF annehmen. (Wenn Sie sie über die Befehlszeile oder in einer Optionsdatei einstellen, verwenden Sie die numerischen Werte.) Variablen, die als „Aufzählung“ gekennzeichnet sind, sollten normalerweise einen der für die Variable verfügbaren Werte enthalten; solche Variablen können aber auch auf die Zahl gesetzt werden, die der Stelle des gewünschten Wertes in der Aufzählung entspricht. Bei Aufzählungssystemvariablen ist der erste Aufzählungswert 0. Hier liegt ein Unterschied zu ENUM-Spalten vor, bei denen der erste Aufzählungswert der 1 entspricht.

VariablennameWerttypTyp
autocommitbooleschSESSION
big_tablesbooleschSESSION
binlog_cache_sizenumerischGLOBAL
bulk_insert_buffer_sizenumerischGLOBAL | SESSION
character_set_clientStringGLOBAL | SESSION
character_set_connectionStringGLOBAL | SESSION
character_set_resultsStringGLOBAL | SESSION
character_set_serverStringGLOBAL | SESSION
collation_connectionStringGLOBAL | SESSION
collation_serverStringGLOBAL | SESSION
completion_typenumerischGLOBAL | SESSION
concurrent_insertbooleschGLOBAL
connect_timeoutnumerischGLOBAL
convert_character_setStringGLOBAL | SESSION
default_week_formatnumerischGLOBAL | SESSION
delay_key_writeOFF | ON | ALLGLOBAL
delayed_insert_limitnumerischGLOBAL
delayed_insert_timeoutnumerischGLOBAL
delayed_queue_sizenumerischGLOBAL
div_precision_incrementnumerischGLOBAL | SESSION
engine_condition_pushdownbooleschGLOBAL | SESSION
error_countnumerischSESSION
event_schedulerbooleschGLOBAL
expire_logs_daysnumerischGLOBAL
flushbooleschGLOBAL
flush_timenumerischGLOBAL
foreign_key_checksbooleschSESSION
ft_boolean_syntaxnumerischGLOBAL
group_concat_max_lennumerischGLOBAL | SESSION
identitynumerischSESSION
innodb_autoextend_incrementnumerischGLOBAL
innodb_commit_concurrencynumerischGLOBAL
innodb_concurrency_ticketsnumerischGLOBAL
innodb_max_dirty_pages_pctnumerischGLOBAL
innodb_max_purge_lagnumerischGLOBAL
innodb_support_xabooleschGLOBAL | SESSION
innodb_sync_spin_loopsnumerischGLOBAL
innodb_table_locksbooleschGLOBAL | SESSION
innodb_thread_concurrencynumerischGLOBAL
innodb_thread_sleep_delaynumerischGLOBAL
insert_idbooleschSESSION
interactive_timeoutnumerischGLOBAL | SESSION
join_buffer_sizenumerischGLOBAL | SESSION
key_buffer_sizenumerischGLOBAL
last_insert_idnumerischSESSION
local_infilebooleschGLOBAL
log_warningsnumerischGLOBAL
long_query_timenumerischGLOBAL | SESSION
low_priority_updatesbooleschGLOBAL | SESSION
max_allowed_packetnumerischGLOBAL | SESSION
max_binlog_cache_sizenumerischGLOBAL
max_binlog_sizenumerischGLOBAL
max_connect_errorsnumerischGLOBAL
max_connectionsnumerischGLOBAL
max_delayed_threadsnumerischGLOBAL
max_error_countnumerischGLOBAL | SESSION
max_heap_table_sizenumerischGLOBAL | SESSION
max_insert_delayed_threadsnumerischGLOBAL
max_join_sizenumerischGLOBAL | SESSION
max_relay_log_sizenumerischGLOBAL
max_seeks_for_keynumerischGLOBAL | SESSION
max_sort_lengthnumerischGLOBAL | SESSION
max_tmp_tablesnumerischGLOBAL | SESSION
max_user_connectionsnumerischGLOBAL
max_write_lock_countnumerischGLOBAL
myisam_stats_methodAufzählungGLOBAL | SESSION
multi_read_rangenumerischGLOBAL | SESSION
myisam_data_pointer_sizenumerischGLOBAL
log_bin_trust_function_creatorsbooleschGLOBAL
myisam_max_sort_file_sizenumerischGLOBAL | SESSION
myisam_repair_threadsnumerischGLOBAL | SESSION
myisam_sort_buffer_sizenumerischGLOBAL | SESSION
myisam_use_mmapbooleschGLOBAL
ndb_extra_loggingnumerischGLOBAL
net_buffer_lengthnumerischGLOBAL | SESSION
net_read_timeoutnumerischGLOBAL | SESSION
net_retry_countnumerischGLOBAL | SESSION
net_write_timeoutnumerischGLOBAL | SESSION
old_passwordsnumerischGLOBAL | SESSION
optimizer_prune_levelnumerischGLOBAL | SESSION
optimizer_search_depthnumerischGLOBAL | SESSION
preload_buffer_sizenumerischGLOBAL | SESSION
query_alloc_block_sizenumerischGLOBAL | SESSION
query_cache_limitnumerischGLOBAL
query_cache_sizenumerischGLOBAL
query_cache_typeAufzählungGLOBAL | SESSION
query_cache_wlock_invalidatebooleschGLOBAL | SESSION
query_prealloc_sizenumerischGLOBAL | SESSION
range_alloc_block_sizenumerischGLOBAL | SESSION
read_buffer_sizenumerischGLOBAL | SESSION
read_onlynumerischGLOBAL
read_rnd_buffer_sizenumerischGLOBAL | SESSION
rpl_recovery_ranknumerischGLOBAL
safe_show_databasebooleschGLOBAL
secure_authbooleschGLOBAL
server_idnumerischGLOBAL
slave_compressed_protocolbooleschGLOBAL
slave_net_timeoutnumerischGLOBAL
slave_transaction_retriesnumerischGLOBAL
slow_launch_timenumerischGLOBAL
sort_buffer_sizenumerischGLOBAL | SESSION
sql_auto_is_nullbooleschSESSION
sql_big_selectsbooleschSESSION
sql_big_tablesbooleschSESSION
sql_buffer_resultbooleschSESSION
sql_log_binbooleschSESSION
sql_log_offbooleschSESSION
sql_log_updatebooleschSESSION
sql_low_priority_updatesbooleschGLOBAL | SESSION
sql_max_join_sizenumerischGLOBAL | SESSION
sql_modeAufzählungGLOBAL | SESSION
sql_notesbooleschSESSION
sql_quote_show_createbooleschSESSION
sql_safe_updatesbooleschSESSION
sql_select_limitnumerischSESSION
sql_slave_skip_counternumerischGLOBAL
updatable_views_with_limitAufzählungGLOBAL | SESSION
sql_warningsbooleschSESSION
sync_binlognumerischGLOBAL
sync_frmbooleschGLOBAL
storage_engineAufzählungGLOBAL | SESSION
table_definition_cachenumerischGLOBAL
table_open_cachenumerischGLOBAL
table_typeAufzählungGLOBAL | SESSION
thread_cache_sizenumerischGLOBAL
time_zoneStringGLOBAL | SESSION
timestampbooleschSESSION
tmp_table_sizeAufzählungGLOBAL | SESSION
transaction_alloc_block_sizenumerischGLOBAL | SESSION
transaction_prealloc_sizenumerischGLOBAL | SESSION
tx_isolationAufzählungGLOBAL | SESSION
unique_checksbooleschSESSION
wait_timeoutnumerischGLOBAL | SESSION
warning_countnumerischSESSION

5.2.4. Server-Statusvariablen

Der Server verwaltet eine Vielzahl von Statusvariablen, die Daten zu seinem Betrieb enthalten. Sie können sich diese Variablen und die zugehörigen Werte mit der Anweisung SHOW STATUS anzeigen lassen:

mysql> SHOW STATUS;
+-----------------------------------+------------+
| Variable_name                     | Value      |
+-----------------------------------+------------+
| Aborted_clients                   | 0          |
| Aborted_connects                  | 0          |
| Bytes_received                    | 155372598  |
| Bytes_sent                        | 1176560426 |
...
| Connections                       | 30023      |
| Created_tmp_disk_tables           | 0          |
| Created_tmp_files                 | 3          |
| Created_tmp_tables                | 2          |
...
| Threads_created                   | 217        |
| Threads_running                   | 88         |
| Uptime                            | 1389872    |
+-----------------------------------+------------+

Viele Statusvariablen werden durch die Anweisung FLUSH STATUS auf 0 zurückgesetzt.

Die Statusvariablen haben die nachfolgend beschriebenen Bedeutungen. Variablen ohne Versionsangabe waren bereits vor MySQL 5.1 vorhanden. Informationen zur Implementierungshistorie finden Sie im MySQL 5.0 Reference Manual.

  • Aborted_clients

    Anzahl der Verbindungen, die abgebrochen wurden, weil der Client beendet wurde, ohne die Verbindung ordnungsgemäß zu schließen. Siehe auch Abschnitt A.2.10, „Kommunikationsfehler/abgebrochene Verbindung“.

  • Aborted_connects

    Anzahl der fehlgeschlagenen Versuche, eine Verbindung mit dem MySQL-Server herzustellen. Siehe auch Abschnitt A.2.10, „Kommunikationsfehler/abgebrochene Verbindung“.

  • Binlog_cache_disk_use

    Anzahl der Transaktionen, die den temporären Binärlog-Cache verwendeten, aber den Wert von binlog_cache_size überstiegen, weswegen eine Temporärdatei zur Speicherung von Anweisungen aus der Transaktion benutzt wurde.

  • Binlog_cache_use

    Anzahl der Transaktionen, die den Binärlog-Cache verwendet haben.

  • Bytes_received

    Anzahl der Bytes, die von allen Clients empfangen wurden.

  • Bytes_sent

    Anzahl der Bytes, die an alle Clients gesendet wurden.

  • Com_xxx

    Die Com_xxx-Variablen zum Zählen von Anweisungen geben die Häufigkeit an, mit der die Anweisung xxx ausgeführt wurde. Für jeden Anweisungstyp gibt es eine Statusvariable. So zählen etwa Com_delete und Com_insert die DELETE- bzw. INSERT-Anweisungen.

    Die folgenden Com_stmt_xxx-Statusvariablen sind vorhanden:

    • Com_stmt_prepare

    • Com_stmt_execute

    • Com_stmt_fetch

    • Com_stmt_send_long_data

    • Com_stmt_reset

    • Com_stmt_close

    Diese Variablen stehen für vorbereitete Anweisungsbefehle. Ihre Namen beziehen sich auf den COM_xxx-Befehlssatz, der in der Vermittlungsschicht zum Einsatz kommt. Mit anderen Worten erhöhen sich ihre Werte immer dann, wenn vorbereitete Anweisungs-API-Aufrufe wie mysql_stmt_prepare(), mysql_stmt_execute() usw. ausgeführt werden. Allerdings erhöhen sich Com_stmt_prepare, Com_stmt_execute und Com_stmt_close auch bei PREPARE, EXECUTE bzw. DEALLOCATE PREPARE. Ferner erhöhen sich die Werte der älteren (d. h. seit MySQL 4.1.3 vorhandenen) Anweisungszählvariablen Com_prepare_sql, Com_execute_sql und Com_dealloc_sql bei den Anweisungen PREPARE, EXECUTE und DEALLOCATE PREPARE. Com_stmt_fetch steht für die Gesamtanzahl der beim Holen von Cursorn abgesetzten Netzwerkrundreisen.

    Alle Com_stmt_xxx-Variablen werden auch dann erhöht, wenn ein Argument einer vorbereiteten Anweisung unbekannt ist oder während der Ausführung ein Fehler aufgetreten ist. Mit anderen Worten entsprechen ihre Werte der Anzahl der abgesetzten (und nicht der erfolgreich verarbeiteten) Anfragen.

  • Compression

    Gibt an, ob die Clientverbindung eine Komprimierung im Client/Server-Protokoll verwendet. Wurde in MySQL 5.1.2 hinzugefügt.

  • Connections

    Anzahl der Versuche, eine Verbindung mit dem MySQL-Server herzustellen (unabhängig davon, ob diese erfolgreich waren oder nicht).

  • Created_tmp_disk_tables

    Anzahl der vom Server bei der Ausführung von Anweisungen automatisch auf der Festplatte erstellten Temporärtabellen.

  • Created_tmp_files

    Gibt an, wie viele Temporärdateien mysqld erstellt hat.

  • Created_tmp_tables

    Anzahl der vom Server bei der Ausführung von Anweisungen automatisch im Speicher erstellten Temporärtabellen. Wenn Created_tmp_disk_tables einen hohen Wert hat, sollten Sie den Wert von tmp_table_size erhöhen, damit Temporärtabellen im Speicher statt auf Festplatte erstellt werden.

  • Delayed_errors

    Anzahl der mit INSERT DELAYED geschriebenen Datensätze, bei denen ein Fehler aufgetreten ist (wahrscheinlich duplicate key).

  • Delayed_insert_threads

    Anzahl der verzögerten INSERT DELAYED-Threads, die in Verwendung sind.

  • Delayed_writes

    Anzahl der geschriebenen INSERT DELAYED-Datensätze.

  • Flush_commands

    Anzahl der ausgeführten FLUSH-Anweisungen.

  • Handler_commit

    Anzahl der internen COMMIT-Anweisungen.

  • Handler_discover

    Der MySQL-Server kann bei der NDB Cluster-Speicher-Engine fragen, ob sie eine Tabelle mit einem gegebenen Namen kennt. Dies bezeichnet man als Entdeckung. Handler_discover gibt die Häufigkeit ein, mit der Tabellen mithilfe dieser Methode entdeckt wurden.

  • Handler_delete

    Häufigkeit, mit der Datensätze aus Tabellen gelöscht wurden.

  • Handler_read_first

    Häufigkeit, mit der der erste Eintrag aus einem Index gelesen wurde. Wenn dieser Wert hoch ist, kann man davon ausgehen, dass der Server eine große Zahl vollständiger Indexscans ausführt (z. B. für die Spalte SELECT col1 FROM foo, vorausgesetzt, col1 ist indiziert).

  • Handler_read_key

    Anzahl der Anforderungen zum Auslesen eines Datensatzes basierend auf einem Schlüssel. Wenn der Wert hoch ist, können Sie davon ausgehen, dass Ihre Tabellen passend für Ihre Abfragen indiziert sind.

  • Handler_read_next

    Anzahl der Anforderungen zum Auslesen des nächsten Datensatzes in der Schlüsselreihenfolge. Dieser Wert wird hochgezählt, wenn Sie eine Indexspalte mit einer Bereichsbeschränkung abfragen oder einen Indexscan ausführen.

  • Handler_read_prev

    Anzahl der Anforderungen zum Auslesen des vorherigen Datensatzes in der Schlüsselreihenfolge. Diese Lesemethode wird in erster Linie zur Optimierung von ORDER BY ... DESC verwendet.

  • Handler_read_rnd

    Anzahl der Anforderungen zum Auslesen eines Datensatzes basierend auf einer festen Position. Dieser Wert ist hoch, wenn Sie viele Abfragen ausführen, die eine Sortierung des Ergebnisses erfordern. Sie setzen dann wahrscheinlich viele Abfragen ab, die für MySQL das Scannen ganzer Tabellen erforderlich machen, oder verwenden Joins, die die Schlüssel nicht optimal nutzen.

  • Handler_read_rnd_next

    Anzahl der Anforderungen zum Auslesen des nächsten Datensatzes in der Datendatei. Dieser Wert ist hoch, wenn Sie viele Tabellenscans ausführen. Im Allgemeinen lässt dies darauf schließen, dass Ihre Tabellen nicht korrekt indiziert sind oder Ihre Abfragen nicht so geschrieben sind, dass sie die vorhandenen Indizes nutzen können.

  • Handler_rollback

    Anzahl der internen ROLLBACK-Anweisungen.

  • Handler_update

    Anzahl der Anforderungen zur Aktualisierung eines Datensatzes in einer Tabelle.

  • Handler_write

    Anzahl der Anforderungen zum Einfügen eines Datensatzes in eine Tabelle.

  • Innodb_buffer_pool_pages_data

    Anzahl der Seiten, die (schmutzige wie auch saubere) Daten enthalten.

  • Innodb_buffer_pool_pages_dirty

    Anzahl der derzeit schmutzigen Seiten.

  • Innodb_buffer_pool_pages_flushed

    Anzahl der Anforderungen nach einem Neuladen der Pufferpoolseiten.

  • Innodb_buffer_pool_pages_free

    Anzahl der freien Seiten.

  • Innodb_buffer_pool_pages_latched

    Anzahl der verriegelten Seiten im InnoDB-Pufferpool. Dies sind die Seiten, die derzeit gelesen oder geschrieben oder aus einem anderen Grund nicht auf Festplatte synchronisiert werden können.

  • Innodb_buffer_pool_pages_misc

    Anzahl der Seiten, die in Verwendung sind, weil sie aufgrund administrativer Mehrbelastung (z. B. Datensatzsperren oder eines adaptiven Hash-Index) zugewiesen wurden. Dieser Wert kann auch als Innodb_buffer_pool_pages_totalInnodb_buffer_pool_pages_freeInnodb_buffer_pool_pages_data berechnet werden.

  • Innodb_buffer_pool_pages_total

    Gesamtgröße des Pufferpools in Seiten.

  • Innodb_buffer_pool_read_ahead_rnd

    Anzahl der vorab durchgeführten „zufälligen“ Leseoperationen, die durch InnoDB eingeleitet wurden. Dies geschieht, wenn eine Abfrage einen Großteil einer Tabelle in zufälliger Reihenfolge scannt.

  • Innodb_buffer_pool_read_ahead_seq

    Anzahl der vorab durchgeführten sequenziellen Leseoperationen, die durch InnoDB eingeleitet wurden. Dies geschieht, wenn InnoDB einen vollständigen sequenziellen Tabellenscan durchführt.

  • Innodb_buffer_pool_read_requests

    Anzahl der Anforderungen logischer Leseoperationen durch InnoDB.

  • Innodb_buffer_pool_reads

    Anzahl der Anforderungen logischer Leseoperationen, die InnoDB nicht aus dem Pufferpool erfüllen konnte, weswegen eine Leseoperationen für eine einzelne Seite ausgeführt werden musste.

  • Innodb_buffer_pool_wait_free

    Normalerweise erfolgen Schreiboperationen in den InnoDB-Pufferpool im Hintergrund. Wenn es allerdings notwendig ist, eine Seite zu lesen oder zu erstellen, und keine sauberen Seiten verfügbar sind, ist es auch erforderlich zu warten, bis die Seiten neu geschrieben wurden. Dieser Zähler enthält die Anzahl der Instanzen dieser Wartevorgänge. Wenn die Größe des Pufferpools korrekt eingestellt wurde, sollte dieser Wert niedrig sein.

  • Innodb_buffer_pool_write_requests

    Anzahl der Schreiboperationen in den InnoDB-Pufferpool.

  • Innodb_data_fsyncs

    Anzahl der bislang aufgetretenen fsync()-Operationen.

  • Innodb_data_pending_fsyncs

    Aktuelle Anzahl anhängiger fsync()-Operationen.

  • Innodb_data_pending_reads

    Aktuelle Anzahl anhängiger Leseoperationen.

  • Innodb_data_pending_writes

    Aktuelle Anzahl anhängiger Schreiboperationen.

  • Innodb_data_read

    Menge der bislang gelesenen Daten (in Byte).

  • Innodb_data_reads

    Gesamtanzahl der Datenleseoperationen.

  • Innodb_data_writes

    Gesamtanzahl der Datenschreiboperationen.

  • Innodb_data_written

    Menge der bislang geschriebenen Daten (in Byte).

  • Innodb_dblwr_writes, Innodb_dblwr_pages_written

    Anzahl der durchgeführten doppelten Schreiboperationen und Anzahl der Seiten, die zu diesem Zweck geschrieben wurden. Siehe auch Abschnitt 14.2.14.1, „Festplattenein- und -ausgaben“.

  • Innodb_log_waits

    Häufigkeit, mit der der Logpuffer zu klein und ein Wartevorgang erforderlich war, bis der Vorgang nach dem Neuschreiben fortgesetzt werden konnte.

  • Innodb_log_write_requests

    Anzahl der Logschreibeanforderungen.

  • Innodb_log_writes

    Anzahl der physischen Schreiboperationen in die Logdatei.

  • Innodb_os_log_fsyncs

    Anzahl der abgeschlossenen fsync()-Schreiboperationen in die Logdatei.

  • Innodb_os_log_pending_fsyncs

    Anzahl der anhängigen fsync()-Operationen für die Logdatei.

  • Innodb_os_log_pending_writes

    Anzahl der anhängigen Schreiboperationen für die Logdatei.

  • Innodb_os_log_written

    Anzahl der in die Logdatei geschriebenen Bytes.

  • Innodb_page_size

    Die einkompilierte InnoDB-Seitengröße (standardmäßig 16 Kbyte). Viele Werte werden in Seiten gezählt. Die Angabe der Seitengröße erlaubt eine einfache Konvertierung in Bytes.

  • Innodb_pages_created

    Anzahl der erstellten Seiten.

  • Innodb_pages_read

    Anzahl der gelesenen Seiten.

  • Innodb_pages_written

    Anzahl der geschriebenen Seiten.

  • Innodb_row_lock_current_waits

    Anzahl der Datensatzsperren, auf die derzeit gewartet wird.

  • Innodb_row_lock_time

    Die mit dem Erwirken von Datensatzsperren verbrachte Zeit (in Millisekunden).

  • Innodb_row_lock_time_avg

    Die durchschnittliche Zeit zum Erwirken einer Datensatzsperre (in Millisekunden).

  • Innodb_row_lock_time_max

    Die maximale Zeit zum Erwirken einer Datensatzsperre (in Millisekunden).

  • Innodb_row_lock_waits

    Häufigkeit, mit der auf eine Datensatzsperre gewartet werden musste.

  • Innodb_rows_deleted

    Anzahl der Datensätze, die aus InnoDB-Tabellen gelöscht wurden.

  • Innodb_rows_inserted

    Anzahl der Datensätze, die in InnoDB-Tabellen eingefügt wurden.

  • Innodb_rows_read

    Anzahl der Datensätze, die aus InnoDB-Tabellen gelesen wurden.

  • Innodb_rows_updated

    Anzahl der Datensätze, die in InnoDB-Tabellen aktualisiert wurden.

  • Key_blocks_not_flushed

    Anzahl der Schlüsselblöcke im Schlüssel-Cache, die geändert, aber noch nicht neu auf Festplatte geschrieben wurden.

  • Key_blocks_unused

    Anzahl der unbenutzten Blöcke im Schlüssel-Cache. Sie können anhand dieses Wertes bestimmen, wie groß der verwendete Anteil des Schlüssel-Caches ist. Lesen Sie auch die Beschreibung zu key_buffer_size in Abschnitt 5.2.2, „Server-Systemvariablen“.

  • Key_blocks_used

    Anzahl der benutzten Blöcke im Schlüssel-Cache. Dieser Wert ist eine Art Hochwassermarke, die die maximale Anzahl von Blöcken angibt, die jemals gleichzeitig verwendet wurden.

  • Key_read_requests

    Anzahl der Anforderungen zum Auslesen eines Schlüsselblocks aus dem Cache.

  • Key_reads

    Die Anzahl physischer Lesezugriffe eines Schlüsselblocks von der Festplatte. Wenn der Wert von Key_reads hoch ist, dann ist Ihr Wert für key_buffer_size wahrscheinlich zu niedrig. Die Cache-Fehlrate kann berechnet werden als Key_reads ÷ Key_read_requests.

  • Key_write_requests

    Die Anzahl der Anforderungen zum Schreiben eines Schlüsselblocks in den Cache.

  • Key_writes

    Anzahl physischer Schreibvorgänge eines Schlüsselblocks auf die Festplatte.

  • Last_query_cost

    Gesamtkosten der letzten kompilierten Abfrage nach Berechnung durch den Abfrageoptimierer. Dieser Wert ist praktisch, um die Kosten verschiedener Abfragepläne für dieselbe Abfrage zu vergleichen. Der Vorgabewert 0 bedeutet, dass noch keine Abfrage kompiliert wurde. Last_query_cost hat sitzungsbezogen Geltung.

  • Max_used_connections

    Maximale Anzahl von Verbindungen, die seit dem Start des Servers gleichzeitig in Verwendung waren.

  • Not_flushed_delayed_rows

    Anzahl der Datensätze, die darauf warten, in INSERT DELAY-Warteschlangen geschrieben zu werden.

  • Open_files

    Anzahl der offenen Dateien.

  • Open_streams

    Anzahl der offenen Streams (hauptsächlich zum Loggen verwendet).

  • Open_tables

    Anzahl der offenen Tabellen.

  • Opened_tables

    Anzahl der Tabellen, die geöffnet wurden. Wenn der Wert von Opened_tables hoch ist, dann ist Ihr Wert für table_open_cache wahrscheinlich zu niedrig.

  • Qcache_free_blocks

    Anzahl freier Speicherblöcke im Abfrage-Cache.

  • Qcache_free_memory

    Menge des freien Speichers für den Abfrage-Cache.

  • Qcache_hits

    Anzahl der Treffer im Abfrage-Cache.

  • Qcache_inserts

    Anzahl der Abfragen, die zum Abfrage-Cache hinzugefügt wurden.

  • Qcache_lowmem_prunes

    Anzahl der Abfragen, die wegen Speichermangels aus dem Abfrage-Cache gelöscht wurden.

  • Qcache_not_cached

    Anzahl der nicht im Cache abgelegten Abfragen (weil diese entweder nicht speicherbar waren oder aufgrund der query_cache_type-Einstellung nicht abgelegt wurden).

  • Qcache_queries_in_cache

    Anzahl der im Abfrage-Cache registrierten Abfragen.

  • Qcache_total_blocks

    Gesamtzahl von Blöcken im Abfrage-Cache.

  • Questions

    Anzahl der Anweisungen, die Clients an den Server gesendet haben.

  • Rpl_status

    Status der ausfallsicheren Replikation (noch nicht implementiert).

  • Select_full_join

    Anzahl der Joins, die Tabellenscans durchführen, weil sie keine Indizes verwenden. Wenn der Wert nicht 0 ist, sollten Sie die Indizes Ihrer Tabellen sorgfältig prüfen.

  • Select_full_range_join

    Anzahl der Joins, die eine Bereichssuche in einer Referenztabelle verwendet haben.

  • Select_range

    Anzahl der Joins, die Bereiche in der ersten Tabelle verwendet haben. Dies ist normalerweise auch dann kein kritisches Problem, wenn der Wert zu groß ist.

  • Select_range_check

    Anzahl der Joins ohne Schlüssel, die nach jedem Datensatz auf Schlüsselverwendung prüfen. Wenn der Wert nicht 0 ist, sollten Sie die Indizes Ihrer Tabellen sorgfältig prüfen.

  • Select_scan

    Anzahl der Joins, die einen vollständigen Scan der ersten Tabelle durchgeführt haben.

  • Slave_open_temp_tables

    Anzahl der Temporärtabellen, die der Slave-SQL-Thread derzeit geöffnet hält.

  • Slave_running

    Ist ON, wenn dieser Server ein Slave ist, der mit einem Master verbunden ist.

  • Slave_retried_transactions

    Gesamthäufigkeit seit dem Serverstart, mit der der Replikations-Slave-SQL-Thread Transaktionen erneut versucht hat.

  • Slow_launch_threads

    Anzahl der Threads, deren Erzeugung länger als die durch slow_launch_time angegebene Anzahl von Sekunden dauerte.

  • Slow_queries

    Anzahl der Abfragen, die länger als die durch long_query_time angegebene Anzahl von Sekunden dauerten. Siehe auch Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“.

  • Sort_merge_passes

    Anzahl der Merge-Durchgänge, die der Sortieralgorithmus durchführen musste. Wenn dieser Wert hoch ist, sollten Sie unter Umständen den Wert der Systemvariable sort_buffer_size erhöhen.

  • Sort_range

    Anzahl der Sortiervorgänge, die mit Bereichen durchgeführt wurden.

  • Sort_rows

    Anzahl der sortierten Datensätze.

  • Sort_scan

    Anzahl der Sortiervorgänge, die durchgeführt wurden, indem die Tabelle gescannt wurde.

  • Ssl_xxx

    Für SSL-Verbindungen verwendete Variablen.

  • Table_locks_immediate

    Häufigkeit, mit der eine Tabellensperre sofort erwirkt werden konnte.

  • Table_locks_waited

    Häufigkeit, mit der eine Tabellensperre nicht sofort erwirkt werden konnte und ein Wartevorgang erforderlich wurde. Wenn dieser Wert hoch und die Leistung problematisch niedrig ist, sollten Sie zunächst Ihre Abfragen optimieren und dann Ihre Tabelle(n) entweder unterteilen oder die Replikation verwenden.

  • Threads_cached

    Anzahl der Threads im Thread-Cache.

  • Threads_connected

    Anzahl der momentan offenen Verbindungen.

  • Threads_created

    Anzahl der Threads, die zur Verwaltung von Verbindungen erstellt wurden. Wenn der Wert von Threads_created hoch ist, sollten Sie den Wert von thread_cache_size erhöhen. Die Cache-Trefferrate kann berechnet werden als Threads_created ÷ Connections.

  • Threads_running

    Anzahl nicht schlafender Threads.

  • Uptime

    Dauer seit dem Serverstart (in Sekunden).

5.2.5. Der SQL-Modus des Servers

Der MySQL-Server kann in verschiedenen SQL-Modi betrieben werden und diese Modi auf unterschiedliche Weise für verschiedene Clients anwenden. Diese Funktionalität erlaubt es jeder Anwendung, den Betriebsmodus des Servers an die eigenen Anforderungen anzupassen.

Modi definieren, welche SQL-Syntax MySQL unterstützen soll und welche Art von Gültigkeitsprüfungen in Bezug auf die Daten durchgeführt werden sollen. Dies erleichtert die Verwendung von MySQL in verschiedenen Umgebungen und in Verbindung mit anderen Datenbankservern.

Sie stellen den SQL-Standardmodus ein, indem Sie mysqld mit der Option --sql-mode="modes" starten. modes ist hierbei eine Liste verschiedener Modi, die durch Kommata (‘,’) voneinander getrennt sind. Der Standardwert ist leer (d. h. es sind keine Modi ausgewählt). Der Wert modes kann ebenfalls als leer angegeben werden (--sql-mode=""), wenn Sie ihn explizit löschen wollen.

Sie können den SQL-Modus zur Laufzeit mithilfe der Anweisung SET [GLOBAL|SESSION] sql_mode='modes' zur Einstellung des Systemwertes sql_mode ändern. Die Einstellung der GLOBAL-Variable erfordert die Berechtigung SUPER und wirkt sich auf den Betrieb aller Clients aus, die nachfolgend eine Verbindung herstellen. Von der Änderung der SESSION-Variable ist nur der aktuelle Client betroffen. Jeder Client kann jederzeit seinen eigenen sql_mode-Sitzungswert ändern.

Sie können den globalen oder sitzungsspezifischen sql_mode-Wert mit den folgenden Anweisungen ändern:

SELECT @@global.sql_mode;
SELECT @@session.sql_mode;

Die wahrscheinlich wichtigsten sql_mode-Werte sind die folgenden:

  • ANSI

    Ändert Syntax und Verhalten so, dass eine höhere Kompatibilität mit Standard-SQL erzielt wird.

  • STRICT_TRANS_TABLES

    Wenn ein Wert nicht wie eingegeben in eine transaktionssichere Tabelle eingefügt werden konnte, wird die Anweisung abgebrochen. Bei nicht transaktionssicheren Tabellen wird die Anweisung abgebrochen, wenn der Wert in einer Anweisung für genau einen Datensatz oder im ersten Datensatz einer Anweisung für mehrere Datensätze erscheint. Weitere Informationen erhalten Sie im Verlauf dieses Abschnitts.

  • TRADITIONAL

    Hierbei verhält sich MySQL wie ein „traditionelles“ SQL-Datenbanksystem. Eine einfache Beschreibung dieses Modus wäre: „Gib eine Fehlermeldung anstelle einer Warnung aus, wenn ein falscher Wert in eine Spalte eingefügt wird“. Hinweis: Die Anweisung INSERT/UPDATE wird abgebrochen, sobald der Fehler bemerkt wird. Wenn Sie eine nicht transaktionssichere Speicher-Engine verwenden, ist dies ein unter Umständen unerwünschtes Verhalten, weil Datenänderungen, die vor dem Fehler ausgeführt wurden, nicht rückgängig gemacht werden, was zu einer „unvollständigen“ Aktualisierung führt.

Wenn in diesem Handbuch vom „strikten Modus“ die Rede ist, bezeichnet dies einen Modus, in dem zumindest STRICT_TRANS_TABLES oder STRICT_ALL_TABLES aktiviert ist.

Die folgende Liste beschreibt alle unterstützten Modi:

  • ALLOW_INVALID_DATES

    Führt keine vollständige Datumsüberprüfung durch. Geprüft wird nur, ob die Monatsangabe zwischen 1 und 12 und die Tagesangabe zwischen 1 und 31 liegt. Dies ist sehr praktisch für Webanwendungen, bei denen man die Jahres-, Monats- und Tagesangabe drei verschiedenen Feldern entnimmt und diese Angaben dann genau so gespeichert werden sollen, wie der Benutzer sie eingegeben hat (d. h. ohne Plausibilitätsprüfung). Dieser Modus betrifft DATE- und DATETIME-Spalten. Für TIMESTAMP-Spalten gilt er hingegen nicht, da diese immer ein gültiges Datum erfordern.

    Für den Server ist es erforderlich, dass Monats- und Tagesangaben gültig sind und sich nicht einfach nur in den Bereichen 1 bis 12 bzw. 1 bis 31 bewegen. Wenn der strikte Modus deaktiviert ist, werden ungültige Daten wie '2004-04-31' in '0000-00-00' umgewandelt, und es wird eine Warnung erzeugt. Ist der strikte Modus hingegen aktiviert, dann erzeugen ungültige Datumsangaben einen Fehler. Um derartige Daten zuzulassen, aktivieren Sie ALLOW_INVALID_DATES.

  • ANSI_QUOTES

    Hierbei wird ‘"’ als Anführungszeichen für Bezeichner (wie ‘`’) und nicht als String-Anführungszeichen behandelt. Auch wenn dieser Modus aktiviert ist, können Sie ‘`’ als Anführungszeichen für Bezeichner verwenden. Ist ANSI_QUOTES aktiviert, dann dürfen Sie doppelte Anführungszeichen für einen literalen String verwenden, da dieser andernfalls als Bezeichner erkannt würde.

  • ERROR_FOR_DIVISION_BY_ZERO

    Erzeugt im strikten Modus einen Fehler (sonst eine Warnung), wenn bei INSERT- oder UPDATE-Anweisungen eine Division durch Null (oder MOD(X,0)) auftritt. Wenn dieser Modus nicht aktiviert ist, gibt MySQL stattdessen NULL als Ergebnis einer Division durch Null zurück. Bei INSERT IGNORE oder UPDATE IGNORE erzeugt MySQL eine Warnung bezüglich einer Division durch Null, das Ergebnis des Vorgangs ist aber NULL.

  • HIGH_NOT_PRECEDENCE

    Die Vorrangstellung des Operators NOT besteht darin, dass Ausdrücke wie NOT a BETWEEN b AND c als NOT (a BETWEEN b AND c) verarbeitet werden. Bei einigen älteren Versionen von MySQL wurde der Ausdruck hingegen als (NOT a) BETWEEN b AND c aufgefasst. Dieses ältere Vorrangsverhalten kann verwendet werden, indem man den SQL-Modus HIGH_NOT_PRECEDENCE aktiviert.

    mysql> SET sql_mode = '';
    mysql> SELECT NOT 1 BETWEEN -5 AND 5;
            -> 0
    mysql> SET sql_mode = 'broken_not';
    mysql> SELECT NOT 1 BETWEEN -5 AND 5;
            -> 1
    
  • IGNORE_SPACE

    Gestattet Leerzeichen zwischen einem Funktionsnamen und dem Zeichen ‘(’. Hierdurch wird die Behandlung aller Funktionsnamen als reservierte Wörter erzwungen. Dies wiederum bedingt, dass Sie Datenbank-, Tabellen- oder Spaltennamen, die Sie verwenden wollen, als referenzierte Wörter in Anführungszeichen setzen müssen. Weil es beispielsweise eine Funktion USER() gibt, sind die Namen der Tabelle user in der mysql-Datenbank und der Spalte User in dieser Tabelle reservierte Wörter, müssen also in Anführungszeichen gesetzt werden:

    SELECT "User" FROM mysql."user";
    

    Der SQL-Modus IGNORE_SPACE gilt für integrierte Funktionen, nicht aber für gespeicherte Routinen. Nach einem Routinennamen müssen unabhängig davon, ob IGNORE_SPACE aktiviert ist oder nicht, immer Leerzeichen stehen dürfen.

  • NO_AUTO_CREATE_USER

    Verhindert, dass GRANT automatisch neue Benutzer erstellt, sofern es dies tun würde (es sei denn, es wird ein nicht leeres Passwort angegeben).

  • NO_AUTO_VALUE_ON_ZERO

    NO_AUTO_VALUE_ON_ZERO wirkt sich auf die Verarbeitung von AUTO_INCREMENT-Spalten aus. Normalerweise erzeugen Sie die nächste Sequenznummer für die Spalte, indem Sie entweder NULL oder 0 einfügen. NO_AUTO_VALUE_ON_ZERO unterdrückt dieses Verhalten für 0, sodass nur NULL die nächste Sequenznummer erzeugt.

    Dieser Modus kann nützlich sein, wenn 0 in einer AUTO_INCREMENT-Spalte einer Tabelle gespeichert wurde. (Nebenbei gesagt: Das Speichern von 0 ist keine empfehlenswerte Vorgehensweise.) Wenn Sie beispielsweise die Tabelle mit mysqldump speichern und sie dann neu laden, erzeugt MySQL normalerweise neue Sequenznummern, sobald die 0-Werte gefunden werden; das Ergebnis ist also eine Tabelle, deren Inhalt sich von dem ursprünglich gespeicherten unterscheidet. Die Aktivierung von NO_AUTO_VALUE_ON_ZERO vor dem Neuladen der Speicherauszugsdatei löst dieses Problem. mysqldump schließt nun automatisch eine Anweisung in seine Ausgabe mit ein, die NO_AUTO_VALUE_ON_ZERO aktiviert, um das Problem zu vermeiden.

  • NO_BACKSLASH_ESCAPES

    Deaktiviert die Verwendung des Backslashs (‘\’) als Escape-Zeichen innerhalb von Strings. Wenn dieser Modus aktiviert ist, wird der Backslash zu einem ganz gewöhnlichen Zeichen.

  • NO_DIR_IN_CREATE

    Wenn Sie eine Tabelle erstellen, werden in diesem Modus alle INDEX DIRECTORY- und DATA DIRECTORY-Direktiven ignoriert. Diese Option ist praktisch bei Slave-Replikationsservern.

  • NO_ENGINE_SUBSTITUTION

    Verhindert die automatische Ersetzung der vorgabeseitigen Speicher-Engine, wenn eine Anweisung wie CREATE TABLE eine Speicher-Engine angibt, die deaktiviert oder nicht einkompiliert ist.

  • NO_FIELD_OPTIONS

    Sorgt dafür, dass MySQL-spezifische Spaltenoptionen in der Ausgabe von SHOW CREATE TABLE nicht angegeben werden. Dieser Modus wird von mysqldump im Portabilitätsmodus verwendet.

  • NO_KEY_OPTIONS

    Sorgt dafür, dass MySQL-spezifische Indexoptionen in der Ausgabe von SHOW CREATE TABLE nicht angegeben werden. Dieser Modus wird von mysqldump im Portabilitätsmodus verwendet.

  • NO_TABLE_OPTIONS

    Sorgt dafür, dass MySQL-spezifische Tabellenoptionen (wie ENGINE) in der Ausgabe von SHOW CREATE TABLE nicht angegeben werden. Dieser Modus wird von mysqldump im Portabilitätsmodus verwendet.

  • NO_UNSIGNED_SUBTRACTION

    Bei Subtraktionsoperationen wird das Ergebnis nicht als UNSIGNED gekennzeichnet, wenn einer der Operanden ohne Vorzeichen ist. Beachten Sie, dass hiermit BIGINT UNSIGNED nicht mehr in allen Kontexten hundertprozentig einsetzbar ist. Siehe auch Abschnitt 12.8, „Cast-Funktionen und Operatoren“.

  • NO_ZERO_DATE

    Im strikten Modus wird '0000-00-00' nicht als gültiges Datum zugelassen. Mit der Option IGNORE können Sie trotzdem Nulldatumsangaben einfügen. Außerhalb des strikten Modus wird das Datum zwar akzeptiert, aber es wird eine Warnung erzeugt.

  • NO_ZERO_IN_DATE

    Im strikten Modus werden Daten nicht akzeptiert, wenn die Monats- oder Tagesangabe 0 ist. Wenn der Modus mit der Option IGNORE verwendet wird, fügt MySQL das Datum '0000-00-00' für derartige Datumsangaben ein. Außerhalb des strikten Modus wird das Datum zwar akzeptiert, aber es wird eine Warnung erzeugt.

  • ONLY_FULL_GROUP_BY

    Erlaubt keine Abfragen, bei denen die GROUP BY-Klausel auf eine Spalte verweist, die in der Ausgabespaltenliste nicht vorhanden ist.

  • PIPES_AS_CONCAT

    Behandelt || als Operator zur String-Verkettung (also identisch mit CONCAT()) statt als Synonym von OR.

  • REAL_AS_FLOAT

    Behandelt REAL als Synonym von FLOAT. Standardmäßig behandelt MySQL REAL als Synonym von DOUBLE.

  • STRICT_ALL_TABLES

    Aktiviert den strikten Modus für alle Speicher-Engines. Ungültige Datenwerte werden abgewiesen. Zusätzliche Informationen folgen.

  • STRICT_TRANS_TABLES

    Aktiviert den strikten Modus für transaktionssichere Speicher-Engines sowie – sofern möglich – für nicht transaktionssichere Speicher-Engines. Zusätzliche Informationen folgen.

Der strikte Modus steuert, wie MySQL Eingabewerte behandelt, die ungültig sind oder fehlen. Ein Wert kann aus mehreren Gründen ungültig sein. So kann er den falschen Datentyp für die Spalte aufweisen oder außerhalb des zulässigen Bereichs liegen. Ein Wert fehlt, wenn ein neuer Datensatz, der eingefügt werden soll, keinen Wert für eine Spalte enthält, für die keine explizite DEFAULT-Klausel definiert ist.

Bei transaktionssicheren Tabellen tritt bei ungültigen oder fehlenden Werten in einer Anweisung ein Fehler auf, wenn einer der Modi STRICT_ALL_TABLES oder STRICT_TRANS_TABLES aktiviert ist. Die Anweisung wird abgebrochen, und es erfolgt ein Rollback.

Bei nicht transaktionssicheren Tabellen ist das Verhalten in beiden Modi gleich, wenn der betreffende Wert im ersten einzufügenden oder zu aktualisierenden Datensatz auftritt. Die Anweisung wird abgebrochen, und die Tabelle bleibt unverändert. Wenn die Anweisung mehrere Datensätze einfügt oder ändert und der unpassende Wert im zweiten oder einem nachfolgenden Datensatz auftritt, dann hängt das Ergebnis davon ab, welche Option aktiviert ist:

  • Bei STRICT_ALL_TABLES gibt MySQL einen Fehler zurück und ignoriert die verbleibenden Datensätze. Allerdings bleiben die zuvor durch Einfügung oder Aktualisierung an Datensätzen vorgenommenen Änderung erhalten. Das bedeutet, dass unter Umständen eine Teilaktualisierung erfolgt, was vielleicht nicht wünschenswert ist. Um dies zu vermeiden, sollten Sie am besten Anweisungen nur für jeweils einen Datensatz verwenden, da diese abgebrochen werden können, ohne die Tabelle zu verändern.

  • Bei STRICT_TRANS_TABLES wandelt MySQL einen ungültigen Wert in den nächstgelegenen für die Spalte gültigen Wert um und fügt diesen umgewandelten Wert dann ein. Fehlt ein Wert, dann fügt MySQL den impliziten Vorgabewert für den Spaltendatentyp ein. In beiden Fällen erzeugt MySQL zudem eine Warnung (statt eines Fehlers) und fährt dann mit der Verarbeitung der Anweisung fort. Implizite Vorgabewerte sind in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben.

Der strikte Modus untersagt ungültige Datumswerte wie '2004-04-31'. Nicht verboten sind hingegen Datumsangaben mit Nullbestandteilen wie etwa '2004-04-00' oder „Nulldaten“. Um auch diese zu unterbinden, aktivieren Sie die SQL-Modi NO_ZERO_IN_DATE und NO_ZERO_DATE zusätzlich zum strikten Modus.

Wenn Sie den strikten Modus nicht verwenden (d. h. weder STRICT_TRANS_TABLES noch STRICT_ALL_TABLES sind aktiviert), dann fügt MySQL korrigierte Werte für ungültige oder fehlende Angaben ein und erzeugt Warnungen. Im strikten Modus können Sie dieses Verhalten erzeugen, indem Sie INSERT IGNORE bzw. UPDATE IGNORE verwenden. Siehe auch Abschnitt 13.5.4.25, „SHOW WARNINGS.

Die folgenden Spezialmodi sind als Abkürzungen für Kombinationen von Moduswerten aus obiger Liste aufzufassen.

Die Beschreibungen enthalten alle Moduswerte, die in der aktuellen MySQL-Version vorhanden sind. Bei älteren Versionen enthalten die Kombinationsmodi keine einzelnen Moduswerte, die erst in neueren Versionen verfügbar sind.

  • ANSI

    Entspricht REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE. Siehe auch Abschnitt 1.9.3, „MySQL im ANSI-Modus laufen lassen“.

  • DB2

    Entspricht PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS.

  • MAXDB

    Entspricht PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER.

  • MSSQL

    Entspricht PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS.

  • MYSQL323

    Entspricht NO_FIELD_OPTIONS, HIGH_NOT_PRECEDENCE.

  • MYSQL40

    Entspricht NO_FIELD_OPTIONS, HIGH_NOT_PRECEDENCE.

  • ORACLE

    Entspricht PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER.

  • POSTGRESQL

    Entspricht PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS.

  • TRADITIONAL

    Entspricht STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER.

5.2.6. Herunterfahren des MySQL Servers

Beim Herunterfahren des Servers laufen die folgenden Vorgänge ab:

  1. Das Herunterfahren wird eingeleitet.

    Das Herunterfahren des Servers kann auf mehreren Wegen veranlasst werden. So kann etwa ein Benutzer mit der Berechtigung SHUTDOWN den Befehl mysqladmin shutdown ausführen. mysqladmin kann auf jeder von MySQL unterstützen Plattform benutzt werden. Auch andere betriebssystemspezifische Methoden sind möglich, um das Herunterfahren einzuleiten: Unter Unix wird der Server heruntergefahren, wenn er ein SIGTERM-Signal empfängt. Unter Windows wird ein Server, der als Dienst ausgeführt wird, beendet, wenn der Dienste-Manager ihn dazu anweist.

  2. Bei Bedarf erstellt der Server einen Abschaltungs-Thread.

    Je nachdem, wie das Herunterfahren eingeleitet wurde, erstellt der Server unter Umständen einen Thread, um den Abschaltvorgang zu verwalten. Wurde das Herunterfahren von einem Client angefordert, dann wird ein Abschaltungs-Thread erstellt. Ist das Herunterfahren Folge eines empfangenen SIGTERM-Signals, dann erledigt der Signal-Thread die Abschaltung entweder selbst oder erstellt zu diesem Zweck einen separaten Thread. Versucht der Server vergeblich einen Abschaltungs-Thread zu erstellen (etwa weil nicht genügend Speicher zur Verfügung steht), dann gibt er eine Diagnosemeldung aus, die im Fehlerlog erscheint:

    Error: Can't create thread to kill server
    
  3. Der Server nimmt keine neuen Verbindungen mehr an.

    Um die Initialisierung neuer Aktivitäten während des Herunterfahrens zu vermeiden, beendet der Server die Annahme neuer Clientverbindungen. Er tut dies, indem er die Netzwerkverbindungen schließt, auf denen er normalerweise auf Verbindungen horcht: den TCP/IP-Port, die Unix-Socketdatei und die Named Pipe und den gemeinsamen Speicher unter Windows.

  4. Der Server beendet alle aktuellen Aktivitäten.

    Für jeden Thread, der mit einer Clientverbindung verknüpft ist, wird die Verbindung zum Client abgebrochen, und der Thread wird als terminiert gekennzeichnet. Wenn ein Thread diese Kennzeichnung erkennt, beendet er sich. Threads leer laufender Verbindungen beenden sich sehr schnell. Threads hingegen, die zum betreffenden Zeitpunkt Anweisungen verarbeiten, überprüfen ihren Status regelmäßig und benötigen insofern länger, um sich zu beenden. Weitere Informationen zur Thread-Terminierung finden Sie in Abschnitt 13.5.5.3, „KILL. Beachten Sie dort insbesondere die Erläuterungen zu terminierten REPAIR TABLE- und OPTIMIZE TABLE-Operationen an MyISAM-Tabellen.

    Wenn bei Threads eine Transaktion offen ist, wird diese via Rollback rückgängig gemacht. Beachten Sie, dass, wenn ein Thread eine nicht transaktionssichere Tabelle aktualisiert, Anweisungen für mehrere Datensätze wie UPDATE oder INSERT eine teilaktualisierte Tabelle entstehen lassen können, weil der Vorgang vor seinem Abschluss terminiert werden kann.

    Wenn der Server ein Master-Replikationsserver ist, werden Threads, die derzeit angeschlossenen Slaves zugeordnet sind, wie andere Client-Threads behandelt. Das bedeutet, dass jeder dieser Threads als terminiert gekennzeichnet wird und sich beendet, sobald er zum nächsten Mal seinen Status überprüft.

    Ist der Server ein Slave-Replikationsserver, dann werden die E/A- und SQL-Threads – sofern aktiv – beendet, bevor Client-Threads als terminiert gekennzeichnet werden. Der SQL-Thread darf seine aktuelle Anweisung abschließen, um Replikationsprobleme zu vermeiden, und wird dann beendet. Befand sich der SQL-Thread zu diesem Zeitpunkt mitten in einer Transaktion, dann wird diese Transaktion rückgängig gemacht.

  5. Speicher-Engines werden heruntergefahren oder geschlossen.

    An dieser Stelle wird der Tabellen-Cache auf die Festplatte geschrieben, und alle offenen Tabellen werden geschlossen.

    Alle Speicher-Engines führen ggf. Vorgänge aus, die für die jeweils verwalteten Tabellen erforderlich sind. So synchronisiert MyISAM beispielsweise alle anhängigen Indexschreiboperationen für eine Tabelle. InnoDB schreibt seinen Pufferpool auf die Festplatte (sofern innodb_fast_shutdown nicht 2 ist), speichert die aktuelle LSN in den Tablespace und beendet seine eigenen internen Threads.

  6. Der Server wird beendet.

5.3. mysqld-max, ein erweiterter mysqld-Server

Ein MySQL-Max-Server ist eine Version des MySQL-Servers mysqld, in die zusätzliche Funktionen integriert sind. Welche MySQL-Max-Distribution verwendet werden kann, hängt von Ihrer Plattform ab:

  • Unter Windows enthalten MySQL-Binärdistributionen sowohl den Standardserver (mysqld.exe) als auch den MySQL-Max-Server (mysqld-max.exe), d. h. es ist keine gesonderte Distribution erforderlich; Sie verwenden einfach eine normale Windows-Distribution. Siehe auch Abschnitt 2.3, „Installation von MySQL unter Windows“.

  • Wenn Sie MySQL unter Linux mithilfe von RPM-Distributionen installieren, setzt das MySQL-Max-RPM voraus, dass Sie das reguläre Server-RPM bereits installiert haben. Sie installieren also zunächst mithilfe des MySQL-server-RPM einen Standardserver namens mysqld und nachfolgend mit dem MySQL-Max-RPM einen Server namens mysqld-max. Weitere Informationen zu Linux-RPM-Paketen finden Sie in Abschnitt 2.4, „MySQL unter Linux installieren“.

  • Alle anderen MySQL-Max-Distributionen enthalten einen einzelnen Server namens mysqld, der jedoch die Zusatzfunktionen enthält.

Sie finden die MySQL-Max-Binärdateien auf der MySQL AB-Website unter http://dev.mysql.com/downloads/.

MySQL AB erstellt MySQL-Max-Server unter Verwendung der folgenden configure-Optionen:

  • --with-server-suffix=-max

    Diese Option fügt dem Versions-String mysqld das Suffix -max hinzu.

  • --with-innodb

    Diese Option aktiviert die Unterstützung für die InnoDB-Speicher-Engine. MySQL-Max-Server enthalten die InnoDB-Unterstützung generell. Seit MySQL 4.0 ist InnoDB standardmäßig in allen Binärdistributionen enthalten, d. h. Sie benötigen zur InnoDB-Unterstützung keinen MySQL-Max-Server.

  • --with-bdb

    Diese Option aktiviert die Unterstützung der BDB-Speicher-Engine (Berkeley DB) auf denjenigen Plattformen, für die BDB verfügbar ist. (Beachten Sie die nachfolgenden Hinweise.)

  • --with-blackhole-storage-engine

    Diese Option aktiviert die Unterstützung für die BLACKHOLE-Speicher-Engine.

  • --with-csv-storage-engine

    Diese Option aktiviert die Unterstützung für die CSV-Speicher-Engine.

  • --with-example-storage-engine

    Diese Option aktiviert die Unterstützung für die EXAMPLE-Speicher-Engine.

  • --with-federated-storage-engine

    Diese Option aktiviert die Unterstützung für die FEDERATED-Speicher-Engine.

  • --with-ndbcluster

    Diese Option aktiviert die Unterstützung der NDB Cluster-Speicher-Engine auf denjenigen Plattformen, für die Cluster verfügbar sind. (Beachten Sie die nachfolgenden Hinweise.)

  • USE_SYMDIR

    Diese Definition wird aktiviert, um die Unterstützung symbolischer Datenbankverknüpfungen unter Windows zu aktivieren. Seit MySQL 4.0 ist die Unterstützung symbolischer Verknüpfungen für alle Windows-Server aktiviert, d. h. Sie benötigen hierfür keinen MySQL-Max-Server.

MySQL-Max-Binärdistributionen sind praktisch für Benutzer, die vorkompilierte Programme installieren wollen. Wenn Sie MySQL unter Verwendung einer Quelldistribution erstellen, können Sie Ihren eigenen Max-Server erstellen, indem Sie zum Zeitpunkt der Konfiguration genau diejenigen Funktionen aktivieren, mit denen die MySQL-Max-Binärdistributionen erstellt werden.

Sofern möglich, enthalten MySQL-Max-Server die BDB-Speicher-Engine; diese wird jedoch nicht von allen Plattformen unterstützt.

Zurzeit werden MySQL-Cluster nur von Linux (auf den meisten Plattformen), Solaris und Mac OS X unterstützt. Einige Benutzer haben berichtet, dass sie einen aus einer Quelldistribution erstellten MySQL-Cluster erfolgreich unter BSD-Betriebssystemen zum Laufen bekommen haben; hierfür gibt es aber derzeit keinen offiziellen Support. Beachten Sie, dass auch dann, wenn die Server mit Cluster-Unterstützung kompiliert werden, die NDB Cluster-Speicher-Engine standardmäßig nicht aktiviert wird. Sie müssen den Server mit der Option --ndbcluster starten, um ihn als Teil eines MySQL-Clusters verwenden zu können. (Detaillierte Informationen finden Sie in Abschnitt 16.4, „MySQL Cluster: Konfiguration“.)

Die folgende Tabelle listet die Plattformen auf, deren MySQL-Max-Binärdateien Unterstützung für BDB und NDB-Cluster enthalten.

SystemBDB-UnterstützungNDB-Unterstützung
AIX 4.3NeinNein
HP-UX 11.0NeinNein
Linux-AlphaNeinJa
Linux-IA-64NeinNein
Linux-IntelJaJa
Mac OS XNeinJa
NetWareNeinNein
SCO OSR5JaNein
Solaris-SPARCJaJa
Solaris-IntelNeinJa
UnixWareJaNein
Windows NT/2000/XPJaNein

Um herauszufinden, welche Speicher-Engines Ihr Server unterstützt, verwenden Sie die SHOW ENGINES-Anweisung. (Siehe auch Abschnitt 13.5.4.9, „SHOW ENGINES.) Zum Beispiel:

mysql> SHOW ENGINES\G
*************************** 1. row ***************************
      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 2. row ***************************
      Engine: CSV
     Support: YES
     Comment: CSV storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 3. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 4. row ***************************
      Engine: MyISAM
     Support: DEFAULT
     Comment: Default engine as of MySQL 3.23 with great performance
Transactions: NO
          XA: NO
  Savepoints: NO
...

Die exakte Ausgabe von SHOW ENGINES kann je nach verwendeter MySQL-Version (und aktivierten Funktionen) variieren. Die Support-Werte in der Ausgabe geben den Umfang der Unterstützung für die jeweilige Funktion entsprechend nachfolgender Tabelle an:

WertBedeutung
YESDiese Funktion wird unterstützt und ist aktiv.
NODie Funktion wird nicht unterstützt.
DISABLEDDie Funktion wird unterstützt, wurde aber deaktiviert.

Der Wert NO bedeutet, dass der Server ohne Unterstützung für die Funktion kompiliert wurde; sie kann also zur Laufzeit nicht aktiviert werden.

Der Wert DISABLED tritt entweder auf, weil der Server mit einer Option gestartet wurde, die die Funktion deaktiviert, oder weil nicht alle Optionen angegeben wurden, die für die Aktivierung der Funktion erforderlich sind. Im zweiten Fall sollte im Fehlerlog ein Eintrag vorhanden sein, der angibt, warum die Option deaktiviert ist. Siehe auch Abschnitt 5.12.1, „Die Fehler-Logdatei“.

DISABLED wird unter Umständen auch für eine Speicher-Engine angezeigt, wenn der Server zwar mit Unterstützung für diese Engine kompiliert, aber mit der Option --skip-engine gestartet wurde. So deaktiviert beispielsweise --skip-innodb die InnoDB-Engine. Bei der NDB Cluster-Speicher-Engine bedeutet DISABLED, dass der Server mit Unterstützung für MySQL-Cluster kompiliert, aber nicht mit der Option --ndb-cluster gestartet wurde.

Alle MySQL-Server unterstützen MyISAM-Tabellen, weil MyISAM die vorgabeseitige Speicher-Engine ist.

5.4. Startprogramme für den MySQL-Server

Dieser Abschnitt beschreibt verschiedene Programme, die zum Starten des MySQL-Servers mysqld verwendet werden.

5.4.1. mysqld_safe — Startskript für den MySQL-Server

mysqld_safe ist die empfohlene Methode zum Starten eines mysqld-Servers unter Unix und NetWare. mysqld_safe fügt einige Sicherheitsfunktionen hin zu, so etwa das Neustarten des Servers bei Auftreten eines Fehlers und das Loggen von Laufzeitinformationen in eine Fehlerlogdatei. Das NetWare-spezifische Verhalten wird im weiteren Verlauf dieses Abschnitts beschrieben.

Hinweis: Um die Abwärtskompatibilität mit älteren Versionen von MySQL aufrechtzuerhalten, enthalten MySQL-Binärdistributionen auch weiterhin safe_mysqld als symbolische Verknüpfung mit mysqld_safe. Allerdings sollten Sie sich nicht fest darauf verlassen, da dieses Feature mit an Sicherheit grenzender Wahrscheinlichkeit in Zukunft entfernt werden wird.

Standardmäßig versucht mysqld_safe eine ausführbare Datei namens mysqld-max zu starten, sofern diese vorhanden ist; andernfalls wird mysqld gestartet. Beachten Sie die Auswirkungen dieses Verhaltens:

  • Unter Linux ist das MySQL-Max-RPM auf dieses Verhalten von mysqld_safe angewiesen. Das RPM installiert eine ausführbare Datei namens mysqld-max; aufgrund dessen verwendet mysqld_safe ab sofort automatisch diese Datei anstelle von mysqld.

  • Wenn Sie eine MySQL-Max-Distribution installieren, die einen Server namens mysqld-max enthält, und nachfolgend auf eine Nicht-Max-Version von MySQL aktualisieren wollen, dann beachten Sie, dass mysqld_safe nach wie vor versuchen wird, den alten Server mysqld-max auszuführen. Führen Sie ein solches Upgrade durch, dann sollten Sie den alten mysqld-max-Server manuell entfernen, um sicherzustellen, dass mysqld_safe den neuen Server mysqld ausführt.

Um dieses Standardverhalten außer Kraft zu setzen und den Namen des auszuführenden Servers explizit anzugeben, müssen Sie eine der Optionen --mysqld oder --mysqld-version für mysqld_safe angeben. Sie können auch --ledir verwenden, um das Verzeichnis anzugeben, in dem mysqld_safe nach dem Server suchen soll.

Viele der Optionen für mysqld_safe sind identisch mit den Optionen für mysqld. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

Alle für mysqld_safe auf der Befehlszeile angegebenen Optionen werden an mysqld übergeben. Wenn Sie Optionen verwenden wollen, die für mysqld_safe spezifisch sind und von mysqld nicht unterstützt werden, dann geben Sie sie nicht über die Befehlszeile an. Stattdessen sollten Sie sie im Abschnitt [mysqld_safe] einer Optionsdatei auflisten. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

mysqld_safe liest alle Optionen aus den Abschnitten [mysqld], [server] und [mysqld_safe] in Optionsdateien aus. Aus Gründen der Abwärtskompatibilität werden auch [safe_mysqld]-Abschnitte ausgelesen, aber Sie sollten diese Abschnitte bei MySQL 5.1-Installationen in [mysqld_safe] umbenennen.

mysqld_safe unterstützt die folgenden Optionen:

  • --help

    Zeigt eine Hilfsmeldung an und wird dann beendet.

  • --autoclose

    (Nur NetWare.) mysqld_safe stellt unter NetWare eine Bildschirmpräsenz bereit. Wenn Sie das NLM mysqld_safe entladen (herunterfahren), verschwindet der Bildschirm standardmäßig nicht. Stattdessen wird eine Benutzereingabe angefordert:

    *<NLM has terminated; Press any key to close the screen>*
    

    Wenn Sie hingegen wollen, dass NetWare den Bildschirm automatisch schließt, dann verwenden Sie die Option --autoclose für mysqld_safe.

  • --basedir=path

    Der Pfad zum MySQL-Installationsverzeichnis.

  • --core-file-size=size

    Größe der Speicherauszugsdatei, die mysqld erstellen können soll. Der Optionswert wird an ulimit -c übergeben.

  • --datadir=path

    Der Pfad zum Datenverzeichnis.

  • --defaults-extra-file=path

    Der Name einer Optionsdatei, die zusätzlich zu den normalen Optionsdateien ausgelesen wird. Wenn diese Option verwendet wird, muss Sie auf der Befehlszeile die erste angegebene Option sein.

  • --defaults-file=file_name

    Der Name einer Optionsdatei, die anstelle der normalen Optionsdateien ausgelesen wird. Wenn diese Option verwendet wird, muss Sie auf der Befehlszeile die erste angegebene Option sein.

  • --ledir=path

    Wenn mysqld_safe den Server nicht finden kann, können Sie diese Option verwenden, um einen Pfadnamen zu dem Verzeichnis anzugeben, in dem sich der Server befindet.

  • --log-error=file_name

    Schreibt das Fehlerlog in die angegebene Datei. Siehe auch Abschnitt 5.12.1, „Die Fehler-Logdatei“.

  • --mysqld=prog_name

    Name des Serverprogramms (im Verzeichnis ledir), das Sie starten wollen. Diese Option ist erforderlich, wenn Sie die MySQL-Binärdistribution verwenden, aber das Datenverzeichnis sich außerhalb der Binärdistribution befindet. Wenn mysqld_safe den Server nicht finden kann, können Sie die Option --ledir verwenden, um einen Pfadnamen zu dem Verzeichnis anzugeben, in dem sich der Server befindet.

  • --mysqld-version=suffix

    Diese Option ähnelt --mysqld, Sie geben aber nur das Suffix für den Serverprogrammnamen an. Als Basisname wird mysqld vorausgesetzt. Wenn Sie beispielsweise --mysqld-version=max verwenden, startet mysqld_safe das Programm mysqld-max im Verzeichnis ledir. Wenn das Argument für --mysqld-version leer ist, verwendet mysqld_safe mysqld im Verzeichnis ledir.

  • --nice=priority

    Stellt die Zeitplanungspriorität mit dem Programm nice auf den angegebenen Wert.

  • --no-defaults

    Optionsdateien werden nicht auslesen. Wenn diese Option verwendet wird, muss Sie auf der Befehlszeile die erste angegebene Option sein.

  • --open-files-limit=count

    Anzahl der Dateien, die mysqld öffnen können sollte. Der Optionswert wird an ulimit -n übergeben. Beachten Sie, dass Sie mysqld_safe als root starten müssen, damit dies einwandfrei funktioniert!

  • --pid-file=file_name

    Der Pfadname der Prozesskennungsdatei.

  • --port=port_num

    Portnummer, die der Server beim Horchen auf TCP/IP-Verbindungen verwenden soll. Die Portnummer muss 1.024 oder höher sein, sofern der Server nicht vom Systembenutzer root gestartet wird.

  • --socket=path

    Unix-Socketdatei, die der Server bei Horchen auf lokale Verbindungen verwenden soll.

  • --timezone=timezone

    Weist der Zeitzonen-Umgebungsvariablen TZ den angegebenen Optionswert zu. Informationen zu zulässigen Formaten für Zeitzonenangaben finden Sie in der Dokumentation zu Ihrem Betriebssystem.

  • --user={user_name | user_id}

    Führt den Server mysqld als Benutzer mit dem spezifizierten Benutzernamen (user_name) oder der numerischen Benutzerkennung (user_id) aus. („Benutzer“ bezeichnet in diesem Kontext ein Systemanmeldekonto und keinen in den Grant-Tabellen aufgeführten MySQL-Benutzer.)

Wenn Sie mysqld_safe mit den Optionen --defaults-file oder --defaults-extra-option ausführen, um eine Optionsdatei zu benennen, dann muss diese Option als erste auf der Befehlszeile angegeben werden, da die Optionsdatei andernfalls nicht benutzt wird. So wird die Optionsdatei etwa bei folgendem Befehl nicht verarbeitet:

mysql> mysqld_safe --port=port_num --defaults-file=file_name

Verwenden Sie stattdessen den folgenden Befehl:

mysql> mysqld_safe --defaults-file=file_name --port=port_num

Das Skript mysqld_safe ist so abgefasst, dass es normalerweise einen Server starten kann, der aus einer Quell- oder eine Binärdistribution von MySQL installiert wurde, auch wenn diese Distributionstypen den Server normalerweise an etwas anderen Positionen installieren. (Siehe auch Abschnitt 2.1.5, „Installationslayouts“.) mysqld_safe setzt voraus, dass eine der folgenden Bedingungen erfüllt ist:

  • Server und Datenbanken befinden sich relativ zum Arbeitsverzeichnis (d. h. zu dem Verzeichnis, aus dem heraus mysqld_safe aufgerufen wurde). Bei Binärdistributionen sucht mysqld_safe in seinem Arbeitsverzeichnis nach den Verzeichnissen bin und data. Bei Quelldistributionen hingegen wird nach den Verzeichnissen libexec und var gesucht. Diese Bedingung sollte erfüllt sein, wenn Sie mysqld_safe aus Ihrem MySQL-Installationsverzeichnis heraus aufrufen (z. B. /usr/local/mysql bei einer Binärdistribution).

  • Wenn der Server und die Datenbanken relativ zum Arbeitsverzeichnis nicht vorgefunden werden, versucht mysqld_safe sie anhand absoluter Pfadnamen zu ermitteln. Typische Positionen sind /usr/local/libexec und /usr/local/var. Die tatsächlichen Verzeichnisse werden den Werten entnommen, die bei der Erstellung in die Distribution einkonfiguriert wurden. Sie sollten korrekt sein, wenn MySQL im während der Konfiguration angegebenen Verzeichnis installiert ist.

Da mysqld_safe den Server und die Datenbanken relativ zum eigenen Arbeitsverzeichnis zu finden versucht, können Sie eine MySQL-Binärdistribution an beliebiger Stelle installieren, solange Sie mysqld_safe aus dem MySQL-Installationsverzeichnis heraus aufrufen:

shell> cd mysql_installation_directory
shell> bin/mysqld_safe &

Wenn mysqld_safe fehlschlägt, obwohl es aus dem MySQL-Installationsverzeichnis heraus aufgerufen wurde, können Sie die Optionen --ledir und --datadir angeben, um die Verzeichnisse anzuzeigen, in denen der Server und die Datenbanken auf Ihrem System vorhanden sind.

Normalerweise sollten Sie das Skript mysqld_safe nicht bearbeiten. Konfigurieren Sie stattdessen mysqld_safe über Befehlszeilenoptionen oder Optionen im Abschnitt [mysqld_safe] einer Optionsdatei my.cnf. In seltenen Fällen kann es unter Umständen erforderlich sein, mysqld_safe zu modifizieren, damit der Server korrekt startet. Beachten Sie allerdings, dass Ihre geänderte Version von mysqld_safe bei einem zukünftigen MySQL-Upgrade überschrieben werden könnte; deswegen sollten Sie eine Kopie der editierten Version erstellen, die Sie bei Bedarf neu installieren können.

Unter NetWare ist mysqld_safe ein NLM, das aus dem ursprünglichen Unix-Shell-Skript portiert wurde. Es startet den Server wie folgt:

  1. Eine Reihe von System- und Optionstest wird ausgeführt.

  2. Die MyISAM-Tabellen werden überprüft.

  3. Es wird eine Bildschirmpräsenz für den MySQL-Server bereitgestellt.

  4. mysqld wird gestartet und überwacht. Wird es mit einem Fehler beendet, so erfolgt ein Neustart.

  5. Fehlermeldungen von mysqld werden in die Datei host_name.err im Datenverzeichnis geschrieben.

  6. Bildschirmausgaben von mysqld_safe werden in die Datei host_name.safe im Datenverzeichnis geschrieben.

5.4.2. mysql.server — Startskript für den MySQL-Server

MySQL-Distributionen unter Unix enthalten ein Skript namens mysql.server. Dieses kann auf Systemen wie Linux oder Solaris verwendet werden, die Ausführungsverzeichnisse im System V-Stil verwenden. Ferner wird es vom Mac OS X-Startobjekt für MySQL benutzt.

Sie finden mysql.server im Verzeichnis support-files, das sich im MySQL-Installationsverzeichnis befindet, oder in einer MySQL-Quelldistribution.

Wenn Sie das Linux-Server-RPM-Paket (MySQL-server-VERSION.rpm) einsetzen, wird das Skript mysql.server im Verzeichnis /etc/init.d unter dem Namen mysql installiert. Sie müssen die Installation also nicht manuell vornehmen. Weitere Informationen zu Linux-RPM-Paketen finden Sie in Abschnitt 2.4, „MySQL unter Linux installieren“.

Manche Anbieter stellen RPM-Pakete bereit, die ein Startskript unter einem anderen Namen wie etwa mysqld installieren.

Wenn Sie MySQL aus einer Quelldistribution installieren oder ein Binärdistributionsformat verwenden, das mysql.server nicht automatisch installiert, können Sie es manuell installieren. Eine Anleitung finden Sie in Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.

mysql.server liest Optionen aus den Abschnitten [mysql.server] und [mysqld] der Optionsdateien aus. Aus Gründen der Abwärtskompatibilität werden auch [mysql_server]-Abschnitte ausgelesen, aber Sie sollten diese Abschnitte bei MySQL 5.1-Installationen in [mysql.server] umbenennen.

5.4.3. mysqld_multi — Verwalten mehrerer MySQL-Server

mysqld_multi wurde entwickelt, um mehrere mysqld-Prozesse zu verwalten, die auf Verbindungen über verschiedene Unix-Socketdateien oder TCP/IP-Ports horchen. Das Skript kann Server starten und beenden und den aktuellen Status melden. Eine Alternative zur Verwaltung mehrerer Server ist der MySQL Instance Manager (siehe auch Abschnitt 5.5, „mysqlmanager — Der MySQL Instance Manager“).

mysqld_multi sucht nach Abschnitten namens [mysqldN] in my.cnf (bzw. in der Datei, die mit der Option --config-file angegeben wurde). N kann eine beliebige positive Ganzzahl sein. Diese Zahl wird in der folgenden Abhandlung als Abschnittsnummer bzw. als GNR (vom Englischen „Group Number“) bezeichnet. Abschnittsnummern trennen Abschnitte in Optionsdateien voneinander und werden als Argumente für mysqld_multi verwendet. Sie geben an, welche Server Sie starten oder beenden bzw. zu welchen Servern Sie einen Statusbericht anfordern wollen. Die Optionen, die in diesen Abschnitten aufgelistet sind, sind identisch mit denen, die Sie im Abschnitt [mysqld] angeben würden, der zum Starten von mysqld verwendet wird. (Siehe z. B. Abschnitt 2.9.2.2, „MySQL automatisch starten und anhalten“.) Wenn Sie allerdings mehrere Server verwenden, ist es erforderlich, dass jeder dieser Server seinen eigenen Optionswert (z. B. die Unix-Socketdatei oder die TCP/IP-Portnummer) verwendet. Weitere Informationen dazu, welche Optionen in einer Multiserverumgebung für jeden Server eindeutig sein müssen, finden Sie in Abschnitt 5.13, „Mehrere MySQL-Server auf derselben Maschine laufen lassen“.

Um mysqld_multi aufzurufen, verwenden Sie folgende Syntax:

shell> mysqld_multi [options] {start|stop|report} [GNR[,GNR] ...]

start, stop und report geben die jeweilig durchzuführende Operation an. Sie können die angegebene Operation für einen oder mehrere Server abhängig davon durchführen lassen, welche GNR-Liste auf die Option folgt. Ist keine Liste vorhanden, dann führt mysqld_multi den Vorgang für alle Server in der Optionsdatei aus.

Jeder GNR-Wert stellt eine Abschnittsnummer bzw. einen Abschnittsnummernbereich für Optionsdateien dar. Der Wert sollte die Zahl am Ende des Abschnittsnamens in der Optionsdatei sein. So lautet die GNR für einen Abschnitt namens [mysqld17] etwa 17. Um einen Zahlenbereich anzugeben, trennen Sie die erste und die letzte Zahl durch einen Bindestrich. Der GNR-Wert 10-13 bezeichnet also die Abschnitte [mysqld10] bis [mysqld13]. Mehrere Abschnitte oder Abschnittsbereiche lassen sich – getrennt durch Kommata – auf der Befehlszeile angeben. Es dürfen keine Whitespace-Zeichen (d. h. Leerzeichen oder Tabulatoren) in der GNR-Liste erscheinen, da alle auf ein solches Zeichen folgenden Angaben ignoriert werden.

Der folgende Befehl startet einen einzelnen Server unter Verwendung des Optionsabschnitts [mysqld17]:

shell> mysqld_multi start 17

Der folgende Befehl beendet mehrere Server unter Verwendung der Abschnittsgruppen [mysqld8] sowie [mysqld10] bis [mysqld13]:

shell> mysqld_multi stop 8,10-13

Ein Beispiel, wie man eine Optionsdatei konfigurieren kann, bietet der folgende Befehl:

shell> mysqld_multi --example

mysqld_multi unterstützt die folgenden Optionen:

  • --help

    Zeigt eine Hilfsmeldung an und wird dann beendet.

  • --config-file=name

    Gibt den Namen einer alternativen Optionsdatei an. Die Option bestimmt, wo mysqld_multi nach [mysqldN]-Optionsabschnitten sucht. Ohne Angabe dieser Option werden alle Optionen aus der normalen Optionsdatei my.cnf ausgelesen. Die Option beeinflusst nicht, wo mysqld_multi seine eigenen Optionen ausliest (diese werden immer dem Abschnitt [mysqld_multi] in der normalen Datei my.cnf entnommen).

  • --example

    Zeigt eine Beispieloptionsdatei an.

  • --log=file_name

    Gibt den Namen der Logdatei an. Wenn die Datei vorhanden ist, werden geloggte Einträge angehängt.

  • --mysqladmin=prog_name

    Gibt die mysqladmin-Binärdatei an, die zum Beenden von Servern verwendet wird.

  • --mysqld=prog_name

    Die zu verwendende mysqld-Binärdatei. Beachten Sie, dass Sie auch mysqld_safe als Wert angeben können. Wenn Sie den Server mit mysqld_safe starten, können Sie die Optionen mysqld oder ledir im entsprechenden Abschnitt [mysqldN] angeben. Diese Optionen bezeichnen den Namen des Servers, den mysqld_safe starten soll, und den Pfadnamen des Verzeichnisses, in dem der Server sich befindet. (Beschreibungen zu diesen Optionen finden Sie in Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“.) Beispiel:

    [mysqld38]
    mysqld = mysqld-max
    ledir  = /opt/local/mysql/libexec
    
  • --no-log

    Schreibt Loginformationen in stdout statt in die Logdatei. (Standardmäßig erfolgt die Ausgabe in die Logdatei.)

  • --password=password

    Passwort des MySQL-Kontos, das für den Aufruf von mysqladmin verwendet wird. Beachten Sie, dass der Passwortwert – anders als bei anderen MySQL-Programmen – bei dieser Option nicht optional ist.

  • --silent

    Stummer Modus (Warnungen werden deaktiviert).

  • --tcp-ip

    Alle betreffenden MySQL-Server werden statt über die Unix-Socketdatei über den TCP/IP-Port angebunden. (Wenn eine Socketdatei fehlt, kann der Server zwar unter Umständen noch laufen, ist aber nur über den TCP/IP-Port erreichbar.) Standardmäßig werden Verbindungen unter Verwendung der Unix-Socketdatei hergestellt. Diese Option wirkt sich auf alle stop- und reportOperationen aus.

  • --user=user_name

    Benutzername des MySQL-Kontos, das für den Aufruf von mysqladmin verwendet wird.

  • --verbose

    Zeigt mehr Informationen an.

  • --version

    Zeigt die Versionsinformation an und wird dann beendet.

Einige Anmerkungen zu mysqld_multi:

  • Extrem wichtig: Bevor Sie mysqld_multi verwenden, müssen Sie die Bedeutung der Optionen, die an die mysqld-Server übergeben werden, verstanden haben und genau wissen, warum Sie separate mysqld-Prozesse benutzen wollen. Die Verwendung mehrerer mysqld-Server mit demselben Datenverzeichnis ist extrem gefährlich. Sofern Sie nicht genauestens wissen, was Sie tun, verwenden Sie in jedem Fall getrennte Datenverzeichnisse. Das Starten mehrerer Server mit demselben Datenverzeichnis steigert die Leistungsfähigkeit eines Thread-basierten Systems nicht! Siehe auch Abschnitt 5.13, „Mehrere MySQL-Server auf derselben Maschine laufen lassen“.

  • Wichtig: Vergewissern Sie sich, dass das Datenverzeichnis jedes Servers für das Unix-Konto, unter dem der jeweilige mysqld-Prozess gestartet wurde, uneingeschränkt zugänglich ist. Verwenden Sie hierfür keinesfalls das Unix-Konto root, sofern Sie nicht genauestens wissen, was Sie tun. Siehe auch Abschnitt 5.7.5, „Wie man MySQL als normaler Benutzer laufen läßt“.

  • Vergewissern Sie sich, dass das MySQL-Konto, welches zum Beenden der mysqld-Server (mit dem Programm mysqladmin) verwendet wird, für jeden Server den gleichen Benutzernamen und das gleiche Passwort hat. Außerdem müssen Sie sicherstellen, dass das Konto über die Berechtigung SHUTDOWN verfügt. Wenn die Server, die Sie verwalten wollen, unterschiedliche Benutzernamen oder Passwörter für die Administrationskonten aufweisen, sollten Sie auf jedem Server ein Konto mit jeweils demselben Benutzernamen und Passwort einrichten. Sie könnten etwa ein gemeinsames Konto multi_admin erstellen, indem Sie auf jedem Server die folgenden Befehle ausführen:

    shell> mysql -u root -S /tmp/mysql.sock -p
    Enter password:
    mysql> GRANT SHUTDOWN ON *.*
        -> TO 'multi_admin'@'localhost' IDENTIFIED BY 'multipass';
    

    Siehe auch Abschnitt 5.8.2, „Wie das Berechtigungssystem funktioniert“. Sie müssen diesen Schritt für jeden mysqld-Server durchführen. Ändern Sie die Verbindungsparameter entsprechend, wenn Sie mit den einzelnen Servern Verbindungen herstellen. Beachten Sie, dass der Hostnamensteil des Kontonamens die Herstellung einer Verbindung als multi_admin von dem Host aus ermöglichen muss, auf dem sie mysqld_multi ausführen wollen.

  • Die Unix-Socketdatei und die TCP/IP-Portnummer müssen für jeden mysqld-Server unterschiedlich sein.

  • Die Option --pid-file ist sehr wichtig, wenn Sie mysqld_safe zum Starten von mysqld verwenden (z. B. --mysqld=mysqld_safe). Jeder mysqld-Server sollte seine eigene Prozesskennungsdatei haben. Der Vorteil der Verwendung von mysqld_safe anstelle von mysqld besteht darin, dass mysqld_safe seinen mysqld-Prozess überwacht und ihn neu startet, wenn der Prozess aufgrund eines Signals, welches mit kill -9 gesendet wurde, oder aus einem anderen Grund (z. B. wegen eines Segmentierungsfehlers) terminiert wurde. Bitte beachten Sie, dass das Skript mysqld_safe unter Umständen erfordert, dass Sie es von einer bestimmten Position aus starten. Das bedeutet, dass Sie möglicherweise in ein bestimmtes Verzeichnis wechseln müssen, bevor Sie mysqld_multi ausführen. Wenn Sie Probleme mit dem Starten haben, rufen Sie das Skript mysqld_safe zur Anzeige auf. Suchen Sie dort die folgenden Zeilen:

    ----------------------------------------------------------------
    MY_PWD=`pwd`
    # Check if we are starting this relative (for the binary release)
    if test -d $MY_PWD/data/mysql -a -f ./share/mysql/english/errmsg.sys -a \
     -x ./bin/mysqld
    ----------------------------------------------------------------
    

    Der mit diesen Zeilen durchgeführte Test sollte erfolgreich sein, andernfalls könnten Probleme auftreten. Siehe auch Abschnitt 5.4.1, „mysqld_safe — Startskript für den MySQL-Server“.

  • Sie sollten die Option --user für mysqld verwenden. Zu diesem Zweck müssen Sie das Skript mysqld_multi jedoch als Unix-Benutzer root ausführen. Das Einfügen der Option in die Optionsdatei ist irrelevant: Wenn Sie nicht der Superuser sind und die mysqld-Prozesse unter Ihrem eigenen Unix-Konto gestartet werden, erhalten Sie lediglich eine Warnung.

Das folgende Beispiel zeigt, wie Sie eine Optionsdatei zur Verwendung mit mysqld_multi einrichten könnten. Die Reihenfolge, in der die mysqld-Programme gestartet oder beendet werden, hängt von der Reihenfolge ab, in der sie in der Optionsdatei aufgeführt sind. Abschnittsnummern müssen keine durchgehende Folge bilden. Der erste und der fünfte [mysqldN]-Abschnitt wurden im Beispiel absichtlich weggelassen, um zu veranschaulichen, dass es „Lücken“ in der Optionsdatei geben darf. Dies erhöht die Flexibilität.

# This file should probably be in your home dir (~/.my.cnf)
# or /etc/my.cnf
# Version 2.1 by Jani Tolonen

[mysqld_multi]
mysqld     = /usr/local/bin/mysqld_safe
mysqladmin = /usr/local/bin/mysqladmin
user       = multi_admin
password   = multipass

[mysqld2]
socket     = /tmp/mysql.sock2
port       = 3307
pid-file   = /usr/local/mysql/var2/hostname.pid2
datadir    = /usr/local/mysql/var2
language   = /usr/local/share/mysql/english
user       = john

[mysqld3]
socket     = /tmp/mysql.sock3
port       = 3308
pid-file   = /usr/local/mysql/var3/hostname.pid3
datadir    = /usr/local/mysql/var3
language   = /usr/local/share/mysql/swedish
user       = monty

[mysqld4]
socket     = /tmp/mysql.sock4
port       = 3309
pid-file   = /usr/local/mysql/var4/hostname.pid4
datadir    = /usr/local/mysql/var4
language   = /usr/local/share/mysql/estonia
user       = tonu

[mysqld6]
socket     = /tmp/mysql.sock6
port       = 3311
pid-file   = /usr/local/mysql/var6/hostname.pid6
datadir    = /usr/local/mysql/var6
language   = /usr/local/share/mysql/japanese
user       = jani

Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

5.5. mysqlmanager — Der MySQL Instance Manager

mysqlmanager ist der MySQL Instance Manager (IM). Es handelt sich bei diesem Programm um einen über einen TCP/IP-Port ausgeführten Daemon, der die Überwachung und Verwaltung von MySQL-Datenbankserverinstanzen ermöglicht. Der MySQL Instance Manager ist für Unix und verwandte Betriebssysteme sowie für Windows verfügbar.

Der MySQL Instance Manager kann anstelle des Skripts mysqld_safe verwendet werden, um den MySQL-Server sogar von einem Remotehost aus zu starten. Der MySQL Instance Manager implementiert ferner die Funktionalität (sowie beinahe die vollständige Syntax) des Skripts mysqld_multi. Eine detaillierte Beschreibung des MySQL Instance Managers folgt.

5.5.1. MySQL Instance Manager: MySQL-Server starten

In der Regel wird der MySQL-Datenbankserver mysqld mit dem Skript mysql.server gestartet, welches normalerweise im Ordner /etc/init.d/ abgelegt ist. Das Skript ruft standardmäßig das Skript mysqld_safe auf. Sie können die Variable use_mysqld_safe im Skript aber auch auf 0 (Null) setzen, um mit dem MySQL Instance Manager einen Server zu starten.

In diesem Fall hängt das Verhalten des MySQL Instance Managers von den Optionen ab, die in der MySQL-Konfigurationsdatei angegeben sind. Wenn keine Konfigurationsdatei vorhanden ist, erstellt der MySQL Instance Manager eine Serverinstanz namens mysqld und versucht diese mit den vorgabeseitigen (d. h. einkompilierten) Konfigurationswerten zu starten. Das bedeutet, dass der IM die Position eines nicht an der Standardposition installierten mysqld nicht erschließen kann. Wenn Sie den MySQL-Server an einer anderen als der Standardposition installiert haben, sollten Sie eine Konfigurationsdatei verwenden. Siehe auch Abschnitt 2.1.5, „Installationslayouts“.

Ist eine Konfigurationsdatei vorhanden, dann liest der IM deren [mysqld]-Abschnitte (z. B. [mysqld], [mysqld1], [mysqld2] usw.) aus. Jeder dieser Abschnitte gibt eine Instanz an. Wenn der MySQL Instance Manager gestartet wird, versucht er seinerseits alle Serverinstanzen zu starten, die er finden kann. Wird er beendet, dann beendet er selbst standardmäßig alle laufenden Serverinstanzen.

Beachten Sie, dass es eine Sonderoption --mysqld-path=path-to-mysqld-binary gibt, die nur vom IM erkannt wird. Mit dieser Variable können Sie dem IM mitteilen, wo die mysqld-Binärdatei abgelegt ist. Sie sollten ferner die Optionen basedir und datadir für den Server angeben.

Der typische Ablauf beim Starten und Beenden eines MySQL-Servers mit dem MySQL Instance Manager sieht wie folgt aus:

  1. Der MySQL Instance Manager wird mit dem Skript /etc/init.d/mysql gestartet.

  2. Der MySQL Instance Manager startet alle Instanzen und überwacht sie.

  3. Wenn eine Serverinstanz fehlschlägt, startet der MySQL Instance Manager sie neu.

  4. Wird der MySQL Instance Manager heruntergefahren (z. B. mit dem Befehl /etc/init.d/mysql stop), dann fährt er seinerseits zunächst alle Serverinstanzen herunter.

5.5.2. MySQL Instance Manager: Verbinden und Anlegen von Benutzerkonten

Die Kommunikation mit dem MySQL Instance Manager wird mithilfe des MySQL-Client/Server-Protokolls verwaltet. Insofern können Sie mithilfe des mysql-Standardclientprogramms wie auch mit der MySQL-C-API eine Verbindung mit dem IM herstellen. Der IM unterstützt die Version des MySQL-Client/Server-Protokolls, das von den Client-Tools und -Bibliotheken verwendet wird, die den Distributionen seit MySQL 4.1 beiliegen.

5.5.2.1. Instance Manager-Benutzer und Passwörter

Der MySQL Instance Manager speichert die Benutzerdaten in einer Passwortdatei. Der Standardname dieser Passwortdatei lautet /etc/mysqlmanager.passwd.

Passworteinträge haben das folgende Format:

petr:*35110DC9B4D8140F5DE667E28C72DD2597B5C848

Sind keine Einträge in der Datei /etc/mysqlmanager.passwd vorhanden, dann können Sie keine Verbindung zum Instance Manager herstellen.

Um einen neuen Eintrag zu erzeugen, rufen Sie den Instance Manager mit der Option --passwd auf. Die Ausgabe kann nachfolgend an die Datei /etc/mysqlmanager.passwd angehängt werden, um einen neuen Benutzer hinzuzufügen. Hier ein Beispiel:

shell> mysqlmanager --passwd >> /etc/mysqlmanager.passwd
Creating record for new user.
Enter user name: mike
Enter password: password
Re-type password: password

Der vorangegangene Befehl bewirkt das Hinzufügen der folgenden Zeile zur Datei /etc/mysqlmanager.passwd:

mike:*00A51F3F48415C7D4E8908980D443C29C69B60C9

5.5.2.2. MySQL-Serverkonten zur Statusüberwachung

Um den Serverstatus zu überwachen, versucht der MySQL Instance Manager in regelmäßigen Abständen eine Verbindung zur MySQL-Serverinstanz herzustellen. Hierzu verwendet er das Benutzerkonto MySQL_Instance_Manager@localhost mit dem Passwort check_connection.

Sie müssen kein Benutzerkonto MySQL_Instance_M@localhost erstellen, damit der MySQL Instance Manager den Serverstatus überwacht, denn eine fehlgeschlagene Anmeldung ist bereits ausreichend, um sicherzustellen, dass der Server betriebsbereit ist. Wenn allerdings dieses Konto nicht vorhanden ist, werden fehlgeschlagene Anmeldeversuche vom Server im allgemeinen Anfragelog vermerkt (siehe auch Abschnitt 5.12.2, „Die allgemeine Anfragen-Logdatei“).

5.5.3. MySQL Instance Manager: Befehlsoptionen

Der MySQL Instance Manager unterstützt eine Reihe von Befehlszeilenoptionen. Eine kurze Auflistung erhalten Sie, indem Sie mysqlmanager mit der Option --help aufrufen.

mysqlmanager unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --bind-address=IP

    Die IP-Adresse, zu der eine Bindung hergestellt wird.

  • --default-mysqld-path=path

    Unter Unix der Pfadname der MySQL-Serverbinärdatei, sofern kein Pfad im Instanzabschnitt angegeben ist. Beispiel: --default-mysqld-path=/usr/sbin/mysqld

  • --defaults-file=file_name

    Datei, aus der die Einstellungen für den Instance Manager und MySQL Server ausgelesen werden sollen. Alle Konfigurationsänderungen, die der Instance Manager durchführt, werden an dieser Datei vorgenommen. Wenn diese Option verwendet wird, muss Sie auf der Befehlszeile die erste angegebene Option sein.

  • --install

    Gibt an, dass der Instance Manager unter Windows als Dienst installiert werden soll.

  • --log=file_name

    Der Pfad zur IM-Logdatei. Wird mit der Option --run-as-service verwendet.

  • --monitoring-interval=seconds

    Das Intervall zur Überwachung der Instanzen, angegeben in Sekunden. Der Vorgabewert beträgt 20 Sekunden. Der Instance Manager versucht mit jeder überwachten Instanz eine Verbindung herzustellen, um festzustellen, ob sie läuft bzw. nicht abgestürzt ist. Stellt der Instance Manager fest, dass die Instanz terminiert wurde, versucht er mehrfach, sie neu zu starten. Über die Option nonguarded im Abschnitt der betreffenden Instanz kann man dieses Verhalten für eine bestimmte Instanz deaktivieren.

  • --passwd, -P

    Bereitet einen Eintrag für die Passwortdatei vor und beendet sich dann.

  • --password-file=file_name

    Datei, in der nach Instance Manager-Benutzern und -Passwörtern gesucht wird. Die Standarddatei ist /etc/mysqlmanager.passwd.

  • --pid-file=file_name

    Die zu verwendende Prozesskennung. Standardmäßig heißt die Datei mysqlmanager.pid.

  • --port=port_num

    Die TCP/IP-Portnummer, die für eingehende Verbindungen verwendet werden soll (der von der IANA vergebene Standardport ist 2273).

  • --print-defaults

    Gibt die aktuellen Standardwerte an und beendet sich nachfolgend. Wenn diese Option verwendet wird, muss Sie auf der Befehlszeile die erste angegebene Option sein.

  • --remove

    Gibt unter Windows an, dass der Instance Manager als Windows-Dienst entfernt wird. Dies setzt voraus, dass der Instance Manager zuvor mit der Option --install ausgeführt wurde.

  • --run-as-service

    Gibt an, dass eine Daemonisierung durchgeführt und nachfolgend der Engelsprozess gestartet werden soll. Der Engelsprozess ist einfach und stürzt mit hoher Wahrscheinlichkeit nicht ab. Im Falle eines Absturzes startet er den Instance Manager selbst neu.

  • --socket=path

    Unter Unix die Socketdatei, die für eingehende Verbindungen verwendet werden soll. Standardmäßig heißt die Datei /tmp/mysqlmanager.sock.

  • --standalone

    Führt den Instance Manager unter Windows im autarken Modus aus.

  • --user=user_name

    Benutzername, unter dem mysqlmanager gestartet und ausgeführt werden soll. Es wird empfohlen, mysqlmanager unter demselben Benutzerkonto auszuführen, unter dem auch der Server mysqld läuft. („Benutzer“ bezeichnet in diesem Kontext ein Systemanmeldekonto und keinen in den Grant-Tabellen aufgeführten MySQL-Benutzer.)

  • --version, -V

    Gibt die Versionsinformation aus und wird dann beendet.

5.5.4. MySQL Instance Manager: Konfigurationsdateien

Der Instance Manager verwendet die Standarddatei my.cnf. Aus dem Abschnitt [manager] liest er Optionen für sich selbst, aus den [mysqld]-Abschnitten Optionen für die Erstellung von Instanzen aus. Der Abschnitt [manager] enthält Optionen, die unter Abschnitt 5.5.3, „MySQL Instance Manager: Befehlsoptionen“ aufgeführt sind. Hier ein Beispiel für einen [manager]-Abschnitt:

# MySQL Instance Manager options section
[manager]
default-mysqld-path = /usr/local/mysql/libexec/mysqld
socket=/tmp/manager.sock
pid-file=/tmp/manager.pid
password-file = /home/cps/.mysqlmanager.passwd
monitoring-interval = 2
port = 1999
bind-address = 192.168.1.5

Der MySQL Instance Manager liest und verwaltet die Datei /etc/my.cnf nur unter Linux. Unter Windows liest der MySQL Instance Manager die Datei my.ini in dem Verzeichnis aus, in dem der Instance Manager installiert ist. Die Standardposition der Optionsdatei kann mit der Option --defaults-file=file_name geändert werden.

Instanzabschnitte geben Optionen an, die für jede Instanz beim Start festgelegt werden. Es handelt sich hierbei in erster Linie um normale MySQL-Serveroptionen, allerdings sind auch ein paar IM-spezifische Optionen vorhanden:

  • mysqld-path = path

    Pfadname zur Binärdatei des mysqld-Servers.

  • shutdown-delay = seconds

    Dauer (in Sekunden), die der IM auf das Herunterfahren der Instanz warten soll. Der Vorgabewert beträgt 35 Sekunden. Wird dieses Intervall überschritten, dann geht der IM davon aus, dass die Instanz abgestürzt ist, und versucht sie zu terminieren. Wenn Sie InnoDB mit großen Tabellen verwenden, sollten Sie diesen Wert erhöhen.

  • nonguarded

    Diese Option sollte angegeben werden, wenn Sie die IM-Überwachungsfunktion für eine bestimmte Instanz deaktivieren wollen.

Es folgen einige Beispiele für Instanzabschnitte:

[mysqld]
mysqld-path=/usr/local/mysql/libexec/mysqld
socket=/tmp/mysql.sock
port=3307
server_id=1
skip-stack-trace
core-file
skip-bdb
log-bin
log-error
log=mylog
log-slow-queries

[mysqld2]
nonguarded
port=3308
server_id=2
mysqld-path= /home/cps/mysql/trees/mysql-5.1/sql/mysqld
socket     = /tmp/mysql.sock5
pid-file   = /tmp/hostname.pid5
datadir= /home/cps/mysql_data/data_dir1
language=/home/cps/mysql/trees/mysql-5.1/sql/share/english
log-bin
log=/tmp/fordel.log

5.5.5. MySQL Instance Manager: Unterstützte Befehle

Wenn Sie eine Passwortdatei für den MySQL Instance Manager eingerichtet haben und dieser ausgeführt wird, können Sie mit ihm eine Verbindung herstellen. Sie können den Client mysql verwenden, um eine Verbindung über eine MySQL-Standard-API herzustellen. Die folgende Liste zeigt die vom Instance Manager derzeit verarbeiteten Befehle mit Beispielen.

  • START INSTANCE instance_name

    Dieser Befehl versucht eine Instanz zu starten.

    mysql> START INSTANCE mysqld4;
    Query OK, 0 rows affected (0,00 sec)
    
  • STOP INSTANCE instance_name

    Dieser Befehl versucht eine Instanz zu beenden.

    mysql> STOP INSTANCE mysqld4;
    Query OK, 0 rows affected (0,00 sec)
    
  • SHOW INSTANCES

    Zeigt die Namen aller geladenen Instanzen an.

    mysql> SHOW INSTANCES;
    +---------------+---------+
    | instance_name | status  |
    +---------------+---------+
    | mysqld3       | offline |
    | mysqld4       | online  |
    | mysqld2       | offline |
    +---------------+---------+
    3 rows in set (0,04 sec)
    
  • SHOW INSTANCE STATUS instance_name

    Zeigt den Status und die Versionsinformation für eine Instanz an.

    mysql> SHOW INSTANCE STATUS mysqld3;
    +---------------+--------+---------+
    | instance_name | status | version |
    +---------------+--------+---------+
    | mysqld3       | online | unknown |
    +---------------+--------+---------+
    1 row in set (0.00 sec)
    
  • SHOW INSTANCE OPTIONS instance_name

    Zeigt die von der Instanz verwendeten Optionen an.

    mysql> SHOW INSTANCE OPTIONS mysqld3;
    +---------------+---------------------------------------------------+
    | option_name   | value                                             |
    +---------------+---------------------------------------------------+
    | instance_name | mysqld3                                           |
    | mysqld-path   | /home/cps/mysql/trees/mysql-4.1/sql/mysqld        |
    | port          | 3309                                              |
    | socket        | /tmp/mysql.sock3                                  |
    | pid-file      | hostname.pid3                                     |
    | datadir       | /home/cps/mysql_data/data_dir1/                   |
    | language      | /home/cps/mysql/trees/mysql-4.1/sql/share/english |
    +---------------+---------------------------------------------------+
    7 rows in set (0.01 sec)
    
  • SHOW instance_name LOG FILES

    Dieser Befehl listet alle von der Instanz verwendeten Logdateien auf. Die Ergebnisliste enthält die Pfade und die Größe der Logdateien. Wird in der Konfigurationsdatei kein Logdateipfad (wie etwa log=/var/mysql.log) angegeben, dann versucht der Instance Manager, die Position der Logdatei zu erschließen. Wenn der IM die Position jedoch nicht erraten kann, dann sollten Sie sie unter Verwendung der entsprechenden Logoption explizit im Instanzabschnitt der Konfigurationsdatei angeben.

    mysql> SHOW mysqld LOG FILES;
    +-------------+------------------------------------+----------+
    | Logfile     | Path                               | Filesize |
    +-------------+------------------------------------+----------+
    | ERROR LOG   | /home/cps/var/mysql/owlet.err      | 9186     |
    | GENERAL LOG | /home/cps/var/mysql/owlet.log      | 471503   |
    | SLOW LOG    | /home/cps/var/mysql/owlet-slow.log | 4463     |
    +-------------+------------------------------------+----------+
    3 rows in set (0.01 sec)
    
  • SHOW instance_name LOG {ERROR | SLOW | GENERAL} size[,offset_from_end]

    Dieser Befehl ruft einen Teil der angegebenen Logdatei ab. Da die meisten Benutzer wohl an den neuesten Logmeldungen interessiert sein werden, können Sie mit dem Parameter size die Anzahl der Bytes definieren, die Sie – rückwärts vom Ende der Logdatei ausgehend – abrufen wollen. Sie können Daten aber auch aus einem Bereich mitten in der Datei abrufen, indem Sie den optionalen Parameter offset_from_end angeben. Das folgende Beispiel ruft 21 Datenbytes ab, beginnend 23 Bytes vor dem Ende der Logdatei und zwei Bytes vor ihrem Ende endend:

    mysql> SHOW mysqld LOG GENERAL 21, 2;
    +---------------------+
    | Log                 |
    +---------------------+
    | using password: YES |
    +---------------------+
    1 row in set (0.00 sec)
    
  • SET instance_name.option_name=option_value

    Dieser Befehl bearbeitet die Konfigurationsdatei der angegebenen Instanz dahingehend, dass er Instanzoptionen ändert oder hinzufügt. Der IM geht dabei davon aus, dass die Konfigurationsdatei sich in /etc/my.cnf befindet. Sie sollten sicherstellen, dass die Datei existiert und die passenden Berechtigungen hat.

    mysql> SET mysqld2.port=3322;
    Query OK, 0 rows affected (0.00 sec)
    

    Änderungen, die an der Konfigurationsdatei vorgenommen werden, werden erst beim nächsten Start des MySQL-Servers umgesetzt. Außerdem werden diese Änderungen erst im lokalen Cache des Instance Managers für die Instanzeinstellungen gespeichert, wenn der Befehl FLUSH INSTANCES ausgeführt wird.

  • UNSET instance_name.option_name

    Dieser Befehl entfernt eine Option aus der Konfigurationsdatei einer Instanz.

    mysql> UNSET mysqld2.port;
    Query OK, 0 rows affected (0.00 sec)
    

    Änderungen, die an der Konfigurationsdatei vorgenommen werden, werden erst beim nächsten Start des MySQL-Servers umgesetzt. Außerdem werden diese Änderungen erst im lokalen Cache des Instance Managers für die Instanzeinstellungen gespeichert, wenn der Befehl FLUSH INSTANCES ausgeführt wird.

  • FLUSH INSTANCES

    Dieser Befehl erzwingt das Neueinlesen der Konfigurationsdatei durch den IM und die Aktualisierung der internen Strukturen. Der Befehl sollte nach einer Bearbeitung der Konfigurationsdatei ausgeführt werden. Er startet Instanzen nicht neu.

    mysql> FLUSH INSTANCES;
    Query OK, 0 rows affected (0.04 sec)
    

5.6. mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen

Einige Releases von MySQL enthalten Änderungen an der Struktur der Systemtabellen in der mysql-Datenbank, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Update auf eine neue Version von MySQL durchführen, sollten Sie auch Ihre Systemtabellen aktualisieren, um sicherzustellen, dass ihre Struktur auf dem neuesten Stand ist. Andernfalls können Sie bestimmte Funktionen unter Umständen nicht nutzen. Erstellen Sie zunächst eine Sicherung der mysql-Datenbank und gehen Sie dann wie nachfolgend beschrieben vor.

Unter Unix und verwandten Systemen aktualisieren Sie die Systemtabellen, indem Sie das Skript mysql_fix_privilege_tables ausführen:

shell> mysql_fix_privilege_tables

Sie müssen dieses Skript zur Laufzeit des Servers ausführen. Es versucht dann, eine Verbindung zu dem Server herzustellen, der auf dem lokalen Host als root ausgeführt wird. Wenn Ihr root-Konto ein Passwort erfordert, geben Sie dieses wie folgt auf der Befehlszeile an:

shell> mysql_fix_privilege_tables --password=root_password

Das Skript mysql_fix_privilege_tables führt alle Vorgänge aus, die notwendig sind, um Ihre Systemtabellen in das aktuelle Format zu konvertieren. Unter Umständen wird mehrmals die Warnung Duplicate column name angezeigt, die Sie aber getrost ignorieren können.

Nach der Ausführung des Skripts beenden Sie den Server und starten ihn neu.

Auf Windows-Systemen enthalten MySQL-Distributionen ein SQL-Skript namens mysql_fix_privilege_tables.sql, das Sie mithilfe des Clients mysql ausführen können. Wenn Ihre MySQL-Installation sich beispielsweise im Verzeichnis C:\Programme\MySQL\MySQL Server 5.1 befindet, sieht der Befehl wie folgt aus:

C:\> cd "C:\Program Files\MySQL\MySQL Server 5.1"
C:\> bin\mysql -u root -p mysql
mysql> SOURCE scripts/mysql_fix_privilege_tables.sql

Der Befehl mysql fordert Sie dann auf, das root-Passwort einzugeben. Folgen Sie dieser Aufforderung.

Wenn Ihre Installation sich in einem anderen Verzeichnis befindet, geben Sie die entsprechenden Pfadnamen ein.

Wie bei der Vorgehensweise unter Unix können auch hier Warnungen vom Typ Duplicate column name angezeigt werden, während mysql die Anweisungen im Skript mysql_fix_privilege_tables.sql verarbeitet, und auch hier können Sie diese ignorieren.

Nach der Ausführung des Skripts beenden Sie den Server und starten ihn neu.

5.7. Absichern von MySQL gegen Angreifer

Dieser Abschnitt beschreibt einige allgemeine Sicherheitsfragen, die man beachten sollte, und erläutert, was Sie tun können, um Ihre MySQL-Installation besser gegen Angriffe und Missbrauch zu schützen. Informationen, die speziell das Zugriffssteuerungssystem betreffen, das MySQL zur Konfiguration von Benutzerkonten und zur Überprüfung des Datenbankzugriffs verwendet, finden Sie in Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“.

5.7.1. Allgemeine Sicherheitsrichtlinien

Jeder, der MySQL auf einem mit dem Internet verbundenen Computer betreibt, sollte diesen Abschnitt lesen, um die häufigsten sicherheitsspezifischen Fehler zu vermeiden.

In unserer Beschreibung zur Sicherheit wollen wir die Notwendigkeit betonen, den gesamten Serverhost (und nicht nur den MySQL-Server) gegen alle möglichen Angriffe zu schützen: Lauschangriffe, Modifikationen, Wiedergabe und DoS (Denial of Service, Dienstablehnung). Wir werden an dieser Stelle nicht alle Aspekte der Verfügbarkeit und Fehlertoleranz behandeln.

MySQL benutzt ein Sicherheitssystem, welches auf ACLs (Access Control Lists, Zugriffssteuerungslisten) basiert, für alle Verbindungen, Abfragen und anderen Operationen, die Benutzer durchzuführen versuchen können. Ferner unterstützt werden SSL-verschlüsselte Verbindungen zwischen MySQL-Clients und -Servern. Viele der hier beschriebenen Konzepte sind keineswegs MySQL-spezifisch, sondern gelten vielmehr für fast alle gängigen Anwendungen.

Wenn Sie MySQL ausführen, befolgen Sie, sofern irgendwie möglich, die folgenden Richtlinien:

  • Gewähren Sie niemals irgendjemandem (mit Ausnahme von MySQL-root-Konten) Zugang zur Tabelle user in der mysql-Datenbank! Dies ist entscheidend. Das verschlüsselte Passwort ist das echte Passwort in MySQL. Jeder, der das Passwort kennt, welches in der Tabelle user aufgeführt ist, und Zugang zu dem für das betreffende Konto gelisteten Host hat, kann sich problemlos als dieser Benutzer anmelden.

  • Machen Sie sich mit dem MySQL-Zugriffsberechtigungssystem vertraut. Die Anweisungen GRANT und REVOKE werden zur Steuerung des Zugriffs auf MySQL verwendet. Gewähren Sie nie mehr Berechtigungen als notwendig. Gewähren Sie Berechtigungen niemals allen Hosts.

    Checkliste:

    • Geben Sie mysql -u root ein. Wenn Sie mit dem Server erfolgreich eine Verbindung herstellen können, ohne nach einem Passwort gefragt worden zu sein, dann kann jede Person als MySQL-Benutzer root eine solche Verbindung mit Ihrem MySQL-Server herstellen und hat nachfolgend alle Berechtigungen! Lesen Sie noch einmal die MySQL-Installationsanleitung und achten Sie dabei insbesondere auf Informationen zur Einstellung eines root-Passworts. Siehe auch Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“.

    • Überprüfen Sie mithilfe der Anweisung SHOW GRANTS, welche Konten worauf zugreifen können. Entfernen Sie dann nicht erforderliche Berechtigungen mit der REVOKE-Anweisung.

  • Speichern Sie Passwörter nicht unverschlüsselt in Ihrer Datenbank. Wenn der Computer in die Hände eines Angreifers fällt, kann dieser die Passwortliste lesen und die Passwörter verwenden. Verwenden Sie stattdessen MD5(), SHA1() oder eine andere unidirektionale Hashing-Funktion und speichern Sie den Hash-Wert.

  • Wählen Sie keine Passwörter aus Wörterbüchern aus. Es gibt Spezialprogramme zum Knacken von Passwörtern. Sogar Passwörter wie „fisch98“ sind ziemlich schlecht. Wesentlich besser ist „duaxg98“: Dieses Passwort enthält zwar auch das Wort „fisch“, jedoch wurde jeder Buchstabe auf einer QWERTZ-Standardtastatur durch die Taste zu seiner Linken ersetzt. Eine andere Methode, ein Passwort zu verwenden, besteht darin, die jeweils ersten Buchstaben jedes Wortes eines Satzes zu benutzen; so wird etwa aus „Hoch auf dem gelben Wagen“ ganz einfach das Passwort „HadgW“. Dieses Passwort ist vergleichsweise einfach zu merken und einzugeben, aber für jemanden, der den Satz gar nicht kennt, schwer zu erraten.

  • Schaffen Sie eine Firewall an. Diese schützt Sie vor mindestens 50 Prozent aller Sicherheitslücken in jeder beliebigen Software. Setzen Sie MySQL hinter die Firewall oder in eine DMZ (De-Militarized Zone, entmilitarisierte Zone).

    Checkliste:

    • Scannen Sie Ihre Ports aus dem Internet heraus mithilfe eines Tools wie nmap. MySQL verwendet standardmäßig Port 3306. Dieser Port sollte für nicht vertrauenswürdige Hosts nicht zugänglich sein. Eine weitere einfache Möglichkeit zu prüfen, ob Ihr MySQL-Port offen ist oder nicht, besteht darin, den folgenden Befehl an einem entfernten System einzugeben. Hierbei ist server_host der Hostname oder die IP-Nummer des Hosts, auf dem Ihr MySQL-Server ausgeführt wird:

      shell> telnet server_host 3306
      

      Wenn Sie eine Verbindung erhalten und einige sinnlose Zeichen angezeigt werden, ist der Port geöffnet; Sie sollten ihn dann umgehend mit Ihrer Firewall oder Ihrem Router schließen, es sei denn, es gäbe einen guten Grund dafür, dass der Port offen ist. Wenn telnet hängt oder die Verbindung abgewiesen wird, dann ist der Port gesperrt – so soll es sein.

  • Schenken Sie Daten, die von Benutzern Ihrer Anwendungen eingegeben wurden, kein Vertrauen. Benutzer können Ihren Code überlisten, indem Sie Sonderzeichen oder Zeichenfolgen mit vorangestelltem Escape-Zeichen in Webformulare, URLs oder andere Eingabemöglichkeiten der von Ihnen erstellten Anwendungen eintragen. Sie müssen sicherstellen, dass Ihre Anwendung auch dann sicher bleibt, wenn ein Benutzer so etwas wie „; DROP DATABASE mysql;“ eingibt. Dies ist natürlich ein Extrembeispiel, aber große Sicherheitslücken oder umfangreiche Datenverlust können die Folge sein, wenn Hacker ähnliche Methoden verwenden und Sie nicht darauf vorbereitet sind.

    Ein häufiger Fehler besteht darin, nur String-Datenwerte zu schützen. Denken Sie daran, auch numerische Daten abzusichern. Wenn eine Anwendung eine Abfrage wie SELECT * FROM table WHERE ID=234 erzeugt, weil ein Benutzer den Wert 234 eingegeben hat, dann kann der Benutzer auch den Wert 234 OR 1=1 eingeben; hierauf generiert die Anwendung die Abfrage SELECT * FROM table WHERE ID=234 OR 1=1. Folge ist, dass der Server jeden Datensatz in der Tabelle abruft. Mithin wird jeder Datensatz angezeigt, zudem wird der Server extrem belastet. Die einfachste Möglichkeit, sich vor diesem Angriffstyp zu schützen, besteht darin, numerische Konstanten in Anführungszeichen zu setzen: SELECT * FROM table WHERE ID='234'. Gibt nämlich der Benutzer zusätzliche Daten an, so werden sie alle Teil des Strings. In einem numerischen Kontext wandelt MySQL diesen String automatisch in eine Zahl um und entfernt alle nachfolgenden nichtnumerischen Zeichen.

    Manche Leute gehen davon aus, dass eine Datenbank, die nur öffentlich verfügbare Daten enthält, nicht geschützt werden muss. Das stimmt nicht. Auch wenn jeder Datensatz in der Datenbank angezeigt werden dürfte, sollten Sie sich trotzdem etwa gegen DoS-Angriffe schützen (z. B. jene, die auf der im vorigen Absatz beschriebenen Methode basieren und den Server dazu bringen, Ressourcen zu vergeuden). Andernfalls kann Ihr Server für legitime Benutzer unerreichbar werden.

    Checkliste:

    • Geben Sie einfache und doppelte Anführungszeichen (‘'’ bzw. ‘"’) in all Ihre Webformulare ein. Wird irgendein MySQL-Fehler ausgegeben, dann untersuchen Sie das Problem umgehend.

    • Versuchen Sie, dynamische URLs durch Hinzufügen von %22 (‘"’), %23 (‘#’) und %27 (‘'’) zu modifizieren.

    • Versuchen Sie, die Datentypen in dynamischen URLs von numerischen auf Zeichentypen umzustellen, indem Sie die in den obigen Beispielen verwendeten Zeichen eingeben. Ihre Anwendung sollte gegen solche und ähnliche Angriffe gewappnet sein.

    • Geben Sie Buchstaben, Leer- und Sonderzeichen statt Ziffern in numerische Felder ein. Ihre Anwendung sollte diese Zeichen entfernen, bevor Sie sie an MySQL übergibt, oder andernfalls einen Fehler erzeugen. Die Übergabe ungeprüfter Werte an MySQL ist extrem gefährlich!

    • Überprüfen Sie die Daten, bevor Sie sie an MySQL übergeben.

    • Lassen Sie Ihre Anwendung eine Verbindung mit der Datenbank unter Verwendung eines anderen Benutzernamens als desjenigen herstellen, den Sie für administrative Zwecke verwenden. Geben Sie Ihren Anwendungen nicht mehr Zugriffsberechtigungen als notwendig.

  • Viele APIs stellen eine Methode bereit, um Sonderzeichen in Datenwerten zu kennzeichnen. Richtig verwendet, verhindert dies, dass Anwendungsbenutzer Werte eingeben können, die eine Erzeugung von Anweisungen durch die Anwendung verursachen könnten, welche einen anderen Effekt als von Ihnen erwünscht hervorrufen:

    • MySQL-C-API: Verwenden Sie den API-Aufruf mysql_real_escape_string().

    • MySQL++: Verwenden Sie die Modifizierer escape und quote für Abfrage-Streams.

    • PHP: Verwenden Sie die Funktion mysql_escape_string(), die auf der gleichnamigen Funktion in der MySQL-C-API basiert. (Bei PHP vor Version 4.0.3 benutzen Sie stattdessen addslashes().) In PHP 5 können Sie die Erweiterung mysqli einsetzen, die das verbesserte MySQL-Authentifizierungsprotokoll und Passwörter ebenso unterstützt wie vorbereitete Anweisungen mit Platzhaltern.

    • Perl DBI: Verwenden Sie die Methode quote() oder Platzhalter.

    • Ruby DBI: Verwenden Sie Platzhalter.

    • Java JDBC: Verwenden Sie ein PreparedStatement-Objekt und Platzhalter.

    Andere Programmierschnittstellen weisen möglicherweise ähnliche Funktionalitäten auf.

  • Übertragen Sie keine unverschlüsselten Daten über das Internet. Auf solche Daten kann jeder zugreifen, der die Zeit und die Fähigkeiten hat, sie abzufangen und für eigene Zwecke zu verwenden. Verwenden Sie stattdessen ein verschlüsseltes Protokoll wie SSL oder SSH. MySQL unterstützt interne SSL-Verbindungen ab Version 4.0. Eine andere Methode besteht in der Verwendung der SSH-Portweiterleitung, mit der man einen verschlüsselten (und komprimierten) Kommunikationstunnel einrichten kann.

  • Machen Sie sich mit den Hilfsprogrammen tcpdump und strings vertraut. In den meisten Fällen können Sie durch Absetzen eines Befehls wie des folgenden überprüfen, ob MySQL-Datenströme unverschlüsselt sind:

    shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
    

    (Das funktioniert unter Linux und sollte mit kleinen Anpassungen auf unter anderen Betriebssystemen laufen.) Warnung: Wenn Sie keine Klartextdaten sehen, bedeutet dies nicht notwendigerweise, dass die Daten tatsächlich verschlüsselt sind. Sofern Sie ein hohes Maß an Sicherheit benötigen, sollten Sie sich an einen Sicherheitsexperten wenden.

5.7.2. Absichern von MySQL gegen Angreifer

Wenn Sie eine Verbindung mit einem MySQL-Server herstellen, sollten Sie ein Passwort verwenden. Dieses Passwort wird nicht unverschlüsselt über die Verbindung übertragen. Die Behandlung des Passworts während der Herstellung der Clientverbindung wurde in MySQL 4.1.1 so aktualisiert, dass sie nun sehr sicher ist. Wenn Sie immer noch Passwörter im alten Stil (d. h. vor MySQL 4.1.1) verwenden, beachten Sie, dass der Verschlüsselungsalgorithmus nicht so leistungsfähig ist wie der neuere Algorithmus. Mit ein wenig Aufwand kann ein cleverer Angreifer den Datenverkehr zwischen Client und Server abfangen und das Passwort knacken. (Eine Beschreibung der verschiedenen Methoden für den Umgang mit Passwörtern finden Sie in Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“.)

Alle übrigen Informationen werden unverschlüsselt übertragen und können von jedem gelesen werden, der die Verbindung überwachen kann. Wenn die Verbindung zwischen Client und Server durch ein nicht vertrauenswürdiges Netzwerk verläuft und Sie deswegen Bedenken haben, können Sie das komprimierte Protokoll verwenden, um die Entschlüsselung der Daten erheblich zu erschweren. Sie können auch den internen SSL-Support von MySQL verwenden, um die Sicherheit der Verbindung noch mehr zu erhöhen. Siehe auch Abschnitt 5.9.7, „Verwendung sicherer Verbindungen“. Alternativ stellen Sie mit SSH eine verschlüsselte TCP/IP-Verbindung zwischen einem MySQL-Server und einem MySQL-Client her. Einen Open-Source-SSH-Client finden Sie unter http://www.openssh.org/, eine kommerzielle Variante unter http://www.ssh.com/.

Um ein MySQL-System möglichst sicher zu machen, sollten Sie die folgenden Vorschläge dringend beachten:

  • Verlangen Sie für alle MySQL-Konten die Nutzung eines Passworts. Ein Clientprogramm kennt die Identität seines Benutzers nicht unbedingt. Bei Client/Server-Anwendungen ist es durchaus üblich, dass der Benutzer einen beliebigen Benutzernamen für das Clientprogramm angeben kann. So kann beispielsweise jede beliebige Person das Programm mysql verwenden, um eine Verbindung als eine andere Person herzustellen, indem sie mysql -u other_user db_name aufruft, wenn für other_user kein Passwort konfiguriert ist. Wenn alle Konten ein Passwort besitzen, wird das Herstellen einer Verbindung unter Verwendung des Kontos eines anderen Benutzers erheblich schwieriger.

    Eine Beschreibung der Methoden zur Konfiguration von Passwörtern finden Sie in Abschnitt 5.9.5, „Kennwörter einrichten“.

  • Führen Sie den MySQL-Server niemals als Unix-Benutzer root aus. Dies ist extrem gefährlich, weil jeder Benutzer mit der Berechtigung FILE in der Lage ist, auf dem Server die Erstellung von Dateien als root anzufordern (z. B. ~root/.bashrc). Um dies zu verhindern, verweigert mysqld die Ausführung als root, sofern dies nicht ausdrücklich mit der Option --user=root festgelegt wurde.

    mysqld kann (und sollte) stattdessen als gewöhnlicher, nichtberechtigter Benutzer ausgeführt werden. Sie können ein separates Unix-Konto namens mysql einrichten, um die Sicherheit noch weiter zu erhöhen. Dieses Konto verwenden Sie dann nur zur Administration von MySQL. Um mysqld als ein anderer Unix-Benutzer zu starten, fügen Sie die Option user hinzu, die den Benutzernamen im Abschnitt [mysqld] der Optionsdatei my.cnf angibt, in der Sie die Serveroptionen konfigurieren. Zum Beispiel:

    [mysqld]
    user=mysql
    

    Hierdurch wird der Server unabhängig davon, ob Sie ihn manuell oder mithilfe von mysqld_safe oder mysql.server starten, als der angegebene Benutzer gestartet. Weitere Informationen finden Sie unter Abschnitt 5.7.5, „Wie man MySQL als normaler Benutzer laufen läßt“.

    Die Ausführung von mysqld als ein anderer Unix-Benutzer als root hat nicht zur Folge, dass Sie den Benutzernamen root in der Tabelle user ändern müssen. Benutzernamen für MySQL-Konten haben nichts mit den Benutzernamen für Unix-Konten zu tun.

  • Unterbinden Sie die Verwendung von symbolischen Verknüpfungen mit Tabellen. (Diese Funktionalität kann mit der Option --skip-symbolic-links deaktiviert werden.) Dies ist insbesondere dann wichtig, wenn Sie mysqld als root ausführen, da jeder Benutzer, der Schreibzugriff auf das Datenverzeichnis des Servers hat, jede beliebige Datei im System löschen kann! Siehe auch Abschnitt 7.6.1.2, „Benutzung symbolischer Links für Tabellen“.

  • Vergewissern Sie sich, dass der einzige Unix-Benutzer mit Lese- und Schreibberechtigungen in den Datenbankverzeichnissen der Benutzer ist, als der mysqld ausgeführt wird.

  • Gewähren Sie die Berechtigungen PROCESS und SUPER ausschließlich Administratoren. Die Ausgabe von mysqladmin processlist und SHOW PROCESSLIST zeigt den Text aller Anweisungen, die gerade ausgeführt werden. Insofern kann jeder Benutzer, der die Serverprozessliste anzeigen kann, unter Umständen Anweisungen sehen, die von anderen Benutzern abgesetzt werden – z. B. auch UPDATE user SET password=PASSWORD('not_secure').

    mysqld reserviert eine zusätzliche Verbindung für Benutzer mit der Berechtigung SUPER, sodass ein MySQL-Benutzer root sich auch dann anmelden und die Serveraktivitäten überprüfen kann, wenn alle normalen Verbindungen gerade verwendet werden.

    Die Berechtigung SUPER kann zur Terminierung von Clientverbindungen, zur Änderung des Serverbetriebs durch Modifikation von Systemvariablen und zur Steuerung von Replikationsservern verwendet werden.

  • Gewähren Sie die Berechtigung FILE ausschließlich Administratoren. Jeder Benutzer mit dieser Berechtigung kann eine Datei an beliebiger Stelle im Dateisystem mit den Berechtigungen des mysqld-Daemons speichern. Um dies ein wenig sicherer zu gestalten, überschreiben Dateien, die mit SELECT ... INTO OUTFILE erzeugt wurden, keine vorhandenen Dateien und können von allen geschrieben werden.

    Die Berechtigung FILE kann auch eingesetzt werden, um jede Datei zu lesen, die von allen gelesen werden kann oder für den Unix-Benutzer, als der der Server ausgeführt wird, zugänglich ist. Mit dieser Berechtigung können Sie jede Datei in eine Datenbanktabelle einlesen. Dies könnte beispielsweise missbraucht werden, indem man mit LOAD DATA die Datei /etc/passwd in eine Tabelle einlädt, die dann mit SELECT angezeigt werden könnte.

  • Wenn Sie Ihrem DNS nicht trauen, sollten Sie IP-Nummern statt Hostnamen in den Grant-Tabellen verwenden. In jedem Fall sollten Sie sehr vorsichtig mit der Erstellung von Einträgen in Grant-Tabellen unter Verwendung von Hostnamenswerten sein, die Jokerzeichen enthalten.

  • Wenn Sie die Anzahl der für ein Konto verwendbaren Verbindungen einschränken wollen, können Sie dies tun, indem Sie die Variable max_user_connections in mysqld einstellen. Die GRANT-Anweisung unterstützt auch Ressourcensteuerungsoptionen, mit denen die Servernutzung durch ein Konto beschränkt werden kann. Siehe auch Abschnitt 13.5.1.3, „GRANT und REVOKE.

5.7.3. Startoptionen für mysqld in Bezug auf Sicherheit

Die folgenden mysqld-Optionen sind sicherheitsrelevant:

  • --allow-suspicious-udfs

    Diese Option bestimmt, ob UDFs (User-Defined Functions, benutzerdefinierte Funktionen), die nur ein xxx-Symbol für die Hauptfunktion aufweisen, geladen werden dürfen. Standardmäßig ist die Option deaktiviert, und es dürfen nur UDFs geladen werden, die mindestens ein Hilfssymbol aufweisen. Hierdurch soll das Laden von Funktionen aus solchen freigegebenen Objektdateien verhindert werden, die keine zulässigen UDFs enthalten. Siehe auch Abschnitt 26.3.4.6, „Vorsichtsmaßnahmen bei benutzerdefinierten Funktionen (UDF)“.

  • --local-infile[={0|1}]

    Wenn Sie den Server mit --local-infile=0 starten, können Clients LOCAL in LOAD DATA-Anweisungen nicht verwenden. Siehe auch Abschnitt 5.7.4, „Sicherheitsprobleme mit LOAD DATA LOCAL.

  • --old-passwords

    Erzwingt die Erzeugung kurzer Passwort-Hashes (wie vor Version 4.1) auch für neue Passwörter. Dies kann zu Kompatibilitätszwecken erforderlich sein, wenn der Server ältere Clientprogramme unterstützen muss. Siehe auch Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“.

  • --safe-show-database (AUSGELAUFEN)

    In älteren MySQL-Versionen konnte mit dieser Option festgelegt werden, dass die SHOW DATABASES-Anweisung die Namen nur derjenigen Datenbanken anzeigte, für die der Benutzer eine entsprechende Berechtigung hatte. In MySQL 5.1 steht diese Option nicht mehr zur Verfügung, da dies nun das Standardverhalten ist und es eine SHOW DATABASES-Berechtigung gibt, die zur kontenspezifischen Steuerung des Zugriffs auf Datenbanknamen verwendet werden kann. Siehe auch Abschnitt 13.5.1.3, „GRANT und REVOKE.

  • --safe-user-create

    Wenn diese Option aktiviert ist, kann ein Benutzer nur dann neue Benutzer mit der GRANT-Anweisung erstellen, wenn er die Berechtigung INSERT für die Tabelle mysql.user hat. Wenn Sie wollen, dass ein bestimmter Benutzer die Möglichkeit zur Einrichtung neuer Benutzer hat, die diejenigen Berechtigungen haben, die der erstellende Benutzer gewähren darf, dann sollten Sie dem Benutzer die folgende Berechtigung gewähren:

    GRANT INSERT(user) ON mysql.user TO 'user_name'@'host_name';
    

    Hierdurch ist gewährleistet, dass der Benutzer Berechtigungsspalten nicht direkt ändern kann, sondern die GRANT-Anweisung zur Gewährung von Berechtigungen an andere Benutzer verwenden muss.

  • --secure-auth

    Unterbindet die Authentifizierung für Konten, die alte Passwörter (d. h. solche im Stil vor MySQL 4.1) haben.

    Der Client mysql verfügt ebenfalls über eine Option namens --secure-auth, die Verbindungen mit einem Server verhindert, wenn dieser für das Clientkonto ein Passwort im alten Format anfordert.

  • --skip-grant-tables

    Mit dieser Option verwendet der Server das Berechtigungssystem überhaupt nicht. Das bedeutet, dass jeder, der Zugriff auf den Server erhält, uneingeschränkten Zugang zu allen Datenbanken bekommt. Sie können einen laufenden Server dazu bringen, die Grant-Tabellen wieder zu verwenden, indem Sie mysqladmin flush-privileges oder mysqladmin reload über die System-Shell ausführen oder die MySQL-Anweisung FLUSH PRIVILEGES absetzen. Diese Option unterbindet auch das Laden von Plug-Ins und benutzerdefinierten Funktionen (UDFs).

  • --skip-name-resolve

    Hostnamen werden nicht aufgelöst. Alle Host-Spaltenwerte in den Grant-Tabellen müssen IP-Nummern oder localhost sein.

  • --skip-networking

    TCP/IP-Verbindungen über das Netzwerk werden unterbunden. Alle Verbindungen zu mysqld müssen über Unix-Socketdateien erfolgen.

  • --skip-show-database

    Bei dieser Option darf die SHOW DATABASES-Anweisung nur von Benutzern verwendet werden, die die Berechtigung SHOW DATABASES haben. Die Anweisung zeigt dann alle Datenbanknamen an. Ohne diese Option dürfen alle Benutzer SHOW DATABASES verwenden, aber die Datenbanknamen werden nur angezeigt, wenn der Benutzer die Berechtigung SHOW DATABASES oder spezifische Berechtigungen für eine Datenbank hat. Beachten Sie, dass jede globale Berechtigung als Berechtigung für die Datenbank betrachtet wird.

5.7.4. Sicherheitsprobleme mit LOAD DATA LOCAL

Die LOAD DATA-Anweisung kann eine Datei, die sich auf dem Serverhost befindet, oder eine Datei laden, die auf dem Clienthost abgelegt ist, wenn das Schlüsselwort LOCAL angegeben ist.

Es gibt bei der Unterstützung der LOCAL-Version von LOAD DATA zwei potenzielle Sicherheitsrisiken:

  • Die Übertragung der Datei vom Client- auf den Serverhost wird durch den MySQL-Server eingeleitet. Theoretisch ließe sich ein gepatchter Server erstellen, der das Clientprogramm anweisen könnte, eine Datei nach Maßgabe des Servers (statt der vom Client in der LOAD DATA-Anweisung festgelegten Datei) zu übertragen. Ein solcher Server könnte dann auf jede Datei auf dem Clienthost zugreifen, auf die der Clientbenutzer Lesezugriff hat.

  • In einer Webumgebung, in der die Clients Verbindungen über einen Webserver herstellen, könnte ein Benutzer mit LOAD DATA LOCAL beliebige Dateien lesen, auf die der Webserverprozess Lesezugriff hat (vorausgesetzt, der Benutzer kann einen beliebigen Befehl den SQL-Server betreffend ausführen). In dieser Umgebung ist der Client aus Sicht des MySQL-Servers eigentlich der Webserver und nicht das entfernte Programm, das von dem Benutzer ausgeführt wird, der die Verbindung zum Webserver hergestellt hat.

Um diese Probleme zu beheben, haben wir die Verfahrensweise für LOAD DATA LOCAL beginnend mit MySQL 3.23.49 und MySQL 4.0.2 (4.0.13 unter Windows) wie folgt geändert:

  • Standardmäßig werden alle MySQL-Clients und -Bibliotheken mit der Option --enable-local-infile kompiliert, um die Kompatibilität mit MySQL 3.23.48 und vorher aufrechtzuerhalten.

  • Wenn Sie MySQL aus der Quelldistribution erstellt, aber configure nicht mit der Option --enable-local-infile aufgerufen haben, kann LOAD DATA LOCAL nicht von beliebigen Clients verwendet werden, sofern nicht ausdrücklich der Aufruf von mysql_options(... MYSQL_OPT_LOCAL_INFILE, 0) einkompiliert wurde. Siehe auch Abschnitt 24.2.3.48, „mysql_options().

  • Sie können alle LOAD DATA LOCAL-Befehle auf der Serverseite deaktivieren, indem Sie mysqld mit der Option --local-infile=0 starten.

  • Für den Befehlszeilenclient mysql kann LOAD DATA LOCAL durch Angabe der Option --local-infile[=1] aktiviert bzw. mit der Option --local-infile=0 deaktiviert werden. Ähnlich aktiviert die Option --local bzw. -L das Laden lokaler Dateien für mysqlimport. In jedem Fall setzt die erfolgreiche Verwendung einer lokalen Ladeoperation voraus, dass die Durchführung derartiger Operationen durch den Server zugelassen ist.

  • Wenn Sie LOAD DATA LOCAL in Perl-Skripten oder anderen Programmen verwenden, die den Abschnitt [client] aus Optionsdateien auslesen, können Sie die Option local-infile=1 in diesem Abschnitt hinzufügen. Allerdings sollten Sie sie mit dem Präfix loose- versehen, um Probleme mit Programmen zu vermeiden, die local-infile nicht verstehen:

    [client]
    loose-local-infile=1
    
  • Wenn LOAD DATA LOCAL INFILE deaktiviert ist – sei es am Server oder am Client –, dann erhält ein Client, der eine solche Anweisung abzusetzen versucht, die folgende Fehlermeldung:

    ERROR 1148: The used command is not allowed with this MySQL version
    

5.7.5. Wie man MySQL als normaler Benutzer laufen läßt

Unter Windows können Sie den Server als Windows-Dienst über ein normales Benutzerkonto ausführen.

Unter Unix kann jeder Benutzer den MySQL-Server mysqld starten und ausführen. Allerdings sollten Sie aus Sicherheitsgründen eine Ausführung des Servers als Unix-Benutzer root unterbinden. Gehen Sie wie folgt vor, um den Server mysqld so zu ändern, dass er als normaler Unix-Benutzer user_name ohne spezielle Berechtigungen ausgeführt wird:

  1. Beenden Sie mit mysqladmin shutdown den Server, sofern er ausgeführt wird.

  2. Ändern Sie die Datenbankverzeichnisse und -dateien so ab, dass user_name Berechtigungen zum Lesen und Schreiben von Dateien in diese Verzeichnisse hat (dies müssen Sie unter Umständen als Unix-Benutzer root tun):

    shell> chown -R user_name /path/to/mysql/datadir
    

    Wenn Sie dies versäumen, kann der Server, wenn er als user_name ausgeführt wird, nicht auf Datenbanken oder Tabellen zugreifen.

    Wenn Verzeichnisse oder Dateien im MySQL-Datenverzeichnis symbolische Verknüpfungen sind, müssen Sie diese Verknüpfungen nachverfolgen und die Verzeichnisse und Dateien ändern, auf die sie verweisen. chown -R verfolgt die symbolischen Verknüpfungen möglicherweise nicht.

  3. Starten Sie den Server als Benutzer user_name. Wenn Sie MySQL 3.22 oder höher verwenden, besteht eine Alternative darin, mysqld als Unix-Benutzer root zu starten und dabei die Option --user=user_name zu verwenden. mysqld wird gestartet und schaltet dann auf die Ausführung als Unix-Benutzer user_name um, bevor Verbindungen akzeptiert werden.

  4. Um den Server beim Systemstart automatisch als der betreffende Benutzer zu starten, geben Sie den Benutzernamen durch Hinzufügen einer Option user im Abschnitt [mysqld] der Optionsdateien /etc/my.cnf oder my.cnf im Datenverzeichnis des Servers an. Zum Beispiel:

    [mysqld]
    user=user_name
    

Wenn Ihr Unix-System selbst nicht geschützt ist, sollten Sie für die MySQL-root-Konten Passwörter in den Grant-Tabellen konfigurieren. Andernfalls kann jeder Benutzer mit einem Anmeldekonto auf diesem Computer den Client mysql mit der Option --user=root ausführen und beliebige Operationen durchführen. (Es empfiehlt sich generell, MySQL-Konten mit Passwörtern zu verknüpfen, ist aber absolut erforderlich, wenn andere Anmeldekonten auf dem Serverhost vorhanden sind.) Siehe auch Abschnitt 2.9, „Einstellungen und Tests nach der Installation“.

5.8. Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem

MySQL verfügt über ein fortschrittliches, aber nicht standardkonformes Sicherheits- und Berechtigungssystem. Im Folgenden wird beschrieben, wie dieses System funktioniert.

5.8.1. Was das Berechtigungssystem macht

Die wesentliche Funktion des MySQL-Berechtigungssystems ist die Authentifizierung von Benutzern, die von einem gegebenen Host eine Verbindung herstellen, und die Zuweisung von Berechtigungen für eine Datenbank wie SELECT, INSERT, UPDATE und DELETE an diesen Benutzer.

Weitere Funktionalitäten umfassen die Möglichkeit zur Authentifizierung anonymer Benutzer und die Gewährung von Berechtigungen für MySQL-spezifische Funktionen wie LOAD DATA INFILE und administrativen Operationen.

5.8.2. Wie das Berechtigungssystem funktioniert

Das MySQL-Berechtigungssystem stellt sicher, dass alle Benutzer nur diejenigen Operationen ausführen können, die sie auch ausführen dürfen. Wenn Sie als Benutzer eine Verbindung mit einem MySQL-Server herstellen, dann wird Ihre Identität über den Host, von dem aus Sie die Verbindung herstellen, und den angegebenen Benutzernamen bestimmt. Wenn Sie nach Herstellung der Verbindung Abfragen absetzen, gewährt das System Berechtigungen entsprechend Ihrer Identität und dem, was Sie tun wollen.

MySQL berücksichtigt bei der Identifizierung sowohl Ihren Host- als auch Ihren Benutzernamen, da es wenig Grund zu der Annahme gibt, dass ein bestimmter Benutzername überall im Internet jeweils derselben Person zuzuordnen ist. So muss beispielsweise der Benutzer joe, der eine Verbindung von office.example.com aus herstellt, keineswegs mit dem Benutzer joe identisch sein, der seine Verbindung von home.example.com aus aufbaut. MySQL löst diese Diskrepanz, indem es Ihnen gestattet, zwischen Benutzern auf unterschiedlichen Hosts zu unterscheiden, die zufällig den gleichen Namen haben: Sie können einen Satz mit Berechtigungen für Verbindungen von joe auf office.example.com und einen anderen Berechtigungssatz für Verbindungen von joe auf home.example.com gewähren.

Die MySQL-Zugriffssteuerung umfasst zwei Stufen, wenn Sie ein Clientprogramm ausführen, das eine Verbindung mit dem Server herstellt:

  • Stufe 1: Der Server überprüft, ob er Ihnen die Verbindungsherstellung gestattet.

  • Stufe 2: Sofern Sie eine Verbindung herstellen konnten, überprüft der Server nun jede von Ihnen abgesetzte Anweisung, um zu ermitteln, ob Sie ausreichende Berechtigungen für deren Durchführung genießen. Versuchen Sie beispielsweise, Datensätze aus einer Tabelle in einer Datenbank auszuwählen oder eine Tabelle aus der Datenbank zu löschen, dann vergewissert sich der Server, dass Sie die Berechtigung SELECT für die Tabelle bzw. die Berechtigung DROP für die Datenbank haben.

Werden Ihre Berechtigungen (sei es von Ihnen selbst oder jemandem anderes) geändert, während Sie eine Verbindung haben, dann haben diese Änderungen nicht unbedingt sofort für die nächste abgesetzte Anweisung Gültigkeit. Weitere Informationen finden Sie in Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“.

Der Server speichert Berechtigungsinformationen in den Grant-Tabellen der mysql-Datenbank (d. h. in der Datenbank namens mysql). Der MySQL-Server liest die Inhalte dieser Tabellen beim Start in den Speicher ein. Unter den in Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“, beschriebenen Umständen erfolgt zudem ein Neueinlesen der Inhalte. Entscheidungen der Zugriffssteuerung basieren auf den im Arbeitsspeicher vorhandenen Kopien der Grant-Tabellen.

Normalerweise manipulieren Sie die Inhalte der Grant-Tabellen indirekt, indem Sie mit Anweisungen wie GRANT oder REVOKE Konten einrichten und die Berechtigungen für jedes einzelne Konto steuern. Siehe auch Abschnitt 13.5.1, „Anweisungen zur Benutzerkontenverwaltung“. Die nachfolgende Beschreibung erläutert die den Grant-Tabellen zugrundeliegende Struktur und die Frage, wie der Server die Inhalte dieser Tabellen für die Interaktion mit Clients verwendet.

Der Server benutzt die Tabellen user, db und host in der Datenbank mysql für beide Stufen der Zugriffssteuerung. Die Spalten in den Tabellen user und db sind nachfolgend aufgeführt. Die Tabelle host ähnelt der Tabelle db, weist aber einen speziellen Einsatzbereich auf, der in Abschnitt 5.8.6, „Zugriffskontrolle, Phase 2: Anfrageüberprüfung“, beschrieben wird.

Tabellennameuserdb
Spalten für GültigkeitsbereicheHostHost
 UserDb
 PasswordUser
BerechtigungsspaltenSelect_privSelect_priv
 Insert_privInsert_priv
 Update_privUpdate_priv
 Delete_privDelete_priv
 Index_privIndex_priv
 Alter_privAlter_priv
 Create_privCreate_priv
 Drop_privDrop_priv
 Grant_privGrant_priv
 Create_view_privCreate_view_priv
 Show_view_privShow_view_priv
 Create_routine_privCreate_routine_priv
 Alter_routine_privAlter_routine_priv
 Execute_privExecute_priv
 Trigger_privTrigger_priv
 Event_privEvent_priv
 Create_tmp_table_privCreate_tmp_table_priv
 Lock_tables_privLock_tables_priv
 References_privReferences_priv
 Reload_priv 
 Shutdown_priv 
 Process_priv 
 File_priv 
 Show_db_priv 
 Super_priv 
 Repl_slave_priv 
 Repl_client_priv 
Sicherheitsspaltenssl_type 
 ssl_cipher 
 x509_issuer 
 x509_subject 
Spalten zur Ressourcensteuerungmax_questions 
 max_updates 
 max_connections 
 max_user_connections 

Die Spalten Event_priv und Trigger_priv wurden in MySQL 5.1.6 hinzugefügt.

Während der zweiten Stufe der Zugriffssteuerung führt der Server eine Anforderungsverifizierung durch, um sicherzustellen, dass jeder Client über die erforderlichen Berechtigungen für jede abgesetzt Anforderung verfügt. Neben den Grant-Tabellen user, db und host kann der Server auch die Tabellen tables_priv und columns_priv für Anforderungen abfragen, die Tabellen betreffen. Die Tabellen tables_priv und columns_priv ermöglichen eine feiner abgestufte Berechtigungssteuerung auf der Tabellen- und Spaltenebene. Die Tabellen haben die folgenden Spalten:

Tabellennametables_privcolumns_priv
Spalten für GültigkeitsbereicheHostHost
 DbDb
 UserUser
 Table_nameTable_name
  Column_name
BerechtigungsspaltenTable_privColumn_priv
 Column_priv 
Weitere SpaltenTimestampTimestamp
 Grantor 

Die Spalten Timestamp und Grantor werden derzeit nicht benutzt und sollen deswegen an dieser Stelle nicht weiter behandelt werden.

Zur Verifizierung von Anforderungen, die gespeicherte Routinen betreffen, kann der Server auch die Tabelle procs_priv abfragen. Diese Tabelle weist die folgenden Spalten auf:

Tabellennameprocs_priv
Spalten für GültigkeitsbereicheHost
 Db
 User
 Routine_name
 Routine_type
BerechtigungsspaltenProc_priv
Weitere SpaltenTimestamp
 Grantor

Die Spalte Routine_type ist eine ENUM-Spalte, die mit den Werten 'FUNCTION' bzw. 'PROCEDURE' den Typ der Routine angibt, auf die sich der Datensatz bezieht. Diese Spalte gestattet die separate Gewährung von Berechtigungen für eine Funktion oder Prozedur gleichen Namens.

Die Spalten Timestamp und Grantor werden derzeit nicht benutzt und sollen deswegen an dieser Stelle nicht weiter behandelt werden.

Jede Grant-Tabelle enthält Gültigkeitsbereichs- und Berechtigungsspalten:

  • Bereichsspalten bestimmen den Gültigkeitsbereich aller Datensätze in den Tabellen, d. h. den Kontext, in dem der Datensatz gültig ist. So würde beispielsweise eine Tabelle user mit den Host- und User-Werten 'thomas.loc.gov' bzw. 'bob' zur Authentifizierung von Verbindungen verwendet, die vom Host thomas.loc.gov aus durch einen Client, der den Benutzernamen bob angibt, hergestellt würden. Ähnlich würde ein Datensatz in der Tabelle db mit den Werten 'thomas.loc.gov', 'bob' und 'reports' in den Spalten Host, User und Db verwendet werden, wenn der Benutzer bob vom Host thomas.loc.gov aus auf die Datenbank reports zuzugreifen versucht. Die Tabellen tables_priv und columns_priv enthalten Gültigkeitsbereichsspalten, die die Tabellen oder Tabellenkombinationen angeben, für die der jeweilige Datensatz gilt. Die Bereichsspalten in procs_priv geben die jeweilige gespeicherte Routine an, für die der Datensatz gilt.

  • Berechtigungsspalten legen fest, welche Berechtigungen durch einen Datensatz gewährt werden, d. h. welche Operationen durchgeführt werden können. Der Server kombiniert die Daten in den verschiedenen Grant-Tabellen zu einer vollständigen Beschreibung der Berechtigungen eines Benutzers. Abschnitt 5.8.6, „Zugriffskontrolle, Phase 2: Anfrageüberprüfung“, beschreibt, welches Regeln hierbei zugrundegelegt werden.

Bereichsspalten enthalten Strings. Diese werden wie nachfolgend gezeigt deklariert, wobei der Vorgabewert jeweils der Leer-String ist:

SpaltennameTyp
HostCHAR(60)
UserCHAR(16)
PasswordCHAR(16)
DbCHAR(64)
Table_nameCHAR(64)
Column_nameCHAR(64)
Routine_nameCHAR(64)

Bei der Überprüfung der Host-Werte im Zuge der Berechtigungsverifizierung wird keine Unterscheidung der Groß-/Kleinschreibung vorgenommen. Die User-, Password-, Db- und Table_name-Werte hingegen unterscheiden die Groß-/Kleinschreibung. Nicht unterschieden wird sie wiederum bei Column_name- und Routine_name-Werten.

In den Tabellen user, db und host wird jede Berechtigung in einer separaten Spalte aufgeführt, die als ENUM('N','Y') DEFAULT 'N' deklariert ist. Anders gesagt: Jede Berechtigung lässt sich aktivieren oder deaktivieren, wobei sie vorgabeseitig immer deaktiviert ist.

In den Tabellen tables_priv, columns_priv und procs_priv sind die Berechtigungsspalten als SET-Spalten deklariert. Werte in diesen Spalten können eine beliebige Kombination der Berechtigungen enthalten, die von der Tabelle gesteuert werden:

TabellennameSpaltennameMögliche Elemente des Satzes
tables_privTable_priv'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter', 'Create View', 'Show view', 'Trigger'
tables_privColumn_priv'Select', 'Insert', 'Update', 'References'
columns_privColumn_priv'Select', 'Insert', 'Update', 'References'
procs_privProc_priv'Execute', 'Alter Routine', 'Grant'

Kurz gesagt verwendet der Server die Grant-Tabellen wie folgt:

  • Die Bereichsspalten in der Tabelle user bestimmen, ob eingehende Verbindungen abgewiesen oder zugelassen werden. Bei zulässigen Verbindungen geben alle in der Tabelle user gewährten Berechtigungen die globalen Berechtigungen (Superuser-Berechtigungen) des Benutzers an. Jede Berechtigung, die in dieser Tabelle gewährt wird, gilt für alle Datenbanken auf dem Server.

    Hinweis: Da alle globalen Berechtigungen als Berechtigungen für alle Datenbanken zu betrachten sind, erlaubt das Vorhandensein einer beliebigen globalen Berechtigung für einen Benutzer diesem, alle Datenbanknamen mit SHOW DATABASES oder durch Untersuchen der Tabelle SCHEMATA von INFORMATION_SCHEMA anzuzeigen.

  • Die Bereichsspalten der Tabelle db bestimmen dabei, welche Benutzer von welchen Hosts aus auf welche Datenbanken zugreifen können. Die Berechtigungsspalten legen hingegen fest, welche Operationen zulässig sind. Eine auf der Datenbankebene gewährte Berechtigung gilt für die Datenbank und alle in ihr enthaltenen Tabellen.

  • Die Tabelle host wird in Verbindung mit der Tabelle db benutzt, wenn ein bestimmte Datensatz in der Tabelle db für mehrere Hosts gelten soll. Wenn Sie beispielsweise einem Benutzer die Verwendung einer Datenbank von verschiedenen Hosts in Ihrem Netzwerk aus gestatten wollen, lassen Sie den Wert Host im Datensatz des betreffenden Benutzers in der Tabelle db frei und geben Sie dann einen Datensatz für jeden der betreffenden Hosts in die Tabelle host ein. Diese Vorgehensweise wird in Abschnitt 5.8.6, „Zugriffskontrolle, Phase 2: Anfrageüberprüfung“, genauer beschrieben.

    Hinweis: Die Tabelle host muss mit Anweisungen wie INSERT, UPDATE und DELETE direkt modifiziert werden. Anweisungen wie GRANT und REVOKE, die die Grant-Tabellen indirekt manipulieren, haben keine Auswirkungen auf diese Tabelle. Die meisten MySQL-Installationen verwenden die Tabelle ohnehin nicht.

  • Die Tabellen tables_priv und columns_priv ähneln der Tabelle db, sind aber feiner abgestuft: Sie werden nicht auf Datenbankebene, sondern auf der Tabellen- und der Spaltenebene angewendet. Eine auf der Tabellenebene gewährte Berechtigung gilt für die Tabelle und alle in ihr enthaltenen Spalten. Eine auf der Spaltenebene gewährte Berechtigung gilt indes nur für eine bestimmte Spalte.

  • Die Tabelle procs_priv gilt für gespeicherte Routinen. Eine auf der Routinenebene gewährte Berechtigung gilt nur für eine bestimmte Routine.

Administrative Berechtigungen (wie etwa RELOAD oder SHUTDOWN) werden nur in der Tabelle user festgelegt. Der Grund hierfür besteht darin, dass administrative Operationen auf dem Server selbst erfolgen und nicht datenbankspezifisch sind, d. h. es gibt keinen Grund, diese Berechtigungen in anderen Grant-Tabellen aufzuführen. Tatsächlich muss der Server, um zu ermitteln, ob Sie eine administrative Operation durchführen dürfen, nur die Tabelle user abfragen.

Die Berechtigung FILE wird ebenfalls nur in der Tabelle user festgelegt. Sie ist im Eigentlichen keine administrative Berechtigung, aber die Fähigkeit zum Lesen oder Schreiben von Dateien auf dem Serverhost hängt nicht von der Datenbank ab, auf die Sie zugreifen.

Der Server mysqld liest die Inhalte der Grant-Tabellen beim Start in den Speicher ein. Sie können ihn mit der Anweisung FLUSH PRIVILEGES oder durch Ausführen der Befehle mysqladmin flush-privileges oder mysqladmin reload anweisen, die Tabellen neu einzulesen. Änderungen an den Grant-Tabellen werden umgesetzt wie in Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“, beschrieben.

Wenn Sie die Inhalte der Grant-Tabellen ändern, empfiehlt es sich sicherzustellen, dass Ihre Änderungen die Berechtigungen so konfigurieren, wie Sie es auch wünschen. Um die Berechtigungen eines gegebenen Kontos zu überprüfen, verwenden Sie die Anweisung SHOW GRANTS. (Siehe auch Abschnitt 13.5.4.11, „SHOW GRANTS.) Um also etwa die Berechtigungen zu ermitteln, die einem Konto mit den Host- und User-Werten pc84.example.com bzw. bob gewährt werden, setzen Sie folgende Anweisung ab:

SHOW GRANTS FOR 'bob'@'pc84.example.com';

Weitere Hilfe zur Diagnose von Problemen in Zusammenhang mit Berechtigungen finden Sie in Abschnitt 5.8.8, „Gründe für Access denied-Fehler“. Allgemeine Richtlinien zu Sicherheitsfragen finden Sie außerdem in Abschnitt 5.7, „Absichern von MySQL gegen Angreifer“.

5.8.3. Von MySQL zur Verfügung gestellte Berechtigungen

Die Informationen zu Kontenberechtigungen sind in den Tabellen user, db, host, tables_priv, columns_priv und procs_priv in der mysql-Datenbank abgelegt. Der MySQL-Server liest die Inhalte dieser Tabellen beim Start in den Speicher ein. Unter den in Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“, beschriebenen Umständen erfolgt zudem ein Neueinlesen der Inhalte. Entscheidungen der Zugriffssteuerung basieren auf den im Arbeitsspeicher vorhandenen Kopien der Grant-Tabellen.

Die in den Anweisungen GRANT und REVOKE zur Bezeichnung von Berechtigungen verwendeten Namen sind in der folgenden Tabelle aufgeführt. Diese enthält außerdem Angaben zu dem mit der jeweiligen Berechtigung in den Grant-Tabellen verknüpften Spaltennamen und zum Kontext, in dem die Berechtigung gültig ist. Weitere Informationen zur Bedeutung der einzelnen Berechtigungen können Sie Abschnitt 13.5.1.3, „GRANT und REVOKE, entnehmen.

BerechtigungSpalteKontext
CREATECreate_privDatenbanken, Tabellen oder Indizes
DROPDrop_privDatenbanken oder Tabellen
GRANT OPTIONGrant_privDatenbanken, Tabellen oder gespeicherte Routinen
REFERENCESReferences_privDatenbanken oder Tabellen
EVENTEvent_privDatenbanken
ALTERAlter_privTabellen
DELETEDelete_privTabellen
INDEXIndex_privTabellen
INSERTInsert_privTabellen
SELECTSelect_privTabellen
UPDATEUpdate_privTabellen
TRIGGERTrigger_privTabellen
CREATE VIEWCreate_view_privViews
SHOW VIEWShow_view_privViews
ALTER ROUTINEAlter_routine_privgespeicherte Routinen
CREATE ROUTINECreate_routine_privgespeicherte Routinen
EXECUTEExecute_privgespeicherte Routinen
FILEFile_privDateizugriff auf dem Serverhost
CREATE TEMPORARY TABLESCreate_tmp_table_privServeradministration
LOCK TABLESLock_tables_privServeradministration
CREATE USERCreate_user_privServeradministration
PROCESSProcess_privServeradministration
RELOADReload_privServeradministration
REPLICATION CLIENTRepl_client_privServeradministration
REPLICATION SLAVERepl_slave_privServeradministration
SHOW DATABASESShow_db_privServeradministration
SHUTDOWNShutdown_privServeradministration
SUPERSuper_privServeradministration

Einige Releases von MySQL enthalten Änderungen an der Struktur der Grant-Tabellen, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Upgrade auf eine neue MySQL-Version durchführen, sollten Sie Ihre Grant-Tabellen aktualisieren, damit sichergestellt ist, dass diese auf der aktuellen Struktur basieren und auf diese Weise neue Funktionalitäten nutzen können. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Die Berechtigungen EVENT und TRIGGER wurden in MySQL 5.1.6 hinzugefügt.

Um gespeicherte Funktionen zu erstellen oder zu verändern, benötigen Sie bei aktiviertem binärem Loggen unter Umständen auch die Berechtigung SUPER (siehe auch Beschreibung in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“).

Die Berechtigungen CREATE und DROP gestatten Ihnen die Erstellung neuer bzw. das Löschen vorhandener Datenbanken und Tabellen. Wenn Sie einem Benutzer die Berechtigung DROP für die Datenbank mysql gewähren, kann dieser Benutzer die Datenbank löschen, in der die MySQL-Zugriffsberechtigungen gespeichert sind.

Die Berechtigungen SELECT, INSERT, UPDATE und DELETE gestatten Ihnen die Durchführung der betreffenden Operationen an Datensätzen in vorhandenen Tabellen einer Datenbank.

SELECT-Anweisungen erfordern die Berechtigung SELECT nur dann, wenn Sie sie tatsächlich Datensätze aus eine Tabelle abrufen. Einige SELECT-Anweisungen greifen nicht auf Tabellen zu und können deswegen ohne Berechtigung für eine bestimmte Datenbank ausgeführt werden. So können Sie etwa den Client mysql als einfachen Taschenrechner zur Auswertung von Ausdrücken verwenden, die keine Tabellen referenzieren:

SELECT 1+1;
SELECT PI()*2;

Die Berechtigung INDEX erlaubt Ihnen das Erstellen und Löschen von Indizes. INDEX gilt für vorhandene Tabellen. Wenn Sie die Berechtigung CREATE für eine Tabelle haben, können Sie Indexdefinitionen in die CREATE TABLE-Anweisung einfügen.

Die Berechtigung ALTER gestattet es Ihnen, mit ALTER TABLE die Struktur einer Tabelle zu ändern oder die Tabelle umzubenennen.

Die Berechtigung CREATE ROUTINE ist zur Erstellung gespeicherter Routinen (Funktionen und Prozeduren) erforderlich. Die Berechtigung ALTER ROUTINE benötigen Sie zum Ändern oder Löschen gespeicherter Routinen und die Berechtigung EXECUTE für deren Ausführung.

Die Berechtigung TRIGGER erlaubt Ihnen das Erstellen und Löschen von Triggern. Sie benötigen diese Berechtigung für eine Tabelle, um Trigger für diese Tabelle erstellen oder löschen zu dürfen. (Vor MySQL 5.1.6 erforderten diese Operationen die Berechtigung SUPER.)

Die Berechtigung EVENT erlaubt Ihnen die Erstellung von Ereignissen im Ereignisplaner.

Mit der Berechtigung GRANT können Sie anderen Benutzern die Berechtigungen gewähren, die Sie selbst besitzen. Sie kann für Datenbanken, Tabellen und gespeicherte Routinen verwendet werden.

Die Berechtigung FILE gibt Ihnen die Erlaubnis, Dateien auf dem Serverhost mit den LOAD DATA INFILE- und SELECT ... INTO OUTFILE-Anweisungen zu lesen bzw. zu schreiben. Ein Benutzer mit der Berechtigung FILE kann jede Datei auf dem Server lesen, die entweder von allen oder vom MySQL-Server gelesen werden kann. (Daraus folgt, dass der Benutzer jede Datei in jedem Datenbankverzeichnis lesen kann, da der Server auf all diese Dateien zugreifen darf.) Die Berechtigung FILE erlaubt dem Benutzer auch die Erstellung neuer Dateien in allen Verzeichnissen, auf die der MySQL-Server Schreibzugriff hat. Der Server kann vorhandene Dateien jedoch nicht überschreiben (dies ist eine Sicherheitsmaßnahme).

Die verbleibenden Berechtigungen werden für administrative Operationen verwendet. Viele von ihnen können mit dem Programm mysqladmin oder durch Absetzen von SQL-Anweisungen ausgeführt werden. Die folgende Tabelle zeigt, die Ausführung welcher mysqladmin-Befehle mit den einzelnen administrativen Berechtigungen möglich ist:

BerechtigungFür Berechtigte verfügbare Befehle
RELOADflush-hosts, flush-logs, flush-privileges, flush-status, flush-tables, flush-threads, refresh, reload
SHUTDOWNshutdown
PROCESSprocesslist
SUPERkill

Der Befehl reload weist den Server an, die Grant-Tabellen erneut in den Speicher einzulesen. flush-privileges ist ein Synonym für reload. Der Befehl refresh schließt die Logdateien und öffnet sie dann neu und schreibt zudem alle Tabellen neu auf Festplatte. Die übrigen flush-xxx-Befehle führen Funktionen aus, die refresh ähneln, sind aber spezieller und in bestimmten Fällen vorzuziehen. Wenn Sie beispielsweise nur die Logdateien neu schreiben wollen, ist flush-logs eine bessere Wahl als refresh.

Der Befehl shutdown fährt den Server herunter. Eine entsprechende SQL-Anweisung gibt es nicht.

Der Befehl processlist zeigt Informationen zu den Threads an, die auf dem Server ausgeführt werden (und somit auch zu den Anweisungen, die von den Clients ausgeführt werden). Der Befehl kill terminiert Server-Threads. Eigene Threads können Sie immer anzeigen oder terminieren; zum Anzeigen von Threads, die von anderen Benutzern gestartet wurden, benötigen Sie die Berechtigung PROCESS und zum Terminieren solcher Threads die Berechtigung SUPER. Siehe auch Abschnitt 13.5.5.3, „KILL.

Die Berechtigung CREATE TEMPORARY TABLES ermöglicht die Verwendung des Schlüsselwortes TEMPORARY in CREATE TABLE-Anweisungen.

Die Berechtigung LOCK TABLES gestattet die Verwendung expliziter LOCK TABLES-Anweisungen zum Sperren von Tabellen, für die Sie die Berechtigung SELECT haben. Dies umfasst auch das Setzen von Schreibsperren, wodurch das Lesen der Tabellen durch andere unterbunden wird.

Die Berechtigung REPLICATION CLIENT ermöglicht die Verwendung von SHOW MASTER STATUS und SHOW SLAVE STATUS.

Die Berechtigung REPLICATION SLAVE sollte Konten gewährt werden, die von Slave-Servern zum Herstellen einer Verbindung mit dem aktuellen Server als Master verwendet werden. Ohne diese Berechtigung kann der Slave keine Updates anfordern, die an den Datenbanken auf dem Master-Server vorgenommen wurden.

Die Berechtigung SHOW DATABASES ermöglicht dem Konto die Anzeige von Datenbanknamen durch Absetzen einer SHOW DATABASE-Anweisung. Konten, die diese Berechtigung nicht haben, sehen nur solche Datenbanken, für die sie Berechtigungen haben; wurde der Server mit der Option --skip-show-database gestartet, dann kann die Anweisung überhaupt nicht verwendet werden. Beachten Sie, dass jede globale Berechtigung eine Berechtigung für die Datenbank ist.

Es empfiehlt sich deswegen, einem Konto nur diejenigen Berechtigungen zu gewähren, die es tatsächlich braucht. Besondere Vorsicht sollten Sie bei Gewährung der Berechtigung FILE sowie administrativer Berechtigungen walten lassen:

  • Die Berechtigung FILE kann missbraucht werden, um beliebige Dateien, die der MySQL-Server auf dem Serverhost lesen kann, in eine Datenbanktabelle einzulesen. Dies betrifft alle World-Readable-Dateien sowie Dateien im Datenverzeichnis des Servers. Die Tabelle kann dann mit SELECT aufgerufen und ihr Inhalt an den Clienthost übertragen werden.

  • Die Berechtigung GRANT gestattet Benutzern, ihre Berechtigungen an andere Benutzer weiterzugeben. Zwei Benutzer, die unterschiedliche Berechtigungen haben und beide über die Berechtigung GRANT verfügen, können ihre Berechtigungen kombinieren.

  • Die Berechtigung ALTER kann verwendet werden, um das Berechtigungssystem durch Umbenennen zu unterlaufen.

  • Die Berechtigung SHUTDOWN kann verwendet werden, um durch Herunterfahren des Servers anderen Benutzern Dienste vollständig zu verweigern.

  • Mit der Berechtigung PROCESS kann man aktuell ausgeführte Anweisungen einschließlich solcher, mit denen Passwörter eingestellt oder geändert werden, unverschlüsselt anzeigen.

  • Mit der Berechtigung SUPER schließlich lassen sich andere Clients terminieren und die Betriebsweise des Servers ändern.

  • Berechtigungen, die für die mysql-Datenbank selbst gewährt wurden, können zum Ändern von Passwörtern und anderen Daten benutzt werden, die für Zugriffsberechtigungen relevant sind. Passwörter werden verschlüsselt gespeichert, d. h. ein arglistiger Benutzer kann sie nicht einfach im Klartext auslesen. Allerdings kann ein Benutzer mit Schreibzugriff auf die Spalte Password der Tabelle user das Passwort eines Kontos ändern und dann unter Verwendung dieses Kontos eine Verbindung mit dem MySQL-Server herstellen.

Es gibt aber auch einige Dinge, die Sie mit dem MySQL-Berechtigungssystem nicht tun können:

  • Sie können nicht explizit angeben, dass einem bestimmten Benutzer der Zugriff verweigert werden soll. Anders gesagt ist es nicht möglich, einen Benutzervergleich durchzuführen und bei Übereinstimmung die Verbindung zu verweigern.

  • Sie können nicht festlegen, dass ein Benutzer Berechtigungen zum Erstellen oder Löschen von Tabellen in einer Datenbank hat, aber die Datenbank selbst nicht erstellen bzw. löschen darf.

  • Ein Passwort gilt immer global für ein Konto. Sie können kein Passwort für ein bestimmtes Objekt wie eine Datenbank, eine Tabelle oder eine Routine vergeben.

5.8.4. Verbinden mit dem MySQL-Server

Wenn Sie auf einen MySQL-Server zugreifen wollen, erwarten MySQL-Clientprogramme im Allgemeinen die Angabe bestimmter Verbindungsparameter von Ihnen:

  • den Namen des Hosts, auf dem der MySQL-Server ausgeführt wird

  • Ihren Benutzernamen

  • Ihr Passwort

Der Client mysql kann beispielsweise wie folgt über die Befehlszeile gestartet werden (die Eingabeaufforderung wird durch shell> repräsentiert):

shell> mysql -h host_name -u user_name -pyour_pass

Alternative Formen der Optionen -h, -u und -p sind --host=host_name, --user=user_name und --password=your_pass. Beachten Sie, dass zwischen -p oder --password= und dem nachfolgenden Passwort kein Leerzeichen stehen darf.

Wenn Sie die Option -p oder --password verwenden, aber keinen Passwortwert angeben, fordert das Clientprogramm Sie zur Eingabe des Passworts auf. Das Passwort wird bei der Eingabe nicht angezeigt. Dies ist sicherer als die Angabe des Passworts über die Befehlszeile. Ein Benutzer auf Ihrem System kann ein über die Befehlszeile angegebenes Passwort unter Umständen anzeigen, indem er einen Befehl wie ps auxww ausführt. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

MySQL-Clientprogramme verwenden Standardwerte für alle Verbindungsparameteroptionen, die Sie nicht angeben:

  • Der Standardhostname ist localhost.

  • Der vorgabeseitige Benutzername heißt unter Windows ODBC, unter Unix ist es Ihr Anmeldename.

  • Wenn weder die Option -p noch die Option --password angegeben wird, wird kein Passwort übergeben.

Das bedeutet für einen Unix-Benutzer mit dem Anmeldenamen joe, dass alle folgenden Befehle äquivalent sind:

shell> mysql -h localhost -u joe
shell> mysql -h localhost
shell> mysql -u joe
shell> mysql

Andere MySQL-Clients verhalten sich ähnlich.

Sie können andere Standardwerte festlegen, die zur Herstellung einer Verbindung verwendet werden sollen, damit Sie sie nicht jedes Mal auf der Befehlszeile angeben müssen, wenn Sie ein Clientprogramm aufrufen. Hierzu gibt es mehrere Möglichkeiten:

  • Sie können die Verbindungsparameter im Abschnitt [client] einer Optionsdatei angeben. Der entsprechende Abschnitt der Datei kann etwa so aussehen:

    [client]
    host=host_name
    user=user_name
    password=your_pass
    

    Abschnitt 4.3.2, „my.cnf-Optionsdateien“, enthält eine eingehendere Beschreibung der Optionsdateien.

  • Sie können bestimmte Verbindungsparameter auch über Umgebungsvariablen angeben. Der Host kann für mysql mithilfe von MYSQL_HOST festgelegt werden. Der MySQL-Benutzername kann über USER angegeben werden (dies gilt nur für Windows und NetWare). Das Passwort kann über MYSQL_PWD angegeben werden. Dies beeinträchtigt jedoch die Sicherheit (siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“). Eine Liste der Variablen finden Sie unter Anhang F, Umgebungsvariablen.

5.8.5. Zugriffskontrolle, Phase 1: Verbindungsüberprüfung

Wenn Sie eine Verbindung mit einem MySQL-Server herzustellen versuchen, kann dieser die Verbindungsanfrage basierend auf Ihrer Identität und darauf, ob Sie diese Identität durch Übermittlung nachgewiesen haben, annehmen oder abweisen. Im Falle der Abweisung verweigert Ihnen der Server jedweden Zugriff. Andernfalls akzeptiert der Server die Verbindung. Er schaltet dann auf Stufe 2 um und erwartet Ihre Anforderungen.

Ihre Identität basiert auf zwei Datenelementen:

  • dem Clienthost, von dem aus Sie die Verbindung herstellen

  • Ihrem MySQL-Benutzernamen

Die Identitätsprüfung wird mithilfe der drei Gültigkeitsbereichsspalten (Host, User und Password) der Tabelle user durchgeführt. Der Server akzeptiert die Verbindung nur dann, wenn die Werte in den Spalten Host und User eines Datensatzes in der Tabelle user mit dem vom Client übermittelten Host- und Benutzernamen übereinstimmen und der Client nachfolgend das Passwort für diesen Datensatz sendet.

Die Host-Werte in der Tabelle user können wie folgt angegeben werden:

  • Ein Host-Wert kann ein Hostname oder eine IP-Adresse oder aber 'localhost' (zur Bezeichnung des lokalen Hosts) sein.

  • Sie können die Jokerzeichen ‘%’ und ‘_’ in Host-Spaltenwerten benutzen. Sie haben die gleiche Bedeutung wie bei Mustervergleichsoperationen, die mit dem Operator LIKE durchgeführt werden. So stimmt etwa der Host-Wert '%' mit allen Hostnamen überein, während der Wert '%.mysql.com' eine Übereinstimmung mit allen Hosts der Domäne mysql.com bedingt.

  • Bei Host-Werten, die als IP-Nummern angegeben werden, können Sie ein Netzmaske angeben, die die Anzahl der Bits definiert, die für die Netzwerknummer verwendet werden. Zum Beispiel:

    GRANT ALL PRIVILEGES ON db.* TO david@'192.58.197.0/255.255.255.0';
    

    Hiermit kann david von jedem Clienthost aus eine Verbindung herstellen, der die IP-Nummer client_ip hat, sofern für diese die folgende Bedingung wahr ist:

    client_ip & netmask = host_ip
    

    Das bedeutet für die gerade gezeigte GRANT-Anweisung:

    client_ip & 255.255.255.0 = 192.58.197.0
    

    IP-Nummern, die dieser Bedingung genügen und eine Verbindung mit dem MySQL-Server herstellen können, sind mithin diejenigen im Bereich zwischen 192.58.197.0 und 192.58.197.255.

    Hinweis: Die Netzmaske kann nur verwendet werden, um den Server anzuweisen, die ersten acht, 16, 24 oder alle 32 Bits der Adresse zu verwenden. Ein paar Beispiele:

    • 192.0.0.0/255.0.0.0: Alle Hosts im Klasse-A-Netzwerk 192.

    • 192.168.0.0/255.255.0.0: Alle Hosts im Klasse-B-Netzwerk 192.168.

    • 192.168.1.0/255.255.255.0: Alle Hosts im Klasse-C-Netzwerk 192.168.1.

    • 192.168.1.1: Nur die angegebene IP-Adresse.

    Die folgende Netzmaske (28 Bits) wird hingegen nicht funktionieren:

    192.168.0.1/255.255.255.240
    
  • Ein leerer Host-Wert in einem Datensatz der Tabelle db bedeutet, dass die Berechtigungen mit denen im Datensatz in der host-Tabelle kombiniert werden sollen, der mit dem Hostnamen des Clients übereinstimmt. Diese Berechtigungen werden mithilfe des logischen UND (Schnittmenge), nicht des logischen ODER (Gesamtmenge) verknüpft. Abschnitt 5.8.6, „Zugriffskontrolle, Phase 2: Anfrageüberprüfung“, beschreibt die Verwendung der Tabelle host im Detail.

    Ein leerer Host-Wert in den anderen Grant-Tabellen entspricht '%'.

Da es möglich ist, Jokerwerte in den IP-Adressen der Host-Spalte zu verwenden (z. B. '144.155.166.%', um eine Übereinstimmung mit jedem Host in einem bestimmten Subnetz zu erzielen), könnte jemand versuchen, diese Funktionalität auszunutzen, indem er einen Host 144.155.166.somewhere.com nennt. Um derartige Versuche zu durchkreuzen, verbietet MySQL Mustervergleiche mit Hostnamen, die mit Ziffern und einem Punkt beginnen. Das bedeutet, dass ,wenn Sie einen Host mit dem Namen 1.2.foo.com oder ähnlich haben, dieser Name niemals eine Übereinstimmung in der Host-Spalte der Grant-Tabellen finden wird. Ein IP-Jokerwert kann nur mit IP-Adressen, nicht jedoch mit Hostnamen übereinstimmen.

In der Spalte User sind Jokerzeichen nicht zulässig, Sie können jedoch einen leeren Wert angeben, der mit jedem Namen übereinstimmt. Wenn der Datensatz in der Tabelle user, der mit einer eingehenden Verbindung übereinstimmt, einen leeren Benutzernamen aufweist, dann wird der Benutzer als anonymer Benutzer ohne Namen und nicht als Benutzer mit dem Namen betrachtet, der eigentlich vom Client übergeben wurde. Folglich wird ein leerer Benutzername für alle weiteren Zugriffsüberprüfungen während der gesamten Dauer der Verbindung (also während der zweiten Stufe) verwendet.

Die Spalte Password darf leer sein. Dies ist kein Joker und bedeutet auch keine Übereinstimmung mit beliebigen Passwörtern. Vielmehr besagt dies, dass der Benutzer eine Verbindung ohne Angabe eines Passworts herstellen muss.

Nichtleere Password-Werte in der Tabelle user stehen für verschlüsselte Passwörter. MySQL speichert Passwörter nicht in unverschlüsselter, problemlos ersichtlicher Form. Stattdessen wird das von einem Benutzer, der eine Verbindung herstellen will, eingegebene Passwort verschlüsselt (und zwar mit der Funktion PASSWORD()). Dieses verschlüsselte Passwort wird dann während des Verbindungsaufbaus verwendet, um zu überprüfen, ob das Passwort korrekt ist. (Dieser Vorgang läuft ab, ohne dass das verschlüsselte Passwort jemals über die Verbindung übermittelt wird.) Aus der Sicht von MySQL ist das verschlüsselte Passwort das echte Passwort, d. h. Sie sollten niemals jemandem den Zugriff darauf ermöglichen. Insbesondere sollten Sie Nichtadministratoren niemals Lesezugriff auf die Tabellen in der mysql-Datenbank gewähren.

MySQL 5.1 verwendet eine stärkere, erstmals in MySQL 4.1 implementierte Authentifizierungsmethode, die während des Verbindungsvorgangs einen besseren Passwortschutz bietet als frühere Versionen. Sie ist auch dann sicher, wenn TCP/IP-Pakete abgefangen oder die mysql-Datenbank aufgezeichnet wird. Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“, enthält eine eingehendere Beschreibung der Passwortverschlüsselung.

Die folgende Tabelle zeigt, wie verschiedene Kombinationen von Host- und User-Werten in der Tabelle user auf eingehende Verbindungen angewendet werden.

Host WertUser WertZulässige Verbindungen
'thomas.loc.gov''fred'fred, stellt Verbindung her über thomas.loc.gov
'thomas.loc.gov'''Beliebiger Benutzer, stellt Verbindung her über thomas.loc.gov
'%''fred'fred, stellt Verbindung her über beliebigen Host
'%'''Beliebiger Benutzer, stellt Verbindung her über beliebigen Host
'%.loc.gov''fred'fred, stellt Verbindung her über beliebigen Host in der Domäne loc.gov
'x.y.%''fred'fred, stellt Verbindung her über x.y.net, x.y.com, x.y.edu und so weiter (dies ist wahrscheinlich nicht sehr sinnvoll)
'144.155.166.177''fred'fred, stellt Verbindung her vom Host mit der IP-Adresse 144.155.166.177
'144.155.166.%''fred'fred, stellt Verbindung her über beliebigen Host im Klasse-C-Subnetz 144.155.166
'144.155.166.0/255.255.255.0''fred'wie oben

Es kann durchaus vorkommen, dass für die Host- und Benutzernamen einer eingehenden Verbindung mehrere passende Datensätze in der Tabelle user vorhanden sind. Die obigen Beispiele demonstrieren dies: Mehrere der angezeigten Einträge stimmen mit einer Verbindung von fred über thomas.loc.gov überein.

Wenn mehrere Übereinstimmungen möglich sind, muss der Server ermitteln, welche davon er verwenden soll. Dieses Problem löst er wie folgt:

  • Wenn der Server die Tabelle user in den Speicher einliest, sortiert er die Datensätze.

  • Versucht nun ein Client eine Verbindung herzustellen, dann durchsucht der Server die Datensätze in der Sortierreihenfolge.

  • Der Server verwendet den ersten mit dem Host- und Benutzernamen des Clients übereinstimmenden Datensatz.

Um zu verstehen, wie dies funktioniert, nehmen wir einmal an, dass die Tabelle user wie folgt aussieht:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

Wenn der Server die Tabelle in den Speicher einliest, sortiert er die Datensätze mit den spezifischsten Host-Werten nach oben. Literale Hostnamen und IP-Nummern sind am spezifischsten. Das Muster '%' bedeutet „jeder Host“ und ist am wenigsten spezifisch. Datensätze mit demselben Host-Wert werden nach den spezifischsten User-Werten sortiert (wobei ein leerer User-Wert die Bedeutung „beliebiger Benutzer“ hat und am wenigsten spezifisch ist). Bei der oben gezeigten Tabelle user sieht das Ergebnis nach der Sortierung wie folgt aus:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

Wenn ein Client eine Verbindung herzustellen versucht, durchsucht der Server die sortierten Datensätze und verwendet die erste gefundene Übereinstimmung. Stellt jeffrey über localhost eine Verbindung her, dann liegt bei zwei Datensätzen in der Tabelle eine Übereinstimmung vor: zum einen der Datensatz mit den Host- und User-Werten 'localhost' und '', zum anderen der Datensatz mit den Werten '%' und 'jeffrey'. Der Datensatz 'localhost' taucht jedoch in der sortierten Tabelle zuerst auf, wird also vom Server verwendet.

Es folgt ein weiteres Beispiel. Angenommen, die Tabelle user sähe so aus:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-

Die sortierte Tabelle hat dann folgendes Aussehen:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

Für eine Verbindung von jeffrey an thomas.loc.gov liegt eine Übereinstimmung gleich beim ersten Datensatz vor; bei einer Verbindung von jeffrey an whitehouse.gov trifft dies für den zweiten Datensatz zu.

Die Ansicht ist weitverbreitet, dass für einen gegebenen Benutzernamen alle Datensätze, die diesen Namen ausdrücklich angeben, zuerst verwendet werden, wenn der Server eine Übereinstimmung für die Verbindung sucht. Dies ist allerdings unzutreffend. Das obige Beispiel veranschaulicht dies: Eine Verbindung von jeffrey an thomas.loc.gov findet ihre erste Übereinstimmung nicht bei dem Datensatz, der 'jeffrey' als Wert in der Spalte User enthält, sondern beim Datensatz ohne Benutzernamen. Hieraus folgt, dass jeffrey als anonymer Benutzer authentifiziert wird, obwohl er bei der Verbindungsherstellung einen Benutzernamen angegeben hat.

Wenn Sie eine Verbindung mit dem Server herstellen können, aber Ihre Berechtigungen nicht dem entsprechen, was Sie erwarten, dann wurden Sie wahrscheinlich über ein anderes Konto authentifiziert. Um zu ermitteln, welches Konto der Server für Ihre Authentifizierung verwendet hat, verwenden Sie die Funktion CURRENT_USER(). (Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.) Sie gibt einen Wert im Format user_name@host_name zurück, der die Werte User und Host des entsprechenden Datensatzes in der Tabelle user angibt. Angenommen, jeffrey hat eine Verbindung hergestellt und setzt die folgende Abfrage ab:

mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost     |
+----------------+

Das hier gezeigte Ergebnis gibt an, dass der übereinstimmende Datensatz in der Tabelle user einen leeren Wert in der Spalte User aufweist. Mit anderen Worten behandelt der Server jeffrey als anonymen Benutzer.

Ein anderer Schritt, den Sie zur Diagnose von Authentifizierungsproblemen anwenden können, besteht darin, die Tabelle user auszudrucken und sie manuell zu sortieren, um zu ermitteln, wo die erste Übereinstimmung auftritt.

5.8.6. Zugriffskontrolle, Phase 2: Anfrageüberprüfung

Nachdem Sie eine Verbindung hergestellt haben, wechselt der Server zu Stufe 2 der Zugriffssteuerung. Für jede Anforderung, die Sie über die Verbindung absetzen, ermittelt der Server, welche Operation Sie durchführen wollen, und überprüft dann, ob Sie die zu diesem Zweck erforderlichen Berechtigungen besitzen. Hier nun kommen die Berechtigungsspalten in den Grant-Tabellen ins Spiel. Diese Berechtigungen können aus den folgenden Tabellen stammen: user, db, host, tables_priv, columns_priv oder procs_priv. (An dieser Stelle kann es unter Umständen hilfreich sein, noch einmal Abschnitt 5.8.2, „Wie das Berechtigungssystem funktioniert“, zu lesen. Dort sind die Spalten aufgelistet, die in den verschiedenen Grant-Tabellen vorhanden sind.)

Die Tabelle user gewährt Berechtigungen, die Ihnen auf globaler Basis zugewiesen werden und die unabhängig von der gewählten Standarddatenbank gelten. Wenn die Tabelle user Ihnen beispielsweise die Berechtigung DELETE gewährt, können Sie Datensätze aus allen Tabellen in allen Datenbanken auf dem Serverhost löschen! Anders gesagt sind Berechtigungen für die Tabelle user Superuser-Berechtigungen. Es ist klug, Berechtigungen in der Tabelle user nur Superusern wie beispielsweise Datenbankadministratoren zu gewähren. Bei allen anderen Benutzern sollten Sie die Berechtigungen in der Tabelle user auf 'N' stehen lassen und Berechtigungen nur auf spezifischeren Ebenen gewähren. Sie können Berechtigungen für bestimmte Datenbanken, Tabellen, Spalten und Routinen gewähren.

Die Tabellen db und host gewähren datenbankspezifische Berechtigungen. Werte in den Bereichsspalten dieser Tabellen können die folgende Form annehmen:

  • Die Jokerzeichen ‘%’ und ‘_’ können in den Spalten Host und Db dieser Tabellen verwendet werden. Sie haben die gleiche Bedeutung wie bei Mustervergleichsoperationen, die mit dem Operator LIKE durchgeführt werden. Wenn Sie eines der Zeichen beim Gewähren von Berechtigungen literal verwenden wollen, müssen Sie es mit einem Backslash kennzeichnen. Um beispielsweise den Unterstrich (‘_’) als Teil eines Datenbanknamens zu verwenden, geben Sie ihn als ‘\_’ in der GRANT-Anweisung an.

  • Der Wert '%' in der Spalte Host der Tabelle db bedeutet „ein beliebiger Host“. Ein leerer Host-Wert in der Tabelle db hat die Bedeutung „Weitere Informationen der Tabelle host entnehmen“ (dieser Vorgang wird im weiteren Verlauf dieses Abschnitts noch beschrieben).

  • Der Wert '%' oder ein leerer Wert in der Spalte Host der Tabelle host bedeutet „ein beliebiger Host“.

  • Der Wert '%' oder ein leerer Wert in der Spalte Db in einer dieser Tabellen bedeutet „eine beliebige Datenbank“.

  • Ein leerer User-Wert in einer der Tabellen führt zur Übereinstimmung mit dem anonymen Benutzer.

Der Server liest die Tabellen db und host in den Speicher ein und sortiert sie, während er gleichzeitig die Tabelle user einliest. Der Server sortiert die Tabelle db nach den Bereichsspalten Host, Db und User und die Tabelle host nach den Bereichsspalten Host und Db. Wie bei der Sortierung der Tabelle user werden auch hier die spezifischeren Werte an den Anfang und die weniger spezifischen an das Ende der Tabelle gesetzt, und auch hier verwendet der Server bei der Suche nach Übereinstimmungen das erste passende Ergebnis.

Die Tabellen tables_priv columns_priv und proc_priv gewähren tabellenspezifische, spaltenspezifische und routinenspezifische Berechtigungen. Werte in den Bereichsspalten dieser Tabellen können die folgende Form annehmen:

  • Die Jokerzeichen ‘%’ und ‘_’ können in der Spalte Host verwendet werden. Sie haben die gleiche Bedeutung wie bei Mustervergleichsoperationen, die mit dem Operator LIKE durchgeführt werden.

  • Der Wert '%' oder ein leerer Wert in der Spalte Host bedeutet „ein beliebiger Host“.

  • Die Spalten Db, Table_name und Column_name dürfen weder Jokerzeichen enthalten noch leer sein.

Der Server sortiert die Tabellen tables_priv, columns_priv und procs_priv nach den Spalten Host, Db und User. Dies ähnelt der Sortierung der Tabelle db, ist aber einfacher, da nur die Spalte Host Jokerzeichen enthalten darf.

Der Server verwendet die sortierten Tabellen zur Verifizierung aller empfangenen Anforderungen. Bei Anforderungen, die administrative Berechtigungen voraussetzen (z. B. SHUTDOWN oder RELOAD), überprüft der Server nur den Datensatz in der Tabelle user, weil dies die einzige Tabelle ist, die administrative Berechtigungen angibt. Der Server gewährt den Zugriff, wenn der Datensatz die angeforderte Operation gestattet; andernfalls wird der Zugriff abgewiesen. Wenn Sie also beispielsweise mysqladmin shutdown ausführen wollen, aber Ihr Datensatz in der Tabelle user Ihnen die Berechtigung SHUTDOWN nicht gewährt, dann verweigert der Server Ihnen den Zugriff, ohne die Tabellen db oder host auch nur abgefragt zu haben. (Da diese Tabellen keine Shutdown_priv-Spalte enthalten, ist dies ohnehin unnötig.)

Bei datenbankbezogenen Anforderungen (INSERT, UPDATE usw.) überprüft der Server zuerst die globalen Berechtigungen (Superuser-Berechtigungen), indem er den Datensatz in der Tabelle user abfragt. Gestattet der Datensatz die angeforderte Operation, dann wird der Zugriff gewährt. Wenn die globalen Berechtigungen in der Tabelle user nicht ausreichend sind, ermittelt der Server die datenbankspezifischen Berechtigungen, indem er die Tabellen db und host überprüft:

  1. Der Server sucht in der Tabelle db nach einer Übereinstimmung der Spalten Host, Db und User. Die Spalten Host und User werden auf Übereinstimmung mit dem Hostnamen und dem MySQL-Benutzernamen des Benutzers geprüft, der die Verbindung herstellen will. Die Spalte Db wird mit der Datenbank verglichen, auf die der Benutzer zugreifen will. Kann kein Datensatz für Host und User gefunden werden, dann wird der Zugriff verweigert.

  2. Ist ein übereinstimmender Datensatz in der Tabelle db vorhanden und ist die Spalte Host nicht leer, dann definiert der Datensatz die datenbankspezifischen Berechtigungen für den Benutzer.

  3. Ist die Spalte Host im übereinstimmenden Datensatz der Tabelle db leer, dann bedeutet dies, dass die Tabelle host auflistet, welche Hosts auf die Datenbank zugreifen dürfen. In diesem Fall wird in der Tabelle host erneut eine Übereinstimmung mit den Spalten Host und Db gesucht. Wird kein passender Datensatz in der Tabelle host gefunden, dann wird der Zugriff verweigert. Wird allerdings eine Übereinstimmung gefunden, dann werden die datenbankspezifischen Berechtigungen des Benutzers als Schnittmenge (nicht als Gesamtmenge!) der Berechtigungen in den Einträgen der Tabellen db und host berechnet, d. h. die Berechtigungen müssen in beiden Einträgen jeweils 'Y' sein. (Auf diese Weise können Sie allgemeine Berechtigungen im Datensatz der Tabelle db gewähren und diese dann über die Tabelle host auf Hostbasis selektiv einschränken.)

Nachdem er die datenbankspezifischen Berechtigungen ermittelt hat, die durch die Einträge in den Tabellen db und host gewährt werden, fügt der Server diese den durch die Tabelle user gewährten Berechtigungen hinzu. Gestattet das Ergebnis die angeforderte Operation, dann wird der Zugriff gewährt. Andernfalls überprüft der Server nachfolgend die Tabellen- und Spaltenberechtigungen des Benutzers in den Tabellen tables_priv bzw. columns_priv, fügt diese den Benutzerberechtigungen hinzu und gestattet oder verweigert auf der Basis des Ergebnisses den Zugriff. Bei Operationen in Zusammenhang mit gespeicherten Routinen verwendet der Server die Tabelle procs_priv statt tables_priv und columns_priv.

Ausgedrückt in booleschen Termini, lässt sich die vorangegangene Beschreibung der Berechnung von Benutzerberechtigungen wie folgt zusammenfassen:

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
OR routine privileges

Es ist vielleicht nicht einleuchtend, warum der Server, wenn die globalen Berechtigungen im Datensatz der Tabelle user zunächst nicht als ausreichend für die angeforderte Operation erachtet werden, diese Berechtigungen später zu den Berechtigungen für die Datenbanken, Tabellen und Spalten hinzufügt. Der Grund hierfür besteht darin, dass eine Anforderung mehrere Berechtigungstypen erfordern kann. Wenn Sie beispielsweise eine INSERT INTO ... SELECT-Anweisung ausführen, benötigen Sie sowohl die Berechtigung INSERT als auch die Berechtigung SELECT. Ihre Berechtigungen sehen unter Umständen so aus, dass der Datensatz in der Tabelle user eine dieser Berechtigungen und der Datensatz in der Tabelle db die andere Berechtigung gewährt. In diesem Fall besitzen Sie die erforderlichen Berechtigungen, um die Anforderung durchzuführen, aber der Server kann dies nicht mithilfe nur einer Tabelle bestimmen; vielmehr müssen die von den Einträgen in beiden Tabellen gewährten Berechtigungen kombiniert werden.

Die Tabelle host wird von GRANT- und REVOKE-Anweisungen nicht beeinflusst, liegt also in den meisten MySQL-Installationen brach. Wenn Sie sie jedoch manuell modifizieren, können Sie sie für bestimmte Spezialzwecke einsetzen, z. B. um eine Liste sicherer Server zu führen. Bei TcX beispielsweise enthält die Tabelle host eine Liste aller Systeme im lokalen Netzwerk. Diesen sind alle Berechtigungen gewährt.

Sie können die Tabelle host auch verwenden, um Hosts anzugeben, die nicht sicher sind. Nehmen wir an, dass Sie einen Computer namens public.your.domain haben, der sich in einem öffentlichen Bereich befindet, den Sie als nicht sicher erachten. Sie können Zugriff auf alle Hosts in Ihrem Netzwerk mit Ausnahme dieses Computers gewähren, indem Sie die Einträge der Tabelle host wie folgt verwenden:

+--------------------+----+-
| Host               | Db | ...
+--------------------+----+-
| public.your.domain | %  | ... (all privileges set to 'N')
| %.your.domain      | %  | ... (all privileges set to 'Y')
+--------------------+----+-

Natürlich sollten Sie Ihre Änderungen an den Grant-Tabellen immer testen (z. B. mit SHOW GRANTS), um sicherzustellen, dass Ihre Zugriffsberechtigungen tatsächlich so konfiguriert sind, wie Sie es wünschen.

5.8.7. Wann Berechtigungsänderungen wirksam werden

Beim Start liest mysqld den gesamten Inhalt der Grant-Tabellen in den Speicher. Die Tabellen im Arbeitsspeicher werden zu diesem Zeitpunkt für die Zugriffssteuerung verbindlich.

Wenn der Server die Grant-Tabellen neu lädt, sind Berechtigungen für vorhandene Clientverbindungen hiervon wie folgt betroffen:

  • Änderungen an Berechtigungen für Tabellen und Spalten werden beginnend mit der nächsten Anforderung des Clients gültig.

  • Datenbankberechtigungen werden bei der nächsten USE db_name-Anweisung gültig.

  • Änderungen an globalen Berechtigungen und Passwörtern werden gültig, wenn der Client beim nächsten Mal eine Verbindung herstellen will.

Wenn Sie die Grant-Tabellen indirekt mit Anweisungen wie GRANT, REVOKE oder SET PASSWORD modifizieren, bemerkt der Server diese Änderungen und lädt die Grant-Tabellen sofort wieder neu in den Speicher.

Ändern Sie die Grant-Tabellen hingegen direkt mit Anweisungen wie INSERT, UPDATE oder DELETE, dann werden Ihre berechtigungsbezogenen Änderungen erst umgesetzt, wenn Sie den Server neu starten oder ihn zum Neuladen der Tabellen anweisen. Um die Grant-Tabellen manuell neu zu laden, setzen Sie eine FLUSH PRIVILEGES-Anweisung ab oder führen den Befehl mysqladmin flush-privileges oder mysqladmin reload aus.

Wenn Sie die Grant-Tabellen ändern, aber vergessen, sie neu zu laden, dann werden Ihre Änderungen erst dann umgesetzt, wenn Sie den Server neu starten. Unter Umständen wundern Sie sich aus diesem Grund darüber, dass Ihre Änderungen überhaupt keinen Unterschied zu machen scheinen!

5.8.8. Gründe für Access denied-Fehler

Wenn beim Versuch, eine Verbindung zum MySQL-Server herzustellen, Probleme auftreten, dann können Sie die in diesem Abschnitt beschriebenen Schritte ausführen, um diese Probleme zu beseitigen.

  • Vergewissern Sie sich zunächst, dass der Server auch ausgeführt wird. Läuft er nicht, dann können Sie auch keine Verbindung herstellen. Wenn Sie beispielsweise versuchen, eine Verbindung zum Server herzustellen, und eine Meldung wie die folgende angezeigt wird, dann kann Ursache hierfür auch sein, dass der Server schlichtweg nicht läuft:

    shell> mysql
    ERROR 2003: Can't connect to MySQL server on 'host_name' (111)
    shell> mysql
    ERROR 2002: Can't connect to local MySQL server through socket
    '/tmp/mysql.sock' (111)
    

    Ferner ist es möglich, dass der Server zwar ausgeführt wird, Sie aber eine Verbindung über einen TCP/IP-Port, eine Named Pipe oder eine Unix-Socketdatei herstellen wollen, die nicht mit der Ressource übereinstimmt, auf der der Server horcht. Um dieses Problem zu beheben, geben Sie beim Aufruf eines Clientprogramms eine Option --port oder --socket an, um die korrekte Portnummer bzw. Named Pipe oder Unix-Socketdatei anzugeben. Mithilfe des folgenden Befehls ermitteln Sie, wo die Socketdatei sich befindet:

    shell> netstat -ln | grep mysql
    
  • Die Grant-Tabellen müssen korrekt konfiguriert sein, damit der Server sie zur Zugriffssteuerung verwenden kann. Bei einigen Distributionstypen (z. B. Binärdistributionen für Windows oder RPM-Distributionen für Linux) initialisiert der Installationsvorgang die mysql-Datenbank, die die Grant-Tabellen enthält. Wenn Ihre Distribution dies nicht tut, dann müssen Sie die Grant-Tabellen manuell initialisieren, indem Sie das Skript mysql_install_db ausführen. Detaillierte Informationen finden Sie in Abschnitt 2.9.2, „Schritte nach der Installation unter Unix“.

    Eine Möglichkeit, zu ermitteln, ob Sie die Grant-Tabellen initialisieren müssen, besteht darin, nach einem Verzeichnis mysql zu suchen, das sich im Datenverzeichnis befindet. (Das Datenverzeichnis heißt normalerweise data oder var und befindet sich seinerseits im MySQL-Installationsverzeichnis.) Vergewissern Sie sich, dass eine Datei namens user.MYD im Datenverzeichnis mysql vorhanden ist. Sollte dies nicht der Fall sein, dann führen Sie das Skript mysql_install_db aus. Nach Ausführung des Skripts und dem Starten des Servers können Sie die anfänglich vorhandenen Berechtigungen durch Ausführung des folgenden Befehls überprüfen:

    shell> mysql -u root test
    

    Der Server sollte die Herstellung dieser Verbindung ohne Fehler gestatten.

  • Nach einer frischen Installation sollten Sie eine Verbindung mit dem Server herstellen und Ihre Benutzer und deren Zugriffsberechtigungen einrichten:

    shell> mysql -u root mysql
    

    Der Server sollte diese Verbindung gestatten, da der MySQL-Benutzer root anfänglich kein Passwort hat. Dies ist natürlich auch ein Sicherheitsrisiko d. h. Sie sollten das Passwort für das root-Konto einrichten, während Sie auch die übrigen MySQL-Konten konfigurieren. Anweisungen zur Einstellung der anfänglichen Passwörter finden Sie in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“.

  • Haben Sie, sofern Sie eine vorhandene MySQL-Installation auf eine neuere Version aktualisiert haben, das Skript mysql_fix_privilege_tables ausgeführt? Wenn nicht, holen Sie dies schleunigst nach. Die Struktur der Grant-Tabellen ändert sich ab und an, wenn neue Funktionalitäten hinzugefügt werden. Deswegen sollten Sie nach einem Upgrade immer sicherstellen, dass Ihre Tabellen die aktuell gültige Struktur aufweisen. Informationen zur Vorgehensweise finden Sie in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

  • Wenn ein Clientprogramm beim Verbindungsversuch die folgende Fehlermeldung erhält, bedeutet dies, dass der Server Passwörter in einem neueren Format als dem erwartet, das der Client erzeugen kann:

    shell> mysql
    Client does not support authentication protocol requested
    by server; consider upgrading MySQL client
    

    Informationen dazu, wie Sie in diesem Fall verfahren, finden Sie in Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“, und Abschnitt A.2.3, „Client does not support authentication protocol.

  • Wenn Sie eine Verbindung als root herstellen und die folgende Fehlermeldung erhalten, dann heißt das, dass kein Datensatz in der Tabelle user gefunden wurde, der in der Spalte User den Wert 'root' aufweist – mysqld kann den Hostnamen Ihres Clients in diesem Fall nicht auflösen:

    Access denied for user ''@'unknown' to database mysql
    

    Sie müssen den Server in einem solchen Fall mit der Option --skip-grant-tables neu starten und in Ihrer Datei /etc/hosts bzw. \windows\hosts einen Eintrag für den Host hinzufügen.

  • Zur Erinnerung: Clientprogramme verwenden Verbindungsparameter, die in Optionsdateien oder über Umgebungsvariablen angegeben sind. Wenn ein Clientprogramm offensichtlich unzutreffende Standardverbindungsparameter sendet, weil Sie auf der Befehlszeile keine entsprechenden Informationen angegeben haben, überprüfen Sie die Umgebung und alle relevanten Optionsdateien. Wenn Sie beispielsweise bei der Ausführung eines Clients ohne Optionen die Fehlermeldung Access denied erhalten, vergewissern Sie sich, dass Sie in keiner Ihrer Optionsdateien ein altes Passwort angegeben haben!

    Sie können die Verwendung von Optionsdateien durch ein Clientprogramm unterdrücken, indem Sie es mit der Option --no-defaults aufrufen. Zum Beispiel:

    shell> mysqladmin --no-defaults -u root version
    

    Die von Clients verwendeten Optionsdateien sind in Abschnitt 4.3.2, „my.cnf-Optionsdateien“ aufgelistet. Umgebungsvariablen werden in Anhang F, Umgebungsvariablen beschrieben.

  • Wenn Sie die folgende Fehlermeldung erhalten, bedeutet dies, dass Sie das falsche root-Passwort benutzen:

    shell> mysqladmin -u root -pxxxx ver
    Access denied for user 'root'@'localhost' (using password: YES)
    

    Wenn dieser Fehler auftritt, obwohl Sie gar kein Passwort angegeben haben, ergibt sich daraus, dass ein falsches Passwort in irgendeiner Optionsdatei aufgeführt sein muss. Probieren Sie in diesem Fall die Option --no-defaults wie im vorhergehenden Abschnitt beschrieben aus.

    Informationen zur Änderung von Passwörtern finden Sie in Abschnitt 5.9.5, „Kennwörter einrichten“.

    Haben Sie das root-Passwort verloren oder vergessen, dann können Sie mysqld mit --skip-grant-tables neu starten, um das Passwort zu ändern. Siehe auch Abschnitt A.4.1, „Wie ein vergessenes Kennwort zurückgesetzt wird“.

  • Wenn Sie ein Passwort mit SET PASSWORD, INSERT oder UPDATE ändern, müssen Sie es mit der Funktion PASSWORD() verschlüsseln. Verwenden Sie PASSWORD() für diese Anweisungen nicht, dann funktioniert das Passwort nicht. So wird mit der folgenden Anweisung ein Passwort zwar eingestellt, aber nicht verschlüsselt – und der Benutzer kann nachfolgend keine Verbindung herstellen:

    SET PASSWORD FOR 'abe'@'host_name' = 'eagle';
    

    Stattdessen muss das Passwort wie folgt eingestellt werden:

    SET PASSWORD FOR 'abe'@'host_name' = PASSWORD('eagle');
    

    Die Funktion PASSWORD() ist entbehrlich, wenn Sie ein Passwort mit GRANT- oder CREATE USER-Anweisungen oder dem Befehl mysqladmin password festlegen. Sie alle verschlüsseln das Passwort automatisch mit PASSWORD(). Siehe auch Abschnitt 5.9.5, „Kennwörter einrichten“, und Abschnitt 13.5.1.1, „CREATE USER.

  • localhost ist ein Synonym für Ihren lokalen Hostnamen und zudem der standardmäßige Host, mit dem Clients eine Verbindung herzustellen versuchen, wenn Sie keinen Host explizit angeben.

    Um dieses Problem auf solchen Systemen zu umgehen, können Sie die Option --host=127.0.0.1 verwenden, um den Serverhost explizit anzugeben. Hierdurch wird eine TCP/IP-Verbindung mit dem lokalen mysqld-Server hergestellt. Sie können TCP/IP auch verwenden, indem Sie eine Option --host angeben, die den eigentlichen Hostnamen des lokalen Hosts verwendet. In diesem Fall muss der Hostname in einem Datensatz in der Tabelle user auf dem Serverhost angegeben sein, auch wenn Sie das Clientprogramm auf demselben Host wie den Server ausführen.

  • Wenn Sie die Fehlermeldung Access denied erhalten, wenn Sie mit mysql -u user_name eine Verbindung zur Datenbank herstellen, liegt unter Umständen ein Problem mit der Tabelle user vor. Sie können dies überprüfen, indem Sie mysql -u root mysql ausführen und die folgende SQL-Anweisung absetzen:

    SELECT * FROM user;
    

    Das Ergebnis sollte einen Datensatz mit Host- und User-Spaltenwerten enthalten, die mit dem Hostnamen Ihres Computers bzw. Ihrem MySQL-Benutzernamen übereinstimmen.

  • Die Fehlermeldung Access denied sagt Ihnen, als wer Sie eine Verbindung herzustellen versuchen, von welchem Clienthost Sie diese Verbindung herzustellen versuchen und ob Sie ein Passwort angegeben haben. Normalerweise sollte genau ein Datensatz in der Tabelle user vorhanden sein, für den eine Übereinstimmung mit dem Host- und dem Benutzernamen vorliegt, die in der Fehlermeldung angegeben werden. Erhalten Sie beispielsweise eine Fehlermeldung, die using password: NO enthält, dann bedeutet dies, dass Sie versucht haben, sich ohne Passwort anzumelden.

  • Tritt der folgende Fehler auf, wenn Sie versuchen, eine Verbindung von einem anderen als dem Host herzustellen, auf dem der MySQL-Server ausgeführt wird, dann bedeutet dies, dass in der Tabelle user kein Datensatz mit einem zum Clienthost passenden Host-Wert gefunden wurde:

    Host ... is not allowed to connect to this MySQL server
    

    Sie können dieses Problem beheben, indem Sie ein Konto für die Kombination aus Clienthostname und Benutzername erstellen, die Sie zur Verbindungsherstellung verwenden.

    Wenn Sie IP-Adresse oder Hostname des Computers, von dem aus Sie die Verbindung herstellen, nicht kennen, dann sollten Sie einen Datensatz mit dem Wert '%' in die Spalte Host der Tabelle user einfügen. Nachdem Sie versucht haben, eine Verbindung vom Clientsystem herzustellen, ermitteln Sie mit einer SELECT USER()-Abfrage, wie Sie die Verbindung tatsächlich hergestellt haben. (Ändern Sie nachfolgend den Eintrag '%' im betreffenden Datensatz der Tabelle user zu dem im Log angegebenen Hostnamen. Wenn Sie dies versäumen, bleibt Ihr System unsicher, da es dem angegebenen Benutzernamen Verbindungen von jedem Host aus gestattet.)

    Unter Linux kann ein anderer Grund für diese Fehlermeldung darin bestehen, dass Sie eine aus einer Binärdistribution stammende MySQL-Version verwenden, die mit einer anderen Version der glibc-Bibliothek als der von Ihnen verwendeten kompiliert wurde. In diesem Fall sollten Sie entweder Ihr Betriebssystem oder glibc aktualisieren oder eine Quelldistribution der MySQL-Version herunterladen und selbst kompilieren. Dies ist kein Problem, da Kompilierung und Installation eines Quellcode-RPM in der Regel einfach und schnell erledigt sind.

  • Wenn Sie beim Verbindungsversuch einen Hostnamen angeben, aber eine Fehlermeldung erhalten, in der der Hostname nicht oder an seiner Stelle eine IP-Adresse angegeben ist, dann bedeutet dies, dass am MySQL-Server bei dem Versuch, die IP-Adresse des Clients in einen Namen aufzulösen, ein Fehler aufgetreten ist:

    shell> mysqladmin -u root -pxxxx -h some_hostname ver
    Access denied for user 'root'@'' (using password: YES)
    

    Dies weist auf ein DNS-Problem hin. Um es zu beheben, setzen Sie den internen DNS-Hostnamens-Cache durch Ausführen von mysqladmin flush-hosts zurück. Siehe auch Abschnitt 7.5.6, „Wie MySQL DNS benutzt“.

    Die folgenden Lösungen versprechen dauerhaften Erfolg:

    • Ermitteln Sie, was bei Ihrem DNS-Server nicht stimmt, und beheben Sie das Problem.

    • Geben Sie in den MySQL-Grant-Tabellen IP-Adressen statt Hostnamen an.

    • Fügen Sie für den Namen des Clientcomputers einen Eintrag in /etc/hosts bzw. \windows\hosts hinzu.

    • Starten Sie mysqld mit der Option --skip-name-resolve.

    • Starten Sie mysqld mit der Option --skip-host-cache.

    • Stellen Sie eine Verbindung mit localhost her, wenn Sie unter Unix den Server und den Client auf demselben Computer ausführen. Für Verbindungen mit localhost verwendet Unix statt TCP/IP eine Unix-Socketdatei.

    • Stellen Sie eine Verbindung mit dem Hostnamen . (Punkt) her, wenn Sie unter Windows den Server und den Client auf demselben Computer ausführen und der Server Named Pipes unterstützt. Verbindungen mit . verwenden statt TCP/IP eine Named Pipe.

  • Wenn mysql -u root test funktioniert, aber mysql -h your_hostname -u root test zur Fehlermeldung Access denied führt (wobei your_hostname der tatsächliche Hostname des lokalen Hosts ist), dann steht unter Umständen für Ihren Host nicht der korrekte Name in der Tabelle user. Ein häufig auftretendes Problem besteht hier darin, dass der Host-Wert des Datensatzes in der Tabelle user einen unqualifizierten Hostnamen angibt, die Namensauflösungsroutinen Ihres Systems aber einen vollqualifizierten Domänennamen zurückgeben (oder umgekehrt). Wenn Sie also beispielsweise einen Eintrag mit dem Host 'tcx' in der Tabelle user haben, aber Ihr DNS MySQL meldet, dass Ihr Hostname 'tcx.subnet.se' lautet, dann funktioniert der Eintrag nicht. Versuchen Sie, der Tabelle user einen Eintrag hinzufügen, der die IP-Adresse Ihres Hosts als Host-Spaltenwert enthält. (Alternativ können Sie einen Eintrag in der Tabelle user mit einem Host-Wert hinzufügen, der ein Jokerzeichen enthält – z. B. 'tcx.%'. Allerdings ist die Verwendung von Hostnamen, die auf ‘%’ enden, ein Sicherheitsrisiko. Wir raten dringend davon ab!)

  • Wenn mysql -u user_name test funktioniert, mysql -u user_name other_db_name aber nicht, dann haben Sie dem betreffenden Benutzer keinen Datenbankzugriff auf other_db_name gewährt.

  • Wenn mysql -u user_name bei einer Ausführung auf dem Serverhost funktioniert, mysql -h host_name -u user_name jedoch bei der Ausführung auf dem Clienthost jedoch nicht, dann haben Sie für den betreffenden Benutzernamen den Zugriff vom entfernten Host auf den Server nicht aktiviert.

  • Wenn Sie nicht feststellen können, warum Sie den Fehler Access denied erhalten, entfernen Sie aus der Tabelle user alle Einträge, die Host-Werte mit Jokerzeichen aufweisen (d. h. Einträge, die ‘%’ oder ‘_’ enthalten). Ein sehr häufiger Fehler besteht darin, einen neuen Eintrag mit Host='%' und User='some_user' einzufügen, weil man der Ansicht ist, dass dies die Angabe von localhost zur Verbindung von demselben Computer aus ermöglicht. Der Grund dafür, dass dies nicht funktioniert, ist, dass die Standardberechtigungen einen Eintrag mit Host='localhost' und User='' enthalten. Da dieser Eintrag einen Host-Wert 'localhost' aufweist, der spezifischer ist als '%', wird er anstelle des neuen Eintrags verwendet, wenn eine Verbindung von localhost aus hergestellt wird! Die korrekte Vorgehensweise besteht darin, einen zweiten Eintrag mit Host='localhost' und User='some_user' einzufügen oder den Eintrag mit Host='localhost' und User='' zu löschen. Nach dem Löschen des Eintrags dürfen Sie nicht vergessen, eine FLUSH PRIVILEGES-Anweisung abzusetzen, um die Grant-Tabellen neu zu laden.

  • Wenn Sie den folgenden Fehler erhalten, liegt unter Umständen ein Problem mit den Tabellen db oder host vor:

    Access to database denied
    

    Wenn der in der Tabelle db gewählte Eintrag einen leeren Wert in der Spalte Host aufweist, müssen Sie sicherstellen, dass mindestens ein entsprechender Eintrag in der Tabelle host vorhanden ist, der angibt, für welche Hosts der Eintrag in der Tabelle db gilt.

  • Wenn Sie eine Verbindung mit dem MySQL-Server herstellen können, aber immer dann eine Fehlermeldung Access denied erhalten, wenn Sie eine SELECT ... INTO OUTFILE- oder LOAD DATA INFILE-Anweisung absetzen, ist für Ihren Eintrag in der Tabelle user die Berechtigung FILE nicht aktiviert.

  • Ändern Sie die Grant-Tabellen direkt (z. B. mit INSERT, UPDATE oder DELETE) und werden Ihre Änderungen offenbar ignoriert, dann dürfen Sie nicht vergessen, eine FLUSH PRIVILEGES-Anweisung oder den Befehl mysqladmin flush-privileges auszuführen, damit der Server Ihre Berechtigungstabellen neu einliest. Andernfalls werden Ihre Änderungen erst beim nächsten Neustart des Servers umgesetzt. Denken Sie auch immer daran, dass Sie, wenn Sie das root-Passwort mit einem UPDATE-Befehl geändert haben, das neue Passwort erst nach dem Schreiben der Berechtigungen angeben müssen, da der Server vorher gar nicht weiß, dass Sie Ihr Passwort geändert haben!

  • Wenn Ihre Berechtigungen im Verlauf einer Sitzung offensichtlich geändert werden, besteht die Möglichkeit, dass ein MySQL-Administrator die Änderungen vorgenommen hat. Das Neuladen der Grant-Tabellen wirkt sich auf neue Clientverbindungen, aber auch auf vorhandene Verbindungen aus (siehe auch Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“).

  • Wenn Sie bei einem Perl-, PHP-, Python- oder ODBC-Programm Probleme mit dem Zugriff haben, sollten Sie versuchen, eine Serververbindung mit mysql -u user_name db_name oder mysql -u user_name -pyour_pass db_name herzustellen. Wenn Sie eine Verbindung mit dem mysql-Client herstellen können, wird das Problem von Ihrem Programm und nicht von den Zugriffsberechtigungen verursacht. (Zwischen -p und dem Passwort ist kein Leerzeichen vorhanden; Sie können auch die Syntax --password=your_pass zur Angabe des Passworts verwenden. Wenn Sie die Option -p bzw. --password ohne Passwortwert benutzen, fordert Sie MySQL zur Eingabe des Passworts auf.)

  • Zu Testzwecken starten Sie den mysqld-Server mit der Option --skip-grant-tables. Sie können dann die MySQL-Grant-Tabellen ändern und das Skript mysqlaccess zur Überprüfung verwenden, ob Ihre Änderungen die gewünschte Wirkung hervorrufen. Wenn Sie mit den Änderungen zufrieden sind, führen Sie mysqladmin flush-privileges aus, um dem mysqld-Server anzuweisen, die neuen Grant-Tabellen ab sofort zu verwenden. (Das Neuladen der Grant-Tabellen hat Vorrang vor der Option --skip-grant-tables. Dies ermöglicht Ihnen, den Server zur sofortigen Verwendung der neuen Grant-Tabellen anzuweisen, ohne dass ein Serverneustart erforderlich wäre.)

  • Wenn alles andere fehlschlägt, starten Sie den mysqld-Server mit einer Debug-Option (z. B. --debug=d,general,query). Hierdurch werden Host- und Benutzerinformationen zu Verbindungsversuchen sowie Angaben zu allen abgesetzten Befehlen ausgegeben. Siehe auch Abschnitt E.1.2, „Trace-Dateien erzeugen“.

  • Wenn Sie andere Probleme mit den MySQL-Grant-Tabellen haben und diese der Mailingliste beschreiben wollen, fügen Sie auch immer einen Speicherauszug der MySQL-Grant-Tabellen bei. Diesen können Sie mit dem Befehl mysqldump mysql erstellen. Verwenden Sie zum Übermitteln eines Fehlerberichts die in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“ beschriebenen Anweisungen. In manchem Fällen müssen Sie mysqld unter Umständen mit der Option --skip-grant-tables neu starten, um mysqldump ausführen zu können.

5.8.9. Kennwort-Hashing ab MySQL 4.1

MySQL-Benutzerkonten sind in der Tabelle user der Datenbank mysql aufgelistet. Jedem MySQL-Konto wird ein Passwort zugewiesen. Allerdings wird in der Spalte Password der Tabelle user nicht die unverschlüsselte Version des Passworts gespeichert, sondern ein auf dessen Basis berechneter Hash-Wert. Die Hash-Werte für Passwörter werden mit der Funktion PASSWORD() berechnet.

MySQL verwendet die Passwörter in zwei Phasen der Client/Server-Kommunikation:

  • Wenn ein Client eine Verbindung zum Server herstellen will, gibt es einen ersten Authentifizierungsschritt, bei dem der Client ein Passwort mit einem Hash-Wert vorweisen muss, der mit dem Hash-Wert übereinstimmt, welcher in der Tabelle user für das vom Client verwendete Konto gespeichert ist.

  • Wenn der Client die Verbindung hergestellt hat, kann er – sofern er über ausreichende Berechtigungen verfügt – die Passwort-Hashes für die in der Tabelle user gelisteten Konten einstellen oder ändern. Der Client kann dies tun, indem er mithilfe der Funktion PASSWORD() einen Passwort-Hash erzeugt oder die Anweisungen GRANT oder SET PASSWORD verwendet.

Mit anderen Worten benutzt der Server die Hash-Werte während der Authentifizierung, wenn der Client erstmals eine Verbindung herzustellen versucht. Dagegen erzeugt der Server Hash-Werte, wenn ein verbundener Client die Funktion PASSWORD() aufruft oder eine GRANT- oder SET PASSWORD-Anweisung benutzt, um ein Passwort einzustellen oder zu ändern.

Die Methode für das Passwort-Hashing wurde in MySQL 4.1 geändert, um mehr Sicherheit zu bieten und das Risiko zu verringern, dass Passwörter abgefangen werden. Allerdings wird diese neue Methode nur von Servern und Clients unter MySQL 4.1 und höher verstanden, was Kompatibilitätsprobleme verursachen kann. Ein Client unter Version 4.1 oder höher kann mit einem Server unter einer Version vor 4.1 eine Verbindung herstellen, da der Client sowohl die alte als auch die neue Hashing-Methode versteht. Allerdings kann es zu Schwierigkeiten kommen, wenn ein Client unter einer alten Version mit einem Server unter Version 4.1 oder höher einen Verbindungsaufbau probiert. So kann eine Verbindung, die ein mysql-Client unter Version 3.23 mit einem Server unter 5.1 herzustellen versucht, mit der folgenden Fehlermeldung fehlschlagen:

shell> mysql -h localhost -u root
Client does not support authentication protocol requested
by server; consider upgrading MySQL client

Ein anderes häufiges Beispiel für dieses Phänomen tritt auf, wenn nach einem Upgrade auf MySQL 4.1 versucht wird, die ältere PHP-mysql-Erweiterung zu verwenden. (Siehe auch Abschnitt 24.3.1, „Allgemeine Probleme mit MySQL und PHP“.)

Im Folgenden werden die Unterschiede zwischen der alten und der neuen Passwortmethode beschrieben. Ferner werden wir erläutern, was Sie tun müssen, wenn Sie Ihren Server unter Beibehaltung der Abwärtskompatibilität mit Clients unter Versionen vor 4.1 aktualisieren wollen. Zusätzliche Informationen finden Sie unter Abschnitt A.2.3, „Client does not support authentication protocol. Diese Hinweise sind besonders wichtig für PHP-Programmierer, die ihre MySQL-Datenbanken von einer Version vor 4.1 auf Version 4.1 oder höher migrieren.

Hinweis: In der Beschreibung wird das Verhalten von Version 4.1 und höher dem Verhalten älterer Versionen gegenübergestellt. Tatsächlich aber wurde das hier beschriebene Verhalten erst mit Version 4.1.1 implementiert. MySQL 4.1.0 ist eine „merkwürdige“ Version, denn sie weist eine etwas andere Methode auf als die Versionen 4.1.1 und folgende. Die Unterschiede zwischen 4.1.0 und den neueren Versionen sind im MySQL 5.0 Reference Manual ausführlicher beschrieben.

In MySQL vor Version 4.1 sind die Passwort-Hashes, die mit der Funktion PASSWORD() berechnet werden, 16 Bytes lang. Solche Hashes sehen etwa so aus:

mysql> SELECT PASSWORD('mypass');
+--------------------+
| PASSWORD('mypass') |
+--------------------+
| 6f8c114b58f2ce9e   |
+--------------------+

Die Spalte Password in der Tabelle user (in der diese Hashes gespeichert werden) ist bei MySQL vor Version 4.1 ebenfalls 16 Bytes lang.

Seit MySQL 4.1 erzeugt die geänderte PASSWORD()-Funktion einen 41 Byte langen Hash-Wert:

mysql> SELECT PASSWORD('mypass');
+-------------------------------------------+
| PASSWORD('mypass')                        |
+-------------------------------------------+
| *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
+-------------------------------------------+

Entsprechend muss die Spalte Password in der Tabelle user ebenfalls 41 Byte lang sein, um diese Werte aufnehmen zu können:

  • Wenn Sie eine Neuinstallation von MySQL 5.1 durchführen, wird die Spalte Password automatisch auf 41 Byte verlängert.

  • Die Aktualisierung von MySQL 4.1 (4.1.1 oder höher in der Serie 4.1) auf MySQL 5.1 sollte diesbezüglich unproblematisch zu sein, da beide Versionen dieselbe Hashing-Methode für Passwörter einsetzen. Wollen Sie hingegen von einem älteren MySQL-Release auf Version 5.1 aktualisieren, dann sollten Sie zunächst ein Upgrade auf 4.1 durchführen und diese 4.1-Installation dann auf 5.1 aktualisieren.

Die verbreiterte Password-Spalte kann Passwort-Hashes im alten wie im neuen Format aufnehmen. Das Format eines gegebenen Hash-Wertes kann auf zweierlei Art und Weise bestimmt werden:

  • Der offensichtliche Unterschied ist die Länge (16 Bytes im Vergleich zu 41 Bytes).

  • Ein zweiter Unterschied besteht darin, dass Passwort-Hashes im neuen Format immer mit dem Zeichen ‘*’ beginnen, was bei alten Passwörtern nie der Fall ist.

Das längere Format für Passwort-Hashes hat bessere kryptografische Eigenschaften, und die auf langen Hashes basierende Clientauthentifizierung ist sicherer als die alte, auf kurzen Hashes basierende Methode.

Die Unterschiede zwischen kurzen und langen Passwort-Hashes sind sowohl dafür, wie der Server Passwörter während der Authentifizierung verwendet, als auch dafür relevant, wie er Passwort-Hashes für verbundene Clients erzeugt, die Operationen zur Passwortänderung durchführen.

Die Breite der Password-Spalte wirkt sich auf die Art und Weise aus, wie der Server Passwort-Hashes während der Authentifizierung benutzt:

  • Wenn die Spalte kurz ist, wird die Authentifizierung mit kurzen Hashes verwendet.

  • Ist die Spalte hingegen lang, dann kann sie kurze wie auch lange Hashes aufnehmen, und der Server kann beide Formate verwenden:

    • Clients unter einer Version vor 4.1 können zwar Verbindungen herstellen, aber sie können, weil sie nur die alte Hashing-Methode kennen, eine Authentifizierung nur für Konten mit kurzen Hashes durchführen.

    • Clients unter 4.1 und höher können sich mit Konten authentifizieren, die kurze oder lange Hashes haben.

Auch bei Konten mit kurzen Hashes ist der Authentifizierungsvorgang eigentlich ein bisschen sicherer für Clients unter 4.1 und höher als bei älteren Clients. Aus sicherheitstechnischer Sicht sieht der Übergang von der geringsten zur höchsten Sicherheit wie folgt aus:

  • Clients unter Versionen vor 4.1 mit kurzem Passwort-Hash

  • Clients unter Versionen ab 4.1 mit kurzem Passwort-Hash

  • Clients unter Versionen ab 4.1 mit langem Passwort-Hash

Die Art und Weise, wie der Server Passwort-Hashes für verbundene Clients erzeugt, wird von der Breite der Spalte Password und von der Option --old-passwords beeinflusst. Ein Server unter 4.1 oder höher erzeugt lange Hashes nur, wenn bestimmte Bedingungen erfüllt werden: Die Spalte Password muss breit genug für lange Werte sein, und die Option --old-passwords darf nicht angegeben worden sein. Diese Bedingungen gelten wie folgt:

  • Die Spalte Password muss breit genug sein, um lange Hashes (41 Bytes) aufzunehmen. Wenn die Spalte nicht aktualisiert wurde und noch die Breite von 16 Bytes hat, stellt der Server fest, dass lange Hashes nicht in die Spalte passen. Insofern werden nur kurze Hashes erzeugt, wenn ein Client passwortändernde Operationen mit PASSWORD(), GRANT oder SET PASSWORD durchführt. Dieses Verhalten tritt auf, wenn Sie auf Version 4.1 aktualisiert, aber das Skript mysql_fix_privilege_tables zur Verbreiterung der Spalte Password noch nicht ausgeführt haben.

  • Ist die Spalte Password breit, dann kann sie kurze und lange Passwort-Hashes speichern. In diesem Fall erzeugen PASSWORD(), GRANT und SET PASSWORD lange Hashes, sofern der Server nicht mit der Option --old-passwords gestartet wurde. Diese Option erzwingt am Server die Erzeugung kurzes Hashes.

Der Zweck der Option --old-passwords besteht darin, Ihnen die Beibehaltung der Abwärtskompatibilität mit Clients unter Versionen vor 4.1 unter solchen Umständen zu ermöglichen, unter denen der Server andernfalls lange Passwort-Hashes erzeugen würde. Die Option beeinträchtigt die Authentifizierung nicht (denn Clients unter 4.1 und höher können weiterhin Konten mit langen Passwort-Hashes verwenden), verhindert aber die Erstellung eines langen Passwort-Hashes in der Tabelle user als Folge einer passwortändernden Operation. Andernfalls könnte das Konto nicht länger von Clients unter einer alten MySQL-Version verwendet werden. Ohne die Option --old-passwords wäre das folgende, nicht wünschenswerte Szenario möglich:

  • Ein alter Client stellt eine Verbindung zu einem Konto her, das einen kurzen Passwort-Hash hat.

  • Der Client ändert sein eigenes Passwort. Ohne die Option --old-passwords führt dies dazu, dass das Konto einen langen Passwort-Hash erhält.

  • Beim nächsten Verbindungsversuch des alten Clients mit dem betreffenden Konto schlägt die Verbindung fehl, weil das Konto einen langen Passwort-Hash aufweist, der zur Authentifizierung die neue Hashing-Methode benötigt. (Sobald für ein Konto ein langer Passwort-Hash in der Tabelle user gespeichert wird, können nur Clients unter Version 4.1 und höher eine Authentifizierung durchführen, weil ältere Clients die langen Hashes nicht verstehen.)

Dieses Szenario veranschaulicht, dass es, wenn Sie Clients unter Versionen vor 4.1 unterstützen müssen, gefährlich ist, einen Server unter 4.1 oder höher ohne die Option --old-passwords zu verwenden. Bei Ausführung des Servers mit der Option --old-passwords erzeugen passwortändernde Optionen keine langen Passwort-Hashes, d. h. Konten geraten für ältere Clients nicht außer Reichweite. (Diese Clients können sich nicht versehentlich selbst aussperren, indem sie ihr Passwort ändern und am Ende einen langen Passwort-Hash erhalten.)

Der Nachteil der Option --old-passwords besteht darin, dass alle von Ihnen erstellten oder geänderten Passwörter kurze Hashes verwenden – auch die Clients unter Version 4.1 und höher. Auf diese Weise verlieren Sie die zusätzliche Sicherheit, die lange Passwort-Hashes bieten. Wenn Sie ein Konto erstellen wollen, das einen langen Hash hat (etwa zur Verwendung durch Clients unter 4.1), dann müssen Sie dies tun, während der Server ohne die Option --old-passwords läuft.

Die folgenden Szenarios sind bei Ausführung eines Servers unter Version 4.1 möglich:

Szenario 1: Kurze Password-Spalte in der Tabelle user

  • In der Spalte Password können nur kurze Hashes gespeichert werden.

  • Der Server verwendet nur kurze Hashes zur Clientauthentifizierung.

  • Bei verbundenen Clients verwenden Operationen, die Passwort-Hashes mithilfe von PASSWORD(), GRANT oder SET PASSWORD erzeugen, ausschließlich kurzes Hashes. Änderungen am Passwort eines Kontos führen dazu, dass dieses Konto einen kurzen Passwort-Hash erhält.

  • Die Option --old-passwords kann verwendet werden, ist aber überflüssig, weil der Server bei einer kurzen Password-Spalte ohnehin nur kurze Passwort-Hashes erzeugt.

Szenario 2: Lange Password-Spalte, Server wurde nicht mit der Option --old-passwords gestartet

  • In der Spalte Password können kurze wie auch lange Hashes gespeichert werden.

  • Clients unter 4.1 und höher können sich mit Konten authentifizieren, die kurze oder lange Hashes haben.

  • Clients vor 4.1 können sich nur mithilfe von Konten authentifizieren, die kurze Hashes haben.

  • Bei verbundenen Clients verwenden Operationen, die Passwort-Hashes mithilfe von PASSWORD(), GRANT oder SET PASSWORD erzeugen, ausschließlich lange Hashes. Änderungen am Passwort eines Kontos führen dazu, dass dieses Konto einen langen Passwort-Hash hat.

Wie weiter oben beschrieben, besteht die Gefahr bei diesem Szenario darin, dass Konten, die einen kurzen Passwort-Hash aufweisen, für Clients unter einer Version vor 4.1 unzugänglich werden. Eine Änderung am Passwort eines solchen Kontos, die mithilfe von GRANT, PASSWORD() oder SET PASSWORD vorgenommen wird, führt dazu, dass das Konto einen langen Passwort-Hash erhält. Von diesem Punkt an kann ein Client unter einer Version vor 4.1 eine Authentifizierung über dieses Konto erst dann durchführen, wenn er seinerseits auf 4.1 oder höher aktualisiert wurde.

Um dieses Problem zu beseitigen, können Sie das Passwort auf eine spezielle Art und Weise ändern. So verwenden Sie etwa normalerweise SET PASSWORD wie folgt, um ein Kontopasswort zu ändern:

SET PASSWORD FOR 'some_user'@'some_host' = PASSWORD('mypass');

Um das Passwort zu ändern, aber einen kurzen Hash zu erstellen, verwenden Sie stattdessen die Funktion OLD_PASSWORD():

SET PASSWORD FOR 'some_user'@'some_host' = OLD_PASSWORD('mypass');

OLD_PASSWORD() ist in Situationen nützlich, in denen Sie ausdrücklich einen kurzen Hash erzeugen wollen.

Szenario 3: Lange Password-Spalte, Server unter Version 4.1 oder höher wurde mit der Option --old-passwords gestartet

  • In der Spalte Password können kurze wie auch lange Hashes gespeichert werden.

  • Clients unter 4.1 oder höher können sich mit Konten authentifizieren, die kurze oder lange Hashes haben. (Beachten Sie aber, dass die Erzeugung langer Hashes nur dann möglich ist, wenn der Server ohne die Option --old-passwords gestartet wurde.)

  • Clients vor 4.1 können sich nur mit Konten authentifizieren, die kurze Hashes haben.

  • Bei verbundenen Clients verwenden Operationen, die Passwort-Hashes mithilfe von PASSWORD(), GRANT oder SET PASSWORD erzeugen, ausschließlich kurzes Hashes. Änderungen am Passwort eines Kontos führen dazu, dass dieses Konto einen kurzen Passwort-Hash erhält.

In diesem Szenario können Sie keine Konten mit langen Passwort-Hashes erstellen, weil die Option --old-passwords deren Erzeugung verhindert. Ferner wird, wenn Sie ein Konto mit einem langem Hash vor Verwendung der Option --old-passwords erstellen, eine Änderung dieses Passworts bei aktivierter Option --old-passwords dazu führen, dass das Konto ein kurzes Passwort erhält, wodurch die sicherheitstechnischen Vorzüge eines langen Hashs verloren gehen.

Die Nachteile dieser Szenarien lassen sich wie folgt zusammenfassen:

In Szenario 1 müssen Sie auf die Vorteile langer Hashes verzichten, die eine sicherere Authentifizierung ermöglichen.

In Szenario 2 werden Konten mit kurzen Hashes für Clients unter einer Version vor 4.1 unzugänglich, wenn sie ihre Passwörter ändern, ohne die Option OLD_PASSWORD() ausdrücklich zu verwenden.

In Szenario 3 verhindert --old-passwords, dass Konten mit kurzen Hashes unzugänglich werden; passwortändernde Operationen setzen allerdings Konten mit langen Hashes auf kurze Hashes herunter, was Sie auch nicht ändern können, solange die Option --old-passwords gültig bleibt.

5.8.9.1. Auswirkungen der Änderungen beim Kennwort-Hashing auf Applikationen

Ein Upgrade auf MySQL 4.1 oder höher kann Kompatibilitätsprobleme für Anwendungen verursachen, die PASSWORD() zur Erzeugung von Passwörter für eigene Zwecke verwenden. Anwendungen sollten dies möglichst nicht tun, weil PASSWORD() einzig und allein zur Verwaltung von Passwörtern für MySQL-Konten eingesetzt werden sollten. Manche Anwendungen verwenden PASSWORD() allerdings trotzdem für ihre eigenen Zwecke.

Wenn Sie von einer alten MySQL-Version auf 4.1 oder höher aktualisieren und den Server unter Bedingungen ausführen, bei denen er lange Passwort-Hashes erzeugt, wird eine Anwendung, die PASSWORD() für eigene Passwörter verwendet, beschädigt. Die empfohlene Vorgehensweise besteht in solchen Fällen darin, die Anwendung so zu ändern, dass sie eine andere Funktion wie SHA1() oder MD5() zur Erzeugung von Hash-Werten verwendet. Sollte dies nicht möglich sei, dann können Sie die Funktion OLD_PASSWORD() benutzen, die zur Erzeugung von Passwörtern im alten Format bereitsteht. Allerdings sollten Sie beachten, dass OLD_PASSWORD() unter Umständen nicht auf Dauer unterstützt werden wird.

Läuft der Server unter Umständen, unter denen er kurze Hashes erzeugt, steht OLD_PASSWORD() zwar zur Verfügung, ist aber äquivalent zu PASSWORD().

PHP-Programmierer, die ihre MySQL-Datenbanken von Version 4.0 oder älter auf 4.1 oder höher migrieren, sollten Abschnitt 24.3, „MySQLs PHP-API“, lesen.

5.9. MySQL-Benutzerkontenverwaltung

Dieser Abschnitt beschreibt, wie Konten für Clients auf Ihrem MySQL-Server eingerichtet werden. Behandelt werden die folgenden Themen:

  • Bedeutung von Kontennamen und Passwörtern bei der Verwendung in MySQL im Vergleich zu den vom Betriebssystem verwendeten Namen und Passwörtern

  • Einrichtung neuer und Entfernung vorhandener Konten

  • Ändern von Passwörtern

  • Richtlinien zur sicheren Passwortverwendung

  • Verwenden sicherer Verbindungen mit SSL

5.9.1. MySQL-Benutzernamen und -Kennwörter

Ein MySQL-Konto wird durch einen Benutzernamen und den oder die Clienthosts definiert, von denen aus der Benutzer eine Verbindung zum Server herstellen kann. Ein Konto hat auch ein Passwort. Es gibt mehrere Unterschiede zwischen der Verwendung von Benutzernamen und Passwörtern unter MySQL und der Verwendung durch Ihr Betriebssystem:

  • Benutzernamen, die MySQL zu Authentifizierungszwecken verwendet, haben nicht mit den von Windows oder Unix eingesetzten Benutzernamen (Anmeldenamen) zu tun. Unter Unix versuchen die meisten MySQL-Clients standardmäßig, eine Anmeldung unter Verwendung des aktuellen Unix-Benutzernamens als MySQL-Benutzername durchzuführen, aber dies dient lediglich der Bequemlichkeit. Diese Voreinstellung kann ganz einfach außer Kraft gesetzt werden, da Clientprogramme die Angabe beliebiger Benutzernamen mit der Option -u bzw. --user erlauben. Da dies impliziert, dass jeder versuchen kann, unter Verwendung eines beliebigen Benutzernamens eine Serververbindung herzustellen, können Sie eine Datenbank nur schützen, indem Sie für alle MySQL-Konten Passwörter konfigurieren. Jeder, der einen Benutzernamen für ein Konto angibt, welches über kein Passwort verfügt, kann erfolgreich eine Verbindung zum Server herstellen.

  • MySQL-Benutzernamen dürfen bis zu 16 Zeichen lang sein. Diese Beschränkung ist bei MySQL-Servern und -Clients fest vorgegeben; sie durch Änderung der Tabellendefinitionen in der mysql-Datenbank zu umgehen, funktioniert nicht.

    Hinweis: Sie sollten die Tabellen in der mysql-Datenbank grundsätzlich nicht auf eine andere als die von MySQL AB vorgeschriebene, in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“, geschilderte Weise ändern. Jeder Versuch, die Systemtabellen von MySQL auf eine andere Weise zu ändern, führt zu undefiniertem (und nicht unterstütztem!) Verhalten.

    Die Benutzernamen des Betriebssystems haben überhaupt keine Beziehung zu den MySQL-Benutzernamen und können sogar eine ganz andere Maximallänge aufweisen. So sind etwa Unix-Benutzernamen normalerweise auf acht Zeichen beschränkt.

  • Auch haben MySQL-Passwörter nichts mit den Passwörtern zu tun, mit denen Sie sich an Ihrem Betriebssystem anmelden. Es gibt also keine notwendige Verbindung zwischen dem Passwort, mit dem Sie sich an einem Windows- oder Unix-Computer anmelden, und dem Passwort, das Sie für den Zugriff auf den MySQL-Server auf diesem Computer verwenden.

  • MySQL verschlüsselt Passwörter mit einem eigenen Algorithmus. Diese Verschlüsselung unterscheidet sich von der, die während des Anmeldevorgangs unter Unix eingesetzt wird. Die MySQL-Passwortverschlüsselung ist identisch mit der durch die SQL-Funktion PASSWORD() implementierten. Die Unix-Passwortverschlüsselung hingegen ist identisch mit der durch die SQL-Funktion ENCRYPT() implementierten. Details finden Sie in den Beschreibungen zu den Funktionen PASSWORD() und ENCRYPT() in Abschnitt 12.10.2, „Verschlüsselungs- und Kompressionsfunktionen“. Seit Version 4.1 verwendet MySQL eine stärkere Authentifizierungsmethode, die während des Anmeldevorgangs einen besseren Passwortschutz gewährleistet als frühere Versionen. Sie ist auch dann sicher, wenn TCP/IP-Pakete abgefangen oder die mysql-Datenbank aufgezeichnet wird. (Bei den früheren Versionen wurden die Passwörter zwar in verschlüsselter Form in der Tabelle user abgelegt, aber die Kenntnis des verschlüsselten Passwortwertes konnte zur Verbindung mit dem MySQL-Server bereits genügen.)

Wenn Sie MySQL installieren, werden einige Vorgabekonten in die Grant-Tabellen eingetragen. Die Namen und Zugriffsberechtigungen dieser Konten sind in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“, beschrieben. Dort finden Sie auch eine Erläuterung, wie Sie Passwörter für diese Konten konfigurieren. Nachfolgend werden MySQL-Konten normalerweise mit Anweisungen wie GRANT oder REVOKE eingerichtet, geändert und entfernt. Siehe auch Abschnitt 13.5.1, „Anweisungen zur Benutzerkontenverwaltung“.

Wenn Sie über einen Befehlszeilenclient eine Verbindung mit einem MySQL-Server herstellen, sollten Sie den Benutzernamen und das Passwort des zu verwendenden Kontos angeben:

shell> mysql --user=monty --password=guess db_name

Verwenden Sie lieber kurze Optionen, dann sieht der Befehl wie folgt aus:

shell> mysql -u monty -pguess db_name

Zwischen der Option -p und dem nachfolgenden Passwortwert darf kein Leerzeichen vorhanden sein. Siehe auch Abschnitt 5.8.4, „Verbinden mit dem MySQL-Server“.

Obige Befehle enthalten den Passwortwert in der Befehlszeile. Dies kann ein Sicherheitsrisiko darstellen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“. Um dieses Problem zu umgehen, geben Sie die Option --password bzw. -p ohne nachfolgenden Passwortwert an:

shell> mysql --user=monty --password db_name
shell> mysql -u monty -p db_name

Wenn die Passwortoption keinen Passwortwert enthält, zeigt das Clientprogramm eine Eingabeaufforderung an und wartet auf die Eingabe des Passworts. (In diesen Beispielen wird db_name nicht als Passwort interpretiert, da es von der vorangegangenen Passwortoption durch ein Leerzeichen getrennt ist.)

Auf manchen Systemen beschränkt die von MySQL zur Passworteingabe verwendete Bibliotheksroutine die Eingabe auf acht Zeichen. Dies ist ein Problem der Systembibliothek und nicht von MySQL. Intern beschränkt MySQL die Länge des Passworts nicht. Um dieses Problem zu umgehen, setzen Sie das MySQL-Passwort entweder auf einen Wert, der maximal acht Zeichen umfasst, oder legen es in einer Optionsdatei ab.

5.9.2. Hinzufügen neuer MySQL-Benutzer

Es gibt zwei Vorgehensweisen zum Hinzufügen von MySQL-Konten:

  • Verwenden von Anweisungen zur Erstellung von Konten (z. B. CREATE USER oder GRANT)

  • direktes Modifizieren der MySQL-Grant-Tabellen mit Anweisungen wie INSERT, UPDATE oder DELETE

Die zu bevorzugende Methode ist die Verwendung von Anweisungen zur Kontenerstellung, denn diese sind knapper und zudem weniger fehleranfällig. CREATE USER und GRANT sind in Abschnitt 13.5.1.1, „CREATE USER, und Abschnitt 13.5.1.3, „GRANT und REVOKE, beschrieben.

Eine weitere Option zur Erstellung von Konten besteht in der Verwendung eines der vielen erhältlichen Drittanbieterprogramme, die Funktionen zur MySQL-Kontenverwaltung anbieten. phpMyAdmin ist ein solches Programm.

Die folgenden Beispiele zeigen, wie man mit dem mysql-Client neue Benutzer einrichtet. Die Beispiele setzen voraus, dass die Berechtigungen entsprechend der Beschreibung in Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“, auf die Vorgabewerte gesetzt sind. Das bedeutet, dass Sie, um Änderungen vornehmen zu können, eine Verbindung zum MySQL-Server als MySQL-Benutzer root herstellen müssen und das root-Konto die Berechtigung INSERT für die mysql-Datenbank sowie die administrative Berechtigung RELOAD benötigt.

Verwenden Sie zunächst das Programm mysql, um als MySQL-Benutzer root eine Verbindung zum Server herzustellen:

shell> mysql --user=root mysql

Wenn Sie für das Konto root ein Passwort konfiguriert haben, müssen Sie auch eine Option --password bzw. -p für diesen und alle weiteren in diesem Abschnitt folgenden mysql-Befehle angeben.

Wenn Sie die Verbindung zum Server als root hergestellt haben, können Sie neue Konten hinzufügen. Die folgenden Anweisungen richten mit GRANT vier neue Benutzerkonten ein:

mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'
    ->     IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%'
    ->     IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost';
mysql> GRANT USAGE ON *.* TO 'dummy'@'localhost';

Die mit diesen GRANT-Anweisungen erstellten Konten haben die folgenden Eigenschaften:

  • Zwei der Konten haben den Benutzernamen monty und das Passwort some_pass. Beide Konten sind Superuser-Konten mit allen Berechtigungen für beliebige Operationen. Eines der Konten ('monty'@'localhost') kann nur für eine Verbindung vom lokalen Host verwendet werden. Das andere Konto ('monty'@'%') erlaubt die Verbindung von einem beliebigen anderen Host. Beachten Sie, dass beide Konten erforderlich sind, damit monty von einem beliebigen Host aus als monty eine Verbindung herstellen kann. Würde das localhost-Konto nicht eingerichtet, dann hätte das anonyme Benutzerkonto für localhost, welches von mysql_install_db eingerichtet wird, Vorrang für die Anmeldung von monty am lokalen Host. Die Folge wäre, dass monty als anonymer Benutzer behandelt würde. Grund hierfür ist, dass das Konto für anonyme Benutzer einen spezifischeren Wert in der Host-Spalte aufweist als das Konto 'monty'@'%' und deswegen in der Tabelle user weiter oben einsortiert wird. (Die Sortierung der Tabelle user ist in Abschnitt 5.8.5, „Zugriffskontrolle, Phase 1: Verbindungsüberprüfung“, beschrieben.)

  • Ein Konto hat den Benutzernamen admin und kein Passwort. Dieses Konto kann nur für eine Verbindung vom lokalen Host verwendet werden. Gewährt werden die administrativen Berechtigungen RELOAD und PROCESS. Diese Berechtigungen gestatten dem Benutzer admin die Ausführung der Befehle mysqladmin reload, mysqladmin refresh und mysqladmin flush-xxx sowie des Befehls mysqladmin processlist . Für den Zugriff auf Datenbanken werden keine Berechtigungen gewährt. Sie können solche Berechtigungen später durch Absetzen zusätzlicher GRANT-Anweisungen hinzufügen.

  • Ein Konto hat den Benutzernamen dummy und kein Passwort. Dieses Konto kann nur für eine Verbindung vom lokalen Host verwendet werden. Es werden keine Berechtigungen gewährt. Die Berechtigung USAGE in der GRANT-Anweisung erlaubt Ihnen die Erstellung eines Kontos ohne Gewährung von Berechtigungen. Es werden also alle globalen Berechtigungen auf 'N' gesetzt. Es ist davon auszugehen, dass Sie diesem Konto später gewisse Berechtigungen gewähren werden.

Als Alternative zu GRANT können Sie dieselben Konten auch direkt durch Absetzen von INSERT-Anweisungen und ein nachfolgendes Neuladen der Grant-Tabellen durch den Server mithilfe von FLUSH PRIVILEGES erstellen:

shell> mysql --user=root mysql
mysql> INSERT INTO user
    ->     VALUES('localhost','monty',PASSWORD('some_pass'),
    ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user
    ->     VALUES('%','monty',PASSWORD('some_pass'),
    ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user SET Host='localhost',User='admin',
    ->     Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
    ->     VALUES('localhost','dummy','');
mysql> FLUSH PRIVILEGES;

Der Grund für die Verwendung von FLUSH PRIVILEGES bei der Erstellung von Konten mit INSERT besteht darin, dass der Server zum Neuladen der Grant-Tabellen angewiesen werden muss. Andernfalls wird Ihre Änderung erst umgesetzt, wenn Sie den Server neu starten. Bei GRANT ist das Absetzen von FLUSH PRIVILEGES nicht erforderlich.

Die Funktion PASSWORD() wird bei INSERT zur Verschlüsselung des Passwortes verwendet. Die Anweisung GRANT verschlüsselt das Passwort direkt, d. h. PASSWORD() ist hier nicht erforderlich.

Die 'Y'-Werte aktivieren die Berechtigungen für die Konten. Je nach MySQL-Version müssen Sie unter Umständen eine unterschiedliche Anzahl von 'Y'-Werten in den ersten beiden INSERT-Anweisungen verwenden. Für das admin-Konto sollten Sie vielleicht eher die besser lesbare erweiterte INSERT-Syntax unter Verwendung von SET benutzen.

In der INSERT-Anweisung für das Konto dummy sind nur die Spalten Host, User und Password in der Tabelle user zugewiesene Werte. Keine der Berechtigungsspalten wird explizit eingestellt, weswegen MySQL ihnen allen den Standardwert 'N' zuweist. Dies entspricht dem, was auch GRANT USAGE tut.

Beachten Sie, dass es zur Einrichtung eines Superuser-Kontos erforderlich ist, einen Eintrag in der Tabelle user zu erstellen, bei dem die Berechtigungsspalten auf 'Y' gesetzt sind. Berechtigungen in der Tabelle user sind global, d. h. es sind keine anderen Einträge in einer anderen Grant-Tabelle erforderlich.

Die nächsten Beispiele erstellen drei Konten und gewähren ihnen Zugang zu bestimmten Datenbanken. Alle haben den Benutzernamen custom und das Passwort obscure.

Um die Konten mit GRANT zu erstellen, verwenden Sie die folgenden Anweisungen:

shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
    ->     ON bankaccount.*
    ->     TO 'custom'@'localhost'
    ->     IDENTIFIED BY 'obscure';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
    ->     ON expenses.*
    ->     TO 'custom'@'whitehouse.gov'
    ->     IDENTIFIED BY 'obscure';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
    ->     ON customer.*
    ->     TO 'custom'@'server.domain'
    ->     IDENTIFIED BY 'obscure';

Die drei Konten können wie folgt verwendet werden:

  • Das erste Konto kann auf die Datenbank bankaccount zugreifen, dies allerdings nur vom lokalen Host aus.

  • Das zweite Konto kann auf die Datenbank expenses zugreifen, dies allerdings nur vom Host whitehouse.gov aus.

  • Das dritte Konto kann auf die Datenbank customer zugreifen, dies allerdings nur vom Host server.domain aus.

Um die custom-Konten ohne GRANT einrichten zu können, verwenden Sie wie folgt INSERT-Anweisungen zur direkten Änderung der Grant-Tabellen:

shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
    ->     VALUES('localhost','custom',PASSWORD('obscure'));
mysql> INSERT INTO user (Host,User,Password)
    ->     VALUES('whitehouse.gov','custom',PASSWORD('obscure'));
mysql> INSERT INTO user (Host,User,Password)
    ->     VALUES('server.domain','custom',PASSWORD('obscure'));
mysql> INSERT INTO db
    ->     (Host,Db,User,Select_priv,Insert_priv,
    ->     Update_priv,Delete_priv,Create_priv,Drop_priv)
    ->     VALUES('localhost','bankaccount','custom',
    ->     'Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
    ->     (Host,Db,User,Select_priv,Insert_priv,
    ->     Update_priv,Delete_priv,Create_priv,Drop_priv)
    ->     VALUES('whitehouse.gov','expenses','custom',
    ->     'Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
    ->     (Host,Db,User,Select_priv,Insert_priv,
    ->     Update_priv,Delete_priv,Create_priv,Drop_priv)
    ->     VALUES('server.domain','customer','custom',
    ->     'Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;

Die ersten drei INSERT-Anweisungen fügen Einträge in der Tabelle user hinzu, die dem Benutzer custom die Verbindungsherstellung an den verschiedenen Hosts unter Verwendung des betreffenden Passwortes gestatten, gewähren aber keine globale Berechtigungen (alle Berechtigungen erhalten den Standardwert 'N'). Die nachfolgenden drei INSERT-Anweisungen fügen Einträge in der Tabelle db hinzu, die custom Berechtigungen für die Datenbanken bankaccount, expenses und customer unter der Voraussetzung gewähren, dass der Zugriff vom angegebenen Host aus erfolgt. Wie bei der direkten Änderung der Grant-Tabellen üblich, müssen Sie den Server auch hier mit FLUSH PRIVILEGES zum Neuladen der Grant-Tabellen anweisen, damit die Änderungen an den Berechtigungen übernommen werden.

Wenn Sie einem bestimmten Benutzer den Zugriff von allen Computern in einer bestimmten Domäne (z. B. mydomain.com) gestatten wollen, können Sie eine GRANT-Anweisung absetzen, die das Jokerzeichen ‘%’ im Hostpart des Kontennamens verwendet:

mysql> GRANT ...
    ->     ON *.*
    ->     TO 'myname'@'%.mydomain.com'
    ->     IDENTIFIED BY 'mypass';

Um das gleiche Ergebnis durch direkte Modifikation der Grant-Tabellen zu erzielen, tun Sie folgendes:

mysql> INSERT INTO user (Host,User,Password,...)
    ->     VALUES('%.mydomain.com','myname',PASSWORD('mypass'),...);
mysql> FLUSH PRIVILEGES;

5.9.3. Entfernen von Benutzerkonten in MySQL

Um ein Konto zu entfernen, verwenden Sie die Anweisung DROP USER, die in Abschnitt 13.5.1.2, „DROP USER, beschrieben ist.

5.9.4. Begrenzen von Benutzer-Ressourcen

Eine Möglichkeit, die Nutzung der MySQL-Serverressourcen einzuschränken, besteht in der Einstellung der Systemvariablen max_user_connections auf einen Wert ungleich Null. Allerdings arbeitet diese Methode streng global und ermöglicht keine Verwaltung einzelner Konten. Außerdem wird hierbei nur die Anzahl der Verbindungen beschränkt, die gleichzeitig über ein einzelnes Konto verwendet werden, nicht jedoch, was ein Client tun kann, sobald die Verbindung hergestellt ist. Diese beiden Steuerungsformen sind für viele MySQL-Administratoren interessant – insbesondere für solche, die für Internetprovider tätig sind.

In MySQL 5.1 können Sie die folgenden Serverressourcen für einzelne Konten einschränken:

  • Anzahl der Abfragen, die ein Konto pro Stunde absetzen kann

  • Anzahl der Updates, die ein Konto pro Stunde durchführen kann

  • Häufigkeit, mit der ein Konto pro Stunde Verbindungen herstellen kann

Jede Anweisung, die ein Client absetzen kann, erhöht den Zähler für das Abfragelimit. Der Updatezähler hingegen wird nur bei Anweisungen hochgezählt, die Datenbanken oder Tabellen ändern.

Es ist auch möglich, die Anzahl gleichzeitiger Verbindungen zum Server pro Konto zu beschränken.

In diesem Kontext ist unter einem Konto ein Datensatz in der Tabelle user zu verstehen. Jedes Konto wird durch die User- und Host-Spaltenwerte eindeutig bezeichnet.

Voraussetzung für die Verwendung dieser Funktion ist, dass die Tabelle user in der mysql-Datenbank die ressourcenspezifischen Spalten enthält. Ressourcenbeschränkungen sind in den Spalten max_questions, max_updates, max_connections und max_user_connections abgelegt. Wenn Ihre Tabelle user diese Spalten nicht aufweist, muss sie aktualisiert werden. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Um Ressourcenbeschränkungen mit einer GRANT-Anweisung einzustellen, verwenden Sie eine WITH-Klausel, die alle zu beschränkenden Ressourcen und einen stundenbezogenen Zähler benennt, der den jeweiligen Maximalwert angibt. Um also etwa ein neues Konto zu erstellen, das auf die Datenbank customer in eingeschränkter Weise zugreifen kann, setzen Sie folgende Anweisung ab:

mysql> GRANT ALL ON customer.* TO 'francis'@'localhost'
    ->     IDENTIFIED BY 'frank'
    ->     WITH MAX_QUERIES_PER_HOUR 20
    ->          MAX_UPDATES_PER_HOUR 10
    ->          MAX_CONNECTIONS_PER_HOUR 5
    ->          MAX_USER_CONNECTIONS 2;

Nicht alle Beschränkungstypen müssen in der WITH-Klausel aufgeführt sein. Zudem ist die Reihenfolge der aufgeführten Typen beliebig. Der Wert des Stundenlimits sollte eine ganze Zahl sein, die den Wert pro Stunde angibt. Wird die GRANT-Anweisung ohne WITH-Klausel abgesetzt, dann werden alle Beschränkungen auf den Standardwert Null gesetzt (d. h. es gibt keine Beschränkungen). Bei MAX_USER_CONNECTIONS ist der Höchstwert eine ganze Zahl, die die maximale Anzahl der Verbindungen angibt, die das Konto gleichzeitig halten kann. Wenn der Wert auf die Vorgabe Null gesetzt ist, bestimmt die Systemvariable max_user_connections die maximale Anzahl gleichzeitiger Verbindungen für das Konto.

Um die Beschränkungen für ein vorhandenes Konto einzustellen oder zu ändern, verwenden Sie eine GRANT USAGE-Anweisung auf der globalen Ebene (ON *.*). Die folgende Anweisung setzt das Abfragelimit für francis auf 100:

mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
    ->     WITH MAX_QUERIES_PER_HOUR 100;

Diese Anweisung ändert nicht die vorhandenen Berechtigungen des Kontos, sondern nur die vorhandenen Maximalwerte.

Um eine vorhandene Beschränkung zu entfernen, setzen Sie den Wert auf Null. Um etwa die Beschränkung der Häufigkeit aufzuheben, mit der francis eine Verbindung herstellen kann, verwenden Sie folgende Anweisung:

mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
    ->     WITH MAX_CONNECTIONS_PER_HOUR 0;

Eine Zählung der Ressourcennutzung findet statt, wenn für ein Konto ein Wert ungleich Null für die Beschränkung einer bestimmten Ressource konfiguriert ist.

Wenn der Server läuft, ermittelt er, wie häufig jedes Konto welche Ressourcen verwendet. Wenn ein Konto die höchste Anzahl zulässiger Verbindungen innerhalb einer Stunde erreicht, werden weitere Verbindungsanfragen des Kontos abgewiesen, bis die Stunde verstrichen ist. Ähnlich werden weitere Abfragen oder Updates abgewiesen, wenn für diese der jeweilige Maximalwert durch ein Konto erreicht wird. In all diesen Fällen wird eine entsprechende Fehlermeldung angezeigt.

Die Zählung der Ressourcennutzungen erfolgt auf Konten- und nicht auf Clientbasis. Wenn Ihr Konto beispielsweise eine Beschränkung von 50 Abfragen pro Stunde hat, dann können Sie diese nicht verdoppeln, indem Sie gleichzeitig zwei Clientverbindungen zum Server herstellen. Die Abfragen, die über die beiden Verbindungen abgesetzt werden, werden zusammengezählt.

Die aktuellen Ressourcenzähler können global oder auch für einzelne Konten zurückgesetzt werden:

  • Um die aktuellen Zähler für alle Konten zu nullen, setzen Sie eine FLUSH USER_RESOURCES-Anweisung ab. Die Werte können auch durch Neuladen der Grant-Tabellen (etwa mit einer FLUSH PRIVILEGES-Anweisung oder dem Befehl mysqladmin reload) zurückgesetzt werden.

  • Zähler eines bestimmten Kontos können auf Null gesetzt werden, indem eine beliebige Beschränkung erneut definiert wird. Verwenden Sie zu diesem Zweck wie oben beschrieben die Anweisung GRANT USAGE und geben Sie den Wert, der für das Konto bereits festgelegt ist, erneut an.

Das Zurücksetzen der Zähler wirkt sich nicht auf die Beschränkung MAX_USER_CONNECTIONS aus.

Beim Serverstart beginnen alle Zähler bei Null zu zählen, d. h. vorhandene Werte lassen sich nicht über einen Neustart hinweg übertragen.

5.9.5. Kennwörter einrichten

Passwörter können mit mysqladmin über die Befehlszeile zugewiesen werden:

shell> mysqladmin -u user_name -h host_name password "newpwd"

Der Befehl setzt das Passwort des Kontos zurück, bei dessen Datensatz in der Tabelle user eine Übereinstimmung mit user_name in der Spalte User und eine Übereinstimmung des Clienthosts, von dem aus Sie die Verbindung herstellen, in der Spalte Host vorliegt.

Eine weitere Möglichkeit, einem Konto ein Passwort zuzuweisen, besteht im Absetzen einer SET PASSWORD-Anweisung:

mysql> SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit');

Nur Benutzer wie root, die die mysql-Datenbank aktualisieren dürfen, können die Passwörter anderer Benutzer ändern. Sofern Sie nicht als anonymer Benutzer verbunden sind, können Sie Ihr eigenes Passwort durch Weglassen der FOR-Klausel ändern:

mysql> SET PASSWORD = PASSWORD('biscuit');

Sie können auch eine GRANT USAGE-Anweisung auf der globalen Ebene (ON *.*) verwenden, um einem Konto ein Passwort zuzuweisen, ohne die aktuellen Berechtigungen dieses Kontos zu beeinträchtigen:

mysql> GRANT USAGE ON *.* TO 'jeffrey'@'%' IDENTIFIED BY 'biscuit';

Zwar ist die Zuweisung von Passwörtern unter Verwendung einer der zuvor beschriebenen Methoden generell vorzuziehen, aber Sie können die Tabelle user auch direkt ändern:

  • Um bei Erstellung eines neuen Kontos ein Passwort zuzuweisen, setzen Sie einen Wert in die Spalte Password:

    shell> mysql -u root mysql
    mysql> INSERT INTO user (Host,User,Password)
        -> VALUES('%','jeffrey',PASSWORD('biscuit'));
    mysql> FLUSH PRIVILEGES;
    
  • Wollen Sie das Passwort eines vorhandenen Kontos ändern, dann weisen Sie mit UPDATE den Password-Spaltenwert zu:

    shell> mysql -u root mysql
    mysql> UPDATE user SET Password = PASSWORD('bagel')
        -> WHERE Host = '%' AND User = 'francis';
    mysql> FLUSH PRIVILEGES;
    

Wenn Sie einem Konto mit SET PASSWORD, INSERT oder UPDATE ein nichtleeres Passwort zuweisen, müssen Sie die Funktion PASSWORD() zur Verschlüsselung verwenden. PASSWORD() ist erforderlich, weil die Tabelle user Passwörter nicht als Klartext, sondern in verschlüsselter Form speichert. Wenn Sie dies vergessen, werden Sie Passwörter wahrscheinlich so einstellen:

shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
    -> VALUES('%','jeffrey','biscuit');
mysql> FLUSH PRIVILEGES;

Die Folge ist, dass der literale Wert 'biscuit' und nicht der verschlüsselte Wert als Passwort in der Tabelle user gespeichert wird. Wenn jeffrey dann unter Angabe dieses Passworts eine Verbindung zum Server herzustellen versucht, wird der Wert verschlüsselt und dann mit dem in der Tabelle user gespeicherten Wert verglichen. Dieser gespeicherte Wert ist jedoch der literale String 'biscuit' – der Vergleich schlägt fehl, und der Server weist die Verbindungsanfrage ab:

shell> mysql -u jeffrey -pbiscuit test
Access denied

Bei der Zuweisung von Passwörtern mit der Anweisung GRANT ... IDENTIFIED BY oder dem Befehl mysqladmin password wird die Verschlüsselung des Passworts automatisch erledigt. In diesen Fällen ist die Verwendung der Funktion PASSWORD() nicht erforderlich.

Hinweis: Die PASSWORD()-Verschlüsselung unterscheidet sich von der Unix-Passwortverschlüsselung. Siehe auch Abschnitt 5.9.1, „MySQL-Benutzernamen und -Kennwörter“.

5.9.6. Wie Sie Ihre Kennwörter sicher halten

Auf der administrativen Ebene sollten Sie nichtadministrativen Konten niemals Zugriff auf die Grant-Tabelle user gestatten.

Wenn Sie ein Clientprogramm ausführen, um eine Verbindung mit dem MySQL-Server herzustellen, ist es nicht ratsam, Ihr Passwort so einzugeben, dass es von anderen Benutzern erraten werden könnte. Die Methoden, die Sie zur Angabe Ihres Passworts bei Ausführung von Clientprogrammen verwenden können, sind einschließlich einer Risikoeinschätzung jeder Methode nachfolgend aufgeführt:

  • Sie verwenden die Option -pyour_pass bzw. --password=your_pass auf der Befehlszeile. Zum Beispiel:

    shell> mysql -u francis -pfrank db_name
    

    Dies ist praktisch, aber unsicher, weil Ihr Passwort für Systemstatusprogramme wie ps sichtbar wird, die von anderen Benutzern zur Anzeige von Befehlszeilen aufgerufen werden können. MySQL-Clients überschreiben das befehlszeilenbasierte Passwortargument bei der Initialisierung normalerweise mit Nullen. Es gibt allerdings noch einen ganz kurzen Zeitraum, für den der Wert sichtbar ist. Auf einigen Systemen ist diese Strategie ohnehin ohne Wirkung, und die Passwörter bleiben für ps sichtbar. (Das Problem tritt etwa bei System V-Unix und unter Umständen auch bei anderen Systemen auf.)

  • Sie verwenden die Option -p bzw. --password ohne Passwortangabe. In diesem Fall fordert das Clientprogramm zur Eingabe des Passworts über das Terminal auf:

    shell> mysql -u francis -p db_name
    Enter password: ********
    

    Die Zeichen ‘*’ geben an, wo Sie Ihr Passwort eingegeben haben. Das Passwort wird bei der Eingabe nicht angezeigt.

    Diese Methode zur Passworteingabe ist sicherer als die Angabe über die Befehlszeile, da das Passwort anderen Benutzern nicht angezeigt wird. Allerdings ist diese Eingabemethode nur für Programme geeignet, die Sie interaktiv ausführen. Wollen Sie einen Client aus einem Skript heraus aufrufen, das nicht interaktiv läuft, dann gibt es keine Möglichkeit, das Passwort über das Terminal einzugeben. Bei manchen Systemen werden Sie sogar feststellen, dass die erste Zeile Ihres Skript gelesen und irrtümlich als Passwort interpretiert wird.

  • Sie speichern Ihr Passwort in einer Optionsdatei. Unter Unix etwa können Sie Ihr Passwort im Abschnitt [client] der Datei .my.cnf im Stammverzeichnis auflisten:

    [client]
    password=your_pass
    

    Wenn Sie Ihr Passwort in .my.cnf speichern, dann sollte diese Datei ausschließlich für Sie zugänglich sein. Um dies sicherzustellen, setzen Sie die Dateizugriffsmethode auf 400 oder 600. Zum Beispiel:

    shell> chmod 600 .my.cnf
    

    Abschnitt 4.3.2, „my.cnf-Optionsdateien“, erläutert Optionsdateien im Detail.

  • Sie speichern Ihr Passwort in der Umgebungsvariable MYSQL_PWD. Diese Methode der Angabe eines MySQL-Passworts muss als extrem unsicher betrachtet werden und sollte nicht verwendet werden. Einige Versionen von ps enthalten eine Option zur Anzeige der Umgebung laufender Prozesse. Wenn Sie MYSQL_PWD einstellen, wird Ihr Passwort allen Benutzern zugänglich gemacht, die ps ausführen. Sogar auf Systemen ohne eine solche Version von ps ist es nicht ratsam, davon auszugehen, dass keine andere Methoden vorhanden sind, mit denen Benutzer Prozessumgebungen untersuchen können. Siehe auch Anhang F, Umgebungsvariablen.

Insgesamt betrachtet sind die sichersten Methoden die Aufforderung des Clientprogramms zur Eingabe des Passwortes oder die Angabe des Passwortes in einer angemessen geschützten Optionsdatei.

5.9.7. Verwendung sicherer Verbindungen

MySQL unterstützt sichere (verschlüsselte) Verbindungen zwischen MySQL-Clients und dem Server unter Verwendung des SSL-Protokolls (Secure Sockets Layer). Dieser Abschnitt beschreibt, wie man SSL-Verbindungen verwendet. Ferner wird eine Möglichkeit beschrieben, SSH unter Windows einzurichten. Informationen dazu, wie man die Verwendung von SSL-Verbindungen durch die Benutzer erzwingt, finden Sie in Abschnitt 13.5.1.3, „GRANT und REVOKE.

Die Standardkonfiguration von MySQL ist auf Geschwindigkeit optimiert, weswegen verschlüsselte Verbindungen standardmäßig nicht verwendet werden. Andernfalls wäre das Client/Server-Protokoll erheblich langsamer. Die Verschlüsselung von Daten ist ein prozessorintensiver Vorgang, der zusätzliche Operationen seitens des Computers erfordert und andere MySQL-Aufgaben verzögern kann. Bei Anwendungen hingegen, die die Sicherheit verschlüsselter Verbindungen erfordern, ist der zusätzliche Rechenaufwand in jedem Fall gerechtfertigt.

MySQL gestattet die Aktivierung der Verschlüsselung auf der Basis einzelner Verbindungen. Sie können je nach Anforderungen einzelner Anwendungen zwischen einer normalen unverschlüsselten Verbindung oder einer sicheren verschlüsselten SSL-Verbindung wählen.

5.9.7.1. Grundlegende SSL-Konzepte

Um verstehen zu können, wie MySQL SSL verwendet, ist es notwendig, einige grundlegende Konzepte zu SSL und X509 zu kennen. Leser, die mit diesen Konzepten vertraut sind, können diesen Teil des Handbuchs überspringen.

Standardmäßig verwendet MySQL unverschlüsselte Verbindungen zwischen Client und Server. Das bedeutet, dass jemand, der Zugriff auf das Netzwerk hat, den gesamten Datenverkehr überwachen und die Daten bei Versand oder Empfang überprüfen könnte. Schlimmer noch: Selbst eine Modifikation der Daten während der Übertragung zwischen Client und Server ist möglich. Um die Sicherheit ein wenig zu erhöhen, können Sie den Client/Server-Datenverkehr durch Angabe der Option --compress beim Aufruf des Clientprogramms komprimieren. Ein entschlossener Angreifer würde sich hiervon jedoch nicht abhalten lassen.

Wenn Sie Daten in sicherer Form über ein Netzwerk übertragen müssen, ist eine unverschlüsselte Verbindung nicht akzeptabel. Die Verschlüsselung stellt eine Möglichkeit dar, beliebige Daten unlesbar zu machen. Tatsächlich erfordert die moderne Praxis viele zusätzliche Sicherheitselemente von Verschlüsselungsalgorithmen. Sie sollten viele bekannte Angriffstypen abwehren können, z. B. eine Änderung der Reihenfolge verschlüsselter Daten oder die zweimalige Wiedergabe von Daten.

SSL ist ein Protokoll, welches mithilfe verschiedener Verschlüsselungsalgorithmen sicherstellen soll, dass Daten, die über ein öffentliches Netzwerk übertragen wurden, vertrauenswürdig sind. SSL verfügt über Methoden zur Erkennung von Änderungen, Verlusten oder Wiedergabe von Daten. Ferner enthalten sind Algorithmen, die eine Identitätsprüfung unter Verwendung des X509-Standards ermöglichen.

X509 erlaubt eine Identifizierung über das Internet. Der bevorzugte Anwendungsfall hierfür ist der E-Commerce. Einfach gesagt wird ein Unternehmen benötigt, welches als „Zertifizierungsstelle“ (Certificate Authority, CA) elektronische Zertifikate an Antragssteller vergibt. Zertifikate basieren auf asymmetrischen Verschlüsselungsalgorithmen mit zwei Schlüsseln: einem öffentlichen und einem Geheimschlüssel. Der Halter eines Zertifikats kann einem Gegenüber das Zertifikat als Identitätsnachweis vorlegen. Das Zertifikat besteht aus dem öffentlichen Schlüssel seines Besitzers. Daten, die mit diesem öffentlichen Schlüssel verschlüsselt wurden, können nur mit dem entsprechenden Geheimschlüssel wieder entschlüsselt werden. Dieser Geheimschlüssel befindet sich im Besitz des Zertifikatshalters.

Wenn Sie weitere Informationen zu SSL, X509 oder zum Thema Verschlüsselung suchen, geben Sie die entsprechenden Begriffe in die Internetsuchmaschine Ihrer Wahl ein.

5.9.7.2. Verwendung von SSL-Verbindungen mit OpenSSL

Um SSL-Verbindungen zwischen dem MySQL-Server und den Clientprogrammen zu verwenden, muss Ihr System entweder OpenSSL oder yaSSL unterstützen. In diesem Abschnitt behandeln wir OpenSSL. Wenn sie yaSSL verwenden, lesen Sie stattdessen Abschnitt 5.9.7.3, „Verwendung von SSL-Verbindungen mit yaSSL“.

Gehen Sie wie folgt vor, um mithilfe von OpenSSL sichere Verbindungen für MySQL zu erstellen:

  1. Installieren Sie, soweit nicht bereits vorhanden, die OpenSSL-Bibliothek. Wir haben MySQL mit OpenSSL 0.9.6 getestet. Wenn Sie OpenSSL benötigen, besuchen Sie die Site http://www.openssl.org.

  2. Wenn Sie MySQL konfigurieren, rufen Sie das Skript configure mit den Optionen --with-vio und --with-openssl auf:

    shell> ./configure --with-vio --with-openssl
    
  3. Stellen Sie sicher, dass Sie Ihre Grant-Tabellen so aktualisiert haben, dass die SSL-spezifischen Spalten in der Tabelle mysql.user enthalten sind. Dies ist erforderlich, wenn Ihre Grant-Tabellen aus einer Version vor MySQL 4.0.0 stammen. Der Aktualisierungsvorgang ist in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“, beschrieben.

  4. Um zu überprüfen, ob ein laufender mysqld-Server OpenSSL unterstützt, prüfen Sie den Wert der Systemvariable have_openssl:

    mysql> SHOW VARIABLES LIKE 'have_openssl';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | have_openssl  | YES   |
    +---------------+-------+
    

    Ist der Wert YES, dann unterstützt der Server OpenSSL-Verbindungen.

5.9.7.3. Verwendung von SSL-Verbindungen mit yaSSL

Die in MySQL integrierte yaSSL-Unterstützung erleichtert die Verwendung sicherer Verbindungen. Sie müssen OpenSSL nicht installieren und auch die anderen in Abschnitt 5.9.7.2, „Verwendung von SSL-Verbindungen mit OpenSSL“, beschriebenen Schritte nicht durchführen. Außerdem verwenden MySQL und yaSSL dasselbe Lizenzmodell.

Zurzeit wird yaSSL auf den folgenden Plattformen unterstützt:

  • Linux/x86-64 Red Hat Enterprise 3.0

  • Linux RHAS21 Itanium-2 mit gcc, statisch verknüpft

  • Linux Itanium-2 mit gcc

  • Windows (alle Builds)

Um beim Erstellen von MySQL aus einer Quelldistribution yaSSL zu aktivieren, sollten Sie MySQL wie folgt konfigurieren:

shell> ./configure --with-yassl

Beachten Sie, dass die yaSSL-Unterstützung auf Unix-Plattformen die Installation von /dev/urandom oder /dev/random erfordert, damit echte Zufallszahlen abgerufen werden können. Weitere Informationen (insbesondere zu yaSSL auf Solaris-Versionen vor 2.8 und HP-UX) finden Sie im Bug Nr. 13164.

Um den MySQL-Server mit yaSSL-Unterstützung zu starten, verwenden Sie dieselben Optionen wie beim OpenSSL-Support und geben die zur Herstellung einer sicheren Verbindung erforderlichen Zertifikate an:

shell> mysqld --ssl-ca=cacert.pem \
       --ssl-cert=server-cert.pem \
       --ssl-key=server-key.pem
  • --ssl-ca benennt das CA-Zertifikat.

  • --ssl-cert benennt das Serverzertifikat.

  • --ssl-key benennt das Clientzertifikat.

Um eine sichere Verbindung zu einem MySQL-Server mit yaSSL-Unterstützung herzustellen, starten Sie Ihren Client wie folgt:

shell> mysql --ssl-ca=cacert.pem \
       --ssl-cert=server-cert.pem \
       --ssl-key=server-key.pem

Mit anderen Worten sind die Optionen dieselben wie beim Server, und das Zertifikat der Zertifizierungsstelle muss das gleiche sein.

Wenn Sie eine sichere Verbindung von einem Anwendungsprogramm aus herstellen wollen, stellen Sie mit der mysql_ssl_set()-API-Funktion die passenden Zertifikatsoptionen ein, bevor Sie mysql_real_connect() aufrufen. Siehe auch Abschnitt 24.2.3.64, „mysql_ssl_set().

5.9.7.4. Einrichtung von SSL-Zertifikaten für MySQL

An dieser Stelle folgt ein Beispiel zur Konfiguration von SSL-Zertifikaten für MySQL mit OpenSSL:

DIR=`pwd`/openssl
PRIV=$DIR/private

mkdir $DIR $PRIV $DIR/newcerts
cp /usr/share/ssl/openssl.cnf $DIR
replace ./demoCA $DIR -- $DIR/openssl.cnf

# Create necessary files: $database, $serial and $new_certs_dir
# directory (optional)

touch $DIR/index.txt
echo "01" > $DIR/serial

#
# Generation of Certificate Authority(CA)
#

openssl req -new -x509 -keyout $PRIV/cakey.pem -out $DIR/cacert.pem \
    -config $DIR/openssl.cnf

# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Generating a 1024 bit RSA private key
# ................++++++
# .........++++++
# writing new private key to '/home/monty/openssl/private/cakey.pem'
# Enter PEM pass phrase:
# Verifying password - Enter PEM pass phrase:
# -----
# You are about to be asked to enter information that will be
# incorporated into your certificate request.
# What you are about to enter is what is called a Distinguished Name
# or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# Country Name (2 letter code) [AU]:FI
# State or Province Name (full name) [Some-State]:.
# Locality Name (eg, city) []:
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB
# Organizational Unit Name (eg, section) []:
# Common Name (eg, YOUR name) []:MySQL admin
# Email Address []:

#
# Create server request and key
#
openssl req -new -keyout $DIR/server-key.pem -out \
    $DIR/server-req.pem -days 3600 -config $DIR/openssl.cnf

# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Generating a 1024 bit RSA private key
# ..++++++
# ..........++++++
# writing new private key to '/home/monty/openssl/server-key.pem'
# Enter PEM pass phrase:
# Verifying password - Enter PEM pass phrase:
# -----
# You are about to be asked to enter information that will be
# incorporated into your certificate request.
# What you are about to enter is what is called a Distinguished Name
# or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# Country Name (2 letter code) [AU]:FI
# State or Province Name (full name) [Some-State]:.
# Locality Name (eg, city) []:
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB
# Organizational Unit Name (eg, section) []:
# Common Name (eg, YOUR name) []:MySQL server
# Email Address []:
#
# Please enter the following 'extra' attributes
# to be sent with your certificate request
# A challenge password []:
# An optional company name []:

#
# Remove the passphrase from the key (optional)
#

openssl rsa -in $DIR/server-key.pem -out $DIR/server-key.pem

#
# Sign server cert
#
openssl ca  -policy policy_anything -out $DIR/server-cert.pem \
    -config $DIR/openssl.cnf -infiles $DIR/server-req.pem

# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Enter PEM pass phrase:
# Check that the request matches the signature
# Signature ok
# The Subjects Distinguished Name is as follows
# countryName           :PRINTABLE:'FI'
# organizationName      :PRINTABLE:'MySQL AB'
# commonName            :PRINTABLE:'MySQL admin'
# Certificate is to be certified until Sep 13 14:22:46 2003 GMT
# (365 days)
# Sign the certificate? [y/n]:y
#
#
# 1 out of 1 certificate requests certified, commit? [y/n]y
# Write out database with 1 new entries
# Data Base Updated

#
# Create client request and key
#
openssl req -new -keyout $DIR/client-key.pem -out \
    $DIR/client-req.pem -days 3600 -config $DIR/openssl.cnf

# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Generating a 1024 bit RSA private key
# .....................................++++++
# .............................................++++++
# writing new private key to '/home/monty/openssl/client-key.pem'
# Enter PEM pass phrase:
# Verifying password - Enter PEM pass phrase:
# -----
# You are about to be asked to enter information that will be
# incorporated into your certificate request.
# What you are about to enter is what is called a Distinguished Name
# or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# Country Name (2 letter code) [AU]:FI
# State or Province Name (full name) [Some-State]:.
# Locality Name (eg, city) []:
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB
# Organizational Unit Name (eg, section) []:
# Common Name (eg, YOUR name) []:MySQL user
# Email Address []:
#
# Please enter the following 'extra' attributes
# to be sent with your certificate request
# A challenge password []:
# An optional company name []:

#
# Remove a passphrase from the key (optional)
#
openssl rsa -in $DIR/client-key.pem -out $DIR/client-key.pem

#
# Sign client cert
#

openssl ca  -policy policy_anything -out $DIR/client-cert.pem \
    -config $DIR/openssl.cnf -infiles $DIR/client-req.pem

# Sample output:
# Using configuration from /home/monty/openssl/openssl.cnf
# Enter PEM pass phrase:
# Check that the request matches the signature
# Signature ok
# The Subjects Distinguished Name is as follows
# countryName           :PRINTABLE:'FI'
# organizationName      :PRINTABLE:'MySQL AB'
# commonName            :PRINTABLE:'MySQL user'
# Certificate is to be certified until Sep 13 16:45:17 2003 GMT
# (365 days)
# Sign the certificate? [y/n]:y
#
#
# 1 out of 1 certificate requests certified, commit? [y/n]y
# Write out database with 1 new entries
# Data Base Updated

#
# Create a my.cnf file that you can use to test the certificates
#

cnf=""
cnf="$cnf [client]"
cnf="$cnf ssl-ca=$DIR/cacert.pem"
cnf="$cnf ssl-cert=$DIR/client-cert.pem"
cnf="$cnf ssl-key=$DIR/client-key.pem"
cnf="$cnf [mysqld]"
cnf="$cnf ssl-ca=$DIR/cacert.pem"
cnf="$cnf ssl-cert=$DIR/server-cert.pem"
cnf="$cnf ssl-key=$DIR/server-key.pem"
echo $cnf | replace " " '
' > $DIR/my.cnf

Um SSL-Verbindungen zu testen, starten Sie den Server wie folgt, wobei $DIR der Pfadname zu dem Verzeichnis ist, in dem sich die Beispieloptionsdatei my.cnf befindet:

shell> mysqld --defaults-file=$DIR/my.cnf &

Danach rufen Sie ein Clientprogramm mit derselben Optionsdatei auf:

shell> mysql --defaults-file=$DIR/my.cnf

Wenn Sie eine MySQL-Quelldistribution haben, können Sie Ihre Konfiguration auch durch eine dahingehende Änderung der genannten Datei my.cnf testen, dass diese auf das Demozertifikat und die Schlüsseldateien im Verzeichnis SSL der Distribution verweist.

5.9.7.5. SSL-Befehlsoptionen

Die folgende Liste beschreibt Optionen, die zur Angabe der SSL-Nutzung, der Zertifikatsdateien und der Schlüsseldateien dienen. Diese Optionen können über die Befehlszeile oder in einer Optionsdatei angegeben werden.

  • --ssl

    Am Server legt diese Option fest, dass der Server SSL-Verbindungen zulässt. Bei einem Clientprogramm gestattet sie dem Client die Herstellung einer Serververbindung unter Verwendung von SSL. Die Angabe der Option allein reicht nicht aus, um die Verwendung einer SSL-Verbindung zu bewirken. Sie müssen auch die Optionen --ssl-ca, --ssl-cert und --ssl-key angeben.

    Diese Option wird häufiger in ihrer negativen Form angegeben, um festzulegen, dass SSL nicht verwendet werden soll. Zu diesem Zweck geben Sie --skip-ssl oder --ssl=0 an.

    Beachten Sie, dass die Verwendung von --ssl das Vorhandensein einer SSL-Verbindung nicht erfordert. Werden beispielsweise Server oder Client ohne SSL-Unterstützung kompiliert, dann wird eine normale unverschlüsselte Verbindung verwendet.

    Die sichere Art, die Verwendung einer SSL-Verbindung zu gewährleisten, besteht in der Erstellung eines Kontos auf dem Server mit einer REQUIRE SSL-Klausel in der GRANT-Anweisung. Danach stellen Sie über dieses Konto eine Verbindung zum Server her, wobei die SSL-Unterstützung sowohl am Server als auch am Client aktiviert sein muss.

  • --ssl-ca=file_name

    Pfad zu einer Datei, die eine Liste vertrauenswürdiger SSL-CAs enthält.

  • --ssl-capath=directory_name

    Pfad zu einem Verzeichnis, welches Zertifikate vertrauenswürdiger SSL-CAs im PEM-Format enthält.

  • --ssl-cert=file_name

    Name der SSL-Zertifikatsdatei, die zur Herstellung einer sicheren Verbindung verwendet wird.

  • --ssl-cipher=cipher_list

    Eine Liste zulässiger Chiffren, die für die SSL-Verschlüsselung verwendet werden dürfen. cipher_list hat das gleiche Format wie der Befehl openssl ciphers.

    Beispiel: --ssl-cipher=ALL:-AES:-EXP

  • --ssl-key=file_name

    Name der SSL-Schlüsseldatei, die zur Herstellung einer sicheren Verbindung verwendet wird.

5.9.7.6. Verbinden mit einem entfernten MySQL-Server von Windows mit SSH aus

Der folgende Hinweise beschreibt, wie man unter Verwendung von SSH eine sichere Verbindung mit einem entfernte MySQL-Server herstellt (von David Carlson, ):

  1. Installieren Sie einen SSH-Client auf Ihrem Windows-Computer. Für Benutzer ist der beste nicht kostenlose Client, den ich gefunden habe, SecureCRT von http://www.vandyke.com/. Eine weitere Option ist f-secure von http://www.f-secure.com/. Es gibt auch kostenlose Varianten, die Sie via Google finden können (http://directory.google.com/Top/Computers/Security/Products_and_Tools/Cryptography/SSH/Clients/Windows/).

  2. Starten Sie Ihren Windows-SSH-Client. Nehmen Sie folgende Einstellung vor: Host_Name = yourmysqlserver_URL_or_IP. Setzen Sie ferner userid=your_userid, um sich an Ihrem Server anzumelden. Dieser userid-Wert ist unter Umständen nicht mit dem Benutzernamen Ihres MySQL-Kontos identisch.

  3. Konfigurieren Sie die Portweiterleitung. Sie können entweder eine Remote-Weiterleitung (via local_port: 3306, remote_host: yourmysqlservername_or_ip, remote_port: 3306 ) oder eine lokale Weiterleitung einstellen (über port: 3306, host: localhost, remote port: 3306).

  4. Speichern Sie alles (ansonsten müssen Sie die Schritte beim nächsten Mal wiederholen).

  5. Melden Sie sich mit der gerade erstellten SSH-Sitzung an Ihrem Server an.

  6. Starten Sie auf Ihrem Windows-Computer eine ODBC-Anwendung (z. B. Microsoft Access).

  7. Erstellen Sie unter Windows eine neue Datei und stellen Sie mithilfe des ODBC-Treibers wie gewöhnlich die Verbindung zu MySQL her; der einzige Unterschied besteht darin, dass Sie localhost statt yourmysqlservername als MySQL-Hostserver angeben.

An diesem Punkt nun sollte eine ODBC-Verbindung zu MySQL vorhanden sein, die mit SSH verschlüsselt wird.

5.10. Datensicherung und Wiederherstellung

Dieser Abschnitt erläutert, wie man (vollständige und inkrementelle) Datenbanksicherungen durchführt und Tabellen pflegt. Die Syntax der hier beschriebenen SQL-Anweisungen wird in Kapitel 13, SQL-Anweisungssyntax, beschrieben. Ein Großteil der hier vermittelten Informationen bezieht sich in erster Linie auf MyISAM-Tabellen. Weitere Informationen zu Sicherungsvorgängen für InnoDB-Tabellen können Sie Abschnitt 14.2.8, „Sichern und Wiederherstellen einer InnoDB-Datenbank“ entnehmen.

5.10.1. Datenbank-Datensicherungen

Da MySQL-Tabellen als Dateien gespeichert werden, ist die Durchführung einer Datensicherung recht einfach. Um ein konsistentes Backup zu erhalten, führen Sie für die gewünschten Tabellen nacheinander die Anweisungen LOCK TABLES und FLUSH TABLES aus. Siehe auch Abschnitt 13.4.5, „LOCK TABLES und UNLOCK TABLES, und Abschnitt 13.5.5.2, „FLUSH. Sie benötigen lediglich eine Lesesperre, d. h. andere Clients können die Tabellen weiterhin abfragen, während Sie eine Kopie der Dateien im Datenbankverzeichnis erstellen. Die Anweisung FLUSH TABLES ist erforderlich, um sicherzustellen, dass alle aktiven Indexseiten auf Festplatte geschrieben werden, bevor Sie die Sicherung starten.

Um eine Tabelle auf SQL-Ebene zu sichern, können Sie SELECT INTO ... OUTFILE verwenden. Bei dieser Anweisung darf die Ausgabedatei nicht bereits vorhanden sein, da das Überschreiben vorhandener Dateien ein Sicherheitsrisiko darstellen würde. Siehe auch Abschnitt 13.2.7, „SELECT.

Eine weitere Methode zur Sicherung einer Datenbank besteht in der Verwendung des Programms mysqldump oder des Skripts mysqlhotcopy. Siehe auch Abschnitt 8.10, „mysqldump — Programm zur Datensicherung“, und Abschnitt 8.11, „mysqlhotcopy — Backup-Programm für Datenbanken“.

  1. Erstellen Sie eine vollständige Sicherung Ihrer Datenbank:

    shell> mysqldump --tab=/path/to/some/dir --opt db_name
    

    Oder:

    shell> mysqlhotcopy db_name /path/to/some/dir
    

    Sie können auch eine binäre Sicherung erstellen, indem Sie einfach alle Tabellendateien (*.frm, *.MYD und *.MYI) kopieren, während der Server keine Aktualisierungen vornimmt. Das Skript mysqlhotcopy verwendet diese Methode. (Beachten Sie aber, dass diese Methoden nicht funktionieren, wenn Ihre Datenbank InnoDB-Tabellen enthält. InnoDB speichert die Tabelleninhalte nicht in Datenbankverzeichnissen, und mysqlhotcopy funktioniert nur bei MyISAM-Tabellen.)

  2. Wenn mysqld läuft, beenden Sie es und starten Sie es dann mit der Option --log-bin[=file_name] neu. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“. Die Binärlogdateien vermitteln Ihnen die Informationen, die Sie zur Replikation von Änderungen an der Datenbank benötigen, die nach dem Punkt, an dem Sie mysqldump ausgeführt haben, durchgeführt wurden.

Bei InnoDB-Tabellen können Sie ein Onlinebackup durchführen, bei dem die Tabellen nicht gesperrt werden; siehe auch Abschnitt 8.10, „mysqldump — Programm zur Datensicherung“.

MySQL unterstützt inkrementelle Backups: Zu diesem Zweck müssen Sie den Server mit der Option --log-bin starten (Abschnitt 5.12.3, „Die binäre Update-Logdatei“). Sobald Sie ein inkrementelles Backup erstellen wollen (d. h. eine Sicherung, die alle seit dem letzten vollständigen oder inkrementellen Backup vorgenommenen Änderungen enthält), dann sollten Sie das Binärlog mit FLUSH LOGS rotieren. Danach müssen Sie alle Binärlogs, die aus dem Zeitraum zwischen dem letzten vollständigen oder inkrementellen Backup und dem vorletzten erstellten Log stammen, an die Sicherungsposition kopieren. Diese Binärlogs bilden die inkrementelle Sicherung; wenn eine Wiederherstellung erforderlich ist, wenden Sie sie wie weiter unten erläutert an. Wenn Sie beim nächsten Mal eine vollständige Sicherung durchführen, sollten Sie das Binärlog ebenfalls mit FLUSH LOGS, mysqldump --flush-logs oder mysqlhotcopy --flushlog rotieren. Siehe auch Abschnitt 8.10, „mysqldump — Programm zur Datensicherung“, und Abschnitt 8.11, „mysqlhotcopy — Backup-Programm für Datenbanken“.

Wenn Ihr MySQL-Server ein Slave-Replikationsserver ist, dann sollten Sie unabhängig von der gewählten Sicherungsmethode auch die Dateien master.info und relay-log.info sichern, wenn Sie ein Backup der Daten auf Ihrem Slave durchführen. Diese Dateien werden immer benötigt, um die Replikation nach Wiederherstellung der Daten auf dem Slave fortzusetzen. Wenn Ihr Slave Gegenstand der Replikation von LOAD DATA INFILE-Befehlen ist, sollten Sie auch alle SQL_LOAD-*-Dateien sichern, die ggf. in dem mit der Option --slave-load-tmpdir angegebenen Verzeichnis vorhanden sind. (Sofern die Option nicht angegeben wurde, ist die Position standardmäßig der Wert der Variable tmpdir.) Der Slave benötigt diese Dateien, um die Replikation unterbrochener LOAD DATA INFILE-Operationen fortzusetzen.

Wenn Sie MyISAM-Tabellen wiederherstellen müssen, probieren Sie dies zunächst mit REPAIR TABLE oder myisamchk -r. Dies sollte in 99,9 Prozent aller Fälle funktionieren. Schlägt der Befehl myisamchk fehl, dann probieren Sie die nachfolgend beschriebene Vorgehensweise aus. Beachten Sie, dass dies nur funktioniert, wenn Sie durch Starten von MySQL mit der Option --log-bin das binäre Loggen aktiviert haben.

  1. Stellen Sie das ursprüngliche mysqldump-Backup oder das binäre Backup wieder her.

  2. Führen Sie den folgenden Befehl aus, um die Aktualisierungen in den Binärlogs erneut auszuführen:

    shell> mysqlbinlog binlog.[0-9]* | mysql
    

    In manchen Fällen wollen Sie unter Umständen nur bestimmte Binärlogs in bestimmten Verzeichnissen erneut ausführen (wobei Sie in der Regel alle Binärlogs ab dem Datum der wiedergestellten Sicherung wiederherstellen sollten – möglicherweise abgesehen von einigen falschen Anweisungen). Weitere Informationen zum Hilfsprogramm mysqlbinlog und seiner Verwendung finden Sie in Abschnitt 8.8, „mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien“.

Sie können auch selektive Sicherungen einzelner Dateien vornehmen:

  • Um einen Speicherauszug einer Tabelle zu erstellen, verwenden Sie SELECT * INTO OUTFILE 'file_name' FROM tbl_name.

  • Um die Tabelle wieder zu laden, verwenden Sie LOAD DATA INFILE 'file_name' REPLACE .... Um Datensatzdubletten zu verhindern, muss die Tabelle einen PRIMARY KEY- oder einen UNIQUE-Index aufweisen. Das Schlüsselwort REPLACE sorgt dafür, dass alte Datensätze durch neue ersetzt werden, wenn ein eindeutiger Schlüsselwert in einem neuen Datensatz dem eines alten Datensatzes entspricht.

Wenn Sie bei der Durchführung von Sicherungen Probleme mit der Serverleistung haben, besteht eine mögliche Abhilfe darin, die Replikation zu konfigurieren und Backups auf dem Slave statt auf dem Master durchzuführen. Siehe auch Abschnitt 6.1, „Einführung in die Replikation“.

Wenn Sie ein Veritas-Dateisystem verwenden, können Sie das Backup wie folgt erstellen:

  1. Führen Sie im Clientprogramm FLUSH TABLES WITH READ LOCK aus.

  2. Führen Sie unter einer anderen Shell mount vxfs snapshot aus.

  3. Führen Sie nun wiederum auf dem ersten Client UNLOCK TABLES aus.

  4. Kopieren Sie die Dateien aus dem Schnappschuss.

  5. Trennen Sie den Schnappschuss ab.

5.10.2. Beispielhaftes Vorgehen zur Datensicherung und Wiederherstellung

Dieser Abschnitt erläutert eine Vorgehensweise zur Durchführung von Backups, die eine Wiederherstellung von Daten nach mehreren Arten von Abstürzen gestattet:

  • Absturz des Betriebssystems

  • Stromausfall

  • Absturz des Dateisystems

  • Hardwareproblem (Festplatte, Hauptplatine usw.)

Die Befehlsbeispiele enthalten keine Optionen wie --user und --password für die Programme mysqldump und mysql. Sie sollten diese Optionen nach Bedarf hinzufügen, sodass der MySQL-Server Ihnen das Herstellen einer Verbindung gestattet.

Wir setzen voraus, dass die Daten in der InnoDB-Speicher-Engine gespeichert sind, die Transaktionen und automatische Wiederherstellung nach einem Absturz unterstützt. Ferner wird vorausgesetzt, dass der MySQL-Server zum Zeitpunkt des Absturzes Daten verarbeitet; wäre dies nicht der Fall, dann wäre keine Wiederherstellung erforderlich.

In Fällen von Betriebssystemabstürzen oder Stromausfällen können wir davon ausgehen, dass die Festplattendaten von MySQL nach einem Neustart wieder verfügbar sind. Die InnoDB-Datendateien enthalten unter Umständen aufgrund des Absturzes keine konsistenten Daten, aber InnoDB liest seine Logs aus und findet darin die Liste der anhängigen abgeschlossenen und nicht abgeschlossenen Transaktionen, die noch nicht in die Datendateien geschrieben wurden. InnoDB führt für die nicht abgeschlossenen Transaktionen automatisch einen Rollback aus, die abgeschlossenen Transaktionen hingegen werden in die Datendateien geschrieben. Informationen zum Wiederherstellungsprozess erhält der Benutzer über das MySQL-Fehlerlog. Hier ein Beispielauszug aus einem Log:

InnoDB: Database was not shut down normally.
InnoDB: Starting recovery from log files...
InnoDB: Starting log scan based on checkpoint at
InnoDB: log sequence number 0 13674004
InnoDB: Doing recovery: scanned up to log sequence number 0 13739520
InnoDB: Doing recovery: scanned up to log sequence number 0 13805056
InnoDB: Doing recovery: scanned up to log sequence number 0 13870592
InnoDB: Doing recovery: scanned up to log sequence number 0 13936128
...
InnoDB: Doing recovery: scanned up to log sequence number 0 20555264
InnoDB: Doing recovery: scanned up to log sequence number 0 20620800
InnoDB: Doing recovery: scanned up to log sequence number 0 20664692
InnoDB: 1 uncommitted transaction(s) which must be rolled back
InnoDB: Starting rollback of uncommitted transactions
InnoDB: Rolling back trx no 16745
InnoDB: Rolling back of trx no 16745 completed
InnoDB: Rollback of uncommitted transactions completed
InnoDB: Starting an apply batch of log records to the database...
InnoDB: Apply batch completed
InnoDB: Started
mysqld: ready for connections

In Fällen von Dateisystemabstürzen oder Hardwareproblemen können wir davon ausgehen, dass die MySQL-Festplattendaten nach einem Neustart nicht verfügbar sind. Das bedeutet wiederum, dass MySQL nicht erfolgreich gestartet werden kann, da einige Datenblöcke auf der Festplatte nicht mehr lesbar sind. In diesem Fall ist es erforderlich, die Festplatte neu zu formatieren, eine neue Festplatte zu installieren oder das zugrundeliegende Problem anderweitig zu beheben. Danach müssen wir unsere MySQL-Daten aus Backups wiederherstellen, d. h. es sollten bereits Backups vorhanden sein. Um dies sicherzustellen, sollten wir eine Sicherungsrichtlinie erstellen.

5.10.2.1. Richtlinien für die Datensicherung

Wir alle wissen, dass die regelmäßige Durchführung von Sicherungen geplant werden muss. Ein vollständiges Backup (d. h. ein Schnappschuss der Daten zu einem gegebenen Zeitpunkt) kann in MySQL mit verschiedenen Tools erfolgen. So ermöglicht etwa InnoDB Hot Backup eine online durchgeführte physische Sicherung der InnoDB-Datendateien ohne Sperre, und mysqldump erlaubt ein online erstelltes logisches Backup. Wir werden an dieser Stelle mysqldump beschreiben.

Nehmen wir an, Sie erstellen am Sonntag um 13:00 Uhr ein Backup. Dies ist ein Zeitpunkt, an dem die Serverlast niedrig ist. Der folgende Befehl erstellt ein vollständiges Backup all Ihrer InnoDB-Tabellen in allen Datenbanken:

shell> mysqldump --single-transaction --all-databases > backup_sunday_1_PM.sql

Dies ist eine online ausgeführte, nicht sperrende Sicherung, die Lese- und Schreibvorgänge in den Tabellen nicht beeinträchtigt. Wir haben bereits weiter oben gesagt, dass unsere Tabellen InnoDB-Tabellen sind, d. h. --single-transaction verwendet eine konsistente Leseoperation und gewährleistet, dass die von mysqldump erkannten Daten nicht geändert werden. (Änderungen, die von anderen Clients an den InnoDB-Tabellen durchgeführt werden, werden vom mysqldump-Prozess nicht erkannt.) Wenn auch andere Tabellentypen vorhanden sind, müssen wir davon ausgehen, dass diese während des Sicherungsvorgangs nicht geändert werden. So müssen wir beispielsweise für die MyISAM-Tabellen in der mysql-Datenbank voraussetzen, dass während der Sicherung keine administrativen Änderungen an den MySQL-Konten vorgenommen werden.

Am Ende steht eine .sql-Datei, die von mysqldump erzeugt wird. Sie enthält einen Satz von INSERT-SQL-Anweisungen, die zum Neuladen der gespeicherten Tabellen zu einem späteren Zeitpunkt verwendet werden können.

Vollständige Backups sind erforderlich, aber manchmal unpraktisch. Sie erzeugen große Sicherungsdateien, und die Erstellung dauert recht lange. Außerdem sind sie nicht optimal in dem Sinn, dass alle aufeinanderfolgenden Sicherungen alle Daten enthalten – d. h. auch solche, die seit dem letzten vollständigen Backup nicht geändert wurden. Wenn wir also ein vollständiges Backup als Ausgangspunkt erstellt haben, ist es effektiver, nachfolgend inkrementelle Sicherungen zu erstellen. Diese sind kleiner, und ihre Erstellung verläuft schneller. Der Nachteil besteht darin, dass Sie im Fehlerfall nicht einfach ein einziges vollständiges Backup aufspielen können, um Ihre Daten wiederherzustellen. Sie müssen vielmehr auch die inkrementellen Sicherungen aufspielen, um die dort gespeicherten Änderungen wiederherzustellen.

Um inkrementelle Sicherungen zu erstellen, müssen wir die inkrementellen Änderungen speichern. Der MySQL-Server sollte immer mit der Option --log-bin gestartet werden, damit er diese Änderungen beim Aktualisieren von Daten in einer Datei speichert. Diese Option aktiviert das binäre Loggen, d. h. der Server schreibt jede SQL-Anweisung, die Daten ändert, in eine Datei: das MySQL-Binärlog. Wenn man einen Blick in das Datenverzeichnis eines MySQL-Servers wirft, der mit der Option --log-bin gestartet wurde und schon ein paar Tage läuft, dann findet man dort die folgenden MySQL-Binärlogdateien:

-rw-rw---- 1 guilhem  guilhem   1277324 Nov 10 23:59 gbichot2-bin.000001
-rw-rw---- 1 guilhem  guilhem         4 Nov 10 23:59 gbichot2-bin.000002
-rw-rw---- 1 guilhem  guilhem        79 Nov 11 11:06 gbichot2-bin.000003
-rw-rw---- 1 guilhem  guilhem       508 Nov 11 11:08 gbichot2-bin.000004
-rw-rw---- 1 guilhem  guilhem 220047446 Nov 12 16:47 gbichot2-bin.000005
-rw-rw---- 1 guilhem  guilhem    998412 Nov 14 10:08 gbichot2-bin.000006
-rw-rw---- 1 guilhem  guilhem       361 Nov 14 10:07 gbichot2-bin.index

Bei jedem Neustart erstellt der MySQL-Server eine neue Binärlogdatei, für deren Benennung er die nächste Nummer in der Nummernfolge verwendet. Solange der Server ausgeführt wird, können Sie ihn auch manuell anweisen, die aktuelle Binärlogdatei zu schließen und eine neue zu erstellen. Hierzu verwenden Sie die SQL-Anweisung FLUSH LOGS oder geben den Befehl mysqladmin flush-logs ein. Auch mysqldump bietet eine Option zum Schreiben der Logs auf die Festplatte. Die .index-Datei im Datenverzeichnis enthält eine Liste aller MySQL-Binärlogs in diesem Verzeichnis. Die Datei wird zur Replikation verwendet.

Die MySQL-Binärlogs sind für die Wiederherstellung wichtig, denn sie bilden den Satz inkrementeller Backups. Wenn Sie die Logs beim Erstellen einer vollständigen Sicherung auf Festplatte schreiben, dann enthält ein ggf. nachfolgend erstelltes Backup alle Änderungen seit dem Backup. Wir wollen den obigen mysqldump-Befehl ein wenig abändern, damit er die MySQL-Binärlogs zum Zeitpunkt einer vollständigen Sicherung auf die Festplatte schreibt und die Speicherauszugsdatei den Namen des neuen aktuellen Binärlogs enthält:

shell> mysqldump --single-transaction --flush-logs --master-data=2 \
         --all-databases > backup_sunday_1_PM.sql

Nach Ausführung dieses Befehls enthält das Datenverzeichnis eine neue Binärlogdatei namens gbichot2-bin.000007. Die am Ende erstellte .sql-Datei enthält die folgenden Zeilen:

-- Position to start replication or point-in-time recovery from
-- CHANGE MASTER TO MASTER_LOG_FILE='gbichot2-bin.000007',MASTER_LOG_POS=4;

Weil der mysqldump-Befehl ein vollständiges Backup erstellt hat, bedeuten diese Zeilen zweierlei:

  • Die .sql-Datei enthält alle Änderungen, die vorgenommen wurden, bevor Änderungen in die Binärlogdatei gbichot2-bin.000007 oder eine neuere Binärlogdatei geschrieben wurden.

  • Alle nach dem Backup geloggten Datenänderungen sind noch nicht in der .sql-Datei, wohl aber in der Binärlogdatei gbichot2-bin.000007 oder einer neueren Binärlogdatei vorhanden.

Am Montag um 13:00 Uhr erstellen wir eine inkrementelle Sicherungsdatei, indem wir die Logdateien auf die Festplatte schreiben, um so eine neue Binärlogdatei zu erstellen. So erstellt beispielsweise der Befehl mysqladmin flush-logs die Datei gbichot2-bin.000008. Alle Änderungen, die zwischen Sonntag, 13:00 Uhr (Erstellung des vollständigen Backups), und Montag, 13:00 Uhr, vorgenommen wurden, sind in der Datei gbichot2-bin.000007 enthalten. Diese inkrementelle Sicherung ist wichtig, weswegen sie an einen sicheren Ort kopiert werden sollte. (Sie können sie etwa auf Band oder DVD sichern oder auf einen anderen Computer kopieren.) Am Dienstag um 13:00 Uhr wird der Befehl mysqladmin flush-logs erneut ausgeführt. Alle Änderungen, die zwischen Montag, 13:00 Uhr, und Dienstag, 13:00 Uhr, angefallen sind, sind in der Datei gbichot2-bin.000008 vermerkt (auch diese sollten Sie an einen sicheren Ort kopieren).

Die MySQL-Binärlogs benötigen Festplattenspeicher. Um Speicher freizugeben, sollten Sie sie von Zeit zu Zeit bereinigen. Eine Möglichkeit, dies zu tun, besteht im Löschen von Binärlogs, die nicht mehr benötigt werden (beispielsweise nachdem ein vollständiges Backup erstellt wurde):

shell> mysqldump --single-transaction --flush-logs --master-data=2 \
         --all-databases --delete-master-logs > backup_sunday_1_PM.sql

Hinweis: Das Löschen von MySQL-Binärlogs mit mysqldump --delete-master-logs kann gefährlich sein, wenn Ihr Server ein Replikations-Master ist, denn unter Umständen haben die Slave-Server den Inhalt des Binärlogs noch nicht vollständig verarbeitet. Die Beschreibung der PURGE MASTER LOGS-Anweisung erläutert, was zu prüfen ist, bevor die MySQL-Binärlogs gelöscht werden. Siehe auch Abschnitt 13.6.1.1, „PURGE MASTER LOGS.

5.10.2.2. Verwenden von Datensicherungen zur Wiederherstellung

Nehmen wir nun an, dass es am Mittwoch um 8:00 Uhr zu einem folgenschweren Absturz kommt, der eine Wiederherstellung aus den Sicherungen erfordert. Zu diesem Zweck stellen wir zunächst das letzte vollständige Backup (von Sonntag, 13:00 Uhr) wieder her. Da die vollständige Sicherungsdatei nichts anderes als eine Sammlung von SQL-Anweisungen ist, ist die Wiederherstellung sehr einfach:

shell> mysql < backup_sunday_1_PM.sql

An dieser Stelle sind die Daten auf dem Stand von Sonntag, 13:00 Uhr. Um nun die seitdem vorgenommenen Änderungen wiederherzustellen, müssen wir die inkrementellen Sicherungen verwenden, d. h. die Binärlogdateien gbichot2-bin.000007 und gbichot2-bin.000008. Besorgen Sie sich diese Dateien nun von dort, wo Sie sie gesichert hatten, und verarbeiten Sie ihren Inhalt wie folgt:

shell> mysqlbinlog gbichot2-bin.000007 gbichot2-bin.000008 | mysql

Wir haben nun die Daten auf dem Stand von Dienstag, 13:00 Uhr, wiederhergestellt. Noch aber fehlen die Daten zwischen diesem Zeitpunkt und dem des Absturzes. Um diese nicht zu verlieren, hätten wir den MySQL-Server so konfiguriert haben müssen, dass er seine MySQL-Binärlogs an einem sicheren Ort (RAID-Festplatten, SAN, usw.) speichert – nicht aber auf der Festplatte, wo er seine Datendateien speichert, damit die Logs sich im Schadensfalls nicht auf der zerstörten Festplatte befinden. (Zu diesem Zweck können wir den Server mit der Option --log-bin starten, die eine Position auf einem anderen physischen Gerät als demjenigen angibt, auf dem das Datenverzeichnis liegt. Auf diese Weise gehen die Logs nicht verloren, wenn das Gerät mit dem Datenverzeichnis zerstört wird.) Hätten wir das gemacht, dann hätten wir jetzt die Datei gbichot2-bin.000009 zur Hand und könnten sie einfach mit mysqlbinlog und mysql aufspielen, um die letzten Datenänderungen bis zum Moment des Absturzes verlustfrei wiederherzustellen.

5.10.2.3. Backup-Strategien

Bei einem Betriebssystemabsturz oder einem Stromausfall erledigt InnoDB die gesamte Datenwiederherstellung automatisch. Um jedoch ruhig schlafen zu können, sollten Sie unbedingt folgende Richtlinien beachten:

  • Führen Sie den MySQL-Server immer mit der Option --log-bin oder sogar --log-bin=log_name aus. Der angegebene Logdateiname befindet sich dabei auf einem anderen Medium als dem Laufwerk, auf dem das Datenverzeichnis gespeichert ist. Sofern Sie solche sicheren Medien haben, können Sie sie unter Umständen auch gut für eine Festplattenlastverteilung einsetzen (was sich positiv auf die Leistung auswirkt).

  • Erstellen Sie regelmäßig vollständige Backups. Verwenden Sie dazu den letzten der oben angegebenen mysqldump-Befehle, um ein Online-Backup ohne Sperren durchzuführen.

  • Erstellen Sie regelmäßig inkrementelle Backups, indem Sie die Logs mit FLUSH LOGS oder mysqladmin flush-logs auf die Festplatte schreiben.

5.10.3. Zeitpunktbezogene Wiederherstellung

Wenn am MySQL-Server das binäre Loggen aktiviert ist, können Sie mit dem Hilfsprogramm mysqlbinlog Daten ab dem angegebenen Zeitpunkt („Point in Time“) bis zum aktuellen oder einem anderen angegebenen Zeitpunkt wiederherstellen. Informationen zur Aktivierung des Binärlogs und zur Verwendung von mysqlbinlog finden Sie in Abschnitt 5.12.3, „Die binäre Update-Logdatei“, und Abschnitt 8.8, „mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien“.

Um Daten aus einem Binärlog wiederherzustellen, müssen Sie den Pfad und den Namen der aktuellen Binärlogdatei kennen. Sie finden den Pfad normalerweise in der Optionsdatei (also je nach System my.cnf oder my.ini). Ist der Pfad nicht in der Optionsdatei enthalten, dann wurde er unter Umständen beim Serverstart als Option auf der Befehlszeile angegeben. Die Option zur Aktivierung des binären Loggens heißt --log-bin. Den Namen der aktuellen Binärlogdatei ermitteln Sie mit der folgenden Anweisung:

mysql> SHOW BINLOG EVENTS \G

Sie können, wenn Sie dies vorziehen, auch folgenden Befehl über die Befehlszeile ausführen:

shell> mysql --user=root -p -E -e "SHOW BINLOG EVENTS"

Geben Sie das root-Passwort für Ihren Server ein, wenn mysql Sie dazu auffordert.

5.10.3.1. Angabe von Zeitpunkten für die Wiederherstellung

Um die Start- und Endzeitpunkte für die Wiederherstellung festzulegen, geben Sie für mysqlbinlog die Optionen --start-date und --stop-date im DATETIME an. Nehmen wir beispielsweise an, dass am 20. April 2005 um genau 10:00 Uhr eine SQL-Anweisung ausgeführt wurde, mit der eine große Tabelle gelöscht wurde. Um die Tabelle und ihre Daten wiederherzustellen, könnten Sie das Backup der vorhergehenden Nacht wiederherstellen und dann den folgenden Befehl ausführen:

shell> mysqlbinlog --stop-date="2005-04-20 9:59:59" \
         /var/log/mysql/bin.123456 | mysql -u root -p

Dieser Befehl stellt alle Daten bis zum durch die Option --stop-date angegebenen Zeitpunkt wieder her. Haben Sie die fehlerhafte SQL-Anweisung, die zum Löschen der Tabellen eingegeben wurde, erst Stunden später entdeckt, dann werden Sie wahrscheinlich auch die nachfolgenden durchgeführten Operationen wiederherstellen wollen. Davon ausgehend könnten Sie mysqlbinlog noch einmal unter Angabe eines Startzeitpunkts ausführen:

shell> mysqlbinlog --start-date="2005-04-20 10:01:00" \
         /var/log/mysql/bin.123456 | mysql -u root -p

In diesem Befehl werden die SQL-Anweisungen, die ab 10:01 Uhr aufgezeichnet wurden, erneut aufgeführt. Die Kombination aus der Wiederherstellung der Speicherauszugsdatei der vorangegangenen Nacht und der Ausführung der beiden mysqlbinlog-Befehle stellt alle Aktionen mit Ausnahme derjenigen wieder her, die im Zeitraum zwischen 9:59:59 Uhr und 10:01:00 Uhr ausgeführt wurden. Überprüfen Sie die Logdatei, um die exakten Zeiten angeben zu können. Der nächste Abschnitt beschreibt die erforderlichen Abläufe.

5.10.3.2. Angabe von Positionsnummern für die Wiederherstellung

Statt Datums- und Zeitangaben anzugeben, können Sie die Optionen --start-position und --stop-position für mysqlbinlog zur Angabe von Logpositionen verwenden. Diese Optionen arbeiten genauso wie die Optionen für Start- und Endzeitpunkt, nur werden Positionsangaben aus dem Log spezifiziert. Die Angabe dieser Logposition ist unter Umständen eine exaktere Wiederherstellungsmethode – insbesondere dann, wenn viele Transaktionen zur gleichen Zeit wie die schädliche SQL-Anweisung auftraten. Zur Bestimmung der Positionsnummer können Sie mysqlbinlog für einen Zeitbereich in der Umgebung des Zeitpunkts ausführen, an dem die unerwünschte Transaktion durchgeführt wurde, die Ergebnisse aber zur Überprüfung in einer Textdatei umleiten. Dies wird wie folgt gemacht:

shell> mysqlbinlog --start-date="2005-04-20 9:55:00" \
         --stop-date="2005-04-20 10:05:00" \
         /var/log/mysql/bin.123456 > /tmp/mysql_restore.sql

Dieser Befehl erstellt eine kleine Textdatei im Verzeichnis /tmp, die die im zeitlichen Bereich der misslichen SQL-Anweisung abgesetzten Anweisungen enthält. Öffnen Sie diese Datei mit einem Texteditor und suchen Sie nach der Anweisung, die nicht wiederholt werden soll. Bestimmen Sie die Positionen im Binärlog für das Beenden und Wiederaufnehmen der Wiederherstellung und notieren Sie sich diese. Die Positionen sind gekennzeichnet mit log_pos, gefolgt von einer Zahl. Nach der Wiederherstellung der vorherigen Sicherungsdatei verarbeiten Sie die Binärlogdatei unter Verwendung der Positionsnummern. So würden Sie z. B. Befehle in der Art der folgenden verwenden:

shell> mysqlbinlog --stop-position="368312" /var/log/mysql/bin.123456 \
         | mysql -u root -p

shell> mysqlbinlog --start-position="368315" /var/log/mysql/bin.123456 \
         | mysql -u root -p

Der erste Befehl stellt alle Transaktionen bis zur angegebenen Endposition wieder her. Der zweite Befehl führt die Wiederherstellung aller Transaktionen vom angegebenen Fortsetzungspunkt bis zum Ende des Binärlogs durch. Da die Ausgabe von mysqlbinlog vor jeder aufgezeichneten SQL-Anweisung SET TIMESTAMP-Anweisungen enthält, finden sich in den wiederhergestellten Daten und den zugehörigen MySQL-Logs die ursprünglichen Ausführungszeitpunkte der Transaktionen wieder.

5.10.4. Benutzung von myisamchk für Tabellenwartung und Absturzreparatur

Dieser Abschnitt beschreibt, wie man mit myisamchk MyISAM-Tabellen überprüft oder repariert (also Tabellen, für die .MYD- und .MYI-Dateien zur Speicherung von Daten und Indizes vorhanden sind). Allgemeine Hinweise zu myisamchk finden Sie in Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“.

Sie können mit myisamchk Informationen zu Ihren Datenbanktabellen abrufen oder sie überprüfen, reparieren oder optimieren. Die folgenden Abschnitte erläutern, wie Sie diese Operationen durchführen und wie man einen Wartungsplan für Tabellen einrichtet.

Auch wenn die Tabellenreparatur mit myisamchk verhältnismäßig sicher ist, sollten Sie immer ein Backup erstellen, bevor Sie eine Reparatur oder Wartungsoperationen durchführen, bei denen viele Änderungen an einer Tabelle vorgenommen werden.

myisamchk-Operationen, die sich auf Indizes auswirken, können die Neuerstellung von FULLTEXT-Indizes mit Volltextparametern auslösen, die nicht mit den vom MySQL-Server verwendeten Werten kompatibel sind. Um dieses Problem zu umgehen, beachten Sie die Hinweise in Abschnitt 8.2.1, „Allgemeine Optionen für myisamchk.

In vielen Fällen kann es auch einfacher sein, die Wartung einer MyISAM-Tabelle mit SQL-Anweisungen durchzuführen, die Operationen ausführen, wie Sie auch von myisamchk unterstützt werden:

  • Um MyISAM-Tabellen zu überprüfen oder zu reparieren, verwenden Sie CHECK TABLE oder REPAIR TABLE.

  • Um MyISAM-Tabellen zu optimieren, benutzen Sie OPTIMIZE TABLE.

  • Um MyISAM-Tabellen zu analysieren, benutzen Sie ANALYZE TABLE.

Diese Anweisungen können wahlweise direkt oder mithilfe des Clientprogramms mysqlcheck eingesetzt werden. Ein Vorteil dieser Anweisungen im Vergleich zu myisamchk besteht darin, dass der Server die gesamte Arbeit erledigt. Bei myisamchk müssen Sie sicherstellen, dass der Server die Tabellen nicht zur selben Zeit verwendet, damit es nicht zu unerwünschten Interaktionen zwischen myisamchk und dem Server kommt. Siehe auch Abschnitt 13.5.2.1, „ANALYZE TABLE, Abschnitt 13.5.2.3, „CHECK TABLE, Abschnitt 13.5.2.5, „OPTIMIZE TABLE, und Abschnitt 13.5.2.6, „REPAIR TABLE.

5.10.4.1. Benutzung von myisamchk für die Fehlerbeseitigung nach Abstürzen

Dieser Abschnitt beschreibt, wie Sie MySQL-Datenbanken auf beschädigte Daten überprüfen und mit diesen ggf. verfahren können. Wenn Ihre Tabellen häufig beschädigt werden, sollten Sie die Ursache hierfür ermitteln. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

Eine Erklärung, wie Schäden an MyISAM-Tabellen auftreten können, finden Sie in Abschnitt 14.1.4, „MyISAM-Tabellenprobleme“.

Wenn Sie mysqld mit deaktivierter externer Sperre ausführen (was ab MySQL 4.0 das Standardverhalten ist), dann können Sie myisamchk nicht für das zuverlässige Überprüfen einer Tabelle verwenden, wenn mysqld genau diese Tabelle benutzt. Wenn Sie ganz sicher sind, dass niemand über mysqld auf die Tabellen zugreifen kann, während Sie myisamchk ausführen, müssen Sie lediglich mysqladmin flush-tables ausführen, bevor Sie die Überprüfung der Tabellen starten. Können Sie dies nicht gewährleisten, dann müssen Sie mysqld stoppen, solange Sie die Tabellen überprüfen. Führen Sie myisamchk zur Überprüfung von Tabellen aus, die gleichzeitig von mysqld aktualisiert werden, dann erhalten Sie unter Umständen eine Warnung, dass eine Tabelle beschädigt sei, obwohl dies gar nicht stimmt.

Wenn der Server mit aktivierter externer Sperrung ausgeführt wird, können Sie die Tabellen jederzeit mit myisamchk überprüfen. In diesem Fall muss der Server, wenn er eine Tabelle zu aktualisieren versucht, die myisamchk gerade verwendet, warten, bis myisamchk den Vorgang abgeschlossen hat, bevor er fortfährt.

Verwenden Sie myisamchk zur Reparatur oder Optimierung von Tabellen, dann müssen Sie immer sicherstellen, dass der Server mysqld die Tabelle nicht verwendet. (Dies gilt auch bei deaktivierter externer Sperrung.) Beenden Sie mysqld nicht, dann sollten Sie zumindest mysqladmin flush-tables ausführen, bevor Sie myisamchk starten. Wenn der Server und myisamchk gleichzeitig auf die Tabellen zugreifen, können Ihre Tabellen beschädigt werden.

Wenn Sie eine Wiederherstellung nach einem Absturz durchführen, müssen Sie beachten, dass zu jeder MyISAM-Tabelle tbl_name in einer Datenbank drei Dateien im Datenbankverzeichnis gehören:

DateiZweck
tbl_name.frmDefinitionsdatei (Formatdatei)
tbl_name.MYDDatendatei
tbl_name.MYIIndexdatei

Jeder dieser drei Dateitypen kann auf unterschiedliche Weise beschädigt werden, meistens treten Probleme aber in Zusammenhang mit Daten- und Indexdateien auf.

myisamchk erstellt datensatzweise eine Kopie der .MYD-Datendatei. Die Reparatur wird beendet, indem die alte .MYD-Datei entfernt und der neuen Daten dann der ursprüngliche Dateiname zugewiesen wird. Wenn Sie --quick verwenden, erstellt myisamchk keine temporäre .MYD-Datei, sondern setzt stattdessen voraus, dass die .MYD-Datei korrekt ist, und erstellt nur eine neue Indexdatei – die vorhandene .MYD-Datei wird nicht angerührt. Dies ist sicher, da myisamchk automatisch erkennt, ob die .MYD-Datei beschädigt ist (in diesem Fall wird diese Reparatur abgebrochen). Sie können für myisamchk auch zweimal die Option --quick angeben. In diesem Fall bricht myisamchk bei einigen Fehlern (z. B. Schlüsseldubletten) nicht ab, sondern versucht diese zu beheben, indem die .MYD-Datei modifiziert wird. Normalerweise ist die Verwendung zweier --quick-Optionen nur dann sinnvoll, wenn zu wenig freier Festplattenspeicher für eine normale Reparatur vorhanden ist. In diesem Fall sollten Sie zumindest ein Backup der Tabelle erstellen, bevor Sie myisamchk ausführen.

5.10.4.2. Wie Tabellen auf Fehler überprüft werden

Verwenden Sie die folgenden Befehle, um eine MyISAM-Tabelle auf Fehler zu prüfen:

  • myisamchk tbl_name

    Hierdurch werden 99,99 Prozent aller Fehler gefunden. Nicht gefunden werden lediglich Datenschäden, bei denen nur die Datendatei betroffen ist (dies kommt ausgesprochen selten vor). Wenn Sie eine Tabelle überprüfen wollen, sollten Sie normalerweise myisamchk ohne Optionen oder aber mit der Option -s (stumm) ausführen.

  • myisamchk -m tbl_name

    Hierdurch werden 99,999 Prozent aller Fehler gefunden. Zunächst werden alle Indexeinträge auf Fehler geprüft, dann werden alle Datensätze gelesen. Für alle Schlüsselwerte in den Datensätzen wird eine Prüfsumme berechnet, die mit der Prüfsumme der Schlüssel im Indexbaum übereinstimmen muss.

  • myisamchk -e tbl_name

    Führt eine vollständige und umfassende Überprüfung aller Daten durch (-e bedeutet „Extended Check“, also erweiterte Überprüfung). Jeder Schlüssel in jedem Datensatz wird prüfweise gelesen, um sicherzustellen, dass er tatsächlich auf den korrekten Datensatz verweist.Das kann bei umfangreichen Tabellen mit vielen Indizes recht lange dauern. Normalerweise wird myisamchk nach dem ersten gefundenen Fehler beendet. Wenn Sie weitere Informationen benötigen, können Sie die Option -v (ausführlicher Modus) hinzufügen. In diesem Fall läuft myisamchk weiter, bis maximal 20 Fehler gefunden wurden.

  • myisamchk -e -i tbl_name

    Dies ähnelt dem vorherigen Befehl, aber die Option -i weist myisamchk an, zusätzliche Statistikinformationen auszugeben.

In den meisten Fällen ist ein einfacher myisamchk-Befehl ohne andere Argumente als den Tabellennamen zum Überprüfen einer Tabelle ausreichend.

5.10.4.3. Wie Tabellen repariert werden

In diesem Abschnitt wird beschrieben, wie man myisamchk für MyISAM-Tabellen (Erweiterungen .MYI und .MYD) verwendet.

Sie können (und sollten möglichst auch) MyISAM-Tabellen mit CHECK TABLE- und REPAIR TABLE-Anweisungen überprüfen bzw. reparieren. Siehe auch Abschnitt 13.5.2.3, „CHECK TABLE, und Abschnitt 13.5.2.6, „REPAIR TABLE.

Zu den Symptomen beschädigter Tabellen gehören auch Abfragen, die unerwartet abgebrochen werden, und wahrnehmbare Fehler wie die folgenden:

  • tbl_name.frm ist gegen Änderungen gesperrt

  • Die Datei tbl_name.MYI kann nicht gefunden werden (Fehlercode: nnn)

  • Unerwartetes Ende der Datei

  • Aufzeichnungsdatei ist abgestürzt

  • Fehler nnn vom Tabellen-Handler erhalten

Um weitere Informationen zum Fehler zu erhalten, führen Sie perror nnn aus, wobei nnn die Fehlernummer ist. Die folgenden Beispiele zeigen, wie man mit perror die Bedeutungen der häufigsten Fehlernummern ermittelt, die ein Problem mit einer Tabelle angeben:

shell> perror 126 127 132 134 135 136 141 144 145
126 = Index file is crashed / Wrong file format
127 = Record-file is crashed
132 = Old database file
134 = Record was already deleted (or record file crashed)
135 = No more room in record file
136 = No more room in index file
141 = Duplicate unique key or constraint on write or update
144 = Table is crashed and last repair failed
145 = Table was marked as crashed and should be repaired

Beachten Sie, dass die Fehler 135 („No more room in record file“) und 136 („No more room in index file“) nicht mit einer einfachen Tabellenreparatur behoben werden können. In diesem Fall müssen Sie mit ALTER TABLE die Tabellenoptionswerte MAX_ROWS und AVG_ROW_LENGTH erhöhen:

ALTER TABLE tbl_name MAX_ROWS=xxx AVG_ROW_LENGTH=yyy;

Wenn Sie die aktuellen Tabellenoptionswerte nicht kennen, verwenden Sie SHOW CREATE TABLE.

Bei Auftreten anderer Fehler müssen Sie Ihre Tabellen reparieren. myisamchk erkennt und behebt normalerweise die meisten Probleme.

Der Reparaturvorgang umfasst die nachfolgend beschriebenen vier Stufen. Bevor Sie anfangen, sollten Sie in das Datenbankverzeichnis wechseln und die Berechtigungen für die Tabellendateien überprüfen. Unter Unix müssen Sie sicherstellen, dass diese von dem Benutzer gelesen werden können, als der mysqld ausgeführt wird (und von Ihnen natürlich auch, denn schließlich müssen Sie auf die Dateien zugreifen können, die Sie überprüfen wollen). Sollte sich herausstellen, dass Sie Dateien ändern müssen, dann sollten diese auch von Ihnen geschrieben werden können.

Dieser Abschnitt ist für Fälle vorgesehen, in denen die Überprüfung einer Tabelle fehlschlägt (siehe auch die Beschreibung in Abschnitt 5.10.4.2, „Wie Tabellen auf Fehler überprüft werden“) oder Sie die erweiterten Funktionen einsetzen wollen, die myisamchk bereitstellt.

Die Optionen, die Sie zur Wartung von Tabellen mit myisamchk verwenden können, sind in Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“, beschrieben.

Wenn Sie eine Tabelle über die Befehlszeile reparieren wollen, müssen Sie den Server mysqld zunächst beenden. Beachten Sie, dass, wenn Sie mysqladmin shutdown auf einem entfernten Server ausführen, der Server mysqld auch nach der entsprechenden Meldung von mysqladmin noch eine Weile weiterläuft, bis die gesamte Anweisungsbearbeitung beendet wurde und alle Änderungen auf Festplatte geschrieben wurden.

Stufe 1: Tabellen überprüfen

Führen Sie myisamchk *.MYI oder – wenn genug Zeit vorhanden ist – myisamchk -e *.MYI aus. Verwenden Sie die Option -s (stumm) zur Unterdrückung nicht benötigter Informationen.

Wenn der Server mysqld beendet ist, sollten Sie die Option --update-state verwenden, um myisamchk anzuweisen, die Tabelle als „geprüft“ zu kennzeichnen.

Sie müssen nur diejenigen Tabellen reparieren, für die myisamchk einen Fehler meldet. Fahren Sie bei solchen Tabellen mit Stufe 2 fort.

Erhalten Sie bei der Überprüfung unerwartete Fehler (z. B. out of memory) oder stürzt myisamchk ab, dann fahren Sie mit Stufe 3 fort.

Stufe 2: Einfache und sichere Reparatur

Probieren Sie zunächst myisamchk -r -q tbl_name aus (-r -q bedeutet „schneller Wiederherstellungsmodus“). Hierbei wird versucht, die Indexdatei zu reparieren, ohne die Datendatei anzurühren. Wenn die Datendatei alles Erforderliche enthält und die Löschverknüpfungen auf die korrekten Positionen innerhalb der Datendatei verweisen, sollte diese Vorgehensweise funktionieren, d. h. die Tabelle sollte nachfolgend repariert sein. Fahren Sie nun mit der Reparatur der nächsten Tabelle fort. Andernfalls wenden Sie folgende Vorgehensweise an:

  1. Erstellen Sie ein Backup der Datendatei, bevor Sie fortfahren.

  2. Verwenden Sie myisamchk -r tbl_name (-r bedeutet „Wiederherstellungsmodus“). Hierdurch werden falsche und gelöschte Datensätze aus der Datendatei entfernt, und die Indexdatei wird neu erstellt.

  3. Schlägt der vorherige Schritt fehl, dann setzen Sie myisamchk --safe-recover tbl_name ab. Der sichere Wiederherstellungsmodus verwendet eine alte Wiederherstellungsmethode, die ein paar Fälle behebt, die im normalen Wiederherstellungsmodus unberücksichtigt bleiben; sie ist aber langsamer.

Hinweis: Wenn Sie eine Reparaturoption erheblich beschleunigen wollen, sollten Sie die Werte der Variablen sort_buffer_size und key_buffer_size jeweils auf 25 Prozent Ihres verfügbaren Speichers setzen, wenn Sie myisamchk ausführen.

Erhalten Sie bei der Reparatur unerwartete Fehler (z. B. out of memory) oder stürzt myisamchk ab, dann fahren Sie mit Stufe 3 fort.

Stufe 3: Schwierige Reparatur

Diese Stufe sollten Sie nur erreichen, wenn der erste 16-Kbyte-Block der Indexdatei zerstört ist oder falsche Daten enthält oder aber die Indexdatei ganz fehlt. In diesem Fall muss eine neue Indexdatei erstellt werden. Gehen Sie wie folgt vor:

  1. Verschieben Sie die Datendatei an einen sicheren Ort.

  2. Erstellen Sie unter Verwendung der Tabellenbeschreibungsdatei neue (leere) Daten- und Indexdateien:

    shell> mysql db_name
    mysql> SET AUTOCOMMIT=1;
    mysql> TRUNCATE TABLE tbl_name;
    mysql> quit
    
  3. Kopieren Sie die alte Datendatei wieder auf die neu erstellte Datendatei. (Verschieben Sie die alte Datei nicht einfach auf die neue, sondern behalten Sie eine Kopie für den Fall, dass etwas fehlschlägt.)

Kehren Sie zurück zu Stufe 2. myisamchk -r -q sollte nun funktionieren. (Das heißt, die Stufen sollten sich nicht in endloser Abfolge wiederholen.)

Sie können auch die SQL-Anweisung REPAIR TABLE tbl_name USE_FRM verwenden, die den gesamten Vorgang automatisch ausführt. Es gibt außerdem nicht die Möglichkeit unerwünschter Interaktion zwischen einem Hilfsprogramm und dem Server, weil der Server gar nicht läuft, wenn Sie REPAIR TABLE verwenden. Siehe auch Abschnitt 13.5.2.6, „REPAIR TABLE.

Stufe 4: Sehr schwierige Reparatur

Diese Stufe sollten Sie nur erreichen, wenn die .frm-Beschreibungsdatei ebenfalls abgestürzt ist. Dies sollte eigentlich nie passieren, da die Beschreibungsdatei nach Erstellung der Tabelle nicht mehr geändert wird:

  1. Stellen Sie die Beschreibungsdatei aus einer Sicherungskopie wieder her und kehren Sie zu Stufe 3 zurück. Sie können auch die Indexdatei wiederherstellen und dann bei Stufe 2 fortfahren; in diesem Fall sollten Sie allerdings mit myisamchk -r beginnen.

  2. Wenn Sie über keine Sicherungskopie verfügen, aber genau wissen, wie die Tabelle erstellt worden war, erstellen Sie eine Kopie der Tabelle in einer andere Datenbank. Entfernen Sie die neue Datendatei und verschieben Sie die .frm-Beschreibungsdatei und die .MYI-Indexdatei aus der anderen Datenbank in die abgestürzte Datenbank. Auf diese Weise erhalten Sie eine neue Beschreibungs- und Indexdatei, während die .MYD-Datendatei nicht angerührt wird. Kehren Sie zu Stufe 2 zurück und versuchen Sie, die Indexdatei neu zu erstellen.

5.10.4.4. Tabellenoptimierung

Um fragmentierte Datensätze zu vereinigen und die infolge des Löschens und Aktualisierens von Datensätzen entstandene Platzvergeudung zu beseitigen, führen Sie myisamchk im Wiederherstellungsmodus aus:

shell> myisamchk -r tbl_name

Sie können eine Tabelle auf die gleiche Weise optimieren, indem Sie die SQL-Anweisung OPTIMIZE TABLE verwenden. OPTIMIZE TABLE führt eine Reparatur der Tabelle und eine Schlüsselanalyse durch und sortiert zudem den Indexbaum, sodass die Schlüsselsuche beschleunigt wird. Es gibt außerdem nicht die Möglichkeit unerwünschter Interaktion zwischen einem Hilfsprogramm und dem Server, weil der Server gar nicht läuft, wenn Sie OPTIMIZE TABLE verwenden. Siehe auch Abschnitt 13.5.2.5, „OPTIMIZE TABLE.

myisamchk bietet eine Reihe weiterer Optionen, die Sie zur Optimierung der Leistungsfähigkeit einer Tabelle verwenden können:

  • --analyze, -a

  • --sort-index, -S

  • --sort-records=index_num, -R index_num

Eine vollständige Beschreibung der verfügbaren Optionen finden Sie in Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“.

5.10.4.5. Informationen über eine Tabelle erhalten

Um die Beschreibung einer Tabelle oder Statistiken zu ihr zu erhalten, verwenden Sie die hier beschriebenen Befehle. Einige der Informationen werden wir im weiteren Verlauf näher erläutern.

  • myisamchk -d tbl_name

    Führt myisamchk im „Beschreibungsmodus“ aus, um eine Beschreibung Ihrer Tabelle zu erzeugen. Wenn Sie den MySQL-Server mit deaktivierter externer Sperrung starten, meldet myisamchk unter Umständen einen Fehler für eine Tabelle, die aktualisiert wird, während es ausgeführt wird. Da myisamchk die Tabelle im Beschreibungsmodus allerdings nicht ändert, besteht kein Risiko der Beschädigung von Daten.

  • myisamchk -d -v tbl_name

    Wenn Sie -v hinzufügen, läuft myisamchk im ausführlichen Modus, d. h. es werden mehr Informationen zu den ablaufenden Vorgängen erzeugt.

  • myisamchk -eis tbl_name

    Zeigt nur die wichtigsten Informationen zu einer Tabelle an. Dieser Vorgang ist langsam, da die gesamte Tabelle gelesen werden muss.

  • myisamchk -eiv tbl_name

    Ähnlich wie -eis, aber Sie erfahren jeweils, was gerade getan wird.

Eine Beispielausgabe für einige dieser Befehle folgt. Sie basieren auf einer Tabelle mit den folgenden Größen für die Daten- und die Indexdatei:

-rw-rw-r--   1 monty    tcx     317235748 Jan 12 17:30 company.MYD
-rw-rw-r--   1 davida   tcx      96482304 Jan 12 18:35 company.MYI

Beispielausgabe von myisamchk -d:

MyISAM file:     company.MYI
Record format:   Fixed length
Data records:    1403698  Deleted blocks:         0
Recordlength:    226

table description:
Key Start Len Index   Type
1   2     8   unique  double
2   15    10  multip. text packed stripped
3   219   8   multip. double
4   63    10  multip. text packed stripped
5   167   2   multip. unsigned short
6   177   4   multip. unsigned long
7   155   4   multip. text
8   138   4   multip. unsigned long
9   177   4   multip. unsigned long
    193   1           text

Beispielausgabe von myisamchk -d -v:

MyISAM file:         company
Record format:       Fixed length
File-version:        1
Creation time:       1999-10-30 12:12:51
Recover time:        1999-10-31 19:13:01
Status:              checked
Data records:            1403698  Deleted blocks:              0
Datafile parts:          1403698  Deleted data:                0
Datafile pointer (bytes):      3  Keyfile pointer (bytes):     3
Max datafile length:  3791650815  Max keyfile length: 4294967294
Recordlength:                226

table description:
Key Start Len Index   Type                  Rec/key     Root Blocksize
1   2     8   unique  double                      1 15845376      1024
2   15    10  multip. text packed stripped        2 25062400      1024
3   219   8   multip. double                     73 40907776      1024
4   63    10  multip. text packed stripped        5 48097280      1024
5   167   2   multip. unsigned short           4840 55200768      1024
6   177   4   multip. unsigned long            1346 65145856      1024
7   155   4   multip. text                     4995 75090944      1024
8   138   4   multip. unsigned long              87 85036032      1024
9   177   4   multip. unsigned long             178 96481280      1024
    193   1           text

Beispielausgabe von myisamchk -eis:

Checking MyISAM file: company
Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4
Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3
Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4
Total:    Keyblocks used:  98%  Packed:   17%

Records:          1403698    M.recordlength:     226
Packed:             0%
Recordspace used:     100%   Empty space:          0%
Blocks/Record:   1.00
Record blocks:    1403698    Delete blocks:        0
Recorddata:     317235748    Deleted data:         0
Lost space:             0    Linkdata:             0

User time 1626.51, System time 232.36
Maximum resident set size 0, Integral resident set size 0
Non physical pagefaults 0, Physical pagefaults 627, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 639, Involuntary context switches 28966

Beispielausgabe von myisamchk -eiv:

Checking MyISAM file: company
Data records: 1403698   Deleted blocks:       0
- check file-size
- check delete-chain
block_size 1024:
index  1:
index  2:
index  3:
index  4:
index  5:
index  6:
index  7:
index  8:
index  9:
No recordlinks
- check index reference
- check data record references index: 1
Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
- check data record references index: 2
Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4
- check data record references index: 3
Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
- check data record references index: 4
Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3
- check data record references index: 5
Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 6
Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 7
Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 8
Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 9
Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4
Total:    Keyblocks used:   9%  Packed:   17%

- check records and index references
*** LOTS OF ROW NUMBERS DELETED ***

Records:         1403698   M.recordlength:   226   Packed:           0%
Recordspace used:    100%  Empty space:        0%  Blocks/Record: 1.00
Record blocks:   1403698   Delete blocks:      0
Recorddata:    317235748   Deleted data:       0
Lost space:            0   Linkdata:           0

User time 1639.63, System time 251.61
Maximum resident set size 0, Integral resident set size 0
Non physical pagefaults 0, Physical pagefaults 10580, Swaps 0
Blocks in 4 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 10604, Involuntary context switches 122798

Erläuterungen zu den Informationstypen, die myisamchk erzeugt, folgen an dieser Stelle. „Keyfile“ bezeichnet dabei die Indexdatei. „Eintrag“ und „Datensatz“ sind Synonyme.

  • MyISAM file

    Name der MyISAM-Datei (Indexdatei).

  • File-version

    Version des MyISAM-Formats. Ist derzeit immer 2.

  • Creation time

    Zeitpunkt der Erstellung der Datendatei.

  • Recover time

    Letzte Neuerstellung der Index- oder Datendatei.

  • Data records

    Anzahl der Datensätze in der Tabelle.

  • Deleted blocks

    Anzahl der gelöschten Blöcke, für die noch Speicher reserviert ist. Sie können Ihre Tabelle optimieren, um diesen Speicherbedarf zu minimieren. Siehe auch Abschnitt 5.10.4.4, „Tabellenoptimierung“.

  • Datafile parts

    Beim dynamischen Datensatzformat die Anzahl der vorhandenen Datenblöcke. Bei einer optimierten Tabelle ohne fragmentierte Datensätze entspricht der Wert Data records.

  • Deleted data

    Anzahl der Bytes unbeanspruchter gelöschter Daten. Sie können Ihre Tabelle optimieren, um diesen Speicherbedarf zu minimieren. Siehe auch Abschnitt 5.10.4.4, „Tabellenoptimierung“.

  • Datafile pointer

    Größe des Datendateizeigers in Byte. Beträgt normalerweise zwischen zwei und fünf Bytes. Den meisten Tabellen reichen zwei Bytes aus. Dies lässt sich allerdings von MySQL noch nicht steuern. Bei festen Tabellen ist dies eine Datensatzadresse. Bei dynamischen Tabellen ist es hingegen eine Byteadresse.

  • Keyfile pointer

    Größe des Indexdateizeigers in Byte. Beträgt normalerweise zwischen ein und drei Bytes. Den meisten Tabellen reichen zwei Bytes aus, der Wert wird jedoch von MySQL automatisch berechnet. Es handelt sich immer um eine Blockadresse.

  • Max datafile length

    Maximaler Umfang der Datendatei in Bytes.

  • Max keyfile length

    Maximaler Umfang der Indexdatei in Bytes.

  • Recordlength

    Maximaler Speicherbedarf je Datensatz in Bytes.

  • Record format

    Format, in dem die Datensätze in den Tabellen gespeichert werden. Die obigen Beispiele verwenden Fixed length. Weitere mögliche Werte sind Compressed und Packed.

  • table description

    Eine Liste aller Schlüssel in der Tabelle. Für jeden Schlüssel zeigt myisamchk einige maschinennahe Informationen an:

    • Key

      Die Schlüsselnummer.

    • Start

      Startposition des Index im Datensatz.

    • Len

      Länge des Indexbestandteils. Bei gepackten Zahlen sollte dies immer die Gesamtbreite der Spalte sein. Bei Strings hingegen kann der Wert kürzer sein als die volle Breite der indizierten Spalte, weil Sie das Präfix einer String-Spalte indizieren können.

    • Index

      Gibt an, ob ein Schlüsselwert mehrfach im Index enthalten sein kann. Mögliche Werte sind unique (eindeutig) oder multip. (mehrfach).

    • Type

      Gibt den Datentyp an, den dieser Indexbestandteil hat. Dies ist ein MyISAM-Datentyp mit den möglichen Werten packed, stripped oder empty.

    • Root

      Adresse des Stammindexblocks.

    • Blocksize

      Größe jedes Indexblocks. Ist standardmäßig 1024, der Wert kann aber bei der Kompilierung geändert werden, sofern MySQL aus einer Quelldistribution erstellt wird.

    • Rec/key

      Diese ist ein statistischer Wert, der vom Optimierer verwendet wird. Er besagt, wie viele Datensätze pro Wert für diesen Index vorhanden sind. Bei einem eindeutigen Index ist der Wert immer 1. Dies kann aber geändert werden, nachdem eine Tabelle mit myisamchk -a geladen (oder erheblich verändert) wurde. Erfolgt überhaupt keine Änderung, dann wird ein Standardwert von 30 zugewiesen.

    In der in den Beispielen gezeigten Tabelle gibt es zwei table description-Zeilen für den neunten Index. Hierdurch wird signalisiert, dass es sich um einen mehrteiligen Index mit zwei Teilen handelt.

  • Keyblocks used

    Prozentualer Anteil der verwendeten Schlüsselblöcke. Wenn eine Tabelle gerade erst mit myisamchk neu organisiert wurde (wie die Tabelle in den Beispielen), dann sind die Werte sehr hoch und reichen fast an das theoretische Maximum heran.

  • Packed

    MySQL versucht, Schlüsselwerte mit gemeinsamem Suffix zu packen. Dies ist nur bei Indizes für CHAR- und VARCHAR-Spalten möglich. Bei langen indizierten Strings mit ähnlichen führenden Bestandteilen kann dies die Menge des verwendeten Speichers erheblich reduzieren. Im dritten der obigen Beispiele ist der vierte Schlüssel zehn Zeichen lang, und es wird eine Speicherersparnis in Höhe von 60 Prozent erzielt.

  • Max levels

    Tiefe des B-Trees für diesen Schlüssel. Große Tabellen mit langen Schlüsselwerten erhalten hohe Werte.

  • Records

    Anzahl der Datensätze in der Tabelle.

  • M.recordlength

    Durchschnittliche Länge eines Datensatzes. Bei Tabellen mit Datensätzen fester Länge ist dies die exakte Länge des Datensatzes, da alle Datensätze die gleiche Länge haben.

  • Packed

    MySQL schneidet Leerzeichen am Ende von Strings ab. Der Wert Packed gibt den prozentualen Anteil der hierdurch erzielten Einsparungen an.

  • Recordspace used

    Verwendeter Anteil der Datendatei in Prozent.

  • Empty space

    Nicht verwendeter Anteil der Datendatei in Prozent.

  • Blocks/Record

    Durchschnittliche Anzahl der Blöcke je Datensatz (d. h. aus wie vielen Verknüpfungen ein fragmentierter Datensatz besteht). Bei festen Tabellen ist dies immer 1.0. Der Wert sollte möglichst nah an 1,0 herankommen. Wird er zu groß, dann können Sie die Tabelle reorganisieren. Siehe auch Abschnitt 5.10.4.4, „Tabellenoptimierung“.

  • Recordblocks

    Anzahl der verwendeten Blöcke (Verknüpfungen). Bei festen Tabellen ist dieser Wert identisch mit der Anzahl der Datensätze.

  • Deleteblocks

    Anzahl der gelöschten Blöcke (Verknüpfungen).

  • Recorddata

    Anzahl der verwendeten Bytes in der Datendatei.

  • Deleted data

    Anzahl der gelöschten (d. h. nicht verwendeten) Bytes in der Datendatei.

  • Lost space

    Wenn ein Datensatz aktualisiert wird und sich seine Länge verringert, geht Speicherplatz verloren. Dies ist die Summe dieser Verluste in Byte.

  • Linkdata

    Wenn das dynamische Tabellenformat verwendet wird, werden die Datensatzfragmente durch Zeiger miteinander verknüpft. Die Zeiger haben eine Länge zwischen vier und sieben Bytes. Linkdata gibt den gesamten von diesen Zeigern verwendeten Speicherplatz an.

Wurde eine Tabelle mit myisampack komprimiert, dann zeigt myisamchk -d zusätzliche Informationen zu allen Tabellenspalten an. In Abschnitt 8.4, „myisampack — Erzeugung komprimierter, schreibgeschützter MyISAM Tabellen“, finden Sie ein Beispiel für diese Informationen und eine Beschreibung ihrer Bedeutung.

5.10.4.6. Erstellen eines Wartungsplans für Tabellen

Statt abzuwarten, bis Probleme auftreten, bietet es sich an, Tabellen regelmäßig zu überprüfen. Eine Möglichkeit, MyISAM-Tabellen zu überprüfen und zu reparieren, besteht in der Verwendung der Anweisungen CHECK TABLE und REPAIR TABLE. Siehe auch Abschnitt 13.5.2.3, „CHECK TABLE, und Abschnitt 13.5.2.6, „REPAIR TABLE.

Eine weitere Methoden ist die Nutzung von myisamchk. Bei Wartungsproblemen können Sie myisamchk -s verwenden. Mit der Option -s (--silent) läuft myisamchk im stummen Modus, d. h. Meldungen werden nur ausgegeben, wenn Fehler auftreten.

Auch die Aktivierung der automatisierten Überprüfung von MyISAM-Tabellen ist empfehlenswert. Wann immer ein Computer beispielsweise im Verlauf eines Updates einen Neustart durchführt, müssen Sie jede Tabelle, die hiervon betroffen sein könnte, überprüfen, bevor Sie sie weiter verwenden. (Man bezeichnet solche Tabellen auch als „voraussichtlich abgestürzte Tabellen“.) Um MyISAM-Tabellen automatisch zu überprüfen, starten Sie den Server mit der Option --myisam-recover. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

Doch auch im normalen Systembetrieb sollten Sie die Tabellen regelmäßig überprüfen. Bei MySQL AB führen wir einmal wöchentlich einen cron-Job zur Überprüfung wichtiger Tabellen durch, wobei wir eine Zeile ähnlich der folgenden in einer Datei crontab verwenden:

35 0 * * 0 /path/to/myisamchk --fast --silent /path/to/datadir/*/*.MYI

Hierbei werden Informationen zu abgestürzten Tabellen ausgegeben, die wir untersuchen können, um ggf. erforderliche Reparaturen durchzuführen.

Da seit Jahren kein Fall unerwartet abgestürzter Tabellen aufgetreten ist (also Tabellen, die aus anderen Gründen als Problemen mit der Hardware beschädigt wurden), betrachten wir die wöchentliche Überprüfung als ausreichend.

Wir empfehlen, myisamchk -s anfangs in jeder Nacht für alle Tabellen auszuführen, die während der jeweils letzten 24 Stunden aktualisiert wurden, bis Sie MySQL so weit trauen, wie wir es tun.

Normalerweise erfordern MySQL-Tabellen recht wenig Pflege. Wenn Sie MyISAM-Tabellen mit Datensätzen dynamischer Größe (also Tabellen mit VARCHAR-, BLOB- oder TEXT-Spalten) oder Tabellen mit vielen gelöschten Datensätzen haben, dann sollten Sie diese Tabellen von Zeit zu Zeit defragmentieren, d. h. den unbenutzten Speicher wieder zur Benutzung freigeben. Dies können Sie tun, indem Sie die fraglichen Tabellen mit einer OPTIMIZE TABLE-Anweisung verarbeiten. Alternativ können Sie, wenn Sie den mysqld-Server eine Zeitlang anhalten können, in das Datenverzeichnis wechseln und den folgenden Befehl bei angehaltenem Server ausführen:

shell> myisamchk -r -s --sort-index --sort_buffer_size=16M */*.MYI

5.11. Lokalisierung und internationaler Gebrauch von MySQL

Dieser Abschnitt beschreibt, wie Sie den Server für die Verwendung anderer Zeichensätze konfigurieren. Ferner werden wir erläutern, wie Sie die Zeitzone des Servers einstellen und die Unterstützung verbindungsspezifischer Zeitzonen aktivieren.

5.11.1. Der für Daten und zum Sortieren benutzte Zeichensatz

Standardmäßig verwendet MySQL den Zeichensatz latin1 (cp1252 West European) und die Sortierung latin1_swedish_ci, die gemäß den in Schweden und Finnland gültigen Regeln sortiert. Diese Standardeinstellungen sind für die Vereinigten Staaten und die meisten Länder Westeuropas angemessen.

Alle MySQL-Binärdistributionen werden mit der Option --with-extra-charsets=complex kompiliert. Hierdurch wird allen Standardprogrammen ein Code hinzugefügt, der es ihnen gestattet, latin1 und alle Multibyte-Zeichensätze in der Binärdatei zu verarbeiten. Andere Zeichensätze werden bei Bedarf aus einer Zeichensatzdefinitionsdatei geladen.

Der Zeichensatz bestimmt, welche Zeichen in Bezeichnern zulässig sind. Die Sortierung hingegen definiert die Art und Weise, wie Strings von den Klauseln ORDER BY und GROUP BY der SELECT-Anweisung sortiert werden.

Sie können den Standardzeichensatz und die Standardsortierung auf dem Server mit den Optionen --character-set-server bzw. --collation-server beim Serverstart ändern. Die Sortierung muss für den gewählten Standardzeichensatz zulässig sein. (Mit der Anweisung SHOW COLLATION können Sie die für den jeweiligen Zeichensatz zulässige Sortierung ermitteln.) Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

Welche Zeichensätze verfügbar sind, hängt von den Optionen --with-charset=charset_name und --with-extra-charsets=list-of-charsets | complex | all | none des Befehls configure sowie von den in SHAREDIR/charsets/Index gelisteten Zeichensatz-Konfigurationsdateien ab. Siehe auch Abschnitt 2.8.2, „Typische configure-Optionen“.

Wenn Sie den Zeichensatz während der Ausführung von MySQL ändern, kann sich dies auch auf die Sortierreihenfolge auswirken. Das bedeutet, dass Sie myisamchk -r -q --set-collation=collation_name für alle Tabellen ausführen müssen, da andernfalls Ihre Indizes nicht korrekt sortiert sind.

Wenn ein Client eine Verbindung mit einem MySQL-Server herstellt, gibt der Server dem Client seinen Standardzeichensatz an. Der Client schaltet dann für diese Verbindung auf den betreffenden Zeichensatz um.

Sie sollten mysql_real_escape_string() verwenden, wenn Sie Strings für eine SQL-Abfrage kennzeichnen. mysql_real_escape_string() ist identisch mit der alten Funktion mysql_escape_string(), nur nimmt es den MYSQL-Verbindungs-Handle als ersten Parameter entgegen, sodass der korrekte Zeichensatz bei der Kennzeichnung von Zeichen berücksichtigt werden kann.

Wird der Client mit anderen als den Pfaden kompiliert, unter denen der Server installiert ist, und hat der Benutzer, der MySQL konfiguriert hat, nicht alle Zeichensätze in die MySQL-Binärdatei eingefügt, dann müssen Sie dem Client angeben, wo er die zusätzlichen Zeichensätze finden kann, die er braucht, wenn der Server mit einem anderen Zeichensatz ausgeführt wird als der Client.

Dies können Sie durch Angabe der Option --character-sets-dir tun, die den Pfad zu dem Verzeichnis angibt, in dem die dynamischen MySQL-Zeichensätze gespeichert sind. Sie können beispielsweise in einer Optionsdatei folgende Angaben machen:

[client]
character-sets-dir=/usr/local/mysql/share/mysql/charsets

Die Verwendung eines bestimmten Zeichensatzes durch den Client erzwingen Sie wie folgt:

[client]
default-character-set=charset_name

Allerdings ist dies normalerweise nicht erforderlich.

5.11.1.1. Deutscher Zeichensatz

In MySQL 5.1 werden Zeichensatz und Sortierung normalerweise getrennt angegeben. Wenn Sie also die deutsche Sortierreihenfolge verwenden wollen, sollten Sie den Zeichensatz latin1 und die Sortierung latin1_german1_ci oder latin1_german2_ci auswählen. Um den Server beispielsweise mit der Sortierung latin1_german1_ci zu starten, verwenden Sie die Optionen --character-set-server=latin1 und --collation-server=latin1_german1_ci.

Informationen zu den Unterschieden zwischen diesen beiden Sortierungen finden Sie in Abschnitt 10.9.2, „Westeuropäische Zeichensätze“.

5.11.2. Nicht englische Fehlermeldungen

Standardmäßig erzeugt mysqld seine Fehlermeldungen auf Englisch, die Anzeige kann aber auch in den folgenden Sprachen erfolgen: Dänisch, Deutsch, Estnisch, Französisch, Griechisch, Italienisch, Japanisch, Koreanisch, Niederländisch, Norwegisch und Neunorwegisch, Polnisch, Portugiesisch, Rumänisch, Russisch, Schwedisch, Slowakisch, Spanisch, Tschechisch und Ungarisch.

Um in mysqld Fehlermeldungen in einer bestimmten Sprache zu erhalten, starten Sie den Server mit der Option --language bzw. -L. Der Optionswert kann entweder ein Sprachenname oder der vollständige Pfad zu einer Fehlermeldungsdatei sein. Zum Beispiel:

shell> mysqld --language=swedish

Oder:

shell> mysqld --language=/usr/local/share/swedish

Der Sprachname sollte in Kleinbuchstaben angegeben werden.

Standardmäßig befinden sich die Sprachdateien im Unterverzeichnis share/LANGUAGE des MySQL-Basisverzeichnisses.

Sie können den Inhalt der vom Server erzeugten Fehlermeldungen auch ändern. Details hierzu finden Sie im Handbuch MySQL Internals unter http://dev.mysql.com/doc/. Wenn Sie Änderungen an den Fehlermeldungen vorgenommen haben und dann auf eine neuere Version von MySQL aktualisieren, müssen Sie diese Änderungen nach dem Upgrade erneut eintragen.

5.11.3. Einen neuen Zeichensatz hinzufügen

In diesem Abschnitt beschreiben wir den Vorgang des Hinzufügens eines neuen Zeichensatzes zu MySQL. Für die folgende Anleitung benötigen Sie eine MySQL-Quelldistribution. Um die korrekte Vorgehensweise zu bestimmen, ermitteln Sie zunächst, ob der gewünschte Zeichensatz einfach oder komplex ist:

  • Benötigt der Zeichensatz keine speziellen Routinen für die String-Sortierung und keine Multibyteunterstützung, dann handelt es sich um einen einfachen Zeichensatz.

  • Benötigt der Zeichensatz eine dieser Funktionen, dann ist er komplex.

Beispielsweise sind latin1 und danish einfache Zeichensätze, big5 und czech hingegen sind komplexe Zeichensätze.

In der folgenden Anleitung wird der Name des Zeichensatzes als MYSET angegeben.

Bei einem einfachen Zeichensatz verfahren Sie wie folgt:

  1. Fügen Sie MYSET am Ende der Datei sql/share/charsets/Index ein. Weisen Sie ihm eine eindeutige Nummer zu.

  2. Erstellen Sie die Datei sql/share/charsets/MYSET.conf. (Sie können eine Kopie von sql/share/charsets/latin1.conf als Basis für diese Datei verwenden.)

    Die Syntax für diese Datei ist sehr einfach:

    • Kommentare beginnen mit dem Rautenzeichen ‘#’ und erstrecken sich bis zum Ende der Zeile.

    • Wörter werden durch eine beliebige Anzahl von Whitespace-Zeichen voneinander getrennt.

    • Bei der Definition des Zeichensatzes muss jedes Wort eine Zahl im Hexadezimalformat sein.

    • Das Array ctype enthält die ersten 257 Wörter. Die Arrays to_lower[], to_upper[] und sort_order[] nehmen nachfolgend je 256 Wörter entgegen.

    Siehe auch Abschnitt 5.11.4, „Die Zeichendefinitionsarrays“.

  3. Fügen Sie den Namen des Zeichensatzes zu den Listen CHARSETS_AVAILABLE und COMPILED_CHARSETS in der Datei configure.in hinzu.

  4. Führen Sie Konfiguration und Kompilierung aus und testen Sie die Distribution.

Bei einem komplexen Zeichensatz verfahren Sie wie folgt:

  1. Erstellen Sie die Datei strings/ctype-MYSET.c in der MySQL-Quelldistribution.

  2. Fügen Sie MYSET am Ende der Datei sql/share/charsets/Index ein. Weisen Sie ihm eine eindeutige Nummer zu.

  3. Suchen Sie nach vorhandenen ctype-*.c-Dateien (z. B. strings/ctype-big5.c), um den Definitionsbedarf zu ermitteln Beachten Sie, dass die Arrays in Ihrer Datei Namen wie ctype_MYSET, to_lower_MYSET usw. aufweisen müssen. Diese entsprechen den Arrays eines einfachen Zeichensatzes. Siehe auch Abschnitt 5.11.4, „Die Zeichendefinitionsarrays“.

  4. Fügen Sie weit oben in der Datei einen speziellen Kommentar wie den folgenden ein:

    /*
     * This comment is parsed by configure to create ctype.c,
     * so don't change it unless you know what you are doing.
     *
     * .configure. number_MYSET=MYNUMBER
     * .configure. strxfrm_multiply_MYSET=N
     * .configure. mbmaxlen_MYSET=N
     */
    

    Das Programm configure verwendet diesen Kommentar, um den Zeichensatz automatisch in die MySQL-Bibliothek einzufügen.

    Die Zeilen strxfrm_multiply und mbmaxlen werden in den folgenden Abschnitten erläutert. Sie müssen sie nur einfügen, wenn Sie die Funktionen für die String-Sortierung bzw. für Multibytezeichensätze benötigen.

  5. Danach sollten Sie einige der folgenden Funktionen erstellen:

    • my_strncoll_MYSET()

    • my_strcoll_MYSET()

    • my_strxfrm_MYSET()

    • my_like_range_MYSET()

    Siehe auch Abschnitt 5.11.5, „Unterstützung für String-Vergleiche“.

  6. Fügen Sie den Namen des Zeichensatzes zu den Listen CHARSETS_AVAILABLE und COMPILED_CHARSETS in der Datei configure.in hinzu.

  7. Führen Sie Konfiguration und Kompilierung aus und testen Sie die Distribution.

Die Datei sql/share/charsets/README enthält weitere Anweisungen.

Wenn der Zeichensatz in die MySQL-Distribution eingefügt werden soll, schicken Sie einen Patch an die MySQL-Mailingliste internals. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

5.11.4. Die Zeichendefinitionsarrays

to_lower[] und to_upper[] sind einfache Arrays, die die Klein- bzw. Großbuchstaben enthalten, die den einzelnen Mitgliedszeichen des Zeichensatzes entsprechen. Zum Beispiel:

to_lower['A'] should contain 'a'
to_upper['a'] should contain 'A'

sort_order[] bildet die Art und Weise ab, wie Zeichen zu Vergleichs- und Sortierzwecken anzuordnen sind. Recht häufig – aber nicht immer – ist dies identisch mit to_upper[], was bedeutet, dass bei der Sortierung die Groß-/Kleinschreibung unterschieden wird. MySQL sortiert Zeichen basierend auf den Werten von sort_order[]-Elementen. Informationen zu komplexeren Sortierregeln entnehmen Sie der Beschreibung der String-Sortierung in Abschnitt 5.11.5, „Unterstützung für String-Vergleiche“.

ctype[] ist ein Array mit Bitwerten, wobei jeweils ein Element für ein Zeichen vorhanden ist. (Beachten Sie, dass to_lower[], to_upper[] und sort_order[] über den Zeichenwert indiziert werden, ctype[] hingegen über den Zeichenwert + 1. Dies ist eine Altkonvention zur Verarbeitung von EOF.)

In m_ctype.h finden Sie die folgenden Bitmaskendefinitionen:

#define _U      01      /* Uppercase */
#define _L      02      /* Lowercase */
#define _N      04      /* Numeral (digit) */
#define _S      010     /* Spacing character */
#define _P      020     /* Punctuation */
#define _C      040     /* Control character */
#define _B      0100    /* Blank */
#define _X      0200    /* heXadecimal digit */

Der Eintrag ctype[] eines Zeichens sollte die Union der anwendbaren Bitmaskenwerte sein, die das Zeichen beschreiben. Beispielsweise ist 'A' sowohl ein Großbuchstabe (_U) als auch eine Hexadezimalziffer (_X), d. h. ctype['A'+1] sollte folgenden Wert enthalten:

_U + _X = 01 + 0200 = 0201

5.11.5. Unterstützung für String-Vergleiche

Wenn die Sortierregeln Ihrer Sprache zu komplex sind, um mit der einfachen sort_order[]-Tabelle verarbeitet zu werden, dann müssen Sie die String-Sortierfunktionen verwenden.

Die beste Dokumentation hierfür sind die vorhandenen Zeichensätze. Sehen Sie sich beispielsweise die Zeichensätze big5, czech, gbk, sjis und tis160 einmal an.

Sie müssen den Wert strxfrm_multiply_MYSET=N in dem speziellen Kommentar oben in der Datei angeben. N sollte dabei auf das maximale Verhältnis gesetzt werden, auf das die Strings bei my_strxfrm_MYSET anwachsen dürfen (es muss sich dabei um einen positiven Integer handeln).

5.11.6. Unterstützung für Multi-Byte-Zeichen

Wenn Sie Unterstützung für einen neuen Zeichensatz hinzufügen wollen, der Multibytezeichen enthält, dann müssen Sie die Multibytezeichenfunktionen verwenden.

Die beste Dokumentation hierfür sind die vorhandenen Zeichensätze. Sehen Sie sich beispielsweise die Zeichensätze euc_kr, gb2312, gbk, sjis und ujis einmal an. Diese sind in den ctype-charset_name.c-Dateien im Verzeichnis strings implementiert.

Sie müssen den Wert mbmaxlen_MYSET=N in dem speziellen Kommentar oben in der Quelldatei angeben. N sollte auf die Größe (in Byte) des größten Zeichens im Zeichensatz gesetzt werden.

5.11.7. Probleme mit Zeichensätzen

Wenn Sie einen Zeichensatz verwenden wollen, der nicht in Ihre Binärdatei einkompiliert ist, können die folgenden Probleme auftreten:

  • Ihr Programm verwendet einen falschen Pfad für die Speicherposition der Zeichensätze (Vorgabe ist /usr/local/mysql/share/mysql/charsets). Dies kann mit der Option --character-sets-dir behoben werden, wenn Sie das fragliche Programm ausführen.

  • Der Zeichensatz ist ein Multibytezeichensatz, der nicht dynamisch geladen werden kann. In diesem Fall müssen Sie das Programm mit Unterstützung für den Zeichensatz neu kompilieren.

  • Der Zeichensatz ist ein dynamischer Zeichensatz, aber Sie haben keine Konfigurationsdatei für ihn. In diesem Fall sollten Sie die Konfigurationsdatei für den Zeichensatz aus einer neuen MySQL-Distribution installieren.

  • Wenn Ihre Datei Index den Namen für diesen Zeichensatz nicht enthält, zeigt Ihr Programm die folgende Fehlermeldung an:

    ERROR 1105: File '/usr/local/share/mysql/charsets/?.conf'
    not found (Errcode: 2)
    

    In diesem Fall sollten Sie sich entweder eine neue Datei Index beschaffen oder die Namen fehlender Zeichensätze manuell in die aktuelle Datei eintragen.

Bei MyISAM-Tabellen können Sie Name und Nummer des Zeichensatzes für eine Tabelle mit myisamchk -dvv tbl_name überprüfen.

5.11.8. Zeitzonen-Unterstützung des MySQL-Servers

Beim MySQL-Server gibt es mehrere verschiedene Zeitzoneneinstellungen:

  • Die Systemzeitzone. Wenn der Server startet, versucht er die Zeitzone des Hostcomputers zu ermitteln und weist diesen Wert dann der Systemvariable system_time_zone zu. Der Wert wird nachfolgend nicht mehr geändert.

  • Die aktuelle Zeitzone des Servers. Die globale Systemvariable time_zone gibt die Zeitzone an, in der der Server derzeit läuft. Der Startwert für time_zone ist 'SYSTEM', d. h. die Serverzeitzone ist mit der Systemzeitzone identisch. Der Ausgangswert lässt sich mit der Option --default-time-zone=timezone auch ausdrücklich festlegen. Wenn Sie die Berechtigung SUPER haben, können Sie den globalen Wert mit folgender Anweisung zur Laufzeit ändern:

    mysql> SET GLOBAL time_zone = timezone;
    
  • Verbindungsspezifische Zeitzonen. Jeder Client, der eine Verbindung herstellt, hat eine eigene Zeitzoneneinstellung, die von der Sitzungsvariablen time_zone vorgegeben wird. Standardmäßig erhält die Sitzungsvariable den Wert von der globalen Variable time_zone, der Client kann seine Zeitzone aber mit folgender Anweisung ändern:

    mysql> SET time_zone = timezone;
    

Die aktuellen Werte der globalen und der clientspezifischen Zeitzone lassen sich wie folgt abrufen:

mysql> SELECT @@global.time_zone, @@session.time_zone;

timezone-Werte können als Strings angegeben werden, die einen Offset zur UTC angeben (z. B. '+10:00' oder '-6:00'). Wenn die Zeitzonen-Informationstabellen in der mysql-Datenbank erstellt und ausgefüllt wurden, können Sie auch benannte Zeitzonen wie etwa 'Europe/Helsinki', 'US/Eastern' oder 'MET' verwenden. Mit dem Wert 'SYSTEM' kann angegeben werden, dass die Zeitzone denselben Wert haben sollte wie die Systemzeitzone. Bei den Zeitzonennamen wird die Groß-/Kleinschreibung nicht unterschieden.

Der MySQL-Installationsvorgang erzeugt Zeitzonentabellen in der mysql-Datenbank, lädt diese aber nicht. Dies müssen Sie manuell tun. (Wenn Sie von einer früheren Version auf MySQL 4.1.3 oder höher aktualisieren, sollten Sie die Tabellen erstellen, indem Sie ein Upgrade Ihrer mysql-Datenbank durchführen. Verwenden Sie hierzu die Anleitung in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.)

Wenn Ihr System eine eigene zoneinfo-Datenbank hat (dies ist ein Satz von Dateien, die die Zeitzonen beschreiben), dann sollten Sie das Programm mysql_tzinfo_to_sql zum Ausfüllen der Zeitzonentabellen verwenden. Beispiele für solche Systeme sind Linux, FreeBSD, Sun Solaris und Mac OS X. Eine wahrscheinliche Position für diese Dateien ist das Verzeichnis /usr/share/zoneinfo. Verfügt Ihr System nicht über eine zoneinfo-Datenbank, dann können Sie das im weiteren Verlauf dieses Abschnitts genannte Paket herunterladen und verwenden.

Das Programm mysql_tzinfo_to_sql wird zum Laden der Zeitzonentabellen verwendet. Auf der Befehlszeile übergeben Sie den Pfadnamen des zoneinfo-Verzeichnisses an mysql_tzinfo_to_sql und leiten die Ausgabe in das Programm mysql. Zum Beispiel:

shell> mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

mysql_tzinfo_to_sql liest die Zeitzonendateien Ihres Systems aus und erzeugt daraus SQL-Anweisungen. mysql verarbeitet diese Anweisungen, um die Zeitzonentabellen zu laden.

mysql_tzinfo_to_sql kann auch zum Laden einer einzelnen Zeitzonendatei und zur Erzeugung von Schaltsekunden verwendet werden:

  • Um eine einzelne Zeitzonendatei tz_file zu laden, die einem Zeitzonennamen tz_name entspricht, rufen Sie mysql_tzinfo_to_sql wie folgt auf:

    shell> mysql_tzinfo_to_sql tz_file tz_name | mysql -u root mysql
    
  • Wenn Ihre Zeitzone Schaltsekunden berücksichtigen muss, initialisieren Sie die Schaltsekundeninformation wie folgt (hierbei ist tz_file der Name der Zeitzonendatei):

    shell> mysql_tzinfo_to_sql --leap tz_file | mysql -u root mysql
    

Verfügt Ihr System über keine zoneinfo-Datenbank (dies gilt beispielsweise für Windows oder HP-UX), dann können Sie das Paket mit den vorerstellten Zeitzonentabellen verwenden, welches unter http://dev.mysql.com/downloads/timezones.html heruntergeladen werden kann. Dieses Paket enthält .frm-, .MYD- und .MYI-Dateien für die MyISAM-Zeitzonentabellen. Diese Tabellen sollten Teil der mysql-Datenbank sein, d. h. Sie sollten Sie Dateien im Unterverzeichnis mysql des Datenverzeichnisses Ihres MySQL-Servers ablegen. Währenddessen sollte der Server beendet sein.

Warnung: Verwenden Sie das herunterzuladende Paket nicht, wenn Ihr System über eine zoneinfo-Datenbank verfügt. Benutzen Sie stattdessen das Hilfsprogramm mysql_tzinfo_to_sql. Andernfalls kann es zu Diskrepanzen in der Verarbeitung von Datum und Uhrzeit zwischen MySQL und anderen Anwendungen auf Ihrem System kommen.

Informationen zu Zeitzoneneinstellungen in der Replikationskonfiguration finden Sie in Abschnitt 6.8, „Replikation: Features und bekannte Probleme“.

5.12. Die MySQL-Logdateien

MySQL schreibt mehrere verschiedene Logdateien, mit deren Hilfe Sie ermitteln können, was in mysqld abläuft:

LogdateiGeloggte Informationen
FehlerlogProbleme beim Starten, Ausführen oder Beenden von mysqld
Abfrageloghergestellte Clientverbindungen, ausgeführte Anweisungen
Binärlogalle datenändernden Anweisungen (wird auch zur Replikation verwendet)
Logdatei für langsame AbfragenAbfragen, die länger als in long_query_time (in Sekunden) angegeben zur Ausführung benötigen oder keine Indizes verwendet haben

Standardmäßig werden alle Logdateien im Datenverzeichnis mysqld erstellt. Sie können das Schließen und Neuöffnen der Logdateien (in manchen Fällen auch das Wechseln zu einer neuen Logdatei) erzwingen, indem Sie die Logdateien auf die Festplatte schreiben. Das Schreiben der Logdateien auf Festplatte erfolgt, wenn Sie eine FLUSH LOGS-Anweisung absetzen oder mysqladmin flush-logs oder mysqladmin refresh ausführen. Siehe auch Abschnitt 13.5.5.2, „FLUSH.

Wenn Sie die Replikationsfunktionen von MySQL verwenden, erstellen die Slave-Replikationsserver weitere Logdateien, die Relay-Logs heißen. Diese werden in Kapitel 6, Replikation bei MySQL, beschrieben.

5.12.1. Die Fehler-Logdatei

Die Fehlerlogdatei enthält Informationen, die angeben, wann mysqld gestartet und beendet wurde und welche kritischen Fehler während der Laufzeit des Servers ggf. aufgetreten sind. Wenn mysqld feststellt, dass eine Tabelle automatisch überprüft oder repariert werden muss, dann schreibt es eine Meldung in das Fehlerlog.

Bei einigen Betriebssystemen enthält das Fehlerlog einen Stapel-Trace, wenn mysqld abstürzt. Mit dem Trace kann bestimmt werden, wo mysqld abgestürzt ist. Siehe auch Abschnitt E.1.4, „Einen Stack-Trace benutzen“.

Wenn mysqld unerwartet abstürzt und mysqld_safe den Server neu starten muss, schreibt mysqld_safe die Meldung restarted mysqld in das Fehlerlog.

Mit der Option --log-error[=file_name] können Sie angeben, wo mysqld das Fehlerlog speichern soll. Wird für file_name kein Wert angegeben, dann verwendet mysqld den Namen host_name.err und schreibt die Datei in das Datenverzeichnis. Wenn Sie FLUSH LOGS ausführen, wird das Fehlerlog durch Ergänzung des Suffixes -old umbenannt, und mysqld erzeugt eine neue leere Logdatei. (Wenn die Option --log-error nicht angegeben wird, erfolgt keine Umbenennung.)

Wenn Sie --log-error nicht angeben oder (unter Windows) die Option --console verwenden, werden Fehler in stderr (Standardfehlerausgabe) geschrieben. Normalerweise ist dies Ihr Terminal.

Unter Windows wird die Fehlerausgabe in die .err-Datei geschrieben, sofern --console nicht angegeben ist.

5.12.2. Die allgemeine Anfragen-Logdatei

Wenn Sie wissen wollen, was bei mysqld intern vor sich geht, sollten Sie es mit der Option --log[=file_name] oder -l [file_name] starten. Wird keine Wert file_name angegeben, dann lautet der Vorgabename host_name.log. Aufgezeichnet werden alle Verbindungen und Anweisungen. Dieses Log kann sehr praktisch sein, wenn Sie einen Fehler bei einem Client vermuten und genau wissen wollen, was dieser Client an mysqld gesendet hat.

mysqld schreibt die Anweisungen in der Reihenfolge in das Abfragelog, in der sie empfangen werden. Diese Reihenfolge kann sich von der Ausführungsreihenfolge unterscheiden. Dies steht im Gegensatz zum Binärlog, bei dem Anweisungen nach ihrer Ausführung, aber vor dem Aufheben von Sperren geschrieben werden. (Außerdem enthält das Abfragelog alle Anweisungen, wogegen das Binärlog keine Anweisungen enthält, die nur Daten auswählen.)

Bei Serverneustarts und beim Schreiben des Logs auf Festplatte wird keine neue allgemeine Abfragelogdatei erstellt (auch wenn sie beim Schreiben auf Festplatte geschlossen und neu geöffnet wird). Unter Unix können Sie die Datei mit den folgenden Befehlen umbenennen und eine neue Datei erstellen:

shell> mv host_name.log host_name-old.log
shell> mysqladmin flush-logs
shell> cp host_name-old.log backup-directory
shell> rm host_name-old.log

Unter Windows können Sie die Logdatei nicht umbenennen, solange sie vom Server geöffnet ist. Sie müssen zunächst den Server beenden, die Datei umbenennen und den Server dann neu starten, um eine neue Logdatei zu erstellen.

5.12.3. Die binäre Update-Logdatei

Das Binärlog enthält alle Anweisungen, die Daten aktualisieren oder hätten aktualisieren können (beispielsweise eine DELETE-Anweisung ohne zutreffenden Datensatz). Die Anweisungen werden in Form von „Ereignissen“ gespeichert, die die Änderungen beschreiben. Ferner enthält das Binärlog auch Informationen dazu, wie lange die Ausführung datenverändernder Anweisungen jeweils gedauert hat.

Hinweis: Das Binärlog hat beginnend mit MySQL 5.0 das alte Update-Log ersetzt, welches nun nicht mehr vorhanden ist. Das Binärlog enthält alle Informationen, die bereits im Update-Log vorhanden waren, in einem effizienteren Format und ist zudem transaktionssicher. Wenn Sie Transaktionen verwenden, müssen Sie für Backups das MySQL-Binärlog statt des alten Update-Logs verwenden.

Das Binärlog enthält keine Anweisungen, die keine Daten ändern. Wenn Sie alle Anweisungen aufzeichnen wollen (um etwa eine problematische Abfrage zu ermitteln), dann verwenden Sie das allgemeine Abfragelog. Siehe auch Abschnitt 5.12.2, „Die allgemeine Anfragen-Logdatei“.

Der primäre Zweck des Binärlogs besteht darin, eine möglichst vollständige Aktualisierung von Datenbanken im Zuge eines Wiederherstellungsvorgangs zu ermöglichen, denn das Binärlog enthält alle Updates, die nach Erstellung einer Sicherung erfolgten. Außerdem wird das Binärlog auf Master-Replikationsservern zur Aufzeichnung von Anweisungen verwendet, die an Slave-Server gesendet werden. Siehe auch Kapitel 6, Replikation bei MySQL.

Die Ausführung des Servers mit aktiviertem Binärlog verringert die Leistungsfähigkeit um ca. 1 Prozent. Die vom Binärlog in Zusammenhang mit der Datenwiederherstellung und der Replikationskonfiguration gebotenen Vorteile machen diese vernachlässigbare Leistungseinbuße jedoch mehr als wett.

Wenn mysqld mit der Option --log-bin[=base_name] gestartet wird, schreibt es eine Logdatei mit allen SQL-Befehlen, die Daten aktualisieren. Wird kein base_name-Wert angegeben, dann wird als Name der Datei standardmäßig der Name des Hostcomputers gefolgt von -bin gewählt. Wenn der Basisname angegeben wird, jedoch nicht als absoluter Pfadname, dann schreibt der Server die Datei in das Datenverzeichnis. Die Angabe eines Basisnamens wird empfohlen (siehe Abschnitt A.8.1, „Offene Probleme in MySQL“ zu den Gründen).

Wenn Sie eine Erweiterung im Lognamen angeben (z. B. --log-bin=base_name.extension), dann wird diese stillschweigend entfernt und ignoriert.

mysqld hängt eine numerische Erweiterung an den Basisnamen des Binärlogs an. Diese Zahl wird jedes Mal erhöht, wenn der Server eine neue Logdatei erstellt. Hierdurch entsteht eine geordnete Abfolge von Dateien. Der Server erstellt bei jedem Neustart und beim Schreiben der Logs jedes Mal eine neue Logdatei. Ferner wird ein neues Binärlog automatisch erstellt, wenn die Größe der aktuellen Logdatei den Wert max_binlog_size erreicht. Ein Binärlog kann, wenn Sie große Transaktionen verwenden, unter Umständen auch größer werden als durch max_binlog_size angegeben. Das liegt daran, dass eine Transaktion vollständig in eine Datei geschrieben und niemals auf mehrere Dateien verteilt wird.

Um im Überblick zu behalten, welche Binärlogdateien bereits verwendet wurden, erstellt mysqld außerdem eine Indexdatei, die die Namen aller verwendeten Binärlogdateien enthält. Standardmäßig hat diese denselben Basisnamen wie die Binärlogdatei zuzüglich der Erweiterung '.index'. Sie können den Namen der Indexdatei für Binärlogs mit der Option --log-bin-index[=file_name] ändern. Solange mysqld ausgeführt wird, sollten Sie diese Datei nicht manuell bearbeiten, da dies mysqld durcheinander bringen könnte.

Schreibvorgänge in die Binärlogdatei und die Indexdatei für Binärlogs werden auf identische Weise verarbeitet, nämlich als Schreiboperationen in MyISAM-Tabellen. Siehe auch Abschnitt A.4.3, „Wie MySQL mit vollen Festplatten umgeht“.

Mit der Anweisung RESET MASTER können Sie alle Binärlogdateien löschen, mit der Anweisung PURGE MASTER LOGS einen Teil davon. Siehe auch Abschnitt 13.5.5.5, „RESET, und Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“.

Das Binärlogformat hat einige bekannte Beschränkungen, die sich auf die Wiederherstellung aus Backups auswirken können. Siehe auch Abschnitt 6.8, „Replikation: Features und bekannte Probleme“.

Das binäre Loggen für gespeicherte Routinen und Trigger erfolgt wie in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“, beschrieben.

Sie können die folgenden Optionen für mysqld verwenden, um zu beeinflussen, was in der Binärlogdatei aufgezeichnet wird. Beachten Sie auch die auf die Liste folgenden Erläuterungen.

Wenn Sie die Replikation verwenden, beeinflussen die hier beschriebenen Optionen, welche Anweisungen vom Master-Server an die Slaves gesendet werden. Es gibt auch Optionen für Slave-Server, mit denen gesteuert wird, welche vom Master empfangenen Anweisungen ausgeführt und welche ignoriert werden. Detaillierte Informationen finden Sie in Abschnitt 6.9, „Replikationsoptionen in my.cnf“.

  • --binlog-do-db=db_name

    Weist den Server an, das binäre Loggen auf Updates zu beschränken, für die die Standarddatenbank db_name heißt (d. h. die mit USE gewählte Datenbank). Alle anderen nicht ausdrücklich erwähnten Datenbanken werden ignoriert. Wenn Sie diese Option verwenden, sollten Sie sicherstellen, dass Sie Aktualisierungen nur in der Standarddatenbank durchführen.

    Hierzu gibt es eine Ausnahme für die Anweisungen CREATE DATABASE, ALTER DATABASE und DROP DATABASE. Der Server entscheidet auf der Basis der in der Anweisung genannten Datenbank (nicht der Standarddatenbank), ob die Anweisungen protokolliert werden sollen oder nicht.

    Hier ein Beispiel für etwas, das nicht so funktioniert, wie Sie es vielleicht erwarten: Wenn der Server mit binlog-do-db=sales gestartet wird und Sie USE prices; UPDATE sales.january SET amount=amount+1000; ausführen, wird diese Anweisung nicht in das Binärlog geschrieben.

    Um mehrere Datenbanken zu loggen, verwenden Sie mehrere Optionen, wobei die Option einmal für jede Datenbank angegeben werden muss.

  • --binlog-ignore-db=db_name

    Weist den Server an, das binäre Loggen von Updates zu unterdrücken, für die die Standarddatenbank db_name heißt (d. h. die mit USE gewählte Datenbank). Wenn Sie diese Option verwenden, sollten Sie sicherstellen, dass Sie Aktualisierungen nur in der Standarddatenbank durchführen.

    Wie bei der Option --binlog-do-db gibt es auch hier eine Ausnahme für die Anweisungen CREATE DATABASE, ALTER DATABASE und DROP DATABASE. Der Server entscheidet auf der Basis der in der Anweisung genannten Datenbank (nicht der Standarddatenbank), ob die Anweisungen protokolliert werden sollen oder nicht.

    Hier ein Beispiel für etwas, das nicht so funktioniert, wie Sie es vielleicht erwarten: Wenn der Server mit binlog-ignore-db=sales gestartet wird und Sie USE prices; UPDATE sales.january SET amount=amount+1000; ausführen, wird diese Anweisung in das Binärlog geschrieben.

    Um mehrere Datenbanken zu ignorieren, verwenden Sie mehrere Optionen, wobei die Option einmal für jede Datenbank angegeben werden muss.

Der Server wertet die Optionen zum Loggen von Updates im Binärlog oder zum Ignorieren der Updates entsprechend den folgenden Regeln aus. Wie bereits erwähnt, gibt es eine Ausnahme für die Anweisungen CREATE DATABASE, ALTER DATABASE und DROP DATABASE. In solchen Fällen ersetzt die Datenbank, die erstellt, geändert oder gelöscht wird, in den folgenden Regeln die Standarddatenbank.

  1. Sind --binlog-do-db- oder --binlog-ignore-db-Regeln vorhanden?

    • Nein: Anweisung in Binärlog schreiben und beenden.

    • Ja: Mit nächstem Schritt fortfahren.

  2. Es sind Regeln vorhanden (--binlog-do-db, --binlog-ignore-db oder beide). Gibt es eine Standarddatenbank (d. h. wurde eine Datenbank mit USE ausgewählt)?

    • Nein: Anweisung nicht schreiben, sondern beenden.

    • Ja: Mit nächstem Schritt fortfahren.

  3. Es gibt eine Standarddatenbank. Gibt es --binlog-do-db-Regeln?

    • Ja: Liegt eine Übereinstimmung der Standarddatenbank mit einer der --binlog-do-db-Regeln vor?

      • Ja: Anweisung schreiben und beenden.

      • Nein: Anweisung nicht schreiben, sondern beenden.

    • Nein: Mit nächstem Schritt fortfahren.

  4. Es gibt --binlog-ignore-db-Regeln. Liegt eine Übereinstimmung der Standarddatenbank mit einer der --binlog-ignore-db-Regeln vor?

    • Ja: Anweisung nicht schreiben, sondern beenden.

    • Nein: Abfrage schreiben und beenden.

So schreibt beispielsweise ein Slave, der nur mit --binlog-do-db=sales ausgeführt wird, keine Anweisungen in das Binärlog, bei der sich die Standarddatenbank von sales unterscheidet (anders gesagt kann --binlog-do-db auch manchmal „andere Datenbanken ignorieren“ bedeuten).

Wenn Sie die Replikation verwenden, sollten Sie alte Binärlogdateien erst dann löschen, wenn Sie ganz sicher sind, dass kein Slave sie mehr benötigt. Laufen Ihre Slaves also etwa nie länger als drei Tage am Stück, dann können Sie einmal täglich mysqladmin flush-logs auf dem Master ausführen und dann alle Logs entfernen, die älter als drei Tage sind. Sie können die Dateien dabei zwar manuell entfernen, aber die Verwendung von PURGE MASTER LOGS ist vorzuziehen, weil diese Anweisung gleichzeitig auch die Indexdatei für die Binärlogs sicher aktualisiert (und weil sie auch ein Datumsargument entgegennehmen kann). Siehe auch Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“.

Ein Client, der die Berechtigung SUPER hat, kann das binäre Loggen seiner eigenen Anweisungen mithilfe einer SET SQL_LOG_BIN=0-Anweisung deaktivieren. Siehe auch Abschnitt 13.5.3, „SET.

Sie können den Inhalt von Binärlogdateien mit dem Hilfsprogramm mysqlbinlog anzeigen. Die kann praktisch sein, wenn Sie die Anweisungen im Log neu verarbeiten wollen. So können Sie einen MySQL-Server beispielsweise aus dem Binärlog heraus wie folgt aktualisieren:

shell> mysqlbinlog log_file | mysql -h server_name

Weitere Informationen zum Hilfsprogramm mysqlbinlog und seiner Verwendung finden Sie in Abschnitt 8.8, „mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien“. mysqlbinlog kann auch mit Relay-Logs verwendet werden, da diese im selben Format wie Binärlogdateien geschrieben sind.

Das binäre Loggen erfolgt unmittelbar nach Abschluss einer Anweisung, aber vor dem Aufheben ggf. vorhandener Sperren und dem Schreiben in die Datenbank. Auf diese Weise ist sichergestellt, dass die Anweisungen in der Reihenfolge ihrer Ausführung geloggt werden.

Aktualisierungen nicht transaktionssicherer Tabellen werden im Binärlog unmittelbar nach ihrer Ausführung gespeichert. Im Verlauf einer noch nicht geschriebenen Transaktion werden alle Änderungen (UPDATE, DELETE oder INSERT), die transaktionssichere Tabellen wie etwa BDB- oder InnoDB-Tabellen betreffen, zwischengespeichert, bis vom Server eine COMMIT-Anweisung empfangen wird. Dann schreibt mysqld die gesamte Transaktion in das Binärlog, bevor die COMMIT-Anweisung ausgeführt wird. Wenn der Thread, der die Transaktion verarbeitet, startet, reserviert er zur Zwischenspeicherung von Anweisungen einen Puffer der mit binlog_cache_size angegebenen Größe. Ist eine Anweisung größer, dann öffnet der Thread eine Temporärdatei, um die Transaktion zu speichern. Endet der Thread, dann wird auch die Temporärdatei wieder gelöscht.

Für Modifikationen an nicht transaktionssicheren Tabellen kann kein Rollback durchgeführt werden. Wenn eine Transaktion, für die ein Rollback erfolgt, Änderungen an nicht transaktionssicheren Tabellen enthält, dann wird die gesamte Transaktionen am Ende mit einer ROLLBACK-Anweisung geloggt, um sicherzustellen, dass die Modifikationen an diesen Tabellen repliziert werden.

Die Statusvariable Binlog_cache_use zeigt die Anzahl der Transaktionen an, die diesen Puffer (und möglicherweise auch eine Temporärdatei) zur Speicherung von Anweisungen verwendet haben. Die Statusvariable Binlog_cache_disk_use gibt an, wie viele dieser Transaktionen tatsächlich eine Temporärdatei erstellen mussten. Mithilfe dieser beiden Variablen kann die Größe von binlog_cache_size optimiert werden: Wählen Sie einen ausreichend hohen Wert, damit die Verwendung von Temporärdateien möglichst vermieden wird.

Die Systemvariable max_binlog_cache_size kann benutzt werden, um die Gesamtspeicherkapazität zu begrenzen, die zur Zwischenspeicherung einer Transaktion mit mehreren Anweisungen verwendet wird (Standardwert: 4 Gbyte). Ist eine Transaktion größer als dieser Wert, dann schlägt sie fehl, und es wird ein Rollback durchgeführt.

Wenn Sie das Binärlog verwenden, werden nebenläufige in normale Einfügeoperationen für die Anweisungen CREATE ... SELECT oder INSERT ... SELECT umgewandelt. Hierdurch wird gewährleistet, dass Sie eine exakte Kopie Ihrer Tabellen neu erstellen können, indem Sie das Log während eines Sicherungsvorgangs anwenden.

Beachten Sie, dass sich das Binärlogformat in MySQL 5.1 von dem in vorherigen MySQL-Versionen unterscheidet. Grund hierfür sind Erweiterungen bei der Replikation. Siehe auch Abschnitt 6.6, „Replikation: Kompatibilität zwischen MySQL-Versionen“.

Standardmäßig wird das Binärlog nicht bei jeder Schreiboperation auf Festplatte synchronisiert. Wenn also das Betriebssystem oder der Computer selbst (d. h. nicht nur der MySQL-Server) abstürzen, dann sind die letzten Änderungen im Binärlog unter Umständen verloren gegangen. Um dies zu verhindern, können Sie mithilfe der Systemvariablen sync_binlog die Synchronisierung des Binärlogs nach jeder N-Schreiboperation erzwingen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“. Der sicherste – aber auch langsamste – Wert für sync_binlog ist 1. Aber auch dann, wenn sync_binlog auf 1 steht, besteht die Möglichkeit von Inkonsistenzen zwischen dem Tabelleninhalt und dem Inhalt des Binärlogs im Falle eines Absturzes. Wenn Sie beispielsweise InnoDB-Tabellen benutzen und der MySQL-Server eine COMMIT-Anweisung verarbeitet, dann schreibt er die gesamte Transaktion in das Binärlog und übergibt sie dann an InnoDB. Stürzt der Server zwischen diesen beiden Vorgängen ab, dann erfolgt beim Neustart ein Rollback der Transaktion durch InnoDB; sie ist aber weiterhin im Binärlog vorhanden. Dieses Problem lässt sich mit der Option --innodb-safe-binlog beheben, die die Konsistenz zwischen InnoDB-Tabellen und dem Binärlog herstellt. (Hinweis: --innodb-safe-binlog wird ab MySQL 5.0 nicht mehr benötigt, weil die XA-Transaktionsunterstützung implementiert wurde.)

Damit diese Option ein höheres Maß an Sicherheit gewähren kann, sollte der MySQL-Server auch so konfiguriert werden, dass das Binär- und die InnoDB-Logs bei jeder Transaktion synchronisiert werden. Die InnoDB-Logs werden standardmäßig synchronisiert, und das Binärlog kann mit der Option sync_binlog=1 synchronisiert werden. Diese Option bewirkt, dass der MySQL-Server nach einem Absturz und dem beim folgenden Neustart ausgeführten Rollback die betreffenden Transaktionen aus dem Binärlog ausschneidet. Hierdurch ist sichergestellt, dass das Binärlog die exakten Daten der InnoDB-Tabellen widerspiegelt und der Slave insofern immer synchron zum Master bleibt (d. h. keine Anweisung empfängt, für die ein Rollback durchgeführt wurde).

Beachten Sie, dass die Option --innodb-safe-binlog auch dann verwendet werden kann, wenn der MySQL-Server andere Speicher-Engines als InnoDB aktualisiert. Aus dem Binärlog entfernt werden durch die Wiederherstellungsfunktionen von InnoDB nur Anweisungen und Transaktionen, die InnoDB-Tabellen betreffen. Wenn der MySQL-Server bei der Wiederherstellung nach einem Absturz feststellt, dass das Binärlog kürzer als erwartet ist, dann fehlt ihm mindestens eine erfolgreich übermittelte InnoDB-Transaktion. Dies sollte normalerweise nicht passieren, wenn die Synchronisierung gezielt über sync_binlog=1 und das Festplatten-/Dateisystem geregelt wurde (was nicht immer klappt); der Server gibt also die Fehlermeldung The binary log <name> is shorter than its expected size. aus. In diesem Fall ist das Binärlog nicht korrekt, und die Replikation sollte mit einem neuen Schnappschuss der Master-Daten neu gestartet werden.

5.12.4. Die Logdatei für langsame Anfragen

Wenn mysqld mit der Option --log-slow-queries[=file_name] gestartet wird, schreibt es eine Logdatei mit allen SQL-Befehlen, deren Ausführung länger gedauert hat als durch long_query_time (in Sekunden) angegeben. Die Zeit zum Erwirken der ersten Tabellensperren wird dabei nicht als Ausführungszeit berücksichtigt. Der Mindestwert von long_query_time ist 1.

Wird kein file_name-Wert angegeben, dann wird als Name der Datei standardmäßig der Name des Hostcomputers gefolgt von -slow.log gewählt. Wenn ein Dateiname zwar angegeben ist, jedoch nicht als absoluter Pfadname, dann schreibt der Server die Datei in das Datenverzeichnis.

Eine Anweisung wird in das Log für langsame Abfragen geschrieben, nachdem sie abgeschlossen wurde und alle Sperren aufgehoben wurden. Die Reihenfolge, in der die Anweisungen ins Log geschrieben werden, kann sich mithin von der Ausführungsreihenfolge unterscheiden.

Das Log für langsame Abfragen kann zum Ermitteln von Abfragen verwendet werden, deren Ausführung sehr lange dauert und die deswegen für Optimierungen prädestiniert sind. Allerdings kann die Überprüfung dieses Logs eine recht schwierige Aufgabe sein. Um sie zu vereinfachen, können Sie das Log für langsame Abfragen mit dem Befehl mysqldumpslow verarbeiten, um Abfragen zusammenzufassen, die im Log erscheinen.

Bei MySQL 5.1 werden langsame Abfragen, die keine Indizes verwenden, ebenso im Log aufgezeichnet wie solche, die Indizes benutzen. Um zu verhindern, dass Abfragen ohne Indizes in das Log geschrieben werden, verwenden Sie die Option --log-queries-not-using-indexes. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

Bei MySQL 5.1 können Sie mit der Serveroption --log-slow-admin-statements festlegen, dass langsame administrative Anweisungen wie OPTIMIZE TABLE, ANALYZE TABLE und ALTER TABLE ebenfalls in das Log für langsame Abfragen geschrieben werden.

Abfragen, die vom Abfrage-Cache verarbeitet werden, werden im Log für langsame Abfragen nicht aufgezeichnet. Gleiches gilt für Abfragen, die vom Vorhandensein eines Index nicht profitieren würden, da die Tabellen keinen oder nur einen Datensatz umfasst.

5.12.5. Wartung und Pflege der Logdateien

MySQL Server erstellt eine Reihe verschiedener Logdateien, mit denen Sie ganz einfach feststellen können, was vor sich geht. Siehe auch Abschnitt 5.12, „Die MySQL-Logdateien“. Allerdings müssen Sie diese Dateien regelmäßig bereinigen, damit sichergestellt ist, dass die Logs nicht zu viel Festplattenspeicher belegen.

Wenn Sie MySQL mit aktiviertem Loggen verwenden, dann sollten Sie alte Logdateien von Zeit zu Zeit sichern und entfernen und MySQL anweisen, neue Logdateien zu erstellen. Siehe auch Abschnitt 5.10.1, „Datenbank-Datensicherungen“.

Auf einer Linux-Installation (Red Hat) können Sie hierfür das Skript mysql-log-rotate verwenden. Wenn Sie MySQL aus einer RPM-Distribution installiert haben, sollte dieses Skript automatisch installiert worden sein. Allerdings sollten Sie mit dem Skript vorsichtig umgehen, wenn Sie das Binärlog zur Replikation verwenden. Entfernen Sie Binärlogs erst, wenn Sie sicher sind, dass die Inhalte von allen Slaves verarbeitet wurden.

Auf anderen Systemen müssen Sie selbst ein kurzes Skript installieren, welches Sie über cron (oder ein passendes Gegenstück) starten, um Logdateien zu verarbeiten.

Sie können die Einrichtung und Verwendung neuer Logdateien in MySQL mit mysqladmin flush-logs oder der SQL-Anweisung FLUSH LOGS erzwingen.

Beim Schreiben einer Logdatei auf die Festplatte geschieht folgendes:

  • Wenn das Loggen allgemeiner Abfragen (--log) oder langsamer Abfragen (--log-slow-queries) verwendet wird, schließt der Server die entsprechende Logdatei und öffnet sie dann neu.

  • Beim binären Loggen (--log-bin) schließt der Server die aktuelle Logdatei und öffnet eine neue Logdatei mit der nächsthöheren Sequenznummer.

Wenn die Logs auf Festplatte geschrieben werden, erstellt der Server eine neue Binärlogdatei. Die Logs für allgemeine und langsame Abfragen hingegen werden nur geschlossen und dann wieder geöffnet. Wenn Sie unter Unix neue Dateien erstellen wollen, benennen Sie die aktuellen Logs um, bevor Sie sie auf die Festplatte schreiben. Beim Schreiben auf Festplatte öffnet der Server dann neue Logdateien mit den ursprünglichen Namen. Wenn beispielsweise die Logdateien für allgemeine und langsame Abfragen die Namen mysql.log bzw. mysql-slow.log haben, können Sie folgende Befehlssequenz verwenden:

shell> cd mysql-data-directory
shell> mv mysql.log mysql.old
shell> mv mysql-slow.log mysql-slow.old
shell> mysqladmin flush-logs

An dieser Stelle können Sie eine Sicherung von mysql.old und mysql-slow.log erstellen und diese dann von der Festplatte entfernen.

Unter Windows können Sie die Logdateien nicht umbenennen, solange sie vom Server geöffnet sind. Sie müssen zunächst den Server beenden, die Dateien umbenennen und den Server dann neu starten, um neue Logdateien zu erstellen.

5.13. Mehrere MySQL-Server auf derselben Maschine laufen lassen

In manchen Fällen kann es wünschenswert oder erforderlich sein, mehrere mysqld-Server auf demselben Computer auszuführen. Dies ist etwa der Fall, wenn Sie einen neuen MySQL-Release testen wollen, ohne die vorhandene Produktionskonfiguration anzurühren, oder wenn Sie verschiedenen Benutzern Zugang zu unterschiedlichen mysqld-Servern gestatten wollen, die dann von diesen Benutzern selbst verwaltet werden. (Ein solcher Fall läge bei einem Internetprovider vor, der separate MySQL-Installationen für verschiedene Kunden bereithält.)

Damit mehrere Server auf demselben Computer ausgeführt werden können, benötigt jeder Server eindeutige Werte für verschiedene Betriebsparameter. Diese können über die Befehlszeile oder in Optionsdateien angegeben werden. Siehe auch Abschnitt 4.3, „Angabe von Programmoptionen“.

Zumindest die folgenden Optionen müssen für jeden Server unterschiedlich sein:

  • --port=port_num

    --port steuert die Portnummer für TCP/IP-Verbindungen.

  • --socket=path

    --socket gibt unter Unix den Pfad zur Unix-Socketdatei und unter Windows den Namen der Named Pipe an. Unter Windows müssen separate Pipe-Namen nur für diejenigen Server angegeben werden, die Named-Pipe-Verbindungen unterstützen.

  • --shared-memory-base-name=name

    Diese Option wird derzeit nur unter Windows verwendet. Sie bezeichnet den Namen des gemeinsamen Speichers, mit dem ein Windows-Server Clients das Herstellen einer Verbindung über gemeinsamen Speicher gestattet. Die Angabe ist nur für Server erforderlich, die Verbindungen über gemeinsamen Speicher unterstützen.

  • --pid-file=file_name

    Diese Option wird nur unter Unix verwendet. Sie gibt den Pfadnamen der Datei an, in die der Server seine Prozesskennung schreibt.

Wenn Sie die folgenden Logdateioptionen verwenden, müssen diese für jeden Server anders sein:

  • --log=file_name

  • --log-bin=file_name

  • --log-update=file_name

  • --log-error=file_name

  • --bdb-logdir=file_name

Weitere Informationen zu Logdateien finden Sie in Abschnitt 5.12.5, „Wartung und Pflege der Logdateien“.

Zur Leistungsoptimierung können Sie auch die folgenden Optionen für jeden Server individuell angeben, um so die Last auf mehrere physische Festplatten zu verteilen:

  • --tmpdir=path

  • --bdb-tmpdir=path

Auch die Verwendung verschiedener Temporärverzeichnisse wird empfohlen, um besser bestimmen zu können, welche MySQL-Server welche der vorhandenen Temporärdateien erstellt hat.

Mit sehr wenigen Ausnahmen sollte jeder Server ein eigenes Datenverzeichnis haben, das mit der Option --datadir=path angegeben wird.

Warnung: Normalerweise sollten Daten in denselben Datenbanken niemals von zwei Servern aktualisiert werden. Dies kann zu unliebsamen Überraschungen führen, wenn Ihr Betriebssystem keine fehlerfreie Systemsperrung unterstützt. Wenn Sie (ungeachtet dieser Warnung) mehrere Server betreiben, die dasselbe Datenverzeichnis verwenden, müssen Sie, wenn das Loggen aktiviert ist, die passenden Optionen zur Angabe der Logdateinamen festlegen, die für jeden Server eindeutig sein müssen. Andernfalls versuchen die Server nämlich, in die gleichen Logdateien zu schreiben. Beachten Sie, dass eine solche Konfiguration nur bei MyISAM- und MERGE-Tabellen funktioniert, nicht aber bei anderen Speicher-Engines.

Die Warnung vor der gemeinsamen Nutzung eines Datenverzeichnisses durch mehrere Server gilt auch in einer NFS-Umgebung. Mehreren MySQL-Servern den Zugriff auf ein gemeinsames Datenverzeichnis über NFS zu gestatten, ist eine ganz schlechte Idee.

  • Das Problem ist hierbei primär, dass NFS in punkto Geschwindigkeit einen Flaschenhals darstellt. NFS ist für einen solchen Einsatz schlichtweg ungeeignet.

  • Ein weiteres Risiko besteht bei NFS darin, dass Sie eine Möglichkeit finden müssen, sicherzustellen, dass zwei oder mehr Server einander nicht stören. Normalerweise wird die NFS-Dateisperrung vom Daemon lockd verwaltet; es gibt aber derzeit keine Plattform, die die Sperrung in jeder Situation hundertprozentig zuverlässig ausführt.

Machen Sie es sich einfach: Lassen Sie die Freigabe eines Datenverzeichnisses für mehrere Server über NFS einfach bleiben. Eine bessere Lösung besteht in der Verwendung eines Computers, der mehrere Prozessoren enthält und ein Betriebssystem verwendet, das Threads effizient verwaltet.

Wenn Sie mehrere MySQL-Installationen in verschiedenen Verzeichnissen haben, können Sie das Basisinstallationsverzeichnis für jeden Server mit der Option --basedir=path angeben; in diesem Fall verwendet jeder Server ein anderes Datenverzeichnis, eigene Logdateien und eine eigene Prozesskennungsdatei. (Standardmäßig werden diese Werte relativ zum Basisverzeichnis gesetzt.) In diesem Fall müssen Sie als weitere Optionen nur --socket und --port angeben. Angenommen, Sie installieren verschiedene MySQL-Versionen aus einer tar-Datei mit einer Binärdistribution. Diese Versionen werden an verschiedenen Positionen installiert, d. h. Sie können den Server für jede Installation mit dem Befehl bin/mysqld_safe in seinem jeweiligen Basisverzeichnis starten. mysqld_safe bestimmt die korrekte --basedir-Option, die an mysqld übergeben werden muss; Sie müssen dann nur noch die Optionen --socket und --port für mysqld_safe angeben.

Wie in den vorangegangenen Abschnitten bereits erläutert, können zusätzliche Server durch Einstellen von Umgebungsvariablen oder durch Angabe passender Befehlszeilenoptionen gestartet werden. Wenn Sie allerdings auf Dauer mehrere Server ausführen wollen, ist es praktischer, die Optionswerte, die für jeden Server eindeutig sein müssen, mithilfe von Optionsdateien anzugeben. Die Option --defaults-file ist für diese Zwecke praktisch.

5.13.1. Mehrere Server unter Windows verwenden

Sie können mehrere Server unter Windows ausführen, indem Sie sie manuell über die Befehlszeile starten und die jeweils passenden Betriebsparameter angeben. Auf Windows NT-basierten Systemen können Sie mehrere Server auch als Windows-Dienste installieren und sie auf diese Weise ausführen. Eine allgemeine Anleitung zur Ausführung von MySQL-Servern über die Befehlszeile oder als Dienste finden Sie in Abschnitt 2.3, „Installation von MySQL unter Windows“. Dieser Abschnitt beschreibt, wie man sicherstellt, dass jeder Server mit unterschiedlichen Werten für diejenigen Optionen gestartet wird, die je Server eindeutig sein müssen (z. B. das Datenverzeichnis). Diese Optionen sind in Abschnitt 5.13, „Mehrere MySQL-Server auf derselben Maschine laufen lassen“, beschrieben.

5.13.1.1. Mehrere Server unter Windows auf der Befehlszeile starten

Um mehrere Server manuell über die Befehlszeile zu starten, können Sie die erforderlichen Optionen ebenfalls über die Befehlszeile oder in einer Optionsdatei angeben. Die Verwendung einer Optionsdatei ist praktischer. Sie müssen aber in jedem Fall sicherstellen, dass jeder Server eigene Optionen zugeordnet bekommt. Zu diesem Zweck erstellen Sie für jeden Server eine Optionsdatei und übergeben dem Server beim Start den Dateinamen mit der Option --defaults-file.

Angenommen, Sie wollen mysqld über Port 3307 mit dem Datenverzeichnis C:\mydata1 und mysqld-max über Port 3308 mit dem Datenverzeichnis C:\mydata2 ausführen. (Vergewissern Sie sich zu diesem Zweck vor dem Starten der Server, dass die Datenverzeichnisse vorhanden sind und jeweils eine eigene Kopie der mysql-Datenbank mit den Grant-Tabellen enthalten.) Erstellen Sie nun zwei Optionsdateien. Legen Sie beispielsweise eine Datei namens C:\my-opts1.cnf an, die wie folgt aussieht:

[mysqld]
datadir = C:/mydata1
port = 3307

Legen Sie nun eine zweite Datei namens C:\my-opts2.cnf an, die wie folgt aussieht:

[mysqld]
datadir = C:/mydata2
port = 3308

Jetzt starten Sie die Server mit jeweils eigener Optionsdatei:

C:\> C:\mysql\bin\mysqld --defaults-file=C:\my-opts1.cnf
C:\> C:\mysql\bin\mysqld-max --defaults-file=C:\my-opts2.cnf

Unter NT starten beide Server in den Vordergrund (d. h. eine Eingabeaufforderung wird erst wieder angezeigt, wenn der Server später beendet wird); Sie müssen deswegen zwei Befehle in separaten Konsolenfenstern ausführen.

Um die Server herunterzufahren, müssen Sie mit jedem Server unter Angabe der entsprechenden Portnummer eine Verbindung herstellen:

C:\> C:\mysql\bin\mysqladmin --port=3307 shutdown
C:\> C:\mysql\bin\mysqladmin --port=3308 shutdown

Mit Servern, die auf die beschriebene Weise konfiguriert wurden, können Clients über TCP/IP Verbindungen herstellen. Wenn Ihre Windows-Version Named Pipes unterstützt und Sie Named-Pipe-Verbindungen auch zulassen wollen, dann verwenden Sie die Server mysqld-nt oder mysqld-max-nt und geben Sie Optionen an, die die Named Pipe aktivieren und den zugehörigen Namen definieren. Jeder Server, der Named-Pipe-Verbindungen unterstützt, muss einen eindeutigen Namen für die Pipe verwenden. Beispielsweise könnte die Datei C:\my-opts1.cnf wie folgt aussehen:

[mysqld]
datadir = C:/mydata1
port = 3307
enable-named-pipe
socket = mypipe1

Starten Sie den Server in diesem Fall wie folgt:

C:\> C:\mysql\bin\mysqld-nt --defaults-file=C:\my-opts1.cnf

Ändern Sie C:\my-opts2.cnf auf ähnliche Weise für die Verwendung durch den zweiten Server ab.

Eine ähnliche Vorgehensweise gilt für Server, die Verbindungen über gemeinsamen Speicher unterstützen sollen. Sie aktivieren solche Verbindungen mit der Option --shared-memory und vergeben dann für jeden Server mit der Option --shared-memory-base-name einen eindeutigen Namen für den freigegebenen Speicher.

5.13.1.2. Mehrere Server unter Windows als Dienste starten

Unter Windows NT-basierten Systemen kann ein MySQL-Server als Windows-Dienst ausgeführt werden. Die Vorgehensweise zum Installieren, Steuern und Entfernen eines einzelnen MySQL-Dienstes sind in Abschnitt 2.3.12, „Starten von MySQL als Windows-Dienst“, beschrieben.

Sie können auch mehrere MySQL-Server als Dienste installieren. In diesem Fall müssen Sie sicherstellen, dass jeder Server neben allen Parametern, die für jeden Server eindeutig sein müssen, auch einen eigenen Dienstnamen verwendet.

Bei der folgenden Anleitung wird davon ausgegangen, dass Sie den Server mysqld-nt aus zwei verschiedenen MySQL-Versionen ausführen wollen, die in C:\mysql-5.0.19 bzw. C:\mysql-5.1.5-alpha installiert sind. (Dies kann etwa der Fall sein, wenn Sie Version 5.0.19 als Produktionsserver ausführen und gleichzeitig Tests mit Version 5.1.5-alpha durchführen wollen.)

Die folgenden Prinzipien finden Anwendung, wenn Sie einen MySQL-Dienst mit der Option --install oder --install-manual installieren:

  • Wenn Sie keinen Dienstnamen angeben, verwendet der Server den Standarddienstnamen MySQL und liest seine Optionen aus dem Abschnitt [mysqld] in den Standardoptionsdateien aus.

  • Geben Sie hingegen auf die Option --install folgend einen Dienstnamen an, dann ignoriert der Server den Abschnitt [mysqld] und liest stattdessen die Optionen aus dem Abschnitt aus, der den gleichen Namen wie der Dienst hat. Der Server liest Optionen aus den Standardoptionsdateien aus.

  • Wenn Sie eine Option --defaults-file auf den Dienstnamen folgend angeben, ignoriert der Server die Standardoptionsdateien und liest seine Optionen aus dem Abschnitt [mysqld] der benannten Datei aus.

Hinweis: Vor MySQL 4.0.17 wird der Abschnitt [mysqld] in den Standardoptionsdateien nur dann vom Server gelesen, wenn dieser mit dem Standarddienstnamen (MySQL) oder dem explizit angegebenen Dienstnamen mysqld installiert wurde. Ab Version 4.0.17 lesen alle Server, falls sie die Standardoptionsdateien auslesen, den Abschnitt [mysqld]. Dies gilt auch für Server, die mit einem anderen Dienstnamen installiert wurden. Sie können den Abschnitt [mysqld] also für diejenigen Optionen verwenden, die allen MySQL-Diensten gemeinsam sind, und zusätzlich einen Abschnitt mit dem Namen eines bestimmten Dienstes konfigurieren, der dann von dem Server benutzt wird, der mit diesem Dienstnamen installiert wurde.

Basierend auf diesen Informationen stehen Ihnen verschiedene Möglichkeiten zur Verfügung, mehrere Dienste einzurichten. Die folgende Anleitung beschreibt einige Beispiele. Bevor Sie jedoch eines davon ausprobieren, fahren Sie alle vorhandenen MySQL-Dienste herunter und entfernen Sie sie.

  • Methode 1: Geben Sie die Optionen für alle Dienste in einer der Standardoptionsdateien an. Verwenden Sie zu diesem Zweck einen anderen Dienstnamen für jeden Server. Angenommen, Sie wollen mysqld-nt aus Version 5.0.19 mit dem Dienstnamen mysqld1 und mysqld-nt aus Version 5.1.5-alpha mit dem Dienstnamen mysqld2 ausführen. In diesem Fall können Sie den Abschnitt [mysqld1] für Version 5.0.19 und den Abschnitt [mysqld2] für Version 5.1.5-alpha verwenden. Sie können C:\my.cnf etwa wie folgt konfigurieren:

    # options for mysqld1 service
    [mysqld1]
    basedir = C:/mysql-5.0.19
    port = 3307
    enable-named-pipe
    socket = mypipe1
    
    # options for mysqld2 service
    [mysqld2]
    basedir = C:/mysql-5.1.5-alpha
    port = 3308
    enable-named-pipe
    socket = mypipe2
    

    Installieren Sie die Dienste wie folgt und verwenden Sie dabei die vollständigen Serverpfadnamen, um sicherzustellen, dass Windows für jeden Dienst die korrekte ausführbare Datei registriert:

    C:\> C:\mysql-5.0.19\bin\mysqld-nt --install mysqld1
    C:\> C:\mysql-5.1.5-alpha\bin\mysqld-nt --install mysqld2
    

    Um die Dienste zu starten, verwenden Sie den Dienste-Manager oder NET START mit den entsprechenden Dienstnamen:

    C:\> NET START mysqld1
    C:\> NET START mysqld2
    

    Um die Dienste zu beenden, verwenden Sie den Dienste-Manager oder NET STOP mit den entsprechenden Dienstnamen:

    C:\> NET STOP mysqld1
    C:\> NET STOP mysqld2
    
  • Methode 2: Sie geben Sie Optionen für jeden Server in einer separaten Datei an und geben bei der Installation --defaults-file an, um den Servern die jeweils zu verwendende Datei mitzuteilen. In diesem Fall sollten die Optionen in jeder Datei in einem Abschnitt [mysqld] aufgelistet sein.

    Bei dieser Methode erstellen Sie zur Angabe der Optionen für mysqld-nt aus Version 5.0.19 eine Datei C:\my-opts1.cnf, die wie folgt aussieht:

    [mysqld]
    basedir = C:/mysql-5.0.19
    port = 3307
    enable-named-pipe
    socket = mypipe1
    

    Legen Sie nun für mysqld-nt aus Version 5.1.5-alpha eine zweite Datei namens C:\my-opts2.cnf an, die wie folgt aussieht:

    [mysqld]
    basedir = C:/mysql-5.1.5-alpha
    port = 3308
    enable-named-pipe
    socket = mypipe2
    

    Installieren Sie die Dienste wie folgt (geben Sie jeden Befehl in eine eigene Zeile ein):

    C:\> C:\mysql-5.0.19\bin\mysqld-nt --install mysqld1
               --defaults-file=C:\my-opts1.cnf
    C:\> C:\mysql-5.1.5-alpha\bin\mysqld-nt --install mysqld2
               --defaults-file=C:\my-opts2.cnf
    

    Um bei der Installation eines MySQL-Servers als Dienst eine Option --defaults-file anzugeben, müssen Sie der Option den Dienstnamen voranstellen.

    Nach der Installation der Dienste starten und beenden Sie sie auf die gleiche Weise wie im vorherigen Beispiel.

Zum Entfernen mehrerer Dienste verwenden Sie für jeden einzelnen Dienst mysqld --remove und geben dabei auf die Option --remove folgend einen Dienstnamen an. Wenn der Dienst den Standardnamen (MySQL) hat, können Sie die Angabe auch weglassen.

5.13.2. Mehrere MySQL-Server unter Unix laufen lassen

Die einfachste Möglichkeit, mehrere Server unter Unix auszuführen, besteht darin, sie mit verschiedenen TCP/IP-Ports und Unix-Socketdateien zu kompilieren, sodass jeder Server auf eine andere Netzwerkschnittstelle horcht. Auch das Einkompilieren verschiedener Basisverzeichnisse für jede Installation hat automatisch ein dediziertes einkompiliertes Verzeichnis zur Folge, in dem Datenverzeichnis, Logdatei und Prozesskennungsdatei des betreffenden Servers abgelegt sind.

Nehmen wir einmal an, dass der vorhandene Server (Version 5.0.19) für den TCP/IP-Standardport (3306) und die Standardsocketdatei (/tmp/mysql.sock) konfiguriert ist. Um nun einen neuen Server unter MySQL 5.1.5-alpha mit anderen Betriebsparametern zu konfigurieren, verwenden Sie den Befehl configure wie folgt:

shell> ./configure --with-tcp-port=port_number \
             --with-unix-socket-path=file_name \
             --prefix=/usr/local/mysql-5.1.5-alpha

Hierbei müssen sich port_number und file_name von der TCP/IP-Standardportnummer bzw. dem Standardpfadnamen der Unix-Socketdatei unterscheiden. Ferner sollte die Option --prefix ein anderes Installationsverzeichnis als jenes angeben, in dem sich die vorhandene MySQL-Installation befindet.

Wenn Ihr MySQL-Server auf eine gegebene Portnummer horcht, dann können Sie mit folgendem Befehl herausfinden, welche Betriebsparameter er für verschiedene wichtige konfigurierbare Variablen (einschließlich Basisverzeichnis und Unix-Socketdatei) verwendet:

shell> mysqladmin --host=host_name --port=port_number variables

Anhand der von diesem Befehl angezeigten Informationen können Sie festlegen, welche Optionswerte Sie nicht verwenden dürfen, wenn Sie einen zusätzlichen Server konfigurieren.

Beachten Sie, dass, wenn Sie localhost als Hostnamen angeben, mysqladmin standardmäßig statt TCP/IP eine Verbindung über eine Unix-Socketdatei verwendet. Ab MySQL 4.1 können Sie das zu verwendende Verbindungsprotokoll mit der Option --protocol={TCP|SOCKET|PIPE|MEMORY} explizit angeben.

Sie müssen keinen neuen MySQL-Server kompilieren, nur um neu mit einer anderen Unix-Socketdatei und TCP/IP-Portnummer zu starten. Sie können auch dieselbe Serverbinärdatei verwenden und diese mehrfach aufrufen – mit jeweils anderen Parameterwerten zur Laufzeit. Eine Möglichkeit hierzu besteht in der Verwendung von Befehlszeilenoptionen:

shell> mysqld_safe --socket=file_name --port=port_number

Um einen zweiten Server zu starten, geben Sie andere Optionswerte für --socket und --port an und übergeben zudem eine Option --datadir=path an mysqld_safe, damit der Server ein anderes Datenverzeichnis benutzt.

Eine weitere Möglichkeit, mit der sich ein ähnlicher Effekt erzielen lässt, besteht darin, den Namen der Unix-Socketdatei und die TCP/IP-Portnummer mithilfe von Umgebungsvariablen anzugeben:

shell> MYSQL_UNIX_PORT=/tmp/mysqld-new.sock
shell> MYSQL_TCP_PORT=3307
shell> export MYSQL_UNIX_PORT MYSQL_TCP_PORT
shell> mysql_install_db --user=mysql
shell> mysqld_safe --datadir=/path/to/datadir &

Dies steht eine schnelle Möglichkeit dar, einen zweiten Server zu Testzwecken zu starten. Das Praktische an dieser Methode ist, dass die Einstellungen der Umgebungsvariablen für alle Clientprogramme gelten, die Sie von derselben Shell aufrufen. Auf diese Weise werden Verbindungen für diese Clients automatisch an den zweiten Server geleitet.

Anhang F, Umgebungsvariablen, enthält eine Liste aller anderen Umgebungsvariablen, die Sie zur Beeinflussung von mysqld verwenden können.

Für die automatische Ausführung des Servers sollte das Startskript, welches beim Systemstart ausgeführt wird, den folgenden Befehl jeweils einmal pro Server ausführen und dabei den jeweils passenden Optionsdateipfad angeben:

shell> mysqld_safe --defaults-file=file_name

Jede Optionsdatei sollte die Optionswerte für jeweils einen bestimmten Server angeben.

Eine andere Möglichkeit zum Starten mehrerer Server bietet unter Unix das Skript mysqld_multi. Siehe auch Abschnitt 5.4.3, „mysqld_multi — Verwalten mehrerer MySQL-Server“.

5.13.3. Verwendung von Client-Programmen in einer Mehrserverumgebung

Um eine Verbindung von einem Clientprogramm mit einem MySQL-Server herzustellen, der auf anderen als den in Ihren Client einkompilierten Netzwerkschnittstellen lauscht, können Sie eine der folgenden Methoden benutzen:

  • Starten Sie den Client mit --host=host_name --port=port_number, --host=127.0.0.1 --port=port_number bzw. --host=localhost --socket=file_name, um eine TCP/IP-Verbindung mit einem entfernten Server, eine TCP/IP-Verbindung mit dem lokalen Server oder eine Verbindung mit dem lokalen Server über eine Unix-Socketdatei oder eine Named Pipe unter Windows herzustellen.

  • Ab MySQL 4.1 starten Sie den Client mit --protocol=tcp, --protocol=socket, --protocol=pipe bzw. --protocol=memory, um eine Verbindung über TCP/IP, eine Unix-Socketdatei, eine Named Pipe oder gemeinsamen Speicher herzustellen. Bei TCP/IP-Verbindungen müssen Sie auch die Optionen --host und --port angeben. Bei den anderen Verbindungstypen können Sie eine Option --socket zur Festlegung einer Unix-Socketdatei bzw. einer Named-Pipe-Datei oder eine Option --shared-memory-base-name zur Bezeichnung des Namens des gemeinsamen Speichers angeben. Verbindungen über gemeinsamen Speicher werden nur unter Windows unterstützt.

  • Unter Unix stellen Sie, bevor Sie Ihre Clients starten, die Umgebungsvariablen MYSQL_UNIX_PORT und MYSQL_TCP_PORT so ein, dass sie die Unix-Socketdatei bzw. die TCP/IP-Portnummer angeben. Wenn Sie normalerweise eine bestimmte Socketdatei oder Portnummer verwenden, können Sie die Befehle, die die Werte der Umgebungsvariablen einstellen, in Ihrer Datei .login ablegen, damit diese bei jeder Anmeldung automatisch konfiguriert werden. Siehe auch Anhang F, Umgebungsvariablen.

  • Geben Sie die Vorgaben für die Unix-Socketdatei und die TCP/IP-Portnummer im Abschnitt [client] einer Optionsdatei an. Sie können beispielsweise C:\my.cnf unter Windows oder .my.cnf in Ihrem Stammverzeichnis unter Unix verwenden. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

  • In einem C-Programm können Sie die Socketdatei- oder Portnummerargumente im Aufruf mysql_real_connect() angeben. Sie können das Programm auch die Optionsdateien auslesen lassen, indem Sie mysql_options() aufrufen. Siehe auch Abschnitt 24.2.3, „C-API: Funktionsbeschreibungen“.

  • Wenn Sie das Perl-Modul DBD::mysql verwenden, können Sie ebenfalls Optionen aus MySQL-Optionsdateien auslesen. Zum Beispiel:

    $dsn = "DBI:mysql:test;mysql_read_default_group=client;"
            . "mysql_read_default_file=/usr/local/mysql/data/my.cnf";
    $dbh = DBI->connect($dsn, $user, $password);
    

    Siehe auch Abschnitt 24.4, „MySQLs Perl-API“.

    Andere Programmierschnittstellen bieten unter Umständen ähnliche Funktionalitäten zum Auslesen von Optionsdateien.

5.14. MySQL-Anfragen-Cache

Der Abfrage-Cache speichert den Text einer SELECT-Anweisung gemeinsam mit dem zugehörigen Ergebnis, das an den Client gesendet wurde. Wenn später eine identische Anweisung empfangen wird, ruft der Server die Ergebnisse aus dem Abfrage-Cache ab, statt die Anweisung erneut zu verarbeiten und auszuführen.

Der Abfrage-Cache ist extrem nützlich in Umgebungen, in denen sich Tabellen nicht besonders häufig ändern und der Server häufig identische Abfragen empfängt. Dies ist eine typische Situation insbesondere für Webserver, die basierend auf den Datenbankinhalten viele dynamische Seiten erzeugen.

Hinweis: Der Abfrage-Cache gibt keine veralteten Daten zurück. Wenn Tabellen modifiziert werden, werden alle entsprechenden Einträge im Abfrage-Cache synchronisiert.

Hinweis: Der Abfrage-Cache funktioniert nicht in Umgebungen, in denen mehrere mysqld-Server dieselben MyISAM-Tabellen aktualisieren.

Hinweis: Der Abfrage-Cache wird nicht bei serverseitig vorbereiteten Anweisungen benutzt. Wenn Sie serverseitig vorbereitete Anweisungen verwenden, müssen Sie berücksichtigen, dass diese Anweisungen nicht vom Abfrage-Cache profitieren. Siehe auch Abschnitt 24.2.4, „C-API: Prepared Statements“.

An dieser Stelle folgen ein paar Leistungsdaten für den Abfrage-Cache. Diese Ergebnisse wurden erzeugt, indem die MySQL-Benchmarks auf einem Linux-Alpha-System mit 2 × 500 MHz, 2 Gbyte RAM und einem Abfrage-Cache von 64 Mbyte ausgeführt wurden.

  • Wenn alle von Ihnen durchgeführten Abfragen einfacher Natur sind (z. B. das Auswählen eines Datensatzes aus einer Tabelle mit nur einem Datensatz), aber sich noch voneinander unterscheiden, sodass die Abfragen nicht im Cache abgelegt werden können, dann liegt die Mehrbelastung bei Nutzung eines aktiven Abfrage-Caches bei 13 Prozent. Dies sollte als ungünstigster Fall betrachtet werden. In der Praxis neigen Abfragen dazu, wesentlich komplizierter zu sein, d. h. die Mehrbelastung ist in der Regel deutlich niedriger.

  • Suchvorgänge nach einem einzelnen Datensatz in einer Tabelle mit nur einem Datensatz sind mit Abfrage-Cache um 238 Prozent schneller als ohne. Dieser Wert kann annähernd als zu erwartende Mindestbeschleunigung für im Cache abgelegte Abfragen betrachtet werden.

Um den Abfrage-Cache beim Serverstart zu deaktivieren, setzen Sie die Systemvariable query_cache_size auf 0. Durch Deaktivierung des Codes für den Abfrage-Cache erhalten Sie keine merkliche Mehrbelastung. Wenn Sie MySQL aus der Quelldistribution erstellen, lässt sich die Abfrage-Cachefunktionalität auf dem Server vollständig abschalten, indem Sie configure mit der Option --without-query-cache aufrufen.

5.14.1. Wie der Anfragen-Cache funktioniert

Dieser Abschnitt beschreibt, wie der Abfrage-Cache funktioniert, wenn er betriebsbereit ist. Abschnitt 5.14.3, „Konfiguration des Anfragen-Cache“, erläutert, wie Sie ermitteln können, ob die Betriebsbereitschaft gegeben ist.

Eingehende Abfragen werden vor Ihrer Verarbeitung mit denen im Abfrage-Cache verglichen; die folgenden beiden Abfragen werden also aus der Sicht des Abfrage-Caches als unterschiedlich betrachtet:

SELECT * FROM tbl_name
Select * from tbl_name

Abfragen müssen absolut (das heißt bytegenau) gleich sein, damit sie als identisch gelten. Außerdem können Abfrage-Strings, die identisch sind, auch aus anderen Gründen wie unterschiedliche Abfragen behandelt werden. Abfragen, die verschiedene Datenbanken, Protokollversionen oder Standardzeichensätze verwenden, gelten als unterschiedliche Abfragen und werden separate im Cache abgelegt.

Bevor ein Abfrageergebnis aus dem Abfrage-Cache abgerufen wird, prüft MySQL, ob der Benutzer die Berechtigung SELECT für alle betreffenden Datenbanken und Tabellen hat. Ist dies nicht der Fall, dann wird das Ergebnis im Cache nicht verwendet.

Wird ein Abfrageergebnis aus dem Abfrage-Cache zurückgegeben, dann zählt der Server die Statusvariable Qcache_hits hoch, nicht aber Com_select. Siehe auch Abschnitt 5.14.4, „Anfragen-Cache-Status und -Wartung“.

Wenn eine Tabelle geändert wird, werden alle Abfragen, die die Tabelle verwenden, ungültig und insofern aus dem Cache entfernt. Dies betrifft auch Abfragen, die MERGE-Tabellen verwenden, welche die geänderte Tabelle abbilden. Eine Tabelle kann von vielen Anweisungstypen geändert werden, so etwa INSERT, UPDATE, DELETE, TRUNCATE, ALTER TABLE, DROP TABLE oder DROP DATABASE.

Transaktionssichere InnoDB-Tabellen, die geändert wurden, werden ungültig, wenn eine COMMIT-Anweisung ausgeführt wird.

Der Abfrage-Cache funktioniert auch innerhalb von Transaktionen, wenn Sie InnoDB-Tabellen verwenden, denn anhand der Tabellenversionsnummer bestimmt er, ob seine Inhalte nach wie vor gültig sind.

In MySQL 5.1 werden Abfragen, die von Views erstellt werden, im Cache abgelegt.

Der Abfrage-Cache funktioniert bei Abfragen der Typen SELECT SQL_CALC_FOUND_ROWS ... und SELECT FOUND_ROWS(). FOUND_ROWS() gibt den korrekten Wert auch dann zurück, wenn die vorherige Abfragen aus dem Cache geholt wurde, da die Anzahl der gefundenen Datensätze ebenfalls im Cache abgelegt ist.

Eine Abfrage landet nicht im Abfrage-Cache, wenn sie eine der Funktionen enthält, die in der folgenden Tabellen aufgeführt sind.

BENCHMARK()CONNECTION_ID()CURDATE()
CURRENT_DATE()CURRENT_TIME()CURRENT_TIMESTAMP()
CURTIME()DATABASE()ENCRYPT() mit genau einem Parameter
FOUND_ROWS()GET_LOCK()LAST_INSERT_ID()
LOAD_FILE()MASTER_POS_WAIT()NOW()
RAND()RELEASE_LOCK()SYSDATE()
UNIX_TIMESTAMP() ohne ParameterUSER() 

Auch unter den folgenden Bedingungen wird eine Abfrage nicht im Abfrage-Cache gespeichert:

  • Sie verweist auf benutzerdefinierte Funktionen (UDFs).

  • Sie verweist auf Benutzervariablen.

  • Sie verweist auf Tabellen in der mysql-Systemdatenbank.

  • Sie hat eine der folgenden Formen:

    SELECT ... IN SHARE MODE
    SELECT ... FOR UPDATE
    SELECT ... INTO OUTFILE ...
    SELECT ... INTO DUMPFILE ...
    SELECT * FROM ... WHERE autoincrement_col IS NULL
    

    Die letzte Form wird nicht gespeichert, weil Sie als ODBC-Workaround zur Ermittlung des letzten Einfügekennungswertes eingesetzt wird. Siehe auch Abschnitt 25.1.6.1.1, „Abruf von Auto-Increment-Werten“.

  • Sie wurde als vorbereitete Anweisung abgesetzt, auch wenn keine Platzhalter verwendet wurden. So wird etwa folgende Abfrage nicht im Cache gespeichert:

    char *my_sql_stmt = "SELECT a, b FROM table_c";
    /* ... */
    mysql_stmt_prepare(stmt, my_sql_stmt, strlen(my_sql_stmt));
    

    Siehe auch Abschnitt 24.2.4, „C-API: Prepared Statements“.

  • Sie verwendet TEMPORARY-Tabellen.

  • Sie verwendet überhaupt keine Tabellen.

  • Der Benutzer hat eine Berechtigung auf Spaltenebene für eine der betreffenden Tabellen.

5.14.2. Anfragen-Cache-Optionen in SELECT

In SELECT-Anweisungen können zwei für den Abfrage-Cache spezifische Optionen angegeben werden:

  • SQL_CACHE

    Das Abfrageergebnis wird im Abfrage-Cache gespeichert, wenn der Wert der Systemvariable query_cache_type ON oder DEMAND ist.

  • SQL_NO_CACHE

    Das Abfrageergebnis wird nicht im Cache gespeichert.

Ein paar Beispiele:

SELECT SQL_CACHE id, name FROM customer;
SELECT SQL_NO_CACHE id, name FROM customer;

5.14.3. Konfiguration des Anfragen-Cache

Die Serversystemvariable have_query_cache gibt an, ob der Abfrage-Cache verfügbar ist:

mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+

Wenn Sie eine MySQL-Standardbinärdatei verwenden, ist der Wert immer YES – und zwar auch dann, wenn die Zwischenspeicherung von Abfragen deaktiviert ist.

Mehrere andere Systemvariablen steuern den Betrieb des Abfrage-Caches. Diese können in einer Optionsdatei oder über die Befehlszeile beim Start von mysqld angegeben werden. Die Namen aller Systemvariablen für den Abfrage-Cache beginnen stets mit query_cache_. Sie sind in Abschnitt 5.2.2, „Server-Systemvariablen“, kurz beschrieben. An dieser Stelle sollen zusätzliche Konfigurationsinformationen erläutert werden.

Die Größe des Abfrage-Caches stellen Sie mit der Systemvariable query_cache_size ein. Die Einstellung 0 deaktiviert den Abfrage-Cache. Standardwert ist 0, d. h. der Abfrage-Cache ist vorgabeseitig deaktiviert.

Wenn Sie query_cache_size auf einen Wert ungleich Null setzen, beachten Sie, dass der Abfrage-Cache eine Mindestgröße von ca. 40 Kbyte benötigt, um seine Strukturen zuzuweisen. (Der exakte Wert hängt von der Systemarchitektur ab.) Wenn Sie den Wert zu niedrig ansetzen, erhalten Sie eine Warnung wie im folgenden Beispiel:

mysql> SET GLOBAL query_cache_size = 40000;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1282
Message: Query cache failed to set size 39936; new query cache size is 0

mysql> SET GLOBAL query_cache_size = 41984;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'query_cache_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| query_cache_size | 41984 |
+------------------+-------+

Ist die Größe des Abfrage-Caches größer als 0, dann beeinflusst die Variable query_cache_type die Wirkungsweise. Die Variable kann auf die folgenden Werte gesetzt werden:

  • Der Wert 0 oder OFF verhindert das Speichern von Abfragen im und das Abrufen aus dem Cache.

  • Der Wert 1 oder ON gestattet das Speichern von Abfragen im Cache. Ausgenommen sind Anweisungen, die mit SELECT SQL_NO_CACHE beginnen.

  • Der Wert 2 oder DEMAND speichert nur diejenigen Anweisungen im Cache, die mit SELECT SQL_CACHE beginnen.

Die Einstellung des GLOBAL-Wertes query_cache_type bestimmt das Verhalten des Abfrage-Caches für alle Clients, die nach Durchführung der Änderung eine Verbindung herstellen. Einzelne Clients können das Verhalten des Caches bezüglich ihrer eigenen Verbindung steuern, indem Sie den SESSION-Wert query_cache_type einstellen. So kann ein Client beispielsweise die Verwendung des Abfrage-Caches für eigene Abfragen wie folgt deaktivieren:

mysql> SET SESSION query_cache_type = OFF;

Um die maximale Größe einzelner Abfrageergebnisse zu steuern, die im Cache gespeichert werden können, stellen Sie die Systemvariable query_cache_limit ein. Der Vorgabewert ist 1 Mbyte.

Wenn eine Abfrage im Cache abgelegt werden soll, wird ihr Ergebnis (d. h. die Daten, die an den Client gesendet werden) während des Abrufens des Ergebnisses im Abfrage-Cache abgelegt. Dies bedeutet, dass die Daten nicht am Stück verwaltet werden. Der Abfrage-Cache reserviert Blöcke zur Speicherung dieser Daten nach Bedarf, d. h. wenn ein Block voll ist, wird der nächste zugewiesen. Da der Speicherreservierungsvorgang (in zeitlicher Hinsicht) aufwändig ist, reserviert der Abfrage-Cache die Blöcke mit einer Mindestgröße, die durch die Systemvariable query_cache_min_res_unit festgelegt wird. Wird eine Abfrage ausgeführt, dann wird der letzte Ergebnisblock auf die tatsächliche Datengröße zugeschnitten, sodass unbenutzter Speicher freigegeben wird. Je nach Typ der von Ihrem Server ausgeführten Abfragen kann es für Sie hilfreich sein, den Wert von query_cache_min_res_unit zu optimieren:

  • Der Vorgabewert von query_cache_min_res_unit beträgt 4 Kbyte. Dies sollte für die meisten Fälle ausreichend sein.

  • Wenn Sie viele Abfragen mit kleinen Ergebnissen haben, kann die standardmäßige Blockgröße zur Speicherfragmentierung führen, wie durch eine große Anzahl freier Blöcke zu erkennen ist. Die Fragmentierung wiederum kann das Entfernen (Löschen) von Abfragen aus dem Abfragen aufgrund von Speichermangel erforderlich machen. In diesem Fall sollten Sie den Wert von query_cache_min_res_unit verringern. Die Anzahl freier Blöcke und entfernter Abfragen wird durch die Werte der Statusvariablen Qcache_free_blocks bzw. Qcache_lowmem_prunes angegeben.

  • Weist die Mehrzahl Ihrer Abfragen hingegen große Ergebnisse auf (dies können Sie mit den Statusvariablen Qcache_total_blocks und Qcache_queries_in_cache überprüfen), dann können sie die Leistung steigern, indem Sie query_cache_min_res_unit erhöhen. Allerdings sollten Sie den Wert nicht zu groß wählen (siehe obige Beschreibung).

5.14.4. Anfragen-Cache-Status und -Wartung

Sie können mit der folgenden Anweisung überprüfen, ob der Abfrage-Cache auf Ihrem MySQL-Server vorhanden ist:

mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+

Um den Abfrage-Cache zu defragmentieren und den vorhandenen Speicher so besser zu nutzen, setzen Sie die Anweisung FLUSH QUERY CACHE ab. Diese Anweisung entfernt keine Abfragen aus dem Cache.

Die Anweisung RESET QUERY CACHE entfernt alle Abfrageergebnisse aus dem Abfrage-Cache. Auch die Anweisung FLUSH TABLES tut dies.

Wenn Sie die Leistung des Abfrage-Caches überwachen wollen, können Sie mit SHOW STATUS die Statusvariablen für den Cache anzeigen:

mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+--------+
| Variable_name           | Value  |
+-------------------------+--------+
| Qcache_free_blocks      | 36     |
| Qcache_free_memory      | 138488 |
| Qcache_hits             | 79570  |
| Qcache_inserts          | 27087  |
| Qcache_lowmem_prunes    | 3114   |
| Qcache_not_cached       | 22989  |
| Qcache_queries_in_cache | 415    |
| Qcache_total_blocks     | 912    |
+-------------------------+--------+

Beschreibungen dieser Variablen finden Sie in Abschnitt 5.2.4, „Server-Statusvariablen“. An dieser Stelle wollen wir einige Anwendungsmöglichkeiten für sie beschreiben.

Die Gesamtzahl der SELECT-Anweisungen berechnen Sie mit folgender Formel:

  Com_select
+ Qcache_hits
+ queries with errors found by parser

Den Wert Com_select erhalten Sie über folgende Formel:

  Qcache_inserts
+ Qcache_not_cached
+ queries with errors found during the column-privileges check

Der Abfrage-Cache verwendet Blöcke variabler Länge, d. h. Qcache_total_blocks und Qcache_free_blocks lassen Rückschlüsse auf die Speicherfragmentierung des Abfrage-Caches zu. Nach Absetzen von FLUSH QUERY CACHE bleibt nur ein einziger freie Block übrig.

Alle im Cache gespeicherten Abfragen benötigen mindestens zwei Blöcke (einen für den Abfragetext und einen weiteren für die Ergebnisse). Ferner benötigt jede Tabelle, die von einer Abfrage verwendet wird, einen Block. Wenn jedoch zwei oder mehr Abfragen dieselbe Tabelle verwenden, muss nur ein Tabellenblock reserviert werden.

Mithilfe der in der Statusvariable Qcache_lowmem_prunes gespeicherten Information können Sie die Größe des Abfrage-Cache optimieren. Diese Variable zählt die Anzahl der Abfragen, die aus dem Cache entfernt wurden, um Speicherplatz für die Aufnahme neuer Abfragen zu schaffen. Der Abfrage-Cache entscheidet auf der Basis der zuletzt verwendeten Abfragen, welche Abfragen aus dem Cache entfernt werden können. Hinweise zur Optimierung finden Sie in Abschnitt 5.14.3, „Konfiguration des Anfragen-Cache“.

Kapitel 6. Replikation bei MySQL

Dieses Kapitel beschreibt die verschiedenen Replikationsfunktionen in MySQL. Es stellt Replikationskonzepte vor, erläutert die Konfiguration von Replikationsservern und dient als Referenz der verfügbaren Replikationsoptionen. Ferner vorhanden ist eine Liste mit häufig gestellten Fragen (und den zugehörigen Antworten) sowie Hilfestellung zur Behebung von Replikationsproblemen.

Eine Beschreibung der Syntax replikationsspezifischer SQL-Anweisungen finden Sie in Abschnitt 13.6, „SQL-Befehle in Bezug auf Replikation“.

6.1. Einführung in die Replikation

MySQL unterstützt die unidirektionale, asynchrone Replikation, bei der ein Server als Master agiert, während mehrere andere Server die Rolle der Slaves erfüllen. Dies steht im Gegensatz zur synchronen Replikation, die ein Kennzeichen von MySQL Cluster ist (siehe auch Kapitel 16, MySQL Cluster).

Bei der Single-Master-Replikation schreibt der Master-Server Updates in seine Binärlogdateien und führt zudem einen Index dieser Dateien, um den Überblick über die Logrotation zu behalten. Die Binärlogdateien dienen als Datenspeicher für Updates, die an alle Slave-Server gesendet werden. Wenn ein Slave eine Verbindung zu seinem Master herstellt, nennt er dem Master die Position, bis zu der er die Logdateien beim letzten erfolgreichen Update gelesen hat. Der Slave empfängt daraufhin alle Änderungen, die seit jenem Zeitpunkt durchgeführt wurden. Nachfolgend wechselt er in den Leerlauf und wartet darauf, dass der Master ihn über neue Aktualisierungen in Kenntnis setzt.

Ein Slave-Server kann seinerseits als Master agieren, um beispielsweise eine Verkettung von Replikationsservern realisieren zu können.

Die Multi-Master-Replikation ist zwar auch möglich, aber hierbei können Probleme auftreten, die bei der Single-Master-Replikation ausgeschlossen sind. Siehe auch Abschnitt 6.15, „Auto-Increment in der Multi-Master-Replikation“.

Sofern Sie die Replikation verwenden, sollten alle Änderungen an Tabellen, die repliziert werden, auf dem Master-Server durchgeführt werden. Andernfalls müssen Sie nämlich immer sorgfältig darauf achten, Konflikte zwischen von Benutzern vorgenommenen Änderungen an den Tabellen auf dem Master und solchen Änderungen zu vermeiden, die an Tabellen auf dem Slave vorgenommen werden. Beachten Sie ferner, dass Updates auf der Slave-Seite abhängig davon, ob Sie eine anweisungs- oder eine datensatzbasierte Replikation verwenden, unterschiedlich verarbeitet werden können. Betrachten Sie einmal das folgende Szenario, bei dem ein Datensatz auf dem Slave eingefügt wird, gefolgt von einer Anweisung auf Master-Seite, die die Tabelle leert:

slave> INSERT INTO tbl VALUES (1);
master> DELETE FROM tbl;

Der Master weiß nichts über die INSERT-Operation auf dem Slave-Server. Bei der anweisungsbasierten Replikation wird tbl auf dem Master und dem Slave geleert, sobald der Slave auf den Stand des Masters gebracht wird, weil der Master seine DELETE-Anweisung dann an den Slave sendet. Infolgedessen hat tbl nachfolgend auf beiden Servern den gleichen Inhalt. Bei der datensatzbasierten Replikation ist die Wirkung von DELETE auf den Slave eine andere. Der Master schreibt nämlich jeden aus der Tabelle zu löschenden Datensatz in sein Binärlog. Der Slave löscht daraufhin nur diejenigen Datensätze, die dort erscheinen – und nicht denjenigen, der direkt auf dem Slave eingefügt worden war. Hieraus ergeben sich unterschiedliche Inhalte der Tabellen auf dem Master und dem Slave, was zu Replikationsproblemen führen kann.

Informationen zur datensatzbasierten Replikation finden Sie in Abschnitt 6.3, „Zeilenbasierte Replikation“.

Die Replikation bietet Vorteile in puncto Robustheit, Geschwindigkeit und Systemadministration:

  • Die Robustheit wird durch eine Master/Slave-Konfiguration erhöht. Im Fall von Problemen auf dem Master können Sie auf den Slave als Sicherungskopie umschalten.

  • Eine verbesserte Reaktionszeit lässt sich für Clients erzielen, indem die Last bei der Verarbeitung von Clientabfragen auf die Master- und Slave-Server verteilt wird. SELECT-Abfragen können an einen Slave geschickt werden, um die Verarbeitungsbelastung des Masters zu senken. Allerdings sollten Anweisungen, die Daten verändern, in jedem Fall an den Master geschickt werden, damit die Synchronisation zwischen Master und Slaves erhalten bleibt. Die Lastverteilungsstrategie ist effizient, wenn in erster Linie nichtändernde Abfragen abgesetzt werden – aber dies ist auch der Normalfall.

  • Ein weiterer Vorteil der Replikation besteht darin, dass Sie Datenbanksicherungen über einen Slave-Server durchführen können, ohne den Master zu stören. Der Master verarbeitet dann weiterhin alle Aktualisierungen auch während der Erstellung des Backups. Siehe auch Abschnitt 5.10.1, „Datenbank-Datensicherungen“.

6.2. Replikation: Implementation

Die MySQL-Replikation basiert darauf, dass der Master-Server alle Änderungen an Ihren Datenbanken (Updates, Löschvorgänge usw.) in seinen Binärlogs vermerkt. Aus diesem Grund müssen Sie das binäre Loggen auf dem Master-Server aktivieren. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

Alle Slave-Server erhalten vom Master die gespeicherten Änderungen, die der Master in seinem Binärlog vermerkt hat, sodass jeder Slave dieselben Änderungen an seiner Kopie der Daten vornehmen kann.

Es ist extrem wichtig, sich klar zu machen, dass das Binärlog nichts anderes als eine Aufzeichnung darstellt, die zu genau dem Zeitpunkt beginnt, an dem Sie das binäre Loggen aktivieren. Insofern benötigen alle zu konfigurierenden Slaves Kopien der Master-Datenbank mit ihrem Aussehen zum Zeitpunkt der Aktivierung der Binärlogs auf dem Master. Wenn Sie Ihre Slaves mit Datenbanken starten, die nicht hundertprozentig denselben Status haben wie der Master beim Aktivieren der Binärlogs, dann werden höchstwahrscheinlich Probleme auftreten.

Eine Möglichkeit, die Daten des Masters auf den Slave zu kopieren, besteht im Absetzen der LOAD DATA FROM MASTER-Anweisung. Allerdings funktioniert LOAD DATA FROM MASTER nur, wenn alle Tabellen auf dem Master die MyISAM-Speicher-Engine verwenden. Ferner erwirkt die Anweisung eine globale Lesesperre, d. h., während die Tabellen auf den Slave übertragen werden, sind keine Updates auf dem Master möglich. Sobald wir die Funktion für sperrenfreie Tabellenbackups im laufenden Betrieb implementiert haben, wird diese globale Lesesperre nicht mehr erforderlich sein.

Aufgrund dieser Einschränkungen empfehlen wir Ihnen bis auf weiteres, LOAD DATA FROM MASTER nur dann zu verwenden, wenn die Datenmenge auf dem Master relativ gering oder eine längere Lesesperre auf dem Master hinnehmbar ist. Zwar kann die tatsächliche Geschwindigkeit von LOAD DATA FROM MASTER von System zu System variieren, aber als Faustregel können Sie eine Übertragungsrate von 1 Mbyte Daten/Sekunde erwarten. Dies ist ein grober Anhaltspunkt, der aber recht genau sein sollte, wenn sowohl Master als auch Slave über 700-MHz-Pentium-Prozessoren verfügen und über ein Netzwerk mit einer Übertragungsrate von 100 Mbit/s miteinander verbunden sind.

Nachdem auf dem Slave eine Kopie der Master-Daten installiert wurde, stellt er eine Verbindung zum Master her und wartet auf Updates, die er verarbeiten kann. Fällt der Master aus oder verliert der Slave die Verbindung zu ihm, dann versucht er in regelmäßigen Abständen, die Verbindung neu herzustellen, bis der Empfang von Updates wieder möglich ist. Die Option --master-connect-retry steuert das Intervall, in dem die Neuverbindung versucht wird. Voreingestellt sind 60 Sekunden.

Jeder Slave vermerkt die Position, an der das Lesen beim letzten Update vom Master-Server beendet wurde. Der Master selbst weiß nicht, wie viele Slaves an ihn angeschlossen sind oder welche Slaves zu einem gegebenen Zeitpunkt aktuell sind.

6.3. Zeilenbasierte Replikation

Die Replikationsfunktionen in MySQL basierten ursprünglich auf der Weitergabe von SQL-Anweisungen vom Master an den Slave. Dies bezeichnete man als anweisungsbasierte Replikation (Statement-Based Replication, SBR). Seit MySQL 5.1.5 gibt es noch eine andere Basis für die Replikation: die datensatzbasierte Replikation (Row-Based Replication, RBR). Statt die SQL-Anweisungen an den Slave zu senden, schreibt der Master alle Ereignisse, die angeben, wie einzelne Datensätze in der Tabelle geändert werden, in sein Binärlog.

Bei der klassischen anweisungsbasierten Replikation kann es Probleme mit der Replikation gespeicherter Routinen geben. Diese Probleme können Sie umgehen, indem Sie stattdessen die datensatzbasierte Replikation benutzen. Eine umfassende Liste möglicher Probleme finden Sie unter Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“.

Wenn Sie MySQL aus dem Quellcode erstellen, steht die datensatzbasierte Replikation nur dann zur Verfügung, wenn Sie configure mit der Option --with-row-based-replication aufrufen.

MySQL Server verwendet standardmäßig auch dann die anweisungsbasierte Replikation, wenn MySQL mit Unterstützung der datensatzbasierten Replikation konfiguriert wurde. Wenn Sie die datensatzbasierte Replikation verwenden wollen, starten Sie den Server mit der Option --binlog-format=row, um die datensatzbasierte Replikation global (d. h. für alle Clientverbindungen) zu aktivieren. Die Option aktiviert automatisch auch innodb_locks_unsafe_for_binlog, was bei der datensatzbasierten Replikation sicher zu verwenden ist.

Die anweisungsbasierte Replikation kann beim Serverstart entweder durch Angabe von --binlog-format=statement oder durch vollständiges Weglassen der Option --binlog-format ausgewählt werden.

Die datensatzbasierte Replikation bewirkt, dass die meisten Änderungen unter Verwendung des datensatzbasierten Formats in das Binärlog geschrieben werden. Allerdings müssen einige Änderungen auch als Anweisungen in das Binärlog geschrieben werden:

  • ANALYZE TABLE

  • REPAIR TABLE

  • OPTIMIZE TABLE

Die Option --binlog-row-event-max-size ist für Server verfügbar, die die datensatzbasierte Replikation unterstützen. Datensätze werden in Blöcken von einer Größe in das Binärlog geschrieben, die den Wert dieser Option nicht übersteigt. Der Wert muss ein Vielfaches von 256 sein, Standard ist 1024.

6.4. Replikation: Implementationsdetails

Die MySQL-Replikation wird unter Verwendung von drei Threads implementiert: einem auf dem Master und zweien auf dem Slave. Wenn eine START SLAVE-Anweisung auf einem Slave-Server abgesetzt wird, erstellt der Slave einen I/O-Thread, der eine Verbindung zum Master herstellt und ihn auffordert, die in seinen Binärlogs aufgezeichneten Änderungen zu senden. Der Master erstellt daraufhin einen Thread, um die Inhalte des Binärlogs an den Slave zu senden. Dieser Thread erscheint als Binlog Dump in der Ausgabe von SHOW PROCESSLIST auf dem Master. Der Slave-I/O-Thread liest die Aktualisierungen, die der Binlog Dump-Thread des Masters sendet, und kopiert diese in lokale Dateien, die Relay-Logs heißen und sich im Datenverzeichnis des Slaves befinden. Der dritte Thread ist der SQL-Thread, den der Slave erstellt, um die Relay-Logs zu lesen und die enthaltenen Aktualisierungen auszuführen.

In der vorhergehenden Beschreibung wurden drei Threads pro Master/Slave-Verbindung beschrieben. Ein Master, der mehrere Slaves hat, erstellt einen Thread pro aktuell angeschlossenem Slave, und jeder Slave hat seine eigenen I/O- und SQL-Threads.

Der Slave verwendet zwei Threads, d. h., das Lesen der Updates vom Master und ihre Ausführung können auf zwei unabhängige Tasks verteilt werden. Auf diese Weise wird der Task zum Lesen der Anweisungen auch dann nicht verlangsamt, wenn die Anweisungsausführung selbst langsam erfolgt. Wenn beispielsweise der Slave-Server eine Zeit lang nicht ausgeführt wurde und dann gestartet wird, kann sein I/O-Thread schnell alle Inhalte des Binärlogs vom Master holen – und zwar auch dann, wenn der SQL-Thread nicht mitkommt. Sollte der Slave beendet werden, bevor der SQL-Thread alle erhaltenen Anweisungen ausgeführt hat, so hat der I/O-Thread zumindest alles abgerufen, d. h., eine sichere Kopie der Anweisungen ist lokal in den Relay-Logs auf dem Slave gespeichert und kann beim nächsten Start des Servers direkt ausgeführt werden. Auf diese Weise kann der Master-Server seine Binärlogs schneller bereinigen, da er nicht mehr warten muss, bis der Slave die Inhalte abgerufen hat.

Die SHOW PROCESSLIST-Anweisung vermittelt Informationen dazu, welche replikationsbezogenen Vorgänge auf Master und Slave ablaufen. Das folgende Beispiel veranschaulicht, wie die drei Threads in der Ausgabe von SHOW PROCESSLIST erscheinen.

Auf dem Master-Server sieht die Ausgabe von SHOW PROCESSLIST wie folgt aus:

  mysql> SHOW PROCESSLIST\G
  *************************** 1. row ***************************
  Id: 2
  User: root
  Host: localhost:32931
  db: NULL
  Command: Binlog Dump
  Time: 94
  State: Has sent all binlog to slave; waiting for binlog to
  be updated
  Info: NULL

Hierbei ist Thread 2 ein Binlog Dump-Replikations-Thread für einen angeschlossenen Slave. State gibt an, dass alle anhängigen Aktualisierungen an den Slave gesendet wurden und der Master darauf wartet, dass neue Änderungen stattfinden. Wenn keine Binlog Dump-Threads auf einem Master vorhanden sind, bedeutet dies, dass die Replikation nicht ausgeführt wird, d. h., es sind derzeit keine Slaves angebunden.

Auf dem Slave-Server sieht die Ausgabe von SHOW PROCESSLIST wie folgt aus:

  *************************** 1. row ***************************
  Id: 10
  User: system user
  Host:
  db: NULL
  Command: Connect
  Time: 11
  State: Waiting for master to send event
  Info: NULL
  *************************** 2. row ***************************
  Id: 11
  User: system user
  Host:
  db: NULL
  Command: Connect
  Time: 11
  State: Has read all relay log; waiting for the slave I/O
  thread to update it
  Info: NULL

Hieraus ist ersichtlich, dass Thread 10 der I/O-Thread ist, der mit dem Master-Server kommuniziert. Thread 11 ist der SQL-Thread, der die Updates verarbeitet, die in den Relay-Logs gespeichert sind. Zum Zeitpunkt der Ausführung von SHOW PROCESSLIST waren beide Threads beschäftigungslos und warteten auf weitere Aktualisierungen.

Der Wert in der Spalte Time zeigt ggf., wie groß der Rückstand zwischen Slave und Master ist. Siehe auch Abschnitt 6.11, „Replikation: häufig gestellte Fragen“.

6.4.1. Thread-Zustände des Replikationsmasters

Die folgende Liste zeigt die häufigsten Statusangaben, die in der Spalte State für den Binlog Dump-Thread des Masters erscheinen können. Wenn keine Binlog Dump-Threads auf einem Master vorhanden sind, bedeutet dies, dass die Replikation nicht ausgeführt wird, d. h., es sind derzeit keine Slaves angebunden.

  • Sending binlog event to slave

    Binärlogs enthalten Ereignisse, wobei ein Ereignis normalerweise eine Änderung sowie zugehörige Informationen umfasst. Der Thread hat ein Ereignis aus dem Binärlog gelesen und sendet dieses nun an den Slave.

  • Finished reading one binlog; switching to next binlog

    Der Thread hat das Lesen einer Binärlogdatei beendet und öffnet die nächste, um sie an den Slave zu senden.

  • Has sent all binlog to slave; waiting for binlog to be updated

    Der Thread hat alle anhängigen Updates aus den Binärlogs gelesen und an den Slave gesendet. Er ist nun untätig und wartet auf neue Ereignisse, die aufgrund von Änderungen am Master in das Binärlog geschrieben werden.

  • Waiting to finalize termination

    Eine nur ganz kurz angezeigte Statusangabe, die besagt, dass der Thread gerade beendet wird.

6.4.2. I/O-Thread-Zustände von Replikationsslaves

Die folgende Liste zeigt die häufigsten Statusangaben, die in der Spalte State für den I/O-Thread auf dem Slave-Server erscheinen können. Dieser Status erscheint auch in der Spalte Slave_IO_State, die von SHOW SLAVE STATUS angezeigt wird. Sie können also mit dieser Anweisung einen guten Eindruck davon erhalten, was gerade passiert.

  • Connecting to master

    Der Thread versucht, eine Verbindung zum Master herzustellen.

  • Checking master version

    Eine Statusangabe, die nur ganz kurz angezeigt wird, nachdem die Verbindung zum Master erfolgreich hergestellt werden konnte.

  • Registering slave on master

    Eine Statusangabe, die nur ganz kurz angezeigt wird, nachdem die Verbindung zum Master erfolgreich hergestellt werden konnte.

  • Requesting binlog dump

    Eine Statusangabe, die nur ganz kurz angezeigt wird, nachdem die Verbindung zum Master erfolgreich hergestellt werden konnte. Der Thread fordert beim Master die Inhalte der Binärlogs beginnend bei der angegebenen Binärlogdatei und Position an.

  • Waiting to reconnect after a failed binlog dump request

    Wenn die Anforderung des Binärlogs fehlgeschlagen ist (etwa aufgrund eines Verbindungsabbruchs), dann wechselt der Thread in diesen Status, solange er schläft, versucht aber in regelmäßigen Abständen, die Verbindung wiederherzustellen. Das Intervall zwischen den Verbindungsversuchen kann mit der Option --master-connect-retry angegeben werden.

  • Reconnecting after a failed binlog dump request

    Der Thread versucht, erneut eine Verbindung zum Master herzustellen.

  • Waiting for master to send event

    Der Thread hat die Verbindung zum Master hergestellt und wartet auf das Eintreffen von Binärlogereignissen. Dies kann recht lange dauern, wenn der Master untätig ist. Dauert der Wartevorgang länger als slave_read_timeout Sekunden, dann tritt eine Zeitüberschreitung auf. Der Thread geht dann davon aus, dass die Verbindung abgebrochen ist, und versucht, sie neu herzustellen.

  • Queueing master event to the relay log

    Der Thread hat ein Ereignis gelesen und kopiert es in sein Relay-Log, damit der SQL-Thread es verarbeiten kann.

  • Waiting to reconnect after a failed master event read

    Ein Lesefehler ist aufgetreten (aufgrund eines Verbindungsabbruchs). Der Thread schläft für master-connect-retry Sekunden und versucht dann, die Verbindung neu herzustellen.

  • Reconnecting after a failed master event read

    Der Thread versucht, erneut eine Verbindung zum Master herzustellen. Wenn die Verbindung wiederhergestellt werden konnte, wechselt der Status zu Waiting for master to send event.

  • Waiting for the slave SQL thread to free enough relay log space

    Sie verwenden einen relay_log_space_limit-Wert ungleich null. Die Relay-Logs sind in ihrer Summe auf eine Größe angewachsen, die diesen Wert überschreitet. Der I/O-Thread wartet, bis der SQL-Thread durch die Verarbeitung von Relay-Log-Inhalten genug Speicher freigegeben hat, sodass Relay-Logs gelöscht werden können.

  • Waiting for slave mutex on exit

    Eine Statusangabe, die beim Beenden des Threads ganz kurz angezeigt wird.

6.4.3. SQL-Thread-Zustände von Replikationsslaves

Die folgende Liste zeigt die häufigsten Statusangaben, die in der Spalte State für den SQL-Thread auf dem Slave-Server erscheinen können.

  • Reading event from the relay log

    Der Thread hat ein Ereignis aus dem Relay-Log gelesen, sodass dieses Ereignis verarbeitet werden kann.

  • Has read all relay log; waiting for the slave I/O thread to update it

    Der Thread hat alle Ereignisse in den Relay-Log-Dateien verarbeitet und wartet nun darauf, dass der I/O-Thread neue Ereignisse in das Relay-Log schreibt.

  • Waiting for slave mutex on exit

    Eine nur ganz kurz angezeigte Statusangabe, die besagt, dass der Thread gerade beendet wird.

Die Spalte State für den I/O-Thread kann auch den Text einer Anweisung anzeigen. Das bedeutet, dass der Thread ein Ereignis aus dem Relay-Log gelesen und die Anweisung daraus extrahiert hat und diese nun ausführt.

6.4.4. Relay- und Statusdateien bei der Replikation

Standardmäßig haben Dateinamen von Relay-Logs die Form host_name-relay-bin.nnnnnn. Hierbei ist host_name der Name des Slave-Serverhosts und nnnnnn eine Sequenznummer. Aufeinander folgende Relay-Log-Dateien werden mit laufenden Sequenznummern beginnend bei 000001 erstellt. Der Slave verwendet eine Indexdatei, um die Übersicht über die derzeit verwendeten Relay-Log-Dateien zu behalten. Der Standardname der Relay-Log-Indexdatei lautet host_name-relay-bin.index. Standardmäßig erstellt der Slave-Server die Relay-Log-Dateien in seinem Datenverzeichnis. Die Standarddateinamen können mit den Serveroptionen --relay-log und --relay-log-index außer Kraft gesetzt werden. Siehe auch Abschnitt 6.9, „Replikationsoptionen in my.cnf“.

Relay-Logs haben dasselbe Format wie Binärlogs und können mit mysqlbinlog gelesen werden. Der SQL-Thread löscht eine Relay-Log-Datei automatisch, sobald er alle Ereignisse in dieser Datei ausgeführt hat und sie nicht mehr benötigt. Es gibt keine dedizierte Methode zum Löschen von Relay-Logs – der SQL-Thread kümmert sich selbst darum. Allerdings rotiert FLUSH LOGS die Relay-Logs, was Auswirkungen darauf hat, wann der SQL-Thread sie löscht.

Ein Slave-Server erstellt unter den folgenden Bedingungen eine neue Relay-Log-Datei:

  • bei jedem Start des I/O-Threads

  • wenn die Logs – beispielsweise mit FLUSH LOGS oder mysqladmin flush-logs – synchronisiert werden

  • wenn die aktuelle Relay-Log-Datei zu groß wird. Die Bedeutung von „zu groß“ ermitteln Sie wie folgt:

    • Wenn der Wert von max_relay_log_size größer als 0 ist, gibt er die maximale Größe einer Relay-Log-Datei an.

    • Wenn der Wert von max_relay_log_size 0 ist, bestimmt max_binlog_size die maximale Größe einer Relay-Log-Datei.

Ein Slave-Replikationsserver erstellt zwei weitere kleine Dateien im Datenverzeichnis. Diese Statusdateien heißen standardmäßig master.info und relay-log.info. Die Namen können mit den Optionen --master-info-file und --relay-log-info-file geändert werden. Siehe auch Abschnitt 6.9, „Replikationsoptionen in my.cnf“.

Die beiden Statusdateien enthalten Informationen wie die in der Ausgabe der Anweisung SHOW SLAVE STATUS gezeigte (siehe auch Abschnitt 13.6.2, „SQL-Anweisungen für die Steuerung von Slave-Servern“). Weil die Statusdateien auf der Festplatte gespeichert sind, überdauern sie das Herunterfahren des Slave-Servers. Beim nächsten Start des Servers liest er die beiden Dateien dann aus, um zu ermitteln, wie weit er beim Lesen der Binärlogs vom Master und bei der Verarbeitung der eigenen Relay-Logs gekommen ist.

Der I/O-Thread aktualisiert die Datei master.info. Die folgende Tabelle zeigt die Entsprechungen zwischen den Zeilen in der Datei und den von SHOW SLAVE STATUS angezeigten Spalten.

ZeileBeschreibung
1Anzahl der Zeilen in der Datei
2Master_Log_File
3Read_Master_Log_Pos
4Master_Host
5Master_User
6Passwort (wird von SHOW SLAVE STATUS nicht angezeigt)
7Master_Port
8Connect_Retry
9Master_SSL_Allowed
10Master_SSL_CA_File
11Master_SSL_CA_Path
12Master_SSL_Cert
13Master_SSL_Cipher
14Master_SSL_Key

Der SQL-Thread aktualisiert die Datei relay-log.info. Die folgende Tabelle zeigt die Entsprechungen zwischen den Zeilen in der Datei und den von SHOW SLAVE STATUS angezeigten Spalten.

ZeileBeschreibung
1Relay_Log_File
2Relay_Log_Pos
3Relay_Master_Log_File
4Exec_Master_Log_Pos

Wenn Sie die Daten des Slaves sichern, sollten Sie neben den Relay-Log-Dateien auch diese beiden Statusdateien sichern. Sie werden stets benötigt, um die Replikation nach Wiederherstellung der Daten auf dem Slave fortzusetzen. Wenn Sie die Relay-Logs verlieren, aber noch über die Datei relay-log.info verfügen, können Sie ermitteln, wie weit der SQL-Thread die Binärlogs des Masters bereits ausgeführt hatte. Dann können Sie den Slave durch Absetzen von CHANGE MASTER TO mit den Optionen MASTER_LOG_FILE und MASTER_LOG_POS anweisen, die Binärlogs von diesem Punkt an erneut zu lesen. (Dies setzt natürlich voraus, dass die Binärlogs noch auf dem Master-Server vorhanden sind.)

Wenn Ihr Slave Gegenstand der Replikation von LOAD DATA INFILE-Anweisungen ist, sollten Sie auch alle SQL_LOAD-*-Dateien sichern, die in dem vom Slave zu diesem Zweck verwendeten Verzeichnis vorhanden sind. Der Slave benötigt diese Dateien, um die Replikation unterbrochener LOAD DATA INFILE-Operationen fortzusetzen. Die Verzeichnisposition wird mit der Option --slave-load-tmpdir angegeben. Wird die Option nicht angegeben, dann bezeichnet der Wert der Systemvariablen tmpdir die Verzeichnisposition.

6.5. Wie man eine Replikation aufsetzt

Dieser Abschnitt beschreibt kurz, wie man die vollständige Replikation eines MySQL Servers konfiguriert. Es wird angenommen, dass Sie alle Datenbanken auf dem Master replizieren wollen und die Replikation zuvor noch nicht konfiguriert haben. Sie müssen Ihren Master-Server kurz herunterfahren, um die beschriebenen Schritte vollständig durchführen zu können.

Beschrieben wird der Vorgang für die Konfiguration eines einzelnen Slaves; mehrere Slaves können Sie konfigurieren, indem Sie die entsprechenden Schritte wiederholen.

Zwar ist diese Vorgehensweise die direkteste zur Konfiguration eines Slaves, sie ist aber nicht die einzige. Wenn Sie beispielsweise eine Momentaufnahme der Daten auf dem Master haben und auf diesem bereits die Serverkennung eingestellt und das binäre Loggen aktiviert ist, dann können Sie einen Slave konfigurieren, ohne den Master herunterzufahren oder auch nur Aktualisierungen zu unterbinden. Weitere Informationen finden Sie unter Abschnitt 6.11, „Replikation: häufig gestellte Fragen“.

Wenn Sie eine MySQL-Replikationskonfiguration administrieren wollen, sollten Sie dieses Kapitel vollständig lesen und alle Anweisungen ausprobieren, die in Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“, und Abschnitt 13.6.2, „SQL-Anweisungen für die Steuerung von Slave-Servern“, beschrieben sind. Ferner sollten Sie sich mit den Replikationsstartoptionen vertraut machen, die in Abschnitt 6.9, „Replikationsoptionen in my.cnf“, erläutert werden.

Hinweis: Diese Methode und einige der replikationsspezifischen SQL-Anweisungen, die in späteren Abschnitten beschrieben werden, erfordern die Berechtigung SUPER.

  1. Vergewissern Sie sich, dass die auf dem Master und dem Slave installierten MySQL-Versionen kompatibel im Sinne der in Abschnitt 6.6, „Replikation: Kompatibilität zwischen MySQL-Versionen“, aufgeführten Tabelle sind. Im Idealfall sollten Sie die jeweils aktuellste MySQL-Version sowohl auf dem Master als auch auf dem Slave verwenden.

    Wenn Sie auf ein Problem stoßen, melden Sie dieses bitte erst als Bug, nachdem Sie sich vergewissert haben, dass es auch im aktuellen MySQL-Release vorhanden ist.

  2. Konfigurieren Sie ein Konto auf dem Master-Server, über das der Slave eine Verbindung herstellen kann. Dieses Konto benötigt die Berechtigung REPLICATION SLAVE. Wenn das Konto ausschließlich zur Replikation verwendet wird (was wir empfehlen), dann brauchen Sie keine weiteren Berechtigungen zu gewähren.

    Nehmen wir nun an, dass Ihre Domäne mydomain.com heißt und dass Sie ein Konto mit dem Benutzernamen repl erstellen wollen, das Slave-Server unter Angabe des Passworts slavepass von einem beliebigen Host in Ihrer Domäne aus für den Zugriff auf den Master verwenden kann. Dieses Konto erstellen Sie mit folgender GRANT-Anweisung:

    mysql> GRANT REPLICATION SLAVE ON *.*
        -> TO 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
    

    Beabsichtigen Sie, die Anweisungen LOAD TABLE FROM MASTER oder LOAD DATA FROM MASTER auf dem Slave-Host zu verwenden, dann müssen Sie diesem Konto weitere Berechtigungen gewähren:

    • Gewähren Sie dem Konto die globalen Berechtigungen SUPER und RELOAD.

    • Gewähren Sie die Berechtigung SELECT für alle Tabellen, die Sie laden wollen. Alle Master-Tabellen, für die das Konto keine SELECT-Berechtigung hat, werden von LOAD DATA FROM MASTER ignoriert.

    Weitere Informationen zur Konfiguration von Benutzerkonten und Berechtigungen finden Sie in Abschnitt 5.9, „MySQL-Benutzerkontenverwaltung“.

  3. Synchronisieren Sie alle Tabellen und unterbinden Sie Schreibanweisungen, indem Sie eine FLUSH TABLES WITH READ LOCK-Anweisung ausführen:

    mysql> FLUSH TABLES WITH READ LOCK;
    

    Beachten Sie, dass FLUSH TABLES WITH READ LOCK bei InnoDB-Tabellen auch COMMIT-Operationen sperrt. Wenn Sie eine globale Lesesperre erwirkt haben, können Sie eine Dateisystem-Momentaufnahme Ihrer InnoDB-Tabellen erstellen. Intern (d. h. innerhalb der InnoDB-Speicher-Engine) ist diese Momentaufnahme nicht konsistent, weil die InnoDB-Caches nicht synchronisiert wurden, aber dies ist nicht weiter problematisch, weil InnoDB dieses Problem beim Start beseitigt und ein konsistentes Ergebnis abliefert. Das bedeutet, dass bei InnoDB die Wiederherstellung von Daten nach einem Absturz verlustfrei möglich ist, wenn der Neustart auf der Basis dieser Momentaufnahme erfolgt. Allerdings gibt es keine Möglichkeit, den MySQL Server zu beenden und gleichzeitig eine konsistente Momentaufnahme Ihrer InnoDB-Tabellen zu gewährleisten.

    Lassen Sie den Client laufen, von dem aus Sie die FLUSH TABLES-Anweisung absetzen, damit die Lesesperre aktiv bleibt. (Wenn Sie den Client beenden, wird die Sperre aufgehoben.) Erstellen Sie nun eine Momentaufnahme der Daten auf Ihrem Master-Server.

    Die einfachste Möglichkeit zur Erstellung einer Momentaufnahme ist die Verwendung eines Archivierungsprogramms: Hiermit erstellen Sie eine binäre Sicherung der Datenbanken im Datenverzeichnis Ihres Master-Servers. Sie können beispielsweise tar unter Unix oder PowerArchiver, WinRAR, WinZip oder eine ähnliche Software unter Windows verwenden. Um mit tar ein Archiv zu erstellen, das alle Datenbanken enthält, wechseln Sie in das Datenverzeichnis des Master-Servers und führen dann folgenden Befehl aus:

    shell> tar -cvf /tmp/mysql-snapshot.tar .
    

    Wollen Sie, dass das Archiv nur eine Datenbank namens this_db enthält, dann verwenden Sie stattdessen folgenden Befehl:

    shell> tar -cvf /tmp/mysql-snapshot.tar ./this_db
    

    Danach kopieren Sie die Archivdatei in das Verzeichnis /tmp auf dem Slave-Serverhost. Auf diesem System wechseln Sie nun in das Datenverzeichnis des Slaves und entpacken die Archivdatei mithilfe des folgenden Befehls:

    shell> tar -xvf /tmp/mysql-snapshot.tar
    

    Wenn auf dem Slave-Server andere Benutzerkonten als auf dem Master vorhanden sind, sollten Sie die Datenbank mysql unter Umständen nicht replizieren. In diesem Fall sollten Sie sie aus dem Archiv ausschließen. Ferner sollten Sie weder Logdateien noch die Dateien master.info oder relay-log.info in das Archiv einfügen.

    Während die mit FLUSH TABLES WITH READ LOCK erwirkte Lesesperre gültig ist, lesen Sie den Namen des aktuellen Binärlogs und den Versatz auf dem Master aus:

    mysql > SHOW MASTER STATUS;
    +---------------+----------+--------------+------------------+
    | File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +---------------+----------+--------------+------------------+
    | mysql-bin.003 | 73       | test         | manual,mysql     |
    +---------------+----------+--------------+------------------+
    

    Die Spalte File zeigt den Namen der Logdatei an, Position den Versatz innerhalb der Datei. In diesem Beispiel heißt die Binärlogdatei mysql-bin.003, der Versatz ist 73. Notieren Sie diese Werte. Sie benötigen sie später beim Konfigurieren des Slaves. Die Werte stellen die Replikationskoordinaten dar, bei denen der Slave die Verarbeitung neuer Updates vom Master startet.

    Wenn der Master zuvor ohne aktiviertes Binärloggen ausgeführt wurde, sind die von SHOW MASTER STATUS oder mysqldump --master-data angezeigten Werte für Lognamen und Position leer. In diesem Fall lauten die Werte, die Sie später als Logdateinamen und Position auf dem Slave angeben müssen, '' (Leer-String) und 4.

    Nachdem Sie die Momentaufnahme erstellt und Lognamen und Versatz aufgezeichnet haben, können Sie die Schreibaktivitäten auf dem Master neu starten:

    mysql> UNLOCK TABLES;
    

    Wenn Sie InnoDB-Tabellen einsetzen, sollten Sie im Idealfall das Tool InnoDB Hot Backup verwenden, welches ohne Sperre auf dem Master-Server eine konsistente Momentaufnahme erstellt und Lognamen und Versatz passend für die Momentaufnahme speichert, sodass die Angaben später auf dem Slave benutzt werden können. Hot Backup ist ein kommerzielles (d. h. nicht kostenloses) Zusatztool, das nicht Bestandteil der MySQL-Standarddistribution ist. Weitere Informationen finden Sie auf der Homepage von InnoDB Hot Backup unter http://www.innodb.com/manual.php.

    Wenn Sie Hot Backup nicht einsetzen, besteht die schnellste Methode zur Erstellung einer binären Momentaufnahme der InnoDB-Tabellen darin, den Master-Server herunterzufahren und die Datendateien, Logdateien und Tabellenformatdateien (.frm) von InnoDB zu kopieren. Um den aktuellen Logdateinamen und den Versatz aufzuzeichnen, sollten Sie folgende Anweisungen absetzen, bevor Sie den Server herunterfahren:

    mysql> FLUSH TABLES WITH READ LOCK;
    mysql> SHOW MASTER STATUS;
    

    Dann notieren Sie Lognamen und Versatz aus der Ausgabe von SHOW MASTER STATUS wie oben beschrieben. Danach fahren Sie den Server herunter, ohne die Tabellen zu entsperren; hierdurch ist sicherstellt, dass der Server mit einem Status beendet wird, der den Angaben zu Logdatei und Versatz entspricht:

    shell> mysqladmin -u root shutdown
    

    Eine Alternative, die sowohl bei MyISAM- als auch bei InnoDB-Tabellen funktioniert, besteht darin, einen SQL-Speicherauszug des Masters anstatt – wie oben beschrieben – einer binären Kopie zu erstellen. Hierzu führen Sie mysqldump --master-data auf dem Master aus und laden die SQL-Speicherauszugsdatei später in Ihren Slave. Allerdings ist die Erstellung einer binären Kopie schneller.

  4. Vergewissern Sie sich, dass der Abschnitt [mysqld] der Datei my.cnf auf dem Master-Host die Option log-bin enthält. Der Abschnitt sollte ferner eine Option server-id=master_id enthalten, wobei master_id ein positiver Integer zwischen 1 und 232 – 1 sein muss. Zum Beispiel:

    [mysqld]
    log-bin=mysql-bin
    server-id=1
    

    Wenn diese Optionen nicht vorhanden sind, fügen Sie sie hinzu und starten den Server neu. Der Server kann erst als Replikationsmaster agieren, wenn das binäre Loggen aktiviert ist.

    Hinweis: Um die größtmögliche Dauerhaftigkeit und Konsistenz in einer Replikationskonfiguration für InnoDB mit Transaktionen zu erzielen, sollten Sie innodb_flush_log_at_trx_commit=1 und sync_binlog=1 in der Datei my.cnf auf dem Master angeben.

  5. Beenden Sie den Server, der als Slave vorgesehen ist, und fügen Sie in seiner Datei my.cnf die folgenden Zeilen hinzu:

    [mysqld]
    server-id=slave_id
    

    Der Wert slave_id muss wie master_id auch ein positiver Integer zwischen 1 und 232 – 1 sein. Ferner muss sich die Kennung des Slaves von der des Masters unterscheiden. Zum Beispiel:

    [mysqld]
    server-id=2
    

    Wenn Sie mehrere Slaves konfigurieren, muss jeder einen eindeutigen server-id-Wert haben, der sich von dem des Masters und von denen aller anderen Slaves unterscheidet. Betrachten Sie server-id-Werte als etwas Ähnliches wie IP-Adressen: Diese Kennungen identifizieren jede Serverinstanz in der Gruppe der Replikationspartner eindeutig.

    Wenn Sie keinen server-id-Wert angeben, wird er auf 1 gesetzt, sofern Sie master-host nicht definiert haben; andernfalls wird der Wert auf 2 gesetzt. Beachten Sie, dass, wenn Sie server-id weglassen, ein Master Verbindungen aller Slaves abweist und auch ein Slave sich weigert, eine Verbindung mit einem Master herzustellen. Auf diese Weise ist das Übergehen von server-id nur für ein Backup mit einem Binärlog geeignet.

  6. Wenn Sie eine binäre Sicherung der Daten auf dem Master-Server erstellt haben, kopieren Sie sie in das Datenverzeichnis des Slaves, bevor Sie diesen starten. Stellen Sie sicher, dass die Berechtigungen für Dateien und Verzeichnisse korrekt sind. Das Systemkonto, über das Sie den Slave-Server ausführen, muss die Dateien wie beim Master auch lesen und schreiben können.

    Wenn Sie ein Backup mit mysqldump erstellen, starten Sie den Slave zuerst. Die Speicherauszugsdatei wird in einem späteren Schritt geladen.

  7. Starten Sie den Slave-Server. Erfolgte bereits früher eine Replikation, dann starten Sie den Slave mit der Option --skip-slave-start, damit er nicht sofort versucht, eine Verbindung mit dem Master herzustellen. Sie sollten den Slave-Server außerdem mit der Option --log-warnings starten, um im Falle von Problemen (z. B. Netzwerk- oder Verbindungsproblemen) mehr Meldungen im Fehlerlog zu erhalten. Die Option ist standardmäßig aktiviert, aber abgebrochene Verbindungen werden nicht im Fehlerlog vermerkt, sofern der Optionswert nicht größer als 1 ist.

  8. Wenn Sie mit mysqldump ein Backup der Daten auf dem Master-Server erstellt haben, laden Sie die Speicherauszugsdatei in den Slave-Server:

    shell> mysql -u root -p < dump_file.sql
    
  9. Führen Sie die folgende Anweisung auf dem Slave aus und ersetzen Sie dabei die Optionswerte durch die für Ihr System geeigneten Werte:

    mysql> CHANGE MASTER TO
        -> MASTER_HOST='master_host_name',
        -> MASTER_USER='replication_user_name',
        -> MASTER_PASSWORD='replication_password',
        -> MASTER_LOG_FILE='recorded_log_file_name',
        -> MASTER_LOG_POS=recorded_log_position;
    

    Die folgende Tabelle zeigt die maximal zulässige Länge bei Optionen, die String-Werte enthalten:

    MASTER_HOST60
    MASTER_USER16
    MASTER_PASSWORD32
    MASTER_LOG_FILE255
  10. Starten Sie die Slave-Threads:

    mysql> START SLAVE;
    

Nachdem Sie diesen Vorgang durchgeführt haben, sollte der Slave eine Verbindung mit dem Master herstellen und alle Updates nachholen, die seit Erstellung der Momentaufnahme erstellt wurden.

Wenn Sie es versäumt haben, die Option server-id für den Master einzustellen, dann können Slaves keine Verbindung herstellen.

Wenn Sie es versäumt haben, die Option server-id für den Slave einzustellen, dann erhalten Sie im Fehlerlog des Slaves die folgende Meldung:

Warning: You should set server-id to a non-0 value if master_host
is set; we will force server id to 2, but this MySQL server will
not act as a slave.

Ferner werden Sie Fehlermeldungen im Fehlerlog des Slaves vorfinden, wenn eine Replikation aus irgendeinem anderen Grund nicht möglich ist.

Sobald ein Slave mit der Replikation begonnen hat, finden Sie in seinem Datenverzeichnis zwei Dateien namens master.info und relay-log.info. Der Slave verwendet diese beiden Dateien, um zu vermerken, welcher Anteil des Master-Binärlogs bereits verarbeitet wurde. Sie dürfen diese Dateien keinesfalls entfernen oder bearbeiten, sofern Sie nicht genau wissen, was Sie tun und welche Auswirkungen dies haben kann. Und auch in diesem Fall sollten Sie besser die CHANGE MASTER TO-Anweisung verwenden, um die Replikationsparameter zu ändern. Der Slave aktualisiert die Statusdateien automatisch entsprechend den Werten, die in dieser Anweisung angegeben sind.

Hinweis: Der Inhalt von master.info setzt einige der Serveroptionen, die auf der Befehlszeile oder in der Datei my.cnf angegeben sind, außer Kraft. Weitere Informationen finden Sie in Abschnitt 6.9, „Replikationsoptionen in my.cnf“.

Sobald Sie über eine Momentaufnahme des Masters verfügen, können Sie diese zur Konfiguration weiterer Slaves verwenden. Folgen Sie dabei einfach der oben beschriebenen Anleitung. Sie müssen also keine neue Momentaufnahme erstellen, sondern können dieselbe auch für jeden weiteren Slave verwenden.

6.6. Replikation: Kompatibilität zwischen MySQL-Versionen

Das Binärlogformat, wie es in MySQL 5.1 implementiert ist, unterscheidet sich erheblich von dem vorheriger Versionen. Dies gilt insbesondere für den Umgang mit Zeichensätzen, LOAD DATA INFILE und Zeitzonen.

Wir empfehlen die Verwendung der jeweils aktuellen MySQL-Version, weil die Replikationsfunktionen kontinuierlich verbessert werden. Ferner empfehlen wir die Verwendung derselben Version auf Master und Slave. Empfohlen wird außerdem die Aktualisierung von Mastern und Slaves, die unter Alpha- oder Betaversionen laufen, auf neue (Produktions-)Versionen. In vielen Fällen schlägt die Replikation von einem neueren Master auf einen älteren Slave fehl. Generell können Slaves, die unter MySQL 5.1.x laufen, mit älteren Mastern (sogar solchen unter MySQL 3.23, 4.0 oder 4.1) verwendet werden, nicht jedoch umgekehrt.

Hinweis: Sie dürfen keinesfalls eine Replikation von einem Master, der ein neueres Binärlogformat aufweist, auf einen Slave durchführen, der ein älteres Format benutzt (z. B. von MySQL 5.0 auf MySQL 4.1). Dies hat gravierende Auswirkungen auf die Aktualisierung von Replikationsservern (siehe auch Abschnitt 6.7, „Upgrade eines Replikationssetups“).

Diese Angaben beziehen sich auf die Replikationskompatibilität auf Protokollebene. Es gibt weitere Einschränkungen, z. B. bei Fragen der Kompatibilität auf SQL-Ebene. So kann etwa ein Master unter 5.1 keine Replikation auf einen Slave unter 5.0 durchführen, wenn die replizierten Anweisungen SQL-Funktionen verwenden, die zwar in 5.1, nicht aber in 5.0 vorhanden sind. Diese und andere Probleme werden in Abschnitt 6.8, „Replikation: Features und bekannte Probleme“, behandelt.

6.7. Upgrade eines Replikationssetups

Wenn Sie Server aktualisieren, die Bestandteile einer Replikationskonfiguration sind, hängt die Vorgehensweise zur Aktualisierung von den aktuellen Serverversionen und der Version ab, auf die Sie aktualisieren.

6.7.1. Replikation: Upgrade auf 5.0

Dieser Abschnitt betrifft die Aktualisierung der Replikation von MySQL 3.23, 4.0 oder 4.1 auf MySQL 5.1. Ein 4.0-Server sollte unter Version 4.0.3 oder höher laufen.

Wenn Sie einen Master von einer früheren MySQL-Release-Serie auf 5.1 aktualisieren, dann müssen Sie zuallererst einmal gewährleisten, dass alle Slaves dieses Masters denselben 5.1.x-Release verwenden. Ist dies nicht der Fall, dann sollten Sie zuerst die Slaves aktualisieren. Um einen Slave zu aktualisieren, fahren Sie ihn herunter, aktualisieren ihn auf die entsprechende Version 5.1.x und starten nachfolgend zunächst den Server und dann die Replikation neu. Der 5.1-Slave kann alte Relay-Logs, die vor dem Upgrade geschrieben wurden, lesen und die enthaltenen Anweisungen ausführen. Relay-Logs, die vom Slave nach dem Upgrade erstellt wurden, haben bereits das 5.1-Format.

Nachdem die Slaves aktualisiert wurden, fahren Sie den Master herunter, aktualisieren ihn auf denselben 5.1.x-Release wie die Slaves und starten ihn dann neu. Der 5.1-Master kann alte Binärlogs, die vor dem Upgrade geschrieben wurden, lesen und an die 5.1-Slaves schicken. Die Slaves erkennen das alte Format und verarbeiten es entsprechend. Binärlogs, die vom Master nach dem Upgrade erstellt wurden, haben bereits das 5.1-Format. Auch diese werden von den 5.1-Slaves erkannt.

Es sind also bei der Aktualisierung auf MySQL 5.1 keine weiteren Maßnahmen durchzuführen – Sie müssen lediglich beachten, dass Sie ggf. zuerst die Slaves auf MySQL 5.1 aktualisieren, bevor Sie dies beim Master tun. Beachten Sie, dass ein Downgrade von 5.1 auf ältere Versionen nicht so einfach ist: Sie müssen gewährleisten, dass alle Binär- und Relay-Logs im 5.1-Format vollständig verarbeitet wurden, damit Sie sie entfernen können, bevor Sie mit dem Downgrade fortfahren.

Das Downgrade einer Replikationskonfiguration auf eine ältere Version ist nicht mehr möglich, wenn Sie von der anweisungs- auf die datensatzbasierte Replikation umgestellt haben und die erste datensatzbasierte Anweisung in das Binärlog geschrieben wurde. Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“.

6.8. Replikation: Features und bekannte Probleme

Generell erfordert die Replikationskompatibilität auf SQL-Ebene, dass alle verwendeten Funktionen sowohl vom Master als auch vom Slave unterstützt werden. Wenn Sie eine Funktion auf einem Master-Server verwenden, die nur ab einer bestimmten MySQL-Version verfügbar ist, dann können Sie keine Replikation auf einen Slave vornehmen, der älter ist als diese Version. Derartige Inkompatibilitäten treten häufig zwischen verschiedenen Serien auf. So können Sie beispielsweise keine Replikation von MySQL 5.1 auf 5.0 durchführen. Allerdings können solche Inkompatibilitäten auch innerhalb derselben Serie auftreten. So ist beispielsweise die Funktion SLEEP() seit MySQL 5.0.12 verfügbar. Wenn Sie diese Funktion auf dem Master-Server verwenden, können Sie sie nicht auf einen Slave replizieren, der älter ist als MySQL 5.0.12.

Beabsichtigen Sie, die Replikation zwischen MySQL 5.1 und einer älteren Version durchzuführen, dann sollten Sie im MySQL-Referenzhandbuch zu dieser älteren Release-Serie nach Informationen zu den Replikationseigenschaften dieser Serie suchen.

Die folgende Liste enthält genauere Angaben dazu, was unterstützt wird und was nicht. Zusätzliche InnoDB-spezifische Informationen zur Replikation finden Sie in Abschnitt 14.2.6.5, „InnoDB und MySQL-Replikation“.

Bei der klassischen anweisungsbasierten Replikation kann es Probleme mit der Replikation gespeicherter Routinen geben. Diese Probleme können Sie umgehen, indem Sie stattdessen die datensatzbasierte Replikation benutzen. Eine umfassende Liste möglicher Probleme finden Sie unter Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“. Eine Beschreibung der datensatzbasierten Replikation finden Sie in Abschnitt 6.3, „Zeilenbasierte Replikation“.

  • Die Replikation von AUTO_INCREMENT-, LAST_INSERT_ID()- und TIMESTAMP-Werten erfolgt korrekt.

  • Die Funktionen USER(), UUID() und LOAD_FILE() werden ohne Änderung repliziert und funktionieren daher nur dann korrekt auf dem Slave, wenn die datensatzbasierte Replikation aktiviert ist. (Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“.)

  • Die folgende Beschränkung gilt nur für die anweisungsbasierte, nicht für die datensatzbasierte Replikation. Die Funktionen GET_LOCK(), RELEASE_LOCK(), IS_FREE_LOCK() und IS_USED_LOCK(), die Sperren auf Benutzerebene verwalten, werden repliziert, ohne dass der Slave den zugehörigen Kontext auf dem Master kennt. Aus diesem Grund sollten diese Funktionen nicht zum Einfügen in eine Tabelle auf dem Master verwendet werde, da der Kontext auf dem Slave ganz anders aussehen würde. (So sollten Sie etwa keine Anweisung wie INSERT INTO mytable VALUES(GET_LOCK(...)) absetzen.)

  • Die Variablen FOREIGN_KEY_CHECKS, SQL_MODE, UNIQUE_CHECKS und SQL_AUTO_IS_NULL werden (ab MySQL 5.0) alle repliziert. Die Systemvariable storage_engine (die auch table_type heißt) wird in MySQL 5.1 noch nicht repliziert, was für die Replikation zwischen verschiedenen Speicher-Engines von Vorteil ist.

  • Die Replikation funktioniert zwischen Mastern und Slaves unter MySQL 5.0 und 5.1 in beliebiger Kombination – auch dann, wenn Master und Slave unterschiedliche Werte für die Zeichensatz- und/oder die globalen Zeitzonenvariablen aufweisen. (Beachten Sie, dass dies nicht in Fällen zutrifft, in denen Master und/oder Slave unter MySQL 4.1 oder früher laufen.)

  • Folgendes gilt für die Replikation zwischen MySQL Servern, die unterschiedliche Zeichensätze benutzen:

    1. Wenn der Master MySQL 4.1 verwendet, müssen Sie immer dieselben globalen Werte für Zeichensatz und Sortierfolge auf dem Master und dem Slave verwenden – unabhängig davon, welche MySQL-Version auf dem Slave läuft. (Diese werden von den Optionen --character-set-server und --collation-server gesteuert.) Andernfalls kann es Fehler aufgrund von Schlüsseldubletten auf dem Slave geben, da ein Schlüssel, der im Zeichensatz des Masters eindeutig ist, dies im Zeichensatz des Slaves nicht unbedingt sein muss. Beachten Sie, dass dies keine Rolle mehr spielt, wenn Master und Slave beide unter MySQL 5.0 oder höher laufen.

    2. Wenn der Master älter ist als MySQL 4.1.3, dann sollte auf den beteiligten Clients kein anderer Zeichensatz als der global angegebene verwendet werden, weil der Slave eine solche Änderung des Zeichensatzes nicht bemerkt. Clients sollten also SET NAMES, SET CHARACTER SET usw. nicht benutzen. Wenn sowohl Master als auch Slave unter 4.1.3 oder höher laufen, können die Clients die zeichensatzbezogenen Sitzungsvariablen frei einstellen, da diese Werte in das Binärlog geschrieben und auf diese Weise dem Slave mitgeteilt werden. Clients können also SET NAMES oder SET CHARACTER SET verwenden oder Variablen wie COLLATION_CLIENT oder COLLATION_SERVER einstellen. Nicht ändern können Clients hingegen den globalen Wert dieser Variablen: Wie bereits gesagt, Master und Slave müssen für den globalen Zeichensatz immer identische Werte aufweisen.

    3. Wenn sich auf dem Master Datenbanken mit Zeichensätzen befinden, die sich vom globalen character_set_server-Wert unterscheiden, dann sollten Sie Ihre CREATE TABLE-Anweisungen so formulieren, dass Tabellen in diesen Datenbanken nicht implizit auf den Standardzeichensatz der Datenbank angewiesen sind (siehe auch Bug 2326). Ein guter Workaround hierfür besteht darin, in der CREATE TABLE-Anweisung Zeichensatz und Sortierfolge explizit anzugeben.

  • Wenn der Master MySQL 4.1 verwendet, dann sollte auf Master und Slave dieselbe Systemzeitzone eingestellt sein. Andernfalls werden einige Anweisungen – wie etwa solche, die die Funktionen NOW() oder FROM_UNIXTIME() verwenden – nicht korrekt repliziert. Sie können die Zeitzone, in der der MySQL Server läuft, mit der Option --timezone=timezone_name des Skripts mysqld_safe oder durch Einstellen der Umgebungsvariablen TZ ändern. Master und Slave sollten ferner auch dieselbe Standardeinstellung für die Verbindungszeitzone aufweisen, d. h., der Wert des Parameters --default-time-zone sollte auf Master und Slave gleich sein. Beachten Sie, dass dies nicht notwendig ist, wenn der Master unter MySQL 5.0 oder höher läuft.

  • CONVERT_TZ(...,...,@session.time_zone) wird nur dann korrekt repliziert, wenn Master und Slave unter MySQL 5.0.4 oder höher laufen.

  • Sitzungsvariablen werden nicht korrekt repliziert, wenn sie in Anweisungen verwendet werden, die Tabellen aktualisieren. So fügt SET MAX_JOIN_SIZE=1000 gefolgt von INSERT INTO mytable VALUES(@MAX_JOIN_SIZE) auf dem Master nicht dieselben Daten ein wie auf dem Slave. Dies betrifft allerdings nicht die gängige Sequenz aus SET TIME_ZONE=... gefolgt von INSERT INTO mytable VALUES(CONVERT_TZ(...,...,@time_zone)).

    Die Replikation von Sitzungsvariablen ist kein Problem, wenn die datensatzbasierte Replikation benutzt wird. Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“.

  • Es ist auch möglich, transaktionssichere Tabellen auf dem Master in nichttransaktionssichere Tabellen auf dem Slave zu replizieren. Sie können beispielsweise eine InnoDB-Tabelle auf dem Master als MyISAM-Tabelle auf dem Slave replizieren. Allerdings kommt es, wenn Sie dies tun, zu Problemen, wenn der Slave mitten in einem BEGIN/COMMIT-Block angehalten wird, weil er nachfolgend am Anfang des BEGIN-Blocks neu einstartet. Dieses Problem steht auf unserer Aufgabenliste und wird in Bälde behoben sein.

  • Änderungsanweisungen, die benutzerdefinierte Variablen (also Variablen des Typs @var_name) referenzieren, werden korrekt repliziert. (Dies gilt jedoch nicht für Versionen vor 4.1.) Beachten Sie, dass beginnend mit MySQL 5.0 bei den Namen von Benutzervariablen die Groß-/Kleinschreibung unterschieden wird, wenn Sie die Replikation zwischen MySQL 5.0 und älteren Versionen einrichten.

  • Slaves können unter Verwendung von SSL eine Verbindung zum Master herstellen.

  • Die globale Systemvariable slave_transaction_retries wirkt sich wie folgt auf die Replikation aus: Wenn ein SQL-Thread auf einem Replikationsslave eine Transaktion nicht ausführen kann, weil eine InnoDB-Blockade aufgetreten ist oder die Werte innodb_lock_wait_timeout von InnoDB bzw. TransactionDeadlockDetectionTimeout oder TransactionInactiveTimeout von NDBCluster überschritten wurden, erfolgt die durch slave_transaction_retries angegebene Anzahl von Neuversuchen, bevor der Vorgang mit einer Fehlermeldung beendet wird. Der Standardwert ist 10. Die Gesamtzahl der Neuversuche finden Sie in der Ausgabe von SHOW STATUS. (Siehe auch Abschnitt 5.2.4, „Server-Statusvariablen“.)

  • Wenn eine der Tabellenoptionen DATA DIRECTORY oder INDEX DIRECTORY in einer CREATE TABLE-Anweisung auf dem Master-Server verwendet wird, wird dieselbe Option auch auf dem Slave umgesetzt. Dies kann zu Problemen führen, wenn im Dateisystem des Slave-Hosts kein entsprechendes Verzeichnis vorhanden ist, oder wenn es zwar vorhanden ist, aber der Slave-Server nicht darauf zugreifen kann. MySQL unterstützt eine sql_mode-Option namens NO_DIR_IN_CREATE. Wenn dieser SQL-Modus am Slave-Server aktiviert ist, ignoriert der Slave die Tabellenoptionen DATA DIRECTORY und INDEX DIRECTORY beim Replizieren von CREATE TABLE-Anweisungen. Infolgedessen werden die MyISAM-Daten- und Indexdateien im Datenbankverzeichnis der Tabelle erstellt.

  • Die folgende Beschränkung betrifft nur die anweisungsbasierte Replikation, nicht die datensatzbasierte Replikation: Die Daten auf dem Master und dem Slave können verschieden werden, wenn eine Abfrage so formuliert wird, dass die Datenänderung nichtdeterministisch ist, d. h. dem Gutdünken des Abfrageoptimierers überlassen wird. (Dies ist auch abgesehen von der Replikation nicht zu empfehlen.) Eine umfassende Erläuterung dieses Problems finden Sie unter Abschnitt A.8.1, „Offene Probleme in MySQL“.

  • FLUSH LOGS, FLUSH MASTER, FLUSH SLAVE und FLUSH TABLES WITH READ LOCK werden nicht geloggt, weil dies bei der Replikation auf einen Slave Probleme verursachen würde. Ein Syntaxbeispiel finden Sie in Abschnitt 13.5.5.2, „FLUSH. Die Anweisungen FLUSH TABLES, ANALYZE TABLE, OPTIMIZE TABLE und REPAIR TABLE werden in das Binärlog geschrieben und infolgedessen auf die Slaves repliziert. Dies ist normalerweise unproblematisch, weil diese Anweisungen die Tabellendaten nicht verändern. Allerdings kann dies unter bestimmten Umständen trotzdem Probleme verursachen. Wenn Sie die Berechtigungstabellen in der mysql-Datenbank replizieren und diese Tabellen direkt und ohne Verwendung von GRANT aktualisieren, müssen Sie eine FLUSH PRIVILEGES-Anweisung auf den Slaves absetzen, damit die neuen Berechtigungen gültig werden. Ferner müssen Sie, wenn Sie FLUSH TABLES beim Umbenennen einer MyISAM-Tabelle absetzen, die Teil einer MERGE-Tabelle ist, auf den Slaves eine FLUSH TABLES-Anweisung manuell absetzen. Diese Anweisungen werden in das Binärlog geschrieben, sofern Sie nicht NO_WRITE_TO_BINLOG oder den Alias LOCAL angegeben haben.

  • MySQL unterstützt genau einen Master und mehrere Slaves. Zukünftig beabsichtigen wir, einen Votieralgorithmus hinzuzufügen, der den Master automatisch wechselt, falls Probleme in Verbindung mit dem aktuellen Master auftreten. Ferner werden wir Agentenprozesse zur Durchführung einer Lastverteilung implementieren, indem SELECT-Anweisungen an verschiedene Slaves gesendet werden.

  • Wenn ein Server heruntergefahren wird und neu startet, werden seine MEMORY-Tabellen geleert. Der Master repliziert diesen Effekt wie folgt auf seine Slaves: Wenn der Master eine MEMORY-Tabelle nach dem Start zum ersten Mal verwendet, loggt er ein Ereignis, welches den Slaves angibt, dass die Tabelle geleert werden muss, indem eine DELETE-Anweisung für die betreffende Tabelle in das Binärlog geschrieben wird. Weitere Informationen finden Sie in Abschnitt 14.4, „Die MEMORY-Speicher-Engine“.

  • Beachten Sie, dass das Folgende nicht gilt, wenn die datensatzbasierte Replikation verwendet wird, denn diese erfordert überhaupt keine Replikation von Temporärtabellen. (Siehe auch Abschnitt 6.3, „Zeilenbasierte Replikation“.)

    Temporärtabellen werden normalerweise repliziert. Eine Ausnahme liegt vor, wenn Sie den Slave-Server (und nicht nur die Slave-Threads) heruntergefahren und Temporärtabellen repliziert haben, die in Updates verwendet werden, welche noch nicht auf dem Slave ausgeführt wurden. Haben Sie den Slave-Server heruntergefahren, dann stehen die Temporärtabellen, die von diesen Aktualisierungen benötigt werden, beim Neustart des Servers nicht mehr zur Verfügung. Um dieses Problem zu umgehen, fahren Sie den Slave nicht herunter, solange Temporärtabellen geöffnet sind. Stattdessen wenden Sie folgende Vorgehensweise an:

    1. Setzen Sie eine STOP SLAVE-Anweisung ab.

    2. Überprüfen Sie mit SHOW STATUS den Wert der Variablen Slave_open_temp_tables.

    3. Wenn der Wert 0 ist, beenden Sie den Slave mit einem mysqladmin shutdown-Befehl.

    4. Ist der Wert nicht 0, dann starten Sie die Slave-Threads mit START SLAVE neu.

    5. Wiederholen Sie den Vorgang nachfolgend so oft, bis die Variable Slave_open_temp_tables 0 ist und Sie den Slave beenden können.

  • Die Verbindung mit Servern in einer Master/Slave-Zirkelbeziehung ist sicher, wenn Sie die Option --log-slave-updates benutzen. Das bedeutet, dass Sie eine Konfiguration wie die folgende erstellen können:

    A -> B -> C -> A
    

    Allerdings funktionieren viele Anweisungen in einer solchen Konfiguration nicht einwandfrei, sofern Ihr Code nicht so formuliert ist, dass potenzielle Probleme berücksichtigt werden, die aufgrund von auf verschiedenen Servern in unterschiedlicher Reihenfolge durchgeführten Updates entstehen können.

    Serverkennungen werden in Binärlogereignisse kodiert, d. h., Server A erkennt, wenn ein Ereignis, das er liest, ursprünglich von ihm selbst erstellt worden ist, und führt es dann nicht aus (es sei denn, Server A wurde mit der Option --replicate-same-server-id gestartet, die aber nur in wenigen Fällen wichtig ist). Es kommt also nicht zu Endlosschleifen. Eine solche Zirkelkonfiguration funktioniert nur, wenn Sie keine Updates durchführen, durch die es zu Konflikten zwischen Tabellen kommt: Wenn Sie Daten sowohl auf A als auch auf C einfügen, sollten Sie keinesfalls einen Datensatz auf A einfügen, dessen Schlüssel unter Umständen mit einem Datensatz auf C kollidiert. Ebenso wenig sollten Sie dieselben Datensätze auf zwei Servern aktualisieren, wenn die Reihenfolge, in der die Updates durchgeführt werden, von Bedeutung ist.

  • Wenn eine Anweisung auf einem Slave einen Fehler erzeugt, wird der Slave-SQL-Thread terminiert, und der Slave schreibt eine Meldung in sein Fehlerlog. In diesem Fall sollten Sie manuell eine Verbindung zum Slave herstellen und die Ursache des Problems bestimmen. (Hierfür ist SHOW SLAVE STATUS recht praktisch.) Danach beheben Sie das Problem (z. B. durch Erstellen einer nichtvorhandenen Tabelle) und führen dann START SLAVE aus.

  • Einen Master-Server herunterzufahren und später neu zu starten ist sicher. Wenn ein Slave seine Verbindung zum Master verliert, versucht er sofort eine Neuverbindung und wiederholt diesen Versuch in regelmäßigen Abständen, bis er erfolgreich ist. Standardmäßig erfolgt alle 60 Sekunden ein Versuch zur Neuverbindung. Dies lässt sich mit der Option --master-connect-retry ändern. Ein Slave kann auch mit Ausfällen der Netzwerkkonnektivität zurechtkommen. Allerdings bemerkt er einen solchen Ausfall erst, wenn er für slave_net_timeout Sekunden keine Daten vom Master empfangen hat. Sind die Ausfälle kurz, dann sollten Sie den Wert von slave_net_timeout verringern. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

  • Das (saubere) Herunterfahren des Slaves ist auch sicher, weil er vermerkt, an welcher Stelle er beendet wurde. Unsauberes Herunterfahren hingegen kann insbesondere dann Probleme verursachen, wenn der Festplatten-Cache vor Terminierung des Systems nicht auf die Festplatte geschrieben worden war. Ihre Systemfehlertoleranz erhöht sich erheblich, wenn Sie eine gute unterbrechungsfreie Stromversorgung verwenden. Eine unsaubere Beendigung des Masters kann Inkonsistenzen zwischen dem Inhalt der Tabellen und dem Binärlog auf dem Master zur Folge haben. Dies lässt sich durch Verwendung von InnoDB-Tabellen und der Option --innodb-safe-binlog auf dem Master vermeiden. Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

    Hinweis: --innodb-safe-binlog wird in MySQL 5.1 nicht benötigt, weil es durch die in MySQL 5.0 eingeführte Unterstützung von XA-Transaktionen obsolet geworden ist. Siehe auch Abschnitt 13.4.7, „XA-Transaktionen“.

  • Aufgrund des nichttransaktionssicheren Wesens von MyISAM-Tabellen kann es vorkommen, dass eine Anweisung eine Tabelle nur teilweise aktualisiert und dann einen Fehlercode zurückgibt. Dies kann beispielsweise beim Einfügen mehrerer Datensätze geschehen, wenn einer dieser Datensätze gegen einen Schlüssel-Constraint verstößt, oder wenn eine lange Update-Anweisung nach Aktualisierung einer Anzahl von Datensätzen terminiert wurde. Wenn dies auf dem Master passiert, wird der Slave-Thread beendet. Es liegt dann am Datenbankadministrator, zu entscheiden, was zu tun ist, sofern der Fehlercode nicht zulässig ist und die Ausführung der Anweisung auf dem Slave denselben Fehlercode verursacht. Wenn dieses Verhalten der Fehlercodeauswertung nicht gewünscht ist, können einige oder alle Fehler mit der Option --slave-skip-errors maskiert (d. h. ignoriert) werden.

  • Wenn Sie transaktionssichere Tabellen aus nichttransaktionssicheren Tabellen in einer BEGIN/COMMIT-Sequenz aktualisieren, sind die Änderungen im Binärlog unter Umständen nicht synchron zu den Tabellenzuständen, wenn die nichttransaktionssichere Tabelle aktualisiert wird, bevor die Transaktion übergeben wird. Die Ursache hierfür ist, dass die Transaktion erst dann in das Binärlog geschrieben wird, wenn sie übergeben wird.

  • In Situationen, in denen Transaktionen Updates für transaktionssichere und nichttransaktionssichere Tabellen vermischen, ist die Reihenfolge der Anweisungen im Binärlog korrekt, und alle erforderlichen Anweisungen werden – auch bei einem Rollback – in das Binärlog geschrieben. Aktualisiert allerdings eine zweite Verbindung die nichttransaktionssichere Tabelle, bevor die Transaktion der ersten Verbindung abgeschlossen ist, dann kann die geloggte Anweisungsreihenfolge falsch sein, weil die Änderung der zweiten Verbindung unmittelbar nach ihrer Ausführung geschrieben wird – unabhängig von dem Zustand der Transaktion, die von der ersten Verbindung durchgeführt wurde.

6.9. Replikationsoptionen in my.cnf

Dieser Abschnitt beschreibt die Optionen, die Sie auf Replikationsslaves verwenden können. Sie können diese Optionen wahlweise auf der Befehlszeile oder in einer Optionsdatei angeben.

Auf dem Master und jedem Slave müssen Sie die Option server-id angeben, um eine eindeutige Replikationskennung zu erstellen. Wählen Sie auf jedem Server eine eindeutige Zahl zwischen 1 und 232 – 1. Außerdem muss jede Kennung sich von jeder anderen Kennung unterscheiden. Zum Beispiel: server-id=3

Optionen, die Sie auf dem Master-Server zur Steuerung des binären Loggens verwenden können, sind in Abschnitt 5.12.3, „Die binäre Update-Logdatei“, beschrieben.

Einige Replikationsoptionen für Slave-Server werden in dem Sinne speziell gehandhabt, dass sie ignoriert werden, wenn beim Start des Slaves eine Datei master.info vorhanden ist und diese einen Wert für die betreffende Option enthält. Dies betrifft die folgenden Optionen:

  • --master-host

  • --master-user

  • --master-password

  • --master-port

  • --master-connect-retry

  • --master-ssl

  • --master-ssl-ca

  • --master-ssl-capath

  • --master-ssl-cert

  • --master-ssl-cipher

  • --master-ssl-key

Die Datei master.info in MySQL 5.1 enthält Werte, die den SSL-Optionen entsprechen. Daneben sieht das Format dieser Datei in der ersten Zeile auch die Nennung der Gesamtanzahl aller Zeilen in der Datei vor. Wenn Sie einen älteren Server (vor MySQL 4.1.1) auf eine neuere Version aktualisieren, setzt der neue Server die Datei master.info beim Start automatisch auf das neue Format. Wenn Sie hingegen ein Downgrade auf einen älteren Server durchführen, sollten Sie die erste Zeile manuell entfernen, bevor Sie den älteren Server zum ersten Mal starten.

Ist beim Start des Slave-Servers keine Datei master.info vorhanden, dann werden für diese Optionen die Werte verwendet, die in Optionsdateien oder auf der Befehlszeile angegeben wurden. Dies ist etwa der Fall, wenn Sie den Server zum ersten Mal als Replikationsslave starten, oder wenn Sie RESET SLAVE ausgeführt haben und den Slave nun herunterfahren und neu starten.

Ist die Datei master.info beim Start des Slaves vorhanden, dann verarbeitet der Server ihren Inhalt und ignoriert Werte, die für die in der Datei aufgeführten Optionen übergeben wurden. Wenn Sie den Slave-Server also mit anderen Werten für die Startoptionen starten als denen in der Datei master.info, dann haben die von Ihnen übergebenen Werte keine Auswirkung, weil der Server die Angaben der Datei master.info entnimmt. Um andere Werte verwenden zu können, müssen Sie entweder nach dem Entfernen der Datei master.info einen Neustart durchführen oder die Werte bei laufendem Slave-Server mit der Anweisung CHANGE MASTER TO zurücksetzen (Letztere ist die empfohlene Methode).

Angenommen, Sie geben folgende Option in Ihrer Datei my.cnf an:

[mysqld]
master-host=some_host

Wenn Sie den Server zum ersten Mal als Replikationsslave starten, liest und verwendet er diese Option aus der Datei my.cnf. Danach zeichnet der Server den Wert in der Datei master.info auf. Wenn Sie den Server beim nächsten Mal starten, liest er den Master-Hostwert nur aus der Datei master.info und ignoriert den Wert in der Optionsdatei. Wenn Sie später in der Datei my.cnf den anderen Master-Host some_other_host angeben, hat diese Änderung keine Auswirkungen. Sie müssen stattdessen CHANGE MASTER TO verwenden.

Da der Server einer vorhandenen Datei master.info Vorrang vor den gerade beschriebenen Startoptionen gewährt, sollten Sie diese Werte unter Umständen überhaupt nicht mit Startoptionen angeben, sondern sie stattdessen mit der CHANGE MASTER TO-Anweisung festlegen. Siehe auch Abschnitt 13.6.2.1, „CHANGE MASTER TO.

Dieses Beispiel zeigt eine etwas umfangreichere Nutzung der Startoptionen zur Konfiguration eines Slave-Servers:

[mysqld]
server-id=2
master-host=db-master.mycompany.com
master-port=3306
master-user=pertinax
master-password=freitag
master-connect-retry=60
report-host=db-slave.mycompany.com

Die folgende Liste beschreibt die Startoptionen zur Steuerung der Replikation. Viele dieser Optionen können bei laufendem Server mit der Anweisung CHANGE MASTER TO zurückgesetzt werden. Andere wie beispielsweise die --replicate-*-Optionen können nur beim Start des Slave-Servers zurückgesetzt werden. Wir beabsichtigen dies zu beheben.

  • --log-slave-updates

    Normalerweise vermerkt ein Slave Updates, die er von einem Master-Server erhalten hat, nicht in seinem eigenen Binärlog. Diese Option weist den Slave jedoch an, Updates, die von seinem SQL-Thread ausgeführt wurden, in sein eigenes Binärlog zu schreiben. Damit diese Option Wirkung zeigt, muss der Slave auch mit der Option --log-bin gestartet werden, um das binäre Loggen zu aktivieren. --log-slave-updates wird verwendet, wenn Sie Replikationsserver seriell verketten. Nehmen wir an, Sie wollen die Replikationsserver wie folgt anordnen:

    A -> B -> C
    

    Hier dient A als Master von Slave B, und B agiert seinerseits als Master von Slave C. Damit dies funktioniert, muss B gleichermaßen Master und Slave sein. Sie müssen A und B mit der Option --log-bin starten, um das binäre Loggen zu aktivieren. Ferner muss B auch mit der Option --log-slave-updates gestartet werden, damit Änderungen, die von A empfangen wurden, von B auch im eigenen Binärlog vermerkt werden.

  • --log-warnings

    Mit dieser Option schreibt ein Server mehr Meldungen zu seinen Aktionen in das Fehlerlog. In Hinsicht auf die Replikation erzeugt der Server Warnungen, wenn er nach einem Netzwerk- oder Verbindungsausfall eine Neuverbindung herstellen konnte, und gibt auch an, wann die einzelnen Slave-Threads gestartet wurden. Die Option ist standardmäßig aktiviert. Sie können sie mithilfe von --skip-log-warnings deaktivieren. Unterbrochene Verbindungen werden nicht in das Fehlerlog protokolliert, sofern der Wert größer als 1 ist.

  • --master-connect-retry=seconds

    Die Anzahl von Sekunden, für die der Slave-Thread im Falle eines Ausfalls der Verbindung oder des Master-Servers schläft, bevor er eine Neuverbindung mit dem Master herzustellen versucht. Der entsprechende Wert in der Datei master.info hat ggf. Vorrang. Ist der Wert nicht angegeben, dann wird 60 als Vorgabe benutzt.

  • --master-host=host_name

    Hostname oder IP-Adresse des Master-Replikationsservers. Der entsprechende Wert in der Datei master.info hat ggf. Vorrang. Ist kein Master-Host angegeben, dann wird der Slave-Thread nicht gestartet.

  • --master-info-file=file_name

    Der Name der Datei, in der der Slave Angaben zum Master vermerkt. Der Standardname lautet mysql.info im Datenverzeichnis.

  • --master-password=password

    Das Passwort des Kontos, welches der Slave zur Authentifizierung verwendet, wenn er sich beim Master anmeldet. Der entsprechende Wert in der Datei master.info hat ggf. Vorrang. Sofern nicht angegeben, wird ein leeres Passwort angenommen.

  • --master-port=port_number

    Die Nummer des TCP/IP-Ports, auf dem der Master horcht. Der entsprechende Wert in der Datei master.info hat ggf. Vorrang. Sofern nicht angegeben, wird der einkompilierte Wert (normalerweise 3306) als Vorgabe verwendet.

  • --master-retry-count=count

    Häufigkeit, mit der der Slave eine Neuverbindung mit dem Master probiert, bevor er aufgibt.

  • --master-ssl, --master-ssl-ca=file_name, --master-ssl-capath=directory_name, --master-ssl-cert=file_name, --master-ssl-cipher=cipher_list, --master-ssl-key=file_name

    Diese Optionen werden zur Einstellung einer sicheren, SSL-verschlüsselten Replikationsverbindung zum Master-Server benutzt. Die Bedeutungen sind mit denen der entsprechenden Optionen --ssl, --ssl-ca, --ssl-capath, --ssl-cert, --ssl-cipher und --ssl-key identisch, die in Abschnitt 5.9.7.5, „SSL-Befehlsoptionen“, beschrieben werden. Die entsprechenden Werte in der Datei master.info haben ggf. Vorrang.

  • --master-user=user_name

    Der Benutzername des Kontos, welches der Slave zur Authentifizierung verwendet, wenn er sich beim Master anmeldet. Dieses Konto benötigt die Berechtigung REPLICATION SLAVE. Der entsprechende Wert in der Datei master.info hat ggf. Vorrang. Wenn der Master-Benutzername nicht angegeben ist, wird der Name test als Vorgabe verwendet.

  • --max-relay-log-size=size

    Größe, bei der der Server die Relay-Logs automatisch rotiert. Weitere Informationen finden Sie unter Abschnitt 6.4.4, „Relay- und Statusdateien bei der Replikation“.

  • --read-only

    Bewirkt, dass der Slave keine Updates gestattet, sofern diese nicht von Slave-Threads oder von Benutzern mit der Berechtigung SUPER stammen. Auf diese Weise lässt sich sicherstellen, dass ein Slave-Server keine Aktualisierungen von Clients akzeptiert. Diese Option gilt nicht für TEMPORARY-Tabellen.

  • --relay-log=file_name

    Der Name des Relay-Logs. Der Standardname lautet host_name-relay-bin.nnnnnn, wobei host_name der Name des Slave-Serverhosts ist und nnnnnn angibt, dass Relay-Logs mit fortlaufender Nummerierung erstellt werden. Sie können die Option angeben, um vom Hostnamen unabhängige Namen für Relay-Logs zu erstellen. Ferner ist sie praktisch, wenn Ihre Relay-Logs dazu tendieren, sehr groß zu werden (und Sie max_relay_log_size nicht verringern wollen), und Sie sie an einer anderen Position als im Datenverzeichnis ablegen müssen, oder wenn Sie die Geschwindigkeit durch eine Lastverteilung auf mehrere Festplatten optimieren wollen.

  • --relay-log-index=file_name

    Der Name, der für die Indexdatei des Relay-Logs verwendet wird. Der Standardname lautet host_name-relay-bin.index im Datenverzeichnis, wobei host_name der Name des Slave-Servers ist.

  • --relay-log-info-file=file_name

    Der Name der Datei, in der der Slave Angaben zu den Relay-Logs vermerkt. Der Standardname lautet relay-log.info im Datenverzeichnis.

  • --relay-log-purge={0|1}

    Aktiviert oder deaktiviert das automatische Löschen von Relay-Logs, wenn sie nicht mehr benötigt werden. Der Vorgabewert ist 1 (aktiviert). Dies ist eine globale Variable, die dynamisch mit SET GLOBAL relay_log_purge = N geändert werden kann.

  • --relay-log-space-limit=size

    Diese Option setzt eine Obergrenze für die Gesamtgröße aller Relay-Logs auf dem Slave, angegeben in Byte. Der Wert 0 hat die Bedeutung „unbeschränkt“. Die Option ist praktisch auf Slave-Servern, bei denen die Festplattenkapazität begrenzt ist. Wenn der Grenzwert erreicht wird, beendet der I/O-Thread das Auslesen von Ereignissen aus dem Binärlog des Masters, bis der SQL-Thread aufgeholt und eine Anzahl nicht mehr benötigter Relay-Logs gelöscht hat. Beachten Sie, dass das Limit nicht absolut ist: Es gibt Fälle, in denen der SQL-Thread mehr Ereignisse benötigt, bevor er Relay-Logs löschen kann. In diesem Fall überschreitet der I/O-Thread den Grenzwert so weit, wie es notwendig ist, damit der SQL-Thread einige Relay-Logs löschen kann (andernfalls würde der Slave nämlich blockiert). Sie sollten --relay-log-space-limit auf einen Wert setzen, der mindestens zweimal so groß ist wie der Wert von --max-relay-log-size (oder --max-binlog-size, sofern --max-relay-log-size 0 ist). In diesem Fall besteht die Möglichkeit, dass der I/O-Thread auf freien Speicher warten muss, weil --relay-log-space-limit überschritten wurde, der SQL-Thread aber kein Relay-Log löschen und deswegen die Anforderung des I/O-Threads nicht bearbeiten kann. Also ist der I/O-Thread gezwungen, --relay-log-space-limit vorübergehend zu ignorieren.

  • --replicate-do-db=db_name

    Weist den Slave an, die Replikation auf Anweisungen zu beschränken, deren Standarddatenbank (also die von USE gewählte Datenbank) db_name ist. Um mehrere Datenbanken anzugeben, verwenden Sie diese Option mehrfach (d. h. jeweils einmal pro Datenbank). Beachten Sie, dass hierbei keine datenbankübergreifenden Anweisungen wie UPDATE some_db.some_table SET foo='bar' repliziert werden, solange eine andere Datenbank (oder gar keine Datenbank) gewählt ist.

    Hier ein Beispiel für etwas, das nicht so funktioniert, wie Sie es vielleicht erwarten: Wenn der Slave mit der Option --replicate-do-db=sales gestartet wird und Sie die folgenden Anweisungen auf dem Master absetzen, wird die UPDATE-Anweisung nicht repliziert:

    USE prices;
    UPDATE sales.january SET amount=amount+1000;
    

    Der wichtigste Grund für dieses Verhalten nach dem Motto „Nur die Standarddatenbank überprüfen“ besteht darin, dass es schwierig ist, allein der Anweisung zu entnehmen, ob sie repliziert werden soll (wenn Sie beispielsweise DELETE-Anweisungen für mehrere Tabellen oder UPDATE-Anweisungen für mehrere Tabellen verwenden, die datenbankübergreifend agieren). Außerdem geht es schneller, wenn nur die Standarddatenbank (statt aller Datenbanken) überprüft wird, sofern es keinen Grund dafür gibt.

    Wenn Sie datenbankübergreifende Aktualisierungen zum Laufen bringen wollen, verwenden Sie stattdessen --replicate-wild-do-table=db_name.%. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

  • --replicate-do-table=db_name.tbl_name

    Weist den Slave-Thread an, die Replikation auf die angegebene Tabelle zu beschränken. Um mehrere Tabellen anzugeben, verwenden Sie diese Option mehrfach (d. h. jeweils einmal pro Tabelle). Dies funktioniert – anders als --replicate-do-db – auch bei datenbankübergreifenden Änderungen. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

  • --replicate-ignore-db=db_name

    Weist den Slave an, keine Anweisungen zu replizieren, deren Standarddatenbank (also die von USE gewählte Datenbank) db_name ist. Um mehrere zu ignorierende Datenbanken anzugeben, verwenden Sie diese Option mehrfach (d. h. jeweils einmal pro Datenbank). Sie sollten die Option allerdings nicht angeben, wenn Sie datenbankübergreifende Änderungen ausführen, die aber nicht repliziert werden sollen. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

    Hier ein Beispiel für etwas, das nicht so funktioniert, wie Sie es vielleicht erwarten: Wenn der Slave mit der Option --replicate-ignore-db=sales gestartet wird und Sie die folgenden Anweisungen auf dem Master absetzen, wird die UPDATE-Anweisung nicht repliziert:

    USE prices;
    UPDATE sales.january SET amount=amount+1000;
    

    Wenn Sie datenbankübergreifende Aktualisierungen zum Laufen bringen wollen, verwenden Sie stattdessen --replicate-wild-ignore-table=db_name.%. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

  • --replicate-ignore-table=db_name.tbl_name

    Weist den Slave-Thread an, eine Anweisung, die die angegebene Tabelle ändert, auch dann nicht zu replizieren, wenn andere Tabellen von derselben Anweisung geändert werden könnten. Um mehrere zu ignorierende Tabellen anzugeben, verwenden Sie diese Option mehrfach (d. h. jeweils einmal pro Tabelle). Dies funktioniert – anders als --replicate-ignore-db – auch bei datenbankübergreifenden Änderungen. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

  • --replicate-rewrite-db=from_name->to_name

    Weist den Slave an, die Standarddatenbank (also die von USE gewählte Datenbank) in to_name zu übersetzen, wenn sie auf dem Master den Namen from_name hatte. Hiervon sind nur tabellenbezogene Anweisungen betroffen (also keine Anweisungen wie CREATE DATABASE, DROP DATABASE und ALTER DATABASE), und diese auch nur dann, wenn from_name die Standarddatenbank auf dem Master ist. Dies funktioniert bei datenbankübergreifenden Änderungen nicht. Die Übersetzung des Datenbanknamens erfolgt vor dem Prüfen der --replicate-*-Regeln.

    Wenn Sie diese Option auf der Befehlszeile verwenden und das Zeichen ‘>’ für Ihren Befehls-Interpreter ein Sonderzeichen ist, müssen Sie den Optionswert in Anführungszeichen setzen. Zum Beispiel:

    shell> mysqld --replicate-rewrite-db="olddb->newdb"
    
  • --replicate-same-server-id

    Wird auf Slave-Servern verwendet. Normalerweise sollten Sie die Standardeinstellung 0 verwenden, um durch eine Kreisreplikation verursachte Endlosschleifen zu verhindern. Wenn Sie den Wert 1 wählen, überspringt der Slave keine Ereignisse, die seine eigene Serverkennung enthalten – dies ist normalerweise nur in seltenen Fällen gewollt. Der Wert 1 kann bei Verwendung von --log-slave-updates nicht gewählt werden. Beachten Sie, dass der Slave-I/O-Thread standardmäßig noch nicht einmal dann Ereignisse aus dem Binärlog in das Relay-Log schreibt, wenn diese die Kennung des Slaves aufweisen (diese Optimierung hilft beim Einsparen von Festplattenkapazität). Wenn Sie also --replicate-same-server-id verwenden wollen, müssen Sie den Slave in jedem Fall mit dieser Option starten, bevor Sie ihn dazu bringen, eigene Ereignisse zu lesen, die der Slave-SQL-Thread ausführen soll.

  • --replicate-wild-do-table=db_name.tbl_name

    Weist den Slave-Thread an, die Replikation auf Anweisungen zu beschränken, bei denen die aktualisierten Tabellen den angegebenen Mustern für Datenbank- und Tabellennamen entsprechen. Muster dürfen die Jokerzeichen ‘%’ und ‘_’ enthalten; diese haben dieselbe Bedeutung wie beim Mustervergleichsoperator LIKE. Um mehrere Tabellen anzugeben, verwenden Sie diese Option mehrfach (d. h. jeweils einmal pro Tabelle). Dies funktioniert bei datenbankübergreifenden Änderungen. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

    Beispiel: --replicate-wild-do-table=foo%.bar% repliziert nur Updates, die eine Tabelle betreffen, bei der der Datenbankname mit foo und der Tabellenname mit bar beginnt.

    Wenn als Muster für den Tabellennamen % angegeben wird, dann liegt eine Entsprechung für jeden Tabellennamen vor, und die Option gilt auch für Anweisungen auf Datenbankebene (CREATE DATABASE, DROP DATABASE und ALTER DATABASE). Wenn Sie beispielsweise --replicate-wild-do-table=foo%.% angeben, werden die Anweisungen auf Datenbankebene repliziert, wenn der Datenbankname foo% entspricht.

    Um Jokerzeichen literal in den Mustern für Datenbank- oder Tabellennamen zu verwenden, kennzeichnen Sie sie mit einem Backslash. Um also beispielsweise alle Tabellen einer Datenbank namens my_own%db zu replizieren, nicht aber Tabellen aus my1ownAABCdb, sollten Sie die Zeichen ‘_’ und ‘%’ wie folgt kennzeichnen: --replicate-wild-do-table=my\_own\%db. Wenn Sie die Option auf der Befehlszeile angeben, müssen Sie unter Umständen je nach Befehls-Interpreter die Backslashes verdoppeln oder den Optionswert in Anführungszeichen setzen. So müssen Sie bei der bash-Shell etwa --replicate-wild-do-table=my\\_own\\%db angeben.

  • --replicate-wild-ignore-table=db_name.tbl_name

    Weist den Slave-Thread an, eine Anweisung nicht zu replizieren, bei der eine beliebige Tabelle dem angegebenen Jokerzeichenmuster entspricht. Um mehrere zu ignorierende Tabellen anzugeben, verwenden Sie diese Option mehrfach (d. h. jeweils einmal pro Tabelle). Dies funktioniert bei datenbankübergreifenden Änderungen. Siehe auch Abschnitt 6.10, „Wie Server Replikationsregeln auswerten“.

    Beispiel: --replicate-wild-ignore-table=foo%.bar% repliziert keine Updates, die eine Tabelle betreffen, bei der der Datenbankname mit foo und der Tabellenname mit bar beginnt.

    Informationen zur Funktionsweise von Mustervergleichen entnehmen Sie der Beschreibung zur Option --replicate-wild-do-table. Die Regeln zur Verwendung literaler Jokerzeichen im Optionswert sind dieselben wie bei --replicate-wild-ignore-table.

  • --report-host=slave_name

    Hostname oder IP-Adresse des Slaves, der oder die bei der Slave-Registrierung an den Master gemeldet wurde. Dieser Wert erscheint in der Ausgabe von SHOW SLAVE HOSTS auf dem Master-Server. Lassen Sie den Wert ungesetzt, wenn Sie nicht wollen, dass der Slave sich selbstständig beim Master registriert. Beachten Sie, dass es für den Master nicht ausreichend ist, die IP-Adresse des Slaves bei dessen Verbindungsherstellung einfach dem TCP/IP-Socket zu entnehmen. Aufgrund der Netzadressübersetzung (NAT) und anderer Routing-relevanter Probleme kann diese IP-Adresse unter Umständen nicht verwendet werden, um den Slave vom Master oder anderen Hosts aus zu kontaktieren.

  • --report-port=slave_port_num

    Die Nummer des TCP/IP-Ports zur Verbindung mit dem Slave, die bei der Slave-Registrierung an den Master gemeldet wurde. Nehmen Sie die Einstellung nur vor, wenn der Slave nicht auch einem Standardport lauscht oder Sie einen speziellen Tunnel vom Master oder anderen Clients zum Slave verwenden. Wenn Sie sich nicht sicher sind, verwenden Sie die Option nicht.

  • --skip-slave-start

    Weist den Slave-Server an, die Slave-Threads nicht zu starten, wenn der Server startet. Um die Threads später zu starten, können Sie die Anweisung START SLAVE verwenden.

  • --slave_compressed_protocol={0|1}

    Wenn diese Option auf 1 gesetzt ist, wird eine Komprimierung des Slave/Master-Protokolls verwendet, wenn sowohl Slave als auch Master diese unterstützen.

  • --slave-load-tmpdir=file_name

    Der Name des Verzeichnisses, in dem der Slave Temporärdateien erstellt. Diese Option entspricht standardmäßig dem Wert der Systemvariablen tmpdir. Wenn der Slave-SQL-Thread eine LOAD DATA INFILE-Anweisung repliziert, extrahiert er die zu ladende Datei aus dem Relay-Log in Temporärdateien und lädt diese dann in die Tabelle. Wenn die auf dem Master geladene Datei sehr groß ist, sind auch die Temporärdateien auf dem Slave groß. Aus diesem Grund kann es sich empfehlen, den Slave mit dieser Option anzuweisen, die Temporärdateien in ein Verzeichnis auf einem Dateisystem zu speichern, auf dem ausreichend viel Festplattenkapazität vorhanden ist. In diesem Fall sind auch die Relay-Logs riesig, weswegen Sie auch diese mit der Option --relay-log gleichermaßen auf jenem Dateisystem ablegen sollten.

    Das mit dieser Option angegebene Verzeichnis sollte auf einem festplattenbasierten (d. h. nicht speicherresidenten) Dateisystem liegen, da die Temporärdateien, die zur Replikation von LOAD DATA INFILE verwendet werden, einen Systemneustart überdauern müssen. Das Verzeichnis sollte außerdem nicht eines sein, welches beim Systemstart vom Betriebssystem geleert wird.

  • --slave-net-timeout=seconds

    Anzahl der Sekunden, für die auf weitere Daten vom Master gewartet wird, bevor der Slave die Verbindung als unterbrochen betrachtet, den Lesevorgang abbricht und eine Neuverbindung probiert. Der erste Versuch findet unmittelbar nach Überschreiten dieses Werts statt. Die Abstände zwischen den Neuversuchen werden von der Option --master-connect-retry gesteuert.

  • --slave-skip-errors=[err_code1,err_code2,...|all]

    Normalerweise wird die Replikation beendet, wenn ein Fehler auf dem Slave auftritt. Sie haben auf diese Weise die Möglichkeit, Inkonsistenzen in den Daten manuell zu beheben. Diese Option weist den Slave-SQL-Thread an, mit der Replikation fortzufahren, wenn eine Anweisung einen der im Optionswert aufgeführten Fehler zurückgibt.

    Verwenden Sie diese Option nicht, sofern Sie nicht genau wissen, warum Sie Fehler erhalten. Sind in Ihrer Replikationskonfiguration und Clientprogrammen ebenso wenig Fehler vorhanden wie Bugs in MySQL, dann sollte eigentlich nie ein Fehler auftreten, der die Replikation beendet. Die unüberlegte Verwendung dieser Option hat zur Folge, dass die Synchronisation zwischen Master und Slave unwiederbringlich verloren geht, ohne dass Sie überhaupt wissen, warum dies so ist.

    Die Fehlercodes sind als Zahlenangaben in den Fehlermeldungen im Fehlerlog des Slaves und in der Ausgabe von SHOW SLAVE STATUS enthalten. Anhang B, Fehlercodes und -meldungen, listet die Serverfehlercodes auf.

    Sie könnten theoretisch auch den nicht sehr empfehlenswerten Wert all angeben, damit der Slave alle Fehlermeldungen ignoriert und weiterarbeitet – egal, was auch passiert. Aber das sollten Sie besser lassen. Selbstredend gibt es, wenn Sie all verwenden, keine Garantie bezüglich der Datenintegrität. Sollten die Daten auf dem Slave in einem solchen Fall auch nicht annähernd denen auf dem Master entsprechen, so bitten wir von Beschwerden (und der Meldung von Bugs) abzusehen. Wir haben Sie gewarnt!

    Ein paar Beispiele:

    --slave-skip-errors=1062,1053
    --slave-skip-errors=all
    

6.10. Wie Server Replikationsregeln auswerten

Wenn ein Master-Server keine Anweisung in sein Binärlog schreibt, wird die Anweisung auch nicht repliziert. Schreibt der Server die Anweisung hingegen in das Log, dann wird die Anweisung an alle Slaves geschickt, und jeder Slave bestimmt, ob er sie ausführt oder ignoriert.

Auf der Master-Seite basieren die Entscheidungen darüber, welche Anweisungen zu loggen sind, auf den Optionen --binlog-do-db und --binlog-ignore-db, die das binäre Loggen steuern. Eine Beschreibung der Regeln, die der Server bei der Auswertung dieser Optionen verwendet, finden Sie in Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

Auf der Slave-Seite werden die Entscheidungen darüber, ob und welche vom Master empfangenen Anweisungen ausgeführt oder ignoriert werden, entsprechend den --replicate-*-Optionen getroffen, mit denen der Slave gestartet wurde. Der Slave wertet diese Optionen entsprechend der folgenden Vorgehensweise aus.

  1. Sind --replicate-do-db- oder --replicate-ignore-db-Optionen vorhanden?

    • Ja: Unter Verwendung derselben Regeln testen wie bei den Optionen --binlog-do-db und --binlog-ignore-db. Welches Ergebnis hat der Test?

      • Anweisung ignorieren: Ignorieren und beenden.

      • Anweisung zulassen: Anweisung nicht sofort ausführen, sondern die Entscheidung verschieben. Mit nächstem Schritt fortfahren.

    • Nein: Mit nächstem Schritt fortfahren.

  2. Wird gerade eine gespeicherte Funktion ausgeführt?

    • Ja: Abfrage ausführen und beenden.

    • Nein: Mit nächstem Schritt fortfahren.

  3. Sind --replicate-*-table-Optionen vorhanden?

    • Nein: Abfrage ausführen und beenden.

    • Ja: In diesem Fall hängt das Verhalten davon ab, ob die anweisungsbasierte Replikation oder die datensatzbasierte Replikation verwendet wird:

      • Anweisungsbasierte Replikation: Mit nächstem Schritt fortfahren und mit der Auswertung der Tabellenregeln in der angegebenen Reihenfolge (zuerst die Nicht-„wild“-, dann die „wild“-Regeln) beginnen. Nur Tabellen, die aktualisiert werden sollen, werden mit den Regeln verglichen. Heißt die Anweisung etwa INSERT INTO sales SELECT * FROM prices, dann wird nur sales mit den Regeln verglichen. Wenn mehrere Tabellen durch eine entsprechende Anweisung aktualisiert werden, gewinnt die erste Tabelle, die „Do“ oder „Ignore“ entspricht: Der Server vergleicht die erste Tabelle also mit den Regeln. Konnte keine Entscheidung getroffen werden, dann überprüft er die zweite Tabelle usw.

      • Datensatzbasierte Replikation: Alle Änderungen an Tabellendatensätzen werden einzeln gefiltert. Bei Updates für mehrere Tabellen wird jede Tabelle entsprechend den Regeln separat gefiltert. Einige Änderungen werden ausgeführt, andere unter Umständen nicht – dies hängt jeweils von den Regeln und den vorgenommenen Änderungen ab. Die datensatzbasierte Replikation verarbeitet Fälle, die bei der anweisungsbasierten Replikation nicht korrekt repliziert würden, ihrerseits korrekt. Betrachten Sie folgendes Beispiel, welches davon ausgeht, dass Tabellen in der Datenbank foo repliziert werden sollen:

        mysql> USE bar;
        mysql> INSERT INTO foo.sometable VALUES (1);                    
        

  4. Gibt es --replicate-do-table-Regeln?

    • Ja: Entspricht die Tabelle einer dieser Regeln?

      • Ja: Abfrage ausführen und beenden.

      • Nein: Mit nächstem Schritt fortfahren.

    • Nein: Mit nächstem Schritt fortfahren.

  5. Gibt es --replicate-ignore-table-Regeln?

    • Ja: Entspricht die Tabelle einer dieser Regeln?

      • Ja: Abfrage ignorieren und beenden.

      • Nein: Mit nächstem Schritt fortfahren.

    • Nein: Mit nächstem Schritt fortfahren.

  6. Gibt es --replicate-wild-do-table-Regeln?

    • Ja: Entspricht die Tabelle einer dieser Regeln?

      • Ja: Abfrage ausführen und beenden.

      • Nein: Mit nächstem Schritt fortfahren.

    • Nein: Mit nächstem Schritt fortfahren.

  7. Gibt es --replicate-wild-ignore-table-Regeln?

    • Ja: Entspricht die Tabelle einer dieser Regeln?

      • Ja: Abfrage ignorieren und beenden.

      • Nein: Mit nächstem Schritt fortfahren.

    • Nein: Mit nächstem Schritt fortfahren.

  8. Es gab keine Entsprechung für eine --replicate-*-table-Regel. Gibt es noch eine weitere Tabelle, die auf diese Regeln geprüft werden kann?

    • Ja: Schleife wiederholen.

    • Nein: Wir haben nun alle zu aktualisierenden Tabellen getestet und konnten keine Übereinstimmung mit einer Regel finden. Sind --replicate-do-table- oder --replicate-wild-do-table-Regeln vorhanden?

      • Ja: Es gab „Do“-Regeln, aber keine Übereinstimmung. Abfrage ignorieren und beenden.

      • Nein: Abfrage ausführen und beenden.

6.11. Replikation: häufig gestellte Fragen

Frage: Wie konfiguriere ich einen Slave, wenn der Master ausgeführt wird und ich ihn nicht anhalten will?

Antwort: Es gibt mehrere Möglichkeiten. Wenn Sie zu einem bestimmten Zeitpunkt ein auf einer Momentaufnahme basiertes Backup des Masters erstellt und den Binärlognamen und den Versatz (aus der Ausgabe von SHOW MASTER STATUS) für die Momentaufnahme notiert haben, gehen Sie wie folgt vor:

  1. Stellen Sie sicher, dass der Slave eine eindeutige Serverkennung hat.

  2. Führen Sie die folgende Anweisung auf dem Slave aus. Geben Sie dabei für jede Option die passenden Werte an:

    mysql> CHANGE MASTER TO
        ->     MASTER_HOST='master_host_name',
        ->     MASTER_USER='master_user_name',
        ->     MASTER_PASSWORD='master_pass',
        ->     MASTER_LOG_FILE='recorded_log_file_name',
        ->     MASTER_LOG_POS=recorded_log_position;
    
  3. Führen Sie START SLAVE auf dem Slave aus.

Wenn Sie über keine Sicherungskopie des Master-Servers verfügen, können Sie wie nachfolgend beschrieben ganz einfach eine solche erstellen. Alle Schritte sind dabei auf dem Master-Host durchzuführen.

  1. Setzen Sie die folgende Anweisung ab, um eine globale Lesesperre zu erwirken:

    mysql> FLUSH TABLES WITH READ LOCK;
    
  2. Führen Sie bei weiterhin aktiver Sperre den folgenden Befehl (oder eine entsprechende Variante) aus:

    shell> tar zcf /tmp/backup.tar.gz /var/lib/mysql
    
  3. Setzen Sie nun folgende Anweisung ab und notieren Sie die Ausgabe (Sie werden sie später noch benötigen):

    mysql> SHOW MASTER STATUS;
    
  4. Heben Sie die Sperre auf:

    mysql> UNLOCK TABLES;
    

Eine Alternative zu dieser Vorgehensweise zur Erstellung einer binären Kopie besteht darin, einen SQL-Speicherauszug des Masters zu erstellen. Hierzu führen Sie mysqldump --master-data auf dem Master aus und laden die SQL-Speicherauszugsdatei später in Ihren Slave. Allerdings ist die Erstellung einer binären Kopie schneller.

Unabhängig davon, welche der beiden Methoden Sie verwenden, befolgen Sie danach die Anleitung für den Fall, dass Sie eine Momentaufnahme erstellt und den Logdateinamen und den Offset vermerkt haben. Sie können dieselbe Momentaufnahme mehrfach verwenden. Wenn Sie die Momentaufnahme des Masters erst einmal haben, können Sie beliebig lang mit der Konfiguration des Slaves warten: Es müssen lediglich die Binärlogs auf dem Master intakt bleiben. Allerdings bestehen zwei praktische Beschränkungen, die Sie beachten müssen: Sie dürfen nicht länger als notwendig warten, um zu vermeiden, dass die zur Aufnahme der Binärlogs auf dem Master erforderliche Speichermenge zu groß wird und dass der Slave nicht schnell genug auf den Stand des Masters gebracht werden kann.

Sie können außerdem LOAD DATA FROM MASTER verwenden. Dies ist eine praktische Anweisung, die eine Momentaufnahme auf den Slave überträgt und gleichzeitig auch noch den Logdateinamen und den Versatz automatisch einstellt. Zukünftig wird LOAD DATA FROM MASTER die empfohlene Vorgehensweise zur Konfiguration eines Slaves werden. Beachten Sie allerdings, dass die Anweisung nur bei MyISAM-Tabellen funktioniert und für einen relativ langen Zeitraum eine Lesesperre setzt. Sie ist noch nicht so effektiv implementiert, wie wir uns das wünschen. Wenn Sie größere Tabellen haben, besteht die bevorzugte Methode also derzeit noch darin, nach der Ausführung von FLUSH TABLES WITH READ LOCK eine binäre Momentaufnahme auf dem Master-Server zu erstellen.

Frage: Muss der Slave fortlaufend mit dem Master verbunden sein?

Antwort: Nein. Der Slave kann stunden- oder sogar tagelang ausgeschaltet oder getrennt sein – erfolgt eine Neuverbindung, dann werden alle Aktualisierungen aufgeholt. Sie können beispielsweise eine Master/Slave-Beziehung über eine Wählverbindung konfigurieren, bei der die Verbindung nur sporadisch und nur für kurze Zeit hergestellt wird. Eine Auswirkung hiervon ist natürlich, dass man zu keinem Zeitpunkt die Synchronisation zwischen Slave und Master gewährleisten kann, sofern nicht bestimmte Maßnahmen ergriffen werden. Zukünftig wird eine Option eingeführt werden, mit der der Master blockiert wird, bis mindestens ein Slave synchronisiert wurde.

Frage: Wie erkenne ich, wie weit ein Slave im Vergleich zum Master im Rückstand ist? Anders formuliert: Wie ermittle ich den Zeitpunkt der letzten vom Slave replizierten Abfrage?

Antwort: Lesen Sie die Spalte Seconds_Behind_Master in der Ausgabe von SHOW SLAVE STATUS aus. Siehe auch Abschnitt 6.4, „Replikation: Implementationsdetails“.

Wenn der Slave-SQL-Thread ein Ereignis ausführt, welches er vom Master gelesen hat, dann setzt er seine eigene Zeit auf den Zeitstempel des Ereignisses um. (Dies ist auch Voraussetzung dafür, dass TIMESTAMP korrekt repliziert wird.) In der Spalte Time der Ausgabe von SHOW PROCESSLIST beschreibt die angezeigte Sekundenzahl für den Slave-SQL-Thread die Anzahl der Sekunden zwischen dem Zeitstempel des letzten replizierten Ereignisses und der Echtzeit des Slave-Systems. Auf diese Weise können Sie den Zeitpunkt des letzten replizierten Ereignisses ermitteln. Beachten Sie, dass, wenn Ihr Slave für eine Stunde vom Master getrennt wurde und dann eine neue Verbindung herstellt, in der Spalte Time sofort Werte wie 3600 für den Slave-SQL-Thread in der Ausgabe von SHOW PROCESSLIST erscheinen. Dies liegt daran, dass der Slave Anweisungen ausführt, die eine Stunde alt sind.

Frage: Wie kann ich den Master zwingen, Updates zu sperren, bis der Slave den Rückstand aufgeholt hat?

Antwort: Gehen Sie wie folgt vor:

  1. Führen Sie auf dem Master die folgenden Anweisungen aus:

    mysql> FLUSH TABLES WITH READ LOCK;
    mysql> SHOW MASTER STATUS;
    

    Notieren Sie die Replikationskoordinaten (Logdateiname und Versatz) in der Ausgabe der SHOW-Anweisung.

  2. Setzen Sie auf dem Slave folgende Anweisung ab. Die Argumente für die Funktion MASTER_POS_WAIT() sind die Replikationskoordinaten, die Sie im vorherigen Schritt ermittelt haben:

    mysql> SELECT MASTER_POS_WAIT('log_name', log_offset);
    

    Die SELECT-Anweisung sperrt den Master, bis der Slave die entsprechende Position in der angegebenen Logdatei erreicht hat. An dieser Stelle läuft der Slave synchron zum Master, und die Anweisung gibt ihre Werte zurück.

  3. Setzen Sie nun auf dem Master die folgende Anweisung ab, damit er wieder Updates verarbeiten kann:

    mysql> UNLOCK TABLES;
    

Frage: Welche Aspekte muss ich bei der Konfiguration der 2-Wege-Replikation beachten?

Antwort: Die MySQL-Replikation unterstützt derzeit kein Sperrprotokoll zwischen Master und Server, mit dem die Atomizität eines verteilten (serverübergreifenden) Updates gewährleistet werden kann. Es ist also möglich, dass Client A ein Update auf dem Co-Master 1 vornimmt, während gleichzeitig (also bevor dieses Update an den Co-Master 2 weitergegeben wird) Client B ein Update auf dem Co-Master 2 durchführt, welches für das Update von Client A eine andere Wirkung hervorruft als auf Co-Master 1. Auf diese Weise erzeugt das Update von Client A nach der Ankunft auf dem Co-Master 2 Tabellen, die sich von denen auf dem Co-Master 1 unterscheiden – und zwar auch, nachdem alle Updates von Co-Master 2 ebenfalls weitergegeben wurden. Dies bedeutet, dass Sie niemals zwei Server in einer 2-Wege-Replikationsbeziehung miteinander verketten sollten, sofern Sie nicht sicher sind, dass Ihre Updates in beliebiger Reihenfolge erfolgen können, oder im Clientcode den Fall unterschiedlicher Updatereihenfolgen irgendwie berücksichtigen.

Sie sollten auch daran denken, dass, soweit es Updates betrifft, die 2-Wege-Replikation die Leistungsfähigkeit – sofern überhaupt – nicht allzu sehr optimiert. Jeder Server muss dieselbe Anzahl von Updates ausführen – ebenso wie es auch bei nur einem Server der Fall wäre. Der einzige Unterschied besteht darin, dass es zu weniger konkurrierenden Sperranforderungen kommt, weil die Updates, die von einem anderen Server kommen, in nur einem Slave-Thread serialisiert werden. Aber auch dieser Vorteil kann durch Netzwerklatenzen schon wieder aufgewogen werden.

Frage: Wie kann ich mit der Replikation die Leistung meines Systems verbessern?

Antwort: Sie sollten einen Server als Master konfigurieren und alle Schreiboperationen an ihn richten. Nachfolgend sollten Sie so viele Slaves einrichten, wie es Budget und Platzverhältnisse zulassen, und Leseoperationen dann auf Master und Slaves verteilen. Sie können die Slaves auch mit den Optionen --skip-innodb, --skip-bdb, --low-priority-updates und --delay-key-write=ALL starten, um Slave-seitig Geschwindigkeitsvorteile erzielen zu können. In diesem Fall verwendet der Slave nichttransaktionssichere MyISAM-Tabellen statt InnoDB- und BDB-Tabellen, um den transaktionsbedingten Mehraufwand zu umgehen und die Geschwindigkeit so zu steigern.

Frage: Was kann ich tun, um den Clientcode in meinen eigenen Anwendungen so zu formulieren, dass eine leistungssteigernde Replikation verwendet wird?

Antwort: Wenn der Teil Ihres Codes, der für den Datenbankzugriff zuständig ist, einwandfrei abstrahiert bzw. modularisiert ist, sollte die Konvertierung in eine Form, die in einer Replikationskonfiguration läuft, schnell und einfach erfolgen. Ändern Sie die Implementierung Ihres Datenbankzugriffs so, dass alle Schreiboperationen an den Master gesendet werden, und senden Sie die Leseoperationen an den Master oder einen Slave. Wenn Ihr Code nicht derart abstrahierbar ist, bietet Ihnen die Konfiguration eines Replikationssystems vielleicht die Möglichkeit und die Motivation, ihn entsprechend zu bereinigen. Erstellen Sie zunächst eine Wrapper-Bibliothek oder ein Wrapper-Modul, das die folgenden Funktionen implementiert:

  • safe_writer_connect()

  • safe_reader_connect()

  • safe_reader_statement()

  • safe_writer_statement()

Der Namensteil safe_ in den Funktionsnamen verweist darauf, dass die jeweilige Funktion alle Fehlerbedingungen selbst abfängt. Sie können für die Funktionen auch andere Namen verwenden. Wichtig ist lediglich, dass Sie über eine einheitliche Schnittstelle verfügen, um Lese- und Schreibverbindungen herzustellen und Lese- oder Schreiboperationen auszuführen.

Nachfolgend konvertieren Sie Ihren Clientcode so, dass er die Wrapper-Bibliothek verwendet. Unter Umständen ist dies anfangs ein schmerzlicher und beängstigender Vorgang, der sich aber langfristig auszahlt. Alle Anwendungen, die den gerade beschriebenen Ansatz verfolgen, können von einer Master/Slave-Konfiguration profitieren, auch wenn diese mehrere Slaves umfasst. Der Code ist weitaus einfacher zu pflegen, und das Hinzufügen von Problembehandlungsoptionen ist trivial. Sie müssen nur ein oder zwei Funktionen modifizieren – beispielsweise, wie lang eine Anweisung zur Ausführung benötigte oder welche der abgesetzten Anweisungen den Fehler zurückgegeben hat.

Wenn Sie viel Code geschrieben haben, sollten Sie diese Konvertierungsarbeit mit dem Hilfsprogramm replace automatisieren, welches Bestandteil der MySQL-Standarddistributionen ist, oder Ihr eigenes Konvertierungsskript abfassen. Im Idealfall verwendet Ihr Code konsistent die gängigen Stilkonventionen bei der Programmierung. Andernfalls wird es ohnehin einfacher sein, ihn neu zu erstellen oder ihn zumindest durchzuarbeiten und dabei manuell so zu vereinheitlichen, dass der Stil konsistent ist.

Frage: Wie stark und unter welchen Umständen kann die MySQL-Replikation die Leistung meines Systems verbessern?

Antwort: Die MySQL-Replikation ist am vorteilhaftesten für Systeme, die häufig Leseoperationen und seltener Schreiboperationen verarbeiten müssen. Theoretisch können Sie Ihr System bei Implementierung einer Konfiguration mit einem Master und mehreren Slaves skalieren, indem Sie weitere Slaves hinzufügen, bis entweder Ihre Netzwerkbandbreite erschöpft ist oder Ihr Aktualisierungsaufkommen so stark zugenommen hat, dass es der Master nicht mehr verarbeiten kann.

Um zu ermitteln, wie viele Slaves Sie verwenden können, bevor die Vorteile sich zu relativieren beginnen, und wie weit Sie die Leistungsfähigkeit Ihres Standorts verbessern können, müssen Sie Ihre Abfragemuster und das Verhältnis zwischen dem Durchsatz für Leseoperationen (Leseoperationen/Sekunde oder reads) und Schreiboperationen (writes) kennen auf einem typischen Master und einem typischen Slave durch Benchmark-Tests in Erfahrung bringen. Das folgende Beispiel zeigt eine relativ stark vereinfachte Berechnung der Auswirkungen der Replikation auf einem hypothetischen System.

Angenommen, die Systemlast umfasst 10 Prozent Schreiboperationen und 90 Prozent Leseoperationen. Durch ein Benchmarking haben wir ermittelt, dass reads 1200 – 2 × writes ist. Anders gesagt, kann das System 1200 Leseoperationen pro Sekunde ohne Schreiboperationen verarbeiten, ein Schreibvorgang erfolgt durchschnittlich halb so schnell wie ein Lesevorgang, und die Beziehung ist linear. Nehmen wir nun ferner an, dass der Master und jeder Slave jeweils die gleiche Kapazität aufweisen und dass wir einen Master und N Slaves haben. Daraus ergibt sich für jeden Server (Master oder Slave):

reads = 1200 – 2 × writes

reads = 9 × writes / (N + 1) (Leseoperationen werden aufgeteilt, während Schreiboperationen an alle Server gehen)

9 × writes / (N + 1) + 2 × writes = 1200

writes = 1200 / (2 + 9/(N+1))

Die letzte Gleichung gibt die maximale Anzahl von Schreibvorgängen für N Slaves basierend auf einer maximalen Leserate von 1200 pro Minute und einem Verhältnis von neun Leseoperationen pro Schreiboperation an.

Diese Analyse lässt die folgenden Rückschlüsse zu:

  • Wenn N = 0 ist (d. h. keine Replikation), dann kann unser System ca. 1200 ÷ 11 = 109 Schreiboperationen pro Sekunde verarbeiten.

  • Bei N = 1 sind 184 Schreiboperationen pro Sekunde möglich.

  • Bei N = 8 sind 400 Schreiboperationen pro Sekunde möglich.

  • Bei N = 17 sind 480 Schreiboperationen pro Sekunde möglich.

  • Schließlich kommen wir, je mehr sich N der Unendlichkeit (und unserem Budget der negativen Unendlichkeit) annähert, auf einen Wert von 600 Schreiboperationen pro Sekunde, während wir unseren Systemdurchsatz etwa auf das 5,5fache gesteigert haben. Bei nur acht Servern beträgt die Steigerung hingegen knapp das Vierfache.

Beachten Sie, dass diese Berechnungen eine uneingeschränkte Netzwerkbandbreite voraussetzen und mehrere andere Faktoren vernachlässigen, die für Ihr System von Bedeutung sein könnten. In vielen Fällen können Sie keine Berechnung ähnlich der obigen durchführen, mit der sich exakt voraussagen ließe, wie sich das Hinzufügen von N Replikationsslaves auf Ihr System auswirken würde. Allerdings kann Ihnen die Beantwortung der folgenden Fragen dabei helfen, zu bestimmen, ob und inwieweit eine Replikation die Leistungsfähigkeit Ihres Systems verbessern könnte:

  • Welches Verhältnis besteht zwischen Lese- und Schreiboperationen auf Ihrem System?

  • Wie viel mehr Schreiboperationen kann ein Server verarbeiten, wenn Sie die Anzahl der Leseoperationen verringern?

  • Wie viele Slaves unterstützt die Bandbreite in Ihrem Netzwerk?

Frage: Wie kann ich mithilfe der Replikation eine Redundanz oder Hochverfügbarkeit realisieren?

Antwort: Mit den derzeit verfügbaren Funktionen sollten Sie einen Master und einen Slave (oder mehrere Slaves) einrichten und ein Skript verfassen, welches den Master auf Verfügbarkeit prüft. Dann weisen Sie Ihre Anwendungen und die Slaves an, bei einem Ausfall des Masters einen anderen Master zu wählen. Hier ein paar Vorschläge:

  • Verwenden Sie die CHANGE MASTER TO-Anweisung, um einen Slave anzuweisen, den Master zu wechseln.

  • Eine gute Möglichkeit, Ihre Anwendungen bezüglich des Standorts des Masters auf dem aktuellen Stand zu halten, ist die Verwendung eines dynamischen DNS-Eintrags für den Master. Bei bind können Sie nsupdate verwenden, um Ihr DNS dynamisch zu aktualisieren.

  • Starten Sie Ihre Slaves mit der Option --log-bin und ohne die Option --log-slave-updates. Auf diese Weise ist ein Slave in der Lage, zum Master zu werden, sobald Sie die Anweisungen STOP SLAVE, RESET MASTER und CHANGE MASTER TO auf anderen Slaves absetzen. Angenommen, wir hätten folgende Konfiguration:

           WC
            \
             v
     WC----> M
           / | \
          /  |  \
         v   v   v
        S1   S2  S3
    

    In diesem Diagramm bezeichnet M den Master, S die Slaves und WC die Clients, die Schreib- und Lesevorgänge an die Datenbank absetzen. (Clients, die nur aus der Datenbank lesen, sind nicht vorhanden, da bei ihnen keine Änderungen erforderlich sind.) S1, S2 und S3 sind Slaves, die mit der Option --log-bin und ohne --log-slave-updates laufen. Da die von einem Slave empfangenen Updates nicht im Binärlog vermerkt werden, sofern nicht die Option --log-slave-updates angegeben ist, sind die Binärlogs auf den Slaves anfangs leer. Fällt nun M aus irgendeinem Grund aus, dann können Sie einen der Slaves auswählen, der dann der neue Master wird. Wenn Sie also etwa S1 auswählen, sollten alle WC auf S1 umgelenkt werden, der die Updates in sein Binärlog schreibt. S2 und S3 replizieren nachfolgend von S1.

    Sinn der Ausführung des Slaves ohne --log-slave-updates ist es, zu verhindern, dass Slaves Updates zweimal erhalten, was vorkommen kann, wenn einer der Slaves zum neuen Master wird. Nehmen wir einmal an, bei S1 wäre die Option --log-slave-updates aktiviert. Er schreibt nun Updates, die er von M empfängt, in sein eigenes Binärlog. Wenn S2 von M auf S1 also umschaltet, empfängt er Updates von S1, die er bereits von M erhalten hat.

    Stellen Sie sicher, dass alle Slaves alle Anweisungen im jeweiligen Relay-Log verarbeitet haben. Setzen Sie auf jedem Slave STOP SLAVE IO_THREAD ab und suchen Sie dann in der Ausgabe von SHOW PROCESSLIST die Angabe Has read all relay log. Wenn dieser Zustand von allen Slaves erreicht wurde, können sie auf die neue Konfiguration umgestellt werden. Auf dem Slave S1, der neuer Master werden soll, setzen Sie STOP SLAVE und RESET MASTER ab.

    Auf den anderen Slaves S2 und S3 setzen Sie STOP SLAVE und CHANGE MASTER TO MASTER_HOST='S1' ab (wobei 'S1' den echten Hostnamen von S1 darstellt). Zu CHANGE MASTER fügen Sie nun alle Informationen darüber hinzu, wie von S2 oder S3 aus eine Verbindung mit S1 hergestellt wird (also user, password, port). Sie müssen in CHANGE MASTER den Namen des Binärlogs von S1 oder der Binärlogposition, ab der gelesen werden soll, nicht angeben. Wir wissen, dass es das erste Binärlog und die Position 4 ist (dies sind die Standardwerte von CHANGE MASTER). Abschließend setzen Sie START SLAVE auf S2 und S3 ab.

    Nun weisen Sie alle WC an, ihre Anweisung an S1 zu leiten. Von diesem Punkt an werden alle Updateanweisungen, die von WC an S1 gesendet werden, in das Binärlog von S1 geschrieben, welches dann alle Updateanweisungen enthält, die seit dem Ausfall von M an S1 gesendet wurden.

    Das Ergebnis ist folgende Konfiguration:

           WC
          /
          |
     WC   |  M(unavailable)
      \   |
       \  |
        v v
         S1<--S2  S3
          ^       |
          +-------+
    

    Wenn M wieder betriebsbereit ist, müssen Sie darauf dieselbe CHANGE MASTER-Anweisung absetzen, die Sie auf S2 und S3 verwendet haben, damit M ein Slave von S1 wird und alle WC-Schreiboperationen empfängt, die er seit dem Ausfall verpasst hat. Um M wieder zum Master zu machen (etwa weil es sich dabei um das leistungsfähigste System handelt), verwenden Sie die beschriebene Methode erneut und tun dabei so, als ob S1 nicht mehr verfügbar wäre und M nun zum neuen Master wird. Während dieses Vorgangs dürfen Sie nicht vergessen, RESET MASTER auf M auszuführen, bevor Sie S1, S2 und S3 zu Slaves von M machen. Andernfalls empfangen diese Server alte WC-Schreiboperationen, die abgesetzt wurden, bevor M ausfiel.

Frage: Woher weiß ich, ob ein Master-Server das anweisungsbasierte oder das datensatzbasierte Binärlogformat verwendet?

Antwort: Überprüfen Sie den Wert der Systemvariablen binlog_format:

mysql> SHOW VARIABLES LIKE 'binlog_format';

Dieser heißt entweder STATEMENT (anweisungsbasierte Replikation) oder ROW (datensatzbasierte Replikation).

Frage: Wie weise ich einen Slave an, die datensatzbasierte Replikation zu verwenden?

Antwort: Slaves wissen automatisch, welches Format sie verwenden müssen.

6.12. Vergleich zwischen anweisungsbasierter und zeilenbasierter Replikation

Jedes Binärlogformat hat seine Vor- und Nachteile. Dieser Abschnitt fasst diese zusammen, um Ihnen eine Einschätzung zu erlauben, welches Format in Ihrer speziellen Situation das geeignetere ist.

Vorteile der anweisungsbasierten Replikation:

  • Bewährte Technologie, seit MySQL 3.23 vorhanden.

  • Kleinere Logdateien. Wenn Änderungs- oder Löschvorgänge viele Datensätze betreffen, sind die Logdateien wesentlich kleiner. Kleinere Logdateien erfordern weniger Speicherplatz und sind schneller gesichert.

  • Logdateien enthalten alle Anweisungen, mit denen Änderungen vorgenommen wurden, d. h., sie können zur Überwachung der Datenbank verwendet werden.

  • Logdateien können nicht nur zu Replikationszwecken, sondern auch zur Point-in-Time-Wiederherstellung verwendet werden. Siehe auch Abschnitt 5.10.3, „Zeitpunktbezogene Wiederherstellung“.

  • Ein Slave kann eine neuere MySQL-Version mit einer anderen Datensatzstruktur verwenden.

Nachteile der anweisungsbasierten Replikation:

  • Nicht alle UPDATE-Anweisungen können repliziert werden: Jedes nichtdeterministische Verhalten (z. B. bei der Verwendung von Zufallsfunktionen in einer SQL-Anweisung) ist bei der anweisungsbasierten Replikation schwer zu replizieren. Bei Anweisungen, die eine nichtdeterministische benutzerdefinierte Funktion (User-Defined Function, UDF) verwenden, ist die Replikation des Ergebnisses bei der anweisungsbasierten Replikation überhaupt nicht möglich (dagegen repliziert die datensatzbasierte Replikation einfach den von der UDF zurückgegebenen Wert).

  • Anweisungen können nicht korrekt repliziert werden, wenn sie eine UDF verwenden, die nichtdeterministisch ist (d. h. deren Wert von anderen Aspekten als den übergebenen Parametern abhängt).

  • Anweisungen können nicht korrekt repliziert werden, wenn sie eine der folgenden Funktionen enthalten:

    • LOAD_FILE()

    • UUID()

    • USER()

    • FOUND_ROWS()

    Alle übrigen Funktionen (einschließlich RAND(), NOW(), LOAD DATA INFILE usw.) werden korrekt repliziert.

  • INSERT ... SELECT erfordert eine höhere Zahl von Sperren auf Datensatzebene als bei der datensatzbasierten Replikation.

  • UPDATE-Anweisungen, die einen Tabellenscan erfordern (weil in der WHERE-Klausel kein Index verwendet wird), müssen eine höhere Anzahl von Datensätzen sperren als bei der datensatzbasierten Replikation.

  • (Nur bei InnoDB) Eine INSERT-Anweisung, die AUTO_INCREMENT verwendet, blockiert andere, nicht kollidierende INSERT-Anweisungen.

  • Langsamere Umsetzung von Daten auf dem Slave bei komplexen Abfragen.

  • Gespeicherte Funktionen (nicht aber gespeicherte Prozeduren) werden mit demselben NOW()-Wert wie die aufrufende Anweisung ausgeführt. (Dies kann abhängig von den Umständen ein Vor- oder Nachteil sein.)

  • Deterministische UDFs müssen auf die Slaves angewendet werden.

  • Wenn am Slave etwas nicht stimmt, nehmen die Unterschiede zwischen Master und Slave im Laufe der Zeit zu.

  • Tabellen müssen auf dem Master und dem Slave (fast) identisch sein.

Vorteile der datensatzbasierten Replikation:

  • Alles kann repliziert werden. Dies ist die sicherste Form der Replikation. Beachten Sie, dass zurzeit DDL-Anweisungen (Data Definition Language) wie etwa CREATE TABLE anweisungsbasiert repliziert werden, während bei DML-Anweisungen (Data Manipulation Language) sowie bei GRANT- und REVOKE-Anweisungen die Replikation datensatzbasiert erfolgt. Für Anweisungen wie CREATE ... SELECT wird eine CREATE-Anweisung aus der Tabellendefinition erstellt, die dann anweisungsbasiert repliziert wird, während das Einfügen von Datensätzen datensatzbasiert repliziert wird.

  • Die Technologie ist dieselbe wie bei den meisten anderen Datenbanksystemen – Kenntnisse anderer Systeme lassen sich einfach auf MySQL übertragen.

  • In vielen Fällen geht es bei Tabellen mit Primärschlüsseln schneller, wenn man die Daten auf den Slave anwendet.

  • Bei den folgenden Anweisungstypen werden weniger Sperren auf dem Master benötigt (was die Nebenläufigkeit erhöht):

    • INSERT ... SELECT

    • INSERT -Anweisungen mit AUTO_INCREMENT

    • UPDATE- oder DELETE-Anweisungen mit WHERE-Klauseln, die keine Schlüssel verwenden und die meisten der untersuchten Datensätze unverändert lassen

  • Weniger Sperren auf dem Slave bei INSERT-, UPDATE- oder DELETE-Anweisungen.

  • Es ist möglich, mehrere Threads hinzuzufügen, um Daten zukünftig auf den Slave anzuwenden (dies funktioniert bei SMP-Systemen besser).

Nachteile der datensatzbasierten Replikation:

  • Größere Logdateien (in manchen Fällen sogar wesentlich größer).

  • Das Binärlog enthält Daten für umfangreiche Anweisungen, die per Rollback rückgängig gemacht wurden.

  • Wenn Sie mit der datensatzbasierten Replikation eine Anweisung (z. B. eine UPDATE- oder DELETE-Anweisung) replizieren, muss jeder geänderte Datensatz in das Binärlog geschrieben werden. Im Gegensatz dazu wird bei Verwendung der anweisungsbasierten Replikation nur die Anweisung in das Binärlog geschrieben. Wenn die Anweisung viele Datensätze ändert, schreibt die datensatzbasierte Replikation deutlich mehr Daten in das Binärlog. In diesem Fall wird das Binärlog für eine längere Zeit gesperrt, um die Daten schreiben zu können, was Probleme mit der Nebenläufigkeit verursachen kann.

  • Deterministische UDFs, die große BLOB-Werte erzeugen, werden merklich langsamer repliziert.

  • Sie können die Logs darauf überprüfen, welche Anweisungen ausgeführt wurden.

  • Sie können auf dem Slave nicht nachprüfen, welche Anweisungen vom Master empfangen und dann ausgeführt wurden.

6.13. Replikation: Problemlösungen

Wenn Sie die Anleitung befolgt haben und Ihre Replikationskonfiguration trotzdem nicht funktioniert, sollten Sie zuallererst das Fehlerlog auf Meldungen überprüfen. Allzu viele Benutzer haben bei Auftreten eines Problems kostbare Zeit damit vergeudet, dies nicht gleich gemacht zu haben.

Wenn Sie aus dem Fehlerlog nicht ableiten können, welches Problem vorliegt, probieren Sie die folgenden Methoden aus:

  • Überprüfen Sie, ob am Master das binäre Loggen aktiviert ist, indem Sie eine SHOW MASTER STATUS-Anweisung absetzen. Bei aktiviertem Loggen ist Position ungleich null. Sollte das binäre Loggen nicht aktiviert sein, dann stellen Sie sicher, dass der Master mit den Optionen --log-bin und --server-id läuft.

  • Überprüfen Sie, ob der Slave ausgeführt wird. Mit SHOW SLAVE STATUS können Sie feststellen, ob die Werte von Slave_IO_Running und Slave_SQL_Running jeweils Yes lauten. Andernfalls überprüfen Sie die Optionen, die beim Start des Slave-Servers angegeben waren. So verhindert etwa --skip-slave-start, dass die Slave-Threads gestartet werden, bis Sie eine START SLAVE-Anweisung absetzen.

  • Wird der Slave ausgeführt, dann prüfen Sie, ob er eine Verbindung zum Master herstellen konnte. Setzen Sie SHOW PROCESSLIST ab, suchen Sie die I/O- und SQL-Threads und überprüfen Sie die zugehörigen State-Spalten. Siehe auch Abschnitt 6.4, „Replikation: Implementationsdetails“. Wenn für den I/O-Thread als Status Connecting to master angegeben ist, überprüfen Sie die Berechtigungen für den Replikationsbenutzer auf dem Master, den Hostnamen des Masters und Ihre DNS-Konfiguration und stellen Sie sicher, dass der Master ausgeführt wird und auch vom Slave erreicht werden kann.

  • Wurde der Slave bereits vorher ausgeführt, dann aber beendet, dann liegt das in der Regel daran, dass irgendeine Anweisung, die auf dem Master erfolgreich verarbeitet wurde, auf dem Slave fehlgeschlagen ist. Dies sollte niemals passieren, wenn Sie eine korrekte Momentaufnahme auf dem Master erstellt und die Daten auf dem Slave niemals außerhalb des Slave-Threads modifiziert haben. Wird der Slave unerwartet beendet, dann liegt entweder ein Bug vor, oder Sie sind auf eine der bekannten Einschränkungen der Replikation gestoßen, die in Abschnitt 6.8, „Replikation: Features und bekannte Probleme“, beschrieben sind. Wenn es sich um einen Bug handelt, lesen Sie Abschnitt 6.14, „Berichten von Replikationsfehlern und -problemen“, um zu erfahren, wie Sie diesen melden.

  • Wenn eine Anweisung, die auf dem Master klaglos verarbeitet wurde, nicht auf dem Slave ausgeführt werden kann, probieren Sie folgende Vorgehensweise aus, sofern die Durchführung einer vollständigen Datenbankneusynchronisierung durch Löschen der Datenbanken auf dem Slave und Kopieren einer neuen Momentaufnahme vom Master nicht realisierbar ist:

    1. Ermitteln Sie, ob die betreffende Tabelle auf dem Slave sich von der auf dem Master unterscheidet. Versuchen Sie zu ergründen, was geschehen ist. Dann machen Sie die Tabelle auf dem Slave identisch zu der auf dem Master und führen START SLAVE aus.

    2. Funktioniert der vorherige Schritt nicht oder ist er nicht durchführbar, dann prüfen Sie, ob es sicher ist, die Änderung (sofern erforderlich) manuell durchzuführen und die nächste Anweisung vom Master zu ignorieren.

    3. Wenn Sie feststellen, dass Sie die nächste Anweisung vom Master übergehen können, setzen Sie die folgenden Anweisungen ab:

      mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = N;
      mysql> START SLAVE;
      

      Der Wert von N sollte 1 sein, wenn die nächste Anweisung vom Master weder AUTO_INCREMENT noch LAST_INSERT_ID() verwendet. Andernfalls wählen Sie den Wert 2. Grund hierfür ist die Tatsache, dass Anweisungen, die AUTO_INCREMENT oder LAST_INSERT_ID() verwenden, zwei Ereignisse in das Binärlog des Masters schreiben.

    4. Wenn Sie ganz sicher sind, dass der Slave vollkommen synchron zum Master gestartet wurde und niemand die betreffenden Tabellen außerhalb des Slave-Threads modifiziert hat, dann ist die Diskrepanz mit hoher Wahrscheinlichkeit Ergebnis eines Bugs. Wenn Sie die aktuelle MySQL-Version verwenden, melden Sie dieses Problem bitte. Wenn Sie hingegen eine ältere Version einsetzen, aktualisieren Sie – sofern möglich – auf den aktuellen Produktions-Release, um festzustellen, ob das Problem fortbesteht.

6.14. Berichten von Replikationsfehlern und -problemen

Wenn Sie festgestellt haben, dass kein benutzerseitiger Fehler vorliegt und die Replikation trotzdem nicht stabil ist oder womöglich gar nicht funktioniert, ist es an der Zeit, uns einen Bugreport zu schicken. Wir benötigen von Ihnen so viele Informationen wie möglich, um den Bug aufzuspüren. Bitte nehmen Sie sich für die Vorbereitung des Bugreports Zeit und seien Sie sorgfältig bei Ihren Angaben.

Wenn Sie einen reproduzierbaren Testfall haben, der den Bug demonstriert, geben Sie diesen bitte in unsere Fehlerdatenbank ein. Eine Anleitung zur Vorgehensweise finden Sie in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“. Wenn Sie ein „Phantomproblem“ haben (d. h. eines, welches sich nicht gezielt reproduzieren lässt), dann gehen Sie wie folgt vor:

  1. Stellen Sie sicher, dass kein Fehler vorhanden ist. Wenn Sie am Slave beispielsweise Änderungen außerhalb des Slave-Threads vornehmen, dann sind die Daten nicht mehr synchron, und es kann bei Updates zu Verstößen aufgrund von Dubletten eindeutiger Schlüssel kommen. In diesem Fall bleibt der Slave-Thread stehen und wartet, bis Sie die Tabellen manuell bereinigt und die Synchronisation auf diese Weise wiederhergestellt haben. Dies ist kein replikationsbezogenes Problem. Die Replikation schlägt vielmehr aufgrund eines äußeren Störeinflusses fehl.

  2. Führen Sie den Slave mit den Optionen --log-slave-updates und --log-bin aus. Diese Optionen bewirken, dass der Slave die Updates, die er vom Master erhält, in seine eigenen Binärlogs schreibt.

  3. Speichern Sie alle Beweismittel, bevor Sie den Replikationsstatus zurücksetzen. Wenn wir keine oder nur bruchstückhafte Informationen erhalten, wird es schwierig bis unmöglich, die Problemursache zu ermitteln. Folgende Beweisstücke sollten Sie übermitteln:

    • alle Binärlogs des Masters

    • alle Binärlogs des Slaves

    • Ausgabe von SHOW MASTER STATUS auf dem Master zum Zeitpunkt der Feststellung des Problems

    • Ausgabe von SHOW SLAVE STATUS auf dem Slave zum Zeitpunkt der Feststellung des Problems

    • Fehlerlogs von Master und Slave

  4. Überprüfen Sie mit mysqlbinlog die Binärlogs. Folgender Befehl sollte zur Ermittlung der problematischen Abfrage hilfreich sein. Hierbei sind log_pos und log_file die Werte Master_Log_File bzw. Read_Master_Log_Pos in der Ausgabe von SHOW SLAVE STATUS.

    shell> mysqlbinlog -j log_pos \
              log_file | head
    

Nachdem Sie alle Beweisstücke für das Problem gesammelt haben, versuchen Sie es zunächst als separaten Testfall zu extrahieren. Geben Sie das Problem danach mit möglichst vielen Informationen in unsere Bugdatenbank ein. Die Vorgehensweise ist in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschrieben.

6.15. Auto-Increment in der Multi-Master-Replikation

Wenn mehrere Server als Replikationsmaster konfiguriert sind, müssen spezielle Schritte unternommen werden, um Schlüsselkollisionen bei der Verwendung von AUTO_INCREMENT-Spalten zu verhindern; andernfalls könnten mehrere Master beim Einfügen von Datensätzen versuchen, denselben AUTO_INCREMENT-Wert zu verwenden.

Die Systemvariablen auto_increment_increment und auto_increment_offset ermöglichen die Multi-Master-Replikation in Verbindung mit AUTO_INCREMENT-Spalten. Jede dieser Variablen hat einen Standard- und Mindestwert von 1. Der Höchstwert beträgt jeweils 65.535.

Diese beiden Variablen beeinflussen das Verhalten von AUTO_INCREMENT-Spalten wie folgt:

  • auto_increment_increment steuert das Intervall zwischen aufeinander folgenden AUTO_INCREMENT-Werten.

  • auto_increment_offset bestimmt den Startwert der Spalte AUTO_INCREMENT.

Durch Auswahl nichtkollidierender Werte auf verschiedenen Mastern wird dafür gesorgt, dass Server in einer Multimaster-Umgebung beim Einfügen neuer Datensätze in dieselbe Tabelle keine kollidierenden AUTO_INCREMENT-Werte verwenden. Stellen Sie die Variablen wie folgt ein, um N Master-Server zu konfigurieren:

  • Setzen Sie auto_increment_increment auf jedem Master auf N.

  • Stellen Sie auf jedem der N Master einen unterschiedlichen Wert für auto_increment_offset ein (0, 1, 2, … , N – 1).

Weitere Informationen zu auto_increment_increment und auto_increment_offset finden Sie in Abschnitt 5.2.2, „Server-Systemvariablen“.

Kapitel 7. Optimierung

Inhaltsverzeichnis

7.1. Überblick über die Optimierung
7.1.1. MySQL: konzeptionelle Einschränkungen
7.1.2. Applikationskonzepte unter Beachtung von Portabilitätsaspekten
7.1.3. Wofür benutzen wir MySQL?
7.1.4. Die MySQL-Benchmark-Reihe
7.1.5. Wie Sie Ihre eigenen Benchmarks benutzen
7.2. SELECT-Anweisungen und andere Anfragen optimieren
7.2.1. EXPLAIN-Syntax (Informationen über ein SELECT erhalten)
7.2.2. Anfragenperformance abschätzen
7.2.3. Geschwindigkeit von SELECT-Anweisungen
7.2.4. Optimierungen der WHERE-Klausel
7.2.5. Bereichsoptimierung
7.2.6. Optimierung durch Indexverschmelzung
7.2.7. IS NULL-Optimierung
7.2.8. Optimierung von DISTINCT
7.2.9. Optimierung von LEFT JOIN und RIGHT JOIN
7.2.10. Optimierung verschachtelter Joins
7.2.11. Vereinfachungsmöglichkeit für äußere Joins
7.2.12. ORDER BY-Optimierung
7.2.13. GROUP BY-Optimierung
7.2.14. LIMIT-Optimierung
7.2.15. Vermeidung von Tabellenscans
7.2.16. Geschwindigkeit von INSERT-Anweisungen
7.2.17. Geschwindigkeit von UPDATE-Anweisungen
7.2.18. Geschwindigkeit von DELETE-Anfragen
7.2.19. Weitere Optimierungstipps
7.3. Probleme mit Sperren
7.3.1. Wie MySQL Tabellen sperrt
7.3.2. Themen, die Tabellensperren betreffen
7.3.3. Gleichzeitige Einfügevorgänge
7.4. Optimierung der Datenbankstruktur
7.4.1. Überlegungen zum Datenbankdesign
7.4.2. Wie Sie Ihre Daten so klein wie möglich bekommen
7.4.3. Spaltenindizes
7.4.4. Mehrspaltige Indizes
7.4.5. Wie MySQL Indizes benutzt
7.4.6. Der MyISAM-Schlüssel-Cache
7.4.7. Sammlung von MyISAM-Indexstatistiken
7.4.8. Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
7.4.9. Warum gibt es so viele offene Tabellen?
7.5. Optimierung des MySQL Servers
7.5.1. System/Kompilierzeitpunkt und Tuning der Startparameter
7.5.2. Serverparameter feineinstellen
7.5.3. Leistung des Abfragenoptimierers steuern
7.5.4. Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
7.5.5. Wie MySQL Speicher benutzt
7.5.6. Wie MySQL DNS benutzt
7.6. Festplatte, Anmerkungen
7.6.1. Symbolische Verknüpfungen

Die Optimierung ist eine komplexe Aufgabe, denn sie setzt letztendlich ein umfassendes Verständnis des gesamten zu optimierenden Systems voraus. Zwar ist es möglich, in eingeschränktem Maße lokale Optimierungen ohne umfangreiche Kenntnisse Ihres Systems oder Ihrer Anwendung vorzunehmen, aber je optimaler Sie Ihr System gestalten wollen, desto mehr müssen Sie darüber wissen.

In diesem Kapitel werden wir versuchen, die verschiedenen Möglichkeiten zur Optimierung von MySQL zu erläutern und entsprechende Beispiele zu geben. Bedenken Sie aber, dass es stets zusätzliche Möglichkeiten gibt, das System zu beschleunigen, wobei dabei jedoch immer auch der entsprechende Aufwand zu berücksichtigen ist.

7.1. Überblick über die Optimierung

Der wesentlichste Faktor bei der Beschleunigung eines Systems ist sein grundsätzlicher Aufbau. Ferner müssen Sie wissen, welche Bearbeitungen Ihr System durchführt und wo Engpässe vorliegen. In den meisten Fällen treten Engpässe aufgrund folgender Ursachen auf:

  • Suchvorgänge auf der Festplatte. Die Festplatte braucht Zeit, um Daten zu finden. Bei modernen Festplatten beträgt die durchschnittliche Dauer eines Suchvorgangs weniger als 10 Millisekunden, d. h., wir können von einem theoretischen Wert von 100 Suchvorgängen pro Sekunden ausgehen. Dieser Wert lässt sich durch neue Festplatten nur geringfügig verbessern und ist für nur eine einzige Tabelle sehr schwierig zu optimieren. Die Verteilung von Daten auf mehrere Festplatten ist jedoch geeignet, die Suchdauer zu verbessern.

  • Lese- und Schreiboperationen auf Festplatte. Wenn die Festplatte die korrekte Position erreicht hat, müssen die Daten gelesen werden. Moderne Festplatten liefern einen Datendurchsatz von mindestens 10 bis 20 Mbyte/s. Dieser Wert ist einfacher zu optimieren als der Suchwert, da parallel von mehreren Festplatten gelesen werden kann.

  • Prozessorzyklen. Wenn die Daten im Hauptspeicher gelandet sind, müssen wir sie verarbeiten, um das gewünschte Ergebnis zu erhalten. Der am meisten einengende Faktor ist das Vorhandensein von im Vergleich zum verfügbaren Speicher kleinen Tabellen. Bei kleinen Tabellen wiederum ist Geschwindigkeit jedoch nicht das Problem.

  • Speicherbandbreite. Wenn der Prozessor mehr Daten benötigt, als in den Prozessor-Cache passen, dann wird die Bandbreite des Hauptspeichers zum Engpass. Dies kommt zwar bei den meisten Systemen höchst selten vor, sollte jedoch immer in Betracht gezogen werden.

7.1.1. MySQL: konzeptionelle Einschränkungen

Wenn Sie die MyISAM-Speicher-Engine verwenden, benutzt MySQL eine extrem schnelle Tabellensperrung, die mehrere lesende Benutzer oder einen schreibenden Benutzer gestattet. Das größte Problem bei dieser Speicher-Engine tritt auf, wenn ein konstanter Strom von gemischten Änderungs- und langsamen Auswahlanweisungen für eine einzelne Tabelle vorhanden ist. Wenn dies bei bestimmten Tabellen ein Problem darstellt, können Sie für diese eine andere Speicher-Engine verwenden. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

MySQL kann sowohl mit transaktionssicheren als auch mit nichttransaktionssicheren Tabellen arbeiten. Um die reibungslose Arbeit mit nichttransaktionssicheren Tabellen (also Tabellen, für die im Fehlerfall kein Rollback durchgeführt werden kann) zu erleichtern, unterstützt MySQL die folgenden Regeln. Beachten Sie, dass diese Regeln nur dann gültig sind, wenn MySQL nicht im strikten SQL-Modus ausgeführt wird oder Sie IGNORE für INSERT- oder UPDATE-Anweisungen angegeben haben.

  • Für alle Spalten gibt es Vorgabewerte.

  • Wenn Sie einen unpassenden oder ungültigen Wert in eine Spalte eingeben, setzt MySQL diesen automatisch auf den „bestmöglichen“ Wert, statt einen Fehler zu melden. Bei numerischen Werten ist dies entweder 0 oder der kleinst- oder größtmögliche Wert. Bei Strings wird entweder der Leer-String oder der Bestandteil des Strings benutzt, der noch in der Spalte gespeichert werden kann.

  • Alle berechneten Ausdrücke geben einen Wert zurück, der verwendet werden kann, statt eine Fehlerbedingung auszugeben. So gibt etwa 1 ÷ 0 NULL zurück.

Um obiges Verhalten zu ändern, können Sie eine striktere Datenverarbeitung aktivieren, indem Sie den SQL-Modus auf dem Server entsprechend ändern. Weitere Informationen zum Umgang mit Daten finden Sie in Abschnitt 1.9.6, „Wie MySQL mit Constraints umgeht“, Abschnitt 5.2.5, „Der SQL-Modus des Servers“, und Abschnitt 13.2.4, „INSERT.

7.1.2. Applikationskonzepte unter Beachtung von Portabilitätsaspekten

Da alle SQL-Server unterschiedliche Teile des SQL-Standards implementieren, ist die Entwicklung portierbarer Datenbankanwendungen sehr aufwändig. Bei sehr simplen Auswahl- und Einfügeoperationen mag die einfache Portierbarkeit noch gegeben sein, aber je mehr Funktionalitäten Sie benötigen, umso komplexer wird sie. Wenn Sie eine Anwendung brauchen, die auf vielen verschiedenen Datenbanksystemen schnell ist, wird es noch schwieriger.

Alle Datenbanksysteme haben Schwachpunkte: Entwicklungsseitig enthalten sie Kompromisse, die ein unterschiedliches Verhalten verursachen.

Um eine komplexe Anwendung portierbar zu machen, müssen Sie zunächst ermitteln, auf welchen SQL-Servern sie laufen muss, und dann bestimmen, welche Funktionen diese Server unterstützen. Sie können mit dem MySQL-Programm crash-me Funktionen, Typen und Einschränkungen ermitteln, die für eine Auswahl von Datenbankservern gelten. crash-me prüft nicht alle denkbaren Funktionen, ist aber mit etwa 450 Tests vergleichsweise umfassend. Ein Beispiel für die Art von Informationen, die sich mit crash-me ermitteln lassen, ist etwa die Tatsache, dass Sie keine Spaltennamen verwenden sollten, die mehr als 18 Zeichen umfassen, wenn Sie Informix oder DB2 einsetzen wollen.

Das Programm crash-me und die MySQL-Benchmarks hängen stark von der jeweiligen Datenbank ab. Sehen Sie sich einmal an, wie sie geschrieben sind, um ein Gefühl dafür erhalten, was Sie tun müssen, um Ihre eigenen Anweisungen so datenbankunabhängig wie möglich zu machen. Sie finden die Programme im Verzeichnis sql-bench der MySQL-Quelldistributionen. Sie sind in Perl geschrieben und verwenden die DBI-Datenbankschnittstelle. Bereits die Verwendung von DBI löst das Portabilitätsproblem teilweise, denn die Schnittstelle bietet datenbankübergreifende Zugriffsmethoden. Siehe auch Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“.

Wenn Sie nach Datenbankunabhängigkeit streben, brauchen Sie ein gutes Gespür für die Engpässe auf den einzelnen SQL-Servern. So ist MySQL beispielsweise sehr schnell, wenn es um das Abrufen und Aktualisieren von Datensätzen in MyISAM-Tabellen geht, hat aber Probleme bei Fällen, in denen gleichzeitig langsame Lese- und Schreibvorgänge verwaltet werden müssen. Oracle andererseits zeigt sich ausgesprochen widerspenstig, wenn Sie auf Datensätze zugreifen wollen, die Sie kürzlich aktualisiert (und noch nicht auf Festplatte synchronisiert) haben. Transaktionssichere Datenbanksysteme sind generell nicht besonders gut zur Erstellung von Zusammenfassungstabellen aus Logtabellen geeignet, weil in diesem Fall die Sperrung von Datensätzen praktisch nutzlos ist.

Um Ihre Anwendung wirklich datenbankunabhängig zu machen, sollten Sie eine leicht zu erweiternde Schnittstelle definieren, über die Sie Ihre Daten manipulieren. C++ beispielsweise ist auf den meisten Systemen verfügbar, weswegen es sinnvoll ist, eine Datenbankschnittstelle auf Basis einer C++-Klasse zu verwenden.

Wenn Sie die eine oder andere Funktion verwenden, die für ein gegebenes Datenbanksystem spezifisch ist (z. B. die MySQL-Anweisung REPLACE), dann sollten Sie dieselbe Funktion für andere SQL-Server implementieren, indem Sie eine alternative Methode einkodieren. Auch wenn diese Alternative langsamer ist, so erlaubt sie es anderen Servern doch, dieselben Aufgaben auszuführen.

Bei MySQL können Sie mit der Syntax /*! */ MySQL-spezifische Schlüsselwörter zu einer Anweisung hinzufügen. Der Code in /* */ wird von den meisten anderen SQL-Servern als Kommentar betrachtet (und insofern ignoriert). Informationen zum Schreiben von Kommentaren finden Sie in Abschnitt 9.4, „Kommentar“.

Wenn die Leistungsfähigkeit wichtiger ist als die Genauigkeit (wie es beispielsweise bei Webanwendungen der Fall ist), dann können Sie eine Anwendungsschicht erstellen, die alle Ergebnisse zwischenspeichert, um die Performance noch besser zu optimieren. Indem Sie ältere Ergebnisse nach einer bestimmten Zeit ungültig werden lassen, können Sie den Cache ausreichend aktuell halten. Auf diese Weise können Sie Belastungsspitzen abfangen, indem Sie die Cache-Größe dynamisch erhöhen und den Ungültigkeitszeitpunkt nach hinten verschieben, bis sich die Belastung wieder normalisiert hat.

In diesem Fall sollten die Angaben zur Tabellenerstellung Informationen zur ursprünglichen Cache-Größe und dazu enthalten, wie oft die Tabelle normalerweise aktualisiert wird.

Eine interessante Alternative zur Implementierung eines Anwendungs-Caches ist die Verwendung des Abfrage-Caches von MySQL. Wenn Sie den Abfrage-Cache aktivieren, bestimmt der Server selbst, ob ein Abfrageergebnis wiederverwendet werden kann. Dies vereinfacht Ihre Anwendung. Siehe auch Abschnitt 5.14, „MySQL-Anfragen-Cache“.

7.1.3. Wofür benutzen wir MySQL?

Dieser Abschnitt beschreibt eine sehr frühe Anwendung für MySQL.

Im Verlauf der ursprünglichen Entwicklung von MySQL wurden die Funktionen an die Anforderungen unseres größten Kunden angepasst, der das Data-Warehousing für einige der großen schwedischen Handelshäuser implementierte.

Von allen Läden erhielten wir wöchentliche Übersichten über alle Kundenkartentransaktionen, und es wurde von uns verlangt, brauchbare Informationen für Geschäftsinhaber bereitzustellen, damit diese feststellen konnten, wie sich ihre Werbekampagnen auf das Kaufverhalten ihrer Kunden auswirkten.

Das Datenvolumen war gewaltig (ca. sieben Millionen Transaktionen pro Monat), und wir hatten Daten für vier bis zehn Jahre, die wir den Benutzern präsentieren sollten. Allwöchentlich erhielten wir Anfragen von unseren Kunden, die sofortigen Zugriff auf neue, auf diesen Daten basierende Berichte benötigten.

Dieses Problem lösten wir, indem wir alle Daten eines Monats in komprimierten „Transaktionstabellen“ speicherten. Wir hatten eine Anzahl einfacher Makros, die aus den Tabellen, in denen die Transaktionen gespeichert waren, nach verschiedenen Kriterien (Produktgruppe, Kundennummer, Filiale usw.) gruppierte Übersichtstabellen erstellten. Diese Berichte waren Webseiten, die mithilfe eines kleinen Perl-Skripts dynamisch erzeugt wurden. Das Skript analysierte eine Webseite, führte die enthaltenen SQL-Anweisungen aus und fügte die Ergebnisse ein. Wir hätten stattdessen sicher PHP oder mod_perl verwendet, aber diese waren seinerzeit noch nicht verfügbar.

Für die grafische Ausgabe schrieben wir ein kleines Tool in C, das SQL-Abfrageergebnisse verarbeiten und auf Basis der Ergebnisse GIF-Grafiken erstellen konnte. Auch dieses Tool wurde von dem Perl-Skript, welches die Webseiten analysierte, dynamisch ausgeführt.

In den meisten Fällen konnte ein neuer Bericht einfach erstellt werden, indem man ein vorhandenes Skript kopierte und die von ihm verwendete SQL-Abfrage einfach anpasste. In manchen Fällen mussten wir neue Spalten zu einer vorhandenen Übersichtstabelle hinzufügen oder eine neue Tabelle erstellen. Auch dies war ganz einfach, weil wir alle Tabellen mit den Transaktionen auf Festplatte speicherten. (In der Summe hatten wir dann 50 Gbyte Transaktionstabellen sowie 200 Gbyte weiterer Kundendaten.)

Außerdem gestatteten wir unseren Kunden via ODBC den direkten Zugriff auf die Übersichtstabellen, sodass Kunden bei Bedarf selbst mit den Daten experimentieren konnten.

Dieses System funktionierte gut, und wir hatten keine Probleme mit der Verwaltung der Daten auf einer eher bescheidenen Hardware (Sun Ultra SPARCstation, 2 × 200 MHz). Am Ende wurde das System dann auf Linux migriert.

7.1.4. Die MySQL-Benchmark-Reihe

Anhand dieser Benchmark-Reihe kann jeder Benutzer ermitteln, welche Operationen eine gegebene SQL-Implementierung gut oder weniger gut ausführt. Sie können sich einen guten Eindruck davon verschaffen, wie die Benchmarks funktionieren, indem Sie sich den Code und die Ergebnisse im Verzeichnis sql-bench einer beliebigen MySQL-Quelldistribution ansehen.

Beachten Sie, dass diese Benchmark nur einen Thread verwendet – sie misst also die Mindestdauer der durchgeführten Operationen. Wir planen, die Benchmark-Reihe in Zukunft durch Multithread-Tests zu ergänzen.

Um die Benchmark-Reihe verwenden zu können, müssen folgende Voraussetzungen erfüllt sein:

  • Die Benchmark-Reihe wird als Bestandteil der MySQL-Quelldistributionen ausgeliefert. Sie können entweder eine Release-Version von http://dev.mysql.com/downloads/ herunterladen oder den aktuellen Entwicklungs-Source-Tree verwenden. (Siehe auch Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“.)

  • Die Benchmark-Skripten sind in Perl geschrieben und verwenden das Perl-DBI-Modul für den Zugriff auf Datenbankserver; insofern muss DBI installiert sein. Ferner benötigen Sie die serverspezifischen BDB-Treiber für jeden Server, den Sie testen wollen. Um beispielsweise MySQL, PostgreSQL und DB2 prüfen zu können, müssen die Module DBD::mysql, DBD::Pg und DBD::DB2 installiert sein. Siehe auch Abschnitt 2.13, „Anmerkungen zur Perl-Installation“.

Nachdem Sie sich eine MySQL-Quelldistribution besorgt haben, finden Sie die Benchmark-Reihe im dortigen Verzeichnis sql-bench. Um die Benchmark-Tests durchzuführen, erstellen Sie MySQL und wechseln dann in das Verzeichnis sql-bench. Dort führen Sie das Skript run-all-tests aus:

 shell> cd sql-bench shell>
perl run-all-tests
--server=server_name 

server_name sollte der Name eines der unterstützten Server sein. Um eine Liste aller Optionen und unterstützten Server zu erhalten, rufen Sie folgenden Befehl auf:

 shell> perl run-all-tests --help

Das Skript crash-me befindet sich ebenfalls im Verzeichnis sql-bench. crash-me versucht durch Ausführung von Abfragen zu ermitteln, welche Funktionen ein Datenbanksystem unterstützt und welche Fähigkeiten und Einschränkungen es aufweist. Beispielsweise wird ermittelt,

  • welche Datentypen unterstützt werden,

  • wie viele Indizes unterstützt werden,

  • welche Funktionen unterstützt werden,

  • wie groß eine Abfrage sein darf,

  • wie groß eine VARCHAR-Spalte sein darf.

Die Ergebnisse von crash-me finden Sie für viele verschiedene Datenbankserver unter http://dev.mysql.com/tech-resources/crash-me.php. Weitere Informationen zu Benchmark-Ergebnissen finden Sie unter http://dev.mysql.com/tech-resources/benchmarks/.

7.1.5. Wie Sie Ihre eigenen Benchmarks benutzen

Sie sollten Ihre Anwendung und Ihre Datenbank in jedem Fall mit der Benchmark-Reihe prüfen, um festzustellen, wo ggf. Engpässe vorhanden sind. Wenn Sie einen Engpass behoben (oder ihn durch ein „Dummymodul“ ersetzt) haben, können Sie mit der Suche nach weiteren Engpässen fortfahren. Auch wenn die Gesamtleistung für Ihre Anwendung derzeit akzeptabel sein sollte, sollten Sie zumindest einen Plan für jeden Engpass erstellen und entscheiden, wie Sie ihn bei Bedarf beseitigen, sofern dieser Bedarf eines Tages auftreten sollte.

Beispiele für portable Benchmark-Programme finden Sie in der MySQL-Benchmark-Reihe. Siehe auch Abschnitt 7.1.4, „Die MySQL-Benchmark-Reihe“. Sie können ein beliebiges Programm dieser Reihe nehmen und an Ihre eigenen Bedürfnisse anpassen. Dies erlaubt Ihnen, verschiedene Lösungen für Ihr Problem auszuprobieren und zu ermitteln, welche wirklich die schnellste ist.

Eine weitere kostenlose Benchmark-Reihe ist die Open Source Database Benchmark, die Sie unter http://osdb.sourceforge.net/ erhalten.

Häufig treten Probleme nur dann auf, wenn das System sehr stark ausgelastet ist. Viele unserer Kunden wenden sich an uns, wenn sie ein (getestetes) Produktionssystem haben, welches unter Last Ausfallerscheinungen zeigt. In den meisten Fällen werden leistungsbezogene Probleme durch Faktoren des grundlegenden Datenbankdesigns (etwa im Fall von Schwächen bei Tabellenscans unter Last) oder durch Probleme mit dem Betriebssystem oder mit Bibliotheken verursacht. Meistens würden sich diese Probleme wesentlich einfacher beheben lassen, wenn das jeweilige System nicht bereits in der Produktion verwendet würde.

Um derartige Probleme zu vermeiden, sollten Sie den Aufwand auf sich nehmen und Benchmark-Tests Ihrer Anwendung unter maximaler Last durchführen:

Wie die Namen dieser Programme bereits suggerieren, besteht ihr Zweck darin, Ihr System in die Knie zu zwingen. Es sollte also klar sein, dass Sie diese Programme nur auf Entwicklungssystemen einsetzen.

7.2. SELECT-Anweisungen und andere Anfragen optimieren

Zunächst einmal gibt es einen Faktor, der sich auf alle Anweisungen auswirkt: Je komplexer Ihre Berechtigungskonfiguration ist, desto höher ist der Aufwand für MySQL. Die Verwendung einfacherer Berechtigungen beim Absetzen von GRANT-Anweisungen gestattet MySQL eine Verringerung der berechtigungsbedingten Mehrbelastung, wenn Clients Anweisungen ausführen. Wenn Sie beispielsweise keine Berechtigungen auf Tabellen- oder Spaltenebene gewähren, muss der Server keinerlei Überprüfung der Tabellen tables_priv und columns_priv durchführen. Analog ist auch keine Ressourcenzählung durchzuführen, wenn Sie die Ressourcen für kein Konto beschränken. Wenn Sie eine sehr hohe Auslastung durch die Anweisungsverarbeitung haben, kann es lohnenswert sein, eine vereinfachte Gewährungsstruktur zu verwenden, um die Mehrbelastung durch die Überprüfung von Berechtigungen zu verringern.

Hängt Ihr Problem mit einem bestimmten MySQL-Ausdruck oder einer MySQL-Funktion zusammen, dann können Sie eine Timingprüfung durchführen, indem Sie die Funktion BENCHMARK() mithilfe des Clientprogramms mysql aufrufen. Die Syntax lautet BENCHMARK(loop_count,expression). Der Rückgabewert ist immer null, aber mysql gibt eine Zeile aus, die näherungsweise die Ausführungsdauer der Anweisung angibt. Zum Beispiel:

mysql> SELECT BENCHMARK(1000000,1+1);
+------------------------+
| BENCHMARK(1000000,1+1) |
+------------------------+
|                      0 |
+------------------------+
1 row in set (0.32 sec)

Dieses Ergebnis wurde mit einem Pentium II-System (400 MHz) ermittelt. Es zeigt, dass MySQL auf diesem System 1.000.000 einfache Additionsausdrücke in 0,32 Sekunden ausführen kann.

Eigentlich sollten alle MySQL-Funktionen hochgradig optimiert sein, aber es gibt unter Umständen ein paar Ausnahmen. BENCHMARK() ist ein hervorragendes Tool, um zu ermitteln, ob irgendeine Funktion für Ihre Abfragen problematisch sein könnte.

7.2.1. EXPLAIN-Syntax (Informationen über ein SELECT erhalten)

 EXPLAIN tbl_name 

Oder:

 EXPLAIN [EXTENDED | PARTITIONS] SELECT
select_options 

Die EXPLAIN-Anweisung kann entweder als Synonym für DESCRIBE oder als Möglichkeit verwendet werden, um Informationen bezüglich der Frage zu ermitteln, wie MySQL eine SELECT-Anweisung ausführt:

  • EXPLAIN tbl_name ist synonym zu DESCRIBE tbl_name oder SHOW COLUMNS FROM tbl_name.

  • Wenn Sie einer SELECT-Anweisung das Schlüsselwort EXPLAIN voranstellen, zeigt MySQL Informationen des Optimierers zum Ausführungsplan der Abfrage an. MySQL erläutert also, wie es die SELECT-Anweisung verarbeiten würde, und gibt zudem an, wie und in welcher Reihenfolge Tabellen miteinander verknüpft werden.

  • EXPLAIN PARTITIONS ist seit MySQL 5.1.5 verfügbar. Es ist nur praktisch, wenn Sie Abfragen untersuchen, die sich auf partitionierte Tabellen beziehen. Detaillierte Informationen finden Sie in Abschnitt 17.3.4, „Abruf von Informationen über Partitionen“.

Dieser Abschnitt beschreibt die zweite Verwendungsmöglichkeit von EXPLAIN: die Anforderung von Informationen zum Abfrageausführungsplan. Eine Beschreibung der Anweisungen DESCRIBE und SHOW COLUMNS finden Sie in Abschnitt 13.3.1, „DESCRIBE (Informationen über Spalten abrufen)“, und Abschnitt 13.5.4.3, „SHOW COLUMNS.

Mithilfe von EXPLAIN können Sie ermitteln, wo Sie Indizes für Tabellen konfigurieren sollten, um SELECT-Anweisungen zu beschleunigen, die Datensätze mithilfe von Indizes finden. Sie können mit EXPLAIN auch überprüfen, ob der Optimierer die Tabellen in optimaler Reihenfolge verknüpft. Um den Optimierer zur Verwendung einer Verknüpfungsreihenfolge zu zwingen, die der Reihenfolge entspricht, in der die Tabellen in der SELECT-Anweisung aufgeführt sind, beginnen Sie die Anweisung mit SELECT STRAIGHT_JOIN statt mit SELECT.

Wenn das Problem auftritt, dass Indizes nicht benutzt werden, obwohl Sie annehmen, dass dies eigentlich der Fall sein sollte, dann führen Sie ANALYZE TABLE aus, um die Tabellenstatistiken wie etwa die Kardinalität der Schlüssel, die sich auf die durch den Optimierer vorgenommene Auswahl auswirken kann, zu aktualisieren. Siehe auch Abschnitt 13.5.2.1, „ANALYZE TABLE.

EXPLAIN gibt je einen Datensatz für jede in der SELECT-Anweisung verwendete Tabelle zurück. Die Tabellen sind in der Ausgabe in der Reihenfolge aufgeführt, in der MySQL sie bei der Verarbeitung der Abfrage lesen würde. MySQL löst alle Joins mithilfe einer Methode auf, die Single-Sweep-Multi-Join heißt. Hierbei liest MySQL einen Datensatz aus der ersten Tabelle und sucht dann einen passenden Datensatz in der zweiten Tabelle, der dritten Tabelle usw. Sind alle Tabellen verarbeitet, dann gibt MySQL die gewählten Spalten aus und durchsucht die Tabellenliste in umgekehrter Reihenfolge, bis eine Tabelle gefunden wird, bei der mehr passende Datensätze vorhanden sind. Der nächste Datensatz wird aus genau dieser Tabelle gelesen, und dann wird der Prozess mit der nächsten Tabelle fortgesetzt.

Wenn das Schlüsselwort EXTENDED verwendet wird, erzeugt EXPLAIN zusätzliche Informationen, die durch Absetzen einer SHOW WARNINGS-Anweisung nach der EXPLAIN-Anweisung angezeigt werden können. Diese Informationen geben Hinweise zum Optimierungsprozess, z. B. wie der Optimierer Tabellen- und Spaltennamen in der SELECT-Anweisung qualifiziert oder wie die SELECT-Anweisung nach der Anwendung der Umformulierungs- und Optimierungsregeln aussieht.

Hinweis: Sie können die Schlüsselwörter EXTENDED und PARTITIONS nicht gemeinsam in derselben EXPLAIN-Anweisung verwenden.

Jeder von EXPLAIN ausgegebene Datensatz enthält Angaben zu genau einer Tabelle. Dabei enthält jeder Datensatz die folgenden Spalten:

  • id

    Der SELECT-Bezeichner. Dies ist die Sequenznummer der SELECT-Anweisung innerhalb der Abfrage.

  • select_type

    Der Typ der SELECT-Anweisung. Dies kann jeder der in der folgenden Tabelle aufgeführten Typen sein:

    SIMPLEeinfache SELECT-Anweisung (ohne UNION oder Unterabfragen).
    PRIMARYäußerste SELECT-Anweisung.
    UNIONzweite oder spätere SELECT-Anweisung in einer UNION.
    DEPENDENT UNIONzweite oder spätere SELECT-Anweisung in einer UNION, abhängig von der äußeren Abfrage.
    UNION RESULTErgebnis einer UNION.
    SUBQUERYerste SELECT-Anweisung in einer Unterabfrage.
    DEPENDENT SUBQUERYerste SELECT-Anweisung in einer Unterabfrage, abhängig von der äußeren Abfrage.
    DERIVEDabgeleitete Tabellen-SELECT-Anweisung (Unterabfrage in FROM-Klausel).

    DEPENDENT bezeichnet normalerweise die Verwendung einer korrelierten Unterabfrage. Siehe auch Abschnitt 13.2.8.7, „Korrelierte Unterabfragen“.

  • table

    Die Tabelle, die der Ausgabedatensatz referenziert.

  • type

    Der Join-Typ. Die verschiedenen Join-Typen sind nachfolgend aufgelistet, sortiert vom besten bis zum schlechtesten:

    • system

      Diese Tabelle hat nur einen Datensatz (Systemtabelle). Dies ist ein Sonderfall des Join-Typs const.

    • const

      Die Tabelle hat maximal einen passenden Datensatz, der beim Start der Abfrage gelesen wird. Da nur ein Datensatz vorhanden ist, können die Werte aus den Spalten dieses Datensatzes vom Optimierer im Folgenden als Konstanten behandelt werden. const-Tabellen sind sehr schnell, da sie nur einmal gelesen werden.

      const wird verwendet, wenn Sie alle Teile eines Primärschlüssels oder eines eindeutigen Indexes mit Konstantenwerten vergleichen. In der folgenden Abfrage kann tbl_name als const-Tabelle verwendet werden:

       SELECT * FROM tbl_name WHERE
      primary_key=1;
      
      SELECT * FROM tbl_name WHERE
      primary_key_part1=1 AND
      primary_key_part2=2; 
    • eq_ref

      Für jede Datensatzkombination aus den vorherigen Tabellen wird genau ein Datensatz aus dieser Tabelle gelesen. Anders als die Typen system und const ist dies der beste Join-Typ. Er wird verwendet, wenn alle Teile eines Indexes vom Join verwendet werden und der Index ein Primärschlüssel oder ein eindeutiger Index ist.

      eq_ref kann für indizierte Spalten benutzt werden, die mithilfe des Operators = verglichen werden. Der Vergleichswert kann eine Konstante oder ein Ausdruck sein, der Spalten aus Tabellen verwendet, die vor dieser Tabelle gelesen wurden. In den folgenden Beispielen kann MySQL einen eq_ref-Join zur Verarbeitung von ref_table verwenden:

      SELECT * FROM ref_table,other_table
        WHERE ref_table.key_column=other_table.column;
      
      SELECT * FROM ref_table,other_table
        WHERE ref_table.key_column_part1=other_table.column
        AND ref_table.key_column_part2=1;
      
    • ref

      Alle Datensätze mit passenden Indexwerten werden aus dieser Tabelle für jede Kombination von Datensätzen in den vorherigen Tabellen gelesen. ref wird benutzt, wenn der Join nur ein linkes Präfix des Schlüssels verwendet oder der Schlüssel kein Primärschlüssel und auch kein eindeutiger Index ist (d. h., wenn der Join keinen einzelnen Datensatz basierend auf dem Schlüsselwert auswählen kann). Wenn der verwendete Schlüssel nur einigen wenigen Datensätzen entspricht, ist dies ein guter Join-Typ.

      ref kann für indizierte Spalten benutzt werden, die mithilfe der Operatoren = oder <=> verglichen werden. In den folgenden Beispielen kann MySQL einen ref-Join zur Verarbeitung von ref_table verwenden:

       SELECT * FROM ref_table WHERE
      key_column=expr;
      
      SELECT * FROM
      ref_table,other_table
      WHERE
      ref_table.key_column=other_table.column;
      
      SELECT * FROM
      ref_table,other_table
      WHERE
      ref_table.key_column_part1=other_table.column
      AND
      ref_table.key_column_part2=1;
      
    • ref_or_null

      Dieser Join-Typ ähnelt ref weitgehend, allerdings führt MySQL hierbei eine zusätzliche Suche nach Datensätzen durch, die NULL-Werte enthalten. Diese Join-Typ-Optimierung wird meistens bei der Auflösung von Unterabfragen verwendet. In den folgenden Beispielen kann MySQL einen ref_or_null-Join zur Verarbeitung von ref_table verwenden:

       SELECT * FROM ref_table WHERE
      key_column=expr OR
      key_column IS NULL; 

      Siehe auch Abschnitt 7.2.7, „IS NULL-Optimierung“.

    • index_merge

      Dieser Join-Typ gibt an, dass die Indexverschmelzungsoptimierung verwendet wird. In diesem Fall enthält die Spalte key im ausgegebenen Datensatz eine Liste der verwendeten Indizes, und key_len enthält eine Liste der längsten Schlüsselteile für die verwendeten Indizes. Weitere Informationen finden Sie unter Abschnitt 7.2.6, „Optimierung durch Indexverschmelzung“.

    • unique_subquery

      Dieser Typ ersetzt ref in einigen IN-Unterabfragen der folgenden Form:

       value IN (SELECT
      primary_key FROM
      single_table WHERE
      some_expr) 

      unique_subquery ist eine Nachschlagefunktion für Indizes, die zur Effizienzsteigerung die Unterabfrage vollständig ersetzt.

    • index_subquery

      Dieser Join-Typ ähnelt unique_subquery. Er ersetzt IN-Unterabfragen, funktioniert aber bei nichteindeutigen Indizes in Unterabfragen folgender Form:

       value IN (SELECT
      key_column FROM
      single_table WHERE
      some_expr) 
    • range

      Es werden nur Datensätze abgerufen, die in einem gegebenen Bereich liegen. Sie werden anhand eines Indexes ausgewählt. Die Spalte key im Ausgabedatensatz zeigt an, welcher Index verwendet wird. key_len enthält den längsten verwendeten Schlüsselteil. Die Spalte ref ist für diesen Typ NULL.

      range kann verwendet werden, wenn eine Schlüsselspalte unter Verwendung eines der Operatoren =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN oder IN mit einer Konstante verglichen wird:

      SELECT * FROM tbl_name
        WHERE key_column = 10;
      
      SELECT * FROM tbl_name
        WHERE key_column BETWEEN 10 and 20;
      
      SELECT * FROM tbl_name
        WHERE key_column IN (10,20,30);
      
      SELECT * FROM tbl_name
        WHERE key_part1= 10 AND key_part2 IN (10,20,30);
      
    • index

      Dieser Join-Typ ist mit ALL bis auf die Tatsache identisch, dass nur der Indexbaum gescannt wird. Insofern ist er in der Regel schneller als ALL, weil die Indexdatei gewöhnlich kleiner ist als die Datendatei.

      MySQL kann diesen Join-Typ verwenden, wenn die Abfrage nur Spalten benutzt, die Teil eines einzelnen Indexes sind.

    • ALL

      Ein vollständiger Tabellenscan wird für jede Kombination von Datensätzen aus den vorherigen Tabellen durchgeführt. Dies ist normalerweise nicht von Vorteil, wenn die Tabelle die erste nicht als const gekennzeichnete Tabelle ist, und in allen anderen Fällen sogar ganz schlimm. Sie können ALL normalerweise vermeiden, indem Sie Indizes hinzufügen, die das Abrufen von Datensätzen aus der Tabelle basierend auf Konstanten- oder Spaltenwerten aus früheren Tabellen erlauben.

  • possible_keys

    Die Spalte possible_keys gibt an, unter welchen Indizes MySQL auswählen kann, um Datensätze in dieser Tabelle zu suchen. Beachten Sie, dass diese Spalte vollständig unabhängig von der Reihenfolge der Tabellen ist, wie sie in der Ausgabe von EXPLAIN angezeigt wird. Das bedeutet, dass einige der Schlüssel in possible_keys mit der erzeugten Tabellenreihenfolge unter Umständen praktisch nicht verwendbar sind.

    Wenn diese Spalte NULL ist, gibt es keine relevanten Indizes. In diesem Fall können Sie die Leistungsfähigkeit Ihrer Abfrage möglicherweise verbessern, indem Sie die WHERE-Klausel daraufhin untersuchen, ob sie eine oder mehrere Spalten referenziert, die für die Indexerstellung geeignet wären. Sollte dies der Fall sein, so erstellen Sie einen passenden Index und überprüfen die Abfrage dann mit EXPLAIN erneut. Siehe auch Abschnitt 13.1.2, „ALTER TABLE.

    Um anzuzeigen, welche Indizes eine Tabelle hat, verwenden Sie SHOW INDEX FROM tbl_name.

  • key

    Die Spalte key gibt den Schlüssel(index) an, für dessen Verwendung sich MySQL tatsächlich entschieden hat. Der Schlüssel ist NULL, wenn kein Index ausgewählt wurde. Um das Verwenden oder Ignorieren eines Indexes, der in der Spalte possible_keys aufgeführt ist, durch MySQL zu erzwingen oder zu ignorieren, verwenden Sie FORCE INDEX oder USE INDEX bzw. IGNORE INDEX in Ihrer Abfrage. Siehe auch Abschnitt 13.2.7, „SELECT.

    Bei MyISAM- und BDB-Tabellen erleichtert die Ausführung von ANALYZE TABLE dem Optimierer die Auswahl geeigneter Indizes. Bei MyISAM-Tabellen tut myisamchk --analyze dasselbe. Siehe auch Abschnitt 13.5.2.1, „ANALYZE TABLE, und Abschnitt 5.10.4, „Benutzung von myisamchk für Tabellenwartung und Absturzreparatur“.

  • key_len

    Die Spalte key_len gibt die Länge des Schlüssels an, für dessen Verwendung sich MySQL entschieden hat. Die Länge ist NULL, wenn in der Spalte key NULL steht. Beachten Sie, dass der Wert von key_len Ihnen die Feststellung gestattet, wie viele Teile eines mehrteiligen Schlüssels MySQL tatsächlich verwendet.

  • ref

    Die Spalte ref zeigt an, welche Spalten oder Konstanten mit dem in der Spalte key genannten Index verglichen werden, um Datensätze aus der Tabelle auszuwählen.

  • rows

    Die Spalte rows gibt die Anzahl der Datensätze an, die MySQL glaubt untersuchen zu müssen, um die Abfrage ausführen zu können.

  • Extra

    Diese Spalte enthält zusätzliche Angaben dazu, wie MySQL die Abfrage auflöst. Es folgt eine Erläuterung der Werte, die in dieser Spalte erscheinen können:

    • Distinct

      MySQL sucht nach unterschiedlichen Werten, d. h., die Suche nach weiteren Datensätzen zur aktuellen Datensatzkombination wird beendet, sobald der erste Datensatz gefunden wurde.

    • Not exists

      MySQL konnte eine LEFT JOIN-Optimierung an der Abfrage vornehmen und untersucht für die vorhergehende Datensatzkombination keine weiteren Datensätze in dieser Tabelle, sobald ein Datensatz gefunden wurde, der den LEFT JOIN-Kriterien entspricht. Hier ein Beispiel für einen Abfragetyp, der auf diese Weise optimiert werden kann:

      SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id
        WHERE t2.id IS NULL;
      

      Nehmen wir an, t2.id sei als NOT NULL definiert. In diesem Fall scannt MySQL t1 und sucht die Datensätze in t2 unter Verwendung der Werte aus t1.id heraus. Findet MySQL einen passenden Datensatz in t2, dann weiß es, dass t2.id niemals NULL sein kann, und scannt die weiteren Datensätze in t2, die denselben id-Wert aufweisen, nicht mehr. Für jeden Datensatz in t1 muss MySQL also nur einen einzigen Suchvorgang in t2 durchführen – unabhängig davon, wie viele entsprechende Datensätze in t2 tatsächlich vorhanden sind.

    • range checked for each record (index map: N)

      MySQL hat keinen geeigneten Index gefunden, aber festgestellt, dass einige der Indizes verwendet werden könnten, nachdem Spaltenwerte aus vorhergehenden Tabellen bekannt geworden sind. Für jede Datensatzkombination in den vorherigen Tabellen überprüft MySQL, ob es möglich ist, zum Abrufen von Datensätzen eine der Zugriffsmethoden range oder index_merge zu verwenden. Dies ist nicht sehr schnell, aber immer noch schneller als die Durchführung eines Joins ohne Index. Die Anwendbarkeitskriterien entsprechen den in Abschnitt 7.2.5, „Bereichsoptimierung“, und Abschnitt 7.2.6, „Optimierung durch Indexverschmelzung“, beschriebenen, nur sind hier alle Spaltenwerte für die vorhergehende Tabelle bekannt und werden als Konstanten betrachtet.

    • Using filesort

      MySQL muss einen zusätzlichen Durchlauf vornehmen, um zu ermitteln, wie die Datensätze in sortierter Reihenfolge abgerufen werden können. Diese Sortierung erfolgt, indem alle Datensätze entsprechend dem Join-Typ überprüft und Sortierschlüssel sowie der Zeiger auf den Datensatz für alle Datensätze gespeichert werden, die der WHERE-Klausel entsprechen. Die Schlüssel werden dann sortiert und die Datensätze entsprechend in sortierter Reihenfolge abgerufen. Siehe auch Abschnitt 7.2.12, „ORDER BY-Optimierung“.

    • Using index

      Die Spaltendaten werden ausschließlich unter Verwendung von Angaben im Indexbaum aus der Tabelle abgerufen – es erfolgt kein zusätzlicher Suchvorgang, um jeweils den eigentlichen Datensatz auszulesen. Diese Strategie kann verwendet werden, wenn die Abfrage nur Spalten benutzt, die Teil eines einzelnen Indexes sind.

    • Using temporary

      Um die Abfrage aufzulösen, muss MySQL eine Temporärtabelle zur Aufnahme des Ergebnisses erstellen. Dies geschieht typischerweise, wenn die Abfrage GROUP BY- und ORDER BY-Klauseln enthält, die Spalten unterschiedlich auflisten.

    • Using where

      Mit einer WHERE-Klausel wird festgelegt, welche Datensätze mit der nächsten Tabelle verglichen oder an den Client gesendet werden. Sofern Sie nicht gezielt alle Datensätze aus der Tabelle abrufen oder untersuchen wollen, haben Sie in der Abfrage einen Fehler gemacht, wenn der Wert Extra nicht Using where ist und ALL oder index als Join-Typ für die Tabelle angegeben ist.

      Wollen Sie Ihre Abfragen so schnell wie möglich machen, dann sollten Sie nach den Extra-Werten Using filesort und Using temporary suchen.

    • Using sort_union(…), Using union(…), Using intersect(…)

      Diese Werte geben an, wie Indexscans für den Join-Typ index_merge zusammengefasst werden. Weitere Informationen finden Sie in Abschnitt 7.2.6, „Optimierung durch Indexverschmelzung“.

    • Using index for group-by

      Ähnlich wie die Tabellenzugriffsmethode Using index gibt Using index for group-by an, dass MySQL einen Index gefunden hat, der zum Abrufen aller Datensätze einer GROUP BY- oder DISTINCT-Abfrage ohne zusätzlichen Festplattenzugriff auf die eigentliche Tabelle verwendet werden kann. Außerdem wird der Index auf die effizienteste Art und Weise verwendet, sodass für jede Gruppe nur ein paar wenige Indexeinträge gelesen werden. Detaillierte Informationen finden Sie in Abschnitt 7.2.13, „GROUP BY-Optimierung“.

    • Using where with pushed condition

      Dieses Element ist ausschließlich für NDB Cluster-Tabellen verfügbar. Es bedeutet, dass MySQL Cluster einen Bedingungs-Pushdown verwendet, um die Effizienz eines direkten Vergleichs (=) zwischen einer nichtindizierten Spalte und einer Konstanten zu steigern. In solchen Fällen wird die Bedingung in den Datenknoten des Clusters „eingekellert“, wo sie dann in allen Partitionen gleichzeitig ausgewertet wird. Hierdurch wird der Versand unpassender Datensätze über das Netzwerk vermieden, und die entsprechenden Abfragen werden um den Faktor 5 bis 10 im Vergleich zu Fällen beschleunigt, in denen ein Bedingungs-Pushdown hätte verwendet werden können, aber nicht verwendet wurde.

      Angenommen, eine Cluster-Tabelle sei wie folgt definiert:

      CREATE TABLE t1 (
          a INT, 
          b INT, 
          KEY(a)
      ) ENGINE=NDBCLUSTER;
      

      In diesem Fall kann ein Bedingungs-Pushdown bei einer Abfrage wie der folgenden verwendet werden:

      SELECT a,b FROM t1 WHERE b = 10;
      

      Die Ausgabe von EXPLAIN SELECT sieht dann wie folgt aus:

      mysql> EXPLAIN SELECT a,b FROM t1 WHERE b = 10\G
      *************************** 1. row ***************************
                 id: 1
        select_type: SIMPLE
              table: t1
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 10
              Extra: Using where with pushed condition
      

      Ein Bedingungs-Pushdown kann nicht mit einer der beiden folgenden Abfragen verwendet werden:

      SELECT a,b FROM t1 WHERE a = 10;
      SELECT a,b FROM t1 WHERE b + 1 = 10;
      

      Bezüglich der ersten dieser zwei Abfragen ist der Bedingungs-Pushdown nicht anwendbar, weil in der Spalte a ein Index vorhanden ist. Im Falle der zweiten Abfrage kann ein Bedingungs-Pushdown nicht verwendet werden, weil der Vergleich unter Berücksichtigung der nichtindizierten Spalte b ein indirekter Vergleich ist. (Er wäre allerdings gültig, wenn Sie in der WHERE-Klausel b + 1 = 10 auf b = 9 reduzieren würden.)

      Allerdings kann ein Bedingungs-Pushdown auch verwendet werden, wenn eine indizierte Spalte unter Verwendung eines der Operatoren > oder < mit einer Konstanten verglichen wird:

      mysql> EXPLAIN SELECT a,b FROM t1 WHERE a<2\G
      *************************** 1. row ***************************
                 id: 1
        select_type: SIMPLE
              table: t1
               type: range
      possible_keys: a
                key: a
            key_len: 5
                ref: NULL
               rows: 2
              Extra: Using where with pushed condition
      

      Merken Sie sich in Bezug auf einen Bedingungs-Pushdown Folgendes:

      • Der Bedingungs-Pushdown ist nur für MySQL Cluster relevant und tritt nicht auf, wenn Sie Abfragen unter Verwendung anderer Speicher-Engines an Tabellen absetzen.

      • Bedingungs-Pushdowns werden nicht standardmäßig eingesetzt. Um sie zu aktivieren, können Sie mysqld mit der Option --engine-condition-pushdown oder die folgende Anweisung ausführen:

        SET engine_condition_pushdown=On;
        

Sie erhalten einen geeigneten Anhaltspunkt zu der Frage, wie gut ein Join ist, indem Sie das Produkt der Werte in der Spalte rows der Ausgabe von EXPLAIN erstellen. Hieraus ergibt sich grob, wie viele Datensätze MySQL untersuchen muss, um die Abfrage auszuführen. Wenn Sie die Abfragen mit der Systemvariablen max_join_size beschränken, wird dieses Datensatzprodukt auch benutzt, um zu bestimmen, welche SELECT-Anweisungen für mehrere Tabellen ausgeführt und welche abgebrochen werden. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

Das folgende Beispiel zeigt, wie ein Join mehrerer Tabellen auf der Basis der von EXPLAIN übermittelten Angaben progressiv optimiert werden kann.

Angenommen, Sie hätten die folgende SELECT-Anweisung, die Sie mit EXPLAIN untersuchen wollen:

EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
               tt.ProjectReference, tt.EstimatedShipDate,
               tt.ActualShipDate, tt.ClientID,
               tt.ServiceCodes, tt.RepetitiveID,
               tt.CurrentProcess, tt.CurrentDPPerson,
               tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
               et_1.COUNTRY, do.CUSTNAME
        FROM tt, et, et AS et_1, do
        WHERE tt.SubmitTime IS NULL
          AND tt.ActualPC = et.EMPLOYID
          AND tt.AssignedPC = et_1.EMPLOYID
          AND tt.ClientID = do.CUSTNMBR;

Für dieses Beispiel gelten die folgenden Annahmen:

  • Die zu vergleichenden Spalten wurden wie folgt deklariert:

    TabelleSpalteDatentyp
    ttActualPCCHAR(10)
    ttAssignedPCCHAR(10)
    ttClientIDCHAR(10)
    etEMPLOYIDCHAR(15)
    doCUSTNMBRCHAR(15)
  • Die Tabellen haben die nachfolgenden Indizes:

    TabelleIndex
    ttActualPC
    ttAssignedPC
    ttClientID
    etEMPLOYID (Primärschlüssel)
    doCUSTNMBR (Primärschlüssel)
  • Die tt.ActualPC-Werte sind nicht gleichmäßig verteilt.

Anfangs – also vor der Durchführung von Optimierungen – erzeugt die EXPLAIN-Anweisung die folgenden Angaben:

table type possible_keys key  key_len ref  rows  Extra
et    ALL  PRIMARY       NULL NULL    NULL 74
do    ALL  PRIMARY       NULL NULL    NULL 2135
et_1  ALL  PRIMARY       NULL NULL    NULL 74
tt    ALL  AssignedPC,   NULL NULL    NULL 3872
           ClientID,
           ActualPC
      range checked for each record (key map: 35)

Da type für jede Tabelle ALL ist, gibt diese Ausgabe an, dass MySQL ein kartesisches Produkt aller Tabellen erzeugt, also jede mögliche Kombination von Datensätzen. Dies dauert recht lang, weil das Produkt der Anzahl der Datensätze in jeder Tabelle untersucht werden muss. Im vorliegenden Fall beträgt dieses Produkt 74 × 2135 × 74 × 3872 = 45.268.558.720 Datensätze. Wenn die Tabellen noch größer wären, kann man sich nur vage vorstellen, wie lange dies dauern würde.

Ein Problem besteht hier darin, dass MySQL Indizes für Spalten effizienter verwenden kann, wenn sie mit demselben Typ und derselben Größe deklariert wurden. In diesem Kontext werden VARCHAR und CHAR als identisch betrachtet, wenn sie mit derselben Größe deklariert werden. tt.ActualPC wird aber als CHAR(10) und et.EMPLOYID als CHAR(15) deklariert – die Längen stimmen also nicht überein.

Um diese Fehlanpassung zwischen den Spaltenlängen aufzuheben, verlängern Sie ActualPC mit ALTER TABLE von 10 auf 15 Zeichen Länge:

mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);

Nun sind tt.ActualPC und et.EMPLOYID beide VARCHAR(15). Die erneute Ausführung der EXPLAIN-Anweisung erzeugt folgende Ausgabe:

table type   possible_keys key     key_len ref         rows    Extra
tt    ALL    AssignedPC,   NULL    NULL    NULL        3872    Using
             ClientID,                                         where
             ActualPC
do    ALL    PRIMARY       NULL    NULL    NULL        2135
      range checked for each record (key map: 1)
et_1  ALL    PRIMARY       NULL    NULL    NULL        74
      range checked for each record (key map: 1)
et    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC 1

Dies ist noch nicht perfekt, aber es ist schon wesentlich besser: Das Produkt der rows-Werte ist bereits um den Faktor 74 geringer – die Ausführung dieser Version dauert nur ein paar Sekunden.

Eine weitere Änderung kann vorgenommen werden, um die Nichtübereinstimmung der Spaltenlängen für die Vergleiche tt.AssignedPC = et_1.EMPLOYID und tt.ClientID = do.CUSTNMBR zu beseitigen:

mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
    ->                MODIFY ClientID   VARCHAR(15);

Nach dieser Änderung sieht die Ausgabe von EXPLAIN so aus:

table type   possible_keys key      key_len ref           rows Extra
et    ALL    PRIMARY       NULL     NULL    NULL          74
tt    ref    AssignedPC,   ActualPC 15      et.EMPLOYID   52   Using
             ClientID,                                         where
             ActualPC
et_1  eq_ref PRIMARY       PRIMARY  15      tt.AssignedPC 1
do    eq_ref PRIMARY       PRIMARY  15      tt.ClientID   1

An dieser Stelle ist die Abfrage schon fast perfekt optimiert. Als letztes Problem verbleibt die Tatsache, dass MySQL standardmäßig voraussetzt, dass Werte in der Spalte tt.ActualPC gleichmäßig verteilt sind; dies ist aber bei der Tabelle tt nicht der Fall. Glücklicherweise ist es einfach, MySQL zur Analyse der Schlüsselverteilung zu bewegen:

mysql> ANALYZE TABLE tt;

Mit den zusätzlichen Indexangaben ist der Join perfekt, und EXPLAIN erzeugt folgendes Ergebnis:

table type   possible_keys key     key_len ref           rows Extra
tt    ALL    AssignedPC    NULL    NULL    NULL          3872 Using
             ClientID,                                        where
             ActualPC
et    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC   1
et_1  eq_ref PRIMARY       PRIMARY 15      tt.AssignedPC 1
do    eq_ref PRIMARY       PRIMARY 15      tt.ClientID   1

Beachten Sie, dass die Spalte rows in der Ausgabe von EXPLAIN eine begründete Annahme des MySQL-Join-Optimierers ist. Sie sollten überprüfen, ob die Zahlen annähernd realistisch sind, indem Sie das rows-Produkt mit der tatsächlichen Anzahl der von der Abfrage zurückgegebenen Datensätze vergleichen. Unterscheiden sich diese Werte erheblich, dann erhalten Sie unter Umständen eine bessere Leistung, wenn Sie STRAIGHT_JOIN in Ihrer SELECT-Abfrage verwenden und versuchen, die Tabellen in der FROM-Klausel in einer anderen Reihenfolge aufzulisten.

7.2.2. Anfragenperformance abschätzen

In den meisten Fällen können Sie die Leistungsfähigkeit von Abfragen einschätzen, indem Sie die Anzahl der Suchvorgänge auf der Festplatte ermitteln. Bei kleinen Tabellen finden Sie gewöhnlich pro derartigen Suchvorgang einen Datensatz (weil der Index im Zweifelsfall im Cache liegt). Bei größeren Tabellen können Sie bei der Verwendung von B-Tree-Indizes schätzungsweise die folgende Anzahl von Suchvorgängen annehmen, um einen Datensatz zu finden: log(row_count) / log(index_block_length / 3 × 2 / (index_length + data_pointer_length)) + 1.

In MySQL ist ein Indexblock gewöhnlich 1024 Byte groß, der Datenzeiger umfasst weitere vier Byte. Bei einer Tabelle mit 500.000 Datensätzen und einer Indexlänge von drei Byte (der Größe von MEDIUMINT) gibt die Formel log(500.000/log(1024/3*2/(3+4))+1 = 4 Suchvorgänge aus.

Dieser Index würde eine Speicherkapazität von 500.000 × 7 × 3/2 = 5,2 Mbyte benötigen (ein typisches Indexpuffer-Füllungsverhältnis von 2 : 3 vorausgesetzt), d. h., Sie hätten wahrscheinlich einen Großteil des Indexes im Speicher und benötigen nur ein oder zwei Aufrufe zum Datenlesen, um den Datensatz zu finden.

Bei Schreiboperationen hingegen benötigen Sie vier Suchanforderungen, um zu ermitteln, wo ein neuer Indexwert abgelegt werden muss, und normalerweise zwei Suchvorgänge, um den Index zu aktualisieren und den Datensatz zu schreiben.

Beachten Sie, dass die vorangegangene Beschreibung nicht bedeutet, dass Ihre Anwendungsleistung sich nach und nach um den Logarithmus N verringert. Solange alles vom Betriebssystem oder vom MySQL Server zwischengespeichert wird, verringert sich die Geschwindigkeit nur marginal, wenn die Tabellen größer werden. Sobald die Daten zu umfangreich geworden sind, um zwischengespeichert zu werden, geht alles viel langsamer, bis Ihre Anwendungen nur noch mit Suchvorgängen auf der Festplatte beschäftigt sind (deren Anzahl sich um log N erhöht). Um dies zu vermeiden, müssen Sie die Größe des Schlüssel-Caches erhöhen, wenn der Umfang Ihrer Daten zunimmt. Bei MyISAM-Tabellen wird die Größe des Schlüssel-Caches von der Systemvariablen key_buffer_size gesteuert. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

7.2.3. Geschwindigkeit von SELECT-Anweisungen

Wenn Sie eine langsame SELECT … WHERE-Anweisung beschleunigen wollen, besteht der erste Schritt in aller Regel darin, zu überprüfen, ob Sie einen Index hinzufügen können. Alle Referenzierungen zwischen verschiedenen Tabellen sollten normalerweise über Indizes erfolgen. Sie können mit der EXPLAIN-Anweisung ermitteln, welche Indizes für eine SELECT-Anweisung verwendet werden. Siehe auch Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“, und Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“.

Hier ein paar allgemeine Tipps zur Beschleunigung von Abfragen für MyISAM-Tabellen:

  • Um MySQL bei der Optimierung von Abfragen zu unterstützen, verwenden Sie ANALYZE TABLE oder führen myisamchk --analyze für eine Tabelle aus, nachdem Sie die Daten dort eingeladen haben. Hierdurch wird ein Wert für jeden Indexteil geändert, der die durchschnittliche Anzahl von Datensätzen angibt, die denselben Wert haben. (Bei eindeutigen Indizes ist dies immer 1.) MySQL entscheidet anhand dessen, welcher Index ausgewählt wird, wenn Sie zwei Tabellen basierend auf einem nichtkonstanten Ausdruck verknüpfen. Sie können das Ergebnis der Tabellenanalyse mit SHOW INDEX FROM tbl_name und nachfolgender Überprüfung des Werts Cardinality verifizieren. myisamchk --description --verbose zeigt Angaben zur Indexverteilung.

  • Um einen Index und die Daten gemäß diesem Index zu sortieren, verwenden Sie myisamchk --sort-index --sort-records=1 (in diesem Beispiel erfolgt die Sortierung nach Index 1). Dies ist eine gute Möglichkeit, Abfragen zu beschleunigen, wenn Sie einen eindeutigen Index haben, anhand dessen Sie alle Datensätze in der von Index vorgegebenen Reihenfolge auslesen wollen. Beachten Sie, dass, wenn Sie beim ersten Mal eine große Tabelle auf diese Weise sortieren, dies sehr lang dauern kann.

7.2.4. Optimierungen der WHERE-Klausel

Dieser Abschnitt behandelt Optimierungen, die für die Verarbeitung von WHERE-Klauseln durchgeführt werden können. Die Beispiele verwenden SELECT-Anweisungen, dieselben Optimierungen gelten aber auch für WHERE-Klauseln in DELETE- und UPDATE-Anweisungen.

Wir arbeiten fortlaufend am MySQL-Optimierer, weswegen dieser Abschnitt nicht vollständig ist. MySQL führt eine Vielzahl von Optimierungen durch, die nicht alle an dieser Stelle dokumentiert sind.

Es folgen einige von MySQL durchgeführte Optimierungen:

  • Entfernung unnötiger Klammern:

       ((a AND b) AND c OR (((a AND b) AND (c AND d))))
    -> (a AND b AND c) OR (a AND b AND c AND d)
    
  • Umstellen von Konstanten:

       (a<b AND b=c) AND a=5
    -> b>5 AND b=c AND a=5
    
  • Entfernung von Konstantenbedingungen (erforderlich zum Umstellen von Konstanten):

       (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
    -> B=5 OR B=6
    
  • Konstantenausdrücke, die von Indizes verwendet werden, werden nur einmal ausgewertet.

  • COUNT(*) für eine einzelne Tabelle ohne WHERE wird direkt aus den Tabellendaten für MyISAM- und MEMORY-Tabellen abgerufen. Dies wird auch für jeden NOT NULL-Ausdruck gemacht, der nur für eine einzige Tabelle verwendet wird.

  • Früherkennung ungültiger Konstantenausdrücke. MySQL erkennt sehr schnell, wenn eine SELECT-Anweisung nicht möglich ist, und gibt keine Datensätze zurück.

  • HAVING wird mit WHERE verschmolzen, wenn Sie GROUP BY nicht verwenden oder Funktionen (wie COUNT(), MIN() usw.) zusammenfassen.

  • Für jede Tabelle in einem Join wird eine einfachere WHERE-Klausel erstellt, um eine schnelle WHERE-Auswertung für die Tabelle zu erhalten und außerdem Datensätze so früh wie möglich zu überspringen.

  • Bevor andere Tabellen in der Abfrage gelesen werden, werden zunächst alle Konstantentabellen ausgelesen. Zu den Konstantentabellen gehören die folgenden:

    • Leere Tabellen oder solche mit nur einem Datensatz.

    • Tabellen, die mit einer WHERE-Klausel für einen Primärschlüssel oder einen eindeutigen Index verwendet werden, wobei alle Indexteile mit Konstantenausdrücken verglichen werden und als NOT NULL definiert sind.

    Alle folgenden Tabellen werden als Konstantentabellen verwendet:

    SELECT * FROM t WHERE primary_key=1;
    SELECT * FROM t1,t2
      WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
    
  • Die beste Join-Kombination zur Verknüpfung der Tabellen wird durch Ausprobieren aller Möglichkeiten ermittelt. Wenn alle Spalten in den ORDER BY- und GROUP BY-Klauseln aus derselben Tabelle stammen, dann wird diese Tabelle beim Verknüpfen bevorzugt.

  • Wenn eine ORDER BY- und eine davon unterschiedliche GROUP BY-Klausel vorhanden sind, oder wenn ORDER BY oder GROUP BY Spalten aus anderen als der ersten Tabelle in der Join-Warteschlange enthalten, dann wird eine Temporärtabelle erstellt.

  • Wenn Sie die Option SQL_SMALL_RESULT verwenden, dann benutzt MySQL eine speicherresidente Temporärtabelle.

  • Alle Tabellenindizes werden abgefragt, und der beste Index wird verwendet, sofern der Optimierer nicht der Ansicht ist, dass die Verwendung eines Tabellenscans effizienter ist. Früher wurde ein Scan basierend darauf eingesetzt, ob der beste Index sich über einen Anteil von mehr als 30 Prozent der Tabelle erstreckte; mittlerweile wird die Frage, ob ein Index oder ein Scan verwendet werden soll, nicht mehr auf der Basis eines festen Prozentwerts entschieden. Der Optimierer ist mittlerweile komplexer, und seine Schätzungen fußen auf weiteren Faktoren wie Tabellengröße, Anzahl der Datensätze und I/O-Blockgröße.

  • In manchen Fällen kann MySQL Datensätze aus dem Index auslesen, ohne überhaupt die Datendatei abfragen zu müssen. Wenn alle aus dem Index verwendeten Spalten numerisch sind, wird zur Auflösung der Abfrage nur der Indexbaum verwendet.

  • Bevor ein Datensatz ausgegeben wird, werden alle Datensätze, die nicht der HAVING-Klausel entsprechen, übersprungen.

Hier einige Beispiele für Abfragen, die sehr schnell sind:

SELECT COUNT(*) FROM tbl_name;

SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;

SELECT MAX(key_part2) FROM tbl_name
  WHERE key_part1=constant;

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... LIMIT 10;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;

MySQL löst die folgenden Abfragen nur mithilfe des Indexbaums auf und setzt dabei voraus, dass die indizierten Spalten numerisch sind:

SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;

SELECT COUNT(*) FROM tbl_name
  WHERE key_part1=val1 AND key_part2=val2;

SELECT key_part2 FROM tbl_name GROUP BY key_part1;

Die folgenden Abfragen verwendet die Indizierung zur Abfrage von Datensätzen in sortierter Reihenfolge ohne separaten Sortierdurchlauf:

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... ;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... ;

7.2.5. Bereichsoptimierung

Die Zugriffsmethode range ruft mithilfe eines einzelnen Indexes eine Teilmenge der Datensätze ab, die in der Tabelle innerhalb eines oder mehrerer Indexwertintervalle liegen. Sie kann für einen ein- oder mehrteiligen Index verwendet werden. Die folgenden Abschnitte erläutern detailliert, wie Intervalle aus der WHERE-Klausel extrahiert werden.

7.2.5.1. Die Bereichszugriffsmethode (Range Access) für Indizes, die aus einzelnen Komponenten bestehen

Bei einem einteiligen Index lassen sich die Indexwertintervalle bequem durch entsprechende Bedingungen in der WHERE-Klausel darstellen. Deswegen sprechen wir in diesem Fall von Bereichsbedingungen statt von „Intervallen“.

Die Definition einer Bereichsbedingung für einen einteiligen Index sieht wie folgt aus:

  • Bei BTREE- und HASH-Indizes ist der Vergleich eines Schlüsselteils mit einem Konstantenwert eine Bereichsbedingung, wenn die Operatoren =, <=>, IN, IS NULL oder IS NOT NULL verwendet werden.

  • Bei BTREE-Indizes ist der Vergleich eines Schlüsselteils mit einem Konstantenwert eine Bereichsbedingung, wenn die Operatoren >, <, >=, <=, BETWEEN, != oder <> verwendet werden, oder aber bei LIKE 'pattern' (wobei 'pattern' nicht mit einem Jokerzeichen beginnt).

  • Bei allen Indextypen bilden mehrere Bereichsbedingungen, die mit OR oder AND kombiniert werden, eine Bereichsbedingung.

In den obigen Erläuterungen bezeichnet „Konstantenwert“ eines der folgenden Elemente:

  • eine Konstante aus dem Abfrage-String

  • eine Spalte aus einer const- oder system-Tabelle aus demselben Join

  • das Ergebnis einer unkorrelierten Unterabfrage

  • jeden Ausdruck, der vollständig aus Unterausdrücken der vorangegangenen Typen zusammengesetzt ist

Es folgen ein paar Beispiele für Abfragen mit Bereichsbedingungen in der WHERE-Klausel:

SELECT * FROM t1
  WHERE key_col > 1 
  AND key_col < 10;

SELECT * FROM t1 
  WHERE key_col = 1 
  OR key_col IN (15,18,20);

SELECT * FROM t1 
  WHERE key_col LIKE 'ab%' 
  OR key_col BETWEEN 'bar' AND 'foo';

Beachten Sie, dass einige nichtkonstante Werte während der Weitergabephase für Konstanten ihrerseits in Konstanten umgewandelt werden könnten.

MySQL versucht, die Bereichsbedingungen für alle möglichen Indizes aus der WHERE-Klausel zu extrahieren. Während des Extraktionsvorgangs werden Bedingungen, die nicht zur Bildung der Bereichsbedingung verwendet werden können, gelöscht; Bedingungen, die überschneidende Bereiche erzeugen, werden kombiniert; schließlich werden Bedingungen, die leere Bereiche erzeugen, entfernt.

Betrachten Sie die folgende Anweisung (hierbei ist key1 eine indizierte Spalte, während nonkey nicht indiziert ist):

SELECT * FROM t1 WHERE
  (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR
  (key1 < 'bar' AND nonkey = 4) OR
  (key1 < 'uux' AND key1 > 'z');

Der Extraktionsprozess für den Schlüssel key1 sieht wie folgt aus:

  1. Am Anfang steht die ursprüngliche WHERE-Klausel:

    (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR
    (key1 < 'bar' AND nonkey = 4) OR
    (key1 < 'uux' AND key1 > 'z')
    
  2. Nun werden nonkey = 4 und key1 LIKE '%b' entfernt, weil sie für einen Bereichsscan nicht verwendet werden können. Die korrekte Vorgehensweise zur Entfernung besteht darin, sie durch TRUE zu ersetzen, damit bei der Durchführung des Bereichsscans keine passenden Datensätze übersehen werden. Nach der Ersetzung mit TRUE erhalten wir Folgendes:

    (key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR
    (key1 < 'bar' AND TRUE) OR
    (key1 < 'uux' AND key1 > 'z')
    
  3. Die folgenden Kollapsbedingungen sind immer wahr oder falsch:

    • (key1 LIKE 'abcde%' OR TRUE) ist immer wahr.

    • (key1 < 'uux' AND key1 > 'z') ist immer falsch.

    Wenn wir diese Bedingungen durch Konstanten ersetzen, erhalten wir Folgendes:

    (key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
    

    Durch Entfernen unnötiger TRUE- und FALSE-Konstanten erhalten wir:

    (key1 < 'abc') OR (key1 < 'bar')
    
  4. Die Zusammenfassung überschneidender Intervalle hat die Bedingung zum Ergebnis, die endgültig für den Bereichsscan verwendet werden muss:

    (key1 < 'bar')
    

Im Allgemeinen (und wie auch durch obiges Beispiel veranschaulicht) ist die für einen Bereichsscan verwendete Bedingung weniger restriktiv als die WHERE-Klausel. MySQL führt eine zusätzliche Prüfung durch, um Datensätze auszufiltern, die zwar die Bereichsbedingung erfüllen, nicht aber die vollständige WHERE-Klausel.

Der Extraktionsalgorithmus für die Bereichsbedingung kann verschachtelte AND- und/oder OR-Konstrukte beliebiger Tiefe verarbeiten. Außerdem hängt seine Ausgabe nicht von der Reihenfolge ab, in der die Bedingungen in der WHERE-Klausel erscheinen.

7.2.5.2. Die Bereichszugriffsmethode für mehrteilige Indizes

Die Bereichsbedingungen für einen mehrteiligen Index stellen eine Erweiterung der Bereichsbedingungen für einen einteiligen Index dar. Eine Bereichsbedingung für einen mehrteiligen Index beschränkt die Indexdatensätze auf solche, die innerhalb eines oder mehrerer Schlüsseltupelintervalle liegen. Schlüsseltupelintervalle werden über eine Menge von Schlüsseltupeln definiert, wobei die Sortierung dem Index entnommen wird.

Betrachten Sie beispielsweise einen mehrteiligen Index, der als key1(key_part1, key_part2, key_part3) definiert ist, und die folgende Menge der in der Schlüsselreihenfolge aufgelisteten Schlüsseltupel:

key_part1  key_part2  key_part3
  NULL       1          'abc'
  NULL       1          'xyz'
  NULL       2          'foo'
   1         1          'abc'
   1         1          'xyz'
   1         2          'abc'
   2         1          'aaa'

Die Bedingung key_part1 = 1 definiert das folgende Intervall:

(1,-inf,-inf) <= (key_part1,key_part2,key_part3) < (1,+inf,+inf)

Das Intervall deckt das vierte, das fünfte und das sechste Tupel in der obigen Datenmenge ab und kann von der Bereichszugriffsmethode verwendet werden.

Im Gegensatz dazu definiert die Bedingung key_part3 = 'abc' kein einzelnes Intervall und kann von der Bereichszugriffsmethode nicht verwendet werden.

Die folgenden Beschreibungen erläutern im Detail, wie Bereichsbedingungen bei mehrteiligen Indizes funktionieren.

  • Bei HASH-Indizes kann jedes Intervall verwendet werden, das identische Werte enthält. Das bedeutet, dass das Intervall nur für Bedingungen in der folgenden Form erzeugt werden kann:

        key_part1 cmp const1
    AND key_part2 cmp const2
    AND ...
    AND key_partN cmp constN;
    

    Hierbei sind const1, const2, … Konstanten, cmp ist einer der Vergleichsoperatoren =, <=> oder IS NULL, und die Bedingungen decken alle Indexbestandteile ab. (Das bedeutet, es gibt N Bedingungen: eine für jeden Teil eines N-teiligen Indexes.) Nachfolgend gezeigt ist etwa eine Bereichsbedingung für einen dreiteiligen HASH-Index:

    key_part1 = 1 AND key_part2 IS NULL AND key_part3 = 'foo'
    

    Eine Definition dessen, was als Konstanten betrachtet wird, finden Sie in Abschnitt 7.2.5.1, „Die Bereichszugriffsmethode (Range Access) für Indizes, die aus einzelnen Komponenten bestehen“.

  • Bei einem BTREE-Index kann ein Intervall für Bedingungen verwendbar sein, die mit AND kombiniert wurden, wobei jede Bedingung einen Schlüsselteil mit einem Konstantenwert unter Verwendung von =, <=>, IS NULL, >, <, >=, <=, !=, <>, BETWEEN oder LIKE 'pattern' vergleicht (wobei 'pattern' nicht mit einem Jokerzeichen beginnen darf). Ein Intervall kann verwendet werden, solange es möglich ist, ein einzelnes Schlüsseltupel zu bestimmen, das alle Datensätze enthält, die der Bedingung entsprechen (bzw. zwei Intervalle, wenn <> oder != verwendet werden). Betrachten Sie etwa folgende Bedingung:

    key_part1 = 'foo' AND key_part2 >= 10 AND key_part3 > 10
    

    Das einzelne Intervall ist:

    ('foo',10,10) < (key_part1,key_part2,key_part3) < ('foo',+inf,+inf)
    

    Es ist möglich, dass das erstellte Intervall mehr Datensätze enthält als die Ursprungsbedingung. So umfasst das obige Intervall beispielsweise den Wert ('foo', 11, 0), der die ursprüngliche Bedingung nicht erfüllt.

  • Wenn Bedingungen, die Mengen von Datensätzen innerhalb von Intervallen abdecken, mit OR kombiniert werden, bilden sie eine Bedingung, die eine Menge von Datensätzen abdeckt, die in der Union dieser Intervalle enthalten sind. Werden die Bedingungen mit AND kombiniert, dann bilden sie eine Bedingung, die die Menge von Datensätzen in der Schnittmenge der Intervalle abdeckt. Betrachten Sie etwa die folgende Bedingung für einen zweiteiligen Index:

    (key_part1 = 1 AND key_part2 < 2) OR (key_part1 > 5)
    

    Die Intervalle sehen hier wie folgt aus:

    (1,-inf) < (key_part1,key_part2) < (1,2)
    (5,-inf) < (key_part1,key_part2)
    

    In diesem Beispiel verwendet das Intervall für die erste Zeile einen Schlüsselteil für die linke Grenze und zwei Schlüsselteile für die rechte Grenze. Das Intervall in der zweiten Zeile benutzt dagegen nur einen Schlüsselteil. Die Spalte key_len in der Ausgabe von EXPLAIN gibt die maximale Länge des verwendeten Schlüsselpräfixes an.

    In manchen Fällen kann key_len anzeigen, dass ein Schlüsselteil verwendet wurde, aber dies entspricht unter Umständen nicht dem, was Sie erwarten. Angenommen, key_part1 und key_part2 können NULL sein. In diesem Fall zeigt die Spalte key_len zwei Schlüsselteillängen für die folgende Bedingung an:

    key_part1 >= 1 AND key_part2 < 2
    

    Tatsächlich aber wird die Bedingung wie folgt konvertiert:

    key_part1 >= 1 AND key_part2 IS NOT NULL
    

Abschnitt 7.2.5.1, „Die Bereichszugriffsmethode (Range Access) für Indizes, die aus einzelnen Komponenten bestehen“, beschreibt, wie Optimierungen zur Kombination oder Beseitigung von Intervallen für Bereichsbedingungen für einen einteiligen Index durchgeführt werden. Für Bereichsbedingungen für mehrteilige Indizes werden die Schritte analog durchgeführt.

7.2.6. Optimierung durch Indexverschmelzung

Die Indexverschmelzungsmethode wird verwendet, um Datensätze mit mehreren range-Scans abzurufen und deren Ergebnisse zu einem Ergebnis zu verschmelzen. Die Verschmelzung kann Unions, Schnittmengen oder Schnittmengen-Unions der zugrunde liegenden Scans erzeugen.

In der Ausgabe von EXPLAIN erscheint die Indexverschmelzungsmethode als index_merge in der type-Spalte. In diesem Fall enthält die Spalte key eine Liste der verwendeten Indizes, und key_len enthält eine Liste der längsten Schlüsselteile für diese Indizes.

Ein paar Beispiele:

SELECT * FROM tbl_name WHERE key_part1 = 10 OR key_part2 = 20;

SELECT * FROM tbl_name
  WHERE (key_part1 = 10 OR key_part2 = 20) AND non_key_part=30;

SELECT * FROM t1, t2
  WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%')
  AND t2.key1=t1.some_col;

SELECT * FROM t1, t2
  WHERE t1.key1=1
  AND (t2.key1=t1.some_col OR t2.key2=t1.some_col2);

Die Indexverschmelzungsmethode umfasst mehrere Zugriffsalgorithmen (diese können dem Feld Extra in der Ausgabe von EXPLAIN entnommen werden):

  • Using intersect(…)

  • Using union(…)

  • Using sort_union(…)

Die folgenden Abschnitte beschreiben diese Methoden im Detail.

Hinweis: Der Optimierungsalgorithmus für die Indexverschmelzung weist die folgenden bekannten Defizite auf:

  • Wenn ein Bereichsscan für einen Schlüssel möglich ist, wird eine Indexverschmelzung nicht in Betracht gezogen. Betrachten Sie etwa folgende Abfrage:

    SELECT * FROM t1 WHERE (goodkey1 < 10 OR goodkey2 < 20) AND badkey < 30;
    

    Hierbei sind zwei Pläne möglich:

    • ein Indexverschmelzungsscan unter Verwendung der Bedingung (goodkey1 < 10 OR goodkey2 < 20)

    • ein Bereichsscan unter Verwendung der Bedingung badkey < 30

    Der Optimierer allerdings zieht nur den zweiten Plan in Betracht. Wenn Sie dies nicht wollen, können Sie mit IGNORE INDEX oder FORCE INDEX dafür sorgen, dass der Optimierer auch die Indexverschmelzung berücksichtigt. Die folgenden beiden Abfragen werden unter Verwendung der Indexverschmelzung ausgeführt:

    SELECT * FROM t1 FORCE INDEX(goodkey1,goodkey2)
      WHERE (goodkey1 < 10 OR goodkey2 < 20) AND badkey < 30;
    
    SELECT * FROM t1 IGNORE INDEX(badkey)
      WHERE (goodkey1 < 10 OR goodkey2 < 20) AND badkey < 30;
    
  • Wenn Ihre Abfrage eine komplexe WHERE-Klausel mit tiefer AND- oder OR-Verschachtelung enthält und MySQL nicht den optimalen Plan auswählt, versuchen Sie die Terme mithilfe der folgenden Identitätsgesetze zu verteilen:

    (x AND y) OR z = (x OR z) AND (y OR z)
    (x OR y) AND z = (x AND z) OR (y AND z)
    
  • Die Indexverschmelzung ist nicht für Volltextindizes einsetzbar. Wir beabsichtigen, dies in einem zukünftigen MySQL-Release zu ändern.

Die Auswahl zwischen verschiedenen möglichen Varianten der Indexverschmelzungsmethode und anderen Zugriffsmethoden basiert auf Kostenschätzungen der verschiedenen verfügbaren Optionen.

7.2.6.1. Der Zugriffsalgorithmus Schnittmenge (Intersection) bei der Indexverschmelzung

Diese Zugriffsmethode kann verwendet werden, wenn eine WHERE-Klausel in mehrere Bereichsbedingungen für verschiedene, mit AND kombinierte Schlüssel konvertiert wurde und jede Bedingung eines der folgenden Elemente ist:

  • In dieser Form, wo der Index genau N Teile hat (d. h. alle Indexteile sind abgedeckt):

    key_part1=const1 AND key_part2=const2 ... AND key_partN=constN
    
  • Jede Bereichsbedingung über einen Primärschlüssel einer InnoDB- oder BDB-Tabelle.

Ein paar Beispiele:

SELECT * FROM innodb_table WHERE primary_key < 10 AND key_col1=20;

SELECT * FROM tbl_name
  WHERE (key1_part1=1 AND key1_part2=2) AND key2=2;

Der Indexverschmelzungs-Schnittmengenalgorithmus führt gleichzeitige Scans aller verwendeten Indizes durch und erzeugt die Schnittmenge der Datensatzsequenzen, die er den verschmolzenen Indexscans entnimmt.

Wenn alle in der Abfrage verwendeten Spalten von den verwendeten Indizes abgedeckt werden, werden keine vollständigen Tabellendatensätze abgerufen. (In diesem Fall enthält die Ausgabe von EXPLAIN Using index im Feld Extra.) Hier ein Beispiel für eine solche Abfrage:

SELECT COUNT(*) FROM t1 WHERE key1=1 AND key2=1;

Wenn die verwendeten Indizes nicht alle in der Abfrage verwendeten Spalten abdecken, werden vollständige Datensätze nur dann abgerufen, wenn die Bereichsbedingungen für alle Schlüssel erfüllt sind.

Wenn eine der verschmolzenen Bedingungen eine Bedingung über einen Primärschlüssel einer InnoDB- oder BDB-Tabelle ist, dann wird sie nicht zum Abrufen von Datensätzen, sondern zum Ausfiltern von Datensätzen verwendet, die mit anderen Bedingungen abgerufen wurden.

7.2.6.2. Der Zugriffsalgorithmus Union bei der Indexverschmelzung

Die Anwendbarkeitskriterien für diesen Algorithmus ähneln denen des Schnittmengenalgorithmus der Indexverschmelzungsmethode. Dieser Algorithmus kann verwendet werden, wenn die WHERE-Klausel der Tabelle in mehrere Bereichsbedingungen für verschiedene, mit OR kombinierte Schlüssel konvertiert wurde und jede Bedingung eines der folgenden Elemente ist:

  • In dieser Form, wo der Index genau N Teile hat (d. h. alle Indexteile sind abgedeckt):

    key_part1=const1 AND key_part2=const2 ... AND key_partN=constN
    
  • Jede Bereichsbedingung über einen Primärschlüssel einer InnoDB- oder BDB-Tabelle.

  • Eine Bedingung, auf die der Schnittmengenalgorithmus der Indexverschmelzungsmethode anwendbar ist.

Ein paar Beispiele:

SELECT * FROM t1 WHERE key1=1 OR key2=2 OR key3=3;

SELECT * FROM innodb_table WHERE (key1=1 AND key2=2) OR
  (key3='foo' AND key4='bar') AND key5=5;

7.2.6.3. Der Zugriffsalgorithmus Sort-Union bei der Indexverschmelzung

Dieser Zugriffsalgorithmus wird verwendet, wenn die WHERE-Klausel in verschiedene Bereichsbedingungen konvertiert wurde, die mit OR verknüpft wurden, aber für die der Union-Algorithmus der Indexverschmelzungsmethode nicht anwendbar ist.

Ein paar Beispiele:

SELECT * FROM tbl_name WHERE key_col1 < 10 OR key_col2 < 20;

SELECT * FROM tbl_name
     WHERE (key_col1 > 10 OR key_col2 = 20) AND nonkey_col=30;

Der Unterschied zwischen dem Sort-Union-Algorithmus und dem Union-Algorithmus besteht darin, dass der Sort-Union-Algorithmus zunächst die Datensatzkennungen aller Datensätze abrufen und diese sortieren muss, bevor er Datensätze zurückgeben kann.

7.2.7. IS NULL-Optimierung

MySQL kann dieselbe Optimierung an col_name IS NULL vornehmen, die es auch für col_name = constant_value durchführen kann. So kann MySQL etwa Indizes und Bereiche zur Suche nach NULL mit IS NULL verwenden.

Ein paar Beispiele:

SELECT * FROM tbl_name WHERE key_col IS NULL;

SELECT * FROM tbl_name WHERE key_col <=> NULL;

SELECT * FROM tbl_name
  WHERE key_col=const1 OR key_col=const2 OR key_col IS NULL;

Wenn eine WHERE-Klausel eine Bedingung col_name IS NULL für eine Spalte enthält, die als NOT NULL deklariert ist, dann wird dieser Ausdruck wegoptimiert. Diese Optimierung findet allerdings nicht in Fällen statt, in denen die Spalte ohnehin NULL erzeugen könnte – z. B. wenn sie aus einer Tabelle auf der rechten Seite eines LEFT JOIN stammt.

MySQL kann auch die Kombination col_name = expr AND col_name IS NULL optimieren; diese Form tritt bei aufgelösten Unterabfragen häufig auf. EXPLAIN zeigt ref_or_null an, wenn diese Optimierung verwendet wird.

Diese Optimierung kann je Schlüsselteil eine IS NULL-Bedingung verarbeiten.

Es folgen einige Beispiele für optimierte Abfragen (hierbei wird davon ausgegangen, dass ein Index für die Spalten a und b der Tabelle t2 vorhanden ist):

SELECT * FROM t1 WHERE t1.a=expr OR t1.a IS NULL;

SELECT * FROM t1, t2 WHERE t1.a=t2.a OR t2.a IS NULL;

SELECT * FROM t1, t2
  WHERE (t1.a=t2.a OR t2.a IS NULL) AND t2.b=t1.b;

SELECT * FROM t1, t2
  WHERE t1.a=t2.a AND (t2.b=t1.b OR t2.b IS NULL);

SELECT * FROM t1, t2
  WHERE (t1.a=t2.a AND t2.a IS NULL AND ...)
  OR (t1.a=t2.a AND t2.a IS NULL AND ...);

Bei ref_or_null wird zunächst der Referenzschlüssel ausgelesen. Danach erfolgt eine separate Suche nach Datensätzen mit einem NULL-Schlüsselwert.

Beachten Sie, dass die Optimierung nur eine IS NULL-Ebene verarbeiten kann. In der folgenden Abfrage verwendet MySQL Schlüsselsuchvorgänge nur für den Ausdruck (t1.a=t2.a AND t2.a IS NULL). Der Schlüsselteil zu b kann von MySQL nicht verwendet werden:

SELECT * FROM t1, t2
     WHERE (t1.a=t2.a AND t2.a IS NULL)
     OR (t1.b=t2.b AND t2.b IS NULL);

7.2.8. Optimierung von DISTINCT

DISTINCT kombiniert mit ORDER BY benötigt in vielen Fällen eine Temporärtabelle.

Weil DISTINCT unter Umständen GROUP BY verwendet, sollten Sie wissen, wie MySQL mit Spalten in ORDER BY- oder HAVING-Klauseln verfährt, die nicht Teil der gewählten Spalten sind. Siehe auch Abschnitt 12.11.3, „GROUP BY mit versteckten Feldern“.

In vielen Fällen kann eine DISTINCT-Klausel als Sonderfall von GROUP BY betrachtet werden. So sind beispielsweise die beiden folgenden Abfragen gleichwertig:

SELECT DISTINCT c1, c2, c3 FROM t1 WHERE c1 > const;

SELECT c1, c2, c3 FROM t1 WHERE c1 > const GROUP BY c1, c2, c3;

Aufgrund dieser Äquivalenz können die Optimierungen, die für GROUP BY-Abfragen verwendbar sind, auch auf Abfragen mit einer DISTINCT-Klausel angewendet werden. Insofern sollten Sie, um weitere Informationen zu Optimierungsmöglichkeiten bei DISTINCT-Abfragen zu erhalten, unter Abschnitt 7.2.13, „GROUP BY-Optimierung“, nachschlagen.

Wenn Sie LIMIT row_count mit DISTINCT kombinieren, beendet MySQL die Abfrage, sobald row_count eindeutige Datensätze gefunden wurden.

Wenn Sie nicht Spalten aus allen in einer Abfrage aufgeführten Tabellen verwenden, beendet MySQL das Scannen unbenutzter Tabellen, sobald die erste Übereinstimmung gefunden wurde. Im folgenden Fall (in dem vorausgesetzt wird, dass t1 vor t2 benutzt wird, was mit EXPLAIN verifiziert werden kann) beendet MySQL das Auslesen von t2 für einen beliebigen Datensatz in t1, sobald der erste Datensatz in t2 gefunden wird:

SELECT DISTINCT t1.a FROM t1, t2 where t1.a=t2.a;

7.2.9. Optimierung von LEFT JOIN und RIGHT JOIN

MySQL implementiert A LEFT JOIN B join_condition wie folgt:

  • Tabelle B ist so konfiguriert, dass sie von Tabelle A und allen Tabellen abhängt, von denen auch Tabelle A abhängt.

  • Tabelle A ist ihrerseits so konfiguriert, dass sie von allen Tabellen (mit Ausnahme von B) abhängt, die in der LEFT JOIN-Bedingung verwendet werden.

  • Anhand der LEFT JOIN-Bedingung wird entschieden, wie Datensätze aus der Tabelle B abgerufen werden. (Das bedeutet, dass keine Bedingung in der WHERE-Klausel verwendet wird.)

  • Alle Standardoptimierungen für Joins werden durchgeführt; einzige Ausnahme ist, dass jede Tabelle stets erst gelesen wird, nachdem alle Tabellen gelesen wurden, von denen sie abhängt. Gibt es eine Zirkelabhängigkeit, dann gibt MySQL einen Fehler aus.

  • Alle Standardoptimierungen für WHERE werden durchgeführt.

  • Wenn ein Datensatz in A vorhanden ist, der der WHERE-Klausel entspricht, aber kein Datensatz in B, der der ON-Bedingung entspricht, dann wird ein zusätzlicher Datensatz in B erzeugt, bei dem alle Spalten auf NULL gesetzt sind.

  • Wenn Sie mit LEFT JOIN Datensätze suchen, die in keiner der Tabellen vorhanden sind, und die Überprüfung col_name IS NULL im WHERE-Teil vorhanden ist (wobei col_name eine als NOT NULL deklarierte Spalte ist), dann beendet MySQL die Suche nach weiteren Datensätzen (für eine bestimmte Schlüsselkombination), wenn es genau einen Datensatz gefunden hat, der der LEFT JOIN-Bedingung entspricht.

Die Implementierung von RIGHT JOIN erfolgt analog zu der von LEFT JOIN, wobei lediglich die Rollen der Tabellen umgekehrt werden.

Der Join-Optimierer berechnet die Reihenfolge, in der die Tabellen verknüpft werden sollten. Die durch LEFT JOIN oder STRAIGHT_JOIN erzwungene Lesereihenfolge für die Tabellen unterstützt den Join-Optimierer bei seiner Arbeit wesentlich effizienter, weil erheblich weniger Tabellenumstellungen zu überprüfen sind. Beachten Sie, dass dies bedeutet, dass, wenn Sie eine Abfrage folgenden Typs ausführen, MySQL einen vollständigen Scan in b durchführt, weil diese Tabelle aufgrund von LEFT JOIN vor d gelesen wird:

SELECT *
  FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key)
  WHERE b.key=d.key;

Die Lösung besteht in diesem Fall darin, die Reihenfolge umzukehren, in der a und b in der FROM-Klausel aufgelistet werden:

SELECT *
  FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key)
  WHERE b.key=d.key;

Wenn bei einem LEFT JOIN die WHERE-Bedingung für den erzeugten NULL-Datensatz immer falsch ist, dann wird der LEFT JOIN in einen normalen Join umgesetzt. So wäre beispielsweise die WHERE-Klausel in der folgenden Abfrage falsch, wenn t2.column1 NULL wäre:

SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;

Aus diesem Grund kann die Abfrage problemlos in einen normalen Join konvertiert werden:

SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;

Dies kann schneller erfolgen, weil MySQL die Tabelle t2 vor t1 verwenden kann, sofern dies einen besseren Abfrageplan zum Ergebnis hätte. Mit STRAIGHT_JOIN können Sie eine bestimmte Tabellenreihenfolge erzwingen.

7.2.10. Optimierung verschachtelter Joins

Die Syntax zum Ausdrücken von Joins gestattet auch verschachtelte Joins. Die nachfolgende Beschreibung bezieht sich auf die in Abschnitt 13.2.7.1, „JOIN, beschriebene Join-Syntax.

Die Syntax von table_factor ist im Vergleich zum SQL-Standard erweitert. SQL akzeptiert nur table_reference, nicht aber eine in Klammern gesetzte Liste mit Referenzierungen. Dies ist eine konservative Erweiterung, sofern wir jedes Komma in einer Liste mit table_reference-Elementen als äquivalent zu einem inneren Join betrachten. Zum Beispiel:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

ist äquivalent mit

SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

In MySQL ist CROSS JOIN syntaktisch ein Äquivalent zu INNER JOIN (diese lassen sich gegeneinander austauschen). Nach SQL-Standard hingegen sind beide nicht äquivalent. INNER JOIN wird bei einer ON-Klausel und CROSS JOIN andernfalls verwendet.

Klammern können in Join-Ausdrücken, die nur innere Join-Operationen enthalten, ignoriert werden. Betrachten Sie folgenden Ausdruck:

t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL)
   ON t1.a=t2.a

Nach Entfernen der Klammern und Gruppieren der Operationen auf der linken Seite entsteht folgender Ausdruck:

(t1 LEFT JOIN t2 ON t1.a=t2.a) LEFT JOIN t3
    ON t2.b=t3.b OR t2.b IS NULL

Trotzdem sind die beiden Ausdrücke nicht äquivalent. Um dies nachzuweisen, nehmen wir an, dass die Tabellen t1, t2 und t3 die folgenden Zustände haben:

  • Tabelle t1 enthält die Datensätze {1}, {2}.

  • Tabelle t2 enthält den Datensatz {1,101}.

  • Tabelle t3 enthält den Datensatz {101}.

In diesem Fall gibt der erste Ausdruck eine Ergebnismenge mit den Datensätzen {1,1,101,101}, {2,NULL,NULL,NULL} zurück; der zweite Ausdruck hingegen gibt die Datensätze {1,1,101,101}, {2,NULL,NULL,101} zurück:

mysql> SELECT *
    -> FROM t1
    ->      LEFT JOIN
    ->      (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL)
    ->      ON t1.a=t2.a;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL | NULL |
+------+------+------+------+

mysql> SELECT *
    -> FROM (t1 LEFT JOIN t2 ON t1.a=t2.a)
    ->      LEFT JOIN t3
    ->      ON t2.b=t3.b OR t2.b IS NULL;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL |  101 |
+------+------+------+------+

Im folgenden Beispiel wird ein äußerer Join gemeinsam mit einem inneren Join verwendet:

t1 LEFT JOIN (t2, t3) ON t1.a=t2.a

Dieser Ausdruck kann nicht in den folgenden Ausdruck transformiert werden:

t1 LEFT JOIN t2 ON t1.a=t2.a, t3.

Für die gegebenen Tabellenzustände geben die beiden Ausdrücke verschiedene Datensatzmengen zurück:

mysql> SELECT *
    -> FROM t1 LEFT JOIN (t2, t3) ON t1.a=t2.a;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL | NULL |
+------+------+------+------+

mysql> SELECT *
    -> FROM t1 LEFT JOIN t2 ON t1.a=t2.a, t3;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL |  101 |
+------+------+------+------+

Aus diesem Grund ändern wir, wenn wir in einem Join-Ausdruck mit äußeren Join-Operatoren die Klammern weglassen, unter Umständen die Ergebnismenge für den ursprünglichen Ausdruck.

Genauer formuliert: Wir dürfen die Klammern im rechten Operanden der linken äußeren Join-Operation und im linken Operanden einer rechten Join-Operation nicht ignorieren. Oder: Die Klammern der inneren Tabellenausdrücke äußerer Join-Operationen dürfen nicht unbeachtet bleiben. Klammern für den anderen Operanden (d. h. den Operanden der äußeren Tabelle) können hingegen ignoriert werden.

Der Ausdruck

(t1,t2) LEFT JOIN t3 ON P(t2.b,t3.b)

ist äquivalent zu folgendem Ausdruck:

t1, t2 LEFT JOIN t3 ON P(t2.b,t3.b)

Dies gilt für alle Tabellen t1,t2,t3 und alle Bedingungen P für Attribute t2.b und t3.b.

Immer dann, wenn die Join-Operationen in einem Join-Ausdruck (join_table) nicht von links nach rechts ausgeführt werden, redet man von verschachtelten Joins. Betrachten Sie einmal die folgenden Abfragen:

SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b) ON t1.a=t2.a
  WHERE t1.a > 1

SELECT * FROM t1 LEFT JOIN (t2, t3) ON t1.a=t2.a
  WHERE (t2.b=t3.b OR t2.b IS NULL) AND t1.a > 1

Diese Abfragen enthalten die folgenden verschachtelten Joins:

t2 LEFT JOIN t3 ON t2.b=t3.b
t2, t3

Der verschachtelte Join wird in der ersten Abfrage mit einem Left-Join gebildet, während er in der zweiten Abfrage aufgrund einer inneren Join-Operation entsteht.

In der ersten Abfrage können die Klammern weggelassen werden: Die grammatische Struktur des Join-Ausdrucks schreibt dieselbe Ausführungsreihenfolge für Join-Operationen vor. Bei der zweiten Abfrage dürfen die Klammern nicht weggelassen werden, obwohl der Join-Ausdruck hier auch ohne sie eindeutig interpretiert werden könnte. (In unserer erweiterten Syntax sind die Klammern im Ausdruck (t2, t3) der zweiten Abfrage erforderlich, obwohl die Abfrage theoretisch auch ohne sie analysiert werden könnte: Wir hätten immer noch eine eindeutige syntaktische Struktur für die Abfrage, da LEFT JOIN und ON die Rolle der linken und rechten Begrenzungen für den Ausdruck (t2,t3) übernähmen.)

Die obigen Beispiele veranschaulichen die folgenden Aspekte:

  • Bei Join-Ausdrücken, die nur innere Joins (und keine äußeren Joins) enthalten, können die Klammern entfernt werden. Sie können die Klammern entfernen und die Auswertung von links nach rechts vornehmen (tatsächlich kann die Auswertung der Tabellen sogar in beliebiger Reihenfolge erfolgen).

  • Dies gilt allerdings in der Regel nicht für äußere Joins oder mit inneren Joins gemischte äußere Joins. Ein Entfernen der Klammern kann das Ergebnis ändern.

Abfragen mit verschachtelten äußeren Joins werden in derselben Weise ausgeführt wie Abfragen mit inneren Joins. Genauer gesagt, wird eine Abwandlung des Join-Algorithmus mit verschachtelten Schleifen benutzt. Vergegenwärtigen Sie sich, mit welchem Algorithmusschema ein Join mit verschachtelten Schleifen eine Abfrage ausführt. Angenommen, wir haben eine Join-Abfrage über drei Tabellen T1,T2,T3 der folgenden Form:

SELECT * FROM T1 INNER JOIN T2 ON P1(T1,T2)
                 INNER JOIN T3 ON P2(T2,T3)
  WHERE P(T1,T2,T3).

Hierbei seien P1(T1,T2) und P2(T3,T3) Join-Bedingungen (für Ausdrücke), während P(t1,t2,t3) eine Bedingung über Spalten der Tabellen T1,T2,T3 ist.

Der Algorithmus für Joins mit verschachtelten Schleifen würde die Abfrage wie folgt ausführen:

FOR each row t1 in T1 {
  FOR each row t2 in T2 such that P1(t1,t2) {
    FOR each row t3 in T3 such that P2(t2,t3) {
      IF P(t1,t2,t3) {
         t:=t1||t2||t3; OUTPUT t;
      }
    }
  }
}

Die Notation t1||t2||t3 bedeutet einen „Datensatz, der durch Verkettung der Spalten der Datensätze t1, t2 und t3 entsteht“. In einigen der folgenden Beispiele bezeichnet, wenn ein Datensatzname erscheint, NULL die Tatsache, dass NULL für jede Spalte dieses Datensatzes benutzt wird. Beispielsweise bedeutet t1||t2||NULLeinen Datensatz, der aus den verketteten Spalten der Datensätze t1 und t2 sowie NULL für jede Spalte von t3 besteht“.

Betrachten wir nun eine Abfrage mit verschachtelten äußeren Joins:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON P2(T2,T3))
              ON P1(T1,T2)
  WHERE P(T1,T2,T3).

Für diese Abfrage ändern wir das Muster für verschachtelte Schleifen ab und erhalten Folgendes:

FOR each row t1 in T1 {
  BOOL f1:=FALSE;
  FOR each row t2 in T2 such that P1(t1,t2) {
    BOOL f2:=FALSE;
    FOR each row t3 in T3 such that P2(t2,t3) {
      IF P(t1,t2,t3) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f2=TRUE;
      f1=TRUE;
    }
    IF (!f2) {
      IF P(t1,t2,NULL) {
        t:=t1||t2||NULL; OUTPUT t;
      }
      f1=TRUE;
    }
  }
  IF (!f1) {
    IF P(t1,NULL,NULL) {
      t:=t1||NULL||NULL; OUTPUT t;
    }
  }
}

Generell wird für jede verschachtelte Schleife für die erste innere Tabelle einer äußeren Join-Operation ein Flag eingeführt, welches vor der Schleife gelöscht und danach wieder gesetzt wird. Das Flag wird gesetzt, wenn für den aktuellen Datensatz aus der äußeren Tabelle eine Entsprechung in der Tabelle gefunden wird, die den inneren Operanden darstellt. Wenn das Flag am Ende des Schleifenzyklus immer noch nicht gelöscht ist, dann wurde für den aktuellen Datensatz in der äußeren Tabelle keine Entsprechung gefunden. In diesem Fall wird der Datensatz mit NULL-Werten für die Spalten der inneren Tabellen ergänzt. Der Ergebnisdatensatz wird zur letzten Überprüfung an die Ausgabe oder in die nächste verschachtelte Schleife übergeben – aber nur dann, wenn der Datensatz die Join-Bedingung für alle eingebetteten äußeren Joins erfüllt.

In unserem Beispiel ist die mit dem folgenden Ausdruck beschriebene äußere Join-Tabelle eingebettet:

(T2 LEFT JOIN T3 ON P2(T2,T3))

Beachten Sie, dass der Optimierer für die Abfrage mit inneren Joins eine andere Reihenfolge für verschachtelte Schleifen wählen könnte – etwa die folgende:

FOR each row t3 in T3 {
  FOR each row t2 in T2 such that P2(t2,t3) {
    FOR each row t1 in T1 such that P1(t1,t2) {
      IF P(t1,t2,t3) {
         t:=t1||t2||t3; OUTPUT t;
      }
    }
  }
}

Bei Abfragen mit äußeren Joins kann der Optimierer nur eine Reihenfolge wählen, bei der Schleifen für äußere Tabellen den Schleifen für die inneren Tabellen vorangehen. Insofern ist für unsere Abfrage mit äußeren Joins nur eine Verschachtelungsreihenfolge möglich. Bei der folgenden Abfrage wird der Optimierer zwei verschiedene Verschachtelungen auswerten:

SELECT * T1 LEFT JOIN (T2,T3) ON P1(T1,T2) AND P2(T1,T3)
  WHERE P(T1,T2,T3)

Die Verschachtelungen sind

FOR each row t1 in T1 {
  BOOL f1:=FALSE;
  FOR each row t2 in T2 such that P1(t1,t2) {
    FOR each row t3 in T3 such that P2(t1,t3) {
      IF P(t1,t2,t3) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f1:=TRUE
    }
  }
  IF (!f1) {
    IF P(t1,NULL,NULL) {
      t:=t1||NULL||NULL; OUTPUT t;
    }
  }
}

und

FOR each row t1 in T1 {
  BOOL f1:=FALSE;
  FOR each row t3 in T3 such that P2(t1,t3) {
    FOR each row t2 in T2 such that P1(t1,t2) {
      IF P(t1,t2,t3) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f1:=TRUE
    }
  }
  IF (!f1) {
    IF P(t1,NULL,NULL) {
      t:=t1||NULL||NULL; OUTPUT t;
    }
  }
}

In beiden Verschachtelungen muss T1 in der äußeren Schleife verarbeitet werden, weil sie in einem äußeren Join verwendet wird. T2 und T3 werden hingegen in einem inneren Join benutzt, d. h., der Join muss in der inneren Schleife verarbeitet werden. Allerdings können, weil der Join ein innerer Join ist, T2 und T3 in beliebiger Ordnung verarbeitet werden.

Bei der Beschreibung des Algorithmus mit verschachtelten Schleifen für innere Joins haben wir ein paar Details übergangen, deren Wirkung auf die Leistungsfähigkeit der Abfrageausführung beträchtlich sein kann. Wir haben beispielsweise so genannte „Pushdown-Bedingungen“ nicht erwähnt. Angenommen, unsere WHERE-Bedingung P(T1,T2,T3) könnte mit einer konjunktiven Formel dargestellt werden:

P(T1,T2,T2) = C1(T1) AND C2(T2) AND C3(T3).

In diesem Fall verwendet MySQL in der Tat das folgende Schema mit verschachtelten Schleifen zur Ausführung der Abfrage mit inneren Joins:

FOR each row t1 in T1 such that C1(t1) {
  FOR each row t2 in T2 such that P1(t1,t2) AND C2(t2)  {
    FOR each row t3 in T3 such that P2(t2,t3) AND C3(t3) {
      IF P(t1,t2,t3) {
         t:=t1||t2||t3; OUTPUT t;
      }
    }
  }
}

Sie erkennen, dass die Konjunkte C1(T1), C2(T2) und C3(T3) aus der innersten in die äußerste Schleife verschoben werden, wo sie dann ausgewertet werden können. Wenn C1(T1) eine sehr restriktive Bedingung ist, dann kann dieser Bedingungs-Pushdown die Anzahl der Datensätze aus Tabelle T1, die an die inneren Schleifen weitergegeben werden, erheblich verringern. Hieraus ergibt sich eine beachtliche Verbesserung bei der Ausführungszeit für die Abfrage.

Bei einer Abfrage mit äußeren Joins muss die WHERE-Bedingung erst geprüft werden, wenn festgestellt wurde, dass für den aktuellen Datensatz in der äußeren Tabelle eine Entsprechung in den inneren Tabellen vorhanden ist. Aufgrund dessen kann die Optimierung mit einer Pushdown-Bedingung aus den inneren verschachtelten Schleifen nicht direkt auf Abfragen mit äußeren Joins angewendet werden. Deswegen müssen an dieser Stelle konditionale Pushdown-Prädikate in Verbindung mit Überwachungs-Flags eingeführt werden, die gesetzt werden, sobald eine Übereinstimmung gefunden wurde.

Betrachten Sie noch einmal unser Beispiel mit äußeren Joins:

P(T1,T2,T3)=C1(T1) AND C(T2) AND C3(T3)

Hier sieht das Schema der verschachtelten Schleifen unter Verwendung überwachter Pushdown-Bedingungen wie folgt aus:

FOR each row t1 in T1 such that C1(t1) {
  BOOL f1:=FALSE;
  FOR each row t2 in T2
      such that P1(t1,t2) AND (f1?C2(t2):TRUE) {
    BOOL f2:=FALSE;
    FOR each row t3 in T3
        such that P2(t2,t3) AND (f1&&f2?C3(t3):TRUE) {
      IF (f1&&f2?TRUE:(C2(t2) AND C3(t3))) {
        t:=t1||t2||t3; OUTPUT t;
      }
      f2=TRUE;
      f1=TRUE;
    }
    IF (!f2) {
      IF (f1?TRUE:C2(t2) && P(t1,t2,NULL)) {
        t:=t1||t2||NULL; OUTPUT t;
      }
      f1=TRUE;
    }
  }
  IF (!f1 && P(t1,NULL,NULL)) {
      t:=t1||NULL||NULL; OUTPUT t;
  }
}

Generell können Pushdown-Prädikate aus Join-Bedingungen wie P1(T1,T2) und P(T2,T3) extrahiert werden. In diesem Fall wird ein Pushdown-Prädikat auch von einem Flag überwacht, das eine Überprüfung des Prädikats auf den mit NULL ergänzten Datensatz verhindert, der im Zuge der entsprechenden Join-Operation erzeugt wurde.

Beachten Sie, dass ein Zugriff nach Schlüssel aus einer inneren Tabelle auf eine andere Tabelle im selben verschachtelten Join unzulässig ist, wenn er durch ein Prädikat aus der WHERE-Bedingung herbeigeführt wird. (Wir könnten in diesem Fall einen bedingten Schlüsselzugriff verwenden, aber diese Methode ist in MySQL 5.1 noch nicht implementiert.)

7.2.11. Vereinfachungsmöglichkeit für äußere Joins

Tabellenausdrücke in der FROM-Klausel einer Abfrage werden in vielen Fällen vereinfacht.

Auf der Parserebene werden Abfragen mit rechten äußeren Join-Operationen in gleichwertige Abfragen konvertiert, die nur Left-Join-Operationen enthalten. Im Allgemeinen erfolgt die Konvertierung auf der Basis der folgenden Regel:

(T1, ...) RIGHT JOIN (T2,...) ON P(T1,...,T2,...) =
(T2, ...) LEFT JOIN (T1,...) ON P(T1,...,T2,...).

Alle inneren Join-Ausdrücke der Form T1 INNER JOIN T2 ON P(T1,T2) werden durch die Liste T1,T2 ersetzt, und P(T1,T2) wird als Konjunkt mit der WHERE-Bedingung (oder mit der Join-Bedingung des einbettenden Joins, sofern vorhanden) verknüpft.

Wenn der Optimierer Pläne für Join-Abfragen mit einer äußeren Join-Operation auswertet, berücksichtigt er nur diejenigen Pläne, bei denen bei einer solchen Operation zunächst auf die äußeren und erst dann auf die inneren Tabellen zugegriffen wird. Die Optimiereroptionen sind eingeschränkt, weil nur solche Pläne uns die Ausführung von Abfragen mit äußeren Join-Operationen über das Schema mit verschachtelten Schleifen gestatten.

Angenommen, wir haben eine Abfrage folgenden Aussehens:

SELECT * T1 LEFT JOIN T2 ON P1(T1,T2)
  WHERE P(T1,T2) AND R(T2)

Hierbei schränkt R(T2) die Anzahl passender Datensätze aus der Tabelle T2 erheblich ein. Wenn wir die Abfrage in ihrer ursprünglichen Form ausgeführt hätten, hätte der Optimierer keine andere Chance gehabt, als zuerst auf die Tabelle T1 und erst dann auf T2 zuzugreifen. Dies hätte einen sehr ineffizienten Ausführungsplan zur Folge gehabt.

Glücklicherweise wandelt MySQL eine solche Abfrage in eine Abfrage ohne äußere Join-Operation um, wenn die WHERE-Bedingung nullabweisend wird. Eine Bedingung heißt nullabweisend für eine äußere Join-Operation, wenn sie für jeden NULL-ergänzten Datensatz, der für die Operation erstellt wurde, stets FALSE oder UNKNOWN ist.

Betrachten Sie folgenden äußeren Join:

T1 LEFT JOIN T2 ON T1.A=T2.A

Für ihn sind Bedingungen wie die folgenden nullabweisend:

T2.B IS NOT NULL,
T2.B > 3,
T2.C <= T1.C,
T2.B < 2 OR T2.C > 1

Bedingungen wie die folgenden sind hingegen nicht nullabweisend:

T2.B IS NULL,
T1.B < 3 OR T2.B IS NOT NULL,
T1.B < 3 OR T2.B > 3

Die allgemeinen Regeln zur Überprüfung, ob eine Bedingung für einen äußeren Join nullabweisend ist oder nicht, sind recht einfach. Eine Bedingung ist nullabweisend, wenn sie

  • die Form A IS NOT NULL hat, wobei A ein Attribut einer der inneren Tabellen ist,

  • ein Prädikat ist, das eine innere Tabelle referenziert, die UNKNOWN ist, wenn eines ihrer Argumente NULL ist,

  • eine Konjunktion mit einer nullabweisenden Bedingung als Konjunkt ist,

  • eine Disjunktion nullabweisender Bedingungen ist.

Eine Bedingung kann für eine äußere Join-Operation nullabweisend sein und gleichzeitig für eine andere nicht. Betrachten Sie folgende Abfrage:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 LEFT JOIN T3 ON T3.B=T1.B
  WHERE T3.C > 0

Hier ist die WHERE-Bedingung für die zweite äußere Join-Operation nullabweisend, nicht jedoch für die erste.

Wenn die WHERE-Bedingung für eine äußere Join-Operation in einer Abfrage nullabweisend ist, wird die äußere Join-Operation durch eine innere Join-Operation ersetzt.

So wird etwa obige Abfrage durch die folgende ersetzt:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 INNER JOIN T3 ON T3.B=T1.B
  WHERE T3.C > 0

Für die ursprüngliche Abfrage würde der Optimierer Pläne auswerten, die mit der Zugriffsreihenfolge T1,T2,T3 kompatibel wären. Für die ersetzende Abfrage wird außerdem die Zugriffssequenz T3,T1,T2 in Betracht gezogen.

Eine Konvertierung einer äußeren Join-Operation kann eine Konvertierung einer anderen derartigen Operation auslösen. Betrachten Sie folgende Abfrage:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 LEFT JOIN T3 ON T3.B=T2.B
  WHERE T3.C > 0

Diese wird in die folgende Abfrage konvertiert:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 INNER JOIN T3 ON T3.B=T2.B
  WHERE T3.C > 0

Diese wiederum ist äquivalent mit dieser Abfrage:

SELECT * FROM (T1 LEFT JOIN T2 ON T2.A=T1.A), T3
  WHERE T3.C > 0 AND T3.B=T2.B

Nun kann die verbleibende äußere Join-Operation ebenfalls durch einen inneren Join ersetzt werden, weil die Bedingung T3.B=T2.B nullabweisend ist und wir eine Abfrage erhalten, die überhaupt keine äußeren Joins enthält:

SELECT * FROM (T1 INNER JOIN T2 ON T2.A=T1.A), T3
  WHERE T3.C > 0 AND T3.B=T2.B

Manchmal gelingt es, eine eingebettete äußere Join-Operation zu ersetzen, aber der einbettende äußere Join kann nicht konvertiert werden. Betrachten Sie folgende Abfrage:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A
  WHERE T3.C > 0

Sie wird wie folgt konvertiert:

SELECT * FROM T1 LEFT JOIN
              (T2 INNER JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A
  WHERE T3.C > 0,

Dies lässt sich nur in einer Form umschreiben, die nach wie vor die einbettende äußere Join-Operation enthält:

SELECT * FROM T1 LEFT JOIN
              (T2,T3)
              ON (T2.A=T1.A AND T3.B=T2.B)
  WHERE T3.C > 0.

Wenn Sie versuchen, eine eingebettete äußere Join-Operation zu konvertieren, dann müssen Sie die Join-Bedingung für den einbettenden äußeren Join gemeinsam mit der WHERE-Bedingung berücksichtigen. Betrachten Sie folgende Abfrage:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A AND T3.C=T1.C
  WHERE T3.D > 0 OR T1.D > 0

Hier ist die WHERE-Bedingung für den eingebetteten äußeren Join nicht nullabweisend, wohl aber die Join-Bedingung des einbettenden äußeren Joins T2.A=T1.A AND T3.C=T1.C. Insofern kann die Abfrage wie folgt konvertiert werden:

SELECT * FROM T1 LEFT JOIN
              (T2, T3)
              ON T2.A=T1.A AND T3.C=T1.C AND T3.B=T2.B
  WHERE T3.D > 0 OR T1.D > 0

7.2.12. ORDER BY-Optimierung

In manchen Fällen kann MySQL mit einem Index eine ORDER BY-Klausel erfüllen, ohne dass eine zusätzliche Sortierung erforderlich wäre.

Der Index kann auch verwendet werden, wenn die ORDER BY-Klausel dem Index nicht exakt entspricht, solange alle nicht verwendeten Bestandteile des Indexes und alle zusätzlichen ORDER BY-Spalten Konstanten in der WHERE-Klausel sind. Die folgenden Abfragen lösen den ORDER BY-Teil mithilfe des Indexes auf:

SELECT * FROM t1 
  ORDER BY key_part1,key_part2,... ;
    
SELECT * FROM t1 
  WHERE key_part1=constant 
  ORDER BY key_part2;
    
SELECT * FROM t1 
  ORDER BY key_part1 DESC, key_part2 DESC;
    
SELECT * FROM t1
  WHERE key_part1=1 
  ORDER BY key_part1 DESC, key_part2 DESC;

In manchen Fällen kann MySQL Indizes nicht zur Auflösung von ORDER BY verwenden, obwohl es mithilfe der Indizes Datensätze findet, die der WHERE-Klausel entsprechen. Dies betrifft u. a. die folgenden Fälle:

  • Sie verwenden ORDER BY für verschiedene Schlüssel:

    SELECT * FROM t1 ORDER BY key1, key2;
    
  • Sie verwenden ORDER BY für Teile eines Schlüssels, die nicht aufeinander folgen:

    SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;
    
  • Sie verwenden ASC und DESC gemischt:

    SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
    
  • Der Schlüssel, der zum Holen der Datensätze verwendet wird, ist nicht derselbe wie derjenige, der in der ORDER BY-Klausel verwendet wird:

    SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
    
  • Sie verknüpfen zahlreiche Tabellen, und die Spalten in der ORDER BY-Klausel stammen nicht alle aus der ersten nichtkonstanten Tabelle, die zum Abrufen von Datensätzen verwendet wird. (Dies ist die erste Tabelle in der Ausgabe von EXPLAIN, die nicht den Join-Typ const aufweist.)

  • Sie haben verschiedene ORDER BY- und GROUP BY-Ausdrücke.

  • Der Typ des verwendeten Tabellenindexes speichert die Datensätze nicht in ihrer Reihenfolge. Dies gilt beispielsweise für einen HASH-Index in einer MEMORY-Tabelle.

Mit EXPLAIN SELECT … ORDER BY können Sie überprüfen, ob MySQL Indizes zur Auflösung der Abfrage verwenden kann. Wenn Sie Using filesort in der Spalte Extra sehen, ist dies nicht möglich. Siehe auch Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“.

Die verwendete filesort-Optimierung vermerkt nicht nur den Sortierschlüsselwert und die Datensatzposition, sondern auch die Spalten, die für die Abfrage erforderlich sind. Hiermit wird verhindert, dass Datensätze zweimal ausgelesen werden. Der filesort-Algorithmus funktioniert wie folgt:

  1. Die Datensätze, die der WHERE-Klausel entsprechen, werden gelesen.

  2. Für jeden Datensatz wird ein Tupel mit Werten aufgezeichnet, die den Sortierschlüsselwert und die Datensatzposition sowie die Spalten umfassen, die für die Abfrage erforderlich sind.

  3. Die Tupel werden nach dem Sortierschlüsselwert sortiert.

  4. Die Datensätze werden in der sortierten Reihenfolge abgerufen, aber die erforderlichen Spalten werden direkt aus den sortierten Tupeln ausgelesen, statt ein zweites Mal auf die Tabelle zuzugreifen.

Dieser Algorithmus stellt gegenüber dem in älteren MySQL-Versionen verwendeten eine erhebliche Verbesserung dar.

Um eine Verlangsamung zu vermeiden, wird diese Optimierung nur verwendet, wenn die Gesamtgröße der zusätzlichen Spalten im Sortiertupel den Wert der Systemvariablen max_length_for_sort_data nicht überschreitet. (Wenn Sie dieser Variablen einen zu hohen Wert zuweisen, treten typische Symptome wie eine hohe Festplatten- und eine niedrige Prozessoraktivität auf.)

Wenn Sie die Geschwindigkeit von ORDER BY erhöhen wollen, überprüfen Sie, ob Sie MySQL dazu bewegen können, Indizes statt einer zusätzlichen Sortierphase zu verwenden. Ist dies nicht möglich, dann können Sie die folgenden Strategien ausprobieren:

  • Sie erhöhen den Wert der Variablen sort_buffer_size.

  • Sie erhöhen den Wert der Variablen read_rnd_buffer_size.

  • Sie ändern tmpdir so, dass die Variable auf ein dediziertes Dateisystem mit viel freiem Speicher weist. Die Option akzeptiert mehrere Pfade, die zyklisch abwechselnd verwendet werden. Die Pfade sollten unter Unix mit Doppelpunkten (‘:’) und unter Windows, NetWare und OS/2 mit Semikola (‘;’) voneinander getrennt werden. Mithilfe dieser Funktion können Sie die Last auf mehrere Verzeichnisse verteilen. Hinweis: Die Pfade sollten auf Verzeichnisse in Dateisystemen verweisen, die sich auf verschiedenen physischen Festplatten befinden – nicht auf verschiedenen Partitionen derselben Festplatte.

Standardmäßig sortiert MySQL alle GROUP BY col1, col2, …-Abfragen so, als ob Sie in der Abfrage auch ORDER BY col1, col2, … angegeben hätten. Wenn Sie ausdrücklich eine ORDER BY-Klausel angeben, die dieselbe Spaltenliste enthält, optimiert MySQL diese ohne Geschwindigkeitseinbuße weg, auch wenn die Sortierung tatsächlich stattfindet. Enthält eine Abfrage eine GROUP BY-Klausel, während Sie die Mehrbelastung durch die Sortierung des Ergebnisses vermeiden wollen, dann können Sie diese Sortierung durch Angabe von ORDER BY NULL unterdrücken. Zum Beispiel:

INSERT INTO foo
SELECT a, COUNT(*) FROM bar GROUP BY a ORDER BY NULL;

7.2.13. GROUP BY-Optimierung

Die allgemeinste Art und Weise, eine GROUP BY-Klausel zu erfüllen, besteht darin, die gesamte Tabelle zu scannen und eine neue Temporärtabelle zu erstellen, in der alle Datensätze aus allen Gruppen aufeinander folgend aufgeführt sind, und dann mithilfe dieser Temporärtabelle Gruppen zu erkennen und – sofern möglich – Zusammenfassungsfunktionen anzuwenden. In manchen Fällen kann MySQL jedoch auf andere Weise wesentlich effizienter vorgehen und die Erstellung von Temporärtabellen umgehen, indem ein Indexzugriff verwendet wird.

Die wichtigsten Voraussetzungen zur Verwendung von Indizes für GROUP BY bestehen darin, dass alle GROUP BY-Spalten Attribute aus demselben Index referenzieren und dass der Index seine Schlüssel in der Reihenfolge speichert (beispielsweise ist dies ein BTREE- und kein HASH-Index). Ob die Verwendung von Temporärtabellen durch einen Indexzugriff ersetzt werden kann, hängt auch davon ab, welche Teile eines Indexes in einer Abfrage verwendet werden, welche Bedingungen für diese Teile spezifiziert sind und welche Zusammenfassungsfunktionen ausgewählt wurden.

Es gibt zwei Möglichkeiten, eine GROUP BY-Abfrage über den Indexzugriff auszuführen; sie beide werden in den folgenden Abschnitten beschrieben. Bei der ersten Methode wird die Gruppierungsoperation ggf. gemeinsam mit allen Bereichsprädikaten angewandt. Die zweite Methode führt zunächst einen Bereichsscan durch und gruppiert dann die Ergebnistupel.

7.2.13.1. Lockere Indexscans

Die effizienteste Möglichkeit, GROUP BY zu verarbeiten, besteht in der Verwendung des Indexes zum direkten Abrufen der Gruppenfelder. Bei dieser Zugriffsmethode verwendet MySQL die Eigenschaft einiger Indextypen, dass die Schlüssel sortiert sind (z. B. BTREE). Diese Eigenschaft erlaubt die Verwendung von Suchvorgangsgruppen in einem Index, ohne dass alle Schlüssel im Index berücksichtigt werden müssten, die die WHERE-Bedingungen erfüllen. Diese Zugriffsmethode berücksichtigt also nur einen Bruchteil der Schlüssel in einem Index und heißt deswegen lockerer Indexscan. Wenn keine WHERE-Klausel vorhanden ist, liest ein lockerer Indexscan so viele Schlüssel, wie Gruppen vorhanden sind. Diese Anzahl kann bedeutend kleiner sein als die aller Schlüssel. Wenn die WHERE-Klausel Bereichsprädikate enthält (siehe auch die Beschreibung des Join-Typs range in Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“), dann sucht ein lockerer Indexscan nach dem jeweils ersten Schlüssel aller Gruppen, die die Bereichsbedingungen erfüllen, und liest dann erneut die kleinstmögliche Anzahl Schlüssel aus. Dies ist unter den folgenden Bedingungen möglich:

  • Die Abfrage gilt einer einzelnen Tabelle.

  • Die GROUP BY-Klausel enthält die ersten aufeinander folgenden Teile des Indexes. (Wenn die Abfrage statt einer GROUP BY- eine DISTINCT-Klausel enthält, referenzieren alle den Anfang des Indexes.)

  • Wenn überhaupt, so werden als einzige Zusammenfassungsfunktionen MIN() und MAX() verwendet, die zudem alle dieselbe Spalte referenzieren.

  • Alle Teile des Indexes, die nicht aus der in der Abfrage referenzierten GROUP BY-Klausel stammen, müssen Konstanten sein (d. h., sie müssen in Gleichungen mit Konstanten referenziert werden). Ausgenommen ist lediglich das Argument der Funktionen MIN() und MAX().

Die EXPLAIN-Ausgabe für solche Abfragen zeigt Using index for group-by in der Spalte Extra an.

Die folgenden Abfragen gehören in diese Kategorie, vorausgesetzt, ein Index idx(c1,c2,c3) ist für die Tabelle t1(c1,c2,c3,c4) vorhanden:

SELECT c1, c2 FROM t1 GROUP BY c1, c2;
SELECT DISTINCT c1, c2 FROM t1;
SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;

Die folgenden Abfragen können aus den angegebenen Gründen nicht mit dieser schnellen Auswahlmethode ausgeführt werden:

  • Es sind andere Zusammenfassungsfunktionen als MIN() oder MAX() vorhanden, z. B.:

    SELECT c1, SUM(c2) FROM t1 GROUP BY c1;
    
  • Die Felder in der GROUP BY-Klausel referenzieren nicht den Anfang des Indexes:

    SELECT c1,c2 FROM t1 GROUP BY c2, c3;
    
  • Die Abfrage referenziert einen Teil eines Schlüssels, der nach dem GROUP BY-Teil kommt und für den keine Gleichzeit mit einer Konstante vorliegt. Ein Beispiel:

    SELECT c1,c3 FROM t1 GROUP BY c1, c2;
    

7.2.13.2. Enggefasster Indexscan

Ein enggefasster Indexscan kann je nach Abfragebedingung entweder ein vollständiger Indexscan oder ein Bereichsindexscan sein.

Wenn die Bedingungen für einen lockeren Indexscan nicht erfüllt werden, ist es trotzdem möglich, die Erstellung von Temporärtabellen für GROUP BY-Abfragen zu umgehen. Wenn in der WHERE-Klausel Bereichsbedingungen vorhanden sind, liest diese Methode nur die Schlüssel aus, die diese Bedingungen erfüllen. Andernfalls wird ein Indexscan durchgeführt. Da diese Methode alle Schlüssel in jedem von der WHERE-Klausel definierten Bereich liest oder den gesamten Index scannt, sofern keine Bereichsbedingungen vorhanden sind, sprechen wir hier vom enggefassten Indexscan. Beachten Sie, dass die Gruppierungsoperation beim enggefassten Indexscan erst durchgeführt wird, wenn alle Schlüssel gefunden wurden, die die Bereichsbedingungen erfüllen.

Damit diese Methode funktioniert, ist eine Konstantengleichheitsbedingung für alle Spalten in einer Abfrage ausreichend, wenn diese Abfrage die Schlüssel referenziert, die vor oder zwischen den Teilen des GROUP BY-Schlüssels auftreten. Die Konstanten aus den Gleichheitsbedingungen füllen alle „Lücken“ in den Suchschlüsseln auf, sodass es möglich ist, vollständige Präfixe des Indexes zu bilden. Diese Indexpräfixe können dann für Indexsuchvorgänge verwendet werden. Wenn Sie die Sortierung des GROUP BY-Ergebnisses benötigen und es möglich ist, Suchschlüssel zu bilden, die Präfixe des Indexes sind, dann vermeidet MySQL außerdem zusätzliche Sortieroperationen, weil das Suchen mit Präfixen in einem sortierten Index bereits alle Schlüssel in der korrekten Reihenfolge abruft.

Die folgenden Abfragen funktionieren beim oben beschriebenen lockeren Indexscan nicht, wohl allerdings beim enggefassten Indexscan (sofern ein Index idx(c1,c2,c3) für die Tabelle t1(c1,c2,c3,c4) vorhanden ist).

  • In der GROUP BY-Klausel ist zwar eine Lücke vorhanden, aber diese wird von der Bedingung c2 = 'a' abgedeckt.

    SELECT c1, c2, c3 FROM t1 WHERE c2 = 'a' GROUP BY c1, c3;
    
  • GROUP BY beginnt nicht mit dem ersten Teil des Schlüssels, aber es ist eine Bedingung vorhanden, die eine Konstante für diesen Teil angibt:

    SELECT c1, c2, c3 FROM t1 WHERE c1 = 'a' GROUP BY c2, c3;
    

7.2.14. LIMIT-Optimierung

In manchen Fällen verarbeitet MySQL eine Abfrage anders, wenn Sie LIMIT row_count verwenden und HAVING nicht einsetzen:

  • Wenn Sie nur ein paar Datensätze mit LIMIT auswählen, benutzt MySQL in manchen Fällen Indizes, obwohl eigentlich ein vollständiger Tabellenscan zu bevorzugen wäre.

  • Wenn Sie LIMIT row_count mit ORDER BY benutzen, beendet MySQL die Sortierung, sobald die ersten row_count Datensätze des sortierten Ergebnisses gefunden wurden, statt das gesamte Ergebnis zu sortieren. Erfolgt die Sortierung mithilfe eines Indexes, dann ist sie sehr schnell. Ist eine Dateisortierung erforderlich, dann müssen alle Datensätze ausgewählt werden, die der Abfrage ohne LIMIT-Klausel entsprechen, und die meisten davon (oder alle) müssen sortiert werden, bevor sichergestellt ist, dass die ersten row_count Datensätze gefunden wurden. In jedem Fall ist es, wenn die ersten Datensätze gefunden wurden, nicht mehr notwendig, den Rest der Ergebnismenge zu sortieren, weswegen MySQL dies auch nicht tut.

  • Wenn Sie LIMIT row_count mit DISTINCT kombinieren, beendet MySQL die Abfrage, sobald row_count eindeutige Datensätze gefunden wurden.

  • In manchen Fällen kann eine GROUP BY-Klausel durch Lesen des Schlüssels in der Reihenfolge (oder Durchführung einer Sortierung für den Schlüssel) und nachfolgende Berechnung von Zusammenfassungen aufgelöst werden, bis der Schlüsselwert sich ändert. In diesem Fall berechnet LIMIT row_count keine unnötigen GROUP BY-Werte.

  • Sobald MySQL die erforderliche Anzahl von Datensätzen an den Client gesendet hat, bricht es die Abfrage ab, sofern Sie nicht SQL_CALC_FOUND_ROWS verwenden.

  • LIMIT 0 gibt schnell eine leere Menge zurück. Dies kann praktisch sein, um die Gültigkeit einer Abfrage zu überprüfen. Wenn Sie eines der MySQL-APIs verwenden, können Sie damit auch die Typen der Ergebnisspalten ermitteln. (Dieser Trick funktioniert nicht im MySQL Monitor, der in solchen Fällen lediglich Empty set anzeigt. Stattdessen sollten Sie SHOW COLUMNS oder DESCRIBE für diesen Zweck verwenden.)

  • Wenn der Server Temporärtabellen zur Auflösung der Abfrage verwendet, dann berechnet er auf der Basis der LIMIT row_count-Klausel, wie viel Speicher erforderlich ist.

7.2.15. Vermeidung von Tabellenscans

Die Ausgabe von EXPLAIN zeigt ALL in der type-Spalte, wenn MySQL die Abfrage unter Verwendung eines Tabellenscans auflöst. Dies geschieht in der Regel unter den folgenden Bedingungen:

  • Die Tabelle ist so klein, dass ein Tabellenscan schneller ist als eine Schlüsselsuche. Dies betrifft in erster Linie Tabellen mit weniger als zehn Datensätzen und geringer Datensatzlänge.

  • In der ON- oder WHERE-Klausel für indizierte Spalten sind keine verwendbaren Einschränkungen vorhanden.

  • Sie vergleichen indizierte Spalten mit Konstantenwerten, und MySQL hat (basierend auf dem Indexbaum) berechnet, dass die Konstanten einen zu großen Teil der Tabelle abdecken und ein Tabellenscan schneller ginge. Siehe auch Abschnitt 7.2.4, „Optimierungen der WHERE-Klausel“.

  • Sie verwenden einen Schlüssel mit niedriger Kardinalität (d. h., viele Datensätze entsprechen dem Schlüsselwert) über eine andere Spalte. In diesem Fall geht MySQL davon aus, dass die Verwendung des Schlüssels viele Suchvorgänge nach sich ziehen würde und ein Tabellenscan schneller ginge.

Bei kleinen Tabellen ist ein Tabellenscan oft die passende Lösung. Die Auswirkungen auf die Leistung sind vernachlässigbar. Bei großen Tabellen sollten Sie die folgenden Methoden ausprobieren, damit der Optimierer sich nicht fälschlicherweise für einen Tabellenscan entscheidet:

  • Aktualisieren Sie die Schlüsselverteilung in der gescannten Tabelle mit ANALYZE TABLE tbl_name. Siehe auch Abschnitt 13.5.2.1, „ANALYZE TABLE.

  • Verwenden Sie FORCE INDEX für die gescannte Tabelle, um MySQL mitzuteilen, dass Tabellenscans im Vergleich zur Verwendung des angegebenen Indexes sehr kostspielig sind:

    SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
      WHERE t1.col_name=t2.col_name;
    

    Siehe auch Abschnitt 13.2.7, „SELECT.

  • Starten Sie mysqld mit der Option --max-seeks-for-key=1000, oder weisen Sie den Optimierer mit SET max_seeks_for_key=1000 an, vorauszusetzen, dass kein Schlüsselscan mehr als 1000 Schlüsselsuchvorgänge auslösen wird. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

7.2.16. Geschwindigkeit von INSERT-Anweisungen

Die Zeit, die für das Einfügen eines Datensatzes erforderlich ist, wird von den folgenden Faktoren bestimmt (hierbei geben die Zahlen in den Klammern näherungsweise den Anteil an):

  • Verbindung herstellen: (3)

  • Abfrage an den Server senden: (2)

  • Abfrage analysieren: (2)

  • Datensatz einfügen: (1 × Datensatzlänge)

  • Indizes einfügen: (1 × Anzahl der Indizes)

  • Schließen: (1)

Hierbei wird der Mehraufwand für das Öffnen von Tabellen nicht berücksichtigt (dies ist einmal je nebenläufiger Abfrageausführung erforderlich).

Die Größe der Tabelle verlangsamt das Einfügen von Indizes um den Faktor LogN (für B-Tree-Indizes).

Sie können Einfügeoperationen mit den folgenden Methoden beschleunigen:

  • Wenn Sie gleichzeitig viele Datensätze vom selben Client aus einfügen, verwenden Sie INSERT-Anweisungen mit mehreren VALUES-Listen, um mehrere Datensätze zur selben Zeit einzufügen. Dies ist erheblich (in manchen Fällen sogar um mehrere Größenordnungen) schneller als die Verwendung separater INSERT-Anweisungen für je einen Datensatz. Wenn Sie zu einer Tabelle, die nicht leer ist, Daten hinzufügen, dann können Sie die Variable bulk_insert_buffer_size optimieren, um das Einfügen noch mehr zu beschleunigen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

  • Wenn Sie eine große Menge Datensätze von verschiedenen Clients einfügen, können Sie den Vorgang durch Verwendung der INSERT DELAYED-Anweisung beschleunigen. Siehe auch Abschnitt 13.2.4.2, „INSERT DELAYED.

  • Bei einer MyISAM-Tabelle können Sie nebenläufige Einfügeoperationen verwenden, um Datensätze einzufügen, während gleichzeitig SELECT-Anweisungen ausgeführt werden, sofern sich in der Mitte der Tabelle keine gelöschten Datensätze befinden. Siehe auch Abschnitt 7.3.3, „Gleichzeitige Einfügevorgänge“.

  • Wenn Sie eine Tabelle aus einer Textdatei laden, verwenden Sie LOAD DATA INFILE. Dies ist normalerweise 20-mal schneller als die Verwendung von INSERT-Anweisungen. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

  • Durch geringen Mehraufwand können Sie LOAD DATA INFILE für eine MyISAM-Tabelle noch schneller machen, wenn diese Tabelle viele Indizes enthält. Gehen Sie wie folgt vor:

    1. Erstellen Sie die Tabelle mit CREATE TABLE (optional).

    2. Führen Sie eine FLUSH TABLES-Anweisung oder den Befehl mysqladmin flush-tables aus.

    3. Setzen Sie myisamchk --keys-used=0 -rq /path/to/db/tbl_name ab. Hierdurch wird die Verwendung aller Indizes für die Tabelle unterbunden.

    4. Fügen Sie mit LOAD DATA INFILE Daten in die Tabelle ein. Hierbei werden keine Indizes aktualisiert – der Vorgang ist also sehr schnell.

    5. Wenn Sie zukünftig nur aus der Tabelle lesen wollen, komprimieren Sie sie mit myisampack. Siehe auch Abschnitt 14.1.3.3, „Kennzeichen komprimierter Tabellen“.

    6. Erstellen Sie die Indizes mit myisamchk -rq /path/to/db/tbl_name neu. Hierdurch wird der Indexbaum zunächst im Speicher erstellt, bevor er auf die Festplatte geschrieben wird. Dies ist viel schneller als die Aktualisierung des Indexes im Zuge von LOAD DATA INFILE, da zahlreiche Suchvorgänge auf der Festplatte entfallen. Außerdem ist der resultierende Indexbaum einwandfrei verteilt.

    7. Führen Sie eine FLUSH TABLES-Anweisung oder den Befehl mysqladmin flush-tables aus.

    Beachten Sie, dass LOAD DATA INFILE obige Optimierung automatisch durchführt, wenn die MyISAM-Tabelle, in die Sie die Daten einfügen, leer ist. Der wesentliche Unterschied besteht darin, dass Sie myisamchk wesentlich mehr Temporärspeicher für die Indexerstellung zuweisen können, als Sie durch den Server zur Indexneuerstellung reservieren lassen würden, wenn er die LOAD DATA INFILE-Anweisung ausführt.

    Sie können die Indizes für eine MyISAM-Tabelle ferner aktivieren oder deaktivieren, indem Sie statt myisamchk die folgenden Anweisungen verwenden. Bei Verwendung dieser Anweisungen können Sie die FLUSH TABLE-Operationen übergehen:

    ALTER TABLE tbl_name DISABLE KEYS;
    ALTER TABLE tbl_name ENABLE KEYS;
    
  • Um INSERT-Operationen zu beschleunigen, die mit mehreren Anweisungen durchgeführt werden, sperren Sie Ihre Tabellen:

    LOCK TABLES a WRITE;
    INSERT INTO a VALUES (1,23),(2,34),(4,33);
    INSERT INTO a VALUES (8,26),(6,29);
    UNLOCK TABLES;
    

    Hiervon profitiert die Leistungsfähigkeit, weil der Indexpuffer nur einmal auf die Festplatte synchronisiert wird, nachdem alle INSERT-Anweisungen abgeschlossen wurden. Im Normalfall gäbe es so viele Synchronisierungsvorgänge für Indexpuffer, wie INSERT-Anweisungen vorhanden sind. Explizite Sperranweisungen sind nicht erforderlich, wenn Sie alle Datensätze mit einer einzelnen INSERT-Anweisung einfügen können.

    Bei transaktionssicheren Tabellen sollten Sie START TRANSACTION und COMMIT statt LOCK TABLES benutzen, um die Einfügeoperationen zu beschleunigen.

    Eine Sperrung verringert auch die Gesamtdauer für die Überprüfung mehrerer Verbindungen, auch wenn sich die Gesamtwartezeit für einzelne Verbindungen erhöhen kann, weil diese auf das Erwirken der Sperren warten. Zum Beispiel:

    1. Verbindung 1 führt 1.000 Einfügeoperationen durch.

    2. Die Verbindungen 2, 3 und 4 fügen je eine Einfügeoperation durch.

    3. Verbindung 5 führt 1.000 Einfügeoperationen durch.

    Wenn Sie keine Sperrung verwenden, werden die Verbindungen 2, 3 und 4 vor den Verbindungen 1 und 5 beendet; setzen Sie hingegen eine Sperre, dann werden die Verbindungen 2, 3 und 4 zwar (wahrscheinlich) nicht eher als die Verbindungen 1 und 5 enden, aber der gesamte Zeitbedarf verringert sich um ca. 40 Prozent.

    INSERT-, UPDATE- und DELETE-Operationen sind in MySQL sehr schnell, aber Sie können eine noch bessere Gesamtperformance erzielen, indem Sie Sperren für alles setzen, was mehr als fünf Einfüge- oder Änderungsoperationen in einem Datensatz umfasst. Wenn Sie sehr viele Einfügeoperationen in einem Datensatz vornehmen, könnten Sie ab und zu (d. h. etwa alle 1.000 Datensätze) ein LOCK TABLES gefolgt von einem UNLOCK TABLES absetzen, damit auch andere Threads auf die Tabelle zugreifen können. Dies bringt trotz allem einen ansehnlichen Leistungsgewinn.

    Auch wenn Sie die soeben beschriebenen Strategien verwenden, ist INSERT beim Laden von Daten allerdings nach wie vor wesentlich langsamer als LOAD DATA INFILE.

  • Um die Leistung bei MyISAM-Tabellen für LOAD DATA INFILE und INSERT gleichermaßen zu optimieren, vergrößern Sie den Schlüssel-Cache, indem Sie den Wert der Systemvariablen key_buffer_size erhöhen. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

7.2.17. Geschwindigkeit von UPDATE-Anweisungen

Eine Änderungsanweisung wird wie eine SELECT-Abfrage optimiert, es kommt jedoch der zusätzliche Mehraufwand einer Schreiboperation hinzu. Die Geschwindigkeit der Schreiboperation hängt von der Menge der zu ändernden Daten und der Anzahl der zu aktualisierenden Indizes ab. Indizes, die nicht geändert werden, werden nicht aktualisiert.

Eine andere Möglichkeit, Updates zu beschleunigen, besteht darin, sie aufzuschieben und dann viele Updates direkt hintereinander durchzuführen. Wenn Sie die Tabelle sperren, ist die gemeinsame Durchführung vieler Änderungen wesentlich schneller, als wenn Sie immer nur ein Update zur selben Zeit durchführen.

Bei einer MyISAM-Tabelle, die das dynamische Datensatzformat verwendet, kann die Änderung eines Datensatzes auf eine höhere Gesamtlänge dazu führen, dass der Datensatz geteilt wird. Wenn Sie dies oft tun, dürfen Sie keinesfalls vergessen, gelegentlich OPTIMIZE TABLE abzusetzen. Siehe auch Abschnitt 13.5.2.5, „OPTIMIZE TABLE.

7.2.18. Geschwindigkeit von DELETE-Anfragen

Die zum Löschen einzelner Datensätze erforderliche Zeit ist direkt proportional zur Anzahl der Indizes. Um Datensätze schneller zu löschen, können Sie den Wert des Schlüssel-Caches erhöhen, indem Sie die Systemvariable key_buffer_size entsprechend einstellen. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

Wenn Sie alle Datensätze aus einer Tabelle löschen wollen, ist TRUNCATE TABLE tbl_name schneller als DELETE FROM tbl_name. Siehe auch Abschnitt 13.2.9, „TRUNCATE.

7.2.19. Weitere Optimierungstipps

Dieser Abschnitt listet eine Anzahl verschiedener Tipps zur Verbesserung der Abfrageverarbeitungsgeschwindigkeit auf:

  • Verwenden Sie permanente Verbindungen zur Datenbank, um die zusätzliche Belastung durch das Herstellen und Abbauen von Verbindungen zu umgehen. Können Sie keine Permanentverbindungen verwenden und stellen Sie viele neue Verbindungen zur Datenbank her, dann sollten Sie den Wert der Variablen thread_cache_size ändern. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

  • Überprüfen Sie immer, ob alle Ihre Abfragen wirklich die Indizes verwenden, die Sie in den Tabellen erstellt haben. In MySQL können Sie dies mit der EXPLAIN-Anweisung tun. Siehe auch Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“.

  • Versuchen Sie komplexe SELECT-Abfragen an häufig aktualisierte MyISAM-Tabellen zu umgehen, um Probleme in Verbindung mit der Tabellensperrung zu vermeiden, die aufgrund des konkurrierenden Zugriffs durch Leser und Schreiber entstehen.

  • Bei MyISAM-Tabellen, bei denen in der Mitte keine gelöschten Datensätze vorhanden sind, können Sie Datensätze am Ende einfügen, während gleichzeitig eine andere Abfrage aus der Tabelle liest. Wenn ein solches Verhalten wichtig ist, sollten Sie die Tabelle so verwenden, dass möglichst keine Datensätze gelöscht werden. Eine andere Möglichkeit besteht darin, die Tabelle mit OPTIMIZE TABLE zu defragmentieren, wenn Sie viele Datensätze gelöscht haben. Siehe auch Abschnitt 14.1, „Die MyISAM-Speicher-Engine“.

  • Um komprimierungsbedingte Probleme zu beheben, die im Zusammenhang mit ARCHIVE-Tabellen auftreten können, können Sie OPTIMIZE TABLE verwenden. Siehe auch Abschnitt 14.8, „Die ARCHIVE-Speicher-Engine“.

  • Verwenden Sie ALTER TABLE … ORDER BY expr1, expr2, …, wenn Sie Datensätze gewöhnlich in der Reihenfolge expr1, expr2, … abrufen. Wenn Sie diese Option nach umfangreicheren Änderungen in der Tabelle verwenden, können Sie die Leistung unter Umständen steigern.

  • In manchen Fällen kann es sinnvoll sein, eine Spalte hinzuzufügen, die auf den Daten in anderen Spalten basierende „Hash-Werte“ enthält. Wenn diese Spalte kurz und ausreichend eindeutig ist, kann dies wesentlich schneller sein als ein „breiter“ Index über viele Spalten. In MySQL ist die Verwendung dieser Zusatzspalte ganz einfach:

    SELECT * FROM tbl_name
      WHERE hash_col=MD5(CONCAT(col1,col2))
      AND col1='constant' AND col2='constant';
    
  • Bei MyISAM-Tabellen, die sich häufig verändern, sollten Sie die Verwendung von Spalten variabler Länge (VARCHAR, BLOB und TEXT) möglichst unterlassen. Die Tabelle verwendet das dynamische Datensatzformat, sobald auch nur eine einzige Spalte variabler Länge vorhanden ist. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

  • Es ist normalerweise nicht sinnvoll, eine Tabelle in mehrere getrennte Tabellen zu unterteilen, weil die Datensätze dann sehr groß werden. Beim Zugriff auf einen Datensatz besteht die größte Anforderung aus leistungstechnischer Sicht im Suchvorgang, der auf der Festplatte ausgeführt wird, um das erste Byte des Datensatzes zu finden. Wurde der Beginn der Daten gefunden, dann können die meisten modernen Festplatten den vollständigen Datensatz für die meisten Anwendungen ausreichend schnell lesen. Die einzigen Fälle, in denen das Aufteilen einer Tabelle einen nennenswerten Unterschied macht, liegen vor, wenn es sich um eine MyISAM-Tabelle handelt, die das dynamische Datensatzformat verwendet, welches Sie in eine feste Datensatzgröße umwandeln können, oder wenn Sie die Tabelle sehr häufig scannen müssen, die meisten Spalten aber nicht benötigen. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

  • Müssen Sie häufig Ergebnisse wie beispielsweise Summenwerte basierend auf Daten aus einer Vielzahl von Datensätzen berechnen, dann kann es praktisch sein, eine neue Tabelle einzurichten und den Zähler in Echtzeit zu aktualisieren. Eine Änderung der folgenden Form ist sehr schnell:

    UPDATE tbl_name SET count_col=count_col+1 WHERE key_col=constant;
    

    Dies ist sehr wichtig, wenn Sie MySQL-Speicher-Engines wie MyISAM verwenden, die nur Sperren auf Tabellenebene bieten (d. h. mehrere Leser bei einem Schreiber). Dies bietet auch bei den meisten anderen Datenbanksystemen eine bessere Performance, da der Datensatzsperrmanager in diesem Fall weniger zu tun hat.

  • Wenn Sie Statistiken aus großen Logtabellen ermitteln müssen, sollten Sie Zusammenfassungstabellen verwenden, statt die gesamte Logtabelle zu scannen. Die Erstellung der Zusammenfassungen sollte wesentlich schneller sein als die Berechnung von „Echtzeitstatistiken“. Die Neuerstellung von Übersichtstabellen aus den Logs ist, wenn sich (abhängig von Geschäftsentscheidungen) Faktoren ändern, schneller als eine Anpassung der laufenden Anwendung.

  • Sofern möglich, sollten Sie Berichte als „Echtzeitberichte“ oder als „statistische Berichte“ klassifizieren, wobei die für die statistischen Berichte erforderlichen Daten nur aus Zusammenfassungstabellen erzeugt werden, die ihrerseits in regelmäßigen Abständen aus den Echtzeitdaten erstellt werden.

  • Nutzen Sie die Tatsache, dass Spalten Standardwerte haben. Fügen Sie Werte nur dann explizit ein, wenn sich der einzufügende Wert von der Vorgabe unterscheidet. Hierdurch verringern Sie die Analysearbeit für MySQL und erhöhen die Einfügegeschwindigkeit.

  • In manchen Fällen ist es sinnvoll, Daten zu packen und in einer BLOB-Spalte zu speichern. In diesem Fall muss Ihre Anwendung zwar Code zum Packen und Entpacken der Daten enthalten, aber Sie sparen sich auf einer gewissen Ebene viele Zugriffe. Dies ist praktisch, wenn Sie Daten haben, die sich nicht gut in die zeilen- und spaltenbasierte Struktur einer Tabelle einfügen lassen.

  • Normalerweise sollten Sie alle Daten nichtredundant halten. (Beachten Sie dabei die in der Datenbanktheorie so genannte Dritte Normalform.) Allerdings gibt es auch Situationen, in denen die Duplizierung von Daten oder die Erstellung zusammenfassender Tabellen zur Geschwindigkeitssteigerung beitragen können.

  • Bei einigen Aufgaben können etwa gespeicherte Routinen oder benutzerdefinierte Funktionen Optionen zur Optimierung der Leistung sein. Weitere Informationen finden Sie in Kapitel 19, Gespeicherte Prozeduren und Funktionen, und Abschnitt 26.3, „Hinzufügen neuer Funktionen zu MySQL“.

  • Sie können immer einen kleinen Geschwindigkeitsvorteil gewinnen, indem Sie Abfragen oder Antworten in Ihrer Anwendung in einem Cache ablegen und dann zahlreiche Einfüge- oder Aktualisierungsvorgänge gemeinsam ausführen. Wenn Ihr Datenbanksystem Tabellensperren unterstützt (wie es beispielsweise bei MySQL und Oracle der Fall ist), dann sollten Sie so sicherstellen können, dass der Index-Cache nur einmal nach Durchführung aller Änderungen synchronisiert wird. Sie können auch vom Abfrage-Cache von MySQL profitieren, um ähnliche Ergebnisse zu erhalten (siehe auch Abschnitt 5.14, „MySQL-Anfragen-Cache“).

  • Verwenden Sie INSERT DELAYED, wenn Sie nicht unbedingt wissen müssen, wann Ihre Daten geschrieben werden. Dies verringert die Gesamtauswirkungen von Einfügeoperationen, weil zahlreiche Datensätze im Zuge eines einzigen Schreibvorgangs auf die Festplatte geschrieben werden.

  • Verwenden Sie INSERT LOW_PRIORITY, wenn Sie SELECT-Anweisungen Vorrang vor den Einfügeoperationen gewähren wollen.

  • Verwenden Sie SELECT HIGH_PRIORITY, um abgerufene Datensätze in der Warteschlange nach vorne zu setzen: In diesem Fall wird die SELECT-Anweisung auch ausgeführt, wenn ein anderer Client darauf wartet, schreiben zu können.

  • Verwenden Sie INSERT-Anweisungen für mehrere Datensätze, um zahlreiche Daten mit einer SQL-Anweisung zu speichern. Dies wird von vielen SQL-Servern (einschließlich MySQL) unterstützt.

  • Laden Sie mit LOAD DATA INFILE große Datenmengen. Dies ist schneller als die Verwendung von INSERT-Anweisungen.

  • Erzeugen Sie mit AUTO_INCREMENT eindeutige Werte.

  • Verwenden Sie hin und wieder OPTIMIZE TABLE, um eine Fragmentierung von MyISAM-Tabellen mit dynamischem Datensatzformat zu verhindern. Siehe auch Abschnitt 14.1.3, „MyISAM-Tabellenformate“.

  • Verwenden Sie, sofern möglich, MEMORY-Tabellen, um die Geschwindigkeit zu erhöhen. Siehe auch Abschnitt 14.4, „Die MEMORY-Speicher-Engine“. MEMORY-Tabellen sind für nichtkritische Daten nützlich, auf die häufig zugegriffen wird, also etwa Informationen zum zuletzt angezeigten Werbebanner für Benutzer, in deren Webbrowser Cookies nicht aktiviert sind. In vielen Webanwendungen stellen Benutzersitzungen eine andere Alternative für den Umgang mit flüchtigen Statusdaten dar.

  • Bei Webservern sollten Bilder und andere Binärressourcen normalerweise als Dateien gespeichert werden: In der Datenbank speichern Sie also statt der Datei selbst nur einen Verweis darauf. Die meisten Webserver können Dateien besser zwischenspeichern als Datenbankinhalte, weswegen die Verwendung von Dateien in der Regel schneller ist.

  • Spalten mit identischen Daten in verschiedenen Tabellen sollten mit identischen Datentypen deklariert werden, damit auf den entsprechenden Spalten basierende Joins beschleunigt werden.

  • Verwenden Sie möglichst einfache Spaltennamen. In einer Tabelle namens customer sollten Sie statt einer Spalte customer_name besser einfach den Spaltennamen name benutzen. Damit die Namen auf andere SQL-Server portierbar sind, sollten Sie sie stets kürzer als 18 Zeichen halten.

  • Wenn Geschwindigkeit für Sie ein absoluter Schlüsselaspekt ist, sollten Sie einen Blick auf maschinennahe Schnittstellen zur Datenspeicherung werfen, die von verschiedenen SQL-Servern unterstützt werden. Indem Sie beispielsweise direkt auf die MyISAM-Speicher-Engine von MySQL zugreifen, können Sie die Geschwindigkeit im Vergleich zur SQL-Schnittstelle um das Zwei- bis Fünffache erhöhen. Zu diesem Zweck müssen die Daten auf demselben Server wie die Anwendung liegen, und der Zugriff sollte möglichst nur von einem Prozess aus erfolgen (da die externe Dateisperrung wirklich langsam ist). Man könnte diese Probleme beseitigen, indem man maschinennahe MyISAM-Befehle am MySQL Server implementiert (dies wäre eine einfache Möglichkeit, bei Bedarf mehr Leistung herauszuholen). Durch sorgfältiges Design der Datenbankschnittstelle könnte es recht einfach sein, diesen Optimierungstyp zu unterstützen.

  • Wenn Sie numerische Daten verwenden, ist es in vielen Fällen schneller, auf Daten in einer Datenbank (über eine laufende Verbindung) statt in einer Textdatei zuzugreifen. Die Daten in der Datenbank sind wahrscheinlich in einem kompakteren Format gespeichert als in der Textdatei, weswegen beim Zugriff weniger Festplattenzugriffe auftreten. Außerdem können Sie Code in Ihrer Anwendung einsparen, denn Sie müssen die Textdateien nicht analysieren, um Zeilen- und Spaltenbegrenzungen zu finden.

  • Bei einigen Operationen kann die Replikation einen Leistungsgewinn bringen. Sie können die Abrufvorgänge durch die Clients auf mehrere Server verteilen, um einen Lastausgleich zu erzielen. Damit der Master bei der Erstellung von Backups nicht verlangsamt wird, können Sie Sicherungen mit einem Slave-Server erstellen. Siehe auch Kapitel 6, Replikation bei MySQL.

  • Die Deklaration einer MyISAM-Tabelle mit der Tabellenoption DELAY_KEY_WRITE=1 beschleunigt Indexaktualisierungen, da diese erst auf Festplatte geschrieben werden, wenn die Tabelle geschlossen wird. Der Nachteil besteht darin, dass Sie, wenn der Server terminiert wird, während eine solche Tabelle geöffnet ist, sicherstellen müssen, dass die Tabelle unbeschädigt ist, indem Sie den Server mit der Option --myisam-recover ausführen oder myisamchk verwenden, bevor Sie den Server neu starten. (Allerdings sollten Sie auch in diesem Fall keine Daten verlieren, wenn Sie DELAY_KEY_WRITE verwenden, weil die Schlüsselinformationen sich immer aus den Datensätzen in der Datendatei ableiten lassen.)

7.3. Probleme mit Sperren

7.3.1. Wie MySQL Tabellen sperrt

MySQL verwendet die Sperrung auf Tabellenebene für MyISAM- und MEMORY-Tabellen, die Sperrung auf Seitenebene für BDB-Tabellen und die Sperrung auf Datensatzebene für InnoDB-Tabellen.

In vielen Fällen können Sie eine begründete Annahme dazu treffen, welcher Sperrungstyp der beste für eine Anwendung ist; generell ist es aber schwierig zu sagen, dass ein bestimmter Sperrungstyp besser ist als ein anderer. Alles hängt von der Anwendung ab, und verschiedene Teile einer Anwendung können unterschiedliche Sperrungstypen erfordern.

Um zu entscheiden, ob Sie eine Speicher-Engine mit Sperrung auf Datensatzebene verwenden sollten, müssen Sie einschätzen, was Ihre Anwendung tut und welche Mischung aus Auswahl- und Änderungsanweisungen sie verwendet. Die meisten Webanwendungen führen beispielsweise sehr viele Auswahloperationen, relativ wenig Löschvorgänge, vorzugsweise auf Schlüsselwerten basierende Änderungen und Einfügungen in nur ein paar bestimmte Tabellen durch. Die MyISAM-Basiskonfiguration von MySQL ist für solche Zwecke hervorragend geeignet.

Die Tabellensperrung in MySQL schließt ein Deadlock bei Speicher-Engines aus, die Sperren auf Tabellenebene verwenden. Die Deadlock-Vermeidung wird verwaltet, indem zu Anfang einer Abfrage immer alle erforderlichen Sperren auf einmal angefordert und die Tabellen immer in derselben Reihenfolge gesperrt werden.

Die Tabellensperrmethode, die MySQL für WRITE-Sperren verwendet, funktioniert wie folgt:

  • Wenn keine Sperre für die Tabelle vorhanden ist, wird eine Schreibsperre verhängt.

  • Andernfalls wird die Sperranforderung in die Warteschlange für Schreibsperranforderungen gesetzt.

Die Tabellensperrmethode, die MySQL für READ-Sperren verwendet, funktioniert wie folgt:

  • Wenn keine Schreibsperre für die Tabelle vorhanden ist, wird eine Lesesperre verhängt.

  • Andernfalls wird die Sperranforderung in die Warteschlange für Lesesperranforderungen gesetzt.

Wenn eine Sperre aufgehoben wird, wird die Sperrmöglichkeit zunächst den Threads in der Warteschleife für Schreibsperranforderungen und dann den Threads in der Warteschleife für Lesesperranforderungen verfügbar gemacht: Wenn Sie also viele Änderungen an einer Tabelle vorgenommen haben, warten SELECT-Anweisungen, bis keine Änderungen mehr anhängig sind.

Sie können die Zugriffssituation bezüglich der Tabellensperren auf Ihrem System analysieren, indem Sie die Statusvariablen Table_locks_waited und Table_locks_immediate überprüfen:

mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Table_locks_immediate | 1151552 |
| Table_locks_waited    | 15324   |
+-----------------------+---------+

Wenn eine MyISAM-Tabelle keine freien Blöcke in der Mitte enthält, werden Datensätze immer am Ende der Datendatei eingefügt. In diesem Fall können Sie INSERT- und SELECT-Anweisungen bei einer MyISAM-Tabelle ohne Sperre gleichzeitig verwenden. Sie können also Datensätze in eine MyISAM-Tabelle einfügen, während andere Clients zur selben Zeit daraus lesen. (Löcher können entstehen, wenn Datensätze in der Mitte der Tabelle gelöscht oder aktualisiert wurden. Wenn Löcher vorhanden sind, sind gleichzeitige Einfügeoperationen nicht möglich; sie werden allerdings sofort wieder verfügbar, sobald alle Löcher mit neuen Daten gefüllt wurden.)

Wenn Sie viele INSERT- und SELECT-Operationen an einer Tabelle durchführen wollen, während gleichzeitige Einfügeoperationen gerade nicht möglich sind, dann können Sie Datensätze in eine Temporärtabelle einfügen und die echte Tabelle dann sporadisch mit den Datensätzen aus dieser Temporärtabelle aktualisieren. Dies ist etwa mit dem folgenden Code möglich:

mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
mysql> INSERT INTO real_table SELECT * FROM insert_table;
mysql> TRUNCATE TABLE insert_table;
mysql> UNLOCK TABLES;

InnoDB verwendet Datensatzsperren, BDB hingegen Seitensperren. Bei diesen beiden Speicher-Engines sind Deadlocks möglich, weil sie während der Verarbeitung von SQL-Anweisungen automatisch Sperren erwirken – und nicht gleich beim Start der Transaktion.

Vorteile der Sperrung auf Datensatzebene:

  • weniger Sperrkonflikte beim Zugriff auf verschiedene Datensätze in vielen Threads

  • weniger Änderungen bei Rollbacks

  • Möglichkeit einer sehr langen Sperrdauer für einen Datensatz

Nachteile der Sperrung auf Datensatzebene:

  • erfordert mehr Speicher als die Sperrung auf Seiten- oder Tabellenebene

  • langsamer als die Sperrung auf Seiten- oder Tabellenebene, wenn sie für einen großen Teil der Tabelle verwendet wird, weil Sie wesentlich mehr Sperren erwirken müssen

  • definitiv wesentlich langsamer als die anderen Sperrungsoptionen, wenn Sie häufig GROUP BY-Operationen für einen großen Teil der Daten durchführen oder oft die gesamte Tabelle scannen müssen

Tabellensperren sind Sperren auf Seiten- oder Datensatzebene in den folgenden Fällen überlegen:

  • Die meisten Anweisungen für die Tabelle sind Leseoperationen.

  • Eine Mischung von Lese- und Schreiboperationen, wobei die Schreiboperationen Updates oder Löschvorgänge für einen einzelnen Datensatz sind, der mit einem Schlüssellesevorgang geholt werden kann:

    UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;
    DELETE FROM tbl_name WHERE unique_key_col=key_value;
    
  • SELECT in Kombination mit gleichzeitigen INSERT-Anweisungen und sehr wenigen UPDATE- oder DELETE-Anweisungen.

  • Viele Scans oder GROUP BY-Operationen über die gesamte Tabelle ohne Schreiber.

Bei Sperren höherer Ebene können Sie Anwendungen einfacher optimieren, indem Sie Sperren verschiedener Typen unterstützen, weil der Overhead wesentlich geringer ist als bei Sperren auf Datensatzebene.

Andere Optionen als Sperrungen auf Datensatz- und Seitenebene:

  • Versionierung (wie sie beispielsweise in MySQL für nebenläufige Einfügeoperationen verwendet wird). Hierbei können ein Schreiber und mehrere Leser nebeneinander arbeiten. Dies bedeutet, dass die Datenbank oder Tabelle verschiedene Views der Daten abhängig vom Zeitpunkt des Zugriffsbeginns unterstützt. Andere gängige Bezeichnungen hierfür sind „Zeitreise“, „Copy on Write“ (Kopieren beim Schreiben) und „Copy on Demand“ (Kopieren bei Bedarf).

  • Copy on Demand ist der Sperrung auf Seiten- oder Datensatzebene in vielen Fällen überlegen. Schlimmstenfalls kann sie jedoch wesentlich mehr Speicher beanspruchen als normale Sperren.

  • Anstelle von Sperren auf Datensatzebene können Sie auch Sperren auf Anwendungsebene verwenden – in MySQL etwa GET_LOCK() und RELEASE_LOCK(). Dies sind beratende Sperren, d. h., sie funktionieren nur in „wohlerzogenen“ Anwendungen.

7.3.2. Themen, die Tabellensperren betreffen

Um eine sehr hohe Sperrgeschwindigkeit zu erzielen, verwendet MySQL die Tabellensperrung (statt der Sperrung auf Seiten-, Datensatz- oder Spaltenebene) für alle Speicher-Engines mit Ausnahme von InnoDB und BDB.

Bei InnoDB- und BDB-Tabellen setzt MySQL die Tabellensperrung nur dann ein, wenn Sie die Tabelle mit LOCK TABLES explizit sperren. Bei diesen Speicher-Engines raten wir von der Verwendung von LOCK TABLES vollständig ab, weil InnoDB eine automatische Sperrung auf Datensatzebene und BDB die Sperrung auf Seitenebene verwendet, um die Transaktionsisolierung sicherzustellen.

Bei großen Tabellen ist die Tabellensperrung für die meisten Anwendungen wesentlich besser als die Datensatzsperrung. Es gibt allerdings auch ein paar Fallstricke:

  • Die Tabellensperrung gestattet mehreren Threads das Lesen aus der Tabelle zur selben Zeit; will ein Thread hingegen in eine Tabelle schreiben, so muss er zunächst exklusiven Zugriff erhalten. Alle anderen Threads, die auf die betreffende Tabelle zugreifen wollen, müssen warten, bis das Update abgeschlossen ist.

  • Tabellenupdates erhalten eine höhere Priorität als Abrufvorgänge, weil sie normalerweise als wichtiger betrachtet werden. Auf diese Weise soll sichergestellt werden, dass Updates für eine Tabelle auch dann nicht „verhungern“, wenn sehr viele SELECT-Anweisungen für die Tabelle abgesetzt werden.

  • Die Tabellensperre kann beispielsweise Probleme verursachen, wenn ein Thread wartet, weil die Festplatte voll ist und erst freier Speicher benötigt wird, damit er fortgesetzt werden kann. In diesem Fall werden alle Threads, die auf die problematische Tabelle zugreifen wollen, ebenfalls in einen Wartezustand versetzt, bis wieder genug Festplattenkapazität verfügbar ist.

Die Tabellensperre ist auch in folgendem Szenario nachteilig:

  • Ein Client setzt eine SELECT-Anweisung ab, deren Ausführung sehr lange dauert.

  • Ein anderer Client setzt dann eine UPDATE-Anweisung für dieselbe Tabelle ab. Dieser Client wartet, bis die SELECT-Anweisung abgeschlossen ist.

  • Wieder ein anderer Client setzt eine weitere SELECT-Anweisung für dieselbe Tabelle ab. Weil UPDATE aber eine höhere Priorität hat als SELECT, wartet diese SELECT-Anweisung darauf, dass die UPDATE-Anweisung wie auch die erste SELECT-Anweisung fertig gestellt werden.

Die folgenden Punkte beschreiben einige Möglichkeiten, um den konkurrierenden Zugriff, der durch Tabellensperren verursacht werden kann, zu vermeiden oder zumindest zu verringern:

  • Versuchen Sie die Ausführung der SELECT-Anweisungen zu beschleunigen, sodass die Tabellensperren verkürzt werden. Zu diesem Zweck müssen Sie unter Umständen einige Zusammenfassungstabellen erstellen.

  • Starten Sie mysqld mit der Option --low-priority-updates. So erhalten alle Anweisungen, die eine Tabelle aktualisieren (also ändern), eine niedrigere Priorität gegenüber SELECT-Anweisungen. In diesem Fall würde die zweite SELECT-Anweisung in obigem Beispiel vor der UPDATE-Anweisung ausgeführt werden, und Sie müssten nicht warten, bis die erste SELECT-Anweisung abgeschlossen ist.

  • Sie können mit der Anweisung SET LOW_PRIORITY_UPDATES=1 festlegen, dass alle Aktualisierungen, die über eine bestimmte Verbindung erfolgen, mit niedrigerer Priorität verarbeitet werden sollen. Siehe auch Abschnitt 13.5.3, „SET.

  • Sie können einer bestimmten INSERT-, UPDATE- oder DELETE-Anweisung mit dem Attribut LOW_PRIORITY eine niedrigere Priorität zuweisen.

  • Sie können einer bestimmten SELECT-Anweisung mit dem Attribut HIGH_PRIORITY eine höhere Priorität zuweisen. Siehe auch Abschnitt 13.2.7, „SELECT.

  • Sie können mysqld mit einem niedrigen Wert für die Systemvariable max_write_lock_count starten: In diesem Fall wird MySQL gezwungen, die Priorität aller SELECT-Anweisungen, die auf eine Tabelle warten, zu senken, nachdem eine bestimmte Anzahl von Einfügeoperationen in die Tabelle stattgefunden hat. Auf diese Weise können nach einer bestimmten Anzahl von WRITE-Sperren auch READ-Sperren gesetzt werden.

  • Wenn Sie Probleme mit INSERT in Verbindung mit SELECT haben, sollten Sie in Betracht ziehen, auf MyISAM-Tabellen umzustellen, denn diese unterstützen gleichzeitige SELECT- und INSERT-Anweisungen.

  • Mischen Sie Einfüge- und Löschoperationen in derselben Tabelle, dann kann INSERT DELAYED sehr hilfreich sein. Siehe auch Abschnitt 13.2.4.2, „INSERT DELAYED.

  • Wenn Sie Probleme mit gemischten SELECT- und DELETE-Anweisungen haben, dann kann die Option LIMIT für DELETE nützlich sein. Siehe auch Abschnitt 13.2.1, „DELETE.

  • Die Verwendung von SQL_BUFFER_RESULT bei SELECT-Anweisungen kann dabei helfen, die Dauer der Tabellensperren zu verkürzen. Siehe auch Abschnitt 13.2.7, „SELECT.

  • Sie können den Sperrcode in mysys/thr_lock.c so abändern, dass nur eine einzelne Warteschlange verwendet wird. In diesem Fall hätten Schreib- und Lesesperren dieselbe Priorität, was bei einigen Anwendungen von Nutzen sein kann.

Hier noch ein paar Tipps zu Tabellensperren in MySQL:

  • Gleichzeitige Benutzer stellen kein Problem dar, wenn Sie Update- nicht mit Auswahloperationen mischen, die viele Datensätze in derselben Tabelle untersuchen müssen.

  • Sie können mit LOCK TABLES die Geschwindigkeit erhöhen, weil viele Updates innerhalb einer einzelnen Sperre wesentlich schneller erfolgen als die Durchführung von Updates ohne Sperre. Auch das Aufteilen des Tabelleninhalts auf mehrere Tabellen kann hilfreich sein.

  • Wenn Sie auf geschwindigkeitsspezifische Probleme in Verbindung mit Tabellensperren bei MySQL treffen, können Sie die Leistung möglicherweise durch Konvertierung einiger Ihrer Tabellen in InnoDB- oder BDB-Tabellen verbessern. Siehe auch Abschnitt 14.2, „InnoDB-Tabellen“, und Abschnitt 14.5, „Die BDB-Speicher-Engine“.

7.3.3. Gleichzeitige Einfügevorgänge

Bei einer MyISAM-Tabelle können Sie nebenläufige Einfügeoperationen verwenden, um Datensätze einzufügen, während gleichzeitig SELECT-Anweisungen ausgeführt werden, sofern sich in der Mitte der Tabelle keine gelöschten Datensätze befinden.

Unter Umständen, bei denen gleichzeitige Einfügeoperationen verwendet werden können, ist es nur sehr selten notwendig, den Modifizierer DELAYED für INSERT-Anweisungen zu verwenden. Siehe Abschnitt 13.2.4.2, „INSERT DELAYED.

Wenn Sie das Binärlog verwenden, werden nebenläufige in normale Einfügeoperationen für die Anweisungen CREATE ... SELECT oder INSERT ... SELECT umgewandelt. Hierdurch wird gewährleistet, dass Sie eine exakte Kopie Ihrer Tabellen neu erstellen können, indem Sie das Log während eines Sicherungsvorgangs anwenden.

Bei LOAD DATA INFILE können, wenn Sie CONCURRENT bei einer MyISAM-Tabelle angeben, die die Bedingungen für gleichzeitige Einfügeoperationen erfüllt (d. h. keine freien Blöcke in der Mitte enthält), andere Threads Daten aus der Tabelle abrufen, während LOAD DATA ausgeführt wird. Die Verwendung dieser Option beeinflusst die Leistungsfähigkeit von LOAD DATA auch dann geringfügig, wenn gleichzeitig kein anderer Thread die Tabelle verwendet.

7.4. Optimierung der Datenbankstruktur

7.4.1. Überlegungen zum Datenbankdesign

MySQL speichert Datensätze und Indexdaten in separaten Dateien. Viele andere Datenbanksysteme (sogar fast alle) speichern Datensätze und Indexdaten in derselben Datei. Wir sind allerdings der Ansicht, dass die Vorgehensweise von MySQL für eine Vielzahl moderner Systeme die bessere Wahl ist.

Eine andere Möglichkeit zur Speicherung der Datensätze besteht darin, die Daten für jede Spalte in einem separaten Bereich zu halten (Beispiele für Datenbanksysteme, die diesen Ansatz verwenden, sind SDBM und Focus). Allerdings führt dies zu einem erheblichen Leistungseinbruch, sobald auf mehr als eine Spalte zugegriffen wird. Aufgrund dieses Verhaltens beim Zugriff auf mehrere Spalten glauben wir nicht, dass dieses Modell für universelle Datenbanken gut geeignet ist.

Der häufigere Fall ist jedoch der, dass Indizes und Daten gemeinsam gespeichert werden (wie beispielsweise bei Oracle/Sybase usw.). In diesem Fall finden Sie die Datensatzinformationen auf der Blattseite des Indexes. Der Vorteil dieses Designs besteht darin, dass hierbei in vielen Fällen – abhängig davon, wie gut der Index zwischengespeichert wird – ein Lesevorgang auf der Festplatte eingespart wird. Es gibt aber auch Nachteile:

  • Tabellenscans sind wesentlich langsamer, weil Sie die Indizes durchlesen müssen, um an die Daten zu kommen.

  • Sie können die Daten für eine Abfrage nicht einfach der Indextabelle entnehmen.

  • Sie verbrauchen mehr Speicherplatz, weil Sie Indizes aus den Knoten duplizieren müssen (Sie können den Datensatz nicht in den Knoten speichern).

  • Aufgrund von Löschvorgängen degeneriert die Tabelle im Laufe der Zeit, weil die Indizes in Knoten normalerweise bei Löschvorgängen nicht aktualisiert werden.

  • Es ist schwieriger, nur die Indexdaten zwischenzuspeichern.

7.4.2. Wie Sie Ihre Daten so klein wie möglich bekommen

Eine der einfacheren Optimierungen besteht darin, Ihre Tabellen so zu implementieren, dass sie möglichst wenig Platz auf der Festplatte einnehmen. Dies kann erhebliche Verbesserungen zur Folge haben, weil die Lesevorgänge von der Festplatte schneller erfolgen und kleinere Tabellen normalerweise weniger Hauptspeicher benötigen, während ihre Inhalte bei der Abfrageausführung aktiv verarbeitet werden. Auch die Indizierung ist weniger ressourcenbeanspruchend, wenn sie an schmaleren Spalten vorgenommen wird.

MySQL unterstützt viele verschiedene Speicher-Engines (Tabellentypen) und Datensatzformate. Für jede Tabelle können Sie neu entscheiden, welche Speicher- und Indizierungsmethode verwendet werden soll. Die Auswahl des für Ihre Anwendung geeigneten Tabellenformats kann Ihnen einen erheblichen Performancezuwachs bringen. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

Sie können die Leistungsfähigkeit Ihrer Tabellen optimieren und den Speicherbedarf minimieren, indem Sie die folgenden Methoden benutzen:

  • Verwenden Sie den jeweils effizientesten (d. h. kleinstmöglichen) Datentyp. MySQL bietet viele Spezialtypen, mit denen sich Festplatten- und Arbeitsspeicher einsparen lassen. Setzen Sie beispielsweise möglichst die kleineren Integer-Typen ein, um kleinere Tabellen zu erhalten. MEDIUMINT ist häufig besser geeignet als INT, weil eine MEDIUMINT-Spalte 25 Prozent weniger Platz benötigt.

  • Wenn möglich, deklarieren Sie Spalten als NOT NULL. Hierdurch wird alles schneller, und Sie sparen ein Bit je Spalte. Wenn Sie NULL in Ihrer Anwendung wirklich benötigen, sollten Sie es natürlich benutzen; Sie sollten lediglich verhindern, dass alle Spalten vorgabeseitig so eingestellt sind.

  • Wenn Ihre MyISAM-Tabellen keine Spalten variabler Länge (VARCHAR, TEXT oder BLOB) enthalten, wird ein festes Datensatzformat verwendet. Dieses ist schneller, kann allerdings mehr Platz beanspruchen. Siehe auch Abschnitt 14.1.3, „MyISAM-Tabellenformate“. Sie können mit der Option ROW_FORMAT=FIXED für CREATE TABLE angeben, dass Sie Datensätze fester Länge verwenden wollen, auch wenn VARCHAR-Spalten vorhanden sind.

  • InnoDB-Tabellen verwenden ein kompaktes Speicherformat. In Versionen vor MySQL 5.0.3 enthalten InnoDB-Datensätze einige redundante Informationen, z. B. die Anzahl und die Längen der einzelnen Spalten (und zwar auch bei Spalten fester Größe). Standardmäßig werden Tabellen im kompakten Format erstellt (ROW_FORMAT=COMPACT). Wenn Sie ein Downgrade auf eine ältere MySQL-Version durchführen wollen, können Sie das alte Format mit ROW_FORMAT=REDUNDANT anfordern.

    Das kompakte InnoDB-Format ändert auch die Art und Weise, wie CHAR-Spalten, die Daten im UTF-8-Format enthalten, gespeichert werden. Bei ROW_FORMAT=REDUNDANT belegt eine Spalte CHAR(N) im UTF-8-Format 3 × N Byte (davon ausgehend, dass die maximale Länge eines UTF-8-kodierten Zeichens drei Byte beträgt). Viele Sprachen können vorwiegend mit UTF-8-Zeichen geschrieben werden, die nur ein Byte umfassen, weswegen eine feste Speicherlänge häufig Platzverschwendung ist. Beim ROW_FORMAT=COMPACT-Format reserviert InnoDB eine variable Speichermenge im Bereich zwischen N und 3 × N Byte für diese Spalten, indem Leerzeichen am Ende nach Bedarf abgeschnitten werden. Die Mindestspeichergröße wird als N Byte vermerkt, um in typischen Fällen interne Updates durchführen zu können.

  • Der Primärindex einer Tabelle sollte so kurz wie möglich sein. Dies macht die Identifizierung eines Datensatzes einfach und effizient.

  • Erstellen Sie nur Indizes, die Sie auch wirklich benötigen. Indizes sind praktisch, um Daten abzurufen, aber von Nachteil, wenn Sie Daten schnell speichern müssen. Wenn Sie auf eine Tabelle in erster Linie durch das Durchsuchen einer Kombination von Spalten zugreifen, dann erstellen Sie für diese Kombination einen Index. Der erste Teil des Indexes sollte die meistverwendete Spalte sein. Wenn Sie beim Auswählen aus der Tabelle immer viele Spalten verwenden, sollten Sie die Spalte benutzen, die mehr Dubletten aufweist, damit der Index besser komprimiert werden kann.

  • Wenn es sehr wahrscheinlich ist, dass eine String-Spalte ein eindeutiges Präfix innerhalb der ersten paar Zeichen aufweist, dann ist es besser, nur dieses Präfix zu indizieren. Hierzu verwenden Sie die MySQL-Funktionalität zur Erstellung eines Indexes aus dem linken Teil der Spalte (siehe Abschnitt 13.1.4, „CREATE INDEX). Kürzere Indizes sind nicht nur deswegen schneller, weil sie weniger Festplattenkapazität benötigen, sondern auch, weil sie auf diese Weise mehr Treffer im Index-Cache erhalten (d. h., es sind weniger Suchvorgänge auf der Festplatte erforderlich). Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

  • Unter manchen Umständen kann es von Vorteil sein, eine Tabelle, die sehr häufig gescannt wird, in zwei Tabellen aufzutrennen. Dies gilt insbesondere, wenn es sich um eine Tabelle im dynamischen Format handelt und es möglich ist, dass eine kleinere statische Tabelle entsteht, die beim Scannen der Tabelle zum Auffinden der gewünschten Datensätze benutzt werden kann.

7.4.3. Spaltenindizes

Alle MySQL-Datentypen lassen sich indizieren. Die Verwendung von Indizes der relevanten Spalten ist die beste Möglichkeit, die Leistung von SELECT-Operationen zu optimieren.

Die maximale Anzahl von Indizes pro Tabelle und die maximale Indexlänge werden durch die verwendete Speicher-Engine bestimmt. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen. Alle Speicher-Engines unterstützen mindestens 16 Indizes pro Tabelle und eine Indexgesamtlänge von mindestens 256 Byte. Bei den meisten Speicher-Engines liegen die Grenzen höher.

Mit der Syntax col_name(N) in einer Indexdefinition können Sie einen Index erstellen, der nur die ersten N Zeichen einer String-Spalte verwendet. Wenn Sie auf diese Weise nur ein Präfix der Spaltenwerte indizieren, kann dies die Indexdatei erheblich kleiner machen. Bei der Indizierung einer BLOB- oder TEXT-Spalte müssen Sie eine Präfixlänge für den Index angeben. Zum Beispiel:

CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));

Präfixe können bis zu 1.000 Byte lang sein (767 Byte bei InnoDB-Tabellen). Beachten Sie, dass Präfixbeschränkungen in Byte angegeben werden, wohingegen die Präfixlänge in CREATE TABLE-Anweisungen als Anzahl der Zeichen interpretiert wird. Dies muss bei der Angabe einer Präfixlänge für eine Spalte, die einen Multibytezeichensatz verwendet, in jedem Fall berücksichtigt werden.

Sie können außerdem FULLTEXT-Indizes erstellen. Diese werden für die Volltextsuche verwendet. Nur die MyISAM-Speicher-Engine unterstützt FULLTEXT-Indizes, und auch nur für CHAR-, VARCHAR- und TEXT-Spalten. Die Indizierung erfolgt stets über die gesamte Spalte – eine Teilindizierung (Spaltenpräfix) wird nicht unterstützt. Detaillierte Informationen finden Sie in Abschnitt 12.7, „MySQL-Volltextsuche“.

Sie können auch Indizes für raumbezogene Typen erstellen. Derzeit unterstützt nur MyISAM R-Tree-Indizes für raumbezogene Typen. Andere Speicher-Engines verwenden B-Trees zur Indizierung raumbezogener Typen. (Ausnahmen sind lediglich ARCHIVE und NDBCLUSTER, die überhaupt keine raumbezogene Indizierung unterstützen.)

Die MEMORY-Engine verwendet standardmäßig HASH-Indizes, unterstützt aber auch BTREE-Indizes.

7.4.4. Mehrspaltige Indizes

MySQL kann zusammengesetzte Indizes erstellen (d. h. Indizes über mehrere Spalten). Ein Index kann bis zu 15 Spalten umfassen. Bei bestimmten Datentypen können Sie ein Präfix der Spalte indizieren (siehe Abschnitt 7.4.3, „Spaltenindizes“).

Ein mehrspaltiger Index kann als sortiertes Array betrachtet werden, das Werte enthält, die durch Verkettung der Werte der indizierten Spalten entstanden sind.

MySQL verwendet mehrspaltige Indizes derart, dass Abfragen schnell sind, wenn Sie einen bekannten Teil der ersten Spalte des Indexes in einer WHERE-Klausel angeben – und zwar auch dann, wenn Sie keine Werte für andere Spalten angeben.

Angenommen, eine Tabelle habe die folgende Spezifikation:

CREATE TABLE test (
    id INT NOT NULL,
    last_name CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name,first_name)
);

Der Index name ist ein Index über die Spalten last_name und first_name. Der Index kann für Abfragen, die Werte in einem bekannten Bereich für last_name angeben, oder sowohl für last_name als auch für first_name verwendet werden. Aus diesem Grund wird der Index name in den folgenden Abfragen benutzt:

SELECT * FROM test WHERE last_name='Widenius';

SELECT * FROM test
  WHERE last_name='Widenius' AND first_name='Michael';

SELECT * FROM test
  WHERE last_name='Widenius'
  AND (first_name='Michael' OR first_name='Monty');

SELECT * FROM test
  WHERE last_name='Widenius'
  AND first_name >='M' AND first_name < 'N';

Im Gegensatz dazu wird der Index name in den folgenden Abfragen nicht benutzt:

SELECT * FROM test WHERE first_name='Michael';

SELECT * FROM test
  WHERE last_name='Widenius' OR first_name='Michael';

Die Art und Weise, wie MySQL Indizes zur Verbesserung der Abfrageleistung verwendet, wird in Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“, näher beschrieben.

7.4.5. Wie MySQL Indizes benutzt

Indizes werden verwendet, um schnell Datensätze mit bestimmten Spaltenwerten zu finden. Ohne Index müsste MySQL mit der Suche beim ersten Datensatz beginnen und dann die gesamte Tabelle nach passenden Datensätzen durchforsten. Je größer die Tabelle, desto höher sind die Kosten dafür. Wenn die Tabelle einen Index für die fraglichen Spalten aufweist, kann MySQL die Position in der Mitte der Datendatei, an der die Suche beginnen soll, schnell bestimmen, ohne alle Daten in der Datei überprüfen zu müssen. Wenn eine Tabelle 1.000 Datensätze hat, ist dies mindestens hundertmal schneller als ein sequenzielles Lesen. Wenn Sie hingegen auf die meisten Datensätze zugreifen müssen, ist das sequenzielle Lesen schneller, weil die Anzahl der Festplattenzugriffe geringer ist.

Die meisten MySQL-Indizes (PRIMARY KEY, UNIQUE, INDEX und FULLTEXT) sind in B-Trees gespeichert. Zu erwähnende Ausnahmen sind, dass Indizes für raumbezogene Datentypen R-Typen verwenden und MEMORY-Tabellen auch Hash-Indizes unterstützen.

Strings werden automatisch präfixkomprimiert; Gleiches gilt für Leerzeichen am Ende des Strings. Siehe auch Abschnitt 13.1.4, „CREATE INDEX.

Generell werden Indizes wie nachfolgend beschrieben verwendet. Die spezifischen Eigenschaften von Hash-Indizes, die in Verbindung mit MEMORY-Tabellen verwendet werden, werden am Ende dieses Abschnitts erläutert.

MySQL verwendet Indizes für die folgenden Operationen:

  • Zum schnellen Auffinden von Datensätzen, die der WHERE-Klausel entsprechen.

  • Zum Ignorieren bestimmter Datensätze. Wenn mehrere Indizes vorhanden sind, verwendet MySQL normalerweise denjenigen, der die kleinste Anzahl von Datensätzen findet.

  • Zum Abrufen von Datensätzen aus anderen Tabellen bei der Durchführung von Joins.

  • Zum Auffinden des MIN()- oder MAX()-Werts für eine bestimmte indizierte Spalte key_col. Dies wird mit einem Vorprozessor optimiert, der überprüft, ob Sie WHERE key_part_N = constant für alle Schlüsselteile verwenden, die im Index vor key_col erscheinen. In diesem Fall führt MySQL eine einfache Schlüsselsuche nach jedem MIN()- oder MAX()-Ausdruck durch und ersetzt ihn durch eine Konstante. Wenn alle Ausdrücke durch Konstanten ersetzt werden konnten, wird die Abfrage umgehend abgeschlossen. Zum Beispiel:

    SELECT MIN(key_part2),MAX(key_part2)
      FROM tbl_name WHERE key_part1=10;
    
  • Zum Sortieren oder Gruppieren einer Tabelle, sofern das Sortieren bzw. Gruppieren auf der Basis des linken Präfixes eines verwendbaren Schlüssels erfolgt (z. B. ORDER BY key_part1, key_part2). Wenn auf alle Schlüsselteile DESC folgt, wird der Schlüssel in umgekehrter Reihenfolge gelesen. Siehe auch Abschnitt 7.2.12, „ORDER BY-Optimierung“.

  • In manchen Fällen kann eine Abfrage so optimiert werden, dass sie Werte abruft, ohne die eigentlichen Datensätze zu untersuchen. Wenn eine Abfrage nur Spalten einer Tabelle verwendet, die numerisch sind und bei einem Schlüssel ein linkes Präfix bilden, dann können die ausgewählten Werte auch aus dem Indexbaum abgerufen werden, was deutlich schneller ist:

    SELECT key_part3 FROM tbl_name 
      WHERE key_part1=1
    

Nehmen wir an, dass Sie folgende SELECT-Anweisung absetzen:

mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;

Wenn für col1 und col2 ein mehrspaltiger Index vorhanden ist, können die entsprechenden Datensätze direkt abgerufen werden. Sind separate einspaltige Indizes für col1 und col2 vorhanden, dann versucht der Optimierer, den restriktivsten Index zu ermitteln, indem er überprüft, welcher Index weniger Spalten findet; dieser Index wird dann zum Abrufen von Datensätzen benutzt.

Wenn die Tabelle einen mehrspaltigen Index aufweist, kann ein beliebiges linkes Präfix des Indexes vom Optimierer zum Suchen von Datensätzen verwendet werden. Haben Sie beispielsweise einen dreispaltigen Index für (col1, col2, col3), dann bietet dieser Suchfunktionalität für (col1), (col1, col2) und (col1, col2, col3).

MySQL kann keinen Teilindex verwenden, wenn die Spalten kein linkes Präfix für den Index bilden. Betrachten Sie einmal die folgenden SELECT-Anweisungen:

SELECT * FROM tbl_name WHERE col1=val1;
SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;

SELECT * FROM tbl_name WHERE col2=val2;
SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;

Wenn ein Index für (col1, col2, col3) vorhanden ist, verwenden diese nur die ersten beiden Abfragen. Die dritte und die vierte Abfrage beziehen sich zwar auf indizierte Spalten, aber (col2) und (col2, col3) sind keine linken Präfixe von (col1, col2, col3).

Ein B-Tree-Index kann für Spaltenvergleiche in Ausdrücken benutzt werden, die die Operatoren =, >, >=, <, <= oder BETWEEN verwenden. Der Index kann auch für LIKE-Vergleiche benutzt werden, wenn das Argument zu LIKE ein Konstanten-String ist, der nicht mit einem Jokerzeichen beginnt. Die folgenden SELECT-Anweisungen verwenden beispielsweise Indizes:

SELECT * FROM tbl_name WHERE key_col LIKE 'Patrick%';
SELECT * FROM tbl_name WHERE key_col LIKE 'Pat%_ck%';

In der ersten Anweisung werden nur Datensätze mit 'Patrick' <= key_col< 'Patricl' berücksichtigt. In der zweiten Anweisung werden nur Datensätze mit 'Pat' <= key_col< 'Pau' berücksichtigt.

Die folgenden SELECT-Anweisungen verwenden keine Indizes:

SELECT * FROM tbl_name WHERE key_col LIKE '%Patrick%';
SELECT * FROM tbl_name WHERE key_col LIKE other_col;

In der ersten Anweisung beginnt der Wert LIKE mit einem Jokerzeichen. In der zweiten Anweisung ist der LIKE-Wert keine Konstante.

Wenn Sie … LIKE '%string%' verwenden und string mehr als drei Zeichen umfasst, verwendet MySQL den Turbo-Boyer-Moore-Algorithmus zur Initialisierung des Musters für den String; mit diesem Muster wird die Suche dann schneller durchgeführt.

Eine Suche unter Verwendung von col_name IS NULL setzt Indizes ein, wenn col_name indiziert ist.

Ein Index, der nicht alle AND-Ebenen in der WHERE-Klausel einbezieht, wird nicht zur Optimierung der Abfrage benutzt. Um also einen Index verwenden zu können, muss in jeder AND-Gruppe ein Präfix des Indexes benutzt werden.

Die folgenden WHERE-Klauseln verwenden Indizes:

... WHERE index_part1=1 AND index_part2=2 AND other_column=3
    /* index = 1 OR index = 2 */
... WHERE index=1 OR A=10 AND index=2
    /* optimized like "index_part1='hello'" */
... WHERE index_part1='hello' AND index_part3=5
    /* Can use index on index1 but not on index2 or index3 */
... WHERE index1=1 AND index2=2 OR index1=3 AND index3=3;

Die folgenden WHERE-Klauseln verwenden Indizes nicht:

    /* index_part1 is not used */
... WHERE index_part2=1 AND index_part3=2

    /*  Index is not used in both parts of the WHERE clause  */
... WHERE index=1 OR A=10

    /* No index spans all rows  */
... WHERE index_part1=1 OR index_part2=10

Manchmal verwendet MySQL auch dann keinen Index, wenn ein solcher vorhanden ist. Ein Umstand, unter dem dies geschieht, liegt vor, wenn der Optimierer der Ansicht ist, dass MySQL bei Verwendung eines Indexes auf einen sehr großen Anteil der Datensätze in der Tabelle zugreifen muss. (In diesem Fall ist ein Tabellenscan mit hoher Wahrscheinlichkeit schneller, weil weniger Suchvorgänge erforderlich sind.) Wenn eine solche Abfrage jedoch dank einer LIMIT-Klausel nur ein paar Datensätze abruft, verwendet MySQL trotzdem einen Index, da sich die Datensätze, die zum Ergebnis gehören, auf diese Weise schneller finden lassen.

Hash-Indizes weisen etwas andere Eigenschaften auf als die soeben beschriebenen:

  • Sie werden nur zu Vergleichen verwendet, die die Operatoren = oder <=> benutzen (aber sie sind extrem schnell). Nicht verwendet werden sie für Vergleiche mit <, bei denen ein Wertebereich gefunden wird.

  • Der Optimierer kann einen Hash-Index nicht zur Beschleunigung von ORDER BY-Operationen verwenden. (Dieser Indextyp kann nicht zur Suche nach dem nächsten Eintrag in der Reihenfolge benutzt werden.)

  • MySQL kann nicht näherungsweise bestimmen, wie viele Datensätze zwischen zwei Werten vorhanden sind (diese Angabe verwendet der Bereichsoptimierer für die Entscheidung, welchen Index er verwenden soll). Dies kann sich auf einige Abfragen auswirken, wenn Sie eine MyISAM-Tabelle in eine MEMORY-Tabelle mit einem Hash-Index konvertieren.

  • Nur vollständige Schlüssel können zur Suche nach einem Datensatz benutzt werden. (Bei einem B-Tree-Index kann dagegen ein beliebiges linkes Präfix des Schlüssels zum Suchen von Datensätzen eingesetzt werden.)

7.4.6. Der MyISAM-Schlüssel-Cache

Um die Festplattenzugriffe zu minimieren, verwendet die MyISAM-Speicher-Engine eine Strategie, auf der zahlreiche Datenbanksysteme basieren. Sie benutzt einen Cache-Mechanismus, um die am häufigsten abgerufenen Tabellenblöcke im Speicher zu halten:

  • Für Indexblöcke wird eine spezielle Struktur namens Schlüssel-Cache (oder Schlüsselpuffer) implementiert. Diese Struktur enthält eine Anzahl von Blockpuffern, in denen die meistverwendeten Indexblöcke abgelegt werden.

  • Für Datenblöcke verwendet MySQL keinen speziellen Cache. Stattdessen wird der Dateisystem-Cache des nativen Betriebssystems benutzt.

Dieser Abschnitt beschreibt zunächst den grundlegenden Betrieb des MyISAM-Schlüssel-Caches. Nachfolgend werden Funktionen erläutert, die die Leistungsfähigkeit des Schlüssel-Caches optimieren und mit denen Sie den Cache-Betrieb besser steuern können:

  • Mehrere Threads können gleichzeitig auf den Cache zugreifen.

  • Sie können mehrere Schlüssel-Caches einrichten und Tabellenindizes speziellen Caches zuweisen.

Die Größe des Schlüssel-Caches stellen Sie mit der Systemvariablen key_buffer_size ein. Wenn diese Variable auf null gesetzt ist, wird kein Cache verwendet. Der Schlüssel-Cache wird ferner nicht benutzt, wenn der Wert key_buffer_size zu klein ist, um die Mindestanzahl von Blockpuffern (8) zu reservieren.

Wenn der Schlüssel-Cache nicht betriebsbereit ist, erfolgt der Zugriff auf Indexdateien nur über die Puffer des nativen Dateisystems, die vom Betriebssystem bereitgestellt werden. (Anders gesagt, wird auf Tabellenindexblöcke unter Verwendung derselben Methode zugegriffen wie auf Tabellendatenblöcke.)

Ein Indexblock ist eine zusammenhängende Zugriffseinheit für MyISAM-Indexdateien. Normalerweise entspricht die Größe eines Indexblocks der Größe der Knoten des B-Trees. (Indizes werden auf der Festplatte mit einer B-Tree-Datenstruktur dargestellt. Knoten am unteren Ende des Trees sind Blattknoten, Knoten oberhalb der Blätter Nichtblattknoten.)

Alle Blockpuffer in einer Schlüssel-Cache-Struktur haben dieselbe Größe. Diese Größe kann der Größe eines Tabellenindexblocks entsprechen, sie kann aber auch höher oder niedriger sein. Normalerweise ist einer dieser beiden Werte ein Vielfaches des anderen.

Wenn ein Zugriff auf Daten aus einem Tabellenindexblock erfolgen muss, dann überprüft der Server zunächst, ob er in einem Blockpuffer des Schlüssel-Caches vorhanden ist. Ist dies der Fall, dann greift der Server auf die Daten im Schlüssel-Cache statt auf der Festplatte zu: Er liest aus und/oder schreibt in den Cache statt auf die Festplatte. Andernfalls wählt der Server einen Cache-Blockpuffer, der einen oder mehrere andere Tabellenindexblöcke enthält, und ersetzt die dortigen Daten durch eine Kopie des erforderlichen Tabellenindexblocks. Sobald der neue Indexblock sich im Cache befindet, kann auf die Indexdaten zugegriffen werden.

Wenn ein für die Ersetzung gewählter Block modifiziert wurde, wird dieser als „schmutzig“ bezeichnet. In diesem Fall wird der Inhalt vor der Ersetzung in den Tabellenindex geschrieben, von dem er kam.

Normalerweise verwendet der Server eine LRU-Strategie (Least Recently Used): Wenn ein Block zur Ersetzung gewählt werden muss, entscheidet er sich für den Indexblock, der am längsten nicht mehr verwendet wurde. Um die Auswahl zu erleichtern, unterhält das Schlüssel-Cache-Modul eine spezielle Warteschlange (die LRU-Kette) mit allen verwendeten Blöcken. Wenn auf einen Block zugegriffen wird, wird er ans Ende der Warteschlange gesetzt. Müssen Blöcke ersetzt werden, dann sind die Blöcke am Anfang der Warteschlange die am längsten nicht verwendeten und werden infolgedessen als Erste geräumt.

7.4.6.1. Zugriff auf den gemeinsam verwendeten Schlüsselspeicher

Threads können gleichzeitig auf Schlüssel-Cache-Puffer zugreifen. Dabei ist Folgendes zu beachten:

  • Ein Puffer kann von mehreren Threads benutzt werden, sofern er derzeit nicht aktualisiert wird.

  • Wenn ein Puffer gerade aktualisiert wird, müssen Threads, die ihn verwenden wollen, warten, bis das Update abgeschlossen ist.

  • Mehrere Threads können Anfragen erzeugen, die zu Ersetzungen im Cache-Block führen können, solange sie sich nicht gegenseitig stören (d. h. solange sie verschiedene Indexblöcke benötigen und insofern auch verschiedene Cache-Blöcke ersetzt werden).

Der gemeinsame Zugriff auf den Schlüssel-Cache ermöglicht dem Server eine erhebliche Verbesserung des Durchsatzes.

7.4.6.2. Mehrfache Index-Caches

Der gemeinsame Zugriff auf den Schlüssel-Cache verbessert die Leistung, beseitigt das Problem des gleichzeitigen Zugriffs durch mehrere Threads aber nicht vollständig. Diese wetteifern weiterhin um Steuerstrukturen, mit denen der Zugriff auf die Schlüssel-Cache-Puffer verwaltet wird. Um also die Rivalität um den Schlüssel-Cache-Zugriff weiter zu verringern, stellt MySQL zusätzlich mehrere Schlüssel-Caches bereit. Diese Funktion erlaubt es Ihnen, verschiedenen Schlüssel-Caches unterschiedliche Tabellenindizes zuzuweisen.

Wenn mehrere Schlüssel-Caches vorhanden sind, muss der Server wissen, welchen Cache er bei der Verarbeitung von Abfragen für eine gegebene MyISAM-Tabelle verwenden soll. Standardmäßig werden alle MyISAM-Tabellenindizes im vorgabeseitigen Schlüssel-Cache zwischengespeichert. Um Tabellenindizes einem bestimmten Schlüssel-Cache zuzuweisen, verwenden Sie die Anweisung CACHE INDEX (siehe Abschnitt 13.5.5.1, „CACHE INDEX). Die folgende Anweisung beispielsweise weist Indizes der Tabellen t1, t2 und t3 dem Schlüssel-Cache namens hot_cache zu:

mysql> CACHE INDEX t1, t2, t3 IN hot_cache;
+---------+--------------------+----------+----------+
| Table   | Op                 | Msg_type | Msg_text |
+---------+--------------------+----------+----------+
| test.t1 | assign_to_keycache | status   | OK       |
| test.t2 | assign_to_keycache | status   | OK       |
| test.t3 | assign_to_keycache | status   | OK       |
+---------+--------------------+----------+----------+

Der in der CACHE INDEX-Anweisung referenzierte Schlüssel-Cache kann erstellt werden, indem seine Größe mit einer SET GLOBAL-Anweisung zur Parametereinstellung oder in den Startoptionen des Servers angegeben wird. Zum Beispiel:

mysql> SET GLOBAL keycache1.key_buffer_size=128*1024;

Um einen Schlüssel-Cache zu beseitigen, setzen Sie seine Größe auf null:

mysql> SET GLOBAL keycache1.key_buffer_size=0;

Beachten Sie, dass Sie den vorgabeseitigen Schlüssel-Cache nicht zerstören können. Alle diesbezüglichen Versuche werden ignoriert:

mysql> SET GLOBAL key_buffer_size = 0;

mysql> show variables like 'key_buffer_size';
+-----------------+---------+
| Variable_name   | Value   |
+-----------------+---------+
| key_buffer_size | 8384512 |
+-----------------+---------+

Schlüssel-Cache-Variablen sind strukturierte Systemvariablen, die einen Namen und Komponenten aufweisen. Bei keycache1.key_buffer_size etwa ist keycache1 der Cache-Variablenname und key_buffer_size die Cache-Komponente. Eine Beschreibung der Syntax zur Referenzierung strukturierter Systemvariablen für den Schlüssel-Cache finden Sie in Abschnitt 5.2.3.1, „Strukturierte Systemvariablen“.

Standardmäßig werden Tabellenindizes dem vorgabeseitigen Schlüssel-Cache (Haupt-Schlüssel-Cache) zugewiesen, der beim Serverstart erstellt wird. Wird ein Schlüssel-Cache zerstört, dann werden alle ihm zugewiesenen Indizes wieder dem Standard-Schlüssel-Cache zugewiesen.

Für einen gut ausgelasteten Server empfehlen wir eine Strategie mit drei Schlüssel-Caches:

  • Ein „heißer“ Schlüssel-Cache, der 20 Prozent des für alle Schlüssel-Caches reservierten Speichers verwendet. Diesen setzen Sie für Tabellen ein, in denen sehr viele Suchvorgänge, aber keine Änderungen erfolgen.

  • Ein „kalter“ Schlüssel-Cache, der weitere 20 Prozent des für alle Schlüssel-Caches reservierten Speichers verwendet. Dieser Cache unterstützt mittelgroße, häufig geänderte Tabellen (z. B. Temporärtabellen).

  • Ein „warmer“ Schlüssel-Cache, der die verbleibenden 60 Prozent des Schlüssel-Cache-Speichers belegt. Diesen verwenden Sie als vorgabeseitigen Schlüssel-Cache, der standardmäßig von allen anderen Tabellen benutzt wird.

Ein Grund dafür, warum die Verwendung dreier Schlüssel-Caches von Vorteil ist, besteht darin, dass der Zugriff auf eine Schlüssel-Cache-Struktur den Zugriff auf die anderen nicht behindert. Anweisungen, die auf Tabellen zugreifen, die dem einen Cache zugewiesen sind, konkurrieren nicht mit Anweisungen, deren referenzierte Tabellen auf einen anderen Cache zugreifen. Ein Leistungsgewinn wird aber auch aus anderen Gründen erzielt:

  • Der heiße Cache wird nur für anfordernde Abfragen verwendet, d. h., sein Inhalt ändert sich nicht. Dies bedeutet, dass, wann immer ein Indexblock von der Festplatte abgerufen werden muss, der Inhalt des für die Ersetzung gewählten Cache-Blocks nicht zuerst synchronisiert werden muss.

  • Ist ein Index dem heißen Cache zugewiesen, dann ist, wenn keine Abfragen kommen, die einen Indexscan erfordern, die Wahrscheinlichkeit hoch, dass die Indexblöcke, die den Nichtblattknoten des B-Trees entsprechen, im Cache verbleiben.

  • Ein Updatevorgang, wie er am häufigsten für Temporärtabellen vorgenommen wird, wird wesentlich schneller durchgeführt, wenn der geänderte Knoten sich im Cache befindet und nicht erst von der Festplatte gelesen werden muss. Wenn die Größe der Indizes der Temporärtabellen mit der Größe des kalten Schlüssel-Caches vergleichbar ist, dann ist die Wahrscheinlichkeit, dass der aktualisierte Knoten sich im Cache befindet, extrem hoch.

CACHE INDEX richtet eine Verknüpfung zwischen einer Tabelle und einem Schlüssel-Cache ein, die jedoch nur bis zum nächsten Serverneustart bestehen bleibt. Wenn diese Verknüpfung jedes Mal, wenn der Server neu startet, erstellt werden soll, können Sie dies etwa mit einer Optionsdatei erreichen: Setzen Sie Variableneinstellungen, mit denen Ihre Schlüssel-Caches konfiguriert werden, und eine Option namens init-file in die Optionsdatei, die eine Datei bezeichnet, welche die auszuführenden CACHE INDEX-Anweisungen enthält. Zum Beispiel:

key_buffer_size = 4G
hot_cache.key_buffer_size = 2G
cold_cache.key_buffer_size = 2G
init_file=/path/to/data-directory/mysqld_init.sql

Die Anweisungen in mysqld_init.sql werden bei jedem Start des Servers ausgeführt. Die Datei sollte eine SQL-Anweisung pro Zeile enthalten. Das folgende Beispiel weist verschiedene Tabellen jeweils hot_cache und cold_cache zu:

CACHE INDEX db1.t1, db1.t2, db2.t3 IN hot_cache
CACHE INDEX db1.t4, db2.t5, db2.t6 IN cold_cache

7.4.6.3. Strategie des Einfügens am Mittelpunkt

Standardmäßig verwendet das System zur Schlüssel-Cache-Verwaltung die LRU-Strategie zur Auswahl der zu räumenden Schlüssel-Cache-Blöcke, unterstützt aber auch eine komplexere Methode namens Strategie des Einfügens am Mittelpunkt.

Bei Verwendung dieser Strategie wird die LRU-Kette in zwei Teile aufgeteilt: eine heiße Unterkette und eine warme Unterkette. Der Trennpunkt zwischen diesen beiden Teilen ist nicht fest, sondern das Schlüssel-Cache-Verwaltungssystem achtet darauf, dass der warme Teil nicht „zu klein“ wird und immer mindestens key_cache_division_limit Prozent der Schlüssel-Cache-Blöcke enthält. key_cache_division_limit ist eine Komponente der strukturierten Schlüssel-Cache-Variablen, d. h., ihr Wert ist ein Parameter, der pro Cache eingestellt werden kann.

Wenn ein Indexblock aus einer Tabelle in den Schlüssel-Cache eingelesen wird, wird er an das Ende der warmen Unterkette gesetzt. Nach einer bestimmten Anzahl von Treffern (d. h. von Zugriffen auf den Block) wird er in die heiße Unterkette hochgestuft. Zurzeit ist die Anzahl der für das Hochstufen eines Blocks erforderlichen Treffer für alle Indexblöcke gleich (nämlich 3).

Ein Block, der in die heiße Unterkette hochgestuft wurde, wird an das Ende der Kette gesetzt. Der Block kreist dann innerhalb dieser Unterkette. Bleibt der Block lang genug am Anfang der Unterkette, dann wird er in die warme Unterkette zurückgestuft. Der Zeitpunkt wird vom Wert der Schlüssel-Cache-Komponente key_cache_age_threshold bestimmt.

Der Schwellwert definiert, dass bei einem Schlüssel-Cache mit N Blöcken der am Anfang der heißen Unterkette stehende Block an den Anfang der warmen Unterkette gesetzt wird, sofern er nicht innerhalb der letzten N× key_cache_age_threshold / 100 Treffer aufgerufen wurde. Er wird dann erster Anwärter auf die Räumung, weil für die Ersetzung vorgesehene Blöcke am Anfang der warmen Unterkette entfernt werden.

Die Strategie des Einfügens am Mittelpunkt gestattet Ihnen, Blöcke, die offensichtlich wichtig sind, immer im Cache zu behalten. Wenn Sie die direkte LRU-Strategie bevorzugen, belassen Sie den Wert von key_cache_division_limit auf der Vorgabe von 100.

Die Strategie des Einfügens am Mittelpunkt ist hilfreich zur Leistungssteigerung, wenn die Ausführung einer Abfrage einen Indexscan erfordert und so im Endeffekt all diejenigen Indexblöcke aus dem Cache wirft, die wichtigen B-Tree-Knoten entsprechen. Um dies zu vermeiden, müssen Sie die Strategie mit einem Wert von deutlich weniger als 100 für key_cache_division_limit verwenden, denn so werden „wertvolle“, häufig gefundene Knoten auch bei einem Indexscan in der heißen Unterkette gehalten.

7.4.6.4. Vorladen von Indizes (Preloading)

Sind genug Blöcke in einem Schlüssel-Cache vorhanden, um die Blöcke eines vollständigen Indexes – oder zumindest die Blöcke, die den Nichtblattknoten entsprechen – aufzunehmen, dann ist es sinnvoll, den Schlüssel-Cache mit den Indexblöcken schon vor der eigentlichen Verwendung vorab zu laden. Dieses Vorabladen gestattet es Ihnen, die Tabellenindexblöcke auf effizienteste Art und Weise in einem Schlüssel-Cache-Puffer abzulegen – nämlich durch sequenzielles Lesen der Indexblöcke von der Festplatte.

Ohne Vorabladen werden die Blöcke so im Schlüssel-Cache abgelegt, wie sie von den Abfragen benötigt werden. Zwar bleiben die Blöcke dann im Cache, weil genug Puffer für sie alle vorhanden sind, aber sie werden dann nicht sequenziell, sondern in zufälliger Abfolge von der Festplatte abgerufen.

Um einen Index vorab in einen Cache zu laden, verwenden Sie die Anweisung LOAD INDEX INTO CACHE. Die folgende Anweisung beispielsweise lädt Knoten (Indexblöcke) mit Indizes der Tabellen t1 und t2:

mysql> LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
+---------+--------------+----------+----------+
| Table   | Op           | Msg_type | Msg_text |
+---------+--------------+----------+----------+
| test.t1 | preload_keys | status   | OK       |
| test.t2 | preload_keys | status   | OK       |
+---------+--------------+----------+----------+

Der Modifizierer IGNORE LEAVES bewirkt, dass nur Blöcke für Indexknoten, die nicht Endknoten (Blätter) sind, geladen werden. Auf diese Weise lädt die gezeigte Anweisung alle Indexblöcke von t1, von t2 hingegen nur Blöcke für die Nichtblattknoten.

Wenn ein Index mit einer CACHE INDEX-Anweisung einem Schlüssel-Cache zugewiesen wurde, platziert das Vorabladen die Indexblöcke in diesem Cache. Andernfalls wird der Index in den vorgabeseitigen Schlüssel-Cache geladen.

7.4.6.5. Blockgröße des Index-Caches

Mit der Variablen key_cache_block_size ist es möglich, die Größe von Blockpuffern für einen einzelnen Schlüssel-Cache anzugeben. Auf diese Weise können Sie die Leistung von I/O-Operationen für Indexdateien optimieren.

Die beste Leistung für I/O-Operationen erhalten Sie, wenn die Größe der Lesepuffer der Größe der I/O-Puffer des nativen Betriebssystems entspricht. Allerdings gewährleistet das Einstellen der Schlüsselknotengröße auf die Größe der I/O-Puffer nicht immer die beste Gesamtperformance. Wenn der Server die großen Blattknoten ausliest, ruft er eine Menge unnötiger Daten ab, wodurch im Endeffekt das Lesen anderer Blattknoten verhindert wird.

Zurzeit lässt sich die Größe der Indexblöcke in einer Tabelle nicht steuern. Der Größenwert wird vom Server eingestellt, wenn die .MYI-Indexdatei erstellt wird, und hängt von der Größe der Schlüssel in den in der Tabellendefinition vorhandenen Indizes ab. In den meisten Fällen ist sie identisch mit der I/O-Puffergröße.

7.4.6.6. Restrukturierung eines Index-Caches

Ein Schlüssel-Cache kann jederzeit durch Änderung seiner Parameterwerte umstrukturiert werden. Zum Beispiel:

mysql> SET GLOBAL cold_cache.key_buffer_size=4*1024*1024;

Wenn Sie den Schlüssel-Cache-Komponenten key_buffer_size oder key_cache_block_size einen anderen als den aktuellen Wert zuweisen, zerstört der Server die alte Struktur des Caches und erstellt eine neue, die auf den geänderten Werten basiert. Wenn der Cache schmutzige Blöcke enthält, speichert der Server sie auf der Festplatte, bevor er den Cache zerstört und neu erstellt. Eine Umstrukturierung findet hingegen nicht statt, wenn Sie andere Schlüssel-Cache-Parameter einstellen.

Wenn Sie einen Schlüssel-Cache umstrukturieren, synchronisiert der Server zunächst die Inhalte schmutziger Puffer (soweit vorhanden) auf die Festplatte. Danach ist der Inhalt des Caches nicht mehr verfügbar. Allerdings blockiert die Umstrukturierung keine Abfragen, die dem Cache zugewiesene Indizes verwenden müssen. Stattdessen greift der Server in diesem Fall über das native Dateisystem-Caching direkt auf die Tabellenindizes zu. Das Dateisystem-Caching ist nicht so effizient wie ein Schlüssel-Cache, d. h., die Abfragen werden zwar ausgeführt, aber Sie können von Geschwindigkeitseinbußen ausgehen. Nachdem der Cache umstrukturiert wurde, werden ihm zugewiesene Indizes dort wieder zwischengespeichert, und das Dateisystem-Caching wird nicht mehr für die Indizes verwendet.

7.4.7. Sammlung von MyISAM-Indexstatistiken

Speicher-Engines sammeln tabellenspezifische Statistiken, die der Optimierer verwenden kann. Tabellenstatistiken basieren auf Wertegruppen. Eine Wertegruppe ist eine Menge von Datensätzen mit demselben Schlüsselpräfixwert. Für die Zwecke des Optimierers ist die durchschnittliche Wertegruppengröße eine wichtige Angabe.

MySQL verwendet diese Information,

  • um zu bestimmen, wie viele Datensätze für jeden ref-Zugriff gelesen werden müssen,

  • um einzuschätzen, wie viele Datensätze ein Teil-Join – oder, genauer, eine Operation der folgenden Form – erzeugt:

    (...) JOIN tbl_name ON tbl_name.key = expr
    

Wenn die Durchschnittsgröße der Wertegruppen für einen Index ansteigt, wird der Index für diese beiden Aufgaben zunehmend weniger nützlich, weil auch die durchschnittliche Anzahl von Datensätzen pro Suchvorgang steigt: Damit der Index für Optimierungszwecke gut geeignet ist, wäre es optimal, wenn jeder Indexwert auf eine kleine Anzahl von Datensätzen in der Tabelle abzielt. Hat ein gegebener Indexwert eine hohe Zahl von Datensätzen zum Ergebnis, dann ist sein Nutzen eingeschränkt, und die Wahrscheinlichkeit, dass MySQL ihn verwendet, ist geringer.

Die durchschnittliche Wertegruppengröße bezieht sich auf die Kardinalität der Tabelle, d. h. die Anzahl der Wertegruppen. Die SHOW INDEX-Anweisung zeigt einen Kardinalitätswert basierend auf N ÷ S an, wobei N die Anzahl der Datensätze in der Tabelle und S die durchschnittliche Wertegruppengröße darstellt. Dieses Verhältnis gibt einen Näherungswert für die Anzahl der Wertegruppen in der Tabelle an.

Bei einem Join, der auf dem Vergleichsoperator <=> basiert, wird NULL nicht anders behandelt als andere Werte: NULL <=> NULL (wie N<=> N für jeden anderen Wert N).

Basiert ein Join jedoch auf dem Operator =, dann unterscheidet sich NULL von Nicht-NULL-Werten: expr1 = expr2 ist nicht wahr, wenn expr1 oder expr2 (oder beide) NULL sind. Dies wirkt sich auf ref-Zugriffe für Vergleiche der Form tbl_name.key = expr aus: MySQL greift nicht auf die Tabelle zu, wenn der aktuelle Wert von expr NULL ist, weil der Vergleich nicht wahr sein kann.

Bei =-Vergleichen spielt es keine Rolle, wie viele NULL-Werte in der Tabelle vorhanden sind. Der für Optimierungszwecke relevante Wert ist die Durchschnittsgröße der Gruppe von Nicht-NULL-Werten. Allerdings gestattet MySQL derzeit keine Ermittlung oder Verwendung dieser Durchschnittsgröße.

Bei MyISAM-Tabellen haben Sie mit der Systemvariablen myisam_stats_method in eingeschränktem Maße Kontrolle über die Ermittlung der Tabellenstatistiken. Diese Variable hat zwei mögliche Werte, die sich wie folgt voneinander unterscheiden:

  • Wenn myisam_stats_method nulls_equal ist, dann werden alle NULL-Werte als identisch behandelt (d. h., sie alle bilden eine Wertegruppe).

    Wenn die NULL-Wertegruppe wesentlich größer ist als die Durchschnittsgröße der Gruppe der Nicht-NULL-Werte, dann erhöht diese Methode die durchschnittliche Wertegruppengröße. Aufgrund dessen erscheint der Index dem Optimierer weniger nützlich, als er es für Joins, die nach Nicht-NULL-Werten suchen, tatsächlich ist. Im Ergebnis kann die nulls_equal-Methode also dazu führen, dass der Optimierer den Index für ref nicht verwendet, obwohl er es sollte.

  • Wenn myisam_stats_method nulls_unequal ist, werden NULL-Werte nicht als identisch betrachtet. Stattdessen bildet jeder NULL-Wert eine separate Wertegruppe der Größe 1.

    Wenn Sie viele NULL-Werte haben, verschiebt diese Methode den Durchschnittswert für die Wertegruppengröße nach unten. Ist der Durchschnittswert der Gruppe der Nicht-NULL-Werte hoch, dann kann dieses Verhalten dazu führen, dass der Optimierer den Wert des Indexes für Joins überschätzt, die nach Nicht-NULL-Werten suchen. Aufgrund dessen kann der nulls_unequal-Ansatz dazu führen, dass der Optimierer diesen Index für ref-Suchvorgänge verwendet, obwohl andere Methoden besser geeignet wären.

Wenn Sie häufig viele Joins benutzen, die <=> statt = verwenden, dann werden NULL-Werte in Vergleichen nicht gesondert betrachtet, sondern ein NULL-Wert entspricht dem anderen. In diesem Fall ist nulls_equal die passende Statistikmethode.

Die Systemvariable myisam_stats_method hat globale und sitzungsbezogene Werte. Das Einstellen des globalen Werts wirkt sich auf die MyISAM-Statistikermittlung bei allen MyISAM-Tabellen aus. Im Gegensatz dazu wirkt der Sitzungswert nur auf Statistiken zur aktuellen Clientverbindung. Sie können also, indem Sie den Sitzungswert von myisam_stats_method einstellen, die Neuerstellung der Statistiken zu einer Tabelle mit einer gegebenen Methode erzwingen, ohne dass andere Clients hiervon beeinträchtigt würden.

Zur Neuerstellung der Tabellenstatistiken können Sie eine der folgenden Methoden benutzen:

  • Stellen Sie myisam_stats_method ein und setzen Sie dann eine CHECK TABLE-Anweisung ab.

  • Führen Sie myisamchk --stats_method=method_name --analyze aus.

  • Ändern Sie die Tabelle so ab, dass die Statistiken veralten (indem Sie beispielsweise einen Datensatz einfügen und ihn dann löschen), stellen Sie myisam_stats_method ein und setzen Sie eine ANALYZE TABLE-Anweisung ab.

Die Verwendung von myisam_stats_method hat auch ein paar Nachteile:

Sie können die Ermittlung von Tabellenstatistiken wie gerade beschrieben erzwingen. Allerdings kann MySQL die Statistiken auch automatisch sammeln. Wenn beispielsweise während der Ausführung von Anweisungen für eine Tabelle einige dieser Anweisungen die Tabelle ändern, ermittelt MySQL unter Umständen Statistiken. (Dies kann etwa bei Masseneinfüge- oder -löschoperationen oder bei bestimmten ALTER TABLE-Anweisungen der Fall sein.) Wenn dies geschieht, werden die Statistiken ohne Berücksichtigung des aktuellen Werts von myisam_stats_method gesammelt. Wenn Sie also Statistiken mit einer bestimmten Methode ermitteln, aber myisam_stats_method bei einer späteren automatischen Statistiksammlung auf eine andere Methode gesetzt wird, dann wird diese andere Methode verwendet.

Es gibt keine Möglichkeit, festzustellen, welche Methode zur Erzeugung von Statistiken für eine gegebene MyISAM-Tabelle verwendet wurde.

myisam_stats_method gilt nur für MyISAM-Tabellen. Die übrigen Speicher-Engines haben jeweils eigene Methoden zur Ermittlung von Tabellenstatistiken. Diese ähneln der Methode nulls_equal.

7.4.8. Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank

Wenn Sie einen mysqladmin status-Befehl ausführen, sollten Sie etwa folgendes Ergebnis erhalten:

Uptime: 426 Running threads: 1 Questions: 11082
Reloads: 1 Open tables: 12

Der Open tables-Wert von 12 kann etwas verwirrend sein, wenn Sie nur sechs Tabellen haben.

MySQL arbeitet mit mehreren Threads, d. h., mehrere Clients setzen unter Umständen gleichzeitig Abfragen für eine gegebene Tabelle ab. Um das Problem mit mehreren Client-Threads, die unterschiedliche Zustände bezüglich derselben Tabelle haben, zu minimieren, wird die Tabelle von allen nebenläufigen Threads unabhängig geöffnet. Zwar wird hierdurch mehr Speicher verbraucht, aber in der Regel wird die Leistung verbessert. Bei MyISAM-Tabellen ist pro Client, der eine Tabelle geöffnet hält, ein zusätzlicher Dateideskriptor für die Datendatei erforderlich. (Dies steht im Gegensatz zum Indexdateideskriptor, der von allen Threads gemeinsam verwendet wird.)

Die Systemvariablen table_open_cache, max_connections und max_tmp_tables bestimmen die maximale Anzahl der Dateien, die der Server geöffnet hält. Wenn Sie einen oder mehrere dieser Werte erhöhen, stoßen Sie unter Umständen auf ein Limit, das Ihr Betriebssystem bezüglich der prozessbezogenen Anzahl offener Dateideskriptoren setzt. Viele Betriebssysteme erlauben Ihnen eine Anhebung der Beschränkung für offene Dateien, auch wenn sich die jeweilige Methode von Betriebssystem zu Betriebssystem unterscheidet. Informationen dazu, ob und wie es möglich ist, diesen Wert anzuheben, entnehmen Sie der Dokumentation zu Ihrem Betriebssystem.

table_open_cache bezieht sich auf max_connections. So sollten Sie etwa für 200 gleichzeitig laufende Verbindungen einen Tabellen-Cache mit einer Größe von mindestens 200 × N haben, wobei N die maximale Anzahl von Tabellen pro Join in einer beliebigen von Ihnen ausgeführten Abfrage ist. Sie müssen ferner einige zusätzliche Dateideskriptoren für Temporärtabellen und -dateien reservieren.

Stellen Sie sicher, dass Ihr Betriebssystem die Anzahl der mit der Einstellung von table_open_cache verbundenen Deskriptoren für offene Dateien verarbeiten kann. Wenn für table_open_cache ein zu hoher Wert eingestellt ist, stehen für MySQL irgendwann unter Umständen keine Dateideskriptoren mehr zur Verfügung: MySQL verweigert dann Verbindungen, kann Abfragen nicht ausführen und wird im Ganzen sehr instabil. Sie müssen ferner berücksichtigen, dass die MyISAM-Speicher-Engine zwei Dateideskriptoren für jede offene Tabelle benötigt. Sie können die Anzahl der MySQL zur Verfügung stehenden Dateideskriptoren mit der Startoption --open-files-limit für mysqld_safe erhöhen. Siehe auch Abschnitt A.2.17, „Datei nicht gefunden“.

Der Cache für die offenen Tabellen wird auf einem Niveau von table_open_cache Einträgen gehalten. Der Standardwert beträgt 64, kann aber mit der Option --table_open_cache für mysqld geändert werden. Beachten Sie, dass MySQL zur Ausführung von Abfragen vorübergehend auch mehr Tabellen öffnen kann.

MySQL schließt nicht verwendete Tabellen und entfernt sie aus dem Tabellen-Cache, wenn

  • der Cache voll ist und ein Thread eine Tabelle zu öffnen versucht, die nicht im Cache enthalten ist,

  • der Cache mehr als table_open_cache Einträge enthält und eine Tabelle im Cache von keinem Thread mehr verwendet wird,

  • die Tabelle synchronisiert wird. Dies passiert, wenn jemand eine FLUSH TABLES-Anweisung absetzt oder einen der Befehle mysqladmin flush-tables oder mysqladmin refresh ausführt.

Wenn der Tabellen-Cache Einträge enthält, ermittelt der Server einen zu verwendenden Cache-Eintrag wie folgt:

  • Tabellen, die zurzeit nicht verwendet werden, werden freigegeben. Hierbei wird mit der Tabelle begonnen, die am längsten nicht verwendet wurde.

  • Wenn eine neue Tabelle geöffnet werden muss, der Cache aber voll ist und keine Tabelle freigegeben werden kann, dann wird der Cache vorübergehend nach Bedarf erweitert.

Ist der Cache vorübergehend erweitert und eine Tabelle erhält den Status „nicht verwendet“, dann wird diese Tabelle geschlossen und aus dem Cache entfernt.

Eine Tabelle wird für jeden nebenläufigen Zugriff geöffnet. Das bedeutet, dass die Tabelle zweimal geöffnet werden muss, wenn zwei Threads auf dieselbe Tabelle zugreifen oder ein Thread die Tabelle zweimal in derselben Abfrage referenziert (beispielsweise beim Join einer Tabelle mit sich selbst). Jeder gleichzeitige Öffnungsvorgang erfordert einen Eintrag im Tabellen-Cache. Der erste Öffnungsvorgang einer MyISAM-Tabelle nimmt zwei Dateideskriptoren entgegen, nämlich je einen für die Daten- und die Indexdatei. Jede zusätzliche Verwendung der Tabelle benötigt nur einen Deskriptor für die Datendatei. Der Deskriptor für die Indexdateien wird von allen Threads gemeinsam verwendet.

Wenn Sie eine Tabelle mit der Anweisung HANDLER tbl_name OPEN öffnen, wird für den Thread ein dediziertes Tabellenobjekt reserviert. Dieses Tabellenobjekt wird nicht mit anderen Threads gemeinsam genutzt und wird erst geschlossen, wenn der Thread HANDLER tbl_name CLOSE aufruft oder beendet wird. In diesem Fall wird die Tabelle in den Tabellen-Cache zurückgeführt (sofern dieser nicht voll ist). Siehe auch Abschnitt 13.2.3, „HANDLER.

Sie können ermitteln, ob Ihr Tabellen-Cache zu klein ist, indem Sie die Statusvariable Opened_tables für mysqld überprüfen:

mysql> SHOW STATUS LIKE 'Opened_tables';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Opened_tables | 2741  |
+---------------+-------+

Wenn der Wert sehr groß ist (und zwar auch dann, wenn Sie nicht viele FLUSH TABLES-Anweisungen abgesetzt haben), dann sollten Sie die Größe des Tabellen-Caches erhöhen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“, und Abschnitt 5.2.4, „Server-Statusvariablen“.

7.4.9. Warum gibt es so viele offene Tabellen?

Wenn sich viele MyISAM-Tabellen im selben Datenbankverzeichnis befinden, verlaufen Operationen wie das Öffnen, Schließen und Erstellen von Tabellen sehr langsam. Führen Sie SELECT-Anweisungen für viele verschiedene Tabellen aus, dann tritt eine geringe Mehrbelastung auf, wenn der Tabellen-Cache voll ist, weil für jede Tabelle, die geöffnet wird, eine andere geschlossen werden muss. Sie können diese Mehrbelastung verringern, indem Sie den Tabellen-Cache vergrößern.

7.5. Optimierung des MySQL Servers

7.5.1. System/Kompilierzeitpunkt und Tuning der Startparameter

Wir beginnen mit den Faktoren auf der Systemebene, weil einige dieser Entscheidungen sehr früh getroffen werden müssen, um einen beträchtlichen Leistungszugewinn zu erzielen. In anderen Fällen kann ein kurzer Blick in diesen Abschnitt ausreichen. Allerdings kann es immer praktisch sein, ein Gespür dafür zu entwickeln, welcher Zugewinn sich durch Änderung von Faktoren auf dieser Ebene erzielen lässt.

Das Betriebssystem, welches verwendet werden soll, ist ein wesentlicher Faktor. Um aus Mehrprozessorrechnern die optimale Leistung zu erzielen, sollten Sie Solaris (aufgrund seiner gut funktionierenden Thread-Implementierung) oder Linux verwenden (weil der Kernel der Versionen 2.4 und höher eine gute SMP-Unterstützung bietet). Beachten Sie, dass ältere Linux-Kernels standardmäßig eine Dateigrößenbeschränkung auf 2 Gbyte aufweisen. Wenn Sie einen solchen Kernel verwenden, Ihre Dateien aber größer werden könnten als 2 Gbyte, dann sollten Sie sich den LFS-Patch (Large File Support) für das ext2-Dateisystem besorgen. Andere Dateisysteme wie ReiserFS und XFS weisen diese Beschränkung auf 2 Gbyte nicht auf.

Bevor Sie MySQL in die Produktion nehmen, sollten Sie es auf der vorgesehenen Plattform testen.

Weitere Tipps:

  • Wenn Sie genug RAM haben, können Sie in Betracht ziehen, alle Auslagerungsgeräte zu entfernen. Einige Betriebssysteme verwenden unter bestimmten Umständen ein Auslagerungsgerät auch dann, wenn freier Speicher vorhanden ist.

  • Vermeiden Sie externe Sperren. Seit MySQL 4.0 ist die externe Sperrung standardmäßig auf allen Systemen deaktiviert. Mit den Optionen --external-locking und --skip-external-locking können Sie externe Sperren explizit aktivieren bzw. deaktivieren.

    Beachten Sie, dass die Deaktivierung externer Sperren die Funktionalität von MySQL nicht beeinträchtigt, solange Sie nur einen einzelnen Server ausführen. Denken Sie aber immer daran, den Server abzuschalten (oder die relevanten Tabellen zu sperren und zu synchronisieren), bevor Sie myisamchk ausführen. Auf einigen Systemen ist die Deaktivierung externer Sperren obligatorisch, weil sie dort ohnehin nicht funktionieren.

    Der einzige Fall, in dem Sie die externe Sperrung nicht deaktivieren können, liegt vor, wenn Sie mehrere MySQL Server (nicht Clients) mit demselben Datenbestand betreiben, oder wenn Sie mit myisamchk eine Tabelle überprüfen (nicht reparieren), ohne den Server zuvor angewiesen zu haben, die Tabellen zuerst zu sperren und zu synchronisieren. Beachten Sie, dass von der Verwendung mehrerer MySQL Server für den gleichzeitigen Zugriff auf dieselben Daten generell abzuraten ist, sofern Sie nicht MySQL Cluster verwenden.

    Die Anweisungen LOCK TABLES und UNLOCK TABLES verwenden interne Sperren, d. h., Sie können sie auch bei deaktivierter externer Sperrung verwenden.

7.5.2. Serverparameter feineinstellen

Mit dem folgenden Befehl können Sie die standardmäßigen Puffergrößen festlegen, die der Server mysqld verwendet:

shell> mysqld --verbose --help

Dieser Befehl erzeugt eine Liste aller mysqld-Optionen und konfigurierbarer Systemvariablen. Die Ausgabe enthält die Standardwerte der Variablen und sieht etwa so aus:

help                              TRUE
abort-slave-event-count           0
allow-suspicious-udfs             FALSE
auto-increment-increment          1
auto-increment-offset             1
automatic-sp-privileges           TRUE
basedir                           /home/jon/bin/mysql/
bdb                               FALSE
bind-address                      (No default value)
character-set-client-handshake    TRUE
character-set-server              latin1
character-sets-dir                /home/jon/bin/mysql/share/mysql/charsets/
chroot                            (No default value)
collation-server                  latin1_swedish_ci
completion-type                   0
concurrent-insert                 1
console                           FALSE
datadir                           /home/jon/bin/mysql/var/
default-character-set             latin1
default-collation                 latin1_swedish_ci
default-time-zone                 (No default value)
disconnect-slave-event-count      0
enable-locking                    FALSE
enable-pstack                     FALSE
engine-condition-pushdown         FALSE
external-locking                  FALSE
gdb                               FALSE
large-pages                       FALSE
init-connect                      (No default value)
init-file                         (No default value)
init-slave                        (No default value)
innodb                            TRUE
innodb_checksums                  TRUE
innodb_data_home_dir              (No default value)
innodb_doublewrite                TRUE
innodb_fast_shutdown              1
innodb_file_per_table             FALSE
innodb_flush_log_at_trx_commit    1
innodb_flush_method               (No default value)
innodb_locks_unsafe_for_binlog    FALSE
innodb_log_arch_dir               (No default value)
innodb_log_group_home_dir         (No default value)
innodb_max_dirty_pages_pct        90
innodb_max_purge_lag              0
innodb_status_file                FALSE
innodb_table_locks                TRUE
innodb_support_xa                 TRUE
isam                              FALSE
language                          /home/jon/bin/mysql/share/mysql/english
local-infile                      TRUE
log                               /home/jon/bin/mysql/var/master1.log
log-bin                           /home/jon/bin/mysql/var/master1
log-bin-index                     (No default value)
log-bin-trust-routine-creators    FALSE
log-error                         /home/jon/bin/mysql/var/master1.err
log-isam                          myisam.log
log-queries-not-using-indexes     FALSE
log-short-format                  FALSE
log-slave-updates                 FALSE
log-slow-admin-statements         FALSE
log-slow-queries                  (No default value)
log-tc                            tc.log
log-tc-size                       24576
log-update                        (No default value)
log-warnings                      1
low-priority-updates              FALSE
master-connect-retry              60
master-host                       (No default value)
master-info-file                  master.info
master-password                   (No default value)
master-port                       3306
master-retry-count                86400
master-ssl                        FALSE
master-ssl-ca                     (No default value)
master-ssl-capath                 (No default value)
master-ssl-cert                   (No default value)
master-ssl-cipher                 (No default value)
master-ssl-key                    (No default value)
master-user                       test
max-binlog-dump-events            0
memlock                           FALSE
myisam-recover                    OFF
ndbcluster                        FALSE
ndb-connectstring                 (No default value)
ndb-mgmd-host                     (No default value)
ndb-nodeid                        0
ndb-autoincrement-prefetch-sz     32
ndb-distibution                   KEYHASH
ndb-force-send                    TRUE
ndb_force_send                    TRUE
ndb-use-exact-count               TRUE
ndb_use_exact_count               TRUE
ndb-shm                           FALSE
ndb-optimized-node-selection      TRUE
ndb-cache-check-time              0
ndb-index-stat-enable             TRUE
ndb-index-stat-cache-entries      32
ndb-index-stat-update-freq        20
new                               FALSE
old-alter-table                   FALSE
old-passwords                     FALSE
old-style-user-limits             FALSE
pid-file                          /home/jon/bin/mysql/var/hostname.pid1
port                              3306
relay-log                         (No default value)
relay-log-index                   (No default value)
relay-log-info-file               relay-log.info
replicate-same-server-id          FALSE
report-host                       (No default value)
report-password                   (No default value)
report-port                       3306
report-user                       (No default value)
rpl-recovery-rank                 0
safe-user-create                  FALSE
secure-auth                       FALSE
server-id                         1
show-slave-auth-info              FALSE
skip-grant-tables                 FALSE
skip-slave-start                  FALSE
slave-load-tmpdir                 /tmp/
socket                            /tmp/mysql.sock
sporadic-binlog-dump-fail         FALSE
sql-mode                          OFF
symbolic-links                    TRUE
tc-heuristic-recover              (No default value)
temp-pool                         TRUE
timed_mutexes                     FALSE
tmpdir                            (No default value)
use-symbolic-links                TRUE
verbose                           TRUE
warnings                          1
back_log                          50
binlog_cache_size                 32768
bulk_insert_buffer_size           8388608
connect_timeout                   5
date_format                       (No default value)
datetime_format                   (No default value)
default_week_format               0
delayed_insert_limit              100
delayed_insert_timeout            300
delayed_queue_size                1000
expire_logs_days                  0
flush_time                        0
ft_max_word_len                   84
ft_min_word_len                   4
ft_query_expansion_limit          20
ft_stopword_file                  (No default value)
group_concat_max_len              1024
innodb_additional_mem_pool_size   1048576
innodb_autoextend_increment       8
innodb_buffer_pool_awe_mem_mb     0
innodb_buffer_pool_size           8388608
innodb_concurrency_tickets        500
innodb_file_io_threads            4
innodb_force_recovery             0
innodb_lock_wait_timeout          50
innodb_log_buffer_size            1048576
innodb_log_file_size              5242880
innodb_log_files_in_group         2
innodb_mirrored_log_groups        1
innodb_open_files                 300
innodb_sync_spin_loops            20
innodb_thread_concurrency         20
innodb_commit_concurrency         0
innodb_thread_sleep_delay         10000
interactive_timeout               28800
join_buffer_size                  131072
key_buffer_size                   8388600
key_cache_age_threshold           300
key_cache_block_size              1024
key_cache_division_limit          100
long_query_time                   10
lower_case_table_names            0
max_allowed_packet                1048576
max_binlog_cache_size             4294967295
max_binlog_size                   1073741824
max_connect_errors                10
max_connections                   100
max_delayed_threads               20
max_error_count                   64
max_heap_table_size               16777216
max_join_size                     4294967295
max_length_for_sort_data          1024
max_relay_log_size                0
max_seeks_for_key                 4294967295
max_sort_length                   1024
max_tmp_tables                    32
max_user_connections              0
max_write_lock_count              4294967295
multi_range_count                 256
myisam_block_size                 1024
myisam_data_pointer_size          6
myisam_max_extra_sort_file_size   2147483648
myisam_max_sort_file_size         2147483647
myisam_repair_threads             1
myisam_sort_buffer_size           8388608
myisam_stats_method               nulls_unequal
net_buffer_length                 16384
net_read_timeout                  30
net_retry_count                   10
net_write_timeout                 60
open_files_limit                  0
optimizer_prune_level             1
optimizer_search_depth            62
preload_buffer_size               32768
query_alloc_block_size            8192
query_cache_limit                 1048576
query_cache_min_res_unit          4096
query_cache_size                  0
query_cache_type                  1
query_cache_wlock_invalidate      FALSE
query_prealloc_size               8192
range_alloc_block_size            2048
read_buffer_size                  131072
read_only                         FALSE
read_rnd_buffer_size              262144
div_precision_increment           4
record_buffer                     131072
relay_log_purge                   TRUE
relay_log_space_limit             0
slave_compressed_protocol         FALSE
slave_net_timeout                 3600
slave_transaction_retries         10
slow_launch_time                  2
sort_buffer_size                  2097144
sync-binlog                       0
sync-frm                          TRUE
sync-replication                  0
sync-replication-slave-id         0
sync-replication-timeout          10
table_open_cache                  64
table_lock_wait_timeout           50
thread_cache_size                 0
thread_concurrency                10
thread_stack                      196608
time_format                       (No default value)
tmp_table_size                    33554432
transaction_alloc_block_size      8192
transaction_prealloc_size         4096
updatable_views_with_limit        1
wait_timeout                      28800

Wird gerade ein mysqld-Server ausgeführt, dann können Sie die aktuellen Werte seiner Systemvariablen anzeigen, indem Sie eine Verbindung mit ihm herstellen und die folgende Anweisung absetzen:

mysql> SHOW VARIABLES;

Mit der folgenden Anweisung können Sie statistische Informationen und Statusangaben für einen laufenden Server abrufen:

mysql> SHOW STATUS;

Angaben zu Systemvariablen und Status erhalten Sie auch mit mysqladmin:

shell> mysqladmin variables
shell> mysqladmin extended-status

Eine vollständige Beschreibung aller System- und Statusvariablen finden Sie in Abschnitt 5.2.2, „Server-Systemvariablen“, und Abschnitt 5.2.4, „Server-Statusvariablen“.

MySQL verwendet Algorithmen, die sehr gut skalierbar sind, d. h., Sie können MySQL gewöhnlich mit sehr wenig Speicher ausführen. Andererseits erhalten Sie eine umso bessere Performance, je mehr Speicher Sie MySQL zugestehen.

Wenn Sie einen MySQL Server optimieren, dann sind die beiden wichtigsten zu konfigurierenden Variablen key_buffer_size und table_open_cache. Sie sollten erst ganz sicher sein, dass Sie für diese Variablen geeignete Werte eingestellt haben, bevor Sie andere Variablen zu konfigurieren versuchen.

Die folgenden Beispiele zeigen einige typische Variablenwerte für verschiedene Laufzeitkonfigurationen.

  • Wenn Sie mindestens 256 Mbyte Speicher und viele Tabellen haben und für eine moderate Anzahl von Clients die optimale Leistung erzielen wollen, sollten Sie einmal Folgendes probieren:

    shell> mysqld_safe --key_buffer_size=64M --table_open_cache=256 \
               --sort_buffer_size=4M --read_buffer_size=1M &
    
  • Haben Sie nur 128 Mbyte Speicher und nur ein paar Tabellen, die aber häufig sortiert werden müssen, dann können Sie Folgendes ausprobieren:

    shell> mysqld_safe --key_buffer_size=16M --sort_buffer_size=1M
    

    Bei sehr vielen gleichzeitigen Problemen können Auslagerungsprobleme auftreten, sofern mysqld nicht für die Verwendung von sehr wenig Speicher für die jeweilige Verbindung konfiguriert wurde. mysqld arbeitet besser, wenn Sie genug Speicher für alle Verbindungen haben.

  • Bei sehr wenig Speicher und vielen Verbindungen verwenden Sie Folgendes:

    shell> mysqld_safe --key_buffer_size=512K --sort_buffer_size=100K \
               --read_buffer_size=100K &
    

    Oder sogar Folgendes:

    shell> mysqld_safe --key_buffer_size=512K --sort_buffer_size=16K \
               --table_open_cache=32 --read_buffer_size=8K \
               --net_buffer_length=1K &
    

Wenn Sie GROUP BY- oder ORDER BY-Operationen an Tabellen durchführen, die wesentlich größer sind als der verfügbare Speicher, dann sollten Sie den Wert von read_rnd_buffer_size erhöhen, um nach Durchführung von Sortieroperationen das Auslesen von Datensätzen zu beschleunigen.

Wenn Sie MySQL installiert haben, enthält das Verzeichnis support-files eine Anzahl verschiedener my.cnf-Beispieldateien, nämlich my-huge.cnf, my-large.cnf, my-medium.cnf und my-small.cnf. Diese können Sie als Basis zur Optimierung Ihres Systems verwenden. (Unter Windows schauen Sie im MySQL-Installationsverzeichnis nach.)

Wenn Sie für mysqld oder mysqld_safe eine Option auf der Befehlszeile angeben, ist diese nur für den betreffenden Aufruf des Servers gültig. Um diese Option jedes Mal bei Ausführung des Servers zu verwenden, müssen Sie sie in einer Optionsdatei ablegen.

Um die Wirkung einer Parameteränderung zu prüfen, können Sie Folgendes tun:

shell> mysqld --key_buffer_size=32M --verbose --help

Die Variablenwerte sind kurz vor Ende der Ausgabe aufgeführt. Vergewissern Sie sich, dass die Optionen --verbose und --help am Ende stehen. Andernfalls werden die Auswirkungen von Optionen, die nach diesen beiden Optionen auf der Befehlszeile angegeben wurden, in der Ausgabe nicht berücksichtigt.

Informationen zur Optimierung der InnoDB-Speicher-Engine finden Sie in Abschnitt 14.2.11, „Tipps zur Leistungssteigerung“.

7.5.3. Leistung des Abfragenoptimierers steuern

Die Aufgabe des Abfrageoptimierers besteht darin, einen optimalen Plan für die Ausführung einer SQL-Abfrage zu entwickeln. Da der Unterschied zwischen „gut“ und „schlecht“ aus leistungstechnischer Sicht mehrere Größenordnungen betragen kann (d. h. Sekunden im Vergleich zu Stunden oder sogar Tagen), führten die meisten Abfrageoptimierer (einschließlich des MySQL-Optimierers) unter allen möglichen Plänen zur Abfragebewertung eine mehr oder minder umfangreiche Suche nach dem optimalen Plan durch. Bei Join-Abfragen wächst die Anzahl möglicher Pläne, die vom MySQL-Optimierer untersucht werden, exponentiell mit der Anzahl der Tabellen, die in einer Abfrage referenziert werden. Bei einer kleinen Anzahl von Tabellen (etwa 7 bis 10) ist dies unproblematisch. Werden hingegen größere Abfragen abgesetzt, dann kann die für die Abfrageoptimierung erforderliche Zeit schnell zum Engpass für die Leistung des Servers werden.

Eine flexiblere Methode zur Abfrageoptimierung gewährt dem Benutzer Kontrolle darüber, wie erschöpfend der Optimierer bei der Suche nach einem optimalen Abfragebewertungsplan vorgeht. Hintergedanke ist, dass umso weniger Zeit für die Kompilierung einer Abfrage aufgewendet wird, je weniger Pläne vom Optimierer untersucht werden. Andererseits kann es sein, dass der Optimierer, weil er einige Pläne überspringt, den optimalen Plan übersieht.

Das Verhalten des Optimierers in Bezug auf die Anzahl der Pläne, die er bewertet, kann über zwei Systemvariablen gesteuert werden:

  • Die Variable optimizer_prune_level weist den Optimierer an, bestimmte Pläne basierend auf der geschätzten Anzahl der Datensätze, auf die pro Tabelle zugegriffen wird, zu übergehen. Unsere Erfahrung zeigt, dass diese Art der „begründeten Annahme“ optimale Pläne nur in sehr seltenen Fällen verfehlt. Aus diesem Grund ist die Option standardmäßig aktiviert (optimizer_prune_level=1). Wenn Sie allerdings das Gefühl haben, dass der Optimierer einen besseren Abfrageplan hätte finden können, dann können Sie die Option auch abschalten (optimizer_prune_level=0); allerdings besteht dann das Risiko, dass die Abfragekompilierung deutlich länger dauert. Beachten Sie, dass der Optimierer auch bei Verwendung dieser Heuristik eine grob exponentielle Anzahl von Plänen untersucht.

  • Die Variable optimizer_search_depth sagt dem Optimierer, wie weit er bei unvollständigen Plänen „vorausschauen“ soll, um einzuschätzen, ob ein Plan erweitert werden soll. Niedrige Werte für optimizer_search_depth führen zu um mehrere Größenordnungen kürzeren Abfragekompilierungszeiten. So kann die Kompilierung von Abfragen mit 12, 13 oder mehr Tabellen leicht Stunden oder sogar Tage dauern, wenn optimizer_search_depth einen Wert hat, der annähernd der Anzahl der Tabellen in der Abfrage entspricht. Umgekehrt benötigt der Compiler für dieselbe Abfrage noch nicht einmal eine Minute, wenn optimizer_search_depth den Wert 3 oder 4 hat. Wenn Sie nicht sicher sind, welcher Wert für optimizer_search_depth sinnvoll sein könnte, können Sie ihn auf 0 setzen; so weisen Sie den Optimierer an, den Wert automatisch zu ermitteln.

7.5.4. Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst

Die meisten der folgenden Tests wurden unter Linux mit den MySQL-Benchmarks durchgeführt, sie sollten aber trotzdem ausreichend aussagekräftig auch für andere Betriebssysteme und Belastungsbereiche sein.

Sie erhalten die schnellsten ausführbaren Dateien, indem Sie mit der Option -static verknüpfen.

Unter Linux kompilieren Sie den Server am besten mit pgcc und -O3. Sie benötigen etwa 200 Mbyte Speicher zur Kompilierung von sql_yacc.cc mit diesen Optionen, weil gcc oder pgcc eine Menge Speicher benötigt, um alle Funktionen zu integrieren. Ferner sollten Sie bei der Konfiguration von MySQL CXX=gcc einstellen, um die Miteinbeziehung der Bibliothek libstdc++ zu vermeiden, denn diese wird nicht benötigt. Beachten Sie, dass bei einigen Versionen von pgcc die resultierende Binärdatei nur auf echten Pentium-Prozessoren läuft, auch wenn Sie eine Compileroption verwendet haben, mit der Sie angeben wollten, dass der Ergebniscode auf allen x586-Prozessoren (z. B. AMD) laufen soll.

Sie können eine Geschwindigkeitszunahme von 10 bis 30 Prozent erzielen, indem Sie einen besseren Compiler und geeignetere Kompilierungsoptionen verwenden. Dies ist besonders wichtig, wenn Sie den MySQL Server selbst kompilieren.

Als wir die Cygnus CodeFusion- und Fujitsu-Compiler testeten, stellte sich heraus, dass keiner von diesen ausreichend wenig Bugs aufwies, um MySQL mit aktivierten Optimierungen zu kompilieren.

MySQL-Standarddistributionen werden mit der Unterstützung für alle Zeichensätze kompiliert. Wenn Sie MySQL selbst kompilieren, sollten Sie die Unterstützung nur für diejenigen Zeichensätze integrieren, die Sie tatsächlich verwenden werden. Dies wird mit der Option --with-charset für configure gesteuert.

Es folgt eine Liste einiger Maßnahmen, die wir vorgenommen haben:

  • Wenn Sie pgcc verwenden und alles mit -O6 kompilieren, ist der Server mysqld um ein Prozent schneller als mit gcc 2.95.2.

  • Wenn Sie dynamisch verknüpfen (also ohne -static), ist das Ergebnis unter Linux um 13 Prozent langsamer. Beachten Sie, dass Sie eine dynamisch verknüpfte MySQL-Bibliothek weiterhin für Ihre Clientanwendungen benutzen können. Es ist der Server, der für die Leistungsfähigkeit die kritischste Komponente darstellt.

  • Wenn Sie Ihre mysqld-Binärdatei mit strip mysqld bearbeiten, kann die resultierende Binärdatei um bis zu 4 Prozent schneller sein.

  • Bei einer Verbindung von einem Client zu einem Server, der auf demselben Host läuft, ist die Leistung um 7,5 Prozent geringer, wenn Sie die Verbindung über TCP/IP statt über eine Unix-Socketdatei herstellen. (Unter Unix verwendet MySQL, wenn Sie die Verbindung zum Hostnamen localhost herstellen, standardmäßig eine Socketdatei.)

  • TCP/IP-Verbindungen von einem Client mit einem Server sind um 8 bis 11 Prozent langsamer, wenn der Server auf einem entfernten System liegt, als bei Verbindung mit einem Server auf demselben Host (und zwar auch bei Verbindungen über 100-Mbit/s-Ethernet).

  • Bei Ausführung unserer Benchmark-Tests über sichere Verbindungen (d. h., alle Daten wurden durch die interne SSL-Unterstützung verschlüsselt) war die Leistung um 55 Prozent geringer als bei unverschlüsselten Verbindungen.

  • Wenn Sie mit --with-debug=full kompilieren, sind die meisten Abfragen 20 Prozent langsamer. Einige Abfragen können deutlich länger benötigen; so laufen die MySQL-Benchmarks um 35 Prozent langsamer. Wenn Sie --with-debug (ohne =full) angeben, liegt der Geschwindigkeitsverlust lediglich bei 15 Prozent. Bei einer Version von mysqld, die mit --with-debug=full kompiliert wurde, können Sie die Speicherüberprüfung zur Laufzeit abschalten, indem Sie sie mit der Option --skip-safemalloc starten. Die Ausführungsgeschwindigkeit sollte in diesem Fall nicht allzu weit unter derjenigen liegen, die sich bei einer Konfiguration mit --with-debug erzielen lässt.

  • Auf einem Sun UltraSPARC-IIe ist ein mit Forte 5.0 kompilierter Server 4 Prozent schneller als ein mit gcc 3.2 kompilierter Server.

  • Auf einem Sun UltraSPARC-IIe ist ein mit Forte 5.0 kompilierter Server im 32-Bit-Modus 4 Prozent schneller als im 64-Bit-Modus.

  • Die Kompilierung mit gcc 2.95.2 für UltraSPARC mit den Optionen -mcpu=v8 -Wa und -xarch=v8plusa bietet einen Leistungszuwachs von 4 Prozent.

  • Auf Solaris 2.5.1 ist MIT-pthreads 8 bis 12 Prozent langsamer als native Solaris-Threads auf einem einzelnen Prozessor. Bei hoher Belastung oder mehr Prozessoren sollte der Unterschied noch größer sein.

  • Die Kompilierung auf Linux-x86 mit gcc ohne Frame-Zeiger (-fomit-frame-pointer oder -fomit-frame-pointer -ffixed-ebp) macht mysqld 1 bis 4 Prozent schneller.

Von MySQL AB angebotene MySQL-Binärdistributionen für Linux wurden früher generell mit pgcc kompiliert. Aufgrund eines Bugs in pgcc, der dazu führte, dass die erzeugten Binärdateien nicht auf AMD-Prozessoren liefen, mussten wir jedoch zu gcc zurückkehren. Wir werden gcc weiterhin verwenden, bis dieser Bug behoben ist. In der Zwischenzeit können Sie, wenn Sie kein AMD-System haben, durch Kompilierung mit pgcc eine schnellere Binärdatei erstellen. Die MySQL-Standardbinärdatei für Linux ist statisch verknüpft, um Geschwindigkeit und Portabilität zu optimieren.

7.5.5. Wie MySQL Speicher benutzt

Die folgende Liste gibt einige Möglichkeiten an, wie der mysqld-Server Speicher verwendet. Sofern anwendbar, wird der Name der Systemvariablen angegeben, die für die Speichernutzung relevant ist:

  • Der Schlüsselpuffer (Variable key_buffer_size) wird von allen Threads gemeinsam verwendet. Andere Puffer, die der Server benutzt, werden nach Bedarf zugewiesen. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

  • Jede Verbindung verwendet mehrere Thread-spezifische Bereiche:

    • einen Stapel (standardmäßig 192 Kbyte groß, Variable thread_stack)

    • einen Verbindungspuffer (Variable net_buffer_length)

    • einen Ergebnispuffer (Variable net_buffer_length)

    Verbindungs- und Ergebnispuffer werden nach Bedarf dynamisch bis auf den durch max_allowed_packet angegebenen Wert vergrößert. Während der Ausführung einer Abfrage wird eine Kopie des aktuellen Abfrage-Strings ebenfalls reserviert.

  • Alle Threads verwenden denselben Basisspeicher.

  • Wenn ein Thread nicht mehr benötigt wird, wird der ihm zugewiesene Speicher freigegeben und dem System zurückgegeben, sofern der Thread nicht zurück in den Thread-Cache wandert (in diesem Fall bleibt der Speicher reserviert).

  • Vor MySQL 5.1.4 wurden nur für komprimierte MyISAM-Tabellen Speicher zugeordnet. Seit MySQL 5.1.4 lässt sich die Systemvariable myisam_use_mmap auf 1 setzen, um die Speicherzuordnung für alle MyISAM-Tabellen zu aktivieren. Abschnitt 5.2.2, „Server-Systemvariablen“.

  • Jede Anforderung, die einen sequenziellen Scan einer Tabelle durchführt, reserviert einen Lesepuffer (Variable read_buffer_size).

  • Beim Lesen von Datensätzen in willkürlicher Folge (z. B. nach einer Sortierung) kann ein Zufallslesepuffer reserviert werden, um Festplattenzugriffe zu umgehen (Variable read_rnd_buffer_size).

  • Alle Joins werden in einem einzigen Durchlauf ausgeführt, und die meisten Joins können sogar ohne Temporärtabelle erledigt werden. Die meisten Temporärtabellen sind speicherbasierte Hash-Tabellen. Temporärtabellen mit einer großen Datensatzlänge (berechnet als Summe aller Spaltenlängen) oder solche, die BLOB-Spalten enthalten, werden auf der Festplatte gespeichert.

    Wenn eine interne HEAP-Tabelle die durch tmp_table_size angegebene Größe überschreitet, macht MySQL die HEAP-Tabelle im Speicher nach Bedarf automatisch zu einer festplattenbasierten MyISAM-Tabelle. Sie können auch die Größe der Temporärtabelle erhöhen, indem Sie die mysqld-Option tmp_table_size oder die SQL-Option SQL_BIG_TABLES im Clientprogramm einstellen. Siehe auch Abschnitt 13.5.3, „SET.

  • Die meisten Anforderungen, die eine Sortierung durchführen, reservieren einen Sortierpuffer und abhängig von der Größe der Ergebnismenge null bis zwei Temporärdateien. Siehe auch Abschnitt A.4.4, „Wohin MySQL temporäre Dateien speichert“.

  • Praktisch die gesamte Analyse und Berechnung erfolgt in einem lokalen Speicherbereich. Bei kleinen Elementen ist keine Speichermehrbelastung gegeben, d. h., die normale langsame Speicherreservierung und -freigabe werden umgangen. Speicher wird nur für unerwartet große Strings reserviert. Dies wird mit malloc() und free() bewerkstelligt.

  • Für jede MyISAM-Tabelle, die geöffnet wird, wird die Indexdatei einmal geöffnet. Die Datendatei wird für jeden gleichzeitig laufenden Thread einmal geöffnet. Für jeden nebenläufigen Thread werden eine Tabellenstruktur, Spaltenstrukturen für jede Spalte und ein Puffer der Größe 3 × N reserviert. (Hierbei ist N die maximale Datensatzlänge abzüglich vorhandener BLOB-Spalten.) Eine BLOB-Spalte erfordert fünf bis acht Byte zuzüglich der Länge der BLOB-Daten. Die MyISAM-Speicher-Engine unterhält einen zusätzlichen Puffer zur internen Verwendung.

  • Bei Tabellen mit BLOB-Spalten wird ein Puffer dynamisch vergrößert, um größere BLOB-Werte einlesen zu können. Wenn Sie eine Tabelle scannen, wird ein Puffer reserviert, der so groß ist wie der größte BLOB-Wert.

  • Handler-Strukturen für alle in Verwendung befindlichen Tabellen werden in einem Cache gespeichert und als FIFO verwaltet. Standardmäßig hat der Cache 64 Einträge. Wenn eine Tabelle von zwei laufenden Threads gleichzeitig verwendet wurde, enthält der Cache zwei Einträge für die Tabelle. Siehe auch Abschnitt 7.4.8, „Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank“.

  • Eine FLUSH TABLES-Anweisung oder der Befehl mysqladmin flush-tables schließt alle Tabellen, die gerade nicht verwendet werden, und kennzeichnet alle in Verwendung befindlichen Tabellen, damit diese geschlossen werden, sobald der ausführende Thread endet. Hierdurch wird der größte Teil des in Verwendung befindlichen Speichers freigegeben. FLUSH TABLES wird erst abgeschlossen, wenn alle Tabellen geschlossen wurden.

ps und andere Systemstatusprogramme melden unter Umständen, dass mysqld viel Speicher benötigt. Dies kann von Thread-Stapeln an verschiedenen Speicheradressen verursacht werden. Die Solaris-Version von ps beispielsweise zählt die Menge des nicht verwendeten Speichers zwischen den Stapeln als verwendeten Speicher. Sie können dies überprüfen, indem Sie den verfügbaren Auslagerungsspeicher mit swap -s verifizieren. Wir testen mysqld mit verschiedenen Speicherleckdetektoren (sowohl kommerzieller als auch freier Herkunft), d. h., es sollten keine Speicherlecks vorhanden sein.

7.5.6. Wie MySQL DNS benutzt

Wenn ein neuer Client eine Verbindung mit mysqld herstellt, dann erzeugt mysqld einen neuen Thread, um die Anforderung zu bearbeiten. Dieser Thread überprüft zunächt, ob der Hostname sich im Hostnamens-Cache befindet. Ist dies nicht der Fall, dann versucht der Thread, den Hostnamen aufzulösen:

  • Wenn das Betriebssystem die Thread-sicheren Aufrufe gethostbyaddr_r() und gethostbyname_r() unterstützt, führt der Thread unter ihrer Verwendung die Hostnamensauflösung durch.

  • Unterstützt das Betriebssystem die Thread-sicheren Aufrufe nicht, dann sperrt der Thread ein Mutex und ruft stattdessen gethostbyaddr() und gethostbyname() auf. In diesem Fall kann ein anderer Thread Hostnamen, die nicht im Hostnamens-Cache vorhanden sind, erst auflösen, wenn der erste Thread das Mutex wieder aufgehoben hat.

Sie können DNS-Lookups für Hostnamen deaktivieren, indem Sie mysqld mit der Option --skip-name-resolve starten. Allerdings können Sie in diesem Fall nur IP-Adressen in den MySQL-Grant-Tabellen verwenden.

Wenn Ihr DNS sehr langsam ist und Sie viele Hosts haben, können Sie die Leistung steigern, indem Sie entweder DNS-Lookups mit --skip-name-resolve deaktivieren oder den HOST_CACHE_SIZE-Wert (Standard: 128) erhöhen und mysqld neu kompilieren.

Sie können den Hostnamens-Cache deaktivieren, indem Sie den Server mit der Option --skip-host-cache starten. Um den Cache zu leeren, setzen Sie eine FLUSH HOSTS-Anweisung ab oder führen den Befehl mysqladmin flush-hosts aus.

Wenn Sie TCP/IP-Verbindungen vollständig deaktivieren wollen, starten Sie mysqld mit der Option --skip-networking.

7.6. Festplatte, Anmerkungen

  • Suchvorgänge auf der Festplatte stellen einen für die Leistung beträchtlichen Engpass dar. Dieses Problem wird in dem Moment umso offensichtlicher, wenn die Datenmengen so groß werden, dass ein effizientes Caching unmöglich wird. Bei großen Datenbanken, bei denen der Datenzugriff mehr oder weniger zufällig erfolgt, können Sie sich darauf verlassen, dass Sie mindestens einen Lese- und mehrere Suchvorgänge benötigen, um Daten zu schreiben. Um dieses Problem zu verringern, sollten Sie Festplatten mit schnellen Zugriffszeiten verwenden.

  • Erhöhen Sie die Anzahl der verfügbaren Festplattenspindeln (und verringern Sie dadurch die Suchbelastung), indem Sie entweder Dateien auf anderen Festplatten symbolisch verknüpfen oder das Striping verwenden:

    • Symbolische Verknüpfungen

      Sie verknüpfen die Index- und Datendateien von MyISAM-Tabellen von ihren normalen Positionen im Datenverzeichnis aus auf eine andere Festplatte (für die zudem das Striping angewendet werden kann). Hierdurch werden Such- und Lesezeiten verkürzt (vorausgesetzt, die Festplatte wird nicht noch für andere Zwecke verwendet). Siehe auch Abschnitt 7.6.1, „Symbolische Verknüpfungen“.

    • Striping

      Striping bedeutet, dass Sie viele Festplatten haben und den ersten Block auf der ersten Festplatte, den zweiten Block auf der zweiten und den N-ten Block auf der Festplatte mit der Nummer N MOD number_of_disks ablegen. Wenn Ihre normale Datengröße also geringer ist als die Stripe-Größe (oder perfekt angepasst ist), dann erhalten Sie eine wesentlich bessere Performance. Das Striping hängt sehr stark vom Betriebssystem und der Stripe-Größe ab. Insofern sollten Sie Benchmark-Tests Ihrer Anwendung mit verschiedenen Stripe-Größen durchführen. Siehe auch Abschnitt 7.1.5, „Wie Sie Ihre eigenen Benchmarks benutzen“.

      Der Geschwindigkeitsunterschied für das Striping hängt in erheblichem Maße von den Parametern ab. Je nachdem, wie Sie Ihre Striping-Parameter einstellen und über wie viel Festplatten Sie verfügen, können die Unterschiede mehrere Größenordnungen betragen. Sie müssen sich entscheiden, ob Sie die Optimierung für den wahlfreien oder den sequenziellen Zugriff durchführen wollen.

  • Aus Gründen der Zuverlässigkeit sollten Sie RAID 0+1 (Striping plus Spiegelung) verwenden, allerdings benötigen Sie in diesem Fall 2 × N Laufwerke, um N Laufwerke mit Daten aufzunehmen. Dies ist die wahrscheinlich beste Option, sofern Sie über das nötige Kleingeld verfügen. Allerdings müssen Sie unter Umständen in eine Volumeverwaltungssoftware investieren, um ein solches Setup effizient steuern zu können.

  • Empfehlenswert ist auch der Ansatz, den RAID-Level entsprechend der Wichtigkeit der Daten zu variieren. So können Sie etwa Daten moderater Wichtigkeit, die sich wiederherstellen lassen, auf einer RAID-0-Festplatte speichern, wirklich wichtige Daten (z. B. Hostinformationen und Logdateien) hingegen auf einer RAID 0+1- oder einer RAID-N-Festplatte ablegen. RAID N kann problematisch werden, wenn Sie viele Schreibvorgänge haben, da die Aktualisierung der Paritätsbits zeitaufwändig werden kann.

  • Unter Linux können Sie deutlich mehr Leistung erzielen, indem Sie die Schnittstelle Ihrer Festplatte mit hdparm konfigurieren. (Bis zu 100 Prozent unter Last sind nicht ungewöhnlich.) Die folgenden hdparm-Optionen sollten für MySQL – und auch für viele andere Anwendungen – recht gut geeignet sein:

    hdparm -m 16 -d 1
    

    Beachten Sie, dass, wenn Sie diesen Befehl verwenden, Leistung und Zuverlässigkeit von Ihrer Hardware abhängen; aus diesem Grund empfehlen wir Ihnen dringend, Ihr System nach der Verwendung von hdparm umfassend zu testen. Weitere Informationen entnehmen Sie der hdparm-Manpage. Die unvorsichtige Verwendung von hdparm kann zu Schäden am Dateisystem führen! Erstellen Sie deswegen immer ein Backup, bevor Sie zu experimentieren beginnen.

  • Ferner können Sie die Parameter für das von der Datenbank verwendete Dateisystem einstellen:

    Wenn Sie nicht wissen müssen, wann zuletzt auf die Dateien zugegriffen wurde (was bei einem Datenbankserver eigentlich auch nicht wichtig ist), dann können Sie Ihre Dateisysteme mit der Option -o noatime einbinden. Hierdurch werden Updates bis zum letzten Zugriffszeitpunkt in Inoden auf dem Dateisystem übersprungen, wodurch einige Suchvorgänge auf der Festplatte unnötig werden.

    Bei vielen Betriebssystemen können Sie für ein Dateisystem eine asynchrone Aktualisierung konfigurieren; hierzu binden Sie es mit der Option -o async ein. Wenn Ihr Computer ausreichend stabil ist, sollten Sie auf diese Weise mehr Performance erhalten, ohne zu viel Zuverlässigkeit zu opfern. (Unter Linux ist dieses Flag standardmäßig aktiv.)

7.6.1. Symbolische Verknüpfungen

Sie können Tabellen und Datenbanken aus dem Datenbankverzeichnis an andere Positionen verschieben und sie durch symbolische Verknüpfungen auf diese neuen Positionen ersetzen. Sie könnten dies beispielsweise tun, um eine Datenbank auf ein Dateisystem mit mehr freiem Speicher zu verschieben oder die Geschwindigkeit Ihres Systems durch Verteilen Ihrer Tabellen auf verschiedene Festplatten zu erhöhen.

Die empfohlene Vorgehensweise hierfür besteht schlicht darin, für Datenbanken symbolische Verknüpfungen auf eine andere Festplatte zu erstellen. Symbolische Verknüpfungen für Tabellen sollten hingegen nur als letzter Ausweg verwendet werden.

7.6.1.1. Benutzung symbolischer Links für Datenbanken

Unter Unix erstellen Sie eine symbolische Verknüpfung mit einer Datenbank, indem Sie zuerst ein Verzeichnis auf einer Festplatte erstellen, auf der sich genug freier Speicher befindet, und dann eine symbolische Verknüpfung zu diesem Verzeichnis aus dem MySQL-Datenverzeichnis einrichten.

shell> mkdir /dr1/databases/test
shell> ln -s /dr1/databases/test /path/to/datadir

MySQL unterstützt Verknüpfungen von einem Verzeichnis auf mehrere Datenbanken nicht. Das Ersetzen eines Datenbankverzeichnisses durch eine symbolische Verknüpfung funktioniert, solange Sie keine symbolischen Verknüpfungen zwischen Datenbanken erstellen. Angenommen, Sie haben eine Datenbank db1 im MySQL-Datenverzeichnis und erstellen dann eine symbolische Verknüpfung db2, die auf db1 zeigt:

shell> cd /path/to/datadir
shell> ln -s db1 db2

Im Ergebnis scheint für jede Tabelle tbl_a in db1 offenbar auch eine Tabelle tbl_a in db2 vorhanden zu sein. Wenn ein Client db1.tbl_a und ein anderer Client db2.tbl_a aktualisiert, sind Probleme vorprogrammiert.

Wenn Sie dies aber wirklich tun müssen, ist es möglich, indem Sie die Quelldatei mysys/my_symlink.c ändern. Suchen Sie dort nach folgender Anweisung:

if (!(MyFlags & MY_RESOLVE_LINK) ||
    (!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode)))

Ändern Sie diese wie folgt ab:

if (1)

7.6.1.2. Benutzung symbolischer Links für Tabellen

Auf Systemen, die keinen vollständig funktionsfähigen realpath()-Aufruf aufweisen, sollten Sie Tabellen nicht symbolisch verknüpfen. (Linux und Solaris unterstützen realpath().) Sie können überprüfen, ob Ihr System symbolische Verknüpfungen unterstützt, indem Sie eine SHOW VARIABLES LIKE 'have_symlink'-Anweisung absetzen.

Symbolische Verknüpfungen werden nur bei MyISAM-Tabellen vollständig unterstützt. Bei Dateien, die von auf anderen Speicher-Engines basierenden Tabellen verwendet werden, werden Sie seltsame Probleme bekommen, wenn Sie versuchen, symbolische Verknüpfungen zu verwenden.

Die Verarbeitung symbolischer Verknüpfungen für MyISAM-Tabellen funktioniert wie folgt:

  • Im Datenverzeichnis befinden sich immer die Tabellenformatdatei (.frm-Datei), die Datendatei (.MYD-Datei) und die Indexdatei (.MYI-Datei). Die Daten- und die Indexdatei können an eine andere Position verschoben und durch symbolische Verknüpfungen im Datenverzeichnis ersetzt werden. Für die Formatdatei ist dies nicht möglich.

  • Sie können die Daten- und die Indexdatei separat in verschiedene Verzeichnisse verschieben und durch Verknüpfungen ersetzen.

  • Sie können einen laufenden MySQL Server anweisen, die symbolischen Verknüpfungen mithilfe der Optionen DATA DIRECTORY und INDEX DIRECTORY für CREATE TABLE zu erstellen. Siehe auch Abschnitt 13.1.5, „CREATE TABLE. Alternativ können die Verknüpfungen mithilfe von ln -s auch manuell über die Befehlszeile eingerichtet werden, wenn mysqld nicht ausgeführt wird.

  • myisamchk ersetzt eine symbolische Verknüpfung nicht durch die Daten- oder Indexdatei, sondern bearbeitet direkt die Datei, auf die die Verknüpfung verweist. Temporärdateien werden in dem Verzeichnis erstellt, in dem sich die Daten- bzw. Indexdatei befindet.

  • Hinweis: Wenn Sie eine Tabelle löschen, die symbolische Verknüpfungen erstellt, dann werden sowohl die Verknüpfung als auch die Datei, auf die die Verknüpfung verweist, gelöscht. Dies ist ein ausgesprochen triftiger Grund, warum Sie mysqld nicht als root des Systems ausführen oder Benutzern Schreibzugriff auf die MySQL-Datenbankverzeichnisse gewähren sollten.

  • Wenn Sie eine Tabelle mit ALTER TABLE … RENAME umbenennen und sie nicht in einer Datenbank verschieben, werden die symbolischen Verknüpfungen im Datenbankverzeichnis auf die neuen Namen umgestellt und die Daten- und Indexdatei entsprechend umbenannt.

  • Verwenden Sie ALTER TABLE … RENAME zur Verschiebung einer Tabelle in eine andere Datenbank, dann wird die Tabelle in das andere Datenbankverzeichnis verschoben. Die alten Verknüpfungen und die Dateien, auf die sie verwiesen, werden gelöscht. Dies bedeutet, dass es für die neue Tabelle keine symbolische Verknüpfung gibt.

  • Wenn Sie keine symbolischen Verknüpfungen verwenden, sollten Sie die Option --skip-symbolic-links für mysqld einsetzen, um zu gewährleisten, dass niemand mit mysqld eine Datei außerhalb des Datenverzeichnisses löschen oder umbenennen kann.

Die folgenden tabellenbezogenen Operationen in Verbindung mit symbolischen Verknüpfungen werden noch nicht unterstützt:

  • ALTER TABLE ignoriert die Tabellenoptionen DATA DIRECTORY und INDEX DIRECTORY.

  • BACKUP TABLE und RESTORE TABLE beachten symbolische Verknüpfungen nicht.

  • Die .frm-Datei darf niemals eine symbolische Verknüpfung sein (wie oben bereits angemerkt; nur Daten- und Indexdateien dürfen symbolische Verknüpfungen sein). Wenn Sie dies trotzdem versuchen (um beispielsweise Synonyme zu erstellen), dann erhalten Sie falsche Ergebnisse. Angenommen, Sie haben eine Datenbank db1 im MySQL-Datenverzeichnis und eine Tabelle tbl1 in dieser Datenbank. Nun erstellen Sie im Verzeichnis db1 eine symbolische Verknüpfung tbl2, die auf tbl1 verweist:

    shell> cd /path/to/datadir/db1
    shell> ln -s tbl1.frm tbl2.frm
    shell> ln -s tbl1.MYD tbl2.MYD
    shell> ln -s tbl1.MYI tbl2.MYI
    

    Probleme treten auf, wenn ein Thread db1.tbl1 liest und ein anderer db1.tbl2 aktualisiert:

    • Der Abfrage-Cache wird „hintergangen“ (denn er kann nicht wissen, dass tbl1 nicht geändert wurde, und gibt aufgrund dessen veraltete Ergebnisse zurück).

    • ALTER-Anweisungen für tbl2 schlagen ebenfalls fehl.

7.6.1.3. Daten unter Windows auf verschiedene Platten aufteilen

Symbolische Verknüpfungen sind standardmäßig auf allen Windows-Servern aktiv. Auf diese Weise können Sie ein Datenbankverzeichnis auf eine andere Festplatte verschieben, indem Sie eine Verknüpfung darauf erstellen. Dies ähnelt der Art und Weise, wie symbolische Verknüpfungen unter Unix funktionieren, auch wenn die Vorgehensweise zur Einrichtung der Verknüpfung eine andere ist. Wenn Sie keine symbolischen Verknüpfungen benötigen, können Sie sie mit der Option --skip-symbolic-links deaktivieren.

Unter Windows erstellen Sie eine Verknüpfung mit einer MySQL-Datenbank, indem Sie eine Datei im Datenverzeichnis anlegen, die den Pfad zum Zielverzeichnis enthält. Diese Datei sollte db_name.sym heißen, wobei db_name der Name der Datenbank ist.

Angenommen, das MySQL-Datenverzeichnis heißt C:\mysql\data. Nun wollen Sie, dass die Datenbank foo auf D:\data\foo abgelegt wird. Gehen Sie wie folgt vor, um eine symbolische Verknüpfung zu erstellen:

  1. Vergewissern Sie sich, dass das Verzeichnis D:\data\foo vorhanden ist (andernfalls müssen Sie es erstellen). Wenn sich in Ihrem Datenverzeichnis bereits ein Datenbankverzeichnis namens foo befindet, sollten Sie es nach D:\data verschieben. Andernfalls wird die Verknüpfung unbrauchbar sein. Um Probleme zu vermeiden, stellen Sie sicher, dass der Server beim Verschieben des Datenbankverzeichnisses nicht ausgeführt wird.

  2. Erstellen Sie eine Textdatei namens C:\mysql\data\foo.sym, die den Pfadnamen D:\data\foo\ enthält.

Danach werden alle Tabellen, die Sie in der Datenbank foo anlegen, in D:\data\foo erstellt. Beachten Sie, dass die symbolische Verknüpfung nicht verwendet wird, wenn ein Verzeichnis mit demselben Namen wie die Datenbank im MySQL-Datenverzeichnis vorhanden ist.

Kapitel 8. Client- und Hilfsprogramme

Es gibt eine Vielzahl verschiedener MySQL-Clientprogramme, die Verbindungen mit dem Server herstellen, um auf Datenbanken zuzugreifen oder administrative Aufgaben durchzuführen. Auch andere Hilfsprogramme sind verfügbar. Diese stellen keine Clientverbindung mit dem Server her, sondern führen MySQL-spezifische Operationen durch.

In diesem Kapitel bieten wir einen kurzen Überblick über diese Programme und beschreiben sie nachfolgend jeweils im Detail. In der Beschreibung der Programme sind die Syntax zum Aufruf und die unterstützten Optionen enthalten. In Kapitel 4, Benutzung von MySQL-Programmen, finden Sie allgemeine Informationen zum Aufruf von Programmen und zur Angabe von Programmoptionen.

8.1. Überblick über Client- und Hilfsprogramme

Die folgende Liste stellt eine kurze Beschreibung der MySQL-Clientprogramme und Hilfsprogramme dar:

MySQL AB bietet auch eine Anzahl von Tools mit grafischer Oberfläche an, um MySQL Server zu administrieren oder anderweitig zu bearbeiten. Grundlegende Informationen zu diesen Programmen finden Sie in Kapitel 4, Benutzung von MySQL-Programmen.

Jedes MySQL-Programm akzeptiert viele verschiedene Optionen. Die meisten Programme enthalten eine Option --help, über die Sie eine vollständige Beschreibung der verschiedenen Programmoptionen erhalten können. Probieren Sie z. B. mysql --help aus.

MySQL-Clientprogramme, die unter Verwendung der MySQL-Client/Server-Bibliothek mit dem Server kommunizieren, verwenden die folgenden Umgebungsvariablen:

MYSQL_UNIX_PORTdie vorgabeseitige Unix-Socketdatei. Sie wird für Verbindungen mit localhost verwendet.
MYSQL_TCP_PORTdie Standardportnummer. Wird für TCP/IP-Verbindungen verwendet.
MYSQL_PWDdas Standardpasswort.
MYSQL_DEBUGgibt Trace-Optionen für das Debuggen an.
TMPDIRVerzeichnis, in dem Temporärtabellen und -dateien erstellt werden.

Die Verwendung von MYSQL_PWD ist nicht sicher. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

Sie können die standardmäßigen oder durch Umgebungsvariablen festgelegten Optionswerte für alle Standardprogramme außer Kraft setzen, indem Sie andere Optionen in einer Optionsdatei oder über die Befehlszeile angeben. Siehe auch Abschnitt 4.3, „Angabe von Programmoptionen“.

8.2. myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM

Das Hilfsprogramm myisamchk holt Informationen zu Ihren Datenbanktabellen und überprüft, repariert und optimiert sie. myisamchk funktioniert bei MyISAM-Tabellen (d. h. Tabellen, die über .MYD- und .MYI-Dateien zum Speichern von Daten und Indizes verfügen).

Rufen Sie myisamchk wie folgt auf:

shell> myisamchk [options] tbl_name ...

Mithilfe von Optionen geben Sie myisamchk an, was es tun soll. Diese Optionen sind in den folgenden Abschnitten beschrieben. Eine Liste der Optionen erhalten Sie ferner, indem Sie myisamchk --help aufrufen.

Ohne Angabe von Optionen überprüft myisamchk Ihre Tabelle; dies ist die Standardoperation. Um weitere Informationen abzurufen oder myisamchk zur Durchführung von Korrekturmaßnahmen anzuweisen, geben Sie die Optionen wie nachfolgend beschrieben an.

tbl_name ist dabei die Datenbanktabelle, die Sie überprüfen oder reparieren wollen. Führen Sie myisamchk in einem anderen als dem Datenbankverzeichnis aus, dann müssen Sie den Pfad zum Datenbankverzeichnis angeben, weil myisamchk sonst nicht weiß, wo es die Datenbank suchen soll. Eigentlich ist es myisamchk sogar egal, ob die Dateien, die Sie verarbeiten wollen, sich im Datenbankverzeichnis befinden. Sie können die Dateien, die einer Datenbanktabelle entsprechen, an eine andere Position kopieren und Wiederherstellungsoperationen auch dort vornehmen.

Bei Bedarf können Sie auf der Befehlszeile auch mehrere Tabellen für myisamchk angeben. Ferner ist es möglich, eine Tabelle durch Angabe ihrer Indexdatei (d. h. der Datei mit der Dateierweiterung .MYI) auszuwählen. Auf diese Weise können Sie alle Tabellen in einem Verzeichnis auswählen, indem Sie das Muster *.MYI verwenden. Befinden Sie sich beispielsweise in einem Datenbankverzeichnis, dann können Sie alle dort vorhandenen MyISAM-Tabellen wie folgt überprüfen:

shell> myisamchk *.MYI

Befinden Sie sich nicht im Datenbankverzeichnis, dann können Sie alle dort vorhandenen Tabellen trotzdem überprüfen, indem Sie den Verzeichnispfad angeben:

shell> myisamchk /path/to/database_dir/*.MYI

Sie können sogar alle Tabellen in allen Datenbanken überprüfen. Hierzu geben Sie den Pfad zum MySQL-Datenverzeichnis mit Jokerzeichen an:

shell> myisamchk /path/to/datadir/*/*.MYI

Die empfohlene Vorgehensweise zur schnellen Überprüfung aller MyISAM-Tabellen ist die folgende:

shell> myisamchk --silent --fast /path/to/datadir/*/*.MYI

Wenn Sie alle MyISAM-Tabellen überprüfen und alle ggf. beschädigten Tabellen reparieren wollen, können Sie den folgenden Befehl verwenden:

shell> myisamchk --silent --force --fast --update-state \
          --key_buffer_size=64M --sort_buffer_size=64M \
          --read_buffer_size=1M --write_buffer_size=1M \
          /path/to/datadir/*/*.MYI

Dieser Befehl setzt mindestens 64 Mbyte freien Arbeitsspeicher voraus. Weitere Informationen zur Speicherzuweisung bei myisamchk finden Sie in Abschnitt 8.2.5, „Speicherbenutzung von myisamchk.

Sie müssen sicherstellen, dass kein anderes Programm die Tabellen verwendet, während Sie myisamchk ausführen. Andernfalls kann bei der Ausführung von myisamchk folgende Fehlermeldung angezeigt werden:

warning: clients are using or haven't closed the table properly

Das bedeutet, dass Sie gerade versuchen, eine Tabelle zu überprüfen, die von einem anderen Programm (z. B. dem Server mysqld) verändert wurde, welches die Datei noch nicht geschlossen hat oder abgestürzt ist, bevor es die Datei korrekt schließen konnte.

Wenn mysqld läuft, müssen Sie durch Verwendung von FLUSH TABLES das Synchronisieren aller Änderungen an Tabellen erzwingen, die noch im Speicher gepuffert sind. Nachfolgend müssen Sie sicherstellen, dass kein anderes Programm die Tabellen verwendet, während Sie myisamchk ausführen. Die einfachste Möglichkeit, dieses Problem zu umgehen, ist die Tabellenüberprüfung mit CHECK TABLE anstelle von myisamchk.

8.2.1. Allgemeine Optionen für myisamchk

Die in diesem Abschnitt beschriebenen Optionen können für alle Arten von Wartungsvorgängen verwendet werden, die von myisamchk an Tabellen vorgenommen werden. Die nachfolgenden Abschnitte beschreiben dann Optionen, die spezifisch für bestimmte Operationen wie die Überprüfung oder Reparatur von Tabellen sind.

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --debug=debug_options, -# debug_options

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • --silent, -s

    Stummer Modus. Eine Ausgabe erfolgt nur, wenn ein Fehler auftritt. Sie können -s zweimal angeben (-ss), um myisamchk vollständig zum Verstummen zu bringen.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben. Die Option kann gemeinsam mit -d und -e eingesetzt werden. Verwenden Sie -v mehrfach (-vv, -vvv), um noch mehr Angaben auszugeben.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

  • --wait, -w

    Statt mit einem Fehler beendet zu werden, wenn die Tabelle gesperrt ist, wartet das Programm, bis die Sperre aufgehoben ist, und fährt dann mit der Ausführung fort. Beachten Sie, dass, wenn Sie mysqld mit deaktivierter externer Sperrung ausführen, die Tabelle nur durch einen weiteren myisamchk-Befehl gesperrt werden kann.

Sie können mit der Syntax --var_name=value auch die folgenden Variablen einstellen:

VariableStandardwert
decode_bits9
ft_max_word_lenversionsspezifisch
ft_min_word_len4
ft_stopword_fileintegrierte Liste
key_buffer_size523264
myisam_block_size1024
read_buffer_size262136
sort_buffer_size2097144
sort_key_blocks16
stats_methodnulls_unequal
write_buffer_size262136

Welche myisamchk-Variablen unterstützt werden und welche Standardwerte sie haben, ermitteln Sie mit myisamchk --help:

sort_buffer_size wird benutzt, wenn die Schlüssel durch Sortierung repariert werden, was bei Verwendung von --recover der Normalfall ist.

key_buffer_size verwenden Sie bei der Überprüfung der Tabelle mit --extend-check oder aber dann, wenn die Schlüssel durch Einfügen von Schlüsseldatensätzen in die Tabelle (ähnlich normalen Einfügeoperationen) repariert werden. Die Reparatur über den Schlüsselpuffer wird in den folgenden Fällen verwendet:

  • Sie verwenden --safe-recover.

  • Die zur Sortierung der Schlüssel erforderlichen Temporärdateien wären mehr als doppelt so groß wie bei der direkten Erstellung der Schlüsseldatei. Dies passiert häufig, wenn Sie große Schlüsselwerte für CHAR-, VARCHAR- oder TEXT-Spalten haben, weil im Zuge des Sortiervorgangs die vollständigen Schlüsselwerte gespeichert werden müssen. Wenn Sie viel Speicher für temporäre Daten haben und die Reparatur durch Sortierung mithilfe von myisamchk erzwingen wollen, verwenden Sie die Option --sort-recover.

Die Reparatur über den Schlüsselpuffer benötigt wesentlich weniger Festplattenspeicher als die Sortierung, ist allerdings auch langsamer.

Wenn Sie eine schnellere Reparatur wünschen, setzen Sie die Variablen key_buffer_size und sort_buffer_size auf einen Wert von ca. 25 Prozent Ihres verfügbaren Speichers. Sie können beide Variablen auf hohe Werte setzen, da immer nur eine von ihnen gleichzeitig verwendet wird.

myisam_block_size ist die Größe, die für Indexblöcke verwendet wird.

stats_method beeinflusst, wie NULL-Werte bei der Erfassung von Indexstatistiken behandelt werden, wenn die Option --analyze angegeben wurde. Sie agiert wie die Systemvariable myisam_stats_method. Weitere Informationen entnehmen Sie der Beschreibung von myisam_stats_method in Abschnitt 5.2.2, „Server-Systemvariablen“, und Abschnitt 7.4.7, „Sammlung von MyISAM-Indexstatistiken“.

ft_min_word_len und ft_max_word_len geben die minimale bzw. maximale Wortlänge für FULLTEXT-Indizes an. ft_stopword_file gibt die Datei mit den Stoppwörtern an. Diese Optionen müssen unter den nachfolgend beschriebenen Umständen eingestellt werden.

Wenn Sie mit myisamchk eine Operation durchführen, die Tabellenindizes verändert (dies können etwa Reparatur- oder Analyseoperationen sein), dann werden die FULLTEXT-Indizes unter Verwendung der standardmäßigen Volltextparameterwerte für die minimale und maximale Wortlänge und die Stoppwortdatei verwendet, sofern Sie nichts anderes angeben. Dies kann dazu führen, dass Abfragen fehlschlagen.

Das Problem tritt auf, weil diese Parameter nur dem Server bekannt sind. Sie werden nicht in den MyISAM-Indexdateien gespeichert. Um das Problem zu umgehen, wenn Sie die minimale oder maximale Wortlänge oder die Stoppwortdatei am Server geändert haben, geben Sie dieselben Werte ft_min_word_len, ft_max_word_len und ft_stopword_file für myisamchk an, die Sie für mysqld verwendet haben. Haben Sie also beispielsweise die Mindestwortlänge auf 3 gesetzt, dann können Sie eine Tabelle mit myisamchk wie folgt reparieren:

shell> myisamchk --recover --ft_min_word_len=3 tbl_name.MYI

Wenn Sie gewährleisten wollen, dass myisamchk und der Server dieselben Werte für Volltextparameter verwenden, können Sie sie jeweils in die Abschnitte [mysqld] und [myisamchk] einer Optionsdatei eintragen:

[mysqld]
ft_min_word_len=3

[myisamchk]
ft_min_word_len=3

Eine Alternative zur Verwendung von myisamchk besteht in der Nutzung von REPAIR TABLE, ANALYZE TABLE, OPTIMIZE TABLE oder ALTER TABLE. Diese Anweisungen werden vom Server ausgeführt, der die korrekten Werte der Volltextparameter kennt.

8.2.2. Prüfoptionen für myisamchk

myisamchk unterstützt die folgenden Optionen für Operationen zur Tabellenüberprüfung:

  • --check, -c

    Überprüft die Tabelle auf Fehler. Dies ist die Standardoption; sie wird verwendet, wenn Sie keine Option angeben, die ausdrücklich einen Operationstyp spezifiziert.

  • --check-only-changed, -C

    Überprüft nur Tabellen, die seit der letzten Überprüfung geändert wurden.

  • --extend-check, -e

    Überprüft die Tabelle sehr gründlich. Das kann recht lange dauern, wenn die Tabelle viele Indizes hat. Sie sollten die Option nur in Extremfällen einsetzen. Normalerweise sollten Sie mit myisamchk oder myisamchk --medium-check ermitteln können, ob Fehler in einer Tabelle vorhanden sind.

    Wenn Sie --extend-check verwenden und viel Speicher haben, können Sie die Variable key_buffer_size auf einen großen Wert setzen. Hierdurch wird der Reparaturvorgang schneller ausgeführt.

  • --fast, -F

    Überprüft nur Tabellen, die nicht ordnungsgemäß geschlossen wurden.

  • --force, -f

    Führt eine Reparaturoperation automatisch aus, wenn myisamchk Fehler in der Tabelle findet. Der Reparaturtyp ist derselbe, der auch mit der Option --recover bzw. -r angegeben wird.

  • --information, -i

    Gibt informative Statistiken zur überprüften Tabelle aus.

  • --medium-check, -m

    Führt eine Überprüfung durch, die schneller ist als eine --extend-check-Operation. Hierdurch werden nur 99,99 Prozent aller Fehler gefunden (dies sollte allerdings in den meisten Fällen ausreichend sein).

  • --read-only, -T

    Kennzeichnet die Tabelle nicht als überprüft. Das kann praktisch sein, wenn Sie mit myisamchk eine Tabelle überprüfen, die gerade von einer anderen Anwendung benutzt wird, welche keine Sperrung verwendet. Dies kann beispielsweise mysqld sein, wenn es mit deaktivierter externer Sperrung ausgeführt wird.

  • --update-state, -U

    Speichert Daten in der .MYI-Datei, die angeben, wann die Tabelle zum letzten Mal überprüft wurde und ob sie abgestürzt war. Diese Option sollten Sie verwenden, um die Option --check-only-changed optimal nutzen zu können, nicht jedoch, wenn der Server mysqld die Tabelle verwendet und ohne externe Sperrung ausgeführt wurde.

8.2.3. Reparaturoptionen für myisamchk

myisamchk unterstützt die folgenden Optionen für Operationen zur Tabellenreparatur:

  • --backup, -B

    Erstellt ein Backup der Datei .MYD als file_name-time.BAK.

  • --character-sets-dir=path

    Das Verzeichnis, in dem Zeichensätze installiert sind. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --correct-checksum

    Korrigiert die Prüfsummeninformation für die Tabelle.

  • --data-file-length=len, -D len

    Gibt die maximale Länge der Datendatei an (zur Neuerstellung der Datendatei, wenn diese „voll“ ist).

  • --extend-check, -e

    Führt eine Reparatur durch, die alle Datensätze aus der Datendatei wiederherzustellen versucht, bei denen dies möglich ist. Normalerweise werden hierdurch auch viele nicht mehr erforderliche Datensätze gefunden. Verwenden Sie diese Option nur, wenn Sie vollkommen verzweifelt sind.

  • --force, -f

    Überschreibt alte Zwischendateien (Dateien mit Namen wie tbl_name.TMD) anstatt abzubrechen.

  • --keys-used=val, -k val

    Bei myisamchk ist die Option ein Bitwert, der angibt, welche Indizes aktualisiert werden müssen. Jedes Binärbit des Optionswerts entspricht einem Tabellenindex, wobei der erste Index Bit 0 ist. Der Optionswert 0 deaktiviert Änderungen an allen Indizes, was zur Beschleunigung von Einfügeoperationen genutzt werden kann. Deaktivierte Indizes können mit myisamchk -r reaktiviert werden.

  • --parallel-recover, -p

    Verwendet dieselbe Methode wie -r und -n, erstellt aber alle Schlüssel parallel unter Verwendung verschiedener Threads. Der Code hat bislang nur Betaqualität. Verwendung auf eigene Gefahr!

  • --quick, -q

    Beschleunigt die Reparatur, da die Datendatei nicht geändert wird. Sie können diese Option zweimal angeben, um die Änderung der Originaldatendatei durch myisamchk im Falle von Schlüsseldubletten zu erzwingen.

  • --recover, -r

    Führt eine Reparatur aus, die praktisch jedes Problem behebt (ausgenommen sind eindeutige Schlüssel, die nicht eindeutig sind – ein Fehler, der bei MyISAM-Tabellen extrem selten vorkommt). Wenn Sie eine Tabelle wiederherstellen wollen, sollten Sie diese Option zuerst ausprobieren. --safe-recover sollten Sie nur verwenden, wenn myisamchk meldet, dass die Tabelle mit --recover nicht wiederhergestellt werden kann. (In dem unwahrscheinlichen Fall, dass --recover fehlschlägt, bleibt die Datendatei intakt.)

    Wenn Sie sehr viel Speicher haben, sollten Sie den Wert von sort_buffer_size erhöhen.

  • --safe-recover, -o

    Führt eine Reparatur unter Verwendung einer alten Wiederherstellungsmethode durch, die alle Datensätze der Reihe nach ausliest und alle Indexbäume entsprechend den gefundenen Datensätzen aktualisiert. Dies ist um eine Größenordnung langsamer als --recover, kann aber ein paar sehr unwahrscheinliche Fälle beheben, die --recover nicht korrigiert. Diese Methode verwendet überdies wesentlich weniger Festplattenspeicher als --recover. Normalerweise sollten Sie zuerst eine Reparatur mit --recover durchführen und --safe-recover nur dann verwenden, wenn --recover fehlschlägt.

    Wenn Sie sehr viel Speicher haben, sollten Sie den Wert von key_buffer_size erhöhen.

  • --set-collation=name

    Gibt die für die Tabellen zu verwendende Sortierung an. Dabei wird der Zeichensatzname implizit durch den ersten Teil des Sortierungsnamens festgelegt.

  • --sort-recover, -n

    Erzwingt die Verwendung der Sortierung zur Auflösung von Schlüsseln durch myisamchk auch für den Fall, dass die Temporärdateien sehr groß werden würden.

  • --tmpdir=path, -t path

    Pfad zu dem Verzeichnis, in dem die Temporärdateien gespeichert werden. Wenn diese Einstellung nicht vorgenommen wird, verwendet myisamchk den Wert der Umgebungsvariablen TMPDIR. tmpdir kann eine Liste der Verzeichnispfade enthalten, in denen zyklisch abwechselnd die Temporärdateien erstellt werden. Die Verzeichnispfade sind unter Unix mit Doppelpunkten (‘:’) und unter Windows, NetWare und OS/2 mit Semikola (‘;’) voneinander zu trennen.

  • --unpack, -u

    Entpackt eine Tabelle, die mit myisampack gepackt wurde.

8.2.4. Weitere Optionen für myisamchk

myisamchk unterstützt die folgenden Optionen für andere Vorgänge als die Überprüfung und Reparatur von Tabellen:

  • --analyze, -a

    Analysiert die Verteilung der Schlüsselwerte. Hierdurch wird die Leistungsfähigkeit von Joins verbessert, denn der Join-Optimierer kann die Reihenfolge, in der die Tabellen verknüpft werden, und die zu verwendenden Indizes besser auswählen. Um Angaben zur Schlüsselverteilung zu erhalten, verwenden Sie den Befehl myisamchk --description --verbose tbl_name oder die Anweisung SHOW INDEX FROM tbl_name.

  • --description, -d

    Gibt eine Beschreibung der Tabelle aus.

  • --set-auto-increment[=value], -A[value]

    Erzwingt für neue Datensätze den Start der AUTO_INCREMENT-Nummerierung beim angegebenen Wert (oder einem höheren Wert, sofern Datensätze mit derart großen AUTO_INCREMENT-Werten bereits vorhanden sind). Wenn value nicht angegeben wurde, beginnen die AUTO_INCREMENT-Zahlen für neue Datensätze beim höchsten derzeit in der Tabelle vorhandenen Wert plus 1.

  • --sort-index, -S

    Sortiert die Blöcke des Indexbaums in absteigender Reihenfolge. Hierdurch werden Suchvorgänge optimiert und Tabellenscans, die Indizes benutzen, beschleunigt.

  • --sort-records=N, -R N

    Sortiert Datensätze nach einem bestimmten Index. Hierdurch werden Ihre Daten stärker lokalisiert, und bereichsbasierte SELECT- und ORDER BY-Operationen, die diesen Index benutzen, werden beschleunigt. (Wenn Sie diese Option zur Sortierung einer Tabelle zum ersten Mal verwenden, kann sie sehr langsam arbeiten.) Um die Indexnummern einer Tabelle zu bestimmen, verwenden Sie SHOW INDEX. Hierdurch werden die Indizes einer Tabelle in derselben Reihenfolge angezeigt, in der sie auch myisamchk erkennt. Die Indizes sind beginnend mit 1 nummeriert.

    Wenn die Schlüssel nicht gepackt sind (PACK_KEYS=0)), dann haben sie dieselbe Länge. Insofern überschreibt myisamchk, wenn es Datensätze sortiert und verschiebt, einfach nur Datensatzoffsets im Index. Sind die Schlüssel hingegen gepackt (PACK_KEYS=1), dann muss myisamchk die Schlüsselblöcke zuerst entpacken, dann die Indizes neu erstellen und die Schlüsselblöcke abschließend wieder packen. (In diesem Fall ist die Neuerstellung der Indizes schneller als die Aktualisierung der Offsets für jeden Index.)

8.2.5. Speicherbenutzung von myisamchk

Die Speicherreservierung ist für die Ausführung von myisamchk sehr wichtig. myisamchk verwendet niemals mehr Speicher als über seine speicherbezogenen Variablen angegeben. Wenn Sie myisamchk für sehr große Tabellen verwenden, sollten Sie zunächst entscheiden, wie viel Speicher Sie verwenden wollen. Standardmäßig werden zur Durchführung von Reparaturen nur etwa 3 Mbyte benutzt. Durch Verwendung höherer Werte können Sie die Verarbeitungsgeschwindigkeit von myisamchk beschleunigen. Wenn Sie beispielsweise mehr als 32 Mbyte RAM haben, könnten Sie Optionen wie die folgenden (zusätzlich zu ggf. anderen angegebenen Optionen) verwenden:

shell> myisamchk --sort_buffer_size=16M --key_buffer_size=16M \
           --read_buffer_size=1M --write_buffer_size=1M ...

Die Nutzung von --sort_buffer_size=16M sollte in den meisten Fällen ausreichend sein.

Beachten Sie, dass myisamchk Temporärdateien in TMPDIR benutzt. Wenn TMPDIR auf ein Speicherdateisystem verweist, kann es leicht zu Problemen aufgrund mangelnden Hauptspeichers kommen. In diesem Fall führen Sie myisamchk mit der Option --tmpdir=path aus, um ein Verzeichnis auf einem Dateisystem anzugeben, auf dem mehr Speicher zur Verfügung steht.

Bei der Reparatur benötigt myisamchk auch eine Menge Festplattenkapazität.

  • Die doppelte Größe der Datendatei (einmal für die Originaldatei, einmal für die Kopie). Dieser Festplattenspeicher wird nicht benötigt, wenn Sie eine Reparatur mit der Option --quick durchführen, denn in diesem Fall wird nur die Indexdatei neu erstellt. Der Festplattenspeicher muss auf demselben Dateisystem wie die ursprüngliche Datendatei vorhanden sein! (Das liegt daran, dass die Kopie im gleichen Verzeichnis erstellt wird wie die Originaldatei.)

  • Platz für die neue Indexdatei, die die alte Datei ersetzt. Die alte Indexdatei wird zu Beginn der Reparaturoperation gekürzt, d. h., Sie können diesen Speicherbedarf in der Regel ignorieren. Der Festplattenspeicher muss auf demselben Dateisystem wie die ursprüngliche Indexdatei vorhanden sein!

  • Wenn Sie --recover oder --sort-recover (nicht aber --safe-recover) verwenden, benötigen Sie Platz für einen Sortierpuffer. Die folgende Formel ermöglicht die Berechnung der erforderlichen Kapazität:

    (largest_key + row_pointer_length) × number_of_rows × 2
    

    Sie können die Länge der Schlüssel und row_pointer_length mit myisamchk -dv tbl_name überprüfen. Diese Festplattenkapazität wird im Temporärverzeichnis reserviert, das mit TMPDIR oder --tmpdir=path angegeben wird.

Sollte während der Reparatur ein Problem in Bezug auf den Festplattenspeicher auftreten, dann können Sie --safe-recover statt --recover verwenden.

8.3. myisamlog — Anzeige von MyISAM-Logdateiinhalten

myisamlog verarbeitet den Inhalt einer MyISAM-Logdatei.

Rufen Sie myisamlog wie folgt auf:

shell> myisamlog [options] [log_file [tbl_name] ...]

Die Standardoperation ist die Aktualisierung (-u). Erfolgt eine Wiederherstellung (Option -r), dann werden alle Schreiboperationen und ggf. Änderungen und Löschungen durchgeführt. Fehler werden nur gezählt. Der Standardname der Logdatei lautet myisam.log, sofern kein Argument log_file übergeben wurde. Werden auf der Befehlszeile Tabellen angegeben, dann werden auch nur diese Tabellen aktualisiert.

myisamlog versteht die folgenden Optionen:

  • -?, -I

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • -c N

    Führt nur N Befehle aus.

  • -f N

    Gibt die maximale Anzahl offener Dateien an.

  • -i

    Zeigt vor dem Beenden zusätzliche Informationen an.

  • -o offset

    Gibt den Startoffset an.

  • -p N

    Entfernt N Komponenten aus dem Pfad.

  • -r

    Führt eine Wiederherstellungsoperation durch.

  • -R record_pos_file record_pos

    Gibt die Datensatzpositionsdatei und die Datensatzposition an.

  • -u

    Führt eine Aktualisierungsoperation durch.

  • -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben. Diese Option kann mehrfach angegeben werden, um den Umfang der Ausgabe kontinuierlich zu erhöhen.

  • -w write_file

    Gibt die zu schreibende Datei an.

  • -V

    Zeigt Versionsinformationen an.

8.4. myisampack — Erzeugung komprimierter, schreibgeschützter MyISAM Tabellen

Das Hilfsprogramm myisampack komprimiert MyISAM-Tabellen. Es komprimiert dabei jede Spalte in der Tabelle separat. Normalerweise erzielt myisampack für die Datendatei Komprimierungsraten von 40 bis 70 Prozent.

Wird die Tabelle später verwendet, dann liest der Server die zur Dekomprimierung der Spalten erforderlichen Angaben in den Speicher ein. Hierdurch wird die Leistungsfähigkeit beim Zugriff auf einzelne Datensätze erheblich verbessert, da Sie nur genau einen Datensatz dekomprimieren müssen.

Sofern möglich, verwendet MySQL mmap() für die Speicherzuordnung bei komprimierten Tabellen. Funktioniert mmap() nicht, dann nutzt MySQL ersatzweise normale Schreib- und Leseoperationen für Dateien.

Beachten Sie bitte Folgendes:

  • Wenn der mysqld-Server mit deaktivierter externer Sperrung aufgerufen wurde, sollte myisampack nicht aufgerufen werden, sofern die Möglichkeit besteht, dass die Tabelle während des Komprimierungsvorgangs durch den Server aktualisiert werden könnte. Am besten wird der Server vor der Komprimierung der Tabellen beendet.

  • Wenn eine Tabelle gepackt wurde, ist sie schreibgeschützt. Dies ist normalerweise auch beabsichtigt (z. B. beim Zugriff auf komprimierte Tabellen auf einer CD). Die Möglichkeit, in eine gepackte Tabelle zu schreiben, ist von uns zur mittel- bis langfristigen Implementierung vorgesehen.

  • myisampack kann BLOB- oder TEXT-Spalten packen. (Das ältere Programm pack_isam für ISAM-Tabellen bot diese Möglichkeit nicht.)

Rufen Sie myisampack wie folgt auf:

shell> myisampack [options] file_name ...

Jedes Dateinamensargument sollte der Name einer Indexdatei (.MYI-Datei) sein. Wenn Sie sich nicht im Datenbankverzeichnis befinden, sollten Sie auch den Pfadnamen zu der Datei angeben. Die Erweiterung .MYI dürfen Sie nach Belieben weglassen.

Nachdem Sie eine Tabelle mit myisampack komprimiert haben, sollten Sie myisamchk -rq zur Neuerstellung der Indizes verwenden. Siehe Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“.

myisampack unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --backup, -b

    Erstellt ein Backup der Datendateien aller Tabellen. Die Sicherungsdateien erhalten den Namen tbl_name.OLD.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • --force, -f

    Erzeugt auch dann eine gepackte Tabelle, wenn diese größer als die Ursprungstabelle wird oder noch eine Zwischendatei von myisampack vorhanden ist. (myisampack erzeugt im Verlauf der Komprimierung eine Zwischendatei namens tbl_name.TMD im Datenbankverzeichnis. Wenn Sie myisampack terminieren, dann wird die .TMD-Datei unter Umständen nicht gelöscht.) Normalerweise wird myisampack mit einem Fehler beendet, wenn es eine vorhandene Datei tbl_name.TMD findet. Mit --force packt myisampack die Tabelle jedoch in jedem Fall.

  • --join=big_tbl_name, -j big_tbl_name

    Fasst alle auf der Befehlszeile aufgeführten Tabellen zu einer großen Tabelle big_tbl_name zusammen. Alle Tabellen, die zusammengefasst werden sollen, müssen eine identische Struktur aufweisen (d. h. gleiche Spaltennamen und -typen, gleiche Indizes usw.).

  • --packlength=len, -p len

    Gibt die Speichergröße für die Datensatzlänge (in Byte) an. Der Wert darf zwischen 1 und 3 liegen. myisampack speichert alle Datensätze mit 1, 2 oder 3 Byte langen Längenzeigern. In den meisten normalen Fällen kann myisampack den korrekten Längenwert bestimmen, bevor es mit dem Packen der Datei beginnt. Es kann allerdings während des Packvorgangs feststellen, dass es eine geringere Länge hätte verwenden können. In diesem Fall gibt myisampack einen Hinweis aus, dass Sie, wenn Sie dieselbe Datei beim nächsten Mal packen, eine geringere Datensatzlänge verwenden können.

  • --silent, -s

    Stummer Modus. Eine Ausgabe erfolgt nur, wenn ein Fehler auftritt.

  • --test, -t

    Die Tabelle wird nicht gepackt, sondern das Packen wird lediglich geprüft.

  • --tmpdir=path, -T path

    Verwendet das angegebene Verzeichnis als Position, an der myisamchk Temporärdateien erstellt.

  • --verbose, -v

    Ausführlicher Modus. Gibt Informationen zum Fortschritt des Komprimierungsvorgangs und -ergebnisses aus.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

  • --wait, -w

    Sorgt dafür, dass der Packvorgang nach einer Wartezeit neu versucht wird, wenn die Tabelle gerade verwendet wird. Wenn der mysqld-Server mit deaktivierter externer Sperrung aufgerufen wurde, sollte myisampack nicht aufgerufen werden, sofern die Möglichkeit besteht, dass die Tabelle während des Komprimierungsvorgangs durch den Server aktualisiert werden könnte.

Die nachfolgend gezeigte Befehlsfolge veranschaulicht eine typische Tabellenkomprimierungssitzung:

shell> ls -l station.*
-rw-rw-r--   1 monty    my         994128 Apr 17 19:00 station.MYD
-rw-rw-r--   1 monty    my          53248 Apr 17 19:00 station.MYI
-rw-rw-r--   1 monty    my           5767 Apr 17 19:00 station.frm

shell> myisamchk -dvv station

MyISAM file:     station
Isam-version:  2
Creation time: 1996-03-13 10:08:58
Recover time:  1997-02-02  3:06:43
Data records:              1192  Deleted blocks:              0
Datafile parts:            1192  Deleted data:                0
Datafile pointer (bytes):     2  Keyfile pointer (bytes):     2
Max datafile length:   54657023  Max keyfile length:   33554431
Recordlength:               834
Record format: Fixed length

table description:
Key Start Len Index   Type                 Root  Blocksize    Rec/key
1   2     4   unique  unsigned long        1024       1024          1
2   32    30  multip. text                10240       1024          1

Field Start Length Type
1     1     1
2     2     4
3     6     4
4     10    1
5     11    20
6     31    1
7     32    30
8     62    35
9     97    35
10    132   35
11    167   4
12    171   16
13    187   35
14    222   4
15    226   16
16    242   20
17    262   20
18    282   20
19    302   30
20    332   4
21    336   4
22    340   1
23    341   8
24    349   8
25    357   8
26    365   2
27    367   2
28    369   4
29    373   4
30    377   1
31    378   2
32    380   8
33    388   4
34    392   4
35    396   4
36    400   4
37    404   1
38    405   4
39    409   4
40    413   4
41    417   4
42    421   4
43    425   4
44    429   20
45    449   30
46    479   1
47    480   1
48    481   79
49    560   79
50    639   79
51    718   79
52    797   8
53    805   1
54    806   1
55    807   20
56    827   4
57    831   4

shell> myisampack station.MYI
Compressing station.MYI: (1192 records)
- Calculating statistics

normal:     20  empty-space:   16  empty-zero:     12  empty-fill:  11
pre-space:   0  end-space:     12  table-lookups:   5  zero:         7
Original trees:  57  After join: 17
- Compressing file
87.14%
Remember to run myisamchk -rq on compressed tables

shell> ls -l station.*
-rw-rw-r--   1 monty    my         127874 Apr 17 19:00 station.MYD
-rw-rw-r--   1 monty    my          55296 Apr 17 19:04 station.MYI
-rw-rw-r--   1 monty    my           5767 Apr 17 19:00 station.frm

shell> myisamchk -dvv station

MyISAM file:     station
Isam-version:  2
Creation time: 1996-03-13 10:08:58
Recover time:  1997-04-17 19:04:26
Data records:               1192  Deleted blocks:              0
Datafile parts:             1192  Deleted data:                0
Datafile pointer (bytes):      3  Keyfile pointer (bytes):     1
Max datafile length:    16777215  Max keyfile length:     131071
Recordlength:                834
Record format: Compressed

table description:
Key Start Len Index   Type                 Root  Blocksize    Rec/key
1   2     4   unique  unsigned long       10240       1024          1
2   32    30  multip. text                54272       1024          1

Field Start Length Type                         Huff tree  Bits
1     1     1      constant                             1     0
2     2     4      zerofill(1)                          2     9
3     6     4      no zeros, zerofill(1)                2     9
4     10    1                                           3     9
5     11    20     table-lookup                         4     0
6     31    1                                           3     9
7     32    30     no endspace, not_always              5     9
8     62    35     no endspace, not_always, no empty    6     9
9     97    35     no empty                             7     9
10    132   35     no endspace, not_always, no empty    6     9
11    167   4      zerofill(1)                          2     9
12    171   16     no endspace, not_always, no empty    5     9
13    187   35     no endspace, not_always, no empty    6     9
14    222   4      zerofill(1)                          2     9
15    226   16     no endspace, not_always, no empty    5     9
16    242   20     no endspace, not_always              8     9
17    262   20     no endspace, no empty                8     9
18    282   20     no endspace, no empty                5     9
19    302   30     no endspace, no empty                6     9
20    332   4      always zero                          2     9
21    336   4      always zero                          2     9
22    340   1                                           3     9
23    341   8      table-lookup                         9     0
24    349   8      table-lookup                        10     0
25    357   8      always zero                          2     9
26    365   2                                           2     9
27    367   2      no zeros, zerofill(1)                2     9
28    369   4      no zeros, zerofill(1)                2     9
29    373   4      table-lookup                        11     0
30    377   1                                           3     9
31    378   2      no zeros, zerofill(1)                2     9
32    380   8      no zeros                             2     9
33    388   4      always zero                          2     9
34    392   4      table-lookup                        12     0
35    396   4      no zeros, zerofill(1)               13     9
36    400   4      no zeros, zerofill(1)                2     9
37    404   1                                           2     9
38    405   4      no zeros                             2     9
39    409   4      always zero                          2     9
40    413   4      no zeros                             2     9
41    417   4      always zero                          2     9
42    421   4      no zeros                             2     9
43    425   4      always zero                          2     9
44    429   20     no empty                             3     9
45    449   30     no empty                             3     9
46    479   1                                          14     4
47    480   1                                          14     4
48    481   79     no endspace, no empty               15     9
49    560   79     no empty                             2     9
50    639   79     no empty                             2     9
51    718   79     no endspace                         16     9
52    797   8      no empty                             2     9
53    805   1                                          17     1
54    806   1                                           3     9
55    807   20     no empty                             3     9
56    827   4      no zeros, zerofill(2)                2     9
57    831   4      no zeros, zerofill(1)                2     9

myisampack zeigt die folgenden Informationen an:

  • normal

    Anzahl der Spalten, für die keine zusätzliche Komprimierung verwendet wird.

  • empty-space

    Anzahl der Spalten, die ausschließlich aus Leerzeichen bestehende Werte enthalten. Diese benötigen genau ein Bit.

  • empty-zero

    Anzahl der Spalten, die ausschließlich aus binären Nullen bestehende Werte enthalten. Diese benötigen genau 1 Bit.

  • empty-fill

    Anzahl der Integer-Spalten, die nicht den gesamten Bytebereich des entsprechenden Typs besetzen. Diese werden auf einen kleineren Typ umgestellt. So kann beispielsweise eine BIGINT-Spalte (8 Byte) als TINYINT-Spalte (1 Byte) gespeichert werden, wenn alle in ihr enthaltenen Werte zwischen -128 und 127 liegen.

  • pre-space

    Anzahl der Dezimalspalten, die mit Leerzeichen am Anfang gespeichert werden. In diesem Fall enthält jeder Wert die Anzahl dieser Leerzeichen.

  • end-space

    Anzahl der Spalten, die viele Leerzeichen am Ende aufweisen. In diesem Fall enthält jeder Wert die Anzahl dieser Leerzeichen.

  • table-lookup

    Die Spalte enthielt nur eine kleine Anzahl verschiedener Werte und wurde deswegen vor der Komprimierung in eine ENUM-Spalte konvertiert.

  • zero

    Anzahl der Spalten, in der alle Werte null sind.

  • Original trees

    Anfängliche Anzahl der Huffman-Bäume.

  • After join

    Anzahl der separaten Huffman-Bäume, die nach dem Verknüpfen von Bäumen zum Zwecke der Speicherersparnis übrig bleiben.

Nachdem eine Tabelle komprimiert wurde, zeigt myisamchk -dvv zusätzliche Informationen zu allen Tabellenspalten an:

  • Type

    Der Datentyp. Der Wert kann die folgenden Deskriptoren enthalten:

    • constant

      Alle Datensätze haben denselben Wert.

    • no endspace

      Leerzeichen am Ende nicht speichern.

    • no endspace, not_always

      Leerzeichen am Ende nicht speichern, für alle Werte keine Komprimierung für Leerzeichen am Ende durchführen.

    • no endspace, no empty

      Leerzeichen am Ende nicht speichern. Leere Werte nicht speichern.

    • table-lookup

      Die Spalte wurde in eine ENUM-Spalte konvertiert.

    • zerofill(N)

      Die N höchstwertigen Bytes im Wert sind immer 0 und werden nicht gespeichert.

    • no zeros

      Nullen nicht speichern.

    • always zero

      Nullwerte werden nur mit einem Bit gespeichert.

  • Huff tree

    Anzahl der mit der Spalte verknüpften Huffman-Bäume.

  • Bits

    Anzahl der im Huffman-Baum verwendeten Bits.

Nachdem Sie myisampack ausgeführt haben, müssen Sie myisamchk starten, um die Indizes neu zu erstellen. Zur gleichen Zeit können Sie auch die Indexblöcke sortieren und Statistiken erstellen, die der MySQL-Optimierer benötigt, um effizienter arbeiten zu können:

shell> myisamchk -rq --sort-index --analyze tbl_name.MYI

Nachdem Sie die gepackte Tabelle im MySQL-Datenbankverzeichnis installiert haben, sollten Sie mysqladmin flush-tables ausführen, um die Verwendung der neuen Tabelle durch mysqld zu erzwingen.

Um eine gepackte Tabelle zu entpacken, verwenden Sie die Option --unpack für myisamchk.

8.5. mysql — Das MySQL-Befehlszeilenwerkzeug mysql

mysql ist eine einfache SQL-Shell (mit GNU-readline-Fähigkeiten). Es unterstützt interaktiven wie auch nichtinteraktiven Einsatz. Bei interaktiver Nutzung werden die Abfrageergebnisse im ASCII-Tabellenformat angezeigt. Wird es hingegen nichtinteraktiv verwendet (z. B. als Filter), dann wird das Ergebnis durch Tabulatoren getrennt aufgelistet. Das Ausgabeformat kann mit den folgenden Befehlsoptionen beeinflusst werden.

Wenn Sie bei großen Ergebnismengen Probleme aufgrund mangelnden Speichers haben, verwenden Sie die Option --quick. Hierdurch wird mysql gezwungen, die Ergebnisse datensatzweise vom Server abzurufen, statt vor der Anzeige die gesamte Ergebnismenge zu holen und sie temporär im Speicher abzulegen. Dies wird durch Rückgabe der Ergebnismenge mithilfe der C-API-Funktion mysql_use_result() in der Client/Server-Bibliothek statt mit mysql_store_result() ermöglicht.

Die Verwendung von mysql ist ganz leicht. Rufen Sie es einfach wie folgt über die Eingabeaufforderung Ihres Befehls-Interpreters auf:

shell> mysql db_name

Oder:

shell> mysql --user=user_name --password=your_password db_name

Geben Sie dann eine SQL-Anweisung ein, die auf ‘;’, \g oder \G endet, und betätigen Sie die Eingabetaste.

Sie können SQL-Anweisungen wie folgt in einer Skriptdatei (Stapelverarbeitungsdatei) ausführen:

shell> mysql db_name < script.sql > output.tab

8.5.1. mysql Optionen

mysql unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --batch, -B

    Gibt die Ergebnisse mit einem Tabulator als Spaltentrennzeichen aus. Jeder Datensatz beginnt in einer neuen Zeile. Bei dieser Option verwendet mysql die Verlaufsdatei nicht.

  • --character-sets-dir=path

    Das Verzeichnis, in dem Zeichensätze installiert sind. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --compress, -C

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --database=db_name, -D db_name

    Die zu verwendende Datenbank. Diese Option ist in erster Linie für Optionsdateien gedacht.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'. Standardwert ist 'd:t:o,/tmp/mysql.trace'.

  • --debug-info, -T

    Gibt einige Debuginformationen aus, wenn das Programm beendet wird.

  • --default-character-set=charset_name

    Verwendet charset_name als Standardzeichensatz. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --execute=statement, -e statement

    Führt die Anweisung aus und wird dann beendet. Das Standardausgabeformat entspricht dem mit --batch erzeugten. Einige Beispiele finden Sie in Abschnitt 4.3.1, „Befehlszeilenoptionen für mysqld“.

  • --force, -f

    Das Programm wird auch dann fortgesetzt, wenn ein SQL-Fehler auftritt.

  • --host=host_name, -h host_name

    Stellt eine Verbindung zum MySQL Server auf dem angegebenen Host her.

  • --html, -H

    Erzeugt eine HTML-formatierte Ausgabe.

  • --ignore-space, -i

    Ignoriert Leerzeichen nach Funktionsnamen. Die Auswirkung dieser Option wird in der Erläuterung zu IGNORE_SPACE in Abschnitt 5.2.5, „Der SQL-Modus des Servers“, beschrieben.

  • --local-infile[={0|1}]

    Aktiviert oder deaktiviert die LOCAL-Funktionalität für LOAD DATA INFILE. Ohne angegebenen Wert aktiviert die Option LOCAL. Die Option kann als --local-infile=0 oder als --local-infile=1 angegeben werden, wenn LOCAL ausdrücklich deaktiviert bzw. aktiviert werden soll. Die Aktivierung von LOCAL wirkt sich nicht aus, wenn die Unterstützung durch den Server fehlt.

  • --named-commands, -G

    Aktiviert benannte mysql-Befehle. Neben Befehlen im Kurzformat sind auch solche mit langen Namen zulässig. Beispielsweise werden sowohl quit als auch \q akzeptiert. Siehe auch Abschnitt 8.5.2, „mysql-Befehle“.

  • --no-auto-rehash, -A

    Das automatische Rehashing wird unterbunden. Diese Option sorgt zwar für einen schnelleren Start von mysql, aber Sie müssen den Befehl rehash absetzen, wenn Sie die Vervollständigung von Tabellen- und Spaltennamen verwenden wollen.

  • --no-beep, -b

    Unterbindet die Ausgabe eines Warntons bei Auftreten eines Fehlers.

  • --no-named-commands, -g

    Deaktiviert benannte Befehle. Verwenden Sie nur die Form \* oder setzen Sie benannte Befehle nur am Anfang einer Zeile ein, die mit einem Semikolon (‘;’) endet. mysql startet standardmäßig mit aktivierter Option. Allerdings funktionieren Befehle im langen Format auch bei dieser Option noch in der ersten Zeile. Siehe auch Abschnitt 8.5.2, „mysql-Befehle“.

  • --no-pager

    Die Abfrageergebnisse sollen nicht mit dem Pager (d. h. nicht seitenweise) ausgegeben werden. Abschnitt 8.5.2, „mysql-Befehle“, enthält eine eingehendere Beschreibung zum Pager.

  • --no-tee

    Unterbindet das Kopieren der Ausgabe in einer Datei. Abschnitt 8.5.2, „mysql-Befehle“, enthält eine eingehendere Beschreibung von Tee-Dateien.

  • --one-database, -o

    Ignoriert alle Anweisungen mit Ausnahme derjenigen, die an die auf der Befehlszeile genannte Standarddatenbank gerichtet sind. Dies ist nützlich, um Aktualisierungen anderer Datenbanken im Binärlog zu übergehen.

  • --pager[=command]

    Verwendet den angegebenen Befehl zur Anzeige der Abfrageausgabe Seite für Seite. Wird der Befehl weggelassen, dann wird der Standardpager verwendet, der in Ihrer Umgebungsvariable PAGER gespeichert ist. Gültige Pager sind less, more, cat [> filename] usw. Diese Option wird nur unter Unix verwendet. Im Stapelbetrieb funktioniert sie nicht. Abschnitt 8.5.2, „mysql-Befehle“, enthält eine eingehendere Beschreibung zum Pager.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --prompt=format_str

    Setzt die Eingabeaufforderung auf das angegebene Format. Standardwert ist mysql>. Die Sondersequenzen, die die Eingabeaufforderung enthalten kann, sind unter Abschnitt 8.5.2, „mysql-Befehle“, beschrieben.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --quick, -q

    Unterbindet die Zwischenspeicherung der einzelnen Abfrageergebnisse (d. h., jeder Datensatz wird direkt beim Empfang angezeigt). Hierdurch kann der Server verlangsamt werden, wenn die Ausgabe aussetzt. Bei dieser Option verwendet mysql die Verlaufsdatei nicht.

  • --raw, -r

    Schreibt Spaltenwerte ohne Konvertierung mit Escape-Zeichen. Wird häufig mit der Option --batch verwendet.

  • --reconnect

    Wenn die Verbindung zum Server abbricht, wird automatisch eine Wiederverbindung versucht. Bei jedem Verbindungsabbruch wird genau ein Wiederverbindungsversuch unternommen. Um diese Versuche zu unterbinden, verwenden Sie --skip-reconnect.

  • --safe-updates, --i-am-a-dummy, -U

    Gestattet nur diejenigen UPDATE- und DELETE-Anweisungen, die über Schlüsselwerte angeben, welche Datensätze zu ändern sind. Wenn Sie diese Option in einer Optionsdatei angegeben haben, können Sie sie mithilfe von --safe-updates auf der Befehlszeile außer Kraft setzen. Weitere Informationen zu dieser Option finden Sie in Abschnitt 8.5.4, „mysql: Tipps“.

  • --secure-auth

    Sendet kein Passwort im alten (d. h. vor MySQL 4.1.1 gültigen) Format an den Server. Hierdurch werden Verbindungen auf solche Server beschränkt, die das neue Passwortformat verwenden.

  • --show-warnings

    Sorgt dafür, dass – sofern erforderlich – nach jeder Anweisung Warnungen angezeigt werden. Diese Option gilt für den interaktiven und den Stapelbetrieb.

  • --sigint-ignore

    Ignoriert SIGINT-Signale (diese werden normalerweise durch Eingabe von Strg+C abgesetzt).

  • --silent, -s

    Stummer Modus. Erzeugt weniger Ausgabedaten. Diese Option kann mehrfach angegeben werden, um den Umfang der Ausgabe kontinuierlich zu verringern.

  • --skip-column-names, -N

    Schreibt keine Spaltennamen in die Ergebnisse.

  • --skip-line-numbers, -L

    Schreibt keine Zeilennummern für Fehler. Dies ist praktisch, wenn Sie Ergebnisdateien vergleichen wollen, die Fehlermeldungen enthalten.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --table, -t

    Zeigt die Ausgabe im Tabellenformat an. Dies ist das Standardverhalten bei interaktivem Betrieb und kann zudem für die Ausgabe im Stapelbetrieb verwendet werden.

  • --tee=file_name

    Hängt eine Kopie der Ausgabe an die angegebene Datei an. Diese Option funktioniert im Stapelbetrieb nicht. Eine eingehendere Beschreibung von Tee-Dateien finden Sie in Abschnitt 8.5.2, „mysql-Befehle“.

  • --unbuffered, -n

    Synchronisiert den Puffer nach jeder Abfrage.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms erzeugt. Diese Option kann mehrfach angegeben werden, um den Umfang der Ausgabe kontinuierlich zu erhöhen. (Beispielsweise erzeugt -v -v -v auch im Stapelbetrieb eine Ausgabe im Tabellenformat.)

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

  • --vertical, -E

    Gibt die Abfrageausgabe vertikal angeordnet aus (d. h. eine Zeile pro Spaltenwert). Ohne diese Option können Sie die vertikale Ausgabe für einzelne Anweisungen festlegen, indem Sie sie mit \G abschließen.

  • --wait, -w

    Wenn die Verbindung nicht hergestellt werden kann, erfolgt anstelle eines Abbruchs nach einer Wartezeit ein neuer Verbindungsversuch.

  • --xml, -X

    Erzeugt eine XML-formatierte Ausgabe.

Sie können mit der Syntax --var_name=value auch die folgenden Variablen einstellen:

  • connect_timeout

    Anzahl der Sekunden bis zur Zeitüberschreitung der Verbindung. (Der Vorgabewert ist 0.)

  • max_allowed_packet

    Maximaler Umfang der vom Server gesendeten oder empfangenen Pakete. (Der Vorgabewert ist 16 Mbyte.)

  • max_join_size

    Das automatische Limit für Datensätze in einem Join bei Verwendung von --safe-updates. (Der Vorgabewert beträgt 1.000.000.)

  • net_buffer_length

    Puffergröße für die TCP/IP- und Socketkommunikation. (Der Vorgabewert ist 16 Kbyte.)

  • select_limit

    Automatisches Limit für SELECT-Anweisungen bei Verwendung von --safe-updates. (Der Vorgabewert beträgt 1.000.)

Es ist ferner möglich, Variablen über die Syntax --set-variable=var_name=value oder -O var_name=value einzustellen. Diese Syntax ist jedoch veraltet.

Unter Unix schreibt der mysql-Client einen Eintrag mit ausgeführten Anweisungen in eine Verlaufsdatei. Standardmäßig heißt diese Verlaufsdatei .mysql_history und wird im Stammverzeichnis erstellt. Durch Einstellen der Umgebungsvariablen MYSQL_HISTFILE können Sie eine andere Datei angeben.

Wenn Sie keine Verlaufsdatei führen wollen, entfernen Sie zunächst .mysql_history (sofern vorhanden) und verwenden daraufhin eine der folgenden Methoden:

  • Setzen Sie die Variable MYSQL_HISTFILE auf /dev/null. Damit diese Einstellung bei jeder Anmeldung angewendet wird, müssen Sie sie in eine der Startdateien Ihrer Shell schreiben.

  • Erstellen Sie .mysql_history als symbolische Verknüpfung auf /dev/null:

    shell> ln -s /dev/null $HOME/.mysql_history
    

    Dies müssen Sie nur einmal tun.

8.5.2. mysql-Befehle

mysql sendet jede von Ihnen abgesetzte SQL-Anweisung zur Ausführung an den Server. Es gibt aber auch eine Reihe von Befehlen, die mysql selbst interpretiert. Eine Liste dieser Befehle erhalten Sie, indem Sie help oder \h an der Eingabeaufforderung mysql> eingeben:

mysql> help

List of all MySQL commands:
Note that all text commands must be first on line and end with ';'
?         (\?) Synonym for `help'.
clear     (\c) Clear command.
connect   (\r) Reconnect to the server. Optional arguments are db and host.
delimiter (\d) Set statement delimiter. NOTE: Takes the rest of the line as
               new delimiter.
edit      (\e) Edit command with $EDITOR.
ego       (\G) Send command to mysql server, display result vertically.
exit      (\q) Exit mysql. Same as quit.
go        (\g) Send command to mysql server.
help      (\h) Display this help.
nopager   (\n) Disable pager, print to stdout.
notee     (\t) Don't write into outfile.
pager     (\P) Set PAGER [to_pager]. Print the query results via PAGER.
print     (\p) Print current command.
prompt    (\R) Change your mysql prompt.
quit      (\q) Quit mysql.
rehash    (\#) Rebuild completion hash.
source    (\.) Execute an SQL script file. Takes a file name as an argument.
status    (\s) Get status information from the server.
system    (\!) Execute a system shell command.
tee       (\T) Set outfile [to_outfile]. Append everything into given
               outfile.
use       (\u) Use another database. Takes database name as argument.
warnings  (\W) Show warnings after every statement.
nowarning (\w) Don't show warnings after every statement.

Für jeden Befehl gibt es eine Lang- und eine Kurzform. Anders als bei der Langform wird die Groß-/Kleinschreibung bei der Kurzform unterschieden. Der Langform eines Befehls kann optional ein Semikolon als Trennzeichen folgen; dieses sollte bei der Kurzform weggelassen werden.

Für den Befehl delimiter sollten Sie die Verwendung des Backslashs (‘\’) vermeiden, da dieser bei MySQL als Escape-Zeichen dient.

Die Befehle edit, nopager, pager und system funktionieren nur unter Unix.

Der Befehl status bietet Informationen zur Verbindung und zum verwendeten Server. Wenn der Client mit --safe-updates gestartet wurde, gibt status auch die Werte für die mysql-Variablen aus, die sich auf Ihre Abfragen auswirken.

Um Abfragen und ihre Ausgaben zu loggen, verwenden Sie den Befehl tee. Alle auf dem Bildschirm angezeigten Daten werden an eine angegebene Datei angehängt. Dies kann auch zu Debugzwecken sehr praktisch sein. Sie können diese Funktion auf der Befehlszeile mit der Option --tee oder interaktiv mit dem Befehl tee aktivieren. Die Datei tee kann interaktiv mit dem Befehl notee deaktiviert werden. Die erneute Ausführung von tee reaktiviert das Loggen wieder. Wird kein Parameter angegeben, dann wird die vorherige Datei verwendet. Beachten Sie, dass tee Abfrageergebnisse nach jeder Anweisung synchronisiert – unmittelbar bevor mysql die nächste Eingabeaufforderung anzeigt.

Mithilfe der Option --pager können Sie Abfrageergebnisse im interaktiven Modus mit Unix-Programmen wie less, more o. Ä. durchsuchen. Wenn Sie keinen Wert für die Option angeben, überprüft mysql den Wert der Umgebungsvariablen PAGER und setzt den Pager auf diesen Wert. Interaktiv lässt sich das Paging mithilfe des Befehls pager aktivieren und mit nopager deaktivieren. Der Befehl nimmt ein optionales Argument entgegen; ist es vorhanden, dann wird das entsprechende Pager-Programm ausgewählt. Ohne Argumentangabe wird der Pager, der über die Befehlszeile angegeben wurde, oder stdout ausgewählt (sofern überhaupt kein Pager festgelegt wurde).

Die seitenweise Ausgabe funktioniert nur unter Unix, da sie die Funktion popen() verwendet, die unter Windows nicht existiert. Unter Windows kann stattdessen die Option tee zur Speicherung der Abfrageausgabe verwendet werden, auch wenn dies in bestimmten Situationen zum Durchsuchen der Ausgabe nicht so praktisch ist wie pager.

Es folgen ein paar Tipps zum Befehl pager:

  • Sie können damit in eine Datei schreiben, und die Ergebnisse landen dann auch nur in dieser Datei:

    mysql> pager cat > /tmp/log.txt
    

    Sie können auch Optionen für das Programm übergeben, das Sie als Pager verwenden wollen:

    mysql> pager less -n -i -S
    
  • Beachten Sie die Option -S im obigen Beispiel. Sie kann zum Durchblättern sehr breiter Abfrageergebnisse recht praktisch sein. Manchmal sind sehr breite Ergebnismengen auf dem Bildschirm schlecht zu lesen. Die Option -S für den Befehl less kann die Lesbarkeit der Ergebnisse erheblich steigern, denn sie erlaubt das horizontale Scrolling mit den Pfeiltasten auf der Computertastatur. Sie können die Option -S auch interaktiv innerhalb von less verwenden, um das horizontale Scrolling nach Belieben ein- und auszuschalten. Weitere Informationen finden Sie auf der Manpage zu less:

    shell> man less
    
  • Sie können zur Verarbeitung der Ausgabe sehr komplexe Pager-Befehle angeben:

    mysql> pager cat | tee /dr1/tmp/res.txt \
              | tee /dr2/tmp/res2.txt | less -n -i -S
    

    In diesem Beispiel würde der Befehl die Abfrageergebnisse an zwei Dateien in zwei verschiedenen Verzeichnissen auf zwei separaten Dateisystemen senden, die als /dr1 und /dr2 eingebunden sind. Via less werden die Ergebnisse aber auch auf dem Bildschirm angezeigt.

Sie können die Funktionen von tee und pager auch kombinieren. Wenn Sie eine tee-Datei aktivieren und pager auf less setzen, können Sie die Ergebnisse mit dem Programm less durchsuchen und gleichzeitig alles an eine Datei anhängen. Der Unterschied zwischen tee unter Unix, wenn es mit dem pager-Befehl verwendet wird, und dem in mysql integrierten tee-Befehl besteht darin, dass das integrierte tee auch dann funktioniert, wenn der Unix-Befehl tee nicht vorhanden ist. Außerdem loggt das integrierte tee alles, was auf dem Bildschirm ausgegeben wird; im Gegensatz dazu wird von dem unter Unix mit pager verwendeten tee nicht so viel protokolliert. Zudem lässt sich das tee-Dateiloggen interaktiv aus mysql heraus ein- und ausschalten. Dies ist nützlich, wenn Sie nur einige, nicht aber alle Abfragen in einer Datei loggen wollen.

Die Standardeingabeaufforderung mysql> kann umkonfiguriert werden. Der String zur Definition der Eingabeaufforderung kann die folgenden Spezialsequenzen enthalten:

OptionBeschreibung
\vServerversion
\dStandarddatenbank
\hServerhost
\paktuelle TCP/IP-Port bzw. aktuelle Socketdatei
\uIhr Benutzername
\UIhr vollständiger user_name@host_name-Kontenname
\\literales ‘\’-Backslash-Zeichen
\nZeilenwechselzeichen
\tTabulatorzeichen
\ Leerzeichen (folgt dem Backslash)
\_Leerzeichen
\Raktuelle Uhrzeit im 24-Stunden-Format (0 - 23)
\raktuelle Uhrzeit im 12-Stunden-Format (1 - 12)
\mMinuten der aktuellen Uhrzeit
\yaktuelles Jahr (zweistellig)
\Yaktuelles Jahr (vierstellig)
\Daktuelles vollständiges Datum
\sSekunden der aktuellen Uhrzeit
\waktueller Wochentag, angegeben mit drei Buchstaben („Mon“, „Tue“ usw.)
\PAM/PM
\oaktueller Monat im numerischen Format
\Oaktueller Monat, angegeben mit drei Buchstaben („Jan“, „Feb“ usw.)
\cZähler, der bei jeder von Ihnen abgesetzten Anweisung hochgezählt wird
\SSemikolon
\'einfaches Anführungszeichen
\"doppeltes Anführungszeichen

\’ gefolgt von einem beliebigen anderen Buchstaben wird zu genau diesem Buchstaben.

Wenn Sie den Befehl prompt ohne Argument eingeben, setzt mysql die Eingabeaufforderung auf die Standardform (mysql>) zurück.

Sie können die Eingabeaufforderung auf verschiedene Weise einstellen:

  • Sie verwenden eine Umgebungsvariable. Sie können der Umgebungsvariablen MYSQL_PS1 als Wert einen Eingabeaufforderungs-String zuweisen. Zum Beispiel:

    shell> export MYSQL_PS1="(\u@\h) [\d]> "
    
  • Sie verwenden eine Befehlszeilenoption. Sie können für mysql die Option --prompt auf der Befehlszeile angeben. Zum Beispiel:

    shell> mysql --prompt="(\u@\h) [\d]> "
    (user@host) [database]>
    
  • Sie verwenden eine Optionsdatei. Sie können die Option prompt im Abschnitt [mysql] einer beliebigen MySQL-Optionsdatei (z. B. /etc/my.cnf oder .my.cnf) in Ihrem Stammverzeichnis angeben. Zum Beispiel:

    [mysql]
    prompt=(\\u@\\h) [\\d]>\\_
    

    Beachten Sie in diesem Beispiel die doppelten Backslashs. Wenn Sie die Eingabeaufforderung mit der Option prompt in einer Optionsdatei einstellen, sollten Sie die Backslashes verdoppeln, wenn Sie bestimmte Optionen für die Eingabeaufforderung angeben. Es gibt eine Reihe von Überschneidungen zwischen den zulässigen Optionen für die Eingabeaufforderung und den speziellen Escape-Sequenzen, die in Optionsdateien erkannt werden. (Diese Sequenzen sind in Abschnitt 4.3.2, „my.cnf-Optionsdateien“, aufgelistet.) Diese Überschneidungen können bei Verwendung einzelner Backslashs Probleme verursachen. So wird etwa \s als Leerzeichen statt als aktueller Sekundenwert interpretiert. Das folgende Beispiel zeigt, wie Sie eine Eingabeaufforderung in einer Optionsdatei so definieren, dass die aktuelle Uhrzeit im Format HH:MM:SS> enthalten ist:

    [mysql]
    prompt="\\r:\\m:\\s> "
    
  • Sie stellen die Eingabeaufforderung interaktiv ein. Sie können Ihre Eingabeaufforderung auch interaktiv mithilfe des Befehls prompt (oder \R) einstellen. Zum Beispiel:

    mysql> prompt (\u@\h) [\d]>\_
    PROMPT set to '(\u@\h) [\d]>\_'
    (user@host) [database]>
    (user@host) [database]> prompt
    Returning to default PROMPT of mysql>
    mysql>
    

8.5.3. Wie SQL-Befehle aus einer Textdatei geladen werden

Der Client mysql wird normalerweise interaktiv verwendet. Das sieht etwa so aus:

shell> mysql db_name

Es ist allerdings auch möglich, SQL-Anweisungen in einer Datei abzulegen und mysql dann anzuweisen, seine Eingabe aus dieser Datei auszulesen. Zu diesem Zweck erstellen Sie eine Textdatei text_file, die die Anweisungen enthält, die Sie ausführen wollen. Danach rufen Sie mysql wie folgt auf:

shell> mysql db_name < text_file

Wenn Sie als Erstes eine USE db_name-Anweisung in die Datei setzen, müssen Sie den Datenbanknamen nicht mehr auf der Befehlszeile angeben:

shell> mysql < text_file

Wird mysql bereits ausgeführt, dann können Sie eine SQL-Skriptdatei mithilfe des Befehls source oder \. ausführen:

mysql> source file_name
mysql> \. file_name

In bestimmten Fällen kann es sinnvoll sein, ein Skript Fortschrittsinformationen für den Benutzer anzeigen zu lassen. Hierzu können Sie Anweisungen wie die folgende einfügen:

SELECT '<info_to_display>' AS ' ';

Die gezeigte Anweisung gibt <info_to_display> aus.

Weitere Informationen zum Stapelbetrieb finden Sie in Abschnitt 3.5, „mysql im Stapelbetrieb“.

8.5.4. mysql: Tipps

Dieser Abschnitt beschreibt einige Methoden, mit deren Hilfe Sie mysql effizienter benutzen können.

8.5.4.1. Abfrageergebnisse vertikal anzeigen lassen

Die Lesbarkeit bestimmter Abfrageergebnisse wird erhöht, wenn diese nicht in einem horizontalen, sondern einem vertikalen Tabellenformat angezeigt werden. Die Abfrage wird vertikal angezeigt, indem sie mit \G statt mit einem Semikolon abgeschlossen wird. So lassen sich etwa längere Textwerte mit Zeilenumbrüchen häufig besser lesen, wenn sie vertikal ausgegeben werden:

mysql> SELECT * FROM mails WHERE LENGTH(txt) < 300 LIMIT 300,1\G
*************************** 1. row ***************************
  msg_nro: 3068
     date: 2000-03-01 23:29:50
time_zone: +0200
mail_from: Monty
    reply: monty@no.spam.com
  mail_to: "Thimble Smith" <tim@no.spam.com>
      sbj: UTF-8
      txt: >>>>> "Thimble" == Thimble Smith writes:

Thimble> Hi.  I think this is a good idea.  Is anyone familiar
Thimble> with UTF-8 or Unicode? Otherwise, I'll put this on my
Thimble> TODO list and see what happens.

Yes, please do that.

Regards,
Monty
     file: inbox-jani-1
     hash: 190402944
1 row in set (0.09 sec)

8.5.4.2. Verwendung der Option --safe-updates

Für MySQL-Neulinge kann die Startoption --safe-updates (bzw. --i-am-a-dummy, was den gleichen Effekt hat) ausgesprochen nützlich sein. Sie hilft in Fällen, in denen Sie eine DELETE FROM tbl_name-Anweisung abgesetzt, aber die WHERE-Klausel vergessen haben. Normalerweise werden durch eine solche Anweisung nämlich alle Datensätze in der Tabelle gelöscht. Mit --safe-updates können Sie Datensätze nur dann löschen, wenn die Schlüsselwerte angegeben sind, mit denen sie identifiziert werden. Auf diese Weise werden Unfälle verhindert.

Wenn Sie die Option --safe-updates benutzen, setzt mysql beim Herstellen der Verbindung zum MySQL Server die folgende Anweisung ab:

SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=1000, SQL_MAX_JOIN_SIZE=1000000;

Siehe auch Abschnitt 13.5.3, „SET.

Die Anweisung SET hat die folgenden Auswirkungen:

  • Sie dürfen eine UPDATE- oder DELETE-Anweisung nur dann ausführen, wenn Sie einen Schlüssel-Constraint in der WHERE-Klausel spezifiziert oder eine LIMIT-Klausel angegeben haben (oder beides). Zum Beispiel:

    UPDATE tbl_name SET not_key_column=val WHERE key_column=val;
    
    UPDATE tbl_name SET not_key_column=val LIMIT 1;
    
  • Der Server beschränkt alle umfangreichen SELECT-Ergebnisse auf 1.000 Datensätze, sofern die Anweisung keine LIMIT-Klausel enthält.

  • Der Server bricht tabellenübergreifende SELECT-Anweisungen ab, bei denen voraussichtlich mehr als 1.000.000 Datensatzkombinationen untersucht werden müssten.

Um andere Grenzen als 1.000 und 1.000.000 anzugeben, können Sie die Vorgaben mithilfe der Optionen --select_limit und --max_join_size außer Kraft setzen:

shell> mysql --safe-updates --select_limit=500 --max_join_size=10000

8.5.4.3. Abschalten der automatischen Wiederverbindung in mysql

Wenn die Verbindung zwischen dem mysql-Client und dem Server während des Versands einer Abfrage abbricht, dann versucht der Client, die Verbindung sofort und automatisch wiederherzustellen, und sendet die Abfrage dann erneut. Ihre vorherige Verbindung ist aber auch dann, wenn mysql die Neuverbindung gelingt, definitiv beendet, d. h., alle vorherigen Sitzungsobjekte und Einstellungen sind verloren: Temporärtabellen, Autocommit-Modus und benutzerdefinierte und Sitzungsvariablen. Außerdem wird für alle aktuellen Transaktionen ein Rollback durchgeführt. Dieses Verhalten kann für Sie gefährlich sein. Beachten Sie das folgende Beispiel, in dem der Server heruntergefahren und neu gestartet wurde, ohne dass Sie davon erfahren haben:

mysql> SET @a=1;
Query OK, 0 rows affected (0.05 sec)

mysql> INSERT INTO t VALUES(@a);
ERROR 2006: MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    1
Current database: test

Query OK, 1 row affected (1.30 sec)

mysql> SELECT * FROM t;
+------+
| a    |
+------+
| NULL |
+------+
1 row in set (0.05 sec)

Die Benutzervariable @a ist mit der Verbindung verloren gegangen und nach der Neuverbindung undefiniert. Wenn wichtig ist, dass mysql in dem Fall, dass die Verbindung abreißt, mit einem Fehler beendet wird, dann können Sie den mysql-Client mit der Option --skip-reconnect starten.

8.6. mysqlaccess — Client für die Überprüfung von Zugriffsberechtigungen

mysqlaccess ist ein Diagnosetool, das Yves Carlier für die MySQL-Distribution erstellt hat. Es überprüft die Zugriffsberechtigungen für eine Kombination aus Hostnamen, Benutzernamen und Datenbank. Beachten Sie, dass mysqlaccess den Zugriff nur mithilfe der Tabellen user, db und host überprüft. Nicht verifiziert werden Tabellen-, Spalten- oder Routineberechtigungen, die in den Tabellen tables_priv, columns_priv bzw. procs_priv festgelegt sind.

Rufen Sie mysqlaccess wie folgt auf:

shell> mysqlaccess [host_name [user_name [db_name]]] [options]

mysqlaccess versteht die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --brief, -b

    Erzeugt Berichte in einem einzeiligen tabellarischen Format.

  • --commit

    Kopiert die neuen Zugriffsberechtigungen aus den Temporärtabellen in die ursprünglichen Grant-Tabellen. Damit die neuen Berechtigungen angewendet werden, müssen die Grant-Tabellen auf Festplatte synchronisiert werden. (Führen Sie hierzu etwa den Befehl mysqladmin reload aus.)

  • --copy

    Lädt die temporären Grant-Tabellen aus den Originaltabellen.

  • --db=db_name, -d db_name

    Gibt den Datenbanknamen an.

  • --debug=N

    Gibt die Debugstufe an. N ist ein Integer zwischen 0 und 3.

  • --host=host_name, -h host_name

    Der in den Zugriffsberechtigungen zu verwendende Hostname.

  • --howto

    Zeigt einige Beispiele für die Verwendung von mysqlaccess an.

  • --old_server

    Legt fest, dass der Server ein alter MySQL Server (vor MySQL 3.21) ist, der vollständige WHERE-Klauseln noch nicht verarbeiten kann.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --plan

    Zeigt Vorschläge und Ideen für zukünftige Releases an.

  • --preview

    Zeigt die Unterschiede in den Berechtigungen nach der Durchführung von Änderungen in den Grant-Tabellen an.

  • --relnotes

    Zeigt die Versionshinweise an.

  • --rhost=host_name, -H host_name

    Stellt eine Verbindung zum MySQL Server auf dem angegebenen Host her.

  • --rollback

    Macht die letzten Änderungen an den temporären Grant-Tabellen rückgängig.

  • --spassword[=password], -P[password]

    Verwendet das angegebene Passwort zur Verbindung als Superuser mit dem Server. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --superuser=user_name, -U user_name

    Gibt den Benutzernamen zur Verbindung als Superuser an.

  • --table, -t

    Erzeugt Berichte im Tabellenformat.

  • --user=user_name, -u user_name

    Der in den Zugriffsberechtigungen zu verwendende Benutzername.

  • --version, -v

    Zeigt die Versionsinformation an und wird dann beendet.

Wenn Ihre MySQL-Distribution an einer anderen als der Standardposition installiert ist, müssen Sie die Position ändern, an der mysqlaccess das Vorhandensein des mysql-Clients erwartet. Sie müssen das Skript mysqlaccess im Bereich der Zeile 18 editieren. Suchen Sie nach einer Zeile ähnlich der folgenden:

$MYSQL     = '/usr/local/bin/mysql';    # path to mysql executable

Ändern Sie den Pfad so ab, dass er die Position wiedergibt, an der mysql tatsächlich auf Ihrem System gespeichert ist. Andernfalls erhalten Sie den Fehler Broken pipe, wenn Sie mysqlaccess ausführen.

8.7. mysqladmin — Client für die Verwaltung eines MySQL Servers

mysqladmin ist ein Client zur Durchführung administrativer Aufgaben. Sie können damit Konfiguration und aktuellen Status des Servers überprüfen, Datenbanken erstellen und löschen und vieles mehr.

Rufen Sie mysqladmin wie folgt auf:

shell> mysqladmin [options] command [command-arg] [command [command-arg]] ...

mysqladmin unterstützt die in der folgenden Liste beschriebenen Befehle. Einige Befehle nehmen auf den Befehlsnamen folgend ein Argument entgegen.

  • create db_name

    Erstellt eine neue Datenbank namens db_name.

  • debug

    Weist den Server an, Debuginformationen in das Fehlerlog zu schreiben.

  • drop db_name

    Löscht die Datenbank namens db_name und alle in ihr enthaltenen Tabellen.

  • extended-status

    Zeigt die Serverstatusvariablen und ihre jeweiligen Werte an.

  • flush-hosts

    Synchronisiert alle Daten in den Host-Cache.

  • flush-logs

    Schreibt alle Logs auf Festplatte.

  • flush-privileges

    Lädt die Grant-Tabellen neu (wie reload).

  • flush-status

    Löscht die Statusvariablen.

  • flush-tables

    Synchronisiert alle Tabellen auf Festplatte.

  • flush-threads

    Synchronisiert den Thread-Cache.

  • kill id,id,…

    Terminiert Server-Threads. Werden mehrere Thread-Kennungswerte übergeben, dann dürfen in der Liste keine Leerzeichen enthalten sein.

  • old-password new-password

    Entspricht dem Befehl password, speichert das Passwort aber im alten (vor MySQL 4.1 verwendeten) Hashing-Format. (Siehe auch Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“.)

  • password new-password

    Legt ein neues Passwort fest. Hierdurch wird das Passwort des Kontos, das Sie bei mysqladmin zur Verbindung mit dem Server verwenden, auf new-password gesetzt. Wenn Sie also beim nächsten Mal mysqladmin (oder ein anderes Clientprogramm) über dieses Konto aufrufen, müssen Sie das neue Passwort angeben.

    Wenn der Wert new-password Leerzeichen oder andere Zeichen enthält, die von Ihrem Befehls-Interpreter als Sonderzeichen interpretiert werden, dann müssen Sie es in Anführungszeichen setzen. Dabei sind unter Windows in jedem Fall doppelte statt einfache Anführungszeichen zu benutzen, da Letztere bei der Verarbeitung nicht entfernt, sondern als Teil des Passworts betrachtet werden. Zum Beispiel:

    shell> mysqladmin password "my new password"
    
  • ping

    Überprüft, ob der Server ausgeführt wird. Der Rückgabestatus von mysqladmin ist 0, wenn der Server läuft, andernfalls 1. 0 ist auch im Falle eines Fehlers wie Access denied das Ergebnis, denn hierbei hat der Server die Verbindung zwar abgewiesen, wird aber trotzdem ausgeführt.

  • processlist

    Zeigt eine Liste aktiver Server-Threads an. Dies ähnelt der Ausgabe der Anweisung SHOW PROCESSLIST. Wird die Option --verbose angegeben, dann entspricht die Ausgabe derjenigen von SHOW FULL PROCESSLIST. (Siehe auch Abschnitt 13.5.4.19, „SHOW PROCESSLIST.)

  • reload

    Lädt die Grant-Tabellen neu.

  • refresh

    Synchronisiert alle Tabellen und schließt und öffnet die Logdateien.

  • shutdown

    Beendet den Server.

  • start-slave

    Startet die Replikation auf einem Slave-Server.

  • status

    Zeigt eine kurze Meldung zum Serverstatus an.

  • stop-slave

    Beendet die Replikation auf einem Slave-Server.

  • variables

    Zeigt die Serversystemvariablen und ihre jeweiligen Werte an.

  • version

    Zeigt Versionsinformationen vom Server an.

Alle Befehle lassen sich auf ein beliebiges eindeutiges Präfix kürzen. Zum Beispiel:

shell> mysqladmin proc stat
+----+-------+-----------+----+---------+------+-------+------------------+
| Id | User  | Host      | db | Command | Time | State | Info             |
+----+-------+-----------+----+---------+------+-------+------------------+
| 51 | monty | localhost |    | Query   | 0    |       | show processlist |
+----+-------+-----------+----+---------+------+-------+------------------+
Uptime: 1473624  Threads: 1  Questions: 39487  
Slow queries: 0  Opens: 541  Flush tables: 1  
Open tables: 19  Queries per second avg: 0.0268

Die Ausgabe des Befehls mysqladmin status zeigt die folgenden Werte an:

  • Uptime

    Dauer seit dem Serverstart (in Sekunden).

  • Threads

    Anzahl der aktiven Threads (Clients).

  • Questions

    Anzahl der Abfragen, die seit dem Serverstart von Clients eingegangen sind.

  • Slow queries

    Anzahl der Abfragen, die länger als die durch long_query_time angegebene Anzahl von Sekunden dauerten. Siehe auch Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“.

  • Opens

    Anzahl der Tabellen, die vom Server geöffnet wurden.

  • Flush tables

    Anzahl der vom Server ausgeführten flush-*-, refresh- und reload-Befehle.

  • Open tables

    Anzahl der derzeit offenen Tabellen.

  • Memory in use

    Umfang des Speichers, der direkt von mysqld reserviert wurde. Der Wert wird nur angezeigt, wenn MySQL mit der Option --with-debug=full kompiliert wurde.

  • Maximum memory used

    Maximaler Umfang des Speichers, der direkt von mysqld reserviert wurde. Der Wert wird nur angezeigt, wenn MySQL mit der Option --with-debug=full kompiliert wurde.

Wenn Sie mysqladmin shutdown beim Herstellen einer Verbindung zu einem lokalen Server mithilfe einer Unix-Socketdatei ausführen, wartet mysqladmin, bis die Prozesskennungsdatei des Servers entfernt wurde, um sicherzustellen, dass der Server korrekt beendet wurde.

mysqladmin unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --character-sets-dir=path

    Das Verzeichnis, in dem Zeichensätze installiert sind. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --compress, -C

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --count=N, -c N

    Anzahl der Iterationen, die für die wiederholte Befehlsausführung erforderlich sind. Funktioniert nur mit der Option --sleep.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'. Standardwert ist 'd:t:o,/tmp/mysqladmin.trace'.

  • --default-character-set=charset_name

    Verwendet charset_name als Standardzeichensatz. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --force, -f

    Fordert für den Befehl drop db_name keine Bestätigung an. Bei mehreren Befehlen erfolgt auch bei Auftreten eines Fehlers kein Abbruch.

  • --host=host_name, -h host_name

    Stellt eine Verbindung zum MySQL Server auf dem angegebenen Host her.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --relative, -r

    Zeigt bei gemeinsamer Verwendung mit der Option --sleep den Unterschied zwischen aktuellem und vorherigem Wert. Derzeit funktioniert diese Option nur mit dem Befehl extended-status.

  • --silent, -s

    Wenn keine Verbindung zum Server hergestellt werden kann, erfolgt eine stillschweigende Beendigung.

  • --sleep=delay, -i delay

    Führt Befehle wiederholt aus, wobei dazwischen die mit delay angegebene Anzahl von Sekunden verstreicht. Die Option --count bestimmt die Anzahl der Iterationen.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zur Tätigkeit des Programms ausgegeben.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

  • --vertical, -E

    Erzeugt eine vertikale Ausgabe. Dies ähnelt --relative, die Ausgabe erfolgt jedoch vertikal.

  • --wait[=count], -w[count]

    Wenn die Verbindung nicht hergestellt werden kann, erfolgt anstelle eines Abbruchs nach einer Wartezeit ein neuer Verbindungsversuch. Wenn ein count-Wert spezifiziert wird, gibt dieser die Anzahl der Wiederholungsversuche an. Standardmäßig erfolgt genau eine Wiederholung.

Sie können mit der Syntax --var_name=value auch die folgenden Variablen einstellen:

  • connect_timeout

    Maximale Anzahl der Sekunden bis zur Zeitüberschreitung der Verbindung. Der Vorgabewert ist 43.200 (12 Stunden).

  • shutdown_timeout

    Gibt an (in Sekunden), wie lange auf das Herunterfahren des Servers gewartet wird. Der Vorgabewert ist 3.600 (1 Stunde).

Es ist ferner möglich, Variablen über die Syntax --set-variable=var_name=value oder -O var_name=value einzustellen. Diese Syntax ist jedoch veraltet.

8.8. mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien

Die Binärlogdateien, die der Server erzeugt, sind im Binärformat geschrieben. Um diese Dateien in Textform zu untersuchen, verwenden Sie das Hilfsprogramm mysqlbinlog.

Rufen Sie mysqlbinlog wie folgt auf:

shell> mysqlbinlog [options] log_file ...

Um beispielsweise den Inhalt einer Binärlogdatei namens binlog.000003 anzuzeigen, verwenden Sie folgenden Befehl:

shell> mysqlbinlog binlog.0000003

Die Ausgabe enthält alle Ereignisse, die in binlog.000003 enthalten sind. Zu den einzelnen Ereignisdaten gehören u. a. die ausgeführte Anweisung, die Ausführungsdauer der Anweisung, die Thread-Kennung des absetzenden Clients und der Zeitstempel der Ausführung.

Die Ausgabe von mysqlbinlog kann – beispielsweise durch Verwendung als Eingabe für mysql – neu ausgeführt werden, um die Anweisungen im Log erneut anzuwenden. Dies ist etwa zur Wiederherstellung nach einem Serverabsturz praktisch. Mehr Anwendungsbeispiele finden Sie im weiteren Verlauf dieses Abschnitts.

Normalerweise verwenden Sie mysqlbinlog zum direkten Auslesen von Binärlogdateien und zu deren Anwendung auf den lokalen MySQL Server. Es ist ferner möglich, Binärlogs von einem entfernten Server auszulesen, indem Sie die Option --read-from-remote-server verwenden. Wenn Sie entfernte Binärlogs auslesen, kann mit Verbindungsparameteroptionen angegeben werden, wie die Verbindung zum Server herzustellen ist. Diese Optionen sind --host, --password, --port, --protocol, --socket und --user; sie werden allerdings ignoriert, wenn Sie nicht auch die Option --read-from-remote-server angeben.

Sie können mit mysqlbinlog auch Relay-Logdateien auslesen, die von einem Slave-Server in einer Replikationskonfiguration geschrieben wurden. Relay-Logs haben das gleiche Format wie Binärlogdateien.

Weitere Informationen zu Binär- und Relay-Logs finden Sie in Abschnitt 5.12.3, „Die binäre Update-Logdatei“, und Abschnitt 6.4.4, „Relay- und Statusdateien bei der Replikation“.

mysqlbinlog unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --base64-output

    Gibt alle Binärlogeinträge unter Verwendung der base64-Kodierung aus. Dies dient nur Debugzwecken. Logs, die mithilfe dieser Option erzeugt wurden, sollten nicht auf Produktionssysteme angewendet werden. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --database=db_name, -d db_name

    Listet Einträge nur für genau diese Datenbank auf (nur lokales Log).

  • --force-read, -f

    Mit dieser Option gibt mysqlbinlog, wenn es ein Binärlogereignis liest, das es nicht erkennt, eine Warnung aus, ignoriert das Ereignis und fährt fort. Ohne diese Option beendet sich mysqlbinlog beim Lesen eines solchen Ereignisses.

  • --hexdump, -H

    Zeigt einen hexadezimalen Speicherauszug des Logs in Kommentaren an. Diese Ausgabe kann für das Debuggen der Replikation hilfreich sein. Das Format des hexadezimalen Speicherauszugs wird im weiteren Verlauf dieses Abschnitts beschrieben. Diese Option wurde in MySQL 5.1.2 hinzugefügt.

  • --host=host_name, -h host_name

    Holt das Binärlog vom MySQL Server des angegebenen Hosts.

  • --local-load=path, -l path

    Bereitet lokale Temporärdateien für LOAD DATA INFILE im angegebenen Verzeichnis vor.

  • --offset=N, -o N

    Überspringt die ersten N Einträge im Log.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die zur Verbindung mit einem entfernten Server verwendet werden soll.

  • --position=N, -j N

    Veraltet. Verwenden Sie stattdessen --start-position.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --read-from-remote-server, -R

    Liest das Binärlog von einem MySQL Server, statt eine lokale Logdatei auszulesen. Sofern diese Option nicht angegeben ist, werden auch alle weiteren Verbindungsparameteroptionen ignoriert. Diese Optionen sind --host, --password, --port, --protocol, --socket und --user.

  • --result-file=name, -r name

    Die Ausgabe erfolgt direkt in die angegebene Datei.

  • --server-id=id

    Extrahiert nur diejenigen Ereignisse, die vom Server mit der angegebenen Serverkennung stammen. Diese Option wurde in MySQL 5.1.4 hinzugefügt.

  • --short-form, -s

    Zeigt nur die im Log enthaltenen Anweisungen (d. h. keine zusätzlichen Informationen) an.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --start-datetime=datetime

    Startet das Auslesen des Binärlogs beim ersten Ereignis, dessen Zeitstempel dem durch datetime angegebenen oder einem späteren Zeitpunkt entspricht. Der datetime-Wert ist relativ zur lokalen Zeitzone des Computers, auf dem Sie mysqlbinlog ausführen. Der Wert sollte in einem Format angegeben sein, das für die DATETIME- oder TIMESTAMP-Datentypen unterstützt wird. Zum Beispiel:

    shell> mysqlbinlog --start-datetime="2005-12-25 11:25:56" binlog.000003
    

    Diese Option ist für eine Point-in-Time-Wiederherstellung nützlich. Siehe auch Abschnitt 5.10.2, „Beispielhaftes Vorgehen zur Datensicherung und Wiederherstellung“.

  • --stop-datetime=datetime

    Beendet das Auslesen des Binärlogs beim ersten Ereignis, dessen Zeitstempel dem durch datetime angegebenen oder einem späteren Zeitpunkt entspricht. Diese Option ist für eine Point-in-Time-Wiederherstellung nützlich. Informationen zum datetime-Wert finden Sie weiter oben in der Beschreibung zur Option --start-datetime.

  • --start-position=N

    Startet das Auslesen des Binärlogs beim ersten Ereignis, dessen Position dem Argument N entspricht.

  • --stop-position=N

    Beendet das Auslesen des Binärlogs beim ersten Ereignis, dessen Position N oder höher ist.

  • --to-last-log, -t

    Beendet die Verarbeitung nicht am Ende des bei einem MySQL Server angeforderten Binärlogs, sondern fährt mit der Ausgabe bis zum Ende des letzten Binärlogs fort. Wenn Sie die Ausgabe zum selben MySQL Server leiten, kann dies eine Endlosschleife verursachen. Diese Option erfordert --read-from-remote-server.

  • --disable-log-bin, -D

    Deaktiviert das binäre Loggen. Dies ist nützlich zur Vermeidung einer Endlosschleife, wenn Sie die Option --to-last-log verwenden und die Ausgabe an denselben MySQL Server senden. Ferner ist die Option praktisch bei der Datenwiederherstellung nach einem Absturz: Sie vermeiden hiermit eine Duplizierung der protokollierten Anweisungen.

    Für diese Option benötigen Sie die Berechtigung SUPER. Sie sorgt dafür, dass mysqlbinlog in seine Ausgabe eine SET SQL_LOG_BIN=0-Anweisung einfügt, um das binäre Loggen der restlichen Ausgabe zu deaktivieren. Die SET-Anweisung wird nur dann ausgeführt, wenn Sie die Berechtigung SUPER haben.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem entfernten Server.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

Sie können mit der Syntax --var_name=value auch die folgenden Variablen einstellen:

  • open_files_limit

    Gibt die Anzahl der Deskriptoren für offene Dateien an, die reserviert werden müssen.

Es ist ferner möglich, Variablen über die Syntax --set-variable=var_name=value oder -O var_name=value einzustellen. Diese Syntax ist jedoch veraltet.

Sie können die Ausgabe von mysqlbinlog in den Client mysql umleiten, um die im Binärlog enthaltenen Anweisungen auszuführen. Diese Vorgehensweise dient der Wiederherstellung nach einem Absturz bei Vorhandensein eines alten Backups (siehe Abschnitt 5.10.1, „Datenbank-Datensicherungen“). Zum Beispiel:

shell> mysqlbinlog binlog.000001 | mysql

Oder:

shell> mysqlbinlog binlog.[0-9]* | mysql

Sie können die Ausgabe von mysqlbinlog stattdessen auch in eine Textdatei umleiten, wenn Sie das Anweisungslog zunächst modifizieren müssen (indem Sie beispielsweise Anweisungen entfernen, deren Ausführung Sie aus irgendeinem Grund nicht wünschen). Nach der Editierung der Datei führen Sie die enthaltenen Anweisungen aus, indem Sie sie als Eingabe für das Programm mysql verwenden.

mysqlbinlog verfügt über eine Option --start-position, die nur diejenigen Anweisungen ausgibt, deren Position mindestens der angegebenen Position entspricht (die angegebene Position muss mit dem Start genau eines Ereignisses zusammenfallen). Ferner sind Optionen zum Beenden und Starten bei Erkennung eines Ereignisses mit einem angegebenen Zeitpunkt (Datum und Uhrzeit) vorhanden. Dies ermöglicht Ihnen die Durchführung einer Point-in-Time-Wiederherstellung mithilfe der Option --stop-datetime: Sie können so etwa eine Wiederherstellung nach dem Prinzip „Datenbanken auf den Stand von heute, 10:30 Uhr, setzen“ durchführen.

Wenn Sie mehr als nur ein Binärlog auf dem MySQL Server ausführen wollen, besteht die sichere Methode darin, alle Logs über dieselbe Serververbindung zu verarbeiten. Das folgende Beispiel veranschaulicht, welche Vorgehensweise unsicher sein könnte:

shell> mysqlbinlog binlog.000001 | mysql # DANGER!!
shell> mysqlbinlog binlog.000002 | mysql # DANGER!!

Eine derartige Verarbeitung von Binärlogs über verschiedene Serververbindungen verursacht Probleme, wenn die erste Logdatei eine CREATE TEMPORARY TABLE-Anweisung und das zweite Log eine Anweisung enthält, die die Temporärtabelle verwendet. Wenn der erste mysql-Prozess beendet wird, löscht der Server die Temporärtabelle. Versucht der zweite mysql-Prozess nun auf die Tabelle zuzugreifen, dann meldet der Server eine „unbekannte Tabelle“.

Um solche Probleme zu vermeiden, verwenden Sie stets die gleiche Verbindung zur Ausführung der Inhalte aller Binärlogs, die Sie verarbeiten wollen. Nachfolgend ist eine Möglichkeit beschrieben, dies zu erreichen:

shell> mysqlbinlog binlog.000001 binlog.000002 | mysql

Ein weiterer Ansatz besteht darin, alle Logs in eine einzelne Datei zu schreiben und diese Datei dann zu verarbeiten:

shell> mysqlbinlog binlog.000001 >  /tmp/statements.sql
shell> mysqlbinlog binlog.000002 >> /tmp/statements.sql
shell> mysql -e "source /tmp/statements.sql"

mysqlbinlog kann eine Ausgabe erzeugen, die eine LOAD DATA INFILE-Operation ohne die ursprüngliche Datendatei reproduziert. mysqlbinlog kopiert die Daten in eine Temporärdatei und schreibt eine LOAD DATA LOCAL INFILE-Anweisung, die diese Datei referenziert. Die Standardposition des Verzeichnisses, in das diese Dateien geschrieben werden, ist systemspezifisch. Um ein Verzeichnis explizit anzugeben, verwenden Sie die Option --local-load.

Da mysqlbinlog LOAD DATA INFILE- in LOAD DATA LOCAL INFILE-Anweisungen konvertiert (d. h. LOCAL ergänzt), müssen sowohl der Client als auch der Server, den Sie zur Verarbeitung der Anweisungen verwenden, so konfiguriert sein, dass LOCAL unterstützt wird. Siehe auch Abschnitt 5.7.4, „Sicherheitsprobleme mit LOAD DATA LOCAL.

Warnung: Die für die LOAD DATA LOCAL-Anweisungen erstellten Temporärdateien werden nicht automatisch gelöscht, weil sie benötigt werden, bis Sie diese Anweisungen tatsächlich ausführen. Sie sollten die Temporärdateien also selbst entfernen, wenn Sie das Anweisungslog nicht mehr benötigen. Die Dateien befinden sich im Temporärdateiverzeichnis und haben Namen wie original_file_name-#-#.

Die Option --hexdump erzeugt einen hexadezimalen Speicherauszug („Hex-Dump“) des Loginhalts in Kommentaren:

shell> mysqlbinlog --hexdump master-bin.000001

Beim obigen Befehl sieht die Ausgabe etwa so aus:

/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
# at 4
#051024 17:24:13 server id 1  end_log_pos 98
# Position  Timestamp   Type   Master ID        Size      Master Pos    Flags
# 00000004 9d fc 5c 43   0f   01 00 00 00   5e 00 00 00   62 00 00 00   00 00
# 00000017 04 00 35 2e 30 2e 31 35  2d 64 65 62 75 67 2d 6c |..5.0.15.debug.l|
# 00000027 6f 67 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |og..............|
# 00000037 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |................|
# 00000047 00 00 00 00 9d fc 5c 43  13 38 0d 00 08 00 12 00 |.......C.8......|
# 00000057 04 04 04 04 12 00 00 4b  00 04 1a                |.......K...|
#       Start: binlog v 4, server v 5.0.15-debug-log created 051024 17:24:13
#       at startup
ROLLBACK;

Die Hex-Dump-Ausgabe enthält derzeit die nachfolgend aufgeführten Elemente. Das Format kann sich allerdings bei zukünftigen Versionen ändern.

  • Position: Byteposition in der Logdatei.

  • Timestamp: Zeitstempel des Ereignisses. Im gezeigten Beispiel ist '9d fc 5c 43' die Darstellung von '051024 17:24:13' in hexadezimaler Form.

  • Type: Typ des Logereignisses. Im gezeigten Beispiel bedeutet '0f', dass das Beispielereignis FORMAT_DESCRIPTION_EVENT ist. Die nachfolgende Tabelle listet mögliche Typen auf.

    Geben Sie nun Folgendes ein:NameBedeutung
    00UNKNOWN_EVENTDieses Ereignis sollte keinesfalls im Log vorhanden sein.
    01START_EVENT_V3Zeigt den Anfang einer Logdatei an, die von MySQL 4 oder früher geschrieben wurde.
    02QUERY_EVENTDer häufigste Ereignistyp. Er bezeichnet Anweisungen, die auf dem Master-Server ausgeführt wurden.
    03STOP_EVENTGibt an, dass der Master beendet wurde.
    04ROTATE_EVENTWird geschrieben, wenn der Master eine neue Logdatei eröffnet.
    05INTVAR_EVENTWird hauptsächlich für AUTO_INCREMENT-Werte und in Situationen verwendet, in denen die LAST_INSERT_ID()-Funktion in der Anweisung verwendet wird.
    06LOAD_EVENTWird für LOAD DATA INFILE in MySQL 3.23 verwendet.
    07SLAVE_EVENTFür zukünftige Verwendung reserviert.
    08CREATE_FILE_EVENTWird für LOAD DATA INFILE-Anweisungen verwendet. Hiermit wird der Start der Ausführung einer solchen Anweisung angezeigt. Auf dem Slave-Server wird eine Temporärdatei erstellt. Wird nur in MySQL 4 verwendet.
    09APPEND_BLOCK_EVENTEnthält Daten, die in einer LOAD DATA INFILE-Anweisung verwendet werden. Die Daten werden in einer Temporärdatei auf dem Slave gespeichert.
    0aEXEC_LOAD_EVENTWird für LOAD DATA INFILE-Anweisungen verwendet. Der Inhalt der Temporärdatei wird in der Tabelle auf dem Slave gespeichert. Wird nur in MySQL 4 verwendet.
    0bDELETE_FILE_EVENTRollback einer LOAD DATA INFILE-Anweisung. Die Temporärdatei auf dem Slave sollte gelöscht werden.
    0cNEW_LOAD_EVENTWird für LOAD DATA INFILE in MySQL 4 und früher verwendet.
    0dRAND_EVENTWird für den Versand von Informationen zu Zufallswerten benutzt, wenn die Funktion RAND() in der Anweisung verwendet wird.
    0eUSER_VAR_EVENTDient der Replikation von Benutzervariablen.
    0fFORMAT_DESCRIPTION_EVENTZeigt den Anfang einer Logdatei an, die von MySQL 5 oder später geschrieben wurde.
    10XID_EVENTEreignis, welches das Schreiben einer XA-Transaktion anzeigt.
    11BEGIN_LOAD_QUERY_EVENTWird für LOAD DATA INFILE-Anweisungen in MySQL 5 und höher verwendet.
    12EXECUTE_LOAD_QUERY_EVENTWird für LOAD DATA INFILE-Anweisungen in MySQL 5 und höher verwendet.
    13TABLE_MAP_EVENTFür zukünftige Verwendung reserviert.
    14WRITE_ROWS_EVENTFür zukünftige Verwendung reserviert.
    15UPDATE_ROWS_EVENTFür zukünftige Verwendung reserviert.
    16DELETE_ROWS_EVENTFür zukünftige Verwendung reserviert.
  • Master ID: Serverkennung des Masters, der das Ereignis erstellt hat.

  • Size: Größe des Ereignisses in Byte.

  • Master Pos: Position des Ereignisses in der ursprünglichen Logdatei auf dem Master.

  • Flags: 16 Flags. Zurzeit werden die nachfolgend aufgeführten Flags verwendet. Die übrigen sind für zukünftige Verwendung reserviert.

    FlagNameBedeutung
    01LOG_EVENT_BINLOG_IN_USE_FLogdatei korrekt geschlossen. (Wird nur in FORMAT_DESCRIPTION_EVENT verwendet.) Wenn bei einem Ereignis FORMAT_DESCRIPTION_EVENT das Flag gesetzt ist (d. h. wenn der Flagwert beispielsweise '01 00' lautet), dann wurde die Logdatei nicht korrekt geschlossen. In aller Regel liegt dies an einem Absturz des Masters (etwa aufgrund eines Stromausfalls).
    02 Für zukünftige Verwendung reserviert.
    04LOG_EVENT_THREAD_SPECIFIC_FIst gesetzt, wenn das Ereignis von der Verbindung abhängig ist, über die es erfolgte (z. B. '04 00'). Ein solcher Fall liegt etwa vor, wenn das Ereignis Temporärtabellen verwendet.
    08LOG_EVENT_SUPPRESS_USE_FWird unter bestimmten Umständen gesetzt, wenn das Ereignis nicht von der Standarddatenbank abhängt.

    Die übrigen Flags sind für eine zukünftige Verwendung reserviert.

8.9. mysqlcheck — Hilfsprogramm für die Wartung und Reparatur von Tabellen

Der Client mysqlcheck prüft, repariert, optimiert und analysiert Tabellen.

mysqlcheck ähnelt hinsichtlich seines Funktionsumfangs myisamchk, funktioniert aber anders. Der wesentliche Unterschied besteht darin, dass mysqlcheck verwendet werden muss, wenn der Server mysqld ausgeführt wird, wohingegen myisamchk verwendet werden sollte, wenn er nicht läuft. Der Vorteil der Verwendung von mysqlcheck besteht darin, dass Sie den Server nicht beenden müssen, um Ihre Tabellen zu überprüfen oder zu reparieren.

mysqlcheck verwendet die SQL-Anweisungen CHECK TABLE, REPAIR TABLE, ANALYZE TABLE und OPTIMIZE TABLE auf eine für den Benutzer praktische Weise. Das Programm bestimmt, welche Anweisungen für die gewünschte Operation durchzuführen sind, und sendet diese Anweisungen dann zur Ausführung an den Server. Weitere Informationen dazu, bei welchen Speicher-Engines die jeweiligen Anweisungen funktionieren, finden Sie in Kapitel 13, SQL-Anweisungssyntax.

Die MyISAM-Speicher-Engine unterstützt alle vier Anweisungen, d. h., mysqlcheck kann zur Durchführung aller vier Operationen an MyISAM-Tabellen verwendet werden. Andere Speicher-Engines unterstützen nicht unbedingt alle Operationen. Gegebenenfalls wird eine Fehlermeldung angezeigt. Wenn beispielsweise test.t eine MEMORY-Tabelle ist, dann führt der Versuch, sie zu überprüfen, zu folgendem Ergebnis:

shell> mysqlcheck test t
test.t
note     : The storage engine for the table doesn't support check

Es gibt drei Möglichkeiten, mysqlcheck aufzurufen:

shell> mysqlcheck [options] db_name [tables]
shell> mysqlcheck [options] --databases db_name1 [db_name2 db_name3...]
shell> mysqlcheck [options] --all-databases

Wenn Sie auf db_name folgend keine Tabellen aufführen oder die Optionen --databases oder --all-databases verwenden, dann werden ganze Datenbanken überprüft.

mysqlcheck bietet eine im Vergleich zu anderen Clientprogrammen spezielle Funktion. Das Standardverhalten des Überprüfens von Tabellen (--check) kann geändert werden, indem die Binärdatei umbenannt wird. Wenn Sie ein Tool benötigen, das Tabellen standardmäßig repariert, sollten Sie einfach eine Kopie von mysqlcheck namens mysqlrepair oder eine symbolische Verknüpfung zu mysqlcheck namens mysqlrepair erstellen. Wenn Sie dann mysqlrepair aufrufen, werden die Tabellen standardmäßig repariert.

Die folgenden Namen können verwendet werden, um das Standardverhalten von mysqlcheck zu ändern:

mysqlrepairDie Standardoption ist --repair.
mysqlanalyzeDie Standardoption ist --analyze.
mysqloptimizeDie Standardoption ist --optimize.

mysqlcheck unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --all-databases, -A

    Überprüft alle Tabellen in allen Datenbanken. Dies entspricht der Option --databases bei gleichzeitiger Nennung aller Datenbanken auf der Befehlszeile.

  • --all-in-1, -1

    Statt eine Anweisung für jede Tabelle einzeln abzusetzen, wird eine einzelne Anweisung für jede Datenbank ausgeführt, die alle zu verarbeitenden Tabellen aus dieser Datenbank benennt.

  • --analyze, -a

    Analysiert die Tabellen.

  • --auto-repair

    Wenn eine überprüfte Tabelle beschädigt ist, wird sie automatisch repariert. Reparaturarbeiten werden erledigt, nachdem alle Tabellen überprüft wurden.

  • --character-sets-dir=path

    Das Verzeichnis, in dem Zeichensätze installiert sind. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --check, -c

    Überprüft die Tabellen auf Fehler. Dies ist die Standardoperation.

  • --check-only-changed, -C

    Überprüft nur solche Tabellen, die seit der letzten Überprüfung geändert oder aber nicht korrekt geschlossen wurden.

  • --compress

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --databases, -B

    Verarbeitet alle Tabellen in den aufgeführten Datenbanken. Normalerweise betrachtet mysqlcheck das erste Namensargument auf der Befehlszeile als Datenbank- und alle nachfolgenden Argumente als Tabellennamen. Bei dieser Option hingegen werden alle Namensargumente als Datenbanknamen behandelt.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • --default-character-set=charset_name

    Verwendet charset_name als Standardzeichensatz. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --extended, -e

    Wenn Sie diese Option zur Überprüfung von Tabellen einsetzen, ist sichergestellt, dass diese hundertprozentig konsistent sind; der Vorgang dauert allerdings sehr lange.

    Wenn Sie die Option bei der Reparatur von Tabellen einsetzen, wird eine erweiterte Reparatur durchgeführt, deren Ausführung nicht nur extrem lange dauert, sondern die auch eine Menge überflüssiger Datensätze erzeugt!

  • --fast, -F

    Überprüft nur Tabellen, die nicht ordnungsgemäß geschlossen wurden.

  • --force, -f

    Das Programm wird auch dann fortgesetzt, wenn ein SQL-Fehler auftritt.

  • --host=host_name, -h host_name

    Stellt eine Verbindung zum MySQL Server auf dem angegebenen Host her.

  • --medium-check, -m

    Führt eine Überprüfung durch, die schneller ist als eine --extended-Operation. Hierdurch werden nur 99,99 Prozent aller Fehler gefunden (dies sollte allerdings in den meisten Fällen ausreichend sein).

  • --optimize, -o

    Optimiert die Tabellen.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --quick, -q

    Wenn Sie mit dieser Option Tabellen überprüfen, wird verhindert, dass die Datensätze auf falsche Verknüpfungen geprüft werden. Dies ist die schnellste Prüfmethode.

    Wenn Sie die Option bei der Reparatur von Tabellen einsetzen, wird versucht, nur den Indexbaum zu reparieren. Dies ist die schnellste Reparaturmethode.

  • --repair, -r

    Führt eine Reparatur durch, die fast alle Fehler beheben kann. Ausgenommen sind lediglich eindeutige Schlüssel, die nicht eindeutig sind.

  • --silent, -s

    Stummer Modus. Gibt nur Fehlermeldungen aus.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --tables

    Setzt die Option --databases bzw. -B außer Kraft. Alle auf die Option folgenden Namensargumente werden als Tabellennamen betrachtet.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Gibt Informationen zu den verschiedenen Stufen des Programmablaufs aus.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

8.10. mysqldump — Programm zur Datensicherung

Der Client mysqldump ist ein Sicherungsprogramm, das ursprünglich von Igor Romanenko geschrieben wurde. Er kann zur Erstellung eines Speicherauszugs einer Datenbank oder einer Sammlung von Datenbanken zu Sicherungszwecken oder zur Übertragung von Daten auf einen anderen SQL-Server verwendet werden (dies muss nicht unbedingt ein MySQL Server sein). Der Speicherauszug enthält SQL-Anweisungen zur Erstellung und/oder zum Ausfüllen einer Tabelle.

Wenn Sie eine Sicherung auf dem Server durchführen und es sich bei Ihren Tabellen ausschließlich um MyISAM-Tabellen handelt, sollten Sie stattdessen die Verwendung von mysqlhotcopy in Betracht ziehen, weil dies Sicherung und Wiederherstellung erheblich beschleunigt. Siehe auch Abschnitt 8.11, „mysqlhotcopy — Backup-Programm für Datenbanken“.

Es gibt drei Möglichkeiten, mysqldump aufzurufen:

shell> mysqldump [options] db_name [tables]
shell> mysqldump [options] --databases db_name1 [db_name2 db_name3...]
shell> mysqldump [options] --all-databases

Wenn Sie auf db_name folgend keine Tabellen aufführen oder die Optionen --databases oder --all-databases verwenden, dann werden Speicherauszüge ganzer Datenbanken erstellt.

Um eine Liste der Optionen zu erhalten, die Ihre Version von mysqldump unterstützt, führen Sie mysqldump --help aus.

Wenn Sie mysqldump ohne die Optionen --quick oder --opt ausführen, lädt mysqldump den gesamten Ergebnissatz in den Speicher, bevor der Speicherauszug erstellt wird. Dies kann bei einem Speicherauszug einer großen Datenbank ein Problem darstellen. Standardmäßig ist die Option --opt aktiviert, kann aber mit --skip-opt deaktiviert werden.

Wenn Sie eine relativ aktuelle Kopie von mysqldump zur Erzeugung eines Speicherauszugs verwenden, der in einen sehr alten MySQL Server geladen werden soll, dann sollten Sie die Optionen --opt oder --extended-insert nicht benutzen. Verwenden Sie stattdessen --skip-opt.

mysqldump unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --add-drop-database

    Fügt eine DROP DATABASE-Anweisung vor jede CREATE DATABASE-Anweisung ein.

  • --add-drop-table

    Fügt eine DROP TABLE-Anweisung vor jede CREATE TABLE-Anweisung ein.

  • --add-locks

    Setzt jeden Tabellenspeicherauszug zwischen eine LOCK TABLES- und eine UNLOCK TABLES-Anweisung. Hierdurch werden die Einfügevorgänge beim Neuladen der Speicherauszugsdatei beschleunigt. Siehe auch Abschnitt 7.2.16, „Geschwindigkeit von INSERT-Anweisungen“.

  • --all-databases, -A

    Erstellt einen Speicherauszug aller Tabellen in allen Datenbanken. Dies entspricht der Option --databases bei gleichzeitiger Nennung aller Datenbanken auf der Befehlszeile.

  • --all-tablespaces, -Y

    Fügt zum Tabellenspeicherauszug alle SQL-Anweisungen hinzu, die zur Erstellung von Tablespaces für eine NDB Cluster-Tabelle erforderlich sind. Diese Informationen können nur auf diese Weise in der Ausgabe von mysqldump angegeben werden. Die Option ist derzeit nur für MySQL-Cluster-Tabellen relevant.

    Diese Option wurde in MySQL 5.1.6 hinzugefügt.

  • --allow-keywords

    Erlaubt die Erstellung von Spaltennamen, die Schlüsselwörter sind. Dies funktioniert, indem jedem Spaltennamen der Tabellenname vorangestellt wird.

  • --comments[={0|1}]

    Wenn 0 angegeben wird, unterdrückt die Option zusätzliche Informationen in der Speicherauszugsdatei wie etwa Programmversion, Serverversion und Host. --skip-comments hat den gleichen Effekt wie --comments=0. Der Standardwert ist 1, d. h., die genannten Informationen sind enthalten.

  • --compact

    Erzeugt eine weniger ausführliche Ausgabe. Die Option unterdrückt Kommentare und aktiviert die Optionen --skip-add-drop-table, --no-set-names, --skip-disable-keys und --skip-add-locks.

  • --compatible=name

    Erzeugt eine Ausgabe, bei der die Kompatibilität mit anderen Datenbanksystemen oder älteren MySQL Servern höher ist. name kann folgende Werte annehmen: ansi, mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, no_table_options oder no_field_options. Um mehrere Werte zu verwenden, trennen Sie diese durch Kommata. Diese Werte haben dieselbe Bedeutung wie die entsprechenden Optionen zur Einstellung des SQL-Modus am Server. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

    Die Option garantiert keine Kompatibilität mit anderen Servern. Vielmehr aktiviert sie nur diejenigen SQL-Moduswerte, die zum gegebenen Zeitpunkt verfügbar sind, um die Kompatibilität der Speicherauszugsausgabe zu erhöhen. So führt --compatible=oracle weder eine Zuordnung von Datentypen zu Oracle-Typen durch noch wird die Oracle-Kommentarsyntax verwendet.

  • --complete-insert, -c

    Verwendet vollständige INSERT-Anweisungen, die auch Spaltennamen enthalten.

  • --compress, -C

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --create-options

    Fügt alle MySQL-spezifischen Tabellenoptionen in die CREATE TABLE-Anweisungen ein.

  • --databases, -B

    Erstellt einen Speicherauszug mehrerer Datenbanken. Normalerweise betrachtet mysqldump das erste Namensargument auf der Befehlszeile als Datenbank- und alle nachfolgenden Argumente als Tabellennamen. Bei dieser Option werden jedoch alle Namensargumente als Datenbanknamen betrachtet. CREATE DATABASE- und USE-Anweisungen werden für jede neue Datenbank in die Ausgabe eingefügt.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'. Standardwert ist 'd:t:o,/tmp/mysqldump.trace'.

  • --default-character-set=charset_name

    Verwendet charset_name als Standardzeichensatz. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“. Sofern nicht angegeben, verwendet mysqldump utf8.

  • --delayed-insert

    Schreibt INSERT DELAYED- statt INSERT-Anweisungen.

  • --delete-master-logs

    Löscht auf einem Master-Replikationsserver nach Erstellung des Speicherauszugs die Binärlogs. Diese Option aktiviert automatisch --master-data.

  • --disable-keys, -K

    Setzt bei jeder Tabelle die INSERT-Anweisungen zwischen /*!40000 ALTER TABLE tbl_name DISABLE KEYS */;- und /*!40000 ALTER TABLE tbl_name ENABLE KEYS */;-Anweisungen. Dies beschleunigt das Laden der Speicherauszugsdatei, weil die Indizes nach Einfügen aller Datensätze erstellt werden. Diese Option ist nur bei MyISAM-Tabellen wirksam.

  • --extended-insert, -e

    Verwendet die INSERT-Syntax für mehrere Datensätze (diese enthält verschiedene VALUES-Listen). Ergebnis sind eine kleinere Speicherauszugsdatei und beschleunigte Einfügeoperationen beim Neuladen der Datei.

  • --fields-terminated-by=…, --fields-enclosed-by=…, --fields-optionally-enclosed-by=…, --fields-escaped-by=…, --lines-terminated-by=…

    Diese Optionen werden mit der Option -T verwendet und haben dieselben Bedeutungen wie die jeweiligen Klauseln für LOAD DATA INFILE. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

  • --first-slave, -x

    Veraltet. Heißt jetzt --lock-all-tables.

  • --flush-logs, -F

    Synchronisiert die Logdateien des MySQL Servers auf Festplatte, bevor der Speicherauszugsvorgang gestartet wird. Diese Option erfordert die Berechtigung RELOAD. Beachten Sie, dass, wenn Sie diese Option in Verbindung mit der Option --all-databases (bzw. -A) verwenden, die Logs für jede Datenbank, für die ein Speicherauszug erstellt wird, synchronisiert werden. Eine Ausnahme liegt vor, wenn Sie --lock-all-tables oder --master-data verwenden: In diesem Fall werden die Logs nur einmal geschrieben, und zwar in dem Augenblick, in dem alle Tabellen gesperrt sind. Wenn Sie wollen, dass Speicherauszug und Logsynchronisierung im exakt gleichen Moment erfolgen, sollten Sie --flush-logs wahlweise gemeinsam mit --lock-all-tables oder --master-data verwenden.

  • --force, -f

    Setzt die Ausführung auch dann fort, wenn ein SQL-Fehler während eines Speicherauszugsvorgangs auftritt.

  • --host=host_name, -h host_name

    Speichert den Speicherauszug der Daten vom MySQL Server auf den angegebenen Host. Der Standardhost ist localhost.

  • --hex-blob

    Erstellt den Speicherauszug unter Verwendung der Hexadezimalnotation (z. B. wird aus 'abc' 0x616263). Betroffen sind die Datentypen BINARY, VARBINARY, BLOB und BIT.

  • --lock-all-tables, -x

    Sperrt datenbankübergreifend alle Tabellen. Dieses wird erreicht, indem eine globale Lesesperre für die Gesamtdauer des Speicherauszugs erwirkt wird. Die Option schaltet --single-transaction und --lock-tables automatisch ab.

  • --lock-tables, -l

    Sperrt alle Tabellen vor Beginn des Speicherauszugs. Die Tabellen werden im Falle von MyISAM-Tabellen mit READ LOCAL gesperrt, um nebenläufige Einfügeoperationen durchführen zu können. Bei transaktionssicheren Tabellen wie InnoDB und BDB ist --single-transaction eine wesentlich bessere Option, denn sie erfordert überhaupt kein Sperren der Tabellen.

    Beachten Sie, dass, wenn Sie Speicherauszüge mehrerer Datenbanken erstellen, --lock-tables die Tabellen für jede Datenbank separat sperrt. Insofern stellt diese Option nicht sicher, dass die Tabellen in der Speicherauszugsdatei datenbankübergreifend logisch konsistent sind. Die Tabellen in verschiedenen Datenbanken, von denen ein Speicherauszug erstellt wird, befinden sich unter Umständen in vollkommen unterschiedlichen Zuständen.

  • --master-data[=value]

    Schreibt Dateinamen und Position des Binärlogs in die Ausgabe. Diese Option erfordert die Berechtigung RELOAD, und das Binärlog muss aktiviert sein. Wenn der Optionswert 1 ist, werden Position und Dateiname in die Form einer CHANGE MASTER-Anweisung in die Ausgabe des Speicherauszugs geschrieben. Dies ermöglicht den Start eines Slave-Servers an der korrekten Position in den Binärlogs des Masters, wenn Sie diesen SQL-Speicherauszug des Masters zur Konfiguration eines Slaves einsetzen. Wenn der Optionswert 2 ist, dann wird die CHANGE MASTER-Anweisung als SQL-Kommentar geschrieben. Dies ist auch die Standardaktion, wenn value nicht angegeben wird.

    Die Option --master-data aktiviert --lock-all-tables, sofern --single-transaction nicht ebenfalls angegeben ist (in diesem Fall wird eine globale Lesesperre nur für einen kurzen Zeitraum zum Beginn des Speicherauszugsvorgangs erwirkt). (Siehe auch die Beschreibung zu --single-transaction.) In allen Fällen erfolgen Vorgänge an Logs im exakten Moment des Speicherauszugs. Die Option schaltet --lock-tables automatisch ab.

  • --no-create-db, -n

    Diese Option unterdrückt die CREATE DATABASE-Anweisungen, die andernfalls in der Ausgabe enthalten wären, wenn die Optionen --databases oder --all-databases angegeben wurden.

  • --no-create-info, -t

    Es werden keine CREATE TABLE-Anweisungen geschrieben, die jede gespeicherte Tabelle neu erstellen.

  • --no-data, -d

    Schreibt keine Datensatzinformationen für die Tabelle. Dies ist recht nützlich, wenn Sie einen Speicherauszug nur für die CREATE TABLE-Anweisung für die Tabelle erstellen wollen.

  • --opt

    Dies ist eine Kurzform, die für folgende Option steht: --add-drop-table --add-locks --create-options --disable-keys --extended-insert --lock-tables --quick --set-charset. Ergebnis sollte ein schneller Speicherauszugsprozess sein, an dessen Ende eine Speicherauszugsdatei steht, die problemlos in einen MySQL Server eingeladen werden kann.

    Standardmäßig ist diese Option aktiviert, kann aber mit --skip-opt deaktiviert werden. Um nur einige der mit --opt aktivierten Optionen zu deaktivieren, verwenden Sie die entsprechenden --skip-Optionen (z. B. --skip-add-drop-table oder --skip-quick).

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --quick, -q

    Diese Option ist nützlich, um einen Speicherauszug großer Tabellen zu erstellen. Hier wird mysqldump gezwungen, die Datensätze für eine Tabelle datensatzweise vom Server abzurufen, statt vor dem Schreiben die gesamte Ergebnismenge zu holen und sie temporär im Speicher abzulegen.

  • --quote-names, -Q

    Setzt Datenbank-, Tabellen- und Spaltennamen in ‘`’-Zeichen. Wenn der SQL-Modus ANSI_QUOTES aktiviert ist, werden die Namen in die ‘"’-Anführungszeichen gesetzt. Die Option ist standardmäßig aktiviert. Sie kann mit --skip-quote-names deaktiviert werden, aber diese Option sollte nach anderen Optionen wie etwa --compatible angegeben werden, mit denen --quote-names aktiviert werden könnte.

  • --replace

    Schreibt REPLACE- statt INSERT-Anweisungen. Wurde in MySQL 5.1.3 hinzugefügt.

  • --result-file=file, -r file

    Die Ausgabe erfolgt direkt in die angegebene Datei. Diese Option sollte unter Windows benutzt werden, um die Konvertierung von Zeilenumbrüchen (‘\n’) in Folgen von Absatzschaltung und Zeilenumbruch (‘\r\n’) zu verhindern.

  • --routines, -R

    Erstellt einen Speicherauszug gespeicherter Routinen (Funktionen und Prozeduren) aus Datenbankspeicherauszügen. Die mit ---routines erzeugte Ausgabe enthält CREATE PROCEDURE- und CREATE FUNCTION-Anweisungen zur Neuerstellung der Routinen. Allerdings enthalten diese Anweisungen keine Attribute wie die Routinendefinition oder die Zeitstempel für Erstellung und Änderung. Das bedeutet, dass die Routinen, wenn sie neu geladen werden, mit dem Definitionssatz für den neu ladenden Benutzer und den Zeitstempeln für den Zeitpunkt des Neuladens erstellt werden.

    Wenn Sie Routinen benötigen, die mit den Originalattributen für Definition und Zeitstempel neu erstellt wurden, verwenden Sie --routines nicht. Stattdessen erstellen Sie unter Verwendung eines MySQL-Kontos, das die erforderlichen Berechtigungen für die Datenbank mysql hat, direkt einen Speicherauszug des Inhalts der Tabelle mysql.proc und laden diesen Inhalt dann neu.

    Diese Option wurde in MySQL 5.1.2 hinzugefügt. Zuvor war ein Speicherauszug gespeicherter Routinen nicht möglich.

  • --set-charset

    Fügt SET NAMES default_character_set zur Ausgabe hinzu. Die Option ist standardmäßig aktiviert. Um die SET NAMES-Anweisung zu unterdrücken, verwenden Sie --skip-set-charset.

  • --single-transaction

    Diese Option setzt eine SQL-Anweisung BEGIN ab, bevor der Speicherauszug vom Server durchgeführt wird. Sie ist nur bei transaktionssicheren Tabellen wie InnoDB und BDB nützlich, denn der Speicherauszug spiegelt den konsistenten Zustand der Datenbank zu dem Zeitpunkt wider, an dem BEGIN abgesetzt wurde, ohne dass Anwendungen gesperrt werden.

    Wenn Sie diese Option verwenden, sollten Sie beachten, dass ein Speicherauszug nur von InnoDB-Tabellen in einem konsistenten Zustand erstellt werden kann. MyISAM- oder HEAP-Tabellen, für die unter Verwendung dieser Option ein Speicherauszug erstellt wird, können ihren Zustand trotzdem noch ändern.

    Die Optionen --single-transaction und --lock-tables schließen sich gegenseitig aus, weil LOCK TABLES implizit das Schreiben anhängiger Transaktionen auslöst.

    Um Speicherauszüge großer Tabellen zu erstellen, sollten Sie diese Option mit --quick kombinieren.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --skip-comments

    Siehe Beschreibung zu --comments.

  • --tab=path, -T path

    Erzeugt tabulatorgetrennte Datendateien. Für jede Tabelle, für die ein Speicherauszug erstellt wurde, erzeugt mysqldump eine tbl_namesql-Datei, welche die CREATE TABLE-Anweisung, mit der die Tabelle erstellt wird, enthält, und eine tbl_name.txt mit den Daten dieser Tabelle. Der Optionswert ist das Verzeichnis, in das die Dateien geschrieben werden.

    Standardmäßig werden die .txt-Datendateien mit Tabulatorzeichen zwischen den Spaltenwerten und einem Zeilenumbruch am Ende jeder Zeile formatiert. Das Format kann aber auch explizit mit den Optionen --fields-xxx und --lines--xxx angegeben werden.

    Hinweis: Diese Option sollte nur dann verwendet werden, wenn mysqldump auf demselben Computer läuft wie der Server mysqld. Sie benötigen die Berechtigung FILE, und der Server muss eine Berechtigung zum Schreiben von Dateien in das von Ihnen angegebene Verzeichnis haben.

  • --tables

    Setzt die Option --databases bzw. -B außer Kraft. Alle auf die Option folgenden Namensargumente werden als Tabellennamen betrachtet.

  • --triggers

    Erstellt einen Speicherauszug für Trigger für jede Tabelle, für die ein Speicherauszug erstellt wurde. Die Option ist standardmäßig aktiviert. Sie können sie mithilfe von --skip-triggers deaktivieren.

  • --tz-utc

    Fügt SET TIME_ZONE='+00:00' zur Speicherauszugsdatei hinzu, sodass TIMESTAMP-Spalten in den Speicherauszug integriert und dann auch auf Server in anderen Zeitzonen geladen werden können. Ohne diese Option werden TIMESTAMP-Spalten in den Zeitzonen gespeichert und geladen, die für den Quell- bzw. Zielserver lokal sind; dies kann Werteänderungen zur Folge haben. Außerdem schützt --tz-utc gegen sommerzeitbedingte Änderungen. --tz-utc ist standardmäßig aktiviert. Um es zu deaktivieren, verwenden Sie --skip-tz-utc. Diese Option wurde in MySQL 5.1.2 hinzugefügt.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

  • --where='where_condition', -w 'where_condition'

    Fügt nur diejenigen Datensätze in den Speicherauszug ein, die aufgrund der WHERE-Bedingung ausgewählt werden. Beachten Sie, dass die Bedingung zwingend in Anführungszeichen gesetzt werden muss, wenn sie Leerzeichen oder andere Zeichen enthält, die Ihr Befehls-Interpreter als Sonderzeichen interpretiert.

    Ein paar Beispiele:

    --where="user='jimf'"
    -w"userid>1"
    -w"userid<1"
    
  • --xml, -X

    Schreibt die Ausgabe des Speicherauszugs als sauber formatiertes XML.

Sie können mit der Syntax --var_name=value auch die folgenden Variablen einstellen:

  • max_allowed_packet

    Maximale Größe des Puffers für die Client/Server-Kommunikation. Der Maximalwert beträgt 1 Gbyte.

  • net_buffer_length

    Ausgangsgröße des Puffers für die Client/Server-Kommunikation. Wenn Sie Einfügeanweisungen für mehrere Datensätze (wie etwa mit den Optionen --extended-insert oder --opt) erstellen, legt mysqldump Datensätze an, deren maximale Länge durch net_buffer_length festgelegt ist. Wenn Sie den Wert dieser Variablen erhöhen, sollten Sie auch sicherstellen, dass die Variable net_buffer_length am MySQL Server mindestens genauso groß ist.

Es ist ferner möglich, Variablen über die Syntax --set-variable=var_name=value oder -O var_name=value einzustellen. Diese Syntax ist jedoch veraltet.

Die häufigste Anwendung von mysqldump ist wahrscheinlich die Erstellung eines Backups einer vollständigen Datenbank:

shell> mysqldump --opt db_name > backup-file.sql

Die Speicherauszugsdatei können Sie wie folgt wieder in den Server einlesen.

shell> mysql db_name < backup-file.sql

Oder aber so:

shell> mysql -e "source /path-to-backup/backup-file.sql" db_name

mysqldump ist ferner sehr nützlich zum Ausfüllen von Datenbanken durch Kopieren von Daten von einem MySQL Server auf einen anderen:

shell> mysqldump --opt db_name | mysql --host=remote_host -C db_name

Sie können mit einem einzigen Befehl einen Speicherauszug mehrerer Datenbanken erstellen:

shell> mysqldump --databases db_name1 [db_name2 ...] > my_databases.sql

Um einen Speicherauszug aller Datenbanken zu erstellen, verwenden Sie die Option --all-databases:

shell> mysqldump --all-databases > all_databases.sql

Bei InnoDB-Tabellen bietet mysqldump die Möglichkeit, eine Online-Sicherung zu erstellen:

shell> mysqldump --all-databases --single-transaction > all_databases.sql

Diese Datensicherung muss vor Beginn des Speicherauszugsvorgangs lediglich (mit FLUSH TABLES WITH READ LOCK) eine globale Lesesperre für alle Tabellen erwirken. Sobald diese Sperre aktiv ist, werden die Koordinaten des Binärlogs ausgelesen, und die Sperre wird aufgehoben. Wenn beim Absetzen der FLUSH-Anweisung gerade eine umfangreiche Änderungsanweisung ausgeführt wird, dann – und nur dann! – kann der MySQL Server stehen bleiben, bis diese lange Anweisung ausgeführt ist; danach ist der Server sperrfrei. Wenn die vom MySQL Server empfangenen Änderungsanweisungen (in Bezug auf ihre Ausführungsdauer) kurz sind, sollte die anfängliche Sperrperiode auch bei vielen Änderungen nicht spürbar sein.

Bei der Point-in-Time-Wiederherstellung (die auch als „Roll-Forward“ bezeichnet wird, wenn Sie ein altes Backup wiederherstellen und die seitdem durchgeführten Änderungen neu aufspielen müssen) ist es häufig nützlich, das Binärlog zu rotieren (siehe Abschnitt 5.12.3, „Die binäre Update-Logdatei“) oder zumindest die Binärlogkoordinaten zu kennen, denen der Speicherauszug entspricht:

shell> mysqldump --all-databases --master-data=2 > all_databases.sql

Oder:

shell> mysqldump --all-databases --flush-logs --master-data=2
              > all_databases.sql

Die gleichzeitige Verwendung von --master-data und --single-transaction stellt eine praktische Möglichkeit dar, ein für die Point-in-Time-Wiederherstellung geeignetes Onlinebackup zu erstellen, wenn Tabellen in der InnoDB-Engine gespeichert sind.

Weitere Informationen zur Erstellung von Backups finden Sie in Abschnitt 5.10.1, „Datenbank-Datensicherungen“, und Abschnitt 5.10.2, „Beispielhaftes Vorgehen zur Datensicherung und Wiederherstellung“.

8.11. mysqlhotcopy — Backup-Programm für Datenbanken

mysqlhotcopy ist ein Perl-Skript, das ursprünglich von Tim Bunce entwickelt und beigetragen wurde. Es erstellt mithilfe von LOCK TABLES, FLUSH TABLES und cp oder scp ein schnelles Backup der Datenbank. Dieses Skript stellt die schnellste Möglichkeit dar, eine Sicherungskopie der Datenbank oder einzelner Tabellen zu erstellen, kann aber nur auf dem Computer ausgeführt werden, auf dem auch die Datenbankverzeichnisse gespeichert sind. mysqlhotcopy erlaubt lediglich die Sicherung von MyISAM-Tabellen. Es läuft unter Unix und NetWare.

shell> mysqlhotcopy db_name [/path/to/new_directory]
shell> mysqlhotcopy db_name_1 ... db_name_n /path/to/new_directory

Gesichert werden Tabellen in der angegebenen Datenbank, die einem regulären Ausdruck entsprechen:

shell> mysqlhotcopy db_name./regex/

Der reguläre Ausdruck für den Tabellennamen kann verneint werden, indem man ihm eine Tilde (‘~’) voranstellt:

shell> mysqlhotcopy db_name./~regex/

mysqlhotcopy unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --addtodest

    Benennt das Zielverzeichnis (sofern vorhanden) nicht um, sondern fügt nur Dateien hinzu.

  • --allowold

    Bricht nicht ab, wenn das Ziel vorhanden ist, sondern benennt es durch Anhängen des Suffix _old um.

  • --checkpoint=db_name.tbl_name

    Fügt Prüfpunkteinträge in die angegebene Datenbank db_name und Tabelle tbl_name ein.

  • --chroot=path

    Basisverzeichnis des chroot-Käfigs, auf dem mysqld läuft. Der Wert path sollte mit dem der Option --chroot übereinstimmen, die für mysqld angegeben wurde.

  • --debug

    Aktiviert die Debugausgabe.

  • --dryrun, -n

    Meldet Aktionen, ohne sie auszuführen.

  • --flushlog

    Synchronisiert Logs, nachdem alle Tabellen gesperrt wurden.

  • --host=host_name, -h host_name

    Hostname des lokalen Hosts, der zur Herstellung einer TCP/IP-Verbindung zum lokalen Server verwendet wird. Standardmäßig erfolgt die Verbindung zu localhost über eine Unix-Socketdatei.

  • --keepold

    Gibt an, dass das vorherige (umbenannte) Ziel nach Abschluss nicht gelöscht wird.

  • --method=command

    Methode zum Kopieren von Dateien (cp oder scp).

  • --noindices

    Gibt an, dass vollständige Indexdateien nicht Bestandteil der Sicherung sind. Hierdurch wird die Sicherung beschleunigt, und die Backup-Datei wird kleiner. Die Indizes der neu geladenen Tabellen lassen sich später mit myisamchk -rq rekonstruieren.

  • --password=password, -ppassword

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Beachten Sie, dass der Passwortwert – anders als bei anderen MySQL-Programmen – bei dieser Option nicht optional ist. Wenn Sie das Passwort nicht auf der Befehlszeile angeben wollen, können Sie auch eine Optionsdatei verwenden.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die zur Verbindung mit dem lokalen Server verwendet werden soll.

  • --quiet, -q

    Stummer Modus (außer bei Fehlern).

  • --record_log_pos=db_name.tbl_name

    Zeichnet den Status von Master und Slave in der angegebenen Datenbank db_name und Tabelle tbl_name auf.

  • --regexp=expr

    Kopiert alle Datenbanken, deren Namen dem angegebenen regulären Ausdruck entsprechen.

  • --resetmaster

    Setzt das Binärlog nach Sperren aller Tabellen zurück.

  • --resetslave

    Setzt die Datei master.info nach Sperren aller Tabellen zurück.

  • --socket=path, -S path

    Unix-Socketdatei, die für die Verbindung verwendet werden soll.

  • --suffix=str

    Suffix für Namen kopierter Datenbanken.

  • --tmpdir=path

    Das Temporärverzeichnis. Vorgabe ist /tmp.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

mysqlhotcopy liest die Abschnitte [client] und [mysqlhotcopy] aus Optionsdateien aus.

Um mysqlhotcopy auszuführen, müssen Sie Zugriff auf die Dateien der zu sichernden Tabellen haben und benötigen zudem die Berechtigung SELECT für diese Tabellen sowie die Berechtigung RELOAD (damit Sie FLUSH TABLES ausführen können).

perldoc bietet eine umfassende Dokumentation zu mysqlhotcopy einschließlich Informationen zur Struktur der Tabellen, die für die Optionen --checkpoint und --record_log_pos erforderlich sind:

shell> perldoc mysqlhotcopy

8.12. mysqlimport — Programm zum Datenimport

Der Client mysqlimport stellt eine Befehlszeilenoberfläche für die SQL-Anweisung LOAD DATA INFILE bereit. Die meisten Optionen für mysqlimport entsprechen direkt Klauseln der LOAD DATA INFILE-Syntax. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

Rufen Sie mysqlimport wie folgt auf:

shell> mysqlimport [options] db_name textfile1 [textfile2 ...]

Bei jeder Textdatei, die auf der Befehlszeile angegeben wird, entfernt mysqlimport die Dateinamenserweiterung und bestimmt anhand des Ergebnisses den Namen der Tabelle, in die der Inhalt der Datei importiert werden soll. So würden beispielsweise die Dateien mit den Namen patient.txt, patient.text und patient alle in eine Tabelle namens patient importiert.

mysqlimport unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --columns=column_list, -c column_list

    Diese Option nimmt eine kommagetrennte Liste der Spaltennamen als Wert entgegen. Die Reihenfolge der Spaltennamen gibt an, wie die Spalten in der Datendatei den Tabellenspalten zuzuordnen sind.

  • --compress, -C

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • --delete, -D

    Leert die Tabelle vor dem Import der Textdatei.

  • --fields-terminated-by=…, --fields-enclosed-by=…, --fields-optionally-enclosed-by=…, --fields-escaped-by=…, --lines-terminated-by=…

    Diese Optionen haben dieselbe Bedeutung wie die entsprechenden Klauseln für LOAD DATA INFILE. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

  • --force, -f

    Ignoriert Fehler. Wenn beispielsweise eine Tabelle für eine Textdatei nicht vorhanden ist, wird ggf. mit der Verarbeitung weiterer vorhandener Dateien fortgefahren. Ohne --force wird mysqlimport beendet, wenn eine Tabelle nicht vorhanden ist.

  • --host=host_name, -h host_name

    Importiert Daten in den MySQL Server auf dem angegebenen Host. Der Standardhost ist localhost.

  • --ignore, -i

    Siehe Beschreibung zu --replace.

  • --ignore-lines=N

    Ignoriert die ersten N Zeilen der Datendatei.

  • --local, -L

    Liest die Eingabedateien lokal vom Clienthost.

  • --lock-tables, -l

    Sperrt alle Tabellen für Schreiboperationen, bevor mit der Verarbeitung der Textdateien begonnen wird. Hierdurch ist sichergestellt, dass alle Tabellen auf dem Server synchronisiert sind.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --replace, -r

    Die Optionen --replace und --ignore steuern den Umgang mit eingegebenen Datensätzen, die Duplikate vorhandener Datensätze mit eindeutigen Schlüsselwerten darstellen. Wenn Sie --replace angeben, ersetzen die neuen die vorhandenen Datensätze, die denselben eindeutigen Schlüsselwert aufweisen. Bei Angabe von --ignore hingegen werden neue Datensätze, deren eindeutiger Schlüsselwert bereits einem vorhandenen Datensatz zugewiesen ist, ignoriert. Geben Sie keine Option an, dann tritt ein Fehler auf, wenn ein doppelter Schlüsselwert gefunden wird; in diesem Fall wird der Rest der Textdatei ignoriert.

  • --silent, -s

    Stummer Modus. Eine Ausgabe erfolgt nur, wenn ein Fehler auftritt.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

Die nachfolgende Beispielsitzung veranschaulicht die Verwendung von mysqlimport:

shell> mysql -e 'CREATE TABLE imptest(id INT, n VARCHAR(30))' test
shell> ed
a
100     Max Sydow
101     Count Dracula
.
w imptest.txt
32
q
shell> od -c imptest.txt
0000000   1   0   0  \t   M   a   x       S   y   d   o   w  \n   1   0
0000020   1  \t   C   o   u   n   t       D   r   a   c   u   l   a  \n
0000040
shell> mysqlimport --local test imptest.txt
test.imptest: Records: 2  Deleted: 0  Skipped: 0  Warnings: 0
shell> mysql -e 'SELECT * FROM imptest' test
+------+---------------+
| id   | n             |
+------+---------------+
|  100 | Max Sydow     |
|  101 | Count Dracula |
+------+---------------+

8.13. mysqlshow — Anzeige von Informationen über Datenbanken, Tabellen und Spalten

Mit dem Client mysqlshow können Sie Informationen zu den vorhandenen Datenbanken, deren Tabellen oder den Spalten oder Indizes einer Tabelle schnell anzeigen.

mysqlshow stellt eine Befehlszeilenoberfläche für mehrere SQL-SHOW-Anweisungen bereit. Siehe auch Abschnitt 13.5.4, „SHOW. Dieselben Informationen können Sie auch durch direkte Verwendung dieser Anweisungen abrufen. Sie können sie beispielsweise über das Clientprogramm mysql absetzen.

Rufen Sie mysqlshow wie folgt auf:

shell> mysqlshow [options] [db_name [tbl_name [col_name]]]
  • Wenn keine Datenbank angegeben wird, erscheint eine Liste aller Datenbanknamen.

  • Wird keine Tabelle angegeben, dann werden alle passenden Tabellen in der Datenbank angezeigt.

  • Wird keine Spalte angegeben, dann werden alle passenden Spalten und Spaltentypen in der Tabelle angezeigt.

Die Ausgabe zeigt nur die Namen derjenigen Datenbanken, Tabellen oder Spalten an, für die Sie ausreichende Berechtigungen haben.

Enthält das letzte Argument Shell- oder SQL-spezifische Jokerzeichen (‘*’, ‘?’, ‘%’ oder ‘_’), dann werden nur diejenigen Namen gezeigt, die den jeweiligen Jokerzeichen entsprechen. Enthält ein Datenbankname Unterstriche, dann sollten diese mit einem Backslash (bei manchen Unix-Shells zwingend auch mit zwei Backslashs) markiert werden, um eine Liste der passenden Tabellen oder Spalten zu erhalten. Die Zeichen ‘*’ und ‘?’ werden in die SQL-Jokerzeichen ‘%’ und ‘_’ konvertiert. Dies kann zu Verwirrung führen, wenn Sie versuchen, die Spalten einer Tabelle mit einem ‘_’ im Namen anzuzeigen, denn in diesem Fall zeigt Ihnen mysqlshow nur die Tabellennamen an, die dem Muster entsprechen. Dieses Problem lässt sich allerdings ganz einfach beheben, indem Sie am Ende der Befehlszeile ein zusätzliches ‘%’ als separates Argument anhängen.

mysqlshow unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --character-sets-dir=path

    Das Verzeichnis, in dem Zeichensätze installiert sind. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --compress, -C

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • --default-character-set=charset_name

    Verwendet charset_name als Standardzeichensatz. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • --host=host_name, -h host_name

    Stellt eine Verbindung zum MySQL Server auf dem angegebenen Host her.

  • --keys, -k

    Zeigt die Tabellenindizes an.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --show-table-type

    Zeigt eine Spalte an, die den Tabellentyp angibt (wie bei SHOW FULL TABLES). Der Typ ist BASE TABLE oder VIEW.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --status, -i

    Zeigt zusätzliche Informationen zu jeder Tabelle an.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben. Diese Option kann mehrfach verwendet werden, um den Umfang der angezeigten Informationen zu erhöhen.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

8.14. mysqlslap — Client zur Lastemulation

mysqlslap ist ein Diagnoseprogramm, dessen Zweck die Emulation einer Clientlast für einen MySQL Server ist und das zeitbezogene Angaben der einzelnen Operationsstufen meldet. Das Programm simuliert den Zugriff mehrerer Clients auf den Server. mysqlslap wurde in MySQL 5.1.4 hinzugefügt.

Rufen Sie mysqlslap wie folgt auf:

shell> mysqlslap [options]

mysqlslap unterstützt die folgenden Optionen:

  • --help, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --auto-generate-sql, -a

    Erzeugt automatisch SQL-Anweisungen, wenn diese nicht in Dateien oder als Befehlsoptionen übergeben wurden.

  • --compress, -C

    Komprimiert alle Daten, die zwischen Client und Server ausgetauscht werden, sofern beide die Komprimierung unterstützen.

  • --concurrency, -c

    Anzahl der zu simulierenden Clients beim Absetzen der SELECT-Anweisung.

  • --create=value

    Datei oder String, der bzw. die zur Erstellung der Tabelle verwendet wird.

  • --create-schema=value

    Schema, in dem die Tests ausgeführt werden. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --csv[=file]

    Erzeugt eine Ausgabe von Werten in kommagetrennter Form. Die Ausgabe erfolgt in die angegebene Datei oder, wenn keine Datei angegeben ist, in die Standardausgabe. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --debug[=debug_options], -# [debug_options]

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • --delimiter=str, -F str

    Trennzeichen, das in SQL-Anweisungen verwendet wird, die in Dateien oder über Befehlsoptionen angegeben werden.

  • --engine=engine_name, -e engine_name

    Speicher-Engine, die zur Erstellung der Tabelle verwendet wird.

  • --host=host_name, -h host_name

    Stellt eine Verbindung zum MySQL Server auf dem angegebenen Host her.

  • --iterations=N, -i N

    Häufigkeit, mit der die Tests durchgeführt werden.

  • --lock-directory=path

    Verzeichnis, das zur Speicherung von Sperren verwendet wird. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --number-char-cols=N, -x N

    Anzahl der VARCHAR-Spalten, die verwendet werden, wenn --auto-generate-sql angegeben ist.

  • --number-int-cols=N, -y N

    Anzahl der INT-Spalten, die verwendet werden, wenn --auto-generate-sql angegeben ist.

  • --number-of-queries=N

    Anzahl der Abfragen, auf die jeder Client ungefähr beschränkt wird. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --only-print

    Stellt keine Verbindung mit Datenbanken her. mysqlslap gibt dann nur aus, was es gemacht hätte. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --password[=password], -p[password]

    Verwendet das angegebene Passwort zur Verbindung mit dem Server. Wenn Sie die Kurzform der Option (-p) verwenden, dürfen Sie kein Leerzeichen zwischen Option und Passwort setzen. Lassen Sie den Wert password auf die Option --password bzw. -p folgend weg, dann werden Sie zur Eingabe des Passworts aufgefordert.

    Die Angabe eines Passworts direkt auf der Befehlszeile ist als nicht sicher einzuordnen. Siehe auch Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.

  • --port=port_num, -P port_num

    Die TCP/IP-Portnummer, die für die Verbindung verwendet werden soll.

  • --protocol={TCP|SOCKET|PIPE|MEMORY}

    Das zu verwendende Verbindungsprotokoll.

  • --preserve-schema

    Behält das Schema der mysqlslap-Ausführung bei. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --query=value, -q value

    Datei oder String, der bzw. die die SELECT-Anweisung enthält, die zum Abrufen von Daten verwendet wird.

  • --silent, -s

    Stummer Modus. Es erfolgt keine Ausgabe.

  • --skip-query, -Q

    Führt keine SELECT-Anweisungen aus.

  • --slave

    Folgt den Master-Sperren für andere mysqlslap-Clients. Verwenden Sie diese Option, wenn Sie die Synchronisation zu einem Master-Server mit --lock-directory und NFS beabsichtigen. Diese Option wurde in MySQL 5.1.5 hinzugefügt.

  • --socket=path, -S path

    Bei Verbindungen mit localhost ist dies die zu verwendende Unix-Socketdatei bzw. (unter Windows) der Name der zu verwendenden Named Pipe.

  • --use-threads

    Unter Unix werden standardmäßig fork()-Aufrufe verwendet. Bei dieser Option werden stattdessen pthread-Aufrufe benutzt. Unter Windows werden pthread-Aufrufe ohnehin standardmäßig verwendet, d. h., die Option hat keine Auswirkungen. Diese Option wurde in MySQL 5.1.6 hinzugefügt.

  • --user=user_name, -u user_name

    Verwendet den angegebenen MySQL-Benutzernamen zur Verbindung mit dem Server.

  • --verbose, -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

8.15. mysql_zap — Prozesse beenden, die einem Muster entsprechen

mysql_zap terminiert Prozesse, die mit einem Muster übereinstimmen. Das Programm verwendet den Befehl ps und Unix-Signale, läuft also unter Unix und Unix-ähnlichen Systemen.

Rufen Sie mysql_zap wie folgt auf:

shell> mysql_zap [-signal] [-?Ift] pattern

Eine Übereinstimmung mit einem Prozess liegt vor, wenn die Ausgabezeile von ps das Muster enthält. Standardmäßig fordert mysql_zap für die Terminierung eines Prozesses immer eine Bestätigung an. Geben Sie y ein, um den Prozess zu terminieren, oder q, um mysql_zap zu beenden. Bei jeder anderen Antwort versucht mysql_zap nicht, den Prozess zu terminieren.

Sofern die Option -signal angegeben ist, wird auf diese Weise der Name oder die Nummer des Signals festgelegt, das an die betreffenden Prozesse zu senden ist. Andernfalls versucht mysql_zap, einen Prozess zunächst mit TERM (Signal 15) und nachfolgend mit KILL (Signal 9) zu beenden.

mysql_zap versteht die folgenden weiteren Optionen:

  • --help, -?, -I

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • -f

    Erzwingungsmodus. mysql_zap versucht, jeden Prozess zu terminieren, ohne eine Bestätigung anzufordern.

  • -t

    Testmodus. Zeigt Informationen zu allen Prozessen an, terminiert sie aber nicht.

8.16. perror — Erklärung der Fehlercodes

Auf den meisten Systemen zeigt MySQL neben einer internen Textmeldung den Systemfehlercode auf eine der folgenden Arten an:

message ... (errno: #)
message ... (Errcode: #)

Um zu ermitteln, was der Fehlercode bedeutet, lesen Sie die Dokumentation zu Ihrem System oder verwenden das Hilfsprogramm perror.

perror gibt eine Beschreibung für einen Systemfehlercode oder den Code eines Speicher-Engine- (Tabellen-Handler-)Fehlers aus.

Rufen Sie perror wie folgt auf:

shell> perror [options] errorcode ...

Beispiel:

shell> perror 13 64
Error code  13:  Permission denied
Error code  64:  Machine is not on the network

Um die Fehlermeldung für einen MySQL-Cluster-Fehlercode zu erhalten, rufen Sie perror mit der Option --ndb auf:

shell> perror --ndb errorcode

Beachten Sie, dass die Bedeutung von Systemfehlermeldungen je nach verwendetem Betriebssystem unterschiedlich sein kann. Anders gesagt: Ein Fehlercode kann auf verschiedenen Betriebssystemen auf unterschiedliche Fehler verweisen.

perror unterstützt die folgenden Optionen:

  • --help, --info, -I, -?

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • --ndb

    Gibt die Fehlermeldung für einen MySQL-Cluster-Fehlercode aus.

  • --silent, -s

    Stummer Modus. Gibt nur die Fehlermeldung aus.

  • --verbose, -v

    Ausführlicher Modus. Gibt den Fehlercode und die Fehlermeldung aus. Dies ist das Standardverhalten.

  • --version, -V

    Zeigt die Versionsinformation an und wird dann beendet.

8.17. replace — Hilfsprogramm für String-Ersetzungen

Das Hilfsprogramm replace ersetzt Strings in Dateien oder in der Standardeingabe.

Es gibt die folgenden Möglichkeiten, replace aufzurufen:

shell> replace from to [from to] ... -- file [file] ...
shell> replace from to [from to] ... < input

from ist der String, nach dem gesucht wird, und to der String, der den Such-String ersetzen soll. Es können ein oder mehrere String-Paare angegeben werden.

Mit der Option -- geben Sie an, wo die Liste mit den String-Ersetzungen endet und die Dateinamensliste beginnt. In diesem Fall werden alle Dateien, die auf der Befehlszeile angegeben sind, modifiziert, d. h., Sie sollten vor der Bearbeitung eine Kopie der Originaldateien erstellen. replace zeigt in einer Meldung an, welche der eingegebenen Dateien tatsächlich geändert werden.

Wenn die Option -- nicht angegeben ist, liest replace die Standardeingabe und schreibt in die Standardausgabe.

replace verwendet einen endlichen Automaten, um längere Strings zuerst auf Übereinstimmung zu prüfen. Hiermit können Strings gegeneinander ausgetauscht werden. So werden etwa mit dem folgenden Befehl a und b in den angegebenen Dateien file1 und file2 gegeneinander ausgetauscht:

shell> replace a b b a -- file1 file2 ...

Das Programm replace wird von msql2mysql verwendet. Siehe auch Abschnitt 24.9.1, „msql2mysql — Umwandeln von mSQL-Programmen für die Benutzung mit MySQL“.

replace unterstützt die folgenden Optionen:

  • -?, -I

    Zeigt eine Hilfemeldung an und wird dann beendet.

  • -# debug_options

    Schreibt ein Debuglog. Der String debug_options heißt häufig 'd:t:o,file_name'.

  • -s

    Stummer Modus. Es werden weniger Angaben zu den Aktivitäten des Programms ausgegeben.

  • -v

    Ausführlicher Modus. Es werden zusätzliche Angaben zu den Aktivitäten des Programms ausgegeben.

  • -V

    Zeigt die Versionsinformation an und wird dann beendet.

Kapitel 9. Sprachstruktur

Dieses Kapitel erläutert die Notationsregeln für die folgenden Elemente von SQL-Anweisungen bei der Verwendung von MySQL:

  • literale Werte wie etwa Strings und Zahlen

  • Bezeichner wie Datenbank-, Tabellen- und Spaltennamen

  • benutzerdefinierte und Systemvariablen

  • Kommentare

  • reservierte Wörter

9.1. Literale: wie Strings und Zahlen geschrieben werden

In diesem Abschnitt wird erläutert, wie literale Werte in MySQL geschrieben werden. Hierzu gehören Strings, Zahlen, Hexadezimalwerte, boolesche Werte und NULL. Ferner behandeln wir hier die verschiedenen Nuancen und Fallstricke, auf die Sie beim Umgang mit diesen Grundtypen in MySQL treffen können.

9.1.1. Strings

Ein String ist eine Abfolge von Bytes oder Zeichen, die in einfache (‘'’) oder doppelte Anführungszeichen (‘"’) gesetzt sind. Ein paar Beispiele:

'a string'
"another string"

Wenn der SQL-Modus ANSI_QUOTES aktiviert ist, dürfen String-Literale nur in einfache Anführungszeichen gesetzt werden. Ein in doppelten Anführungszeichen stehender String wird als Bezeichner interpretiert.

Ein binärer String ist ein String, für den kein Zeichensatz und keine Sortierung definiert sind. Ein nichtbinärer String hingegen ist ein String, für den Zeichensatz und Sortierung definiert sind. Bei beiden String-Typen basieren Vergleiche auf den numerischen Werten der String-Einheit. Bei binären Strings ist dies das Byte, bei nichtbinären Strings das einzelne Zeichen (wobei zu beachten ist, dass manche Zeichensätze Zeichen enthalten, die aus mehreren Bytes bestehen).

String-Literale weisen unter Umständen eine optionale Zeichensatzeinführung und eine COLLATE-Klausel auf:

[_charset_name]'string' [COLLATE collation_name]

Ein paar Beispiele:

SELECT _latin1'string';
SELECT _latin1'string' COLLATE latin1_danish_ci;

Weitere Informationen zu diesen Syntaxtypen für Strings finden Sie in Abschnitt 10.3.5, „Zeichensatz und Sortierfolge literaler Strings“.

Innerhalb eines Strings haben bestimmte Sequenzen jeweils eine spezielle Bedeutung. Jede dieser Sequenzen beginnt mit einem Backslash (‘\’). Dieser wird häufig als Escape-Zeichen bezeichnet. MySQL erkennt die folgenden Escape-Sequenzen:

\0 ASCII-konformes 0-Zeichen (NUL).
\' Ein einfaches Anführungszeichen (‘'’).
\" Ein doppeltes Anführungszeichen (‘"’).
\b Ein Rückschrittzeichen.
\n Ein Zeilenwechsel- oder Zeilenvorschubzeichen.
\r Ein Absatzschaltungszeichen.
\t Ein Tabulatorzeichen.
\Z ASCII 26 (Strg+Z). Siehe Anmerkung nach dieser Tabelle.
\\ Ein Backslash-Zeichen (‘\’).
\% Ein ‘%’-Zeichen. Siehe Anmerkung nach dieser Tabelle.
\_ Ein ‘_’-Zeichen. Siehe Anmerkung nach dieser Tabelle.

Diese Sequenzen unterscheiden die Groß-/Kleinschreibung. So wird etwa ‘\b’ als Rückschritt, ‘\B’ hingegen als ‘B’ interpretiert.

Das ASCII-Zeichen 26 kann als ‘\Z’ kodiert werden; hierdurch umgehen Sie Probleme mit der Tatsache, dass dieses Zeichen unter Windows als Dateiende interpretiert wird. Das ASCII-Zeichen 26 verursacht in einer Datei Probleme, wenn Sie mysql db_name< file_name verwenden.

Die Sequenzen ‘\%’ und ‘\_’ erlauben die Suche nach literalen Instanzen von ‘%’ und ‘_’ in Mustervergleichskontexten, in denen sie andernfalls als Jokerzeichen interpretiert würden. Details finden Sie in der Beschreibung zum Operator LIKE in Abschnitt 12.3.1, „String-Vergleichsfunktionen“. Wenn Sie ‘\%’ oder ‘\_’ in Kontexten ohne Mustervergleich verwenden, werden diese als Strings ‘\%’ und ‘\_’ und nicht als ‘%’ und ‘_’ ausgewertet.

Bei allen anderen Escape-Sequenzen wird der Backslash ignoriert. Das bedeutet, dass das gekennzeichnete Zeichen als nicht gekennzeichnetes interpretiert wird. So ist etwa ‘\x’ identisch mit ‘x’.

Es gibt mehrere Möglichkeiten, Anführungszeichen in einen String zu setzen:

  • Ein ‘'’ in einem String, der in ‘'’ gesetzt ist, kann als ‘''’ geschrieben werden.

  • Ein ‘"’ in einem String, der in ‘"’ gesetzt ist, kann als ‘""’ geschrieben werden.

  • Sie stellen dem Anführungszeichen ein Escape-Zeichen (‘\’) voran.

  • Ein ‘'’ in einem String, der in ‘"’ gesetzt ist, erfordert keine spezielle Behandlung und muss weder verdoppelt noch mit einem Escape-Zeichen versehen werden. Ebenso erfordert ein ‘"’ in einem String, der in ‘'’ gesetzt ist, keine Sonderbehandlung.

Die folgenden SELECT-Anweisungen veranschaulichen die Verwendung von Anführungs- und Escape-Zeichen:

mysql> SELECT 'hello', '"hello"', '""hello""', 'hel''lo', '\'hello';
+-------+---------+-----------+--------+--------+
| hello | "hello" | ""hello"" | hel'lo | 'hello |
+-------+---------+-----------+--------+--------+

mysql> SELECT "hello", "'hello'", "''hello''", "hel""lo", "\"hello";
+-------+---------+-----------+--------+--------+
| hello | 'hello' | ''hello'' | hel"lo | "hello |
+-------+---------+-----------+--------+--------+

mysql> SELECT 'This\nIs\nFour\nLines';
+--------------------+
| This
Is
Four
Lines |
+--------------------+

mysql> SELECT 'disappearing\ backslash';
+------------------------+
| disappearing backslash |
+------------------------+

Wenn Sie Binärdaten in eine String-Spalte (z. B. eine BLOB-Spalte) einfügen wollen, müssen die folgenden Zeichen durch Escape-Sequenzen dargestellt werden:

NULNUL-Byte (ASCII 0). Dieses Zeichen wird mit ‘\0’ (einem Backslash gefolgt vom Zeichen ASCII ‘0’) dargestellt.
\Backslash (ASCII 92). Stellen Sie dieses Zeichen als ‘\\’ dar.
'Einfaches Anführungszeichen (ASCII 39). Stellen Sie dieses Zeichen als ‘\'’ dar.
"Doppeltes Anführungszeichen (ASCII 34). Stellen Sie dieses Zeichen als ‘\"’ dar.

Wenn Sie Anwendungsprogramme schreiben, muss jeder String, der eines dieser Sonderzeichen enthalten kann, korrekt gekennzeichnet werden, bevor er als Datenwert in einer SQL-Anweisung verwendet wird, die an den MySQL Server gesendet wird. Dies lässt sich auf zweierlei Weise realisieren:

  • Sie verarbeiten den String mit einer Funktion, die die Sonderzeichen entsprechend kennzeichnet. In einem C-Programm können Sie die C-API-Funktion mysql_real_escape_string() zur Kennzeichnung von Sonderzeichen verwenden. Siehe auch Abschnitt 24.2.3.52, „mysql_real_escape_string(). Die Perl-DBI-Schnittstelle stellt eine Methode quote zur Konvertierung von Sonderzeichen in die entsprechenden Escape-Sequenzen bereit. Siehe auch Abschnitt 24.4, „MySQLs Perl-API“. Andere Spracheschnittstellen bieten unter Umständen ähnliche Funktionalitäten.

  • Eine Alternative zur expliziten Kennzeichnung von Sonderzeichen stellt die Platzhalterfunktion dar, die von vielen MySQL-APIs geboten wird. Sie erlaubt Ihnen das Einfügen spezieller Markierungen in einen Anweisungs-String und das nachfolgende Binden der Datenwerte an diese Markierungen beim Absetzen der Anweisung. In diesem Fall nimmt Ihnen die API die Kennzeichnung der Sonderzeichen in den Werten ab.

9.1.2. Zahlen

Integer-Zahlen werden als Abfolge von Ziffern dargestellt. Fließkommazahlen verwenden den Punkt (‘.’) als Dezimaltrennzeichen. Bei allen Zahlentypen werden durch ein vorangestelltes ‘-’- oder ‘+’-Zeichen negative bzw. positive Werte angezeigt.

Beispiele gültiger Integers:

1221
0
-32

Beispiele gültiger Fließkommazahlen:

294.42
-32032.6809e+10
148.00

Ein Integer kann durchaus in einem Fließkommakontext angegeben werden. Er wird dann als die entsprechende Fließkommazahl interpretiert.

9.1.3. Hexadezimale Werte

MySQL unterstützt Hexadezimalwerte. In numerischen Kontexten verhalten sich diese wie Integers (mit 64-Bit-Präzision). In String-Kontexten hingegen agieren sie als binäre Strings, wobei jedes Hexadezimalziffernpaar in ein Zeichen umgewandelt wird:

mysql> SELECT x'4D7953514C';
        -> 'MySQL'
mysql> SELECT 0xa+0;
        -> 10
mysql> SELECT 0x5061756c;
        -> 'Paul'

Der Standardtyp eines Hexadezimalwerts ist ein String. Wenn Sie gewährleisten wollen, dass der Wert als Zahl behandelt wird, können Sie CAST(... AS UNSIGNED) verwenden:

mysql> SELECT 0x41, CAST(0x41 AS UNSIGNED);
        -> 'A', 65

Die Syntax x'hexstring' basiert auf Standard-SQL. Die Syntax 0x basiert auf ODBC. Hexadezimal-Strings werden von ODBC häufig zur Angabe von Werten für BLOB-Spalten verwendet.

Sie können mit der Funktion HEX() einen String oder eine Zahl in einen String im Hexadezimalformat umwandeln:

mysql> SELECT HEX('cat');
        -> '636174'
mysql> SELECT 0x636174;
        -> 'cat'

9.1.4. Boolesche Werte

Die Konstanten TRUE und FALSE werden als 1 bzw. 0 ausgewertet. Bei den Konstantennamen wird die Groß-/Kleinschreibung nicht unterschieden.

mysql> SELECT TRUE, true, FALSE, false;
        -> 1, 1, 0, 0

9.1.5. Bitfeldwerte

Bitfeldwerte können unter Verwendung der Notation b'value' geschrieben werden. Hierbei ist value ein Binärwert, der mit Nullen und Einsen notiert wird.

Die Bitfeldnotation ist zur Angabe von Werten nützlich, die BIT-Spalten zugewiesen werden sollen:

mysql> CREATE TABLE t (b BIT(8));
mysql> INSERT INTO t SET b = b'11111111';
mysql> INSERT INTO t SET b = b'1010';
+------+----------+----------+----------+
| b+0  | BIN(b+0) | OCT(b+0) | HEX(b+0) |
+------+----------+----------+----------+
|  255 | 11111111 | 377      | FF       |
|   10 | 1010     | 12       | A        |
+------+----------+----------+----------+

9.1.6. NULL-Werte

Der Wert NULL bedeutet „keine Daten“. Die Groß-/Kleinschreibung wird bei NULL nicht unterschieden.

Beachten Sie, dass der NULL-Wert sich von Werten wie 0 für numerische Typen oder vom Leer-String für String-Typen unterscheidet. Siehe auch Abschnitt A.5.3, „Probleme mit NULL-Werten“.

Bei Import- oder Exportoperationen für Textdateien, die mit LOAD DATA INFILE oder SELECT ... INTO OUTFILE durchgeführt werden, wird NULL durch die Sequenz \N dargestellt. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

9.2. Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen

Namen von Datenbanken, Tabellen, Indizes, Spalten und Aliasen sind Bezeichner. Dieser Abschnitt beschreibt die für Bezeichner in MySQL zulässige Syntax.

Die folgende Tabelle beschreibt die Maximallänge und die erlaubten Zeichen für jeden Bezeichnertyp.

BezeichnerMaximale Länge (in Byte)Erlaubte Zeichen
Datenbank64Jedes Zeichen, das in einem Verzeichnisnamen zulässig ist. Ausgenommen sind ‘/’, ‘\’ und ‘.
Tabelle64Jedes Zeichen, das in einem Dateinamen zulässig ist. Ausgenommen sind ‘/’, ‘\’ und ‘.
Spalte64Alle Zeichen
Index64Alle Zeichen
Alias255Alle Zeichen

Neben den in der Tabelle genannten Einschränkungen dürfen Bezeichner weder das ASCII-Zeichen 0 noch ein Byte mit dem Wert 255 enthalten. Namen von Datenbanken, Tabellen und Spalten sollten nicht auf Leerzeichen enden. Die Verwendung von Anführungszeichen in Bezeichnern ist zulässig, sollte allerdings möglichst vermieden werden.

Bezeichner werden im Unicode-Format (UTF-8) gespeichert. Dies gilt für Bezeichner in Tabellendefinitionen, die in .frm-Dateien gespeichert sind, ebenso wie für solche in den Grant-Tabellen der Datenbank mysql. Die Länge der String-Spalten in den Grant-Tabellen (und in allen anderen Tabellen) in MySQL 5.1 wird als Anzahl von Zeichen angegeben. Das bedeutet, dass Sie (anders als bei älteren MySQL-Versionen) Multibytezeichen verwenden können, ohne die Anzahl der Zeichen verringern zu müssen, die für in diesen Spalten gespeicherte Werte erlaubt sind.

Ein Bezeichner kann mit und ohne Anführungszeichen geschrieben werden. Wenn ein Bezeichner ein reserviertes Wort ist oder Sonderzeichen enthält, müssen sie ihn bei jeder Referenzierung in Anführungszeichen setzen. (Ausnahme: Ein Wort, das auf einen Punkt in einem qualifizierten Namen folgt, muss ein Bezeichner sein; es muss also auch dann nicht in Anführungszeichen gesetzt werden, wenn es sich um ein reserviertes Wort handelt.) Eine Liste reservierter Wörter finden Sie unter Abschnitt 9.5, „Ist MySQL pingelig hinsichtlich reservierter Wörter?“. Als Sonderzeichen werden ‘_’ und ‘$’ sowie alle nicht alphanumerischen Zeichen des aktuellen Zeichensatzes betrachtet.

Das Anführungszeichen für Bezeichner ist der Backtick (‘`’):

mysql> SELECT * FROM `select` WHERE `select`.id > 100;

Wenn der SQL-Modus ANSI_QUOTES aktiviert ist, können Sie Bezeichner auch in doppelte Anführungszeichen setzen:

mysql> CREATE TABLE "test" (col INT);
ERROR 1064: You have an error in your SQL syntax. (...)
mysql> SET sql_mode='ANSI_QUOTES';
mysql> CREATE TABLE "test" (col INT);
Query OK, 0 rows affected (0.00 sec)

Hinweis: Da der Server bei aktiviertem ANSI_QUOTES-Modus Strings in doppelten Anführungszeichen in jedem Fall als Bezeichner interpretiert, müssen String-Literale in einfache Anführungszeichen gesetzt werden; doppelte Anführungszeichen dürfen in diesem Fall nicht für String-Literale verwendet werden.

Wie der SQL-Modus des Servers gesteuert wird, entnehmen Sie Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Anführungszeichen für Bezeichner können in einem Bezeichner enthalten sein, wenn Sie den Bezeichner in Anführungszeichen setzen. Wenn das im Bezeichner enthaltene Zeichen dasselbe ist, mit dem auch der Bezeichner selbst umschlossen ist, dann müssen Sie das Zeichen im Bezeichner verdoppeln. Die folgende Anweisung erstellt eine Tabelle namens a`b, die eine Spalte namens c"d enthält:

mysql> CREATE TABLE `a``b` (`c"d` INT);

Es wird davon abgeraten, Namen des Formats Me oder MeN (wie etwa 1e oder 2e2) zu verwenden, weil ein Ausdruck wie 1e+3 nicht eindeutig ist: Abhängig vom Kontext kann er als Ausdruck 1e + 3 oder als Zahl 1e+3 interpretiert werden.

Seien Sie vorsichtig, wenn Sie mit MD5() Tabellennamen erstellen, da hiermit Namen in unzulässigen oder mehrdeutigen Formaten (so, wie gerade beschrieben) erzeugt werden können.

9.2.1. Qualifikatoren für Bezeichner

MySQL unterstützt Namen, die aus einem oder mehreren Bezeichnern bestehen. Die Bestandteile eines mehrteiligen Namens sollten durch Punkte (‘.’) getrennt werden. Die ersten Bestandteile eines mehrteiligen Namens agieren als Qualifikationsmerkmal, das den Kontext beeinflusst, in dem der endgültige Bezeichner interpretiert wird.

Bei MySQL können Sie eine Spalte auf jede der folgenden Weisen referenzieren:

SpaltenreferenzierungBedeutung
col_nameDie Spalte col_name einer in der Anweisung verwendeten Tabelle hat diesen Namen.
tbl_name.col_nameDie Spalte col_name der Tabelle tbl_name aus der Standarddatenbank.
db_name.tbl_name.col_nameDie Spalte col_name der Tabelle tbl_name aus der Datenbank db_name.

Wenn Bestandteile eines mehrteiligen Namens Anführungszeichen erfordern, müssen Sie diese Bestandteile einzeln (statt des gesamten Namens) in Anführungszeichen setzen. So ist etwa `my-table`.`my-column` zulässig – anders als `my-table.my-column`.

Sie müssen das Präfix tbl_name oder db_name.tbl_name für eine Spaltenreferenzierung in einer Anweisung nicht angeben, sofern die Referenzierung eindeutig ist. Angenommen, die Tabellen t1 und t2 enthalten jeweils eine Spalte c. Nun wollen Sie c in einer SELECT-Anweisung abrufen, die sowohl t1 als auch t2 verwendet. In diesem Fall ist c unklar, weil es in Bezug auf die in der Anweisung angegebenen Tabellen nicht eindeutig ist. Sie müssen es mit einem Tabellennamen wie t1.c bzw. t2.c qualifizieren, um anzugeben, welche Tabelle Sie meinen. Analog müssen Sie, um Spaltenwerte aus einer Tabelle t in der Datenbank db1 und einer Tabelle t in der Datenbank db2 in einer Anweisung abzurufen, Spalten in diesen Tabellen als db1.t.col_name und db2.t.col_name referenzieren.

Ein Wort, das auf einen Punkt in einem qualifizierten Namen folgt, muss ein Bezeichner sein; es muss also auch dann nicht in Anführungszeichen gesetzt werden, wenn es sich um ein reserviertes Wort handelt.

Die Syntax .tbl_name bezeichnet die Tabelle tbl_name in der Standarddatenbank. Diese Syntax wird aus Gründen der ODBC-Kompatibilität akzeptiert, weil einige ODBC-Programme Tabellennamen das Zeichen ‘.’ voranstellen.

9.2.2. Groß-/Kleinschreibung in Namen

Bei MySQL entsprechen Datenbanken den Verzeichnissen im Datenverzeichnis. Jede Tabelle in einer Datenbank entspricht mindestens einer Datei (abhängig von der Speicher-Engine möglicherweise auch mehreren) im Datenbankverzeichnis. Hieraus folgt, dass bezüglich der Groß-/Kleinschreibung von Datenbank- und Tabellennamen die Regeln des zugrunde liegenden Betriebssystems beachtet werden müssen. Dies bedeutet, dass die Groß-/Kleinschreibung von Datenbank- und Tabellennamen bei den meisten Unix-Varianten unterschieden wird, bei Windows hingegen nicht. Eine beachtenswerte Ausnahme ist Mac OS X, welches zwar auf Unix basiert, standardmäßig aber einen Dateisystemtyp verwendet, der die Groß-/Kleinschreibung nicht unterscheidet. Allerdings unterstützt Mac OS X auch UFS-Volumes, die wie bei Unix üblich die Groß-/Kleinschreibung unterscheiden. Siehe auch Abschnitt 1.9.4, „MySQL-Erweiterungen zu ANSI SQL92“. Die Systemvariable lower_case_table_names beeinflusst ebenfalls die Vorgehensweise des Servers in Bezug auf die Groß-/Kleinschreibung bei Bezeichnern. Weitere Informationen hierzu folgen in diesem Abschnitt.

Hinweis: Zwar wird die Groß-/Kleinschreibung bei Datenbank- und Tabellennamen auf manchen Plattformen nicht unterschieden, aber Sie sollten eine gegebene Datenbank oder Tabelle auch nicht mit unterschiedlichen Schreibweisen innerhalb derselben Anweisung referenzieren. Die folgende Anweisung würde nicht funktionieren, weil sie eine Tabelle sowohl als my_table als auch als MY_TABLE referenziert:

mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;

Bei Namen von Spalten, Indizes, gespeicherten Routinen und Triggern wird die Groß-/Kleinschreibung auf keiner Plattform unterschieden. Gleiches gilt für Spaltenaliase.

Standardmäßig wird die Groß-/Kleinschreibung bei Tabellenaliasen unter Unix, nicht aber unter Windows oder Mac OS X unterschieden. Die folgende Anweisung würde unter Unix nicht funktionieren, da sie einen Alias sowohl als a als auch als A referenziert:

mysql> SELECT col_name FROM tbl_name AS a
    -> WHERE a.col_name = 1 OR A.col_name = 2;

Unter Windows hingegen ist diese Anweisung zulässig. Damit Sie diesen Unterschieden möglichst wenig Beachtung schenken müssen, sollten Sie am besten eine konsistente Benennungskonvention verwenden, in der Datenbanken und Tabellen immer mit aus Kleinbuchstaben bestehenden Namen erstellt und referenziert werden. Eine solche Konvention wird im Sinne maximaler Portabilität und Benutzerfreundlichkeit empfohlen.

Wie Tabellen- und Datenbanknamen auf Festplatte gespeichert und in MySQL verwendet werden, bestimmt die Systemvariable lower_case_table_names, die Sie beim Start von mysqld einstellen können. lower_case_table_names kann die in der nachfolgenden Tabelle aufgeführten Werte annehmen. Unter Unix ist der Standardwert von lower_case_table_names 0, unter Windows 1 und unter Mac OS X 2.

WertBedeutung
0Tabellen- und Datenbanknamen werden in der Schreibweise auf Festplatte gespeichert, die in der CREATE TABLE- bzw. CREATE DATABASE-Anweisung angegeben wurde. Beim Namensvergleich wird die Groß-/Kleinschreibung unterschieden. Beachten Sie, dass, wenn Sie diese Variable auf einem Dateisystem ohne Unterscheidung der Groß-/Kleinschreibung mit --lower-case-table-names=0 explizit auf 0 setzen und dann MyISAM-Tabellen mit Namen in anderer Schreibung aufrufen, dies zu einer Beschädigung der Indizes führen kann.
1Tabellennamen werden in Kleinbuchstaben auf Festplatte gespeichert. Beim Namensvergleich wird die Groß-/Kleinschreibung nicht unterschieden. MySQL konvertiert beim Speichern und Abrufen alle Tabellennamen in Kleinbuchstaben. Dieses Verhalten gilt auch für Datenbanknamen und Tabellenaliase.
2Tabellen- und Datenbanknamen werden in der Schreibweise auf Festplatte gespeichert, die in der CREATE TABLE- bzw. CREATE DATABASE-Anweisung angegeben wurde; beim Nachschlagen konvertiert MySQL sie jedoch in Kleinbuchstaben. Beim Namensvergleich wird die Groß-/Kleinschreibung nicht unterschieden. Hinweis: Dies funktioniert nur auf Dateisystemen, die die Groß-/Kleinschreibung nicht unterscheiden! InnoDB-Tabellennamen werden in Kleinbuchstaben (wie bei lower_case_table_names=1) gespeichert.

Wenn Sie MySQL nur auf einer Plattform verwenden, dann müssen Sie die Variable lower_case_table_names normalerweise nicht umstellen. Allerdings kann es zu Problemen kommen, wenn Sie Tabellen auf andere Plattformen mit unterschiedlicher Behandlung der Groß-/Kleinschreibung portieren wollen. So können Sie unter Unix beispielsweise zwei verschiedene Tabellen mit den Namen my_table und MY_TABLE verwenden; unter Windows jedoch werden diese beiden Namen als identisch betrachtet. Um Transferprobleme aufgrund der Schreibweise von Datenbank- oder Tabellennamen zu vermeiden, haben Sie zwei Optionen:

  • Sie verwenden lower_case_table_names=1 auf allen Systemen. Der wesentliche Nachteil besteht hierbei darin, dass Sie, wenn Sie SHOW TABLES bzw. SHOW DATABASES verwenden, die Namen nicht in der ursprünglichen Schreibweise angezeigt bekommen.

  • Sie verwenden unter Unix lower_case_table_names=0 und unter Windows lower_case_table_names=2. Hierdurch wird die Schreibweise von Datenbank- und Tabellennamen beibehalten. Allerdings müssen Sie in diesem Fall gewährleisten, dass Ihre Anweisungen unter Windows die korrekte Schreibweise für Datenbank- und Tabellennamen enthalten. Wenn Sie Ihre Anweisungen dann auf Unix übertragen, wo die Groß-/Kleinschreibung unterschieden wird, dann funktionieren sie aufgrund der falschen Schreibweise nicht mehr.

    Ausnahme: Wenn Sie InnoDB-Tabellen verwenden, sollten Sie lower_case_table_names auf allen Plattformen auf 1 setzen. Hiermit wird die Konvertierung von Namen in die Kleinschreibung erzwungen.

Beachten Sie, dass Sie, wenn Sie die Systemvariable lower_case_table_names unter Unix auf 1 setzen wollen, zunächst Ihre alten Datenbank- und Tabellennamen in die Kleinschreibung konvertieren müssen, bevor Sie mysqld mit der neuen Variableneinstellung neu starten.

9.3. Benutzerdefinierte Variablen

Sie können einen Wert in einer Benutzervariablen speichern und diese dann später referenzieren. Auf diese Weise können Sie Werte von einer Anweisung an eine andere übergeben. Benutzerdefinierte Variablen sind verbindungsspezifisch, d. h., eine Benutzervariable, die von einem Client definiert wurde, wird von anderen Clients nicht gesehen und kann von diesen auch nicht verwendet werden. Alle Variablen einer gegebenen Clientverbindung werden automatisch freigegeben, wenn diese Verbindung beendet wird.

Benutzervariablen werden als @var_name notiert, wobei der Variablenname var_name aus alphanumerischen Zeichen des aktuellen Zeichensatzes sowie ‘.’, ‘_’ und ‘$’ bestehen kann. Der Standardzeichensatz ist latin1 (cp1252 West European). Er lässt sich mit der Option --default-character-set für mysqld ändern. Siehe auch Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“. Der Name einer Benutzervariablen darf auch andere Zeichen enthalten, wenn Sie ihn als String oder Bezeichner in Anführungszeichen setzen (z. B. @'my-var', @"my-var" oder @`my-var`).

Hinweis: Bei MySQL vor Version 5.0 wird die Groß-/Kleinschreibung unterschieden, ab MySQL 5.0 hingegen nicht mehr.

Eine Möglichkeit zur Einstellung einer benutzerdefinierten Variablen besteht im Absetzen einer SET-Anweisung:

SET @var_name = expr [, @var_name = expr] ...

Bei SET kann entweder = oder := als Zuweisungsoperator verwendet werden. Der Wert expr einer Variablen kann als Integer, reale Zahl, String oder NULL-Wert ausgewertet werden.

Sie können einer Benutzervariablen auch mit einer anderen Anweisung als SET einen Wert zuweisen. In diesem Fall muss der Zuweisungsoperator := sein; = darf nicht verwendet werden, da es in anderen Anweisungen als SET als Vergleichsoperator benutzt wird:

mysql> SET @t1=0, @t2=0, @t3=0;
mysql> SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
+----------------------+------+------+------+
| @t1:=(@t2:=1)+@t3:=4 | @t1  | @t2  | @t3  |
+----------------------+------+------+------+
|                    5 |    5 |    1 |    4 |
+----------------------+------+------+------+

Benutzervariablen können in Kontexten eingesetzt werden, in denen Ausdrücke zulässig sind. Hierzu gehören zurzeit keine Kontexte, die explizit einen literalen Wert erfordern, also beispielsweise die LIMIT-Klausel einer SELECT-Anweisung oder die IGNORE N LINES-Klausel einer LOAD DATA-Anweisung.

Wenn einer Benutzervariablen ein String-Wert zugewiesen wird, hat sie denselben Zeichensatz und dieselbe Sortierung wie dieser String. Die Erzwingbarkeit ist Benutzervariablen implizit. (Es handelt sich um dieselbe Erzwingbarkeit wie bei Werten einer Tabellenspalte.)

Hinweis: In einer SELECT-Anweisung wird jeder Ausdruck erst dann ausgewertet, wenn er an den Client gesendet wird. Das bedeutet, dass in einer HAVING-, GROUP BY- oder ORDER BY-Klausel keine Referenzierung eines Ausdrucks möglich ist, der Variablen beinhaltet, die in der SELECT-Liste eingestellt werden. Die folgende Anweisung beispielsweise funktioniert nicht wie erwartet:

mysql> SELECT (@aa:=id) AS a, (@aa+3) AS b FROM tbl_name HAVING b=5;

Die Referenzierung von b in der HAVING-Klausel verweist auf ein Alias eines Ausdrucks in der SELECT-Liste, die @aa verwendet. Das funktioniert nicht so, wie man es eigentlich erwarten würde: @aa enthält den Wert von id aus dem zuvor ausgewählten (und nicht dem aktuellen) Datensatz.

Allgemein gesagt darf man niemals einer Benutzervariablen in einem Teil einer Anweisung einen Wert zuweisen und dieselbe Variable in einem anderen Teil derselben Anweisung verwenden. Vielleicht erhalten Sie die erwarteten Ergebnisse, aber dies ist nicht sicher.

Ein weiteres Problem in Zusammenhang mit der Einstellung einer Variablen und ihrer Verwendung in derselben Anweisung besteht darin, dass der standardmäßige Ergebnistyp einer Variablen zu Beginn der Anweisung auf dem Variablentyp basiert. Das folgende Beispiel veranschaulicht dies:

mysql> SET @a='test';
mysql> SELECT @a,(@a:=20) FROM tbl_name;

Bei dieser SELECT-Anweisung meldet MySQL dem Client, dass Spalte eins ein String ist, und konvertiert alle Zugriffe auf @a in Strings, obwohl @a für den zweiten Datensatz eine Zahlenmenge ist. Nachdem die SELECT-Anweisung ausgeführt wurde, wird @a für die nächste Anweisung als Zahl betrachtet.

Um Probleme in Zusammenhang mit diesem Verhalten zu vermeiden, sollten Sie entweder dieselbe Variable nicht gleichzeitig in ein und derselben Anweisung einstellen und verwenden oder aber die Variable auf 0, 0.0 oder '' setzen, um vor ihrer Verwendung den Typ zu definieren.

Wenn Sie eine Variable referenzieren, die noch nicht initialisiert wurde, dann hat diese den Wert NULL, und der Variablentyp ist ein String.

9.4. Kommentar

Der MySQL Server unterstützt drei Kommentarstile:

  • Vom Zeichen ‘#’ bis zum Zeilenende.

  • Von der Sequenz ‘-- ’ bis zum Zeilenende. Bei MySQL erfordert der Kommentarstil ‘-- ’ (doppelter Bindestrich) mindestens ein nachfolgendes Whitespace- oder Steuerzeichen (z. B. ein Leerzeichen, einen Tabulator, einen Zeilenwechsel usw.). Diese Syntax unterscheidet sich leicht von der SQL-Standardkommentarsyntax, wie sie in Abschnitt 1.9.5.7, „'--' als Beginn eines Kommentars“, beschrieben ist.

  • Von der Sequenz /* bis zur folgenden Sequenz */, wie man es von der Programmiersprache C her kennt. Diese Syntax ermöglicht Kommentare, die sich über mehrere Zeilen erstrecken, da öffnende und schließende Sequenz nicht in derselben Zeile stehen müssen.

Das folgende Beispiel veranschaulicht alle drei Kommentarstile:

mysql> SELECT 1+1;     # This comment continues to the end of line
mysql> SELECT 1+1;     -- This comment continues to the end of line
mysql> SELECT 1 /* this is an in-line comment */ + 1;
mysql> SELECT 1+
/*
this is a
multiple-line comment
*/
1;

MySQL Server unterstützt mehrere Kommentarvarianten im C-Stil. Hiermit können Sie Code schreiben, der MySQL-Erweiterungen enthält, aber trotzdem portierbar ist; Sie müssen dann Kommentare in der folgenden Form verwenden:

/*! MySQL-specific code */

In diesem Fall verarbeitet MySQL Server den Code innerhalb des Kommentars wie normale SQL-Anweisungen; andere SQL-Server hingegen ignorieren die Erweiterungen. So erkennt MySQL Server beispielsweise anders als andere Server das Schlüsselwort STRAIGHT_JOIN in der folgenden Anweisung:

SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...

Wenn Sie nach dem Zeichen ‘!’ die Versionsnummer angeben, wird die Syntax nur ausgeführt, wenn die betreffende oder eine neuere MySQL-Version verwendet wird. Das Schlüsselwort TEMPORARY im folgenden Kommentar wird nur von Servern ausgeführt, auf denen MySQL 3.23.02 oder höher läuft:

CREATE /*!32302 TEMPORARY */ TABLE t (a INT);

Die beschriebene Kommentarsyntax wirkt sich darauf aus, wie der Server mysqld SQL-Anweisungen verarbeitet. Auch das Clientprogramm mysql verarbeitet die Anweisungen teilweise, bevor es sie an den Server sendet. (Dies tut es, um die Anweisungsgrenzen in einer Eingabezeile mit mehreren Anweisungen zu ermitteln.)

9.5. Ist MySQL pingelig hinsichtlich reservierter Wörter?

Ein häufig auftretendes Problem liegt vor, wenn Sie einen Bezeichner (z. B. einen Tabellen- oder Datenbanknamen) verwenden wollen, der ein reserviertes Wort wie SELECT oder den Namen eines werksseitig vorhandenen MySQL-Datentyps oder einer Funktion wie TIMESTAMP oder GROUP enthält.

Wenn ein Bezeichner ein reserviertes Wort ist, müssen Sie ihn wie in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“, beschrieben in Anführungszeichen setzen. Ausnahme: Ein Wort, das auf einen Punkt in einem qualifizierten Namen folgt, muss ein Bezeichner sein; es muss also auch dann nicht in Anführungszeichen gesetzt werden, wenn es sich um ein reserviertes Wort handelt.

Funktionsnamen dürfen Sie als Bezeichner verwenden. Beispielsweise ist ABS als Spaltenname zulässig. Standardmäßig ist nämlich bei Funktionsaufrufen kein Whitespace zwischen dem Funktionsnamen und dem nachfolgenden Zeichen ‘(’ zulässig; auf diese Weise kann ein Funktionsaufruf von der Referenzierung eines Spaltennamens unterschieden werden.

Eine Begleiterscheinung dieses Verhaltens besteht darin, dass das Weglassen eines Leerzeichens in manchen Kontexten dazu führen kann, dass ein Bezeichner als Funktionsname interpretiert wird. Folgende Anweisung beispielsweise ist zulässig:

mysql> CREATE TABLE abs (val INT);

Das Weglassen des Leerzeichens nach abs verursacht einen Syntaxfehler, da die Anweisung in diesem Fall die Funktion ABS() aufzurufen scheint:

mysql> CREATE TABLE abs(val INT);
ERROR 1064 (42000) at line 2: You have an error in your SQL
syntax ... near 'abs(val INT)'

Ist der SQL-Modus IGNORE_SPACE aktiviert, dann gestattet der Server bei Funktionsaufrufen das Vorhandensein von Whitespace zwischen dem Funktionsnamen und dem nachfolgenden Zeichen ‘(’. Hierdurch werden Funktionsnamen als reservierte Wörter behandelt. Infolgedessen müssen Bezeichner, die mit Funktionsnamen identisch sind, wie in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“, beschrieben in Anführungszeichen gesetzt werden. Wie der SQL-Modus des Servers gesteuert wird, entnehmen Sie Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Die Wörter in der folgenden Tabelle sind explizit für MySQL 5.1 reserviert. Für den Fall, dass Sie später einmal auf eine höhere Version zu aktualisieren beabsichtigen, sollten Sie auch solche Wörter beachten, die in Zukunft reserviert sein werden. Sie finden diese in den Handbüchern zu höheren MySQL-Versionen. Die meisten der Wörter in der Tabelle sind in Standard-SQL als Spalten- oder Tabellennamen unzulässig (z. B. GROUP). Einige der Wörter sind auch reserviert, weil MySQL sie benötigt und (derzeit) einen yacc-Parser verwendet. Ein reserviertes Wort darf als Bezeichner verwendet werden, wenn Sie es in Anführungszeichen setzen.

ACCESSIBLEADDALL
ALTERANALYZEAND
ASASCASENSITIVE
BEFOREBETWEENBIGINT
BINARYBLOBBOTH
BYCALLCASCADE
CASECHANGECHAR
CHARACTERCHECKCOLLATE
COLUMNCONDITIONCONNECTION
CONSTRAINTCONTINUECONVERT
CREATECROSSCURRENT_DATE
CURRENT_TIMECURRENT_TIMESTAMPCURRENT_USER
CURSORDATABASEDATABASES
DAY_HOURDAY_MICROSECONDDAY_MINUTE
DAY_SECONDDECDECIMAL
DECLAREDEFAULTDELAYED
DELETEDESCDESCRIBE
DETERMINISTICDISTINCTDISTINCTROW
DIVDOUBLEDROP
DUALEACHELSE
ELSEIFENCLOSEDESCAPED
EXISTSEXITEXPLAIN
FALSEFETCHFLOAT
FLOAT4FLOAT8FOR
FORCEFOREIGNFROM
FULLTEXTGRANTGROUP
HAVINGHIGH_PRIORITYHOUR_MICROSECOND
HOUR_MINUTEHOUR_SECONDIF
IGNOREININDEX
INFILEINNERINOUT
INSENSITIVEINSERTINT
INT1INT2INT3
INT4INT8INTEGER
INTERVALINTOIS
ITERATEJOINKEY
KEYSKILLLEADING
LEAVELEFTLIKE
LIMITLINEARLINES
LOADLOCALTIMELOCALTIMESTAMP
LOCKLONGLONGBLOB
LONGTEXTLOOPLOW_PRIORITY
MATCHMEDIUMBLOBMEDIUMINT
MEDIUMTEXTMIDDLEINTMINUTE_MICROSECOND
MINUTE_SECONDMODMODIFIES
NATURALNOTNO_WRITE_TO_BINLOG
NULLNUMERICON
OPTIMIZEOPTIONOPTIONALLY
ORORDEROUT
OUTEROUTFILEPRECISION
PRIMARYPROCEDUREPURGE
RANGEREADREADS
READ_ONLYREAD_WRITEREAL
REFERENCESREGEXPRELEASE
RENAMEREPEATREPLACE
REQUIRERESTRICTRETURN
REVOKERIGHTRLIKE
SCHEMASCHEMASSECOND_MICROSECOND
SELECTSENSITIVESEPARATOR
SETSHOWSMALLINT
SPATIALSPECIFICSQL
SQLEXCEPTIONSQLSTATESQLWARNING
SQL_BIG_RESULTSQL_CALC_FOUND_ROWSSQL_SMALL_RESULT
SSLSTARTINGSTRAIGHT_JOIN
TABLETERMINATEDTHEN
TINYBLOBTINYINTTINYTEXT
TOTRAILINGTRIGGER
TRUEUNDOUNION
UNIQUEUNLOCKUNSIGNED
UPDATEUSAGEUSE
USINGUTC_DATEUTC_TIME
UTC_TIMESTAMPVALUESVARBINARY
VARCHARVARCHARACTERVARYING
WHENWHEREWHILE
WITHWRITEX509
XORYEAR_MONTHZEROFILL

Folgende reservierte Wörter sind neu in MySQL 5.1: LINEAR, RANGE.

MySQL gestattet auch die Verwendung bestimmter Schlüsselwörter als Bezeichner ohne Anführungszeichen, da viele Benutzer sie in der Vergangenheit bereits eingesetzt haben. Beispiele entnehmen Sie der folgenden Liste:

  • ACTION

  • BIT

  • DATE

  • ENUM

  • NO

  • TEXT

  • TIME

  • TIMESTAMP

Kapitel 10. Zeichensatz-Unterstützung

Inhaltsverzeichnis

10.1. Zeichensätze und Sortierfolgen im Allgemeinen
10.2. Zeichensätze und Sortierfolgen in MySQL
10.3. Festlegen von Zeichensätzen und Sortierfolgen
10.3.1. Serverzeichensatz und -sortierfolge
10.3.2. Datenbankzeichensatz und -sortierfolge
10.3.3. Tabellenzeichensatz und -sortierfolge
10.3.4. Spaltenzeichensatz und -sortierfolge
10.3.5. Zeichensatz und Sortierfolge literaler Strings
10.3.6. Nationaler Zeichensatz
10.3.7. Beispiele für die Zuordnung von Zeichensatz und Sortierfolge
10.3.8. Kompatibilität mit anderen Datenbanksystemen
10.4. Verbindungszeichensatz und -sortierfolge
10.5. Probleme mit Sortierfolgen
10.5.1. Verwendung von COLLATE in SQL-Anweisungen
10.5.2. Rangfolgen von COLLATE-Klauseln
10.5.3. Der BINARY-Operator
10.5.4. Spezialfälle, in denen die Festlegung der Sortierfolge problematisch ist
10.5.5. Sortierfolgen müssen für den richtigen Zeichensatz angegeben werden
10.5.6. Beispiel für die Auswirkung von Sortierfolgen
10.6. Operationen, auf die sich die Zeichensatzunterstützung auswirkt
10.6.1. Ergebnis-Strings
10.6.2. CONVERT() und CAST()
10.6.3. SHOW-Anweisungen und INFORMATION_SCHEMA
10.7. Unicode-Unterstützung
10.8. UTF8 für Metadaten
10.9. Zeichensätze und Sortierfolgen, die MySQL unterstützt
10.9.1. Unicode-Zeichensätze
10.9.2. Westeuropäische Zeichensätze
10.9.3. Mitteleuropäische Zeichensätze
10.9.4. Zeichensätze für Südeuropa und den Mittleren Osten
10.9.5. Baltische Zeichensätze
10.9.6. Kyrillische Zeichensätze
10.9.7. Asiatische Zeichensätze

MySQL enthält eine Zeichensatzunterstützung, mit deren Hilfe Sie Daten mit einer Vielzahl von Zeichensätzen speichern und Vergleiche auf der Basis einer Vielzahl von Sortierfolgen durchführen können. Sie können Zeichensätze auf der Server-, der Datenbank-, der Tabellen- und der Spaltenebene angeben. MySQL unterstützt die Verwendung von Zeichensätzen für die Speicher-Engines MyISAM, MEMORY, NDBCluster und InnoDB.

Dieses Kapitel behandelt die folgenden Themen:

  • Was sind Zeichensätze und Sortierfolgen?

  • Standardzeichensatzsystem auf mehreren Ebenen

  • Syntax zur Angabe von Zeichensätzen und Sortierfolgen

  • Betroffene Funktionen und Operationen

  • Unicode-Unterstützung

  • Verfügbare Zeichensätze und Sortierfolgen einschließlich entsprechender Anmerkungen

Zeichensatzbezogene Aspekte wirken sich auf die Datenspeicherung, aber auch auf die Kommunikation zwischen Clientprogrammen und dem MySQL Server aus. Wenn Sie wollen, dass das Clientprogramm mit dem Server unter Verwendung eines Zeichensatzes kommuniziert, der sich vom Standardzeichensatz unterscheidet, dann müssen Sie angeben, welcher Zeichensatz verwendet werden soll. Um beispielsweise den utf8-Unicode-Zeichensatz zu verwenden, setzen Sie nach der Herstellung einer Serververbindung folgende Anweisung ab:

SET NAMES 'utf8';

Weitere Informationen zu zeichensatzbezogenen Fragen in der Client/Server-Kommunikation finden Sie in Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.

10.1. Zeichensätze und Sortierfolgen im Allgemeinen

Ein Zeichensatz ist eine Menge mit Symbolen und Kodierungen. Eine Sortierfolge ist ein Regelsatz für den Vergleich von Zeichen in einem Zeichensatz. Folgendes Beispiel, welches einen imaginären Zeichensatz verwendet, soll den Unterschied verdeutlichen.

Angenommen, wir haben ein Alphabet mit vier Buchstaben: ‘A’, ‘B’, ‘a’, ‘b’. Jedem Buchstaben weisen wir nun eine Zahl zu: ‘A’ = 0, ‘B’ = 1, ‘a’ = 2, ‘b’ = 3. Der Buchstabe ‘A’ ist ein Symbol, die Zahl 0 die Kodierung für ‘A’. Die Kombination aller vier Buchstaben und ihrer Kodierungen bildet den Zeichensatz.

Angenommen, wir wollen zwei String-Werte ‘A’ und ‘B’ miteinander vergleichen. Die einfachste Möglichkeit, dies zu tun, besteht in einem Blick auf die Kodierungen: 0 für ‘A’ und 1 für ‘B’. Da 0 kleiner als 1 ist, sagen wir, dass ‘A’ kleiner als ‘B’ ist. Was wir gerade getan haben, war die Anwendung einer Sortierfolge für unseren Zeichensatz. Die Sortierfolge ist eine Menge von Regeln – wenn auch in diesem Fall nur eine Regel: „Vergleiche die Kodierungen“. Diese einfachste aller möglichen Sortierfolgen nennen wir Binärsortierung.

Was aber, wenn wir ausdrücken wollen, dass Klein- und Großbuchstaben äquivalent sind? Dann hätten wir schon zwei Regeln: (1) Betrachte die Kleinbuchstaben ‘a’ und ‘b’ als äquivalent zu den entsprechenden Großbuchstaben ‘A’ und ‘B’. (2) Vergleiche die Kodierungen. Dies ist eine Sortierfolge ohne Unterscheidung der Groß-/Kleinschreibung. Sie ist ein kleines bisschen komplexer als eine Binärsortierung.

Im wirklichen Leben umfassen die meisten Zeichensätze viele Zeichen: nicht nur ‘A’ und ‘B’, sondern ganze Alphabete – manchmal sogar mehrere Alphabete oder fernöstliche Schreibsysteme mit Tausenden von Zeichen – sowie viele Sonder- und Interpunktionszeichen. Auch für Sortierfolgen gibt es im wirklichen Leben viele Regeln, die nicht nur die Behandlung der Groß-/Kleinschreibung angeben, sondern auch, ob Akzente und Tremata (die Punkte etwa auf den deutschen Umlauten Ä, Ö und Ü) unterschieden und wie Folgen aus mehreren Zeichen zugeordnet werden (beispielsweise die Regel, dass bei einer der beiden deutschen Sortierfolgen die Gleichung ‘Ö’ = ‘OE’ gilt).

MySQL erlaubt Ihnen

  • das Speichern von Strings in einer Vielzahl von Zeichensätzen,

  • das Vergleichen von Strings unter Verwendung einer Vielzahl von Sortierfolgen,

  • das Mischen von Strings verschiedener Zeichensätze oder Sortierfolgen auf demselben Server, in derselben Datenbank oder sogar derselben Tabelle,

  • die Angabe von Zeichensatz und Sortierfolge auf beliebiger Ebene.

In dieser Hinsicht ist MySQL den meisten anderen Datenbanksystemen weit überlegen. Allerdings müssen Sie, um diese Funktionen effizient nutzen zu können, wissen, welche Zeichensätze und Sortierfolgen verfügbar sind, wie Sie die Standardeinstellungen ändern und wie diese das Verhalten von String-Operatoren und -Funktionen beeinflussen.

10.2. Zeichensätze und Sortierfolgen in MySQL

Der MySQL Server kann viele Zeichensätze unterstützen. Um die verfügbaren Zeichensätze aufzulisten, verwenden Sie die Anweisung SHOW CHARACTER SET. Nachfolgend ist eine Teilausgabe abgebildet. Umfassendere Informationen finden Sie in Abschnitt 10.9, „Zeichensätze und Sortierfolgen, die MySQL unterstützt“.

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset  | Description                 | Default collation   | Maxlen |
+----------+-----------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese    | big5_chinese_ci     |      2 |
| dec8     | DEC West European           | dec8_swedish_ci     |      1 |
| cp850    | DOS West European           | cp850_general_ci    |      1 |
| hp8      | HP West European            | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian       | koi8r_general_ci    |      1 |
| latin1   | cp1252 West European        | latin1_swedish_ci   |      1 |
| latin2   | ISO 8859-2 Central European | latin2_general_ci   |      1 |
| swe7     | 7bit Swedish                | swe7_swedish_ci     |      1 |
| ascii    | US ASCII                    | ascii_general_ci    |      1 |
| ujis     | EUC-JP Japanese             | ujis_japanese_ci    |      3 |
| sjis     | Shift-JIS Japanese          | sjis_japanese_ci    |      2 |
| hebrew   | ISO 8859-8 Hebrew           | hebrew_general_ci   |      1 |
| tis620   | TIS620 Thai                 | tis620_thai_ci      |      1 |
| euckr    | EUC-KR Korean               | euckr_korean_ci     |      2 |
| koi8u    | KOI8-U Ukrainian            | koi8u_general_ci    |      1 |
| gb2312   | GB2312 Simplified Chinese   | gb2312_chinese_ci   |      2 |
| greek    | ISO 8859-7 Greek            | greek_general_ci    |      1 |
| cp1250   | Windows Central European    | cp1250_general_ci   |      1 |
| gbk      | GBK Simplified Chinese      | gbk_chinese_ci      |      2 |
| latin5   | ISO 8859-9 Turkish          | latin5_turkish_ci   |      1 |
...

Ein gegebener Zeichensatz hat stets mindestens eine Sortierfolge. Es können aber auch mehrere sein. Um die verfügbaren Sortierfolgen eines Zeichensatzes aufzulisten, verwenden Sie die Anweisung SHOW COLLATION. Um etwa die Sortierfolgen für den Zeichensatz latin1 (cp1252, westeuropäisch) aufzulisten, suchen Sie mit der folgenden Anweisung die Sortierfolgennamen, die mit latin1 beginnen:

mysql> SHOW COLLATION LIKE 'latin1%';
+---------------------+---------+----+---------+----------+---------+
| Collation           | Charset | Id | Default | Compiled | Sortlen |
+---------------------+---------+----+---------+----------+---------+
| latin1_german1_ci   | latin1  |  5 |         |          |       0 |
| latin1_swedish_ci   | latin1  |  8 | Yes     | Yes      |       1 |
| latin1_danish_ci    | latin1  | 15 |         |          |       0 |
| latin1_german2_ci   | latin1  | 31 |         | Yes      |       2 |
| latin1_bin          | latin1  | 47 |         | Yes      |       1 |
| latin1_general_ci   | latin1  | 48 |         |          |       0 |
| latin1_general_cs   | latin1  | 49 |         |          |       0 |
| latin1_spanish_ci   | latin1  | 94 |         |          |       0 |
+---------------------+---------+----+---------+----------+---------+

Die latin1-Sortierfolgen haben die nachfolgend beschriebenen Bedeutungen:

SortierfolgeBedeutung
latin1_german1_ciDeutsch, DIN-1
latin1_swedish_ciSchwedisch/Finnisch
latin1_danish_ciDänisch/Norwegisch
latin1_german2_ciDeutsch, DIN-2
latin1_binBinärsortierung nach latin1-Kodierung
latin1_general_ciMehrsprachig (westeuropäisch)
latin1_general_csMehrsprachig (ISO, westeuropäisch), Unterscheidung der Groß-/Kleinschreibung
latin1_spanish_ciModernes Spanisch

Sortierfolgen haben die folgenden Eigenschaften:

  • Zwei verschiedene Zeichensätze können nicht dieselbe Sortierfolge aufweisen.

  • Jeder Zeichensatz hat genau eine Sortierfolge, die die Standardsortierfolge ist. So ist die Standardsortierfolge für latin1 beispielsweise latin1_swedish_ci. Die Ausgabe von SHOW CHARACTER SET zeigt an, welche Sortierfolgen standardmäßig für die angezeigten Zeichensätze verwendet werden.

  • Für Sortierfolgennamen gibt es eine Konvention: Sie beginnen mit dem Namen des Zeichensatzes, mit dem sie verknüpft sind, enthalten in der Regel den Namen der betreffenden Sprache und enden auf _ci (keine Unterscheidung der Groß-/Kleinschreibung), _cs (Unterscheidung der Groß-/Kleinschreibung) oder _bin (Binärsortierung).

10.3. Festlegen von Zeichensätzen und Sortierfolgen

Standardeinstellungen für Zeichensätze und Sortierfolgen gibt es auf vier Ebenen, nämlich der Server-, der Datenbank-, der Tabellen- und der Spaltenebene. Die folgende Beschreibung mag komplex erscheinen, es hat sich aber in der Praxis gezeigt, dass Standardeinstellungen auf mehreren Ebenen zu natürlichen und offensichtlichen Ergebnissen führen.

CHARACTER SET wird in Klauseln verwendet, die einen Zeichensatz angeben. CHARSET kann als Synonym von CHARACTER SET benutzt werden.

10.3.1. Serverzeichensatz und -sortierfolge

MySQL Server bietet einen Serverzeichensatz und eine Serversortierfolge. Diese können beim Serverstart eingestellt und zur Laufzeit geändert werden.

Anfangs hängen Zeichensatz und Sortierfolge des Servers von den Optionen ab, die Sie beim Start von mysqld verwenden. Sie können --character-set-server für den Zeichensatz benutzen. Daneben können Sie --collation-server hinzufügen, um die Sortierfolge anzugeben. Wenn Sie keinen Zeichensatz bestimmen, entspricht dies der Festlegung --character-set-server=latin1. Geben Sie nur einen Zeichensatz (z. B. latin1), aber keine Sortierfolge an, dann entspricht dies der Festlegung --character-set-server=latin1 --collation-server=latin1_swedish_ci, weil latin1_swedish_ci die Standardsortierfolge für latin1 ist. Aus diesem Grund haben die folgenden drei Befehle dieselben Auswirkungen:

shell> mysqld
shell> mysqld --character-set-server=latin1
shell> mysqld --character-set-server=latin1 \
           --collation-server=latin1_swedish_ci

Eine Möglichkeit, die Einstellungen zu ändern, ist eine Neukompilierung. Wenn Sie die Vorgaben für Zeichensatz und Sortierfolge beim Erstellen aus dem Quellcode ändern wollen, verwenden Sie --with-charset und --with-collation als Argumente für configure. Zum Beispiel:

shell> ./configure --with-charset=latin1

Oder:

shell> ./configure --with-charset=latin1 \
           --with-collation=latin1_german1_ci

Sowohl mysqld als auch configure stellen sicher, dass die Kombination aus Zeichensatz und Sortierfolge gültig ist. Andernfalls zeigt jedes Programm eine Fehlermeldung an und wird dann beendet.

Die aktuellen Werte für Zeichensatz und Sortierfolge können den Systemvariablen character_set_server und collation_server entnommen werden. Diese Variablen lassen sich zur Laufzeit ändern.

10.3.2. Datenbankzeichensatz und -sortierfolge

Jede Datenbank hat einen datenbankspezifischen Zeichensatz und eine Datenbanksortierfolge. Die Anweisungen CREATE DATABASE und ALTER DATABASE bieten optionale Klauseln zur Angabe von Zeichensatz und Sortierfolge:

CREATE DATABASE db_name
    [[DEFAULT] CHARACTER SET charset_name]
    [[DEFAULT] COLLATE collation_name]

ALTER DATABASE db_name
    [[DEFAULT] CHARACTER SET charset_name]
    [[DEFAULT] COLLATE collation_name]

Statt DATABASE kann auch das Schlüsselwort SCHEMA verwendet werden.

Alle Datenbankoptionen werden in einer Textdatei namens db.opt gespeichert, die sich im Datenbankverzeichnis befindet.

Die Klauseln CHARACTER SET und COLLATE ermöglichen die Erstellung von Datenbanken mit unterschiedlichen Zeichensätzen und Sortierfolgen auf demselben MySQL Server.

Beispiel:

CREATE DATABASE db_name CHARACTER SET latin1 COLLATE latin1_swedish_ci;

MySQL wählt Zeichensatz und Sortierfolge für die Datenbank auf folgende Weise:

  • Wenn sowohl CHARACTER SET X als auch COLLATE Y angegeben werden, dann werden der Zeichensatz X und die Sortierfolge Y eingestellt.

  • Wenn CHARACTER SET X ohne COLLATE angegeben wird, dann wird der Zeichensatz X mit seiner Standardsortierfolge eingestellt.

  • Wenn COLLATE Y ohne CHARACTER SET angegeben wird, dann wird der mit Y verknüpfte Zeichensatz mit der Sortierfolge Y eingestellt.

  • Andernfalls werden die Standardwerte für Zeichensatz und Sortierfolge eingestellt.

Datenbankzeichensatz und -sortierfolge werden als Standardwerte verwendet, wenn Zeichensatz und Sortierfolge für die Tabelle nicht in CREATE TABLE-Anweisungen angegeben werden. Einen anderen Zweck haben sie nicht.

Die Werte für Zeichensatz und Sortierfolge der Standarddatenbank können den Systemvariablen character_set_database und collation_database entnommen werden. Der Server stellt diese Variablen immer dann ein, wenn die Standarddatenbank sich ändert. Ist keine Standarddatenbank vorhanden, dann haben die Variablen denselben Wert wie die entsprechenden Systemvariablen für die Serverebene (character_set_server und collation_server).

10.3.3. Tabellenzeichensatz und -sortierfolge

Jede Tabelle hat einen tabellenspezifischen Zeichensatz und eine Tabellensortierfolge. Die Anweisungen CREATE TABLE und ALTER TABLE bieten optionale Klauseln zur Angabe von Zeichensatz und Sortierfolge:

CREATE TABLE tbl_name (column_list)
    [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]]

ALTER TABLE tbl_name
    [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]

Beispiel:

CREATE TABLE t1 ( ... ) CHARACTER SET latin1 COLLATE latin1_danish_ci;

MySQL wählt Zeichensatz und Sortierfolge für die Tabelle auf folgende Weise:

  • Wenn sowohl CHARACTER SET X als auch COLLATE Y angegeben werden, dann werden der Zeichensatz X und die Sortierfolge Y eingestellt.

  • Wenn CHARACTER SET X ohne COLLATE angegeben wird, dann wird der Zeichensatz X mit seiner Standardsortierfolge eingestellt.

  • Wenn COLLATE Y ohne CHARACTER SET angegeben wird, dann wird der mit Y verknüpfte Zeichensatz mit der Sortierfolge Y eingestellt.

  • Andernfalls werden die datenbankspezifischen Standardwerte für Zeichensatz und Sortierfolge eingestellt.

Tabellenzeichensatz und -sortierfolge werden als Standardwerte verwendet, wenn Zeichensatz und Sortierfolge in den Definitionen einzelner Spalten nicht angegeben sind. Tabellenzeichensatz und -sortierfolge sind MySQL-Erweiterungen, die es im SQL-Standard nicht gibt.

10.3.4. Spaltenzeichensatz und -sortierfolge

Jede „Zeichenspalte“ (d. h. eine Spalte des Typs CHAR, VARCHAR oder TEXT) hat einen Spaltenzeichensatz und eine Spaltensortierfolge. Die Spaltendefinitionssyntax bietet optionale Klauseln zur Angabe von Spaltenzeichensatz und -sortierfolge:

col_name {CHAR | VARCHAR | TEXT} (col_length)
    [CHARACTER SET charset_name [COLLATE collation_name]]

Beispiel:

CREATE TABLE Table1
(
    column1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_german1_ci
);

MySQL wählt Zeichensatz und Sortierfolge für eine Spalte auf folgende Weise:

  • Wenn sowohl CHARACTER SET X als auch COLLATE Y angegeben werden, dann werden der Zeichensatz X und die Sortierfolge Y eingestellt.

  • Wenn CHARACTER SET X ohne COLLATE angegeben wird, dann wird der Zeichensatz X mit seiner Standardsortierfolge eingestellt.

  • Wenn COLLATE Y ohne CHARACTER SET angegeben wird, dann wird der mit Y verknüpfte Zeichensatz mit der Sortierfolge Y eingestellt.

  • Andernfalls werden die tabellenspezifischen Standardwerte für Zeichensatz und Sortierfolge eingestellt.

Die Klauseln CHARACTER SET und COLLATE entsprechen dem SQL-Standard.

10.3.5. Zeichensatz und Sortierfolge literaler Strings

Jeder Zeichen-String-Literal hat einen Zeichensatz und eine Sortierfolge.

Ein String-Literal weist unter Umständen eine optionale Zeichensatzeinführung und eine COLLATE-Klausel auf:

[_charset_name]'string' [COLLATE collation_name]

Ein paar Beispiele:

SELECT 'string';
SELECT _latin1'string';
SELECT _latin1'string' COLLATE latin1_danish_ci;

Für die einfache Anweisung SELECT 'string' werden Zeichensatz und Sortierfolge des Strings definiert von den Systemvariablen character_set_connection und collation_connection.

Der Ausdruck _charset_name heißt formal Einführung. Die Einführung zeigt dem Parser an, dass der nachfolgende String den Zeichensatz X verwendet. Da dies in der Vergangenheit zu Verwirrung bei Benutzern geführt hat, wollen wir an dieser Stelle betonen, dass eine Einführung keine Konvertierung zur Folge hat – es handelt sich lediglich um ein Signal, das den Wert des Strings nicht ändert. Eine Einführung ist auch zulässig vor der standardmäßigen und der numerischen hexadezimalen Literalnotation (x'literal' bzw. 0xnnnn) sowie vor ? (Parameterersetzung bei der Verwendung vorbereiteter Anweisungen innerhalb einer Programmiersprachen-Schnittstelle).

Ein paar Beispiele:

SELECT _latin1 x'AABBCC';
SELECT _latin1 0xAABBCC;
SELECT _latin1 ?;

MySQL wählt Zeichensatz und Sortierfolge eines Literals auf folgende Weise:

  • Wenn sowohl _X als auch COLLATE Y angegeben werden, dann werden der Zeichensatz X und die Sortierfolge Y eingestellt.

  • Wenn _X angegeben ist, COLLATE aber nicht, dann wird der Zeichensatz X mit der Standardsortierfolge verwendet.

  • Andernfalls werden als Zeichensatz und Sortierfolge die Werte der Systemvariablen character_set_connection bzw. collation_connection gesetzt.

Ein paar Beispiele:

  • Ein String mit dem Zeichensatz latin1 und der Sortierfolge latin1_german1_ci:

    SELECT _latin1'Müller' COLLATE latin1_german1_ci;
    
  • Ein String mit dem Zeichensatz latin1 und der Standardsortierfolge (latin1_swedish_ci):

    SELECT _latin1'Müller';
    
  • Ein String mit Standardzeichensatz und -sortierfolge der Verbindung:

    SELECT 'Müller';
    

Zeichensatzeinführungen und die COLLATE-Klausel sind entsprechend den Spezifikationen des SQL-Standards implementiert.

10.3.6. Nationaler Zeichensatz

Der SQL-Standard definiert NCHAR oder NATIONAL CHAR als Möglichkeit, anzugeben, dass eine CHAR-Spalte einen bestimmten vordefinierten Zeichensatz verwenden soll. MySQL 5.1 verwendet utf8 als vordefinierten Zeichensatz. So sind beispielsweise die folgenden Datentypdeklarationen gleichwertig:

CHAR(10) CHARACTER SET utf8
NATIONAL CHARACTER(10)
NCHAR(10)

Gleiches gilt für die folgenden:

VARCHAR(10) CHARACTER SET utf8
NATIONAL VARCHAR(10)
NCHAR VARCHAR(10)
NATIONAL CHARACTER VARYING(10)
NATIONAL CHAR VARYING(10)

Sie können mit N'literal' einen String im Nationalzeichensatz erstellen. Die folgenden beiden Anweisungen sind äquivalent:

SELECT N'some text';
SELECT _utf8'some text';

Informationen zur Aktualisierung von Zeichensätzen auf MySQL 5.1 von Versionen vor 4.1 finden Sie im MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1.

10.3.7. Beispiele für die Zuordnung von Zeichensatz und Sortierfolge

Die folgenden Beispiele zeigen, wie MySQL die Standardwerte für den Zeichensatz und die Sortierfolge ermittelt.

Beispiel 1: Tabellen- und Spaltendefinition

CREATE TABLE t1
(
    c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci
) DEFAULT CHARACTER SET latin2 COLLATE latin2_bin;

Hier haben wir eine Spalte mit dem Zeichensatz latin1 und der Sortierfolge latin1_german1_ci. Die Definition ist explizit, d. h., die Werte ergeben sich von selbst. Beachten Sie, dass das Speichern einer latin1-Spalte in einer latin2-Tabelle unproblematisch ist.

Beispiel 2: Tabellen- und Spaltendefinition

CREATE TABLE t1
(
    c1 CHAR(10) CHARACTER SET latin1
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;

Hier nun haben wir eine Spalte mit dem Zeichensatz latin1 und der Standardsortierfolge. Obwohl es naheliegend erscheint, wird die Standardsortierfolge nicht von der Tabellenebene übernommen. Stattdessen hat, weil die Standardsortierfolge von latin1 immer latin1_swedish_ci ist, die Spalte c1 die Sortierfolge latin1_swedish_ci (und nicht latin1_danish_ci).

Beispiel 3: Tabellen- und Spaltendefinition

CREATE TABLE t1
(
    c1 CHAR(10)
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;

Hier haben wir eine Spalte mit den Standardwerten für Zeichensatz und Sortierfolge. Unter diesen Umständen bestimmt MySQL anhand der Angaben auf der Tabellenebene den Zeichensatz und die Sortierfolge für die Spalte. Es ergibt sich, dass der Zeichensatz latin1 und die zugehörige Sortierfolge latin1_danish_ci für die Spalte c1 eingestellt werden.

Beispiel 4: Datenbank-, Tabellen- und Spaltendefinition

CREATE DATABASE d1
    DEFAULT CHARACTER SET latin2 COLLATE latin2_czech_ci;
USE d1;
CREATE TABLE t1
(
    c1 CHAR(10)
);

Wir erstellen eine Spalte ohne Angabe von Zeichensatz und Sortierfolge. Ebenso wenig geben wir einen Zeichensatz und eine Sortierfolge auf der Tabellenebene an. Unter diesen Umständen überprüft MySQL die Datenbankebene, um die Tabelleneinstellungen zu ermitteln, die daraufhin auch zu den Spalteneinstellungen werden. Es ergibt sich, dass der Zeichensatz latin2 und die zugehörige Sortierfolge latin2_czech_ci für die Spalte c1 eingestellt werden.

10.3.8. Kompatibilität mit anderen Datenbanksystemen

Aus Gründen der MaxDB-Kompatibilität sind die folgenden beiden Anweisungen gleichwertig:

CREATE TABLE t1 (f1 CHAR(N) UNICODE);
CREATE TABLE t1 (f1 CHAR(N) CHARACTER SET ucs2);

10.4. Verbindungszeichensatz und -sortierfolge

Verschiedene Systemvariablen zu Zeichensätzen und Sortierfolgen sind spezifisch für die Interaktion eines Clients mit dem Server. Einige dieser Variablen wurden bereits in früheren Abschnitten erwähnt:

  • Die Werte für Zeichensatz und Sortierfolge können den Systemvariablen character_set_server und collation_server entnommen werden.

  • Die Werte für Zeichensatz und Sortierfolge der Standarddatenbank können den Systemvariablen character_set_database und collation_database entnommen werden.

Weitere Systemvariablen zu Zeichensätzen und Sortierfolgen betreffen die Handhabung der Daten einer Verbindung zwischen einem Client und dem Server. Jeder Client hat verbindungsspezifische Systemvariablen für Zeichensatz und Sortierfolge.

Sehen wir uns doch einmal an, was eine „Verbindung“ ist: Sie stellen eine solche her, wenn Sie sich mit dem Server verbinden. Der Client sendet SQL-Anweisungen wie etwa Abfragen über die Verbindung an den Server. Der Server beantwortet diese, indem er beispielsweise Ergebnismengen über die Verbindung an den Client zurückschickt. Dies wirft eine Reihe von Fragen zum Umgang mit Zeichensatz und Sortierfolge bei Clientverbindungen auf, die sich aber alle auf der Basis von Systemvariablen beantworten lassen:

  • Welchen Zeichensatz verwendet eine Anweisung, wenn sie den Client verlässt?

    Der Server entnimmt der Systemvariablen character_set_client den Zeichensatz, in dem sich vom Client gesendete Anweisungen befinden.

  • In welchen Zeichensatz sollte der Server eine Anweisung übersetzen, nachdem er sie erhalten hat?

    Hierzu verwendet der Server die Systemvariablen character_set_connection und collation_connection. Er wandelt die Anweisungen, die vom Client gesendet wurden, aus character_set_client in character_set_connection um (ausgenommen hiervon sind String-Literale, die eine Einführung wie _latin1 oder _utf8 aufweisen). collation_connection ist wichtig für Vergleiche literaler Strings. Für Vergleiche von Strings mit Spaltenwerten ist collation_connection hingegen unerheblich, da Spalten eine eigene Sortierfolge haben, die in diesem Fall Vorrang hat.

  • In welchen Zeichensatz soll der Server übersetzen, bevor er Ergebnismengen oder Fehlermeldungen an den Client zurückschickt?

    Die Systemvariable character_set_results gibt den Zeichensatz an, in dem der Server Abfrageergebnisse an den Client zurückgibt. Hierzu gehören Ergebnisdaten wie etwa Spaltenwerte und ergebnisbezogene Metadaten wie beispielsweise Spaltennamen.

Sie können die Einstellungen dieser Variablen optimieren oder einfach die Standardeinstellungen verwenden.

Es gibt zwei Anweisungen, die sich auf die Zeichensätze einer Verbindung auswirken:

SET NAMES 'charset_name'
SET CHARACTER SET charset_name

SET NAMES gibt an, welchen Zeichensatz der Client zum Versand von SQL-Anweisungen an den Server verwendet. SET NAMES 'cp1251' bedeutet mithin: „Ab jetzt haben von diesem Client eingehende Nachrichten den Zeichensatz cp1251“. Außerdem gibt die Anweisung den Zeichensatz an, den der Server zum Zurücksenden der Ergebnisse an den Client verwenden soll. (Beispielsweise legt er fest, welcher Zeichensatz für Spaltenwerte benutzt werden soll, wenn Sie eine SELECT-Anweisung absetzen.)

Eine SET NAMES 'x'-Anweisung ist äquivalent zu den folgenden drei Anweisungen:

SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;

Das Einstellen von character_set_connection auf x setzt collation_connection auf die Standardsortierfolge für x.

SET CHARACTER SET ähnelt SET NAMES, setzt Zeichensatz und Sortierfolge der Verbindung aber auf die Werte der Datenbank. Eine SET CHARACTER SET x-Anweisung ist äquivalent zu den folgenden drei Anweisungen:

SET character_set_client = x;
SET character_set_results = x;
SET collation_connection = @@collation_database;

Wenn Sie collation_connection einstellen, setzen Sie damit gleichzeitig character_set_connection auf den Zeichensatz, der mit dieser Sortierfolge verknüpft ist.

Wenn ein Client eine Verbindung herstellt, sendet er den Namen des Zeichensatzes, den er verwenden will, an den Server. Der Server stellt auf der Basis dieses Namens die Systemvariablen character_set_client, character_set_results und character_set_connection ein. Im Endeffekt führt der Server eine SET NAMES-Operation unter Verwendung des Zeichensatznamens aus.

Beim mysql-Client ist die Ausführung von SET NAMES bei jedem Systemstart nicht notwendig, wenn Sie einen anderen als den Standardzeichensatz verwenden wollen. Fügen Sie der mysql-Anweisungszeile oder Ihrer Optionsdatei einfach die Option --default-character-set hinzu. Die folgende Option beispielsweise setzt die drei Zeichensatzvariablen bei jedem Aufruf von mysql auf koi8r:

[mysql]
default-character-set=koi8r

Beispiel: Nehmen wir an, column1 sei als CHAR(5) CHARACTER SET latin2 definiert. Wenn Sie SET NAMES oder SET CHARACTER SET nicht angeben, dann sendet der Server bei SELECT column1 FROM t alle Werte für column1 zurück und verwendet dazu den Zeichensatz, den der Client bei der Verbindungsherstellung angegeben hat. Im Gegensatz dazu konvertiert, wenn Sie SET NAMES 'latin1' oder SET CHARACTER SET latin1 vor dem Absetzen der SELECT-Anweisung angeben, der Server die latin2-Werte in latin1, bevor er die Ergebnisse zurückschickt. Die Konvertierung kann verlustbehaftet sein, wenn Zeichen verwendet werden, die nicht in beiden Zeichensätzen vorhanden sind.

Wenn Sie nicht wollen, dass der Server Ergebnismengen konvertiert, dann setzen Sie character_set_results auf NULL:

SET character_set_results = NULL;

Hinweis: Derzeit kann UCS-2 nicht als Clientzeichensatz verwendet werden, d. h., SET NAMES 'ucs2' funktioniert nicht.

Um die Werte der Zeichensatz- und Sortierfolgevariablen anzuzeigen, die für Ihre Verbindung gelten, verwenden Sie die folgenden Anweisungen:

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

10.5. Probleme mit Sortierfolgen

Die folgenden Abschnitte beschreiben verschiedene Aspekte der Sortierfolgen bei Zeichensätzen.

10.5.1. Verwendung von COLLATE in SQL-Anweisungen

Mit der COLLATE-Klausel können Sie die Standardsortierfolge für einen Vergleich außer Kraft setzen. COLLATE kann in verschiedenen Teilen von SQL-Anweisungen verwendet werden. Hier ein paar Beispiele:

  • Bei ORDER BY:

    SELECT k
    FROM t1
    ORDER BY k COLLATE latin1_german2_ci;
    
  • Bei AS:

    SELECT k COLLATE latin1_german2_ci AS k1
    FROM t1
    ORDER BY k1;
    
  • Bei GROUP BY:

    SELECT k
    FROM t1
    GROUP BY k COLLATE latin1_german2_ci;
    
  • Bei Zusammenfassungsfunktionen:

    SELECT MAX(k COLLATE latin1_german2_ci)
    FROM t1;
    
  • Bei DISTINCT:

    SELECT DISTINCT k COLLATE latin1_german2_ci
    FROM t1;
    
  • Bei WHERE:

         SELECT *
         FROM t1
         WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;
    
         SELECT *
         FROM t1
         WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci;
    
  • Bei HAVING:

    SELECT k
    FROM t1
    GROUP BY k
    HAVING k = _latin1 'Müller' COLLATE latin1_german2_ci;
    

10.5.2. Rangfolgen von COLLATE-Klauseln

Die COLLATE-Klausel hat eine hohe Priorität (höher als ||), d. h., die folgenden beiden Ausdrücke sind äquivalent:

x || y COLLATE z
x || (y COLLATE z)

10.5.3. Der BINARY-Operator

Der Operator BINARY wandelt den ihm nachfolgenden String in einen Binär-String um. Dies ist eine einfache Möglichkeit, einen Spaltenvergleich byte- statt zeichenweise durchzuführen. BINARY berücksichtigt auch am Ende stehende Leerzeichen.

mysql> SELECT 'a' = 'A';
        -> 1
mysql> SELECT BINARY 'a' = 'A';
        -> 0
mysql> SELECT 'a' = 'a ';
        -> 1
mysql> SELECT BINARY 'a' = 'a ';
        -> 0

BINARY str ist eine Abkürzung für CAST(str AS BINARY).

Das Attribut BINARY in Zeichenspaltendefinitionen hat einen anderen Effekt. Einer Zeichenspalte, die mit dem Attribut BINARY definiert ist, wird die Binärsortierung des Zeichensatzes der Spalte zugewiesen. Jeder Zeichensatz hat eine Binärsortierfolge. So heißt etwa die Binärsortierung des Zeichensatzes latin1 latin1_bin. Wenn also der Standardzeichensatz der Tabelle latin1 ist, dann sind die folgenden beiden Definitionen äquivalent:

CHAR(10) BINARY
CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin

Der Effekt von BINARY als Spaltenattribut unterscheidet sich von dessen Wirkungsweise vor MySQL 4.1. Ursprünglich führte BINARY zu einer Spalte, die als Binär-String behandelt wurde. Ein Binär-String ist ein String aus Bytes, der weder einen Zeichensatz noch eine Sortierfolge hat; hierin liegt der Unterschied zu einem nichtbinären Zeichen-String, der eine Binärsortierung hat. Bei beiden String-Typen basieren Vergleiche auf den numerischen Werten der String-Einheit, aber bei nichtbinären Strings ist die Einheit das Zeichen, und einige Zeichensätze unterstützen Multibytezeichen. Siehe Abschnitt 11.4.2, „Die BINARY- und VARBINARY-Typen“.

Die Verwendung von CHARACTER SET binary in der Definition einer CHAR-, VARCHAR- oder TEXT-Spalte bewirkt, dass diese als binärer Datentyp behandelt wird. So sind beispielsweise die folgenden Definitionspaare gleichwertig:

CHAR(10) CHARACTER SET binary
BINARY(10)

VARCHAR(10) CHARACTER SET binary
VARBINARY(10)

TEXT CHARACTER SET binary
BLOB

10.5.4. Spezialfälle, in denen die Festlegung der Sortierfolge problematisch ist

Bei der überwiegenden Mehrheit der Anweisungen ist offensichtlich, welche Sortierfolge MySQL zur Auflösung einer Vergleichsoperation verwendet. Beispielsweise sollte es in den folgenden Fällen klar sein, dass die Sortierfolge der Spalte x verwendet wird:

SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;

Wenn allerdings mehrere Operanden vorhanden sind, kann es zu Mehrdeutigkeiten kommen. Zum Beispiel:

SELECT x FROM T WHERE x = 'Y';

Soll diese Abfrage die Sortierfolge der Spalte x oder die des String-Literals 'Y' verwenden?

Der SQL-Standard löst solche Fragen mithilfe so genannter „Sortierfolgevorrangsregeln“. Im Grunde genommen bedeutet dies: Sowohl x als auch 'Y' haben Sortierfolgen – welche Sortierfolge also hat Vorrang? Dies kann schwierig zu lösen sein, aber die folgenden Regeln sollten die meisten Situationen abdecken:

  • Eine explizite COLLATE-Klausel hat einen Sortierfolgenvorrangswert von 0 (d. h. gar keinen Vorrang).

  • Die Verkettung zweier Strings mit verschiedenen Sortierfolgen hat einen Sortierfolgenvorrangswert von 1.

  • Die Verkettung einer Spalte, eines Parameters einer gespeicherten Routine oder einer lokalen Variablen hat einen Sortierfolgenvorrangswert von 2.

  • Eine „Systemkonstante“ (d. h. der von Funktionen wie USER() oder VERSION() zurückgegebene String) hat einen Sortierfolgenvorrangswert von 3.

  • Die Sortierfolge eines Literals hat einen Sortierfolgenvorrangswert von 4

  • NULL oder ein Ausdruck, der von NULL abgeleitet ist, hat einen Sortierfolgenvorrangswert von 5.

Die genannten Sortierfolgenvorrangswerte gelten für MySQL 5.1.

Diese Regeln lösen Mehrdeutigkeiten wie folgt auf:

  • Die Sortierfolge mit dem niedrigsten Sortierfolgenvorrangswert wird verwendet.

  • Weisen beide Seiten hierfür denselben Wert auf, dann wird ein Fehler ausgegeben, wenn die Sortierfolgen nicht identisch sind.

Ein paar Beispiele:

column1 = 'A'Verwendet die Sortierfolge von column1
column1 = 'A' COLLATE xVerwendet die Sortierfolge von 'A'
column1 COLLATE x = 'A' COLLATE yFehler

Mithilfe der Funktion COERCIBILITY() können Sie den Sortierfolgenvorrangswert eines String-Ausdrucks bestimmen:

mysql> SELECT COERCIBILITY('A' COLLATE latin1_swedish_ci);
        -> 0
mysql> SELECT COERCIBILITY(VERSION());
        -> 3
mysql> SELECT COERCIBILITY('A');
        -> 4

Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.

10.5.5. Sortierfolgen müssen für den richtigen Zeichensatz angegeben werden

Jeder Zeichensatz hat eine oder mehrere Sortierfolgen, aber jede Sortierfolge ist nur mit genau einem Zeichensatz verknüpft. Insofern führt die folgende Anweisung zu einer Fehlermeldung, weil die Sortierfolge latin2_bin für den Zeichensatz latin1 unzulässig ist:

mysql> SELECT _latin1 'x' COLLATE latin2_bin;
ERROR 1253 (42000): COLLATION 'latin2_bin' is not valid
for CHARACTER SET 'latin1'

10.5.6. Beispiel für die Auswirkung von Sortierfolgen

Angenommen, die Spalte X in der Tabelle T hat die folgenden latin1-Spaltenwerte:

Muffler
Müller
MX Systems
MySQL

Nehmen wir nun weiter an, dass die Spaltenwerte mithilfe der folgenden Anweisung abgerufen werden:

SELECT X FROM T ORDER BY X COLLATE collation_name;

Die folgende Tabelle zeigt die sich ergebende Reihenfolge der Werte, wenn wir ORDER BY mit verschiedenen Sortierfolgen verwenden:

latin1_swedish_cilatin1_german1_cilatin1_german2_ci
MufflerMufflerMüller
MX SystemsMüllerMuffler
MüllerMX SystemsMX Systems
MySQLMySQLMySQL

Das Zeichen, welches in diesem Fall die verschiedenen Sortierfolgen bewirkt, ist der deutsche Umlaut ü.

  • Die erste Spalte zeigt das Ergebnis von SELECT unter Verwendung der schwedisch-finnischen Sortierfolgenregel, die besagt, dass Ü bei Y einsortiert wird.

  • Die zweite Spalte zeigt das Ergebnis von SELECT unter Verwendung der deutschen Regel DIN-1, die besagt, dass Ü bei U einsortiert wird.

  • Die dritte Spalte zeigt das Ergebnis von SELECT unter Verwendung der deutschen Regel DIN-2, die besagt, dass Ü bei UE einsortiert wird.

10.6. Operationen, auf die sich die Zeichensatzunterstützung auswirkt

Dieser Abschnitt beschreibt Operationen, die Zeichensatzinformationen berücksichtigen.

10.6.1. Ergebnis-Strings

MySQL hat viele Operatoren und Funktionen, die einen String zurückgeben. In diesem Abschnitt wollen wir die Frage beantworten, welchen Zeichensatz und welche Sortierfolge ein solcher String hat.

Bei einfachen Funktionen, die den String als Eingabe entgegennehmen und einen String als Ergebnis ausgeben, sind Zeichensatz und Sortierfolge des Ausgabe-Strings dieselben wie beim ersten Eingabewert. Beispielsweise gibt UPPER(X) einen String zurück, dessen Zeichensatz und Sortierfolge dieselben sind wie bei X. Gleiches gilt für INSTR(), LCASE(), LOWER(), LTRIM(), MID(), REPEAT(), REPLACE(), REVERSE(), RIGHT(), RPAD(), RTRIM(), SOUNDEX(), SUBSTRING(), TRIM(), UCASE() und UPPER().

Hinweis: Anders als alle anderen Funktionen ignoriert die REPLACE()-Funktion stets die Sortierfolge des Eingabe-Strings und führt einen Vergleich mit Unterscheidung der Groß-/Kleinschreibung durch.

Wenn ein Eingabe-String oder ein Funktionsergebnis einen Binär-String zum Ergebnis haben, hat dieser String keinen Zeichensatz und keine Sortierfolge. Dies kann mithilfe der Funktionen CHARSET() und COLLATION() überprüft werden, die beide binary zurückgeben, wenn das Argument ein Binär-String ist:

mysql> SELECT CHARSET(BINARY 'a'), COLLATION(BINARY 'a');
+---------------------+-----------------------+
| CHARSET(BINARY 'a') | COLLATION(BINARY 'a') |
+---------------------+-----------------------+
| binary              | binary                |
+---------------------+-----------------------+

Bei Operationen, die mehrere Eingabe-Strings kombinieren und einen einzelnen Ausgabe-String zurückgeben, gelten die „Zusammenfassungsregeln“ des SQL-Standards zur Bestimmung der Sortierfolge des Ergebnisses:

  • Wenn eine explizite COLLATE X vorhanden ist, wird X verwendet.

  • Wenn explizite COLLATE X und COLLATE Y auftreten, wird ein Fehler zurückgegeben.

  • Andernfalls wird, wenn alle Sortierfolgen X sind, X verwendet.

  • Ansonsten hat das Ergebnis keine Sortierfolge.

Beispielsweise ist bei CASE ... WHEN a THEN b WHEN b THEN c COLLATE X END die resultierende Sortierfolge X. Gleiches gilt für CASE, UNION, ||, CONCAT(), ELT(), GREATEST(), IF() und LEAST().

Bei Operationen, die Zeichendaten umwandeln, werden der Zeichensatz und die Sortierfolge der Strings, die sich aus diesen Operationen ergeben, durch die Systemvariablen character_set_connection und collation_connection definiert. Dies gilt für CAST(), CHAR(), CONV(), FORMAT(), HEX() und SPACE().

10.6.2. CONVERT() und CAST()

CONVERT() stellt eine Möglichkeit zur Konvertierung von Daten zwischen verschiedenen Zeichensätzen dar. Die Syntax sieht wie folgt aus:

CONVERT(expr USING transcoding_name)

Bei MySQL sind die Transkodierungs- mit den entsprechenden Zeichensatznamen identisch.

Ein paar Beispiele:

SELECT CONVERT(_latin1'Müller' USING utf8);
INSERT INTO utf8table (utf8column)
    SELECT CONVERT(latin1field USING utf8) FROM latin1table;

CONVERT(... USING ...) ist entsprechend der SQL-Standardspezifikation implementiert.

Sie können auch mit CAST() einen String in einen anderen Zeichensatz umwandeln. Die Syntax sieht wie folgt aus:

CAST(character_string AS character_data_type CHARACTER SET charset_name)

Beispiel:

SELECT CAST(_latin1'test' AS CHAR CHARACTER SET utf8);

Wenn Sie CAST() ohne Angabe von CHARACTER SET verwenden, werden Zeichensatz und Sortierfolge des Ergebnisses durch die Systemvariablen character_set_connection und collation_connection definiert. Wenn Sie CAST() mit CHARACTER SET X benutzen, hat das Ergebnis den Zeichensatz X und als Sortierfolge die Standardsortierfolge von X.

Sie können eine COLLATE-Klausel nicht innerhalb, wohl aber außerhalb von CAST() verwenden. Mithin ist CAST(... COLLATE ...) unzulässig, CAST(...) COLLATE ... aber ist zulässig.

Beispiel:

SELECT CAST(_latin1'test' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin;

10.6.3. SHOW-Anweisungen und INFORMATION_SCHEMA

Mehrere SHOW-Anweisungen vermitteln zusätzliche Angaben zu Zeichensätzen. Hierzu gehören SHOW CHARACTER SET, SHOW COLLATION, SHOW CREATE DATABASE, SHOW CREATE TABLE und SHOW COLUMNS. Diese Anweisungen wollen wir hier kurz beschreiben. Weitere Informationen finden Sie unter Abschnitt 13.5.4, „SHOW.

INFORMATION_SCHEMA gibt mehrere Tabellen aus, deren Inhalt dem ähnelt, was sich mit SHOW-Anweisungen anzeigen lässt. So enthalten beispielsweise die Tabellen CHARACTER_SETS und COLLATIONS die Angaben, die sich auch mit SHOW CHARACTER SET bzw. SHOW COLLATION ermitteln lassen. Siehe Kapitel 22, Die Datenbank INFORMATION_SCHEMA.

Der Befehl SHOW CHARACTER SET zeigt alle verfügbaren Zeichensätze an. Er nimmt eine optionale LIKE-Klausel entgegen, die angibt, auf welche Zeichensatznamen zu prüfen ist. Zum Beispiel:

mysql> SHOW CHARACTER SET LIKE 'latin%';
+---------+-----------------------------+-------------------+--------+
| Charset | Description                 | Default collation | Maxlen |
+---------+-----------------------------+-------------------+--------+
| latin1  | cp1252 West European        | latin1_swedish_ci |      1 |
| latin2  | ISO 8859-2 Central European | latin2_general_ci |      1 |
| latin5  | ISO 8859-9 Turkish          | latin5_turkish_ci |      1 |
| latin7  | ISO 8859-13 Baltic          | latin7_general_ci |      1 |
+---------+-----------------------------+-------------------+--------+

Die Ausgabe von SHOW COLLATION enthält alle verfügbaren Zeichensätze. Die Anweisung nimmt eine optionale LIKE-Klausel entgegen, die angibt, auf welche Sortierfolgennamen zu prüfen ist. Zum Beispiel:

mysql> SHOW COLLATION LIKE 'latin1%';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1  |  5 |         |          |       0 |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       0 |
| latin1_danish_ci  | latin1  | 15 |         |          |       0 |
| latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
| latin1_bin        | latin1  | 47 |         | Yes      |       0 |
| latin1_general_ci | latin1  | 48 |         |          |       0 |
| latin1_general_cs | latin1  | 49 |         |          |       0 |
| latin1_spanish_ci | latin1  | 94 |         |          |       0 |
+-------------------+---------+----+---------+----------+---------+

SHOW CREATE DATABASE zeigt die CREATE DATABASE-Anweisung an, die eine gegebene Datenbank erstellt:

mysql> SHOW CREATE DATABASE test;
+----------+-----------------------------------------------------------------+
| Database | Create Database                                                 |
+----------+-----------------------------------------------------------------+
| test     | CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-----------------------------------------------------------------+

Wird keine COLLATE-Klausel angezeigt, dann wird die Standardsortierfolge des Zeichensatzes verwendet.

SHOW CREATE TABLE ist ähnlich, zeigt aber die CREATE TABLE-Anweisung zur Erstellung der Tabelle an. Die Spaltendefinitionen enthalten alle ggf. vorhandenen Zeichensatzspezifikationen, und die Tabellenoptionen enthalten in jedem Fall Zeichensatzangaben.

Die SHOW COLUMNS-Anweisung zeigt die Sortierfolgen der Spalten einer Tabelle an, wenn sie mit SHOW FULL COLUMNS aufgerufen wird. Spalten der Datentypen CHAR, VARCHAR und TEXT haben Sortierfolgen. Numerische und andere nicht zeichenbasierte Typen haben keine Sortierfolge (dies wird durch NULL als Collation-Wert angezeigt). Zum Beispiel:

mysql> SHOW FULL COLUMNS FROM person\G
*************************** 1. row ***************************
     Field: id
      Type: smallint(5) unsigned
 Collation: NULL
      Null: NO
       Key: PRI
   Default: NULL
     Extra: auto_increment
Privileges: select,insert,update,references
   Comment:
*************************** 2. row ***************************
     Field: name
      Type: char(60)
 Collation: latin1_swedish_ci
      Null: NO
       Key:
   Default:
     Extra:
Privileges: select,insert,update,references
   Comment:

Der Zeichensatz erscheint nicht direkt in der Anzeige, wohl aber als Teil des Sortierfolgennamens.

10.7. Unicode-Unterstützung

MySQL 5.1 unterstützt zur Speicherung von Unicode-Daten zwei Zeichensätze:

  • ucs2 (Unicode-Zeichensatz UCS-2)

  • utf8 (UTF-8-Kodierung des Unicode-Zeichensatzes)

Bei UCS-2 (binäre Unicode-Darstellung) wird jedes Zeichen durch einen 2 Byte umfassenden Unicode-Code dargestellt, wobei das höherwertige Byte zuerst aufgeführt ist. Zum Beispiel: LATIN CAPITAL LETTER A hat den Code 0x0041 und wird als 2-Byte-Sequenz gespeichert: 0x00 0x41. CYRILLIC SMALL LETTER YERU (Unicode 0x044B) wird als 2-Byte-Sequenz gespeichert: 0x04 0x4B. Weitere Informationen zu Unicode-Zeichen und ihren Codes erhalten Sie auf der Unicode-Homepage.

Derzeit kann UCS-2 nicht als Clientzeichensatz verwendet werden, d. h., SET NAMES 'ucs2' funktioniert nicht.

Der UTF-8-Zeichensatz (transformierte Unicode-Darstellung) ist eine alternative Möglichkeit zur Speicherung von Unicode-Daten. Er ist entsprechend RFC 3629 implementiert. Die Idee hinter dem UTF-8-Zeichensatz ist die, dass verschiedene Unicode-Zeichen mit Bytesequenzen unterschiedlicher Länge kodiert werden:

  • Einfache lateinische Buchstaben, Ziffern und Interpunktionszeichen verwenden je ein Byte.

  • Die Schriftzeichen der meisten europäischen und nahöstlichen Sprachen passen in eine 2-Byte-Sequenz. Dies gilt für die Buchstaben des erweiterten Lateins (einschließlich Tilde, Längestrich, Akut, Gravis und weitere Akzente) sowie das Kyrillische, Griechische, Armenische, Hebräische, Arabische, Syrische usw.

  • Die koreanischen, chinesischen und japanischen Ideogramme schließlich verwenden je 3 Byte.

RFC 3629 beschreibt Sequenzen, die 1 bis 4 Byte umfassen. Zurzeit umfasst die UTF-8-Unterstützung durch MySQL keine 4-Byte-Sequenzen. (Ein älterer Standard für die UTF-8-Kodierung ist in RFC 2279 enthalten, wo UTF-8-Sequenzen mit einer Länge von bis zu 6 Byte beschrieben werden. RFC 3629 hat RFC 2279 ersetzt, weswegen Sequenzen mit 5 oder 6 Byte heute nicht mehr verwendet werden.)

Tipp: Um mit UTF-8 Speicher zu sparen, verwenden Sie VARCHAR statt CHAR. Andernfalls muss MySQL 3 Byte pro Zeichen in einer CHAR CHARACTER SET utf8-Spalte reservieren, da dies die maximale Länge ist. So muss MySQL etwa 30 Byte für eine CHAR(10) CHARACTER SET utf8-Spalte vorsehen.

10.8. UTF8 für Metadaten

Metadaten sind „Daten über Daten“. Alle Daten, die die Datenbank beschreiben – nicht aber solche, die in der Datenbank enthalten sind – bezeichnet man als Metadaten. Insofern sind etwa Spalten-, Datenbank-, Benutzer- und Versionsnamen sowie die meisten String-Ergebnisse aus SHOW-Anweisungen Metadaten. Dies gilt auch für die Inhalte von Tabellen in INFORMATION_SCHEMA, weil diese Tabellen per Definition Informationen zu Datenbankobjekten enthalten.

Die Darstellung von Metadaten muss den folgenden Anforderungen genügen:

  • Alle Metadaten müssen im selben Zeichensatz stehen. Andernfalls würden weder die SHOW-Befehle noch SELECT-Anweisungen für Tabellen im INFORMATION_SCHEMA korrekt arbeiten, weil verschiedene Datensätze in derselben Spalte der Ergebnisse für diese Operationen in verschiedenen Zeichensätzen stehen würden.

  • Metadaten müssen alle Zeichen in allen Sprachen enthalten. Andernfalls könnten Benutzer unter Umständen Spalten und Tabellen nicht in ihrer eigenen Sprache benennen.

Um beide Bedingungen zu erfüllen, speichert MySQL Metadaten in einem Unicode-Zeichensatz (nämlich UTF-8). Dies sorgt keinesfalls für Probleme, wenn Sie keine Buchstaben mit Akzent oder nichtlateinische Zeichen verwenden. Andernfalls aber sollten Sie berücksichtigen, dass Metadaten in UTF-8 stehen.

Die Anforderungen an Metadaten sehen vor, dass die Rückgabewerte der Funktionen USER(), CURRENT_USER(), DATABASE() und VERSION() standardmäßig den UTF-8-Zeichensatz verwenden; dies gilt auch für Synonyme wie SESSION_USER() und SYSTEM_USER().

Der Server setzt die Systemvariable character_set_system auf den Namen des Metadaten-Zeichensatzes:

mysql> SHOW VARIABLES LIKE 'character_set_system';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| character_set_system | utf8  |
+----------------------+-------+

Die Speicherung von Metadaten unter Verwendung von Unicode hat nicht zur Folge, dass der Server Spaltenüberschriften und die Ergebnisse von DESCRIBE-Funktionen standardmäßig im durch character_set_system angegebenen Zeichensatz zurückgibt. Wenn Sie SELECT column1 FROM t verwenden, wird der Name column1 selbst vom Server an den Client in dem Zeichensatz zurückgegeben, der vom Wert der Systemvariablen character_set_results angegeben wird (deren Standartwert ist latin1). Wenn Sie wollen, dass der Server Metadatenergebnisse in einem anderen Zeichensatz zurückgibt, erzwingen Sie mit der SET NAMES-Anweisung eine Zeichensatzkonvertierung am Server. SET NAMES stellt character_set_results und andere zugehörige Systemvariablen um. (Siehe auch Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.) Alternativ kann ein Clientprogramm die Konvertierung nach Empfang des Ergebnisses vom Server vornehmen. Die Konvertierung durch den Client ist effizienter, aber diese Option ist nicht immer verfügbar.

Wenn character_set_results den Wert NULL hat, wird keine Konvertierung durchgeführt und der Server gibt Metadaten im ursprünglichen (d. h. dem durch character_set_system angegebenen) Zeichensatz zurück.

Fehlermeldungen, die der Server an den Client zurückgibt, werden wie Metadaten automatisch in den Zeichensatz des Clients konvertiert.

Keine Sorge, wenn Sie (beispielsweise) die Funktion USER() für einen Vergleich oder eine Zuordnung innerhalb einer einzelnen Anweisung verwenden: MySQL führt die Konvertierung für Sie automatisch durch.

SELECT * FROM Table1 WHERE USER() = latin1_column;

Dies funktioniert, weil der Inhalt von latin1_column vor dem Vergleich automatisch in UTF-8 konvertiert wird.

INSERT INTO Table1 (latin1_column) SELECT USER();

Dies funktioniert, weil der Inhalt von USER() vor der Zuweisung automatisch in latin1 konvertiert wird. Die automatische Konvertierung ist noch nicht vollständig implementiert, sollte aber in einer zukünftigen Version korrekt arbeiten.

Zwar ist die automatische Konvertierung nicht Bestandteil des SQL-Standards, aber das SQL-Standarddokument besagt, dass jeder Zeichensatz (hinsichtlich der unterstützten Zeichen) eine „Teilmenge“ von Unicode ist. Aufgrund des bekannten Prinzips „Was für eine übergeordnete Menge gilt, kann auch für eine Teilmenge gelten“ nehmen wir an, dass eine Sortierfolge für Unicode auch für Vergleiche mit Nicht-Unicode-Strings gelten kann.

10.9. Zeichensätze und Sortierfolgen, die MySQL unterstützt

MySQL unterstützt mehr als 70 Sortierfolgen für über 30 Zeichensätze. In diesem Abschnitt sind die Zeichensätze aufgelistet, die MySQL unterstützt. Es gibt einen Unterabschnitt für jede Gruppe zusammengehöriger Zeichensätze. Für jeden Zeichensatz werden die zulässigen Sortierfolgen aufgeführt.

Sie können die verfügbaren Zeichensätze und ihre jeweiligen Standardsortierfolgen jederzeit mit der Anweisung SHOW CHARACTER SET anzeigen:

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+
| Charset  | Description                 | Default collation   |
+----------+-----------------------------+---------------------+
| big5     | Big5 Traditional Chinese    | big5_chinese_ci     |
| dec8     | DEC West European           | dec8_swedish_ci     |
| cp850    | DOS West European           | cp850_general_ci    |
| hp8      | HP West European            | hp8_english_ci      |
| koi8r    | KOI8-R Relcom Russian       | koi8r_general_ci    |
| latin1   | cp1252 West European        | latin1_swedish_ci   |
| latin2   | ISO 8859-2 Central European | latin2_general_ci   |
| swe7     | 7bit Swedish                | swe7_swedish_ci     |
| ascii    | US ASCII                    | ascii_general_ci    |
| ujis     | EUC-JP Japanese             | ujis_japanese_ci    |
| sjis     | Shift-JIS Japanese          | sjis_japanese_ci    |
| hebrew   | ISO 8859-8 Hebrew           | hebrew_general_ci   |
| tis620   | TIS620 Thai                 | tis620_thai_ci      |
| euckr    | EUC-KR Korean               | euckr_korean_ci     |
| koi8u    | KOI8-U Ukrainian            | koi8u_general_ci    |
| gb2312   | GB2312 Simplified Chinese   | gb2312_chinese_ci   |
| greek    | ISO 8859-7 Greek            | greek_general_ci    |
| cp1250   | Windows Central European    | cp1250_general_ci   |
| gbk      | GBK Simplified Chinese      | gbk_chinese_ci      |
| latin5   | ISO 8859-9 Turkish          | latin5_turkish_ci   |
| armscii8 | ARMSCII-8 Armenian          | armscii8_general_ci |
| utf8     | UTF-8 Unicode               | utf8_general_ci     |
| ucs2     | UCS-2 Unicode               | ucs2_general_ci     |
| cp866    | DOS Russian                 | cp866_general_ci    |
| keybcs2  | DOS Kamenicky Czech-Slovak  | keybcs2_general_ci  |
| macce    | Mac Central European        | macce_general_ci    |
| macroman | Mac West European           | macroman_general_ci |
| cp852    | DOS Central European        | cp852_general_ci    |
| latin7   | ISO 8859-13 Baltic          | latin7_general_ci   |
| cp1251   | Windows Cyrillic            | cp1251_general_ci   |
| cp1256   | Windows Arabic              | cp1256_general_ci   |
| cp1257   | Windows Baltic              | cp1257_general_ci   |
| binary   | Binary pseudo charset       | binary              |
| geostd8  | GEOSTD8 Georgian            | geostd8_general_ci  |
| cp932    | SJIS for Windows Japanese   | cp932_japanese_ci   |
| eucjpms  | UJIS for Windows Japanese   | eucjpms_japanese_ci |
+----------+-----------------------------+---------------------+

10.9.1. Unicode-Zeichensätze

MySQL umfasst zwei Unicode-Zeichensätze. Sie können mit diesen beiden Zeichensätzen Text in ca. 650 Sprachen speichern.

  • Sortierfolgen für ucs2 (UCS-2-Unicode):

    • ucs2_bin

    • ucs2_czech_ci

    • ucs2_danish_ci

    • ucs2_esperanto_ci

    • ucs2_estonian_ci

    • ucs2_general_ci (Standard)

    • ucs2_hungarian_ci

    • ucs2_icelandic_ci

    • ucs2_latvian_ci

    • ucs2_lithuanian_ci

    • ucs2_persian_ci

    • ucs2_polish_ci

    • ucs2_roman_ci

    • ucs2_romanian_ci

    • ucs2_slovak_ci

    • ucs2_slovenian_ci

    • ucs2_spanish2_ci

    • ucs2_spanish_ci

    • ucs2_swedish_ci

    • ucs2_turkish_ci

    • ucs2_unicode_ci

  • Sortierfolgen für utf8 (UTF-8-Unicode):

    • utf8_bin

    • utf8_czech_ci

    • utf8_danish_ci

    • utf8_esperanto_ci

    • utf8_estonian_ci

    • utf8_general_ci (Standard)

    • utf8_hungarian_ci

    • utf8_icelandic_ci

    • utf8_latvian_ci

    • utf8_lithuanian_ci

    • utf8_persian_ci

    • utf8_polish_ci

    • utf8_roman_ci

    • utf8_romanian_ci

    • utf8_slovak_ci

    • utf8_slovenian_ci

    • utf8_spanish2_ci

    • utf8_spanish_ci

    • utf8_swedish_ci

    • utf8_turkish_ci

    • utf8_unicode_ci

Die Sortierfolgen ucs2_hungarian_ci und utf8_hungarian_ci wurden in MySQL 5.1.5 hinzugefügt.

MySQL implementiert die Sortierfolge utf8_unicode_ci entsprechend dem UCA (Unicode Collation Algorithm, Unicode-Sortierfolgenalgorithmus), der unter http://www.unicode.org/reports/tr10/ beschrieben ist. Die Sortierfolge verwendet die UCA-Gewichtungsschlüssel nach Version 4.0.0 (siehe http://www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt). Die folgende Beschreibung verwendet utf8_unicode_ci, gilt aber für ucs2_unicode_ci gleichermaßen.

Zurzeit bietet die Sortierfolge utf8_unicode_ci nur teilweise Unterstützung für den UCA. Einige Zeichen werden noch nicht unterstützt. Gleiches gilt für diakritische Zeichen. Dies betrifft in erster Linie das Vietnamesische und einige Minderheitensprachen in Russland wie etwa das Udmurtische, das Tatarische, das Baschkirische und Mari.

Die bedeutsamste Funktion in utf8_unicode_ci besteht darin, dass Erweiterungen unterstützt werden, d. h., wenn ein Zeichen mit einer Kombination anderer Zeichen gleichgesetzt wird. Beispielsweise wird im Deutschen und einigen anderen Sprachen ‘ß’ mit ‘ss’ gleichgesetzt.

utf8_general_ci ist eine ältere Sortierfolge, die Erweiterungen nicht unterstützt. Hier können nur 1 : 1-Vergleiche zwischen Zeichen durchgeführt werden: Vergleiche für die utf8_general_ci-Sortierfolge sind also schneller, aber unter Umständen weniger korrekt als Vergleiche für utf8_unicode_ci.

Die folgenden Gleichstellungen beispielsweise sind sowohl in utf8_general_ci als auch in utf8_unicode_ci zutreffend:

Ä = A
Ö = O
Ü = U

Ein Unterschied zwischen den Sortierfolgen besteht darin, dass Folgendes für utf8_general_ci wahr ist:

ß = s

Dagegen ist Folgendes für utf8_unicode_ci wahr:

ß = ss

MySQL implementiert sprachspezifische Sortierfolgen für den utf8-Zeichensatz nur dann, wenn die Sortierung mit utf8_unicode_ci bei einer Sprache nicht gut funktioniert. So arbeitet utf8_unicode_ci etwa für das Deutsche oder das Französische einwandfrei, weswegen für diese beiden Sprachen keine utf8-Spezialsortierungen erforderlich sind.

Auch utf8_general_ci ist für Deutsch und Französisch weitgehend angemessen, nur wird hier ‘ß’ mit ‘s’ (statt ‘ss’) gleichgesetzt. Sofern es für Ihre Anwendung ausreichend sein sollte, sollten Sie utf8_general_ci verwenden, weil diese Sortierfolge schneller ist. Ansonsten benutzen Sie utf8_unicode_ci, denn diese Sortierfolge arbeitet exakter.

utf8_swedish_ci wurde wie andere sprachspezifische utf8-Sortierfolgen auch von utf8_unicode_ci abgeleitet und mit zusätzlichen Sprachregeln ergänzt. Beispielsweise funktioniert im Schwedischen die folgende Beziehung – etwas, das der deutsche oder französische Muttersprachler nicht erwarten würde:

Ü = Y < Ö

Die Sortierfolgen utf8_spanish_ci und utf8_spanish2_ci entsprechen dem modernen bzw. dem traditionellen Spanisch. Bei beiden Sortierfolgen ist ‘ñ’ (n mit Tilde) ein separater Buchstabe zwischen ‘n’ und ‘o’. Ferner ist beim traditionellen Spanisch ‘ch’ ein separater Buchstabe zwischen ‘c’ und d und ‘ll’ ein separater Buchstabe zwischen ‘l’ und ‘m’.

10.9.2. Westeuropäische Zeichensätze

Westeuropäische Zeichensätze decken die meisten westeuropäischen Sprachen ab, so etwa Französisch, Spanisch, Katalanisch, Baskisch, Portugiesisch, Italienisch, Albanisch, Niederländisch, Deutsch, Dänisch, Schwedisch, Norwegisch, Finnisch, Färöisch, Isländisch, Irisch, Schottisch und Englisch.

  • Sortierfolgen von ascii (US ASCII):

    • ascii_bin

    • ascii_general_ci (Standard)

  • Sortierfolgen von cp850 (DOS, westeuropäisch):

    • cp850_bin

    • cp850_general_ci (Standard)

  • Sortierfolgen von dec8 (DEC, westeuropäisch):

    • dec8_bin

    • dec8_swedish_ci (Standard)

  • Sortierfolgen von hp8 (HP, westeuropäisch):

    • hp8_bin

    • hp8_english_ci (Standard)

  • Sortierfolgen von latin1 (cp1252, westeuropäisch):

    • latin1_bin

    • latin1_danish_ci

    • latin1_general_ci

    • latin1_general_cs

    • latin1_german1_ci

    • latin1_german2_ci

    • latin1_spanish_ci

    • latin1_swedish_ci (Standard)

    latin1 ist der Standardzeichensatz. latin1 von MySQL entspricht dem Windows-Zeichensatz cp1252. Mithin ist er mit dem offiziellen latin1 nach ISO 8859-1 bzw. dem latin1-Zeichensatz der IANA (Internet Assigned Numbers Authority) identisch, aber der IANA-Zeichensatz behandelt die Codepunkte zwischen 0x80 und 0x9f als „undefiniert“, während cp1252 (und damit auch der latin1-Zeichensatz von MySQL) diesen Positionen Zeichen zuweist. So ist etwa 0x80 das Eurozeichen. Für die „undefinierten“ Einträge in cp1252 übersetzt MySQL 0x81 in das Unicode-Zeichen 0x0081, 0x8d in 0x008d, 0x8f in 0x008f, 0x90 in 0x0090 und 0x9d in 0x009d.

    Die Sortierfolge latin1_swedish_ci ist die Standardsortierfolge, die von der Mehrzahl der MySQL-Kunden wahrscheinlich verwendet wird. Obwohl häufig gesagt wird, dass sie auf den Sortierregeln für das Schwedische und das Finnische basiert, gibt es viele Schweden und Finnen, die dieser Aussage widersprechen.

    Die Sortierfolgen latin1_german1_ci und latin1_german2_ci basieren auf den DIN-1- und DIN-2-Normen. DIN ist das Deutsche Institut für Normung, also die deutsche Standardisierungsorganisation. DIN-1 heißt „Wörterbuchsortierung“, DIN-2 „Telefonbuchsortierung“.

    • Regeln für latin1_german1_ci (Wörterbuchsortierung):

      Ä = A
      Ö = O
      Ü = U
      ß = s
      
    • Regeln für latin1_german2_ci (Telefonbuchsortierung):

      Ä = AE
      Ö = OE
      Ü = UE
      ß = ss
      

    Bei der Sortierfolge latin1_spanish_ci ist ‘ñ’ ein separater Buchstabe zwischen ‘n’ und ‘o’.

  • Sortierfolgen von macroman (Mac, westeuropäisch):

    • macroman_bin

    • macroman_general_ci (Standard)

  • Sortierfolgen von swe7 (Schwedisch, 7 Bit):

    • swe7_bin

    • swe7_swedish_ci (Standard)

10.9.3. Mitteleuropäische Zeichensätze

MySQL bietet in eingeschränktem Maße Unterstützung für die Zeichensätze, die in Tschechien, der Slowakei, Ungarn, Rumänien, Slowenien, Kroatien und Polen verwendet werden.

  • Sortierfolgen von cp1250 (Windows, mitteleuropäisch):

    • cp1250_bin

    • cp1250_croatian_ci

    • cp1250_czech_cs

    • cp1250_general_ci (Standard)

    • cp1250_polish_ci

  • Sortierfolgen von cp852 (DOS, mitteleuropäisch):

    • cp852_bin

    • cp852_general_ci (Standard)

  • Sortierfolgen von keybcs2 (DOS, Kamenicky-tschechoslowakisch):

    • keybcs2_bin

    • keybcs2_general_ci (Standard)

  • Sortierfolgen von latin2 (ISO 8859-2, mitteleuropäisch):

    • latin2_bin

    • latin2_croatian_ci

    • latin2_czech_cs

    • latin2_general_ci (Standard)

    • latin2_hungarian_ci

  • Sortierfolgen von macce (Mac, mitteleuropäisch):

    • macce_bin

    • macce_general_ci (Standard)

10.9.4. Zeichensätze für Südeuropa und den Mittleren Osten

Zu den südeuropäischen und nahöstlichen Zeichensätzen, die von MySQL unterstützt werden, gehören das Armenische, das Arabische, das Georgische, das Griechische, das Hebräische und das Türkische.

  • Sortierfolgen für armscii8 (ARMSCII-8, armenisch):

    • armscii8_bin

    • armscii8_general_ci (Standard)

  • Sortierfolgen von cp1256 (Windows, arabisch):

    • cp1256_bin

    • cp1256_general_ci (Standard)

  • Sortierfolgen von geostd8 (GEOSTD8, georgisch):

    • geostd8_bin

    • geostd8_general_ci (Standard)

  • Sortierfolgen von greek (ISO 8859-7, griechisch):

    • greek_bin

    • greek_general_ci (Standard)

  • Sortierfolgen von hebrew (ISO 8859-8, hebräisch):

    • hebrew_bin

    • hebrew_general_ci (Standard)

  • Sortierfolgen von latin5 (ISO 8859-9, türkisch):

    • latin5_bin

    • latin5_turkish_ci (Standard)

10.9.5. Baltische Zeichensätze

Die baltischen Zeichensätze decken die estnische, die lettische und die litauische Sprache ab.

  • Sortierfolgen von cp1257 (Windows, baltisch):

    • cp1257_bin

    • cp1257_general_ci (Standard)

    • cp1257_lithuanian_ci

  • Sortierfolgen von latin7 (ISO 8859-13, baltisch):

    • latin7_bin

    • latin7_estonian_cs

    • latin7_general_ci (Standard)

    • latin7_general_cs

10.9.6. Kyrillische Zeichensätze

Die kyrillischen Zeichensätze und Sortierfolgen werden für das Weißrussische, das Bulgarische, das Russische und das Ukrainische verwendet.

  • Sortierfolgen von cp1251 (Windows, kyrillisch):

    • cp1251_bin

    • cp1251_bulgarian_ci

    • cp1251_general_ci (Standard)

    • cp1251_general_cs

    • cp1251_ukrainian_ci

  • Sortierfolgen von cp866 (DOS, russisch):

    • cp866_bin

    • cp866_general_ci (Standard)

  • Sortierfolgen von koi8r (KOI8-R, Relcom, russisch):

    • koi8r_bin

    • koi8r_general_ci (Standard)

  • Sortierfolgen von koi8u (KOI8-U, ukrainisch):

    • koi8u_bin

    • koi8u_general_ci (Standard)

10.9.7. Asiatische Zeichensätze

Die von uns unterstützten asiatischen Zeichensätze sind das Chinesische, das Japanische, das Koreanische und das Thailändische. Diese können sehr komplex sein. Beispielsweise müssen die chinesischen Zeichensätze Tausende verschiedener Zeichen zulassen. Weitere Informationen zu den Zeichensätzen cp932 und sjis finden Sie in Abschnitt 10.9.7.1, „Der Zeichensatz cp932.

  • Sortierfolgen von big5 (Big5, chinesisch traditionell):

    • big5_bin

    • big5_chinese_ci (Standard)

  • Sortierfolgen von cp932 (SJIS für Windows, japanisch):

    • cp932_bin

    • cp932_japanese_ci (Standard)

  • Sortierfolgen von eucjpms (UJIS für Windows, japanisch):

    • eucjpms_bin

    • eucjpms_japanese_ci (Standard)

  • Sortierfolgen von euckr (EUC-KR, koreanisch):

    • euckr_bin

    • euckr_korean_ci (Standard)

  • Sortierfolgen von gb2312 (GB2312, chinesisch vereinfacht):

    • gb2312_bin

    • gb2312_chinese_ci (Standard)

  • Sortierfolgen von gbk (GBK, chinesisch vereinfacht):

    • gbk_bin

    • gbk_chinese_ci (Standard)

  • Sortierfolgen von sjis (Shift-JIS, japanisch):

    • sjis_bin

    • sjis_japanese_ci (Standard)

  • Sortierfolgen von tis620 (TIS620, thailändisch):

    • tis620_bin

    • tis620_thai_ci (Standard)

  • Sortierfolgen von ujis (EUC-JP, japanisch):

    • ujis_bin

    • ujis_japanese_ci (Standard)

10.9.7.1. Der Zeichensatz cp932

Warum ist cp932 erforderlich?

In MySQL entspricht der Zeichensatz sjis dem von der IANA definierten Zeichensatz Shift_JIS, der JIS X0201- und JIS X0208-Zeichen unterstützt. (Siehe auch http://www.iana.org/assignments/character-sets.)

Allerdings ist die Bedeutung von „SHIFT JIS“ als Begriff zu Beschreibungszwecken sehr vage geworden und umfasst häufig auch die Erweiterungen auf Shift_JIS, die von verschiedenen Anbietern definiert werden.

So ist beispielsweise das in japanischsprachigen Windows-Umgebungen verwendete „SHIFT JIS“ eine Microsoft-Erweiterung von Shift_JIS, deren exakter Name Microsoft Windows Codepage : 932 oder cp932 lautet. Neben den von Shift_JIS unterstützten Zeichen unterstützt cp932 Erweiterungszeichen wie NEC-Sonderzeichen, NEC-Auswahl-/IBM-Erweiterungszeichen sowie IBM-Auswahlzeichen.

Viele japanische Benutzer haben Probleme mit diesen Erweiterungszeichen. Ursache hierfür sind die folgenden Faktoren:

  • MySQL wandelt Zeichensätze automatisch um.

  • Zeichensätze werden via Unicode (ucs2) konvertiert.

  • Der Zeichensatz sjis unterstützt keine Konvertierung dieser Erweiterungszeichen.

  • Es gibt mehrere Regeln für die Konvertierung aus dem so genannten „SHIFT JIS“ in Unicode, und je nach Konvertierungsregeln werden einige Zeichen anders in Unicode konvertiert. MySQL unterstützt nur eine dieser Regeln (diese wird weiter unten beschrieben).

Der MySQL-Zeichensatz cp932 wurde entwickelt, um diese Probleme zu beseitigen.

Weil MySQL die Zeichensatzkonvertierung unterstützt, ist es wichtig, die beiden Zeichensätze Shift_JIS (IANA) und cp932 in zwei verschiedene Zeichensätze aufzuteilen, weil diese unterschiedliche Konvertierungsregeln bieten.

Wie unterscheidet sich cp932 von sjis?

Der Zeichensatz cp932 unterscheidet sich von sjis wie folgt:

  • cp932 unterstützt NEC-Sonderzeichen, NEC-Auswahl-/IBM-Erweiterungszeichen sowie IBM-Auswahlzeichen.

  • Einige cp932-Zeichen haben zwei verschiedene Codepunkte, die beide in denselben Unicode-Codepunkt konvertiert werden. Wenn Sie aus Unicode in cp932 zurückkonvertieren, muss einer dieser beiden Codepunkte ausgewählt werden. Bei solchen „Roundtrip-Konvertierungen“ wird die von Microsoft empfohlene Regel verwendet. (Siehe auch http://support.microsoft.com/kb/170559/EN-US/.)

    Die Konvertierungsregel funktioniert wie folgt:

    • Wenn das Zeichen sowohl in JIS X 0208 als auch in den NEC-Sonderzeichen enthalten ist, wird der Codepunkt von JIS X 0208 verwendet.

    • Wenn das Zeichen sowohl in den NEC-Sonderzeichen als auch in den IBM-Auswahlzeichen enthalten ist, wird der Codepunkt für NEC-Sonderzeichen verwendet.

    • Wenn das Zeichen sowohl in den IBM-Auswahlzeichen als auch in den NEC-Auswahl-/IBM-Erweiterungszeichen enthalten ist, wird der Codepunkt für IBM-Erweiterungszeichen verwendet.

    Die unter http://www.microsoft.com/globaldev/reference/dbcs/932.htm gezeigte Tabelle enthält Informationen zu den Unicode-Werten der cp932-Zeichen. Bei cp932-Tabelleneinträgen mit Zeichen, unter denen eine vierstellige Zahl erscheint, stellt diese die entsprechende Unicode-Kodierung (ucs2) dar. Bei Tabelleneinträgen mit einem unterstrichenen zweistelligen Wert gibt es einen Bereich mit cp932-Zeichenwerten, die bei diesen beiden Stellen beginnen. Wenn Sie auf einen solchen Tabelleneintrag klicken, gelangen Sie auf eine Seite, auf der der Unicode-Wert für jedes cp932-Zeichen angezeigt wird, das mit diesen Stellen beginnt.

    Die folgenden Links verdienen Ihr besonderes Interesse. Sie entsprechen den Kodierungen der folgenden Zeichenbestände:

  • cp932 unterstützt die Konvertierung benutzerdefinierter Zeichen in Kombination mit eucjpms und beseitigt die Probleme bei der sjis-/ujis-Konvertierung. Weitere Informationen erhalten Sie unter http://www.opengroup.or.jp/jvc/cde/sjis-euc-e.html.

  • Bei einigen Zeichen ist die Konvertierung von und nach ucs2 bei sjis und cp932 unterschiedlich. Die folgenden Tabellen veranschaulichen diese Unterschiede.

    Konvertierung nach ucs2:

    sjis-/cp932-WertKonvertierung sjis nach ucs2Konvertierung cp932 nach ucs2
    5C005C005C
    7E007E007E
    815C20152015
    815F005CFF3C
    8160301CFF5E
    816120162225
    817C2212FF0D
    819100A2FFE0
    819200A3FFE1
    81CA00ACFFE2

    Konvertierung von ucs2:

    ucs2-WertKonvertierung ucs2 nach sjisKonvertierung ucs2 nach cp932
    005C815F5C
    007E7E7E
    00A281913F
    00A381923F
    00AC81CA3F
    2015815C815C
    201681613F
    2212817C3F
    22253F8161
    301C81603F
    FF0D3F817C
    FF3C3F815F
    FF5E3F8160
    FFE03F8191
    FFE13F8192
    FFE23F81CA

Kapitel 11. Datentypen

MySQL unterstützt eine Vielzahl von Datentypen verschiedener Kategorien: numerische Typen, Typen für Datum und Uhrzeit und auch String-Typen (zeichenbasierte Typen). In diesem Kapitel erhalten Sie zunächst eine Übersicht über diese Datentypen. Nachfolgend finden Sie eine detaillierte Beschreibung der Eigenschaften von Typen der jeweiligen Kategorien und eine Zusammenfassung der Speicheranforderungen dieser Datentypen. Die einführende Übersicht ist bewusst kurz gehalten. Detailinformationen zu bestimmten Datentypen – z. B. zu den zur Werteangabe zulässigen Formaten – entnehmen Sie am besten den ausführlicheren Beschreibungen im Verlauf des Kapitels.

MySQL unterstützt auch Erweiterungen zur Verarbeitung raumbezogener Daten. Kapitel 18, Raumbezogene Erweiterungen in MySQL, enthält Informationen zu diesen Datentypen.

Die folgenden Konventionen gelten für eine Reihe der nachfolgenden Datentypbeschreibungen:

  • M gibt die maximale Anzeigebreite für Integer-Typen an. Bei Fließkomma- und Festkommatypen beschreibt M die maximale Anzahl der Stellen. Bei String-Typen schließlich ist M die maximale Länge. Der maximal zulässige Wert für M hängt vom jeweiligen Datentyp ab.

  • D gibt bei Fließkomma- und Festkommatypen die Anzahl der Stellen nach dem Dezimalpunkt an. Der maximale Wert ist 30. Allerdings sollte er nie größer gewählt werden als M – 2.

  • Eckige Klammern (‘[’ und ‘]’) zeigen optionale Bestandteile der Typendefinition an.

11.1. Überblick über Datentypen

11.1.1. Überblick über numerische Datentypen

Es folgt eine Übersicht zu den numerischen Datentypen. Weitere Informationen finden Sie unter Abschnitt 11.2, „Numerische Datentypen“. Die Speicheranforderungen für die Typen sind in Abschnitt 11.5, „Speicherbedarf von Spaltentypen“, beschrieben.

M zeigt die maximale Anzeigebreite an. Der höchste zulässige Wert ist 255. Die Anzeigebreite hat keinen Bezug zur Speichergröße oder zum zulässigen Wertebereich des betreffenden Typs (siehe auch Abschnitt 11.2, „Numerische Datentypen“).

Wenn Sie ZEROFILL für eine numerische Spalte angeben, fügt MySQL automatisch das Attribut UNSIGNED für die Spalte hinzu.

SERIAL ist ein Alias für BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.

SERIAL DEFAULT VALUE ist in der Definition einer Integer-Spalte ein Alias für NOT NULL AUTO_INCREMENT UNIQUE.

Warnung: Wenn Sie die Subtraktion für Integer-Werte verwenden, von denen einer vom Typ UNSIGNED ist, dann hat das Ergebnis kein Vorzeichen. Siehe auch Abschnitt 12.8, „Cast-Funktionen und Operatoren“.

  • BIT[(M)]

    Bitfeldtyp. M gibt die Anzahl von Bits pro Wert in einem Bereich zwischen 1 und 64 an. Wenn M weggelassen wird, wird standardmäßig 1 verwendet.

  • TINYINT[(M)] [UNSIGNED] [ZEROFILL]

    Sehr kleiner Integer. Der vorzeichenbehaftete Bereich liegt zwischen -128 und 127. Der vorzeichenlose Bereich liegt zwischen 0 und 255.

  • BOOL, BOOLEAN

    Diese Typen sind Synonyme für TINYINT(1). Der Wert Null wird als falsch ausgewertet, Werte ungleich null als wahr.

    Die Implementierung der vollständigen Verarbeitung boolescher Typen entsprechend dem SQL-Standard ist für die Zukunft vorgesehen.

  • SMALLINT[(M)] [UNSIGNED] [ZEROFILL]

    Kleiner Integer. Der vorzeichenbehaftete Bereich liegt zwischen -32768 und 32767. Der vorzeichenlose Bereich liegt zwischen 0 und 65535.

  • MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]

    Mittelgroßer Integer. Der vorzeichenbehaftete Bereich liegt zwischen -8388608 und 8388607. Der vorzeichenlose Bereich liegt zwischen 0 und 16777215.

  • INT[(M)] [UNSIGNED] [ZEROFILL]

    Integer normaler Größe. Der vorzeichenbehaftete Bereich liegt zwischen -2147483648 und 2147483647. Der vorzeichenlose Bereich liegt zwischen 0 und 4294967295.

  • INTEGER[(M)] [UNSIGNED] [ZEROFILL]

    Dieser Typ ist synonym zu INT.

  • BIGINT[(M)] [UNSIGNED] [ZEROFILL]

    Großer Integer. Der vorzeichenbehaftete Bereich liegt zwischen -9223372036854775808 und 9223372036854775807. Der vorzeichenlose Bereich liegt zwischen 0 und 18446744073709551615.

    Bestimmte Aspekte sollten Sie in Bezug auf BIGINT-Spalten beachten:

    • Alle Berechnungen werden unter Verwendung vorzeichenbehafteter BIGINT- oder DOUBLE-Werte durchgeführt. Aus diesem Grund sollten Sie – mit Ausnahme von Bitfunktionen – keine vorzeichenlosen großen Integer-Zahlen benutzen, die größer sind als 9223372036854775807 (63 Bits)! Andernfalls können, wenn Sie einen BIGINT- in einen DOUBLE-Wert konvertieren, die letzten Stellen des Ergebnisses aufgrund von Rundungsfehlern unter Umständen falsch sein.

      MySQL kann BIGINT in den folgenden Fällen verarbeiten:

      • Bei der Verwendung von Integer-Zahlen zur Speicherung großer vorzeichenloser Werte in einer BIGINT-Spalte.

      • In MIN(col_name) oder MAX(col_name), wobei col_name eine BIGINT-Spalte referenziert.

      • Bei der Verwendung von Operatoren (+, -, * usw.), wenn beide Operanden Integers sind.

    • Sie können einen exakten Integer-Wert jederzeit in einer BIGINT-Spalte speichern, indem Sie zur Speicherung einen String verwenden. In diesem Fall führt MySQL eine Konvertierung des Strings in eine Zahl durch, wobei keine zwischenzeitliche Darstellung mit doppelter Genauigkeit erfolgt.

    • Die Operatoren -, + und * verwenden die BIGINT-Arithmetik, wenn beide Operanden Integers sind. Das bedeutet, dass Sie, wenn Sie zwei große Integers (oder Ergebnisse von Funktionen, die Integers zurückgeben) miteinander multiplizieren, unerwartete Ergebnisse erhalten können, wenn das Ergebnis größer als 9223372036854775807 ist.

  • FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]

    Kleine Fließkommazahl (mit einfacher Genauigkeit). Zulässige Werte sind der Bereich zwischen -3.402823466E+38 und -1.175494351E-38, 0 und der Bereich zwischen 1.175494351E-38 und 3.402823466E+38. Dies sind theoretische Werte, die auf dem IEEE-Standard basieren. Der tatsächliche Wertebereich kann abhängig von Ihrer Hardware oder Ihrem Betriebssystem ein wenig kleiner sein.

    M ist die Gesamtzahl von Dezimalstellen, D die Anzahl der Stellen hinter dem Dezimalpunkt. Wenn M und D nicht angegeben werden, werden die Werte im Rahmen dessen gespeichert, was hardwareseitig unterstützt wird. Eine Fließkommazahl mit einfacher Genauigkeit ist auf etwa sieben Dezimalstellen genau.

    Sofern angegeben, verbietet UNSIGNED negative Werte.

    Durch die Verwendung von FLOAT können sich unerwartete Probleme ergeben, weil alle Berechnungen in MySQL mit doppelter Genauigkeit erfolgen. Siehe auch Abschnitt A.5.7, „Lösung von Problemen mit nicht übereinstimmenden Zeilen“.

  • DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]

    Fließkommazahl normaler Größe (mit doppelter Genauigkeit). Zulässige Werte sind der Bereich zwischen -1.7976931348623157E+308 und -2.2250738585072014E-308, 0 und der Bereich zwischen 2.2250738585072014E-308 und 1.7976931348623157E+308. Dies sind theoretische Werte, die auf dem IEEE-Standard basieren. Der tatsächliche Wertebereich kann abhängig von Ihrer Hardware oder Ihrem Betriebssystem ein wenig kleiner sein.

    M ist die Gesamtzahl von Dezimalstellen, D die Anzahl der Stellen hinter dem Dezimalpunkt. Wenn M und D nicht angegeben werden, werden die Werte im Rahmen dessen gespeichert, was hardwareseitig unterstützt wird. Eine Fließkommazahl mit doppelter Genauigkeit ist auf etwa 15 Dezimalstellen genau.

    Sofern angegeben, verbietet UNSIGNED negative Werte.

  • DOUBLE PRECISION[(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL]

    Diese Typen sind Synonyme für DOUBLE. Ausnahme: Wenn der SQL-Modus REAL_AS_FLOAT aktiviert ist, ist REAL ein Synonym für FLOAT statt für DOUBLE.

  • FLOAT(p) [UNSIGNED] [ZEROFILL]

    Fließkommazahl. p steht für die Genauigkeit in Bit, aber MySQL verwendet diesen Wert nur zur Bestimmung, ob als Datentyp für das Ergebnis FLOAT oder DOUBLE zugewiesen werden soll. Liegt p zwischen 0 und 24, dann wird FLOAT (ohne M- und D-Werte) als Typ gewählt. Liegt p zwischen 25 und 53, dann wird DOUBLE (ohne M- und D-Werte) als Typ gewählt. Der Bereich der Ergebnisspalte entspricht den Datentypen FLOAT mit einfacher Genauigkeit oder DOUBLE mit doppelter Genauigkeit entsprechend obiger Beschreibung.

    Die Syntax FLOAT(p) wird aus Gründen der ODBC-Kompatibilität unterstützt.

  • DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]

    Gepackte „exakte“ Festkommazahl. M ist die Gesamtzahl von Dezimalstellen (Genauigkeit), D die Anzahl der Stellen hinter dem Dezimalpunkt. Der Dezimalpunkt sowie das Zeichen ‘-’ (für negative Zahlen) werden bei der Zählung für M nicht berücksichtigt. Wenn D 0 ist, haben die Werte keinen Dezimalpunkt und keine Nachkommastellen. Die maximale Anzahl der Stellen (M) beträgt bei DECIMAL 65, die maximale Anzahl unterstützter Dezimalstellen (D) 30. Wird D weggelassen, dann wird als Vorgabe 0 verwendet; fehlt die Angabe M, dann ist 10 der Standardwert.

    Sofern angegeben, verbietet UNSIGNED negative Werte.

    Berechnungen in den Grundrechenarten (+, -, *, /) erfolgen bei DECIMAL-Spalten stets mit einer Genauigkeit von 65 Stellen.

  • DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]

    Diese Typen sind Synonyme für DECIMAL. Das Synonym FIXED steht aus Gründen der Kompatibilität mit anderen Datenbanksystemen zur Verfügung.

11.1.2. Überblick über Datums- und Zeittypen

Es folgt eine Übersicht über die zeitbezogenen Datentypen. Weitere Informationen finden Sie unter Abschnitt 11.3, „Datums- und Zeittypen“. Die Speicheranforderungen für die Typen sind in Abschnitt 11.5, „Speicherbedarf von Spaltentypen“, beschrieben.

Die Zusammenfassungsfunktionen SUM() und AVG() funktionieren bei Zeitwerten nicht. (Sie konvertieren die Werte in Zahlen, wodurch alles, was nach dem ersten nichtnumerischen Zeichen auftaucht, verloren geht.) Um dieses Problem zu umgehen, können Sie die Werte in numerische Einheiten konvertieren, dann die Zusammenfassungsfunktion ausführen und abschließend eine Rückkonvertierung in den Zeitwert durchführen. Ein paar Beispiele:

SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col))) FROM tbl_name;
SELECT FROM_DAYS(SUM(TO_DAYS(date_col))) FROM tbl_name;
  • DATE

    Datum. Der unterstützte Bereich liegt zwischen '1000-01-01' und '9999-12-31'. MySQL zeigt DATE-Werte im Format 'YYYY-MM-DD' an, gestattet Ihnen aber, wahlweise Strings oder Zahlen in DATE-Spalten einzugeben.

  • DATETIME

    Kombination aus Datum und Uhrzeit. Der unterstützte Bereich liegt zwischen '1000-01-01 00:00:00' und '9999-12-31 23:59:59'. MySQL zeigt DATETIME-Werte im Format 'YYYY-MM-DD HH:MM:SS' an, gestattet Ihnen aber, wahlweise Strings oder Zahlen in DATETIME-Spalten einzugeben.

  • TIMESTAMP[(M)]

    Zeitstempel. Der Bereich liegt zwischen '1970-01-01 00:00:00' und einem Zeitpunkt irgendwann im Jahr 2037.

    Eine TIMESTAMP-Spalte ist nützlich, um Datum und Uhrzeit einer INSERT- oder UPDATE-Operation aufzunehmen. Standardmäßig wird die erste TIMESTAMP-Spalte in einer Tabelle automatisch auf das Datum und die Uhrzeit der zuletzt durchgeführten Operation gesetzt, sofern Sie nicht selbst einen Wert angeben. Sie können TIMESTAMP-Spalten auch auf die aktuellen Werte für Datum und Uhrzeit setzen, indem Sie einen NULL-Wert zuweisen. Varianten der automatischen Initialisierung und Eigenschaften von Änderungen sind in Abschnitt 11.3.1.1, „TIMESTAMP-Eigenschaften ab MySQL 4.1“, beschrieben.

    Ein TIMESTAMP-Wert wird als String im Format 'YYYY-MM-DD HH:MM:SS' zurückgegeben, dessen Anzeigebreite auf 19 Zeichen festgelegt ist. Um den Wert als Zahl zu erhalten, sollten Sie +0 zur Zeitstempelspalte hinzufügen.

    Hinweis: Das vor MySQL 4.1 verwendete TIMESTAMP-Format wird von MySQL 5.1 nicht unterstützt. Informationen zum veralteten Format finden Sie im MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1.

  • TIME

    Eine Zeitangabe. Der Bereich liegt zwischen '-838:59:59' und '838:59:59'. MySQL zeigt TIME-Werte im Format 'HH:MM:SS' an, gestattet Ihnen aber, wahlweise Strings oder Zahlen in TIME-Spalten einzugeben.

  • YEAR[(2|4)]

    Ein Jahr im zwei- oder vierstelligen Format. Das vierstellige Format ist standardmäßig voreingestellt. In diesem Format sind zulässige Werte der Bereich zwischen 1901 und 2155 sowie 0000. Im zweistelligen Format ist der Bereich 70 bis 69 zulässig; er bezeichnet die Jahre 1970 bis 2069. MySQL zeigt YEAR-Werte im Format YYYY an, gestattet Ihnen aber, wahlweise Strings oder Zahlen in YEAR-Spalten einzugeben.

11.1.3. Überblick über String-Typen

Es folgt eine Übersicht über die String-Datentypen. Weitere Informationen finden Sie unter Abschnitt 11.4, „String-Typen“. Die Speicheranforderungen für die Typen sind in Abschnitt 11.5, „Speicherbedarf von Spaltentypen“, beschrieben.

Seit MySQL 4.1 weisen die String-Typen eine Reihe von Funktionen auf, die Sie, wenn Sie bislang nur mit älteren MySQL-Versionen (vor 4.1) gearbeitet haben, unter Umständen nicht kennen:

  • Spaltendefinitionen für viele String-Datentypen können ein Attribut CHARACTER SET enthalten, mit dem der Zeichensatz angegeben wird. (CHARSET ist ein Synonym für CHARACTER SET.) Das Attribut COLLATE gibt die Sortierung für den Zeichensatz an. Diese Attribute gelten für CHAR, VARCHAR, die TEXT-Typen, ENUM und SET. Zum Beispiel:

    CREATE TABLE t
    (
        c1 VARCHAR(20) CHARACTER SET utf8,
        c2 TEXT CHARACTER SET latin1 COLLATE latin1_general_cs
    );
    

    Diese Tabellendefinition erstellt zwei Spalten namens c1 und c2. Für die erste Spalte sind der Zeichensatz utf8 und die Standardsortierung für diesen Zeichensatz festgelegt, für die zweite latin1 und eine Sortierung mit Unterscheidung der Groß-/Kleinschreibung.

  • MySQL 5.1 interpretiert Längenangaben in Zeichenspaltendefinitionen als Anzahl von Zeichen. (Früher wurde als Grundlage die Einheit Byte verwendet.)

  • Bei CHAR, VARCHAR und den TEXT-Typen wird, wenn das Attribut BINARY angegeben ist, der Spalte die binäre Sortierung des spaltenspezifischen Zeichensatzes zugewiesen. (In älteren Versionen konnte eine Spalte bei Angabe von BINARY binäre Strings speichern.)

  • Sortierung und Vergleiche basieren bei Zeichenspalten auf dem Zeichensatz, der der Spalte zugewiesen ist. (Früher basierten Sortierung und Vergleich auf der Sortierung des Serverzeichensatzes.) Bei CHAR-und VARCHAR-Spalten können Sie eine binäre Sortierung oder aber das Attribut BINARY angeben, damit für Sortierung und Vergleiche statt der lexikalen Reihenfolge die zugrunde liegenden Zeichencodewerte benutzt werden.

Kapitel 10, Zeichensatz-Unterstützung, enthält weitere Informationen zur Verwendung von Zeichensätzen in MySQL.

  • [NATIONAL] CHAR(M) [BINARY | ASCII | UNICODE]

    Ein String fester Länge, der bei der Speicherung mit Leerzeichen auf die angegebene Länge aufgefüllt wird. M steht für die Spaltenlänge. M liegt in einem Bereich zwischen 0 und 255 Zeichen.

    Hinweis: Am Ende stehende Leerzeichen werden beim Abrufen von CHAR-Werten entfernt.

    Wenn Sie versuchen, die Länge einer CHAR-Spalte auf einen Wert größer 255 zu setzen, dann schlägt die CREATE TABLE- oder ALTER TABLE-Anweisung, mit der Sie dies tun, fehl und gibt eine Fehlermeldung aus:

    mysql> CREATE TABLE c1 (col1 INT, col2 CHAR(500));
    ERROR 1074 (42000): Column length too big for column 'col' (max = 255);
    use BLOB or TEXT instead
    mysql> SHOW CREATE TABLE c1;
    ERROR 1146 (42S02): Table 'test.c1' doesn't exist
    

    CHAR ist eine Abkürzung für CHARACTER. NATIONAL CHAR (und die äquivalente Kurzform NCHAR) ist bei SQL die Standardmethode, um festzulegen, dass eine CHAR-Spalte einen bestimmten vordefinierten Zeichensatz verwendet. Seit Version 4.1 ist utf8 bei MySQL dieser vordefinierte Zeichensatz. Siehe Abschnitt 10.3.6, „Nationaler Zeichensatz“.

    Das Attribut BINARY ist eine Kurzform zur Festlegung der binären Sortierung des Spaltenzeichensatzes. In diesem Fall basieren Sortierung und Vergleich auf numerischen Zeichenwerten.

    Das Attribut ASCII ist eine Abkürzung für CHARACTER SET latin1.

    Das Attribut UNICODE ist eine Abkürzung für CHARACTER SET ucs2.

    Der Datentyp CHAR BYTE ist ein Alias für den Typ BINARY. Grund hierfür sind Kompatibilitätsaspekte.

    MySQL gestattet Ihnen die Erstellung einer Spalte des Typs CHAR(0). Dies ist in erster Linie praktisch, wenn eine Kompatibilität mit alten Anwendungen erforderlich ist, die auf das Vorhandensein einer Spalte angewiesen sind, aber deren Wert überhaupt nicht nutzen. CHAR(0) ist ferner recht praktisch, wenn Sie eine Spalte benötigen, die nur zwei Werte annehmen kann: Eine CHAR(0)-Spalte, die nicht als NOT NULL definiert ist, besetzt genau ein Bit und kann nur die Werte NULL und '' (Leer-String) aufnehmen.

  • CHAR

    Dieser Typ ist synonym zu CHAR(1).

  • [NATIONAL] VARCHAR(M) [BINARY]

    Ein String variabler Länge. M gibt die maximale Spaltenlänge an. Für M liegt der zulässige Bereich zwischen 0 und 65.535. (Die tatsächliche Maximallänge einer VARCHAR-Spalte wird durch die maximale Datensatzlänge und den von Ihnen verwendeten Zeichensatz bestimmt. Die effektive Maximallänge beträgt 65.532 Byte.)

    Hinweis: MySQL 5.1 beachtet die Spezifikation des SQL-Standards und entfernt am Anfang stehende Leerzeichen aus VARCHAR-Werten nicht.

    VARCHAR ist eine Abkürzung für CHARACTER VARYING.

    Das Attribut BINARY ist eine Kurzform zur Festlegung der binären Sortierung des Spaltenzeichensatzes. In diesem Fall basieren Sortierung und Vergleich auf numerischen Zeichenwerten.

    VARCHAR wird mit einem Präfix von 1 oder 2 Byte Länge und den Daten gespeichert. 2 Byte beträgt die Länge des Präfixes, wenn die VARCHAR-Spalte mit einer Länge größer 255 deklariert wurde.

  • BINARY(M)

    Der Typ BINARY ähnelt CHAR, speichert aber Strings aus binären Bytes statt nichtbinärer Zeichen-Strings.

  • VARBINARY(M)

    Der Typ VARBINARY ähnelt VARCHAR, speichert aber Strings aus binären Bytes statt nichtbinärer Zeichen-Strings.

  • TINYBLOB

    Eine BLOB-Spalte mit einer Maximallänge von 255 (28 – 1) Byte.

  • TINYTEXT

    Eine TEXT-Spalte mit einer Maximallänge von 255 (28 – 1) Zeichen.

  • BLOB[(M)]

    Eine BLOB-Spalte mit einer Maximallänge von 65.535 (216 – 1) Byte.

    Für diesen Typ kann optional die Länge M angegeben werden. In diesem Fall erstellt MySQL die Spalte mit dem kleinsten BLOB-Typ, der groß genug zur Aufnahme von Werten mit einer Länge von M Bytes ist.

  • TEXT[(M)]

    Eine TEXT-Spalte mit einer Maximallänge von 65.535 (216 – 1) Zeichen.

    Für diesen Typ kann optional die Länge M angegeben werden. In diesem Fall erstellt MySQL die Spalte mit dem kleinsten TEXT-Typ, der groß genug zur Aufnahme von Werten mit einer Länge von M Zeichen ist.

  • MEDIUMBLOB

    Eine BLOB-Spalte mit einer Maximallänge von 16.777.215 (224 – 1) Byte.

  • MEDIUMTEXT

    Eine TEXT-Spalte mit einer Maximallänge von 16.777.215 (224 – 1) Zeichen.

  • LONGBLOB

    Eine BLOB-Spalte mit einer Maximallänge von 4.294.967.295 (232 – 1) Byte (4 Gbyte). Die maximale effektive (d. h. zulässige) Länge von LONGBLOB-Spalten hängt von der maximalen Paketgröße im Client/Server-Protokoll und dem verfügbaren Speicher ab.

  • LONGTEXT

    Eine TEXT-Spalte mit einer Maximallänge von 4.294.967.295 (232 – 1) Zeichen. Die maximale effektive (d. h. zulässige) Länge von LONGTEXT-Spalten hängt von der maximalen Paketgröße im Client/Server-Protokoll und dem verfügbaren Speicher ab.

  • ENUM('value1','value2',...)

    Eine Auflistung. Es handelt sich dabei um ein String-Objekt, das aus der Liste der Werte 'value1', 'value2', ..., NULL und einem speziellen Fehlerwert '' genau einen Wert auswählt. Eine ENUM-Spalte kann maximal 65.535 verschiedene Werte aufweisen. ENUM-Werte werden intern als Integers dargestellt.

  • SET('value1','value2',...)

    Eine Menge. Es handelt sich um ein String-Objekt, dass null oder mehr Werte haben kann, die jeweils aus der Werteliste 'value1', 'value2', ... stammen. Eine SET-Spalte kann maximal 64 Mitglieder haben. SET-Werte werden intern als Integers dargestellt.

11.1.4. Vorgabewerte von Datentypen

Die Klausel DEFAULT value in der Spezifikation eines Datentyps gibt einen Vorgabewert für eine Spalte an. Mit einer Ausnahme muss der Vorgabewert immer eine Konstante sein. Funktionen oder Ausdrücke sind als Vorgaben nicht zulässig. Das bedeutet, dass Sie beispielsweise als Vorgabewert einer Datumsspalte nicht den Wert einer Funktion wie NOW() oder CURRENT_DATE angeben dürfen. Die genannte Ausnahme besteht darin, dass Sie CURRENT_TIMESTAMP als Vorgabe für eine TIMESTAMP-Spalte festlegen können. Siehe auch Abschnitt 11.3.1.1, „TIMESTAMP-Eigenschaften ab MySQL 4.1“.

Für BLOB- und TEXT-Spalten können keine Vorgaben festgelegt werden.

Wenn eine Spaltendefinition keinen expliziten DEFAULT-Wert enthält, bestimmt MySQL diesen wie folgt:

Wenn die Spalte NULL als Wert annehmen kann, wird sie mit einer expliziten DEFAULT NULL-Klausel definiert.

Kann die Spalte NULL nicht als Wert annehmen, dann definiert MySQL die Spalte ohne explizite DEFAULT-Klausel. Wenn bei der Dateneingabe eine INSERT- oder REPLACE-Anweisung keinen Wert für die Spalte enthält, verarbeitet MySQL sie entsprechend dem zum betreffenden Zeitpunkt gültigen SQL-Modus:

  • Wenn der strikte SQL-Modus nicht aktiviert ist, setzt MySQL die Spalte auf den impliziten Standardwert für den Datentyp der Spalte.

  • Ist der strikte Modus hingegen aktiv, dann erscheint bei transaktionssicheren Tabellen ein Fehler, und für die Anweisung wird ein Rollback durchgeführt. Bei nichttransaktionssicheren Tabellen erscheint ebenfalls ein Fehler; allerdings bleiben, wenn dies erst beim zweiten oder einem nachfolgenden Datensatz geschieht, zuvor eingefügte Datensätze erhalten.

Nehmen wir einmal an, eine Tabelle t sei wie folgt definiert:

CREATE TABLE t (i INT NOT NULL);

In diesem Fall hat i keinen expliziten Vorgabewert, d. h., im strikten Modus würde jede der folgenden Anweisungen einen Fehler erzeugen, und es würde kein Datensatz eingefügt. Wird der strikte Modus nicht verwendet, dann erzeugt nur die dritte Anweisung einen Fehler; bei den ersten beiden Anweisungen wird die implizite Vorgabe eingefügt, die dritte Anweisung schlägt hingegen fehl, weil DEFAULT(i) keinen Wert erzeugen kann:

INSERT INTO t VALUES();
INSERT INTO t VALUES(DEFAULT);
INSERT INTO t VALUES(DEFAULT(i));

Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Sie können für eine gegebene Tabelle die Anweisung SHOW CREATE TABLE verwenden, um anzuzeigen, welche Spalten eine explizite DEFAULT-Klausel aufweisen.

11.2. Numerische Datentypen

MySQL unterstützt alle im SQL-Standard vorgesehen numerischen Datentypen. Hierzu gehören exakte numerische Datentypen (INTEGER, SMALLINT, DECIMAL und NUMERIC) ebenso wie annähernde Typen (FLOAT, REAL und DOUBLE PRECISION). Das Schlüsselwort INT ist ein Synonym für DECIMAL, und das Schlüsselwort INTEGER ist ein Synonym für DEC. Informationen zu den Speicheranforderungen numerischer Typen finden Sie in Abschnitt 11.5, „Speicherbedarf von Spaltentypen“.

Der Datentyp BIT speichert Bitfeldwerte und wird für MyISAM-, MEMORY-, InnoDB- und BDB-Tabellen unterstützt.

In Erweiterung des SQL-Standards unterstützt MySQL auch die Integer-Typen TINYINT, MEDIUMINT und BIGINT. Die folgende Tabelle zeigt den erforderlichen Speicherplatz und den zulässigen Wertebereich der Integer-Typen.

TypBytesMinimumMaximum
  (vorzeichenbehaftet/vorzeichenlos)(vorzeichenbehaftet/vorzeichenlos)
TINYINT1-128127
  0255
SMALLINT2-3276832767
  065535
MEDIUMINT3-83886088388607
  016777215
INT4-21474836482147483647
  04294967295
BIGINT8-92233720368547758089223372036854775807
  018446744073709551615

Eine andere Erweiterung wird von MySQL zur optionalen Spezifizierung der Anzeigebreite eines Integer-Werts unterstützt. Die Angabe erfolgt auf das Schlüsselwort für den Datentyp folgend in Klammern (z. B. INT(4)). Diese optionale Angabe der Anzeigebreite wird verwendet, um die Anzeige von Werten, die eine geringere als die für die Spalte festgelegte Breite aufweisen, nach links mit Leerzeichen aufzufüllen.

Die Anzeigebreite schränkt weder die in einer Spalte speicherbaren Wertebereiche noch die Anzahl der Stellen ein, die für Werte angezeigt werden, deren Breite die festgelegte Spaltenbreite überschreitet.

Wenn hierzu das optionale Erweiterungsattribut ZEROFILL verwendet wird, erfolgt ein Auffüllen nicht mehr mit Leerzeichen, sondern mit Nullen. Bei einer Spalte etwa, die als INT(5) ZEROFILL deklariert ist, wird der Wert 4 als 00004 abgerufen. Beachten Sie, dass, wenn Sie Werte in einer Integer-Spalte speichern, die größer sind als die Anzeigebreite, unter Umständen Probleme auftauchen, wenn MySQL Temporärtabellen für einige komplizierte Joins anlegt, denn in diesen Fällen setzt MySQL voraus, dass die Daten in die ursprüngliche Spaltenbreite passen.

Für alle Integer-Typen gibt es das (nicht standardkonforme) Attribut UNSIGNED. Vorzeichenlose Werte können verwendet werden, wenn in einer Spalte nur nichtnegative Zahlen zulässig sind und Sie für die Spalte einen nach oben erweiterten numerischen Wertebereich benötigen. Wenn beispielsweise eine INT-Spalte als UNSIGNED deklariert wird, ist die Spaltengröße gleich; zulässige Werte entstammen nun aber nicht mehr dem Bereich zwischen -2147483648 und 2147483647, sondern dem Bereich zwischen 0 und 4294967295.

Auch Fließkommazahlen und Festkommazahlen können vorzeichenlos sein. Wie bei Integer-Typen verhindert dieses Attribut die Speicherung negativer Werte in der Spalte. Anders als bei jenen aber bleibt das Maximum für die Spaltenwerte unverändert.

Wenn Sie ZEROFILL für eine numerische Spalte angeben, fügt MySQL automatisch das Attribut UNSIGNED für die Spalte hinzu.

Bei Fließkommadatentypen verwendet MySQL 4 Byte für Werte einfacher und 8 Byte für Werte doppelter Genauigkeit.

Die Datentypen FLOAT und DOUBLE werden zur Darstellung annähernder numerischer Datenwerte verwendet. Für FLOAT gestattet der SQL-Standard optional die Angabe der Genauigkeit (nicht aber des Bereichs des Exponenten) in Bits, die dem Schlüsselwort FLOAT in Klammern folgen. Auch MySQL unterstützt diese optionale Genauigkeitsangabe, der Genauigkeitswert wird allerdings nur zur Bestimmung der Speichergröße verwendet. Eine Genauigkeit von 0 bis 23 hat eine vier Byte lange FLOAT-Spalte mit einfacher Genauigkeit zum Ergebnis. Bei einer Genauigkeit von 24 bis 53 entsteht eine acht Byte lange DOUBLE-Spalte mit doppelter Genauigkeit.

MySQL gestattet eine nicht standardkonforme Syntax: FLOAT(M,D) oder REAL(M,D) oder DOUBLE PRECISION(M,D). Hierbei bedeutet „(M,D)“, dass Werte mit bis zu M Stellen insgesamt angezeigt werden, wovon D Nachkommastellen sind. Beispielsweise erscheint eine Spalte, die als FLOAT(7,4) definiert wurde, in der Anzeige als -999.9999. MySQL führt die Rundung beim Speichern der Werte durch, d. h. wenn Sie 999.00009 in einer FLOAT(7,4)-Spalte einfügen, ist das Ergebnis näherungsweise 999.0001.

MySQL behandelt DOUBLE als Synonym für DOUBLE PRECISION (dies ist eine nicht standardkonforme Erweiterung). Ferner behandelt MySQL REAL als Synonym für DOUBLE PRECISION (nicht standardkonforme Variante), sofern der SQL-Modus REAL_AS_FLOAT nicht aktiviert ist.

Wenn Sie maximale Portabilität benötigen, sollten Sie in Code, in dem die Speicherung annähernder numerischer Datenwerte erforderlich ist, FLOAT oder DOUBLE PRECISION ohne Angabe der Genauigkeit oder der Stellen verwenden.

Die Datentypen DECIMAL und NUMERIC werden zur Speicherung exakter numerischer Datenwerte verwendet. In MySQL ist NUMERIC als DECIMAL implementiert. Diese Typen werden zur Speicherung von Werten benutzt, bei denen die Beibehaltung der exakten Genauigkeit entscheidend ist (z. B. bei Finanzberechnungen).

MySQL 5.1 speichert DECIMAL- und NUMERIC-Werte im binären Format. In älteren Versionen erfolgte die Speicherung als Strings. Siehe auch Kapitel 23, Präzisionsberechnungen.

Wenn Sie eine DECIMAL- oder NUMERIC-Spalte deklarieren, können (und sollten) Genauigkeit und Anzahl der Nachkommastellen angegeben werden. Zum Beispiel:

salary DECIMAL(5,2)

In diesem Beispiel ist 5 die Genauigkeit und 2 die Anzahl der Nachkommastellen. Die Genauigkeit stellt die Anzahl der signifikanten Stellen dar, die für Werte gespeichert werden. Ist für die Nachkommastellen 0 festgelegt, dann haben DECIMAL- und NUMERIC-Werte keinen Dezimalpunkt und keine Nachkommastellen.

Der SQL-Standard erfordert, dass die Spalte salary jeden Wert mit fünf Stellen und zwei Nachkommastellen speichern können muss. Dies bedeutet also, dass der in der Spalte salary speicherbare Wertebereich zwischen -999.99 und 999.99 liegt.

Beim SQL-Standard ist die Syntax DECIMAL(M) gleichbedeutend mit DECIMAL(M,0). Ähnlich hat die Syntax DECIMAL die gleiche Bedeutung wie DECIMAL(M,0), wobei der Implementierung die Entscheidung zum Wert von M überlassen bleibt. MySQL unterstützt diese beiden Varianten der DECIMAL- und NUMERIC-Syntax. Der Vorgabewert von M ist 10.

Die maximale Anzahl von Stellen für DECIMAL oder NUMERIC beträgt 65, der tatsächliche Bereich für eine gegebene DECIMAL- oder NUMERIC-Spalte kann jedoch durch die Angaben für Genauigkeit oder Nachkommastellen eingeschränkt werden. Wenn einer solchen Spalte ein Wert mit mehr Nachkommastellen als zulässig zugewiesen wird, dann wird der Wert der zulässigen Anzahl Nachkommastellen angepasst. (Das exakte Verhalten ist betriebssystemspezifisch, aber in der Regel werden überzählige Nachkommastellen einfach abgeschnitten.)

Der Datentyp BIT wird zur Speicherung von Bitfeldwerten verwendet. Der Typ BIT(M) gestattet die Speicherung von M-Bit-Werten. Dabei kann M in einem Bereich zwischen 1 und 64 liegen.

Zur Angabe von Bitwerten kann die Notation b'value' verwendet werden. value ist ein Binärwert, der aus Einsen und Nullen besteht. So stehen etwa b'111' und b'100000000' für die Zahlen 7 bzw. 128. Siehe auch Abschnitt 9.1.5, „Bitfeldwerte“.

Wenn Sie einer BIT(M)-Spalte einen Wert zuweisen, der weniger als M Bits lang ist, dann wird der Wert nach links mit Nullen aufgefüllt. So entspricht die Zuweisung des Werts b'101' an eine Spalte BIT(6) im Endeffekt der Zuweisung von b'000101'.

Wenn MySQL einen Wert in einer numerischen Spalte speichern soll, der außerhalb des für den Datentyp zulässigen Bereichs liegt, dann hängt das Verhalten von MySQL von dem zum betreffenden Zeitpunkt aktiven SQL-Modus ab. Wenn etwa keine restriktiven Modi aktiviert sind, setzt MySQL den Wert auf den jeweiligen Endwert des Bereichs und speichert dann diesen Wert. Wenn als Modus jedoch TRADITIONAL aktiviert ist, weist MySQL einen Wert außerhalb des Bereichs mit einer Fehlermeldung ab. In diesem Fall schlägt die Einfügeoperation fehl – ganz so, wie es der SQL-Standard vorsieht.

Wird im nichtstrikten Modus einer Integer-Spalte ein Wert außerhalb des zulässigen Bereichs zugewiesen, dann speichert MySQL den Wert, der dem entsprechenden Endpunkt für den Datentyp der Spalte entspricht. Speichern Sie also etwa 256 in einer TINYINT- oder TINYINT UNSIGNED-Spalte, dann speichert MySQL 255 bzw. 127. Wird einer Fließkomma- oder Festkommaspalte ein Wert außerhalb des durch die angegebene (oder vorgabeseitige) Genauigkeit und Nachkommastellenanzahl festgelegten Bereichs zugewiesen, dann speichert MySQL ebenfalls den für diesen Bereich vorgesehenen Endpunkt:

Konvertierungen, die aufgrund von Kürzungsoperationen stattfinden, wenn MySQL nicht im strikten Modus läuft, werden als Warnungen für ALTER TABLE-, LOAD DATA INFILE- und UPDATE-Anweisungen sowie INSERT-Anweisungen für mehrere Datensätze gemeldet. Wenn MySQL im strikten Modus ausgeführt wird, schlagen diese Anweisungen fehl, und einige oder alle Werte werden nicht eingefügt bzw. geändert (dies hängt davon, ob die Tabelle transaktionssicher ist, sowie von weiteren Faktoren ab). Detaillierte Informationen finden Sie in Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

11.3. Datums- und Zeittypen

Datentypen für Datum und Uhrzeit erlauben die Darstellung zeitlicher Werte. In diese Kategorie fallen die Typen DATETIME, DATE, TIMESTAMP, TIME und YEAR. Jeder zeitbezogene Typ hat einen Bereich zulässiger Werte sowie einen „Nullwert“, der verwendet werden kann, wenn Sie einen unzulässigen Wert angeben, den MySQL nicht darstellen kann. Der Typ TIMESTAMP unterstützt ein spezielles Verhalten der automatischen Aktualisierung, welches im weiteren Verlauf beschrieben werden wird. Informationen zu den Speicheranforderungen zeitbezogener Typen finden Sie in Abschnitt 11.5, „Speicherbedarf von Spaltentypen“.

MySQL gibt Warnungen oder Fehler aus, wenn Sie einen unzulässigen Wert einzufügen versuchen. Indem Sie den passenden SQL-Modus wählen, können Sie genauer festlegen, welche Datenarten MySQL unterstützen soll. (Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.) Wenn Sie etwa den Modus ALLOW_INVALID_DATES verwenden, akzeptiert MySQL auch bestimmte irreale Daten wie '1999-11-31'. Dies ist praktisch, wenn Sie einen „möglicherweise falschen“ Wert, den ein Benutzer eingegeben hat (z. B. in ein Webformular), für die zukünftige Verarbeitung in der Datenbank speichern wollen. In diesem Modus überprüft MySQL lediglich, ob der Monat im Bereich zwischen 0 und 12 und der Tag im Bereich zwischen 0 und 31 liegt. Diese Bereiche umfassen deswegen die Null, weil MySQL in DATE- oder DATETIME-Spalten auch die Speicherung von Datumsangaben gestattet, bei denen der Tag oder der Monat und der Tag null sind. Dies ist recht nützlich bei Anwendungen, die ein Geburtsdatum speichern sollen, das Sie nicht genau kennen. In diesem Fall speichern Sie das Datum einfach als '1999-00-00' oder '1999-01-00'. Wenn Sie Datumsangaben auf diese Weise speichern, können Sie nicht davon ausgehen, für Funktionen wie DATE_SUB() oder DATE_ADD korrekte Ergebnisse zu erhalten, denn diese erfordern vollständige Datumsangaben. (Wenn Sie Nullen in Daten nicht erlauben wollen, können Sie den SQL-Modus NO_ZERO_IN_DATE aktivieren.)

MySQL gestattet ferner die Speicherung von '0000-00-00' als „Pseudodatum“ (hierfür darf der SQL-Modus NO_ZERO_DATE jedoch nicht aktiv sein). Dies ist in bestimmten Fällen bequemer (und benötigt zudem weniger Speicher für Daten und Indizes) als die Verwendung von NULL-Werten.

Es folgen einige Gesichtspunkte, die Sie bei der Arbeit mit Datentypen für Datum und Uhrzeit beachten sollten:

  • MySQL ruft Werte für einen Datentyp für Datum und Uhrzeit in einem Standardausgabeformat ab, versucht aber eine Vielzahl von Eingabewertformaten zu verarbeiten, die von Ihnen eingegeben wurden (z. B. wenn Sie einen Wert angeben, der einem zeitbezogenen Typ zugewiesen oder mit diesem verglichen werden soll). Nur die in den folgenden Abschnitten beschriebenen Formate werden unterstützt. Es wird erwartet, dass Sie zulässige Werte angeben. Wenn Sie Werte in anderen Formaten angeben, können unvorhersehbare Ergebnisse die Folge sein.

  • Datumsangaben mit zwei Stellen für die Jahreszahl sind mehrdeutig, da das Jahrhundert unbekannt ist. MySQL interpretiert Werte mit zweistelligen Jahreszahlen gemäß den folgenden Regeln:

    • Jahreszahlen im Bereich zwischen 70 und 99 werden als 1970-1999 interpretiert.

    • Jahreszahlen im Bereich zwischen 00 und 69 werden als 2000-2069 interpretiert.

  • Zwar versucht MySQL, Werte in verschiedenen Formaten zu interpretieren, aber Datumsangaben müssen immer in der Reihenfolge Jahr, Monat, Tag angegeben werden (z. B. '98-09-04'); die Reihenfolge Monat, Tag, Jahr ('09-04-98') oder die im deutschsprachigen Raum verwendete Reihenfolge Tag, Monat, Jahr ('04-09-98') werden nicht unterstützt.

  • MySQL konvertiert Werte eines zeitbezogenen Typs automatisch in eine Zahl, wenn der Wert in einem numerischen Kontext verwendet werden soll (und umgekehrt).

  • Wenn MySQL auf einen zeitbezogenen Wert trifft, der außerhalb des zulässigen Bereichs liegt oder für den betreffenden Typ anderweitig ungültig ist, wird dieser in den „Nullwert“ des betreffenden Typs umgewandelt. Eine Ausnahme liegt bei TIME-Werten außerhalb des gültigen Bereichs vor: Diese werden auf den entsprechenden Endpunkt des TIME-Bereichs gesetzt.

    Die folgende Tabelle zeigt das Format der „Nullwerte“ für die einzelnen Typen. Beachten Sie, dass die Verwendung dieser Werte Warnungen erzeugt, wenn der SQL-Modus NO_ZERO_DATE aktiviert ist.

    DatentypNullwert
    DATETIME'0000-00-00 00:00:00'
    DATE'0000-00-00'
    TIMESTAMP'0000-00-00 00:00:00'
    TIME'00:00:00'
    YEAR0000
  • Die „Nullwerte“ sind zwar speziell, aber Sie können sie speichern oder explizit referenzieren, indem Sie die Werte in der Tabelle verwenden. Alternativ können Sie dies auch unter Verwendung der Werte '0' oder 0 tun, die einfacher zu schreiben sind.

  • Nullwerte“ für Datum und Uhrzeit, die über MyODBC verwendet werden, werden ab MyODBC 2.50.12 automatisch zu NULL konvertiert, da ODBC mit solchen Werten nicht umgehen kann.

11.3.1. Die DATETIME-, DATE- und TIMESTAMP-Typen

Die Typen DATETIME, DATE und TIMESTAMP gehören zusammen. In diesem Abschnitt werden ihre Eigenschaften sowie Gemeinsamkeiten und Unterschiede beschrieben.

Den Typ DATETIME verwenden Sie, wenn Sie Werte benötigen, die sowohl ein Datum als auch eine Uhrzeit enthalten. MySQL ruft DATETIME-Werte im Format 'YYYY-MM-DD HH:MM:SS' ab und zeigt sie auch so an. Der unterstützte Bereich liegt zwischen '1000-01-01 00:00:00' und '9999-12-31 23:59:59'. („Unterstützt“ bedeutet hier, dass früher liegende Werte zwar funktionieren können, dies aber nicht garantiert ist.)

Der Typ DATE erlaubt die Benutzung eines Datums ohne Zeitangabe. MySQL ruft DATE-Werte im Format 'YYYY-MM-DD' ab und zeigt sie auch so an. Der unterstützte Bereich liegt zwischen '1000-01-01' und '9999-12-31'.

Der Datentyp TIMESTAMP schließlich hat je nach MySQL-Version und SQL-Modus des Servers verschiedene Eigenschaften, die im Verlauf dieses Abschnitts noch beschrieben werden.

Sie können DATETIME-, DATE- und TIMESTAMP-Werte mit einem der folgenden gängigen Formate angeben:

  • Als String im Format 'YYYY-MM-DD HH:MM:SS' oder 'YY-MM-DD HH:MM:SS'. Eine weniger strikte Syntax ist ebenfalls erlaubt: Ein beliebiges Interpunktionszeichen darf als Trennzeichen zwischen Datums- oder Zeiteinheiten benutzt werden. Beispielsweise sind '98-12-31 11:30:45', '98.12.31 11+30+45', '98/12/31 11*30*45' und '98@12@31 11^30^45' gleichwertig.

  • Als String im Format 'YYYY-MM-DD' oder 'YY-MM-DD'. Eine weniger strikte Syntax ist auch hier erlaubt. Beispielsweise sind '98-12-31', '98.12.31', '98/12/31' und '98@12@31' gleichwertig.

  • Als String ohne Trennzeichen in den Formaten 'YYYYMMDDHHMMSS' oder 'YYMMDDHHMMSS', sofern der String als Datum sinngebend ist. Zum Beispiel werden '19970523091528' und '970523091528' als '1997-05-23 09:15:28' interpretiert, aber '971122129015' ist unzulässig (der Minutenanteil ist unsinnig) und wird deswegen zu '0000-00-00 00:00:00'.

  • Als String ohne Trennzeichen in den Formaten 'YYYYMMDD' oder 'YYMMDD', sofern der String als Datum sinngebend ist. Zum Beispiel werden '19970523' und '970523' als '1997-05-23' interpretiert, aber '971332' ist unzulässig (der Tages- und der Minutenanteil sind unsinnig) und wird deswegen zu '0000-00-00'.

  • Als Zahl in den Formaten YYYYMMDDHHMMSS oder YYMMDDHHMMSS, sofern die Zahl als Datum sinngebend ist. Beispielsweise werden sowohl 19830905132800 als auch 830905132800 als '1983-09-05 13:28:00' interpretiert.

  • Als Zahl in den Formaten YYYYMMDD oder YYMMDD, sofern die Zahl als Datum sinngebend ist. Beispielsweise werden sowohl 19830905 als auch 830905 als '1983-09-05' interpretiert.

  • Als Ergebnis einer Funktion, die einen Wert zurückgibt, der im Kontext von DATETIME, DATE oder TIMESTAMP sinngebend ist, z. B. NOW() oder CURRENT_DATE.

Unzulässige DATETIME-, DATE- oder TIMESTAMP-Werte werden in den „Nullwert“ des entsprechenden Typs umgewandelt ('0000-00-00 00:00:00' oder '0000-00-00').

Bei als Strings angegebenen Werten, die Trennzeichen für Datumsbestandteile enthalten, ist es nicht erforderlich, zwei Stellen für Monats- oder Tageswerte anzugeben, die kleiner als 10 sind. So wird etwa '1979-6-9' als '1979-06-09' ausgewertet. Ähnlich ist es bei als Strings angegebenen Werten, die Trennzeichen für Uhrzeitbestandteile enthalten, nicht erforderlich, zwei Stellen für Stunden-, Minuten oder Sekundenwerte anzugeben, die kleiner als 10 sind: '1979-10-30 01:02:03' ist das Gleiche wie '1979-10-30 1:2:3'.

Als Zahlen angegebene Werte sollten eine Länge von 6, 8, 12 oder 14 Stellen haben. Wenn eine Zahl 8 oder 14 Stellen lang ist, werden die Formate YYYYMMDD bzw. YYYYMMDDHHMMSS angenommen, wobei das Jahr durch die ersten vier Stellen angegeben wird. Umfasst die Zahl 6 oder 12 Stellen, dann werden die Formate YYMMDD bzw. YYMMDDHHMMSS angenommen, wobei das Jahr durch die ersten beiden Stellen angegeben ist. Zahlen, die eine andere Länge aufweisen, werden so interpretiert, als ob sie am Anfang mit Nullen auf die nächste Länge aufgefüllt würden.

Werte, die als Strings ohne Trennzeichen angegeben werden, werden entsprechend ihrer Länge interpretiert. Ist der String 8 oder 14 Zeichen lang, dann wird angenommen, dass die ersten vier Zeichen das Jahr angeben. Andernfalls wird die Jahresangabe durch die ersten zwei Zeichen erwartet. Der String wird von links nach rechts interpretiert, als Reihenfolge wird Jahr, Monat, Tag, Stunde, Minute und Sekunde angenommen – je nachdem, wie viele Bestandteil im String vorhanden sind. Das bedeutet, dass Sie niemals Strings mit weniger als sechs Zeichen verwenden sollten. Wenn Sie beispielsweise '9903' angeben, um den März 1999 darzustellen, dann fügt MySQL einen „Nullwert“ für das Datum in Ihre Tabelle ein. Dies geschieht, weil die Jahres- und Monatsangaben 99 bzw. 03 sind, der Tag aber vollständig fehlt: Der Wert ist kein gültiges Datum. Sie können jedoch ausdrücklich einen Wert Null zur Darstellung fehlender Monats- oder Tagesangaben spezifizieren. So können Sie etwa '990300' verwenden, um den Wert '1999-03-00' einzufügen.

Sie können bis zu einem gewissen Grad Werte eines Datumstyps einem Objekt zuweisen, welches von einem anderen Datumstyp ist. Allerdings kann es hierdurch zu Werteänderungen oder Datenverlust kommen:

  • Wenn Sie einen DATE-Wert einem DATETIME- oder TIMESTAMP-Objekt zuweisen, wird die Uhrzeit des resultierenden Werts auf '00:00:00' gesetzt, da DATE diese Information nicht enthält.

  • Wenn Sie einen DATETIME- oder TIMESTAMP-Wert einem DATE-Objekt zuweisen, wird die Uhrzeit des resultierenden Werts gelöscht, weil der Typ DATE diese Information nicht speichert.

  • Beachten Sie, dass DATETIME-, DATE- und TIMESTAMP-Werte zwar alle in denselben Formatvarianten angegeben werden können, aber die Typen nicht dieselben Wertebereiche aufweisen. So kann ein TIMESTAMP-Wert nicht vor 1970 und nicht nach 2037 liegen. Das bedeutet, dass ein Datum wie '1968-01-01' zwar als DATETIME- und DATE-Wert zulässig, als TIMESTAMP-Wert jedoch illegal ist und deswegen zu 0 konvertiert wird.

Beachten Sie die folgenden Widrigkeiten bei der Angabe von Datumswerten:

  • Das weniger strikte Format, welches die Angabe von Werten als Strings gestattet, kann heimtückisch sein. So sieht etwa ein Wert wie '10:11:12' wegen des als Trennzeichen verwendeten Doppelpunkts (‘:’) wie eine Uhrzeit aus, in einem Datumskontext wird er jedoch als '2010-11-12' interpretiert. Der Wert '10:45:15' wird zu '0000-00-00' konvertiert, weil '45' kein zulässiger Monat ist.

  • Für den Server ist es erforderlich, dass Monats- und Tagesangaben gültig sind und sich nicht einfach nur in den Bereichen 1 bis 12 bzw. 1 bis 31 bewegen. Wenn der strikte Modus deaktiviert ist, werden ungültige Daten wie '2004-04-31' in '0000-00-00' umgewandelt, und es wird eine Warnung erzeugt. Ist der strikte Modus hingegen aktiviert, dann erzeugen ungültige Datumsangaben einen Fehler. Um derartige Daten zuzulassen, aktivieren Sie ALLOW_INVALID_DATES. Weitere Informationen finden Sie in Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  • Datumsangaben mit zwei Stellen für die Jahreszahl sind mehrdeutig, da das Jahrhundert unbekannt ist. MySQL interpretiert Werte mit zweistelligen Jahreszahlen gemäß den folgenden Regeln:

    • Jahreszahlen im Bereich zwischen 00 und 69 werden als 2000-2069 interpretiert.

    • Jahreszahlen im Bereich zwischen 70 und 99 werden als 1970-1999 interpretiert.

11.3.1.1. TIMESTAMP-Eigenschaften ab MySQL 4.1

Hinweis: Bei älteren MySQL-Versionen (vor 4.1) unterscheiden sich die Eigenschaften des Datentyps TIMESTAMP erheblich von dem, was in diesem Abschnitt beschrieben wurde. Wenn Sie ältere TIMESTAMP-Daten konvertieren müssen, damit sie in MySQL 5.1 funktionieren, lesen Sie in jedem Fall die einschlägigen Abschnitte im MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1.

TIMESTAMP-Spalten werden im selben Format angezeigt wie DATETIME-Spalten. Mit anderen Worten ist die Anzeigebreite auf 19 Zeichen festgesetzt, und das Format lautet YYYY-MM-DD HH:MM:SS.

Der MySQL Server kann auch mit aktiviertem SQL-Modus MAXDB laufen. Wenn am Server dieser Modus aktiv ist, ist TIMESTAMP mit DATETIME identisch. Das bedeutet, dass, wenn dieser Modus zum Zeitpunkt der Erstellung einer Tabelle aktiviert ist, TIMESTAMP-Spalten als DATETIME-Spalten erstellt werden. Aufgrund dessen verwenden solche Spalten das DATETIME-Anzeigeformat und haben denselben Wertebereich, und es gibt keine automatische Initialisierung oder Aktualisierung auf die aktuellen Werte für Datum und Uhrzeit.

Um den Modus MAXDB zu aktivieren, setzen Sie entweder den SQL-Modus des Servers beim Start mit der Serveroption --sql-mode=MAXDB auf MAXDB, oder Sie stellen die globale Variable sql_mode zur Laufzeit ein:

mysql> SET GLOBAL sql_mode=MAXDB;

Ein Client kann den Server auch so einstellen, dass die eigene Verbindung im MAXDB-Modus läuft:

mysql> SET SESSION sql_mode=MAXDB;

Beachten Sie, dass die Informationen im nachfolgenden Abschnitt nur für TIMESTAMP-Spalten in solchen Tabellen gelten, die nicht mit MAXDB als aktivem Modus erstellt wurden, weil solche Spalten als DATETIME-Spalten erstellt werden.

MySQL akzeptiert keine Zeitstempelwerte, die eine Null in der Tages- oder Monatsspalte oder andere Werte enthalten, die kein gültiges Datum darstellen. Die einzige Ausnahme dieser Regel ist der Sonderwert '0000-00-00 00:00:00'.

Bei der Bestimmung, wann die automatische TIMESTAMP-Initialisierung und -Aktualisierung erfolgen soll und welche Spalten dieses Verhalten aufweisen sollen, verfügen Sie über ausgesprochen viel Flexibilität:

  • Für eine TIMESTAMP-Spalte in einer Tabelle können Sie den aktuellen Zeitstempel als Standardwert und Wert für die automatische Aktualisierung angeben. Es ist möglich, den aktuellen Zeitstempel als Vorgabewert für die Initialisierung der Spalte und/oder als Wert für die automatische Aktualisierung zu verwenden. Es ist jedoch nicht möglich, den aktuellen Zeitstempel als Vorgabewert für eine Spalte und als Wert für die automatische Aktualisierung einer anderen Spalte zu verwenden.

  • Sie können festlegen, welche TIMESTAMP-Spalte sich automatisch initialisieren oder auf die aktuellen Werte für Datum und Uhrzeit setzen soll. Dies muss nicht unbedingt die erste TIMESTAMP-Spalte sein.

Die folgenden Regeln bestimmen die Initialisierung und Aktualisierung von TIMESTAMP-Spalten:

  • Wird ein DEFAULT-Wert für die erste TIMESTAMP-Spalte in einer Tabelle festgelegt, so wird dieser nicht ignoriert. Als Vorgabe kann CURRENT_TIMESTAMP oder ein konstanter Wert für Datum und Uhrzeit verwendet werden.

  • DEFAULT NULL ist bei der ersten TIMESTAMP-Spalte dasselbe wie DEFAULT CURRENT_TIMESTAMP. Bei jeder anderen TIMESTAMP-Spalte hingegen wird DEFAULT NULL als DEFAULT 0 behandelt.

  • Jede einzelne TIMESTAMP-Spalte in einer Tabelle kann als diejenige benutzt werden, die mit dem aktuellen Zeitstempel initialisiert oder automatisch aktualisiert wird.

  • In einer CREATE TABLE-Anweisung kann die erste TIMESTAMP-Spalte auf eine der folgenden Weisen deklariert werden:

    • Wenn sowohl DEFAULT CURRENT_TIMESTAMP- als auch ON UPDATE CURRENT_TIMESTAMP-Klauseln vorhanden sind, dann hat die Spalte den aktuellen Zeitstempel als Vorgabewert und wird automatisch aktualisiert.

    • Fehlen sowohl DEFAULT- als auch ON UPDATE-Klausel, dann ist dies das Gleiche wie DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.

    • Mit DEFAULT CURRENT_TIMESTAMP-, aber ohne ON UPDATE-Klausel hat die Spalte den aktuellen Zeitstempel als Vorgabewert, wird jedoch nicht automatisch aktualisiert.

    • Ohne DEFAULT-, aber mit ON UPDATE CURRENT_TIMESTAMP-Klausel hat die Spalte den Standardwert 0 und wird automatisch aktualisiert.

    • Bei einem konstanten DEFAULT-Wert erhält die Spalte den angegebenen Standardwert. Wenn die Spalte eine ON UPDATE CURRENT_TIMESTAMP-Klausel hat, wird sie automatisch aktualisiert, andernfalls nicht.

    Anders gesagt: Sie können den aktuellen Zeitstempel sowohl als Initialisierungs- als auch als Aktualisierungswert, als einen dieser beiden Werte oder gar nicht verwenden. (So können Sie beispielsweise ON UPDATE angeben, um die automatische Aktualisierung zu aktivieren, ohne dass die Spalte automatisch initialisiert werden müsste.)

  • CURRENT_TIMESTAMP, CURRENT_TIMESTAMP() und NOW() können gleichermaßen in DEFAULT- und ON UPDATE-Klauseln verwendet werden. Sie alle haben die Bedeutung „aktueller Zeitstempel“.

    Die Reihenfolge der DEFAULT- und ON UPDATE-Attribute ist unerheblich. Wenn sowohl DEFAULT als auch ON UPDATE für eine TIMESTAMP-Spalte angegeben werden, kann das eine Attribut vor oder hinter dem anderen stehen. So sind beispielsweise die folgenden Anweisungen gleichwertig:

    CREATE TABLE t (ts TIMESTAMP);
    CREATE TABLE t (ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                                 ON UPDATE CURRENT_TIMESTAMP);
    CREATE TABLE t (ts TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                                 DEFAULT CURRENT_TIMESTAMP);
    
  • Um für eine andere als die erste TIMESTAMP-Spalte die automatische Initialisierung oder Aktualisierung festzulegen, müssen Sie dieses Verhalten für die erste TIMESTAMP-Spalte unterdrücken. Dies tun Sie, indem Sie ihr explizit einen konstanten DEFAULT-Wert zuweisen (z. B. DEFAULT 0 oder DEFAULT '2003-01-01 00:00:00'). Nachfolgend gelten für die andere TIMESTAMP-Spalte dieselben Regeln wie für die erste; die einzige Ausnahme besteht darin, dass, wenn Sie sowohl DEFAULT als auch ON UPDATE weglassen, keine automatische Initialisierung oder Aktualisierung erfolgt.

    So sind beispielsweise die folgenden Anweisungen gleichwertig:

    CREATE TABLE t (
        ts1 TIMESTAMP DEFAULT 0,
        ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                      ON UPDATE CURRENT_TIMESTAMP);
    CREATE TABLE t (
        ts1 TIMESTAMP DEFAULT 0,
        ts2 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                      DEFAULT CURRENT_TIMESTAMP);
    

Sie können die aktuelle Zeitzone für jede Verbindung separat einstellen (siehe Beschreibung in Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“). TIMESTAMP-Werte werden in UTC gespeichert; zur Speicherung werden sie aus der aktuellen Zeitzone konvertiert und beim Abrufen wieder in die aktuelle Zeitzone zurückkonvertiert. Solange die Zeitzoneneinstellung gleich bleibt, erhalten Sie denselben Wert zurück, den Sie auch gespeichert haben. Wenn Sie einen TIMESTAMP-Wert speichern, dann die Zeitzone ändern und den Wert abrufen, unterscheidet sich dieser abgerufene vom gespeicherten Wert. Grund hierfür ist die Tatsache, dass unterschiedliche Zeitzonen für die beiden Konvertierungsvorgänge benutzt wurden. Die aktuelle Zeitzone ist über den Wert der Systemvariablen time_zone verfügbar.

Sie können das Attribut NULL in die Definition einer TIMESTAMP-Spalte einfügen, damit die Spalte auch NULL-Werte enthalten kann. Zum Beispiel:

CREATE TABLE t
(
  ts1 TIMESTAMP NULL DEFAULT NULL,
  ts2 TIMESTAMP NULL DEFAULT 0,
  ts3 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
);

Wenn das Attribut NULL nicht angegeben wurde und die Spalte auf NULL gesetzt wird, wird sie automatisch auf den aktuellen Zeitstempel umgestellt. Beachten Sie, dass eine TIMESTAMP-Spalte, die NULL-Werte gestattet, den aktuellen Zeitstempel nur unter einer der folgenden Bedingungen annimmt:

  • Ihr Vorgabewert ist als CURRENT_TIMESTAMP definiert.

  • NOW() oder CURRENT_TIMESTAMP werden in die Spalte eingefügt.

Mit anderen Worten: Eine TIMESTAMP-Spalte, die als NULL definiert ist, wird nur dann automatisch aktualisiert, wenn sie unter Verwendung einer Definition wie der folgenden erstellt wurde:

CREATE TABLE t (ts TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP);

Betrachten Sie im Unterschied dazu folgende Definition einer TIMESTAMP-Spalte, die NULL-Werte erlaubt, DEFAULT TIMESTAMP aber nicht verwendet:

CREATE TABLE t1 (ts TIMESTAMP NULL DEFAULT NULL);
CREATE TABLE t2 (ts TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00');

In diesem Fall müssen Sie explizit einen Wert einfügen, der den aktuellen Werten für Datum und Uhrzeit entspricht. Zum Beispiel:

INSERT INTO t1 VALUES (NOW());
INSERT INTO t2 VALUES (CURRENT_TIMESTAMP);

11.3.2. Der TIME-Typ

Abruf und Anzeige von TIME-Werten durch MySQL erfolgen im Format 'HH:MM:SS' (oder im Format 'HHH:MM:SS' bei einer großen Zahl von Stunden). TIME-Werte liegen in einem Bereich zwischen '-838:59:59' und '838:59:59'. Der Stundenteil kann so groß sein, weil TIME nicht nur eine Uhrzeit darstellen kann (diese muss kleiner sein als 24 Stunden), sondern auch die verstrichene Zeit oder ein Zeitintervall zwischen zwei Ereignissen. Ein solches Intervall kann wesentlich länger als 24 Stunden oder sogar negativ sein.

Zur Angabe von TIME-Werten steht eine Vielzahl von Formaten zur Verfügung:

  • Als String im Format 'D HH:MM:SS.fraction'. Sie können auch eines der folgenden weniger stringenten Syntaxformate verwenden: 'HH:MM:SS.fraction', 'HH:MM:SS', 'HH:MM', 'D HH:MM:SS', 'D HH:MM', 'D HH' oder 'SS'. Hierbei steht D für Tage und kann einen Wert zwischen 0 und 34 haben. Beachten Sie, dass MySQL den Bruchteil (fraction) nicht speichert.

  • Als String ohne Trennzeichen im Format 'HHMMSS', sofern er als Zeitangabe sinngebend ist. Zum Beispiel wird '101112' als '10:11:12' interpretiert, aber '109712' ist unzulässig (der Minutenanteil ist unsinnig) und wird deswegen zu '00:00:00'.

  • Als Zahl im Format HHMMSS, sofern er als Zeitangabe sinngebend ist. So wird etwa 101112 als '10:11:12' interpretiert. Die folgenden alternativen Formate werden ebenfalls verstanden: SS, MMSS, HHMMSS, HHMMSS.fraction. Beachten Sie, dass MySQL den Bruchteil nicht speichert.

  • Als Ergebnis einer Funktion, die einen Wert zurückgibt, der im Kontext von TIME sinngebend ist, z. B. CURRENT_TIME.

Bei als String angegebenen TIME-Werten, die Trennzeichen für Uhrzeitbestandteile enthalten, ist es nicht erforderlich, zwei Stellen für Stunden-, Minuten oder Sekundenwerte anzugeben, die kleiner als 10 sind: '8:3:2' ist das Gleiche wie '08:03:02'.

Seien Sie vorsichtig bei der Zuweisung abgekürzter Werte zu einer TIME-Spalte. Ohne Doppelpunkte interpretiert MySQL die Werte in der Annahme, dass die beiden ganz rechts stehenden Stellen die Sekunden angeben. (MySQL interpretiert TIME-Werte nicht als Uhrzeit, sondern als verstrichene Zeit.) So könnte man etwa annehmen, dass '1112' und 1112 die Bedeutung '11:12:00' (also 12 Minuten nach 11 Uhr) hätten; MySQL liest die Angabe jedoch als '00:11:12' (also 11 Minuten und 12 Sekunden). Ähnlich werden '12' und 12 als '00:00:12' interpretiert. TIME-Werte mit Doppelpunkten hingegen werden immer als Uhrzeit betrachtet: '11:12' bedeutet also '11:12:00' und nicht '00:11:12'.

Standardmäßig werden Werte, die außerhalb des für TIME zulässigen Bereichs liegen, aber ansonsten zulässig sind, auf den nächstgelegenen Endpunkt des Bereichs gesetzt. Beispielsweise werden '-850:00:00' und '850:00:00' zu '-838:59:59' bzw. '838:59:59' konvertiert. Unzulässige TIME-Werte werden zu '00:00:00' konvertiert. Beachten Sie, dass es, weil '00:00:00' selbst ein zulässiger TIME-Wert ist, keine Möglichkeit gibt, festzustellen, ob ein in der Tabelle gespeicherter Wert '00:00:00' als '00:00:00' oder als unzulässiger Wert angegeben wurde.

Zur restriktiveren Behandlung ungültiger TIME-Werte aktivieren Sie den strikten SQL-Modus. In diesem Fall werden Fehler ausgegeben. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

11.3.3. Der YEAR-Typ

Der Datentyp YEAR hat genau ein Byte und dient der Darstellung von Jahreszahlen.

MySQL ruft YEAR-Werte im Format YYYY ab und zeigt sie auch so an. Der Bereich liegt zwischen 1901 und 2155.

Zur Angabe von YEAR-Werten steht eine Vielzahl von Formaten zur Verfügung:

  • Als vierstelliger String im Bereich '1901' bis '2155'.

  • Als vierstellige Zahl im Bereich 1901 bis 2155.

  • Als zweistelliger String im Bereich '00' bis '99'. Werte in den Bereichen '00' bis '69' und '70' bis '99' werden zu YEAR-Werten in den Bereichen 2000 bis 2069 bzw. 1970 bis 1999 konvertiert.

  • Als zweistellige Zahl im Bereich 1 bis 99. Werte in den Bereichen 1 bis 69 und 70 bis 99 werden zu YEAR-Werten in den Bereichen 2001 bis 2069 bzw. 1970 bis 1999 konvertiert. Beachten Sie, dass sich der Bereich der zweistelligen Zahlen leicht von dem der zweistelligen Strings unterscheidet, da Sie Null nicht direkt als Zahl angeben und als 2000 interpretieren lassen können. Die Angabe muss vielmehr als String '0' oder '00' erfolgen, andernfalls wird sie als 0000 interpretiert.

  • Als Ergebnis einer Funktion, die einen Wert zurückgibt, der im Kontext von YEAR sinngebend ist, z. B. NOW().

Unzulässige YEAR-Werte werden zu 0000 konvertiert.

11.3.4. Jahr-2000-Probleme und Datumstypen

Wie in Abschnitt 1.4.5, „Jahr-2000-Konformität“, beschrieben, ist MySQL selbst Jahr-2000-sicher; bestimmte Werte, die in MySQL eingegeben werden, sind es jedoch unter Umständen nicht. Jeder Wert, der eine zweistellige Jahresangabe enthält, ist mehrdeutig, da das Jahrhundert unbekannt ist. Solche Werte müssen in das vierstellige Format umgesetzt werden, da MySQL Jahreszahlen intern vierstellig speichert.

Bei den Typen DATETIME, DATE, TIMESTAMP und YEAR interpretiert MySQL nicht eindeutige Jahreszahlen entsprechend den folgenden Regeln:

  • Jahreszahlen im Bereich zwischen 00 und 69 werden als 2000-2069 interpretiert.

  • Jahreszahlen im Bereich zwischen 70 und 99 werden als 1970-1999 interpretiert.

Denken Sie daran, dass diese Regeln nur heuristischer Natur sind und sinnvoll zu erschließen versuchen, was Ihr Datenwert bedeuten könnte. Wenn die von MySQL verwendeten Regeln keine korrekten Werte erzeugen, sollten Sie eindeutige Angaben mit vierstelligen Jahreszahlen machen.

ORDER BY sortiert zweistellige YEAR-Werte wie erwartet.

Einige Funktionen wie MIN() und MAX() konvertieren einen YEAR-Wert in eine Zahl. Das bedeutet, dass ein Wert mit einer zweistelligen Jahresangabe für diese Funktionen ungeeignet ist. Dieses Problem beheben Sie, indem Sie den TIMESTAMP- oder YEAR-Wert in das vierstellige Jahresformat konvertieren.

11.4. String-Typen

Es gibt die folgenden String-Datentypen: CHAR, VARCHAR, BINARY, VARBINARY, BLOB, TEXT, ENUM und SET. In diesem Abschnitt wird erläutert, wie diese Typen funktionieren und wie Sie sie in Ihren Abfragen verwenden. Informationen zu den Speicheranforderungen von String-Typen finden Sie in Abschnitt 11.5, „Speicherbedarf von Spaltentypen“.

11.4.1. Die CHAR- und VARCHAR-Typen

Die Typen CHAR und VARCHAR ähneln einander, werden aber auf unterschiedliche Weise gespeichert und abgerufen. Weitere Unterschiede sind die maximale Länge und die Behandlung von Leerzeichen am String-Ende. Beim Speichern und Abrufen solcher Werte erfolgt keine Wandlung der Groß-/Kleinschreibung.

Die Typen CHAR und VARCHAR werden unter Angabe einer Länge deklariert, die die maximale Anzahl von Zeichen spezifiziert, die gespeichert werden kann. So kann ein CHAR(30)-Wert beispielsweise 30 Zeichen aufnehmen.

Die Länge einer CHAR-Spalte ist auf den von Ihnen beim Anlegen der Tabelle deklarierten Wert beschränkt. Dieser kann zwischen 0 und 255 liegen. Wenn CHAR-Werte gespeichert werden, dann werden sie nach rechts mit Leerzeichen bis auf die angegebene Länge aufgefüllt. Beim Abrufen von CHAR-Werten werden die am Ende stehenden Leerzeichen dann entfernt.

Werte in VARCHAR-Spalten sind Strings variabler Länge. Diese kann zwischen 0 und 65.535 liegen. (Die effektive Maximallänge einer VARCHAR-Spalte wird durch die maximale Datensatzgröße und den verwendeten Zeichensatz bestimmt. Die gesamte Maximallänge liegt bei 65.532 Byte.)

Im Gegensatz zu CHAR- werden VARCHAR-Werte nur mit so vielen Zeichen wie erforderlich zuzüglich eines Bytes gespeichert, welches die Länge angibt (bei Spalten, die mit einer Länge größer 255 deklariert sind, werden hierfür 2 Byte verwendet).

VARCHAR-Werte werden beim Speichern nicht aufgefüllt. Ferner werden am Ende stehende Leerzeichen entsprechend dem SQL-Standard beim Speichern und Abrufen beibehalten.

Wenn Sie einer CHAR- oder VARCHAR-Spalte einen Wert zuweisen, der die deklarierte Länge der Spalte überschreitet, dann wird der Wert so weit gekürzt, bis er passend ist. Handelt es sich bei den abgeschnittenen Zeichen nicht um Leerzeichen, dann wird eine Warnung erzeugt. Wenn Sie den strikten SQL-Modus verwenden, erscheint beim Abschneiden von anderen Zeichen als Leerzeichen eine Fehlermeldung (statt einer Warnung), und der Wert wird nicht eingefügt. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Die folgende Tabelle veranschaulicht die Unterschiede zwischen den Typen CHAR und VARCHAR. Hierzu wird das jeweilige Ergebnis der Speicherung verschiedener String-Werte in CHAR(4)- und VARCHAR(4)-Spalten angezeigt:

WertCHAR(4)Erforderlicher SpeicherplatzVARCHAR(4)Erforderlicher Speicherplatz
'''    '4 Byte''1 Byte
'ab''ab  '4 Byte'ab '3 Byte
'abcd''abcd'4 Byte'abcd'5 Byte
'abcdefgh''abcd'4 Byte'abcd'5 Byte

Beachten Sie, dass die in der letzten Zeile der Tabelle gezeigten Werte nur gelten, wenn der strikte Modus nicht verwendet wird; wird MySQL hingegen im strikten Modus ausgeführt, dann werden Werte, die die Spaltenlänge überschreiten, nicht gespeichert, und ein Fehler wird ausgegeben.

Wird ein gegebener Wert in die Spalten CHAR(4) und VARCHAR(4) gespeichert, dann sind die aus den Spalten abgerufenen Werte nicht immer identisch, weil in CHAR-Spalten am Ende stehende Leerzeichen beim Abrufen entfernt werden. Das folgende Beispiel veranschaulicht diesen Unterschied:

mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO vc VALUES ('ab  ', 'ab  ');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab  )              | (ab)                |
+---------------------+---------------------+
1 row in set (0.06 sec)

Werte in CHAR- und VARCHAR-Spalten werden entsprechend der zeichensatzspezifischen Sortierungsweise, die der Spalte zugewiesen ist, sortiert und verglichen.

Beachten Sie, dass alle MySQL-Sortierungen vom Typ PADSPACE sind, d. h. alle CHAR- und VARCHAR-Werte in MySQL werden ohne Berücksichtigung der am Ende stehenden Leerzeichen verglichen. Zum Beispiel:

mysql> CREATE TABLE names (myname CHAR(10), yourname VARCHAR(10));
Query OK, 0 rows affected (0.09 sec)

mysql> INSERT INTO names VALUES ('Monty ', 'Monty ');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT myname = 'Monty  ', yourname = 'Monty  ' FROM names;
+--------------------+----------------------+
| myname = 'Monty  ' | yourname = 'Monty  ' |
+--------------------+----------------------+
|                  1 |                    1 |
+--------------------+----------------------+
1 row in set (0.00 sec)

Dies gilt für alle MySQL-Versionen ungeachtet des gewählten SQL-Modus.

Bei solchen Fällen, in denen Leerzeichen am Ende entfernt werden oder Vergleiche diese ignorieren, hat, wenn eine Spalte einen Index hat, der eindeutige Werte erfordert, das Einfügen von Werten, die sich nur durch die Anzahl am Ende stehender Füllleerzeichen unterscheiden, eine Fehlermeldung bezüglich einer Schlüsseldublette zur Folge. Wenn beispielsweise eine Tabelle den Wert 'a' enthält, wird diese Fehlermeldung erzeugt, sobald Sie versuchen, 'a ' zu speichern.

11.4.2. Die BINARY- und VARBINARY-Typen

Die Typen BINARY und VARBINARY ähneln CHAR bzw. VARCHAR. Der Unterschied besteht darin, dass diese beiden Typen binäre (statt nichtbinärer) Strings speichern, d. h., sie enthalten byte- statt zeichenbasierter Strings. Diese Datentypen haben aufgrund dessen keinen Zeichensatz: Sortierung und Vergleiche basieren in diesem Fall auf den numerischen Werten der Bytes in den Werten.

Die zulässige Maximallänge von BINARY und VARBINARY entspricht der von CHAR bzw. VARCHAR, nur wird die Länge von BINARY und VARBINARY in Bytes statt in Zeichen angegeben.

Die Datentypen BINARY und VARBINARY sind nicht identisch mit den Typen CHAR BINARY und VARCHAR BINARY Bei Letzteren hat das Attribut BINARY nicht zur Folge, dass die Spalte als binäre String-Spalte behandelt wird. Stattdessen aktiviert sie die binäre Sortierung für den Spaltenzeichensatz, und die Spalte selbst enthält nichtbinäre zeichenbasierte Strings statt binärer bytebasierter Strings. So wird beispielsweise CHAR(5) BINARY als CHAR(5) CHARACTER SET latin1 COLLATE latin1_bin behandelt (vorausgesetzt, der Standardzeichensatz ist latin1). Hier liegt ein Unterschied zu BINARY(5) vor, das binäre Strings mit einer Länge von 5 Byte speichert, für die kein Zeichensatz und keine Sortierung definiert sind.

Wenn BINARY-Werte gespeichert werden, werden sie nach rechts hin mit dem Füllwert auf die gewünschte Länge aufgefüllt. Der Füllwert ist 0x00 (das Nullbyte). Beim Einfügen werden Werte nach rechts hin mit 0x00 aufgefüllt, und beim Auswählen werden am Ende stehende Nullbytes nicht entfernt. Alle Bytes werden in Vergleichen (einschließlich ORDER BY- und DISTINCT-Operationen) berücksichtigt. 0x00-Bytes und Leerzeichen sind in Vergleichen unterschiedlich, wobei 0x00 einen kleineren Wert als das Leerzeichen hat.

Beispiel: Bei einer BINARY(3)-Spalte wird 'a ' beim Einfügen zu 'a \0'. 'a\0' wird beim Einfügen zu 'a\0\0'. Bei der Auswahl bleiben die gewählten Werte unverändert.

Bei VARBINARY werden weder beim Einfügen Füllbytes angehängt noch bei der Auswahl Bytes abgeschnitten. Alle Bytes werden in Vergleichen (einschließlich ORDER BY- und DISTINCT-Operationen) berücksichtigt. 0x00-Bytes und Leerzeichen sind in Vergleichen unterschiedlich, wobei 0x00 einen kleineren Wert als das Leerzeichen hat.

Bei solchen Fällen, in denen Füllbytes am Ende entfernt werden oder Vergleiche diese ignorieren, hat, wenn eine Spalte einen Index hat, der eindeutige Werte erfordert, das Einfügen von Werten, die sich nur durch die Anzahl am Ende stehender Füllbytes unterscheiden, eine Fehlermeldung bezüglich einer Schlüsseldublette zur Folge. Wenn beispielsweise eine Tabelle den Wert 'a' enthält, wird diese Fehlermeldung erzeugt, sobald Sie versuchen, 'a\0' zu speichern.

Wenn Sie den Datentyp BINARY zur Speicherung binärer Daten verwenden wollen und es wichtig ist, dass der abgerufene mit dem zuvor gespeicherten Wert vollständig identisch ist, dann sollten Sie die beschriebenen Merkmale zum Auffüllen und Abschneiden sorgfältig lesen. Das folgende Beispiel veranschaulicht, wie sich das Auffüllen von BINARY-Werten mit 0x00 auf Vergleiche von Spaltenwerten auswirkt:

mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t SET c = 'a';
Query OK, 1 row affected (0.01 sec)

mysql> SELECT HEX(c), c = 'a', c = 'a\0\0' from t;
+--------+---------+-------------+
| HEX(c) | c = 'a' | c = 'a\0\0' |
+--------+---------+-------------+
| 610000 |       0 |           1 |
+--------+---------+-------------+
1 row in set (0.09 sec)

Wenn der abgerufene Wert mit dem zur Speicherung angegebenen Wert identisch sein muss, ohne dass aufgefüllt wird, dann sollten Sie unter Umständen besser VARBINARY oder einen der BLOB-Datentypen verwenden.

11.4.3. Die Spaltentypen BLOB und TEXT

Ein BLOB ist ein binäres großes Objekt, welches eine variable Menge von Daten aufnehmen kann. Die vier BLOB-Typen sind TINYBLOB, BLOB, MEDIUMBLOB und LONGBLOB. Sie unterscheiden sich lediglich in der maximalen Länge der Werte, die sie aufnehmen können. Die vier TEXT-Typen sind TINYTEXT, TEXT, MEDIUMTEXT und LONGTEXT. Sie entsprechen den vier BLOB-Typen, d. h., sie haben dieselben Längenbeschränkungen und Speicheranforderungen. Siehe auch Abschnitt 11.5, „Speicherbedarf von Spaltentypen“. Beim Speichern und Abrufen von TEXT- und BLOB-Spalten erfolgt keine Wandlung der Groß-/Kleinschreibung.

BLOB-Spalten werden als binäre Strings (Byte-Strings) behandelt, TEXT-Spalten als nichtbinäre Strings (zeichenbasierte Strings). BLOB-Spalten haben keinen Zeichensatz, und die Sortierung basiert auf den numerischen Werten der Bytes in den Spaltenwerten; TEXT-Spalten hingegen haben einen Zeichensatz, dessen Sortierung auch bestimmt, wie die Werte sortiert und verglichen werden.

Wird eine TEXT-Spalte indiziert, dann werden Vergleiche von Indexeinträgen am Ende mit Leerzeichen aufgefüllt. Das bedeutet, dass, wenn der Index eindeutige Werte erfordert, Fehlermeldungen zu doppelt vorhandenen Schlüsseln auftreten werden, wenn sich Werte lediglich in der Anzahl der am Ende stehenden Leerzeichen unterscheiden. Wenn beispielsweise eine Tabelle den Wert 'a' enthält, wird diese Fehlermeldung erzeugt, sobald Sie versuchen, 'a ' zu speichern. Für BLOB-Spalten trifft dies allerdings nicht zu.

Wenn Sie im strikten Modus einer BLOB- oder TEXT-Spalte einen Wert zuweisen, der die zulässige Länge des Datentyps überschreitet, dann wird der Wert so weit gekürzt, bis er passend ist. Handelt es sich bei den abgeschnittenen Zeichen nicht um Leerzeichen, dann wird eine Warnung erzeugt. Wenn Sie den strikten SQL-Modus verwenden, erscheint stattdessen eine Fehlermeldung, und der Wert wird nicht eingefügt. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

In vielerlei Hinsicht können Sie eine BLOB-Spalte als VARBINARY-Spalte betrachten, die beliebig groß sein kann. Ähnlich können Sie eine TEXT-Spalte auch als VARCHAR-Spalte betrachten. BLOB und TEXT unterscheiden sich wie folgt von VARBINARY bzw. VARCHAR:

  • Bei Indizes in BLOB- und TEXT-Spalten müssen Sie eine Länge für das Indexpräfix angeben. Bei CHAR und VARCHAR ist die Präfixlänge optional. Siehe auch Abschnitt 7.4.3, „Spaltenindizes“.

  • BLOB- und TEXT-Spalten können keine DEFAULT-Werte haben.

LONG und LONG VARCHAR lassen sich dem Datentyp MEDIUMTEXT zuordnen. Grund hierfür sind Kompatibilitätsaspekte. Wenn Sie das Attribut BINARY mit einem TEXT-Datentyp verwenden, wird der Spalte die binäre Sortierung des Spaltenzeichensatzes zugewiesen.

MySQL Connector/ODBC definiert BLOB-Werte als LONGVARBINARY und TEXT-Werte als LONGVARCHAR-Werte.

Da BLOB- und TEXT-Werte sehr lang sein können, können Sie bei ihrer Verwendung auf einige Einschränkungen treffen:

  • Nur die ersten max_sort_length Bytes der Spalte werden zur Sortierung verwendet. Der Standardwert von max_sort_length beträgt 1024. Dieser Wert kann mithilfe der Option --max_sort_length=N beim Start des mysqld-Servers geändert werden. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

    Sie können die Berücksichtigung von mehr Bytes bei der Sortierung oder Gruppierung implementieren, indem Sie den Wert von max_sort_length zur Laufzeit erhöhen. Jeder Client kann den Wert für seine Sitzungsvariable max_sort_length selbst ändern:

    mysql> SET max_sort_length = 2000;
    mysql> SELECT id, comment FROM t
        -> ORDER BY comment;
    

    Eine andere Möglichkeit, GROUP BY oder ORDER BY für eine BLOB- oder TEXT-Spalte, die lange Werte enthält, zu verwenden und dabei mehr als die mit max_sort_length angegebene Anzahl von Bytes zu berücksichtigen, besteht darin, den Spaltenwert in ein Objekt fester Länge zu konvertieren. Standardmäßig erfolgt eine solche Konvertierung mit der Funktion SUBSTRING. Die folgende Anweisung beispielsweise hat die Berücksichtigung von 2000 Byte in der Spalte comment für die Sortierung zur Folge:

    mysql> SELECT id, SUBSTRING(comment,1,2000) FROM t
        -> ORDER BY SUBSTRING(comment,1,2000);
    
  • Die maximale Größe eines BLOB- oder TEXT-Objekts ist durch seinen Typ bestimmt. Der größte Wert jedoch, den Sie tatsächlich zwischen Client und Server übertragen können, wird durch die Menge des verfügbaren Speichers und die Größe der Kommunikationspuffer festgelegt. Sie können die Größe des Meldungspuffers ändern, indem Sie der Variablen max_allowed_packet einen anderen Wert zuweisen. Dies muss allerdings sowohl für den Server als auch für Ihr Clientprogramm erfolgen. So können Sie etwa sowohl mit mysql als auch mit mysqldump den max_allowed_packet-Wert auf der Clientseite verändern. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“, Abschnitt 8.5, „mysql — Das MySQL-Befehlszeilenwerkzeug mysql“ und Abschnitt 8.10, „mysqldump — Programm zur Datensicherung“.

Jeder BLOB- und TEXT-Wert wird intern durch ein separat reserviertes Objekt dargestellt. Dies steht im Gegensatz zu allen anderen Datentypen, für die der Speicherplatz pro Spalte genau einmal beim Öffnen der Tabelle reserviert wird.

In manchen Fällen kann es wünschenswert sein, Binärdaten wie Mediendateien in BLOB- oder TEXT-Spalten zu speichern. Beim Umgang mit solchen Daten können sich die MySQL-Funktionen zur String-Verarbeitung als recht praktisch erweisen. Siehe auch Abschnitt 12.3, „String-Funktionen“. Aus Sicherheits- und anderen Gründen empfiehlt es sich in der Regel, dies im Anwendungscode zu tun, statt Benutzern der Anwendung die Berechtigung FILE zu gewähren. Details zu Sprachen und Plattformen können Sie in den MySQL-Foren (http://forums.mysql.com/) diskutieren.

11.4.4. Der Spaltentyp ENUM

Der Datentyp ENUM ist ein String-Objekt mit einem Wert, der aus einer Liste zulässiger Werte ausgewählt wird, die beim Erstellen der Tabelle explizit in der Spaltendefinition aufgelistet werden.

Als Werte kommen unter bestimmten Umständen auch der Leer-String ('') oder NULL in Frage:

  • Wenn Sie einen ungültigen Wert (d. h. einen String, der nicht in der Liste zulässiger Werte vorhanden ist) in eine ENUM-Spalte einzufügen versuchen, dann wird stattdessen als spezieller Fehlerwert der Leer-String eingefügt. Dieser String lässt sich von einem „normalen“ leeren String dadurch unterscheiden, dass er den numerischen Wert 0 hat. Weitere Informationen hierzu folgen weiter unten.

    Wenn der strikte SQL-Modus aktiviert ist, führen Versuche, ungültige ENUM-Werte einzufügen, zu einer Fehlermeldung.

  • Wird für eine ENUM-Spalte die Zulässigkeit von NULL deklariert, dann ist der NULL-Wert für die Spalte erlaubt. Ferner ist in diesem Fall auch der Standardwert NULL. Wenn eine ENUM-Spalte als NOT NULL deklariert wird, dann wird als Vorgabe das erste Element der Liste zulässiger Werte verwendet.

Jeder Wert in der Auflistung hat einen Index:

  • Werte aus der Liste zulässiger Elemente in der Spaltenspezifikation werden beginnend mit 1 nummeriert.

  • Der Indexwert des als Fehlerwert verwendeten Leer-Strings ist 0. Sie können also folgende SELECT-Anweisung verwenden, um Datensätze zu ermitteln, bei denen ungültige ENUM-Werte zugewiesen wurden:

    mysql> SELECT * FROM tbl_name WHERE enum_col=0;
    
  • Der Indexwert des NULL-Werts ist NULL.

  • Der Begriff „Index“ bezeichnet in diesem Kontext nur die Position innerhalb der Auflistung möglicher Werte. Es gibt keine Verbindung zu Tabellenindizes.

Eine Spalte, die als ENUM('one', 'two', 'three') definiert ist, kann jeden der nachfolgend angegebenen Werte annehmen. Auch die Indizes der einzelnen Werte werden angezeigt:

WertIndex
NULLNULL
''0
'one'1
'two'2
'three'3

Eine Auflistung darf maximal 65.535 Elemente enthalten.

Beim Erstellen der Tabelle werden bei ENUM-Mitgliedswerten am Ende stehende Leerzeichen in der Tabellendefinition automatisch entfernt.

Beim Abrufen werden Werte, die in einer ENUM-Spalte gespeichert sind, in der Groß-/Kleinschreibung angezeigt, die bei der Spaltendefinition verwendet wurde. Beachten Sie, dass ENUM-Spalten ein Zeichensatz und eine Sortierung zugewiesen werden können. Bei binären Sortierungen oder solchen, bei denen die Groß-/Kleinschreibung unterschieden wird, wird die Schreibweise beim Zuweisen von Werten zur Spalte berücksichtigt.

Wenn Sie einen ENUM-Wert in einem numerischen Kontext abrufen, wird der Index des Spaltenwerts zurückgegeben. So können Sie beispielsweise numerische Werte wie folgt aus einer ENUM-Spalte abrufen:

mysql> SELECT enum_col+0 FROM tbl_name;

Wenn Sie eine Zahl in einer ENUM-Spalte ablegen, wird diese als Index behandelt, und der mit diesem Index verknüpfte Mitgliedswert wird in der Spalte gespeichert. (Allerdings funktioniert dies nicht bei LOAD DATA, weil diese Anweisung alle Eingaben als Strings behandelt.) Es ist nicht ratsam, eine ENUM-Spalte mit Auflistungswerten zu definieren, die wie Zahlen aussehen, da dies schnell zu Verwirrung führen kann. So hat beispielsweise die folgende Spalte Auflistungswerte mit den String-Werten '0', '1' und '2', aber die numerischen Indexwerte 1, 2 und 3:

numbers ENUM('0','1','2')

ENUM-Werte werden entsprechend der Reihenfolge sortiert, in der sie in der Spaltendefinition aufgeführt wurden. (Anders gesagt: ENUM-Werte werden nach ihren Indexzahlen sortiert.) So wird beispielsweise bei ENUM('a', 'b') 'a' vor 'b' einsortiert, bei ENUM('b', 'a') hingegen wird 'b' vor 'a' einsortiert. Der Leer-String wird immer vor nichtleeren Strings einsortiert, und NULL-Werte werden vor allen anderen Auflistungswerten einsortiert. Um unerwünschte Ergebnisse zu vermeiden, geben Sie die ENUM-Liste am besten in alphabetischer Reihenfolge an. Sie können auch mit GROUP BY CAST(col AS CHAR) oder GROUP BY CONCAT(col) sicherstellen, dass die Spalte lexikalisch statt nach Indexnummer sortiert wird.

Wenn Sie alle möglichen Werte für eine ENUM-Spalte bestimmen wollen, verwenden Sie SHOW COLUMNS FROM tbl_name LIKE enum_col und verarbeiten die ENUM-Definition in der Spalte Type der Ausgabe.

11.4.5. Der Spaltentyp SET

Der Datentyp SET (Menge) ist ein String-Objekt, das null oder mehr Werte haben kann. Alle diese Werte entstammen einer Liste zulässiger Werte, die beim Erstellen der Tabelle angegeben werden. Bei SET-Spaltenwerten, die mehrere Mitglieder der Menge umfassen, werden die Mitgliedswerte durch Kommata (‘,’) getrennt angegeben. Hieraus ergibt sich, dass SET-Mitgliedswerte ihrerseits keine Kommata enthalten sollten.

Eine Spalte, die als SET('one', 'two') NOT NULL definiert ist, kann jeden der folgenden Werte annehmen:

''
'one'
'two'
'one,two'

Ein SET kann maximal 64 Mitgliedswerte umfassen.

Beim Erstellen der Tabelle werden bei SET-Mitgliedswerten am Ende stehende Leerzeichen in der Tabellendefinition automatisch entfernt.

Beim Abrufen werden Werte, die in einer SET-Spalte gespeichert sind, in der Groß-/Kleinschreibung angezeigt, die bei der Spaltendefinition verwendet wurde. Beachten Sie, dass SET-Spalten ein Zeichensatz und eine Sortierung zugewiesen werden können. Bei binären Sortierungen oder solchen, bei denen die Groß-/Kleinschreibung unterschieden wird, wird die Schreibweise beim Zuweisen von Werten zur Spalte berücksichtigt.

MySQL speichert SET-Werte numerisch, wobei das niederwertige Bit des gespeicherten Werts dem ersten Mitgliedswert der Menge entspricht. Wenn Sie einen SET-Wert in einem numerischen Kontext abrufen, sind die Bits dieses Werts entsprechend den Mitgliedswerten der Menge gesetzt, die den Spaltenwert bilden. So können Sie beispielsweise numerische Werte wie folgt aus einer SET-Spalte abrufen:

mysql> SELECT set_col+0 FROM tbl_name;

Wenn eine Zahl in einer SET-Spalte gespeichert wird, bestimmen die Bits, die in der Binärform der Zahl gesetzt sind, die im Spaltenwert vorhandenen Mitglieder. Bei einer Spalte, die als SET('a','b','c','d') definiert ist, haben die Mitglieder die folgenden Dezimal- und Binärwerte:

SET MitgliedswertDezimalwertBinärwert
'a'10001
'b'20010
'c'40100
'd'81000

Wenn Sie dieser Spalte den Wert 9 zuweisen, entspricht dies dem Binärwert 1001, d. h., der erste und der vierte SET-Mitgliedswert ('a' und 'd') werden ausgewählt. Das Ergebnis lautet also 'a,d'.

Bei einem Wert, der mehr als ein SET-Element enthält, spielt es keine Rolle, in welcher Reihenfolge die Elemente beim Einfügen des Werts aufgeführt sind. Ebenso wenig ist relevant, wie häufig ein gegebenes Element in der Liste auftaucht. Wenn der Wert später abgerufen wird, erscheint jedes Element des Werts genau einmal in der Liste, und diese ist in der Reihenfolge sortiert, in der die Mitglieder bei Erstellung der Tabelle aufgeführt wurden. Nehmen wir beispielsweise einmal an, eine Spalte sei als SET('a','b','c','d') definiert:

mysql> CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));

Nun fügen Sie die Werte 'a,d', 'd,a', 'a,d,d', 'a,d,a' und 'd,a,d' ein:

mysql> INSERT INTO myset (col) VALUES 
-> ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0

Beim Abrufen erscheinen alle diese Werte als 'a,d':

mysql> SELECT col FROM myset;
+------+
| col  |
+------+
| a,d  |
| a,d  |
| a,d  |
| a,d  |
| a,d  |
+------+
5 rows in set (0.04 sec)

Wenn Sie eine SET-Spalte auf einen nicht unterstützten Wert setzen, wird dieser ignoriert, und es wird eine Warnung ausgegeben:

mysql> INSERT INTO myset (col) VALUES ('a,d,d,s');
Query OK, 1 row affected, 1 warning (0.03 sec)

mysql> SHOW WARNINGS;
+---------+------+------------------------------------------+
| Level   | Code | Message                                  |
+---------+------+------------------------------------------+
| Warning | 1265 | Data truncated for column 'col' at row 1 |
+---------+------+------------------------------------------+
1 row in set (0.04 sec)

mysql> SELECT col FROM myset;
+------+
| col  |
+------+
| a,d  |
| a,d  |
| a,d  |
| a,d  |
| a,d  |
| a,d  |
+------+
6 rows in set (0.01 sec)

Wenn der strikte SQL-Modus aktiviert ist, führen Versuche, ungültige SET-Werte einzufügen, zu einer Fehlermeldung.

SET-Werte werden numerisch sortiert. NULL-Werte werden dabei vor Nicht-NULL-Werten einsortiert.

Meist werden Sie SET-Werte mithilfe der Funktion FIND_IN_SET() oder des Operators LIKE durchsuchen:

mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';

Die erste Anweisung findet Datensätze, bei denen set_col den Mitgliedswert value enthält. Die zweite ist ähnlich, aber nicht identisch: Sie findet Datensätze, bei denen set_col value an beliebiger Stelle (auch als Teil-String eines anderen Mitglieds) enthält.

Die folgenden Anweisungen sind ebenfalls zulässig:

mysql> SELECT * FROM tbl_name WHERE set_col & 1;
mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';

Die erste Anweisung sucht nach Werten, die das erste Mitglied der Menge enthalten. Die zweite sucht nach einer exakten Übereinstimmung. Seien Sie bei Vergleichen des zweiten Typs vorsichtig. Der Vergleich von Mengenwerten mit 'val1,val2' gibt andere Resultate zurück als der Vergleich mit 'val2,val1'. Sie sollten die Werte in derselben Reihenfolge angeben, in der sie in der Spaltendefinition aufgelistet sind.

Wenn Sie alle möglichen Werte für eine SET-Spalte bestimmen wollen, verwenden Sie SHOW COLUMNS FROM tbl_name LIKE set_col und verarbeiten die SET-Definition in der Spalte Type der Ausgabe.

11.5. Speicherbedarf von Spaltentypen

Die Speicheranforderungen der einzelnen von MySQL unterstützten Datentypen sind nachfolgend nach Kategorie sortiert aufgelistet.

Die maximale Größe eines Datensatzes in einer MyISAM-Tabelle beträgt 65.534 Byte. Jede BLOB- oder TEXT-Spalte trägt nur zwischen 5 und 9 Byte zu dieser Größe bei.

Speicheranforderungen für numerische Typen

DatentypErforderlicher Speicherplatz
TINYINT1 Byte
SMALLINT2 Byte
MEDIUMINT3 Byte
INT, INTEGER4 Byte
BIGINT8 Byte
FLOAT(p)4 Byte, sofern 0 <= p <= 24; 8 Byte, sofern 25 <= p <= 53
FLOAT4 Byte
DOUBLE [PRECISION], REAL8 Byte
DECIMAL(M,D), NUMERIC(M,D)Variiert (siehe nachfolgende Beschreibung)
BIT(M)ca. (M+7) ÷ 8 Byte

Werte für DECIMAL-Spalten (und auch für NUMERIC-Spalten) werden in einem Binärformat dargestellt, das 9 Dezimalstellen (Basis 10) mit 4 Byte repräsentiert. Die Speicheranforderungen für ganzzahlige und Bruchteile eines Werts werden separat bestimmt. Jedes Vielfache von 9 Stellen erfordert 4 Byte, und die „restlichen“ Stellen erfordern einen Bruchteil von 4 Byte. Der für überzählige Stellen erforderliche Speicherplatz ist in der folgenden Tabelle angegeben:

Überzählige StellenAnzahl Bytes
00
11
21
32
42
53
63
74
84
94

Speicheranforderungen für Datums- und Uhrzeittypen

DatentypErforderlicher Speicherplatz
DATE3 Byte
DATETIME8 Byte
TIMESTAMP4 Byte
TIME3 Byte
YEAR1 Byte

Speicheranforderungen für String-Typen

DatentypErforderlicher Speicherplatz
CHAR(M)M Bytes, 0 <= M <= 255
VARCHAR(M)L + 1 Byte, wobei L <= M und 0 <= M <= 255 (siehe nachfolgender Hinweis) or L + 2 Byte, wobei L <= M und 256 <= M <= 65535 (siehe nachfolgender Hinweis)
BINARY(M)M Bytes, 0 <= M <= 255
VARBINARY(M)L + 1 Byte, wobei L <= M und 0 <= M <= 255 (siehe nachfolgender Hinweis) or L + 2 Byte, wobei L <= M und 256 <= M <= 65535 (siehe nachfolgender Hinweis)
TINYBLOB, TINYTEXTL+1 Byte, wobei L < 28
BLOB, TEXTL+2 Byte, wobei L < 216
MEDIUMBLOB, MEDIUMTEXTL+3 Byte, wobei L < 224
LONGBLOB, LONGTEXTL+4 Byte, wobei L < 232
ENUM('value1','value2',...)1 oder 2 Byte, abhängig von der Anzahl der Auflistungswerte (maximal 65.535)
SET('value1','value2',...)1, 2, 3, 4 oder 8 Byte, abhängig von der Anzahl der Mitglieder der Menge (maximal 64)

Bei den Typen CHAR, VARCHAR und TEXT sollten die Werte L und M in obiger Tabelle als Anzahl der Zeichen aufgefasst werden. Längen für diese Typen in der Spaltendefinition geben die Anzahl der Zeichen an. Um beispielsweise einen TINYTEXT-Wert zu speichern, benötigen Sie L Zeichen plus 1 Byte.

VARCHAR und die VARBINARY- und BLOB- und TEXT-Typen haben jeweils variable Längen. Bei ihnen hängen die Speicheranforderungen von den folgenden Faktoren ab:

  • der tatsächlichen Länge des Spaltenwerts

  • der maximal zulässigen Länge der Spalte

  • dem für die Spalte verwendeten Zeichensatz

Eine VARCHAR(10)-Spalte beispielsweise kann einen String mit einer maximalen Länge von 10 aufnehmen. Wenn man voraussetzt, dass die Spalte den Zeichensatz latin1 verwendet (bei dem jedes Zeichen durch 1 Byte dargestellt wird), dann entspricht die tatsächliche Speicheranforderung der Länge des Strings (L) zuzüglich eines Bytes zur Angabe der String-Länge. Beim String 'abcd' ist L 4, und der Speicherbedarf beträgt 5 Byte. Wenn dieselbe Spalte stattdessen als VARCHAR(500) deklariert würde, dann benötigte der String 'abcd' 4 + 2 = 6 Bytes. Es werden 2 Byte (statt nur eines) für das Präfix benötigt, da die Länge der Spalte größer als 255 Zeichen ist.

Um die Anzahl der Bytes zu berechnen, die zur Speicherung eines bestimmten CHAR-, VARCHAR- oder TEXT-Spaltenwerts benötigt werden, müssen Sie den Zeichensatz der betreffenden Spalte in Betracht ziehen. Dies gilt insbesondere bei Verwendung des utf8-Unicode-Zeichensatzes: Hierbei ist darauf zu achten, dass nicht alle utf8-Zeichen dieselbe Anzahl Bytes verwenden. Eine Auflistung der Speicheranforderungen verschiedener Kategorien von utf8-Zeichen finden Sie in Abschnitt 10.7, „Unicode-Unterstützung“.

Hinweis: Die effektive Maximallänge einer VARCHAR- oder VARBINARY-Spalte beträgt 65.532.

Die NDBCLUSTER-Speicher-Engine in MySQL 5.1 unterstützt echte Spalten variabler Breite. Das bedeutet, dass eine VARCHAR-Spalte in einer MySQL-Cluster-Tabelle dieselbe Menge Speicher benötigt, die sie bei Verwendung einer beliebigen anderen Speicher-Engine erfordern würde. Dieses Verhalten unterscheidet sich von dem früherer Versionen von NDBCLUSTER.

Die Typen BLOB und TEXT erfordern je nach maximal möglicher Länge des Datentyps 1 bis 4 Byte zur Aufnahme des Spaltenwerts. Siehe auch Abschnitt 11.4.3, „Die Spaltentypen BLOB und TEXT.

TEXT- und BLOB-Spalten sind in der NDBCLUSTER-Speicher-Engine unterschiedlich implementiert. Dabei besteht jeder Datensatz in einer TEXT-Spalte aus zwei separaten Teilen. Der eine Teil hat eine feste Größe von 256 Byte und wird tatsächlich in der Ursprungstabelle gespeichert. Der andere besteht aus den Daten, die den Umfang von 256 Byte überschreiten. Diese werden in einer verborgenen Tabelle gespeichert. Die Datensätze in dieser zweiten Tabelle sind immer 2.000 Byte lang. Das bedeutet, dass die Größe einer TEXT-Spalte 256 beträgt, wenn size <= 256 (wobei size die Größe des Datensatzes darstellt); andernfalls beträgt die Größe 256 + size + (2000 – (size – 256) % 2000).

Die Größe eines ENUM-Objekts wird anhand der Anzahl verschiedener Auflistungswerte bestimmt. Ein Byte wird für Auflistungen mit bis zu 255 möglichen Werten benötigt. 2 Byte sind für Auflistungen erforderlich, die zwischen 256 und 65.535 mögliche Werte besitzen. Siehe auch Abschnitt 11.4.4, „Der Spaltentyp ENUM.

Die Größe eines SET-Objekts wird anhand der Anzahl verschiedener Mitglieder der Menge bestimmt. Wenn die Größe der Menge N ist, dann benötigt das Objekt (N+7)/8 Byte, gerundet auf 1, 2, 3, 4 oder 8 Byte. Ein SET kann maximal 64 Mitgliedswerte umfassen. Siehe auch Abschnitt 11.4.5, „Der Spaltentyp SET.

11.6. Auswahl des richtigen Datentyps für eine Spalte

Um den Speicher optimal zu nutzen, sollten Sie in allen Fällen den geeignetsten Datentyp auswählen. Wird eine Integer-Spalte etwa für Werte im Bereich zwischen 1 und 99999 verwendet, dann ist MEDIUMINT UNSIGNED als Typ am besten geeignet. Von allen Typen, die alle erforderlichen Werte darstellen können, verwendet dieser Typ am wenigsten Speicher.

Berechnungen in den Grundrechenarten (+,-,*,/) erfolgen bei DECIMAL-Spalten stets mit einer Genauigkeit von 65 Dezimalstellen (Basis 10). Siehe auch Abschnitt 11.1.1, „Überblick über numerische Datentypen“.

Für Berechnungen mit DECIMAL-Werten werden Operationen mit doppelter Genauigkeit verwendet. Sofern die Genauigkeit nicht zu wichtig ist oder Geschwindigkeit die höchste Priorität hat, kann der Typ DOUBLE unter Umständen ausreichend sein. Für eine hohe Genauigkeit können Sie jederzeit eine Konvertierung in einen Festkommatyp durchführen, der als BIGINT gespeichert wird. Dies ermöglicht Ihnen die Durchführung aller Berechnungen mit 64-Bit-Integers und nachfolgend ggf. die Rückkonvertierung der Ergebnisse in Fließkommawerte.

11.7. Verwendung von Datentypen anderer Datenbanken

Um die Verwendung von Code zu erleichtern, den andere Anbieter für SQL-Implementierungen geschrieben haben, ordnet MySQL Datentypen entsprechend der folgenden Tabelle zu. Diese Zuordnungen vereinfachen den Import von Tabellendefinitionen aus anderen Datenbanksystemen in MySQL:

Datentyp bei anderem AnbieterTyp bei MySQL
BOOL,TINYINT
BOOLEANTINYINT
CHAR VARYING(M)VARCHAR(M)
DECDECIMAL
FIXEDDECIMAL
FLOAT4FLOAT
FLOAT8DOUBLE
INT1TINYINT
INT2SMALLINT
INT3MEDIUMINT
INT4INT
INT8BIGINT
LONG VARBINARYMEDIUMBLOB
LONG VARCHARMEDIUMTEXT
LONGMEDIUMTEXT
MIDDLEINTMEDIUMINT
NUMERICDECIMAL

Die Datentypzuordnung erfolgt zum Zeitpunkt der Tabellenerstellung. Nachfolgend werden die ursprünglichen Typenspezifikationen verworfen. Wenn Sie eine Tabelle mit von anderen Anbietern verwendeten Typen erstellen und dann eine DESCRIBE tbl_name-Anweisung absetzen, meldet MySQL die Tabellenstruktur unter Verwendung der gleichwertigen MySQL-Typen. Zum Beispiel:

mysql> CREATE TABLE t (a BOOL, b FLOAT8, c LONG VARCHAR, d NUMERIC);
Query OK, 0 rows affected (0.00 sec)

mysql> DESCRIBE t;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| a     | tinyint(1)    | YES  |     | NULL    |       |
| b     | double        | YES  |     | NULL    |       |
| c     | mediumtext    | YES  |     | NULL    |       |
| d     | decimal(10,0) | YES  |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

Kapitel 12. Funktionen für die Benutzung in SELECT- und WHERE-Klauseln

Ausdrücke können an mehreren Stellen in MySQL-Anweisungen verwendet werden, so etwa in den ORDER BY- oder HAVING-Klauseln von SELECT-Anweisungen, in der WHERE-Klausel einer SELECT-, DELETE- oder UPDATE-Anweisung oder in SET-Anweisungen. Ausdrücke können unter Verwendung von literalen Werten, Spaltenwerten, NULL, integrierten Funktionen, gespeicherten Funktionen, benutzerdefinierten Funktionen und Operatoren geschrieben werden. Dieses Kapitel beschreibt die Funktionen und Operatoren, die für das Formulieren von Ausdrücken in MySQL zulässig sind. Hinweise zum Schreiben gespeicherter und benutzerdefinierter Funktionen finden Sie in Kapitel 19, Gespeicherte Prozeduren und Funktionen, und Abschnitt 26.3, „Hinzufügen neuer Funktionen zu MySQL“.

Ein Ausdruck, der NULL enthält, erzeugt immer einen NULL-Wert, sofern in der Dokumentation zur betreffenden Funktion bzw. zum Operator nichts anderes angegeben ist.

Hinweis: Standardmäßig darf kein Whitespace zwischen einem Funktionsnamen und der ihm folgenden Klammer stehen. Auf diese Weise kann der MySQL-Parser zwischen Funktionsaufrufen und Referenzierungen von Tabellen oder Spalten unterscheiden, die den gleichen Namen wie die Funktion haben. Die Funktionsargumente umgebenden Leerzeichen sind hingegen zulässig.

Sie können den MySQL Server anweisen, Leerzeichen nach Funktionsnamen zu akzeptieren, indem Sie beim Start die Option --sql-mode=IGNORE_SPACE angeben. (Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.) Einzelne Clientprogramme können dieses Verhalten anfordern, indem sie die Option CLIENT_IGNORE_SPACE für mysql_real_connect() angeben. In beiden Fällen werden alle Funktionsnamen zu reservierten Wörtern.

Um Weitschweifigkeiten zu verhindern, stellen die meisten Beispiele in diesem Kapitel die Ausgabe von mysql in gekürzter Form dar. Die folgende Ausgabe zeigt das vollständige Format:

mysql> SELECT MOD(29,9);
+-----------+
| mod(29,9) |
+-----------+
|         2 |
+-----------+
1 rows in set (0.00 sec)

Stattdessen benutzen wir jedoch folgende Ausgabe:

mysql> SELECT MOD(29,9);
        -> 2

12.1. Operatoren

12.1.1. Rangfolge von Operatoren

Die folgende Liste zeigt die Rangordnung der Operatoren in umgekehrter Reihenfolge. Operatoren in der gleichen Zeile haben die gleiche Rangstufe.

:=
||, OR, XOR
&&, AND
NOT
BETWEEN, CASE, WHEN, THEN, ELSE
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
&
<<, >>
-, +
*, /, DIV, %, MOD
^
- (unary minus), ~ (unary bit inversion)
!
BINARY, COLLATE

Hinweis: Wenn der SQL-Modus HIGH_NOT_PRECEDENCE aktiviert ist, entspricht die Rangstufe von NOT der des Operators !. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

Die Abfolge der Operatoren bestimmt die Auswertungsreihenfolge der Begriffe in einem Ausdruck. Um diese Reihenfolge außer Kraft zu setzen und Begriffe explizit zu gruppieren, verwenden Sie Klammern. Zum Beispiel:

mysql> SELECT 1+2*3;
        -> 7
mysql> SELECT (1+2)*3;
        -> 9

12.1.2. Typumwandlung bei der Auswertung von Ausdrücken

Wenn ein Operator mit Operanden verschiedener Typen verwendet wird, findet eine Typenkonvertierung statt, um die Operanden kompatibel zu machen. Einige Konvertierungen treten implizit auf. So wandelt MySQL beispielsweise Zahlen nach Bedarf in Strings um und umgekehrt.

mysql> SELECT 1+'1';
        -> 2
mysql> SELECT CONCAT(2,' test');
        -> '2 test'

Es ist auch möglich, explizite Konvertierungen durchzuführen. Wenn Sie eine Zahl explizit in einen String umwandeln wollen, verwenden Sie die Funktionen CAST() oder CONCAT() (wobei CAST() vorzuziehen ist):

mysql> SELECT 38.8, CAST(38.8 AS CHAR);
        -> 38.8, '38.8'
mysql> SELECT 38.8, CONCAT(38.8);
        -> 38.8, '38.8'

Die folgenden Regeln beschreiben, wie die Konvertierung bei Vergleichsoperationen erfolgt:

  • Wenn eines der Argumente (oder beide) NULL ist, dann ist das Vergleichsergebnis NULL. Eine Ausnahme ist der NULL-sichere Gleichheitsoperator <=>. Bei NULL <=> NULL ist das Ergebnis wahr.

  • Wenn beide Argumente in einer Vergleichsoperation Strings sind, werden sie als Strings verglichen.

  • Sind beide Argumente Integers, dann werden sie als Integers verglichen.

  • Hexadezimalwerte werden als binäre Strings behandelt, wenn sie nicht mit einer Zahl verglichen werden.

  • Wenn eines der Argumente eine TIMESTAMP- oder DATETIME-Spalte und das andere Argument eine Konstante ist, dann wird die Konstante vor Durchführung des Vergleichs in einen Zeitstempel umgewandelt. Dies erhöht die ODBC-Kompatibilität. Beachten Sie jedoch, dass dies nicht bei Argumenten für IN() gemacht wird! Um ganz sicher zu sein, sollten Sie bei Vergleichen immer vollständige Strings für Datum und/oder Uhrzeit verwenden.

  • In allen anderen Fällen werden die Argumente als Fließkommazahlen (reale Zahlen) verglichen.

Die folgenden Beispiele veranschaulichen die Konvertierung von Strings in Zahlen für Vergleichsoperationen:

mysql> SELECT 1 > '6x';
        -> 0
mysql> SELECT 7 > '6x';
        -> 1
mysql> SELECT 0 > 'x6';
        -> 0
mysql> SELECT 0 = 'x6';
        -> 1

Beachten Sie, dass, wenn Sie eine String-Spalte mit einer Zahl vergleichen, MySQL keinen Index für die Spalte verwenden kann, um den Wert schnell abzurufen. Ist str_col eine indizierte String-Spalte, dann kann der Index nicht verwendet werden, um für die folgende Anweisung eine Suche durchzuführen:

SELECT * FROM tbl_name WHERE str_col=1;

Dies liegt daran, dass es viele verschiedene Strings gibt, die in den Wert 1 konvertiert werden: '1', ' 1', '1a', …

12.1.3. Vergleichsoperatoren

Vergleichsoperationen haben einen der Werte 1 (TRUE), 0 (FALSE) oder NULL zum Ergebnis. Diese Operationen funktionieren bei Zahlen und Strings gleichermaßen: Nach Bedarf werden Strings in Zahlen und Zahlen in Strings umgewandelt.

Einige der in diesem Abschnitt beschriebenen Funktionen (z. B. LEAST() und GREATEST()) geben andere Werte als 1 (TRUE), 0 (FALSE) oder NULL zurück. Der Rückgabewert basiert jedoch auf Vergleichsoperationen, die entsprechend den in Abschnitt 12.1.2, „Typumwandlung bei der Auswertung von Ausdrücken“ beschriebenen Regeln durchgeführt wurden.

Um einen Wert zu Vergleichszwecken in einen beliebigen Typ zu konvertieren, können Sie die Funktion CAST() verwenden. String-Werte lassen sich mithilfe von CONVERT() in einen anderen Zeichensatz konvertieren. Siehe auch Abschnitt 12.8, „Cast-Funktionen und Operatoren“.

Standardmäßig wird die Groß-/Kleinschreibung bei String-Vergleichen nicht unterschieden. Ferner wird hierbei der aktuelle Zeichensatz verwendet. Die Vorgabe ist latin1 (cp1252 West European). Dieser Zeichensatz ist auch für Deutsch geeignet.

  • =

    Gleich:

    mysql> SELECT 1 = 0;
            -> 0
    mysql> SELECT '0' = 0;
            -> 1
    mysql> SELECT '0.0' = 0;
            -> 1
    mysql> SELECT '0.01' = 0;
            -> 0
    mysql> SELECT '.01' = 0.01;
            -> 1
    
  • <=>

    NULL-sicheres Gleich. Dieser Operator führt ebenso wie = eine Vergleichsoperation durch, gibt aber 1 statt NULL zurück, wenn beide Operanden NULL sind, und 0 statt NULL, wenn einer der Operanden NULL ist.

    mysql> SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
            -> 1, 1, 0
    mysql> SELECT 1 = 1, NULL = NULL, 1 = NULL;
            -> 1, NULL, NULL
    
  • <>, !=

    Ungleich:

    mysql> SELECT '.01' <> '0.01';
            -> 1
    mysql> SELECT .01 <> '0.01';
            -> 0
    mysql> SELECT 'zapp' <> 'zappp';
            -> 1
    
  • <=

    Kleiner oder gleich:

    mysql> SELECT 0.1 <= 2;
            -> 1
    
  • <

    Kleiner als:

    mysql> SELECT 2 < 2;
            -> 0
    
  • >=

    Größer oder gleich:

    mysql> SELECT 2 >= 2;
            -> 1
    
  • >

    Größer als:

    mysql> SELECT 2 > 2;
            -> 0
    
  • IS boolean_value, IS NOT boolean_value

    Vergleicht einen Wert mit einem booleschen Wert, wobei boolean_value TRUE, FALSE oder UNKNOWN sein kann.

    mysql> SELECT 1 IS TRUE, 0 IS FALSE, NULL IS UNKNOWN;
            -> 1, 1, 1
    mysql> SELECT 1 IS NOT UNKNOWN, 0 IS NOT UNKNOWN, NULL IS NOT UNKNOWN;
            -> 1, 1, 0
    
  • IS NULL, IS NOT NULL

    Prüft, ob ein Wert NULL ist oder nicht.

    mysql> SELECT 1 IS NULL, 0 IS NULL, NULL IS NULL;
            -> 0, 0, 1
    mysql> SELECT 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;
            -> 1, 1, 0
    

    Zum Zwecke der Kompatibilität mit ODBC-Programmen unterstützt MySQL die folgenden Zusatzfunktionen bei der Verwendung von IS NULL:

    • Sie können den Datensatz, der den aktuellen AUTO_INCREMENT-Wert enthält, durch Absetzen einer Anweisung der folgenden Form unmittelbar nach Erzeugung des Werts ermitteln:

      SELECT * FROM tbl_name WHERE auto_col IS NULL
      

      Dieses Verhalten kann mithilfe von SQL_AUTO_IS_NULL=0 deaktiviert werden. Siehe auch Abschnitt 13.5.3, „SET.

    • Bei DATE- und DATETIME- Spalten, die als NOT NULL deklariert sind, können Sie das Sonderdatum '0000-00-00' mithilfe einer Anweisung wie der folgenden ermitteln:

      SELECT * FROM tbl_name WHERE date_column IS NULL
      

      Dies ist erforderlich, um einige ODBC-Anwendungen zum Laufen zu bringen, weil ODBC den Datumswert '0000-00-00' nicht unterstützt.

  • expr BETWEEN min AND max

    Wenn expr größer oder gleich min und expr kleiner oder gleich max ist, gibt BETWEEN 1 zurück, andernfalls 0. Dies ist äquivalent zu dem Ausdruck (min<= expr AND expr<= max), sofern alle Argumente vom selben Typ sind. Andernfalls findet die Typenkonvertierung entsprechend den in Abschnitt 12.1.2, „Typumwandlung bei der Auswertung von Ausdrücken“, beschriebenen Regeln statt, wird aber auf alle drei Argumente angewendet.

    mysql> SELECT 1 BETWEEN 2 AND 3;
            -> 0
    mysql> SELECT 'b' BETWEEN 'a' AND 'c';
            -> 1
    mysql> SELECT 2 BETWEEN 2 AND '3';
            -> 1
    mysql> SELECT 2 BETWEEN 2 AND 'x-3';
            -> 0
    
  • expr NOT BETWEEN min AND max

    Dies ist das Gleiche wie NOT (expr BETWEEN min AND max).

  • COALESCE(value,...)

    Gibt den ersten Nicht-NULL-Wert in der Liste oder aber NULL zurück, sofern keine Nicht-NULL-Werte vorhanden sind.

    mysql> SELECT COALESCE(NULL,1);
            -> 1
    mysql> SELECT COALESCE(NULL,NULL,NULL);
            -> NULL
    
  • GREATEST(value1,value2,...)

    Gibt von zwei oder mehr Argumenten das größte (d. h. das mit dem höchsten Wert) zurück. Die Argumente werden nach denselben Regeln wie bei LEAST() verglichen.

    mysql> SELECT GREATEST(2,0);
            -> 2
    mysql> SELECT GREATEST(34.0,3.0,5.0,767.0);
            -> 767.0
    mysql> SELECT GREATEST('B','A','C');
            -> 'C'
    

    GREATEST() gibt NULL zurück, sofern ein Argument NULL ist.

  • expr IN (value,...)

    Gibt 1 zurück, wenn expr gleich einem der Werte in der IN-Liste ist, andernfalls wird 0 zurückgegeben. Wenn alle Werte Konstanten sind, werden sie entsprechend dem Typ von expr ausgewertet und sortiert. Nachfolgend erfolgt die Suche nach dem Element unter Verwendung einer binären Suche. Das heißt auch, dass IN sehr schnell ist, wenn die IN-Werteliste ausschließlich aus Konstanten besteht. Andernfalls findet die Typenkonvertierung entsprechend den in Abschnitt 12.1.2, „Typumwandlung bei der Auswertung von Ausdrücken“, beschriebenen Regeln statt, wird aber auf alle Argumente angewendet.

    mysql> SELECT 2 IN (0,3,5,'wefwf');
            -> 0
    mysql> SELECT 'wefwf' IN (0,3,5,'wefwf');
            -> 1
    

    Die Anzahl der Werte in der IN-Liste wird nur durch den Wert von max_allowed_packet beschränkt.

    Um mit dem SQL-Standard konform zu gehen, gibt IN NULL nicht nur dann zurück, wenn der Ausdruck auf der linken Seite NULL ist, sondern auch dann, wenn keine Übereinstimmung in der Liste gefunden wird und einer der Ausdrücke in der Liste NULL ist.

    Die IN()-Syntax kann auch zum Schreiben verschiedener Arten von Unterabfragen verwendet werden. Siehe auch Abschnitt 13.2.8.3, „Unterabfragen mit ANY, IN und SOME.

  • expr NOT IN (value,...)

    Dies ist das Gleiche wie NOT (expr IN (value,...)).

  • ISNULL(expr)

    Wenn expr NULL ist, gibt ISNULL() 1 zurück, andernfalls 0.

    mysql> SELECT ISNULL(1+1);
            -> 0
    mysql> SELECT ISNULL(1/0);
            -> 1
    

    ISNULL() kann anstelle von = verwendet werden, um zu überprüfen, ob ein Wert NULL ist. (Der Vergleich eines Werts mit NULL unter Verwendung von = gibt immer FALSE aus.)

    Die Funktion ISNULL() weist einige spezielle Eigenschaften des Vergleichsoperators IS NULL auf. Siehe auch die Beschreibung zu IS NULL.

  • INTERVAL(N,N1,N2,N3,...)

    Gibt 0 zurück, wenn N < N1 ist, 1, wenn N < N2 usw., oder -1, wenn N NULL ist. Alle Argumente werden als Integers behandelt. Es ist erforderlich, dass N1 < N2 < N3 < ... < Nn ist, damit diese Funktion einwandfrei arbeitet. Das liegt daran, dass eine binäre (und damit sehr schnelle) Suche verwendet wird.

    mysql> SELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);
            -> 3
    mysql> SELECT INTERVAL(10, 1, 10, 100, 1000);
            -> 2
    mysql> SELECT INTERVAL(22, 23, 30, 44, 200);
            -> 0
    
  • LEAST(value1,value2,...)

    Gibt von zwei oder mehr Argumenten das kleinste (d. h. das mit dem niedrigsten Wert) zurück. Die Argumente werden unter Anwendung der folgenden Regeln verglichen:

    • Wenn der Rückgabewert in einem INTEGER-Kontext verwendet wird oder alle Argumente Integer-Werte sind, dann werden sie als Integers verglichen.

    • Wenn der Rückgabewert in einem REAL-Kontext verwendet wird oder alle Argumente reale Zahlen sind, dann werden sie als reale Zahlen verglichen.

    • Ist ein Argument ein String mit Unterscheidung der Groß-/Kleinschreibung, dann werden die Argumente als Strings mit Unterscheidung der Groß-/Kleinschreibung verglichen.

    • In allen anderen Fällen werden die Argumente als Strings ohne Unterscheidung der Groß-/Kleinschreibung verglichen.

    LEAST() gibt NULL zurück, sofern ein Argument NULL ist.

    mysql> SELECT LEAST(2,0);
            -> 0
    mysql> SELECT LEAST(34.0,3.0,5.0,767.0);
            -> 3.0
    mysql> SELECT LEAST('B','A','C');
            -> 'A'
    

    Beachten Sie, dass die oben beschriebenen Konvertierungsregeln in einigen Grenzfällen fragwürdige Ergebnisse erzeugen können:

    mysql> SELECT CAST(LEAST(3600, 9223372036854775808.0) as SIGNED);
            -> -9223372036854775808
    

    Dies passiert, weil MySQL 9223372036854775808.0 in einem Integer-Kontext liest. Das Integer-Format ist aber nicht geeignet, den Wert darzustellen, d. h., er wird in einen vorzeichenbehafteten Integer umgewandelt.

12.1.4. Logische Operatoren

In SLQ werden alle logischen Operatoren als TRUE, FALSE oder NULL (UNKNOWN) ausgewertet. In MySQL ist dies als 1 (TRUE), 0 (FALSE) und NULL implementiert. Dies ist größtenteils auf den verschiedenen SQL-Datenbankservern identisch, auch wenn einige Server einen beliebigen Nichtnullwert für TRUE zurückgeben.

  • NOT, !

    Logisches NOT (NICHT). Wird zu 1, wenn der Operand 0 ist, und zu 0, wenn der Operand nicht null ist. NOT NULL gibt NULL zurück.

    mysql> SELECT NOT 10;
            -> 0
    mysql> SELECT NOT 0;
            -> 1
    mysql> SELECT NOT NULL;
            -> NULL
    mysql> SELECT ! (1+1);
            -> 0
    mysql> SELECT ! 1+1;
            -> 1
    

    Das letzte Beispiel erzeugt 1, weil der Ausdruck auf die gleiche Weise ausgewertet wird wie (!1)+1.

  • AND, &&

    Logisches AND (UND). Gibt 1 zurück, wenn alle Operanden weder null noch NULL sind; wenn ein oder mehr Operanden 0 sind, wird 0 zurückgegeben, andernfalls NULL.

    mysql> SELECT 1 && 1;
            -> 1
    mysql> SELECT 1 && 0;
            -> 0
    mysql> SELECT 1 && NULL;
            -> NULL
    mysql> SELECT 0 && NULL;
            -> 0
    mysql> SELECT NULL && 0;
            -> 0
    
  • OR, ||

    Logisches OR (ODER). Wenn beide Operanten nicht NULL sind, ist das Ergebnis 1, sofern ein beliebiger Operand nicht null ist, andernfalls 0. Bei einem NULL-Operanden ist das Ergebnis 1, wenn der andere Operand nicht null ist, andernfalls ist es NULL. Sind beide Operanden NULL, dann ist das Ergebnis NULL.

    mysql> SELECT 1 || 1;
            -> 1
    mysql> SELECT 1 || 0;
            -> 1
    mysql> SELECT 0 || 0;
            -> 0
    mysql> SELECT 0 || NULL;
            -> NULL
    mysql> SELECT 1 || NULL;
            -> 1
    
  • XOR

    Logisches XOR (exklusives ODER). Gibt NULL zurück, wenn ein Operand NULL ist. Bei Nicht-NULL-Operanden wird 1 zurückgegeben, wenn eine ungerade Anzahl von Operanden nicht null ist, andernfalls wird 0 zurückgegeben.

    mysql> SELECT 1 XOR 1;
            -> 0
    mysql> SELECT 1 XOR 0;
            -> 1
    mysql> SELECT 1 XOR NULL;
            -> NULL
    mysql> SELECT 1 XOR 1 XOR 1;
            -> 1
    

    a XOR b ist mathematisch identisch mit (a AND (NOT b)) OR ((NOT a) and b).

12.2. Ablaufsteuerungsfunktionen

  • CASE value WHEN [compare_value] THEN result [WHEN [compare_value] THEN result ...] [ELSE result] END

    CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END

    Die erste Version gibt result zurück, wobei gilt: value=compare_value. Die zweite Version gibt das Ergebnis der ersten Bedingung zurück, die wahr ist. Wenn kein passender Ergebniswert existiert, wird das Ergebnis nach ELSE oder aber NULL (sofern kein ELSE-Teil vorhanden ist) zurückgegeben.

    mysql> SELECT CASE 1 WHEN 1 THEN 'one'
        ->     WHEN 2 THEN 'two' ELSE 'more' END;
            -> 'one'
    mysql> SELECT CASE WHEN 1>0 THEN 'true' ELSE 'false' END;
            -> 'true'
    mysql> SELECT CASE BINARY 'B'
        ->     WHEN 'a' THEN 1 WHEN 'b' THEN 2 END;
            -> NULL
    

    Der vorgabeseitige Rückgabetyp eines CASE-Ausdrucks ist der kompatible zusammengefasste Typ aller Rückgabewerte, hängt aber auch vom Kontext ab, in dem er verwendet wird. Bei Verwendung in einem String-Kontext wird das Ergebnis als String zurückgegeben. Bei Verwendung in einem numerischen Kontext wird das Ergebnis als Dezimalwert, reale Zahl oder Integer-Wert zurückgegeben.

    Hinweis: Die hier gezeigte Syntax des CASE-Ausdrucks unterscheidet sich ein wenig von der SQL-Syntax der CASE-Anweisung, wie sie in Abschnitt 19.2.10.2, „CASE-Anweisung“, zur Verwendung in gespeicherten Routinen beschrieben wird. Die CASE-Anweisung kann keine ELSE NULL-Klausel haben und wird mit END CASE anstelle von END abgeschlossen.

  • IF(expr1,expr2,expr3)

    Wenn expr1 TRUE ist (expr1<> 0 und expr1 <> NULL), dann gibt IF() expr2 zurück; andernfalls gibt es expr3 zurück. IF() gibt je nach Verwendungskontext einen numerischen oder einen String-Wert zurück.

    mysql> SELECT IF(1>2,2,3);
            -> 3
    mysql> SELECT IF(1<2,'yes','no');
            -> 'yes'
    mysql> SELECT IF(STRCMP('test','test1'),'no','yes');
            -> 'no'
    

    Ist nur einer der Ausdrücke expr2 oder expr3 explizit NULL, dann ist der Ergebnistyp der IF()-Funktion der Typ des Nicht-NULL-Ausdrucks.

    expr1 wird als Integer-Wert ausgewertet, d. h., wenn Sie Fließkomma- oder String-Werte prüfen, sollten Sie dies mit einer Vergleichsoperation tun.

    mysql> SELECT IF(0.1,1,0);
            -> 0
    mysql> SELECT IF(0.1<>0,1,0);
            -> 1
    

    Im ersten gezeigten Fall gibt IF(0.1) 0 zurück, weil 0.1 in einen Integer-Wert konvertiert wird, was zur Prüfung von IF(0) führt. Dies ist unter Umständen nicht das, was Sie erwarten. Im zweiten Fall prüft der Vergleich den ursprünglichen Fließkommawert, um festzustellen, ob dieser nicht null ist. Das Ergebnis des Vergleichs wird als Integer verwendet.

    Der Standardrückgabetyp von IF() (der wichtig sein kann, wenn er in einer Temporärtabelle gespeichert wird) wird wie folgt berechnet:

    AusdruckRückgabewert
    expr2 oder expr3 gibt einen String zurückString
    expr2 oder expr3 gibt einen Fließkommawert zurückFließkommazahl
    expr2 oder expr3 gibt einen Integer zurückInteger

    Wenn sowohl expr2 als auch expr3 Strings sind, wird beim Ergebnis die Groß-/Kleinschreibung unterschieden, sofern dies bei einem der Strings ebenfalls der Fall ist.

    Hinweis: Es gibt auch eine IF-Anweisung, die sich von der hier beschriebenen IF()-Funktion unterscheidet. Siehe auch Abschnitt 19.2.10.1, „IF-Anweisung“.

  • IFNULL(expr1,expr2)

    Wenn expr1 nicht NULL ist, gibt IFNULL() expr1 zurück; andernfalls wird expr2 zurückgegeben. IFNULL() gibt je nach Verwendungskontext einen numerischen oder einen String-Wert zurück.

    mysql> SELECT IFNULL(1,0);
            -> 1
    mysql> SELECT IFNULL(NULL,10);
            -> 10
    mysql> SELECT IFNULL(1/0,10);
            -> 10
    mysql> SELECT IFNULL(1/0,'yes');
            -> 'yes'
    

    Der Standardergebniswert von IFNULL(expr1,expr2) ist der „allgemeinere“ der beiden Ausdrücke in der Reihenfolge STRING, REAL oder INTEGER. Betrachten Sie den Fall einer auf Ausdrücken basierenden Tabelle oder einen Fall, in dem MySQL einen von IFNULL() zurückgegebenen Wert intern in einer Temporärtabelle speichern muss:

    mysql> CREATE TABLE tmp SELECT IFNULL(1,'test') AS test;
    mysql> DESCRIBE tmp;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | test  | char(4) |      |     |         |       |
    +-------+---------+------+-----+---------+-------+
    

    In diesem Beispiel ist der Typ der Spalte test CHAR(4).

  • NULLIF(expr1,expr2)

    Gibt NULL zurück, wenn expr1 = expr2 wahr ist; andernfalls wird expr1 zurückgegeben. Dies ist das Gleiche wie CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.

    mysql> SELECT NULLIF(1,1);
            -> NULL
    mysql> SELECT NULLIF(1,2);
            -> 1
    

    Beachten Sie, dass MySQL expr1 zweimal auswertet, wenn die Argumente nicht gleich sind.

12.3. String-Funktionen

String-Funktionen geben NULL zurück, wenn die Länge des Ergebnisses größer wäre als der Wert der Systemvariablen max_allowed_packet. Siehe auch Abschnitt 7.5.2, „Serverparameter feineinstellen“.

Bei Funktionen, die mit String-Positionen operieren, hat die erste Position die Nummer 1.

  • ASCII(str)

    Gibt den numerischen Wert des Zeichens ganz links im String str zurück. Gibt 0 zurück, wenn str der Leer-String ist. Gibt NULL zurück, wenn str NULL ist. ASCII() funktioniert bei Zeichen mit numerischen Werten zwischen 0 und 255.

    mysql> SELECT ASCII('2');
            -> 50
    mysql> SELECT ASCII(2);
            -> 50
    mysql> SELECT ASCII('dx');
            -> 100
    

    Siehe auch die Funktion ORD().

  • BIN(N)

    Gibt eine String-Darstellung des Binärwerts N zurück, wobei N eine BIGINT-Zahl ist. Dies ist äquivalent mit CONV(N,10,2). Gibt NULL zurück, wenn N NULL ist.

    mysql> SELECT BIN(12);
            -> '1100'
    
  • BIT_LENGTH(str)

    Gibt die Länge des Strings str angegeben in Bit zurück.

    mysql> SELECT BIT_LENGTH('text');
            -> 32
    
  • CHAR(N,... [USING charset_name])

    CHAR() interpretiert jedes Argument N als Integer und gibt einen String zurück, der aus den Zeichen besteht, die durch die Codewerte dieser Integers beschrieben werden. NULL-Werte werden übersprungen.

    mysql> SELECT CHAR(77,121,83,81,'76');
            -> 'MySQL'
    mysql> SELECT CHAR(77,77.3,'77.3');
            -> 'MMM'
    

    CHAR()-Argumente, die größer als 255 sind, werden in mehrere Ergebnisbytes konvertiert. So ist beispielsweise CHAR(256) äquivalent zu CHAR(1,0), und CHAR(256*256) ist äquivalent zu CHAR(1,0,0):

    mysql> SELECT HEX(CHAR(1,0)), HEX(CHAR(256));
    +----------------+----------------+
    | HEX(CHAR(1,0)) | HEX(CHAR(256)) |
    +----------------+----------------+
    | 0100           | 0100           |
    +----------------+----------------+
    mysql> SELECT HEX(CHAR(1,0,0)), HEX(CHAR(256*256));
    +------------------+--------------------+
    | HEX(CHAR(1,0,0)) | HEX(CHAR(256*256)) |
    +------------------+--------------------+
    | 010000           | 010000             |
    +------------------+--------------------+
    

    Standardmäßig gibt CHAR() einen Binär-String zurück. Um einen String in einem gegebenen Zeichensatz zu erzeugen, verwenden Sie die optionale Klausel USING:

    mysql> SELECT CHARSET(CHAR(0x65)), CHARSET(CHAR(0x65 USING utf8));
    +---------------------+--------------------------------+
    | CHARSET(CHAR(0x65)) | CHARSET(CHAR(0x65 USING utf8)) |
    +---------------------+--------------------------------+
    | binary              | utf8                           |
    +---------------------+--------------------------------+
    

    Wenn USING angegeben wird und der Ergebnis-String für den angegebenen Zeichensatz unzulässig ist, wird eine Warnung ausgegeben. Ferner wird, wenn der strikte SQL-Modus aktiviert ist, das Ergebnis von CHAR() zu NULL.

  • CHAR_LENGTH(str)

    Gibt die Länge des Strings str angegeben in Zeichen zurück. Ein Multibytezeichen wird als ein Zeichen gezählt. Das bedeutet, dass LENGTH() für einen aus fünf Zweibytezeichen bestehenden String 10 zurückgibt, CHAR_LENGTH() hingegen 5.

  • CHARACTER_LENGTH(str)

    CHARACTER_LENGTH() ist ein Synonym für CHAR_LENGTH().

  • CONCAT(str1,str2,...)

    Gibt den String zurück, der aus der Verkettung der Argumente entsteht. Kann ein oder mehrere Argumente haben. Sind alle Argumente nichtbinäre Strings, dann ist das Ergebnis ein nichtbinärer String. Enthalten die Argumente Binär-Strings, dann ist das Ergebnis ein Binär-String. Ein numerisches Argument wird in seinen äquivalenten Binär-String konvertiert. Wollen Sie dies vermeiden, dann können Sie wie im folgenden Beispiel eine explizite Typenumwandlung vornehmen:

    SELECT CONCAT(CAST(int_col AS CHAR), char_col);
    

    CONCAT() gibt NULL zurück, sofern ein Argument NULL ist.

    mysql> SELECT CONCAT('My', 'S', 'QL');
            -> 'MySQL'
    mysql> SELECT CONCAT('My', NULL, 'QL');
            -> NULL
    mysql> SELECT CONCAT(14.3);
            -> '14.3'
    
  • CONCAT_WS(separator,str1,str2,...)

    CONCAT_WS() (Concatenate With Separator) ist eine Sonderform von CONCAT(). Das erste Argument ist das Trennzeichen für die verbleibenden Argumente. Das Trennzeichen wird zwischen die zu verkettenden Strings gesetzt. Das Trennzeichen kann ein String wie auch die übrigen Argumente sein. Wenn das Trennzeichen NULL ist, ist das Ergebnis ebenfalls NULL.

    mysql> SELECT CONCAT_WS(',','First name','Second name','Last Name');
            -> 'First name,Second name,Last Name'
    mysql> SELECT CONCAT_WS(',','First name',NULL,'Last Name');
            -> 'First name,Last Name'
    

    CONCAT_WS() überspringt Leer-Strings nicht. NULL-Werte nach dem Trennzeichenargument werden hingegen übersprungen.

  • CONV(N,from_base,to_base)

    Wandelt Zahlen zwischen verschiedenen Zahlenbasen um. Gibt eine String-Darstellung der Zahl N zurück, die von der Basis from_base in die Basis to_base konvertiert wurde. Gibt NULL zurück, wenn eines der Argumente NULL ist. Das Argument N wird als Integer interpretiert, kann aber als Integer oder als String angegeben werden. Die kleinste Basis ist 2, die größte 36. Wenn to_base eine negative Zahl ist, wird N als vorzeichenbehaftete Zahl betrachtet. Andernfalls wird N als vorzeichenlos behandelt. CONV() arbeitet mit einer Genauigkeit von 64 Bit.

    mysql> SELECT CONV('a',16,2);
            -> '1010'
    mysql> SELECT CONV('6E',18,8);
            -> '172'
    mysql> SELECT CONV(-17,10,-18);
            -> '-H'
    mysql> SELECT CONV(10+'10'+'10'+0xa,10,10);
            -> '40'
    
  • ELT(N,str1,str2,str3,...)

    Gibt str1 zurück, wenn N = 1 ist, str2, wenn N = 2 usw. Gibt NULL zurück, wenn N kleiner als 1 oder größer als die Anzahl der Argumente ist. ELT() ist die Ergänzung zu FIELD().

    mysql> SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo');
            -> 'ej'
    mysql> SELECT ELT(4, 'ej', 'Heja', 'hej', 'foo');
            -> 'foo'
    
  • EXPORT_SET(bits,on,off[,separator[,number_of_bits]])

    Gibt einen String zurück. Dabei erhalten Sie für jedes im Wert bits gesetzte Bit den String on und für jedes nicht gesetzte Bit den String off. Bits in bits werden von rechts nach links (d. h. von den niederwertigen zu den höherwertigen Bits) untersucht. Strings werden dem Ergebnis hingegen von links nach rechts hinzugefügt. Sie sind durch einen Trenn-String voneinander getrennt (standardmäßig ist dies das Kommazeichen ‘,’). Die Anzahl der zu untersuchenden Bits wird über number_of_bits angegeben (Standard: 64).

    mysql> SELECT EXPORT_SET(5,'Y','N',',',4);
            -> 'Y,N,Y,N'
    mysql> SELECT EXPORT_SET(6,'1','0',',',10);
            -> '0,1,1,0,0,0,0,0,0,0'
    
  • FIELD(str,str1,str2,str3,...)

    Gibt den Index (d. h. die Position) von str in der Liste str1, str2, str3, ... zurück. Gibt 0 zurück, wenn str nicht gefunden wird.

    Sind alle Argumente für FIELD() Strings, dann werden alle Argumente als Strings verglichen. Sind alle Argumente Zahlen, dann werden sie als Zahlen verglichen. Andernfalls werden die Argumente als Fließkommazahlen verglichen.

    Wenn str NULL ist, ist der Rückgabewert 0, weil ein Vergleich von NULL mit einem beliebigen Wert fehlschlägt. FIELD() ist die Ergänzung zu ELT().

    mysql> SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');
            -> 2
    mysql> SELECT FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo');
            -> 0
    
  • FIND_IN_SET(str,strlist)

    Gibt einen Wert im Bereich zwischen 1 und N zurück, wenn der String str Bestandteil der String-Liste strlist ist, die aus N Teil-Strings besteht. Eine String-Liste ist ein String, der aus durch Kommata getrennten Teil-Strings besteht. Wenn das erste Argument ein konstanter String und das zweite eine Spalte des Typs SET ist, wird die Funktion FIND_IN_SET() so optimiert, dass sie eine Bitarithmetik verwendet. Gibt 0 zurück, wenn str nicht in strlist enthalten oder strlist der Leer-String ist. Gibt NULL zurück, wenn eines der Argumente NULL ist. Diese Funktion arbeitet nicht einwandfrei, wenn das erste Argument ein Komma (‘,’) enthält.

    mysql> SELECT FIND_IN_SET('b','a,b,c,d');
            -> 2
    
  • FORMAT(X,D)

    Formatiert die Zahl X in ein Format wie '#,###,###.##', gerundet auf D Dezimalstellen, und gibt das Ergebnis als String zurück. Wenn D 0 ist, hat das Ergebnis keinen Dezimalpunkt und keine Nachkommastellen.

    mysql> SELECT FORMAT(12332.123456, 4);
            -> '12,332.1235'
    mysql> SELECT FORMAT(12332.1,4);
            -> '12,332.1000'
    mysql> SELECT FORMAT(12332.2,0);
            -> '12,332'
    
  • HEX(N_or_S)

    Wenn N_or_S eine Zahl ist, wird eine String-Darstellung des Hexadezimalwerts von N zurückgegeben, wobei N eine Longlong-Zahl (BIGINT) ist. Dies ist äquivalent mit CONV(N,10,16).

    Wenn N_or_S ein String ist, wird eine hexadezimale String-Darstellung von N_or_S zurückgegeben, wobei jedes Zeichen in N_or_S in zwei Hexadezimalstellen konvertiert wird.

    mysql> SELECT HEX(255);
            -> 'FF'
    mysql> SELECT 0x616263;
            -> 'abc'
    mysql> SELECT HEX('abc');
            -> 616263
    
  • INSERT(str,pos,len,newstr)

    Gibt den String str zurück. Hierbei wird der an der Position pos beginnende und len Zeichen lange Teil-String durch den String newstr ersetzt. Gibt den Ursprungs-String zurück, wenn pos größer als die Gesamtlänge des Strings ist. Ersetzt wird der Rest des an der Position pos beginnenden Strings, wenn len größer ist als der verbleibende String. Gibt NULL zurück, wenn eines der Argumente NULL ist.

    mysql> SELECT INSERT('Quadratic', 3, 4, 'What');
            -> 'QuWhattic'
    mysql> SELECT INSERT('Quadratic', -1, 4, 'What');
            -> 'Quadratic'
    mysql> SELECT INSERT('Quadratic', 3, 100, 'What');
            -> 'QuWhat'
    

    Diese Funktion ist multibytesicher.

  • INSTR(str,substr)

    Gibt die Position des ersten Auftretens des Teil-Strings substr im String str zurück. Dies ist weitgehend identisch mit der mit zwei Argumenten arbeitenden Form von LOCATE(); der einzige Unterschied besteht darin, dass die Reihenfolge der Argumente umgekehrt ist.

    mysql> SELECT INSTR('foobarbar', 'bar');
            -> 4
    mysql> SELECT INSTR('xbar', 'foobar');
            -> 0
    

    Diese Funktion ist multibytesicher. Die Groß-/Kleinschreibung wird nur dann unterschieden, wenn mindestens ein Argument ein Binär-String ist.

  • LCASE(str)

    LCASE() ist ein Synonym für LOWER().

  • LEFT(str,len)

    Gibt beginnend von links die durch len angegebene Anzahl von Zeichen des Strings str zurück.

    mysql> SELECT LEFT('foobarbar', 5);
            -> 'fooba'
    
  • LENGTH(str)

    Gibt die Länge des Strings str angegeben in Byte zurück. Ein Multibytezeichen wird als mehrere Bytes gezählt. Das bedeutet, dass LENGTH() für einen aus fünf Zweibytezeichen bestehenden String 10 zurückgibt, CHAR_LENGTH() hingegen 5.

    mysql> SELECT LENGTH('text');
            -> 4
    
  • LOAD_FILE(file_name)

    Liest die Datei und gibt den Dateiinhalt als String zurück. Damit diese Funktion verwendet werden kann, muss die Datei auf dem Serverhost liegen. Sie benötigen die Berechtigung FILE und müssen den vollständigen Pfadnamen der Datei angeben. Die Datei muss von allen lesbar und ihre Größe geringer als max_allowed_packet Bytes sein.

    Wenn die Datei nicht vorhanden ist oder nicht gelesen werden kann, weil eine der vorherigen Bedingungen nicht erfüllt ist, gibt die Funktion NULL zurück.

    mysql> UPDATE t
                SET blob_col=LOAD_FILE('/tmp/picture')
                WHERE id=1;
    
  • LOCATE(substr,str), LOCATE(substr,str,pos)

    Die erste Syntax gibt die Position des ersten Auftretens des Teil-Strings substr im String str zurück. Die zweite Syntax gibt die Position des ersten Auftretens des Teil-Strings substr im String str beginnend bei der Position pos zurück. Gibt 0 zurück, wenn substr nicht in str enthalten ist.

    mysql> SELECT LOCATE('bar', 'foobarbar');
            -> 4
    mysql> SELECT LOCATE('xbar', 'foobar');
            -> 0
    mysql> SELECT LOCATE('bar', 'foobarbar', 5);
            -> 7
    

    Diese Funktion ist multibytesicher. Die Groß-/Kleinschreibung wird nur dann unterschieden, wenn mindestens ein Argument ein Binär-String ist.

  • LOWER(str)

    Gibt den String str mit allen Zeichen zurück, die aufgrund der aktuellen Zeichensatzzuordnung in Kleinbuchstaben umgewandelt wurden. Der Standardzeichensatz ist latin1 (cp1252 West European).

    mysql> SELECT LOWER('QUADRATICALLY');
            -> 'quadratically'
    

    Diese Funktion ist multibytesicher.

  • LPAD(str,len,padstr)

    Gibt den String str zurück. Dieser wurde nach links mit dem String padstr auf eine Länge von len Zeichen aufgefüllt. Wenn str länger als len ist, wird der Rückgabewert auf len Zeichen gekürzt.

    mysql> SELECT LPAD('hi',4,'??');
            -> '??hi'
    mysql> SELECT LPAD('hi',1,'??');
            -> 'h'
    
  • LTRIM(str)

    Gibt den String str zurück, bei dem alle Leerzeichen am Anfang entfernt wurden.

    mysql> SELECT LTRIM('  barbar');
            -> 'barbar'
    

    Diese Funktion ist multibytesicher.

  • MAKE_SET(bits,str1,str2,...)

    Gibt einen Mengenwert (d. h. einen String, der aus mit Kommata getrennten Teil-Strings besteht) zurück. Dieser besteht aus den Strings, bei denen das entsprechende Bit in bits gesetzt ist. str1 entspricht Bit 0, str2 Bit 1 usw. NULL-Werte in str1, str2, ... werden nicht an das Ergebnis angehängt.

    mysql> SELECT MAKE_SET(1,'a','b','c');
            -> 'a'
    mysql> SELECT MAKE_SET(1 | 4,'hello','nice','world');
            -> 'hello,world'
    mysql> SELECT MAKE_SET(1 | 4,'hello','nice',NULL,'world');
            -> 'hello'
    mysql> SELECT MAKE_SET(0,'a','b','c');
            -> ''
    
  • MID(str,pos,len)

    MID(str,pos,len) ist ein Synonym für SUBSTRING(str,pos,len).

  • OCT(N)

    Gibt eine String-Darstellung des Oktalwerts N zurück, wobei N eine BIGINT-Zahl ist. Dies ist äquivalent mit CONV(N,10,8). Gibt NULL zurück, wenn N NULL ist.

    mysql> SELECT OCT(12);
            -> '14'
    
  • OCTET_LENGTH(str)

    OCTET_LENGTH() ist ein Synonym für LENGTH().

  • ORD(str)

    Wenn das Zeichen ganz links im String str ein Multibytezeichen ist, wird der Code dieses Zeichens zurückgegeben. Dieser wird aus den numerischen Werten der Bytes gebildet, aus denen das Zeichen besteht. Hierbei kommt folgende Formel zum Einsatz:

      (1st byte code)
    + (2nd byte code × 256)
    + (3rd byte code × 2562) ...
    

    Wenn das Zeichen ganz links im String kein Multibytezeichen ist, gibt ORD() denselben Wert zurück wie die Funktion ASCII().

    mysql> SELECT ORD('2');
            -> 50
    
  • POSITION(substr IN str)

    POSITION(substr IN str) ist ein Synonym für LOCATE(substr,str).

  • QUOTE(str)

    Setzt einen String in Anführungszeichen, um ein Ergebnis zu erzeugen, das als angemessen gekennzeichneter Datenwert in einer SQL-Anweisung verwendet werden kann. Der String wird in einfache Anführungszeichen gesetzt zurückgegeben. Jedem enthaltenen einzelnen Anführungszeichen (‘'’), Backslash (‘\’), ASCII-NUL und Strg+Z wird ein Backslash vorangestellt. Wenn das Argument NULL ist, ist der Rückgabewert das Wort „NULL“ ohne Anführungszeichen.

    mysql> SELECT QUOTE('Don\'t!');
            -> 'Don\'t!'
    mysql> SELECT QUOTE(NULL);
            -> NULL
    
  • REPEAT(str,count)

    Gibt einen String zurück, der aus dem String str besteht, welcher count Mal wiederholt wird. Wenn count kleiner als 1 ist, wird ein leerer String zurückgegeben. Gibt NULL zurück, wenn str oder count NULL sind.

    mysql> SELECT REPEAT('MySQL', 3);
            -> 'MySQLMySQLMySQL'
    
  • REPLACE(str,from_str,to_str)

    Gibt den String str zurück, bei dem jedes Auftreten des Strings from_str durch den String to_str ersetzt wurde. REPLACE() führt bei der Suche nach from_str einen Vergleich unter Berücksichtigung der Groß-/Kleinschreibung durch.

    mysql> SELECT REPLACE('www.mysql.com', 'w', 'Ww');
            -> 'WwWwWw.mysql.com'
    

    Diese Funktion ist multibytesicher.

  • REVERSE(str)

    Gibt den String str zurück, bei dem die Reihenfolge der Zeichen umgekehrt wurde.

    mysql> SELECT REVERSE('abc');
            -> 'cba'
    

    Diese Funktion ist multibytesicher.

  • RIGHT(str,len)

    Gibt beginnend von rechts die durch len angegebene Anzahl von Zeichen des Strings str zurück.

    mysql> SELECT RIGHT('foobarbar', 4);
            -> 'rbar'
    

    Diese Funktion ist multibytesicher.

  • RPAD(str,len,padstr)

    Gibt den String str zurück. Dieser wurde nach rechts mit dem String padstr auf eine Länge von len Zeichen aufgefüllt. Wenn str länger als len ist, wird der Rückgabewert auf len Zeichen gekürzt.

    mysql> SELECT RPAD('hi',5,'?');
            -> 'hi???'
    mysql> SELECT RPAD('hi',1,'?');
            -> 'h'
    

    Diese Funktion ist multibytesicher.

  • RTRIM(str)

    Gibt den String str zurück, bei dem alle Leerzeichen am Ende entfernt wurden.

    mysql> SELECT RTRIM('barbar   ');
            -> 'barbar'
    

    Diese Funktion ist multibytesicher.

  • SOUNDEX(str)

    Gibt einen Soundex-String aus str zurück. Zwei Strings, die fast identisch klingen, sollten identische Soundex-Strings haben. Ein Soundex-String ist standardmäßig vier Zeichen lang, die Funktion SOUNDEX() gibt aber einen beliebig langen String zurück. Sie können SUBSTRING() für das Ergebnis verwenden, um einen Standard-Soundex-String zu erhalten. Alle nicht alphabetischen Zeichen in str werden ignoriert. Alle internationalen alphabetischen Zeichen außerhalb des Bereichs A bis Z werden als Vokale behandelt.

    mysql> SELECT SOUNDEX('Hello');
            -> 'H400'
    mysql> SELECT SOUNDEX('Quadratically');
            -> 'Q36324'
    

    Hinweis: Diese Funktion implementiert den Soundex-Originalalgorithmus und nicht die gängigere erweiterte Version, wie sie auch von D. Knuth beschrieben wird. Der Unterschied besteht darin, dass die Originalversion zuerst Vokale und dann Duplikate verwirft, während die erweiterte Version umgekehrt vorgeht.

  • expr1 SOUNDS LIKE expr2

    Dies ist das Gleiche wie SOUNDEX(expr1) = SOUNDEX(expr2).

  • SPACE(N)

    Gibt einen String zurück, der aus N Leerzeichen besteht.

    mysql> SELECT SPACE(6);
            -> '      '
    
  • SUBSTRING(str,pos), SUBSTRING(str FROM pos), SUBSTRING(str,pos,len), SUBSTRING(str FROM pos FOR len)

    Die Formen ohne len-Argument geben einen Teil-String des Strings str zurück, der an der Position pos beginnt. Die Formen mit len-Argument geben einen Teil-String des Strings str mit einer Länge von len Zeichen zurück, der an der Position pos beginnt. Die Formen, die FROM verwenden, sind SQL-Standardsyntax. Es ist auch möglich, einen negativen Wert für pos zu verwenden. In diesem Fall liegt der Anfang des Teil-Strings pos Zeichen vom Ende des Strings (statt von seinem Anfang) entfernt. Ein negativer Wert kann für pos in allen Formen dieser Funktion verwendet werden.

    mysql> SELECT SUBSTRING('Quadratically',5);
            -> 'ratically'
    mysql> SELECT SUBSTRING('foobarbar' FROM 4);
            -> 'barbar'
    mysql> SELECT SUBSTRING('Quadratically',5,6);
            -> 'ratica'        
    mysql> SELECT SUBSTRING('Sakila', -3);
            -> 'ila'        
    mysql> SELECT SUBSTRING('Sakila', -5, 3);
            -> 'aki'
    mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
            -> 'ki'
    

    Diese Funktion ist multibytesicher.

    Wenn len kleiner als 1 ist, wird der Leer-String zurückgegeben.

    SUBSTR() ist ein Synonym für SUBSTRING().

  • SUBSTRING_INDEX(str,delim,count)

    Gibt einen Teil-String des Strings str zurück. Der Teil-String umfasst den Teil des Strings vom Anfang bis zum count-sten Auftreten des Trennzeichens delim. Wenn count positiv ist, wird alles links vom (von links gezählt) letzten Trennzeichen zurückgegeben. Wenn count negativ ist, wird alles rechts vom (von rechts gezählt) letzten Trennzeichen zurückgegeben. SUBSTRING_INDEX() führt bei der Suche nach delim einen Vergleich unter Berücksichtigung der Groß-/Kleinschreibung durch.

    mysql> SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);
            -> 'www.mysql'
    mysql> SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2);
            -> 'mysql.com'
    

    Diese Funktion ist multibytesicher.

  • TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str), TRIM(remstr FROM] str)

    Gibt den String str zurück, bei dem alle remstr-Präfixe oder -Suffixe entfernt wurden. Wenn keine der Konfigurationsangaben BOTH, LEADING oder TRAILING angegeben wurde, wird BOTH vorausgesetzt. remstr ist optional; sofern es nicht angegeben ist, werden Leerzeichen entfernt.

    mysql> SELECT TRIM('  bar   ');
            -> 'bar'
    mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
            -> 'barxxx'
    mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
            -> 'bar'
    mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
            -> 'barx'
    

    Diese Funktion ist multibytesicher.

  • UCASE(str)

    UCASE() ist ein Synonym für UPPER().

  • UNHEX(str)

    Führt die umgekehrte Operation von HEX(str) durch: Jedes Paar Hexadezimalziffern im Argument wird als Zahl interpretiert und in das Zeichen umgewandelt, das durch die Zahl dargestellt wird. Das Ergebnis wird als Binär-String zurückgegeben.

    mysql> SELECT UNHEX('4D7953514C');
            -> 'MySQL'
    mysql> SELECT 0x4D7953514C;
            -> 'MySQL'
    mysql> SELECT UNHEX(HEX('string'));
            -> 'string'
    mysql> SELECT HEX(UNHEX('1267'));
            -> '1267'
    
  • UPPER(str)

    Gibt den String str mit allen Zeichen zurück, die aufgrund der aktuellen Zeichensatzzuordnung in Großbuchstaben umgewandelt wurden. Der Standardzeichensatz ist latin1 (cp1252 West European).

    mysql> SELECT UPPER('Hej');
            -> 'HEJ'
    

    Diese Funktion ist multibytesicher.

12.3.1. String-Vergleichsfunktionen

Wenn einer String-Funktion ein Binär-String als Argument übergeben wird, ist der Ergebnis-String ebenfalls ein Binär-String. Eine Zahl, die in einen String konvertiert wird, wird als Binär-String behandelt. Dies betrifft nur Vergleiche.

Wenn ein Ausdruck in einem String-Vergleich die Groß-/Kleinschreibung unterscheidet, dann wird der Vergleich ebenfalls mit Unterscheidung der Groß-/Kleinschreibung durchgeführt.

  • expr LIKE pat [ESCAPE 'escape_char']

    Mustervergleich unter Verwendung eines einfachen SQL-Vergleichs mit regulären Ausdrücken. Gibt 1 (TRUE) oder 0 (FALSE) zurück. Wenn entweder expr oder pat NULL sind, ist das Ergebnis NULL.

    Das Muster muss kein literaler String sein. Es kann beispielsweise auch als String-Ausdruck oder als Tabellenspalte angegeben werden.

    Gemäß dem SQL-Standard führt LIKE die Überprüfung auf Zeichenbasis durch, kann also Ergebnisse erzeugen, die sich von denen des Vergleichsoperators = unterscheiden:

    mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
    +-----------------------------------------+
    | 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
    +-----------------------------------------+
    |                                       0 |
    +-----------------------------------------+
    mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
    +--------------------------------------+
    | 'ä' = 'ae' COLLATE latin1_german2_ci |
    +--------------------------------------+
    |                                    1 |
    +--------------------------------------+
    

    Bei LIKE können Sie die folgenden beiden Jokerzeichen im Muster verwenden:

    ZeichenBeschreibung
    %entspricht einer beliebigen Anzahl von Zeichen (einschließlich null Zeichen).
    _entspricht genau einem Zeichen.
    mysql> SELECT 'David!' LIKE 'David_';
            -> 1
    mysql> SELECT 'David!' LIKE '%D%v%';
            -> 1
    

    Um auf literale Instanzen eines Jokerzeichens zu prüfen, stellen Sie ihm ein Escape-Zeichen voran. Wenn Sie das Escape-Zeichen nicht angeben, wird ‘\’ angenommen.

    StringBeschreibung
    \%entspricht einem ‘%’-Zeichen.
    \_entspricht einem ‘_’-Zeichen.
    mysql> SELECT 'David!' LIKE 'David\_';
            -> 0
    mysql> SELECT 'David_' LIKE 'David\_';
            -> 1
    

    Um ein anderes Escape-Zeichen anzugeben, verwenden Sie die ESCAPE-Klausel:

    mysql> SELECT 'David_' LIKE 'David|_' ESCAPE '|';
            -> 1
    

    Die Escape-Sequenz sollte leer oder genau ein Zeichen lang sein. Ab MySQL 5.1.2 darf die Sequenz nicht leer sein, wenn der SQL-Modus NO_BACKSLASH_ESCAPES aktiviert wurde.

    Die folgenden beiden Anweisungen veranschaulichen, dass die Groß-/Kleinschreibung bei String-Vergleichen nicht unterschieden wird, sofern nicht einer der Operanden ein Binär-String ist:

    mysql> SELECT 'abc' LIKE 'ABC';
            -> 1
    mysql> SELECT 'abc' LIKE BINARY 'ABC';
            -> 0
    

    In MySQL ist LIKE für numerische Ausdrücke zulässig. (Dies stellt eine Erweiterung zu LIKE nach SQL-Standard dar.)

    mysql> SELECT 10 LIKE '1%';
            -> 1
    

    Hinweis: Weil MySQL die C-Escape-Syntax in Strings verwendet (z. B. ‘\n’ zur Darstellung eines Zeilenwechsels), müssen Sie jedes ‘\’, das Sie in LIKE-Strings verwenden, verdoppeln. Um beispielsweise nach ‘\n’ zu suchen, geben Sie es als ‘\\n’ an. Um nach ‘\’ zu suchen, geben Sie es als ‘\\\\’ an; dies ist erforderlich, weil Backslashs einmal vom Parser und dann noch einmal bei Durchführung des Mustervergleichs umgewandelt werden – so bleibt für den Vergleich ein einzelner Backslash übrig.

  • expr NOT LIKE pat [ESCAPE 'escape_char']

    Dies ist das Gleiche wie NOT (expr LIKE pat [ESCAPE 'escape_char']).

  • expr NOT REGEXP pat, expr NOT RLIKE pat

    Dies ist das Gleiche wie NOT (expr REGEXP pat).

  • expr REGEXP pat expr RLIKE pat

    Führt einen Mustervergleich eines String-Ausdrucks expr mit einem Muster pat durch. Das Muster kann ein erweiterter regulärer Ausdruck sein. Die Syntax für reguläre Ausdrücke wird in Anhang G, Beschreibung der MySQL-Syntax für reguläre Ausdrücke, beschrieben. Gibt 1 zurück, wenn expr mit pat übereinstimmt; andernfalls wird 0 zurückgegeben. Wenn entweder expr oder pat NULL sind, ist das Ergebnis auch NULL. RLIKE ist ein Synonym für REGEXP, welches aus Gründen der mSQL-Kompatibilität vorhanden ist.

    Das Muster muss kein literaler String sein. Es kann beispielsweise auch als String-Ausdruck oder als Tabellenspalte angegeben werden.

    Hinweis: Weil MySQL die C-Escape-Syntax in Strings verwendet (z. B. ‘\n’ zur Darstellung eines Zeilenwechsels), müssen Sie jedes ‘\’, das Sie in REGEXP-Strings verwenden, verdoppeln.

    REGEXP unterscheidet die Groß-/Kleinschreibung nur dann, wenn sie mit Binär-Strings verwendet wird.

    mysql> SELECT 'Monty!' REGEXP 'm%y%%';
            -> 0
    mysql> SELECT 'Monty!' REGEXP '.*';
            -> 1
    mysql> SELECT 'new*\n*line' REGEXP 'new\\*.\\*line';
            -> 1
    mysql> SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A';
            -> 1  0
    mysql> SELECT 'a' REGEXP '^[a-d]';
            -> 1
    

    REGEXP und RLIKE verwenden zur Erkennung des Typs eines Zeichens den aktuellen Zeichensatz. Der Standardzeichensatz ist latin1 (cp1252 West European). Warnung: Diese Operatoren sind nicht multibytesicher.

  • STRCMP(expr1,expr2)

    STRCMP() gibt 0 zurück, wenn die Strings identisch sind, -1, wenn das erste Argument entsprechend der aktuellen Sortierreihenfolge kleiner ist als das zweite, und 1 in jedem anderen Fall.

    mysql> SELECT STRCMP('text', 'text2');
            -> -1
    mysql> SELECT STRCMP('text2', 'text');
            -> 1
    mysql> SELECT STRCMP('text', 'text');
            -> 0
    

    STRCMP() verwendet zur Durchführung von Vergleichsoperationen den aktuellen Zeichensatz. Insofern wird die Groß-/Kleinschreibung bei Vergleichen standardmäßig nicht unterschieden, sofern nicht mindestens einer der Operanden ein Binär-String ist.

12.4. Numerische Funktionen

12.4.1. Arithmetische Operationen

Es stehen die normalen arithmetischen Operatoren zur Verfügung. Beachten Sie, dass das Ergebnis im Fall von -, + und * mit BIGINT-Genauigkeit (64-Bit-Genauigkeit) berechnet wird, sofern beide Argumente Integers sind. Wenn eines der Argumente ein vorzeichenloser Integer und das andere auch ein Integer ist, dann ist das Ergebnis ein vorzeichenloser Integer. Siehe auch Abschnitt 12.8, „Cast-Funktionen und Operatoren“.

  • +

    Addition:

    mysql> SELECT 3+5;
            -> 8
    
  • -

    Subtraktion:

    mysql> SELECT 3-5;
            -> -2
    
  • -

    Monadisches Minus. Dieser Operator ändert das Vorzeichen des Arguments.

    mysql> SELECT - 2;
            -> -2
    

    Hinweis: Wenn der Operator mit einem BIGINT verwendet wird, ist der Rückgabewert ebenfalls ein BIGINT. Das bedeutet, dass Sie die Verwendung von bei Integers vermeiden sollten, die den Wert –263 annehmen könnten.

  • *

    Multiplikation:

    mysql> SELECT 3*5;
            -> 15
    mysql> SELECT 18014398509481984*18014398509481984.0;
            -> 324518553658426726783156020576256.0
    mysql> SELECT 18014398509481984*18014398509481984;
            -> 0
    

    Das Ergebnis des letzten Ausdrucks ist falsch, weil das Ergebnis der Integer-Multiplikation den 64-Bit-Bereich von BIGINT-Berechnungen überschreitet. (Siehe auch Abschnitt 11.2, „Numerische Datentypen“.)

  • /

    Division:

    mysql> SELECT 3/5;
            -> 0.60
    

    Die Division durch null erzeugt das Ergebnis NULL:

    mysql> SELECT 102/(1-1);
            -> NULL
    

    Eine Division wird nur dann mit BIGINT-Arithmetik berechnet, wenn sie in einem Kontext durchgeführt wird, in dem das Ergebnis in einen Integer konvertiert wird.

  • DIV

    Integer-Division. Ähnlich wie FLOOR(), aber sicher bei BIGINT-Werten.

    mysql> SELECT 5 DIV 2;
            -> 2
    

12.4.2. Mathematische Funktionen

Alle mathematischen Funktionen geben im Fehlerfall NULL zurück.

  • ABS(X)

    Gibt den absoluten Wert von X zurück.

    mysql> SELECT ABS(2);
            -> 2
    mysql> SELECT ABS(-32);
            -> 32
    

    Diese Funktion kann sicher mit BIGINT-Werten eingesetzt werden.

  • ACOS(X)

    Gibt den Arkuskosinus von X zurück, d. h. den Wert, dessen Kosinus X ist. Gibt NULL zurück, wenn X nicht im Bereich zwischen -1 und 1 liegt.

    mysql> SELECT ACOS(1);
            -> 0
    mysql> SELECT ACOS(1.0001);
            -> NULL
    mysql> SELECT ACOS(0);
            -> 1.5707963267949
    
  • ASIN(X)

    Gibt den Arkussinus von X zurück, d. h. den Wert, dessen Sinus X ist. Gibt NULL zurück, wenn X nicht im Bereich zwischen -1 und 1 liegt.

    mysql> SELECT ASIN(0.2);
            -> 0.20135792079033
    mysql> SELECT ASIN('foo');
    
    +-------------+
    | ASIN('foo') |
    +-------------+
    |           0 |
    +-------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS;
    +---------+------+-----------------------------------------+
    | Level   | Code | Message                                 |
    +---------+------+-----------------------------------------+
    | Warning | 1292 | Truncated incorrect DOUBLE value: 'foo' |
    +---------+------+-----------------------------------------+
    
  • ATAN(X)

    Gibt den Arkustangens von X zurück, d. h. den Wert, dessen Tangens X ist.

    mysql> SELECT ATAN(2);
            -> 1.1071487177941
    mysql> SELECT ATAN(-2);
            -> -1.1071487177941
    
  • ATAN(Y,X), ATAN2(Y,X)

    Gibt den Arkustangens der beiden Variablen X und Y zurück. Dies ähnelt der Berechnung des Arkustangens von Y / X; der einzige Unterschied besteht darin, dass die Vorzeichen beider Argumente zur Bestimmung des Quadranten des Ergebnisses verwendet werden.

    mysql> SELECT ATAN(-2,2);
            -> -0.78539816339745
    mysql> SELECT ATAN2(PI(),0);
            -> 1.5707963267949
    
  • CEILING(X), CEIL(X)

    Gibt den kleinsten Integer-Wert zurück, der nicht kleiner als X ist.

    mysql> SELECT CEILING(1.23);
            -> 2
    mysql> SELECT CEIL(-1.23);
            -> -1
    

    Diese beiden Funktionen sind synonym. Beachten Sie, dass der Rückgabewert in ein BIGINT konvertiert wird.

  • COS(X)

    Gibt den Kosinus von X zurück, wobei X in rad angegeben wird.

    mysql> SELECT COS(PI());
            -> -1
    
  • COT(X)

    Gibt den Kotangens von X zurück.

    mysql> SELECT COT(12);
            -> -1.5726734063977
    mysql> SELECT COT(0);
            -> NULL
    
  • CRC32(expr)

    Berechnet einen Prüfsummenwert (CRC, Cyclic Redundancy Check) und gibt einen vorzeichenlosen 32-Bit-Wert zurück. Das Ergebnis ist NULL, wenn das Argument NULL ist. Als Argument wird ein String erwartet, der dann (sofern möglich) so behandelt wird, als wäre er keiner.

    mysql> SELECT CRC32('MySQL');
            -> 3259397556
    mysql> SELECT CRC32('mysql');
            -> 2501908538
    
  • DEGREES(X)

    Gibt das Argument X umgewandelt von rad in Grad zurück.

    mysql> SELECT DEGREES(PI());
            -> 180
    mysql> SELECT DEGREES(PI() / 2);
            -> 90
    
  • EXP(X)

    Gibt den Wert von e (Basis natürlicher Logarithmen) zur Potenz X zurück.

    mysql> SELECT EXP(2);
            -> 7.3890560989307
    mysql> SELECT EXP(-2);
            -> 0.13533528323661
    mysql> SELECT EXP(0);
            -> 1
    
  • FLOOR(X)

    Gibt den größten Integer-Wert zurück, der nicht größer als X ist.

    mysql> SELECT FLOOR(1.23);
            -> 1
    mysql> SELECT FLOOR(-1.23);
            -> -2
    

    Beachten Sie, dass der Rückgabewert in ein BIGINT konvertiert wird.

  • FORMAT(X,D)

    Formatiert die Zahl X in ein Format wie '#,###,###.##', gerundet auf D Dezimalstellen, und gibt das Ergebnis als String zurück. Detaillierte Informationen finden Sie in Abschnitt 12.3, „String-Funktionen“.

  • LN(X)

    Gibt den natürlichen Logarithmus von X zurück, d. h. den Logarithmus von X zur Basis e.

    mysql> SELECT LN(2);
            -> 0.69314718055995
    mysql> SELECT LN(-2);
            -> NULL
    

    Diese Funktion ist synonym zu LOG(X).

  • LOG(X), LOG(B,X)

    Sofern mit einem Parameter aufgerufen, gibt diese Funktion den natürlichen Logarithmus von X zurück.

    mysql> SELECT LOG(2);
            -> 0.69314718055995
    mysql> SELECT LOG(-2);
            -> NULL
    

    Wenn der Aufruf mit zwei Parametern erfolgt, gibt die Funktion den Logarithmus von X zur (beliebig anzugebenden) Basis B zurück.

    mysql> SELECT LOG(2,65536);
            -> 16
    mysql> SELECT LOG(10,100);
            -> 2
    

    LOG(B,X) ist äquivalent mit LOG(X) / LOG(B).

  • LOG2(X)

    Gibt den Logarithmus von X zur Basis 2 zurück.

    mysql> SELECT LOG2(65536);
            -> 16
    mysql> SELECT LOG2(-100);
            -> NULL
    

    LOG2() ist praktisch, um zu ermitteln, wie viele Bits eine Zahl zur Speicherung benötigt. Die Funktion ist äquivalent zu dem Ausdruck LOG(X) / LOG(2).

  • LOG10(X)

    Gibt den Logarithmus von X zur Basis 10 zurück.

    mysql> SELECT LOG10(2);
            -> 0.30102999566398
    mysql> SELECT LOG10(100);
            -> 2
    mysql> SELECT LOG10(-100);
            -> NULL
    

    LOG10(X) ist äquivalent mit LOG(10,X).

  • MOD(N,M), N % M, N MOD M

    Modulooperation. Gibt den Rest von N geteilt durch M zurück.

    mysql> SELECT MOD(234, 10);
            -> 4
    mysql> SELECT 253 % 7;
            -> 1
    mysql> SELECT MOD(29,9);
            -> 2
    mysql> SELECT 29 MOD 9;
            -> 2
    

    Diese Funktion kann mit BIGINT-Werten sicher eingesetzt werden.

    MOD() funktioniert auch bei Werten mit Nachkommastellen und gibt den exakten Rest nach der Division zurück:

    mysql> SELECT MOD(34.5,3);
            -> 1.5
    
  • PI()

    Gibt den Wert von π (Pi) zurück. Standardmäßig werden sieben Dezimalstellen angezeigt, MySQL verwendet intern jedoch den vollständigen Wert doppelter Genauigkeit.

    mysql> SELECT PI();
            -> 3.141593
    mysql> SELECT PI()+0.000000000000000000;
            -> 3.141592653589793116
    
  • POW(X,Y), POWER(X,Y)

    Gibt den Wert von X potenziert zu Y an.

    mysql> SELECT POW(2,2);
            -> 4
    mysql> SELECT POW(2,-2);
            -> 0.25
    
  • RADIANS(X)

    Gibt das Argument X umgewandelt von Grad in rad zurück. (Beachten Sie, dass π rad 180 Grad entspricht.)

    mysql> SELECT RADIANS(90);
            -> 1.5707963267949
    
  • RAND(), RAND(N)

    Gibt einen zufälligen Fließkommawert v zwischen 0 und 1 inklusive (d. h. im Bereich 0 <= v <= 1.0) zurück. Wenn ein Integer-Argument N angegeben ist, wird es als Ausgangswert verwendet, der eine wiederholbare Sequenz erzeugt.

    mysql> SELECT RAND();
            -> 0.9233482386203
    mysql> SELECT RAND(20);
            -> 0.15888261251047
    mysql> SELECT RAND(20);
            -> 0.15888261251047
    mysql> SELECT RAND();
            -> 0.63553050033332
    mysql> SELECT RAND();
            -> 0.70100469486881
    mysql> SELECT RAND(20);
            -> 0.15888261251047
    

    Um einen zufälligen Integer R im Bereich i <= R <= j zu erhalten, verwenden Sie den Ausdruck FLOOR(i+ RAND() * (ji+ 1)). Um beispielsweise einen ganzzahligen Zufallswert im Bereich zwischen 7 und 12 (einschließlich) zu erhalten, können Sie die folgende Anweisung verwenden:

    SELECT FLOOR(7 + (RAND() * 6));
    

    Sie können eine Spalte mit RAND()-Werten nicht in einer ORDER BY-Klausel angeben, weil ORDER BY die Spalte mehrfach auswerten würde. Allerdings können Sie Datensätze in zufälliger Folge abrufen. Das funktioniert wie folgt:

    mysql> SELECT * FROM tbl_name ORDER BY RAND();
    

    ORDER BY RAND() in Kombination mit LIMIT ist nützlich zur Auswahl eines Zufallswerts aus einer Datensatzmenge:

    mysql> SELECT * FROM table1, table2 WHERE a=b AND c<d -> ORDER BY RAND() LIMIT 1000;
    

    Beachten Sie, dass RAND() in einer WHERE-Klausel jedes Mal, wenn WHERE ausgeführt wird, neu ausgewertet wird.

    RAND() ist nicht als perfekter Zufallsgenerator gedacht, sondern stellt eine gute Möglichkeit da, ad hoc Zufallszahlen zu erzeugen, die innerhalb derselben MySQL-Version plattformübergreifend funktioniert.

  • ROUND(X), ROUND(X,D)

    Gibt das Argument X gerundet auf den nächstgelegenen Integer zurück. Bei zwei übergebenen Argumenten wird X gerundet auf D Dezimalstellen zurückgegeben. D kann negativ sein; in diesem Fall werden D Stellen links des Dezimalpunkts des Werts X null.

    mysql> SELECT ROUND(-1.23);
            -> -1
    mysql> SELECT ROUND(-1.58);
            -> -2
    mysql> SELECT ROUND(1.58);
            -> 2
    mysql> SELECT ROUND(1.298, 1);
            -> 1.3
    mysql> SELECT ROUND(1.298, 0);
            -> 1
    mysql> SELECT ROUND(23.298, -1);
            -> 20
    

    Der Rückgabetyp ist derselbe wie der des ersten Arguments (vorausgesetzt, dies ist ein Integer, eine Fließkommazahl oder eine Dezimalzahl). Das bedeutet, dass bei einem Integer-Argument das Ergebnis ein Integer ist (der keine Dezimalstellen aufweist).

    ROUND() verwendet für genaue Zahlen die Precision-Math-Bibliothek, wenn das erste Argument ein Dezimalwert ist:

    • Bei genauen Zahlen verwendet ROUND() die gängigen Rundungsregeln: Ein Wert mit einem Wert von 5 oder größer nach dem Komma wird auf den nächsten Integer aufgerundet bzw. (bei negativen Werten) abgerundet. (Anders gesagt: Die Rundung erfolgt von Null weg.) Ein Wert mit einem Wert von weniger als 5 nach dem Komma wird auf den nächsten Integer abgerundet bzw. (bei negativen Werten) aufgerundet.

    • Bei Näherungswerten hängt das Ergebnis von der C-Bibliothek ab. Auf vielen Systemen bedeutet dies, dass ROUND() die Regel „auf nächste gerade Zahl aufrunden“ einsetzt: Ein Wert mit Nachkommastellen wird auf den nächsten geraden Integer gerundet.

    Das folgende Beispiel zeigt, wie die Rundung sich bei exakten und bei Näherungswerten voneinander unterscheidet:

    mysql> SELECT ROUND(2.5), ROUND(25E-1);
    +------------+--------------+
    | ROUND(2.5) | ROUND(25E-1) |
    +------------+--------------+
    | 3          |            2 |
    +------------+--------------+
    

    Weitere Informationen finden Sie unter Kapitel 23, Präzisionsberechnungen.

  • SIGN(X)

    Gibt das Vorzeichen des Arguments als -1, 0 oder 1 abhängig davon zurück, ob X negativ, null oder positiv ist.

    mysql> SELECT SIGN(-32);
            -> -1
    mysql> SELECT SIGN(0);
            -> 0
    mysql> SELECT SIGN(234);
            -> 1
    
  • SIN(X)

    Gibt den Sinus von X zurück, wobei X in rad angegeben wird.

    mysql> SELECT SIN(PI());
            -> 1.2246063538224e-16
    mysql> SELECT ROUND(SIN(PI()));
            -> 0
    
  • SQRT(X)

    Gibt die Quadratwurzel einer nichtnegativen Zahl X zurück.

    mysql> SELECT SQRT(4);
            -> 2
    mysql> SELECT SQRT(20);
            -> 4.4721359549996
    mysql> SELECT SQRT(-16);
            -> NULL        
    
  • TAN(X)

    Gibt den Tangens von X zurück, wobei X in rad angegeben wird.

    mysql> SELECT TAN(PI());
            -> -1.2246063538224e-16
    mysql> SELECT TAN(PI()+1);
            -> 1.5574077246549
    
  • TRUNCATE(X,D)

    Gibt die Zahl X auf D Dezimalstellen beschnitten zurück. Wenn D 0 ist, hat das Ergebnis keinen Dezimalpunkt und keine Nachkommastellen. D kann auch negativ sein. In diesem Fall werden D Stellen links vom Dezimalpunkt des Werts X null.

    mysql> SELECT TRUNCATE(1.223,1);
            -> 1.2
    mysql> SELECT TRUNCATE(1.999,1);
            -> 1.9
    mysql> SELECT TRUNCATE(1.999,0);
            -> 1
    mysql> SELECT TRUNCATE(-1.999,1);
            -> -1.9
    mysql> SELECT TRUNCATE(122,-2);
           -> 100
    mysql> SELECT TRUNCATE(10.28*100,0);
           -> 1028
    

    Alle Zahlen werden nach null hin gerundet.

12.5. Datums- und Zeitfunktionen

Dieser Abschnitt beschreibt die Funktionen, die zur Manipulation von zeitbezogenen Werten verwendet werden können. Eine Beschreibung der Wertebereiche für Datums- und Uhrzeittypen und der gültigen Formate, in denen Werte angegeben werden können, finden Sie in Abschnitt 11.3, „Datums- und Zeittypen“.

Es folgt ein Beispiel, welches Datumsfunktionen verwendet. Die folgende Abfrage wählt alle Datensätze aus, die einen date_col-Wert haben, der in den letzten 30 Tagen liegt:

mysql> SELECT something FROM tbl_name
    -> WHERE DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= date_col;

Beachten Sie, dass die Abfrage auch Datensätze mit Daten auswählt, die in der Zukunft liegen.

Funktionen, die Datumswerte erwarten, akzeptieren normalerweise auch DATETIME-Werte und ignorieren dabei den Uhrzeitbestandteil. Ähnlich akzeptieren Funktionen, die Zeitwerte erwarten, normalerweise auch DATETIME-Werte und ignorieren den Datumsbestandteil.

Funktionen, die das aktuelle Datum oder die Uhrzeit zurückgeben, werden nur einmal pro Abfrage ausgewertet, nämlich beim Start der Abfrageausführung. Das bedeutet, dass mehrere Referenzierungen einer Funktion wie NOW() in einer Abfrage immer zum selben Ergebnis führen (für unsere Zwecke enthält eine einzelne Abfrage auch einen Aufruf einer gespeicherten Routine oder eines Triggers sowie alle Subroutinen, die von dieser Routine oder diesem Trigger aufgerufen werden). Dieses Prinzip gilt auch für CURDATE(), CURTIME(), UTC_DATE(), UTC_TIME(), UTC_TIMESTAMP() und für alle zugehörigen Synonyme.

Die Funktionen CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE() und FROM_UNIXTIME() geben Werte in der aktuellen Zeitzone der Verbindung zurück, die als Wert der Systemvariablen time_zone verfügbar ist. Ferner setzt UNIX_TIMESTAMP() voraus, dass sein Argument ein DATETIME-Wert in der aktuellen Zeitzone ist. Siehe auch Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“.

Einige Datumsfunktionen können mit „Nulldaten“ oder unvollständigen Daten wie '2001-11-00' verwendet werden, während dies bei anderen nicht möglich ist. Funktionen, die Teile von Datumsangaben extrahieren, arbeiten meist auch mit unvollständigen Daten. Zum Beispiel:

mysql> SELECT DAYOFMONTH('2001-11-00'), MONTH('2005-00-00');
        -> 0, 0

Andere Funktionen erwarten vollständige Daten und geben NULL zurück, wenn unvollständige Daten übergeben werden. Hierzu gehören Funktionen, die Datumsberechnungen durchführen oder Teile von Datumsangaben Namen zuordnen. Zum Beispiel:

mysql> SELECT DATE_ADD('2006-05-00',INTERVAL 1 DAY);
        -> NULL
mysql> SELECT DAYNAME('2006-05-00');
        -> NULL
  • ADDDATE(date,INTERVAL expr type), ADDDATE(expr,days)

    Wenn mit der Form INTERVAL für das zweite Argument aufgerufen, ist ADDDATE() ein Synonym von DATE_ADD(). Die zugehörige Funktion SUBDATE() ist ein Synonym für DATE_SUB(). Weitere Informationen zum Argument INTERVAL finden Sie in der Beschreibung zu DATE_ADD().

    mysql> SELECT DATE_ADD('1998-01-02', INTERVAL 31 DAY);
            -> '1998-02-02'
    mysql> SELECT ADDDATE('1998-01-02', INTERVAL 31 DAY);
            -> '1998-02-02'
    

    Wenn mit der Form days für das zweite Argument aufgerufen, wird es von MySQL als ganzzahlige Anzahl von Tagen behandelt, die expr hinzugefügt wird.

    mysql> SELECT ADDDATE('1998-01-02', 31);
            -> '1998-02-02'
    
  • ADDTIME(expr,expr2)

    ADDTIME() fügt expr2 expr hinzu und gibt das Ergebnis zurück. expr ist eine Zeitangabe oder ein DATETIME-Wert, expr2 eine Zeitangabe.

    mysql> SELECT ADDTIME('1997-12-31 23:59:59.999999',
        ->                '1 1:1:1.000002');
            -> '1998-01-02 01:01:01.000001'
    mysql> SELECT ADDTIME('01:00:00.999999', '02:00:00.999998');
            -> '03:00:01.999997'
    
  • CONVERT_TZ(dt,from_tz,to_tz)

    CONVERT_TZ() wandelt einen DATETIME-Wert dt von der angegebenen Ausgangszeitzone from_tz in die Zielzeitzone to_tz um und gibt das Ergebnis zurück. Zeitzonen werden wie in Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“, beschrieben angegeben. Die Funktion gibt NULL zurück, wenn die Argumente ungültig sind.

    Fiele der Wert durch die Konvertierung aus from_tz in UTC außerhalb des vom Typ TIMESTAMP unterstützten Bereichs, dann erfolgt keine Konvertierung. Der für TIMESTAMP gültige Bereich ist in Abschnitt 11.1.2, „Überblick über Datums- und Zeittypen“, beschrieben.

    mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
            -> '2004-01-01 13:00:00'
    mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');
            -> '2004-01-01 22:00:00'
    

    Hinweis: Wenn Sie benannte Zeitzonen wie 'MET' oder 'Europe/Moscow' verwenden wollen, müssen die Zeitzonentabellen korrekt konfiguriert sein. Eine Anleitung finden Sie in Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“.

  • CURDATE()

    Gibt das aktuelle Datum als Wert in den Formaten 'YYYY-MM-DD' oder YYYYMMDD aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT CURDATE();
            -> '1997-12-15'
    mysql> SELECT CURDATE() + 0;
            -> 19971215
    
  • CURRENT_DATE, CURRENT_DATE()

    CURRENT_DATE und CURRENT_DATE() sind Synonyme von CURDATE().

  • CURTIME()

    Gibt die aktuelle Uhrzeit als Wert in den Formaten 'HH:MM:SS' oder HHMMSS aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT CURTIME();
            -> '23:50:26'
    mysql> SELECT CURTIME() + 0;
            -> 235026
    
  • CURRENT_TIME, CURRENT_TIME()

    CURRENT_TIME und CURRENT_TIME() sind Synonyme von CURTIME().

  • CURRENT_TIMESTAMP, CURRENT_TIMESTAMP()

    CURRENT_TIMESTAMP und CURRENT_TIMESTAMP() sind Synonyme von NOW().

  • DATE(expr)

    Extrahiert den Datumsteil aus dem DATE- oder DATETIME-Ausdruck expr.

    mysql> SELECT DATE('2003-12-31 01:02:03');
            -> '2003-12-31'
    
  • DATEDIFF(expr,expr2)

    DATEDIFF() gibt die Anzahl der Tage zwischen dem Startdatum expr und dem Enddatum expr2 zurück. expr und expr2 sind DATE- oder DATETIME-Ausdrücke. Nur die Datumsanteile der Werte werden in der Berechnung verwendet.

    mysql> SELECT DATEDIFF('1997-12-31 23:59:59','1997-12-30');
            -> 1
    mysql> SELECT DATEDIFF('1997-11-30 23:59:59','1997-12-31');
            -> -31
    
  • DATE_ADD(date,INTERVAL expr type), DATE_SUB(date,INTERVAL expr type)

    Diese Funktionen führen Datumsberechnungen durch. date ist ein DATETIME- oder DATE-Wert, der das Startdatum angibt. expr ist ein Ausdruck, der den vom Startdatum hinzuzufügenden oder abzuziehenden Intervallwert angibt. expr ist dabei ein String und kann bei negativen Intervallen mit einem ‘-’ beginnen. type ist ein Schlüsselwort, das angibt, wie der Ausdruck zu interpretieren ist.

    Das Schlüsselwort INTERVAL und die Angabe type unterscheiden die Groß-/Kleinschreibung nicht.

    Die folgende Tabelle zeigt die erwartete Form des Arguments expr für die einzelnen type-Werte.

    type WertErwartetes expr-Format
    MICROSECONDMICROSECONDS
    SECONDSECONDS
    MINUTEMINUTES
    HOURHOURS
    DAYDAYS
    WEEKWEEKS
    MONTHMONTHS
    QUARTERQUARTERS
    YEARYEARS
    SECOND_MICROSECOND'SECONDS.MICROSECONDS'
    MINUTE_MICROSECOND'MINUTES.MICROSECONDS'
    MINUTE_SECOND'MINUTES:SECONDS'
    HOUR_MICROSECOND'HOURS.MICROSECONDS'
    HOUR_SECOND'HOURS:MINUTES:SECONDS'
    HOUR_MINUTE'HOURS:MINUTES'
    DAY_MICROSECOND'DAYS.MICROSECONDS'
    DAY_SECOND'DAYS HOURS:MINUTES:SECONDS'
    DAY_MINUTE'DAYS HOURS:MINUTES'
    DAY_HOUR'DAYS HOURS'
    YEAR_MONTH'YEARS-MONTHS'

    MySQL erlaubt die Verwendung beliebiger Interpunktionszeichen als Trennzeichen im Format von expr. Die in der Tabelle gezeigten Trennzeichen sind als Vorschläge aufzufassen. Wenn das Argument date ein DATE-Wert ist und Ihre Berechnungen nur die Teile YEAR, MONTH und DAY (also keine uhrzeitbezogenen Teile) betreffen, ist das Ergebnis ein DATE-Wert. Andernfalls ist das Ergebnis ein DATETIME-Wert.

    Datumsberechnungen können auch mit INTERVAL in Kombination mit den Operatoren + und - durchgeführt werden:

    date + INTERVAL expr type
    date - INTERVAL expr type
    

    INTERVAL expr type ist auf beiden Seiten des Operators + zulässig, wenn der Ausdruck auf der jeweils anderen Seite ein DATE- oder DATETIME-Wert ist. Beim Operator - ist INTERVAL expr type nur auf der rechten Seite der Gleichung zulässig, da das Abziehen eines DATE- oder DATETIME-Werts von einem Intervall unsinnig wäre.

    mysql> SELECT '1997-12-31 23:59:59' + INTERVAL 1 SECOND;
            -> '1998-01-01 00:00:00'
    mysql> SELECT INTERVAL 1 DAY + '1997-12-31';
            -> '1998-01-01'
    mysql> SELECT '1998-01-01' - INTERVAL 1 SECOND;
            -> '1997-12-31 23:59:59'
    mysql> SELECT DATE_ADD('1997-12-31 23:59:59',
        ->                 INTERVAL 1 SECOND);
            -> '1998-01-01 00:00:00'
    mysql> SELECT DATE_ADD('1997-12-31 23:59:59',
        ->                 INTERVAL 1 DAY);
            -> '1998-01-01 23:59:59'
    mysql> SELECT DATE_ADD('1997-12-31 23:59:59',
        ->                 INTERVAL '1:1' MINUTE_SECOND);
            -> '1998-01-01 00:01:00'
    mysql> SELECT DATE_SUB('1998-01-01 00:00:00',
        ->                 INTERVAL '1 1:1:1' DAY_SECOND);
            -> '1997-12-30 22:58:59'
    mysql> SELECT DATE_ADD('1998-01-01 00:00:00',
        ->                 INTERVAL '-1 10' DAY_HOUR);
            -> '1997-12-30 14:00:00'
    mysql> SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);
            -> '1997-12-02'
    mysql> SELECT DATE_ADD('1992-12-31 23:59:59.000002',
        ->            INTERVAL '1.999999' SECOND_MICROSECOND);
            -> '1993-01-01 00:00:01.000001'
    

    Wenn Sie einen Intervallwert angeben, der zu kurz ist (d. h. nicht alle Intervallteile enthält, die aufgrund des Schlüsselworts type erwartet werden), dann geht MySQL davon aus, dass Sie den linken Teil des Intervallwerts weggelassen haben. Geben Sie also etwa als type DAY_SECOND an, dann wird erwartet, dass der Wert von expr Teile für Tage, Stunden, Minuten und Sekunden enthält. Bei einer Angabe '1:10' setzt MySQL voraus, dass die Teile für Tage und Stunden fehlen und der Wert Minuten und Sekunden angibt. Anders gesagt, wird '1:10' DAY_SECOND als äquivalent zu '1:10' MINUTE_SECOND interpretiert. Dies entspricht auch der Art und Weise, wie MySQL TIME-Werte als verstrichene Zeit (statt als Uhrzeit) auffasst.

    Wenn Sie etwas zu einem Datum hinzuaddieren oder davon abziehen, das einen Uhrzeitteil enthält, dann wird das Ergebnis automatisch in einen DATETIME-Wert umgewandelt:

    mysql> SELECT DATE_ADD('1999-01-01', INTERVAL 1 DAY);
            -> '1999-01-02'
    mysql> SELECT DATE_ADD('1999-01-01', INTERVAL 1 HOUR);
            -> '1999-01-01 01:00:00'
    

    Wenn Sie MONTH, YEAR_MONTH oder YEAR hinzuaddieren und das Ergebnis einen Tageswert hat, der größer ist als der letzte Tag des neuen Monats, dann wird der Tag im neuen Monat auf den letzten Tag gesetzt:

    mysql> SELECT DATE_ADD('1998-01-30', INTERVAL 1 MONTH);
            -> '1998-02-28'
    

    Datumsberechnungen erfordern vollständige Datumsangaben; unvollständige Angaben wie '2005-07-00' oder erheblich fehlerhaft formatierte Werte wie die folgenden funktionieren nicht:

    mysql> SELECT DATE_ADD('2006-07-00', INTERVAL 1 DAY);
            -> NULL
    mysql> SELECT '2005-03-32' + INTERVAL 1 MONTH;
            -> NULL
    
  • DATE_FORMAT(date,format)

    Formatiert den Wert date entsprechend dem String format.

    Die folgenden Konfigurationsangaben können im String format verwendet werden. Das Zeichen ‘%’ ist vor jede Formatangabe zu setzen.

    KonfigurationsangabeBeschreibung
    %aAbgekürzter Name des Wochentags (Sun ... Sat)
    %bAbgekürzter Name des Monats (Jan ... Dec)
    %cMonat, numerisch (0 ... 12)
    %DTag im Monat mit englischem Suffix (0th, 1st, 2nd, 3rd, …)
    %dTag im Monat, numerisch (00 ... 31)
    %eTag im Monat, numerisch (0 ... 31)
    %fMikrosekunden (000000 ... 999999)
    %HStunde (00 ... 23)
    %hStunde (01 ... 12)
    %IStunde (01 ... 12)
    %iMinuten, numerisch (00 ... 59)
    %jTag im Jahr (001 ... 366)
    %kStunde (0 ... 23)
    %lStunde (1 ... 12)
    %MMonatsname (January ... December)
    %mMonat, numerisch (00 ... 12)
    %pAM oder PM
    %rUhrzeit im 12-Stunden-Format (hh:mm:ss gefolgt von AM oder PM)
    %SSekunden (00 ... 59)
    %sSekunden (00 ... 59)
    %TUhrzeit im 24-Stunden-Format (hh:mm:ss)
    %UWoche (00 ... 53), wobei Sonntag der erste Tag der Woche ist
    %uWoche (00 ... 53), wobei Montag der erste Tag der Woche ist
    %VWoche (01 ... 53), wobei Sonntag der erste Tag der Woche ist; wird mit %X verwendet
    %vWoche (01 ... 53), wobei Montag der erste Tag der Woche ist; wird mit %x verwendet
    %WName des Wochentags (Sunday ... Saturday)
    %wTag in der Woche (0=Sonntag ... 6=Sonnabend)
    %XJahr der Woche, wobei Sonntag der erste Tag der Woche ist, numerisch, vierstellig; wird mit %V verwendet
    %xJahr der Woche, wobei Montag der erste Tag der Woche ist, numerisch, vierstellig; wird mit %v verwendet
    %YJahr, numerisch, vierstellig
    %yJahr, numerisch, zweistellig
    %%Literales ‘%’-Zeichen
    %xx, steht für jedes nicht oben aufgeführte ‘x

    Da MySQL die Speicherung unvollständiger Daten wie '2004-00-00' gestattet, beginnen die Bereiche für die monats- und tagesbezogenen Konfigurationsangaben bei null.

    mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
            -> 'Saturday October 1997'
    mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
            -> '22:23:00'
    mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
                              '%D %y %a %d %m %b %j');
            -> '4th 97 Sat 04 10 Oct 277'
    mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
                              '%H %k %I %r %T %S %w');
            -> '22 22 10 10:23:00 PM 22:23:00 00 6'
    mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
            -> '1998 52'
    mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
            -> '00'
    
  • DAY(date)

    DAY() ist ein Synonym für DAYOFMONTH().

  • DAYNAME(date)

    Gibt den Namen des Wochentags für date zurück.

    mysql> SELECT DAYNAME('1998-02-05');
            -> 'Thursday'
    
  • DAYOFMONTH(date)

    Gibt den Tag im Monat für date zurück. Der Bereich liegt zwischen 0 und 31.

    mysql> SELECT DAYOFMONTH('1998-02-03');
            -> 3
    
  • DAYOFWEEK(date)

    Gibt den Wochentagindex für date zurück (1 = Sonntag, 2 = Montag, …, 7 = Sonnabend). Diese Indexwerte entsprechen dem ODBC-Standard.

    mysql> SELECT DAYOFWEEK('1998-02-03');
            -> 3
    
  • DAYOFYEAR(date)

    Gibt den Tag im Jahr für date zurück. Der Bereich liegt zwischen 1 und 366.

    mysql> SELECT DAYOFYEAR('1998-02-03');
            -> 34
    
  • EXTRACT(type FROM date)

    Die Funktion EXTRACT() verwendet dieselben Angaben für den Intervalltyp wie DATE_ADD() oder DATE_SUB(), extrahiert aber Teile des Datums, statt daran Berechnungen durchzuführen.

    mysql> SELECT EXTRACT(YEAR FROM '1999-07-02');
           -> 1999
    mysql> SELECT EXTRACT(YEAR_MONTH FROM '1999-07-02 01:02:03');
           -> 199907
    mysql> SELECT EXTRACT(DAY_MINUTE FROM '1999-07-02 01:02:03');
           -> 20102
    mysql> SELECT EXTRACT(MICROSECOND
        ->                FROM '2003-01-02 10:30:00.00123');
            -> 123
    
  • FROM_DAYS(N)

    Gibt für eine Tagesanzahl N den DATE-Wert zurück.

    mysql> SELECT FROM_DAYS(729669);
            -> '1997-10-07'
    

    Verwenden Sie FROM_DAYS() bei alten Datumsangaben mit Vorsicht. Die Funktion ist nicht zur Verwendung mit Daten gedacht, die vor der Einführung des gregorianischen Kalenders (1582) liegen. Siehe auch Abschnitt 12.6, „Welchen Kalender benutzt MySQL?“.

  • FROM_UNIXTIME(unix_timestamp), FROM_UNIXTIME(unix_timestamp,format)

    Gibt eine Darstellung des unix_timestamp-Arguments als Wert in den Formaten 'YYYY-MM-DD HH:MM:SS' oder YYYYMMDDHHMMSS zurück. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird. unix_timestamp ist ein interner Zeitstempelwert, der von der Funktion UNIX_TIMESTAMP() erzeugt wird.

    Wenn format angegeben ist, wird das Ergebnis entsprechend dem String format formatiert, der so verwendet wird wie im Abschnitt zur Funktion DATE_FORMAT() beschrieben.

    mysql> SELECT FROM_UNIXTIME(875996580);
            -> '1997-10-04 22:23:00'
    mysql> SELECT FROM_UNIXTIME(875996580) + 0;
            -> 19971004222300
    mysql> SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),
        ->                      '%Y %D %M %h:%i:%s %x');
            -> '2003 6th August 06:22:58 2003'
    

    Hinweis: Wenn Sie UNIX_TIMESTAMP() und FROM_UNIXTIME() zur Konvertierung zwischen TIMESTAMP-Werten und Unix-Zeitstempelwerten verwenden, ist die Konvertierung verlustbehaftet, weil die Zuordnung nicht in beiden Richtungen 1 : 1 erfolgt. Weitere Informationen entnehmen Sie der Beschreibung der Funktion UNIX_TIMESTAMP().

  • GET_FORMAT(DATE|TIME|DATETIME, 'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL')

    Gibt einen Format-String zurück. Diese Funktion ist praktisch in Verbindung mit den Funktionen DATE_FORMAT() und STR_TO_DATE().

    Die zulässigen Werte für das erste und zweite Argument ergeben verschiedene Möglichkeiten für Format-Strings. (Die Konfigurationsangaben entnehmen Sie der Tabelle in der Beschreibung zu DATE_FORMAT().) Das ISO-Format verweist auf ISO 9075, nicht auf ISO 8601.

    FunktionsaufrufErgebnis
    GET_FORMAT(DATE,'USA')'%m.%d.%Y'
    GET_FORMAT(DATE,'JIS')'%Y-%m-%d'
    GET_FORMAT(DATE,'ISO')'%Y-%m-%d'
    GET_FORMAT(DATE,'EUR')'%d.%m.%Y'
    GET_FORMAT(DATE,'INTERNAL')'%Y%m%d'
    GET_FORMAT(DATETIME,'USA')'%Y-%m-%d-%H.%i.%s'
    GET_FORMAT(DATETIME,'JIS')'%Y-%m-%d %H:%i:%s'
    GET_FORMAT(DATETIME,'ISO')'%Y-%m-%d %H:%i:%s'
    GET_FORMAT(DATETIME,'EUR')'%Y-%m-%d-%H.%i.%s'
    GET_FORMAT(DATETIME,'INTERNAL')'%Y%m%d%H%i%s'
    GET_FORMAT(TIME,'USA')'%h:%i:%s %p'
    GET_FORMAT(TIME,'JIS')'%H:%i:%s'
    GET_FORMAT(TIME,'ISO')'%H:%i:%s'
    GET_FORMAT(TIME,'EUR')'%H.%i.%S'
    GET_FORMAT(TIME,'INTERNAL')'%H%i%s'

    TIMESTAMP kann auch als erstes Argument für GET_FORMAT() verwendet werden. In diesem Fall gibt die Funktion dieselben Werte wie bei DATETIME zurück.

    mysql> SELECT DATE_FORMAT('2003-10-03',GET_FORMAT(DATE,'EUR'));
            -> '03.10.2003'
    mysql> SELECT STR_TO_DATE('10.31.2003',GET_FORMAT(DATE,'USA'));
            -> '2003-10-31'
    
  • HOUR(time)

    Gibt die Stundenangabe in time zurück. Der Bereich des Rückgabewerts liegt zwischen 0 und 23 bei Tageszeitwerten. Allerdings ist der zulässige Bereich für TIME wesentlich größer, d. h., HOUR kann Werte zurückgeben, die größer als 23 sind.

    mysql> SELECT HOUR('10:05:03');
            -> 10
    mysql> SELECT HOUR('272:59:59');
            -> 272
    
  • LAST_DAY(date)

    Nimmt einen DATE- oder DATETIME-Wert entgegen und gibt den entsprechenden Wert des letzten Tages des betreffenden Monats zurück. Gibt NULL zurück, wenn das Argument unzulässig ist.

    mysql> SELECT LAST_DAY('2003-02-05');
            -> '2003-02-28'
    mysql> SELECT LAST_DAY('2004-02-05');
            -> '2004-02-29'
    mysql> SELECT LAST_DAY('2004-01-01 01:01:01');
            -> '2004-01-31'
    mysql> SELECT LAST_DAY('2003-03-32');
            -> NULL
    
  • LOCALTIME, LOCALTIME()

    LOCALTIME und LOCALTIME() sind Synonyme von NOW().

  • LOCALTIMESTAMP, LOCALTIMESTAMP()

    LOCALTIMESTAMP und LOCALTIMESTAMP() sind Synonyme von NOW().

  • MAKEDATE(year,dayofyear)

    Gibt ein Datum zurück, welches auf den übergebenen Werten für das Jahr und den Tag im Jahr basiert. dayofyear muss größer als 0 sein, andernfalls ist das Ergebnis NULL.

    mysql> SELECT MAKEDATE(2001,31), MAKEDATE(2001,32);
            -> '2001-01-31', '2001-02-01'
    mysql> SELECT MAKEDATE(2001,365), MAKEDATE(2004,365);
            -> '2001-12-31', '2004-12-30'
    mysql> SELECT MAKEDATE(2001,0);
            -> NULL
    
  • MAKETIME(hour,minute,second)

    Gibt einen Zeitwert zurück, der aus den Argumenten hour, minute und second berechnet wird.

    mysql> SELECT MAKETIME(12,15,30);
            -> '12:15:30'
    
  • MICROSECOND(expr)

    Gibt die Anzahl der Mikrosekunden für den übergebenen TIME- oder DATETIME-Ausdruck expr als Zahl im Bereich zwischen 0 und 999999 zurück.

    mysql> SELECT MICROSECOND('12:00:00.123456');
            -> 123456
    mysql> SELECT MICROSECOND('1997-12-31 23:59:59.000010');
            -> 10
    
  • MINUTE(time)

    Gibt die Minute für time im Bereich zwischen 0 und 59 zurück.

    mysql> SELECT MINUTE('98-02-03 10:05:03');
            -> 5
    
  • MONTH(date)

    Gibt den Monat für date im Bereich zwischen 0 und 12 zurück.

    mysql> SELECT MONTH('1998-02-03');
            -> 2
    
  • MONTHNAME(date)

    Gibt den vollständigen Namen des Monats für date zurück.

    mysql> SELECT MONTHNAME('1998-02-05');
            -> 'February'
    
  • NOW()

    Gibt die aktuellen Werte für Datum und Uhrzeit als Wert in den Formaten YYYYMMDDHHMMSS oder 'YYYY-MM-DD HH:MM:SS' aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT NOW();
            -> '1997-12-15 23:50:26'
    mysql> SELECT NOW() + 0;
            -> 19971215235026
    

    Aus einer gespeicherten Routine oder einem Trigger heraus gibt NOW() einen Zeitpunkt als Konstante zurück, zu dem die Ausführung der Routine bzw. des Triggers begann. Hier liegt ein Unterschied zum Verhalten von SYSDATE() vor, welches die exakte Zeit seiner Ausführung zurückgibt.

  • PERIOD_ADD(P,N)

    Fügt N Monate zum Zeitraum P (im Format YYMM oder YYYYMM) hinzu. Gibt einen Wert im Format YYYYMM zurück. Beachten Sie, dass das Zeitraumargument P kein Datumswert ist.

    mysql> SELECT PERIOD_ADD(9801,2);
            -> 199803
    
  • PERIOD_DIFF(P1,P2)

    Gibt die Anzahl der Monate zwischen den Zeiträumen P1 und P2 zurück. P1 und P2 sollten im Format YYMM oder YYYYMM übergeben werden. Beachten Sie, dass die Zeitraumargumente P1 und P2 keine Datumswerte sind.

    mysql> SELECT PERIOD_DIFF(9802,199703);
            -> 11
    
  • QUARTER(date)

    Gibt das Quartal im Jahr für date zurück. Der Bereich liegt zwischen 1 und 4.

    mysql> SELECT QUARTER('98-04-01');
            -> 2
    
  • SECOND(time)

    Gibt die Sekunde für time im Bereich zwischen 0 und 59 zurück.

    mysql> SELECT SECOND('10:05:03');
            -> 3
    
  • SEC_TO_TIME(seconds)

    Gibt das Argument seconds, konvertiert in Stunden, Minuten und Sekunden, als Wert in den Formaten 'HH:MM:SS' oder HHMMSS aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT SEC_TO_TIME(2378);
            -> '00:39:38'
    mysql> SELECT SEC_TO_TIME(2378) + 0;
            -> 3938
    
  • STR_TO_DATE(str,format)

    Dies ist die Umkehrung der Funktion DATE_FORMAT(). Sie nimmt einen String str und einen Format-String format entgegen. STR_TO_DATE() gibt einen DATETIME-Wert zurück, wenn der Format-String sowohl Datums- als auch Uhrzeitteile enthält, oder einen DATE- TIME-Wert, wenn der String nur Datums- bzw. Uhrzeitteile umfasst.

    Die DATE-, TIME- oder DATETIME-Werte, die in str enthalten sind, sollten in dem Format angegeben werden, das durch format spezifiziert wurde. Informationen zu den in format verwendbaren Konfigurationsangaben finden Sie in der Beschreibung zur Funktion DATE_FORMAT(). Wenn str einen unzulässigen DATE-, TIME- oder DATETIME-Wert enthält, gibt STR_TO_DATE() NULL zurück. Außerdem erzeugt ein unzulässiger Wert eine Warnung.

    Die Bereichsprüfung der Teile von Datumswerten erfolgt wie in Abschnitt 11.3.1, „Die DATETIME-, DATE- und TIMESTAMP-Typen“, beschrieben. Das bedeutet, dass „Nulldaten“ oder solche, bei denen Bestandteile 0 sind, zulässig sind, sofern dem nicht der aktive SQL-Modus widerspricht.

    mysql> SELECT STR_TO_DATE('00/00/0000', '%m/%d/%Y');
            -> '0000-00-00'
    mysql> SELECT STR_TO_DATE('04/31/2004', '%m/%d/%Y');
            -> '2004-04-31'
    
  • SUBDATE(date,INTERVAL expr type), SUBDATE(expr,days)

    Wenn mit der Form INTERVAL für das zweite Argument aufgerufen wird, ist SUBDATE() ein Synonym von DATE_SUB(). Weitere Informationen zum Argument INTERVAL finden Sie in der Beschreibung zu DATE_ADD().

    mysql> SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);
            -> '1997-12-02'
    mysql> SELECT SUBDATE('1998-01-02', INTERVAL 31 DAY);
            -> '1997-12-02'
    

    Die zweite Form gestattet die Verwendung eines Integer-Werts für days. In solchen Fällen wird der Wert als Anzahl von Tagen interpretiert, die vom DATE- oder DATETIME-Ausdruck expr abgezogen werden.

    mysql> SELECT SUBDATE('1998-01-02 12:00:00', 31);
            -> '1997-12-02 12:00:00'
    

    Hinweis: Sie können mit dem Format "%X%V" keine Konvertierung eines aus einer Jahres- und einer Wochenangabe bestehenden Strings in ein Datum durchführen, weil diese Kombination nicht eindeutig ein Jahr und einen Monat bezeichnet, wenn eine Woche eine Monatsgrenze überschreitet. Insofern müssen Sie, wenn Sie eine Jahr-/Wochen-Kombination in ein Datum umwandeln wollen, auch den Wochentag angeben:

    mysql> SELECT STR_TO_DATE('200442 Monday', '%X%V %W');
            -> '2004-10-18'
    
  • SUBTIME(expr,expr2)

    SUBTIME() zieht expr2 von expr ab und gibt das Ergebnis zurück. expr ist eine Uhrzeitangabe oder ein DATETIME-Wert, expr2 eine Uhrzeitangabe.

    mysql> SELECT SUBTIME('1997-12-31 23:59:59.999999','1 1:1:1.000002');
            -> '1997-12-30 22:58:58.999997'
    mysql> SELECT SUBTIME('01:00:00.999999', '02:00:00.999998');
            -> '-00:59:59.999999'
    
  • SYSDATE()

    Gibt die aktuellen Werte für Datum und Uhrzeit als Wert in den Formaten YYYYMMDDHHMMSS oder 'YYYY-MM-DD HH:MM:SS' aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    Aus einer gespeicherten Routine oder einem Trigger heraus gibt SYSDATE() die Zeit zurück, zu der sie ausgeführt wird. Dies unterscheidet sich vom Verhalten von NOW(), welches die Uhrzeit zurückgibt, zu der die Ausführung der Routine- oder Trigger-Anweisung begann.

  • TIME(expr)

    Extrahiert den Zeitbestandteil des TIME- oder DATETIME-Ausdrucks expr und gibt diesen als String zurück.

    mysql> SELECT TIME('2003-12-31 01:02:03');
            -> '01:02:03'
    mysql> SELECT TIME('2003-12-31 01:02:03.000123');
            -> '01:02:03.000123'
    
  • TIMEDIFF(expr,expr2)

    TIMEDIFF() gibt den Zeitraum zwischen der Startzeit expr und der Endzeit expr2 zurück. expr und expr2 sind Zeit- oder DATETIME-Ausdrücke, müssen aber vom selben Typ sein.

    mysql> SELECT TIMEDIFF('2000:01:01 00:00:00',
        ->                 '2000:01:01 00:00:00.000001');
            -> '-00:00:00.000001'
    mysql> SELECT TIMEDIFF('1997-12-31 23:59:59.000001',
        ->                 '1997-12-30 01:01:01.000002');
            -> '46:58:57.999999'
    
  • TIMESTAMP(expr), TIMESTAMP(expr,expr2)

    Bei nur einem Argument gibt diese Funktion den Datums- oder DATETIME-Ausdruck expr als DATETIME-Wert zurück. Bei zwei Argumenten wird der Zeitausdruck expr2 zum Datums- oder DATETIME-Ausdruck expr hinzugefügt und das Ergebnis als DATETIME-Wert zurückgegeben.

    mysql> SELECT TIMESTAMP('2003-12-31');
            -> '2003-12-31 00:00:00'
    mysql> SELECT TIMESTAMP('2003-12-31 12:00:00','12:00:00');
            -> '2004-01-01 00:00:00'
    
  • TIMESTAMPADD(interval,int_expr,datetime_expr)

    Fügt den Integer-Ausdruck int_expr zum Datums- oder DATETIME-Ausdruck datetime_expr hinzu. Die Einheit für int_expr wird durch das Argument interval angegeben, das einen der folgenden Werte haben sollte: FRAC_SECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER oder YEAR.

    Der interval-Wert kann mithilfe eines der angegebenen Schlüsselwörter oder mit dem Präfix SQL_TSI_ angegeben werden. Beispielsweise sind sowohl DAY als auch SQL_TSI_DAY zulässig.

    mysql> SELECT TIMESTAMPADD(MINUTE,1,'2003-01-02');
            -> '2003-01-02 00:01:00'
    mysql> SELECT TIMESTAMPADD(WEEK,1,'2003-01-02');
            -> '2003-01-09'
    
  • TIMESTAMPDIFF(interval,datetime_expr1,datetime_expr2)

    Gibt den Unterschied zwischen den Datums- oder DATETIME-Ausdrücken datetime_expr1 und datetime_expr2 zurück. Die Einheit für das Ergebnis wird über das Argument interval angegeben. Die zulässigen Werte für interval entsprechen den in der Beschreibung zu TIMESTAMPADD() aufgelisteten Optionen.

    mysql> SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');
            -> 3
    mysql> SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');
            -> -1
    
  • TIME_FORMAT(time,format)

    Wird wie die Funktion DATE_FORMAT() verwendet, der String format darf aber nur Formatangaben für Stunden, Minuten und Sekunden enthalten. Andere Konfigurationsangaben erzeugen einen NULL-Wert oder 0.

    Wenn der time-Wert einen Stundenbestandteil enthält, der größer als 23 ist, erzeugen die Stundenformatangaben %H und %k einen Wert, der größer ist als der normale Bereich 0 ... 23. Die übrigen Konfigurationsangaben für das Stundenformat erzeugen den Stundenwert mod 12.

    mysql> SELECT TIME_FORMAT('100:00:00', '%H %k %h %I %l');
            -> '100 100 04 04 4'
    
  • TIME_TO_SEC(time)

    Gibt das Argument time in Sekunden konvertiert zurück.

    mysql> SELECT TIME_TO_SEC('22:23:00');
            -> 80580
    mysql> SELECT TIME_TO_SEC('00:39:38');
            -> 2378
    
  • TO_DAYS(date)

    Gibt zu einem Datum date eine Anzahl von Tagen zurück. Diese gibt die Anzahl der seit dem Jahr 0 bis zu diesem Datum verstrichenen Tage zurück.

    mysql> SELECT TO_DAYS(950501);
            -> 728779
    mysql> SELECT TO_DAYS('1997-10-07');
            -> 729669
    

    TO_DAYS() ist nicht für die Verwendung mit Werten geeignet, die vor der Einführung des gregorianischen Kalenders (1582) liegen, da die bei der Kalenderumstellung „verlorenen“ Tage von der Funktion nicht berücksichtigt werden. Bei Daten vor 1582 (und standortabhängig möglicherweise auch danach) sind die Ergebnisse dieser Funktion nicht zuverlässig. Weitere Informationen finden Sie in Abschnitt 12.6, „Welchen Kalender benutzt MySQL?“.

    Denken Sie daran, dass MySQL zweistellige Jahresangaben unter Verwendung der in Abschnitt 11.3, „Datums- und Zeittypen“, beschriebenen Regeln in das vierstellige Format umwandelt. Beispielsweise werden '1997-10-07' und '97-10-07' als identische Daten betrachtet.

    mysql> SELECT TO_DAYS('1997-10-07'), TO_DAYS('97-10-07');
            -> 729669, 729669
    
  • UNIX_TIMESTAMP(), UNIX_TIMESTAMP(date)

    Sofern ohne Argument aufgerufen, gibt die Funktion einen Unix-Zeitstempel (Sekunden seit '1970-01-01 00:00:00' im UTC-Format) als vorzeichenlosen Integer zurück. Wenn UNIX_TIMESTAMP() mit einem Argument date aufgerufen wird, gibt es den Wert des Arguments als seit dem Zeitpunkt '1970-01-01 00:00:00' (UTC) verstrichene Sekunden zurück. date kann ein DATE-String, ein DATETIME-String, ein TIMESTAMP oder eine Zahl im Format YYMMDD oder YYYYMMDD sein. Der Server interpretiert date als Wert in der aktuellen Zeitzone und wandelt es in einen internen Wert in UTC um. Clients können ihre Zeitzone wie in Abschnitt 5.11.8, „Zeitzonen-Unterstützung des MySQL-Servers“, beschrieben einstellen.

    mysql> SELECT UNIX_TIMESTAMP();
            -> 882226357
    mysql> SELECT UNIX_TIMESTAMP('1997-10-04 22:23:00');
            -> 875996580
    

    Wenn UNIX_TIMESTAMP für eine TIMESTAMP-Spalte verwendet wird, gibt die Funktion den internen Zeitstempelwert direkt zurück, d. h. ohne implizite Konvertierung des Strings in einen Unix-Zeitstempel. Wenn Sie einen Wert außerhalb des zulässigen Bereichs an UNIX_TIMESTAMP() übergeben, wird 0 zurückgegeben.

    Hinweis: Wenn Sie UNIX_TIMESTAMP() und FROM_UNIXTIME() zur Konvertierung zwischen TIMESTAMP-Werten und Unix-Zeitstempelwerten verwenden, ist die Konvertierung verlustbehaftet, weil die Zuordnung nicht in beiden Richtungen 1 : 1 erfolgt. Beispielsweise kann es aufgrund der Konventionen zur Änderung der lokalen Zeitzone möglich sein, dass zwei UNIX_TIMESTAMP()-Funktionen zwei TIMESTAMP-Werte in denselben Unix-Zeitstempelwert umwandeln. FROM_UNIXTIME() wiederum konvertiert den Wert dann in nur einen der ursprünglichen TIMESTAMP-Werte zurück. Es folgt ein Beispiel unter Verwendung von TIMESTAMP-Werten in der Zeitzone CET (mitteleuropäische Zeit):

    mysql> SELECT UNIX_TIMESTAMP('2005-03-27 03:00:00');
    +---------------------------------------+
    | UNIX_TIMESTAMP('2005-03-27 03:00:00') |
    +---------------------------------------+
    |                            1111885200 |
    +---------------------------------------+
    mysql> SELECT UNIX_TIMESTAMP('2005-03-27 02:00:00');
    +---------------------------------------+
    | UNIX_TIMESTAMP('2005-03-27 02:00:00') |
    +---------------------------------------+
    |                            1111885200 |
    +---------------------------------------+
    mysql> SELECT FROM_UNIXTIME(1111885200);
    +---------------------------+
    | FROM_UNIXTIME(1111885200) |
    +---------------------------+
    | 2005-03-27 03:00:00       |
    +---------------------------+
    

    Wenn Sie UNIX_TIMESTAMP()-Spalten subtrahieren wollen, sollten Sie das Ergebnis in vorzeichenbehaftete Integers umwandeln. Siehe auch Abschnitt 12.8, „Cast-Funktionen und Operatoren“.

  • UTC_DATE, UTC_DATE()

    Gibt das aktuelle UTC-Datum als Wert in den Formaten 'YYYY-MM-DD' oder YYYYMMDD aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT UTC_DATE(), UTC_DATE() + 0;
            -> '2003-08-14', 20030814
    
  • UTC_TIME, UTC_TIME()

    Gibt die aktuelle UTC-Uhrzeit als Wert in den Formaten 'HH:MM:SS' oder HHMMSS aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT UTC_TIME(), UTC_TIME() + 0;
            -> '18:07:53', 180753
    
  • UTC_TIMESTAMP, UTC_TIMESTAMP()

    Gibt die aktuellen UTC-Werte für Datum und Uhrzeit als Wert in den Formaten YYYYMMDDHHMMSS oder 'YYYY-MM-DD HH:MM:SS' aus. Das Ausgabeformat hängt davon ab, ob die Funktion in einem String- oder einem numerischen Kontext verwendet wird.

    mysql> SELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() + 0;
            -> '2003-08-14 18:08:04', 20030814180804
    
  • WEEK(date[,mode])

    Diese Funktion gibt die Nummer der Woche für date zurück. Wird WEEK() mit zwei Argumenten verwendet, dann gestattet Ihnen die Funktion die Angabe, ob die Woche am Sonntag oder Montag beginnt und ob der Rückgabewert im Bereich zwischen 0 und 53 oder 1 und 53 liegen soll. Wird das Argument mode weggelassen, so wird der Wert der Systemvariablen default_week_format verwendet. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

    Die folgende Tabelle beschreibt, wie das Argument mode funktioniert.

     Erster  
    ModusWochentagBereichWoche 1 ist die erste Woche …
    0Sonntag0–53mit einem Sonntag in diesem Jahr
    1Montag0–53mit mehr als drei Tagen innerhalb dieses Jahres
    2Sonntag1–53mit einem Sonntag in diesem Jahr
    3Montag1–53mit mehr als drei Tagen innerhalb dieses Jahres
    4Sonntag0–53mit mehr als drei Tagen innerhalb dieses Jahres
    5Montag0–53mit einem Montag in diesem Jahr
    6Sonntag1–53mit mehr als drei Tagen innerhalb dieses Jahres
    7Montag1–53mit einem Montag in diesem Jahr
    mysql> SELECT WEEK('1998-02-20');
            -> 7
    mysql> SELECT WEEK('1998-02-20',0);
            -> 7
    mysql> SELECT WEEK('1998-02-20',1);
            -> 8
    mysql> SELECT WEEK('1998-12-31',1);
            -> 53
    

    Beachten Sie, dass, wenn ein Datum in die letzte Woche des vorherigen Jahres fällt, MySQL 0 zurückgibt, sofern Sie nicht 2, 3, 6 oder 7 als optionales mode-Argument angeben:

    mysql> SELECT YEAR('2000-01-01'), WEEK('2000-01-01',0);
            -> 2000, 0
    

    Man könnte nun anführen, dass MySQL doch eigentlich 52 für die Funktion WEEK() zurückgeben sollte, da das angegebene Datum eigentlich in der 52. Woche des Jahres 1999 liegt. Wir haben aber beschlossen, stattdessen 0 zurückgeben zu lassen, weil die Funktion „Nummer der Woche im angegebenen Jahr“ zurückgeben soll. Dies macht die Verwendung der Funktion WEEK() zuverlässig, wenn sie mit anderen Funktionen kombiniert wird, die einen Tagesbestandteil aus dem Datum extrahieren.

    Wenn Sie eine Auswertung des Ergebnisses in Bezug auf das Jahr vorziehen, das den ersten Tag der Woche des angegebenen Datums enthält, dann verwenden Sie 0, 2, 5 oder 7 als optionales mode-Argument.

    mysql> SELECT WEEK('2000-01-01',2);
            -> 52
    

    Alternativ verwenden Sie die Funktion YEARWEEK():

    mysql> SELECT YEARWEEK('2000-01-01');
            -> 199952
    mysql> SELECT MID(YEARWEEK('2000-01-01'),5,2);
            -> '52'
    
  • WEEKDAY(date)

    Gibt den Wochentagindex für date zurück (0 = Montag, 1 = Dienstag, …, 6 = Sonntag).

    mysql> SELECT WEEKDAY('1998-02-03 22:23:00');
            -> 1
    mysql> SELECT WEEKDAY('1997-11-05');
            -> 2
    
  • WEEKOFYEAR(date)

    Gibt die Kalenderwoche des Datums als Zahl im Bereich zwischen 1 und 53 zurück. WEEKOFYEAR() ist eine Kompatibilitätsfunktion, die äquivalent zu WEEK(date,3) ist.

    mysql> SELECT WEEKOFYEAR('1998-02-20');
            -> 8
    
  • YEAR(date)

    Gibt das Jahr für date im Bereich zwischen 1000 und 9999 oder aber 0 für das „Nulldatum“ zurück.

    mysql> SELECT YEAR('98-02-03');
            -> 1998
    
  • YEARWEEK(date), YEARWEEK(date,start)

    Gibt Jahr und Woche für ein Datum zurück. Das Argument start funktioniert ganz genauso wie das Argument start für WEEK(). Das Jahr im Ergebnis kann sich im Falle der ersten und der letzten Woche des Jahres vom Jahr im Datumsargument unterscheiden.

    mysql> SELECT YEARWEEK('1987-01-01');
            -> 198653
    

    Beachten Sie, dass die Wochennummer sich von dem, was die Funktion WEEK() für ihre optionalen Argumente 0 oder 1 zurückgäbe (nämlich 0), unterscheidet, denn WEEK() gibt die Woche im Kontext des angegebenen Jahres zurück.

12.6. Welchen Kalender benutzt MySQL?

MySQL verwendet den so genannten proleptischen gregorianischen Kalender.

Jedes Land, das die Zeitrechnung vom julianischen auf den gregorianischen Kalender umgestellt hat, hat bei dieser Umstellung mindestens zehn Tage verloren. Um zu verstehen, wie dies funktioniert, betrachten Sie den Oktober 1582, als die erste Umstellung vom julianischen auf den gregorianischen Kalender erfolgte:

MontagDienstagMittwochDonnerstagFreitagSonnabendSonntag
1234151617
18192021222324
25262728293031

Zwischen dem 4. und dem 15. Oktober liegen keine Daten. Diese Unstetigkeit nennt man Ausschaltung. Alle Daten vor der Ausschaltung waren julianisch, alle nachfolgenden gregorianisch. Die Daten während der Ausschaltung existieren schlichtweg nicht.

Ein Kalender, der für Daten angewendet wird, zu deren Zeit er (noch) nicht verwendet wurde, heißt proleptisch. Auf diese Weise haben wir, wenn wir voraussetzen, dass niemals eine Ausschaltung stattgefunden hat und die Regeln des gregorianischen Kalenders immer gegolten haben, einen proleptischen gregorianischen Kalender. Diesen verwenden wir entsprechend der Vorgabe von SQL auch bei MySQL. Aus diesem Grund müssen vor der Ausschaltung liegende Daten, die als DATE- oder DATETIME-Werte in MySQL gespeichert werden, angepasst werden, um den Unterschied auszugleichen. Wichtig ist in diesem Zusammenhang die Tatsache, dass die Ausschaltung nicht in allen Ländern gleichzeitig erfolgte und dass umso mehr Tage verloren gingen, je später sie erfolgte. In Großbritannien beispielsweise fand sie 1752 statt, als auf Mittwoch, den 2. September, Donnerstag, der 14. September, folgte. Russland behielt den julianischen Kalender bis 1918 bei und verlor bei der Umstellung 13 Tage – was auch bedeutet, dass die berühmte Oktoberrevolution eigentlich im November stattfand.

12.7. MySQL-Volltextsuche

  • MATCH (col1,col2,...) AGAINST (expr [IN BOOLEAN MODE | WITH QUERY EXPANSION])

    MySQL unterstützt die Volltextindizierung und -suche. Ein Volltextindex ist in MySQL ein Index des Typs FULLTEXT. FULLTEXT-Indizes können nur bei MyISAM-Tabellen eingesetzt werden. Sie lassen sich für CHAR-, VARCHAR- und TEXT-Spalten mit CREATE TABLE erstellen oder mit ALTER TABLE oder CREATE INDEX im Nachhinein hinzufügen. Bei größeren Datenmengen erfolgt das Laden Ihrer Daten in eine Tabelle ohne FULLTEXT-Index und das nachfolgende Erstellen des Indexes wesentlich schneller als das Einladen in eine Tabelle mit vorhandenem FULLTEXT-Index.

    Hinweise zu Einschränkungen bei der Volltextsuche finden Sie in Abschnitt 12.7.4, „Beschränkungen der Volltextsuche“.

Die Volltextsuche wird mit der Funktion MATCH() ausgeführt.

mysql> CREATE TABLE articles (
    ->   id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
    ->   title VARCHAR(200),
    ->   body TEXT,
    ->   FULLTEXT (title,body)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO articles (title,body) VALUES
    -> ('MySQL Tutorial','DBMS stands for DataBase ...'),
    -> ('How To Use MySQL Well','After you went through a ...'),
    -> ('Optimizing MySQL','In this tutorial we will show ...'),
    -> ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
    -> ('MySQL vs. YourSQL','In the following database comparison ...'),
    -> ('MySQL Security','When configured properly, MySQL ...');
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM articles
    -> WHERE MATCH (title,body) AGAINST ('database');
+----+-------------------+------------------------------------------+
| id | title             | body                                     |
+----+-------------------+------------------------------------------+
|  5 | MySQL vs. YourSQL | In the following database comparison ... |
|  1 | MySQL Tutorial    | DBMS stands for DataBase ...             |
+----+-------------------+------------------------------------------+
2 rows in set (0.00 sec)

Die Funktion MATCH() führt eine natursprachliche Suche nach einem String in einer Textsammlung durch. Eine Sammlung ist eine Menge von einer oder mehreren Spalten, die Bestandteil eines FULLTEXT-Indexes sind. Der Such-String wird als Argument an AGAINST() übergeben. Für jeden Datensatz in der Tabelle gibt MATCH() einen Relevanzwert zurück, d. h. eine Maßangabe für die Ähnlichkeit zwischen dem Such-String und dem Text in den in MATCH() aufgelisteten Spalten dieses Datensatzes.

Standardmäßig wird die Suche ohne Unterscheidung der Groß-/Kleinschreibung durchgeführt. Sie können jedoch auch eine Suche unter Berücksichtigung der Groß-/Kleinschreibung durchführen, indem Sie eine binäre Sortierung für die indizierten Spalten verwenden. So können Sie etwa einer Spalte, die den Zeichensatz latin1 verwendet, die Sortierung latin1_bin zuweisen, damit bei der Volltextsuche die Groß-/Kleinschreibung unterschieden wird.

Wenn MATCH() in einer WHERE-Klausel verwendet wird (vgl. obiges Beispiel), dann werden die zurückgegebenen Datensätze automatisch nach absteigender Relevanz sortiert. Relevanzwerte sind nichtnegative Fließkommazahlen. Nullrelevanz bezeichnet keinerlei Ähnlichkeit. Die Relevanz wird auf der Basis der Anzahl der Wörter im Datensatz, der Anzahl eindeutiger Wörter im Datensatz, der Gesamtanzahl der Wörter in der Sammlung und der Anzahl der Dokumente (Datensätze) berechnet, die ein bestimmtes Wort enthalten.

Bei der natursprachlichen Volltextsuche ist es erforderlich, dass die in der MATCH()-Funktion genannten Spalten dieselben Spalten sind, die in einem in Ihrer Tabelle vorhandenen FULLTEXT-Index enthalten sind. Beachten Sie bei der obigen Abfrage, dass die in der MATCH()-Funktion aufgeführten Spalten (title und body) dieselben sind, die in der Definition des FULLTEXT-Indexes der Tabelle article genannt sind. Sollten Sie nun title oder body separat durchsuchen wollen, dann müssten Sie für jede Spalte separate FULLTEXT-Indizes erstellen.

Es ist auch möglich, eine boolesche Suche oder eine Suche mit Abfrageerweiterung durchzuführen. Diese Suchtypen sind in Abschnitt 12.7.1, „Boolesche Volltextsuche“, und Abschnitt 12.7.2, „Volltextsuche mit Abfragenerweiterung“, beschrieben.

Das obige Beispiel ist eine einfache Veranschaulichung, die zeigt, wie man die Funktion MATCH() verwendet, wobei Datensätze nach absteigender Relevanz sortiert zurückgegeben werden. Das nächste Beispiel zeigt, wie man die Relevanzwerte explizit abruft. Zurückgegebene Datensätze werden nicht sortiert, weil die SELECT-Anweisung weder eine WHERE- noch eine ORDER BY-Klausel enthält:

mysql> SELECT id, MATCH (title,body) AGAINST ('Tutorial')
    -> FROM articles;
+----+-----------------------------------------+
| id | MATCH (title,body) AGAINST ('Tutorial') |
+----+-----------------------------------------+
|  1 |                        0.65545833110809 |
|  2 |                                       0 |
|  3 |                        0.66266459226608 |
|  4 |                                       0 |
|  5 |                                       0 |
|  6 |                                       0 |
+----+-----------------------------------------+
6 rows in set (0.00 sec)

Das folgende Beispiel ist komplexer. Die Abfrage gibt die Relevanzwerte zurück und sortiert die Datensätze zudem nach absteigender Relevanz. Um dieses Ergebnis zu erhalten, sollten Sie MATCH() zweimal angeben: einmal in der SELECT-Liste und ein weiteres Mal in der WHERE-Klausel. Hierdurch wird die Systembelastung nicht erhöht, da der MySQL-Optimierer bemerkt, dass die beiden MATCH()-Aufrufe identisch sind, und den Code für die Volltextsuche insofern nur einmal aufruft.

mysql> SELECT id, body, MATCH (title,body) AGAINST
    -> ('Security implications of running MySQL as root') AS score
    -> FROM articles WHERE MATCH (title,body) AGAINST
    -> ('Security implications of running MySQL as root');
+----+-------------------------------------+-----------------+
| id | body                                | score           |
+----+-------------------------------------+-----------------+
|  4 | 1. Never run mysqld as root. 2. ... | 1.5219271183014 |
|  6 | When configured properly, MySQL ... | 1.3114095926285 |
+----+-------------------------------------+-----------------+
2 rows in set (0.00 sec)

Die FULLTEXT-Implementierung von MySQL betrachtet alle Folgen echter Wortzeichen (Buchstaben, Ziffern und Unterstriche) als Wort. Die Folge kann auch Apostrophe (') enthalten, aber nur eines je Datensatz. Das bedeutet, dass aaa'bbb als ein Wort betrachtet wird, aaa''bbb hingegen als zwei Wörter. Apostrophe am Anfang oder Ende eines Wortes werden vom FULLTEXT-Parser entfernt, d. h., er verarbeitet 'aaa'bbb' als aaa'bbb.

Der FULLTEXT-Parser bestimmt anhand bestimmter Trennzeichen wie ‘ ’ (Leerzeichen), ‘,’ (Komma), und ‘.’ (Punkt), wo Wörter anfangen und enden. Wenn Wörter nicht durch Trennzeichen getrennt werden (wie es beispielsweise im Chinesischen der Fall ist), kann der FULLTEXT-Parser nicht ermitteln, wo ein Wort beginnt oder endet. Damit Wörter oder andere indizierte Begriffe in solchen Sprachen einem FULLTEXT-Index hinzugefügt werden können, müssen Sie eine Vorabverarbeitung durchführen und sie so durch ein beliebiges Trennzeichen (z. B. ‘"’) voneinander abtrennen.

In MySQL 5.1 ist es möglich, ein Plug-In zu schreiben, das den integrierten Volltext-Parser ersetzt. Detaillierte Informationen finden Sie in Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“. Ein Beispiel für den Quellcode eines solchen Parser-Plug-Ins finden Sie im Verzeichnis plugin/fulltext einer MySQL-Quelldistribution.

Einige Wörter werden bei der Volltextsuche ignoriert:

  • Ignoriert werden alle Wörter, die zu kurz sind. Die standardmäßige Mindestlänge von Wörtern, die von der Volltextsuche gefunden werden, beträgt vier Zeichen.

  • Auch Wörter, die auf der Liste der Stoppwörter stehen, werden ignoriert. Ein Stoppwort ist ein Wort wie „the“ oder „some“, das so verbreitet ist, dass sein semantischer Wert als vernachlässigbar betrachtet wird. Es gibt eine bereits vorhandene Liste mit Stoppwörtern, die aber mit einer benutzerdefinierten Liste überschrieben werden kann.

Die Standardliste mit den Stoppwörtern finden Sie in Abschnitt 12.7.3, „Stoppwörter in der Volltextsuche“. Mindestwortlänge und Stoppwortliste lassen sich wie in Abschnitt 12.7.5, „MySQL-Volltextsuche feineinstellen“, beschrieben ändern.

Jedes korrekte Wort in der Sammlung und in der Abfrage wird entsprechend seiner Bedeutung in der Sammlung oder Abfrage gewichtet. Hieraus ergibt sich, dass ein Wort, dass in vielen Dokumenten vorhanden ist, ein niedrigeres Gewicht (oder sogar ein Nullgewicht) hat, weil sein semantischer Wert in dieser speziellen Sammlung geringer ist. Umgekehrt erhält ein Wort, das selten vorkommt, ein höheres Gewicht. Die Gewichtungen der Wörter werden zusammengefasst, und auf dieser Basis wird die Relevanz des Datensatzes berechnet.

Eine solche Methode funktioniert am besten mit großen Sammlungen (und sie wurde auch speziell auf diesen Zweck hin sorgfältig optimiert). Bei sehr kleinen Tabellen spiegelt die Wortverteilung ihren jeweiligen semantischen Wert nicht adäquat wider. So ist etwa das Wort „MySQL“ in jedem Datensatz der oben gezeigten Tabelle articles vorhanden, d. h., eine Suche nach diesem Wort führt zu keinem Ergebnis:

mysql> SELECT * FROM articles
    -> WHERE MATCH (title,body) AGAINST ('MySQL');
Empty set (0.00 sec)

Das Suchergebnis ist leer, weil das Wort „MySQL“ in mindestens 50 Prozent der Datensätze vorhanden ist. Insofern wird es letztendlich als Stoppwort behandelt. Bei großen Datenmengen ist dieses Verhalten wünschenswert: Eine natursprachliche Abfrage sollte keinesfalls jeden zweiten Datensatz aus einer 1 Gbyte großen Tabelle zurückgeben. Bei kleinen Datenmengen hingegen ist der Ansatz nicht sehr praktisch.

Ein Wort, das in der Hälfte der Datensätze in einer Tabelle auftritt, scheint wenig geeignet, relevante Dokumente zu finden. Tatsächlich werden in einem solchen Fall viele irrelevante Dokumente gefunden. Wie wir alle wissen, passiert dies viel zu häufig, etwa wenn wir versuchen, mit einer Suchmaschine etwas im Internet zu finden. Hieraus ist zu schließen, dass Datensätzen, die das Wort enthalten, ein niedriger semantischer Wert für die spezielle Datenmenge, in der sie auftreten, zugewiesen wird. Denn ein Wort kann die 50-Prozent-Marke in einer Datenmenge überschreiten, in einer anderen jedoch nicht.

Diese Marke hat eine große Bedeutung, wenn Sie die Volltextsuche zum ersten Mal ausprobieren, um zu sehen, wie sie funktioniert: Wenn Sie eine Tabelle erstellen und nur einen oder zwei Datensätze mit Text einfügen, tritt jedes Wort im Text in mindestens 50 Prozent aller Datensätze auf. Die Suche gibt also in keinem Fall Ergebnisse zurück. Sie sollten also mindestens drei (und am besten noch mehr) Datensätze einfügen. Benutzer, die die 50-Prozent-Grenze umgehen wollen, können den booleschen Suchmodus verwenden. Siehe auch Abschnitt 12.7.1, „Boolesche Volltextsuche“.

12.7.1. Boolesche Volltextsuche

MySQL kann eine boolesche Volltextsuche unter Verwendung des Modifizierers IN BOOLEAN MODE durchführen:

mysql> SELECT * FROM articles WHERE MATCH (title,body)
    -> AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
+----+-----------------------+-------------------------------------+
| id | title                 | body                                |
+----+-----------------------+-------------------------------------+
|  1 | MySQL Tutorial        | DBMS stands for DataBase ...        |
|  2 | How To Use MySQL Well | After you went through a ...        |
|  3 | Optimizing MySQL      | In this tutorial we will show ...   |
|  4 | 1001 MySQL Tricks     | 1. Never run mysqld as root. 2. ... |
|  6 | MySQL Security        | When configured properly, MySQL ... |
+----+-----------------------+-------------------------------------+

Die Operatoren + und - geben an, dass ein Wort vorhanden sein muss bzw. nicht sein darf, damit eine Übereinstimmung vorliegt. Insofern ruft diese Abfrage alle Datensätze ab, die das Wort „MySQL“, aber nicht das Wort „YourSQL“ enthalten.

Die boolesche Volltextsuche hat die folgenden Merkmale:

  • Sie verwendet die 50-Prozent-Marke nicht.

  • Datensätze werden nicht automatisch nach absteigender Relevanz sortiert. Dies erkennen Sie am obigen Abfrageergebnis: Der Datensatz mit der höchsten Relevanz ist derjenige, der „MySQL“ zweimal enthält. Er wird aber nicht als Erster, sondern als Letzter aufgeführt.

  • Sie funktioniert auch ohne FULLTEXT-Index, auch wenn eine derart ausgeführte Suche recht lange dauert.

  • Die Volltextparameter für minimale und maximale Wortlängen werden angewendet.

  • Die Stoppwortliste wird angewendet.

Die boolesche Volltextsuche unterstützt die folgenden Operatoren:

  • +

    Ein führendes Pluszeichen gibt an, dass das betreffende Wort in jedem zurückgegebenen Datensatz vorhanden sein muss.

  • -

    Ein führendes Minuszeichen gibt an, dass dieses Wort nicht in einem Datensatz vorhanden sein darf, der zurückgegeben wird.

    Hinweis: Der Operator - schließt nur solche Datensätze aus, die andernfalls Bestandteil des Ergebnisses wären. Aufgrund dessen gibt eine boolesche Suche, die nur mit Minuszeichen gekennzeichnete Begriffe enthält, ein leeres Ergebnis zurück, nicht jedoch „alle Datensätze mit Ausnahme derer, die einen der ausgeschlossenen Begriffe enthalten“.

  • (kein Operator)

    Standardmäßig (also wenn weder + noch - angegeben sind) ist das Wort optional, aber Datensätze, die es enthalten, werden weiter oben einsortiert. Dies ahmt das Verhalten von MATCH() ... AGAINST() ohne den Modifizierer IN BOOLEAN MODE nach.

  • > <

    Diese beiden Operatoren werden verwendet, um den Anteil eines Worts am Relevanzwert zu ändern, der einem Datensatz zugewiesen wird. Der Operator > erhöht den Anteil, der Operator < verringert ihn. Ein Beispiel finden Sie nach dieser Liste.

  • ( )

    Mit Klammern werden Wörter zu Unterausdrücken zusammengefasst. Gruppen in Klammern können verschachtelt werden.

  • ~

    Eine führende Tilde fungiert als Negationsoperator, d. h., der Anteil des Wortes an der Relevanz des Datensatzes wird negativ gewertet. Dies ist nützlich, um „Störungswörter“ zu kennzeichnen. Ein Datensatz, der ein solches Wort enthält, erhält eine geringere Relevanz als andere, wird aber – anders als bei - – nicht vollständig aus dem Ergebnis ausgeschlossen.

  • *

    Das Sternchen dient als Kürzungs- oder Jokeroperator. Anders als andere Operatoren wird es an das betreffende Wort angehängt. Eine Übereinstimmung liegt bei Wörtern vor, die mit dem vor dem Operator * stehenden Wort beginnen.

  • "

    Eine Phrase, die in doppelte Anführungszeichen (‘"’) gesetzt ist, entspricht nur solchen Datensätzen, in denen diese Phrase wortwörtlich (d. h. wie eingegeben) vorkommt. Die Volltextsuche unterteilt die Phrase in Wörter und führt dann eine Suche nach ihnen im FULLTEXT-Index durch. Bei Zeichen, die nicht zum Wort gehören, muss keine exakte Übereinstimmung vorliegen: Die Phrasensuche erfordert lediglich, dass bei passenden Datensätzen dieselben Wörter in genau der in der Phrase angegebenen Reihenfolge vorhanden sind. So entspricht beispielsweise "test phrase" "test, phrase".

    Wenn die Phrase keine Wörter enthält, die im Index vorhanden sind, ist das Ergebnis leer. Wenn beispielsweise alle Wörter Stoppwörter oder kürzer sind als die Mindestlänge für indizierte Wörter, dann ist das Ergebnis leer.

Die folgenden Beispiele veranschaulichen einige Such-Strings, die boolesche Volltextoperatoren verwenden:

  • 'apple banana'

    Findet Datensätze, die mindestens eines der beiden Wörter enthalten.

  • '+apple +juice'

    Findet Datensätze, die beide Wörter enthalten.

  • '+apple macintosh'

    Findet Datensätze, die das Wort „apple“ enthalten, stuft aber solche Datensätze höher ein, die auch „macintosh“ enthalten.

  • '+apple -macintosh'

    Findet Datensätze, die das Wort „apple“, aber nicht das Wort „macintosh“ enthalten.

  • '+apple ~macintosh'

    Findet Datensätze, die das Wort „apple“ enthalten. Datensätze, die außerdem das Wort „macintosh“ enthalten, werden niedriger eingestuft als solche, die es nicht enthalten. Dies ist „sanfter“ als eine Suche nach '+apple -macintosh', bei der ein Datensatz bei Vorhandensein von „macintosh“ überhaupt nicht zurückgegeben wird.

  • '+apple +(>turnover <strudel)'

    Findet Datensätze, die die Wörter „apple“ und „turnover“ oder „apple“ und „strudel“ (in beliebiger Reihenfolge) enthalten, aber stuft „apple turnover“ höher ein als „apple strudel“.

  • 'apple*'

    Findet Datensätze, die Wörter wie „apple“, „apples“, „applesauce“ oder „applet“ enthalten.

  • '"some words"'

    Findet Datensätze, die die exakte Phrase „some words“ enthalten. Dies wäre etwa „some words of wisdom“, nicht aber „some noise words“. Beachten Sie, dass die ‘"’-Anführungszeichen, die die Phrase umschließen, Operatorzeichen sind, die der Trennung der Phrase dienen. Es handelt sich hierbei nicht um Anführungszeichen, die den Such-String selbst umfassen.

12.7.2. Volltextsuche mit Abfragenerweiterung

Die Volltextsuche unterstützt die Abfrageerweiterung (und insbesondere die Variante „blinde Abfrageerweiterung“). Dies ist in der Regel nützlich, wenn eine Suchphrase zu kurz ist, was oft bedeutet, dass der Benutzer auf implizites Wissen angewiesen ist, welches der Volltextsuch-Engine fehlt. So weiß ein Benutzer, der nach dem Begriff „database“ sucht, normalerweise, dass „MySQL“, „Oracle“, „DB2“ und „RDBMS“ Phrasen sind, die „database“ entsprechen und insofern ebenfalls zurückgegeben werden sollten. Dies nennt man implizites Wissen.

Die blinde Abfrageerweiterung (auch „automatisches Relevanzfeedback“ genannt) wird durch Anhängen von WITH QUERY EXPANSION an die Suchphrase aktiviert. Sie funktioniert, indem die Suche zweimal durchgeführt wird, wobei die Suchphrase für die zweite Suche der ursprünglichen Suchphrase entspricht, die mit einigen wenigen Dokumenten aus der ersten Suche verkettet wurde. Wenn also eines der Dokumente das Wort „database“ und das Wort „MySQL“ enthält, findet die zweite Suche Dokumente, die das Wort „MySQL“ enthalten – und zwar auch dann, wenn „database“ gar nicht enthalten ist. Das folgende Beispiel veranschaulicht diesen Unterschied:

mysql> SELECT * FROM articles
    -> WHERE MATCH (title,body) AGAINST ('database');
+----+-------------------+------------------------------------------+
| id | title             | body                                     |
+----+-------------------+------------------------------------------+
|  5 | MySQL vs. YourSQL | In the following database comparison ... |
|  1 | MySQL Tutorial    | DBMS stands for DataBase ...             |
+----+-------------------+------------------------------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM articles
    -> WHERE MATCH (title,body)
    -> AGAINST ('database' WITH QUERY EXPANSION);
+----+-------------------+------------------------------------------+
| id | title             | body                                     |
+----+-------------------+------------------------------------------+
|  1 | MySQL Tutorial    | DBMS stands for DataBase ...             |
|  5 | MySQL vs. YourSQL | In the following database comparison ... |
|  3 | Optimizing MySQL  | In this tutorial we will show ...        |
+----+-------------------+------------------------------------------+
3 rows in set (0.00 sec)

Ein weiteres Beispiel könnte die Suche nach den Maigret-Büchern von Georges Simenon sein, wobei der Benutzer nicht genau weiß, wie sich „Maigret“ schreibt. Eine Suche nach „Megre and the reluctant witnesses“ findet ohne Abfrageerweiterung nur „Maigret and the Reluctant Witnesses“. Eine Suche mit Abfrageerweiterung findet im zweiten Durchlauf alle Bücher mit dem Wort „Maigret“.

Hinweis: Da die blinde Abfrageerweiterung sehr viele irrelevante Dokumente zurückgibt, ist sie nur sinnvoll, wenn die Suchphrase sehr kurz ist.

12.7.3. Stoppwörter in der Volltextsuche

Die folgende Tabelle zeigt die Standardliste der Stoppwörter für die Volltextsuche. Die Stoppwörter sind englisch. Eine Lokalisierung, zum Beispiel die Übersetzung in die deutsche Sprache, ist derzeit noch nicht vorgesehen. (Die Stoppwörter sind im Quellcode hardkodiert.)

a'sableaboutaboveaccording
accordinglyacrossactuallyafterafterwards
againagainstain'tallallow
allowsalmostalonealongalready
alsoalthoughalwaysamamong
amongstanandanotherany
anybodyanyhowanyoneanythinganyway
anywaysanywhereapartappearappreciate
appropriatearearen'taroundas
asideaskaskingassociatedat
availableawayawfullybebecame
becausebecomebecomesbecomingbeen
beforebeforehandbehindbeingbelieve
belowbesidebesidesbestbetter
betweenbeyondbothbriefbut
byc'monc'scamecan
can'tcannotcantcausecauses
certaincertainlychangesclearlyco
comcomecomesconcerningconsequently
considerconsideringcontaincontainingcontains
correspondingcouldcouldn'tcoursecurrently
definitelydescribeddespitediddidn't
differentdodoesdoesn'tdoing
don'tdonedowndownwardsduring
eacheduegeighteither
elseelsewhereenoughentirelyespecially
etetceveneverevery
everybodyeveryoneeverythingeverywhereex
exactlyexampleexceptfarfew
fifthfirstfivefollowedfollowing
followsforformerformerlyforth
fourfromfurtherfurthermoreget
getsgettinggivengivesgo
goesgoinggonegotgotten
greetingshadhadn'thappenshardly
hashasn'thavehaven'thaving
hehe'shellohelphence
herherehere'shereafterhereby
hereinhereuponhersherselfhi
himhimselfhishitherhopefully
howhowbeithoweveri'di'll
i'mi'veieifignored
immediateininasmuchincindeed
indicateindicatedindicatesinnerinsofar
insteadintoinwardisisn't
itit'dit'llit'sits
itselfjustkeepkeepskept
knowknowsknownlastlately
laterlatterlatterlyleastless
lestletlet'slikeliked
likelylittlelooklookinglooks
ltdmainlymanymaymaybe
memeanmeanwhilemerelymight
moremoreovermostmostlymuch
mustmymyselfnamenamely
ndnearnearlynecessaryneed
needsneitherneverneverthelessnew
nextninenonobodynon
nonenoonenornormallynot
nothingnovelnownowhereobviously
ofoffoftenohok
okayoldononceone
onesonlyontoorother
othersotherwiseoughtourours
ourselvesoutoutsideoveroverall
ownparticularparticularlyperperhaps
placedpleasepluspossiblepresumably
probablyprovidesquequiteqv
ratherrdrereallyreasonably
regardingregardlessregardsrelativelyrespectively
rightsaidsamesawsay
sayingsayssecondsecondlysee
seeingseemseemedseemingseems
seenselfselvessensiblesent
seriousseriouslysevenseveralshall
sheshouldshouldn'tsincesix
sosomesomebodysomehowsomeone
somethingsometimesometimessomewhatsomewhere
soonsorryspecifiedspecifyspecifying
stillsubsuchsupsure
t'staketakentelltends
ththanthankthanksthanx
thatthat'sthatsthetheir
theirsthemthemselvesthenthence
therethere'sthereaftertherebytherefore
thereintheresthereuponthesethey
they'dthey'llthey'rethey'vethink
thirdthisthoroughthoroughlythose
thoughthreethroughthroughoutthru
thustotogethertootook
towardtowardstriedtriestruly
trytryingtwicetwoun
underunfortunatelyunlessunlikelyuntil
untoupuponususe
usedusefulusesusingusually
valuevariousveryviaviz
vswantwantswaswasn't
waywewe'dwe'llwe're
we'vewelcomewellwentwere
weren'twhatwhat'swhateverwhen
whencewheneverwherewhere'swhereafter
whereaswherebywhereinwhereuponwherever
whetherwhichwhilewhitherwho
who'swhoeverwholewhomwhose
whywillwillingwishwith
withinwithoutwon'twonderwould
wouldwouldn'tyesyetyou
you'dyou'llyou'reyou'veyour
yoursyourselfyourselveszero 

12.7.4. Beschränkungen der Volltextsuche

  • Die Volltextsuche wird nur für MyISAM-Tabellen unterstützt.

  • Sie kann mit den meisten Multibytezeichensätzen benutzt werden. Eine Ausnahme ist Unicode: Der Zeichensatz utf8 kann verwendet werden, nicht aber der Zeichensatz ucs2.

  • Ideografische Sprachen wie das Chinesische und das Japanische kennen keine Worttrennzeichen. Aus diesem Grund kann der FULLTEXT-Parser bei diesen und anderen Sprachen nicht bestimmen, wo ein Wort anfängt oder endet. Die entsprechenden Auswirkungen und einige Workarounds für das Problem sind in Abschnitt 12.7, „MySQL-Volltextsuche“ beschrieben.

  • Zwar wird die Verwendung mehrerer Zeichensätze innerhalb einer Tabelle unterstützt, aber alle Spalten in einem FULLTEXT-Index müssen denselben Zeichensatz und dieselbe Sortierung haben.

  • Die MATCH()-Spaltenliste muss exakt mit der Spaltenliste in einer FULLTEXT-Indexdefinition der Tabelle übereinstimmen, sofern für MATCH() nicht der Modus IN BOOLEAN MODE aktiviert ist. Die boolesche Suche kann auch in nichtindizierten Spalten erfolgen, ist dann allerdings recht langsam.

  • Das Argument AGAINST() muss eine String-Konstante sein.

12.7.5. MySQL-Volltextsuche feineinstellen

Die Volltextsuchfunktion von MySQL bietet einige wenige vom Benutzer einstellbare Parameter. Sie können mehr Kontrolle über das Verhalten der Volltextsuche erhalten, wenn Sie eine MySQL-Quelldistribution verwenden, denn einige Änderungen erfordern Anpassungen am Quellcode. Siehe auch Abschnitt 2.8, „Installation der Quelldistribution“.

Beachten Sie, dass die Volltextsuche standardmäßig bereits für maximale Effektivität optimiert ist. Eine Modifikation des Standardverhaltens kann in den meisten Fällen zu einer Verringerung der Effizienz führen. Ändern Sie den MySQL-Quellcode nur dann, wenn Sie genau wissen, was Sie tun!

Die meisten Volltextvariablen, die in diesem Abschnitt beschrieben werden, müssen beim Serverstart eingestellt werden. Um sie zu ändern, ist ein Serverneustart erforderlich – eine Modifikation bei laufendem Server ist nicht möglich.

Einige Variablenänderungen erfordern eine Neuerstellung der FULLTEXT-Indizes in Ihren Tabellen. Hinweise hierzu finden Sie am Ende dieses Abschnitts.

  • Die minimalen und maximalen Längen von zu indizierenden Wörtern werden mit den Systemvariablen ft_min_word_len und ft_max_word_len definiert. (Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.) Die standardmäßige Mindestlänge beträgt vier Zeichen, die vorgabeseitige Höchstlänge hängt von der Version ab. Wenn Sie einen der Werte ändern, müssen Sie ihre FULLTEXT-Indizes neu erstellen. Wünschen Sie beispielsweise, dass Wörter mit drei Zeichen durchsucht werden können sollen, dann können Sie die Variable ft_min_word_len umstellen, indem Sie die folgenden Zeilen in eine Optionsdatei schreiben:

    [mysqld]
    ft_min_word_len=3
    

    Danach müssen Sie den Server neu starten und die FULLTEXT-Indizes neu erstellen. Beachten Sie insbesondere die Anmerkungen zu myisamchk in der Anleitung, die auf diese Liste folgt.

  • Um die standardmäßige Stoppwortliste außer Kraft zu setzen, müssen Sie die Systemvariable ft_stopword_file einstellen. (Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.) Der Variablenwert sollte der Pfadname zu der Datei, die die Stoppwortliste enthält, oder der Leer-String sein (in diesem Fall wird die Stoppwortfilterung deaktiviert). Nachdem Sie den Wert dieser Variablen oder den Inhalt der Stoppwortdatei geändert haben, starten Sie den Server neu und erstellen Ihre FULLTEXT-Indizes dann neu.

    Die Stoppwortliste hat eine freie Form, d. h., Sie können beliebige nichtalphanumerische Zeichen wie den Zeilenwechsel, das Leerzeichen oder das Komma verwenden, um Stoppwörter zu trennen. Ausnahmen sind der Unterstrich (_) und ein einzelnes Apostroph ('), die als Teil eines Wortes behandelt werden. Der Zeichensatz der Stoppwortliste ist der Standardzeichensatz des Servers (siehe auch Abschnitt 10.3.1, „Serverzeichensatz und -sortierfolge“).

  • Die 50-Prozent-Marke für natursprachliche Suchvorgänge wird vom jeweiligen Gewichtungsschema bestimmt. Um sie zu deaktivieren, suchen Sie in myisam/ftdefs.h nach der folgenden Zeile:

    #define GWS_IN_USE GWS_PROB
    

    Ändern Sie sie wie folgt ab:

    #define GWS_IN_USE GWS_FREQ
    

    Dann kompilieren Sie MySQL neu. In diesem Fall ist es nicht notwendig, die Indizes neu zu erstellen. Hinweis: Durch diese Änderung beeinträchtigen Sie die Fähigkeit von MySQL zur Bereitstellung passender Relevanzwerte für die Funktion MATCH() erheblich. Wenn Sie tatsächlich nach solchen gängigen Wörtern suchen müssen, sollten Sie stattdessen im Modus IN BOOLEAN MODE suchen, denn bei diesem wird die 50-Prozent-Marke ignoriert.

  • Um die für die boolesche Volltextsuche verwendeten Operatoren zu ändern, stellen Sie die Systemvariable ft_boolean_syntax ein. Diese Variable kann zur Laufzeit des Servers geändert werden, allerdings benötigen Sie hierfür die Berechtigung SUPER. Eine Neuerstellung der Indizes ist in diesem Fall nicht notwendig. Weitere Informationen finden Sie in Abschnitt 5.2.2, „Server-Systemvariablen“, wo auch die Regeln für die Einstellung dieser Variablen beschrieben werden.

Wenn Sie Volltextvariablen ändern, die die Indizierung beeinflussen (ft_min_word_len, ft_max_word_len oder ft_stopword_file), oder die Stoppwortdatei selbst ändern, müssen Sie Ihre FULLTEXT-Indizes nach Durchführung der Änderungen und dem Neustart des Servers neu erstellen. Um die Indizes in diesem Fall neu zu erstellen, reicht es aus, eine QUICK-Reparaturoperation durchzuführen:

mysql> REPAIR TABLE tbl_name QUICK;

Beachten Sie, dass, wenn Sie mit myisamchk eine Operation durchführen, die die Tabellenindizes verändert (dies können etwa Reparatur- oder Analyseoperationen sein), die FULLTEXT-Indizes unter Verwendung der standardmäßigen Volltextparameterwerte für die minimale und maximale Wortlänge und die Stoppwortdatei verwendet werden, sofern Sie nichts anderes angeben. Dies kann dazu führen, dass Abfragen fehlschlagen.

Das Problem tritt auf, weil diese Parameter nur dem Server bekannt sind. Sie werden nicht in den MyISAM-Indexdateien gespeichert. Um das Problem zu umgehen, wenn Sie die Werte für die minimale oder maximale Wortlänge oder die Stoppwortdatei am Server geändert haben, geben Sie dieselben Werte ft_min_word_len, ft_max_word_len und ft_stopword_file für myisamchk an, die Sie für mysqld verwendet haben. Haben Sie also beispielsweise die Mindestwortlänge auf 3 gesetzt, dann können Sie eine Tabelle mit myisamchk wie folgt reparieren:

shell> myisamchk --recover --ft_min_word_len=3 tbl_name.MYI

Wenn Sie gewährleisten wollen, dass myisamchk und der Server dieselben Werte für Volltextparameter verwenden, können Sie sie jeweils in die Abschnitte [mysqld] und [myisamchk] einer Optionsdatei eintragen:

[mysqld]
ft_min_word_len=3

[myisamchk]
ft_min_word_len=3

Eine Alternative zur Verwendung von myisamchk besteht in der Nutzung von REPAIR TABLE-, ANALYZE TABLE-, OPTIMIZE TABLE- oder ALTER TABLE-Anweisungen. Diese Anweisungen werden vom Server ausgeführt, der die korrekten Werte der Volltextparameter kennt.

12.8. Cast-Funktionen und Operatoren

  • BINARY

    Der Operator BINARY wandelt den ihm nachfolgenden String in einen Binär-String um. Dies ist eine einfache Möglichkeit, einen Spaltenvergleich byte- statt zeichenweise durchzuführen. Auf diese Weise unterscheidet der Vergleich die Groß-/Kleinschreibung auch dann, wenn die Spalte nicht als BINARY oder BLOB definiert ist. BINARY berücksichtigt auch am Ende stehende Leerzeichen.

    mysql> SELECT 'a' = 'A';
            -> 1
    mysql> SELECT BINARY 'a' = 'A';
            -> 0
    mysql> SELECT 'a' = 'a ';
            -> 1
    mysql> SELECT BINARY 'a' = 'a ';
            -> 0
    

    In einem Vergleich wirkt sich BINARY auf die gesamte Operation aus. Es kann vor einen beliebigen Operanden gesetzt werden – das Ergebnis bleibt stets das Gleiche.

    BINARY str ist eine Abkürzung für CAST(str AS BINARY).

    Beachten Sie, dass, wenn Sie in bestimmten Kontexten eine indizierte Spalte in BINARY umwandeln, MySQL den Index nicht mehr effizient verwenden kann.

  • CAST(expr AS type), CONVERT(expr,type), CONVERT(expr USING transcoding_name)

    Die Funktionen CAST() und CONVERT() nehmen einen Wert eines Typs entgegen und erzeugen einen Wert eines anderen Typs.

    type kann einen der folgenden Werte haben:

    • BINARY[(N)]

    • CHAR[(N)]

    • DATE

    • DATETIME

    • DECIMAL

    • SIGNED [INTEGER]

    • TIME

    • UNSIGNED [INTEGER]

    BINARY erzeugt einen String des Datentyps BINARY. Eine Erläuterung, wie sich dies auf Vergleiche auswirkt, finden Sie in Abschnitt 11.4.2, „Die BINARY- und VARBINARY-Typen“. Wird die optionale Länge N angegeben, dann verwendet BINARY[N] zur Umwandlung nicht mehr als N Bytes des Arguments. Werte, die kürzer als N Bytes sind, werden mit 0x00-Bytes auf die Länge N aufgefüllt.

    Mit CHAR[N] werden bei der Umwandlung nicht mehr als N Zeichen des Arguments verwendet.

    CAST() und CONVERT(... USING ...) sind SQL-Standardsyntax. Die Form von CONVERT() ohne USING hingegen ist ODBC-Syntax.

    CONVERT() wird mit USING zur Konvertierung von Daten zwischen verschiedenen Zeichensätzen konvertiert. Bei MySQL sind die Transkodierungs- mit den entsprechenden Zeichensatznamen identisch. Die folgende Anweisung beispielsweise konvertiert den String 'abc' im Standardzeichensatz in den entsprechenden String im Zeichensatz utf8:

    SELECT CONVERT('abc' USING utf8);
    

Normalerweise können Sie einen BLOB-Wert oder einen anderen binären Wert nur mit Unterscheidung der Groß-/Kleinschreibung vergleichen, da Binär-Strings keinen Zeichensatz (und deswegen auch keine Groß-/Kleinschreibung) haben. Um einen Vergleich ohne Unterscheidung der Groß-/Kleinschreibung durchzuführen, konvertieren Sie den Wert mit der Funktion CONVERT() in einen nichtbinären String. Wenn der Zeichensatz des Ergebnisses eine Sortierung mit Unterscheidung der Groß-/Kleinschreibung hat, dann unterscheidet die LIKE-Operation die Groß-/Kleinschreibung nicht:

SELECT 'A' LIKE CONVERT(blob_col USING latin1) FROM tbl_name;

Um einen anderen Zeichensatz zu verwenden, ersetzen Sie latin1 in der obigen Anweisung durch dessen Namen. Wenn Sie gewährleisten wollen, dass eine Sortierung ohne Unterscheidung der Groß-/Kleinschreibung verwendet wird, geben Sie auf den Aufruf von CONVERT() folgend eine COLLATE-Klausel an.

CONVERT() kann – allgemeiner gesagt – für den Vergleich von Strings verwendet werden, die in unterschiedlichen Zeichensätzen dargestellt werden.

Die Umwandlungsfunktionen sind nützlich, um eine Spalte eines bestimmten Typs in einer CREATE ... SELECT-Anweisung zu erstellen:

CREATE TABLE new_table SELECT CAST('2000-01-01' AS DATE);

Die Funktionen können auch praktisch sein, um ENUM-Spalten in lexikaler Reihenfolge zu sortieren. Normalerweise erfolgt die Sortierung von ENUM-Spalten unter Verwendung der internen numerischen Werte. Die Umwandlung der Werte in CHAR führt zu einer lexikalen Sortierung:

SELECT enum_col FROM tbl_name ORDER BY CAST(enum_col AS CHAR);

CAST(str AS BINARY) ist das Gleiche wie BINARY str. CAST(expr AS CHAR) behandelt den Ausdruck als String mit dem Standardzeichensatz.

CAST() ändert das Ergebnis auch, wenn Sie es als Teil eines komplexeren Ausdrucks wie etwa CONCAT('Date: ',CAST(NOW() AS DATE)) verwenden.

Sie sollten CAST() nicht zur Extraktion von Daten in verschiedenen Formaten benutzen, sondern stattdessen String-Funktionen wie LEFT() oder EXTRACT() verwenden. Siehe auch Abschnitt 12.5, „Datums- und Zeitfunktionen“.

Um einen String in einem Zahlenkontext in einen numerischen Wert umzuwandeln, müssen Sie normalerweise nichts anderes tun, als den String-Wert wie eine Zahl zu verwenden:

mysql> SELECT 1+'1';
       -> 2

Wenn Sie eine Zahl im String-Kontext verwenden, wird die Zahl automatisch in einen BINARY-String konvertiert.

mysql> SELECT CONCAT('hello you ',2);
        -> 'hello you 2'

MySQL unterstützt Berechnungen mit vorzeichenbehafteten wie auch vorzeichenlosen 64-Bit-Werten. Wenn Sie numerische Operationen (wie +) verwenden und einer der Operanden ein vorzeichenloser Integer ist, dann ist auch das Ergebnis vorzeichenlos. Sie können dieses Verhalten außer Kraft setzen, indem Sie die Umwandlungsoperatoren SIGNED und UNSIGNED zur Umwandlung des Operanden in einen vorzeichenbehafteten bzw. vorzeichenlosen 64-Bit-Integer benutzen.

mysql> SELECT CAST(1-2 AS UNSIGNED)
        -> 18446744073709551615
mysql> SELECT CAST(CAST(1-2 AS UNSIGNED) AS SIGNED);
        -> -1

Beachten Sie, dass, wenn ein Operand ein Fließkommawert ist, das Ergebnis ebenfalls ein Fließkommawert sein wird; die obige Regel findet in diesem Fall keine Anwendung. (In diesem Kontext werden DECIMAL-Spalten als Fließkommawerte betrachtet.)

mysql> SELECT CAST(1 AS UNSIGNED) - 2.0;
        -> -1.0

Wenn Sie in einer Rechenoperation einen String verwenden, dann wird dieser in eine Fließkommazahl umgewandelt.

Konvertieren Sie einen „Nulldatums“-String in ein Datum, dann geben CONVERT() und CAST() NULL zurück und erzeugen bei aktiviertem SQL-Modus NO_ZERO_DATE außerdem eine Warnung.

12.9. XML-Funktionen

Dieser Abschnitt beschreibt XML und zugehörige Funktionalitäten in MySQL.

Beachten Sie, dass es möglich ist, in den MySQL-Clients mysql und mysqldump eine XML-formatierte Ausgabe zu erhalten, indem man sie mit der Option --xml aufruft. Siehe auch Abschnitt 8.5, „mysql — Das MySQL-Befehlszeilenwerkzeug mysql“, und Abschnitt 8.10, „mysqldump — Programm zur Datensicherung“.

Seit Version 5.1.5 enthält MySQL zwei Funktionen, die grundlegende XPath-Funktionalitäten (XML Path Language) bereitstellen.

Beachten Sie, dass sich diese Funktionen derzeit noch in Entwicklung befinden. Wir werden diese und andere Aspekte von XML und XPath in MySQL 5.1 und höher kontinuierlich verbessern. Sie können diese Funktionen im MySQL XML User Forum diskutieren, Fragen stellen und entsprechende Hilfe von anderen Benutzern erhalten.

  • ExtractValue(xml_frag, xpath_expr)

    Diese Funktion nimmt zwei String-Argumente – ein XML-Fragment xml_frag und einen XPath-Ausdruck xpath_expr (auch Lokator genannt) – entgegen und gibt den xpath_expr entsprechenden Wert zurück. Beachten Sie, dass ExtractValue() nur das CDATA zurückgibt, das direkt im xpath_expr entsprechenden Tag enthalten ist, nicht jedoch Tags, die innerhalb des entsprechenden Tags enthalten sind, oder deren Inhalte (siehe auch das als val1 im folgenden Beispiel zurückgegebene Ergebnis).

    Wird keine Übereinstimmung für xpath_expr gefunden, dann gibt die Funktion einen Leer-String zurück. Werden mehrere Übereinstimmungen gefunden, dann werden die Inhalte aller entsprechenden Elemente (in der Reihenfolge der Übereinstimmung) in einem leerzeichengetrennten String zurückgegeben.

    mysql> SELECT
        ->   ExtractValue('<a>ccc<b>ddd</b></a>', '/a') AS val1,
        ->   ExtractValue('<a>ccc<b>ddd</b></a>', '/a/b') AS val2,
        ->   ExtractValue('<a>ccc<b>ddd</b></a>', '//b') AS val3,
        ->   ExtractValue('<a>ccc<b>ddd</b></a>', '/b') AS val4,
        ->   ExtractValue('<a>ccc<b>ddd</b><b>eee</b></a>', '//b') AS val5;
    
    +------+------+------+------+---------+
    | val1 | val2 | val3 | val4 | val5    |
    +------+------+------+------+---------+
    | ccc  | ddd  | ddd  |      | ddd eee |
    +------+------+------+------+---------+
    
  • UpdateXML(xml_target, xpath_expr, new_xml)

    Diese Funktion ersetzt einen Teil eines gegebenen XML-Fragments xml_target durch ein neues XML-Fragment new_xml und gibt das geänderte XML dann zurück. Der Teil von xml_target, der ersetzt wird, entspricht einem XPath-Ausdruck xpath_expr, der vom Benutzer übergeben wurde. Wird kein Ausdruck entdeckt, der xpath_expr entspricht, dann gibt die Funktion das ursprüngliche XML-Fragment xml_target zurück. Alle drei Argumente müssen Strings sein.

    mysql> SELECT
        ->   UpdateXML('<a><b>ccc</b><d></d></a>', '/a', '<e>fff</e>') AS val1,
        ->   UpdateXML('<a><b>ccc</b><d></d></a>', '/b', '<e>fff</e>') AS val2,
        ->   UpdateXML('<a><b>ccc</b><d></d></a>', '//b', '<e>fff</e>') AS val3,
        ->   UpdateXML('<a><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val4
        -> \G
    
    *************************** 1. row ***************************
    val1: <e>fff</e>
    val2: <a><b>ccc</b><d></d></a>
    val3: <a><e>fff</e><d></d></a>
    val4: <a><b>ccc</b><e>fff</e></a>
    

Es folgen nun Beschreibungen und Beispiele einiger einfacher XPath-Ausdrücke:

  • /tag

    Entspricht <tag/>, wenn (und nur wenn) <tag/> das Stammelement ist.

    Beispiel: /a findet eine Übereinstimmung in <a><b/></a>, weil es dem äußersten Tag (Stamm-Tag) entspricht. Es entspricht nicht dem inneren a-Element in <b><a/></b>, weil es in dieser Instanz ein einem anderen Element untergeordnetes Element ist.

  • /tag1/tag2

    Entspricht <tag2/>, wenn (und nur wenn) es ein untergeordnetes Element von <tag1/> und <tag1/> das Stammelement ist.

    Beispiel: /a/b entspricht dem Element b im XML-Fragment <a><b/></a>, weil es ein untergeordnetes Element des Stammelements a ist. Keine Entsprechung liegt in <b><a/></b> vor, weil in diesem Fall b das Stammelement (und damit kein einem anderen Element untergeordnetes Element) ist. Ebenso wenig hat der XPath-Ausdruck eine Übereinstimmung in <a><c><b/></c></a>; hier stammt b zwar von a ab, ist aber im engen Sinne kein a untergeordnetes Element.

    Dieses Konstrukt ist auf drei oder mehr Elemente erweiterbar. So entspricht beispielsweise der XPath-Ausdruck /a/b/c dem Element c im Fragment <a><b><c/></b></a>.

  • //tag

    Entspricht jeder Instanz von tag.

    Beispiel: //a entspricht dem Element a in allen folgenden Fragmenten: <a><b><c/></b></a>; <c><a><b/></a></b>; <c><b><a/></b></c>.

    // kann mit / kombiniert werden. Beispielsweise entspricht //a/b dem Element b in den Fragmenten <a><b/></a> und <a><b><c/></b></a>.

  • Der Operator * agiert als Jokerzeichen, welches jedem Element entspricht. So entspricht beispielsweise der Ausdruck /*/b dem Element b in den XML-Fragmenten <a><b/></a> und <c><b/></c>. Allerdings erzeugt der Ausdruck keine Übereinstimmung im Fragment <b><a/></b>, weil b ein einem anderen Element untergeordnetes Element sein muss. Das Jokerzeichen kann an beliebiger Position verwendet werden: Der Ausdruck /*/b/* entspricht jedem untergeordneten Element eines Elements b, welches selbst nicht das Stammelement ist.

  • Mehrere Lokatoren können mit dem Operator | (logisches OR) verglichen werden. So entspricht etwa der Ausdruck //b|//c allen b- und c-Elementen im XML-Ziel.

  • Es ist auch möglich, ein Element basierend auf dem Wert eines oder mehrerer seiner Attribute zu vergleichen. Dies erfolgt mit der Syntax tag[@attribute="value"]. So entspricht beispielsweise der Ausdruck //b[@id="idB"] dem zweiten Element b im Fragment <a><b id="idA"/><c/><b id="idB"/></a>. Um einen Vergleich mit einem beliebigen Element mit attribute="value" durchzuführen, benutzen Sie den XPath-Ausdruck //*[attribute="value"].

    Um mehrere Attributwerte zu filtern, benutzen Sie einfach mehrere aufeinander folgende Attributvergleichsklauseln. Der Ausdruck //b[@c="x"][@d="y"] beispielsweise entspricht dem Element <b c="x" d="y"/> an beliebiger Stelle in einem gegebenen XML-Fragment.

    Um Elemente zu finden, für die dasselbe Attribut genau einem von mehreren Werten entspricht, müssen Sie mehrere Lokatoren benutzen, die mit dem Operator | verknüpft werden. Um also etwa eine Übereinstimmung für alle Elemente b zu erzielen, deren Attribute c entweder den Wert 17 oder den Wert 23 haben, verwenden Sie den Ausdruck //b[@c="23"]|b[@c="17"].

Eine detaillierte Beschreibung zu Syntax und Einsatz von XPath würde den Rahmen dieses Handbuchs sprengen. Umfassende Informationen erhalten Sie unter XML Path Language (XPath) 1.0 standard. Eine nützliche Ressource für Neulinge im Bereich XPath oder für solche Leser, die ihre Kenntnisse ein wenig auffrischen wollen, ist das Zvon.org XPath Tutorial, das in mehreren Sprachen verfügbar ist.

Die von diesen Funktionen unterstützte XPath-Syntax unterliegt derzeit den folgenden Beschränkungen:

  • Nodeset-Nodeset-Vergleiche (wie etwa '/a/b[@c=@d]') werden nicht unterstützt. Nur Vergleiche der Form [@attribute="const"], wobei const ein konstanter Wert ist, sind zurzeit möglich. Beachten Sie, dass Gleichheit und Ungleichheit (= und !=) die einzigen unterstützten Vergleichsoperatoren sind.

  • Relative Lokatorausdrücke werden nicht unterstützt. XPath-Ausdrücke müssen mit / oder // beginnen.

  • Der Operator :: wird nicht unterstützt.

  • Die folgenden XPath-Funktionen werden nicht unterstützt:

    • id()

    • lang()

    • last()

    • local-name()

    • name()

    • namespace-uri()

    • normalize-space()

    • starts-with()

    • string()

    • substring-after()

    • substring-before()

    • translate()

  • Die folgenden Axes werden nicht unterstützt:

    • following-sibling

    • following

    • preceding-sibling

    • preceding

12.10. Weitere Funktionen

12.10.1. Bitfunktionen

MySQL verwendet die BIGINT-Arithmetik (64-Bit-Arithmetik) für Bitoperationen, d. h., diese Operatoren haben einen maximalen Bereich von 64 Bits.

  • |

    Bit-OR:

    mysql> SELECT 29 | 15;
            -> 31
    

    Das Ergebnis ist ein vorzeichenloser 64-Bit-Integer.

  • &

    Bit-AND:

    mysql> SELECT 29 & 15;
            -> 13
    

    Das Ergebnis ist ein vorzeichenloser 64-Bit-Integer.

  • ^

    Bit-XOR:

    mysql> SELECT 1 ^ 1;
            -> 0
    mysql> SELECT 1 ^ 0;
            -> 1
    mysql> SELECT 11 ^ 3;
            -> 8
    

    Das Ergebnis ist ein vorzeichenloser 64-Bit-Integer.

  • <<

    Verschiebt eine Longlong-Zahl (BIGINT) nach links.

    mysql> SELECT 1 << 2;
            -> 4
    

    Das Ergebnis ist ein vorzeichenloser 64-Bit-Integer.

  • >>

    Verschiebt eine Longlong-Zahl (BIGINT) nach rechts.

    mysql> SELECT 4 >> 2;
            -> 1
    

    Das Ergebnis ist ein vorzeichenloser 64-Bit-Integer.

  • ~

    Invertiert alle Bits.

    mysql> SELECT 5 & ~1;
            -> 4
    

    Das Ergebnis ist ein vorzeichenloser 64-Bit-Integer.

  • BIT_COUNT(N)

    Gibt die Anzahl der Bits zurück, die im Argument N gesetzt sind.

    mysql> SELECT BIT_COUNT(29), BIT_COUNT(b'101010');
            -> 4, 3
    

12.10.2. Verschlüsselungs- und Kompressionsfunktionen

Die in diesem Abschnitt beschriebenen Funktionen führen Ver- und Entschlüsselung sowie Komprimierung und Dekomprimierung durch.

Hinweis: Die Verschlüsselungs- und Komprimierungsfunktionen geben Binär-Strings zurück. Bei vielen dieser Funktionen kann das Ergebnis willkürliche Bytewerte enthalten. Wenn Sie diese Ergebnisse speichern wollen, verwenden Sie eine BLOB-Spalte statt einer CHAR- oder VARCHAR-Spalte, um potenzielle Probleme zu vermeiden, die aufgrund einer Datenwertänderung durch das Entfernen von Leerzeichen am Ende entstehen könnten.

Hinweis: Für die MD5- und SHA-1-Algorithmen sind Exploits bekannt. Sie sollten deswegen die Verwendung einer anderen Verschlüsselungsfunktion in Betracht ziehen, die in diesem Abschnitt beschrieben sind.

  • AES_ENCRYPT(str,key_str), AES_DECRYPT(crypt_str,key_str)

    Diese Funktionen gestatten die Ver- und Entschlüsselung von Daten mithilfe des offiziellen AES-Algorithmus (Advanced Encryption Standard; dieser war früher als „Rijndael“ bekannt). Die Verschlüsselung erfolgt mit einem 128-Bit-Schlüssel, den Sie aber durch Modifizierung des Quellcodes auf 256 Bits erweitern können. Wir haben uns für eine Schlüsselbreite von 128 Bits entschieden, da diese bei hoher Verarbeitungsgeschwindigkeit für die meisten Zwecke ausreichend sicher ist.

    AES_ENCRYPT() verschlüsselt einen String und gibt einen Binär-String zurück. AES_DESCRIPT() entschlüsselt den verschlüsselten String und gibt den Original-String zurück. Die Eingabeargumente dürfen eine beliebige Länge haben. Wenn eines der Argumente NULL ist, ist das Ergebnis dieser Funktion ebenfalls NULL.

    Da AES als Algorithmus auf Blockebene arbeitet, werden Strings unterschiedlicher Länge bei der Verschlüsselung mit Füllzeichen erweitert. Die Länge des Ergebnis-Strings lässt sich mit folgender Formel berechnen:

    16 × (trunc(string_length / 16) + 1)
    

    Wenn AES_DECRYPT() ungültige Daten oder ein inkorrektes Auffüllen erkennt, gibt es NULL zurück. Es ist allerdings möglich, dass AES_DECRYPT() einen Nicht-NULL-Wert zurückgibt, wenn Eingabedaten oder Schlüssel ungültig sind. (Der Rückgabewert ist dann in aller Regel unsinnig).

    Sie können die AES-Funktionen zur Speicherung von Daten in verschlüsselter Form verwenden, indem Sie Ihre Abfragen abändern:

    INSERT INTO t VALUES (1,AES_ENCRYPT('text','password'));
    

    AES_ENCRYPT() und AES_DECRYPT() können als die aus kryptografischer Sicht sichersten Verschlüsselungsfunktionen gelten, die derzeit in MySQL zur Verfügung stehen.

  • COMPRESS(string_to_compress)

    Komprimiert einen String und gibt das Ergebnis als Binär-String zurück. Diese Funktion erfordert es, dass MySQL mit einer Komprimierungsbibliothek wie etwa zlib kompiliert wurde. Andernfalls ist der Rückgabewert immer NULL. Der komprimierte String kann mit UNCOMPRESS() wieder dekomprimiert werden.

    mysql> SELECT LENGTH(COMPRESS(REPEAT('a',1000)));
            -> 21
    mysql> SELECT LENGTH(COMPRESS(''));
            -> 0
    mysql> SELECT LENGTH(COMPRESS('a'));
            -> 13
    mysql> SELECT LENGTH(COMPRESS(REPEAT('a',16)));
            -> 15
    

    Der Inhalt des komprimierten Strings wird wie folgt gespeichert:

    • Leere Strings werden als Leer-Strings gespeichert.

    • Nichtleere Strings werden als unkomprimierte Strings mit einer Länge von 4 Byte gespeichert (wobei das niedrigste Byte zuerst kommt), gefolgt vom komprimierten String. Wenn der String mit einem Leerzeichen endet, wird ein zusätzliches Zeichen ‘.’ hinzugefügt, um Probleme mit dem Abschneiden von Leerzeichen am Ende für den Fall zu vermeiden, dass das Ergebnis in einer CHAR- oder VARCHAR-Spalte gespeichert wird. (Von der Verwendung von CHAR oder VARCHAR zur Speicherung komprimierter Strings wird abgeraten. Verwenden Sie stattdessen besser eine BLOB-Spalte.)

  • DECODE(crypt_str,pass_str)

    Entschlüsselt den verschlüsselten String crypt_str mit pass_str als Passwort. crypt_str sollte ein String sein, der von ENCODE() zurückgegeben wurde.

  • ENCODE(str,pass_str)

    Verschlüsselt str unter Verwendung von pass_str als Passwort. Zur Entschlüsselung des Ergebnisses verwenden Sie DECODE().

    Das Ergebnis ist ein Binär-String derselben Länge wie str.

  • DES_DECRYPT(crypt_str[,key_str])

    Entschlüsselt einen String, der mit DES_ENCRYPT() verschlüsselt wurde. Wenn ein Fehler auftritt, gibt die Funktion NULL zurück.

    Beachten Sie, dass diese Funktion nur funktioniert, wenn MySQL mit SSL-Unterstützung konfiguriert wurde. Siehe auch Abschnitt 5.9.7, „Verwendung sicherer Verbindungen“.

    Wird kein Argument key_str angegeben, dann untersucht DES_DECRYPT() das erste Byte des verschlüsselten Strings, um die DES-Schlüsselnummer zu ermitteln, die zur Verschlüsselung des ursprünglichen Strings verwendet wurde, und liest den Schlüssel dann aus der DES-Schlüsseldatei aus, um die Nachricht zu entschlüsseln. Damit dies klappt, benötigt der Benutzer die Berechtigung SUPER. Die Schlüsseldatei kann mit der Serveroption --des-key-file angegeben werden.

    Wenn Sie der Funktion ein Argument key_str übergeben, wird dieser String als Schlüssel zur Entschlüsselung der Nachricht verwendet.

    Wenn das Argument crypt_str kein verschlüsselter String zu sein scheint, gibt MySQL den übergebenen String crypt_str zurück.

  • DES_ENCRYPT(str[,(key_num|key_str)])

    Verschlüsselt den String mit dem angegebenen Schlüssel unter Verwendung des Triple-DES-Algorithmus.

    Beachten Sie, dass diese Funktion nur funktioniert, wenn MySQL mit SSL-Unterstützung konfiguriert wurde. Siehe auch Abschnitt 5.9.7, „Verwendung sicherer Verbindungen“.

    Der für die Verschlüsselung zu verwendende Schlüssel wird basierend auf dem zweiten Argument zu DES_ENCRYPT() (sofern vorhanden) ausgewählt:

    ArgumentBeschreibung
    Kein ArgumentDer erste Schlüssel aus der DES-Schlüsseldatei wird verwendet.
    key_numDer angegebene Schlüssel (0 bis 9) aus der DES-Schlüsseldatei wird verwendet.
    key_strDer angegebene String wird zur Verschlüsselung von str benutzt.

    Die Schlüsseldatei kann mit der Serveroption --des-key-file angegeben werden.

    Der Rückgabe-String ist ein Binär-String, bei dem das erste Zeichen CHAR(128 | key_num) ist. Wenn ein Fehler auftritt, gibt DES_ENCRYPT() NULL zurück.

    Die 128 wird hinzugefügt, um die Erkennung eines verschlüsselten Schlüssels zu erleichtern. Wenn Sie einen String-Schlüssel verwenden, ist key_num 127.

    Die String-Länge des Ergebnisses wird mit dieser Formel angegeben:

    new_len = orig_len + (8 - (orig_len % 8)) + 1
    

    Jede Zeile in der DES-Schlüsseldatei hat das folgende Format:

    key_num des_key_str
    

    Jeder key_num-Wert muss eine Zahl zwischen 0 und 9 sein. Die Zeilen können in der Datei beliebig sortiert sein. des_key_str ist der String, der zur Verschlüsselung der Nachricht verwendet wird. Es sollte mindestens ein Leerzeichen zwischen der Zahl und dem Schlüssel stehen. Der erste Schlüssel ist der Standardschlüssel: Er wird benutzt, wenn kein Schlüsselargument für DES_ENCRYPT() angegeben wurde.

    Sie können MySQL mit der Anweisung FLUSH DES_KEY_FILE anweisen, neue Schlüsselwerte aus der Schlüsseldatei einzulesen. Dies erfordert die Berechtigung RELOAD.

    Ein Vorteil der Verwendung eines Satzes mit Standardschlüsseln besteht darin, dass dies Anwendungen eine Möglichkeit bietet, auf das Vorhandensein verschlüsselter Spaltenwerte zu prüfen, ohne dem Endbenutzer das Recht zur Verschlüsselung dieser Werte zu geben.

    mysql> SELECT customer_address FROM customer_table 
         > WHERE crypted_credit_card = DES_ENCRYPT('credit_card_number');
    
  • ENCRYPT(str[,salt])

    Verschlüsselt str unter Verwendung des Unix-Systemaufrufs crypt() und gibt einen Binär-String zurück. Das Argument salt sollte ein String mit mindestens zwei Zeichen sein. Wird kein salt-Argument angegeben, dann wird ein zufälliger Wert verwendet.

    mysql> SELECT ENCRYPT('hello');
            -> 'VxuFAJXVARROc'
    

    ENCRYPT() ignoriert zumindest auf einigen Systemen alle bis auf die ersten acht Zeichen von str. Dieses Verhalten wird von der Implementierung des zugrunde liegenden crypt()-Systemaufrufs bestimmt.

    Wenn crypt() nicht auf Ihrem System verfügbar ist (wie es bei Windows der Fall ist), gibt ENCRYPT() immer NULL zurück.

  • MD5(str)

    Berechnet eine MD5-Prüfsumme mit 128 Bits für den String. Der Wert wird als 32 Hexadezimalstellen umfassender Binär-String zurückgegeben. Ist das Argument NULL, so wird auch NULL zurückgegeben. Der Rückgabewert kann z. B. als Hash-Schlüssel verwendet werden.

    mysql> SELECT MD5('testing');
            -> 'ae2b1fca515949e5d54fb22b8ed95575'
    

    Dies ist der „MD5-Message-Digest-Algorithmus“ von RSA Data Security, Inc.

    Wenn Sie den Wert in Großbuchstaben konvertieren wollen, lesen Sie die Beschreibung zur Konvertierung von Binär-Strings im Abschnitt zum Operator BINARY (Abschnitt 12.8, „Cast-Funktionen und Operatoren“).

    Beachten Sie auch die Anmerkung zum MD5-Algorithmus am Anfang dieses Abschnitts.

  • OLD_PASSWORD(str)

    OLD_PASSWORD() wurde zu MySQL hinzugefügt, als die Implementierung von PASSWORD() geändert wurde, um die Sicherheit zu verbessern. OLD_PASSWORD() gibt den Wert der alten (d. h. vor Version 4.1 verwendeten) Implementierung von PASSWORD() als Binär-String zurück und soll Ihnen das Zurücksetzen von Passwörtern auf Clients vor Version 4.1 gestatten, die mit Ihrem MySQL Server unter Version 5.1 eine Verbindung herstellen können sollen, ohne ausgesperrt zu werden. Siehe auch Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“.

  • PASSWORD(str)

    Berechnet einen Passwort-String aus dem Klartextpasswort str und gibt diesen zurück. Der Rückgabewert ist ein Binär-String oder aber NULL, sofern das Argument NULL war. Diese Funktion wird zur Verschlüsselung von MySQL-Passwörtern zur Speicherung in der Spalte Password der Grant-Tabelle user benutzt.

    mysql> SELECT PASSWORD('badpwd');
            -> '*AAB3E285149C0135D51A520E1940DD3263DC008C'
    

    Die PASSWORD()-Verschlüsselung ist unidirektional (d. h. unumkehrbar).

    PASSWORD() führt keine Passwortverschlüsselung in der Art der Verschlüsselung von Unix-Passwörtern durch. Siehe auch ENCRYPT().

    Hinweis: Die Funktion PASSWORD() wird in MySQL Server vom Authentifizierungssystem verwendet. Sie sollten Sie nicht in Ihren eigenen Anwendungen einsetzen. Ziehen Sie zu diesem Zweck eher MD5() oder SHA1() in Betracht. Ferner können Sie RFC 2195 weitere Informationen zum sicheren Umgang mit Passwörtern und Authentifizierung in Ihren Anwendungen entnehmen.

  • SHA1(str), SHA(str)

    Berechnet eine 160 Bits umfassende SHA-1-Prüfsumme für den String. (Siehe auch RFC 3174 mit dem Titel „Secure Hash Algorithm“). Der Wert wird als 40 Hexadezimalstellen umfassender Binär-String zurückgegeben. Ist das Argument NULL, so wird auch NULL zurückgegeben. Diese Funktion lässt sich etwa für die Erstellung eines Hash-Schlüssels verwenden. Sie können sie auch als Kryptografiefunktion zur Speicherung von Passwörtern verwenden. SHA() ist synonym zu SHA1().

    mysql> SELECT SHA1('abc');
            -> 'a9993e364706816aba3e25717850c26c9cd0d89d'
    

    SHA1() kann als aus kryptografischer Sicht sichereres Äquivalent zu MD5() betrachtet werden. Allerdings sollten Sie auch die Anmerkung zu den MD5- und SHA-1-Algorithmen am Anfang dieses Abschnitts beachten.

  • UNCOMPRESS(string_to_uncompress)

    Entkomprimiert einen String, der mit der Funktion COMPRESS() komprimiert wurde. Wenn dieses Argument kein komprimierter Wert ist, ist das Ergebnis NULL. Diese Funktion erfordert es, dass MySQL mit einer Komprimierungsbibliothek wie etwa zlib kompiliert wurde. Andernfalls ist der Rückgabewert immer NULL.

    mysql> SELECT UNCOMPRESS(COMPRESS('any string'));
            -> 'any string'
    mysql> SELECT UNCOMPRESS('any string');
            -> NULL
    
  • UNCOMPRESSED_LENGTH(compressed_string)

    Gibt die Länge zurück, die der komprimierte String vor der Länge hatte.

    mysql> SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));
            -> 30
    

12.10.3. Informationsfunktionen

  • BENCHMARK(count,expr)

    Die Funktion BENCHMARK() wiederholt die Ausführung des Ausdrucks expr mit der mit count angegebenen Häufigkeit. Sie kann verwendet werden, um zu ermitteln, wie schnell MySQL den Ausdruck verarbeitet. Der Ergebniswert ist immer 0. Vorgesehen ist die Verwendung dieser Funktion aus dem Client mysql heraus. Dieser gibt dann die Ausführungszeiten der Abfrage an:

    mysql> SELECT BENCHMARK(1000000,ENCODE('hello','goodbye'));
    +----------------------------------------------+
    | BENCHMARK(1000000,ENCODE('hello','goodbye')) |
    +----------------------------------------------+
    |                                            0 |
    +----------------------------------------------+
    1 row in set (4.74 sec)
    

    Die gemeldete Zeit ist die auf der Clientseite verstrichene Zeit und nicht die Prozessorzeit auf der Serverseite. Wir empfehlen die mehrfache Ausführung von BENCHMARK() und die Interpretation des Ergebnisses im Hinblick darauf, wie hoch die Belastung des Servercomputers ist.

  • CHARSET(str)

    Gibt den Zeichensatz des String-Arguments zurück.

    mysql> SELECT CHARSET('abc');
            -> 'latin1'
    mysql> SELECT CHARSET(CONVERT('abc' USING utf8));
            -> 'utf8'
    mysql> SELECT CHARSET(USER());
            -> 'utf8'
    
  • COERCIBILITY(str)

    Gibt den Sortierfolgenvorrangswert des String-Arguments zurück.

    mysql> SELECT COERCIBILITY('abc' COLLATE latin1_swedish_ci);
            -> 0
    mysql> SELECT COERCIBILITY(USER());
            -> 3
    mysql> SELECT COERCIBILITY('abc');
            -> 4
    

    Die Rückgabewerte haben die in der folgenden Tabelle aufgeführten Bedeutungen. Niedrigere Werte haben dabei eine höhere Rangstufe.

    SortierfolgenvorrangBedeutungBeispiel
    0Explizite SortierungWert mit COLLATE-Klausel
    1Keine SortierungVerkettung von Strings mit unterschiedlichen Sortierungen
    2Implizite SortierungSpaltenwert, Parameter einer gespeicherten Routine oder lokale Variable
    3SystemkonstanteUSER()-Rückgabewert
    4Sortierfolgenvorrang einstellbarLiteraler String
    5IgnorierbarNULL oder ein Ausdruck, der von NULL abgeleitet wurde
  • COLLATION(str)

    Gibt die Sortierung des String-Arguments zurück.

    mysql> SELECT COLLATION('abc');
            -> 'latin1_swedish_ci'
    mysql> SELECT COLLATION(_utf8'abc');
            -> 'utf8_general_ci'
    
  • CONNECTION_ID()

    Gibt die Verbindungskennung (Thread-ID) der Verbindung zurück. Jede Verbindung hat eine Kennung, die in der Gesamtzahl der aktuell verbundenen Clients eindeutig ist.

    mysql> SELECT CONNECTION_ID();
            -> 23786
    
  • CURRENT_USER, CURRENT_USER()

    Gibt die Kombination aus Benutzer- und Hostnamen für das MySQL-Konto zurück, das der Server zur Authentifizierung des aktuellen Clients verwendet hat. Dieses Konto bestimmt Ihre Zugriffsberechtigungen. Innerhalb einer gespeicherten Routine, die mit dem Merkmal SQL SECURITY DEFINER definiert wurde, gibt CURRENT_USER() den Ersteller der Routine zurück. Der Rückgabewert ist ein String im Zeichensatz utf8.

    Der Wert von CURRENT_USER() kann sich vom Wert von USER() unterscheiden.

    mysql> SELECT USER();
            -> 'davida@localhost'
    mysql> SELECT * FROM mysql.user;
    ERROR 1044: Access denied for user ''@'localhost' to
    database 'mysql'
    mysql> SELECT CURRENT_USER();
            -> '@localhost'
    

    Das Beispiel veranschaulicht, dass, obwohl der Client den Benutzernamen davida (gemäß dem Wert der Funktion USER()) angegeben hat, der Server den Client unter Verwendung eines anonymen Benutzerkontos authentifiziert hat. Dies geht aus dem leeren Benutzernamensteil des CURRENT_USER()-Werts hervor. Eine mögliche Ursache hierfür besteht darin, dass in den Grant-Tabellen kein Konto davida aufgeführt ist.

  • DATABASE()

    Gibt den Namen der Standarddatenbank (d. h. der aktuellen Datenbank) als String im Zeichensatz utf8 zurück. Ist keine Standarddatenbank vorhanden, dann gibt DATABASE() NULL zurück. Innerhalb einer gespeicherten Routine ist die Standarddatenbank diejenige, mit der die Routine assoziiert ist. Dies muss nicht unbedingt die gleiche Datenbank sein, die als Standarddatenbank im aufrufenden Kontext verwendet wird.

    mysql> SELECT DATABASE();
            -> 'test'
    

    Ist keine Standarddatenbank vorhanden, dann gibt DATABASE() NULL zurück.

  • FOUND_ROWS()

    Eine SELECT-Anweisung kann eine LIMIT-Klausel enthalten, die die Anzahl der Datensätze beschränkt, die der Server an den Client zurückgibt. In manchen Fällen kann es wünschenswert sein, zu wissen, wie viele Datensätze die Anweisung ohne LIMIT-Klausel zurückgegeben hätte, ohne dass man die Anweisung hierzu erneut ausführen müsste. Um diese Anzahl zu ermitteln, fügen Sie die Option SQL_CALC_FOUND_ROWS in die SELECT-Anweisung ein und rufen danach FOUND_ROWS() auf:

    mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
        -> WHERE id > 100 LIMIT 10;
    mysql> SELECT FOUND_ROWS();
    

    Die zweite SELECT-Anweisung gibt eine Zahl zurück, die angibt, wie viele Datensätze die erste SELECT-Anweisung zurückgegeben hätte, wenn die LIMIT-Klausel nicht enthalten gewesen wäre. (Wenn die vorangegangene SELECT-Anweisung die Option SQL_CALC_FOUND_ROWS nicht enthält, dann gibt FOUND_ROWS() mit LIMIT unter Umständen ein anderes Ergebnis als ohne.)

    Die mit FOUND_ROWS() ermittelte Anzahl der Datensätze ist flüchtig und sollte nicht über die der SELECT SQL_CALC_FOUND_ROWS-Anweisung nachfolgende Anweisung hinaus verfügbar bleiben. Wenn Sie den Wert später noch einmal benötigen sollten, dann sollten Sie ihn speichern:

    mysql> SELECT SQL_CALC_FOUND_ROWS * FROM ... ;
    mysql> SET @rows = FOUND_ROWS();
    

    Wenn Sie SELECT SQL_CALC_FOUND_ROWS verwenden, muss MySQL berechnen, wie viele Datensätze in der vollständigen Ergebnismenge enthalten sind. Allerdings ist dies schneller, als die Abfrage ohne LIMIT erneut auszuführen, weil die Ergebnismenge nicht an den Client gesendet werden muss.

    SQL_CALC_FOUND_ROWS und FOUND_ROWS() können in Situationen nützlich sein, in denen Sie die Anzahl der von einer Abfrage zurückgegebenen Datensätze beschränken, aber auch die Anzahl der Datensätze im vollständigen Ergebnis ermitteln wollen, ohne die Abfrage erneut auszuführen. Ein Beispiel hierfür wäre ein Webskript, das seitenweise eine Darstellung mit Links auf Seiten anzeigt, die auf andere Bereiche eines Suchergebnisses verweisen. Mithilfe von FOUND_ROWS() können Sie bestimmen, wie viele andere Seiten für den Rest des Ergebnisses benötigt werden.

    Die Verwendung von SQL_CALC_FOUND_ROWS und FOUND_ROWS() ist bei UNION-Anweisungen komplexer als bei einfachen SELECT-Anweisungen, weil LIMIT an mehreren Stellen in einer UNION auftreten kann. Es kann auf einzelne SELECT-Anweisungen in der UNION oder aber global auf das Ergebnis der UNION als Ganzes angewendet werden.

    Der Zweck von SQL_CALC_FOUND_ROWS bei UNION besteht in der Rückgabe der Anzahl von Datensätzen, die ohne globale LIMIT-Klausel zurückgegeben worden wäre. Die Benutzung von SQL_CALC_FOUND_ROWS mit UNION ist folgenden Bedingungen unterworfen:

    • Das Schlüsselwort SQL_CALC_FOUND_ROWS muss in der ersten SELECT-Anweisung der UNION auftreten.

    • Der Wert von FOUND_ROWS() ist nur exakt, wenn UNION ALL verwendet wird. Wenn UNION ohne ALL verwendet wird, findet eine Entfernung von Dubletten statt, weswegen der Wert von FOUND_ROWS() nur näherungsweise ist.

    • Wenn LIMIT nicht in der UNION vorhanden ist, wird SQL_CALC_FOUND_ROWS ignoriert und gibt die Anzahl der Reihen in der Temporärtabelle zurück, die zur Verarbeitung der UNION verwendet wird.

  • LAST_INSERT_ID(), LAST_INSERT_ID(expr)

    Gibt den ersten automatisch erzeugten Wert zurück, der für eine AUTO_INCREMENT-Spalte durch die aktuelle INSERT- oder UPDATE-Anweisung eingestellt wurde, die eine solche Spalte modifiziert hat.

    mysql> SELECT LAST_INSERT_ID();
            -> 195
    

    Die erzeugte Kennung wird auf dem Server verbindungsspezifisch gehandhabt: Der von der Funktion an einen bestimmten Client zurückgegebene Wert ist der erste AUTO_INCREMENT-Wert, der für die zuletzt abgesetzte Anweisung, die eine AUTO_INCREMENT-Spalte betraf, von diesem Client erzeugt wurde. Dieser Wert darf nicht von anderen Clients bearbeitet werden, auch wenn diese selbst AUTO_INCREMENT-Werte erzeugen. Dieses Verhalten gewährleistet, dass jeder Client seine eigene Kennung abrufen kann, ohne die Aktivitäten anderer Clients berücksichtigen oder Sperren setzen bzw. Transaktionen verwenden zu müssen.

    Der Wert von LAST_INSERT_ID() wird nicht geändert, wenn Sie die AUTO_INCREMENT-Spalte eines Datensatzes auf einen „nichtmagischen“ Wert (d. h. einen Wert, der nicht NULL und nicht 0 ist) setzen.

    Wichtig: Wenn Sie mehrere Datensätze mithilfe einer einzelnen INSERT-Anweisung einfügen, gibt LAST_INSERT_ID() nur denjenigen Wert zurück, der für den ersten eingefügten Datensatz erzeugt wurde. Grund hierfür ist, dass es möglich sein soll, dieselbe INSERT-Anweisung problemlos auf einem anderen Server zu reproduzieren.

    Zum Beispiel:

    mysql> USE test;
    Database changed
    mysql> CREATE TABLE t (
        ->   id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
        ->   name VARCHAR(10) NOT NULL
        -> );
    Query OK, 0 rows affected (0.09 sec)
    
    mysql> INSERT INTO t VALUES (NULL, 'Bob');
    Query OK, 1 row affected (0.01 sec)
    
    mysql> SELECT * FROM t;
    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    +----+------+
    1 row in set (0.01 sec)
    
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                1 |
    +------------------+
    1 row in set (0.00 sec)
    
    mysql> INSERT INTO t VALUES
        -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> SELECT * FROM t;
    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    |  2 | Mary |
    |  3 | Jane |
    |  4 | Lisa |
    +----+------+
    4 rows in set (0.01 sec)
    
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                2 |
    +------------------+
    1 row in set (0.00 sec)
    

    Obwohl die zweite INSERT-Anweisung drei neue Datensätze in t eingefügt hat, war die für den ersten dieser Datensätze erzeugte Kennung 2, und diesen Wert hat LAST_INSERT_ID() auch für die folgende SELECT-Anweisung zurückgegeben.

    Wenn Sie INSERT IGNORE verwenden und der Datensatz ignoriert wird, wird der AUTO_INCREMENT-Zähler nicht erhöht, und LAST_INSERT_ID() gibt 0 zurück, um anzuzeigen, dass kein Datensatz eingefügt wurde.

    Wenn expr als Argument für LAST_INSERT_ID() angegeben wird, wird der Wert des Arguments von der Funktion zurückgegeben und als nächster Wert von LAST_INSERT_ID() zurückzugebender Wert vermerkt. Dies kann zur Simulierung von Sequenzen verwendet werden:

    1. Erstellen Sie eine Tabelle zur Aufnahme des Sequenzzählers und initialisieren Sie sie:

      mysql> CREATE TABLE sequence (id INT NOT NULL);
      mysql> INSERT INTO sequence VALUES (0);
      
    2. Erstellen Sie mit dieser Tabelle wie folgt Sequenznummern:

      mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
      mysql> SELECT LAST_INSERT_ID();
      

      Die UPDATE-Anweisung erhöht den Sequenzzähler und sorgt dafür, dass der nächste Aufruf von LAST_INSERT_ID() den aktualisierten Wert zurückgibt. Die SELECT-Anweisung ruft diesen Wert ab. Die C-API-Funktion mysql_insert_id() kann ebenfalls zum Abrufen des Werts verwendet werden. Siehe auch Abschnitt 24.2.3.36, „mysql_insert_id().

    Sie können Sequenzen zwar auch ohne Aufruf von LAST_INSERT_ID() erzeugen, aber die Funktion auf diese Weise zu verwenden hat den Vorteil, dass der Kennungswert am Server als letzter automatisch erzeugter Wert vermerkt wird. Dies ist im Multiuser-Betrieb sicher, weil mehrere Clients die Anweisung UPDATE absetzen und jeweils einen eigenen Sequenzwert mit der SELECT-Anweisung (oder mysql_insert_id()) erhalten, ohne andere Clients, die eigene Sequenzwerte erstellen, zu beeinträchtigen bzw. von ihnen beeinträchtigt zu werden.

    Beachten Sie, dass mysql_insert_id() erst nach den INSERT- und UPDATE-Anweisungen aktualisiert wird, d. h., Sie können die C-API-Funktion nicht zum Abrufen des Werts von LAST_INSERT_ID(expr) verwenden, nachdem andere SQL-Anweisungen wie SELECT oder SET ausgeführt wurden.

  • ROW_COUNT()

    ROW_COUNT() gibt die Anzahl der von der vorherigen Anweisung aktualisierten, eingefügten oder gelöschten Datensätze zurück. Dies entspricht der Datensatzanzahl, die vom Client mysql angezeigt wird, und dem Wert der C-API-Funktion mysql_affected_rows().

    mysql> INSERT INTO t VALUES(1),(2),(3);
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> SELECT ROW_COUNT();
    +-------------+
    | ROW_COUNT() |
    +-------------+
    |           3 |
    +-------------+
    1 row in set (0.00 sec)
    
    mysql> DELETE FROM t WHERE i IN(1,2);
    Query OK, 2 rows affected (0.00 sec)
    
    mysql> SELECT ROW_COUNT();
    +-------------+
    | ROW_COUNT() |
    +-------------+
    |           2 |
    +-------------+
    1 row in set (0.00 sec)
    
  • SCHEMA()

    Diese Funktion ist synonym zu DATABASE().

  • SESSION_USER()

    SESSION_USER() ist ein Synonym für USER().

  • SYSTEM_USER()

    SYSTEM_USER() ist ein Synonym für USER().

  • USER()

    Gibt den aktuellen MySQL-Benutzer- und Hostnamen als String im Zeichensatz utf8 zurück.

    mysql> SELECT USER();
            -> 'davida@localhost'
    

    Der Wert gibt den Benutzernamen, den Sie beim Herstellen der Verbindung zum Server eingegeben haben, und den Clienthost an, über den die Verbindung hergestellt wurde. Der Wert kann sich von dem von CURRENT_USER() unterscheiden.

    Sie können den Benutzernamensanteil wie folgt extrahieren:

    mysql> SELECT SUBSTRING_INDEX(USER(),'@',1);
            -> 'davida'
    
  • VERSION()

    Gibt einen String zurück, der die MySQL Server-Version angibt. Der String verwendet den Zeichensatz utf8.

    mysql> SELECT VERSION();
            -> '5.1.5-alpha-standard'
    

    Beachten Sie, dass, wenn Ihr Versions-String mit -log endet, dies bedeutet, dass das Loggen aktiviert ist.

12.10.4. Verschiedene Funktionen

  • DEFAULT(col_name)

    Gibt den Standardwert einer Tabellenspalte zurück. Wenn die Spalte keinen Standardwert hat, wird ein Fehler erzeugt.

    mysql> UPDATE t SET i = DEFAULT(i)+1 WHERE id < 100;
    
  • FORMAT(X,D)

    Formatiert die Zahl X in ein Format wie '#,###,###.##', gerundet auf D Dezimalstellen, und gibt das Ergebnis als String zurück. Detaillierte Informationen finden Sie in Abschnitt 12.3, „String-Funktionen“.

  • GET_LOCK(str,timeout)

    Versucht eine Sperre mit dem String str als Namen zu erwirken. Hierbei wird ein Zeitüberschreitungswert von timeout Sekunden angewendet. Gibt 1 zurück, wenn die Sperrung erfolgreich war, 0, wenn es zu einer Zeitüberschreitung kam (etwa weil zuvor ein anderer Client den Namen gesperrt hatte), oder NULL, wenn ein Fehler aufgetreten ist (z. B. aufgrund von Speichermangel oder einer Terminierung des Threads mit mysqladmin kill). Wurde eine Sperre mit GET_LOCK() erwirkt, so wird diese wieder aufgehoben, wenn Sie RELEASE_LOCK() oder noch einmal GET_LOCK() ausführen oder Ihre Verbindung – gewünscht oder unvorhergesehen – endet.

    Diese Funktion kann zur Implementierung von Anwendungssperren oder zur Simulation von Datensatzsperren verwendet werden. Die Namen werden serverweit gesperrt. Wenn ein Name von einem Client gesperrt wird, blockiert GET_LOCK() alle weiteren Anforderungen von gleichnamigen Sperren durch andere Clients. So wiederum können Clients, die einem gegebenen Sperrennamen zustimmen, diesen Namen zur Durchführung kooperativer beratender Sperrungen verwenden. Sie müssen allerdings beachten, dass auf diese Weise auch Clients, die nicht zu den kooperierenden Clients gehören, unbeabsichtigt oder gezielt einen Namen sperren und so verhindern können, dass ein kooperierender Client den Namen sperren kann. Sie können die Wahrscheinlichkeit hierfür verringern, indem Sie Sperrnamen verwenden, die datenbank- oder anwendungsspezifisch sind. Verwenden Sie beispielsweise Sperrnamen der Form db_name.str oder app_name.str.

    mysql> SELECT GET_LOCK('lock1',10);
            -> 1
    mysql> SELECT IS_FREE_LOCK('lock2');
            -> 1
    mysql> SELECT GET_LOCK('lock2',10);
            -> 1
    mysql> SELECT RELEASE_LOCK('lock2');
            -> 1
    mysql> SELECT RELEASE_LOCK('lock1');
            -> NULL
    

    Der zweite RELEASE_LOCK()-Aufruf gibt NULL zurück, weil die Sperre 'lock1' automatisch durch den zweiten GET_LOCK()-Aufruf aufgehoben wurde.

    Hinweis: Wenn ein Client versucht, eine Sperre zu erwirken, die bereits von einem anderen Client gehalten wird, dann erfolgt die Sperrung gemäß dem Argument timeout. Wird der blockierte Client beendet, dann wird der Thread erst terminiert, wenn eine Zeitüberschreitung der Sperranforderung erfolgt. Dieser Bug ist bekannt.

  • INET_ATON(expr)

    Wird eine Netzwerkadresse als String in der üblichen Schreibweise (vier punktgetrennte Oktette) übergeben, dann gibt die Funktion einen Integer zurück, der den numerischen Wert der Adresse angibt. Adressen können 4 oder 8 Byte umfassen.

    mysql> SELECT INET_ATON('209.207.224.40');
            -> 3520061480
    

    Die Zahl wird immer in der Reihenfolge der Netzwerkbytes erzeugt. Beim obigen Beispiel wird sie als 209×2563 + 207×2562 + 224×256 + 40 berechnet.

    INET_ATON() versteht auch IP-Adressen in der Kurzform:

    mysql> SELECT INET_ATON('127.0.0.1'), INET_ATON('127.1');
            -> 2130706433, 2130706433
    

    Hinweis: Wenn Sie Werte speichern, die von INET_ATON() erzeugt wurden, empfehlen wir die Verwendung einer INT UNSIGNED-Spalte. Wenn Sie eine (vorzeichenbehaftete) INT-Spalte verwenden, können Werte, die IP-Adressen entsprechen, deren erstes Oktett größer als 127 ist, nicht korrekt gespeichert werden. Siehe auch Abschnitt 11.2, „Numerische Datentypen“.

  • INET_NTOA(expr)

    Wenn eine numerische Netzwerkadresse mit einer Länge von 4 oder 8 Byte übergeben wird, gibt die Funktion die punktgetrennte Darstellung der Adresse als String zurück.

    mysql> SELECT INET_NTOA(3520061480);
            -> '209.207.224.40'
    
  • IS_FREE_LOCK(str)

    Überprüft, ob die Sperre mit dem Namen str frei (d. h. nicht gesperrt) ist und verwendet werden kann. Gibt 1 zurück, wenn die Sperre verfügbar ist (also von niemandem benutzt wird), 0, wenn die Sperre aktiv ist, und NULL, wenn ein Fehler aufgetreten ist (z. B. bei einem falschen Argument).

  • IS_USED_LOCK(str)

    Überprüft, ob die Sperre mit dem Namen str verwendet wird (d. h. nicht gesperrt ist). Ist dies der Fall, dann wird die Verbindungskennung des Clients zurückgegeben, der die Sperre hält. Andernfalls wird NULL zurückgegeben.

  • MASTER_POS_WAIT(log_name,log_pos[,timeout])

    Diese Funktion ist praktisch zur Steuerung der Master/Slave-Synchronisation. Sie blockiert, bis der Slave alle Änderungen bis zur im Master-Log angegebenen Position gelesen und übernommen hat. Der Rückgabewert ist die Anzahl der Logereignisse, auf die der Slave warten musste, um bis zur angegebenen Position fortschreiten zu können. Die Funktion gibt NULL zurück, wenn der SQL-Slave-Thread nicht gestartet wurde, die Master-Daten des Slaves nicht initialisiert wurden, die Argumente inkorrekt sind oder ein Fehler auftritt. -1 wird bei einer Zeitüberschreitung zurückgegeben. Wenn der SQL-Slave-Thread endet, während MASTER_POS_WAIT() wartet, gibt die Funktion NULL zurück. Befindet sich der Slave bereits jenseits der angegebenen Position, dann erfolgt die Rückgabe durch die Funktion unmittelbar.

    Wenn ein timeout-Wert angegeben wird, beendet MASTER_POS_WAIT() den Wartevorgang, sobald timeout Sekunden verstrichen sind. timeout muss größer als 0 sein; ein Nullwert oder ein negativer timeout-Wert haben die Bedeutung „kein timeout-Wert“.

  • NAME_CONST(name,value)

    Gibt den angegebenen Wert zurück. Wenn NAME_CONST() zur Erzeugung einer Ergebnismengenspalte verwendet wird, erhält die Spalte den angegebenen Namen.

    mysql> SELECT NAME_CONST('myname', 14);
    +--------+
    | myname |
    +--------+
    |     14 |
    +--------+
    

    Die Funktion wurde in MySQL 5.0.12 hinzugefügt und ist nur zur internen Verwendung vorgesehen. Der Server verwendet sie, wenn er Anweisungen aus gespeicherten Routinen schreibt, die Referenzen auf lokale Routinenvariablen haben (siehe Beschreibung in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“). Sie sehen die Funktion unter Umständen in der Ausgabe von mysqlbinlog.

  • RELEASE_LOCK(str)

    Hebt die Sperre namens str auf, die mit GET_LOCK() erwirkt wurde. Gibt 1 zurück, wenn die Sperre aufgehoben wurde, 0, wenn die Sperre nicht durch diesen Thread erwirkt worden war (wobei die Sperre auch nicht aufgehoben wird), und NULL, wenn der Name nicht existiert. Die Sperre existiert nicht, wenn sie niemals von einem GET_LOCK()-Aufruf erwirkt worden war oder zuvor bereits aufgehoben wurde.

    Die DO-Anweisung ist in Kombination mit RELEASE_LOCK() sehr praktisch. Siehe auch Abschnitt 13.2.2, „DO.

  • SLEEP(duration)

    Setzt eine Unterbrechung mit einer Länge von der durch duration angegebenen Anzahl von Sekunden und gibt dann 0 zurück. Wenn SLEEP() unterbrochen wird, wird 1 zurückgegeben. Die Dauer kann einen in Mikrosekunden angegebenen Bruchteil enthalten.

  • UUID()

    Gibt eine UUID (Universal Unique Identifier) gemäß „DCE 1.1: Remote Procedure Call“ (Anhang A) der CAE-Spezifikation (Common Applications Environment Specifications), veröffentlicht von The Open Group im Oktober 1997 (Dokument Nr. C706, http://www.opengroup.org/public/pubs/catalog/c706.htm), zurück.

    Eine UUID ist eine Zahl, die in Raum und Zeit eindeutig ist. Bei zwei Aufrufen von UUID() wird die Erzeugung zweier vollkommen unterschiedlicher Werte erwartet – und zwar auch dann, wenn diese beiden Aufrufe auf zwei separaten Computern erfolgen, die nicht miteinander verbunden sind.

    Die UUID ist eine 128-Bit-Zahl, die durch einen String aus fünf Hexadezimalzahlen im Format aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee dargestellt wird:

    • Die ersten drei Zahlen werden aus einem Zeitstempel erzeugt.

    • Die vierte Zahl bewahrt die zeitbezogene Eindeutigkeit für den Fall, dass der Zeitstempel seine Monotonie verliert (z. B. aufgrund der Sommerzeit).

    • Die fünfte Zahl schließlich ist eine IEEE 802-Knotennummer, die die räumliche Eindeutigkeit gewährleistet. Ersatzweise wird eine Zufallszahl eingesetzt, wenn die Knotennummer nicht vorhanden ist (weil der Computer beispielsweise keine Ethernetkarte hat oder wir nicht wissen, wie man die Hardwareadresse einer Schnittstelle unter Ihrem Betriebssystem ermitteln kann). In diesem Fall ist die räumliche Eindeutigkeit nicht garantiert. Nichtsdestoweniger ist eine Kollision sehr unwahrscheinlich.

      Derzeit wird die MAC-Adresse einer Schnittstelle nur unter FreeBSD und Linux berücksichtigt. Unter anderen Betriebssystemen verwendet MySQL eine zufällig erzeugte 48-Bit-Zahl.

    mysql> SELECT UUID();
            -> '6ccd780c-baba-1026-9564-0040f4311e29'
    

    Beachten Sie, dass UUID() noch nicht in Verbindung mit der Replikation funktioniert.

  • VALUES(col_name)

    In einer INSERT ... ON DUPLICATE KEY UPDATE-Anweisung können Sie die Funktion VALUES(col_name) in der UPDATE-Klausel verwenden, um Spaltenwerte aus dem INSERT-Teil der Anweisung zu referenzieren. Anders gesagt, verweist VALUES(col_name) in der UPDATE-Klausel auf den Wert von col_name, der eingefügt worden wäre, wäre nicht ein Konflikt aufgrund einer Schlüsseldublette aufgetreten. Diese Funktion ist insbesondere bei Einfügevorgängen für mehrere Datensätze praktisch. Die Funktion VALUES() ist nur sinnvoll in INSERT ... ON DUPLICATE KEY UPDATE-Anweisungen zu verwenden; andernfalls gibt sie NULL zurück. Abschnitt 13.2.4.3, „INSERT ... ON DUPLICATE KEY UPDATE.

    mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
        -> ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
    

12.11. Funktionen und Modifizierer für die Verwendung in GROUP BY-Klauseln

12.11.1. Funktionen zur Benutzung in GROUP BY-Klauseln

Dieser Abschnitt beschreibt Gruppenfunktionen (Zusammenfassungsfunktionen), die Wertemengen bearbeiten. Sofern nicht anders angegeben, ignorieren Gruppenfunktionen NULL-Werte.

Wenn Sie eine Gruppenfunktion in einer Anweisung verwenden, die keine GROUP BY-Klausel enthält, entspricht dies der Gruppierung aller Datensätze.

Die Zusammenfassungsfunktionen SUM() und AVG() funktionieren bei Zeitwerten nicht. (Sie konvertieren die Werte in Zahlen, wodurch alles, was nach dem ersten nichtnumerischen Zeichen auftaucht, verloren geht.) Um dieses Problem zu umgehen, können Sie die Werte in numerische Einheiten konvertieren, dann die Zusammenfassungsfunktion ausführen und abschließend eine Rückkonvertierung in den Zeitwert durchführen. Ein paar Beispiele:

SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col))) FROM tbl_name;
SELECT FROM_DAYS(SUM(TO_DAYS(date_col))) FROM tbl_name;
  • AVG([DISTINCT] expr)

    Gibt den Durchschnittswert von expr zurück. Die Option DISTINCT kann verwendet werden, um den Durchschnitt der unterschiedlichen Werte von expr zurückzugeben.

    AVG() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

    mysql> SELECT student_name, AVG(test_score)
        ->        FROM student
        ->        GROUP BY student_name;
    
  • BIT_AND(expr)

    Gibt das Bit-AND aller Bits in expr zurück. Die Berechnung erfolgt mit 64-Bit-Genauigkeit (BIGINT-Genauigkeit).

    Die Funktion gibt 18446744073709551615 zurück, wenn keine passenden Datensätze vorhanden waren. (Dies ist der Wert eines vorzeichenlosen BIGINT-Werts, bei dem alle Bits gesetzt sind.)

  • BIT_OR(expr)

    Gibt das Bit-OR aller Bits in expr zurück. Die Berechnung erfolgt mit 64-Bit-Genauigkeit (BIGINT-Genauigkeit).

    Die Funktion gibt 0 zurück, wenn keine passenden Datensätze vorhanden waren.

  • BIT_XOR(expr)

    Gibt das Bit-XOR aller Bits in expr zurück. Die Berechnung erfolgt mit 64-Bit-Genauigkeit (BIGINT-Genauigkeit).

    Die Funktion gibt 0 zurück, wenn keine passenden Datensätze vorhanden waren.

  • COUNT(expr)

    Gibt die Anzahl der Nicht-NULL-Werte in den von einer SELECT-Anweisung abgerufenen Datensätzen an.

    COUNT() gibt 0 zurück, wenn keine passenden Datensätze vorhanden waren.

    mysql> SELECT student.student_name,COUNT(*)
        ->        FROM student,course
        ->        WHERE student.student_id=course.student_id
        ->        GROUP BY student_name;
    
    

    COUNT(*) ist dahingehend ein wenig anders, dass es die Anzahl der abgerufenen Datensätze unabhängig davon angibt, ob diese NULL-Werte enthält oder nicht.

    COUNT(*) ist auf eine sehr schnelle Rückgabe optimiert, wenn die SELECT-Anweisung nur Daten aus einer Tabelle abruft, andere Spalten nicht abgerufen werden und keine WHERE-Klausel vorhanden ist. Zum Beispiel:

    mysql> SELECT COUNT(*) FROM student;
    

    Diese Optimierung gilt nur für MyISAM-Tabellen, weil eine exakte Datensatzanzahl für diese Speicher-Engine gespeichert wird und so sehr schnell abgerufen werden kann. Bei transaktionssicheren Speicher-Engines wie InnoDB und BDB ist die Speicherung einer exakten Datensatzanzahl problematischer, weil zum gegebenen Zeitpunkt mehrere Transaktionen stattfinden können, die jede für sich Auswirkungen auf die Anzahl der Datensätze haben kann.

  • COUNT(DISTINCT expr,[expr...])

    Gibt die Anzahl unterschiedlicher Nicht-NULL-Werte zurück.

    COUNT(DISTINCT) gibt 0 zurück, wenn keine passenden Datensätze vorhanden waren.

    mysql> SELECT COUNT(DISTINCT results) FROM student;
    

    In MySQL können Sie die Anzahl unterschiedlicher Ausdruckskombinationen abrufen, die nicht NULL enthalten, indem Sie eine Liste mit Ausdrücken übergeben. In Standard-SQL müssten Sie hierzu eine Verkettung aller Ausdrücke in COUNT(DISTINCT ...) angeben.

  • GROUP_CONCAT(expr)

    Diese Funktion gibt einen String als Ergebnis zurück. Dieser gibt die verketteten Nicht-NULL-Werte einer Gruppe zurück. NULL wird zurückgegeben, wenn keine Nicht-NULL-Werte vorhanden sind. Die vollständige Syntax sieht wie folgt aus:

    GROUP_CONCAT([DISTINCT] expr [,expr ...]
                 [ORDER BY {unsigned_integer | col_name | expr}
                     [ASC | DESC] [,col_name ...]]
                 [SEPARATOR str_val])
    
    mysql> SELECT student_name,
        ->     GROUP_CONCAT(test_score)
        ->     FROM student
        ->     GROUP BY student_name;
    

    Oder:

    mysql> SELECT student_name,
        ->     GROUP_CONCAT(DISTINCT test_score
        ->               ORDER BY test_score DESC SEPARATOR ' ')
        ->     FROM student
        ->     GROUP BY student_name;
    

    In MySQL können Sie die verketteten Werte von Ausdruckskombinationen erhalten. Dubletten können Sie mithilfe von DISTINCT beseitigen. Wenn Sie Werte im Ergebnis sortieren wollen, sollten Sie eine ORDER BY-Klausel verwenden. Um in umgekehrter (absteigender) Reihenfolge zu sortieren, fügen Sie in der ORDER BY-Klausel das Schlüsselwort DESC zum Namen der Spalte zu, nach der die Sortierung erfolgt: Standardmäßig erfolgt die Sortierung aufsteigend. Dies kann mit dem Schlüsselwort ASC explizit festgelegt werden. Auf SEPARATOR folgt der String-Wert, der zwischen die Ergebniswerte gesetzt werden soll. Der Vorgabewert ist ein Komma (‘,’). Sie können das Trennzeichen vollständig beseitigen, indem Sie SEPARATOR '' angeben.

    Sie können mit der Systemvariablen group_concat_max_len eine zulässige Maximallänge angeben. (Der Vorgabewert ist 1024.) Um dies zur Laufzeit zu machen, verwenden Sie folgende Syntax (hierbei ist val ein vorzeichenloser Integer):

    SET [SESSION | GLOBAL] group_concat_max_len = val;
    

    Wurde eine Maximallänge eingestellt, dann wird das Ergebnis auf diesen Wert gekürzt.

    Siehe auch CONCAT() und CONCAT_WS(): Abschnitt 12.3, „String-Funktionen“.

  • MIN([DISTINCT] expr), MAX([DISTINCT] expr)

    Gibt den Mindest- bzw. den Höchstwert von expr zurück. MIN() und MAX() können ein String-Argument entgegennehmen; in diesen Fällen geben Sie den niedrigsten bzw. höchsten String-Wert zurück. Siehe auch Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“. Das Schlüsselwort DISTINCT können Sie verwenden, um den kleinsten bzw. größten unterschiedlichen Wert im Ausdruck expr zu ermitteln; allerdings wird hierbei das gleiche Ergebnis wie beim Weglassen von DISTINCT erzielt.

    MIN() und MAX() geben NULL zurück, wenn keine passenden Datensätze vorhanden waren.

    mysql> SELECT student_name, MIN(test_score), MAX(test_score)
        ->        FROM student
        ->        GROUP BY student_name;
    

    Bei MIN(), MAX() und anderen Zusammenfassungsfunktionen vergleicht MySQL zurzeit ENUM- und SET-Spalten nach ihrem String-Wert anstelle der relativen Position des Strings in der Menge. Dies unterscheidet sich von der von ORDER BY verwendeten Vergleichsmethode. Eine Behebung ist für einen zukünftigen MySQL-Release vorgesehen.

  • STD(expr) STDDEV(expr)

    Gibt die Populationsstandardabweichung von expr zurück. Dies stellt eine Erweiterung des SQL-Standards dar. Die Form STDDEV() dieser Funktion ist zum Zweck der Oracle-Kompatibilität vorhanden. Stattdessen kann die SQL-Standardfunktion STDDEV_POP() verwendet werden.

    Diese Funktionen geben NULL zurück, wenn keine passenden Datensätze vorhanden waren.

  • STDDEV_POP(expr)

    Gibt die Populationsstandardabweichung von expr (Quadratwurzel von VAR_POP()) zurück. Sie können auch STD() oder STDDEV() verwenden, die äquivalent, aber nicht SQL-Standard sind.

    STDDEV_POP() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

  • STDDEV_SAMP(expr)

    Gibt die Beispielstandardabweichung von expr (Quadratwurzel von VAR_SAMP()) zurück.

    STDDEV_SAMP() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

  • SUM([DISTINCT] expr)

    Gibt die Summe von expr zurück. Wenn die Rückgabemenge keine Datensätze enthält, gibt SUM() NULL zurück. Das Schlüsselwort DISTINCT kann in MySQL 5.1 benutzt werden, um nur die Summe unterschiedlicher Werte in expr zu bilden.

    SUM() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

  • VAR_POP(expr)

    Gibt die Populationsstandardvarianz von expr zurück. Hierbei werden Datensätze als gesamte Population und nicht als Beispiel betrachtet, d. h., die Anzahl der Datensätze ist der Nenner. Sie können auch VARIANCE() verwenden, das äquivalent, aber nicht SQL-Standard ist.

    VAR_POP() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

  • VAR_SAMP(expr)

    Gibt die Beispielvarianz von expr zurück. Hieraus ergibt sich, dass der Nenner die Anzahl der Datensätze minus 1 ist.

    VAR_SAMP() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

  • VARIANCE(expr)

    Gibt die Populationsstandardvarianz von expr zurück. Dies stellt eine Erweiterung des SQL-Standards dar. Stattdessen kann die SQL-Standardfunktion VAR_POP() verwendet werden.

    VARIANCE() gibt NULL zurück, wenn keine passenden Datensätze vorhanden waren.

12.11.2. GROUP BY-Modifizierer

Die GROUP BY-Klausel gestattet die Verwendung eines Modifizierers WITH ROLLUP, der bewirkt, dass zusätzliche Datensätze zur zusammenfassenden Ausgabe hinzugefügt werden. Diese Datensätze stellen Zusammenfassungsoperationen einer höherer Ebene (so genannte Superaggregate) dar. ROLLUP gestattet Ihnen auf diese Weise die Beantwortung von Fragen auf mehreren Analyseebenen mit einer einzelnen Abfrage. Es kann beispielsweise verwendet werden, um eine OLAP-Unterstützung (Online Analytical Processing) zu implementieren.

Nehmen wir an, dass in einer Tabelle namens sales die Spalten year, country, product und profit zur Aufzeichnung der Vertriebsrentabilität vorhanden wären:

CREATE TABLE sales
(
    year    INT NOT NULL,
    country VARCHAR(20) NOT NULL,
    product VARCHAR(32) NOT NULL,
    profit  INT
);

Der Inhalt der Tabelle kann jahresbezogen wie folgt mit einer einfachen GROUP BY-Abfrage zusammengefasst werden:

mysql> SELECT year, SUM(profit) FROM sales GROUP BY year;
+------+-------------+
| year | SUM(profit) |
+------+-------------+
| 2000 |        4525 |
| 2001 |        3010 |
+------+-------------+

Die Ausgabe zeigt die Gesamtrendite pro Jahr an. Wenn Sie aber auch die Rendite für den Gesamtzeitraum bestimmen wollen, müssen Sie die einzelnen Werte selbst hinzufügen oder eine zusätzliche Abfrage ausführen.

Alternativ verwenden Sie ROLLUP, wodurch sich die beiden Analyseebenen in einer Abfrage zusammenfassen lassen. Das Hinzufügen eines WITH ROLLUP-Modifizierers zur GROUP BY-Klausel bewirkt, dass die Abfrage einen anderen Datensatz erstellt, der die Endsumme über alle vier Jahre angibt:

mysql> SELECT year, SUM(profit) FROM sales GROUP BY year WITH ROLLUP;
+------+-------------+
| year | SUM(profit) |
+------+-------------+
| 2000 |        4525 |
| 2001 |        3010 |
| NULL |        7535 |
+------+-------------+

Die Super-Aggregat-Zeile, die die Endsumme zusammenfasst, lässt sich am Wert NULL in der Spalte year erkennen.

Die Wirkung von ROLLUP ist etwas komplexer, wenn mehrere GROUP BY-Klauseln vorhanden sind. In diesem Fall erzeugt die Abfrage jedes Mal, wenn eine „Unterbrechung“ (also eine Wertänderung) in einer beliebigen Spalte (mit Ausnahme der letzten Gruppenspalte) vorhanden ist, einen Super-Aggregat-Datensatz.

So könnte etwa ohne ROLLUP eine Zusammenfassung der Tabelle sales basierend auf year, country und product wie folgt aussehen:

mysql> SELECT year, country, product, SUM(profit)
    -> FROM sales
    -> GROUP BY year, country, product;
+------+---------+------------+-------------+
| year | country | product    | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer   |        1500 |
| 2000 | Finland | Phone      |         100 |
| 2000 | India   | Calculator |         150 |
| 2000 | India   | Computer   |        1200 |
| 2000 | USA     | Calculator |          75 |
| 2000 | USA     | Computer   |        1500 |
| 2001 | Finland | Phone      |          10 |
| 2001 | USA     | Calculator |          50 |
| 2001 | USA     | Computer   |        2700 |
| 2001 | USA     | TV         |         250 |
+------+---------+------------+-------------+

Die Ausgabe zeigt Zusammenfassungswerte nur auf der Jahres-, Länder- und/oder Produktebene der Analyse an. Wird nun ROLLUP hinzugefügt, dann erzeugt die Abfrage diverse zusätzliche Datensätze:

mysql> SELECT year, country, product, SUM(profit)
    -> FROM sales
    -> GROUP BY year, country, product WITH ROLLUP;
+------+---------+------------+-------------+
| year | country | product    | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer   |        1500 |
| 2000 | Finland | Phone      |         100 |
| 2000 | Finland | NULL       |        1600 |
| 2000 | India   | Calculator |         150 |
| 2000 | India   | Computer   |        1200 |
| 2000 | India   | NULL       |        1350 |
| 2000 | USA     | Calculator |          75 |
| 2000 | USA     | Computer   |        1500 |
| 2000 | USA     | NULL       |        1575 |
| 2000 | NULL    | NULL       |        4525 |
| 2001 | Finland | Phone      |          10 |
| 2001 | Finland | NULL       |          10 |
| 2001 | USA     | Calculator |          50 |
| 2001 | USA     | Computer   |        2700 |
| 2001 | USA     | TV         |         250 |
| 2001 | USA     | NULL       |        3000 |
| 2001 | NULL    | NULL       |        3010 |
| NULL | NULL    | NULL       |        7535 |
+------+---------+------------+-------------+

Bei dieser Abfrage bewirkt das Hinzufügen von ROLLUP, dass die Ausgabe Zusammenfassungsinformationen auf vier Analyseebenen (und nicht nur auf einer) enthält. Die Ausgabe von ROLLUP interpretieren Sie wie folgt:

  • Auf jede Menge von Produktdatensätzen für ein gegebenes Jahr und Land folgend wird ein zusätzlicher Datensatz erzeugt, der die Gesamtzahl aller Produkte angibt. Bei diesen Datensätzen ist die Spalte product auf NULL gesetzt.

  • Auf jede Menge von Datensätzen für ein gegebenes Jahr und Land folgend wird ein zusätzlicher Datensatz erzeugt, der die Endsumme für alle Länder und Produkte angibt. Bei diesen Datensätzen sind die Spalten country und products auf NULL gesetzt.

  • Abschließend wird auf alle anderen Datensätze folgend ein zusätzlicher zusammenfassender Datensatz erzeugt, der die Endsumme für alle Jahre, Länder und Produkte angibt. Bei diesem Datensatz sind die Spalten year, country und products auf NULL gesetzt.

Weitere Aspekte der Benutzung von ROLLUP

Die folgenden Punkte beschreiben einige für die MySQL-Implementierung von ROLLUP spezifischen Verhaltensweisen:

Wenn Sie ROLLUP verwenden, dürfen Sie nicht gleichzeitig auch eine ORDER BY-Klausel zur Sortierung der Ergebnisse einsetzen. Mit anderen Worten, ROLLUP und ORDER BY schließen sich gegenseitig aus. Trotzdem können Sie Einfluss auf die Sortierreihenfolge nehmen. GROUP BY sortiert in MySQL Ergebnisse, und Sie können die Schlüsselwörter ASC und DESC ausdrücklich für Spaltennamen in der GROUP BY-Liste angeben, um die Sortierfolge für einzelne Spalten zu spezifizieren. (Die von ROLLUP hinzugefügten Zusammenfassungsdatensätze höherer Ebene erscheinen ungeachtet der Sortierfolge trotzdem erst hinter den Datensätzen, aus denen sie berechnet wurden.)

Mit LIMIT können Sie die Anzahl der an den Client zurückgegebenen Datensätze beschränken. LIMIT wird nach ROLLUP angewendet, d. h., die Beschränkung betrifft auch die zusätzlichen Datensätze, die von ROLLUP hinzugefügt worden sind. Zum Beispiel:

mysql> SELECT year, country, product, SUM(profit)
    -> FROM sales
    -> GROUP BY year, country, product WITH ROLLUP
    -> LIMIT 5;
+------+---------+------------+-------------+
| year | country | product    | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer   |        1500 |
| 2000 | Finland | Phone      |         100 |
| 2000 | Finland | NULL       |        1600 |
| 2000 | India   | Calculator |         150 |
| 2000 | India   | Computer   |        1200 |
+------+---------+------------+-------------+

Die Verwendung von LIMIT mit ROLLUP kann Ergebnisse erzeugen, die schwieriger zu interpretieren sind, weil Sie weniger Kontext haben, um die Super-Aggregate zu verstehen.

Die NULL-Indikatoren in jedem Super-Aggregat-Datensatz werden erzeugt, wenn der Datensatz an den Client gesendet wird. Der Server prüft alle in der GROUP BY-Klausel genannten Spalten, die auf die erste (am weitesten links stehende) Spalte folgen, deren Wert geändert wurde. Bei jeder Spalte in der Ergebnismenge, deren Name lexikalisch mit einem dieser Namen übereinstimmt, wird der Wert auf NULL gesetzt. (Wenn Sie Gruppenspalten über die Spaltennummer angeben, identifiziert der Server die auf NULL zu setzenden Spalten anhand ihrer Nummer.)

Weil die NULL-Werte in den Super-Aggregat-Datensätzen als solche während der Abfrageverarbeitung relativ spät in das Ergebnis eingefügt werden, können Sie sie nicht wie NULL-Werte innerhalb der Abfrage selbst überprüfen. So können Sie beispielsweise HAVING product IS NULL nicht zur Abfrage hinzufügen, um alle Datensätze mit Ausnahme der Super-Aggregat-Datensätze aus der Ausgabe zu entfernen.

Andererseits erscheinen die NULL-Werte als NULL auf der Clientseite und können insofern mithilfe einer beliebigen MySQL-Clientprogrammierschnittstelle geprüft werden.

12.11.3. GROUP BY mit versteckten Feldern

MySQL erweitert die Verwendung von GROUP BY dahingehend, dass Sie Spalten oder Berechnungen in der SELECT-Liste verwenden können, die nicht in der GROUP BY-Klausel erscheinen. Dies steht für „ein beliebiger Wert für diese Gruppe“. Sie können die Leistung dadurch optimieren, dass Sie das Sortieren und Gruppieren unnötiger Elemente umgehen. So müssen Sie beispielsweise in der folgenden Abfrage keine Gruppierung von customer.name durchführen:

SELECT order.custid, customer.name, MAX(payments)
  FROM order,customer
  WHERE order.custid = customer.custid
  GROUP BY order.custid;

In Standard-SQL hätten Sie hier customer.name zur GROUP BY-Klausel hinzufügen müssen. In MySQL ist der Name redundant, wenn bei der Ausführung der SQL-Modus ONLY_FULL_GROUP_BY nicht aktiviert ist.

Verwenden Sie diese Funktion nicht, wenn die Spalten, die Sie im GROUP BY-Anteil weglassen, in der Gruppe nicht eindeutig sind! Sie erhalten ansonsten nicht vorhersehbare Ergebnisse.

In manchen Fällen können Sie mit MIN() und MAX() einen bestimmten Spaltenwert auch dann erhalten, wenn dieser nicht eindeutig ist. Folgendes übergibt den Wert von column aus dem Datensatz, der den niedrigsten Wert in der Spalte sort hat:

SUBSTR(MIN(CONCAT(RPAD(sort,6,' '),column)),7)

Siehe auch Abschnitt 3.6.4, „Die Zeilen, die das gruppenweise Maximum eines bestimmten Felds enthalten“.

Beachten Sie, dass Sie, wenn Sie sich an den SQL-Standard halten wollen, Ausdrücke nicht in GROUP BY-Klauseln verwenden dürfen. Sie können diese Einschränkung umgehen, indem Sie ein Alias für den Ausdruck verwenden:

SELECT id,FLOOR(value/100) AS val
  FROM tbl_name
  GROUP BY id, val;

MySQL gestattet hingegen die Benutzung von Ausdrücken in GROUP BY-Klauseln. Zum Beispiel:

SELECT id,FLOOR(value/100)
  FROM tbl_name
  GROUP BY id, FLOOR(value/100);

Kapitel 13. SQL-Anweisungssyntax

Dieses Kapitel beschreibt die Syntax für die meisten von MySQL unterstützten SQL-Anweisungen. Weitere Beschreibungen zu Anweisungen finden Sie in den folgenden Kapiteln:

13.1. Datendefinition: CREATE, DROP, ALTER

13.1.1. ALTER DATABASE

ALTER {DATABASE | SCHEMA} [db_name]
    alter_specification [, alter_specification] ...

alter_specification:
    [DEFAULT] CHARACTER SET charset_name
  | [DEFAULT] COLLATE collation_name

Mit ALTER DATABASE können Sie die grundlegenden Eigenschaften einer Datenbank ändern. Diese Eigenschaften sind in der Datei db.opt im Datenbankverzeichnis gespeichert. Um ALTER DATABASE verwenden zu können, benötigen Sie die Berechtigung ALTER für die Datenbank. ALTER SCHEMA ist ein Synonym für ALTER DATABASE.

Die Klausel CHARACTER SET ändert den Standardzeichensatz der Datenbank. Die Klausel COLLATE ändert die Standardsortierfolge der Datenbank. Kapitel 10, Zeichensatz-Unterstützung, behandelt Namen von Zeichensätzen und Sortierfolgen.

Der Datenbankname kann weggelassen werden. In diesem Fall bezieht sich die Anweisung auf die Standarddatenbank.

13.1.2. ALTER TABLE

ALTER [IGNORE] TABLE tbl_name
    alter_specification [, alter_specification] ...

alter_specification:
    ADD [COLUMN] column_definition [FIRST | AFTER col_name ]
  | ADD [COLUMN] (column_definition,...)
  | ADD INDEX [index_name] [index_type] (index_col_name,...)
  | ADD [CONSTRAINT [symbol]]
        PRIMARY KEY [index_type] (index_col_name,...)
  | ADD [CONSTRAINT [symbol]]
        UNIQUE [INDEX] [index_name] [index_type] (index_col_name,...)
  | ADD FULLTEXT [INDEX] [index_name] (index_col_name,...)
      [WITH PARSER parser_name]
  | ADD SPATIAL [INDEX] [index_name] (index_col_name,...)
  | ADD [CONSTRAINT [symbol]]
        FOREIGN KEY [index_name] (index_col_name,...)
        [reference_definition]
  | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
  | CHANGE [COLUMN] old_col_name column_definition
        [FIRST|AFTER col_name]
  | MODIFY [COLUMN] column_definition [FIRST | AFTER col_name]
  | DROP [COLUMN] col_name
  | DROP PRIMARY KEY
  | DROP INDEX index_name
  | DROP FOREIGN KEY fk_symbol
  | DISABLE KEYS
  | ENABLE KEYS
  | RENAME [TO] new_tbl_name
  | ORDER BY col_name
  | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
  | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
  | DISCARD TABLESPACE
  | IMPORT TABLESPACE
  | table_options
  | partition_options
  | ADD PARTITION partition_definition
  | DROP PARTITION partition_names
  | COALESCE PARTITION number
  | REORGANIZE PARTITION partition_names INTO (partition_definitions)
  | ANALYZE PARTITION partition_names
  | CHECK PARTITION partition_names
  | OPTIMIZE PARTITION partition_names
  | REBUILD PARTITION partition_names
  | REPAIR PARTITION partition_names

ALTER TABLE ermöglicht Ihnen das Ändern der Struktur einer vorhandenen Tabelle. Sie können beispielsweise Spalten hinzufügen oder entfernen, Indizes erstellen oder löschen, den Typ einer vorhandenen Spalte ändern oder Spalten oder die Tabelle umbenennen. Ferner können Sie den Kommentar für die Tabelle und auch den Tabellentyp modifizieren.

Die Syntax für viele der zulässigen Änderungen ähnelt Klauseln der CREATE TABLE-Anweisung. Hierzu gehören table_options-Modifikationen für Optionen wie ENGINE, AUTO_INCREMENT und AVG_ROW_LENGTH. (Allerdings ignoriert ALTER TABLE die Tabellenoptionen DATA DIRECTORY und INDEX DIRECTORY.) Abschnitt 13.1.5, „CREATE TABLE, listet alle Tabellenoptionen auf.

Bei manchen Operationen kann eine Warnung erzeugt werden, wenn diese auf eine Tabelle angewendet werden sollen, deren Speicher-Engine die Operation nicht unterstützt. Diese Warnungen lassen sich mit SHOW WARNINGS anzeigen. Siehe auch Abschnitt 13.5.4.25, „SHOW WARNINGS.

ALTER TABLE erstellt zunächst eine temporäre Kopie der Ursprungstabelle. Die Änderung wird dann an der Kopie vorgenommen, und schließlich wird die Originaltabelle gelöscht und die Kopie entsprechend umbenannt. Während der Ausführung von ALTER TABLE kann die Originaltabelle von anderen Clients gelesen werden. Änderungs- und Schreiboperationen in der Tabelle werden blockiert, bis die neue Tabelle bereit ist, und dann automatisch in die neue Tabelle umgeleitet. Aktualisierungen schlagen nicht fehl.

Beachten Sie, dass, wenn Sie eine andere ALTER TABLE-Option als RENAME verwenden, MySQL immer eine Temporärtabelle erstellt – und zwar auch dann, wenn die Daten strenggenommen nicht kopiert werden müssten (z. B. wenn Sie nur den Namen einer Spalte ändern). Bei MyISAM-Tabellen ist die Neuerstellung des Indexes der zeitaufwändigste Teil des Änderungsvorgangs. Sie können diesen beschleunigen, indem Sie die Systemvariable myisam_sort_buffer_size auf einen hohen Wert setzen.

  • Um ALTER TABLE zu verwenden, benötigen Sie die Berechtigungen ALTER, INSERT und CREATE für die Tabelle.

  • IGNORE ist eine MySQL-Erweiterung zum SQL-Standard. Sie steuert, wie ALTER TABLE funktioniert, wenn Dubletten eindeutiger Schlüssel in der neuen Tabelle vorhanden sind oder (bei aktiviertem striktem Modus) Warnungen auftreten. Wenn IGNORE nicht angegeben ist, wird der Vorgang bei Auftreten von Schlüsseldubletten abgebrochen, und ein Rollback wird durchgeführt. Ist IGNORE angegeben, dann wird nur der erste von mehreren Datensätzen mit Dubletten eindeutiger Schlüssel verwendet. Die übrigen betroffenen Datensätze werden gelöscht. Falsche Werte werden auf den nächstliegenden zulässigen Wert gesetzt.

  • Sie können mehrere ADD-, ALTER-, DROP- und CHANGE-Klauseln in einer ALTER TABLE-Anweisung angeben. Diese werden durch Kommata getrennt. Dies ist eine MySQL-Erweiterung zum SQL-Standard, der nur jeweils eine dieser Klauseln je ALTER TABLE-Anweisung zulässt. Um beispielsweise mehrere Spalten mit einer einzelnen Anweisung zu löschen, tun Sie Folgendes:

    ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
    
  • CHANGE col_name, DROP col_name und DROP INDEX sind MySQL-Erweiterungen zum SQL-Standard.

  • MODIFY ist eine Oracle-Erweiterung zu ALTER TABLE.

  • Das Wort COLUMN ist optional und darf weggelassen werden.

  • Wenn Sie ALTER TABLE tbl_name RENAME TO new_tbl_name ohne zusätzliche Optionen sehen, benennt MySQL alle Dateien, die der Tabelle tbl_name entsprechen, einfach um. Es ist nicht notwendig, eine Temporärtabelle zu erstellen. (Sie können zum Umbenennen von Tabellen auch die Anweisung RENAME TABLE verwenden. Siehe auch Abschnitt 13.1.9, „RENAME TABLE.)

  • column_definition-Klauseln verwenden dieselbe Syntax für ADD und CHANGE wie bei CREATE TABLE. Beachten Sie, dass diese Syntax den Spaltennamen (und nicht nur den Datentyp) enthält. Siehe auch Abschnitt 13.1.5, „CREATE TABLE.

  • Sie können eine Spalte mithilfe einer CHANGE old_col_name column_definition-Klausel umbenennen. Zu diesem Zweck geben Sie den alten und den neuen Spaltennamen sowie den Typ an, den die Spalte zurzeit hat. Um beispielsweise eine INTEGER-Spalte von a zu b umzubenennen, geben Sie Folgendes ein:

    ALTER TABLE t1 CHANGE a b INTEGER;
    

    Wenn Sie den Typ einer Spalte, nicht aber ihren Namen ändern wollen, erfordert die CHANGE-Syntax trotzdem einen alten und neuen Spaltennamen, auch wenn diese dann identisch sind. Zum Beispiel:

    ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;
    

    Sie können den Spaltentyp auch mit MODIFY ändern, ohne die Spalte umzubenennen:

    ALTER TABLE t1 MODIFY b BIGINT NOT NULL;
    
  • Wenn Sie CHANGE oder MODIFY zum Kürzen einer Spalte verwenden, für die ein Index vorhanden ist, und die Länge der Spalte nach der Operation geringer ist als die Indexlänge, dann kürzt MySQL den Index automatisch.

  • Ändern Sie einen Datentyp mit CHANGE oder MODIFY, dann versucht MySQL, vorhandene Spaltenwerte bestmöglich in den neuen Typ zu konvertieren.

  • Um eine Spalte an eine bestimmte Position in einer Tabellenzeile hinzuzufügen, verwenden Sie FIRST oder AFTER col_name. Standardmäßig werden neue Spalten am Ende eingefügt. Sie können FIRST und AFTER auch bei CHANGE- oder MODIFY-Operationen verwenden.

  • ALTER ... SET DEFAULT oder ALTER ... DROP DEFAULT geben einen neuen Vorgabewert für eine Spalte an bzw. entfernen den vorhandenen Vorgabewert. Wenn die alte Vorgabe entfernt wird und die Spalte NULL werden kann, dann wird NULL zum neuen Vorgabewert. Kann die Spalte nicht NULL werden, dann weist MySQL einen Standardwert zu (siehe auch Abschnitt 11.1.4, „Vorgabewerte von Datentypen“).

  • DROP INDEX entfernt einen Index. Dies ist eine MySQL-Erweiterung zum SQL-Standard. Siehe auch Abschnitt 13.1.7, „DROP INDEX.

  • Wenn Spalten aus einer Tabelle entfernt werden, werden die Spalten auch aus allen Indizes gelöscht, deren Bestandteil sie sind. Wenn alle Spalten, die einen Index bilden, gelöscht wurden, dann wird auch der Index gelöscht.

  • Enthält eine Tabelle nur eine Spalte, dann kann diese nicht gelöscht werden. Zur Entfernung der Tabelle verwenden Sie stattdessen DROP TABLE.

  • DROP PRIMARY KEY löscht den Primärschlüssel. Hinweis: Bei älteren MySQL-Versionen löscht DROP PRIMARY KEY, wenn kein Primärindex vorhanden ist, den ersten eindeutigen Index in der Tabelle. Dies trifft bei MySQL 5.1 nicht mehr zu: Wenn Sie hier DROP PRIMARY KEY auf eine Tabelle ohne Primärschlüssel anzuwenden versuchen, erhalten Sie einen Fehler.

    Wenn Sie einer Tabelle mit UNIQUE INDEX oder PRIMARY KEY einen eindeutigen Index bzw. einen Primärschlüssel hinzufügen, wird dieser vor jedem nichteindeutigen Index gespeichert, sodass MySQL Schlüsseldubletten schnellstmöglich erkennt.

  • ORDER BY erlaubt Ihnen die Erstellung einer neuen Tabelle mit allen Datensätzen in einer bestimmten Reihenfolge. Beachten Sie, dass diese Reihenfolge nach Einfüge- und Löschoperationen nicht aufrechterhalten wird. Diese Option ist in erster Linie nützlich, wenn Sie wissen, dass die Datensätze meistens in einer bestimmten Reihenfolge abgefragt werden. Wenn Sie diese Option nach umfangreicheren Änderungen in der Tabelle verwenden, können Sie die Leistung unter Umständen steigern. In bestimmten Fällen kann es MySQL das Sortieren erleichtern, wenn die Tabelle in der Reihenfolge der Spalte angeordnet ist, nach der Sie sie später auch sortieren wollen.

  • Wenn Sie ALTER TABLE auf eine MyISAM-Tabelle anwenden, werden alle nichteindeutigen Indizes in einer separaten Stapeloperation erstellt (wie bei REPAIR TABLE). Dies sollte ALTER TABLE erheblich beschleunigen, wenn Sie viele Indizes haben.

    Die Funktion lässt sich explizit aktivieren. ALTER TABLE ... DISABLE KEYS weist MySQL an, die Aktualisierung nichteindeutiger Indizes für eine MyISAM-Tabelle zu beenden. Danach sollte ALTER TABLE ... ENABLE KEYS verwendet werden, um die fehlenden Indizes neu zu erstellen. MySQL tut dies mit einem speziellen Algorithmus, der wesentlich schneller ist als das aufeinander folgende Einfügen von Schlüsseln. Insofern sollte die Deaktivierung von Schlüsseln vor umfangreichen Einfügeoperationen diese erheblich beschleunigen. Die Verwendung von ALTER TABLE ... DISABLE KEYS erfordert neben den bereits genannten Berechtigungen auch die Berechtigung INDEX.

  • Die Klauseln FOREIGN KEY und REFERENCES werden von der InnoDB-Speicher-Engine unterstützt, die ADD [CONSTRAINT [symbol]] FOREIGN KEY (...) REFERENCES ... (...) implementiert. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“. Von anderen Speicher-Engines werden die Klauseln zwar erkannt, aber ignoriert. Zudem wird die Klausel CHECK von allen Speicher-Engines erkannt, aber ignoriert. Siehe auch Abschnitt 13.1.5, „CREATE TABLE. Diese Verhaltensweise – das Erkennen und nachfolgende Ignorieren von Syntaxklauseln – ist aus Kompatibilitätsgründen vorhanden. Sie erleichtert die Portierung von Codes anderer SQL-Server und die Ausführung von Anwendungen, die Tabellen mit Referenzen erstellen. Siehe auch Abschnitt 1.9.5, „MySQL: Unterschiede im Vergleich zu ANSI SQL92“.

    In separaten Klauseln derselben ALTER TABLE-Anweisung können Sie keinen Fremdschlüssel hinzufügen und einen Fremdschlüssel löschen. Sie müssen hierzu separate Anweisungen verwenden.

  • InnoDB unterstützt die Verwendung von ALTER TABLE zum Löschen von Fremdschlüsseln:

    ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
    

    In separaten Klauseln derselben ALTER TABLE-Anweisung können Sie keinen Fremdschlüssel hinzufügen und einen Fremdschlüssel löschen. Sie müssen hierzu separate Anweisungen verwenden.

    Weitere Informationen finden Sie unter Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

  • Wenn Sie den Standardzeichensatz einer Tabelle und den Zeichensatz aller Zeichenspalten (CHAR, VARCHAR, TEXT) auf einen neuen Zeichensatz umstellen wollen, verwenden Sie eine Anweisung wie die folgende:

    ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
    

    Warnung: Die obige Operation wandelt Spaltenwerte zwischen Zeichensätzen um. Sie sollten dies keinesfalls tun, wenn Sie eine Spalte in einem Zeichensatz (z. B. latin1) haben, die gespeicherten Werte aber eigentlich einen anderen inkompatiblen Zeichensatz (wie utf8) verwenden. In diesem Fall müssen Sie bei solchen Spalten Folgendes tun:

    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
    

    Der Grund, warum dies funktioniert, ist, dass, wenn Sie von oder in BLOB-Spalten konvertieren, keine Konvertierung stattfindet.

    Wenn Sie CONVERT TO CHARACTER SET binary angeben, werden die CHAR-, VARCHAR- und TEXT-Spalten in ihre entsprechenden binären String-Typen umgewandelt (BINARY, VARBINARY, BLOB). Das bedeutet, dass die Spalten keinen Zeichensatz mehr haben; eine nachfolgende CONVERT TO-Operation hat also keine Auswirkungen mehr.

    Um nur den Standardzeichensatz einer Tabelle zu ändern, verwenden Sie folgende Anweisung:

    ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;
    

    Das Wort DEFAULT ist optional. Der Standardzeichensatz ist der Zeichensatz, der verwendet wird, wenn Sie den Zeichensatz für eine neue Spalte, die Sie (etwa mit ALTER TABLE ... ADD column) zu einer Tabelle hinzufügen, nicht explizit angegeben haben.

  • Bei einer InnoDB-Tabelle, die mit einem eigenen Tablespace in einer .ibd-Datei erstellt wurde, kann diese Datei verworfen und importiert werden. Mit folgender Anweisung können Sie die .ibd-Datei verwerfen:

    ALTER TABLE tbl_name DISCARD TABLESPACE;
    

    Hierbei wird die aktuelle .ibd-Datei gelöscht, d. h., Sie sollten zuerst ein Backup erstellt haben. Der Versuch des Zugriffs auf die Tabelle, während die Tablespace-Datei verworfen wird, führt zu einem Fehler.

    Um die .ibd-Sicherungsdatei in die Tabelle zurückzuimportieren, kopieren Sie sie ins Datenbankverzeichnis und setzen dann folgende Anweisung ab:

    ALTER TABLE tbl_name IMPORT TABLESPACE;
    

    Siehe auch Abschnitt 14.2.3.1, „Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)“.

  • ALTER TABLE kann auch bei partitionierten Tabellen verwendet werden, um Partitionen hinzuzufügen, zu löschen, zu verbinden oder aufzutrennen. Auch die Partitionierungswartung ist hiermit möglich.

    Die einfache Angabe einer partition_options-Klausel zu ALTER TABLE für eine partitionierte Tabelle partitioniert diese entsprechend dem Partitionierungsschema neu, welches über die partition_options angegeben wurde. Diese Klausel beginnt immer mit PARTITION BY und verwendet ansonsten dieselbe Syntax und die Regeln, die auch auf die partition_options-Klausel für CREATE TABLE zutreffen. (Weitere Informationen finden Sie in Abschnitt 13.1.5, „CREATE TABLE). Hinweis: Diese Syntax wird derzeit vom MySQL 5.1 Server akzeptiert, tut aber eigentlich noch gar nichts. Wir erwarten die Implementierung im Zuge der Fortentwicklung von MySQL 5.1.

    Die partition_definition-Klausel für ALTER TABLE ADD PARTITION unterstützt dieselben Optionen wie die gleichnamige Klausel für die CREATE TABLE-Anweisung. (Informationen zu Syntax und eine Beschreibung finden Sie in Abschnitt 13.1.5, „CREATE TABLE.) Angenommen, Sie haben wie folgt eine partitionierte Tabelle erstellt:

    CREATE TABLE t1 (
        id INT,
        year_col INT
    )
    PARTITION BY RANGE (year_col) (
        PARTITION p0 VALUES LESS THAN (1991),
        PARTITION p1 VALUES LESS THAN (1995),
        PARTITION p2 VALUES LESS THAN (1999)
    );
    

    Sie können dieser Tabelle nun wie folgt eine neue Partition p3 hinzufügen, die Werte aufnehmen kann, die kleiner als 2002 sind.

    ALTER TABLE t1 ADD PARTITION p3 VALUES LESS THAN (2002);
    

    Hinweis: Sie können ALTER TABLE nicht zum Hinzufügen von Partitionen zu einer Tabelle verwenden, die (noch) nicht partitioniert ist.

    Mit DROP PARTITION können Sie eine oder mehrere RANGE- oder LIST-Partitionen löschen. Diese Anweisung kann nicht für HASH- oder KEY-Partitionen verwendet werden; dort benutzen Sie stattdessen COALESCE PARTITION (siehe unten). In gelöschten Partitionen vorhandene Daten, die in der Liste partition_names aufgeführt sind, werden verworfen. So können Sie beispielsweise in der zuvor definierten Tabelle t1 die Partitionen p0 und p1 wie folgt löschen:

    ALTER TABLE DROP PARTITION p0, p1;
    

    Beachten Sie, dass DROP PARTITION nicht bei Tabellen funktioniert, die die NDB Cluster-Speicher-Engine verwenden. Siehe auch Abschnitt 17.3.1, „Verwaltung von RANGE- und LIST-Partitionen“, und Abschnitt 16.8, „Bekannte Beschränkungen von MySQL Cluster“.

    ADD PARTITION und DROP PARTITION unterstützen IF [NOT] EXISTS derzeit nicht. Ferner ist es nicht möglich, eine Partition oder eine partitionierte Tabelle umzubenennen. Stattdessen müssen Sie, wenn Sie eine Partition umbenennen wollen, diese löschen und neu erstellen. Wollen Sie eine partitionierte Tabelle umbenennen, dann müssen Sie zunächst alle Partitionen löschen, die Tabelle dann umbenennen und schließlich alle gelöschten Partitionen neu erstellen.

    COALESCE PARTITION kann bei Tabellen benutzt werden, die mit HASH oder KEY partitioniert wurden, um die Anzahl der Partitionen um den Wert number zu verringern. Angenommen, Sie haben die Tabelle t2 mit der folgenden Definition erstellt:

    CREATE TABLE t2 (
        name VARCHAR (30),
        started DATE
    )
    PARTITION BY HASH(YEAR(started))
    PARTITIONS (6);
    

    Sie können die Anzahl der von t2 verwendeten Partitionen nun mit der folgenden Anweisung von 6 auf 4 verringern:

    ALTER TABLE t2 COALESCE PARTITION 2;
    

    Die in den letzten number Partitionen enthaltenen Daten werden in die verbleibenden Partitionen eingefügt. In diesem Fall werden die Partitionen 4 und 5 in die ersten vier Partitionen (0 bis 3) eingefügt.

    Um einige, aber nicht alle Partitionen zu ändern, die von einer partitionierten Tabelle verwendet werden, können Sie REORGANIZE PARTITION verwenden. Diese Anweisung kann auf mehrere Arten verwendet werden:

    • Um mehrere Partitionen zu einer zusammenzufassen. Hierzu zählen Sie mehrere Partitionen in der partition_names-Liste auf und geben genau eine Definition für partition_definition an.

    • Um eine vorhandene Partition in mehrere Partitionen aufzuspalten. Hierzu benennen Sie genau eine Partition für partition_names und geben in partition_definitions mehrere Definitionen an.

    • Um die Bereiche für eine Teilmenge der Partitionen, die mit VALUES LESS THAN definiert wird, oder die Wertelisten für eine Teilmenge der Partitionen zu ändern, die mit VALUES IN definiert wird.

    Hinweis: Bei Partitionen, die nicht explizit aufgeführt wurden, verwendet MySQL automatisch die Standardnamen p0, p1, p2 usw.

    Weitere Informationen zu ALTER TABLE ... REORGANIZE PARTITION-Anweisungen und zugehörige Beispiele finden Sie in Abschnitt 17.3, „Partitionsverwaltung“.

  • Mehrere zusätzliche Klauseln ermöglichen die Wartung und Reparatur von Partitionen analog zu der Art und Weise, wie diese Funktionalitäten bei nicht partitionierten Tabellen durch Anweisungen wie CHECK TABLE und REPAIR TABLE (welche von partitionierten Tabellen nicht unterstützt werden) implementiert sind. Hierzu gehören ANALYZE PARTITION, CHECK PARTITION, OPTIMIZE PARTITION, REBUILD PARTITION und REPAIR PARTITION. Jede dieser Optionen nimmt eine partition_names-Klausel entgegen, die einen oder mehrere durch Kommata getrennte Partitionsnamen umfasst. Die Partitionen müssen in der zu ändernden Tabelle bereits vorhanden sein. Weitere Informationen hierzu und zugehörige Beispiele finden Sie in Abschnitt 17.3.3, „Wartung von Partitionen“.

Mit der C-API-Funktion mysql_info() können Sie ermitteln, wie viele Datensätze kopiert und (sofern IGNORE verwendet wird) aufgrund doppelt vorhandener eindeutiger Schlüsselwerte gelöscht wurden. Siehe auch Abschnitt 24.2.3.34, „mysql_info().

Es folgen ein paar Beispiele, die Anwendungsmöglichkeiten für ALTER TABLE zeigen. Beginnen wir mit einer Tabelle t1, die wie folgt erstellt wird:

CREATE TABLE t1 (a INTEGER,b CHAR(10));

So benennen Sie die Tabelle von t1 in t2 um:

ALTER TABLE t1 RENAME t2;

So ändern Sie den Typ der Spalte a von INTEGER auf TINYINT NOT NULL (wobei der Name erhalten bleibt) und den Typ der Spalte b von CHAR(10) zu CHAR(20) sowie deren Namen von b zu c:

ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);

So fügen Sie eine neue TIMESTAMP-Spalte namens d hinzu:

ALTER TABLE t2 ADD d TIMESTAMP;

So fügen Sie Indizes zu den Spalten d und a hinzu:

ALTER TABLE t2 ADD INDEX (d), ADD INDEX (a);

So entfernen Sie die Spalte c:

ALTER TABLE t2 DROP COLUMN c;

So fügen Sie eine neue AUTO_INCREMENT-Spalte namens c hinzu:

ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ADD PRIMARY KEY (c);

Beachten Sie, dass wir c (als PRIMARY KEY) indiziert haben, weil AUTO_INCREMENT-Spalten indiziert werden müssen, und dass wir außerdem c als NOT NULL deklariert haben, weil Primärschlüsselspalten nicht NULL sein dürfen.

Wenn Sie eine AUTO_INCREMENT-Spalte hinzufügen, werden als Spaltenwerte automatisch Sequenznummern eingetragen. Bei MyISAM-Tabellen können Sie die erste Sequenznummer durch Ausführung von SET INSERT_ID=value vor ALTER TABLE oder durch Verwendung der Tabellenoption AUTO_INCREMENT=value einstellen. Siehe auch Abschnitt 13.5.3, „SET.

Sie können die Tabellenoption ALTER TABLE ... AUTO_INCREMENT=value bei InnoDB-Tabellen zur Einstellung der Sequenznummer für neue Datensätze benutzen, wenn der Wert größer ist als der höchste Wert in der AUTO_INCREMENT-Spalte. Ist der Wert kleiner als der aktuelle Maximalwert der Spalte, dann wird keine Fehlermeldung ausgegeben, und der aktuelle Sequenzwert wird nicht geändert.

Wenn Sie bei MyISAM-Tabellen die AUTO_INCREMENT-Spalte nicht ändern, ist die Sequenznummer nicht betroffen. Wenn Sie eine AUTO_INCREMENT-Spalte löschen und dann eine neue AUTO_INCREMENT-Spalte hinzufügen, beginnen die Sequenznummern wieder bei 1.

Siehe auch Abschnitt A.7.1, „Probleme mit ALTER TABLE.

13.1.3. CREATE DATABASE

CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
    [create_specification [, create_specification] ...]

create_specification:
    [DEFAULT] CHARACTER SET charset_name
  | [DEFAULT] COLLATE collation_name

CREATE DATABASE erstellt eine Datenbank des angegebenen Namens. Um CREATE DATABASE verwenden zu können, benötigen Sie die Berechtigung CREATE für die Datenbank. CREATE SCHEMA ist ein Synonym für CREATE DATABASE.

Die Regeln für zulässige Datenbanknamen sind in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“, beschrieben. Wenn die Datenbank vorhanden ist und Sie IF NOT EXISTS nicht angegeben haben, tritt ein Fehler auf.

create_specification-Optionen geben die Datenbankeigenschaften an. Diese Datenbankeigenschaften sind in der Datei db.opt im Datenbankverzeichnis gespeichert. Die Klausel CHARACTER SET gibt den Standardzeichensatz der Datenbank an. Die Klausel COLLATE gibt die Standardsortierfolge der Datenbank an. Kapitel 10, Zeichensatz-Unterstützung, behandelt Namen von Zeichensätzen und Sortierfolgen.

Datenbanken werden in MySQL als Verzeichnisse implementiert, die Dateien enthalten, welche den Tabellen der Datenbank entsprechen. Weil bei der Erstellung einer Datenbank noch keine Tabellen vorhanden sind, erzeugt die Anweisung CREATE DATABASE lediglich ein Verzeichnis im MySQL-Datenverzeichnis sowie die Datei db.opt.

Wenn Sie manuell (z. B. mit mkdir) ein Verzeichnis im Datenverzeichnis erstellen, betrachtet der Server dieses als Datenbankverzeichnis und zeigt es in der Ausgabe von SHOW DATABASES an.

Sie können zur Erstellung von Datenbanken auch das Programm mysqladmin verwenden. Siehe auch Abschnitt 8.7, „mysqladmin — Client für die Verwaltung eines MySQL Servers“.

13.1.4. CREATE INDEX

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
    [USING index_type]
    ON tbl_name (index_col_name,...)
    [WITH PARSER parser_name]

index_col_name:
    col_name [(length)] [ASC | DESC]

CREATE INDEX wird mit einer ALTER TABLE-Anweisung verknüpft, um Indizes zu erstellen. Siehe auch Abschnitt 13.1.2, „ALTER TABLE. Weitere Informationen dazu, wie MySQL Indizes verwendet, finden Sie in Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“.

Normalerweise erstellen Sie alle Indizes für eine Tabelle zu dem Zeitpunkt, an dem Sie auch die Tabelle selbst mit CREATE TABLE anlegen. Siehe auch Abschnitt 13.1.5, „CREATE TABLE. CREATE INDEX erlaubt Ihnen das Hinzufügen von Indizes zu vorhandenen Tabellen.

Eine Spaltenliste in der Form (col1,col2,...) erstellt einen mehrspaltigen Index. Indexwerte werden gebildet, indem die Werte der betreffenden Spalten verkettet werden.

Bei CHAR-, VARCHAR-, BINARY- und VARBINARY-Spalten können Indizes erstellt werden, die nur einen Teil einer Spalte verwenden. Hier verwenden Sie die Syntax col_name(length), um die Länge des Indexpräfixes anzugeben. Indexeinträge umfassen dann die ersten length Zeichen jedes Spaltenwerts bei CHAR- und VARCHAR-Spalten sowie die ersten length Bytes jedes Spaltenwerts bei BINARY- und VARBINARY-Spalten. BLOB- und TEXT-Spalten lassen sich auch indizieren, aber eine Präfixlänge muss angegeben werden.

Die folgende Anweisung erstellt einen Index unter Verwendung der ersten zehn Zeichen der Spalte name:

CREATE INDEX part_of_name ON customer (name(10));

Wenn die ersten zehn Zeichen aller Namen in der Spalte sich durchgehend unterscheiden, dann sollte dieser Index nicht viel langsamer sein als ein Index, der aus der gesamten Spalte name erstellt wurde. Auch die Verwendung von Teilspalten für Indizes kann die Indexdatei wesentlich kleiner machen, wodurch sich viel Festplattenspeicher sparen lässt und INSERT-Operationen unter Umständen auch beschleunigt werden können.

Präfixe können bis 1.000 Byte lang sein (767 Byte bei InnoDB-Tabellen). Beachten Sie, dass Präfixbeschränkungen in Byte angegeben werden, wohingegen die Präfixlänge in CREATE INDEX-Anweisungen bei nichtbinären Datentypen (CHAR, VARCHAR, TEXT) als Anzahl der Zeichen interpretiert wird. Dies muss bei der Angabe einer Präfixlänge für eine Spalte berücksichtigt werden, die einen Multibytezeichensatz verwendet.

In MySQL 5.1 können Sie

  • einen Index für eine Spalte, die NULL-Werte enthalten kann, nur dann hinzufügen, wenn Sie die Speicher-Engines MyISAM, InnoDB, BDB oder MEMORY verwenden,

  • einen Index für eine BLOB- oder TEXT-Spalte nur dann hinzufügen, wenn Sie die Speicher-Engines MyISAM, BDB oder InnoDB verwenden.

Eine index_col_name-Definition kann auf ASC oder DESC enden. Diese Schlüsselwörter sind für zukünftige Erweiterungen zulässig, um eine Speicherung der Indexwerte in auf- oder absteigender Reihenfolge festzulegen. Zurzeit werden sie zwar erkannt, aber ignoriert – Indexwerte werden immer in aufsteigender Reihenfolge gespeichert.

Einige Speicher-Engines gestatten bei der Erstellung eines Indexes die Angabe eines Indextyps. Die Syntax für die Konfigurationsangabe index_type lautet USING type_name. Zulässige Werte für type_name, die von den verschiedenen Speicher-Engines unterstützt werden, sind in der folgenden Tabelle aufgelistet. Sind mehrere Indextypen aufgeführt, so wird der erste standardmäßig verwendet, wenn keine Angabe für index_type vorhanden ist.

Speicher-EngineZulässige Indextypen
MyISAMBTREE
InnoDBBTREE
MEMORY/HEAPHASH, BTREE

Ein paar Beispiele:

CREATE TABLE lookup (id INT) ENGINE = MEMORY;
CREATE INDEX id_index USING BTREE ON lookup (id);

TYPE type_name kann als Synonym für USING type_name benutzt werden, um einen Indextyp anzugeben. Allerdings ist USING die bevorzugte Form. Ferner ist der Indexname, der in der Syntax zur Indexspezifikation vor dem Indextyp steht, bei TYPE nicht optional: Anders als USING ist TYPE kein reserviertes Wort und wird infolgedessen nicht als Indexname interpretiert.

Wenn Sie einen Indextyp angeben, der für eine gegebene Speicher-Engine nicht zulässig ist, aber ein anderer Indextyp vorhanden ist, den die Engine verwenden kann, ohne dass hiervon Abfrageergebnisse betroffen wären, dann verwendet die Engine diesen verfügbaren Typ.

FULLTEXT-Indizes werden nur für MyISAM-Tabellen unterstützt und dürfen nur CHAR-, VARCHAR- und TEXT-Spalten enthalten. Siehe auch Abschnitt 12.7, „MySQL-Volltextsuche“. Eine WITH PARSER-Klausel kann angegeben werden, um ein Parser-Plug-In mit dem Index zu verknüpfen, wenn Volltextindizierungs- und Suchoperationen besondere Maßnahmen erfordern. Diese Klausel ist nur für FULLTEXT-Indizes zulässig. Informationen zur Erstellung von Plug-Ins finden Sie in Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“.

SPATIAL-Indizes werden nur für MyISAM-Tabellen unterstützt und dürfen nur raumbezogene Spalten enthalten, die als NOT NULL definiert sind. Kapitel 18, Raumbezogene Erweiterungen in MySQL, beschreibt raumbezogene Datentypen.

13.1.5. CREATE TABLE

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,...)]
    [table_options] [select_statement]

Oder:

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(] LIKE old_tbl_name [)];

create_definition:
    column_definition
  | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
  | KEY [index_name] [index_type] (index_col_name,...)
  | INDEX [index_name] [index_type] (index_col_name,...)
  | [CONSTRAINT [symbol]] UNIQUE [INDEX]
        [index_name] [index_type] (index_col_name,...)
  | FULLTEXT [INDEX] [index_name] (index_col_name,...)
      [WITH PARSER parser_name]
  | SPATIAL [INDEX] [index_name] (index_col_name,...)
  | [CONSTRAINT [symbol]] FOREIGN KEY
        [index_name] (index_col_name,...) [reference_definition]
  | CHECK (expr)

column_definition:
    col_name type [NOT NULL | NULL] [DEFAULT default_value]
        [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
        [COMMENT 'string'] [reference_definition]

type:
    TINYINT[(length)] [UNSIGNED] [ZEROFILL]
  | SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
  | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
  | INT[(length)] [UNSIGNED] [ZEROFILL]
  | INTEGER[(length)] [UNSIGNED] [ZEROFILL]
  | BIGINT[(length)] [UNSIGNED] [ZEROFILL]
  | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
  | NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
  | DATE
  | TIME
  | TIMESTAMP
  | DATETIME
  | YEAR
  | CHAR(length) [BINARY | ASCII | UNICODE]
  | VARCHAR(length) [BINARY]
  | BINARY(length)
  | VARBINARY(length)
  | TINYBLOB
  | BLOB
  | MEDIUMBLOB
  | LONGBLOB
  | TINYTEXT [BINARY]
  | TEXT [BINARY]
  | MEDIUMTEXT [BINARY]
  | LONGTEXT [BINARY]
  | ENUM(value1,value2,value3,...)
  | SET(value1,value2,value3,...)
  | spatial_type

index_col_name:
    col_name [(length)] [ASC | DESC]

reference_definition:
    REFERENCES tbl_name [(index_col_name,...)]
               [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
               [ON DELETE reference_option]
               [ON UPDATE reference_option]

reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION

table_options: table_option [table_option] ...

table_option:
    {ENGINE|TYPE} [=] engine_name
  | AUTO_INCREMENT [=] value
  | AVG_ROW_LENGTH [=] value
  | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
  | CHECKSUM [=] {0 | 1}
  | COMMENT [=] 'string'
  | CONNECTION [=] 'connect_string'
  | MAX_ROWS [=] value
  | MIN_ROWS [=] value
  | PACK_KEYS [=] {0 | 1 | DEFAULT}
  | PASSWORD [=] 'string'
  | DELAY_KEY_WRITE [=] {0 | 1}
  | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
  | UNION [=] (tbl_name[,tbl_name]...)
  | INSERT_METHOD [=] { NO | FIRST | LAST }
  | DATA DIRECTORY [=] 'absolute path to directory'
  | INDEX DIRECTORY [=] 'absolute path to directory'

partition_options:
    PARTITION BY
           [LINEAR] HASH(expr)
        |  [LINEAR] KEY(column_list)
        |  RANGE(expr)
        |  LIST(expr)
    [PARTITIONS num]
    [  SUBPARTITION BY
           [LINEAR] HASH(expr)
         | [LINEAR] KEY(column_list)
      [SUBPARTITIONS num]
    ]
    [(partition_definition) [, (partition_definition)] ...]

partition_definition:
    PARTITION partition_name
        [VALUES {LESS THAN (expr) | MAXVALUE | IN (value_list)}]
        [[STORAGE] ENGINE [=] engine-name]
        [COMMENT [=] 'comment_text' ]
        [DATA DIRECTORY [=] 'data_dir']
        [INDEX DIRECTORY [=] 'index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] (tablespace_name)]
        [NODEGROUP [=] node_group_id]
        [(subpartition_definition) [, (subpartition_definition)] ...]

subpartition_definition:
    SUBPARTITION logical_name
        [[STORAGE] ENGINE [=] engine-name]
        [COMMENT [=] 'comment_text' ]
        [DATA DIRECTORY [=] 'data_dir']
        [INDEX DIRECTORY [=] 'index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] (tablespace_name)]
        [NODEGROUP [=] node_group_id]

select_statement:
    [IGNORE | REPLACE] [AS] SELECT ...   (Some legal select statement)

CREATE TABLE erstellt eine Tabelle des angegebenen Namens. Für die Tabelle benötigen Sie die Berechtigung CREATE.

Die Regeln für zulässige Tabellennamen sind in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“, beschrieben. Standardmäßig wird die Tabelle in der Standarddatenbank erstellt. Wenn die Tabelle bereits vorhanden ist oder weder die Standarddatenbank noch die angegebene Datenbank vorhanden sind, wird ein Fehler erstellt.

Der Tabellenname kann als db_name.tbl_name angegeben werden, um die Tabelle in einer bestimmten Datenbank zu erstellen. Das funktioniert unabhängig vom Vorhandensein einer Standarddatenbank, sofern die angegebene Datenbank vorhanden ist. Wenn Sie Bezeichner in Anführungszeichen verwenden, setzen Sie Datenbank- und Tabellennamen separat in Anführungszeichen. So ist etwa `mydb`.`mytbl` zulässig – anders als `mydb.mytbl`.

Sie können das Schlüsselwort TEMPORARY bei der Erstellung einer Tabelle verwenden. Eine TEMPORARY-Tabelle ist nur für die aktuelle Verbindung sichtbar und wird beim Beenden dieser Verbindung automatisch gelöscht. Das bedeutet, dass zwei verschiedene Verbindungen Temporärtabellen desselben Namens verwenden können, ohne dass es zu Konflikten mit der jeweils anderen Tabelle oder einer nichttemporären Tabelle gleichen Namens kommt. (Die vorhandene Tabelle wird verborgen, bis die Temporärtabelle gelöscht wird.) Zur Erstellung von Temporärtabellen benötigen Sie die Berechtigung CREATE TEMPORARY TABLES.

Die Schlüsselwörter IF NOT EXISTS verhindern, dass ein Fehler auftritt, wenn die Tabelle vorhanden ist. Allerdings wird nicht überprüft, ob die vorhandene Tabelle die gleiche Struktur wie die in der CREATE TABLE-Anweisung angegebene Tabelle hat. Hinweis: Wenn Sie IF NOT EXISTS in einer CREATE TABLE ... SELECT-Anweisung verwenden, werden alle durch den SELECT-Teil gewählten Datensätze ohne Berücksichtigung der Frage eingefügt, ob die Tabelle bereits vorhanden ist.

MySQL stellt jede Tabelle durch eine .frm-Tabellenformatdatei (Definitionsdatei) im Datenbankverzeichnis dar. Die Speicher-Engine der Tabelle erstellt unter Umständen auch andere Dateien. Im Falle von MyISAM-Tabellen erstellt die Speicher-Engine Daten- und Indexdateien. Es gibt also für jede MyISAM-Tabelle tbl_name drei Dateien auf der Festplatte:

DateiZweck
tbl_name.frmTabellenformatdatei (Definitionsdatei)
tbl_name.MYDDatendatei
tbl_name.MYIIndexdatei

Kapitel 14, Speicher-Engines und Tabellentypen, beschreibt, welche Dateien die einzelnen Speicher-Engines zur Darstellung von Tabellen erstellen.

type stellt den Datentyp einer Spaltendefinition dar. spatial_type ist ein raumbezogener Datentyp. Allgemeine Informationen zu den Eigenschaften von Datentypen (außer raumbezogenen Datentypen) finden Sie in Kapitel 11, Datentypen. Informationen zu raumbezogenen Datentypen finden Sie in Kapitel 18, Raumbezogene Erweiterungen in MySQL.

  • Wenn weder NULL noch NOT NULL angegeben sind, wird die Spalte so behandelt, als ob NULL angegeben worden wäre.

  • Eine Integer-Spalte kann das Zusatzattribut AUTO_INCREMENT erhalten. Wenn Sie den Wert NULL (empfohlen) oder 0 in eine indizierte AUTO_INCREMENT-Spalte einfügen, wird die Spalte auf den nächsten Sequenzwert gesetzt. Normalerweise ist dies value+1, wobei value der derzeit größte Wert der Spalte in der Tabelle ist. AUTO_INCREMENT-Sequenzen beginnen bei 1.

    Um einen AUTO_INCREMENT-Wert nach Einfügen eines Datensatzes abzurufen, verwenden Sie die SQL-Funktion LAST_INSERT_ID() oder die C-API-Funktion mysql_insert_id(). Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“, und Abschnitt 24.2.3.36, „mysql_insert_id().

    Wenn der SQL-Modus NO_AUTO_VALUE_ON_ZERO aktiviert ist, können Sie 0 in AUTO_INCREMENT-Spalten als 0 speichern, ohne einen neuen Sequenzwert zu erzeugen. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

    Hinweis: Es kann nur eine AUTO_INCREMENT-Spalte pro Tabelle geben. Diese muss indiziert sein und darf keinen Standardwert haben. Eine AUTO_INCREMENT-Spalte funktioniert nur dann einwandfrei, wenn sie ausschließlich positive Werte enthält. Das Einfügen eines negativen Werts wird als Einfügen einer sehr großen positiven Zahl aufgefasst. Dies wird gemacht, um genauigkeitsspezifische Probleme zu vermeiden, die beim „Umklappen“ von positiven auf negative Zahlen auftreten können, und um zu gewährleisten, dass Sie nicht versehentlich eine AUTO_INCREMENT-Spalte erhalten, die 0 enthält.

    Bei MyISAM- und BDB-Tabellen können Sie AUTO_INCREMENT in einer Sekundärspalte eines mehrspaltigen Schlüssels angeben. Siehe auch Abschnitt 3.6.9, „Verwendung von AUTO_INCREMENT.

    Um MySQL mit einigen ODBC-Anwendungen kompatibel zu machen, können Sie den AUTO_INCREMENT-Wert für den letzten eingefügten Datensatz mit der folgenden Abfrage ermitteln:

    SELECT * FROM tbl_name WHERE auto_col IS NULL
    
  • Das Attribut SERIAL kann als Alias für BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE verwendet werden.

  • Zeichendatentypen (CHAR, VARCHAR, TEXT) können CHARACTER SET- und COLLATE-Attribute zur Angabe von Zeichensatz und Sortierfolge der Spalte enthalten. Weitere Informationen finden Sie in Kapitel 10, Zeichensatz-Unterstützung. CHARSET ist ein Synonym für CHARACTER SET. Beispiel:

    CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);
    

    MySQL 5.1 interpretiert Längenangaben in Zeichenspaltendefinitionen als Anzahl von Zeichen. (Versionen vor MySQL 4.1 interpretierten sie als Anzahl von Bytes.)

  • Die DEFAULT-Klausel gibt einen Vorgabewert für eine Spalte an. Mit einer Ausnahme muss der Vorgabewert immer eine Konstante sein. Funktionen oder Ausdrücke sind als Vorgabe nicht zulässig. Das bedeutet, dass Sie beispielsweise als Vorgabewert einer Datumsspalte nicht den Wert einer Funktion wie NOW() oder CURRENT_DATE angeben dürfen. Die genannte Ausnahme besteht darin, dass Sie CURRENT_TIMESTAMP als Vorgabe für eine TIMESTAMP-Spalte festlegen können. Siehe auch Abschnitt 11.3.1.1, „TIMESTAMP-Eigenschaften ab MySQL 4.1“.

    Wenn eine Spaltendefinition keinen expliziten DEFAULT-Wert enthält, bestimmt MySQL diesen wie in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben.

    Für BLOB- und TEXT-Spalten können keine Vorgaben festgelegt werden.

  • Ein Kommentar für eine Spalte kann mit der Option COMMENT angegeben werden. Der Kommentar wird über die Anweisungen SHOW CREATE TABLE und SHOW FULL COLUMNS angezeigt.

  • KEY ist normalerweise ein Synonym für INDEX. Das Schlüsselattribut PRIMARY KEY kann auch einfach als KEY angegeben werden, sofern die Angabe in einer Spaltendefinition erfolgt. Dieses Verhalten wurde aus Gründen der Kompatibilität mit anderen Datenbanksystemen implementiert.

  • Ein eindeutiger Index ist dahingehend eingeschränkt, dass alle Werte im Index eindeutig sein müssen. Wenn Sie einen neuen Datensatz mit einem Schlüssel hinzufügen, der dem eines vorhandenen Datensatzes entspricht, tritt ein Fehler auf. Eine Ausnahme hierzu besteht darin, dass, wenn eine Spalte im Index NULL-Werte enthalten darf, diese mehrere NULL-Werte enthalten kann. Diese Ausnahme gilt jedoch nicht für BDB-Tabellen, bei denen eine Spalte mit einem eindeutigen Index NULL nur einmalig gestattet.

  • Ein Primärschlüssel ist ein eindeutiger Index, bei dem alle Schlüsselspalten als NOT NULL definiert sein müssen. Wenn sie nicht explizit als NOT NULL deklariert sind, holt MySQL dies implizit (und stillschweigend) nach. Eine Tabelle darf nur einen Primärschlüssel enthalten. Wenn Sie keinen Primärschlüssel haben und eine Anwendung nach dem Primärschlüssel in Ihren Tabellen fragt, gibt MySQL als Primärschlüssel den ersten eindeutigen Index zurück, der keine NULL-Spalten verwendet.

  • In der erstellten Tabelle wird der Primärschlüssel an die erste Position gesetzt, gefolgt von allen eindeutigen Indizes und nachfolgend den nichteindeutigen Indizes. Dies erleichtert dem MySQL-Optimierer die Priorisierung der zu verwendenden Indizes und die schnelle Erkennung von Dubletten bei den UNIQUE-Schlüsseln.

  • Ein Primärschlüssel kann ein mehrspaltiger Index sein. Sie können allerdings keinen mehrspaltigen Index mithilfe des Schlüsselattributs PRIMARY KEY in einer Spaltendefinition erstellen. Wenn Sie dies tun, wird nur diese eine Spalte als Primärschlüssel gekennzeichnet. Sie müssen hierzu eine separate PRIMARY KEY(index_col_name, ...)-Klausel verwenden.

  • Wenn ein Primärschlüssel oder ein eindeutiger Index aus nur einer Spalte eines Integer-Typs bestehen, können Sie die Spalte auch in SELECT-Anweisungen als _rowid referenzieren.

  • In MySQL lautet der Name eines Primärschlüssels PRIMARY. Bei anderen Indizes erhält, sofern Sie keinen Namen angeben, der Index jeweils denselben Namen wie die erste indizierte Spalte. Es kann optional ein Suffix (_2, _3, ...) angegeben werden, um den Index eindeutig zu machen. Sie können die Indexnamen für eine Tabelle mit SHOW INDEX FROM tbl_name anzeigen. Siehe auch Abschnitt 13.5.4.12, „SHOW INDEX.

  • Einige Speicher-Engines gestatten bei der Erstellung eines Indexes die Angabe eines Indextyps. Die Syntax für die Konfigurationsangabe index_type lautet USING type_name.

    Beispiel:

    CREATE TABLE lookup
      (id INT, INDEX USING BTREE (id))
      ENGINE = MEMORY;
    

    Detaillierte Informationen zu USING finden Sie in Abschnitt 13.1.4, „CREATE INDEX.

    Weitere Informationen dazu, wie MySQL Indizes verwendet, finden Sie in Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“.

  • In MySQL 5.1 unterstützen nur die Speicher-Engines MyISAM, InnoDB, BDB und MEMORY Indizes bei Spalten, die NULL-Werte enthalten. In anderen Fällen müssen Sie indizierte Spalten als NOT NULL deklarieren, andernfalls wird ein Fehler zurückgegeben.

  • Mit der Syntax col_name(length) in einer Indexdefinition können Sie einen Index erstellen, der die Spalte nur teilweise verwendet. Indexeinträge umfassen die ersten length Zeichen jedes Spaltenwerts bei CHAR- und VARCHAR-Spalten sowie die ersten length Bytes jedes Spaltenwerts bei BINARY- und VARBINARY-Spalten. Wenn Sie auf diese Weise nur ein Präfix der Spaltenwerte indizieren, kann dies die Indexdatei erheblich kleiner machen. Siehe auch Abschnitt 7.4.3, „Spaltenindizes“.

    Die Speicher-Engines MyISAM, BDB und InnoDB unterstützen die Indizierung von BLOB- und TEXT-Spalten. Bei der Indizierung einer BLOB- oder TEXT-Spalte müssen Sie eine Präfixlänge für den Index angeben. Zum Beispiel:

    CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));
    

    Präfixe können bis 1.000 Byte lang sein (767 Byte bei InnoDB-Tabellen). Beachten Sie, dass Präfixbeschränkungen in Byte angegeben werden, wohingegen die Präfixlänge in CREATE TABLE-Anweisungen bei nichtbinären Datentypen (CHAR, VARCHAR, TEXT) als Anzahl der Zeichen interpretiert wird. Dies muss bei der Angabe einer Präfixlänge für eine Spalte berücksichtigt werden, die einen Multibytezeichensatz verwendet.

  • Eine index_col_name-Definition kann auf ASC oder DESC enden. Diese Schlüsselwörter sind für zukünftige Erweiterungen zulässig, um eine Speicherung der Indexwerte in auf- oder absteigender Reihenfolge festzulegen. Zurzeit werden sie zwar erkannt, aber ignoriert – Indexwerte werden immer in aufsteigender Reihenfolge gespeichert.

  • Wenn Sie ORDER BY oder GROUP BY für eine TEXT- oder BLOB-Spalte in einer SELECT-Anweisung verwenden, sortiert der Server Werte lediglich unter Verwendung der ersten Bytes. Wie viele Bytes dies sind, wird von der Systemvariablen max_sort_length angegeben. Siehe auch Abschnitt 11.4.3, „Die Spaltentypen BLOB und TEXT.

  • Sie können spezielle Volltextindizes erstellen, die für die Volltextsuche verwendet werden. Nur die MyISAM-Speicher-Engine unterstützt Volltextindizes. Diese können nur aus CHAR-, VARCHAR- und TEXT-Spalten erstellt werden. Die Indizierung erfolgt immer über die gesamte Spalte: Eine Teilindizierung wird nicht unterstützt, und ein eventuell angegebenes Präfix wird ignoriert. Weitere Informationen finden Sie in Abschnitt 12.7, „MySQL-Volltextsuche“. Eine WITH PARSER-Klausel kann angegeben werden, um ein Parser-Plug-In mit dem Index zu verknüpfen, wenn Volltextindizierungs- und Suchoperationen besondere Maßnahmen erfordern. Diese Klausel ist nur für FULLTEXT-Indizes zulässig. Informationen zur Erstellung von Plug-Ins finden Sie in Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“.

  • SPATIAL-Indizes können Sie für raumbezogene Typen erstellen. Solche Typen werden nur für MyISAM-Tabellen unterstützt, und indizierte Spalten müssen als NOT NULL deklariert sein. Siehe auch Kapitel 18, Raumbezogene Erweiterungen in MySQL.

  • InnoDB-Tabellen unterstützen die Überprüfung von Fremdschlüssel-Constraints. Siehe auch Abschnitt 14.2, „InnoDB-Tabellen“. Beachten Sie, dass die Fremdschlüsselsyntax in InnoDB restriktiver ist als die zu Beginn dieses Abschnitts für die CREATE TABLE-Anweisung präsentierte Syntax: Die Spalten der referenzierten Tabellen müssen immer explizit genannt werden. InnoDB unterstützt sowohl ON DELETE- als auch ON UPDATE-Aktionen für Fremdschlüssel. Informationen zur exakten Syntax finden Sie in Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

    Bei anderen Speicher-Engines erkennt MySQL Server die FOREIGN KEY- und REFERENCES-Syntax in CREATE TABLE-Anweisungen, ignoriert sie aber. Zudem wird die Klausel CHECK von allen Speicher-Engines erkannt, aber ignoriert. Siehe auch Abschnitt 1.9.5.5, „Fremdschlüssel“.

  • Bei MyISAM-Tabellen benötigt jede NULL-Spalte ein zusätzliches Bit, aufgerundet auf das nächste Byte. Die maximale Datensatzlänge in Byte kann wie folgt berechnet werden:

    row length = 1
                 + (sum of column lengths)
                 + (number of NULL columns + delete_flag + 7)/8
                 + (number of variable-length columns)
    

    delete_flag ist 1 bei Tabellen mit statischem Datensatzformat. Statische Tabellen verwenden ein Bit im Datensatz für ein Flag, das angibt, ob der Datensatz gelöscht wurde. delete_flag ist 0 bei dynamischen Tabellen, weil das Flag im dynamischen Datensatz-Header gespeichert wird.

    Diese Berechnungen gelten nicht für InnoDB-Tabellen, bei denen der Speicherbedarf von NULL-Spalten sich nicht von dem von NOT NULL-Spalten unterscheidet.

Die Tabellenoption ENGINE gibt die Speicher-Engine für die Tabelle an. TYPE ist ein Synonym hierzu, wobei ENGINE der bevorzugte Name ist.

Die Tabellenoption ENGINE akzeptiert die in der folgenden Tabelle aufgeführten Namen für Speicher-Engines.

Speicher-EngineBeschreibung
ARCHIVESpeicher-Engine zur Archivierung. Siehe auch Abschnitt 14.8, „Die ARCHIVE-Speicher-Engine“.
BDBTransaktionssichere Tabellen mit Seitensperrung. Heißt auch BerkeleyDB. Siehe auch Abschnitt 14.5, „Die BDB-Speicher-Engine“.
CSVTabellen, die Datensätze als kommagetrennte Werte speichern. Siehe auch Abschnitt 14.9, „Die CSV-Speicher-Engine“.
EXAMPLEEine Beispiel-Engine. Siehe auch Abschnitt 14.6, „Die EXAMPLE-Speicher-Engine“.
FEDERATEDSpeicher-Engine, die auf entfernte Tabellen zugreift. Siehe auch Abschnitt 14.7, „Die FEDERATED-Speicher-Engine“.
HEAPEin Synonym für MEMORY.
ISAM (VERALTET)In MySQL 5.1 nicht verfügbar. Wenn Sie von einer älteren Version auf MySQL 5.1 aktualisieren, sollten Sie alle vorhandenen ISAM-Tabellen in MyISAM-Tabellen konvertieren, bevor Sie das Upgrade durchführen.
InnoDBTransaktionssichere Tabellen mit Datensatzsperrung und Fremdschlüsseln. Siehe auch Abschnitt 14.2, „InnoDB-Tabellen“.
MEMORYDie Daten für diese Speicher-Engine werden nur im Speicher abgelegt. Siehe auch Abschnitt 14.4, „Die MEMORY-Speicher-Engine“.
MERGEEine Sammlung von MyISAM-Tabellen, die als eine Tabelle verwendet wird. Heißt auch MRG_MyISAM. Siehe auch Abschnitt 14.3, „Die MERGE-Speicher-Engine“.
MyISAMBinäre portable Speicher-Engine, die als Standard-Engine in MySQL verwendet wird. Siehe auch Abschnitt 14.1, „Die MyISAM-Speicher-Engine“.
NDBCLUSTERFehlertolerante, speicherbasierte Cluster-Tabellen. Heißt auch NDB. Siehe auch Kapitel 16, MySQL Cluster.

Wird eine Speicher-Engine angegeben, die nicht verfügbar ist, dann verwendet MySQL stattdessen die Standard-Engine. Im Normalfall ist dies MyISAM. Wenn beispielsweise eine Tabellendefinition die Option ENGINE=BDB enthält, aber der MySQL Server BDB-Tabellen nicht unterstützt, dann wird die Tabelle als MyISAM-Tabelle erstellt. Auf diese Weise ist eine Replikationskonfiguration realisierbar, bei der Sie transaktionssichere Tabellen auf dem Master haben, während die auf dem Slave erstellten Tabellen nicht transaktionssicher sind (was eine Erhöhung der Verarbeitungsgeschwindigkeit nach sich zieht). In MySQL 5.1 erscheint eine Warnung, wenn die Spezifikation der Speicher-Engine nicht berücksichtigt werden kann.

Die übrigen Tabellenoptionen werden zur Optimierung des Verhaltens der Tabelle verwendet. In den meisten Fällen müssen Sie sie überhaupt nicht angeben. Diese Optionen gelten für alle Speicher-Engines, soweit nichts anderes angegeben ist:

  • AUTO_INCREMENT

    Der AUTO_INCREMENT-Startwert für die Tabelle. In MySQL 5.1 funktioniert dies bei MyISAM-, MEMORY- und InnoDB-Tabellen. Um den ersten AUTO_INCREMENT-Wert für Engines zu setzen, die die Tabellenoption AUTO_INCREMENT nicht unterstützen, fügen Sie einen „Pseudodatensatz“ mit einem Wert ein, der um 1 niedriger ist als der gewünschte Startwert. Nach der Erstellung der Tabelle löschen Sie den Pseudodatensatz dann.

    Bei Engines, die die Tabellenoption AUTO_INCREMENT in CREATE TABLE-Anweisungen unterstützen, können Sie auch ALTER TABLE tbl_name AUTO_INCREMENT = N verwenden, um den AUTO_INCREMENT-Wert zurückzusetzen.

  • AVG_ROW_LENGTH

    Ein Näherungswert für die durchschnittliche Datensatzlänge in Ihrer Tabelle. Sie müssen die Einstellung nur bei großen Tabellen mit Datensätzen unterschiedlicher Größe vornehmen.

    Wenn Sie eine MyISAM-Tabelle erstellen, verwendet MySQL das Produkt der Optionen MAX_ROWS und AVG_ROW_LENGTH, um zu ermitteln, wie groß die resultierende Tabelle sein wird. Geben Sie keine der Optionen an, dann beträgt die maximale Tabellengröße 65.536 Tbyte Daten. (Wenn Ihr Betriebssystem derart große Dateien nicht unterstützt, wird die maximale Größe einer Tabelle durch die betriebssystemseitige Beschränkung der Dateigröße bestimmt.) Wenn Sie die Zeigergrößen gering halten wollen, damit der Index kleiner und schneller wird, und Sie eigentlich keine großen Dateien benötigen, können Sie die Standardzeigergröße durch Einstellen der Systemvariablen myisam_data_pointer_size verringern. (Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.) Wenn Sie wollen, dass alle Ihre Tabellen über das standardmäßige Limit hinaus anwachsen können, und dafür in Kauf nehmen, dass die Tabellen etwas größer und langsamer sind als notwendig, dann können Sie die Standardzeigergröße durch Einstellen der Variablen auch erhöhen.

  • [DEFAULT] CHARACTER SET

    Gibt einen Standardzeichensatz für die Tabelle an. CHARSET ist ein Synonym für CHARACTER SET.

  • COLLATE

    Gibt eine Standardsortierfolge für die Tabelle an.

  • CHECKSUM

    Setzen Sie diese Option auf 1, wenn Sie wollen, dass MySQL eine Prüfsumme für alle Datensätze erstellt, die zudem bei Änderungen in der Tabelle automatisch aktualisiert wird. Dies macht die Aktualisierung der Tabelle zwar ein wenig langsamer, erleichtert aber das Auffinden beschädigter Tabellen. Die Anweisung CHECKSUM TABLE meldet die Prüfsumme. (Nur für MyISAM.)

  • COMMENT

    Ein Kommentar für die Tabelle, der bis zu 60 Zeichen lang sein kann.

  • CONNECTION

    Der Verbindungs-String für eine FEDERATED-Tabelle. (Hinweis: Ältere Versionen von MySQL verwendeten eine Option COMMENT für den Verbindungs-String.)

  • MAX_ROWS

    Maximale Anzahl der Datensätze, die Sie in der Tabelle zu speichern beabsichtigen. Dies ist keine feste Beschränkung, sondern ein Indikator für die Anzahl der Datensätze, die die Tabelle zumindest speichern können muss.

  • MIN_ROWS

    Minimale Anzahl der Datensätze, die Sie in der Tabelle zu speichern beabsichtigen.

  • PACK_KEYS

    Setzen Sie diese Option auf 1, wenn Sie kleinere Indizes wünschen. Hierdurch werden Updates in der Regel langsamer und Leseoperationen schneller. Wenn Sie die Option auf 0 setzen, wird das Packen für alle Schlüssel deaktiviert. Setzen Sie sie hingegen auf DEFAULT, dann wird die Speicher-Engine angewiesen, nur lange CHAR- und VARCHAR-Spalten zu packen. (Nur für MyISAM.)

    Wenn Sie PACK_KEYS nicht verwenden, werden standardmäßig Strings, aber nicht Zahlen gepackt. Bei PACK_KEYS=1 werden auch Zahlen gepackt.

    Beim Packen von binären Zahlenschlüsseln verwendet MySQL die Präfixkompression:

    • Jeder Schlüssel benötigt ein zusätzliches Byte, um anzugeben, wie viele Bytes des vorherigen Schlüssels beim nachfolgenden Schlüssel identisch sind.

    • Der Zeiger auf den Datensatz wird direkt auf den Schlüssel folgend und in absteigender Reihenfolge der Bytewertigkeit gespeichert, um die Komprimierung zu optimieren.

    Das bedeutet, dass, wenn Sie viele gleiche Schlüssel in zwei aufeinander folgenden Datensätzen haben, alle nachfolgenden „identischen“ Schlüssel einschließlich des Zeigers auf den Datensatz nur 2 Byte benötigen. Vergleichen Sie dies einmal mit dem normalen Fall, in dem die nachfolgenden Schlüssel storage_size_for_key + pointer_size Bytes benötigen (wobei die Zeigergröße normalerweise 4 beträgt). Umgekehrt können Sie nur dann umfassend von der Präfixkomprimierung profitieren, wenn Sie viele identische Zahlen haben. Wenn alle Schlüssel vollständig unterschiedlich sind, verwenden Sie pro Schlüssel ein Byte mehr, wenn der jeweilige Schlüssel keine NULL-Werte haben kann. (In diesem Fall wird die Länge des gepackten Schlüssels im selben Byte gespeichert, das zur Kennzeichnung verwendet wird, wenn ein Schlüssel NULL ist.)

  • PASSWORD

    Verschlüsselt die .frm-Datei mit einem Passwort. In der MySQL-Standardversion tut die Option nichts.

  • DELAY_KEY_WRITE

    Setzen Sie diese Option auf 1, wenn Sie Schlüssel-Updates für die Tabelle auf einen Zeitpunkt verschieben wollen, an dem die Tabelle geschlossen ist. Details finden Sie in der Beschreibung zur Systemvariablen delay_key_write in Abschnitt 5.2.2, „Server-Systemvariablen“. (Nur für MyISAM.)

  • ROW_FORMAT

    Definiert, wie die Datensätze gespeichert werden sollen. Bei MyISAM-Tabellen kann der Optionswert FIXED oder DYNAMIC für das statische wie auch das variabel lange Datensatzformat sein. myisampack setzt den Typ auf COMPRESSED. Siehe auch Abschnitt 14.1.3, „MyISAM-Tabellenformate“.

    Bei InnoDB-Tabellen werden die Datensätze standardmäßig im kompakten Format (ROW_FORMAT=COMPACT) gespeichert. Das nichtkompakte Format, welches in älteren MySQL-Versionen verwendet wurde, kann noch über die Angabe von ROW_FORMAT=REDUNDANT angefordert werden.

  • RAID_TYPE

    Die RAID-Unterstützung wurde ab MySQL 5.0 entfernt. Informationen zu RAID finden Sie online im MySQL-4.1-Handbuch unter http://dev.mysql.com/doc/refman/4.1/en/create-table.html.

  • UNION

    UNION wird verwendet, wenn Sie auf eine ganze Sammlung identischer MyISAM-Tabellen zugreifen wollen. Dies funktioniert nur bei MERGE-Tabellen. Siehe auch Abschnitt 14.3, „Die MERGE-Speicher-Engine“.

    Sie benötigen die Berechtigungen SELECT, UPDATE und DELETE für die Tabellen, um die Sammlung einer MERGE zuordnen zu können. (Hinweis: Ursprünglich mussten alle verwendeten Tabellen sich in der gleichen Datenbank wie die MERGE-Tabelle selbst befinden. Diese Einschränkung trifft nicht mehr zu.)

  • INSERT_METHOD

    Wenn Sie Daten in eine MERGE-Tabelle einfügen wollen, müssen Sie mit INSERT_METHOD die Tabelle festlegen, in die der Datensatz einzufügen ist. Die Option INSERT_METHOD ist nur für MERGE-Tabellen sinnvoll. Verwenden Sie die Werte FIRST oder LAST, um die Einfügung in die erste bzw. letzte Tabelle vorzunehmen, oder NO, um Einfügeoperationen ganz auszuschließen. Siehe auch Abschnitt 14.3, „Die MERGE-Speicher-Engine“.

  • DATA DIRECTORY, INDEX DIRECTORY

    Mithilfe von DATA DIRECTORY='directory' oder INDEX DIRECTORY='directory' können Sie angeben, wo die MyISAM-Speicher-Engine die Daten- und Indexdatei einer Tabelle ablegen soll. directory muss als vollständiger Pfadname zum Verzeichnis angegeben werden; relative Pfade sind nicht möglich.

    Diese Optionen funktionieren nur, wenn Sie die Option --skip-symbolic-links nicht verwenden. Außerdem muss Ihr Betriebssystem über einen funktionsfähigen und Thread-sicheren realpath()-Aufruf verfügen. Weitere Informationen finden Sie in Abschnitt 7.6.1.2, „Benutzung symbolischer Links für Tabellen“.

  • Partitionierungsoptionen (partition_options) können zur Steuerung der Partitionierung einer Tabelle benutzt werden, die mit CREATE TABLE erstellt wurde. Sofern angegeben, muss mindestens eine PARTITION BY-Klausel enthalten sein. Diese Klausel enthält die Funktion, die zur Bestimmung der Partition verwendet wird. Die Funktion gibt einen ganzzahligen Wert zwischen 1 und num zurück, wobei num die Gesamtzahl der Partitionen ist. Die nachfolgende Liste zeigt die Auswahlmöglichkeiten für diese Funktion in MySQL 5.1.

    Wichtig: Nicht alle zu Beginn dieses Abschnitts in der Syntax für partition_options aufgeführten Optionen stehen für alle Partitionierungstypen zur Verfügung. Entnehmen Sie den Listings für die jeweiligen Typen die passenden Informationen. Weitere Informationen zu Wirkungsweise und Anwendungsmöglichkeiten der Partitionierung in MySQL sowie zusätzliche Beispiele zur Tabellenerstellung und zu anderen partitionierungsbezogenen Anweisungen in MySQL finden Sie in Kapitel 17, Partitionierung.

    • HASH(expr): Führt ein Hashing einer oder mehrerer Spalten aus, um einen Schlüssel zum Platzieren und Wiederauffinden von Datensätzen zu erstellen. expr ist ein Ausdruck, der eine oder mehrere Tabellenspalten verwendet. Dabei kann es sich um einen zulässigen MySQL-Ausdruck (einschließlich MySQL-Funktionen) handeln, der genau einen Integer-Wert ausgibt. Die nachfolgenden CREATE TABLE-Anweisungen mit PARTITION BY HASH-Option etwa sind alle zulässig:

      CREATE TABLE t1 (col1 INT, col2 CHAR(5))
          PARTITION BY HASH(col1);
      
      CREATE TABLE t1 (col1 INT, col2 CHAR(5))
          PARTITION BY HASH( ORD(col2) );
      
      CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME)
          PARTITION BY HASH ( YEAR(col3) );
      

      VALUES LESS THAN- und VALUES IN-Klauseln dürfen nicht mit PARTITION BY HASH gemeinsam eingesetzt werden.

      PARTITION BY HASH verwendet den Rest des Ausdrucks expr geteilt durch die Anzahl der Partitionen (d. h. den Modulo). Beispiele und Informationen finden Sie in Abschnitt 17.2.3, „HASH-Partitionierung“.

      Das Schlüsselwort LINEAR bringt einen etwas anderen Algorithmus mit sich. In diesem Fall wird die Nummer der Partition, auf der ein Datensatz gespeichert ist, als Ergebnis einer oder mehrerer logischer AND-Operationen ermittelt. Eine Beschreibung und Beispiele für das lineare Hashing finden Sie in Abschnitt 17.2.3.1, „LINEAR HASH-Partitionierung“.

    • KEY(column_list): Dies ähnelt HASH, nur wird die Hashing-Funktion hier von MySQL selbst bereitgestellt, um eine gleichmäßige Datenverteilung zu gewährleisten. Das Argument column_list ist eine einfache Liste mit Tabellenspalten. Dieses Beispiel zeigt eine einfache, durch einen Schlüssel partitionierte Tabelle mit vier Partitionen:

      CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
          PARTITION BY KEY(col3)
          PARTITIONS 4;
      

      Bei Tabellen, die durch einen Schlüssel partitioniert sind, können Sie die lineare Partitionierung durch Angabe des Schlüsselworts LINEAR benutzen. Dies hat die gleichen Auswirkungen wie bei Tabellen, die mit HASH partitioniert wurden: Die Partitionsnummer wird mithilfe des Operators & statt über den Modulo ermittelt (siehe auch Abschnitt 17.2.3.1, „LINEAR HASH-Partitionierung“, und Abschnitt 17.2.4, „KEY-Partitionierung“). Dieses Beispiel verwendet die lineare Partitionierung über einen Schlüssel, um Daten auf fünf Partitionen zu verteilen:

      CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
          PARTITION BY LINEAR KEY(col3)
          PARTITIONS 5;
      

      VALUES LESS THAN- und VALUES IN-Klauseln dürfen nicht mit PARTITION BY KEY gemeinsam eingesetzt werden.

    • RANGE: In diesem Fall zeigt expr unter Verwendung einer Menge von VALUES LESS THAN-Operatoren einen Wertebereich an. Wenn Sie die Bereichspartitionierung verwenden, müssen Sie mindestens eine Partition mit VALUES LESS THAN angeben. VALUES IN können Sie bei der Bereichspartitionierung nicht einsetzen.

      VALUES LESS THAN kann entweder mit einem literalen Wert oder einem Ausdruck benutzt werden, der genau einen Wert zurückgibt.

      Angenommen, Sie haben eine Tabelle, die Sie nach einer Spalte partitionieren wollen, die Jahreswerte enthält. Hierbei wollen Sie das folgende Schema verwenden:

      Partitionsnummer:Jahre
      01990 und früher
      11991–1994
      21995–1998
      31999–2002
      42003–2005
      52006 und später

      Eine Tabelle, die dieses Partitionierungsschema implementiert, kann mit der folgenden CREATE TABLE-Anweisung erstellt werden:

      CREATE TABLE t1 (
          year_col  INT,
          some_data INT
      )
      PARTITION BY RANGE (year_col) (
          PARTITION p0 VALUES LESS THAN (1991),
          PARTITION p1 VALUES LESS THAN (1995),
          PARTITION p2 VALUES LESS THAN (1999),
          PARTITION p3 VALUES LESS THAN (2002),
          PARTITION p4 VALUES LESS THAN (2006),
          PARTITION p5 VALUES LESS THAN MAXVALUE
      );
      

      PARTITION ... VALUES LESS THAN ...-Anweisungen arbeiten konsekutiv, d. h., VALUES LESS THAN MAXVALUE verarbeitet die „übrig gebliebenen“ Werte, die größer sind als der anderweitig angegebene Maximalwert.

      Beachten Sie, dass VALUES LESS THAN-Klauseln sequenziell auf eine Weise verarbeitet werden, die der von case-Abschnitten eines switch ... case-Blocks ähnelt, wie man sie aus vielen Programmiersprachen wie C, Java oder PHP her kennt: Die Klauseln müssen so angeordnet sein, dass der obere Grenzwert einer nachfolgenden VALUES LESS THAN-Klausel größer ist als der der vorherigen Klausel; dabei muss MAXVALUE als Letztes in der Liste erscheinen.

    • LIST(expr): Dies ist praktisch, wenn man Partitionen basierend auf einer Tabellenspalte mit einer beschränkten Menge möglicher Werte (z. B. Land, PLZ usw.) konfiguriert. In einem solchen Fall lassen sich alle Datensätze, die einem bestimmten Land oder einer PLZ zuzuordnen sind, derselben Partition zuweisen, oder eine Partition kann für bestimmte Länder oder Postleitzahlen reserviert werden. Dies ähnelt RANGE mit der Einschränkung, dass nur VALUES IN zur Angabe zulässiger Werte für jede Partition verwendet werden kann.

      VALUES IN wird mit einer Liste passender Werte benutzt. Beispielsweise könnten Sie ein Partitionierungsschema wie das folgende erstellen:

      CREATE TABLE client_firms (
          id   INT,
          name VARCHAR(35)
      )
      PARTITION BY LIST (id) (
          PARTITION r0 VALUES IN (1, 5, 9, 13, 17, 21),
          PARTITION r1 VALUES IN (2, 6, 10, 14, 18, 22),
          PARTITION r2 VALUES IN (3, 7, 11, 15, 19, 23),
          PARTITION r3 VALUES IN (4, 8, 12, 16, 20, 24)
      );
      

      Wenn Sie die Listenpartitionierung verwenden, müssen Sie mindestens eine Partition mit VALUES IN angeben. VALUES LESS THAN können Sie bei der Listenpartitionierung nicht einsetzen.

      Hinweis: Derzeit darf die für VALUES IN verwendete Werteliste nur aus Integers bestehen.

    • Die Anzahl der Partitionen kann optional mit einer PARTITIONS num-Klausel angegeben werden, wobei num die Anzahl der Partitionen ist. Werden diese Klausel und beliebige PARTITION-Klauseln verwendet, muss num gleich der Anzahl aller Partitionen sein, die mit PARTITION-Klauseln deklariert wurden.

      Hinweis: Unabhängig davon, ob Sie eine PARTITIONS-Klausel bei der Erstellung einer Tabelle verwenden, die mit RANGE oder LIST partitioniert wurde, müssen Sie in jedem Fall mindestens eine PARTITION VALUES-Klausel in der Tabellendefinition angeben (siehe unten).

    • Eine Partition kann optional in eine Anzahl Unterpartitionen aufgeteilt werden. Dies kann durch Verwendung der optionalen Klausel SUBPARTITION BY angegeben werden. Die Unterpartitionierung kann mit HASH oder KEY erfolgen. Beide können LINEAR sein. Sie funktionieren auf die gleiche Weise wie oben für die entsprechenden Partitionierungstypen beschrieben. (Es ist nicht möglich, Unterpartitionen nach LIST oder RANGE zu erstellen.)

      Die Anzahl der Unterpartitionen kann mit dem Schlüsselwort SUBPARTITIONS, gefolgt von einem Integer-Wert, angegeben werden.

    Jede Partition kann individuell mit einer partition_definition-Klausel definiert werden. Die einzelnen Teile, aus denen die Klausel besteht, sind die folgenden:

    • PARTITION partition_name: Gibt einen logischen Namen für die Partition an.

    • VALUES-Klausel: Bei der Bereichspartitionierung muss jede Partition eine VALUES LESS THAN-Klausel enthalten, und bei der Listenpartitionierung müssen Sie eine VALUES IN-Klausel je Partition angeben. Hiermit wird bestimmt, welche Datensätze in dieser Partition gespeichert werden sollen. Weitere Informationen und Syntaxinformationen entnehmen Sie der Beschreibung der Partitionierungstypen in Kapitel 17, Partitionierung.

    • Eine optionale COMMENT-Klausel kann zur Beschreibung der Partition angegeben werden. Der Kommentar muss in einzelne Anführungszeichen gesetzt werden. Beispiel:

      COMMENT = 'Data for the years previous to 1999'
      
    • DATA DIRECTORY und INDEX DIRECTORY können zur Angabe des Verzeichnisses verwendet werden, in dem die Daten bzw. die Indizes dieser Partition gespeichert werden sollen. Sowohl data_dir als auch index_dir müssen absolute Pfadnamen sein. Beispiel:

      CREATE TABLE th (id INT, name VARCHAR(30), adate DATE)
      PARTITION BY LIST(YEAR(adate))
      (
        PARTITION p1999 VALUES IN (1995, 1999, 2003)
          DATA DIRECTORY = '/var/appdata/95/data'
          INDEX DIRECTORY = '/var/appdata/95/idx',
        PARTITION p2000 VALUES IN (1996, 2000, 2004)
          DATA DIRECTORY = '/var/appdata/96/data'
          INDEX DIRECTORY = '/var/appdata/96/idx',
        PARTITION p2001 VALUES IN (1997, 2001, 2005)
          DATA DIRECTORY = '/var/appdata/97/data'
          INDEX DIRECTORY = '/var/appdata/97/idx',
        PARTITION p2000 VALUES IN (1998, 2002, 2006)
          DATA DIRECTORY = '/var/appdata/98/data'
          INDEX DIRECTORY = '/var/appdata/98/idx'
      );
      

      DATA DIRECTORY und INDEX DIRECTORY verhalten sich genauso wie in der table_option-Klausel einer CREATE TABLE-Anweisung bei MyISAM-Tabellen.

      Je Partition können ein Daten- und ein Indexverzeichnis angegeben werden. Wenn keine Angaben gemacht werden, werden Daten und Indizes standardmäßig im MySQL-Datenverzeichnis abgelegt.

    • MAX_ROWS und MIN_ROWS können zur Angabe der größten bzw. kleinsten Zahl von Datensätzen verwendet werden, die in der Partition gespeichert werden. Die Werte für max_number_of_rows und min_number_of_rows müssen positive ganze Zahlen sein. Wie bei den gleichnamigen Optionen auf Tabellenebene sind auch dies keine festen Grenzwerte, sondern nur „Vorschläge“ für den Server.

    • Die optionale TABLESPACE-Klausel kann zur Angabe eines Tablespaces für die Partition verwendet werden. (Nur für MySQL Cluster.)

    • Die optionale [STORAGE] ENGINE-Klausel bewirkt, dass die Tabelle in dieser Partition die angegebene Speicher-Engine verwendet. Dies kann jede der vom betreffenden MySQL Server unterstützten Engines sein. Sowohl das Schlüsselwort STORAGE als auch das Gleichheitszeichen (=) sind optional. Wird keine partitionsspezifische Speicher-Engine mit dieser Option angegeben, dann wird die für die gesamte Tabelle gültige Engine auch für diese Partition verwendet.

      Hinweis: Der Partitionierungs-Handler akzeptiert eine Option [STORAGE] ENGINE sowohl für PARTITION als auch für SUBPARTITION. Die derzeit einzige Möglichkeit, diese Klausel zu nutzen, besteht darin, alle Partitionen oder alle Unterpartitionen auf dieselbe Speicher-Engine zu setzen. Der Versuch, verschiedene Engines für Partitionen oder Unterpartitionen einer Tabelle einzustellen, führt zum Fehler ERROR 1469 (HY000): The mix of handlers in the partitions is not allowed in this version of MySQL. Wir beabsichtigen, diese partitionierungsbezogene Einschränkung in einem zukünftigen Release von MySQL 5.1 zu beseitigen.

    • Die Option NODEGROUP kann verwendet werden, um diese Partition zu einem Teil der Knotengruppe zu machen, die als node_group_id angegeben ist. (Nur für MySQL Cluster.)

    • Die Partitionsdefinition kann optional eine oder mehrere subpartition_definition-Klauseln enthalten. Jede dieser Klauseln umfasst zumindest SUBPARTITION name, wobei name ein Bezeichner für die Unterpartition ist. Die Syntax für eine Unterpartitionsdefinition ist mit der einer Partition bis auf die Tatsache identisch, dass das Schlüsselwort PARTITION durch SUBPARTITION zu ersetzen ist.

      Die Unterpartitionierung muss über HASH oder KEY erfolgen und kann nur bei RANGE- oder LIST-Partitionen durchgeführt werden. Siehe auch Abschnitt 17.2.5, „Unterpartitionen“.

    Partitionen können geändert, verbunden und zu Tabellen hinzugefügt sowie aus diesen gelöscht werden. Grundlegende Informationen zu den MySQL-Anweisungen, mit denen diese Aufgaben erledigt werden, finden Sie in Abschnitt 13.1.2, „ALTER TABLE. Detaillierte Beschreibungen und Beispiele finden Sie in Abschnitt 17.3, „Partitionsverwaltung“.

Sie können eine Tabelle aus einer anderen Tabelle erstellen, indem Sie am Ende der CREATE TABLE-Anweisung eine SELECT-Anweisung hinzufügen:

CREATE TABLE new_tbl SELECT * FROM orig_tbl;

MySQL erstellt neue Spalten für alle Elemente in der SELECT-Anweisung. Zum Beispiel:

mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
    ->        PRIMARY KEY (a), KEY(b))
    ->        ENGINE=MyISAM SELECT b,c FROM test2;

Hierbei wird eine MyISAM-Tabelle mit drei Spalten a, b und c erstellt. Beachten Sie, dass die Spalten aus der SELECT-Anweisung rechts an die Tabelle angehängt und nicht in diese eingesetzt werden. Betrachten Sie einmal das folgende Beispiel:

mysql> SELECT * FROM foo;
+---+
| n |
+---+
| 1 |
+---+

mysql> CREATE TABLE bar (m INT) SELECT n FROM foo;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM bar;
+------+---+
| m    | n |
+------+---+
| NULL | 1 |
+------+---+
1 row in set (0.00 sec)

Für jeden Datensatz in der Tabelle foo wird ein Datensatz in bar mit den Werten aus foo und den Standardwerten bei neuen Spalten eingefügt.

In einer Tabelle, die mit CREATE TABLE ... SELECT erstellt wurde, erscheinen die Spalten, die im CREATE TABLE-Teil genannt werden, zuerst. Die in beiden Teilen oder nur im SELECT-Teil genannten Spalten folgen nach. Der Datentyp der SELECT-Spalten kann außer Kraft gesetzt werden, indem die Spalte zusätzlich im CREATE TABLE-Teil genannt wird.

Wenn während des Kopierens der Daten in die Tabelle Fehler auftreten, wird diese automatisch gelöscht und nicht erstellt.

CREATE TABLE ... SELECT erstellt keine automatischen Indizes. Dies wurde bewusst so eingerichtet, um die Anweisung so flexibel wie möglich zu halten. Wenn Sie wollen, dass Indizes in der Tabelle erstellt werden, müssen Sie diese vor der SELECT-Anweisung spezifizieren:

mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;

Es kann dadurch zu Fällen von Datentypkonvertierung kommen. So wird z. B. das AUTO_INCREMENT-Attribut nicht beibehalten, und VARCHAR-Spalten können in CHAR-Spalten umgewandelt werden.

Wenn Sie eine Tabelle mit CREATE ... SELECT erstellen, müssen Sie in jedem Fall Aliase für Funktionsaufrufe oder Ausdrücke in der Abfrage verwenden. Andernfalls kann die CREATE-Anweisung fehlschlagen, oder es können unerwünschte Spaltennamen entstehen.

CREATE TABLE artists_and_works
  SELECT artist.name, COUNT(work.artist_id) AS number_of_works
  FROM artist LEFT JOIN work ON artist.id = work.artist_id
  GROUP BY artist.id;

Sie können den Typ einer erzeugten Spalte auch explizit angeben:

CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;

Mit LIKE können Sie eine leere Tabelle basierend auf der Definition einer anderen Tabelle einschließlich aller Spaltenattribute und Indizes erstellen, die auch in der Ursprungstabelle vorhanden sind:

CREATE TABLE new_tbl LIKE orig_tbl;

CREATE TABLE ... LIKE behält weder für die Ursprungstabelle angegebene DATA DIRECTORY- und INDEX DIRECTORY-Optionen noch Fremdschlüsseldefinitionen bei.

Sie können dem SELECT ein IGNORE oder REPLACE voranstellen, um anzugeben, wie mit Datensätzen zu verfahren ist, in denen Dubletten für eindeutige Schlüssel auftreten. Bei IGNORE werden neue Datensätze, die eine Dublette eines eindeutigen Schlüssels für einen bereits vorhandenen Datensatz enthalten, einfach verworfen. Wenn Sie REPLACE angeben, ersetzen die neuen die vorhandenen Datensätze, die denselben eindeutigen Schlüsselwert aufweisen. Werden weder IGNORE noch REPLACE angegeben, dann führt das Auftreten von Dubletten eindeutiger Schlüssel zu einem Fehler.

Um sicherzustellen, dass das Binärlog zur Wiederherstellung der Originaltabellen verwendet werden kann, gestattet MySQL keine gleichzeitigen Einfügeoperationen während der Ausführung einer CREATE TABLE ... SELECT-Anweisung.

13.1.6. DROP DATABASE

DROP {DATABASE | SCHEMA} [IF EXISTS] db_name

DROP DATABASE löscht alle Tabellen in der Datenbank und nachfolgend auch die Datenbank. Seien Sie im Umgang mit dieser Anweisung extrem sorgfältig! Um DROP DATABASE verwenden zu können, benötigen Sie die Berechtigung DROP für die Datenbank. DROP SCHEMA ist ein Synonym für DROP DATABASE.

IF EXISTS wird verwendet, um einen Fehler abzufangen, wenn die Datenbank nicht vorhanden ist.

Wenn Sie DROP DATABASE für eine symbolisch verknüpfte Datenbank verwenden, werden sowohl die Verknüpfung als auch die Originaldatenbank gelöscht.

DROP DATABASE gibt die Anzahl der entfernten Tabellen zurück. Diese entspricht der Anzahl der gelöschten .frm-Dateien.

Die DROP DATABASE-Anweisung entfernt jene Dateien und Verzeichnisse, die MySQL im normalen Betrieb selbst erstellt hat, aus dem angegebenen Datenbankverzeichnis:

  • Alle Dateien mit den folgenden Erweiterungen:

    .BAK.DAT.HSH
    .MRG.MYD.ISD
    .MYI.db.frm
  • Alle Unterverzeichnisse mit Namen, die aus zwei Hexadezimalstellen (00-ff) bestehen. Dies sind Unterverzeichnisse, die für RAID-Tabellen verwendet werden. (Diese Verzeichnisse werden ab MySQL 5.0 nicht entfernt, weil die Unterstützung für RAID-Tabellen aufgehoben wurde. Sie sollten alle vorhandenen RAID-Tabellen konvertieren und diese Verzeichnisse manuell entfernen, bevor Sie auf MySQL 5.0 oder höher aktualisieren. Weitere Informationen finden Sie im Abschnitt zur Aktualisierung von früheren Releases auf MySQL 5.0 im MySQL 5.0 Reference Manual, welches auf der MySQL-Website erhältlich ist.)

  • Datei db.opt (sofern vorhanden).

Wenn andere Dateien oder Verzeichnisse im Datenbankverzeichnis zurückbleiben, nachdem MySQL die genannten Elemente entfernt hat, kann das Datenbankverzeichnis nicht gelöscht werden. In diesem Fall müssen Sie alle verbleibenden Dateien oder Verzeichnisse manuell entfernen und die DROP DATABASE-Anweisung nachfolgend erneut absetzen.

Sie können Datenbanken auch mit mysqladmin löschen. Siehe auch Abschnitt 8.7, „mysqladmin — Client für die Verwaltung eines MySQL Servers“.

13.1.7. DROP INDEX

DROP INDEX index_name ON tbl_name

DROP INDEX löscht den Index namens index_name aus der Tabelle tbl_name. Diese Anweisung wird einer ALTER TABLE-Anweisung zugewiesen, die den Index löscht. Siehe auch Abschnitt 13.1.2, „ALTER TABLE.

13.1.8. DROP TABLE

DROP [TEMPORARY] TABLE [IF EXISTS]
    tbl_name [, tbl_name] ...
    [RESTRICT | CASCADE]

DROP TABLE löscht eine oder mehrere Tabellen. Für jede Tabelle benötigen Sie die Berechtigung DROP. Alle Tabellendaten und die Tabellendefinition werden entfernt! Seien Sie also auch im Umgang mit dieser Anweisung sehr vorsichtig!

Beachten Sie, dass DROP TABLE bei einer partitionierten Tabelle die Tabellendefinition, alle Partitionen und alle in diesen Partitionen gespeicherten Daten permanent entfernt. Ebenso gelöscht wird die Partitionierungsdefinitiondatei (.par) der gelöschten Tabelle.

Verwenden Sie IF EXISTS, um einen Fehler bei Tabellen abzufangen, die nicht vorhanden sind. Für jede nicht vorhandene Tabelle wird ein Hinweis erzeugt, wenn Sie IF EXISTS benutzen. Siehe auch Abschnitt 13.5.4.25, „SHOW WARNINGS.

RESTRICT und CASCADE erlauben eine leichtere Portierung. Derzeit haben sie aber keine Funktion.

Hinweis: DROP TABLE übergibt die derzeit aktive Transaktion sofort, sofern Sie nicht das Schlüsselwort TEMPORARY benutzen.

Das Schlüsselwort TEMPORARY hat die folgenden Auswirkungen:

  • Die Anweisung löscht nur Temporärtabellen.

  • Die Anweisung beendet keine laufende Transaktion.

  • Zugriffsrechte werden nicht geprüft. (Eine Temporärtabelle ist nur für den Client sichtbar, der sie erstellt hat; insofern ist eine Überprüfung unnötig.)

Die Verwendung von TEMPORARY ist eine gute Möglichkeit, sicherzustellen, dass Sie nicht versehentlich eine nichttemporäre Tabelle löschen.

13.1.9. RENAME TABLE

RENAME TABLE tbl_name TO new_tbl_name
    [, tbl_name2 TO new_tbl_name2] ...

Mit dieser Anweisung werden eine oder mehrere Tabellen umbenannt.

Der Umbenennungsvorgang erfolgt automatisch, d. h., kein anderer Thread kann währenddessen auf die umzubenennende(n) Tabelle(n) zugreifen. Wenn Sie beispielsweise eine Tabelle old_table haben, können Sie eine andere Tabelle new_table erstellen, die dieselbe Struktur hat, aber leer ist, und die vorhandene Tabelle dann wie folgt durch die leere Tabelle ersetzen (sofern backup_table nicht bereits vorhanden ist):

CREATE TABLE new_table (...);
RENAME TABLE old_table TO backup_table, new_table TO old_table;

Wenn die Anweisung mehrere Tabellen umbenennt, erfolgen die Umbenennungen von links nach rechts. Wollen Sie zwei Tabellennamen gegeneinander austauschen, dann können Sie dies wie folgt tun (sofern tmp_table nicht bereits vorhanden ist):

RENAME TABLE old_table TO tmp_table,
             new_table TO old_table,
             tmp_table TO new_table;

Solange zwei Datenbanken sich im selben Dateisystem befinden, können Sie mit RENAME TABLE auch eine Tabelle von einer Datenbank in eine andere verschieben:

RENAME TABLE current_db.tbl_name TO other_db.tbl_name;

RENAME TABLE funktioniert auch bei Views, solange Sie nicht versuchen, einen View in einer anderen Datenbank umzubenennen.

Wenn Sie RENAME ausführen, dürfen keine Tabellen gesperrt und keine Transaktionen aktiv sein. Sie benötigen für die Ursprungstabelle ferner die Berechtigungen ALTER und DROP sowie die Berechtigungen CREATE und INSERT für die neue Tabelle.

Wenn MySQL in einer tabellenübergreifenden Umbenennungsaktion auf Fehler trifft, wird für alle umbenannten Tabellen eine umgekehrte Umbenennung durchgeführt, um den ursprünglichen Zustand wiederherzustellen.

13.2. Datenmanipulation: SELECT, INSERT, UPDATE, DELETE

13.2.1. DELETE

Syntax für eine Tabelle:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

Syntax für mehrere Tabellen:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    tbl_name[.*] [, tbl_name[.*]] ...
    FROM table_references
    [WHERE where_condition]

Oder:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[.*] [, tbl_name[.*]] ...
    USING table_references
    [WHERE where_condition]

Bei der Ein-Tabellen-Syntax löscht die DELETE-Anweisung Datensätze aus tbl_name und gibt die Anzahl gelöschter Datensätze zurück. Sofern angegeben, bestimmt die WHERE-Klausel die Bedingungen dafür, welche Datensätze gelöscht werden. Ohne WHERE-Klausel werden alle Datensätze gelöscht. Wenn die ORDER BY-Klausel vorhanden ist, werden die Datensätze in der angegebenen Reihenfolge gelöscht. Die LIMIT-Klausel kann die Anzahl der zu löschenden Datensätze beschränken.

Bei der Mehrtabellensyntax löscht DELETE aus jeder Tabelle tbl_name die Datensätze, die die Bedingungen erfüllen. In diesem Fall können ORDER BY und LIMIT nicht verwendet werden.

where_condition ist ein Ausdruck, der für jeden zu löschenden Datensatz wahr ist. Er wird wie in Abschnitt 13.2.7, „SELECT, beschrieben angegeben.

Wie bereits gesagt, löscht eine DELETE-Anweisung ohne WHERE-Klausel alle Datensätze. Wenn Sie die Anzahl der gelöschten Datensätze nicht kennen müssen, können Sie dies schneller mit TRUNCATE TABLE erledigen. Siehe auch Abschnitt 13.2.9, „TRUNCATE.

Wenn Sie den Datensatz entfernen, der den höchsten Wert für eine AUTO_INCREMENT-Spalte hat, dann wird der Wert bei BDB-Tabellen später wiederverwendet, nicht jedoch bei MyISAM- oder InnoDB-Tabellen. Wenn Sie im AUTOCOMMIT-Modus alle Datensätze in der Tabelle mit DELETE FROM tbl_name (ohne WHERE-Klausel) löschen, beginnt die Sequenz für alle Speicher-Engines mit Ausnahme von InnoDB und MyISAM neu. Bei InnoDB-Tabellen gibt es bezüglich dieses Verhaltens ein paar Ausnahmen, die in Abschnitt 14.2.6.3, „Wie eine Auto-Increment-Spalte in InnoDB funktioniert“, beschrieben sind.

Bei MyISAM- und BDB-Tabellen können Sie AUTO_INCREMENT in einer Sekundärspalte eines mehrspaltigen Schlüssels angeben. In diesem Fall werden Werte, die am Anfang der Sequenz gelöscht wurden, auch bei MyISAM-Tabellen wiederverwendet. Siehe auch Abschnitt 3.6.9, „Verwendung von AUTO_INCREMENT.

Die DELETE-Anweisung unterstützt die folgenden Modifizierer:

  • Wenn Sie LOW_PRIORITY angeben, verzögert der Server die Ausführung von DELETE, bis kein Client mehr aus der Tabelle liest.

  • Wenn Sie bei MyISAM-Tabellen das Schlüsselwort QUICK angeben, fasst die Speicher-Engine beim Löschen Indexzweige nicht zusammen. Dies kann bestimmte Arten von Löschvorgängen beschleunigen.

  • Das Schlüsselwort IGNORE bewirkt, dass MySQL alle Fehler während des Vorgangs der Datensatzlöschung ignoriert. (Fehler, die bei der Analyse auftreten, werden allerdings wie gewöhnlich verarbeitet.) Fehler, die aufgrund der Verwendung von OPTION ignoriert werden, werden als Warnungen zurückgegeben.

Die Geschwindigkeit von Löschoperationen kann auch von den Faktoren beeinflusst werden, die in Abschnitt 7.2.18, „Geschwindigkeit von DELETE-Anfragen“, beschrieben werden.

Bei MyISAM-Tabellen werden gelöschte Datensätze zu einer verknüpften Liste hinzugefügt. Nachfolgende INSERT-Operationen verwenden die alten Datensatzpositionen neu. Um ungenutzten Speicher wieder freizugeben und die Dateigrößen zu verringern, verwenden Sie die OPTIMIZE TABLE-Anweisung oder das Hilfsprogramm myisamchk zur Reorganisierung der Tabellen. OPTIMIZE TABLE ist einfacher, myisamchk hingegen schneller. Siehe auch Abschnitt 13.5.2.5, „OPTIMIZE TABLE, und Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“.

Der Modifizierer QUICK bestimmt, ob Indexzweige bei Löschoperationen zusammengefasst werden. DELETE QUICK ist am nützlichsten bei Anwendungen, bei denen Indexwerte für gelöschte Datensätze durch ähnliche Indexwerte von später eingefügten Datensätzen ersetzt werden. In diesem Fall werden die von den gelöschten Werten zurückgelassenen Löcher wiederverwendet.

DELETE QUICK ist hingegen nicht nützlich, wenn gelöschte Werte nicht aufgefüllte Indexblöcke zur Folge haben, die einen Bereich von Indexwerten umfassen, bei denen neue Einfügeoperationen auftreten. In diesem Fall kann die Verwendung von QUICK zur Verschwendung von Speicher im Index führen, da dieser Speicher nicht mehr freigegeben wird. Hier ein Beispiel für ein solches Szenario:

  1. Erstellen Sie eine Tabelle, die eine indizierte AUTO_INCREMENT-Spalte enthält.

  2. Fügen Sie viele Datensätze in diese Tabelle ein. Jede Einfügeoperation führt dazu, dass ein Indexwert am Ende des Indexes eingefügt wird.

  3. Löschen Sie mit DELETE QUICK einen Block mit Datensätzen vorne im Spaltenbereich.

In diesem Szenario werden die Indexblöcke, die mit den gelöschten Indexwerten verknüpft sind, nicht aufgefüllt, aber aufgrund der Verwendung von QUICK auch nicht mit anderen Indexblöcken zusammengefasst. Sie bleiben also unaufgefüllt, wenn weitere Einfügeoperationen auftreten, weil die neuen Datensätze keine Indexwerte im gelöschten Bereich haben. Außerdem bleiben sie auch dann unaufgefüllt, wenn Sie später DELETE ohne QUICK verwenden, sofern nicht zufällig einige der gelöschten Indexwerte in Indexblöcken innerhalb oder neben den nicht aufgefüllten Blöcken liegen. Um ungenutzten Indexspeicher unter diesen Umständen wieder freizugeben, verwenden Sie OPTIMIZE TABLE.

Wenn Sie viele Datensätze aus einer Tabelle zu löschen beabsichtigen, kann DELETE QUICK gefolgt von OPTIMIZE TABLE die schnellere Lösung sein. Hierbei wird der Index neu erstellt, statt zahlreiche Zusammenfassungsoperationen für Indexblöcke auszuführen.

Die MySQL-spezifische Option LIMIT row_count für DELETE nennt dem Server die maximale Anzahl Datensätze, die gelöscht werden, bevor die Kontrolle an den Client zurückgegeben wird. Hiermit können Sie gewährleisten, dass eine gegebene DELETE-Anweisung nicht zu viel Zeit in Anspruch nimmt. Sie können die DELETE-Anweisung dann einfach wiederholen, bis die Gesamtzahl betroffener Datensätze kleiner ist als der LIMIT-Wert.

Wenn die DELETE-Anweisung eine ORDER BY-Klausel enthält, werden die Datensätze in der in der Klausel angegebenen Reihenfolge gelöscht. Dies ist nur in Verbindung mit LIMIT wirklich nützlich. Die folgende Anweisung beispielsweise findet Datensätze, die der WHERE-Klausel entsprechen, sortiert sie nach timestamp_column und löscht den ersten (d. h. ältesten) Datensatz:

DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;

Sie können in einer DELETE-Anweisung mehrere Tabellen angeben, aus denen je nach Bedingung der WHERE-Klausel Datensätze gelöscht werden. Allerdings können Sie ORDER BY oder LIMIT nicht in einer DELETE-Anweisung für mehrere Tabellen verwenden. Die Klausel table_references listet die Tabellen auf, die im Join berücksichtigt werden. Die Syntax ist in Abschnitt 13.2.7.1, „JOIN, beschrieben.

Bei der ersten Mehrtabellensyntax werden nur passende Datensätze aus den Tabellen gelöscht, die vor der FROM-Klausel aufgelistet sind. Bei der zweiten Mehrtabellensyntax werden nur passende Datensätze aus den Tabellen gelöscht, die in der FROM-Klausel (vor der USING-Klausel) aufgelistet sind. Die Folge ist, dass Sie Datensätze aus vielen Tabellen gleichzeitig löschen und gleichzeitig in weiteren Tabellen nur suchen lassen können:

DELETE t1, t2 FROM t1, t2, t3 WHERE t1.id=t2.id AND t2.id=t3.id;

Oder:

DELETE FROM t1, t2 USING t1, t2, t3 WHERE t1.id=t2.id AND t2.id=t3.id;

Diese Anweisungen verwenden auf der Suche nach zu löschenden Datensätzen alle drei Tabellen, aber gelöscht werden passende Datensätze tatsächlich nur aus den Tabellen t1 und t2.

Die obigen Beispiele zeigen innere Joins, die den Kommaoperator verwenden. DELETE-Anweisungen für mehrere Tabellen können jedoch einen beliebigen Join-Typ verwenden, der für SELECT-Anweisungen zulässig ist, also etwa LEFT JOIN.

Die Syntax erlaubt .* nach den Tabellennamen, um die Kompatibilität mit Access zu gewährleisten.

Wenn Sie eine DELETE-Anweisung für mehrere Tabellen verwenden, die auch InnoDB-Tabellen einbezieht, für die Fremdschlüssel-Constraints vorhanden sind, dann verarbeitet der MySQL-Optimierer die Tabellen unter Umständen in einer Reihenfolge, die sich von der ihrer Parent/Child-Beziehung unterscheidet. In diesem Fall schlägt die Anweisung fehl, und es wird ein Rollback durchgeführt. Stattdessen sollten Sie die Löschoperation dann aus nur einer Tabelle durchführen und sich auf die ON DELETE-Funktionalität verlassen, die InnoDB bietet, um andere Tabellen entsprechend zu ändern.

Hinweis: Wenn Sie einen Alias für eine Tabelle angegeben haben, müssen Sie diesen bei der Referenzierung der Tabelle verwenden:

DELETE t1 FROM test AS t1, test2 WHERE ...

Datenbankübergreifende Löschvorgänge werden von Löschvorgängen für mehrere Tabellen unterstützt. In diesem Fall müssen Sie die Tabellen aber ohne Verwendung von Aliasen referenzieren. Zum Beispiel:

DELETE test1.tmp1, test2.tmp2 FROM test1.tmp1, test2.tmp2 WHERE ...

Zurzeit können Sie in einer Unterabfrage keine Löschoperation in einer Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

13.2.2. DO

DO expr [, expr] ...

DO führt Ausdrücke aus, gibt aber keine Ergebnisse zurück. In den meisten Fällen ist DO eine Kurzform von SELECT expr, ..., hat aber den Vorteil, dass es etwas schneller ist, sofern das Ergebnis für Sie keine Rolle spielt. Allerdings meldet DO keine Fehler. Stattdessen werden Fehler als Warnungen ausgegeben.

DO ist in erster Linie bei Funktionen praktisch, die Begleiterscheinungen haben (z. B. RELEASE_LOCK()).

13.2.3. HANDLER

HANDLER tbl_name OPEN [ AS alias ]
HANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...)
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE

Die Anweisung HANDLER bietet direkten Zugriff auf die Schnittstellen der Speicher-Engine einer Tabelle. Sie steht für MyISAM- und InnoDB-Tabellen zur Verfügung.

Die Anweisung HANDLER ... OPEN öffnet eine Tabelle und gestattet den Zugriff über nachfolgende HANDLER ... READ-Anweisungen. Dieses Tabellenobjekt wird nicht mit anderen Threads gemeinsam genutzt und wird erst geschlossen, wenn der Thread HANDLER ... CLOSE aufruft oder beendet wird. Wenn Sie die Tabelle unter Verwendung eines Alias öffnen, müssen nachfolgende Referenzierungen durch andere HANDLER-Anweisungen den Alias statt des Tabellennamens verwenden.

Die erste HANDLER ... READ-Syntax holt einen Datensatz, bei dem der angegebene Index den übergebenen Werten entspricht und die WHERE-Bedingung erfüllt ist. Wenn Sie einen mehrspaltigen Index haben, geben Sie die Indexspaltenwerte als kommagetrennte Liste an. Entweder geben Sie Werte für alle Spalten im Index oder aber Werte für das links stehende Präfix der Indexspalten an. Angenommen, ein Index my_idx enthält drei Spalten namens col_a, col_b und col_c in genau dieser Reihenfolge. Die Anweisung HANDLER kann Werte für alle drei Spalten im Index oder für die Spalten in einem links stehenden Präfix angeben. Zum Beispiel:

HANDLER ... READ my_idx = (col_a_val,col_b_val,col_c_val) ...
HANDLER ... READ my_idx = (col_a_val,col_b_val) ...
HANDLER ... READ my_idx = (col_a_val) ...

Um die HANDLER-Schnittstelle für die Referenzierung des Primärschlüssels einer Tabelle zu verwenden, setzen Sie den Bezeichner in Anführungszeichen (`PRIMARY`).

HANDLER tbl_name READ `PRIMARY` ...

Die zweite HANDLER ... READ-Syntax holt aus der Tabelle einen Datensatz in der Indexreihenfolge, die der WHERE-Bedingung entspricht.

Die dritte HANDLER ... READ-Syntax holt aus der Tabelle einen Datensatz in der natürlichen Datensatzreihenfolge, die der WHERE-Bedingung entspricht. Sie ist schneller als HANDLER tbl_name READ index_name, wenn ein vollständiger Tabellenscan gewünscht wird. Die natürliche Datensatzreihenfolge ist die Reihenfolge, in der die Datensätze in der Datendatei einer MyISAM-Tabelle gespeichert sind. Diese Anweisung funktioniert auch bei InnoDB-Tabellen, aber das Konzept greift hier in Ermangelung einer separaten Datendatei nicht.

Ohne eine LIMIT-Klausel holen alle Formen von HANDLER ... READ einen einzelnen Datensatz (sofern vorhanden). Um eine bestimmte Anzahl Datensätze zurückzugeben, fügen Sie eine LIMIT-Klausel ein. Sie hat dieselbe Syntax wie bei der SELECT-Anweisung. Siehe auch Abschnitt 13.2.7, „SELECT.

HANDLER ... CLOSE schließt eine Tabelle, die mit HANDLER ... OPEN geöffnet worden war.

HANDLER ist eine etwas maschinennahe Anweisung. Sie bietet z. B. keine Konsistenz: HANDLER ... OPEN fertigt keine Momentaufnahme der Tabelle an und sperrt sie nicht. Das bedeutet, dass, nachdem eine HANDLER ... OPEN-Anweisung abgesetzt wurde, die Tabellendaten (vom aktuellen, aber auch von anderen Threads) modifiziert werden können und diese Änderungen dann für HANDLER ... NEXT- oder HANDLER ... PREV-Scans unter Umständen nur teilweise sichtbar sind.

Es gibt eine Reihe von Gründen zur Verwendung der HANDLER-Schnittstelle anstelle einer normalen SELECT-Anweisung:

  • HANDLER ist schneller als SELECT:

    • Für HANDLER ... OPEN wird ein dediziertes Speicher-Engine-spezifisches Handler-Objekt reserviert. Das Objekt wird bei nachfolgenden HANDLER-Anweisungen für diese Tabelle wiederverwendet; es muss nicht jeweils neu initialisiert werden.

    • Der Analyseaufwand ist geringer.

    • Es ist kein zusätzlicher Aufwand für den Optimierer oder die Abfrageüberprüfung erforderlich.

    • Die Tabelle muss nicht zwischen zwei Handler-Anforderungen gesperrt werden.

    • Die Handler-Schnittstelle muss keine konsistente Sicht der Daten bieten (Dirty Reads beispielsweise sind zulässig) – die Speicher-Engine kann also Optimierungen verwenden, die SELECT normalerweise nicht zulassen würde.

  • Bei Anwendungen, die eine maschinennahe ISAM-artige Schnittstelle verwenden, erleichtert HANDLER deren Portierung auf MySQL.

  • HANDLER erlaubt Ihnen das Durchlaufen einer Datenbank auf eine Weise, die mit SELECT – wenn überhaupt – nur sehr schwierig zu realisieren ist. Die HANDLER-Schnittstelle ist eine natürlicher anmutende Art der Datensicht, wenn Sie mit Anwendungen arbeiten, die eine interaktive Benutzeroberfläche für die Datenbank bereitstellen.

13.2.4. INSERT

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    VALUES ({expr | DEFAULT},...),(...),...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

Oder:

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

Oder:

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

INSERT fügt neue Datensätze in eine vorhandene Tabelle ein. Die Formen INSERT ... VALUES und INSERT ... SET der Anweisung fügen Datensätze basierend auf explizit angegebenen Werten ein. Die Form INSERT ... SELECT fügt Datensätze ein, die in einer oder mehreren anderen Tabellen ausgewählt wurden. INSERT ... SELECT wird in Abschnitt 13.2.4.1, „INSERT ... SELECT, näher erläutert.

Sie können REPLACE anstelle von INSERT verwenden, um alte Datensätze zu überschreiben. REPLACE ist das Gegenstück zu INSERT IGNORE bei der Behandlung neuer Datensätze, deren eindeutige Schlüsselwerte Dubletten bereits vorhandener Datensätze sind: Die neuen Datensätze ersetzen die alten, statt verworfen zu werden. Siehe auch Abschnitt 13.2.6, „REPLACE.

tbl_name ist die Tabelle, in die die Datensätze eingefügt werden sollen. Die Spalten, für die die Anweisung Werte angibt, lassen sich wie folgt angeben:

  • Sie können eine kommagetrennte Liste von Spaltennamen gefolgt vom Tabellennamen angeben. In diesem Fall muss für jede genannte Spalte in der VALUES-Liste oder der SELECT-Anweisung ein Wert vorhanden sein.

  • Wenn Sie keine Liste mit Spaltennamen für INSERT ... VALUES oder INSERT ... SELECT angeben, dann müssen die Werte für alle Spalten in der Tabelle in der VALUES-Liste oder der SELECT-Anweisung vorhanden sein. Wenn Sie die Reihenfolge der Spalten in der Tabelle nicht kennen, ermitteln Sie sie mit DESCRIBE tbl_name.

  • Die SET-Klausel gibt die Spaltennamen ausdrücklich an.

Spaltenwerte lassen sich auf mehrerlei Weise übergeben:

  • Wenn Sie MySQL nicht im strikten SQL-Modus ausführen, dann wird jede Spalte, für die kein Wert angegeben wird, auf den (expliziten oder impliziten) Standardwert gesetzt. Wenn Sie also etwa eine Spaltenliste angeben, die nicht alle Spalten in der Tabelle aufführt, werden nicht genannte Spalten auf ihre jeweiligen Standardwerte gesetzt. Die Zuweisung von Standardwerten ist in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben. Siehe auch Abschnitt 1.9.6.2, „Constraints auf ungültigen Daten“.

    Wenn Sie wollen, dass eine INSERT-Anweisung einen Fehler erzeugt, wenn Sie nicht alle Werte für alle Spalten ausdrücklich angeben, für die kein Standardwert vorhanden ist, dann sollten Sie den strikten Modus verwenden. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  • Mit dem Schlüsselwort DEFAULT können Sie eine Spalte explizit auf ihren Standardwert setzen. Dies erleichtert das Formulieren von INSERT-Anweisungen, die allen Spalten (bis auf einigen wenigen) Werte zuweisen, denn so brauchen Sie keine unvollständige VALUES-Liste zu erstellen, die nicht für jede Spalte in der Tabelle einen Wert enthält. Andernfalls müssten Sie die Liste der Spaltennamen ausschreiben, die den einzelnen Werten in der VALUES-Liste entspricht.

    Sie können auch DEFAULT(col_name) als eine allgemeinere Form benutzen, mit der in Ausdrücken der Standardwert einer gegebenen Spalte erzeugt werden kann.

  • Wenn sowohl die Spaltenliste als auch die VALUES-Liste leer sind, erstellt INSERT einen Datensatz, bei dem jede Spalte auf den jeweiligen Standardwert gesetzt ist:

    INSERT INTO tbl_name () VALUES();
    

    Im strikten Modus tritt ein Fehler auf, wenn nicht für jede Spalte ein Standardwert angegeben ist. Andernfalls verwendet MySQL den impliziten Standardwert für jede Spalte, der kein expliziter Wert zugewiesen ist.

  • Sie können den Spaltenwert auch durch einen Ausdruck expr angeben. Dies kann eine Typenkonvertierung bedingen, wenn der Ausdruckstyp nicht dem Typ der Spalte entspricht. Die Konvertierung eines gegebenen Werts kann je nach Datentyp zu unterschiedlichen Einfügewerten führen. So hat z. B. das Einfügen des Strings '1999.0e-2' in eine INT-. FLOAT-, DECIMAL(10,6)- oder YEAR-Spalte die Einfügewerte 1999, 19.9921, 19.992100 bzw. 1999 zur Folge. Der Grund dafür, dass der in den INT- und YEAR-Spalten gespeicherte Wert 1999 ist, besteht darin, dass bei der Konvertierung des Strings in den Integer nur der Teil des Strings berücksichtigt wird, der als gültiger Integer bzw. als sinnvolle Jahresangabe betrachtet wird. Bei Fließkomma- und Festkommaspalten wird bei der Umwandlung des Strings in einen Fließkommawert der gesamte String als zulässiger Fließkommawert betrachtet.

    Ein Ausdruck expr kann jede Spalte referenzieren, die zuvor in einer Werteliste eingestellt wurde. Sie könnten dies beispielsweise tun, weil der Wert von col2 die zuvor zugewiesene Spalte col1 referenziert:

    INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
    

    Die folgende Variante ist jedoch nicht zulässig, weil der Wert für col1 die Spalte col2 referenziert, die jedoch erst nach col1 zugewiesen wurde:

    INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
    

    Eine Ausnahme betrifft Spalten, die AUTO_INCREMENT-Werte enthalten. Weil der AUTO_INCREMENT-Wert nach anderen Wertezuweisungen erzeugt wird, gibt eine Referenzierung einer AUTO_INCREMENT-Spalte 0 zurück.

INSERT-Anweisungen, die die VALUES-Syntax verwenden, können mehrere Datensätze einfügen. Zu diesem Zweck fügen Sie mehrere Listen mit Spaltenwerten ein, die jeweils in Klammern gesetzt und durch Kommata getrennt sind. Beispiel:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

Die Werteliste für jeden Datensatz muss in Klammern gesetzt werden. Die folgende Anweisung ist unzulässig, weil die Anzahl der Werte in der Liste nicht der Anzahl der Spaltennamen entspricht:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);

Der Wert der von einer INSERT-Anweisung betroffenen Datensätze kann mit der C-API-Funktion mysql_affected_rows() ermittelt werden. Siehe auch Abschnitt 24.2.3.1, „mysql_affected_rows().

Wenn Sie eine INSERT ... VALUES-Anweisung mit mehreren Wertelisten oder INSERT ... SELECT verwenden, gibt die Anweisung einen Informations-String im folgenden Format zurück:

Records: 100 Duplicates: 0 Warnings: 0

Records gibt die Anzahl der von der Anweisung verarbeiteten Datensätze zurück. (Dies entspricht nicht unbedingt der Anzahl der tatsächlich eingefügten Datensätze, weil Duplicates auch ungleich null sein kann.) Duplicates gibt die Anzahl der Datensätze an, die nicht eingefügt wurden, weil eindeutige Schlüsselwerte andernfalls dupliziert worden wären. Warnings gibt die Anzahl der Spalteneinfügeversuche an, die aus irgendeinem Grund problematisch waren. Warnungen können unter den folgenden Umständen auftreten:

  • Einfügen von NULL in eine Spalte, die als NOT NULL deklariert wurde. Bei INSERT-Anweisung für mehrere Datensätze oder INSERT INTO ... SELECT-Anweisungen wird die Spalte auf den impliziten Standardwert für den betreffenden Spaltendatentyp gesetzt. Bei numerischen Typen ist dies 0, bei String-Typen der Leer-String ('') und der „Nullwert“ bei Datums- und Uhrzeittypen. INSERT INTO ... SELECT-Anweisungen werden auf die gleiche Weise behandelt wie Einfügeoperationen für mehrere Datensätze, weil der Server die Ergebnismenge von SELECT nicht darauf überprüft, ob genau ein Datensatz zurückgegeben wird. (Bei INSERT-Anweisungen für nur einen Datensatz erscheint keine Warnung, wenn NULL in eine NOT NULL-Spalte eingefügt wird. Stattdessen schlägt die Anweisung mit einem Fehler fehl.)

  • Setzen einer numerischen Spalte auf einen Wert außerhalb des zulässigen Wertebereichs. Der Wert wird auf den nächstgelegenen Endpunkt des Bereichs gesetzt.

  • Zuweisen eines Werts wie '10.34 a' zu einer numerischen Spalte. Der nichtnumerische Text am Ende wird entfernt, und der verbleibende numerische Teil wird eingefügt. Hat der String-Wert am Anfang keinen numerischen Teil, dann wird die Spalte auf 0 gesetzt.

  • Einfügen eines Strings in eine String-Spalte (CHAR, VARCHAR, TEXT oder BLOB), die die maximale Länge der Spalte überschreitet. Der Wert wird auf die zulässige Maximallänge der Spalte gekürzt.

  • Einfügen eines Werts in eine Spalte für Datum oder Uhrzeit, der für diesen Datentyp nicht zulässig ist. Die Spalte wird auf den passenden Nullwert des Typs gesetzt.

Wenn Sie die C-API verwenden, kann der Informations-String durch Aufruf der Funktion mysql_info() ermittelt werden. Siehe auch Abschnitt 24.2.3.34, „mysql_info().

Wenn INSERT einen Datensatz in eine Tabelle einfügt, die eine AUTO_INCREMENT-Spalte enthält, dann können Sie den Wert dieser Spalte mithilfe der SQL-Funktion LAST_INSERT_ID() abfragen. Aus der C-API heraus verwenden Sie die Funktion mysql_insert_id(). Sie sollten allerdings beachten, dass die beiden Funktionen sich nicht immer identisch verhalten. Das Verhalten von INSERT-Anweisungen in Bezug auf AUTO_INCREMENT-Spalten wird in Abschnitt 12.10.3, „Informationsfunktionen“, und Abschnitt 24.2.3.36, „mysql_insert_id(), ausführlicher beschrieben.

Die INSERT-Anweisung unterstützt die folgenden Modifizierer:

  • Wenn Sie das Schlüsselwort DELAYED verwenden, legt der Server den oder die einzufügenden Datensätze in einem Puffer ab, und der Client, der die INSERT DELAYED-Anweisung abgesetzt hat, kann sofort weiterarbeiten. Wird die Tabelle gerade verwendet, dann hält der Server die Datensätze zurück. Sobald die Tabelle frei ist, startet der Server mit dem Einfügen der Datensätze und prüft dabei periodisch, ob neue Leseanforderungen für die Tabelle anstehen. In diesem Fall wird die Warteschlange mit den verzögerten Datensätzen angehalten, bis die Tabelle wieder frei wird. Siehe auch Abschnitt 13.2.4.2, „INSERT DELAYED.

    DELAYED wird bei INSERT ... SELECT oder INSERT ... ON DUPLICATE KEY UPDATE ignoriert.

  • Wenn Sie das Schlüsselwort LOW_PRIORITY angeben, wird die Ausführung von INSERT verzögert, bis kein Client mehr aus der Tabelle liest. Dies schließt andere Clients mit ein, die Leseoperationen starten, während bereits vorhandene Clients aus der Tabelle lesen und die INSERT LOW_PRIORITY-Anweisung wartet. Aus diesem Grund ist es möglich, dass ein Client, der eine INSERT LOW_PRIORITY-Anweisung absetzt, sehr lange warten muss – in Umgebungen mit extrem hohen Aufkommen von Leseoperationen sogar für immer. (Dies steht im Gegensatz zu INSERT DELAYED, wo der Client direkt fortfahren kann.) Beachten Sie, dass LOW_PRIORITY normalerweise nicht bei MyISAM-Tabellen benutzt werden sollte, da auf diese Weise gleichzeitige Einfügeoperationen unmöglich gemacht werden. Siehe auch Abschnitt 7.3.3, „Gleichzeitige Einfügevorgänge“.

  • Wenn Sie HIGH_PRIORITY angeben, setzt es die Auswirkungen der Option --low-priority-updates außer Kraft, sofern der Server mit dieser Option gestartet worden war. Außerdem sind auch hier gleichzeitige Einfügeoperationen nicht möglich.

  • Wenn Sie das Schlüsselwort IGNORE angeben, werden Fehler, die während der Ausführung der INSERT-Anweisung auftreten, als Warnungen behandelt. So würde beispielsweise ohne IGNORE ein Datensatz, der einen vorhandenen eindeutigen Index oder einen Primärschlüsselwert in der Tabelle dupliziert, einen Dublettenfehler verursachen, woraufhin die Anweisung abgebrochen würde. Bei IGNORE wird der Datensatz zwar auch nicht eingefügt, aber es wird kein Fehler ausgegeben. Bei Fehler auslösenden Datenkonvertierungen wird die Anweisung abgebrochen, wenn IGNORE nicht angegeben ist. Bei IGNORE hingegen werden ungültige Werte auf den jeweils nächstgelegenen gültigen Wert gesetzt und dann einfügt; außerdem werden Warnungen erzeugt, aber die Anweisung wird nicht abgebrochen. Mit der C-API-Funktion mysql_info() können Sie ermitteln, wie viele Datensätze tatsächlich in die Tabelle eingefügt wurden.

  • Wenn Sie ON DUPLICATE KEY UPDATE angeben und ein Datensatz eingefügt wird, der einen doppelten Wert in einem eindeutigen Index oder einem Primärschlüssel erzeugen würde, dann wird für den alten Datensatz UPDATE ausgeführt. Siehe auch Abschnitt 13.2.4.3, „INSERT ... ON DUPLICATE KEY UPDATE.

13.2.4.1. INSERT ... SELECT

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

Mit INSERT ... SELECT können Sie schnell mehrere Datensätze aus einer oder mehreren Tabellen in eine Tabelle einfügen. Zum Beispiel:

INSERT INTO tbl_temp2 (fld_id)
  SELECT tbl_temp1.fld_order_id
  FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

Die folgenden Bedingungen gelten für eine INSERT ... SELECT-Anweisung:

  • Geben Sie IGNORE an, um Datensätze zu ignorieren, die unzulässige Schlüsseldubletten erzeugen würden.

  • DELAYED wird bei INSERT ... SELECT ignoriert.

  • Die Zieltabelle der INSERT-Anweisung kann in der FROM-Klausel des SELECT-Teils der Abfrage erscheinen. (Dies war bei einigen älteren MySQL-Versionen nicht möglich.)

  • AUTO_INCREMENT-Spalten arbeiten wie gewöhnlich.

  • Um sicherzustellen, dass das Binärlog zur Wiederherstellung der Originaltabellen verwendet werden kann, gestattet MySQL keine nebenläufigen Einfügeoperationen während der Ausführung einer INSERT ... SELECT-Anweisung.

  • Zurzeit können Sie in einer Unterabfrage keine Einfügeoperation in eine Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

Im Werteteil von ON DUPLICATE KEY UPDATE können Sie Spalten in anderen Tabellen referenzieren, solange Sie im SELECT-Teil nicht GROUP BY verwenden. Eine Begleiterscheinung besteht darin, dass Sie nichteindeutige Spaltennamen im Werteteil qualifizieren müssen.

13.2.4.2. INSERT DELAYED

INSERT DELAYED ...

Die Option DELAYED für die INSERT-Anweisung ist eine MySQL-Erweiterung zum SQL-Standard, die sehr praktisch ist, wenn Sie Clients haben, die nicht auf den Abschluss der INSERT-Anweisung warten können oder müssen. Eine solche Situation liegt häufig vor, wenn Sie MySQL zum Loggen verwenden und zudem regelmäßig SELECT- und UPDATE-Anweisungen ausführen, deren Fertigstellung sehr lange dauert.

Wenn ein Client INSERT DELAYED verwendet, wird diese Anweisung vom Server sofort angenommen und der Datensatz in einer Warteschlange abgelegt. Sobald die Tabelle von keinem anderen Thread mehr verwendet wird, wird der Datensatz dann aus der Warteschlange eingefügt.

Ein weiterer wesentlicher Vorteil von INSERT DELAYED besteht darin, dass Einfügeoperationen mehrerer Clients gebündelt und dann in einem Block geschrieben werden. Dies ist bedeutend schneller als die Durchführung vieler separater Einfügeoperationen.

Beachten Sie, dass INSERT DELAYED, sofern die Tabelle gerade nicht anderweitig verwendet wird, langsamer als eine normale INSERT-Anweisung ist. Auch liegt die Serverbelastung etwas höher, weil der Server für jede Tabelle, für die verzögerte Datensätze vorhanden sind, einen separaten Thread verwalten muss. Insofern sollten Sie INSERT DELAYED nur verwenden, wenn Sie wirklich sicher sind, dass Sie die Funktionalität benötigen.

Die Datensätze in der Warteschlange verbleiben nur solange im Speicher, bis sie in die Tabelle eingefügt wurden. Aufgrund dessen gehen, wenn Sie mysqld – etwa mit kill -9 – terminieren oder mysqld unerwartet abstürzt, alle Datensätze in der Warteschlange, die noch nicht auf Festplatte geschrieben wurden, verloren!

Für die Verwendung von DELAYED gelten einige Einschränkungen:

  • INSERT DELAYED funktioniert nur bei MyISAM-, MEMORY- und ARCHIVE-Tabellen. Siehe auch Abschnitt 14.1, „Die MyISAM-Speicher-Engine“, Abschnitt 14.4, „Die MEMORY-Speicher-Engine“ und Abschnitt 14.8, „Die ARCHIVE-Speicher-Engine“.

    Bei MyISAM-Tabellen werden, wenn keine freien Blöcke in der Mitte der Datendatei vorhanden sind, gleichzeitige SELECT- und INSERT-Anweisung unterstützt. Unter diesen Umständen müssen Sie INSERT DELAYED bei MyISAM nur in sehr seltenen Fällen verwenden.

  • INSERT DELAYED sollte nur für INSERT-Anweisungen eingesetzt werden, die Wertelisten angeben. Bei INSERT DELAYED ... SELECT-Anweisungen ignoriert der Server das DELAYED.

  • Ebenso ignoriert der Server das DELAYED bei INSERT ... SELECT- oder INSERT ... ON DUPLICATE KEY UPDATE-Anweisungen.

  • Weil die INSERT DELAYED-Anweisung aus Clientsicht abgeschlossen wird, bevor die Datensätze tatsächlich eingefügt werden, können Sie den von der Anweisung erstellten AUTO_INCREMENT-Wert nicht mit LAST_INSERT_ID() abrufen.

  • Verzögerte Datensätze werden für SELECT-Anweisungen erst sichtbar, wenn sie tatsächlich eingefügt wurden.

  • DELAYED wird auf Slave-Replikationsservern ignoriert, weil andernfalls auf dem Slave andere Daten vorhanden sein könnten als auf dem Master.

Nachfolgend wird ausführlich beschrieben, was geschieht, wenn Sie die Option DELAYED für INSERT oder REPLACE einsetzen. In dieser Beschreibung ist „Thread“ der Thread, der eine INSERT DELAYED-Anweisung empfangen hat, und „Handler“ der Thread, der alle INSERT DELAYED-Anweisungen der betreffenden Tabelle verwaltet.

  • Wenn ein Thread eine DELAYED-Anweisung für eine Tabelle ausführt, wird – sofern nicht bereits vorhanden – ein Handler-Thread erzeugt, um alle DELAYED-Anweisungen für die Tabelle zu verarbeiten.

  • Der Thread überprüft, ob der Handler zuvor bereits eine DELAYED-Sperre erwirkt hat, und weist den Handler andernfalls dazu an. Die DELAYED-Sperre kann auch dann erwirkt werden, wenn andere Threads eine READ- oder WRITE-Sperre für die Tabelle halten. Allerdings wartet der Handler, bis alle ALTER TABLE-Sperren aufgehoben und FLUSH TABLES-Anweisungen abgeschlossen sind, um zu gewährleisten, dass die Tabellenstruktur aktuell ist.

  • Der Thread führt die INSERT-Anweisung aus, schreibt den Datensatz aber nicht in die Tabelle, sondern setzt eine Kopie des endgültigen Datensatzes in eine Warteschlange, die vom Handler verwaltet wird. Syntaxfehler werden vom Thread bemerkt und an das Clientprogramm zurückgemeldet.

  • Der Client kann die Anzahl doppelter Datensätze oder den AUTO_INCREMENT-Wert des resultierenden Datensatzes nicht beim Server erfragen, weil die INSERT-Anweisung vor Durchführung der eigentlichen Einfügeoperation bereits abgeschlossen wird. (Wenn Sie die C-API verwenden, dann gibt die Funktion mysql_info() aus demselben Grund nur irrelevante Angaben zurück.)

  • Das Binärlog wird vom Handler-Thread aktualisiert, sobald der Datensatz in die Tabelle eingefügt wurde. Im Falle des Einfügens mehrerer Datensätze wird das Binärlog aktualisiert, wenn der erste Datensatz eingefügt wird.

  • Jedes Mal, wenn delayed_insert_limit Datensätze geschrieben wurden, überprüft der Handler, ob noch weitere SELECT-Anweisungen anhängig sind. Ist dies der Fall, so gestattet er deren Ausführung, bevor er fortfährt.

  • Wenn der Handler keine Datensätze mehr in der Warteschlange hat, wird die Tabelle entsperrt. Werden innerhalb des durch delayed_insert_timeout (in Sekunden) angegebenen Zeitraums keine neuen INSERT DELAYED-Anweisungen empfangen, dann wird der Handler beendet.

  • Sind mehr als delayed_queue_size Datensätze in einer bestimmten Handler-Warteschlange anhängig, dann fordert der Thread INSERT DELAYED auf, zu warten, bis wieder Platz in der Warteschlange ist. Hierdurch soll gewährleistet werden, dass mysqld nicht den gesamten Speicher für die Warteschlange mit den verzögerten Datensätzen verwendet.

  • Der Handler-Thread erscheint in der MySQL-Prozessliste als delayed_insert in der Spalte Command. Er wird terminiert, wenn Sie eine FLUSH TABLES-Anweisung absetzen oder KILL thread_id ausführen. Allerdings speichert er vor der Terminierung alle in der Warteschlange vorhandenen Datensätze in die Tabelle, bevor er beendet wird. In diesem Zeitraum werden keine neuen INSERT-Anweisungen anderer Threads angenommen. Wenn Sie nachfolgend eine INSERT DELAYED-Anweisung ausführen, wird ein neuer Handler-Thread erstellt.

    Beachten Sie, dass dies bedeutet, dass INSERT DELAYED-Anweisungen Vorrang vor normalen INSERT-Anweisungen haben, wenn ein INSERT DELAYED-Handler ausgeführt wird. Andere Änderungsanweisungen müssen warten, bis die INSERT DELAYED-Warteschlange leer ist oder jemand den Handler-Thread (mit KILL thread_id) terminiert oder eine FLUSH TABLES-Anweisung ausführt.

  • Die folgenden Statusvariablen machen Angaben zu INSERT DELAYED-Anweisungen:

    StatusvariableBedeutung
    Delayed_insert_threadsAnzahl der Handler-Threads
    Delayed_writesAnzahl der mit INSERT DELAYED geschriebenen Datensätze
    Not_flushed_delayed_rowsAnzahl der Datensätze, die noch geschrieben werden müssen

    Sie können diese Variablen anzeigen, indem Sie eine SHOW STATUS-Anweisung absetzen oder den Befehl mysqladmin extended-status ausführen.

13.2.4.3. INSERT ... ON DUPLICATE KEY UPDATE

Wenn Sie ON DUPLICATE KEY UPDATE angeben und ein Datensatz eingefügt wird, der einen doppelten Wert in einem eindeutigen Index oder einem Primärschlüssel erzeugen würde, dann wird für den alten Datensatz UPDATE ausgeführt. Angenommen, die Spalte a wird als UNIQUE deklariert und enthält den Wert 1; in diesem Fall hätten die beiden folgenden Anweisungen dieselbe Wirkung:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=c+1;

UPDATE table SET c=c+1 WHERE a=1;

Der Wert der betroffenen Datensätze ist 1, wenn der Datensatz als neuer Datensatz eingefügt wird, und 2, wenn ein vorhandener Eintrag aktualisiert wird.

Wenn die Spalte b ebenfalls eindeutig ist, ist die INSERT-Anweisung stattdessen gleichbedeutend mit der folgenden UPDATE-Anweisung:

UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

Wenn a=1 OR b=2 mehreren Datensätzen entspricht, wird nur ein Datensatz aktualisiert. Generell sollten Sie von der Verwendung einer ON DUPLICATE KEY-Klausel bei Tabellen mit mehreren eindeutigen Indizes absehen.

Sie können die Funktion VALUES(col_name) in der UPDATE-Klausel verwenden, um Spaltenwerte aus dem INSERT-Teil der INSERT ... UPDATE-Anweisung zu referenzieren. Anders gesagt, verweist VALUES(col_name) in der UPDATE-Klausel auf den Wert von col_name, der eingefügt worden wäre, wäre nicht ein Konflikt aufgrund einer Schlüsseldublette aufgetreten. Diese Funktion ist insbesondere bei Einfügevorgängen für mehrere Datensätze praktisch. Die Funktion VALUES() ist nur in INSERT ... UPDATE-Anweisungen sinnvoll zu verwenden; andernfalls gibt sie NULL zurück. Beispiel:

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
  ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

Diese Anweisung ist identisch mit den folgenden beiden Anweisungen:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=3;
INSERT INTO table (a,b,c) VALUES (4,5,6)
  ON DUPLICATE KEY UPDATE c=9;

Die Option DELAYED wird ignoriert, wenn Sie ON DUPLICATE KEY UPDATE verwenden.

13.2.5. LOAD DATA INFILE

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
    [REPLACE | IGNORE]
    INTO TABLE tbl_name
    [FIELDS
        [TERMINATED BY 'string']
        [[OPTIONALLY] ENCLOSED BY 'char']
        [ESCAPED BY 'char']
    ]
    [LINES
        [STARTING BY 'string']
        [TERMINATED BY 'string']
    ]
    [IGNORE number LINES]
    [(col_name_or_user_var,...)]
    [SET col_name = expr,...)]

Die Anweisung LOAD DATA INFILE liest Datensätze mit extrem hoher Geschwindigkeit aus einer Textdatei in eine Tabelle ein. Der Dateiname muss als literaler String übergeben werden.

Die Syntax für die FIELDS- und LINES-Klauseln gilt auch für die SELECT ... INTO OUTFILE-Anweisung, die im weiteren Verlauf dieses Abschnitts beschrieben wird. (Siehe auch Abschnitt 13.2.7, „SELECT.)

Weitere Informationen zur Effektivität von INSERT im Vergleich zu LOAD DATA INFILE und zur Beschleunigung von LOAD DATA INFILE finden Sie in Abschnitt 7.2.16, „Geschwindigkeit von INSERT-Anweisungen“.

Der von der Systemvariablen character_set_database angegebene Zeichensatz wird zur Interpretation der Daten in der Datei verwendet. SET NAMES und die Einstellung von character_set_client wirken sich hingegen nicht auf die Interpretation der Eingabe aus.

Beachten Sie, dass es derzeit nicht möglich ist, Datendateien zu laden, die den Zeichensatz ucs2 verwenden.

Sie können Datendateien auch mithilfe des Hilfsprogramms mysqlimport laden; dieses sendet dann eine LOAD DATA INFILE-Anweisung an den Server. Die Option --local bewirkt, dass mysqlimport Datendateien vom Clienthost liest. Sie können die Option --compress angeben, um bei langsamen Netzwerken eine bessere Leistung zu erzielen, sofern Client und Server das Komprimierungsprotokoll unterstützen. Siehe auch Abschnitt 8.12, „mysqlimport — Programm zum Datenimport“.

Wenn Sie das Schlüsselwort LOW_PRIORITY angeben, wird die Ausführung von LOAD DATA verzögert, bis kein Client mehr aus der Tabelle liest.

Geben Sie CONCURRENT bei einer MyISAM-Tabelle an, die die Bedingungen für gleichzeitige Einfügeoperationen erfüllt (d. h. keine freien Blöcke in der Mitte enthält), dann können andere Threads Daten aus der Tabelle abrufen, während LOAD DATA ausgeführt wird. Die Verwendung dieser Option beeinflusst die Leistungsfähigkeit von LOAD DATA auch dann geringfügig, wenn gleichzeitig kein anderer Thread die Tabelle verwendet.

Das Schlüsselwort LOCAL wird, sofern angegeben, in Bezug auf die Clientseite der Verbindung interpretiert:

  • Wenn LOCAL angegeben ist, wird die Datei vom Clientprogramm auf dem Clienthost gelesen und an den Server geschickt. Die Datei kann als vollständiger Pfadname angegeben werden, um die exakte Position zu beschreiben. Erfolgt die Angabe als relativer Pfadname, dann wird der Name relativ zum Verzeichnis interpretiert, in dem das Clientprogramm gestartet wurde.

  • Wird LOCAL nicht angegeben, dann muss die Datei sich auf dem Serverhost befinden und wird direkt vom Server gelesen. Der Server wendet zur Bestimmung der Dateiposition die folgenden Regeln an:

    • Wenn der Dateiname absolut angegeben wurde, verwendet ihn der Server wie angegeben.

    • Ist der Dateiname ein relativer Pfadname mit einer oder mehreren am Anfang stehenden Komponenten, dann sucht der Server nach der Datei relativ zum eigenen Datenverzeichnis.

    • Wird ein Dateiname ohne Komponenten am Anfang übergeben, dann sucht der Server im Datenbankverzeichnis der Standarddatenbank nach der Datei.

Beachten Sie, dass, sofern keine LOCAL-Option angegeben wurde, die Regeln zur Folge haben, dass eine Datei namens ./myfile.txt im Datenverzeichnis des Servers gesucht wird, während die Datei myfile.txt aus dem Datenbankverzeichnis der Standarddatenbank gelesen wird. Ist also beispielsweise db1 die Standarddatenbank, dann liest die folgende LOAD DATA-Anweisung die Datei data.txt aus dem Datenbankverzeichnis für db1 aus, obwohl die Anweisung die Datei explizit in die Datenbank db2 lädt:

LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;

Windows-Pfadnamen müssen unter Verwendung von Schrägstrichen (statt Backslashs) angegeben werden. Wenn Sie Backslashs (umgekehrte Schrägstriche) verwenden, müssen Sie sie doppelt angeben.

Aus Sicherheitsgründen müssen Textdateien, die auf dem Server ausgelesen werden, entweder im Datenbankverzeichnis liegen oder von allen gelesen werden können. Außerdem benötigen Sie zur Verwendung von LOAD DATA INFILE für Serverdateien die Berechtigung FILE. Siehe auch Abschnitt 5.8.3, „Von MySQL zur Verfügung gestellte Berechtigungen“.

Die Verwendung von LOCAL ist ein wenig langsamer als der Direktzugriff des Servers auf die Dateien, weil der Inhalt der Datei vom Client über die Verbindung an den Server gesendet werden muss. Die Berechtigung FILE benötigen Sie hingegen zum Laden lokaler Dateien nicht.

Die Option LOCAL funktioniert nur, wenn ihre Verwendung sowohl am Client als auch am Server aktiviert wurde. Wenn beispielsweise mysqld mit --local-infile=0 gestartet wurde, funktioniert LOCAL nicht. Siehe auch Abschnitt 5.7.4, „Sicherheitsprobleme mit LOAD DATA LOCAL.

Unter Unix können Sie, wenn LOAD DATA über eine Pipe lesen soll, die folgende Methode verwenden (hierbei laden wir das Listing des Verzeichnisses / in eine Tabelle):

mkfifo /mysql/db/x/x
chmod 666 /mysql/db/x/x
find / -ls > /mysql/db/x/x
mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x

Die Schlüsselwörter REPLACE und IGNORE steuern den Umgang mit eingegebenen Datensätzen, die Duplikate vorhandener Datensätze mit eindeutigen Schlüsselwerten darstellen.

Wenn Sie REPLACE angeben, ersetzt die Eingabe vorhandene Datensätze. Dies betrifft Datensätze, die denselben Wert bei einem Primärschlüssel oder einem eindeutigen Index wie die neuen Datensätze haben. Siehe auch Abschnitt 13.2.6, „REPLACE.

Bei Angabe von IGNORE hingegen werden neue Datensätze, deren eindeutiger Schlüsselwert bereits einem vorhandenen Datensatz zugewiesen ist, ignoriert. Wenn Sie keine Option angeben, hängt das Verhalten davon ab, ob das Schlüsselwort LOCAL angegeben wird. Ohne LOCAL tritt ein Fehler auf, wenn ein doppelter Schlüsselwert gefunden wird; in diesem Fall wird der Rest der Textdatei ignoriert. Mit LOCAL ist das Standardverhalten so, als ob IGNORE angegeben worden wäre. Das liegt daran, dass der Server keine Möglichkeit hat, die Übertragung der Datei während des Vorgangs zu beenden.

Wenn Sie Fremdschlüssel-Constraints während des Ladevorgangs ignorieren wollen, können Sie eine SET FOREIGN_KEY_CHECKS=0-Anweisung vor der Ausführung von LOAD DATA absetzen.

Wenn Sie LOAD DATA INFILE auf eine leere MyISAM-Tabelle anwenden, werden alle nichteindeutigen Indizes in einer separaten Stapeloperation erstellt (wie bei REPAIR TABLE). Dies sollte LOAD DATA INFILE erheblich beschleunigen, wenn Sie viele Indizes haben. In einigen Extremfällen können Sie die Indizes noch schneller erstellen, indem Sie sie vor dem Einladen der Datei in die Tabelle mit ALTER TABLE ... DISABLE KEYS abschalten und sie nach Abschluss des Ladevorgangs mit ALTER TABLE ... ENABLE KEYS neu erstellen. Siehe auch Abschnitt 7.2.16, „Geschwindigkeit von INSERT-Anweisungen“.

LOAD DATA INFILE ist das Gegenstück zu SELECT ... INTO OUTFILE. (Siehe auch Abschnitt 13.2.7, „SELECT.) Um Daten aus einer Tabelle in eine Datei zu schreiben, benutzen Sie SELECT ... INTO OUTFILE; wollen Sie die Datei wieder in eine Tabelle einlesen, dann verwenden Sie LOAD DATA INFILE. Die Syntax der Klauseln FIELDS und LINES ist bei beiden Anweisungen dieselbe. Beide sind optional, aber FIELDS muss LINES vorangehen, sofern beide angegeben sind.

Wenn Sie eine FIELDS-Klausel festlegen, ist auch jede einzelne Unterklausel (TERMINATED BY, [OPTIONALLY] ENCLOSED BY und ESCAPED BY) ebenfalls optional – Sie müssen lediglich mindestens eine dieser Unterklauseln angeben.

Wenn Sie keine FIELDS-Klausel angeben, entsprechen die Vorgabeeinstellungen dem Folgenden:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'

Wenn Sie keine LINES-Klausel angeben, entsprechen die Vorgabeeinstellungen dem Folgenden:

LINES TERMINATED BY '\n' STARTING BY ''

Anders gesagt, die Standardwerte bewirken, dass LOAD DATA INFILE sich beim Einlesen wie folgt verhält:

  • Es wird nach Zeilenbegrenzungen bei Zeilenumbrüchen gesucht.

  • Zeilenpräfixe werden nicht übersprungen.

  • Zeilen werden bei Tabulatoren in Felder unterteilt.

  • Felder müssen nicht innerhalb von Anführungszeichen abgeschlossen werden.

  • Fälle von Tabulatoren, Zeilenumbrüchen oder ‘\’, denen ‘\’ vorangeht, werden als literale Zeichen interpretiert, die Teile von Feldwerten sind.

Umgekehrt bewirken die Voreinstellungen, dass sich SELECT ... INTO OUTFILE beim Schreiben einer Ausgabe wie folgt verhält:

  • Tabulatoren werden zwischen Felder gesetzt.

  • Mehrere Felder werden nicht zwischen Anführungszeichen gesetzt.

  • \’ wird zur Kennzeichnung von Tabulatoren, Zeilenumbrüchen und ‘\’ verwendet, die innerhalb von Feldwerten auftreten.

  • Am Ende von Zeilen werden Zeilenumbrüche geschrieben.

Der Backslash wird bei MySQL als Escape-Zeichen in Strings verwendet. Insofern müssen Sie, um FIELDS ESCAPED BY '\\' zu schreiben, zwei Backslashes angeben, damit der Wert als ein Backslash interpretiert wird.

Hinweis: Wenn Sie die Textdatei auf einem Windows-System erzeugt haben, müssen Sie unter Umständen LINES TERMINATED BY '\r\n' verwenden, um die Datei korrekt einzulesen, weil Windows-Programme normalerweise zwei Zeichen als Zeilenendzeichen verwenden. Einige Programme wie WordPad verwenden beim Schreiben von Dateien unter Umständen sogar \r als Zeilenendzeichen. Um solche Dateien zu lesen, verwenden Sie LINES TERMINATED BY '\r'.

Wenn alle Zeilen, die Sie einlesen wollen, ein gemeinsames Präfix aufweisen, das Sie ignorieren wollen, können Sie mit LINES STARTING BY 'prefix_string' das Präfix und alles, was davor steht, überspringen. Enthält eine Zeile das Präfix gar nicht, dann wird die gesamte Zeile übersprungen. Nehmen wir an, dass Sie folgende Anweisung absetzen:

LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test
  FIELDS TERMINATED BY ','  LINES STARTING BY 'xxx';

Nehmen wir ferner an, dass die Datendatei wie folgt aussieht:

xxx"abc",1
something xxx"def",2
"ghi",3

In diesem Fall werden als Ergebnis die Datensätze ("abc",1) und ("def",2) erzeugt. Der dritte Datensatz in der Datei wird übersprungen, weil er das Präfix nicht enthält.

Die Option IGNORE number LINES kann verwendet werden, um Zeilen am Anfang der Datei zu ignorieren. So können Sie etwa IGNORE 1 LINES angeben, um eine Kopfzeile zu überspringen, die etwa die Spaltennamen enthält:

LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test IGNORE 1 LINES;

Wenn Sie SELECT ... INTO OUTFILE gemeinsam mit LOAD DATA INFILE verwenden, um Daten aus einer Datenbank in eine Datei zu schreiben und die Datei später wieder in die Datenbank einzulesen, dann müssen die Optionen der beiden Anweisungen zur Behandlung von Feldern und Zeilen einander entsprechen. Andernfalls kann LOAD DATA INFILE den Inhalt der Datei nicht korrekt einlesen. Angenommen, Sie schreiben mit SELECT ... INTO OUTFILE eine Datei mit Feldern, die kommagetrennt sind:

SELECT * INTO OUTFILE 'data.txt'
  FIELDS TERMINATED BY ','
  FROM table2;

Um diese kommagetrennte Datei wieder einzulesen, müssen Sie folgende Anweisung verwenden:

LOAD DATA INFILE 'data.txt' INTO TABLE table2
  FIELDS TERMINATED BY ',';

Haben Sie stattdessen probiert, die Datei mit der folgenden Anweisung einzulesen, dann ist dies nicht gelungen, da LOAD DATA INFILE angewiesen wird, nach Tabulatoren zwischen den Feldern zu suchen:

LOAD DATA INFILE 'data.txt' INTO TABLE table2
  FIELDS TERMINATED BY '\t';

Infolgedessen wird jede Eingabezeile wohl als separates Feld interpretiert werden.

Mit LOAD DATA INFILE können Sie Dateien lesen, die Sie aus externen Quellen erhalten haben. Beispielsweise exportieren viele Programme Daten als kommagetrennte Werte im so genannten CSV-Format (Comma-Separate Values). Hierbei werden die Felder durch Kommata voneinander getrennt und in doppelte Anführungszeichen gesetzt. Wenn Zeilen in einer solchen Datei durch Zeilenumbrüche abgeschlossen werden, veranschaulicht die folgende Anweisung die Optionen zur Feld- und Zeilenbehandlung, wie Sie sie zum Laden der Datei verwenden würden:

LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
  FIELDS TERMINATED BY ',' ENCLOSED BY '"'
  LINES TERMINATED BY '\n';

Alle Optionen zur Feld- und Zeilenbehandlung können einen Leer-String ('') angeben. Wenn der String nicht leer ist, müssen die Werte FIELDS [OPTIONALLY] ENCLOSED BY und FIELDS ESCAPED BY genau ein Zeichen umfassen. Die Werte FIELDS TERMINATED BY, LINES STARTING BY und LINES TERMINATED BY können hingegen auch mehrere Zeichen enthalten. Um etwa Zeilen zu schreiben, die jeweils aus einem aus einer Absatzschaltung und einem Zeilenvorschub bestehenden Zeichenpaar bestehen, geben Sie die Klausel LINES TERMINATED BY '\r\n' an.

Um eine Datei mit Witzen zu lesen, die durch aus %% bestehenden Zeilen getrennt sind, können Sie Folgendes tun:

CREATE TABLE jokes
  (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  joke TEXT NOT NULL);
LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes
  FIELDS TERMINATED BY ''
  LINES TERMINATED BY '\n%%\n' (joke);

FIELDS [OPTIONALLY] ENCLOSED BY steuert die Anführungszeichen um die Felder. Bei der Ausgabe (SELECT ... INTO OUTFILE) werden, wenn Sie das Wort OPTIONALLY weglassen, alle Felder vom durch ENCLOSED BY angegebenen Zeichen umschlossen. Hier ein Beispiel für eine solche Ausgabe (mit dem Komma als Feldtrennzeichen):

"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"

Wenn Sie OPTIONALLY angeben, wird das ENCLOSED BY-Zeichen nur zum Umschließen von Werten in Spalten verwendet, die einen String-Datentyp haben (z. B. CHAR, BINARY, TEXT oder ENUM):

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20

Beachten Sie, dass das Auftreten des ENCLOSED BY-Zeichens in einem Feldwert gekennzeichnet wird, indem man ihm das ESCAPED BY-Zeichen voranstellt. Ferner ist wichtig, dass es, wenn Sie einen leeren ESCAPED BY-Wert angeben, möglich ist, versehentlich eine Ausgabe zu erzeugen, die von LOAD DATA INFILE nicht korrekt eingelesen werden kann. Die obige Ausgabe beispielsweise würde wie folgt angezeigt werden, wenn das Escape-Zeichen leer wäre. Sie werden bemerken, dass das zweite Feld in der vierten Zeile ein auf das Anführungszeichen folgendes Komma enthält, welches das Feld abzuschließen scheint (was nicht zutrifft).

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20

Bei der Eingabe wird das ENCLOSED BY-Zeichen – sofern vorhanden – am Ende der jeweiligen Feldwerte entfernt. (Dies erfolgt unabhängig davon, ob OPTIONALLY angegeben ist oder nicht – OPTIONALLY hat keine Auswirkung auf die Eingabeinterpretation.) Instanzen des ENCLOSED BY-Zeichens, denen das ESCAPED BY-Zeichen vorangestellt ist, werden als Teil des aktuellen Feldwerts interpretiert.

Beginnt das Feld mit dem ENCLOSED BY-Zeichen, dann werden Instanzen dieses Zeichens nur dann als Feldtrennzeichen ausgewertet, wenn ihnen jeweils die TERMINATED BY-Sequenz für Feld oder Zeile folgt. Um Mehrdeutigkeiten zu vermeiden, können Fälle des ENCLOSED BY-Zeichens innerhalb eines Feldwerts verdoppelt werden; sie werden dann als einzelne Instanz des Zeichens ausgewertet. Wird also etwa ENCLOSED BY '"' angegeben, dann wird mit Anführungszeichen wie hier gezeigt verfahren:

"The ""BIG"" boss"  -> The "BIG" boss
The "BIG" boss      -> The "BIG" boss
The ""BIG"" boss    -> The ""BIG"" boss

FIELDS ESCAPED BY steuert, wie Sonderzeichen geschrieben oder gelesen werden. Wenn das FIELDS ESCAPED BY-Zeichen nicht leer ist, dann wird es bei der Ausgabe als Präfix für die folgenden Zeichen verwendet:

  • FIELDS ESCAPED BY-Zeichen

  • FIELDS [OPTIONALLY] ENCLOSED BY-Zeichen

  • das erste Zeichen der Werte FIELDS TERMINATED BY und LINES TERMINATED BY

  • ASCII 0 (eigentlich wird auf das Escape-Zeichen folgend ASCII ‘0’ und kein Nullwertbyte geschrieben)

Ist das FIELDS ESCAPED BY-Zeichen leer, dann werden keinerlei Zeichen gekennzeichnet und NULL wird als NULL (und nicht als \N) ausgegeben. Es ist wahrscheinlich nicht angeraten, ein leeres Escape-Zeichen anzugeben; dies gilt insbesondere dann, wenn Feldwerte in Ihren Daten eines der in der obigen Liste enthaltenen Zeichen enthalten.

Wenn das FIELDS ESCAPED BY-Zeichen nicht leer ist, werden Instanzen dieses Zeichens bei der Eingabe entfernt, und das nachfolgende Zeichen wird literal als Teil des Feldwerts verwendet. Ausnahmen sind die gekennzeichneten Zeichen ‘0’ oder ‘N’ (z. B. \0 oder \N, wenn das Escape-Zeichen ‘\’ ist). Diese Sequenzen werden als ASCII-NUL (Nullwertbyte) bzw. als NULL interpretiert. Die Regeln für den Umgang mit NULL werden im weiteren Verlauf dieses Abschnitts beschrieben.

Weitere Informationen zur ‘\’-Escape-Syntax finden Sie in Abschnitt 9.1, „Literale: wie Strings und Zahlen geschrieben werden“.

In bestimmten Fällen interagieren die Optionen zur Feld- und Zeilenbehandlung:

  • Wenn LINES TERMINATED BY ein Leer-String und FIELDS TERMINATED BY nicht leer ist, werden Zeilen auch mit FIELDS TERMINATED BY abgeschlossen.

  • Sind die Werte von FIELDS TERMINATED BY und FIELDS ENCLOSED BY beide leer (''), dann wird ein festes Datensatzformat (ohne Trennzeichen) verwendet. Bei einem solchen Format fehlt zwar das Trennzeichen, ein Zeilenabschlusszeichen kann aber nichtsdestoweniger vorhanden sein. Stattdessen werden Spaltenwerte unter Berücksichtigung der Anzeigebreiten der Spalten geschrieben und gelesen. Wird z. B. eine Spalte als INT(7) deklariert, dann werden Werte für diese Spalte unter Verwendung von Feldern mit einer Länge von sieben Zeichen geschrieben. Bei der Eingabe werden die Spaltenwerte dann ermittelt, indem sieben Zeichen ausgelesen werden.

    LINES TERMINATED BY wird nach wie vor zur Trennung von Zeilen verwendet. Wenn eine Zeile nicht alle Felder enthält, werden die verbleibenden Spalten auf ihre Vorgabewerte gesetzt. Wenn kein Zeilenabschlusszeichen vorhanden ist, sollten Sie dieses auf '' setzen. In diesem Fall muss die Textdatei alle Felder für jeden Datensatz enthalten.

    Das Festformat für Datensätze beeinflusst auch den Umgang mit NULL-Werten (siehe unten). Beachten Sie, dass dieses Format nicht funktioniert, wenn Sie einen Multibytezeichensatz verwenden.

Die Handhabung von NULL-Werten variiert entsprechend den verwendeten FIELDS- und LINES-Optionen:

  • Bei den FIELDS- und LINES-Standardwerten wird NULL als Feldwert \N in die Ausgabe geschrieben. Analog wird der Feldwert \N bei der Eingabe als NULL gelesen (vorausgesetzt, das ESCAPED BY-Zeichen ist ‘\’).

  • Wenn FIELDS ENCLOSED BY nicht leer ist, dann wird ein Feld, das das Wort NULL als Wert enthält, als NULL-Wert gelesen. Dies unterscheidet sich von dem Wort NULL, wenn es in FIELDS ENCLOSED BY-Zeichen gesetzt ist – dieses wird als 'NULL' gelesen.

  • Ist FIELDS ESCAPED BY leer, dann wird NULL als Wort NULL geschrieben.

  • Beim Festformat (welches verwendet wird, wenn FIELDS TERMINATED BY und FIELDS ENCLOSED BY beide leer sind), wird NULL als Leer-String geschrieben. Beachten Sie, dass dies zur Folge hat, dass NULL-Werte und Leer-Strings in der Tabelle nicht mehr unterschieden werden können, sobald sie in die Datei geschrieben werden, weil beide als Leer-Strings geschrieben werden. Müssen die beiden Werte nach dem Wiedereinlesen der Datei weiterhin unterscheidbar sein, dann sollten Sie das Festformat nicht verwenden.

Manche Fälle werden von LOAD DATA INFILE nicht unterstützt:

  • Datensätze fester Länge (FIELDS TERMINATED BY und FIELDS ENCLOSED BY sind leer) und BLOB- oder TEXT-Spalten.

  • Wenn Sie ein Trennzeichen angeben, das mit einem anderen Trennzeichen (oder dessen Präfix) identisch ist, kann LOAD DATA INFILE die Eingabe nicht korrekt interpretieren. Die folgende FIELDS-Klausel beispielsweise würde Probleme verursachen:

    FIELDS TERMINATED BY '"' ENCLOSED BY '"'
    
  • Wenn FIELDS ESCAPED BY leer ist, bewirkt ein Feldwert, der eine Instanz von FIELDS ENCLOSED BY oder LINES TERMINATED BY gefolgt vom FIELDS TERMINATED BY-Wert enthält, dass LOAD DATA INFILE das Einlesen eines Felds oder einer Zeile zu früh beendet. Dies geschieht, weil LOAD DATA INFILE nicht genau bestimmen kann, wo der Feld- oder Zeilenwert endet.

Das folgende Beispiel lädt alle Spalten der Tabelle persondata:

LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;

Standardmäßig wird, wenn keine Spaltenliste am Ende der LOAD DATA INFILE-Anweisung vorhanden ist, erwartet, dass Eingabezeilen ein Feld für jede Tabellenspalte enthalten. Wenn Sie nur einen Teil der Spalten einer Tabelle laden wollen, müssen Sie eine Spaltenliste angeben:

LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata (col1,col2,...);

Ferner müssen Sie eine Spaltenliste festlegen, wenn die Reihenfolge der Felder in der Eingabedatei sich von der Reihenfolge der Spalten in der Tabelle unterscheidet. Andernfalls kann MySQL nicht ermitteln, wie die Eingabefelder den Tabellenspalten zuzuordnen sind.

Die Spaltenliste kann entweder Spaltennamen oder Benutzervariablen enthalten. Bei Benutzervariablen gestattet Ihnen die SET-Klausel die Durchführung einer Werteumwandlung vor der Zuweisung des Ergebnisses zu den Spalten.

Benutzervariablen in der SET-Klausel können auf unterschiedliche Weise verwendet werden. Die folgenden Werte benutzen die erste Eingabespalte direkt für den Wert von t1.column1 und weisen die zweite Eingabespalte einer Benutzervariablen zu, an der eine Division durchgeführt wird, bevor sie als Wert für t1.column2 verwendet wird:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, @var1)
  SET column2 = @var1/100;

Die SET-Klausel kann zur Übermittlung von Werten benutzt werden, die nicht der Eingabedatei entnommen wurden. Die folgende Anweisung weist column3 das aktuelle Datum und die Uhrzeit zu:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, column2)
  SET column3 = CURRENT_TIMESTAMP;

Sie können einen Eingabewert auch verwerfen, indem Sie ihn einer Benutzervariablen zuweisen, der Variablen aber keine Tabellenspalte zuordnen:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, @dummy, column2, @dummy, column3);

Die Verwendung der Spalten-/Variablenliste und der SET-Klausel ist den folgenden Einschränkungen unterworfen:

  • Zuordnungen in der SET-Klausel sollten auf der linken Seite des Zuweisungsoperators nur Spaltennamen aufweisen.

  • Auf der rechten Seite einer SET-Zuordnung dürfen auch Unterabfragen zum Einsatz kommen. Eine Unterabfrage, die einen Wert zurückgibt, der einer Spalte zugeordnet werden soll, darf nur eine skalare Unterabfrage sein. Außerdem können Sie eine Unterabfrage nicht für Auswahlabfragen an die Tabelle verwenden, die gerade geladen wird.

  • Zeilen, die von einer IGNORE-Klausel ignoriert werden, werden für die Spalten-/Variablenliste oder die SET-Klausel nicht verarbeitet.

  • Benutzervariablen können nicht verwendet werden, wenn Daten mit Festformat geladen werden, da Benutzervariablen keine Anzeigebreite haben.

Wenn eine Eingabezeile verarbeitet wird, unterteilt LOAD DATA sie in Felder und verwendet die Werte entsprechend der Spalten-/Variablenliste und der SET-Klausel, sofern diese vorhanden sind. Der Ergebnisdatensatz wird dann in die Tabelle eingefügt. Sind BEFORE INSERT- oder AFTER INSERT-Trigger für die Tabelle vorhanden, so werden diese vor bzw. nach dem Einfügen des Datensatzes aktiviert.

Hat eine Eingabezeile zu viele Felder, dann werden die überzähligen Felder ignoriert und die Anzahl der Warnungen wird erhöht.

Hat eine Eingabezeile zu wenig Felder, dann werden die Tabellenspalten, deren Eingabefelder fehlen, auf ihre Standardwerte gesetzt. Die Zuweisung von Standardwerten ist in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben.

Ein leerer Feldwert wird anders interpretiert als ein fehlender Feldwert:

  • Bei String-Typen wird die Spalte auf den Leer-String gesetzt.

  • Bei numerischen Typen wird die Spalte auf 0 gesetzt.

  • Bei zeitbezogenen Typen wird die Spalte auf den passenden „Nullwert“ des Typs gesetzt. Siehe auch Abschnitt 11.3, „Datums- und Zeittypen“.

Dies sind dieselben Werte, die als Ergebnis ausgegeben werden, wenn Sie einem String, einem numerischen oder einem zeitbezogenen Wert in einer INSERT- oder UPDATE-Anweisung explizit den Leer-String zuweisen.

TIMESTAMP-Spalten werden nur dann auf die aktuellen Werte für Datum und Uhrzeit gesetzt, wenn ein NULL-Wert (d. h. \N) für die Spalte vorhanden ist oder der Standardwert der TIMESTAMP-Spalte der aktuelle Zeitstempel ist und in der Feldliste (sofern vorhanden) weggelassen wurde.

LOAD DATA INFILE betrachtet alle Eingaben als Strings, d. h., Sie können für ENUM- oder SET-Spalten numerische Werte nicht so eingeben wie von INSERT-Anweisungen her gewohnt. Alle ENUM- und SET-Werte müssen als Strings angegeben werden.

Wenn die LOAD DATA INFILE-Anweisung abgeschlossen ist, gibt sie einen Informations-String im folgenden Format zurück:

Records: 1  Deleted: 0  Skipped: 0  Warnings: 0

Wenn Sie die C-API verwenden, können Sie Informationen zur Anweisung durch einen Aufruf der Funktion mysql_info() ermitteln. Siehe auch Abschnitt 24.2.3.34, „mysql_info().

Warnungen treten unter denselben Umständen auf wie beim Einfügen von Werten mithilfe der INSERT-Anweisung (siehe Abschnitt 13.2.4, „INSERT); der einzige Unterschied besteht darin, dass LOAD DATA INFILE auch dann Warnungen erzeugt, wenn zu wenig oder zu viel Felder im Eingabedatensatz vorhanden sind. Die Warnungen werden nirgends gespeichert; Sie können ihrer Anzahl lediglich entnehmen, ob alles geklappt hat oder nicht.

Mit SHOW WARNINGS erhalten Sie eine Liste der ersten max_error_count Warnungen mit Informationen dazu, was unter Umständen nicht geklappt hat. Siehe auch Abschnitt 13.5.4.25, „SHOW WARNINGS.

13.2.6. REPLACE

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name [(col_name,...)]
    VALUES ({expr | DEFAULT},...),(...),...

Oder:

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...

Oder:

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...

REPLACE funktioniert auf exakt gleiche Weise wie INSERT. Der Unterschied besteht darin, dass, wenn ein alter Datensatz denselben Wert wie ein neuer Datensatz für einen Primärschlüssel oder einen eindeutigen Index hat, der alte Datensatz gelöscht wird, bevor der neue eingefügt wird. Siehe auch Abschnitt 13.2.4, „INSERT.

REPLACE ist eine MySQL-Erweiterung zum SQL-Standard. Es kann Datensätze einfügen, oder es kann Datensätze löschen und einfügen. Wenn Sie eine Anweisung suchen, die dem SQL-Standard entspricht und die entweder einfügt oder aktualisiert, dann benutzen Sie die INSERT ... ON DUPLICATE KEY UPDATE-Anweisung (siehe auch Abschnitt 13.2.4.3, „INSERT ... ON DUPLICATE KEY UPDATE).

Beachten Sie, dass, sofern die Tabelle nicht einen Primärschlüssel oder einen eindeutigen Index hat, die Verwendung von REPLACE unsinnig ist. Die Anweisung wäre dann mit INSERT identisch, weil kein Index vorhanden ist, anhand dessen bestimmt werden könnte, ob ein neuer Datensatz ein Duplikat eines bereits vorhandenen darstellt.

Werte für alle Spalten werden den Werten entnommen, die in der REPLACE-Anweisung angegeben sind. Fehlende Spalten werden – wie bei INSERT – auf ihre Standardwerte gesetzt. Es ist nicht möglich, Werte aus dem aktuellen Datensatz zu referenzieren und diese dann im neuen Datensatz zu verwenden. Wenn Sie eine Zuordnung wie SET col_name = col_name + 1 verwenden, wird die Referenzierung des Spaltennamens auf der rechten Seite wie DEFAULT(col_name) behandelt, d. h., die Zuordnung ist äquivalent zu SET col_name = DEFAULT(col_name) + 1.

Um REPLACE zu verwenden, benötigen Sie die Berechtigungen INSERT und DELETE für die Tabelle.

Die REPLACE-Anweisung gibt einen Wert zurück, der die Anzahl der betroffenen Datensätze angibt. Konkret ist dies die Summe der gelöschten und eingefügten Datensätze. Wenn der Wert bei einer REPLACE-Anweisung für einen Datensatz 1 beträgt, dann wurde ein Datensatz eingefügt und keiner gelöscht. Ist der Wert größer als 1, dann wurden ein oder mehrere alte Datensätze gelöscht, bevor der neue Datensatz eingefügt wurde. Ein einzelner Datensatz kann durchaus mehr als nur einen alten Datensatz ersetzen, sofern die Tabelle mehrere eindeutige Indizes hat und der neue Datensatz Werte verschiedener alter Datensätze in verschiedenen eindeutigen Indizes dupliziert.

Die Anzahl der betroffenen Datensätze erlaubt also die einfache Bestimmung, ob REPLACE nur einen Datensatz hinzugefügt hat oder ob auch Datensätze ersetzt wurden: Überprüfen Sie, ob der Wert 1 (Hinzufügung) oder größer ist (Ersetzung).

Wenn Sie die C-API verwenden, kann die Anzahl der betroffenen Datensätze durch die Funktion mysql_affected_rows() ermittelt werden.

Zurzeit können Sie in einer Unterabfrage keine Ersetzungsoperation in einer Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

MySQL verwendet für REPLACE (und LOAD DATA ... REPLACE) den folgenden Algorithmus:

  1. Es wird versucht, den neuen Datensatz in die Tabelle einzufügen.

  2. Wenn die Einfügeoperation aufgrund einer Schlüsseldublette in einem Primärschlüssel oder einem eindeutigen Index fehlschlägt,

    1. wird der konfliktauslösende Datensatz mit dem doppelten Schlüsselwert aus der Tabelle entfernt,

    2. wird erneut versucht, den neuen Datensatz in die Tabelle einzufügen.

13.2.7. SELECT

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr, ...
    [FROM table_references
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ...]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name' export_options
      | INTO DUMPFILE 'file_name']
    [FOR UPDATE | LOCK IN SHARE MODE]]

SELECT wird zum Abrufen von Datensätzen verwendet, die aus einer oder mehreren Tabellen ausgewählt wurden, und kann UNION-Anweisungen und Unterabfragen enthalten. Siehe auch Abschnitt 13.2.7.2, „UNION, und Abschnitt 13.2.8, „Syntax von Unterabfragen“.

Die meistverwendeten Klauseln für SELECT sind die folgenden:

  • Jede select_expr gibt eine Spalte an, die Sie abrufen wollen. Es muss mindestens ein select_expr vorhanden sein.

  • table_references gibt die Tabelle(n) an, aus der oder denen die Datensätze abgerufen werden sollen. Die Syntax ist in Abschnitt 13.2.7.1, „JOIN, beschrieben.

  • Die WHERE-Klausel gibt, soweit vorhanden, die Bedingung(en) an, die Datensätze erfüllen müssen, damit sie ausgewählt werden. where_condition ist ein Ausdruck, der für jeden auszuwählenden Datensatz wahr ist. Die Anweisung wählt, wenn keine WHERE-Klausel vorhanden ist, alle Datensätze aus.

    Sie können in der WHERE-Klausel alle von MySQL unterstützten Funktionen und Operatoren mit Ausnahme der Zusammenfassungsfunktionen einsetzen. Siehe auch Kapitel 12, Funktionen für die Benutzung in SELECT- und WHERE-Klauseln.

SELECT kann auch verwendet werden, um Datensätze abzurufen, die ohne Referenzierung einer Tabelle berechnet wurden.

Zum Beispiel:

mysql> SELECT 1 + 1;
        -> 2

Sie können DUAL als Pseudotabellenname in Situationen angeben, in denen keine Tabellen referenziert werden:

mysql> SELECT 1 + 1 FROM DUAL;
        -> 2

DUAL ist ausschließlich zum Zweck der Kompatibilität mit anderen Datenbankservern vorhanden, die eine FROM-Klausel erfordern. MySQL benötigt keine solche Klausel, wenn keine Tabellen referenziert werden.

Generell müssen Klauseln in genau der Reihenfolge angegeben werden, die in der Syntaxbeschreibung erscheint. So muss etwa eine HAVING-Klausel hinter den GROUP BY-Klauseln und vor den ORDER BY-Klauseln stehen. Die einzige Ausnahme ist die INTO-Klausel, die entweder wie in der Syntaxbeschreibung gezeigt oder unmittelbar vor der FROM-Klausel stehen kann.

  • Einem Ausdruck select_expr lässt sich mit AS alias_name ein Alias zuweisen. Der Alias wird als Spaltenname des Ausdrucks benutzt und kann in GROUP BY-, ORDER BY- oder HAVING-Klauseln verwendet werden. Zum Beispiel:

    SELECT CONCAT(last_name,', ',first_name) AS full_name
      FROM mytable ORDER BY full_name;
    

    Das Schlüsselwort AS ist beim Zuweisen eines Alias zu select_expr optional. Das obige Beispiel hätte auch wie folgt geschrieben sein können:

    SELECT CONCAT(last_name,', ',first_name) full_name
      FROM mytable ORDER BY full_name;
    

    Allerdings kann, weil AS optional ist, ein kleines Problem auftreten, wenn Sie das Komma zwischen zwei select_expr-Ausdrücken vergessen: MySQL interpretiert den zweiten Ausdruck als Aliasnamen. Sie wird etwa in der folgenden Anweisung columnb als Aliasname behandelt:

    SELECT columna columnb FROM mytable;
    

    Aus diesem Grund hat es sich bewährt, AS beim Festlegen von Spaltenaliasen immer explizit anzugeben.

  • Es ist nicht zulässig, einen Spaltenalias in einer WHERE-Klausel zu verwenden, weil der Spaltenwert unter Umständen nicht bestimmt werden kann, wenn die WHERE-Klausel ausgeführt wird. Siehe auch Abschnitt A.5.4, „Probleme mit alias.

  • Die Klausel FROM table_references gibt die Tabelle(n) an, aus der oder denen die Datensätze abgerufen werden sollen. Wenn Sie mehr als eine Tabelle angeben, führen Sie einen Join durch. Informationen zur Join-Syntax finden Sie in Abschnitt 13.2.7.1, „JOIN. Für jede angegebene Tabelle können Sie optional einen Alias angeben.

    tbl_name [[AS] alias]
        [{USE|IGNORE|FORCE} INDEX (key_list)]
    

    Wie Sie dem Optimierer mit USE INDEX, IGNORE INDEX und FORCE INDEX Hinweise zur Auswahl der Indizes geben, ist in Abschnitt 13.2.7.1, „JOIN, beschrieben.

    Sie können SET max_seeks_for_key=value als alternative Möglichkeit verwenden, um MySQL zur Verwendung von Schlüssel- statt Tabellenscans (sofern möglich) zu zwingen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

  • Sie können eine Tabelle in der Standarddatenbank als tbl_name oder – wenn Sie eine Datenbank ausdrücklich angeben wollen – als db_name.tbl_name referenzieren. Eine Spalte können Sie als col_name, tbl_name.col_name oder db_name.tbl_name.col_name referenzieren. Sie müssen das Präfix tbl_name oder db_name.tbl_name für eine Spaltenreferenzierung nicht angeben, sofern die Referenzierung eindeutig ist. Beispiele für Mehrdeutigkeiten, die die spezifischeren Formen der Spaltenreferenzierung erfordern, finden Sie in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“.

  • Für einen Tabellenverweis kann mit tbl_name AS alias_name oder tbl_name alias_name ein Alias erstellt werden:

    SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
      WHERE t1.name = t2.name;
    
    SELECT t1.name, t2.salary FROM employee t1, info t2
      WHERE t1.name = t2.name;
    
  • Spalten, die für die Ausgabe ausgewählt werden, lassen sich in ORDER BY- und GROUP BY-Klauseln als Spaltennamen, Spaltenaliase oder Spaltenpositionen referenzieren. Spaltenpositionen sind ganze Zahlen, die bei 1 beginnen:

    SELECT college, region, seed FROM tournament
      ORDER BY region, seed;
    
    SELECT college, region AS r, seed AS s FROM tournament
      ORDER BY r, s;
    
    SELECT college, region, seed FROM tournament
      ORDER BY 2, 3;
    

    Um in umgekehrter (absteigender) Reihenfolge zu sortieren, fügen Sie in der ORDER BY-Klausel das Schlüsselwort DESC zum Namen der Spalte zu, nach der die Sortierung erfolgt: Standardmäßig erfolgt die Sortierung aufsteigend. Dies kann mit dem Schlüsselwort ASC explizit festgelegt werden.

    Die Verwendung von Spaltenpositionen ist veraltet, weil die Syntax im SQL-Standard nicht mehr vorhanden ist.

  • Wenn Sie GROUP BY verwenden, werden die Ausgabedatensätze entsprechend den GROUP BY-Spalten sortiert, so als ob Sie eine ORDER BY-Klausel für dieselben Spalten angegeben hätten. Um eine Mehrbelastung durch das Sortieren mit GROUP BY zu vermeiden, fügen Sie ORDER BY NULL hinzu:

    SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
    
  • MySQL erweitert die GROUP BY-Klausel dahingehend, dass Sie ASC und DESC auch nach den in der Klausel benannten Spalten angeben können:

    SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;
    
  • MySQL erweitert die Verwendung von GROUP BY so, dass die Auswahl von Feldern möglich ist, die in der GROUP BY-Klausel nicht genannt sind. Wenn Sie bei einer Abfrage nicht die erwarteten Ergebnisse erhalten, lesen Sie bitte die Beschreibung von GROUP BY in Abschnitt 12.11, „Funktionen und Modifizierer für die Verwendung in GROUP BY-Klauseln“.

  • GROUP BY unterstützt den Modifizierer WITH ROLLUP. Siehe auch Abschnitt 12.11.2, „GROUP BY-Modifizierer“.

  • Die HAVING-Klausel wird fast als Letztes angewandt – unmittelbar bevor die Elemente an den Client gesendet werden, und ohne Optimierung. (Nur LIMIT wird noch nach HAVING angewandt.)

    Der SQL-Standard sieht vor, dass HAVING nur Spalten in der GROUP BY-Klausel oder solche Spalten referenzieren darf, die in Zusammenfassungsfunktionen verwendet werden. Allerdings unterstützt MySQL eine Erweiterung dieses Verhaltens und gestattet HAVING ferner die Referenzierung von Spalten in der SELECT-Liste und Spalten in äußeren Unterabfragen.

    Wenn die HAVING-Klausel eine Spalte referenziert, die mehrdeutig ist, erscheint eine Warnung. In der folgenden Anweisung ist col2 mehrdeutig, weil es sowohl als Alias als auch als Spaltenname verwendet wird:

    SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;
    

    Hier wird das SQL-Standardverhalten angewandt, d. h., wenn ein HAVING-Spaltenname sowohl in einer GROUP BY-Klausel als auch als Spaltenalias in der Liste der Ausgabespalten enthalten ist, hat die Spalte in der GROUP BY-Spalte Vorrang.

  • Verwenden Sie HAVING nicht für Elemente, die in der WHERE-Klausel aufgeführt sein sollten. So sollten Sie beispielsweise nicht Folgendes schreiben:

    SELECT col_name FROM tbl_name HAVING col_name > 0;
    

    Formulieren Sie stattdessen wie folgt:

    SELECT col_name FROM tbl_name WHERE col_name > 0;
    
  • Die HAVING-Klausel kann Zusammenfassungsfunktionen referenzieren, was der WHERE-Klausel nicht möglich ist:

    SELECT user, MAX(salary) FROM users
      GROUP BY user HAVING MAX(salary) > 10;
    

    (Dies funktionierte bei einigen älteren MySQL-Versionen nicht.)

  • Die LIMIT-Klausel kann zur Beschränkung der Anzahl der von der SELECT-Anweisung zurückgegebenen Datensätze verwendet werden. LIMIT nimmt ein oder zwei numerische Argumente entgegen, die (außer bei Verwendung vorbereiteter Anweisungen) beide nichtnegative Integer-Konstanten sein müssen.

    Von den beiden Argumenten gibt das erste den Versatz des ersten zurückzugebenden Datensatzes an, das zweite die maximale Anzahl zurückzugebender Datensätze. Der Versatz des ersten Datensatzes ist 0 (nicht 1):

    SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15
    

    Um alle Datensätze beginnend bei einem bestimmten Versatz bis zum Ende der Ergebnismenge zurückzugeben, können Sie als zweiten Parameter eine sehr große Zahl angeben. Die folgende Anweisung ruft alle Datensätze beginnend beim 96. bis zum letzten Datensatz ab:

    SELECT * FROM tbl LIMIT 95,18446744073709551615;
    

    Sofern nur ein Argument angegeben ist, gibt der Wert die Anzahl der Datensätze an, die beginnend beim ersten Datensatz zurückgegeben werden sollen:

    SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows
    

    Anders gesagt, ist LIMIT row_count äquivalent zu LIMIT 0, row_count.

    Bei vorbereiteten Anweisungen können Sie Platzhalter verwenden. Die folgende Anweisung gibt genau einen Datensatz aus der Tabelle tbl zurück:

    SET @a=1;
    PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?';
    EXECUTE STMT USING @a;
    

    Die folgenden Anweisungen geben den zweiten bis sechsten Datensatz aus der Tabelle tbl zurück:

    SET @skip=1; SET @numrows=5;
    PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?';
    EXECUTE STMT USING @skip, @numrows;
    

    Aus Gründen der Kompatibilität mit PostgreSQL unterstützt MySQL auch die Syntax LIMIT row_count OFFSET offset.

  • Die Form SELECT ... INTO OUTFILE 'file_name' der SELECT-Anweisung schreibt die ausgewählten Datensätze in eine Datei. Die Datei wird auf dem Serverhost erstellt, d. h., Sie benötigen die Berechtigung FILE, um die Syntax verwenden zu können. file_name darf keine vorhandene Datei sein, wodurch u. a. verhindert werden soll, dass Dateien wie /etc/passwd und Datenbanktabellen zerstört werden.

    Die Anweisung SELECT ... INTO OUTFILE ist in erster Linie dazu vorgesehen, eine Tabelle sehr schnell in eine Textdatei auf dem Server zu speichern. Wenn Sie die resultierende Datei auf einem Clienthost statt auf dem Serverhost erstellen wollen, dürfen Sie SELECT ... INTO OUTFILE nicht verwenden. In diesem Fall sollten Sie stattdessen einen Befehl wie mysql -e "SELECT ..." > file_name benutzen, um die Datei auf dem Clienthost anzulegen.

    SELECT ... INTO OUTFILE ist das Gegenstück zu LOAD DATA INFILE. Die Syntax für den export_options-Teil der Anweisung umfasst dieselben FIELDS- und LINES-Klauseln, die bei LOAD DATA INFILE benutzt werden. Siehe auch Abschnitt 13.2.5, „LOAD DATA INFILE.

    FIELDS ESCAPED BY steuert, wie Sonderzeichen geschrieben werden. Wenn das FIELDS ESCAPED BY-Zeichen nicht leer ist, dann wird es bei der Ausgabe als Präfix für die folgenden Zeichen verwendet:

    • FIELDS ESCAPED BY-Zeichen

    • FIELDS [OPTIONALLY] ENCLOSED BY-Zeichen

    • das erste Zeichen der Werte FIELDS TERMINATED BY und LINES TERMINATED BY

    • ASCII NUL (das Nullwertbyte; eigentlich wird auf das Escape-Zeichen folgend ASCII ‘0’ und kein Nullwertbyte geschrieben)

    Die FIELDS TERMINATED BY-, ENCLOSED BY-, ESCAPED BY- oder LINES TERMINATED BY-Zeichen müssen mit Escape-Zeichen gekennzeichnet werden, damit Sie die Datei zuverlässig wiedereinlesen können. ASCII NUL wird gekennzeichnet, um das Ablesen bei manchen Pagern zu vereinfachen.

    Die Ergebnisdatei muss nicht der SQL-Syntax entsprechen, weswegen weitere Zeichen nicht gekennzeichnet werden müssen.

    Ist das FIELDS ESCAPED BY-Zeichen leer, dann werden keinerlei Zeichen gekennzeichnet und NULL wird als NULL (und nicht als \N) ausgegeben. Es ist wahrscheinlich nicht angeraten, ein leeres Escape-Zeichen anzugeben; dies gilt insbesondere dann, wenn Feldwerte in Ihren Daten eines der in der obigen Liste enthaltenen Zeichen enthalten.

    Es folgt ein Beispiel, das eine Datei im CSV-Format erzeugt, welches von vielen Programmen verwendet wird:

    SELECT a,b,a+b INTO OUTFILE '/tmp/result.txt'
      FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
      LINES TERMINATED BY '\n'
      FROM test_table;
    
  • Wenn Sie INTO DUMPFILE statt INTO OUTFILE verwenden, schreibt MySQL nur einen Datensatz ohne Spalten- oder Zeilentrennzeichen und ohne Escape-Kennzeichnung in die Datei. Dies ist praktisch, wenn Sie einen BLOB-Wert in die Datei speichern wollen.

  • Hinweis: In Dateien, die durch INTO OUTFILE oder INTO DUMPFILE erstellt wurden, kann von allen Benutzern geschrieben werden. Grund hierfür ist die Tatsache, dass der MySQL Server keine Datei erstellen kann, deren Besitzer jemand anders als der Benutzer ist, unter dessen Konto der Server ausgeführt wird. (Sie sollten aus diesem und anderen Gründen mysqld niemals als root ausführen.) Die Datei muss von allen schreibbar sein, damit Sie ihren Inhalt modifizieren können.

  • Die Beschreibung der SELECT-Syntax am Anfang dieses Abschnitts zeigt die INTO-Klausel gegen Ende der Anweisung. INTO OUTFILE oder INTO DUMPFILE können auch unmittelbar auf die FROM-Klausel folgend angegeben werden.

  • Eine PROCEDURE-Klausel benennt eine Prozedur, die die Daten in der Ergebnismenge verarbeitet. Ein Beispiel finden Sie in Abschnitt 26.4.1, „PROCEDURE ANALYSE“.

  • Wenn Sie FOR UPDATE mit einer Speicher-Engine verwenden, die Seiten- oder Datensatzsperren verwendet, dann werden die von der Abfrage untersuchten Datensätze bis zum Ende der laufenden Transaktion schreibgesperrt. Mithilfe von LOCK IN SHARE MODE wird eine gemeinsame Sperre gesetzt, die anderen Transaktionen das Lesen, nicht jedoch das Ändern oder Löschen der untersuchten Datensätze gestattet. Siehe auch Abschnitt 14.2.10.5, „Lesevorgänge sperren“.

Sie können auf das Schlüsselwort SELECT folgend eine Reihe von Optionen angeben, die den Betrieb der Anweisung beeinflusst.

Die Optionen ALL, DISTINCT und DISTINCTROW geben an, ob doppelte Datensätze zurückgegeben werden sollen. Wird keine dieser Optionen angegeben, dann wird ALL als Vorgabe vorausgesetzt (d. h., alle passenden Datensätze werden zurückgegeben). DISTINCT und DISTINCTROW sind Synonyme; sie legen fest, dass doppelte Datensätze aus der Ergebnismenge entfernt werden.

HIGH_PRIORITY, STRAIGHT_JOIN und Optionen, die mit SQL_ beginnen, sind MySQL-Erweiterungen zum SQL-Standard.

  • HIGH_PRIORITY gibt SELECT Vorrang vor einer Anweisung, die eine Tabelle aktualisiert. Sie sollten die Option nur bei Abfragen verwenden, die sehr schnell sind und sofort erledigt werden müssen. Eine SELECT HIGH_PRIORITY-Anweisung, die abgesetzt wird, während die Tabelle zum Lesen gesperrt ist, wird auch ausgeführt, wenn eine Aktualisierungsanweisung darauf wartet, dass die Tabelle frei wird.

    HIGH_PRIORITY kann nicht bei SELECT-Anweisungen verwendet werden, die Teil einer Union sind.

  • STRAIGHT_JOIN zwingt den Optimierer zur Verknüpfung der Tabellen in der Reihenfolge, in der sie in der FROM-Klausel angegeben sind. Sie können hiermit eine Abfrage beschleunigen, wenn der Optimierer die Tabellen nicht optimal anordnet. Siehe auch Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“. STRAIGHT_JOIN kann auch in der table_references-Liste angegeben werden. Siehe auch Abschnitt 13.2.7.1, „JOIN.

  • SQL_BIG_RESULT kann mit GROUP BY oder DISTINCT verwendet werden. Sie teilen dem Optimierer hierdurch mit, dass die Ergebnismenge viele Datensätze enthält. In diesem Fall verwendet MySQL bei Bedarf direkt festplattenbasierte Temporärtabellen und zieht die Sortierung der Verwendung einer Temporärtabelle mit einem Schlüssel auf GROUP BY-Elemente vor.

  • SQL_BUFFER_RESULT erzwingt das Ablegen des Ergebnisses in einer Temporärtabelle. Auf diese Weise kann MySQL die Tabellensperren schnell wieder aufheben. Die Option ist zudem in Fällen hilfreich, in denen die Übermittlung des Ergebnisses an den Client sehr lange dauert.

  • SQL_SMALL_RESULT kann mit GROUP BY oder DISTINCT verwendet werden. Sie teilen dem Optimierer hierdurch mit, dass die Ergebnismenge klein ist. In diesem Fall verwendet MySQL schnelle Temporärtabellen zur Speicherung der Ergebnistabelle anstelle einer Sortierung. Normalerweise werden Sie diese Option nicht benötigen.

  • SQL_CALC_FOUND_ROWS weist MySQL an, zu berechnen, wie viele Datensätze ohne Berücksichtigung einer ggf. vorhandenen LIMIT-Klausel in der Ergebnismenge enthalten wären. Die Anzahl der Datensätze kann dann mit SELECT FOUND_ROWS() abgerufen werden. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.

  • Mit SQL_CACHE weisen Sie MySQL an, das Abfrageergebnis im Abfrage-Cache zu speichern, wenn Sie einen query_cache_type-Wert von 2 oder DEMAND verwenden. Bei einer Abfrage, die UNION oder Unterabfragen verwendet, betrifft diese Option alle SELECT-Klauseln in der Abfrage. Siehe auch Abschnitt 5.14, „MySQL-Anfragen-Cache“.

  • SQL_NO_CACHE weist MySQL an, das Abfrageergebnis nicht im Abfrage-Cache zu speichern. Siehe auch Abschnitt 5.14, „MySQL-Anfragen-Cache“. Bei einer Abfrage, die UNION oder Unterabfragen verwendet, betrifft diese Option alle SELECT-Klauseln in der Abfrage.

13.2.7.1. JOIN

MySQL unterstützt die folgenden JOIN-Syntaxen für den table_references-Teil von SELECT-Anweisungen sowie von DELETE- und UPDATE-Anweisungen für mehrere Tabellen:

table_references:
    table_reference [, table_reference] ...

table_reference:
    table_factor
  | join_table

table_factor:
    tbl_name [[AS] alias]
        [{USE|IGNORE|FORCE} INDEX (key_list)]
  | ( table_references )
  | { OJ table_reference LEFT OUTER JOIN table_reference
        ON conditional_expr }

join_table:
    table_reference [INNER | CROSS] JOIN table_factor [join_condition]
  | table_reference STRAIGHT_JOIN table_factor
  | table_reference STRAIGHT_JOIN table_factor ON condition
  | table_reference LEFT [OUTER] JOIN table_reference join_condition
  | table_reference NATURAL [LEFT [OUTER]] JOIN table_factor
  | table_reference RIGHT [OUTER] JOIN table_reference join_condition
  | table_reference NATURAL [RIGHT [OUTER]] JOIN table_factor

join_condition:
    ON conditional_expr
  | USING (column_list)

Eine Tabellenreferenzierung heißt auch Join-Ausdruck.

Die Syntax von table_factor ist im Vergleich zum SQL-Standard erweitert. SQL akzeptiert nur table_reference, nicht aber eine in Klammern gesetzte Liste mit Referenzierungen.

Dies ist eine konservative Erweiterung, sofern wir jedes Komma in einer Liste mit table_reference-Elementen als äquivalent zu einem inneren Join betrachten. Zum Beispiel:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

ist äquivalent mit

SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

In MySQL ist CROSS JOIN syntaktisch ein Äquivalent zu INNER JOIN (diese lassen sich gegeneinander austauschen). Nach SQL-Standard hingegen sind beide nicht äquivalent. INNER JOIN wird bei einer ON-Klausel und CROSS JOIN andernfalls verwendet.

Klammern können in Join-Ausdrücken, die nur innere Join-Operationen enthalten, ignoriert werden. MySQL unterstützt auch verschachtelte Joins (siehe auch Abschnitt 7.2.10, „Optimierung verschachtelter Joins“).

Im ON-Teil sollten keine Bedingungen vorhanden sein, die zur Beschränkung der Datensätze in der Ergebnismenge verwendet werden; geben Sie solche Bedingungen besser in der WHERE-Klausel an. Es gibt aber Ausnahmen zu dieser Regel.

Die oben gezeigte Syntax { OJ ... LEFT OUTER JOIN ...} ist nur aus Gründen der Kompatibilität mit ODBC vorhanden. Die geschweiften Klammern in der Syntax sollten literal notiert werden, sind also keine Metasyntax, wie sie andernorts in Syntaxbeschreibungen verwendet wird.

  • Für einen Tabellenverweis kann mit tbl_name AS alias_name oder tbl_name alias_name ein Alias erstellt werden:

    SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
      WHERE t1.name = t2.name;
    
    SELECT t1.name, t2.salary FROM employee t1, info t2
      WHERE t1.name = t2.name;
    
  • Die Bedingungsanweisung ON ist ein beliebiger Bedingungsausdruck der Form, die in einer WHERE-Klausel verwendet werden kann.

  • Ist für die rechte Tabelle im ON- oder USING-Teil eines LEFT JOIN kein passender Datensatz vorhanden, dann wird für die rechte Tabelle ein Datensatz verwendet, bei dem alle Spalten auf NULL gesetzt sind. Sie können diesen Umstand nutzen, um Datensätze in einer Tabelle zu finden, die kein Gegenstück in einer anderen Tabelle aufweisen:

    SELECT table1.* FROM table1
      LEFT JOIN table2 ON table1.id=table2.id
      WHERE table2.id IS NULL;
    

    Dieses Beispiel findet alle Datensätze in table1 mit einem id-Wert, der nicht in table2 vorhanden ist (d. h. alle Datensätze in table1 ohne entsprechenden Datensatz in table2). Dies setzt voraus, dass table2.id als NOT NULL deklariert wurde. Siehe auch Abschnitt 7.2.9, „Optimierung von LEFT JOIN und RIGHT JOIN.

  • Die USING(column_list)-Klausel benennt eine Liste mit Spalten, die in beiden Tabellen vorhanden sein müssen. Wenn die Tabellen a und b jeweils die Spalten c1, c2 und c3 enthalten, dann vergleicht der folgende Join die entsprechenden Spalten der beiden Tabellen:

    a LEFT JOIN b USING (c1,c2,c3)
    
  • Der NATURAL [LEFT] JOIN beider Tabellen wird als semantisch äquivalent zu einem INNER JOIN oder einem LEFT JOIN mit einer USING-Klausel definiert, die alle Spalten aufführt, die in beiden Tabellen vorhanden sind.

  • INNER JOIN und , (Komma) sind semantisch gleichwertig, wenn keine Join-Bedingung vorhanden ist: Beide erzeugen ein kartesisches Produkt zwischen den angegebenen Tabellen (d. h., jeder Datensatz in der ersten Tabelle wird mit jedem Datensatz in der zweiten Tabelle verknüpft).

  • RIGHT JOIN funktioniert analog zu LEFT JOIN. Um den Code datenbankübergreifend portierbar zu halten, wird empfohlen, LEFT JOIN anstelle von RIGHT JOIN zu verwenden.

  • STRAIGHT_JOIN ist bis auf die Tatsache, dass die linke Tabelle immer vor der rechten gelesen wird, identisch mit JOIN. Dies kann für die (wenigen) Fälle genutzt werden, in denen der Join-Optimierer die Tabellen in der falschen Reihenfolge anordnet.

Sie können Hinweise dazu angeben, welchen Index MySQL beim Abrufen von Informationen aus einer Tabelle verwenden soll. Durch Angabe von USE INDEX (key_list) können Sie MySQL anweisen, nur einen der möglichen Indizes zum Ermitteln von Datensätzen in der Tabelle zu verwenden. Mit der alternativen Syntax IGNORE INDEX (key_list) können Sie MySQL anweisen, einen bestimmten Index nicht zu verwenden. Solche Hinweise sind nützlich, wenn EXPLAIN zeigt, dass MySQL aus einer Liste möglicher Indizes den falschen verwendet.

Sie können auch FORCE INDEX verwenden. Diese Option agiert wie USE INDEX (key_list), es wird aber zusätzlich vorausgesetzt, dass ein Tabellenscan sehr kostspielig ist. Anders gesagt: Ein Tabellenscan wird nur verwendet, wenn die Datensätze in der Tabelle nicht unter der Verwendung eines der gegebenen Indizes gefunden werden können.

USE INDEX, IGNORE INDEX und FORCE INDEX wirken sich erst darauf aus, welche Indizes verwendet werden, wenn MySQL entschieden hat, wie Datensätze in der Tabelle ermittelt werden und wie der Join durchgeführt wird. Sie haben keine Auswirkungen darauf, ob ein Index benutzt wird, wenn eine ORDER BY- oder GROUP BY-Klausel aufgelöst wird.

USE KEY, IGNORE KEY und FORCE KEY sind Synonyme von USE INDEX, IGNORE INDEX und FORCE INDEX.

Hier einige Beispiele für Joins:

SELECT * FROM table1,table2 WHERE table1.id=table2.id;

SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;

SELECT * FROM table1 LEFT JOIN table2 USING (id);

SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
  LEFT JOIN table3 ON table2.id=table3.id;

SELECT * FROM table1 USE INDEX (key1,key2)
  WHERE key1=1 AND key2=2 AND key3=3;

SELECT * FROM table1 IGNORE INDEX (key3)
  WHERE key1=1 AND key2=2 AND key3=3;

Hinweis: Natürliche Joins und Joins mit USING (einschließlich Varianten mit äußeren Joins) werden entsprechend Standard SQL:2003 verarbeitet. Diese Änderungen erhöhen die Kompatibilität von MySQL mit dem SQL-Standard. Allerdings kann es bei manchen Joins zu unterschiedlichen Ausgabespalten kommen. Ferner müssen einige Abfragen, die in älteren Versionen (vor 5.0.12) zu funktionieren schienen, neu geschrieben werden, um dem Standard zu entsprechen. Die folgende Liste enthält weitere Angaben zu verschiedenen Auswirkungen der aktuellen Join-Verarbeitung im Vergleich zur Verarbeitung in älteren Versionen. Der Begriff „älter“ bezeichnet hier Versionen vor MySQL 5.0.12.

  • Die Spalten eines NATURAL- oder USING-Joins können sich von denen älterer Versionen unterscheiden. Insbesondere erscheinen keine redundanten Ausgabespalten mehr, und die Reihenfolge der Spalten für die Erweiterung SELECT * kann anders aussehen.

    Beachten Sie die folgenden Anweisungen:

    CREATE TABLE t1 (i INT, j INT);
    CREATE TABLE t2 (k INT, j INT);
    INSERT INTO t1 VALUES(1,1);
    INSERT INTO t2 VALUES(1,1);
    SELECT * FROM t1 NATURAL JOIN t2;
    SELECT * FROM t1 JOIN t2 USING (j);
    

    In den älteren Versionen erzeugten sie folgende Ausgabe:

    +------+------+------+------+
    | i    | j    | k    | j    |
    +------+------+------+------+
    |    1 |    1 |    1 |    1 |
    +------+------+------+------+
    +------+------+------+------+
    | i    | j    | k    | j    |
    +------+------+------+------+
    |    1 |    1 |    1 |    1 |
    +------+------+------+------+
    

    In der ersten SELECT-Anweisung erscheint Spalte i in beiden Tabellen und wird insofern eine Join-Spalte, d. h., sie sollte laut SQL-Standard nur einmal (und nicht zweimal) in der Ausgabe erscheinen. Ähnlich ist die Spalte j in der zweiten SELECT-Anweisung in der USING-Klausel aufgeführt und sollte ebenfalls nur einmal (und nicht zweimal) in der Ausgabe auftauchen. In beiden Fällen wird die redundante Spalte nicht beseitigt. Auch ist die Reihenfolge der Spalten nicht korrekt im Sinne des SQL-Standards.

    Heute erzeugen die Anweisungen folgende Ausgabe:

    +------+------+------+
    | j    | i    | k    |
    +------+------+------+
    |    1 |    1 |    1 |
    +------+------+------+
    +------+------+------+
    | j    | i    | k    |
    +------+------+------+
    |    1 |    1 |    1 |
    +------+------+------+
    

    Die redundante Spalte ist beseitigt. Auch die Spaltenreihenfolge ist nun korrekt im Sinne des SQL-Standards:

    • Zuerst werden die Spalten, die in beiden Tabellen vorhanden sind, in der Reihenfolge aufgeführt, in der sie in der ersten Tabelle erscheinen.

    • Als Zweites erscheinen Spalten, die nur in der ersten Tabelle vorhanden sind, und zwar in der Reihenfolge, in der sie in der Tabelle erscheinen.

    • Als Drittes erscheinen Spalten, die nur in der zweiten Tabelle vorhanden sind, und zwar in der Reihenfolge, in der sie in der Tabelle erscheinen.

  • Die Auswertung eines natürlichen Vielfach-Joins unterscheidet sich auf eine Weise, die ein Neuformulieren von Abfragen erforderlich machen kann. Angenommen, Sie haben drei Tabellen t1(a,b), t2(c,b) und t3(a,c), die jeweils einen Datensatz aufweisen: t1(1,2), t2(10,2) und t3(7,10). Nehmen wir ferner an, dass Sie folgenden NATURAL JOIN auf die drei Tabellen haben:

    SELECT ... FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;
    

    In älteren Versionen wurde der linke Operand des zweiten Joins als t2 betrachtet, wohingegen er eigentlich der verschachtelte Join (t1 NATURAL JOIN t2) sein sollte. Infolgedessen werden die Spalten von t3 nur auf gemeinsame Spalten in t2 geprüft; hat t3 gemeinsame Spalten mit t1, dann werden diese nicht als Equi-Join-Spalten betrachtet. Insofern wurde obige Abfrage bei älteren Versionen in den folgenden Equi-Join transformiert:

    SELECT ... FROM t1, t2, t3
      WHERE t1.b = t2.b AND t2.c = t3.c;
    

    Diesem Join fehlt aber ein weiteres Equi-Join-Prädikat (t1.a = t3.a). Aufgrund dessen wird als Ergebnis ein Datensatz ausgegeben – und nicht das korrekte leere Ergebnis. Die korrekte äquivalente Abfrage sieht wie folgt aus:

    SELECT ... FROM t1, t2, t3
      WHERE t1.b = t2.b AND t2.c = t3.c AND t1.a = t3.a;
    

    Wenn Sie in aktuellen MySQL-Versionen dasselbe Abfrageergebnis wie bei den älteren Versionen erhalten, dann formulieren Sie den natürlichen Join als Equi-Join um.

  • Früher hatten der Kommaoperator (,) und JOIN dieselbe Rangstufe, d. h., der Join-Ausdruck t1, t2 JOIN t3 wurde als ((t1, t2) JOIN t3) interpretiert. Jetzt hat JOIN Vorrang vor dem Komma, d. h., der Ausdruck wird als (t1, (t2 JOIN t3)) ausgewertet. Diese Änderung betrifft Anweisungen, die eine ON-Klausel verwenden, denn diese Klausel kann nur Spalten in den Operanden des Joins referenzieren, und die Änderung in der Rangstufe wirkt sich darauf aus, wie interpretiert wird, was diese Operanden sind.

    Beispiel:

    CREATE TABLE t1 (i1 INT, j1 INT);
    CREATE TABLE t2 (i2 INT, j2 INT);
    CREATE TABLE t3 (i3 INT, j3 INT);
    INSERT INTO t1 VALUES(1,1);
    INSERT INTO t2 VALUES(1,1);
    INSERT INTO t3 VALUES(1,1);
    SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);
    

    In älteren Versionen war die SELECT-Anweisung aufgrund der impliziten Gruppierung von t1,t2 als (t1,t2) zulässig. Jetzt hat JOIN Vorrang, d. h., die Operanden für die ON-Klausel sind t2 und t3. Da t1.i1 keine Spalte in einem der Operanden ist, ist das Ergebnis der Fehler Unknown column 't1.i1' in 'on clause'. Um die Verarbeitung des Joins zuzulassen, gruppieren Sie die ersten beiden Tabellen explizit mithilfe von Klammern, sodass die Operanden für die ON-Klausel (t1,t2) und t3 sind:

    SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);
    

    Alternativ umgehen Sie die Verwendung des Kommaoperators und verwenden stattdessen JOIN:

    SELECT * FROM t1 JOIN t2 JOIN t3 ON (t1.i1 = t3.i3);
    

    Diese Änderung gilt auch für INNER JOIN, CROSS JOIN, LEFT JOIN und RIGHT JOIN: Sie alle haben nun Vorrang vor dem Kommaoperator.

  • Früher konnte die ON-Klausel Spalten in Tabellen referenzieren, die auf ihrer rechten Seite aufgeführt wurden. Jetzt kann eine ON-Klausel nur ihre Operanden referenzieren.

    Beispiel:

    CREATE TABLE t1 (i1 INT);
    CREATE TABLE t2 (i2 INT);
    CREATE TABLE t3 (i3 INT);
    SELECT * FROM t1 JOIN t2 ON (i1 = i3) JOIN t3;
    

    Früher war diese SELECT-Anweisung zulässig. Nun schlägt die Anweisung mit dem Fehler Unknown column 'i3' in 'on clause' fehl, weil i3 eine Spalte in t3 ist, die kein Operand der ON-Klausel ist. Die Anweisung sollte wie folgt umgeschrieben werden:

    SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);
    
  • Früher konnte eine USING-Klausel als ON-Klausel neugeschrieben werden, die die entsprechenden Spalten vergleichen konnte. Die beiden folgenden Klauseln etwa sind semantisch identisch:

    a LEFT JOIN b USING (c1,c2,c3)
    a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3
    

    Heute haben diese beiden Klauseln nicht mehr dieselbe Bedeutung:

    • Bezüglich der Ermittlung, welche Datensätze die Join-Bedingung erfüllen, bleiben beide Joins semantisch identisch.

    • Allerdings ist diese semantische Identität nicht mehr in Bezug auf die Frage vorhanden, wie die für die SELECT *-Erweiterung anzuzeigenden Spalten bestimmt werden. Der USING-Join wählt den zusammengefassten Wert der entsprechenden Spalten, während der ON-Join alle Spalten aus allen Tabellen auswählt. Bei obigem USING-Join wählt SELECT * die folgenden Werte aus:

      COALESCE(a.c1,b.c1), COALESCE(a.c2,b.c2), COALESCE(a.c3,b.c3)
      

      Beim ON-Join wählt SELECT * die folgenden Werte aus:

      a.c1, a.c2, a.c3, b.c1, b.c2, b.c3
      

      Bei einem inneren Join ist COALESCE(a.c1,b.c1) das Gleiche wie a.c1 oder b.c1, weil beide Spalten denselben Wert haben. Bei einem äußeren Join (wie LEFT JOIN) darf eine der beiden Spalten NULL sein. Diese Spalte wird im Ergebnis weggelassen.

13.2.7.2. UNION

SELECT ...
UNION [ALL | DISTINCT] SELECT ...
[UNION [ALL | DISTINCT] SELECT ...]

UNION wird verwendet, um das Ergebnis einer Anzahl von SELECT-Anweisungen zu einer Ergebnismenge zusammenzufassen.

Ausgewählte Spalten, die an den entsprechenden Positionen jeder SELECT-Anweisung aufgelistet sind, sollten vom selben Typ sein. (So sollte etwa die erste von der ersten Anweisung ausgewählte Spalte denselben Typ haben wie die erste von den anderen Anweisungen gewählte Spalte.) Die in der ersten SELECT-Anweisung verwendeten Spaltennamen werden als Spaltennamen für die zurückgegebenen Ergebnisse benutzt.

Die SELECT-Anweisungen sind normale Auswahlanweisungen, es gelten jedoch die folgenden Einschränkungen:

  • Nur die letzte SELECT-Anweisung kann INTO OUTFILE verwenden.

  • HIGH_PRIORITY kann nicht bei SELECT-Anweisungen verwendet werden, die Teil einer Union sind. Wenn Sie es für die erste SELECT-Anweisung angeben, hat dies keine Auswirkungen. Bei einer Angabe für eine nachfolgende SELECT-Anweisung tritt ein Syntaxfehler auf.

Geben Sie das Schlüsselwort ALL an, dann enthält das Ergebnis alle passenden Datensätze aus allen SELECT-Anweisungen. Wenn Sie DISTINCT angeben, werden doppelte Datensätze aus dem Ergebnis entfernt. Wird kein Schlüsselwort benutzt, dann entspricht das Standardverhalten dem von DISTINCT (Entfernung doppelter Datensätze).

Das Schlüsselwort DISTINCT ist optional ohne Wirkung, ist aber in der Syntax zulässig, da der SQL-Standard dies vorschreibt. (In MySQL stellt DISTINCT das Standardverhalten einer Union dar.)

Sie können UNION ALL und UNION DISTINCT in derselben Abfrage gemeinsam verwenden. Derart gemischte UNION-Typen werden dahingehend verarbeitet, dass eine DISTINCT-Union Vorrang vor einer ALL-Union zu ihrer Linken hat. Eine DISTINCT-Union kann explizit mit UNION DISTINCT oder implizit durch Verwendung von UNION ohne nachfolgende Schlüsselwörter DISTINCT oder ALL erzeugt werden.

Wenn Sie eine ORDER BY- oder LIMIT-Klausel zur Sortierung bzw. Beschränkung des gesamten Ergebnisses der Union benutzen wollen, setzen Sie die einzelnen SELECT-Anweisungen in Klammern und platzieren Sie die ORDER BY- oder LIMIT-Klausel an dem Ende. Das folgende Beispiel verwendet beide Klauseln:

(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

Diese Art von ORDER BY kann keine Spaltenreferenzierungen verwenden, die einen Tabellennamen enthalten (d. h. Namen im Format tbl_name.col_name). Geben Sie stattdessen einen Spaltenalias in der ersten SELECT-Anweisung an und referenzieren Sie diesen Alias in der ORDER BY-Klausel. Alternativ können Sie die Spalten auch in der ORDER BY-Klausel unter Angabe ihrer Spaltenposition referenzieren. (Ein Alias ist allerdings vorzuziehen, weil das Angeben von Spaltenpositionen veraltet ist.)

Ferner muss, wenn einer zu sortierenden Spalte ein Alias zugewiesen wird, die ORDER BY-Klausel den Alias und nicht den Spaltennamen referenzieren. Die erste der folgenden Anweisungen funktioniert – im Gegensatz zur zweiten, die mit dem Fehler Unknown column 'a' in 'order clause' fehlschlägt:

(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b;
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;

Um ORDER BY oder LIMIT auf eine einzelne SELECT-Anweisung anzuwenden, setzen Sie die Klausel mit in die Klammern, die die SELECT-Anweisung umschließen:

(SELECT a FROM tbl_name WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM tbl_name WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

Das Einfügen von ORDER BY bei einzelnen SELECT-Anweisungen in Klammern hat nur in Kombination mit LIMIT Auswirkungen. Andernfalls wird ORDER BY wegoptimiert.

Typen und Längen der Spalten in der Ergebnismenge einer Union berücksichtigen Werte, die von allen SELECT-Anweisungen abgerufen wurden. Betrachten Sie etwa einmal Folgendes:

mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+---------------+
| REPEAT('a',1) |
+---------------+
| a             |
| bbbbbbbbbb    |
+---------------+

In einigen früheren Versionen von MySQL würde der zweite Datensatz auf eine Länge von 1 gekürzt.

13.2.8. Syntax von Unterabfragen

Eine Unterabfrage ist eine SELECT-Anweisung innerhalb einer anderen Anweisung.

Seit MySQL 4.1 werden alle Unterabfrageformen und -operationen, die der SQL-Standard vorsieht, ebenso unterstützt wie einige weitere Funktionen, die MySQL-spezifisch sind.

Hier ein Beispiel für eine Unterabfrage:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

In diesem Beispiel ist SELECT * FROM t1 ... die äußere Abfrage (oder äußere Anweisung), und (SELECT column1 FROM t2) ist die Unterabfrage. Man sagt, die Unterabfrage ist in der äußeren Abfrage verschachtelt, und tatsächlich ist es möglich, Unterabfragen bis zu einer beträchtlichen Tiefe zu verschachteln. Eine Unterabfrage muss immer in Klammern stehen.

Unterabfragen haben die folgenden Vorteile:

  • Sie gestatten Abfragen, die strukturiert sind. Auf diese Weise ist es möglich, jeden Teil einer Anweisung zu isolieren.

  • Sie bieten alternative Wege zur Durchführung von Operationen, die andernfalls komplexe Joins und Unions erfordern würden.

  • Sie sind – zumindest nach Meinung vieler – lesbar. Die Unterabfragen waren die eigentliche Innovation, aufgrund derer man auf die Idee kam, SQL seinerzeit als „strukturierte Abfragesprache“ zu bezeichnen.

Hier eine Beispielanweisung, die die wichtigsten Aspekte der Unterabfragensyntax zeigt, wie sie im SQL-Standard spezifiziert ist und von MySQL unterstützt wird:

DELETE FROM t1
WHERE s11 > ANY
(SELECT COUNT(*) /* no hint */ FROM t2
WHERE NOT EXISTS
(SELECT * FROM t3
WHERE ROW(5*t2.s1,77)=
(SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
(SELECT * FROM t5) AS t5)));

Eine Unterabfrage kann einen Skalar (einen einzelnen Wert), einen einzelnen Datensatz, eine einzelne Spalte oder eine Tabelle (d. h. eine oder mehrere Spalten von einem oder mehreren Datensätzen) zurückgeben. Man bezeichnet diese als Skalar-, Spalten-, Datensatz- und Tabellenunterabfragen. Unterabfragen, die einen bestimmten Ergebnistyp zurückgeben, können häufig nur in bestimmten Kontexten verwendet werden, die in den folgenden Abschnitten beschrieben werden.

Es gibt ein paar wenige Einschränkungen bezüglich des Typs der Anweisungen, in denen Unterabfragen verwendet werden können. Eine Unterabfrage kann die gleichen Schlüsselwörter oder Klauseln enthalten wie eine gewöhnliche SELECT-Anweisung: DISTINCT, GROUP BY, ORDER BY, LIMIT, Joins, Indexhinweise, UNION-Konstrukte, Kommentare, Funktionen usw.

Eine Einschränkung besteht darin, dass die äußere Anweisung einer Unterabfrage einen der folgenden Typen aufweisen muss: SELECT, INSERT, UPDATE, DELETE, SET oder DO. Eine weitere Einschränkung ist die Tatsache, dass Sie eine Tabelle derzeit nicht ändern und gleichzeitig in einer Unterabfrage eine Auswahl aus dieser Tabelle treffen können. Dies gilt für Anweisungen wie DELETE, INSERT, REPLACE, UPDATE und (da Unterabfragen in der SET-Klausel verwendet werden können) LOAD DATA INFILE. Eine umfassendere Beschreibung der Einschränkungen bei Unterabfragen finden Sie in Abschnitt I.3, „Beschränkungen von Unterabfragen“.

13.2.8.1. Die Unterabfrage als skalarer Operand

In ihrer einfachsten Form ist eine Unterabfrage eine Skalarunterabfrage, die einen Einzelwert zurückgibt. Eine Skalarunterabfrage ist ein einfacher Operand, und Sie können sie fast überall dort benutzen, wo ein einzelner Spaltenwert oder ein Literal zulässig ist. Sie können dabei voraussetzen, dass eine solche Unterabfrage die Eigenschaften aufweist, die alle Operanden haben: einen Datentyp, eine Länge, eine Angabe dazu, ob sie NULL sein darf oder nicht usw. Zum Beispiel:

CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);

Die Unterabfrage in dieser SELECT-Anweisung gibt einen einzelnen Wert ('abcde') zurück, der den Datentyp CHAR und die Länge 5 aufweist, Zeichensatz und Sortierfolge den mit CREATE TABLE konfigurierten Vorgaben entnimmt und die Information enthält, dass der Wert in der Spalte auch NULL sein kann. Tatsächlich können fast alle Unterabfragen NULL werden. Wäre die im Beispiel verwendete Tabelle leer, dann wäre der Wert der Unterabfrage NULL.

Es gibt nur ganz wenig Kontexte, in denen eine skalare Unterabfrage nicht verwendet werden kann. Wenn eine Anweisung nur einen literalen Wert zulässt, können Sie keine Unterabfrage einsetzen. So erfordert beispielsweise LIMIT literale Integer-Argumente, und LOAD DATA INFILE verlangt einen literalen String für den Dateinamen. Zur Übermittlung solcher Werte können Sie Unterabfragen nicht benutzen.

Wenn die Beispiele in den folgenden Abschnitten das recht spartanische Konstrukt (SELECT column1 FROM t1) enthalten, dann vergegenwärtigen Sie sich, dass Ihr eigener Code wesentlich komplexere und unterschiedlichere Konstruktionen enthalten kann (und wird).

Nehmen wir an, wir erstellen zwei Tabellen:

CREATE TABLE t1 (s1 INT);
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 (s1 INT);
INSERT INTO t2 VALUES (2);

Nun führen Sie eine SELECT-Anweisung aus:

SELECT (SELECT s1 FROM t2) FROM t1;

Das Ergebnis ist 2, weil in Tabelle t2 eine Spalte s1 vorhanden ist, die den Wert 2 hat.

Eine skalare Unterabfrage kann Teil eines Ausdrucks sein. Denken Sie aber immer an die Klammern – auch dann, wenn die Unterabfrage ein Operand ist, der ein Argument für eine Funktion bereitstellt. Zum Beispiel:

SELECT UPPER((SELECT s1 FROM t1)) FROM t2;

13.2.8.2. Vergleiche mit Unterabfragen

Die häufigste Form einer Unterabfrage hat das folgende Aussehen:

non_subquery_operand comparison_operator (subquery)

Hierbei ist comparison_operator einer der folgenden Operatoren:

=  >  <  >=  <=  <>

Zum Beispiel:

  ... 'a' = (SELECT column1 FROM t1)

Früher befand sich der einzige zulässige Ort für eine Unterabfrage auf der rechten Seite eines Vergleichs; einige wenige alte Datenbanksysteme halten nach wie vor an dieser Regel fest.

Hier ein Beispiel für einen Unterabfragenvergleich in der gängigen Form, den Sie mit einem Join nicht durchführen können. Hierbei werden alle Werte in Tabelle t1 gefunden, die einem Maximalwert in Tabelle t2 entsprechen:

SELECT column1 FROM t1
WHERE column1 = (SELECT MAX(column2) FROM t2);

Es folgt ein weiteres Beispiel, welches ebenfalls mit einem Join nicht zu realisieren ist, da für eine der Tabellen eine Zusammenfassung erfolgt. Gefunden werden hier alle Datensätze in der Tabelle t1, die einen Wert enthalten, der in einer gegebenen Spalte zweimal auftritt:

SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);

Bei einem Vergleich, der mit einem dieser Operatoren durchgeführt wird, muss die Unterabfrage einen Skalar zurückgeben. Eine Ausnahme besteht lediglich darin, dass = mit Datensatzunterabfragen verwendet werden kann. Siehe auch Abschnitt 13.2.8.5, „Zeilenunterabfragen“.

13.2.8.3. Unterabfragen mit ANY, IN und SOME

Syntax:

operand comparison_operator ANY (subquery)
operand IN (subquery)
operand comparison_operator SOME (subquery)

Das Schlüsselwort ANY, das einem Vergleichsoperator folgen muss, bedeutet „Gib TRUE zurück, wenn der Vergleich für jeden beliebigen Wert in der Spalte, die die Unterabfrage zurückgibt, wahr ist“. Zum Beispiel:

SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);

Nehmen wir an, dass die Tabelle t1 einen Datensatz mit dem Inhalt (10) umfasst. Der Ausdruck ist wahr, wenn Tabelle t2 (21,14,7) enthält, weil ein Wert 7 in t2 vorhanden ist, der kleiner als 10 ist. Der Ausdruck ist hingegen falsch, wenn Tabelle t2 (20,10) enthält oder leer ist. Der Ausdruck ist schließlich unbekannt (UNKNOWN), wenn Tabelle t2 (NULL,NULL,NULL) enthält.

Das Wort IN ist ein Alias für = ANY. Insofern sind die folgenden beiden Anweisungen gleichwertig:

SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN    (SELECT s1 FROM t2);

Allerdings ist NOT IN kein Alias für <> ANY, wohl aber für <> ALL. Siehe auch Abschnitt 13.2.8.4, „Unterabfragen mit ALL.

Das Wort SOME ist ein Alias für ANY. Insofern sind die folgenden beiden Anweisungen gleichwertig:

SELECT s1 FROM t1 WHERE s1 <> ANY  (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);

Das Wort SOME wird zwar nur selten verwendet, dieses Beispiel zeigt aber, wofür es nützlich sein kann. Die meisten Menschen fassen die Phrase „a ist nicht gleich irgendeinem b“ als „Es gibt kein b, welches gleich a ist“ auf, aber das ist bei der SQL-Syntax nicht gemeint. Hier bedeutet dies vielmehr „Es gibt (mindestens) ein b, dem a nicht gleich ist“. Indem Sie stattdessen <> SOME verwenden, gewährleisten Sie, dass jeder die tatsächliche Meinung der Abfrage versteht.

13.2.8.4. Unterabfragen mit ALL

Syntax:

operand comparison_operator ALL (subquery)

Das Wort ALL, das einem Vergleichsoperator folgen muss, bedeutet „Gib TRUE zurück, wenn der Vergleich für jeden beliebigen Wert in der Spalte, die die Unterabfrage zurückgibt, wahr ist“. Zum Beispiel:

SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);

Nehmen wir an, dass die Tabelle t1 einen Datensatz mit dem Inhalt (10) umfasst. Der Ausdruck ist wahr, wenn Tabelle t2 (-5,0,+5) enthält, weil 10 größer als alle drei Werte in t2 ist. Der Ausdruck ist hingegen falsch, wenn Tabelle t2 (12,6,NULL,-100) enthält, weil es einen Wert (12) in Tabelle t2 gibt, der größer als 10 ist. Der Ausdruck ist unbekannt (d. h. NULL), wenn Tabelle t2 (0,NULL,1) enthält.

Schließlich ist, wenn Tabelle t2 leer ist, das Ergebnis wahr. Aufgrund dessen ist die folgende Anweisung wahr, wenn Tabelle t2 leer ist:

SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);

Folgende Anweisung ist hingegen NULL, wenn Tabelle t2 leer ist:

SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);

Ferner ist auch folgende Anweisung NULL, wenn Tabelle t2 leer ist:

SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);

Generell sind Tabellen, die NULL-Werte enthalten, und leere Tabellen Grenzfälle. Wenn Sie Unterabfragencode formulieren, vergewissern Sie sich immer, dass Sie diese beiden Fälle berücksichtigt haben.

NOT IN ist ein Alias für <> ALL. Insofern sind die folgenden beiden Anweisungen gleichwertig:

SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

13.2.8.5. Zeilenunterabfragen

Bis zu diesem Punkt haben wir ausschließlich Skalar- und Spaltenunterabfragen beschrieben, also Unterabfragen, die einen einzelnen Wert oder eine Wertespalte zurückgeben. Eine Datensatzunterabfrage ist eine Unterabfragenvariante, die einen einzelnen Datensatz zurückgibt – und insofern auch mehrere Spaltenwerte zurückgeben kann. Hier zwei Beispiele:

SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);

Die gezeigten Abfragen sind beide wahr, wenn Tabelle t2 einen Datensatz enthält, bei dem column1 = 1 und column2 = 2 sind.

Die Ausdrücke (1,2) und ROW(1,2) heißen manchmal auch Datensatzkonstruktoren. Beide sind äquivalent. Sie sind zudem auch in anderen Kontexten zulässig. So sind etwa die beiden folgenden Anweisungen semantisch äquivalent (obwohl derzeit nur die zweite optimiert werden kann):

  SELECT * FROM t1 WHERE (column1,column2) = (1,1);
  SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

Der normale Anwendungsfall von Datensatzkonstruktoren sind Vergleiche mit Unterabfragen, die zwei oder mehr Spalten zurückgeben. So entspricht die folgende Abfrage der Aufforderung „Suche alle Datensätze in Tabelle t1, die auch in Tabelle t2 vorhanden sind“:

SELECT column1,column2,column3
FROM t1
WHERE (column1,column2,column3) IN
(SELECT column1,column2,column3 FROM t2);

13.2.8.6. EXISTS und NOT EXISTS

Wenn eine Unterabfrage irgendwelche Datensätze zurückgibt, ist EXISTS subquery wahr und NOT EXISTS subquery ist falsch. Zum Beispiel:

SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);

Traditionell beginnt eine EXISTS-Unterabfrage mit SELECT *, sie könnte aber auch mit SELECT 5 oder SELECT column1 oder etwas ganz anderem anfangen: MySQL ignoriert die SELECT-Liste in einer solchen Unterabfrage, mithin macht es keinen Unterschied.

Bei obigem Beispiel ist die Bedingung wahr, wenn t2 überhaupt Datensätze enthält (und sogar dann, wenn es sich ausschließlich um NULL-Werte handelt). Dies ist aber ein recht abwegiges Beispiel, weil eine [NOT] EXISTS-Unterabfrage fast immer Korrelationen enthält. Hier einige pragmatischere Beispiele:

  • Welche Arten von Geschäften sind in einer oder mehreren Städten vorhanden?

    SELECT DISTINCT store_type FROM stores
      WHERE EXISTS (SELECT * FROM cities_stores
                    WHERE cities_stores.store_type = stores.store_type);
    
  • Welche Art von Geschäften ist in keiner Stadt vorhanden?

    SELECT DISTINCT store_type FROM stores
      WHERE NOT EXISTS (SELECT * FROM cities_stores
                        WHERE cities_stores.store_type = stores.store_type);
    
  • Welche Art von Geschäften ist in allen Städten vorhanden?

    SELECT DISTINCT store_type FROM stores s1
      WHERE NOT EXISTS (
        SELECT * FROM cities WHERE NOT EXISTS (
          SELECT * FROM cities_stores
           WHERE cities_stores.city = cities.city
           AND cities_stores.store_type = stores.store_type));
    

Das letzte Beispiel ist eine doppelt verschachtelte NOT EXISTS-Abfrage: Sie enthält eine NOT EXISTS-Klausel in einer NOT EXISTS-Klausel. Formell beantwortet sie die Frage „Gibt es eine Stadt mit einem Geschäft, das nicht in Stores vorhanden ist?“. Aber es ist einfacher zu sagen, dass eine verschachtelte NOT EXISTS-Klausel die Frage „Ist x für alle y wahr?“ beantwortet.

13.2.8.7. Korrelierte Unterabfragen

Eine korrelierte Unterabfrage ist eine Unterabfrage, die eine Tabelle referenziert, die auch in der äußeren Abfrage erscheint. Zum Beispiel:

SELECT * FROM t1 WHERE column1 = ANY
(SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);

Beachten Sie, dass die Unterabfrage eine Spalte von t1 referenziert, obwohl die FROM-Klausel der Unterabfrage keine Tabelle t1 erwählt. Also sucht MySQL außerhalb der Unterabfrage und findet t1 in der äußeren Abfrage.

Angenommen, Tabelle t1 enthielte einen Datensatz, bei dem column1 = 5 und column2 = 6 sind. Gleichzeitig enthält Tabelle t2 einen Datensatz, bei dem column1 = 5 und column2 = 7 sind. Der einfache Ausdruck ... WHERE column1 = ANY (SELECT column1 FROM t2) wäre wahr, aber in diesem Beispiel ist die WHERE-Klausel innerhalb der Unterabfrage falsch (weil nämlich (5,6) nicht gleich (5,7)); also ist auch die Unterabfrage als Ganzes falsch.

Bereichsregel: MySQL wertet von innen nach außen aus. Zum Beispiel:

SELECT column1 FROM t1 AS x
WHERE x.column1 = (SELECT column1 FROM t2 AS x
WHERE x.column1 = (SELECT column1 FROM t3
WHERE x.column2 = t3.column1));

In dieser Anweisung muss x.column2 eine Spalte in der Tabelle t2 sein, weil SELECT column1 FROM t2 AS x ... t2 umbenennt. Es ist keine Spalte in Tabelle t1, weil SELECT column1 FROM t1 ... eine äußere Abfrage ist, die weiter außen ist.

Bei Unterabfragen in HAVING- oder ORDER BY-Klauseln sucht MySQL auch nach Spaltennamen in der äußeren Auswahlliste.

In bestimmten Fällen wird eine korrelierte Unterabfrage optimiert. Zum Beispiel:

val IN (SELECT key_val FROM tbl_name WHERE correlated_condition)

Andernfalls sind sie ineffizient und zudem wahrscheinlich recht langsam. Das Umschreiben der Abfrage als Join kann die Leistung unter Umständen verbessern.

Korrelierte Unterabfragen können Ergebnisse von Zusammenfassungsfunktionen in der äußeren Abfrage nicht referenzieren.

13.2.8.8. Unterabfragen in der FROM-Klausel

Unterabfragen sind in der FROM-Klausel einer SELECT-Anweisung zulässig. Die eigentliche Syntax lautet:

SELECT ... FROM (subquery) [AS] name ...

Die [AS] name-Klausel ist obligatorisch, weil jede Tabelle in einer FROM-Klausel einen Namen haben muss. Alle Spalten, die in der subquery-Auswahlliste aufgeführt sind, benötigen eindeutige Namen. Sie finden diese Syntax an anderer Stelle in diesem Handbuch beschrieben. Dort wird der Begriff „abgeleitete Tabellen“ verwendet.

Zur Veranschaulichung nehmen wir an, dass Sie folgende Tabelle haben:

CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);

Eine Unterabfrage in der FROM-Klausel verwenden Sie bei der Beispieltabelle wie folgt:

INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3
FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb
WHERE sb1 > 1;

Ergebnis: 2, '2', 4.0.

Es folgt ein weiteres Beispiel: Nehmen wir an, Sie wollen den Durchschnitt einer Anzahl von Summen für eine gruppierte Tabelle ermitteln. Folgendes funktioniert nicht:

SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;

Die nächste Abfrage dagegen übermittelt die gewünschte Information:

SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1
FROM t1 GROUP BY column1) AS t1;

Beachten Sie, dass der Spaltenname, der in der Unterabfrage verwendet wird (sum_column1), in der äußeren Abfrage erkannt wird.

Unterabfragen in der FROM-Klausel können einen Skalar, eine Spalte, einen Datensatz oder eine Tabelle zurückgeben. Unterabfragen in der FROM-Klausel dürfen keine korrelierten Unterabfragen sein.

Unterabfragen in der FROM-Klausel werden auch für die EXPLAIN-Anweisung ausgeführt (d. h., es werden abgeleitete Temporärtabellen erstellt). Grund hierfür ist, dass Abfragen höherer Ebenen während der Optimierungsphase Informationen zu allen Tabellen benötigen.

13.2.8.9. Fehler bei Unterabfragen

Es gibt eine Reihe von Fehlern, die sich nur auf Unterabfragen beziehen. Sie werden in diesem Abschnitt beschrieben.

  • Falsche Anzahl von Spalten aus der Unterabfrage:

    ERROR 1241 (ER_OPERAND_COL)
    SQLSTATE = 21000
    Message = "Operand should contain 1 column(s)"
    

    Dieser Fehler tritt in Fällen wie dem folgenden auf:

    SELECT (SELECT column1, column2 FROM t2) FROM t1;
    

    Sie können eine Unterabfrage verwenden, die mehrere Spalten zurückgibt, sofern das Ziel ein Vergleich ist. Siehe auch Abschnitt 13.2.8.5, „Zeilenunterabfragen“. Allerdings muss die Unterabfrage in anderen Kontexten ein skalarer Operand sein.

  • Falsche Anzahl von Datensätzen aus der Unterabfrage:

    ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
    SQLSTATE = 21000
    Message = "Subquery returns more than 1 row"
    

    Dieser Fehler tritt bei Anweisungen auf, bei denen die Unterabfrage mehr als einen Datensatz zurückgibt. Betrachten Sie einmal das folgende Beispiel:

    SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
    

    Wenn SELECT column1 FROM t2 nur einen Datensatz zurückgibt, funktioniert obige Abfrage. Gibt die Abfrage jedoch mehrere Datensätze zurück, dann tritt der Fehler 1242 auf. In diesem Fall sollten Sie die Abfrage wie folgt neu formulieren:

    SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);
    
  • Falsch verwendete Tabelle in der Unterabfrage:

    Error 1093 (ER_UPDATE_TABLE_USED)
    SQLSTATE = HY000
    Message = "You can't specify target table 'x'
    for update in FROM clause"
    

    Dieser Fehler tritt in Fällen wie dem folgenden auf:

    UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);
    

    Sie können eine Unterabfrage zur Zuweisung innerhalb einer UPDATE-Anweisung verwenden, da Unterabfragen in UPDATE- und DELETE-Anweisungen ebenso zulässig sind wie in SELECT-Anweisungen. Allerdings können Sie nicht dieselbe Tabelle (in diesem Fall Tabelle t1) sowohl in der FROM-Klausel der Unterabfrage als auch als Aktualisierungsziel angeben.

Bei transaktionssicheren Speicher-Engines schlägt bei einem Fehlschlag einer Unterabfrage die gesamte Anweisung fehl. Bei nichttransaktionssicheren Speicher-Engines bleiben Datenänderungen, die vor Auftreten des Fehlers durchgeführt wurden, erhalten.

13.2.8.10. Optimierung von Unterabfragen

Die Entwicklung erfolgt kontinuierlich, d. h., Optimierungstipps sind niemals auf Dauer gültig. Die folgende Liste zeigt einige interessante Tricks, mit denen Sie ein wenig herumprobieren können:

  • Verwendung von Klauseln in Unterabfragen, die die Anzahl oder Reihenfolge der Datensätze in der Unterabfrage betreffen. Zum Beispiel:

    SELECT * FROM t1 WHERE t1.column1 IN
    (SELECT column1 FROM t2 ORDER BY column1);
    SELECT * FROM t1 WHERE t1.column1 IN
    (SELECT DISTINCT column1 FROM t2);
    SELECT * FROM t1 WHERE EXISTS
    (SELECT * FROM t2 LIMIT 1);
    
  • Ersetzen Sie einen Join durch eine Unterabfrage. Probieren Sie z. B. Folgendes aus.

    SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN (
    SELECT column1 FROM t2);
    

    So hätte dies ursprünglich ausgesehen:

    SELECT DISTINCT t1.column1 FROM t1, t2
    WHERE t1.column1 = t2.column1;
    
  • Einige Unterabfragen können aus Gründen der Kompatibilität mit älteren MySQL-Versionen, die Unterabfragen nicht unterstützen, in Joins umgewandelt werden. Allerdings wird hierdurch in einigen Fällen die Leistungsfähigkeit beeinträchtigt. Siehe auch Abschnitt 13.2.8.11, „Umschreiben von Unterabfragen in Joins für frühere MySQL-Versionen“.

  • Verschieben Sie Klauseln von außen in die Unterabfrage. Verwenden Sie beispielsweise diese Abfrage …

    SELECT * FROM t1
    WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);
    

    … statt dieser:

    SELECT * FROM t1
    WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);
    

    Ein weiteres Beispiel: Verwenden Sie diese Abfrage …

    SELECT (SELECT column1 + 5 FROM t1) FROM t2;
    

    … statt dieser:

    SELECT (SELECT column1 FROM t1) + 5 FROM t2;
    
  • Verwenden Sie eine Datensatzunterabfrage statt einer korrelierten Unterabfrage. Verwenden Sie beispielsweise diese Abfrage …

    SELECT * FROM t1
    WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);
    

    … statt dieser:

    SELECT * FROM t1
    WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1
    AND t2.column2=t1.column2);
    
  • Verwenden Sie NOT (a = ANY (...)) statt a <> ALL (...).

  • Verwenden Sie x = ANY (table containing (1,2)) statt x=1 OR x=2.

  • Verwenden Sie = ANY statt EXISTS.

  • Bei unkorrelierten Unterabfragen, die immer genau einen Datensatz zurückgeben, ist IN immer langsamer als =. Verwenden Sie beispielsweise diese Abfrage …

    SELECT * FROM t1 WHERE t1.col_name
    = (SELECT a FROM t2 WHERE b = some_const);
    

    … statt dieser:

    SELECT * FROM t1 WHERE t1.col_name
    IN (SELECT a FROM t2 WHERE b = some_const);
    

Aufgrund dieser Tricks können Programme schneller, aber auch langsamer werden. Mithilfe von MySQL-Funktionen wie BENCHMARK() können Sie überprüfen, was in Ihrer speziellen Situation hilfreich sein kann. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.

Die folgenden Optimierungen nimmt MySQL selbst vor:

  • MySQL führt nichtkorrelierte Unterabfragen nur einmal aus. Mit EXPLAIN können Sie sicherstellen, dass eine gegebene Unterabfrage wirklich nichtkorreliert ist.

  • MySQL schreibt IN-, ALL-, ANY- und SOME-Unterabfragen neu, um möglichst davon zu profitieren, dass die Auswahllistenspalten in der Unterabfrage indiziert sind.

  • MySQL ersetzt Unterabfragen der folgenden Form durch eine Indexsuchfunktion, die EXPLAIN als speziellen Join-Typ beschreibt (unique_subquery oder index_subquery):

    ... IN (SELECT indexed_column FROM single_table ...)
    
  • MySQL erweitert Ausdrücke der folgenden Form mit einem Ausdruck mit MIN() oder MAX(), sofern NULL-Werte oder Leermengen vorhanden sind:

    value {ALL|ANY|SOME} {> | < | >= | <=} (non-correlated subquery)
    

    Betrachten Sie etwa folgende WHERE-Klausel:

    WHERE 5 > ALL (SELECT x FROM t)
    

    Diese könnte vom Optimierer wie folgt geändert werden:

    WHERE 5 > (SELECT MAX(x) FROM t)
    

Es gibt ein Kapitel „How MySQL Transforms Subqueries“ („Wie MySQL Unterabfragen transformiert“) im Handbuch „MySQL Internals“ (MySQL-Interna, derzeit nur auf Englisch verfügbar), welches Sie unter http://dev.mysql.com/doc/ erhalten.

13.2.8.11. Umschreiben von Unterabfragen in Joins für frühere MySQL-Versionen

Bei älteren MySQL-Versionen (vor Version 4.1) wurden nur verschachtelte Abfragen der Formen INSERT ... SELECT ... und REPLACE ... SELECT ... unterstützt. Zwar trifft dies bei MySQL 5.1 nicht mehr zu, aber nach wie vor werden gelegentlich andere Möglichkeiten eingesetzt, um auf Mitgliedschaft in einer Wertemenge zu prüfen. Außerdem ist es unter bestimmten Umständen nicht nur möglich, eine Abfrage ohne Unterabfrage zu schreiben, sondern es kann auch effizienter sein, einige der folgenden Methoden zu verwenden, statt Unterabfragen einzusetzen. Eine dieser Methode ist das Konstrukt IN():

Betrachten Sie etwa folgende Abfrage:

SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);

Sie kann wie folgt umgeschrieben werden:

SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;

Ein anderes Beispiel sind folgende Abfragen:

SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);
SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);

Auch sie lassen sich mithilfe von IN() umschreiben:

SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id
WHERE table2.id IS NULL;

Ein LEFT [OUTER] JOIN kann schneller sein als die äquivalente Unterabfrage, weil der Server unter Umständen in der Lage ist, ihn besser zu optimieren – eine Tatsache, die nicht nur für den MySQL Server gilt. Vor SQL-92 waren äußere Joins nicht vorhanden, d. h., Unterabfragen stellten für bestimmte Aufgaben die einzige Lösung dar. Heute bieten MySQL Server und viele andere moderne Datenbanksysteme eine Vielzahl von Typen für äußere Joins.

MySQL Server unterstützt DELETE-Anweisungen über mehrere Tabellen, die zur effizienten gleichzeitigen Löschung von Datensätzen basierend auf Daten in einer Tabelle (oder sogar mehreren Tabellen) benutzt werden. Auch UPDATE-Anweisungen über mehrere Tabellen werden unterstützt.

13.2.9. TRUNCATE

TRUNCATE [TABLE] tbl_name

TRUNCATE TABLE leert eine Tabelle vollständig. Logisch gesehen ist dies äquivalent zu einer DELETE-Anweisung, die alle Datensätze löscht, aber es gibt unter bestimmten Umständen praktische Unterschiede.

Bei InnoDB-Tabellen wird TRUNCATE TABLE auf DELETE umgesetzt, sofern keine Fremdschlüssel-Constraints vorhanden sind, die die Tabelle referenzieren; andernfalls wird das schnelle Leeren (durch Löschen und Neuerstellen der Tabelle) verwendet. Der AUTO_INCREMENT-Zähler wird von TRUNCATE TABLE unabhängig vom Vorhandensein eines Fremdschlüssel-Constraints zurückgesetzt.

Bei anderen Speicher-Engines unterscheidet sich TRUNCATE TABLE in MySQL 5.1 wie folgt von DELETE:

  • Leerungsoperationen löschen die Tabelle und erstellen sie dann neu, was wesentlich schneller ist als das aufeinander folgende Löschen aller Datensätze.

  • Leerungsoperationen sind nicht transaktionssicher: Wenn Sie eine solche Operation während einer aktiven Transaktion oder einer aktiven Tabellensperrung durchführen wollen, tritt ein Fehler auf.

  • Die Anzahl gelöschter Datensätze wird nicht zurückgegeben.

  • Solange die Tabellenformatdatei tbl_name.frm gültig ist, lässt sich die Tabelle mit TRUNCATE TABLE auch dann als leere Tabelle neu erstellen, wenn die Daten- oder Indexdateien beschädigt wurden.

  • Der Tabellen-Handler speichert den zuletzt verwendeten AUTO_INCREMENT-Wert nicht, sondern fängt mit der Zählung von vorne an. Dies gilt auch für MyISAM- und InnoDB-Tabellen, die Sequenzwerte normalerweise nicht erneut verwenden.

  • Bei der Verwendung mit partitionierten Tabellen behält TRUNCATE TABLE die Partitionierung bei, d. h., Daten- und Indexdateien werden gelöscht und neu erstellt, während die Partitionsdefinitionsdatei (.par) hiervon unberührt bleibt.

TRUNCATE TABLE ist eine Oracle SQL-Erweiterung, die in MySQL übernommen wurde.

13.2.10. UPDATE

Syntax für eine Tabelle:

UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
    SET col_name1=expr1 [, col_name2=expr2 ...]
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

Syntax für mehrere Tabellen:

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1=expr1 [, col_name2=expr2 ...]
    [WHERE where_condition]

Bei der Ein-Tabellen-Syntax aktualisiert die UPDATE-Anweisung Spalten in vorhandenen Datensätzen in tbl_name mit neuen Werten. Die SET-Klausel gibt an, welche Spalten geändert werden und welche Werte diese erhalten sollen. Sofern angegeben, bestimmt die WHERE-Klausel die Bedingungen dafür, welche Datensätze geändert werden. Ohne WHERE-Klausel werden alle Datensätze aktualisiert. Wenn die ORDER BY-Klausel vorhanden ist, werden die Datensätze in der angegebenen Reihenfolge aktualisiert. Die LIMIT-Klausel kann die Anzahl der zu aktualisierenden Datensätze beschränken.

Bei der Mehrtabellensyntax aktualisiert UPDATE in jeder Tabelle table_references die Datensätze, die die Bedingungen erfüllen. In diesem Fall können ORDER BY und LIMIT nicht verwendet werden.

where_condition ist ein Ausdruck, der für jeden zu aktualisierenden Datensatz wahr ist. Er wird wie in Abschnitt 13.2.7, „SELECT, beschrieben angegeben.

Die UPDATE-Anweisung unterstützt die folgenden Modifizierer:

  • Wenn Sie das Schlüsselwort LOW_PRIORITY angeben, wird die Ausführung von UPDATE verzögert, bis kein Client mehr aus der Tabelle liest.

  • Wenn Sie das Schlüsselwort IGNORE verwenden, bricht die UPDATE-Anweisung auch dann nicht ab, wenn während der Aktualisierung Fehler auftreten. Datensätze, bei denen Konflikte aufgrund von Schlüsseldubletten auftreten, werden nicht geändert. Datensätze, bei denen Spalten auf Werte gesetzt werden würden, die Datenkonvertierungsfehler zur Folge hätten, werden stattdessen auf den nächstgelegenen gültigen Wert gesetzt.

Wenn Sie in einem Ausdruck auf eine Spalte in der Tabelle tbl_name zugreifen, verwendet UPDATE den aktuellen Wert der Spalte. So erhöht die folgende Anweisung beispielsweise den aktuellen Wert in der Spalte age um 1:

UPDATE persondata SET age=age+1;

UPDATE-Zuordnungen werden von links nach rechts ausgewertet. Die folgende Anweisung etwa verdoppelt die Spalte age und erhöht sie dann um 1:

UPDATE persondata SET age=age*2, age=age+1;

Wenn Sie eine Spalte auf den Wert aktualisieren, den sie ohnehin gerade hat, dann bemerkt MySQL dies und führt keine Aktualisierung durch.

Wenn Sie eine als NOT NULL deklarierte Spalte aktualisieren, indem Sie sie auf NULL setzen, wird die Spalte stattdessen auf den für den jeweiligen Datentyp vorgesehenen Standardwert gesetzt und der Warnungszähler erhöht. Der Vorgabewert ist 0 bei numerischen Typen, der Leer-String ('') bei String-Typen und der „Nullwert“ für Datums- und Uhrzeittypen.

UPDATE gibt die Anzahl der tatsächlich geänderten Datensätze zurück. Die C-API-Funktion mysql_info() hingegen gibt die Anzahl der Datensätze, die gefunden und aktualisiert wurden, sowie die Anzahl der Warnungen zurück, die während der UPDATE-Operation aufgetreten sind.

Sie können LIMIT row_count verwenden, um den Geltungsbereich von UPDATE einzuschränken. Eine LIMIT-Klausel ist eine Beschränkung für Datensätze. Die Anweisung endet, sobald eine Anzahl von row_count Datensätzen gefunden wurde, die der WHERE-Klausel entsprechen – unabhängig davon, ob sie dann auch geändert wurden oder nicht.

Wenn eine UPDATE-Anweisung eine ORDER BY-Klausel enthält, werden die Datensätze in der in der Klausel angegebenen Reihenfolge aktualisiert.

Sie können auch UPDATE-Operationen durchführen, die sich auf mehrere Tabellen beziehen. Allerdings können Sie ORDER BY oder LIMIT nicht in einer UPDATE-Anweisung für mehrere Tabellen verwenden. Die Klausel table_references listet die Tabellen auf, die im Join berücksichtigt werden. Die Syntax ist in Abschnitt 13.2.7.1, „JOIN, beschrieben. Hier ein Beispiel:

UPDATE items,month SET items.price=month.price
WHERE items.id=month.id;

Das obige Beispiel zeigt einen inneren Join, der den Kommaoperator verwendet. UPDATE-Anweisungen für mehrere Tabellen können jedoch einen beliebigen Join-Typ verwenden, der für SELECT-Anweisungen zulässig ist, also etwa LEFT JOIN.

Sie benötigen die Berechtigung UPDATE nur für diejenigen in einer UPDATE-Anweisung für mehrere Tabellen referenzierten Spalten, die tatsächlich geändert werden. Die Berechtigung SELECT hingegen benötigen Sie für alle Spalten, die gelesen, aber nicht modifiziert werden.

Wenn Sie eine UPDATE-Anweisung für mehrere Tabellen verwenden, die auch InnoDB-Tabellen einbezieht, für die Fremdschlüssel-Constraints vorhanden sind, dann verarbeitet der MySQL-Optimierer die Tabellen unter Umständen in einer Reihenfolge, die sich von der ihrer Parent/Child-Beziehung unterscheidet. In diesem Fall schlägt die Anweisung fehl, und es wird ein Rollback durchgeführt. Stattdessen sollten Sie die Änderung dann in nur einer Tabelle durchführen und sich auf die ON UPDATE-Funktionalität verlassen, die InnoDB bietet, um andere Tabellen entsprechend zu ändern. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

Zurzeit können Sie in einer Unterabfrage keine Aktualisierungsoperation in einer Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

13.3. Grundlegende Befehle des MySQL-Dienstprogramms für Benutzer

13.3.1. DESCRIBE (Informationen über Spalten abrufen)

{DESCRIBE | DESC} tbl_name [col_name | wild]

DESCRIBE vermittelt Informationen zu Spalten in einer Tabelle. Es handelt sich um ein Synonym für SHOW COLUMNS FROM. Diese Anweisungen erlauben auch die Anzeige von Informationen zu Views. (Siehe auch Abschnitt 13.5.4.3, „SHOW COLUMNS.)

col_name kann ein Spaltenname oder aber ein String sein, der die SQL-Jokerzeichen ‘%’ und ‘_’ enthält, um eine Ausgabe nur zu Spalten zu erhalten, die dem String entsprechen. Sie müssen den String nicht in Anführungszeichen setzen, sofern er nicht Leerzeichen oder andere Sonderzeichen enthält.

mysql> DESCRIBE city;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name       | char(35) | NO   |     |         |                |
| Country    | char(3)  | NO   | UNI |         |                |
| District   | char(20) | YES  | MUL |         |                |
| Population | int(11)  | NO   |     | 0       |                |
+------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

Field gibt den Spaltennamen an.

Das Feld Null zeigt an, ob NULL-Werte in der Spalte gespeichert werden können.

Das Feld Key gibt an, ob die Spalte indiziert ist. Mit PRI wird angegeben, dass die Spalte Teil des Primärschlüssels der Tabelle ist, mit UNI hingegen, dass sie Teil eines eindeutigen Indexes ist. Der Wert MUL schließlich signalisiert, dass mehrere Instanzen eines gegebenen Werts innerhalb der Spalte zulässig sind.

Ein möglicher Grund für die Anzeige von MUL in einem eindeutigen Index besteht darin, dass mehrere Spalten einen zusammengesetzten eindeutigen Index bilden. Dann ist die Kombination der Spalten eindeutig, während die einzelnen Spalten durchaus mehrere Instanzen eines gegebenen Werts enthalten können. Beachten Sie, dass in einem zusammengesetzten Index nur die links stehende Spalte einen Eintrag im Feld Key hat.

Das Feld Default gibt den Standardwert der Spalte an.

Das Feld Extra enthält zusätzliche Angaben, die zu einer gegebenen Spalte verfügbar sind. Im gezeigten Beispiel gibt Extra an, dass die Spalte Id mit dem Schlüsselwort AUTO_INCREMENT erstellt wurde.

Die Anweisung DESCRIBE ist aus Gründen der Kompatibilität mit Oracle vorhanden.

Auch die Anweisungen SHOW CREATE TABLE und SHOW TABLE STATUS bieten Informationen zu Tabellen. Siehe auch Abschnitt 13.5.4, „SHOW.

13.3.2. USE

USE db_name

Die Anweisung USE db_name weist MySQL an, die Datenbank db_name als Standarddatenbank (d. h. als aktuelle Datenbank) zu benutzen, auf die sich nachfolgende Anweisungen beziehen. Die Datenbank wird bis zum Ende der Sitzung oder aber so lange als Vorgabe verwendet, bis eine andere USE-Anweisung abgesetzt wird:

USE db1;
SELECT COUNT(*) FROM mytable;   # selects from db1.mytable
USE db2;
SELECT COUNT(*) FROM mytable;   # selects from db2.mytable

Wenn Sie eine bestimmte Datenbank mit USE zur Standarddatenbank machen, können Sie trotzdem auf Tabellen in anderen Datenbanken zugreifen. Im folgenden Beispiel wird auf die Tabelle author in der Datenbank db1 und die Tabelle editor in der Datenbank db2 zugegriffen:

USE db1;
SELECT author_name,editor_name FROM author,db2.editor
  WHERE author.editor_id = db2.editor.editor_id;

Die Anweisung USE ist aus Gründen der Kompatibilität mit Sybase vorhanden.

13.4. Transaktionale und Sperrbefehle von MySQL

MySQL unterstützt lokale Transaktionen (über eine gegebene Clientverbindung) unter Verwendung von Anweisungen wie SET AUTOCOMMIT, START TRANSACTION, COMMIT und ROLLBACK. Siehe auch Abschnitt 13.4.1, „BEGIN/COMMIT/ROLLBACK. Die Unterstützung von XA-Transaktionen erlaubt MySQL außerdem die Teilnahme an verteilten Transaktionen. Siehe auch Abschnitt 13.4.7, „XA-Transaktionen“.

13.4.1. BEGIN/COMMIT/ROLLBACK

START TRANSACTION | BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET AUTOCOMMIT = {0 | 1}

Die Anweisungen START TRANSACTION und BEGIN starten eine neue Transaktion. COMMIT übergibt die aktuelle Transaktion, macht also die entsprechenden Änderungen permanent. Mit ROLLBACK machen Sie die laufende Transaktion rückgängig, d. h., alle Änderungen werden zurückgenommen. Die Anweisung SET AUTOCOMMIT schließlich aktiviert oder deaktiviert den standardmäßigen Autocommit-Modus für die aktuelle Verbindung.

Das optionale Schlüsselwort WORK wird für COMMIT und RELEASE unterstützt, ebenso die CHAIN- und RELEASE-Klauseln. CHAIN und RELEASE können verwendet werden, um den Transaktionsabschluss besser steuern zu können. Der Wert der Systemvariablen completion_type bestimmt das Standardverhalten beim Transaktionsabschluss. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

Die AND CHAIN-Klausel bewirkt, dass eine neue Transaktion beginnt, sobald die aktuelle endet. Die neue Transaktion hat dabei dieselbe Isolierungsstufe wie die zuvor beendete Transaktion. Die RELEASE-Klausel bewirkt, dass der Server die aktuelle Clientverbindung nach Abschluss der aktuellen Transaktion beendet. Das Schlüsselwort NO unterdrückt den Abschluss von CHAIN oder RELEASE. Dies kann nützlich sein, wenn aufgrund der Einstellung der Systemvariablen completion_type der Abschluss von CHAIN oder RELEASE standardmäßig erzwungen wird.

Standardmäßig läuft MySQL im Autocommit-Modus. Das bedeutet, dass, sobald eine Anweisung ausgeführt wird, die eine Tabelle aktualisiert (also ändert), MySQL diese Änderung auf Festplatte speichert.

Verwenden Sie eine transaktionssichere Speicher-Engine (wie InnoDB, BDB oder NDB Cluster), dann können Sie den Autocommit-Modus mit der folgenden Anweisung deaktivieren:

SET AUTOCOMMIT=0;

Nach der Deaktivierung des Autocommit-Modus durch Setzen der AUTOCOMMIT-Variablen auf Null müssen Sie Ihre Änderungen mit COMMIT auf Festplatte speichern oder mit ROLLBACK rückgängig machen, wenn Sie die seit Beginn der Transaktion vorgenommenen Änderungen nicht übernehmen wollen.

Um den Autocommit-Modus für eine einzelne Abfolge von Anweisungen zu deaktivieren, verwenden Sie die Anweisung START TRANSACTION:

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;

Bei START TRANSACTION bleibt Autocommit deaktiviert, bis Sie die Transaktion mit COMMIT oder ROLLBACK beenden. Der Autocommit-Modus kehrt dann in seinen vorherigen Status zurück.

BEGIN und BEGIN WORK werden als Aliase für START TRANSACTION benutzt, um eine Transaktion zu starten. START TRANSACTION ist die SQL-Standardsyntax und wird als Möglichkeit zur Durchführung spontaner Transaktionen empfohlen.

Die BEGIN-Anweisung unterscheidet sich von der Verwendung des Schlüsselworts BEGIN, welches eine mehrteilige BEGIN ... END-Anweisung einleitet. Mit Letzterem wird keine Transaktion begonnen. Siehe auch Abschnitt 19.2.5, „BEGIN ... END-Syntax für komplexe Anweisungen“.

Sie können eine Transaktion auch wie folgt einleiten:

START TRANSACTION WITH CONSISTENT SNAPSHOT;

Die Klausel WITH CONSISTENT SNAPSHOT startet eine konsistente Leseoperation für Speicher-Engines, die diese unterstützen. Derzeit betrifft dies nur InnoDB. Der Effekt ist derselbe wie beim Absetzen einer START TRANSACTION-Anweisung gefolgt von einer SELECT-Anweisung für eine beliebige InnoDB-Tabelle. Siehe auch Abschnitt 14.2.10.4, „Konsistentes Lesen“.

Die Klausel WITH CONSISTENT SNAPSHOT ändert die aktuelle Isolationsstufe der Transaktion nicht, d. h., eine konsistente Momentaufnahme wird nur dann erstellt, wenn die aktuelle Isolationsstufe konsistente Leseoperationen gestattet (REPEATABLE READ oder SERIALIZABLE).

Bei Beginn einer Transaktion wird implizit UNLOCK TABLES ausgeführt.

Beste Ergebnisse erhalten Sie, wenn Sie Transaktionen nur bei Tabellen durchführen, die mit einer einzelnen transaktionssicheren Speicher-Engine verwaltet werden. Andernfalls können die folgenden Probleme auftreten:

  • Wenn Ihre Tabellen mehrere transaktionssichere Speicher-Engines verwenden (z. B. InnoDB und BDB) und die Isolationsstufe nicht SERIALIZABLE ist, besteht die Möglichkeit, dass, wenn eine Transaktion übergeben wird, eine andere laufende Transaktion, die dieselben Tabellen benutzt, nur einen Teil der durch die erste Transaktion vorgenommenen Änderungen erkennt. Die Atomizität der Transaktionen ist mithin bei Verwendung mehrerer Engines nicht gewährleistet, und es können Inkonsistenzen auftreten. (Wenn Transaktionen mehrerer Engines nicht häufig vorkommen, können Sie die Isolationsstufe mit SET TRANSACTION ISOLATION LEVEL für eine Transaktion nach Bedarf auf SERIALIZABLE setzen.)

  • Verwenden Sie in einer Transaktion nichttransaktionssichere Tabellen, dann werden alle Änderungen an diesen Tabellen unabhängig vom Status des Autocommit-Modus sofort gespeichert.

    Wenn Sie nach Aktualisierung einer nichttransaktionssicheren Tabelle in einer Transaktion eine ROLLBACK-Anweisung absetzen, erscheint die Warnung ER_WARNING_NOT_COMPLETE_ROLLBACK. Änderungen an transaktionssicheren Tabellen werden in diesem Fall rückgängig gemacht, nicht jedoch Änderungen an nichttransaktionssicheren Tabellen.

Jede Transaktion wird nach Absetzen von COMMIT am Stück in das Binärlog geschrieben. Transaktionen, die per Rollback rückgängig gemacht wurden, werden nicht geloggt. (Ausnahme: Für Modifikationen an nicht transaktionssicheren Tabellen kann kein Rollback durchgeführt werden. Wenn eine Transaktion, für die ein Rollback erfolgt, Änderungen an nicht transaktionssicheren Tabellen enthält, dann wird die gesamte Transaktion am Ende mit einer ROLLBACK-Anweisung geloggt, um sicherzustellen, dass die Modifikationen an diesen Tabellen repliziert werden.) Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

Sie können die Isolationsstufe für Transaktionen mit SET TRANSACTION ISOLATION LEVEL ändern. Siehe auch Abschnitt 13.4.6, „SET TRANSACTION.

Ein Rollback kann ein relativ langsamer Vorgang sein, der zudem stattfinden kann, ohne dass der Benutzer dies explizit angefordert hat (z. B. wenn ein Fehler aufgetreten ist). Aufgrund dieser Tatsache zeigt SHOW PROCESSLIST in der Spalte State für die Verbindung Rolling back an, solange implizite oder (durch die SQL-Anweisung ROLLBACK) explizite Rollbacks durchgeführt werden.

13.4.2. Statements können nicht zurückgerollt werden

Es gibt Anweisungen, für die kein Rollback möglich ist. Hierzu gehören DDL-Anweisungen (Data Definition Language), z. B. solche, mit denen Datenbanken erstellt oder gelöscht oder Tabellen oder gespeicherte Routinen erstellt, gelöscht oder geändert werden.

Sie sollten Ihre Transaktionen so entwickeln, dass solche Anweisungen nicht vorhanden sind. Wenn Sie eine Anweisung früh in einer Transaktion absetzen, für die kein Rollback möglich ist, und dann später eine andere Anweisung fehlschlägt, dann können durch Absetzen der ROLLBACK-Anweisung nicht alle Auswirkungen der Transaktion rückgängig gemacht werden.

13.4.3. Anweisungen, die implizite Commits verursachen

Alle folgenden Anweisungen (und ggf. auch ihre Synonyme) beenden eine Transaktion implizit – so als ob Sie vor Ausführung der Anweisung eine COMMIT-Anweisung abgesetzt hätten:

  • ALTER FUNCTION, ALTER PROCEDURE, ALTER TABLE, BEGIN, CREATE DATABASE, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, DROP DATABASE, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP TABLE, LOAD MASTER DATA, LOCK TABLES, RENAME TABLE, SET AUTOCOMMIT=1, START TRANSACTION, TRUNCATE TABLE, UNLOCK TABLES.

  • UNLOCK TABLES übergibt eine Transaktion nur dann, wenn zum betreffenden Zeitpunkt Tabellen gesperrt sind.

  • Die Anweisung CREATE TABLE in InnoDB wird als einzelne Transaktion verarbeitet. Das bedeutet, dass eine ROLLBACK-Anweisung seitens des Benutzers die CREATE TABLE-Anweisungen, die der Benutzer während der Transaktion abgesetzt hat, nicht rückgängig machen kann.

Transaktionen können nicht verschachtelt werden. Dies ist eine Folge des impliziten COMMIT, das für jede laufende Transaktion ausgeführt wird, wenn Sie eine START TRANSACTION-Anweisung (oder ein entsprechendes Synonym) absetzen.

13.4.4. SAVEPOINT und ROLLBACK TO SAVEPOINT

SAVEPOINT identifier
ROLLBACK [WORK] TO SAVEPOINT identifier
RELEASE SAVEPOINT identifier

InnoDB unterstützt die SQL-Anweisungen SAVEPOINT, ROLLBACK TO SAVEPOINT, RELEASE SAVEPOINT und das optionale Schlüsselwort WORK für ROLLBACK.

Die SAVEPOINT-Anweisung setzt einen benannten Transaktionsspeicherpunkt mit dem Namen identifier. Hat die laufende Transaktion einen Speicherpunkt gleichen Namens, dann wird der alte Speicherpunkt gelöscht und ein neuer gesetzt.

Die Anweisung ROLLBACK TO SAVEPOINT macht eine Transaktion bis zum benannten Speicherpunkt rückgängig. Änderungen, die die aktuelle Transaktion an Datensätzen nach dem Speicherpunkt vorgenommen hat, werden im Rollback rückgängig gemacht; allerdings hebt InnoDB Datensatzsperren, die nach dem Speicherpunkt im Speicher abgelegt wurden, nicht auf. (Beachten Sie, dass bei einem neu eingefügten Datensatz die Sperrinformation in dem im Datensatz gespeicherten Transaktionsbezeichner enthalten ist, d. h., die Sperre wird nicht separat im Speicher abgelegt. In diesem Fall wird die Datensatzsperre beim Rückgängigmachen aufgehoben.) Speicherpunkte, die zeitlich nach dem genannten Speicherpunkt liegen, werden gelöscht.

Wenn die ROLLBACK TO SAVEPOINT-Anweisung den folgenden Fehler zurückgibt, heißt das, dass es keinen Speicherpunkt des angegebenen Namens gibt:

ERROR 1181: Got error 153 during ROLLBACK

Die Anweisung RELEASE SAVEPOINT entfernt den genannten Speicherpunkt aus der Menge der Speicherpunkte für die laufende Transaktion. Es findet weder eine Übergabe noch ein Rollback statt. Existiert der Speicherpunkt nicht, dann tritt ein Fehler auf.

Alle Speicherpunkte der aktuellen Transaktion werden gelöscht, wenn Sie eine COMMIT- oder ROLLBACK-Anweisung absetzen, die keinen Speicherpunkt benennt.

Seit MySQL 5.0.17 wird eine neue Speicherpunktstufe erstellt, wenn eine gespeicherte Funktion aufgerufen oder ein Trigger aktiviert wird. Die Speicherpunkte der vorherigen Stufen sind dann nicht mehr verfügbar, damit Konflikte mit Speicherpunkten der neuen Stufe vermieden werden. Wenn die Funktion oder der Trigger beendet wird, werden alle hierdurch erstellten Speicherpunkte gelöscht und die vorherige Speicherpunktstufe wird wiederhergestellt.

13.4.5. LOCK TABLES und UNLOCK TABLES

LOCK TABLES
    tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}
    [, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...
UNLOCK TABLES

LOCK TABLES sperrt Tabellen für den aktuellen Thread. Wenn eine Tabelle von anderen Threads gesperrt ist, wird der laufende Vorgang angehalten, bis alle Sperren erwirkt werden können. UNLOCK TABLES hebt Sperren auf, die vom aktuellen Thread gehalten werden. Die Sperren aller Tabellen, die vom aktuellen Thread gesperrt werden, werden implizit aufgehoben, wenn der Thread eine andere LOCK TABLES-Anweisung absetzt oder die Verbindung zum Server geschlossen wird.

Eine Tabellensperre schützt nur gegen unangemessene Lese- und Schreiboperationen durch andere Clients. Der Client, der die Sperre (auch eine Lesesperre) hält, kann Operationen auf Tabellenebene – wie etwa DROP TABLE – durchführen.

Beachten Sie die folgenden Angaben zur Verwendung von LOCK TABLES bei transaktionssicheren Tabellen:

  • LOCK TABLES ist nicht transaktionssicher und übergibt implizit alle aktiven Transaktionen, bevor versucht wird, die Sperre für die Tabelle zu erwirken. Auch das Starten einer Transaktion (z. B. bei START TRANSACTION) führt implizit eine UNLOCK TABLES-Anweisung aus. (Siehe auch Abschnitt 13.4.3, „Anweisungen, die implizite Commits verursachen“.)

  • Die korrekte Vorgehensweise bei der Verwendung von LOCK TABLES in Verbindung mit transaktionssicheren Tabellen wie InnoDB besteht darin, AUTOCOMMIT = 0 zu setzen und UNLOCK TABLES erst dann aufzurufen, wenn die Transaktion explizit übergeben werden soll. Wenn Sie LOCK TABLES aufrufen, setzt InnoDB intern eine eigene Tabellensperre. Auch MySQL setzt eine eigene Tabellensperre. InnoDB hebt seine Sperre beim nächsten Commit-Vorgang auf; damit MySQL seinerseits die Sperre aufhebt, müssen Sie UNLOCK TABLES aufrufen. Sie sollten AUTOCOMMIT = 1 nicht setzen, weil InnoDB dann seine Tabellensperre direkt nach dem Aufruf von LOCK TABLES aufhebt; auf diese Weise kann es zu einer vollständigen Sperrung kommen. Beachten Sie, dass bei AUTOCOMMIT = 1 die InnoDB-Tabellensperre überhaupt nicht gesetzt wird, damit ältere Anwendungen sich nicht versehentlich vollständig ausschließen.

  • ROLLBACK hebt die Sperren bei den nichttransaktionssicheren Tabellen von MySQL nicht auf.

Um LOCK TABLES zu verwenden, benötigen Sie die Berechtigungen LOCK TABLES und SELECT für die betreffenden Tabellen.

Die wichtigsten Gründe zur Verwendung von LOCK TABLES sind die Emulation von Transaktionen oder die Beschleunigung der Aktualisierung von Tabellen. Wir werden dies weiter unten ausführlicher erläutern.

Wenn ein Thread eine Lesesperre für eine Tabelle erwirkt, kann dieser Thread (wie auch alle übrigen Threads) aus der Tabelle nur lesen. Wenn ein Thread eine Schreibsperre für eine Tabelle erwirkt, dann kann nur der Thread, der die Sperre hält, in die Tabelle schreiben. Anderen Threads wird dies untersagt, bis die Sperre aufgehoben ist.

Der Unterschied zwischen READ LOCAL und READ besteht darin, dass READ LOCAL bei aktiver Sperre die Ausführung von INSERT-Anweisungen (also nebenläufigen Einfügeoperationen) zulässt, sofern sie keine Konflikte auslösen. Allerdings kann diese Funktion nicht verwendet werden, um die Datenbankdateien bei aktiver Sperre außerhalb von MySQL zu manipulieren. Bei InnoDB-Tabellen entspricht READ LOCAL READ.

Wenn Sie LOCK TABLES einsetzen, müssen Sie alle Tabellen sperren, die Sie in Ihren Abfragen zu benutzen beabsichtigen. Solange die mit einer LOCK TABLES-Anweisung erwirkten Sperren gültig sind, können Sie nicht auf Tabellen zugreifen, die nicht durch die Anweisung gesperrt wurden. Ferner können Sie eine gesperrte Tabelle auch nicht mehrfach in derselben Abfrage verwenden. Benutzen Sie stattdessen Aliase. In diesem Fall müssen Sie allerdings für jeden Alias separat eine Sperre erwirken.

mysql> LOCK TABLE t WRITE, t AS t1 WRITE;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;

Wenn Ihre Abfragen eine Tabelle unter Verwendung eines Alias referenzieren, müssen Sie die Tabelle sperren, die denselben Alias benutzt. Die Tabelle zu sperren, ohne den Alias anzugeben, funktioniert nicht:

mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

Umgekehrt müssen Sie, wenn Sie eine Tabelle unter Verwendung eines Alias sperren, diese Tabelle unter Verwendung dieses Alias in Ihren Abfragen referenzieren:

mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;

WRITE-Sperren haben in der Regel Vorrang vor READ-Sperren. Hierdurch soll sichergestellt werden, dass Aktualisierungen so schnell wie möglich verarbeitet werden. Das bedeutet, dass, wenn ein Thread eine READ-Sperre erwirkt und dann ein anderer Thread eine WRITE-Sperre anfordert, nachfolgende READ-Sperranforderungen warten müssen, bis der WRITE-Thread die Sperre wieder aufgehoben hat. Sie können mit LOW_PRIORITY WRITE-Sperren anderen Threads das Erwirken von READ-Sperren gestatten, während der Thread auf die WRITE-Sperre wartet. LOW_PRIORITY WRITE-Sperren sollten Sie nur dann verwenden, wenn Sie sicher sind, dass zu einem nachfolgenden Zeitpunkt keine Threads mehr eine READ-Sperre halten werden.

LOCK TABLES funktioniert wie folgt:

  1. Alle zu sperrenden Tabellen werden in einer intern definierten Reihenfolge sortiert. Aus Sicht des Benutzers ist diese Reihenfolge undefiniert.

  2. Wenn eine Tabelle mit einer Lese- und einer Schreibsperre gesperrt ist, wird die Schreib- vor der Lesesperre gesetzt.

  3. Es wird immer nur eine Tabelle gleichzeitig gesperrt, bis der Thread alle Sperren erhalten hat.

Diese Vorgehensweise gewährleistet, dass ein Aussperren ausgeschlossen ist. Es gibt jedoch ein paar andere Aspekte, die Sie bezüglich der Vorgehensweise beachten sollten:

Wenn Sie eine LOW_PRIORITY WRITE-Sperre für eine Tabelle verwenden, bedeutet dies lediglich, dass MySQL auf diese bestimmte Sperre wartet, bis keine Threads mehr vorhanden sind, die eine READ-Sperre benötigen. Wenn der Thread die WRITE-Sperre erwirkt hat und darauf wartet, die Sperre für die nächste Tabelle in der Sperrliste zu erwirken, warten alle anderen Threads darauf, dass die WRITE-Sperre aufgehoben wird. Wenn dies in Bezug auf Ihre Anwendung ein schwerwiegendes Problem darstellen sollte, dann sollten Sie in Betracht ziehen, einige Ihrer Tabellen in transaktionssichere Tabellen umzuwandeln.

Sie können einen Thread, der auf eine Tabellensperre wartet, problemlos mit KILL terminieren. Siehe auch Abschnitt 13.5.5.3, „KILL.

Beachten Sie, dass Sie keine Tabellen sperren sollen, die Sie mit INSERT DELAYED verwenden, weil die Einfügeoperation in diesem Fall durch einen separaten Thread durchgeführt wird.

Normalerweise müssen Sie Tabellen nicht sperren, weil alle UPDATE-Anweisungen für sich atomisch sind: Kein anderer Thread kann eine andere derzeit ausgeführte SQL-Anweisung unterbrechen. Allerdings gibt es einige wenige Fälle, in denen das Sperren von Tabellen von Vorteil sein kann:

  • Wenn Sie viele Operationen für eine Anzahl von MyISAM-Tabellen ausführen wollen, geht dies schneller, wenn Sie die zu verwendenden Tabellen sperren. Das Sperren von MyISAM-Tabellen beschleunigt das Einfügen, Aktualisieren und Löschen in diesen Tabellen. Der Nachteil besteht darin, dass kein Thread eine READ-gesperrte Tabelle ändern kann (einschließlich derjenigen, die die Sperre hält) und dass kein Thread auf eine WRITE-gesperrte Tabelle mit Ausnahme derjenigen zugreifen kann, die die Sperre hält.

    Der Grund dafür, dass MyISAM-Operationen unter LOCK TABLES schneller ausgeführt werden, besteht darin, dass MySQL den Schlüssel-Cache gesperrter Tabellen erst beim Aufruf von UNLOCK TABLES synchronisiert. Normalerweise wird der Schlüssel-Cache nach jeder SQL-Anweisung synchronisiert.

  • Wenn Sie eine Speicher-Engine in MySQL verwenden, die Transaktionen nicht unterstützt, müssen Sie LOCK TABLES einsetzen, um sicherzustellen, dass kein anderer Thread zwischen eine SELECT- und eine UPDATE-Anweisung gelangt. Folgendes Beispiel erfordert LOCK TABLES, um sicher ausgeführt werden zu können:

    LOCK TABLES trans READ, customer WRITE;
    SELECT SUM(value) FROM trans WHERE customer_id=some_id;
    UPDATE customer
      SET total_value=sum_from_previous_statement
      WHERE customer_id=some_id;
    UNLOCK TABLES;
    

    Ohne LOCK TABLES könnte ein anderer Thread unter Umständen zwischen der Ausführung der SELECT- und der Ausführung der UPDATE-Anweisung einen neuen Datensatz in die trans-Tabelle einfügen.

Sie können die Verwendung von LOCK TABLES in vielen Fällen umgehen, indem Sie relative Updates (UPDATE customer SET value=value+new_value) oder die Funktion LAST_INSERT_ID() verwenden. Siehe auch Abschnitt 1.9.5.3, „Transaktionen“.

Sie können das Sperren von Tabellen in manchen Fällen auch umgehen, indem Sie Funktionen für beratende Sperrungen auf Benutzerebene (GET_LOCK() und RELEASE_LOCK()) verwenden. Diese Sperren werden in einer Hash-Tabelle auf dem Server gespeichert und mit pthread_mutex_lock() und pthread_mutex_unlock() mit dem Ziel einer hohen Geschwindigkeit implementiert. Siehe auch Abschnitt 12.10.4, „Verschiedene Funktionen“.

Weitere Informationen zu Methoden beim Sperren finden Sie in Abschnitt 7.3.1, „Wie MySQL Tabellen sperrt“.

Sie können mit der Anweisung FLUSH TABLES WITH READ LOCK Lesesperren für alle Tabellen in allen Datenbanken setzen. Siehe auch Abschnitt 13.5.5.2, „FLUSH. Dies ist eine recht praktische Möglichkeit der Datensicherung, wenn Sie ein Dateisystem wie Veritas einsetzen, das rechtzeitig Schnappschüsse erstellt.

Hinweis: Wenn Sie ALTER TABLE für eine gesperrte Tabelle ausführen, kann die Sperre unter Umständen aufgehoben werden. Siehe auch Abschnitt A.7.1, „Probleme mit ALTER TABLE.

13.4.6. SET TRANSACTION

SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

Diese Anweisung bestimmt die Transaktionsisolationsstufe für die nächste Transaktion, global oder für die aktuelle Sitzung.

Das Standardverhalten von SET TRANSACTION besteht darin, die Isolationsstufe für die nächste (d. h. noch nicht gestartete) Transaktion einzustellen. Wenn Sie das Schlüsselwort GLOBAL verwenden, setzt die Anweisung die Standardtransaktionsstufe global für alle neuen Verbindungen, die nachfolgend hergestellt werden. Vorhandene Verbindungen werden hiervon nicht berührt. Für diesen Zweck benötigen Sie die Berechtigung SUPER. Bei Verwendung des Schlüsselworts SESSION wird die standardmäßige Transaktionsstufe für alle zukünftigen Transaktionen gesetzt, die über die aktuelle Verbindung durchgeführt werden.

Beschreibungen aller InnoDB-Transaktionsisolationsstufen finden Sie in Abschnitt 14.2.10.3, „InnoDB und TRANSACTION ISOLATION LEVEL. InnoDB unterstützt in MySQL 5.1 alle Stufen. Die Standardstufe ist REPEATABLE READ.

Um die globale Standardisolationsstufe für mysqld festzulegen, verwenden Sie die Option --transaction-isolation. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

13.4.7. XA-Transaktionen

Die Unterstützung von XA-Transaktionen ist für die InnoDB-Speicher-Engine verfügbar. Die XA-Implementierung bei MySQL basiert auf dem X/Open CAE-Dokument Distributed Transaction Processing: The XA Specification („Verteilte Transaktionsverarbeitung: Die XA-Spezifikation“). Dieses Dokument wurde von The Open Group veröffentlicht und ist unter http://www.opengroup.org/public/pubs/catalog/c193.htm erhältlich. Die Grenzen der aktuellen XA-Implementierung sind in Abschnitt I.5, „Beschränkungen bei XA-Transaktionen“ beschrieben.

Clientseitig gibt es keine besonderen Anforderungen. Die XA-Schnittstelle zu einem MySQL Server besteht aus SQL-Anweisungen, die mit dem Schlüsselwort XA beginnen. MySQL-Clientprogramme müssen SQL-Anweisungen senden und die Semantik der XA-Anweisungsschnittstelle verstehen können. Sie müssen nicht mit einer aktuellen Clientbibliothek verknüpft sein: Es können auch ältere Clientbibliotheken verwendet werden.

Derzeit unterstützt MySQL Connector/J 5.0.0 XA direkt (mithilfe einer Klassenschnittstelle, die die XA-SQL-Anweisungsschnittstelle für Sie verwaltet).

XA unterstützt verteilte Transaktionen, d. h., mehrere separate transaktionssichere Ressourcen können an einer globalen Transaktion teilnehmen. Transaktionssichere Ressourcen sind häufig relationale Datenbanksysteme, es gibt aber auch andere Ressourcentypen.

Eine globale Transaktion umfasst mehrere Aktionen, die für sich transaktionssicher sind; sie alle aber müssen entweder als Gruppe erfolgreich abgeschlossen werden, oder sie werden im Rahmen eines Rollbacks gemeinsam rückgängig gemacht. Im Endeffekt erweitert dies die ACID-Eigenschaften um eine „Ebene nach oben“, sodass mehrere ACID-Transaktionen konzertiert als Komponenten einer globalen Operation ausgeführt werden, die ebenfalls ACID-Eigenschaften hat. (Allerdings müssen Sie bei einer verteilten Transaktion die Isolationsstufe SERIALIZABLE benutzen, um ACID-Eigenschaften zu erhalten. Bei nichtverteilten Transaktionen ist REPEATABLE READ ausreichend, nicht aber bei verteilten Transaktionen.)

Es folgen einige Beispiele für verteilte Transaktionen:

  • Eine Anwendung kann als Integrations-Tool agieren, welches einen Messaging-Dienst mit einem relationalen Datenbanksystem kombiniert. Die Anwendung stellt sicher, dass Transaktionen, die Versand, Abruf und Verarbeitung von Mitteilungen in Verbindung mit einer transaktionssicheren Datenbank regeln, auch alle in einer globalen Transaktion erfolgen. Man könnte sich dies als „transaktionssichere E-Mail“ vorstellen.

  • Eine Anwendung führt Aktionen durch, die verschiedene Datenbankserver betrifft, z. B. einen MySQL und einen Oracle-Server (oder auch mehrere MySQL Server). Hierbei müssen Aktionen, die mehrere Server betreffen, als Teil einer globalen Transaktion statt als separate Transaktionen stattfinden, die auf jedem Server getrennt ausgeführt werden.

  • Eine Bank speichert Kontendaten in einem relationalen Datenbanksystem. Empfang und Versand von Geld erfolgen über Bankautomaten. Es muss dabei gewährleistet sein, dass alle Vorgänge an den Automaten auf den Konten umgesetzt werden. Dies ist aber nicht allein mit dem Datenbanksystem möglich: Ein globaler Transaktionsmanager integriert Bankautomat- und Datenbankressourcen, um die Gesamtkonsistenz der Finanztransaktionen sicherzustellen.

Anwendungen, die globale Transaktionen verwenden, umfassen einen oder mehrere Ressourcenmanager und einen Transaktionsmanager:

  • Der Ressourcenmanager (RM) ermöglicht den Zugriff auf transaktionssichere Ressourcen. Ein Datenbankserver ist eine Art von Ressourcenmanager. Transaktionen, die vom RM verwaltet werden, müssen entweder im Rahmen eines Commits geschrieben oder im Zuge eines Rollbacks rückgängig gemacht werden können.

  • Ein Transaktionsmanager (TM) koordiniert die Transaktionen, die Teil einer globalen Transaktion sind. Er kommuniziert mit den RMs, die die einzelnen Transaktionen verwalten. Die einzelnen Transaktionen innerhalb einer globalen Transaktion sind die „Verzweigungen“ der globalen Transaktion. Globale Transaktionen und ihre Verzweigungen werden anhand eines Namensschemas unterschieden, welches weiter unten beschrieben werden wird.

Die MySQL-Implementierung von XA erlaubt es einem MySQL Server, als RM zu agieren, der XA-Transaktionen innerhalb einer globalen Transaktion verwaltet. Ein Clientprogramm, das eine Verbindung mit dem MySQL Server herstellt, agiert als TM.

Um eine globale Transaktion auszuführen, ist es erforderlich zu wissen, welche Komponenten betroffen sind, und jede dieser Komponenten an einen Punkt zu bringen, an dem sie übergeben oder rückgängig gemacht werden kann. Abhängig davon, was jede Komponente bezüglich ihres Erfolgs oder Fehlschlags meldet, müssen sie alle als atomische Gruppe übergeben oder rückgängig gemacht werden: Es müssen also entweder alle Komponenten geschrieben werden oder alle Komponenten werden im Zuge eines Rollbacks ungeschehen gemacht. Um eine globale Transaktion verwalten zu können, muss berücksichtigt werden, dass jede Komponente fehlschlagen oder auch das sie verbindende Netzwerk ausfallen kann.

Der Prozess zur Ausführung einer globalen Transaktion basiert auf 2PC (2-Phase Commit, Übergabe in zwei Phasen). Dies findet statt, nachdem die von den Verzweigungen der globalen Transaktion durchgeführten Vorgänge erledigt sind.

  1. In der ersten Phase werden alle Verzweigungen vorbereitet: Sie werden vom TM angewiesen, sich für die Übergabe bereitzuhalten. Normalerweise bedeutet dies, dass jeder RM, der eine Verzweigung verwaltet, die Aktionen für diese Verzweigung in einem zuverlässigen Speicher ablegt. Die Verzweigungen geben an, ob dies jeweils für sie möglich ist. Die Ergebnisse werden in der zweiten Phase verwendet.

  2. In der zweiten Phase weist der TM die RMs an, eine Übergabe oder einen Rollback durchzuführen. Wenn alle Verzweigungen bei der Vorbereitung angegeben haben, dass sie für eine Übergabe bereit sind, werden sie alle zur Übergabe angewiesen. Hat jedoch mindestens eine Verzweigung im Zuge der Vorbereitung gemeldet, dass bei ihr keine Übergabe möglich ist, dann werden alle Verzweigungen zu einem Rollback angewiesen.

In manchen Fällen verwendet eine globale Transaktion unter Umständen nur eine einphasige Übergabe (1PC). Stellt beispielsweise ein TM fest, dass eine globale Transaktion nur eine einzige transaktionssichere Ressource (also nur eine Verzweigung) umfasst, dann kann diese Ressource zur selben Zeit zur Vorbereitung und Übergabe angewiesen werden.

13.4.7.1. SQL-Syntax von XA-Transaktionen

Um XA-Transaktionen in MySQL durchzuführen, verwenden Sie die folgenden Anweisungen:

XA {START|BEGIN} xid [JOIN|RESUME]

XA END xid [SUSPEND [FOR MIGRATE]]

XA PREPARE xid

XA COMMIT xid [ONE PHASE]

XA ROLLBACK xid

XA RECOVER

Bei XA START werden die Klauseln JOIN und RESUME nicht unterstützt.

Bei XA END wird die Klausel SUSPEND [FOR MIGRATE] nicht unterstützt.

Jede XA-Anweisung beginnt mit dem Schlüsselwort XA. Die meisten dieser Anweisungen erfordern einen xid-Wert. xid ist ein XA-Transaktionsbezeichner. Er gibt an, für welche Transaktion die Anweisung gilt. xid-Werte werden vom Client übergeben oder auf dem MySQL Server erzeugt. Ein xid-Wert besteht aus einem bis drei Teilen:

xid: gtrid [, bqual [, formatID ]]

gtrid ist ein globaler Transaktionsbezeichner, bqual ein Verzweigungsbezeichner und formatID eine Zahl, die das Format angibt, welches von den gtrid- und bqual-Werten verwendet wird. Wie aus der Syntax hervorgeht, sind bqual und formatID optional. Der Standardwert von bqual ist '', sofern nichts anderes angegeben ist. Der Standardwert von formatID ist 1, sofern nichts anderes angegeben ist.

gtrid und bqual müssen String-Literale sein, die jeweils bis zu 64 Byte (nicht Zeichen) lang sein dürfen. gtrid und bqual können auf unterschiedliche Art und Weise angegeben werden. Sie können einen String in Anführungszeichen ('ab'), einen Hexadezimal-String (0x6162, X'ab') oder einen Bitwert (b'nnnn') angeben.

formatID ist ein vorzeichenloser Integer.

Die gtrid - und bqual-Werte werden von den XA-Supportroutinen auf dem MySQL Server als Bytewerte interpretiert. Allerdings benutzt der Server bei der Analyse einer SQL-Anweisung, die eine XA-Anweisung enthält, einen speziellen Zeichensatz. Wenn Sie sichergehen wollen, notieren Sie gtrid und bqual als Hexadezimal-String.

xid-Werte werden normalerweise vom TM erzeugt. Die Werte, die von einem TM erzeugt werden, müssen sich von denen unterscheiden, die von anderen TMs gebildet werden. Ein gegebener TM muss seine eigenen xid-Werte in einer Werteliste, die von der Anweisung XA RECOVER zurückgegeben wird, erkennen können.

XA START xid startet eine XA-Transaktion mit dem gegebenen xid-Wert. Jede XA-Transaktion benötigt einen eindeutigen xid-Wert, d. h., der Wert darf nicht gleichzeitig von einer anderen XA-Transaktion verwendet werden. Diese Eindeutigkeit wird mithilfe der Werte gtrid und bqual erzielt. Alle nachfolgenden XA-Anweisungen für die XA-Transaktion müssen unter Verwendung desselben xid-Werts angegeben werden, der in der XA START-Anweisung übergeben wurde. Verwenden Sie eine dieser Anweisungen und geben dabei keinen xid-Wert an, der einer laufenden XA-Transaktion entspricht, dann tritt ein Fehler auf.

Eine oder mehrere XA-Transaktionen können Teil derselben globalen Transaktion sein. Alle XA-Transaktionen in einer gegebenen globalen Transaktion müssen denselben gtrid-Wert im xid-Wert benutzen. Aus diesem Grund müssen gtrid-Werte global eindeutig sein, damit keine Mehrdeutigkeiten darüber aufkommen können, zu welcher globalen Transaktion eine gegebene XA-Transaktion gehört. Der Teil bqual des xid-Werts muss sich für jede XA-Transaktion innerhalb einer globalen Transaktion unterscheiden. (Die Anforderung, dass bqual-Werte unterschiedlich sein müssen, stellt eine Einschränkung der aktuellen XA-Implementierung in MySQL dar. Sie ist nicht Teil der XA-Spezifikation.)

Die Anweisung XA RECOVER gibt Informationen zu denjenigen XA-Transaktionen auf dem MySQL Server zurück, die den Status PREPARED haben. (Siehe auch Abschnitt 13.4.7.2, „XA-Transaktionszustände“.) Die Ausgabe enthält einen Datensatz für jede derartige XA-Transaktion auf dem Server – unabhängig davon, welcher Client sie gestartet hat.

Die Ausgabedatensätze von XA RECOVER sehen wie folgt aus (für einen xid-Beispielwert, der aus den Teilen 'abc', 'def' und 7 besteht):

mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
|        7 |            3 |            3 | abcdef |
+----------+--------------+--------------+--------+

Die Ausgabespalten haben die nachfolgend beschriebenen Bedeutungen:

  • formatID ist der formatID-Teil der Transaktion xid.

  • gtrid_length ist die Länge des gtrid-Teils der Transaktion xid in Byte.

  • bqual_length ist die Länge des bqual-Teils der Transaktion xid in Byte.

  • data ist die Verkettung der Teile gtrid und bqual der Transaktion xid.

13.4.7.2. XA-Transaktionszustände

Eine XA-Transaktion umfasst die folgenden Phasen:

  1. Starten Sie mit XA START eine XA-Transaktion und versetzen Sie sie in den Status ACTIVE.

  2. Sobald die XA-Transaktion aktiv ist, setzen Sie die SQL-Anweisungen für die Transaktion ab. Zuletzt setzen Sie eine XA END-Anweisung ab, mit der Sie die Transaktion in den Zustand IDLE versetzen.

  3. Bei einer XA-Transaktion in diesem Zustand können Sie entweder eine XA PREPARE-Anweisung oder eine XA COMMIT ... ONE PHASE-Anweisung absetzen:

    • XA PREPARE versetzt die Transaktion in den Zustand PREPARED. Bei Eingabe einer XA RECOVER -Anweisung an dieser Stelle wird der xid-Wert der Transaktion in die Ausgabe integriert, weil XA RECOVER alle XA-Transaktionen auflistet, deren Zustand PREPARED ist.

    • XA COMMIT ... ONE PHASE bereit die Transaktion vor und übergibt sie dann direkt. Der xid-Wert wird von XA RECOVER nicht aufgelistet, weil die Transaktion endet.

  4. Bei einer XA-Transaktion im Zustand PREPARED können Sie eine XA COMMIT-Anweisung absetzen, um sie zu übergeben und zu beenden, oder Sie machen sie mit einer XA ROLLBACK-Anweisung rückgängig (sie wird dann ebenfalls beendet).

Es folgt eine einfache XA-Transaktion, die im Rahmen einer globalen Transaktion einen Datensatz in eine Tabelle einfügt:

mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)

mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)

Im Kontext einer gegebenen Clientverbindung schließen sich XA-Transaktionen und lokale Transaktionen (also Nicht-XA-Transaktionen) gegenseitig aus. Wenn beispielsweise mit XA START eine XA-Transaktion gestartet wurde, dann kann eine lokale Transaktion erst begonnen werden, wenn die XA-Transaktion übergeben oder rückgängig gemacht wurde. Umgekehrt können, wenn eine lokale Transaktion mit START TRANSACTION begonnen wurde, XA-Anweisungen erst dann verwendet werden, wenn die Transaktion übergeben oder rückgängig gemacht wurde.

13.5. Anweisungen zur Datenbankadministration

13.5.1. Anweisungen zur Benutzerkontenverwaltung

MySQL-Kontendaten sind in Tabellen der Datenbank mysql gespeichert. Diese Datenbank und das Zugriffssteuerungssystem sind in Kapitel 5, Datenbankverwaltung, ausführlich beschrieben. Sie finden dort weitere Informationen.

Wichtig: Einige Releases von MySQL enthalten Änderungen an der Struktur der Grant-Tabellen, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Upgrade auf eine neue MySQL-Version durchführen, sollten Sie Ihre Grant-Tabellen aktualisieren, damit sichergestellt ist, dass diese auf der aktuellen Struktur basieren und auf diese Weise neue Funktionalitäten nutzen können. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

13.5.1.1. CREATE USER

CREATE USER user [IDENTIFIED BY [PASSWORD] 'password']
    [, user [IDENTIFIED BY [PASSWORD] 'password']] ...

Die CREATE USER-Anweisung erstellt neue MySQL-Konten. Um sie zu verwenden, benötigen Sie die globale Berechtigung CREATE USER oder die Berechtigung INSERT für die Datenbank mysql. Für jedes Konto richtet CREATE USER einen neuen Datensatz in der Tabelle mysql.user ein, der keine Berechtigungen hat. Ist das Konto bereits vorhanden, dann tritt ein Fehler auf. Jedes Konto wird im selben Format wie bei der GRANT-Anweisung benannt (z. B. 'jeffrey'@'localhost'). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten User und Host des kontenspezifischen Datensatzes in der Tabelle user.

Das Konto erhält ein Passwort mit der optionalen IDENTIFIED BY-Klausel. Der Wert user und das Passwort werden auf gleiche Weise übergeben wie bei der GRANT-Anweisung. Insbesondere müssen Sie das Schlüsselwort PASSWORD weglassen, um das Passwort im Klartext angeben zu können. Wenn Sie das Passwort hingegen als von der Funktion PASSWORD() zurückgegebenen Hash-Wert angeben wollen, schließen Sie das Schlüsselwort PASSWORD mit ein. Siehe auch Abschnitt 13.5.1.3, „GRANT und REVOKE.

13.5.1.2. DROP USER

DROP USER user [, user] ...

Die Anweisung DROP USER entfernt ein oder mehrere MySQL-Konten. Sie löscht die Berechtigungsdatensätze des Kontos aus allen Grant-Tabellen. Um diese Anweisung zu verwenden, benötigen Sie die globale Berechtigung CREATE USER oder die Berechtigung DELETE für die Datenbank mysql. Jedes Konto wird im selben Format wie bei der GRANT-Anweisung benannt (z. B. 'jeffrey'@'localhost'). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten User und Host des kontenspezifischen Datensatzes in der Tabelle user.

Mit DROP USER können Sie ein Konto und seine Berechtigungen wie folgt entfernen:

DROP USER user;

Wichtig : DROP USER schließt offene Benutzersitzungen nicht automatisch. Stattdessen wird, wenn ein zu löschender Benutzer gerade eine offene Sitzung hat, die Anweisung erst umgesetzt, wenn die Sitzung dieses Benutzers beendet wurde. Sobald die Sitzung beendet ist, wird der Benutzer gelöscht: Nachfolgende Versuche des Benutzers, sich anzumelden, schlagen dann fehl. Dies ist bewusst so implementiert.

13.5.1.3. GRANT und REVOKE

GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ...
    ON [object_type] {tbl_name | * | *.* | db_name.*}
    TO user [IDENTIFIED BY [PASSWORD] 'password']
        [, user [IDENTIFIED BY [PASSWORD] 'password']] ...
    [REQUIRE
        NONE |
        [{SSL| X509}]
        [CIPHER 'cipher' [AND]]
        [ISSUER 'issuer' [AND]]
        [SUBJECT 'subject']]
    [WITH with_option [with_option] ...]

object_type =
    TABLE
  | FUNCTION
  | PROCEDURE

with_option =
    GRANT OPTION
  | MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONS count

Die GRANT-Anweisung erlaubt Systemadministratoren die Erstellung von MySQL-Benutzerkonten und die Vergabe von Rechten an diese Konten. Um GRANT verwenden zu können, benötigen Sie die Berechtigung GRANT OPTION sowie alle Berechtigungen, die Sie selbst gewähren. Die REVOKE-Anweisung ist in diesem Zusammenhang ebenfalls zu nennen: Sie gestattet Administratoren das Entfernen von Kontenberechtigungen. Siehe auch Abschnitt 13.5.1.5, „REVOKE.

MySQL-Kontendaten sind in Tabellen der Datenbank mysql gespeichert. Diese Datenbank und das Zugriffssteuerungssystem sind in Kapitel 5, Datenbankverwaltung, ausführlich beschrieben. Sie finden dort weitere Informationen.

Wichtig: Einige Releases von MySQL enthalten Änderungen an der Struktur der Grant-Tabellen, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Upgrade auf eine neue MySQL-Version durchführen, sollten Sie Ihre Grant-Tabellen aktualisieren, damit sichergestellt ist, dass diese auf der aktuellen Struktur basieren und auf diese Weise neue Funktionalitäten nutzen können. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Wenn in den Grant-Tabellen Berechtigungsdatensätze vorhanden sind, die Datenbank- oder Tabellennamen mit gemischter Groß-/Kleinschreibung enthalten, und die Systemvariable lower_case_table_names auf einen Nicht-Null-Wert gesetzt ist, dann können diese Berechtigungen nicht mit REVOKE widerrufen werden. Es ist dann erforderlich, die Grant-Tabellen direkt zu manipulieren. (GRANT erstellt solche Datensätze zwar nicht, wenn lower_case_table_names eingestellt ist, aber unter Umständen wurden derartige Datensätze bereits vor Einstellen der Variablen erstellt.)

Berechtigungen können auf unterschiedlichen Ebenen gewährt werden:

  • Globale Ebene

    Globale Berechtigungen gelten für alle Datenbanken auf einem gegebenen Server. Sie werden in der Tabelle mysql.user gespeichert. GRANT ALL ON *.* und REVOKE ALL ON *.* gewähren bzw. widerrufen nur globale Berechtigungen.

  • Datenbankebene

    Datenbankberechtigungen gelten für alle Objekte in einer gegebenen Datenbank. Sie werden in den Tabellen mysql.db und mysql.host gespeichert. GRANT ALL ON db_name.* und REVOKE ALL ON db_name.* gewähren bzw. widerrufen nur Datenbankberechtigungen.

  • Tabellenebene

    Tabellenberechtigungen gelten für alle Spalten in einer gegebenen Tabelle. Sie werden in der Tabelle mysql.tables_priv gespeichert. GRANT ALL ON db_name.tbl_name und REVOKE ALL ON db_name.tbl_name gewähren bzw. widerrufen nur Tabellenberechtigungen.

  • Spaltenebene

    Spaltenberechtigungen gelten für einzelne Spalten in einer gegebenen Tabelle. Sie werden in der Tabelle mysql.columns_priv gespeichert. Wenn Sie REVOKE verwenden, müssen Sie dieselben Spalten angeben, denen die Berechtigungen zuvor gewährt wurden.

  • Routinenebene

    Die Berechtigungen CREATE ROUTINE, ALTER ROUTINE, EXECUTE und GRANT gelten für gespeicherte Routinen (Funktionen und Prozeduren). Sie können auf der globalen und der Datenbankebene gewährt werden. Ferner lassen sich diese Berechtigungen mit Ausnahme von CREATE ROUTINE auf Routinenebene für einzelne Routinen gewähren und werden in der Tabelle mysql.procs_priv gespeichert.

Die Klausel object_type sollte als TABLE, FUNCTION bzw. als PROCEDURE angegeben werden, wenn das nachfolgende Objekt eine Tabelle, eine gespeicherte Funktion oder eine gespeicherte Prozedur ist.

Für die Anweisungen GRANT und REVOKE kann priv_type wie folgt angegeben werden:

BerechtigungBedeutung
ALL [PRIVILEGES]Setzt alle einfachen Berechtigungen außer GRANT OPTION.
ALTERErlaubt die Verwendung von ALTER TABLE.
ALTER ROUTINEErlaubt die Änderung oder Löschung gespeicherter Routinen.
CREATEErlaubt die Verwendung von CREATE TABLE.
CREATE ROUTINEErlaubt die Erstellung gespeicherter Routinen.
CREATE TEMPORARY TABLESErlaubt die Verwendung von CREATE TEMPORARY TABLE.
CREATE USERErlaubt die Verwendung von CREATE USER, DROP USER, RENAME USER und REVOKE ALL PRIVILEGES.
CREATE VIEWErlaubt die Verwendung von CREATE VIEW.
DELETEErlaubt die Verwendung von DELETE.
DROPErlaubt die Verwendung von DROP TABLE.
EVENTErlaubt die Erstellung von Ereignissen für den Ereignisplaner.
EXECUTEErlaubt dem Benutzer die Ausführung gespeicherter Routinen.
FILEErlaubt die Verwendung von SELECT ... INTO OUTFILE und LOAD DATA INFILE.
INDEXErlaubt die Verwendung von CREATE INDEX und DROP INDEX.
INSERTErlaubt die Verwendung von INSERT.
LOCK TABLESErlaubt die Verwendung von LOCK TABLES für Tabellen, für die Sie die Berechtigung SELECT haben.
PROCESSErlaubt die Verwendung von SHOW FULL PROCESSLIST.
REFERENCESNicht implementiert.
RELOADErlaubt die Verwendung von FLUSH.
REPLICATION CLIENTErlaubt dem Benutzer, die Positionen von Slave- oder Master-Servern zu erfragen.
REPLICATION SLAVEFür Replikationsslaves erforderlich (zum Lesen von Binärlogeinträgen auf dem Master).
SELECTErlaubt die Verwendung von SELECT.
SHOW DATABASESSHOW DATABASES zeigt alle Datenbanken.
SHOW VIEWErlaubt die Verwendung von SHOW CREATE VIEW.
SHUTDOWNErlaubt die Verwendung von mysqladmin shutdown.
SUPERErlaubt die Verwendung der Anweisungen CHANGE MASTER, KILL, PURGE MASTER LOGS und SET GLOBAL und des Befehls mysqladmin debug. Erlaubt ferner die (einmalige) Verbindungsherstellung auch in dem Fall, dass der Wert für max_connections erreicht wurde.
TRIGGERErlaubt dem Benutzer das Erstellen und Löschen von Triggern.
UPDATEErlaubt die Verwendung von UPDATE.
USAGESynonym für „keine Berechtigungen
GRANT OPTIONErlaubt die Gewährung von Berechtigungen.

Die Berechtigungen EVENT und TRIGGER wurden in MySQL 5.1.6 hinzugefügt. Ein Trigger ist mit einer Tabelle verknüpft, d. h., um einen Trigger zu erstellen oder zu löschen, benötigen Sie die Berechtigung TRIGGER für die Tabelle, nicht für den Trigger. (Vor MySQL 5.1.6 war für das Erstellen und Löschen von Triggern die Berechtigung SUPER erforderlich.)

Die Berechtigung REFERENCES wird derzeit nicht benutzt.

USAGE kann angegeben werden, wenn Sie einen Benutzer ohne Berechtigungen erstellen wollen.

Verwenden Sie SHOW GRANTS, um zu bestimmen, welche Berechtigungen ein Konto hat. Siehe auch Abschnitt 13.5.4.11, „SHOW GRANTS.

Sie können globale Berechtigungen mit der Syntax ON *.* oder Berechtigungen auf Datenbankebene mit der Syntax ON db_name.* konfigurieren. Wenn Sie ON * angeben und eine Standarddatenbank festgelegt haben, werden die Berechtigungen in dieser Datenbank gewährt. (Warnung: Wenn Sie ON * angeben und keine Standarddatenbank ausgewählt haben, werden die Berechtigungen global gewährt.)

Die Berechtigungen FILE, PROCESS, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHOW DATABASES, SHUTDOWN und SUPER sind administrative Berechtigungen, die nur global gewährt werden können (hierzu wird die Syntax ON *.* verwendet).

Andere Berechtigungen können wahlweise global oder auf individuellen Ebenen festgelegt werden.

Die priv_type-Werte, die Sie für eine Tabelle angeben können, sind SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT OPTION, INDEX, ALTER, CREATE VIEW, SHOW VIEW und TRIGGER.

Die priv_type-Werte, die Sie (bei Verwendung einer column_list-Klausel) für eine Spalte angeben können, sind SELECT, INSERT und UPDATE.

Die priv_type-Werte, die Sie auf der Routinenebene angeben können, sind ALTER ROUTINE, EXECUTE und GRANT OPTION. CREATE ROUTINE ist keine Berechtigung auf Routinenebene, weil Sie diese Berechtigung bereits zur Erstellung einer Routine benötigen.

Auf der globalen, der Datenbank-, der Tabellen- und der Routinenebene weist GRANT ALL nur diejenigen Berechtigungen zu, die auf der gewährten Ebene vorhanden sind. So ist beispielsweise GRANT ALL ON db_name.* eine Anweisung auf Datenbankebene, d. h., es lassen sich hiermit keine nur auf globaler Ebene vorhandenen Berechtigungen (wie z. B. FILE) gewähren.

MySQL gestattet die Konfiguration von Berechtigungen auch für Datenbankobjekte, die nicht existieren. In diesen Fällen muss zu den zu gewährenden Berechtigungen auch die Berechtigung CREATE gehören. Dies ist bewusst so implementiert und soll es dem Datenbankadministrator gestatten, Benutzerkonten und Berechtigungen für Datenbankobjekte vorzubereiten, die erst später erstellt werden.

Wichtig: Wenn Sie eine Tabelle oder Datenbank löschen, widerruft MySQL Berechtigungen nicht automatisch. Wenn Sie allerdings eine Routine löschen, werden alle Berechtigungen auf Routinenebene widerrufen, die für diese Routine gewährt wurden.

Hinweis: Die Jokerzeichen ‘_’ und ‘%’ sind bei der Angabe von Datenbanknamen in GRANT-Anweisungen, die Berechtigungen auf der globalen und der Datenbankebene gewähren, zulässig. Das bedeutet beispielsweise, dass Sie, wenn Sie das Zeichen ‘_’ als Bestandteil eines Datenbanknamens verwenden wollen, dieses Zeichen als ‘\_’ in der GRANT-Anweisung angeben müssen, damit der Benutzer nicht auf weitere Datenbanken zugreifen kann, die dem entstandenen Muster entsprechen (z. B. GRANT ... ON `foo\_bar`.* TO ...).

Um das Gewähren von Rechten an Benutzer über beliebige Hosts zu gestatten, unterstützt MySQL die Angabe des user-Werts in der Form user_name@host_name. Wenn ein user_name- oder host_name-Wert als vorzeichenloser Bezeichner zulässig ist, müssen Sie ihn nicht in Anführungszeichen setzen. Allerdings sind Anführungszeichen erforderlich, um einen user_name-String mit Sonderzeichen (z. B. ‘-’) oder einen host_name-String mit Sonder- oder Jokerzeichen (wie ‘%’) anzugeben. Ein Beispiel hierfür wäre 'test-user'@'test-hostname'. Setzen Sie Benutzer- und Hostnamen separat in Anführungszeichen.

Sie können Jokerzeichen im Hostnamen verwenden. So bezeichnet etwa user_name@'%.loc.gov' jeden user_name auf einem beliebigen Host in der Domäne loc.gov, und user_name@'144.155.166.%' bezeichnet user_name auf einem beliebigen Host im Klasse-C-Subnetz 144.155.166.

Die einfache Form user_name ist ein Synonym für user_name@'%'.

MySQL unterstützt keine Jokerzeichen in Benutzernamen. Anonyme Benutzer werden durch Einfügen von Einträgen mit User='' in die Tabelle mysql.user oder durch Erstellen eines Benutzers mit einem leeren Namen mit der GRANT-Anweisung definiert:

GRANT ALL ON test.* TO ''@'localhost' ...

Wenn Sie Werte in Anführungszeichen angeben, setzen Sie Datenbank-, Tabellen-, Spalten- und Routinenamen als Bezeichner in Backticks (‘`’). Host- und Benutzernamen sowie Passwörter werden als Strings in einfache Anführungszeichen (‘'’) gesetzt.

Warnung: Wenn Sie anonymen Benutzern eine Verbindung zum MySQL Server gestatten wollen, sollten Sie auch allen lokalen Benutzern als user_name@localhost Berechtigungen gewähren. Andernfalls wird das anonyme Benutzerkonto für localhost in der Tabelle mysql.user verwendet, wenn benannte Benutzer versuchen, sich über das lokale System am MySQL Server anzumelden (die Tabelle wird bei der Installation von MySQL erstellt). Detaillierte Informationen finden Sie in Abschnitt 5.8.5, „Zugriffskontrolle, Phase 1: Verbindungsüberprüfung“.

Sie können feststellen, ob dies für Sie zutrifft, indem Sie die folgende Abfrage ausführen, die alle ggf. vorhandenen anonymen Benutzer auflistet:

SELECT Host, User FROM mysql.user WHERE User='';

Wenn Sie das lokale anonyme Benutzerkonto löschen wollen, um das beschriebene Problem zu umgehen, dann verwenden Sie folgende Anweisungen:

DELETE FROM mysql.user WHERE Host='localhost' AND User='';
FLUSH PRIVILEGES;

GRANT unterstützt Hostnamen mit einer Länge von bis zu 60 Zeichen. Die Namen von Datenbanken, Tabellen, Spalten und Routinen dürfen bis zu 64 Zeichen lang sein. Benutzernamen können bis zu 16 Zeichen umfassen. Hinweis: Die zulässige Länge für Benutzernamen kann nicht durch Änderungen an der Tabelle mysql.user modifiziert werden. Wenn Sie dies dennoch versuchen, kann dies zu unvorhersehbaren Folgen führen, die schlimmstenfalls sogar ein Anmelden von Benutzern am MySQL Server verhindern können. Sie sollten die Tabellen in der mysql-Datenbank grundsätzlich nicht auf eine andere als die von MySQL AB vorgeschriebene, in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“, geschilderte Weise ändern.

Die Berechtigungen für eine Tabelle, eine Spalte oder eine Routine werden kumulativ über ein logisches OR der Berechtigungen auf jeder der einzelnen Ebenen gebildet. Wenn die Tabelle mysql.user beispielsweise angibt, dass ein Benutzer die globale Berechtigung SELECT hat, kann ihm diese Berechtigung nicht auf der Datenbank-, der Tabellen- oder der Spaltenebene verweigert werden.

Die Berechtigungen für eine Spalte lassen sich wie folgt berechnen:

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
OR routine privileges

In den meisten Fällen gewähren Sie einem Benutzer nur auf einer dieser Berechtigungsebenen Rechte – das Leben ist also normalerweise nicht so kompliziert. Ausführlich beschrieben wird die Überprüfung von Berechtigungen in Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“.

Wenn Sie Berechtigungen für eine Kombination aus Benutzer- und Hostnamen gewähren, die nicht in der Tabelle mysql.user vorhanden ist, wird ein Eintrag hinzugefügt und verbleibt dort, bis er mit einer DELETE-Anweisung gelöscht wird. Anders gesagt, GRANT kann Einträge in der Tabelle user erstellen; diese lassen sich aber nicht mit REVOKE entfernen, sondern müssen explizit mit DROP USER oder DELETE gelöscht werden.

Warnung: Wenn Sie einen neuen Benutzer ohne IDENTIFIED BY-Klausel erstellen, hat der Benutzer kein Passwort. Dies ist sehr unsicher. Sie können jedoch den SQL-Modus NO_AUTO_CREATE_USER aktivieren: Hierbei wird verhindert, dass GRANT Benutzer automatisch erstellt, wenn diesem nicht mit der IDENTIFIED BY-Klausel ein nichtleeres Passwort zugewiesen wird.

Wenn ein neuer Benutzer erstellt wird oder Sie globale Gewährungsberechtigungen haben, dann wird das Passwort des Benutzers auf das in der IDENTIFIED BY-Klausel gewählte Passwort gesetzt (sofern vorhanden). Hat der Benutzer bereits ein Passwort, so wird dieses durch das neue Passwort ersetzt.

Passwörter können auch mit der Anweisung SET PASSWORD eingestellt werden. Siehe auch Abschnitt 13.5.1.6, „SET PASSWORD.

In der IDENTIFIED BY-Klausel sollte das Passwort als literaler Passwortwert übergeben werden. Es ist – anders als bei der SET PASSWORD-Anweisung – nicht erforderlich, die Funktion PASSWORD() zu verwenden. Zum Beispiel:

GRANT ... IDENTIFIED BY 'mypass';

Wenn Sie das Passwort nicht unverschlüsselt senden wollen und den Hash-Wert kennen, den PASSWORD() für das Passwort zurückgeben würde, dann können Sie diesen Hash-Wert nach dem Schlüsselwort PASSWORD angeben:

GRANT ...
IDENTIFIED BY PASSWORD '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4';

In einem C-Programm können Sie den Hash-Wert mit der C-API-Funktion make_scrambled_password() ermitteln.

Wenn Sie Berechtigungen für eine Datenbank gewähren, wird bei Bedarf ein Eintrag in der Tabelle mysql.db erstellt. Wenn alle Berechtigungen für die Datenbank mit REVOKE entfernt werden, wird dieser Eintrag gelöscht.

Die Berechtigung SHOW DATABASES ermöglicht dem Konto die Anzeige von Datenbanknamen durch Absetzen einer SHOW DATABASE-Anweisung. Konten, die diese Berechtigung nicht haben, sehen nur solche Datenbanken, für die sie Berechtigungen haben; wurde der Server mit der Option --skip-show-database gestartet, dann kann die Anweisung überhaupt nicht verwendet werden.

Wenn ein Benutzer keine Berechtigungen für eine Tabelle hat, wird, wenn er (z. B. mit SHOW TABLES) eine Liste der Tabellen anfordert, der Name der betreffenden Tabelle nicht angezeigt.

Die WITH GRANT OPTION-Klausel gibt dem Benutzer die Möglichkeit, anderen Benutzern beliebige Berechtigungen zu gewähren, die der Benutzer selbst auf einer bestimmten Berechtigungsebene hat. Sie sollten bei der Vergabe der Berechtigung GRANT OPTION mit Umsicht vorgehen, weil zwei Benutzer mit unterschiedlichen Berechtigungen sich diese unter Umständen gegenseitig gewähren können!

Sie können einem anderen Benutzer keine Berechtigung gewähren, die Sie selbst nicht haben – mit GRANT OPTION können Sie nur solche Berechtigungen vergeben, über die Sie selbst auch verfügen.

Beachten Sie, dass, wenn Sie einem Benutzer die Berechtigung GRANT OPTION für eine bestimmte Berechtigungsebene gewähren, dieser Benutzer alle Berechtigungen, die er für diese Ebene hat (oder in Zukunft erhält), beliebig anderen Benutzern zuweisen kann. Angenommen, Sie gewähren einem Benutzer die Berechtigung INSERT für eine Datenbank. Wenn Sie nachfolgend die Berechtigung SELECT für die Datenbank gewähren und WITH GRANT OPTION angeben, dann kann dieser Benutzer anderen Benutzern nicht nur die Berechtigung SELECT gewähren, sondern auch die Berechtigung INSERT. Wenn Sie dann dem Benutzer die Berechtigung UPDATE für die Datenbank gewähren, kann der Benutzer die Berechtigungen INSERT, SELECT und UPDATE gewähren.

Einem nichtadministrativen Benutzer sollten Sie die Berechtigung ALTER weder global noch für die Datenbank mysql gewähren. Andernfalls kann der Benutzer das Berechtigungssystem unterlaufen, indem er Tabellen umbenennt!

Die Optionen MAX_QUERIES_PER_HOUR count, MAX_UPDATES_PER_HOUR count und MAX_CONNECTIONS_PER_HOUR count begrenzen die Anzahl der Abfrage-, Update- und Anmeldevorgänge, die ein Benutzer im Verlauf einer Stunde ausführen kann. Wenn count 0 ist (Standardeinstellung), dann heißt das, dass für den Benutzer keine Beschränkung gilt.

Die Option MAX_USER_CONNECTIONS count schränkt die maximale Anzahl gleichzeitiger Verbindungen ein, die das Konto herstellen kann. Wenn count 0 ist (Standardeinstellung), dann bestimmt die Systemvariable max_user_connections die Anzahl gleichzeitiger Verbindungen für das Konto.

Hinweis: Um für einen vorhandenen Benutzer eine solche Option zur Ressourcenbeschränkung anzugeben, ohne vorhandene Berechtigungen einzuschränken, verwenden Sie GRANT USAGE ON *.* ... WITH MAX_....

Siehe auch Abschnitt 5.9.4, „Begrenzen von Benutzer-Ressourcen“.

MySQL kann zusätzlich zur normalen, auf Benutzernamen und Passwörtern basierenden Authentifizierung Attribute von X509-Zertifikaten überprüfen. Um SSL-spezifische Optionen für ein MySQL-Konto anzugeben, verwenden Sie die REQUIRE-Klausel der GRANT-Anweisung. (Hintergrundinformationen zur Verwendung von SSL mit MySQL finden Sie in Abschnitt 5.9.7, „Verwendung sicherer Verbindungen“.)

Es gibt mehrere verschiedene Gründe zur Beschränkung der Verbindungstypen für ein gegebenes Konto:

  • Wenn für das Konto keine SSL- oder X509-Anforderungen vorhanden sind, sind unverschlüsselte Verbindungen zulässig, sofern Benutzername und Passwort gültig sind. Allerdings können nach Maßgabe des Clients auch verschlüsselte Verbindungen benutzt werden, sofern der Client über die entsprechenden Zertifikats- und Schlüsseldateien verfügt.

  • Die Option REQUIRE SSL weist den Server an, nur SSL-verschlüsselte Verbindungen für das Konto zuzulassen. Beachten Sie, dass diese Option weggelassen werden kann, wenn Zugriffssteuerungs-Datensätze vorhanden sind, die Nicht-SSL-Verbindungen zulassen.

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      IDENTIFIED BY 'goodsecret' REQUIRE SSL;
    
  • REQUIRE X509 bedeutet, dass der Client ein gültiges Zertifikat vorweisen muss, dass aber das Zertifikat selbst, der Aussteller und der Zweck keine Rolle spielen. Erforderlich ist einzig und allein, dass die Signatur bei einem Zertifikat geprüft werden können muss.

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      IDENTIFIED BY 'goodsecret' REQUIRE X509;
    
  • REQUIRE ISSUER 'issuer' schränkt Verbindungsversuche dahingehend ein, dass der Client ein gültiges X509-Zertifikat vorweisen muss, welches von der Zertifizierungsstelle 'issuer' ausgestellt wurde. Wenn der Client ein Zertifikat vorweist, das zwar gültig ist, aber von einem anderen Anbieter stammt, dann weist der Server die Verbindung ab. Die Verwendung von X509-Zertifikaten impliziert immer auch eine Verschlüsselung, d. h., die Option SSL wird in diesem Fall nicht benötigt.

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      IDENTIFIED BY 'goodsecret'
      REQUIRE ISSUER '/C=FI/ST=Some-State/L=Helsinki/
        O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com';
    

    Beachten Sie, dass die 'issuer'-Werte als einzelner String eingegeben werden sollten.

  • REQUIRE SUBJECT 'subject' schränkt Verbindungsversuche dahingehend ein, dass der Client ein gültiges X509-Zertifikat vorweisen muss, bei dem als Zweck subject angegeben ist. Wenn der Client ein Zertifikat vorweist, das zwar gültig ist, aber einen anderen Zweck angibt, dann weist der Server die Verbindung ab.

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      IDENTIFIED BY 'goodsecret'
      REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/
        O=MySQL demo client certificate/
        CN=Tonu Samuel/Email=tonu@example.com';
    

    Beachten Sie, dass die 'subject'-Werte als einzelner String eingegeben werden sollten.

  • REQUIRE CIPHER 'cipher' ist erforderlich, um sicherzustellen, dass Chiffren und Schlüssellängen ausreichender Stärke verwendet werden. SSL selbst kann schwach sein, wenn alte Algorithmen kurze Schlüssel zur Verschlüsselung einsetzen. Mit dieser Option können Sie die Verwendung einer bestimmten Chiffriermethode vorsehen, damit die Verbindung zulässig ist.

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      IDENTIFIED BY 'goodsecret'
      REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';
    

Die Optionen SUBJECT, ISSUER und CIPHER können in der REQUIRE-Klausel wie folgt kombiniert werden:

GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
  IDENTIFIED BY 'goodsecret'
  REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/
    O=MySQL demo client certificate/
    CN=Tonu Samuel/Email=tonu@example.com'
  AND ISSUER '/C=FI/ST=Some-State/L=Helsinki/
    O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com'
  AND CIPHER 'EDH-RSA-DES-CBC3-SHA';

Das Schlüsselwort AND zwischen den REQUIRE-Optionen ist optional.

Die Reihenfolge der Optionen ist unerheblich, allerdings darf keine Option zweimal angegeben werden.

Wenn mysqld startet, werden alle Berechtigungen in den Speicher eingelesen. Detaillierte Informationen finden Sie in Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“.

Beachten Sie, dass, wenn Sie Tabellen-, Spalten- oder Routineberechtigungen auch für nur einen einzigen Benutzer verwenden, der Server die Tabellen-, Spalten- und Routineberechtigungen für alle Benutzer prüft. Dies kann MySQL ein wenig verlangsamen. Analog muss der Server, wenn Sie die Anzahl von Abfragen, Updates oder Verbindungen für Benutzer beschränken wollen, auch diese Werte überwachen.

Die wesentlichsten Unterschiede zwischen dem SQL-Standard und den MySQL-Versionen von GRANT sind die folgenden:

  • In MySQL werden Berechtigungen mit einer Kombination aus Host- und Benutzernamen (und nicht nur mit einem Benutzernamen) verknüpft.

  • Der SQL-Standard bietet keine Berechtigungen auf globaler oder Datenbankebene und unterstützt auch nicht alle von MySQL unterstützten Berechtigungstypen.

  • MySQL unterstützt die Berechtigungen TRIGGER und UNDER des SQL-Standards nicht.

  • Berechtigungen nach SQL-Standard sind hierarchisch strukturiert. Wenn Sie einen Benutzer entfernen, werden alle Berechtigungen widerrufen, die dieser Benutzer hatte. Dies gilt auch für MySQL, wenn Sie DROP USER verwenden. Siehe auch Abschnitt 13.5.1.2, „DROP USER.

  • Wenn Sie in Standard-SQL eine Tabelle löschen, werden alle Berechtigungen für die Tabelle widerrufen. Wenn Sie in Standard-SQL eine Berechtigung widerrufen, werden alle Berechtigungen, die basierend auf dieser Berechtigung gewährt wurden, ebenfalls widerrufen. In MySQL können Berechtigungen nur mit expliziten REVOKE-Anweisungen oder durch Manipulation der in den MySQL-Grant-Tabellen gespeicherten Werte gelöscht werden.

  • In MySQL können INSERT-Berechtigungen auch für nur einige der Spalten in einer Tabelle gewährt werden. In diesem Fall können Sie INSERT-Anweisungen für die Tabelle trotzdem ausführen, sofern Sie diejenigen Spalten weglassen, für die Sie keine INSERT-Berechtigung haben. Die übergangenen Spalten können auf ihre impliziten Vorgabewerte gesetzt werden, sofern der strikte SQL-Modus nicht aktiviert ist. Im strikten Modus wird die Anweisung abgewiesen, wenn eine der übergangenen Spalten keinen Vorgabewert hat. (Der SQL-Standard sieht vor, dass Sie die INSERT-Berechtigung für alle Spalten benötigen.) Abschnitt 5.2.5, „Der SQL-Modus des Servers“, beschreibt den strikten Modus. Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, erläutert implizite Vorgabewerte.

13.5.1.4. RENAME USER

RENAME USER old_user TO new_user
    [, old_user TO new_user] ...

Die RENAME USER-Anweisung benennt MySQL-Konten um. Um sie zu verwenden, benötigen Sie die globale Berechtigung CREATE USER oder die Berechtigung UPDATE für die Datenbank mysql. Ein Fehler tritt auf, wenn ein Konto mit dem alten oder neuen Namen bereits existiert. Jedes Konto wird im selben Format wie bei der GRANT-Anweisung benannt (z. B. 'jeffrey'@'localhost'). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten User und Host des kontenspezifischen Datensatzes in der Tabelle user.

13.5.1.5. REVOKE

REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ...
    ON [object_type] {tbl_name | * | *.* | db_name.*}
    FROM user [, user] ...

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...

Die REVOKE-Anweisung erlaubt Systemadministratoren das Widerrufen von Berechtigungen für MySQL-Konten. Um REVOKE verwenden zu können, benötigen Sie die Berechtigung GRANT OPTION sowie alle Berechtigungen, die Sie widerrufen.

Informationen zu den Ebenen, auf denen Berechtigungen vorhanden sind, den zulässigen Werten für priv_type und der Syntax zur Angabe von Benutzern und Passwörtern finden Sie in Abschnitt 13.5.1.3, „GRANT und REVOKE.

Wenn in den Grant-Tabellen Berechtigungsdatensätze vorhanden sind, die Datenbank- oder Tabellennamen mit gemischter Groß-/Kleinschreibung enthalten, und die Systemvariable lower_case_table_names auf einen Nicht-Null-Wert gesetzt ist, dann können diese Berechtigungen nicht mit REVOKE widerrufen werden. Es ist dann erforderlich, die Grant-Tabellen direkt zu manipulieren. (GRANT erstellt solche Datensätze zwar nicht, wenn lower_case_table_names eingestellt ist, aber unter Umständen wurden derartige Datensätze bereits vor Einstellen der Variablen erstellt.)

Um alle Berechtigungen zu widerrufen, verwenden Sie die folgende Syntax. Hiermit löschen Sie alle globalen Berechtigungen sowie alle Berechtigungen auf Datenbank-, Tabellen- und Spaltenebene für den oder die aufgeführten Benutzer:

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...

Um diese REVOKE-Syntax zu verwenden, benötigen Sie die globale Berechtigung CREATE USER oder die Berechtigung UPDATE für die Datenbank mysql.

13.5.1.6. SET PASSWORD

SET PASSWORD = PASSWORD('some password')
SET PASSWORD FOR user = PASSWORD('some password')

Die Anweisung SET PASSWORD weist einem vorhandenen MySQL-Benutzerkonto ein Passwort zu.

Die erste Syntax stellt das Passwort für den aktuellen Benutzer ein. Ein Client, der über ein nichtanonymes Konto eine Verbindung mit dem Server hergestellt hat, kann das Passwort für dieses Konto ändern.

Die zweite Syntax stellt das Passwort für ein bestimmtes Konto auf dem aktuellen Serverhost ein. Nur Clients mit der Berechtigung UPDATE für die Datenbank mysql können dies tun. Der Wert user sollte im Format user_name@host_name angegeben werden, wobei user_name und host_name exakt so aufgeführt werden müssen, wie sie in den Spalten User bzw. Host des entsprechenden Eintrags in der Tabelle mysql.user notiert sind. Wenn Sie beispielsweise einen Eintrag mit den Werten 'bob' und '%.loc.gov' in den Spalten User bzw. Host haben, dann würden Sie die Anweisung wie folgt schreiben:

SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass');

Dies entspricht den folgenden Anweisungen:

UPDATE mysql.user SET Password=PASSWORD('newpass')
  WHERE User='bob' AND Host='%.loc.gov';
FLUSH PRIVILEGES;

Hinweis: Wenn Sie mit einem Clientprogramm vor Version 4.1 eine Verbindung zu einem Server unter MySQL 4.1 oder höher herstellen, verwenden Sie die obigen Anweisungen SET PASSWORD oder UPDATE erst, wenn Sie Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“, gelesen haben. Das Passwortformat wurde in MySQL 4.1 geändert, und unter bestimmten Bedingungen ist es möglich, dass Sie, wenn Sie Ihr Passwort ändern, nachfolgend keine Serververbindung mehr herstellen können.

Sie können anzeigen, unter welchem Konto der Server Sie authentifiziert hat, indem Sie SELECT CURRENT_USER() ausführen.

13.5.2. Anweisungen für die Tabellenwartung

13.5.2.1. ANALYZE TABLE

ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

ANALYZE TABLE analysiert und speichert die Schlüsselverteilung für eine Tabelle. Während der Analyse ist die Tabelle mit einer Lesesperre versehen. Diese Anweisung funktioniert nur bei MyISAM-, BDB- und InnoDB-Tabellen. Bei MyISAM-Tabellen ist sie äquivalent zur Verwendung von myisamchk -a.

MySQL verwendet die gespeicherte Schlüsselverteilung, um die Reihenfolge zu ermitteln, in der die Tabellen verknüpft werden sollen, wenn Sie einen Join mit etwas anderem als einer Konstante durchführen.

ANALYZE TABLE gibt eine Ergebnismenge mit den folgenden Spalten zurück:

SpalteWert
Tableder Tabellenname
Opist immer analyze
Msg_typestatus, error, info oder warning
Msg_textdie Nachricht

Sie können die gespeicherte Schlüsselverteilung mit der SHOW INDEX-Anweisung vergleichen. Siehe auch Abschnitt 13.5.4.12, „SHOW INDEX.

Wenn die Tabelle seit der letzten ANALYZE TABLE-Anweisung nicht geändert wurde, wird die Tabelle nicht erneut analysiert.

ANALYZE TABLE-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort NO_WRITE_TO_BINLOG (oder sein Alias LOCAL) nicht verwendet wird. Dies wird gemacht, damit ANALYZE TABLE-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

13.5.2.2. BACKUP TABLE

BACKUP TABLE tbl_name [, tbl_name] ... TO '/path/to/backup/directory'

Hinweis: Diese Anweisung ist veraltet. Wir arbeiten derzeit an einem besseren Ersatz, der auch die Online-Sicherung unterstützt. In der Zwischenzeit kann stattdessen das Skript mysqlhotcopy verwendet werden.

BACKUP TABLE kopiert die minimale Anzahl an Tabellendateien, die zur Wiederherstellung der Tabelle benötigt werden, in das Sicherungsverzeichnis, nachdem ggf. gepufferte Änderungen auf Festplatte geschrieben wurden. Die Anweisung funktioniert nur bei MyISAM-Tabellen. Sie kopiert die Definitionsdatei (.frm) und die Datendatei (.MYD). Die .MYI-Indexdatei kann aus diesen beiden Dateien neu erstellt werden. Das Verzeichnis sollte als vollständiger Pfadname angegeben werden. Um die Tabelle wiederherzustellen, verwenden Sie RESTORE TABLE.

Während des Backups wird für jede Tabelle für den Verlauf des Sicherungsvorgangs eine Lesesperre gehalten (d. h. immer für eine Tabelle gleichzeitig). Wenn Sie mehrere Tabellen als Momentaufnahme sichern wollen (und dabei vermeiden wollen, dass diese während der Sicherung geändert werden), setzen Sie zunächst eine LOCK TABLES-Anweisung ab, um eine Lesesperre für alle betreffenden Tabellen zu erwirken.

BACKUP TABLE gibt eine Ergebnismenge mit den folgenden Spalten zurück:

SpalteWert
Tableder Tabellenname
Opist immer backup
Msg_typestatus, error, info oder warning
Msg_textdie Nachricht

13.5.2.3. CHECK TABLE

CHECK TABLE tbl_name [, tbl_name] ... [option] ...

option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

CHECK TABLE prüft eine oder mehrere Tabellen auf Fehler. CHECK TABLE funktioniert bei MyISAM- und InnoDB-Tabellen. Bei MyISAM-Tabellen werden auch die Schlüsselstatistiken aktualisiert.

CHECK TABLE kann auch Views auf Probleme prüfen, z. B. in der View-Definition referenzierte Tabellen, die nicht mehr vorhanden sind.

CHECK TABLE gibt eine Ergebnismenge mit den folgenden Spalten zurück:

SpalteWert
Tableder Tabellenname
Opist immer check
Msg_typestatus, error, info oder warning
Msg_textdie Nachricht

Beachten Sie, dass die Anweisung unter Umständen viele Datensätze für die überprüfte Tabelle ausgeben kann. Der letzte Datensatz hat den Msg_type-Wert status; Msg_text sollte normalerweise den Wert OK haben. Wenn Sie nicht den Wert OK oder aber die Meldung Table is already up to date erhalten, sollten Sie eine Reparatur der Tabelle durchführen. Siehe auch Abschnitt 5.10.4, „Benutzung von myisamchk für Tabellenwartung und Absturzreparatur“. Table is already up to date bedeutet, dass die Speicher-Engine für die Tabelle angegeben hat, dass es keine Notwendigkeit zur Überprüfung gibt.

Die verschiedenen Prüfoptionen, die angegeben werden können, sind in der folgenden Tabelle aufgeführt. Die Optionen dienen nur der Überprüfung von MyISAM-Tabellen; bei InnoDB-Tabellen und Views werden sie ignoriert.

TypBedeutung
QUICKüberprüft Datensätze nicht auf falsche Verknüpfungen.
FASTÜberprüft nur Tabellen, die nicht ordnungsgemäß geschlossen wurden.
CHANGEDüberprüft nur solche Tabellen, die seit der letzten Überprüfung geändert oder aber nicht korrekt geschlossen wurden.
MEDIUMprüft Datensätze, um sicherzustellen, dass gelöschte Verknüpfungen gültig sind. Hierbei wird auch eine Schlüsselprüfsumme für die Datensätze berechnet, die dann mit einer berechneten Prüfsumme für die Schlüssel verglichen wird.
EXTENDEDführt eine vollständige Schlüsselsuche für alle Schlüssel in jedem Datensatz durch. Hierdurch wird sichergestellt, dass die Tabelle hundertprozentig konsistent ist, der Vorgang dauert aber sehr lange.

Wenn keine der Optionen QUICK, MEDIUM oder EXTENDED angegeben wird, wird standardmäßig MEDIUM als Prüftyp für dynamische MyISAM-Tabellen verwendet. Dies hat dieselben Auswirkungen wie die Ausführung von myisamchk --medium-check tbl_name für die Tabelle. Auch bei statischen MyISAM-Tabellen ist MEDIUM der Standardtyp, sofern nicht CHANGED oder FAST angegeben wurde. (In diesen Fällen ist QUICK der Vorgabewert.) Der Datensatzscan wird bei CHANGED und FAST übersprungen, weil die Datensätze sehr selten beschädigt sind.

Sie können Prüfoptionen auch kombinieren. Im folgenden Beispiel etwa erfolgt eine schnelle Prüfung der Tabelle, um zu ermitteln, ob sie korrekt geschlossen wurde:

CHECK TABLE test_table FAST QUICK;

Hinweis: In manchen Fällen verändert CHECK TABLE die Tabelle. Dies geschieht, wenn die Tabelle als „beschädigt“ oder „nicht korrekt geschlossen“ gekennzeichnet wurde, aber CHECK TABLE keine Probleme in der Tabelle findet. In diesem Fall kennzeichnet CHECK TABLE die Tabelle als fehlerfrei.

Wenn eine Tabelle beschädigt ist, liegt das Problem wahrscheinlich bei den Indizes und nicht im Datenteil vor. Alle bislang genannten Prüftypen führen eine umfassende Indexprüfung durch und sollten aufgrund dessen die meisten Fehler finden.

Wenn Sie eine Tabelle, bei der Sie davon ausgehen, dass sie in Ordnung ist, nur sicherheitshalber überprüfen wollen, dann sollten Sie entweder keine Prüfoption oder die Option QUICK angeben. Letzteres sollten Sie tun, wenn Sie sehr in Eile sind und das sehr geringe Risiko in Kauf nehmen wollen, dass QUICK einen Fehler in der Datendatei nicht findet. (In den meisten Fällen sollte MySQL bei normaler Verwendung alle ggf. in der Datendatei vorhandenen Fehler finden. Geschieht dies, so wird die Tabelle als „beschädigt“ gekennzeichnet und kann erst wieder verwendet werden, nachdem sie repariert wurde.)

FAST und CHANGED sollen in erster Linie aus Skripten (die etwa mit cron ausgeführt werden) heraus verwendet werden, wenn Sie Ihre Tabellen von Zeit zu Zeit überprüfen wollen. In den meisten Fällen ist FAST CHANGED vorzuziehen. (Der einzige Fall, wo dies nicht zutrifft, liegt vor, wenn Sie annehmen, einen Bug im MyISAM-Code gefunden zu haben.)

EXTENDED sollte erst verwendet werden, wenn Sie bereits eine normale Überprüfung durchgeführt haben, aber immer noch merkwürdige Fehler zu einer Tabelle erhalten, sobald MySQL versucht, einen Datensatz zu aktualisieren oder einen Datensatz nach seinem Schlüssel zu finden. Die Wahrscheinlichkeit, dass so etwas nach einer normalen Überprüfung passiert, ist sehr gering.

Einige Probleme, die von CHECK TABLE gemeldet werden, können nicht automatisch behoben werden:

  • Found row where the auto_increment column has the value 0.

    Das bedeutet, dass Sie einen Datensatz in der Tabelle haben, bei dem die AUTO_INCREMENT-Indexspalte den Wert 0 enthält. (Ein Datensatz, bei dem die AUTO_INCREMENT-Spalte 0 ist, kann tatsächlich erzeugt werden, indem die Spalte mit UPDATE explizit auf 0 gesetzt wird.)

    Dies ist an sich kein Fehler, kann aber Probleme verursachen, wenn Sie beschließen, die Tabelle zu speichern und sie dann wiederherzustellen, oder eine ALTER TABLE-Anweisung an die Tabelle absetzen. In diesem Fall ändert die AUTO_INCREMENT-Spalte ihren Wert entsprechend den Regeln für AUTO_INCREMENT-Spalten, was Probleme wie beispielsweise Schlüsseldubletten verursachen kann.

    Um die Warnung zu beseitigen, führen Sie einfach eine UPDATE-Anweisung aus, um die Spalte auf einen anderen Wert als 0 zu setzen.

13.5.2.4. CHECKSUM TABLE

CHECKSUM TABLE tbl_name [, tbl_name] ... [ QUICK | EXTENDED ]

CHECKSUM TABLE meldet eine Tabellenprüfsumme.

Bei QUICK wird – sofern möglich – die mitlaufende Prüfsumme gemeldet, andernfalls NULL. Dies ist sehr schnell. Eine mitlaufende Prüfsumme wird durch Angabe der Tabellenoption CHECKSUM = 1 bei Erstellung der Tabelle aktiviert. Zurzeit wird dies nur bei MyISAM-Tabellen unterstützt. Siehe auch Abschnitt 13.1.5, „CREATE TABLE.

Bei EXTENDED wird die gesamte Tabelle Datensatz für Datensatz gelesen und die Prüfsumme berechnet. Dies kann bei großen Tabellen sehr lange dauern.

Wenn weder QUICK noch EXTENDED angegeben sind, gibt MySQL eine mitlaufende Prüfsumme zurück, wenn die Speicher-Engine der Tabelle dies unterstützt; andernfalls wird die Tabelle gescannt.

Bei einer nichtexistenten Tabelle gibt CHECKSUM TABLE NULL zurück und erzeugt eine Warnung.

13.5.2.5. OPTIMIZE TABLE

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

OPTIMIZE TABLE sollte verwendet werden, wenn Sie einen umfangreichen Teil einer Tabelle gelöscht oder viele Änderungen an einer Tabelle mit Datensätzen variabler Länge (also Tabellen mit VARCHAR-, VARBINARY-, BLOB- oder TEXT-Spalten) vorgenommen haben. Gelöschte Datensätze werden zu einer verknüpften Liste hinzugefügt. Nachfolgende INSERT-Operationen verwenden die alten Datensatzpositionen neu. Sie können mit OPTIMIZE TABLE nichtverwendeten Speicher in der Tabelle freigeben und die Datendatei defragmentieren.

In den meisten Konfigurationen müssen Sie OPTIMIZE TABLE gar nicht ausführen. Auch wenn Sie viele Änderungen an Datensätzen variabler Länge vorgenommen haben, ist die Wahrscheinlichkeit, dass Sie dies häufiger als einmal in der Woche oder im Monat tun müssen, sehr gering – und selbst dies nur bei bestimmten Tabellen.

OPTIMIZE TABLE funktioniert nur bei MyISAM-, BDB- und InnoDB-Tabellen.

Bei MyISAM-Tabellen funktioniert OPTIMIZE TABLE wie folgt:

  1. Wenn die Tabelle gelöschte oder geteilte Datensätze aufweist, wird die Tabelle repariert.

  2. Wenn die Indexseiten nicht sortiert sind, werden sie sortiert.

  3. Wenn die Tabellenstatistiken nicht aktuell sind (und eine Reparatur durch Sortierung des Indexes nicht erfolgreich war), werden sie aktualisiert.

Bei BDB wird OPTIMIZE TABLE zurzeit auf ANALYZE TABLE umgesetzt. Siehe auch Abschnitt 13.5.2.1, „ANALYZE TABLE.

Bei InnoDB wird OPTIMIZE TABLE auf ALTER TABLE umgesetzt, wodurch die Tabelle neu erstellt wird, um Indexstatistiken zu aktualisieren und ungenutzten Speicher im Cluster-Index freizugeben.

Sie können OPTIMIZE TABLE auch bei anderen Speicher-Engines zum Laufen bringen, indem Sie mysqld mit den Optionen --skip-new oder --safe-mode starten. In diesem Fall wird OPTIMIZE TABLE einfach auf ALTER TABLE umgesetzt.

OPTIMIZE TABLE gibt eine Ergebnismenge mit den folgenden Spalten zurück:

SpalteWert
Tableder Tabellenname
Opist immer optimize
Msg_typestatus, error, info oder warning
Msg_textdie Nachricht

Beachten Sie, dass MySQL die Tabelle während der Laufzeit von OPTIMIZE TABLE sperrt.

OPTIMIZE TABLE-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort NO_WRITE_TO_BINLOG (oder sein Alias LOCAL) nicht verwendet wird. Dies wird gemacht, damit OPTIMIZE TABLE-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

13.5.2.6. REPAIR TABLE

REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE
    tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]

REPAIR TABLE repariert eine unter Umständen beschädigte Tabelle. Standardmäßig hat dies dieselbe Wirkung wie myisamchk --recover tbl_name. REPAIR TABLE funktioniert bei MyISAM- und ARCHIVE-Tabellen. Siehe auch Abschnitt 14.1, „Die MyISAM-Speicher-Engine“, und Abschnitt 14.8, „Die ARCHIVE-Speicher-Engine“.

Im Normalfall werden Sie diese Anweisung niemals ausführen. Im Katastrophenfall kann REPAIR TABLE Ihnen aber sehr wahrscheinlich alle Daten aus einer MyISAM-Tabelle wiederherstellen. Treten bei Ihren Tabellen häufig Beschädigungen auf, dann sollten Sie versuchen, den Grund dafür zu ermitteln, um REPAIR TABLE nicht mehr fortlaufend einsetzen zu müssen. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“, und Abschnitt 14.1.4, „MyISAM-Tabellenprobleme“.

Warnung: Wenn sich der Server während eines REPAIR TABLE-Vorgangs aufhängt, ist es unabdingbar, unmittelbar nach dem Neustart eine neue REPAIR TABLE-Anweisung für die Tabelle abzusetzen, bevor Sie weitere Operationen an ihr vornehmen. (Es bietet sich ohnehin immer an, zuallererst ein Backup zu erstellen.) Im schlimmsten Fall haben Sie unter Umständen eine neue saubere Indexdatei ohne Informationen zur Datendatei – und könnten im nächsten Schritt möglicherweise Ihre Datendatei überschreiben! Dies ist ein unwahrscheinliches, aber durchaus mögliches Szenario.

REPAIR TABLE gibt eine Ergebnismenge mit den folgenden Spalten zurück:

SpalteWert
Tableder Tabellenname
Opist immer repair
Msg_typestatus, error, info oder warning
Msg_textdie Nachricht

Die Anweisung REPAIR TABLE kann unter Umständen viele Datensätze für die reparierte Tabelle ausgeben. Der letzte Datensatz hat den Msg_type-Wert status; Msg_test sollte normalerweise den Wert OK haben. Wenn Sie einen anderen Status als OK erhalten, sollten Sie die Tabelle mit myisamchk --safe-recover zu reparieren versuchen. (REPAIR TABLE implementiert noch nicht alle Optionen von myisamchk. Wir beabsichtigen aber, die Anweisung in Zukunft flexibler zu gestalten.) Mit myisamchk --safe-recover können Sie auch Optionen verwenden, die REPAIR TABLE nicht unterstützt (z. B. --max-record-length).

Wenn QUICK angegeben wird, versucht REPAIR TABLE, nur den Indexbaum zu reparieren. Dieser Reparaturtyp ähnelt dem von myisamchk --recover --quick.

Wenn Sie EXTENDED verwenden, erstellt MySQL den Index Datensatz für Datensatz, statt einen Index gleichzeitig beim Sortieren zu erzeugen. Dieser Reparaturtyp ähnelt dem von myisamchk --safe-recover.

Es gibt auch einen Modus USE_FRM für REPAIR TABLE. Diesen verwenden Sie, wenn die .MYI-Indexdatei fehlt oder ihr Header beschädigt ist. In diesem Modus erstellt MySQL die .MYI-Datei auf der Basis der Daten aus der .frm-Datei neu. Diese Art der Reparatur ist mit myisamchk nicht möglich. Hinweis: Verwenden Sie diesen Modus nur, wenn Sie die regulären REPAIR-Modi nicht einsetzen können. Der .MYI-Header enthält wichtige Tabellenmetadaten (insbesondere etwa den AUTO_INCREMENT-Wert und Delete link), die bei REPAIR ... USE_FRM verloren gehen. Verwenden Sie USE_FRM nicht für eine komprimierte Tabelle, weil diese Informationen auch in der .MYI-Datei gespeichert sind.

REPAIR TABLE-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort NO_WRITE_TO_BINLOG (oder sein Alias LOCAL) nicht verwendet wird. Dies wird gemacht, damit REPAIR TABLE-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

13.5.2.7. RESTORE TABLE

RESTORE TABLE tbl_name [, tbl_name] ... FROM '/path/to/backup/directory'

RESTORE TABLE stellt eine oder mehrere Tabellen aus einer Sicherung, die mit BACKUP TABLE erstellt wurde, wieder her. Vorhandene Tabellen werden nicht überschrieben: Wenn Sie versuchen, eine vorhandene Tabelle durch Wiederherstellen zu überschreiben, dann tritt ein Fehler auf. Wie BACKUP TABLE funktioniert auch RESTORE TABLE derzeit nur für MyISAM-Tabellen. Das Verzeichnis sollte als vollständiger Pfadname angegeben werden.

Das Backup einer Tabelle besteht aus ihrer .frm-Formatdatei und der .MYD-Datendatei. Beim Wiederherstellungsvorgang werden diese Dateien zunächst wiederhergestellt; darauf basierend wird dann die .MYI-Indexdatei erstellt. Die Wiederherstellung dauert länger als die Sicherung, weil die Indizes neu erstellt werden müssen. Je mehr Indizes die Tabelle hat, desto länger dauert der Vorgang.

RESTORE TABLE gibt eine Ergebnismenge mit den folgenden Spalten zurück:

SpalteWert
Tableder Tabellenname
Opist immer restore
Msg_typestatus, error, info oder warning
Msg_textdie Nachricht

13.5.3. SET

SET variable_assignment [, variable_assignment] ...

variable_assignment:
      user_var_name = expr
    | [GLOBAL | SESSION] system_var_name = expr
    | [@@global. | @@session. | @@]system_var_name = expr

Die Anweisung SET weist verschiedenen Arten von Variablen, die sich auf den Betrieb des Servers oder Ihres Clients auswirken, Werte zu.

Dieser Abschnitt beschreibt die Verwendung von SET zur Zuweisung von Werten an System- oder Benutzervariablen. Allgemeine Informationen zu diesen Variablentypen finden Sie in Abschnitt 5.2.2, „Server-Systemvariablen“, und Abschnitt 9.3, „Benutzerdefinierte Variablen“. Eine Liste der Systemvariablen, die dynamisch zur Laufzeit geändert werden können, finden Sie in Abschnitt 5.2.3.2, „Dynamische Systemvariablen“.

Hinweis: Ältere Versionen von MySQL verwendeten SET OPTION. Diese Funktionalität ist jedoch veraltet – mittlerweile wird SET nur noch ohne OPTION benutzt.

Es gibt auch Varianten der SET-Syntax, die in anderen Kontexten verwendet werden:

Die folgende Erläuterung zeigt die verschiedenen SET-Syntaxen, die zur Einstellung von Variablen benutzt werden können. In den Beispielen wird jeweils der Zuweisungsoperator = benutzt, der Operator := ist aber ebenfalls zulässig.

Eine Benutzervariable wird als @var_name geschrieben und kann wie folgt eingestellt werden:

SET @var_name = expr;

Systemvariablen werden in SET-Anweisungen als var_name referenziert. Unter Umständen kann ihnen auch ein Modifizierer vorangestellt sein:

  • Um explizit anzugeben, dass eine Variable eine globale Variable ist, stellen Sie dem Namen GLOBAL oder @@global. voran. Zum Einstellen globaler Variablen ist die Berechtigung SUPER erforderlich.

  • Um explizit anzugeben, dass eine Variable eine Sitzungsvariable ist, stellen Sie dem Namen SESSION oder @@session. voran.

  • LOCAL und @@local. sind Synonyme von SESSION bzw. @@session..

  • Ist kein Modifizierer vorhanden, dann stellt SET die Sitzungsvariable ein.

Ein paar Beispiele:

SET sort_buffer_size=10000;
SET @@local.sort_buffer_size=10000;
SET GLOBAL sort_buffer_size=1000000, SESSION sort_buffer_size=1000000;
SET @@sort_buffer_size=1000000;
SET @@global.sort_buffer_size=1000000, @@local.sort_buffer_size=1000000;

Die Syntax @@var_name für Systemvariablen wird unterstützt, damit die MySQL-Syntax mit einigen anderen Datenbanksystemen kompatibel ist.

Wenn Sie mehrere Systemvariablen in derselben Anweisung einstellen, wird die zuletzt angegebene GLOBAL- oder SESSION-Option für Variablen verwendet, deren Modus nicht näher spezifiziert ist.

Wenn Sie eine sitzungsspezifische Systemvariable einstellen, bleibt der Wert gültig, bis die aktuelle Sitzung endet oder Sie der Variablen einen anderen Wert zuweisen. Stellen Sie eine globale Systemvariable ein, dann wird der Wert gespeichert und bis zum nächsten Neustart des Servers für alle neuen Verbindungen verwendet. Wenn Sie den Wert einer globalen Systemvariablen permanent ändern wollen, sollten Sie diesen in eine Optionsdatei eintragen. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

Um eine falsche Verwendung zu verhindern, erzeugt MySQL einen Fehler, wenn Sie SET GLOBAL für eine Variable verwenden, für die nur SET SESSION zulässig ist, oder GLOBAL (bzw. @@global.) beim Einstellen einer globalen Variablen nicht angeben.

Um eine SESSION-Variable auf den GLOBAL-Wert oder eine GLOBAL-Variable auf den in MySQL einkompilierten Standardwert zu setzen, verwenden Sie das Schlüsselwort DEFAULT. So sind beispielsweise die beiden folgenden Anweisungen dahingehend identisch, dass sie den Sitzungswert von max_join_size auf den globalen Wert setzen:

SET max_join_size=DEFAULT;
SET @@session.max_join_size=@@global.max_join_size;

Es lassen sich nicht alle Systemvariablen auf DEFAULT setzen. In solchen Fällen tritt bei Verwendung von DEFAULT ein Fehler auf.

Eine Liste der Systemvariablen und ihrer Werte zeigen Sie mit der SHOW VARIABLES-Anweisung an. (Siehe auch Abschnitt 13.5.4.24, „SHOW VARIABLES.) Um einen bestimmten Variablennamen oder eine Liste der Namen zu erhalten, die einem Muster entsprechen, verwenden Sie eine LIKE-Klausel wie folgt:

SHOW VARIABLES LIKE 'max_join_size';
SHOW GLOBAL VARIABLES LIKE 'max_join_size';

Zum Anzeigen einer Variablenliste, deren Namen einem Muster entsprechen, verwenden Sie das Jokerzeichen ‘%’:

SHOW VARIABLES LIKE '%size%';
SHOW GLOBAL VARIABLES LIKE '%size%';

Jokerzeichen können an beliebiger Position im Vergleichsmuster stehen.

Sie können den Wert einer bestimmten Systemvariablen auch mit SELECT ermitteln, indem Sie die Syntax @@[global.|session.]var_name benutzen:

SELECT @@global.max_join_size, @@session.max_join_size;

Wenn Sie eine Variable mit SELECT @@var_name (ohne Modifizierer) abrufen, gibt MySQL den SESSION-Wert, sofern dieser vorhanden ist, und andernfalls den GLOBAL-Wert zurück. (Hier liegt ein Unterschied zu SET @@var_name = value vor, wo immer der Sitzungswert referenziert wird.)

Die folgende Liste beschreibt Variablen, die keine Standardsyntax aufweisen oder nicht in der in Abschnitt 5.2.2, „Server-Systemvariablen“, aufgeführten Liste der Systemvariablen beschrieben sind. Zwar werden die hier beschriebenen Variablen nicht von SHOW VARIABLES angezeigt, Sie können die Werte aber mit SELECT abrufen (Ausnahmen sind CHARACTER SET und SET NAMES). Zum Beispiel:

mysql> SELECT @@AUTOCOMMIT;
+--------------+
| @@AUTOCOMMIT |
+--------------+
|            1 |
+--------------+

Die Groß-/Kleinschreibung dieser Optionen ist irrelevant.

  • AUTOCOMMIT = {0 | 1}

    Stellt den Autocommit-Modus ein. Mit der Einstellung 1 werden alle Änderungen direkt übernommen. Wenn Sie 0 wählen, müssen Sie eine Transaktion mit COMMIT übergeben oder sie mit ROLLBACK abbrechen. Standardmäßig starten Clientverbindungen mit dem AUTOCOMMIT-Wert 1. Wenn Sie AUTOCOMMIT von 0 auf 1 umstellen, führt MySQL automatisch eine COMMIT-Anweisung für alle offenen Transaktionen aus. Eine andere Möglichkeit, eine Transaktion zu starten, besteht in der Verwendung der Anweisungen START TRANSACTION oder BEGIN. Siehe auch Abschnitt 13.4.1, „BEGIN/COMMIT/ROLLBACK.

  • BIG_TABLES = {0 | 1}

    Beim Wert 1 werden alle Temporärtabellen auf der Festplatte statt im Arbeitsspeicher abgelegt. Dies ist ein wenig langsamer, aber der Fehler The table tbl_name is full tritt nicht bei SELECT-Operationen auf, die eine große Temporärtabelle erfordern. Der Standardwert bei einer neuen Verbindung ist 0 (d. h., es werden speicherresidente Temporärtabellen verwendet). Im Normalfall sollten Sie diese Variable niemals umstellen müssen, da speicherresidente Tabellen nach Bedarf automatisch in festplattenbasierte Tabellen konvertiert werden. (Hinweis: Diese Variable hieß früher SQL_BIG_TABLES.)

  • CHARACTER SET {charset_name | DEFAULT}

    Hiermit werden alle Strings vom und an den Client den Angaben entsprechend konvertiert. Sie können neue Zuordnungen angeben, indem Sie die Datei sql/convert.cc in der MySQL-Quelldistribution bearbeiten. SET CHARACTER SET stellt drei sitzungsspezifische Systemvariablen ein: character_set_client und character_set_results werden auf den angegebenen Zeichensatz gesetzt, character_set_connection auf den Wert von character_set_database. Siehe auch Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.

    Die Standardzuordnung kann mit dem Wert DEFAULT wiederhergestellt werden.

    Beachten Sie, dass die Syntax sich bei SET CHARACTER SET von der zur Einstellung der meisten anderen Optionen unterscheidet.

  • FOREIGN_KEY_CHECKS = {0 | 1}

    Bei der Einstellung 1 (Vorgabe) werden Fremdschlüssel-Constraints für InnoDB-Tabellen überprüft. Bei der Einstellung 0 werden sie ignoriert. Die Deaktivierung der Fremdschlüsselüberprüfung kann nützlich sein, um InnoDB-Tabellen in einer anderen als der Reihenfolge neu zu laden, die von den Parent/Child-Beziehungen erfordert wird. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

  • IDENTITY = value

    Diese Variable ist synonym zur Variablen LAST_INSERT_ID. Sie ist aus Gründen der Kompatibilität mit anderen Datenbanksystemen vorhanden. Sie können ihren Wert mit SELECT @@IDENTITY auslesen und mit SET IDENTITY einstellen.

  • INSERT_ID = value

    Stellt den von der folgenden INSERT- oder ALTER TABLE-Anweisung zu verwendenden Wert ein, wenn ein AUTO_INCREMENT-Wert eingefügt wird. Wird in erster Linie beim Binärlog benutzt.

  • LAST_INSERT_ID = value

    Stellt den von LAST_INSERT_ID() zurückzugebenden Wert ein. Dieser wird im Binärlog gespeichert, wenn Sie LAST_INSERT_ID() in einer Anweisung verwenden, die eine Tabelle aktualisiert. Durch Einstellen dieser Variablen wird der von der C-API-Funktion mysql_insert_id() zurückgegebene Wert nicht geändert.

  • NAMES {'charset_name' | DEFAULT}

    SET NAMES setzt die drei Systemvariablen character_set_client, character_set_connection und character_set_results auf den angegebenen Zeichensatz. Das Einstellen von character_set_connection auf charset_name setzt collation_connection auf die Standardsortierfolge für charset_name. Siehe auch Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.

    Die Standardzuordnung kann mit dem Wert DEFAULT wiederhergestellt werden.

    Beachten Sie, dass die Syntax sich bei SET NAMES von der zur Einstellung der meisten anderen Optionen unterscheidet.

  • ONE_SHOT

    Diese Option ist ein Modifizierer und keine Variable. Sie kann verwendet werden, um die Wirkung von Variablen zu beeinflussen, die den Zeichensatz, die Sortierfolge und die Zeitzone einstellen. ONE_SHOT wird in erster Linie zu Replikationszwecken eingesetzt. mysqlbinlog verwendet SET ONE_SHOT zur vorübergehenden Änderung der Werte von Zeichensatz-, Sortierfolgen- und Zeitzonenvariablen, um die ursprünglichen Werte für einen Rollforward zu speichern.

    Sie können ONE_SHOT nur mit den zulässigen Variablen verwenden, andernfalls erhalten Sie einen Fehler wie den folgenden:

    mysql> SET ONE_SHOT max_allowed_packet = 1;
    ERROR 1382 (HY000): The 'SET ONE_SHOT' syntax is reserved for purposes
    internal to the MySQL server
    

    Wenn ONE_SHOT mit zulässigen Variablen benutzt wird, ändert es die Variablen nach Bedarf – jedoch nur für die nächste Anweisung, die nicht SET ist. Nachfolgend setzt der Server alle zeichensatz-, sortierfolgen- und zeitzonenspezifischen Systemvariablen auf ihre vorherigen Werte. Beispiel:

    mysql> SET ONE_SHOT character_set_connection = latin5;
    
    mysql> SET ONE_SHOT collation_connection = latin5_turkish_ci;
    
    mysql> SHOW VARIABLES LIKE '%_connection';
    +--------------------------+-------------------+
    | Variable_name            | Value             |
    +--------------------------+-------------------+
    | character_set_connection | latin5            |
    | collation_connection     | latin5_turkish_ci |
    +--------------------------+-------------------+
    
    mysql> SHOW VARIABLES LIKE '%_connection';
    +--------------------------+-------------------+
    | Variable_name            | Value             |
    +--------------------------+-------------------+
    | character_set_connection | latin1            |
    | collation_connection     | latin1_swedish_ci |
    +--------------------------+-------------------+
    
  • SQL_AUTO_IS_NULL = {0 | 1}

    Bei der Einstellung 1 (Vorgabe) ermitteln Sie den zuletzt eingefügten Datensatz für eine Tabelle, die eine AUTO_INCREMENT-Spalte umfasst, mithilfe des folgenden Konstrukts:

    WHERE auto_increment_column IS NULL
    

    Dieses Verhalten wird von einigen ODBC-Programmen wie etwa Access verwendet.

  • SQL_BIG_SELECTS = {0 | 1}

    Bei der Einstellung 0 bricht MySQL SELECT-Anweisungen ab, deren Ausführung voraussichtlich sehr lange dauern wird (d. h., Anweisungen, bei denen der Optimierer eine Anzahl von untersuchten Datensätzen annimmt, deren Wert max_join_size überschreitet. Dies ist praktisch, wenn eine nicht empfehlenswerte WHERE-Anweisung abgesetzt wurde. Der Standardwert für eine neue Verbindung ist 1, d. h., alle SELECT-Anweisungen sind zulässig.

    Wenn Sie die Systemvariable max_join_size auf einen anderen Wert als DEFAULT setzen, wird SQL_BIG_SELECTS auf 0 gesetzt.

  • SQL_BUFFER_RESULT = {0 | 1}

    SQL_BUFFER_RESULT bewirkt, dass Ergebnisse aus SELECT-Anweisungen in Temporärtabellen abgelegt werden. Auf diese Weise kann MySQL die Tabellensperren schnell wieder aufheben. Die Option ist zudem in Fällen hilfreich, in denen die Übermittlung der Ergebnisse an den Client sehr lange dauert.

  • SQL_LOG_BIN = {0 | 1}

    Bei der Einstellung 0 erfolgt für den Client keine Aufzeichnung in das Binärlog. Der Client benötigt die Berechtigung SUPER, um diese Option einzustellen.

  • SQL_LOG_OFF = {0 | 1}

    Bei der Einstellung 1 erfolgt für den Client keine Aufzeichnung in das Log für allgemeine Abfragen. Der Client benötigt die Berechtigung SUPER, um diese Option einzustellen.

  • SQL_LOG_UPDATE = {0 | 1}

    Diese Variable ist veraltet und wird auf SQL_LOG_BIN umgesetzt.

  • SQL_NOTES = {0 | 1}

    Bei der Einstellung 1 (Standard) werden Warnungen auf Note-Ebene aufgezeichnet. Wird hingegen 0 gewählt, dann werden Note-Warnungen unterdrückt. mysqldump enthält eine Ausgabe, die diese Variable auf 0 setzt, sodass ein Neuladen der Dumpdatei keine Warnungen für Ereignisse erzeugt, die die Integrität des Neuladevorgangs nicht beeinträchtigen.

  • SQL_QUOTE_SHOW_CREATE = {0 | 1}

    Bei der Einstellung 1 setzt der Server Bezeichner für die Anweisungen SHOW CREATE TABLE und SHOW CREATE DATABASE in Anführungszeichen. Bei 0 werden keine Anführungszeichen gesetzt. Die Option ist standardmäßig aktiviert, damit die Replikation auch bei Bezeichnern funktioniert, die Anführungszeichen erfordern. Siehe auch Abschnitt 13.5.4.6, „SHOW CREATE TABLE, und Abschnitt 13.5.4.4, „SHOW CREATE DATABASE.

  • SQL_SAFE_UPDATES = {0 | 1}

    Bei der Einstellung 1 bricht MySQL UPDATE- und DELETE-Anweisungen ab, die keinen Schlüssel in der WHERE-Klausel oder einer LIMIT-Klausel verwenden. Auf diese Weise lassen sich UPDATE- oder DELETE-Anweisungen abfangen, bei denen Schlüssel nicht korrekt eingesetzt werden und die unter Umständen eine große Zahl von Datensätzen ändern oder löschen würden.

  • SQL_SELECT_LIMIT = {value | DEFAULT}

    Die maximale Anzahl von Datensätzen, die von SELECT-Anweisungen zurückgegeben werden können. Der Standardwert bei einer neuen Verbindung lautet „unbegrenzt“. Wenn Sie den Grenzwert geändert haben, kann der Standardwert mit dem Wert DEFAULT für SQL_SELECT_LIMIT wiederhergestellt werden.

    Wenn eine SELECT-Anweisung eine LIMIT-Klausel aufweist, hat diese LIMIT-Klausel Vorrang vor dem Wert von SQL_SELECT_LIMIT.

    SQL_SELECT_LIMIT gilt nicht für SELECT-Anweisungen, die in gespeicherten Routinen ausgeführt werden. Ebenso wenig gelten sie für SELECT-Anweisungen, die keine Ergebnismenge erzeugen, die an den Client zurückgegeben wird. Hierzu gehören SELECT-Anweisungen in Unterabfragen, CREATE TABLE ... SELECT und INSERT INTO ... SELECT.

  • SQL_WARNINGS = {0 | 1}

    Diese Variable steuert, ob INSERT-Anweisungen für einen Datensatz einen Informations-String erzeugen, wenn Warnungen auftreten. Die Standardeinstellung ist 0. Setzen Sie den Wert auf 1, um einen Informations-String zu generieren.

  • TIMESTAMP = {timestamp_value | DEFAULT}

    Stellt die Zeit für diesen Client ein. Auf deren Basis wird der ursprüngliche Zeitstempel ermittelt, wenn Sie Datensätze mit dem Binärlog wiederherstellen. timestamp_value sollte ein Unix-Epochenzeitstempel und kein MySQL-Zeitstempel sein.

  • UNIQUE_CHECKS = {0 | 1}

    Bei der Einstellung 1 (Standard) werden Eindeutigkeitsprüfungen für Sekundärindizes in InnoDB-Tabellen durchgeführt. Wenn der Wert 0 eingestellt wurde, werden keine Eindeutigkeitsprüfungen für Indexeinträge durchgeführt, die in den InnoDB-Einfügepuffer eingefügt wurden. Wenn Sie ganz sicher wissen, dass Ihre Daten keine Verstöße gegen das Eindeutigkeitsgebot enthalten, können Sie hier 0 wählen, um den Import großer Tabellen in InnoDB zu beschleunigen.

13.5.4. SHOW

Es gibt viele Formen von SHOW, die Informationen zu Datenbanken, Tabellen oder Spalten sowie Statusangaben zum Server vermitteln. In diesem Abschnitt werden die folgenden SHOW-Anweisungen beschrieben:

SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']
SHOW CREATE DATABASE db_name
SHOW CREATE FUNCTION funcname
SHOW CREATE PROCEDURE procname
SHOW CREATE TABLE tbl_name
SHOW DATABASES [LIKE 'pattern']
SHOW ENGINE engine_name {LOGS | STATUS }
SHOW [STORAGE] ENGINES
SHOW ERRORS [LIMIT [offset,] row_count]
SHOW FUNCTION STATUS [LIKE 'pattern']
SHOW GRANTS FOR user
SHOW INDEX FROM tbl_name [FROM db_name]
SHOW INNODB STATUS
SHOW PROCEDURE STATUS [LIKE 'pattern']
SHOW [BDB] LOGS
SHOW PLUGIN
SHOW PRIVILEGES
SHOW [FULL] PROCESSLIST
SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern']
SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
SHOW [OPEN] TABLES [FROM db_name] [LIKE 'pattern']
SHOW TRIGGERS
SHOW [GLOBAL | SESSION] VARIABLES [LIKE 'pattern']
SHOW WARNINGS [LIMIT [offset,] row_count]

Es gibt zusätzliche Formen der SHOW-Anweisung, die Informationen zu Replikationsmaster- und -slave-Servern vermitteln (diese werden in Abschnitt 13.6, „SQL-Befehle in Bezug auf Replikation“, beschrieben):

SHOW BINLOG EVENTS
SHOW MASTER LOGS
SHOW MASTER STATUS
SHOW SLAVE HOSTS
SHOW SLAVE STATUS

Wenn die Syntax für eine gegebene SHOW-Anweisung einen LIKE 'pattern'-Teil enthält, ist 'pattern' ein String, der die SQL-Jokerzeichen ‘%’ und ‘_’ enthalten kann. Dieses Muster ist praktisch, um die Ausgabe der Anweisung auf passende Werte zu beschränken.

Mehrere SHOW-Anweisungen akzeptieren zudem eine WHERE-Klausel, die mehr Flexibilität bei der Angabe der anzuzeigenden Datensätze bietet. Siehe auch Abschnitt 22.22, „Erweiterungen der SHOW-Anweisungen“.

13.5.4.1. SHOW CHARACTER SET

SHOW CHARACTER SET [LIKE 'pattern']

Die Anweisung SHOW CHARACTER SET zeigt alle verfügbaren Zeichensätze an. Sie nimmt eine optionale LIKE-Klausel entgegen, die angibt, auf welche Zeichensatznamen zu prüfen ist. Zum Beispiel:

mysql> SHOW CHARACTER SET LIKE 'latin%';
+---------+-----------------------------+-------------------+--------+
| Charset | Description                 | Default collation | Maxlen |
+---------+-----------------------------+-------------------+--------+
| latin1  | cp1252 West European        | latin1_swedish_ci |      1 |
| latin2  | ISO 8859-2 Central European | latin2_general_ci |      1 |
| latin5  | ISO 8859-9 Turkish          | latin5_turkish_ci |      1 |
| latin7  | ISO 8859-13 Baltic          | latin7_general_ci |      1 |
+---------+-----------------------------+-------------------+--------+

Die Spalte Maxlen zeigt die maximale Anzahl von Bytes an, die zur Speicherung eines Zeichens erforderlich sind.

13.5.4.2. SHOW COLLATION

SHOW COLLATION [LIKE 'pattern']

Die Ausgabe von SHOW COLLATION enthält alle verfügbaren Zeichensätze. Sie nimmt eine optionale LIKE-Klausel entgegen, bei der pattern angibt, auf welche Sortierfolgennamen zu prüfen ist. Zum Beispiel:

mysql> SHOW COLLATION LIKE 'latin1%';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1  |  5 |         |          |       0 |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       0 |
| latin1_danish_ci  | latin1  | 15 |         |          |       0 |
| latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
| latin1_bin        | latin1  | 47 |         | Yes      |       0 |
| latin1_general_ci | latin1  | 48 |         |          |       0 |
| latin1_general_cs | latin1  | 49 |         |          |       0 |
| latin1_spanish_ci | latin1  | 94 |         |          |       0 |
+-------------------+---------+----+---------+----------+---------+

Die Spalte Default gibt ab, ob eine Sortierfolge standardmäßig für den Zeichensatz verwendet wird. Compiled zeigt an, ob der Zeichensatz in den Server einkompiliert ist. Sortlen schließlich bezieht sich auf die Menge des Speichers, die zum Sortieren der im Zeichensatz ausgedrückten Strings erforderlich ist.

13.5.4.3. SHOW COLUMNS

SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']

SHOW COLUMNS vermittelt Informationen zu Spalten in einer Tabelle. Die Anweisung funktioniert auch bei Views.

Das Schlüsselwort FULL bewirkt, dass die Ausgabe ihre Berechtigungen sowie alle spaltenspezifischen Kommentare für jede Spalte enthält.

Sie können db_name.tbl_name als Alternative zur Syntax tbl_name FROM db_name verwenden. Die beiden folgenden Anweisungen sind mithin äquivalent:

mysql> SHOW COLUMNS FROM mytable FROM mydb;
mysql> SHOW COLUMNS FROM mydb.mytable;

SHOW FIELDS ist ein Synonym für SHOW COLUMNS. Sie können die Spalten einer Tabelle auch mit dem Befehl mysqlshow db_name tbl_name auflisten.

Die Anweisung DESCRIBE ermittelt ähnliche Informationen wie SHOW COLUMNS. Siehe auch Abschnitt 13.3.1, „DESCRIBE (Informationen über Spalten abrufen)“.

13.5.4.4. SHOW CREATE DATABASE

SHOW CREATE {DATABASE | SCHEMA} db_name

Zeigt die CREATE DATABASE-Anweisung an, mit der die übergebene Datenbank erstellt wurde. SHOW CREATE SCHEMA ist ein Synonym zu SHOW CREATE DATABASE.

mysql> SHOW CREATE DATABASE test\G
*************************** 1. row ***************************
       Database: test
Create Database: CREATE DATABASE `test`
                 /*!40100 DEFAULT CHARACTER SET latin1 */

mysql> SHOW CREATE SCHEMA test\G
*************************** 1. row ***************************
       Database: test
Create Database: CREATE DATABASE `test`
                 /*!40100 DEFAULT CHARACTER SET latin1 */

SHOW CREATE DATABASE setzt Tabellen- und Spaltennamen entsprechend dem Wert von SQL_QUOTE_SHOW_CREATE in Anführungszeichen. Siehe auch Abschnitt 13.5.3, „SET.

13.5.4.5. SHOW CREATE PROCEDURE und SHOW CREATE FUNCTION

SHOW CREATE {PROCEDURE | FUNCTION} sp_name

Diese Anweisung ist eine MySQL-Erweiterung. Analog zu SHOW CREATE TABLE gibt sie den exakten String zurück, mit dem die genannte Routine neu erstellt werden kann.

mysql> SHOW CREATE FUNCTION test.hello\G
*************************** 1. row ***************************
       Function: hello
       sql_mode:
Create Function: CREATE FUNCTION `test`.`hello`(s CHAR(20)) RETURNS CHAR(50)
RETURN CONCAT('Hello, ',s,'!')

13.5.4.6. SHOW CREATE TABLE

SHOW CREATE TABLE tbl_name

Zeigt die CREATE TABLE-Anweisung an, mit der die übergebene Tabelle erstellt wurde. Diese Anweisung funktioniert auch bei Views.

mysql> SHOW CREATE TABLE t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE t (
  id INT(11) default NULL auto_increment,
  s char(60) default NULL,
  PRIMARY KEY (id)
) ENGINE=MyISAM

SHOW CREATE TABLE setzt Tabellen- und Spaltennamen entsprechend dem Wert von SQL_QUOTE_SHOW_CREATE in Anführungszeichen. Siehe auch Abschnitt 13.5.3, „SET.

13.5.4.7. SHOW DATABASES

SHOW {DATABASES | SCHEMAS} [LIKE 'pattern']

SHOW DATABASES listet die Datenbanken auf dem MySQL Server-Host auf. Sofern Sie nicht über die Berechtigung SHOW DATABASES verfügen, werden Ihnen nur diejenigen Datenbanken angezeigt, für die Sie Berechtigungen haben. Sie können diese Liste auch mit mysqlshow anzeigen.

Wurde der Server mit der Option --skip-show-database gestartet, dann können Sie diese Anweisung ohne die Berechtigung SHOW DATABASES überhaupt nicht verwenden.

SHOW SCHEMAS kann ebenfalls verwendet werden.

13.5.4.8. SHOW ENGINE

SHOW ENGINE engine_name {LOGS | STATUS }

SHOW ENGINE zeigt Log- und Statusinformationen zu Speicher-Engines an. Die folgenden Anweisungen werden derzeit unterstützt:

SHOW ENGINE BDB LOGS
SHOW ENGINE INNODB STATUS

SHOW ENGINE BDB LOGS zeigt Statusinformationen zu vorhandenen BDB-Logdateien an. Zurückgegeben werden die folgenden Felder:

  • File

    Der vollständige Pfad zur Logdatei.

  • Type

    Der Logdateityp (BDB bei Berkeley DB-Logdateien).

  • Status

    Der Status der Logdatei (FREE, wenn die Datei entfernt werden kann, oder IN USE, wenn die Datei vom Transaktionssubsystem benötigt wird).

SHOW ENGINE INNODB STATUS zeigt umfassende Informationen zum Zustand der InnoDB-Speicher-Engine an.

Ältere (und mittlerweile nicht mehr verwendete) Synonyme für diese Anweisungen sind SHOW [BDB] LOGS und SHOW INNODB STATUS.

13.5.4.9. SHOW ENGINES

SHOW [STORAGE] ENGINES

SHOW ENGINES zeigt Statusinformationen zu den Speicher-Engines des Servers an. Dies ist besonders nützlich, um zu überprüfen, ob eine Speicher-Engine unterstützt wird, oder um festzustellen, welche Engine standardmäßig benutzt wird. SHOW TABLE TYPES ist ein veraltetes Synonym.

mysql> SHOW ENGINES\G
*************************** 1. row ***************************
      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 2. row ***************************
      Engine: MyISAM
     Support: DEFAULT
     Comment: Default engine as of MySQL 3.23 with great performance
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 3. row ***************************
      Engine: InnoDB
     Support: YES
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES
*************************** 4. row ***************************
      Engine: BerkeleyDB
     Support: YES
     Comment: Supports transactions and page-level locking
Transactions: YES
          XA: NO
  Savepoints: NO
*************************** 5. row ***************************
      Engine: EXAMPLE
     Support: YES
     Comment: Example storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 6. row ***************************
      Engine: ARCHIVE
     Support: YES
     Comment: Archive storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 7. row ***************************
      Engine: CSV
     Support: YES
     Comment: CSV storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 8. row ***************************
      Engine: BLACKHOLE
     Support: YES
     Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 9. row ***************************
      Engine: FEDERATED
     Support: YES
     Comment: Federated MySQL storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 10. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO
          XA: NO
  Savepoints: NO

Der Wert Support gibt an, ob die betreffende Speicher-Engine unterstützt wird und welches die standardmäßig verwendete Engine ist. Wird der Server beispielsweise mit der Option --default-table-type=InnoDB gestartet, dann hat der Wert Support für den Datensatz InnoDB den Wert DEFAULT. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

Die Spalten Transactions, XA und Savepoints wurden in MySQL 5.1.2 hinzugefügt. Sie geben jeweils an, ob die Speicher-Engine Transaktionen, XA-Transaktionen und/oder Speicherpunkte unterstützt.

13.5.4.10. SHOW ERRORS

SHOW ERRORS [LIMIT [offset,] row_count]
SHOW COUNT(*) ERRORS

Diese Anweisung ähnelt SHOW WARNINGS; der Unterschied besteht darin, dass statt Fehlern, Warnungen und Hinweisen lediglich Fehler angezeigt werden.

Die LIMIT-Klausel hat dieselbe Syntax wie bei der SELECT-Anweisung. Siehe auch Abschnitt 13.2.7, „SELECT.

Die SHOW COUNT(*) ERRORS-Anweisung zeigt die Anzahl der Fehler an. Sie können diese Anzahl auch der Variablen error_count entnehmen:

SHOW COUNT(*) ERRORS;
SELECT @@error_count;

Weitere Informationen finden Sie unter Abschnitt 13.5.4.25, „SHOW WARNINGS.

13.5.4.11. SHOW GRANTS

SHOW GRANTS FOR user

Diese Anweisung listet die GRANT-Anweisung(en) auf, die abgesetzt werden muss bzw. müssen, um die Berechtigungen zu kopieren, die einem MySQL-Benutzerkonto zugewiesen sind. Das Konto wird im selben Format wie bei der GRANT-Anweisung angegeben (z. B. 'jeffrey'@'localhost'). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten User und Host des kontenspezifischen Datensatzes in der Tabelle user.

mysql> SHOW GRANTS FOR 'root'@'localhost';
+---------------------------------------------------------------------+
| Grants for root@localhost                                           |
+---------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION |
+---------------------------------------------------------------------+

Um die Berechtigungen des Kontos aufzulisten, über das Sie mit dem Server verbunden sind, können Sie eine der folgenden Anweisungen verwenden:

SHOW GRANTS;
SHOW GRANTS FOR CURRENT_USER;
SHOW GRANTS FOR CURRENT_USER();

SHOW GRANTS zeigt nur die Berechtigungen an, die dem genannten Konto explizit zugewiesen sind. Das Konto kann also über weitere Berechtigungen verfügen, die nicht aufgelistet sind. Ist beispielsweise ein anonymes Konto vorhanden, dann kann das genannte Konto dessen Berechtigungen unter Umständen nutzen; dies wird aber von SHOW GRANTS nicht angezeigt.

13.5.4.12. SHOW INDEX

SHOW INDEX FROM tbl_name [FROM db_name]

SHOW INDEX gibt Informationen zum Tabellenindex zurück. Das Format erinnert an das des Aufrufs SQLStatistics in ODBC.

SHOW INDEX gibt die folgenden Felder zurück:

  • Table

    Der Name der Tabelle.

  • Non_unique

    0, wenn der Index keine Dubletten enthalten darf, andernfalls 1.

  • Key_name

    Der Name des Indexes.

  • Seq_in_index

    Die Sequenznummer der Spalte im Index, beginnend bei 1.

  • Column_name

    Der Spaltenname.

  • Collation

    Gibt an, wie die Spalte im Index sortiert ist. In MySQL können die Werte ‘A’ (aufsteigend) oder NULL (nicht sortiert) auftreten.

  • Cardinality

    Schätzung der Anzahl eindeutiger Werte im Index. Aktualisiert wird der Wert durch Ausführung von ANALYZE TABLE oder myisamchk -a. Cardinality wird basierend auf Statistiken gezählt, die als Integers gespeichert werden, d. h., der Wert ist auch bei kleinen Tabellen unter Umständen nicht exakt. Je höher die Kardinalität, desto größer ist die Chance, dass MySQL den Index bei der Durchführung von Joins verwendet.

  • Sub_part

    Die Anzahl der indizierten Zeichen, wenn die Spalte nur teilweise indiziert ist, oder NULL, wenn die gesamte Spalte indiziert ist.

  • Packed

    Gibt an, wie der Schlüssel gepackt ist. NULL zeigt an, dass der Schlüssel nicht gepackt ist.

  • Null

    Enthält YES, wenn die Spalte NULL sein kann. Andernfalls enthält die Spalte NO.

  • Index_type

    Der verwendete Indextyp (BTREE, FULLTEXT, HASH, RTREE).

  • Comment

    Verschiedene Anmerkungen.

Sie können db_name.tbl_name als Alternative zur Syntax tbl_name FROM db_name verwenden. Die folgenden beiden Anweisungen sind äquivalent:

SHOW INDEX FROM mytable FROM mydb;
SHOW INDEX FROM mydb.mytable;

SHOW KEYS ist ein Synonym für SHOW INDEX. Sie können die Indizes einer Tabelle auch mit dem Befehl mysqlshow -k db_name tbl_name auflisten.

13.5.4.13. SHOW INNODB STATUS

SHOW INNODB STATUS

In MySQL 5.1 ist dies ein veraltetes Synonym für SHOW ENGINE INNODB STATUS. Siehe auch Abschnitt 13.5.4.8, „SHOW ENGINE.

13.5.4.14. SHOW LOGS

SHOW [BDB] LOGS

In MySQL 5.1 ist dies ein veraltetes Synonym für SHOW ENGINE BDB LOGS. Siehe auch Abschnitt 13.5.4.8, „SHOW ENGINE.

13.5.4.15. SHOW OPEN TABLES

SHOW OPEN TABLES [FROM db_name] [LIKE 'pattern']

SHOW OPEN TABLES listet die nichttemporären Tabellen auf, die derzeit im Tabellen-Cache geöffnet sind. Siehe auch Abschnitt 7.4.8, „Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank“.

SHOW OPEN TABLES gibt die folgenden Felder zurück:

  • Database

    Die Datenbank, die die Tabelle enthält.

  • Table

    Der Tabellenname.

  • In_use

    Häufigkeit, mit der die Tabelle zurzeit von Abfragen verwendet wird. Wenn der Wert null ist, dann ist die Tabelle geöffnet, wird aber derzeit nicht verwendet.

  • Name_locked

    Gibt an, ob der Tabellenname gesperrt ist. Die Namenssperrung wird bei Operationen wie dem Löschen oder Umbenennen von Tabellen verwendet.

13.5.4.16. SHOW PLUGIN

SHOW PLUGIN

SHOW PLUGIN zeigt Informationen zu bekannten Plug-Ins an.

mysql> SHOW PLUGIN;
+------------+--------+----------------+---------+
| Name       | Status | Type           | Library |
+------------+--------+----------------+---------+
| MEMORY     | ACTIVE | STORAGE ENGINE | NULL    |
| MyISAM     | ACTIVE | STORAGE ENGINE | NULL    |
| InnoDB     | ACTIVE | STORAGE ENGINE | NULL    |
| ARCHIVE    | ACTIVE | STORAGE ENGINE | NULL    |
| CSV        | ACTIVE | STORAGE ENGINE | NULL    |
| BLACKHOLE  | ACTIVE | STORAGE ENGINE | NULL    |
| FEDERATED  | ACTIVE | STORAGE ENGINE | NULL    |
| MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL    |
+------------+--------+----------------+---------+

SHOW PLUGIN wurde in MySQL 5.1.5 hinzugefügt.

13.5.4.17. SHOW PRIVILEGES

SHOW PRIVILEGES

SHOW PRIVILEGES zeigt eine Liste mit Systemberechtigungen an, die der MySQL Server unterstützt. Wie diese Liste genau aussieht, hängt von der Version Ihres Servers ab.

mysql> SHOW PRIVILEGES\G
*************************** 1. row ***************************
Privilege: Alter
Context: Tables
Comment: To alter the table
*************************** 2. row ***************************
Privilege: Alter routine
Context: Functions,Procedures
Comment: To alter or drop stored functions/procedures
*************************** 3. row ***************************
Privilege: Create
Context: Databases,Tables,Indexes
Comment: To create new databases and tables
*************************** 4. row ***************************
Privilege: Create routine
Context: Functions,Procedures
Comment: To use CREATE FUNCTION/PROCEDURE
*************************** 5. row ***************************
Privilege: Create temporary tables
Context: Databases
Comment: To use CREATE TEMPORARY TABLE
...

13.5.4.18. SHOW PROCEDURE STATUS und SHOW FUNCTION STATUS

SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']

Diese Anweisung ist eine MySQL-Erweiterung. Sie gibt Eigenschaften von Routinen zurück, z. B. Datenbank, Name, Typ und Ersteller sowie Erstellungs- und Änderungsdatum. Wird kein Muster angegeben, dann werden abhängig von der verwendeten Anweisung Informationen zu allen gespeicherten Prozeduren oder allen gespeicherten Funktionen aufgelistet.

mysql> SHOW FUNCTION STATUS LIKE 'hello'\G
*************************** 1. row ***************************
           Db: test
         Name: hello
         Type: FUNCTION
      Definer: testuser@localhost
     Modified: 2004-08-03 15:29:37
      Created: 2004-08-03 15:29:37
Security_type: DEFINER
      Comment:

Sie können Informationen zu gespeicherten Routinen auch der Tabelle ROUTINES in INFORMATION_SCHEMA entnehmen. Siehe auch Abschnitt 22.14, „Die Tabelle INFORMATION_SCHEMA ROUTINES.

13.5.4.19. SHOW PROCESSLIST

SHOW [FULL] PROCESSLIST

SHOW PROCESSLIST zeigt Ihnen, welche Threads gerade ausgeführt werden. Sie können diese Information auch mit mysqladmin processlist anzeigen. Wenn Sie die Berechtigung SUPER haben, werden alle Threads angezeigt. Andernfalls werden nur Ihre eigenen Threads (d. h. Threads, die mit dem MySQL-Benutzerkonto verknüpft sind, das Sie verwenden) angezeigt. Siehe auch Abschnitt 13.5.5.3, „KILL. Wenn Sie das Schlüsselwort FULL nicht angeben, werden nur die ersten hundert Zeichen jeder Anweisung im Feld Info angezeigt.

Diese Anweisung ist recht praktisch, wenn Sie die Fehlermeldung „Too many connections“ erhalten und herausfinden wollen, was gerade passiert. MySQL reserviert eine zusätzliche Verbindung für Konten, die die Berechtigung SUPER haben, damit gewährleistet ist, dass Administratoren jederzeit Verbindungen herstellen können, um das System zu überprüfen. (Dies setzt natürlich voraus, dass Sie diese Berechtigung nicht allen Benutzern gewähren.)

Die Ausgabe von SHOW PROCESSLIST kann etwa so aussehen:

mysql> SHOW FULL PROCESSLIST\G
*************************** 1. row ***************************
Id: 1
User: system user
Host:
db: NULL
Command: Connect
Time: 1030455
State: Waiting for master to send event
Info: NULL
*************************** 2. row ***************************
Id: 2
User: system user
Host:
db: NULL
Command: Connect
Time: 1004
State: Has read all relay log; waiting for the slave I/O thread to update it
Info: NULL
*************************** 3. row ***************************
Id: 3112
User: replikator
Host: artemis:2204
db: NULL
Command: Binlog Dump
Time: 2144
State: Has sent all binlog to slave; waiting for binlog to be updated
Info: NULL
*************************** 4. row ***************************
Id: 3113
User: replikator
Host: iconnect2:45781
db: NULL
Command: Binlog Dump
Time: 2086
State: Has sent all binlog to slave; waiting for binlog to be updated
Info: NULL
*************************** 5. row ***************************
Id: 3123
User: stefan
Host: localhost
db: apollon
Command: Query
Time: 0
State: NULL
Info: SHOW FULL PROCESSLIST
5 rows in set (0.00 sec)

Die Spalten haben die nachfolgend beschriebenen Bedeutungen:

  • Id

    Der Verbindungsbezeichner.

  • User

    Der MySQL-Benutzer, der die Anweisung abgesetzt hat. Die Anzeige system user bezeichnet einen clientlosen Thread, den der Server erzeugt hat, um Tasks intern zu verwalten. Es kann sich dabei um den I/O- oder den SQL-Thread, der auf dem Replikationsserver verwendet wird, oder einen Handler für verzögerte Datensätze handeln. Für den system user ist in der Spalte Host kein Host angegeben.

  • Host

    Der Hostname des Clients, der die Anweisung absetzt (außer bei system user, wo kein Host angegeben wird).

    SHOW PROCESSLIST meldet den Hostnamen für TCP/IP-Verbindungen im Format host_name:client_port, damit Sie schneller feststellen können, welcher Client was tut.

  • db

    Die Standarddatenbank, sofern eine solche ausgewählt wurde; andernfalls NULL.

  • Command

    Der Wert dieser Spalte entspricht den COM_xxx-Befehlen des Client/Server-Protokolls. Siehe auch Abschnitt 5.2.4, „Server-Statusvariablen“.

    Der Wert Command kann einen der folgenden Werte haben: Binlog Dump, Change user, Close stmt, Connect, Connect Out, Create DB, Debug, Delayed insert, Drop DB, Error, Execute, Fetch, Field List, Init DB, Kill, Long Data, Ping, Prepare, Processlist, Query, Quit, Refresh, Register Slave, Reset stmt, Set option, Shutdown, Sleep, Statistics, Table Dump, Time

  • Time

    Die Zeit (in Sekunden), die seit dem Start der Anweisung oder des Befehls bis jetzt vergangen ist.

  • State

    Eine Aktion, ein Ereignis oder ein Zustand. Folgende Werte sind möglich: After create, Analyzing, Changing master, Checking master version, Checking table, Connecting to master, Copying to group table, Copying to tmp table, Creating delayed handler, Creating index, Creating sort index, Creating table from master dump, Creating tmp table, Execution of init_command, FULLTEXT initialization, Finished reading one binlog; switching to next binlog, Flushing tables, Killed, Killing slave, Locked, Making temp file , Opening master dump table, Opening table, Opening tables, Processing request, Purging old relay logs, Queueing master event to the relay log, Reading event from the relay log, Reading from net, Reading master dump table data, Rebuilding the index on master dump table, Reconnecting after a failed binlog dump request, Reconnecting after a failed master event read, Registering slave on master, Removing duplicates, Reopen tables, Repair by sorting, Repair done, Repair with keycache, Requesting binlog dump, Rolling back, Saving state, Searching rows for update, Sending binlog event to slave, Sending data, Sorting for group, Sorting for order, Sorting index, Sorting result, System lock, Table lock, Thread initialized, Updating, User lock, Waiting for INSERT, Waiting for master to send event, Waiting for master update, Waiting for slave mutex on exit, Waiting for table, Waiting for tables, Waiting for the next event in relay log, Waiting on cond, Waiting to finalize termination, Waiting to reconnect after a failed binlog dump request, Waiting to reconnect after a failed master event read, Writing to net, allocating local table, cleaning up, closing tables, converting HEAP to MyISAM, copy to tmp table, creating table, deleting from main table, deleting from reference tables, discard_or_import_tablespace, end, freeing items, got handler lock, got old table, info, init, insert, logging slow query, login, preparing, purging old relay logs, query end, removing tmp table, rename, rename result table, reschedule, setup, starting slave, statistics, storing row into queue, update, updating, updating main table, updating reference tables, upgrading lock, waiting for delay_list, waiting for handler insert, waiting for handler lock, waiting for handler open

    Die gängigsten State-Werte werden im Folgenden beschrieben. Die Mehrzahl der anderen State-Werte sind in erster Linie praktisch, um Bugs im Server zu finden. Weitere Informationen zu Prozesszuständen bei Replikationsservern finden Sie in Abschnitt 6.4, „Replikation: Implementationsdetails“.

    Für die SHOW PROCESSLIST-Anweisung ist der State-Wert NULL.

  • Info

    Die Anweisung, die der Thread ausführt, oder NULL, sofern er keine Anweisung ausführt.

Einige State-Werte finden Sie in der Ausgabe von SHOW PROCESSLIST recht häufig:

  • Checking table

    Der Thread führt eine Tabellenprüfung durch.

  • Closing tables

    Der Thread synchronisiert die geänderten Tabellendaten auf die Festplatte und schließt die verwendeten Tabellen. Dies sollte ein sehr schneller Vorgang sein. Andernfalls sollten Sie überprüfen, ob Ihre Festplatte nicht voll ist oder stark frequentiert wird.

  • Connect Out

    Ein Replikationsslave stellt eine Verbindung zum Master her.

  • Copying to tmp table

    Der Server kopiert Daten in eine Temporärtabelle im Speicher.

  • Copying to tmp table on disk

    Der Server kopiert Daten in eine Temporärtabelle auf die Festplatte. Die temporäre Ergebnismenge war größer als tmp_table_size, und der Thread stellt die Temporärtabelle deswegen vom speicherresidenten in das festplattenbasierte Format um, um Speicher zu sparen.

  • Creating tmp table

    Der Thread erstellt eine Temporärtabelle, die einen Teil des Abfrageergebnisses aufnehmen soll.

  • deleting from main table

    Der Server führt den ersten Teil eines Löschvorgangs über mehrere Tabellen aus. Der Löschvorgang erfolgt nur in der ersten Tabelle und speichert Felder und Offsets, die zum Löschen aus anderen (Referenz-)Tabellen benutzt werden.

  • deleting from reference tables

    Der Server führt den zweiten Teil eines Löschvorgangs über mehrere Tabellen aus und löscht die entsprechenden Datensätze aus anderen Tabellen.

  • Flushing tables

    Der Thread führt FLUSH TABLES aus und wartet, bis alle Threads ihre Tabellen geschlossen haben.

  • FULLTEXT initialization

    Der Server bereitet die Ausführung einer natursprachlichen Volltextsuche vor.

  • Killed

    Jemand hat eine KILL-Anweisung an den Thread abgesetzt. Der Thread wird abgebrochen, wenn beim nächsten Mal das Terminierungs-Flag gesetzt wird. Dieses Flag wird in jeder größeren Schleife in MySQL gesetzt. Trotzdem kann es unter Umständen einen Moment dauern, bis der Thread terminiert ist. Ist der Thread durch einen anderen Thread gesperrt, dann erfolgt die Terminierung erst, wenn der andere Thread die Sperre aufgehoben hat.

  • Locked

    Die Abfrage wird durch eine andere Abfrage gesperrt.

  • Sending data

    Der Thread verarbeitet Datensätze für eine SELECT-Anweisung und sendet zudem Daten an den Client.

  • Sorting for group

    Der Thread führt eine Sortierung infolge einer GROUP BY-Klausel durch.

  • Sorting for order

    Der Thread führt eine Sortierung infolge einer ORDER BY-Klausel durch.

  • Opening tables

    Der Thread versucht, eine Tabelle zu öffnen. Dies sollte ein sehr schneller Vorgang sein, sofern das Öffnen nicht durch irgendeinen Umstand verhindert wird. So kann beispielsweise eine ALTER TABLE- oder eine LOCK TABLE-Anweisung das Öffnen einer Tabelle bis zum Abschluss der Anweisung unterbinden.

  • Reading from net

    Der Server liest ein Paket aus dem Netzwerk.

  • Removing duplicates

    Die Abfrage verwendete SELECT DISTINCT so, dass MySQL die DISTINCT-Operation nicht zu einem frühen Zeitpunkt wegoptimieren konnte. Aus diesem Grund erfordert MySQL eine zusätzliche Phase, um alle duplizierten Datensätze zu entfernen, bevor das Ergebnis an den Client gesendet wird.

  • Reopen table

    Der Thread hat eine Sperre für die Tabelle erwirkt, danach aber festgestellt, dass die zugrunde liegende Tabellenstruktur sich geändert hat. Der Thread hat die Sperre dann aufgehoben und die Tabelle geschlossen und versucht nun, sie wieder zu öffnen.

  • Repair by sorting

    Der Reparaturcode verwendet einen Sortiervorgang zur Erstellung der Indizes.

  • Repair with keycache

    Der Reparaturcode erstellt einen Schlüssel nach dem anderen über den Schlüssel-Cache. Dies ist wesentlich langsamer als Repair by sorting.

  • Searching rows for update

    Der Thread durchläuft die erste Phase zur Suche nach passenden Datensätzen, bevor er sie aktualisiert. Dies muss getan werden, wenn UPDATE den Index ändert, der für die Suche nach den betreffenden Datensätzen verwendet wird.

  • Sleeping

    Der Thread wartet darauf, dass der Client eine neue Anweisung an ihn sendet.

  • statistics

    Der Server berechnet Statistiken zur Entwicklung eines Abfrageausführungsplans.

  • System lock

    Der Thread wartet darauf, eine externe Systemsperre für die Tabelle zu erhalten. Wenn Sie nicht mehrere mysqld-Server verwenden, die auf die gleichen Tabellen zugreifen, können Sie Systemsperren mit der Option --skip-external-locking deaktivieren.

  • Upgrading lock

    Der Handler INSERT DELAYED versucht, eine Sperre für die Tabelle zu erwirken, um Datensätze einzufügen.

  • Updating

    Der Thread sucht nach zu aktualisierenden Datensätzen und aktualisiert diese dann.

  • updating main table

    Der Server führt den ersten Teil eines Änderungsvorgangs über mehrere Tabellen aus. Er führt Änderungen nur in der ersten Tabelle aus und speichert Felder und Offsets, die zur Aktualisierung anderer (Referenz-)Tabellen benutzt werden.

  • updating reference tables

    Der Server führt den zweiten Teil eines Änderungsvorgangs über mehrere Tabellen aus und aktualisiert die entsprechenden Datensätze in den anderen Tabellen.

  • User Lock

    Der Thread wartet auf ein GET_LOCK().

  • Waiting for tables

    Der Thread hat eine Mitteilung erhalten, dass die einer Tabelle zugrunde liegende Struktur sich geändert hat und er die Tabelle neu öffnen muss, um die neue Struktur zu erhalten. Um die Tabelle allerdings neu öffnen zu können, muss er warten, bis alle anderen Threads die fragliche Tabelle geschlossen haben.

    Diese Benachrichtigung erfolgt, wenn ein anderer Thread FLUSH TABLES oder eine der folgenden Anweisungen für die betreffende Tabelle verwendet hat: FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE oder OPTIMIZE TABLE.

  • waiting for handler insert

    Der INSERT DELAYED-Handler hat alle anhängigen Einfügeoperationen verarbeitet und wartet auf neue.

  • Writing to net

    Der Server schreibt ein Paket in das Netzwerk.

Die meisten Zustände entsprechen sehr schnellen Operationen. Wenn ein Thread für mehrere Sekunden in einem dieser Zustände verbleibt, dann weist dies auf ein Problem hin, das untersucht werden muss.

13.5.4.20. SHOW STATUS

SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern']

SHOW STATUS zeigt Serverstatusinformationen an. Diese Informationen können auch mit dem Befehl mysqladmin extended-status ermittelt werden.

Nachfolgend ist auszugsweise eine Ausgabe aufgelistet. Die Liste der Variablen und ihrer Werte kann auf Ihrem Server anders aussehen. Die Bedeutung der Variablen ist in Abschnitt 5.2.4, „Server-Statusvariablen“, beschrieben.

mysql> SHOW STATUS;
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| Aborted_clients          | 0          |
| Aborted_connects         | 0          |
| Bytes_received           | 155372598  |
| Bytes_sent               | 1176560426 |
| Connections              | 30023      |
| Created_tmp_disk_tables  | 0          |
| Created_tmp_tables       | 8340       |
| Created_tmp_files        | 60         |
...
| Open_tables              | 1          |
| Open_files               | 2          |
| Open_streams             | 0          |
| Opened_tables            | 44600      |
| Questions                | 2026873    |
...
| Table_locks_immediate    | 1920382    |
| Table_locks_waited       | 0          |
| Threads_cached           | 0          |
| Threads_created          | 30022      |
| Threads_connected        | 1          |
| Threads_running          | 1          |
| Uptime                   | 80380      |
+--------------------------+------------+

Mit einer LIKE-Klausel zeigt die Anweisung nur die Variablen an, die dem Muster entsprechen:

mysql> SHOW STATUS LIKE 'Key%';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| Key_blocks_used    | 14955    |
| Key_read_requests  | 96854827 |
| Key_reads          | 162040   |
| Key_write_requests | 7589728  |
| Key_writes         | 3813196  |
+--------------------+----------+

Wenn die Option GLOBAL angegeben wird, erhalten Sie die Statuswerte für alle Verbindungen zu MySQL. Bei SESSION erhalten Sie hingegen die Statuswerte der aktuellen Verbindung. Geben Sie überhaupt keine Option an, dann wird SESSION als Vorgabe verwendet. LOCAL ist ein Synonym für SESSION.

Einige Statusvariablen haben nur einen globalen Wert. Bei diesen erhalten Sie denselben Wert sowohl für GLOBAL als auch für SESSION.

13.5.4.21. SHOW TABLE STATUS

SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']

SHOW TABLE STATUS funktioniert wie SHOW TABLE, vermittelt aber zahlreiche Informationen zu den einzelnen Tabellen. Sie können diese Liste auch mit mysqlshow --status db_name anzeigen.

Diese Anweisung erlaubt auch die Anzeige von Informationen zu Views.

SHOW TABLE STATUS gibt die folgenden Felder zurück:

  • Name

    Den Namen der Tabelle.

  • Engine

    Die Speicher-Engine der Tabelle. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen. Vor MySQL 4.1.2 hieß dieser Wert Type.

  • Version

    Die Versionsnummer der .frm-Datei der Tabelle.

  • Row_format

    Das Format für die Datensatzspeicherung (Fixed, Dynamic, Compressed, Redundant, Compact). Das Format von InnoDB-Tabellen wird als Redundant oder Compact gemeldet.

  • Rows

    Anzahl der Datensätze. Einige Speicher-Engines wie etwa MyISAM speichern die exakte Anzahl.

    Bei anderen Engines wie InnoDB hingegen ist dies ein Schätzwert, der vom tatsächlichen Wert um bis zu 40 oder 50 Prozent abweichen kann. In solchen Fällen sollten Sie mit SELECT COUNT(*) eine exakte Anzahl ermitteln.

    Der Rows-Wert ist NULL bei Tabellen in der Datenbank INFORMATION_SCHEMA.

  • Avg_row_length

    Durchschnittliche Länge eines Datensatzes.

  • Data_length

    Die Länge der Datendatei.

  • Max_data_length

    Die maximale Länge der Datendatei. Dies ist die Gesamtzahl der Bytes, die in der Tabelle gespeichert werden können. Sie wird auf der Basis der verwendeten Zeigergröße berechnet.

  • Index_length

    Die Länge der Indexdatei.

  • Data_free

    Anzahl der reservierten, aber nicht verwendeten Bytes.

  • Auto_increment

    Der nächste AUTO_INCREMENT-Wert.

  • Create_time

    Zeitpunkt der Tabellenerstellung.

  • Update_time

    Zeitpunkt der letzten Aktualisierung der Datendatei.

  • Check_time

    Zeitpunkt der letzten Tabellenüberprüfung. Nicht alle Speicher-Engines aktualisieren diese Zeitangabe (in solchen Fällen ist der Wert stets NULL).

  • Collation

    Zeichensatz und Sortierung der Tabelle.

  • Checksum

    Wert der mitlaufenden Prüfsumme (sofern vorhanden).

  • Create_options

    Zusätzliche Optionen, die bei CREATE TABLE angegeben wurden.

  • Comment

    Bei der Erstellung der Tabelle angegebener Kommentar (oder Angaben dazu, warum MySQL nicht auf die Tabellendaten zugreifen konnte).

Im Tabellenkommentar meldet InnoDB den freien Speicher des Tablespaces, zu dem die Tabelle gehört. Bei einer Tabelle, die sich in einem gemeinsamen Tablespace befindet, ist dies der freie Speicher des gemeinsamen Tablespaces. Verwenden Sie mehrere Tablespaces und hat die Tabelle einen eigenen Tablespace, dann bezieht sich die Angabe des freien Speichers nur auf diese Tabelle.

Bei MEMORY-Tabellen geben die Werte Data_length, Max_data_length und Index_length näherungsweise die tatsächliche Menge des reservierten Speichers an. Der Reservierungsalgorithmus reserviert in großem Umfang Speicher, um die Anzahl der Reservierungsoperationen zu verringern.

Bei NDB Cluster-Tabellen zeigt die Ausgabe dieser Anweisung annähernde Werte für die Spalten Avg_row_length und Data_length. Ausgenommen sind lediglich BLOB-Spalten, die nicht berücksichtigt werden. Außerdem wird die Anzahl der Repliken in der Comment-Spalte (als number_of_replicas) angegeben.

Bei Views sind alle von SHOW TABLE STATUS angezeigten Felder NULL; lediglich Name zeigt den Namen des Views an, und Comment enthält view.

13.5.4.22. SHOW TABLES

SHOW [FULL] TABLES [FROM db_name] [LIKE 'pattern']

SHOW TABLES listet alle nichttemporären Tabellen in einer gegebenen Datenbank auf. Sie können diese Liste auch mit mysqlshow db_name anzeigen.

Die Anweisung listet außerdem alle Views in der Datenbank auf. Der Modifizierer FULL wird dahingehend unterstützt, dass SHOW FULL TABLES eine zweite Ausgabespalte anzeigt. Werte der zweiten Spalte sind BASE TABLE bei einer Tabelle und VIEW bei einem View.

Hinweis: Wenn Sie keine Berechtigungen für eine Tabelle haben, dann erscheint diese nicht in der Ausgabe von SHOW TABLES oder mysqlshow db_name.

13.5.4.23. SHOW TRIGGERS

SHOW TRIGGERS [FROM db_name] [LIKE expr]

SHOW TRIGGERS listet die derzeit auf dem MySQL Server definierten Trigger auf. Diese Anweisung erfordert die Berechtigung SUPER.

Für den Trigger ins_sum, wie er in Abschnitt 20.3, „Verwendung von Triggern“, definiert ist, sieht die Ausgabe der Anweisung wie folgt aus:

mysql> SHOW TRIGGERS LIKE 'acc%'\G
*************************** 1. row ***************************
  Trigger: ins_sum
    Event: INSERT
    Table: account
Statement: SET @sum = @sum + NEW.amount
   Timing: BEFORE
  Created: NULL
 sql_mode:
  Definer: myname@localhost

Hinweis: Wenn Sie eine LIKE-Klausel mit SHOW TRIGGERS verwenden, wird der zu prüfende Ausdruck expr mit dem Namen der Tabelle verglichen, für die der Trigger deklariert wurde, und nicht mit dem Namen des Triggers:

mysql> SHOW TRIGGERS LIKE 'ins%';
Empty set (0.01 sec)

Es folgt eine kurze Erläuterung der Spalten in der Ausgabe der Anweisung:

  • Trigger

    Der Name des Triggers.

  • Event

    Das Ereignis, welches die Trigger-Aktivierung ausgelöst hat: 'INSERT', 'UPDATE' oder 'DELETE'.

  • Table

    Die Tabelle, für die der Trigger definiert ist.

  • Statement

    Die bei Aktivierung des Triggers auszuführende Anweisung. Diese entspricht dem Text in der Spalte ACTION_STATEMENT von INFORMATION_SCHEMA.TRIGGERS.

  • Timing

    Einer der beiden Werte 'BEFORE' oder 'AFTER'.

  • Created

    Der Wert dieser Spalte ist zurzeit immer NULL.

  • sql_mode

    Der bei der Ausführung des Triggers gültige SQL-Modus.

  • Definer

    Das Konto, welches den Trigger erstellt hat.

Siehe auch Abschnitt 22.16, „Die Tabelle INFORMATION_SCHEMA TRIGGERS.

13.5.4.24. SHOW VARIABLES

SHOW [GLOBAL | SESSION] VARIABLES [LIKE 'pattern']

SHOW VARIABLES zeigt den Wert einiger MySQL-Systemvariablen. Diese Informationen können auch mit dem Befehl mysqladmin variables ermittelt werden.

Mit der Option GLOBAL erhalten Sie die Werte, die für neue Verbindungen mit MySQL verwendet werden. Mit SESSION erhalten Sie hingegen die für die aktuelle Verbindung gültigen Werte. Geben Sie überhaupt keine Option an, dann wird SESSION als Vorgabe verwendet. LOCAL ist ein Synonym für SESSION.

Sind die Standardwerte ungeeignet, dann können Sie die meisten dieser Variablen beim Start von mysqld mit Befehlsoptionen oder zur Laufzeit mit der SET-Anweisung einstellen. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld, und Abschnitt 13.5.3, „SET.

Nachfolgend ist auszugsweise eine Ausgabe aufgelistet. Die Liste der Variablen und ihrer Werte kann auf Ihrem Server anders aussehen. Abschnitt 5.2.2, „Server-Systemvariablen“, beschreibt die Bedeutung der einzelnen Variablen. Informationen zu ihrer Optimierung finden Sie in Abschnitt 7.5.2, „Serverparameter feineinstellen“.

mysql> SHOW VARIABLES;
+---------------------------------+---------------------------+
| Variable_name                   | Value                     |
+---------------------------------+---------------------------+
| auto_increment_increment        | 1                         |
| auto_increment_offset           | 1                         |
| automatic_sp_privileges         | ON                        |
| back_log                        | 50                        |
| basedir                         | /home/jon/bin/mysql-5.1/  |
| binlog_cache_size               | 32768                     |
| bulk_insert_buffer_size         | 8388608                   |
| character_set_client            | latin1                    |
| character_set_connection        | latin1                    |
...
| max_user_connections            | 0                         |
| max_write_lock_count            | 4294967295                |
| multi_range_count               | 256                       |
| myisam_data_pointer_size        | 6                         |
| myisam_max_sort_file_size       | 2147483647                |
| myisam_recover_options          | OFF                       |
| myisam_repair_threads           | 1                         |
| myisam_sort_buffer_size         | 8388608                   |
| ndb_autoincrement_prefetch_sz   | 32                        |
| ndb_cache_check_time            | 0                         |
| ndb_force_send                  | ON                        |
...
| time_zone                       | SYSTEM                    |
| timed_mutexes                   | OFF                       |
| tmp_table_size                  | 33554432                  |
| tmpdir                          |                           |
| transaction_alloc_block_size    | 8192                      |
| transaction_prealloc_size       | 4096                      |
| tx_isolation                    | REPEATABLE-READ           |
| updatable_views_with_limit      | YES                       |
| version                         | 5.1.6-alpha-log           |
| version_comment                 | Source distribution       |
| version_compile_machine         | i686                      |
| version_compile_os              | suse-linux                |
| wait_timeout                    | 28800                     |
+---------------------------------+---------------------------+

Mit einer LIKE-Klausel zeigt die Anweisung nur die Variablen an, die dem Muster entsprechen:

mysql> SHOW VARIABLES LIKE 'have%';
+-----------------------+----------+
| Variable_name         | Value    |
+-----------------------+----------+
| have_archive          | YES      |
| have_bdb              | NO       |
| have_blackhole_engine | YES      |
| have_compress         | YES      |
| have_crypt            | YES      |
| have_csv              | YES      |
| have_example_engine   | NO       |
| have_federated_engine | NO       |
| have_geometry         | YES      |
| have_innodb           | YES      |
| have_isam             | NO       |
| have_ndbcluster       | DISABLED |
| have_openssl          | NO       |
| have_partitioning     | YES      |
| have_query_cache      | YES      |
| have_raid             | NO       |
| have_rtree_keys       | YES      |
| have_symlink          | YES      |
+-----------------------+----------+

13.5.4.25. SHOW WARNINGS

SHOW WARNINGS [LIMIT [offset,] row_count]
SHOW COUNT(*) WARNINGS

SHOW WARNINGS zeigt die Fehler-, Warnungs- und Hinweismeldungen, die durch die zuletzt abgesetzte Anweisung ausgegeben wurden. Hat diese Anweisung keine Meldungen erzeugt, so ist die Ausgabe leer. Die verwandte Anweisung SHOW ERRORS zeigt nur die Fehler an. Siehe auch Abschnitt 13.5.4.10, „SHOW ERRORS.

Die Liste der Meldungen wird bei jeder neuen Anweisung, die eine Tabelle verwendet, zurückgesetzt.

Die SHOW COUNT(*) WARNINGS-Anweisung zeigt die Gesamtanzahl der Fehler, Warnungen und Hinweise an. Sie können diese Anzahl auch der Variablen warning_count entnehmen:

SHOW COUNT(*) WARNINGS;
SELECT @@warning_count;

Der Wert von warning_count kann größer sein als die Anzahl der von SHOW WARNINGS angezeigten Meldungen. Dies liegt dann daran, dass die Systemvariable max_error_count so niedrig angesetzt ist, dass nicht alle Meldungen gespeichert werden. Ein weiter unten in diesem Anschnitt gezeigtes Beispiel veranschaulicht, wie dies geschehen kann.

Die LIMIT-Klausel hat dieselbe Syntax wie bei der SELECT-Anweisung. Siehe auch Abschnitt 13.2.7, „SELECT.

Der MySQL Server sendet die Gesamtanzahl der Fehler, Warnungen und Hinweise zurück, die aufgrund der letzten Anweisung erzeugt wurden. Wenn Sie die C-API verwenden, lässt sich dieser Wert durch einen Aufruf von mysql_warning_count() ermitteln. Siehe auch Abschnitt 24.2.3.69, „mysql_warning_count().

Warnungen werden für Anweisungen wie LOAD DATA INFILE und DML-Anweisungen wie INSERT, UPDATE, CREATE TABLE und ALTER TABLE erzeugt.

Die folgende DROP TABLE-Anweisung erzeugt einen Hinweis:

mysql> DROP TABLE IF EXISTS no_such_table;
mysql> SHOW WARNINGS;
+-------+------+-------------------------------+
| Level | Code | Message                       |
+-------+------+-------------------------------+
| Note  | 1051 | Unknown table 'no_such_table' |
+-------+------+-------------------------------+

Es folgt ein einfaches Beispiel, das eine Syntaxwarnung für CREATE TABLE und Konvertierungswarnungen für INSERT enthält:

mysql> CREATE TABLE t1 (a TINYINT NOT NULL, b CHAR(4)) TYPE=MyISAM;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1287
Message: 'TYPE=storage_engine' is deprecated, use
         'ENGINE=storage_engine' instead
1 row in set (0.00 sec)

mysql> INSERT INTO t1 VALUES(10,'mysql'),(NULL,'test'),
    -> (300,'Open Source');
Query OK, 3 rows affected, 4 warnings (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 4

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1265
Message: Data truncated for column 'b' at row 1
*************************** 2. row ***************************
  Level: Warning
   Code: 1263
Message: Data truncated, NULL supplied to NOT NULL column 'a' at row 2
*************************** 3. row ***************************
  Level: Warning
   Code: 1264
Message: Data truncated, out of range for column 'a' at row 3
*************************** 4. row ***************************
  Level: Warning
   Code: 1265
Message: Data truncated for column 'b' at row 3
4 rows in set (0.00 sec)

Die maximale Anzahl zu speichernder Fehler-, Warn- und Hinweismeldungen wird von der Systemvariablen max_error_count gesteuert. Der Standardwert ist 64. Um die Anzahl der Meldungen, die Sie speichern wollen, zu ändern, modifizieren Sie den Wert von max_error_count. Im folgenden Beispiel erzeugt die ALTER TABLE-Anweisung drei Warnmeldungen, von denen aber nur eine gespeichert wird, weil max_error_count zuvor auf 1 gesetzt worden war:

mysql> SHOW VARIABLES LIKE 'max_error_count';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_error_count | 64    |
+-----------------+-------+
1 row in set (0.00 sec)

mysql> SET max_error_count=1;
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE t1 MODIFY b CHAR;
Query OK, 3 rows affected, 3 warnings (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 3

mysql> SELECT @@warning_count;
+-----------------+
| @@warning_count |
+-----------------+
|               3 |
+-----------------+
1 row in set (0.01 sec)

mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1263 | Data truncated for column 'b' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

Um Warnungen zu deaktivieren, setzen Sie max_error_count auf 0. In diesem Fall zeigt warning_count zwar noch an, wie viele Warnungen aufgetreten sind, aber keine dieser Meldungen wird gespeichert.

Sie können die Sitzungsvariable SQL_NOTES auf 0 setzen, damit Warnungen auf der Note-Ebene nicht aufgezeichnet werden.

13.5.5. Weitere Verwaltungsanweisungen

13.5.5.1. CACHE INDEX

CACHE INDEX
  tbl_index_list [, tbl_index_list] ...
  IN key_cache_name

tbl_index_list:
  tbl_name [[INDEX|KEY] (index_name[, index_name] ...)]

Die Anweisung CACHE INDEX weist Tabellenindizes einem bestimmten Schlüssel-Cache zu. Sie wird nur bei MyISAM-Tabellen eingesetzt.

Die folgende Anweisung weist Indizes der Tabellen t1, t2 und t3 dem Schlüssel-Cache namens hot_cache zu:

mysql> CACHE INDEX t1, t2, t3 IN hot_cache;
+---------+--------------------+----------+----------+
| Table   | Op                 | Msg_type | Msg_text |
+---------+--------------------+----------+----------+
| test.t1 | assign_to_keycache | status   | OK       |
| test.t2 | assign_to_keycache | status   | OK       |
| test.t3 | assign_to_keycache | status   | OK       |
+---------+--------------------+----------+----------+

Die Syntax von CACHE INDEX gestattet Ihnen, anzugeben, dass nur bestimmte Indizes aus einer Tabelle dem Cache zuzuweisen sind. Die aktuelle Implementierung weist alle Indizes der Tabelle dem Cache zu, weswegen es keinen Grund gibt, einen anderen Parameter als den Tabellennamen zu übergeben.

Der in der CACHE INDEX-Anweisung referenzierte Schlüssel-Cache kann erstellt werden, indem seine Größe mit einer Anweisung zur Parametereinstellung oder in den Parametereinstellungen des Servers angegeben wird. Zum Beispiel:

mysql> SET GLOBAL keycache1.key_buffer_size=128*1024;

Parameter eines Schlüssel-Caches lassen sich als Mitglieder einer strukturierten Systemvariablen einstellen. Siehe auch Abschnitt 5.2.3.1, „Strukturierte Systemvariablen“.

Ein Schlüssel-Cache muss bereits vorhanden sein, bevor Sie ihm Indizes zuweisen:

mysql> CACHE INDEX t1 IN non_existent_cache;
ERROR 1284 (HY000): Unknown key cache 'non_existent_cache'

Standardmäßig werden Tabellenindizes dem (vorgabeseitigen) Hauptschlüssel-Cache zugewiesen, der beim Serverstart erstellt wird. Wird ein Schlüssel-Cache zerstört, dann werden alle ihm zugewiesenen Indizes wieder dem Standardschlüssel-Cache zugewiesen.

Die Indexzuweisung wirkt sich global auf den Server aus: Wenn ein Client einem gegebenen Cache einen Index zuweist, wird der Cache für alle Abfragen verwendet, die diesen Index einbeziehen – unabhängig davon, welcher Client die Abfragen absetzt.

13.5.5.2. FLUSH

FLUSH [LOCAL | NO_WRITE_TO_BINLOG] flush_option [, flush_option] ...

Die FLUSH-Anweisung leert verschiedene interne Caches, die von MySQL verwendet werden, bzw. lädt diese neu. Für die Ausführung von FLUSH benötigen Sie die Berechtigung RELOAD.

Die Anweisung RESET ähnelt FLUSH. Siehe auch Abschnitt 13.5.5.5, „RESET.

flush_option kann die folgenden Werte annehmen:

  • HOSTS

    Leert die Cache-Tabellen auf dem Host. Sie sollten die Hosttabellen leeren, wenn einer Ihrer Hosts die IP-Nummer wechselt oder Sie die Fehlermeldung Host 'host_name' is blocked erhalten. Wenn aufeinander folgend mehr als max_connect_errors Fehler für einen gegebenen Host auftreten, während dieser eine Verbindung mit dem MySQL Server herstellt, dann geht MySQL davon aus, dass etwas nicht stimmt, und sperrt weitere Verbindungsanfragen dieses Hosts. Das Synchronisieren der Hosttabellen gestattet dem Host einen neuen Versuch der Verbindungsherstellung. Siehe auch Abschnitt A.2.5, „Host '...' is blocked-Fehler“. Sie können mysqld mit --max_connect_errors=999999999 starten, um diese Fehlermeldung zu verhindern.

  • DES_KEY_FILE

    Lädt die DES-Schlüssel aus der mit der Option --des-key-file beim Serverstart angegebenen Datei neu.

  • LOGS

    Schließt alle Logdateien und öffnet sie neu. Wenn das binäre Loggen aktiviert ist, wird die Sequenznummer der Binärlogdatei relativ zur vorherigen Datei um den Wert 1 erhöht. Unter Unix ist dies das Gleiche wie das Senden eines SIGHUP-Signals an den mysqld-Server. (Ausnahme sind einige Versionen von Mac OS X 10.3, wo mysqld SIGHUP und SIGQUIT ignoriert.)

    Wenn der Server mit der Option --log-error gestartet wurde, bewirkt FLUSH LOGS, dass das Fehlerlog mit dem Suffix -old umbenannt wird und mysqld eine neue leere Logdatei erstellt. Wenn die Option --log-error nicht angegeben wird, erfolgt keine Umbenennung.

  • PRIVILEGES

    Lädt die Berechtigungen aus der Gesamtstruktur in der mysql-Datenbank neu.

  • QUERY CACHE

    Defragmentiert den Abfrage-Cache, um seinen Speicher besser zu nutzen. FLUSH QUERY CACHE entfernt anders als RESET QUERY CACHE keine Abfragen aus dem Cache.

  • STATUS

    Setzt die meisten Statusvariablen auf null. Dies ist etwas, das Sie nur beim Debuggen einer Abfrage tun sollten. Siehe auch Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

  • {TABLE | TABLES} [tbl_name [, tbl_name] ...]

    Wenn keine Tabellen benannt sind, werden alle Tabellen geschlossen. Das Schließen aller gerade verwendeten Tabellen wird ebenfalls erzwungen. Ferner wird der Schlüssel-Cache synchronisiert. Werden ein oder mehrere Tabellennamen angegeben, dann werden nur die angegebenen Tabellen synchronisiert. FLUSH TABLES entfernt ebenso wie RESET QUERY CACHE zudem alle Abfrageergebnisse aus dem Abfrage-Cache.

  • TABLES WITH READ LOCK

    Schließt alle offenen Tabellen und versieht alle Tabellen für alle Datenbanken mit einer Lesesperre, bis Sie UNLOCK TABLES ausführen. Dies ist eine recht praktische Möglichkeit der Datensicherung, wenn Sie ein Dateisystem wie Veritas einsetzen, das rechtzeitig Schnappschüsse erstellt.

  • USER_RESOURCES

    Setzt alle Benutzerbeschränkungen auf Stundenbasis auf null. Hierdurch können Clients, bei denen der Grenzwert für Verbindungen, Abfragen oder Änderungen pro Stunde erreicht wurde, ihre Aktivitäten direkt wiederaufnehmen. FLUSH USER_RESOURCES wirkt sich allerdings nicht auf die Begrenzung gleichzeitiger Verbindungen aus. Siehe auch Abschnitt 13.5.1.3, „GRANT und REVOKE.

FLUSH-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort NO_WRITE_TO_BINLOG (oder sein Alias LOCAL) nicht verwendet wird. Dies wird gemacht, damit FLUSH-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

Hinweis: FLUSH LOGS, FLUSH MASTER, FLUSH SLAVE und FLUSH TABLES WITH READ LOCK werden keinesfalls geloggt, weil dies bei der Replikation auf einen Slave Probleme verursachen würde.

Sie können auf einige dieser Anweisungen auch mit dem Hilfsprogramm mysqladmin zugreifen, indem Sie die Befehle flush-hosts, flush-logs, flush-privileges, flush-status oder flush-tables verwenden.

Hinweis: Es ist in MySQL 5.1 nicht möglich, FLUSH-Anweisungen in gespeicherten Funktionen oder Triggern abzusetzen. Allerdings können Sie FLUSH in gespeicherten Prozeduren benutzen, solange diese nicht aus gespeicherten Funktionen heraus oder von Triggern aufgerufen werden. Siehe auch Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“.

Informationen dazu, wie die RESET-Anweisung bei der Replikation verwendet wird, finden Sie in Abschnitt 13.5.5.5, „RESET.

13.5.5.3. KILL

KILL [CONNECTION | QUERY] thread_id

Jede Verbindung mit mysqld wird in einem separaten Thread ausgeführt. Mit der Anweisung SHOW PROCESSLIST können Sie die gerade ausgeführten Threads auflisten. Die Terminierung eines Threads ist mit der Anweisung KILL thread_id möglich.

KILL unterstützt die optionalen Modifizierer CONNECTION oder QUERY:

  • KILL CONNECTION entspricht KILL ohne Modifizierer: Es terminiert die Verbindung zur angegebenen Kennung thread_id.

  • KILL QUERY terminiert die über die Verbindung aktuell ausgeführte Anweisung, lässt die Verbindung selbst aber bestehen.

Wenn Sie die Berechtigung PROCESS haben, werden alle Threads angezeigt. Wenn Sie die Berechtigung SUPER haben, können Sie alle Threads und Anweisungen terminieren. Andernfalls werden nur Ihre eigenen Threads und Anweisungen angezeigt und zur Terminierung freigegeben.

Zur Überprüfung und Terminierung von Threads können Sie auch die Befehle mysqladmin processlist und mysqladmin kill verwenden.

Hinweis: Sie können KILL nicht mit der Embedded MySQL Server-Bibliothek verwenden, da der eingebettete Server nur in den Threads der Hostanwendung ausgeführt wird – er selbst erstellt also keine Verbindungs-Threads.

Wenn Sie KILL verwenden, wird ein Thread-spezifisches Terminierungs-Flag für den Thread gesetzt. In den meisten Fällen kann es etwas dauern, bis die Terminierung des Threads abgeschlossen ist, weil das Flag nur in bestimmten Abständen überprüft wird:

  • Bei SELECT-, ORDER BY- und GROUP BY-Schleifen wird das Flag nach dem Lesen eines Datensatzblocks überprüft. Ist das Terminierungs-Flag gesetzt, dann wird die Anweisung abgebrochen.

  • Bei ALTER TABLE wird das Terminierungs-Flag vor jedem Lesen eines Datensatzblocks aus der Ursprungstabelle geprüft. Wurde das Flag gesetzt, dann wird die Anweisung abgebrochen und die Temporärtabelle gelöscht.

  • Bei UPDATE- oder DELETE-Operationen wird das Flag nach jedem gelesenen Block und nach jedem geänderten oder gelöschten Datensatz überprüft. Ist das Terminierungs-Flag gesetzt, dann wird die Anweisung abgebrochen. Beachten Sie, dass, wenn Sie keine Transaktionen verwenden, bereits erfolgte Änderungen nicht rückgängig gemacht werden.

  • GET_LOCK() führt einen Abbruch aus und gibt NULL zurück.

  • Ein INSERT DELAYED-Thread synchronisiert schnell alle Datensätze in seinem Speicher (d. h., er schreibt sie) und wird dann terminiert.

  • Wenn der Thread sich im Tabellensperr-Handler befindet (Zustand Locked), dann wird die Tabellensperre umgehend aufgehoben.

  • Wartet der Thread bei einem Schreibaufruf auf freien Festplattenspeicher, dann wird die Schreiboperation mit der Fehlermeldung „Disk Full“ abgebrochen.

  • Warnung: Die Terminierung einer REPAIR TABLE- oder OPTIMIZE TABLE-Operation führt bei einer MyISAM-Tabelle zu Beschädigungen, die die Tabelle unbrauchbar machen. Lese- oder Schreiboperationen in eine solche Tabelle schlagen fehl, bis Sie sie – ohne Unterbrechung – wieder optimieren oder reparieren.

13.5.5.4. LOAD INDEX INTO CACHE

LOAD INDEX INTO CACHE
  tbl_index_list [, tbl_index_list] ...

tbl_index_list:
  tbl_name
    [[INDEX|KEY] (index_name[, index_name] ...)]
    [IGNORE LEAVES]

Die Anweisung LOAD INDEX INTO CACHE lädt einen Tabellenindex vorab in den Schlüssel-Cache, dem er durch eine explizite CACHE INDEX-Anweisung zugewiesen wurde, oder aber in den vorgabeseitigen Schlüssel-Cache. LOAD INDEX INTO CACHE wird nur bei MyISAM-Tabellen verwendet.

Der Modifizierer IGNORE LEAVES bewirkt, dass nur Blöcke für Indexknoten, die nicht Endknoten (Blätter) sind, geladen werden.

Die folgende Anweisung lädt Knoten (Indexblöcke) mit Indizes der Tabellen t1 und t2:

mysql> LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
+---------+--------------+----------+----------+
| Table   | Op           | Msg_type | Msg_text |
+---------+--------------+----------+----------+
| test.t1 | preload_keys | status   | OK       |
| test.t2 | preload_keys | status   | OK       |
+---------+--------------+----------+----------+

Die Anweisung lädt alle Indexblöcke aus t1. Bei t2 werden nur Blöcke für Nichtendknoten geladen.

Die Syntax von LOAD INDEX INTO CACHE gestattet Ihnen, anzugeben, dass nur bestimmte Indizes aus einer Tabelle geladen werden sollen. Die aktuelle Implementierung lädt alle Indizes der Tabelle in den Cache, weswegen es keinen Grund gibt, einen anderen Parameter als den Tabellennamen zu übergeben.

13.5.5.5. RESET

RESET reset_option [, reset_option] ...

Die RESET-Anweisung wird benutzt, um den Status verschiedener Serveroperationen zu löschen. Sie benötigen die Berechtigung RELOAD, um RESET ausführen zu können.

RESET agiert als stärkere Version der FLUSH-Anweisung. Siehe auch Abschnitt 13.5.5.2, „FLUSH.

reset_option kann die folgenden Werte annehmen:

  • MASTER

    Löscht alle in der Indexdatei aufgeführten Binärlogs, leert den Binärlogindex und setzt ihn zurück und erstellt eine neue Binärlogdatei. (Ist als FLUSH MASTER in MySQL-Versionen vor 3.23.26 bekannt.) Siehe auch Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“.

  • QUERY CACHE

    Entfernt alle Abfrageergebnisse aus dem Abfrage-Cache.

  • SLAVE

    Löscht auf dem Slave die Angabe zur Replikationsposition in den Binärlogs des Masters (d. h., der Slave „vergisst“ die Position). Setzt außerdem das Relay-Log zurück, indem alle vorhandenen Relay-Logdateien gelöscht werden und eine neue Logdatei begonnen wird. (Ist als FLUSH SLAVE in MySQL-Versionen vor 3.23.26 bekannt.) Siehe auch Abschnitt 13.6.2, „SQL-Anweisungen für die Steuerung von Slave-Servern“.

13.6. SQL-Befehle in Bezug auf Replikation

Dieser Abschnitt beschreibt SQL-Anweisungen, die im Zusammenhang mit der Replikation von Bedeutung sind. Eine Gruppe von Anweisungen wird zur Steuerung der Master-Server verwendet, die andere zur Steuerung der Slave-Server.

13.6.1. SQL-Anweisungen für die Steuerung von Master-Servern

Die Replikation kann über die SQL-Schnittstelle gesteuert werden. Dieser Bereich beschreibt die Anweisungen zur Verwaltung der Replikationsmaster-Server. Abschnitt 13.6.2, „SQL-Anweisungen für die Steuerung von Slave-Servern“, beschreibt Anweisungen zur Verwaltung der Slave-Server.

13.6.1.1. PURGE MASTER LOGS

PURGE {MASTER | BINARY} LOGS TO 'log_name'
PURGE {MASTER | BINARY} LOGS BEFORE 'date'

Löscht alle Binärlogs, die im Logindex vor dem angegebenen Log oder Datum aufgelistet sind. Die Logs werden auch von der Liste entfernt, die in der Logindexdatei aufgezeichnet ist, d. h., das übergebene Log wird zum ersten Log auf der Liste.

Beispiel:

PURGE MASTER LOGS TO 'mysql-bin.010';
PURGE MASTER LOGS BEFORE '2003-04-02 22:46:26';

Das Argument date der Variante BEFORE kann im Format 'YYYY-MM-DD hh:mm:ss' angegeben werden. MASTER und BINARY sind Synonyme.

Diese Anweisung kann auch bei laufender Slave-Replikation sicher ausgeführt werden. Sie müssen die Replikation also nicht anhalten. Wenn ein aktiver Slave gerade eines der Logs ausliest, das Sie löschen wollen, dann hat die Anweisung keine Auswirkungen, sondern schlägt mit einem Fehler fehl. Wenn allerdings ein Slave schläft und Sie eines der Logs löschen, die dieser Slave noch lesen muss, dann wird er nach dem Erwachen nicht mehr zur Replikation in der Lage sein.

Um Logs sicher zu löschen, gehen Sie wie folgt vor:

  1. Sie setzen auf allen Slave-Servern SHOW SLAVE STATUS ab, um zu prüfen, welches Log gerade gelesen wird.

  2. Sie zeigen mit SHOW MASTER LOGS eine Liste der Logdateien auf dem Master-Server an.

  3. Ermitteln Sie das zeitlich früheste Log unter allen Slaves. Dies ist das Ziellog. Wenn alle Slaves aktuell sind, muss es das letzte Log auf der Liste sein.

  4. Erstellen Sie eine Kopie aller Logs, die Sie zu löschen beabsichtigen. (Dieser Schritt ist optional, aber stets empfehlenswert.)

  5. Löschen Sie alle Logs bis zum Ziellog (aber nicht das Ziellog selbst).

13.6.1.2. RESET MASTER

RESET MASTER

Löscht alle in der Indexdatei aufgeführten Binärlogs, leert den Binärlogindex und setzt ihn zurück und erstellt eine neue Binärlogdatei.

13.6.1.3. SET SQL_LOG_BIN

SET SQL_LOG_BIN = {0|1}

Aktiviert oder deaktiviert das binäre Loggen für die aktuelle Verbindung (SQL_LOG_BIN ist eine Sitzungsvariable), sofern der Client die Berechtigung SUPER hat. Die Anweisung wird mit einem Fehler abgewiesen, wenn der Client die Berechtigung nicht hat.

13.6.1.4. SHOW BINLOG EVENTS

SHOW BINLOG EVENTS
   [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]

Zeigt die Ereignisse im Binärlog an. Wenn Sie 'log_name' nicht angeben, wird das erste Binärlog angezeigt.

Die LIMIT-Klausel hat dieselbe Syntax wie bei der SELECT-Anweisung. Siehe auch Abschnitt 13.2.7, „SELECT.

Hinweis: Das Absetzen einer SHOW BINLOG EVENTS-Anweisung ohne LIMIT-Klausel kann einen sehr zeit- und ressourcenaufwändigen Prozess starten, weil der Server den vollständigen Inhalt des Binärlogs an den Client zurückgibt (dieses Log enthält alle datenändernden Anweisungen, die vom Server ausgeführt wurden). Als Alternative zu SHOW BINLOG EVENTS können Sie das Hilfsprogramm mysqlbinlog verwenden. Sie können damit das Binärlog in eine Textdatei speichern und später untersuchen. Siehe auch Abschnitt 8.8, „mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien“.

13.6.1.5. SHOW MASTER LOGS

SHOW MASTER LOGS
SHOW BINARY LOGS

Listet die Binärlogdateien auf dem Server auf. Diese Anweisung wird im Zuge eines Vorgangs benutzt, der in Abschnitt 13.6.1.1, „PURGE MASTER LOGS, beschrieben ist. Dort wird gezeigt, wie man ermittelt, welche Logdateien gelöscht werden können.

mysql> SHOW BINARY LOGS;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000015 |    724935 |
| binlog.000016 |    733481 |
+---------------+-----------+

SHOW BINARY LOGS ist äquivalent mit SHOW MASTER LOGS.

13.6.1.6. SHOW MASTER STATUS

SHOW MASTER STATUS

Vermittelt Statusinformationen zu den Binärlogdateien des Masters. Beispiel:

mysql > SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| mysql-bin.003 | 73       | test         | manual,mysql     |
+---------------+----------+--------------+------------------+

13.6.1.7. SHOW SLAVE HOSTS

SHOW SLAVE HOSTS

Zeigt eine Liste der Replikationsslaves an, die derzeit beim Master registriert wird. Slaves, die nicht mit der Option --report-host=slave_name gestartet wurden, werden in der Liste nicht angezeigt.

13.6.2. SQL-Anweisungen für die Steuerung von Slave-Servern

Die Replikation kann über die SQL-Schnittstelle gesteuert werden. Dieser Abschnitt beschreibt die Anweisungen zur Verwaltung der Replikationsslave-Server. Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“, beschreibt Anweisungen zur Verwaltung der Master-Server.

13.6.2.1. CHANGE MASTER TO

CHANGE MASTER TO master_def [, master_def] ...

master_def:
    MASTER_HOST = 'host_name'
  | MASTER_USER = 'user_name'
  | MASTER_PASSWORD = 'password'
  | MASTER_PORT = port_num
  | MASTER_CONNECT_RETRY = count
  | MASTER_LOG_FILE = 'master_log_name'
  | MASTER_LOG_POS = master_log_pos
  | RELAY_LOG_FILE = 'relay_log_name'
  | RELAY_LOG_POS = relay_log_pos
  | MASTER_SSL = {0|1}
  | MASTER_SSL_CA = 'ca_file_name'
  | MASTER_SSL_CAPATH = 'ca_directory_name'
  | MASTER_SSL_CERT = 'cert_file_name'
  | MASTER_SSL_KEY = 'key_file_name'
  | MASTER_SSL_CIPHER = 'cipher_list'

CHANGE MASTER TO ändert die Parameter, die der Slave-Server zur Verbindungsherstellung und Kommunikation mit dem Master-Server verwendet. Die Anweisung aktualisiert auch den Inhalt der Dateien master.info und relay-log.info.

MASTER_USER, MASTER_PASSWORD, MASTER_SSL, MASTER_SSL_CA, MASTER_SSL_CAPATH, MASTER_SSL_CERT, MASTER_SSL_KEY und MASTER_SSL_CIPHER vermitteln dem Slave Informationen dazu, wie er Verbindungen mit dem Master herstellen kann.

Die SSL-Optionen (MASTER_SSL, MASTER_SSL_CA, MASTER_SSL_CAPATH, MASTER_SSL_CERT, MASTER_SSL_KEY und MASTER_SSL_CIPHER) können auch auf Slaves geändert werden, die ohne SSL-Unterstützung kompiliert wurden. Sie werden in der Datei master.info gespeichert, aber ignoriert, bis Sie einen Server verwenden, auf dem die SSL-Unterstützung aktiviert ist.

Wenn Sie einen der Parameter nicht angeben, dann behält er in der Regel seinen alten Wert (Ausnahmen entnehmen Sie der nachfolgenden Erläuterung). Wenn sich beispielsweise das Passwort, mit dem die Verbindung zu Ihrem MySQL-Master hergestellt wird, geändert hat, müssen Sie nur die folgenden Anweisungen absetzen, um dem Slave das neue Passwort mitzuteilen:

STOP SLAVE; -- if replication was running
CHANGE MASTER TO MASTER_PASSWORD='new3cret';
START SLAVE; -- if you want to restart replication

Es ist nicht notwendig, Parameter anzugeben, die sich nicht ändern (Host, Port, Benutzer usw.).

MASTER_HOST und MASTER_PORT sind der Hostname (oder die IP-Adresse) des Master-Hosts bzw. sein TCP/IP-Port. Beachten Sie, dass, wenn MASTER_HOST gleich localhost ist, die Portnummer – wie unter MySQL bei anderen Gelegenheiten auch – unter Umständen ignoriert werden kann (dies ist etwa der Fall, wenn Unix-Socketdateien benutzt werden).

Geben Sie MASTER_HOST oder MASTER_PORT an, dann setzt der Slave voraus, dass der Master-Server sich vom vorherigen unterscheidet (und zwar auch dann, wenn Sie einen Host- oder Portwert angeben, der mit dem aktuellen Wert identisch ist). In diesem Fall werden die alten Namens- und Positionswerte der Binärlogdatei auf dem Master-Server als nun ungültig betrachtet, d. h., wenn Sie MASTER_LOG_FILE und MASTER_LOG_POS in der Anweisung nicht angeben, werden stillschweigend MASTER_LOG_FILE='' und MASTER_LOG_POS=4 angehängt.

MASTER_LOG_FILE und MASTER_LOG_POS sind die Koordinaten, bei denen der Slave-I/O-Thread mit dem Lesen vom Master beginnen soll, wenn der Thread beim nächsten Mal startet. Wenn Sie einen dieser Werte angeben, dürfen Sie RELAY_LOG_FILE oder RELAY_LOG_POS nicht angeben. Wenn weder MASTER_LOG_FILE noch MASTER_LOG_POS angegeben werden, verwendet der Slave die letzten Koordinaten des Slave-SQL-Threads, bevor CHANGE MASTER abgesetzt wurde. Hierdurch ist gewährleistet, dass es bei der Replikation auch dann nicht zu Unstetigkeiten kommt, wenn der Slave-SQL-Thread sehr spät mit dem Slave-I/O-Thread verglichen wurde – etwa dann, wenn Sie beispielsweise nur das zu verwendende Passwort ändern wollen.

CHANGE MASTER löscht alle Relay-Logdateien und beginnt eine neue Relay-Logdatei, sofern Sie nicht RELAY_LOG_FILE oder RELAY_LOG_POS angeben. In diesem Fall werden die Relay-Logs behalten, und die globale Variable relay_log_purge wird stillschweigend auf 0 gesetzt.

CHANGE MASTER ist praktisch, wenn es darum geht, einen Slave zu konfigurieren, und Sie hierfür die Momentaufnahme des Masters benötigen und Logdatei und Offset entsprechend aufgezeichnet haben. Nachdem Sie die Momentaufnahme in den Slave geladen haben, können Sie CHANGE MASTER TO MASTER_LOG_FILE='log_name_on_master', MASTER_LOG_POS=log_offset_on_master auf dem Slave ausführen.

Das folgende Beispiel ändert die Koordinaten des Masters und dessen Binärlogdatei. Dies tut man, wenn man den Slave so konfiguriert, dass er den Master repliziert:

CHANGE MASTER TO
  MASTER_HOST='master2.mycompany.com',
  MASTER_USER='replication',
  MASTER_PASSWORD='bigs3cret',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='master2-bin.001',
  MASTER_LOG_POS=4,
  MASTER_CONNECT_RETRY=10;

Das nächste Beispiel zeigt eine Operation, die weniger häufig benötigt wird. Sie wird verwendet, wenn auf dem Slave Relay-Logs vorhanden sind, die Sie aus irgendeinem Grund erneut ausführen wollen. Zu diesem Zweck muss der Master nicht erreichbar sein. Sie müssen lediglich CHANGE MASTER TO benutzen und den SQL-Thread mit START SLAVE SQL_THREAD starten:

CHANGE MASTER TO
  RELAY_LOG_FILE='slave-relay-bin.006',
  RELAY_LOG_POS=4025;

Sie können die zweite Operation sogar in einer Nicht-Replikations-Konfiguration mit einem eigenständigen Nicht-Slave-Server benutzen, um nach einem Absturz eine Wiederherstellung durchzuführen. Angenommen, Ihr Server ist abgestürzt, und Sie haben eine Sicherung wiederhergestellt. Nun wollen Sie die eigenen Binärlogs des Servers – nicht die Relay-Logs, sondern die regulären Binärlogs – namens (beispielsweise) myhost-bin.* wieder auf den Server aufspielen. Zunächst erstellen Sie ein Backup dieser Binärlogs an einer sicheren Position für den Fall, dass Sie der nachfolgenden Anleitung nicht exakt folgen und der Server deswegen die Binärlogs unbeabsichtigt löscht. Verwenden Sie SET GLOBAL relay_log_purge=0, um die Sicherheit zu erhöhen. Danach starten Sie den Server ohne die Option --log-bin. Stattdessen geben Sie die Optionen --replicate-same-server-id, --relay-log=myhost-bin (damit der Server glaubt, dass es sich bei diesen regulären Logs um Relay-Logs handelt) und --skip-slave-start an. Nach dem Serverstart setzen Sie die folgenden Anweisungen ab:

CHANGE MASTER TO
  RELAY_LOG_FILE='myhost-bin.153',
  RELAY_LOG_POS=410,
  MASTER_HOST='some_dummy_string';
START SLAVE SQL_THREAD;

Der Server liest nun seine eigenen Binärlogs und führt diese aus. Auf diese Weise erfolgt eine Wiederherstellung der Daten. Nach deren Abschluss führen Sie STOP SLAVE aus, fahren den Server herunter, löschen die Dateien master.info und relay-log.info und starten den Server mit den ursprünglichen Optionen neu.

Die Angabe der Option MASTER_HOST (auch mit einem Pseudowert) ist erforderlich, damit der Server annimmt, er sei ein Slave.

13.6.2.2. LOAD DATA FROM MASTER

LOAD DATA FROM MASTER

Diese Anweisung erstellt eine Momentaufnahme des Masters und kopiert diese auf den Slave. Sie aktualisiert die Werte von MASTER_LOG_FILE und MASTER_LOG_POS, sodass der Slave die Replikation an der korrekten Position startet. Ausschlussregeln für Tabellen und Datenbanken, die mit den Optionen --replicate-*-do-* und --replicate-*-ignore-* angegeben werden, werden beachtet. --replicate-rewrite-db wird hingegen nicht berücksichtigt, weil ein Benutzer mit dieser Option eine nichteindeutige Zuordnung wie --replicate-rewrite-db="db1->db3" oder --replicate-rewrite-db="db2->db3" vornehmen könnte, was den Slave beim Laden der Tabellen vom Master verwirren würde.

Die Verwendung dieser Anweisung hängt von den folgenden Bedingungen ab:

  • Sie funktioniert nur bei MyISAM-Tabellen. Der Versuch, eine Tabelle anderen Typs zu laden, führt zu folgendem Fehler:

    ERROR 1189 (08S01): Net error reading from master
    
  • Sie erwirkt während der Aufzeichnung der Momentaufnahme eine globale Lesesperre auf dem Master, wodurch während des Ladevorgangs Updates auf dem Master unterbunden werden.

Wenn Sie große Tabellen laden, müssen Sie die Werte von net_read_timeout und net_write_timeout unter Umständen sowohl auf dem Master- als auch auf den Slave-Servern erhöhen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

Beachten Sie, dass LOAD DATA FROM MASTER keine Tabellen aus der mysql-Datenbank kopiert. Dies erleichtert die Einrichtung verschiedener Benutzer und Berechtigungen auf dem Master und dem Slave.

Um LOAD DATA FROM MASTER verwenden zu können, benötigt das Replikationskonto, welches zur Verbindung mit dem Master-Server verwendet wird, die Berechtigungen RELOAD und SUPER auf dem Master und die Berechtigung SELECT für alle Master-Tabellen, die Sie laden wollen. Alle Master-Tabellen, für die der Benutzer die Berechtigung SELECT nicht hat, werden von LOAD DATA FROM MASTER ignoriert. Dies liegt daran, dass der Master sie vor dem Benutzer verbirgt: LOAD DATA FROM MASTER ruft SHOW DATABASES auf, um die zu ladenden Master-Datenbanken in Erfahrung zu bringen; SHOW DATABASES aber gibt nur Datenbanken zurück, für die der Benutzer Berechtigungen hat. Siehe auch Abschnitt 13.5.4.7, „SHOW DATABASES. Auf der Slave-Seite benötigt der Benutzer, der LOAD DATA FROM MASTER absetzt, Berechtigungen zum Löschen und Erstellen der Datenbanken und Tabellen, die kopiert werden.

13.6.2.3. LOAD TABLE tbl_name FROM MASTER

LOAD TABLE tbl_name FROM MASTER

Überträgt eine Kopie der Tabelle vom Master auf den Slave. Diese Anweisung wurde in erster Linie zum Debuggen von LOAD DATA FROM MASTER-Operationen implementiert. Um LOAD TABLE verwenden zu können, benötigt das Konto, welches zur Verbindung mit dem Master-Server verwendet wird, die Berechtigungen RELOAD und SUPER auf dem Master und die Berechtigung SELECT für die zu ladende Master-Tabelle. Auf der Slave-Seite benötigt der Benutzer, der LOAD TABLE FROM MASTER absetzt, Berechtigungen zum Löschen und Erstellen der Tabelle.

Die Bedingungen für LOAD DATA FROM MASTER gelten auch hier. So funktioniert LOAD TABLE FROM MASTER beispielsweise nur bei MyISAM-Tabellen. Auch die Hinweise zu Zeitüberschreitungen für LOAD DATA FROM MASTER sind anzuwenden.

13.6.2.4. MASTER_POS_WAIT()

SELECT MASTER_POS_WAIT('master_log_file', master_log_pos)

Dies ist eigentlich eine Funktion und keine Anweisung. Mit ihr kann gewährleistet werden, dass der Slave Ereignisse bis zu einer gegebenen Position im Binärlog des Masters gelesen und ausgeführt hat. Eine vollständige Beschreibung finden Sie in Abschnitt 12.10.4, „Verschiedene Funktionen“.

13.6.2.5. RESET SLAVE

RESET SLAVE

RESET SLAVE löscht auf dem Slave die Angabe zur Replikationsposition in den Binärlogs des Masters (d. h., der Slave „vergisst“ die Position). Diese Anweisung ist zur Verwendung für einen sauberen Start vorgesehen: Sie löscht die Dateien master.info und relay-log.info und alle Relay-Logs und beginnt ein neues Relay-Log.

Hinweis: Alle Relay-Logs werden gelöscht – auch dann, wenn sie nicht vollständig vom Slave-SQL-Thread ausgeführt wurden. (Dieser Umstand ist wahrscheinlich auf einem Replikationsslave gegeben, wenn Sie eine STOP SLAVE-Anweisung abgesetzt haben oder der Slave stark belastet ist.)

Verbindungsdaten, die in der Datei master.info gespeichert sind, werden direkt unter Berücksichtigung von Werten zurückgesetzt, die ggf. mit den entsprechenden Startoptionen angegeben werden. Zu diesen Daten gehören Werte wie Master-Host, Master-Port, Master-Benutzer und Master-Passwort. Wenn der Slave-SQL-Thread gerade mit der Replikation von Temporärtabellen beschäftigt war, als er angehalten wurde, und RESET SLAVE abgesetzt wird, dann werden diese replizierten Temporärtabellen auf dem Slave gelöscht.

13.6.2.6. SET GLOBAL SQL_SLAVE_SKIP_COUNTER

SET GLOBAL SQL_SLAVE_SKIP_COUNTER = N

Diese Anweisung überspringt die nächsten N Ereignisse auf dem Master. Dies ist nützlich, wenn Replikationen wiederhergestellt werden sollen, die durch eine Anweisung angehalten wurden.

Die Anweisung ist nur gültig, wenn der Slave-Thread nicht ausgeführt wird. Andernfalls erzeugt er einen Fehler.

13.6.2.7. SHOW SLAVE STATUS

SHOW SLAVE STATUS

Diese Anweisung vermittelt Statusinformationen zu wesentlichen Parametern der Slave-Threads. Wenn Sie diese Anweisung mit dem mysql-Client absetzen, können Sie \G statt des Semikolons als Abschlusszeichen für die Anweisung verwenden, um eine vertikale Ausgabe zu erhalten, die besser zu lesen ist:

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
       Slave_IO_State: Waiting for master to send event
          Master_Host: localhost
          Master_User: root
          Master_Port: 3306
        Connect_Retry: 3
      Master_Log_File: gbichot-bin.005
  Read_Master_Log_Pos: 79
       Relay_Log_File: gbichot-relay-bin.005
        Relay_Log_Pos: 548
Relay_Master_Log_File: gbichot-bin.005
     Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
      Replicate_Do_DB:
  Replicate_Ignore_DB:
           Last_Errno: 0
           Last_Error:
         Skip_Counter: 0
  Exec_Master_Log_Pos: 79
      Relay_Log_Space: 552
      Until_Condition: None
       Until_Log_File:
        Until_Log_Pos: 0
   Master_SSL_Allowed: No
   Master_SSL_CA_File:
   Master_SSL_CA_Path:
      Master_SSL_Cert:
    Master_SSL_Cipher:
       Master_SSL_Key:
Seconds_Behind_Master: 8

SHOW SLAVE STATUS gibt die folgenden Felder zurück:

  • Slave_IO_State

    Eine Kopie des State-Felds in der Ausgabe von SHOW PROCESSLIST für den Slave-I/O-Thread. Sie zeigt an, was der Thread gerade tut: Verbindungsherstellung zum Master, Warten auf vom Master kommende Ereignisse, Wiederverbindung mit dem Master usw. Mögliche Zustände sind in Abschnitt 6.4, „Replikation: Implementationsdetails“, beschrieben. Bei älteren MySQL-Versionen ist eine Überprüfung dieses Felds notwendig, denn diese erlaubten eine fortlaufende Ausführung des Threads auch für den Fall, dass eine Verbindungsherstellung mit dem Master nicht möglich war. Wird er ausgeführt, so liegt kein Problem vor; andernfalls finden Sie den Fehler im Feld Last_Error (siehe unten).

  • Master_Host

    Der aktuelle Master-Host.

  • Master_User

    Der aktuelle Benutzer, der mit dem Master verbunden ist.

  • Master_Port

    Der aktuelle Master-Port.

  • Connect_Retry

    Der aktuelle Wert der Option --master-connect-retry.

  • Master_Log_File

    Der Name der Master-Binärlogdatei, aus der der I/O-Thread derzeit liest.

  • Read_Master_Log_Pos

    Die Position, bis zu der der I/O-Thread im aktuellen Master-Binärlog gelesen hat.

  • Relay_Log_File

    Der Name der Relay-Logdatei, deren Angaben der SQL-Thread derzeit liest und ausführt.

  • Relay_Log_Pos

    Die Position, bis zu der der SQL-Thread Angaben in der aktuellen Relay-Logdatei gelesen und ausgeführt hat.

  • Relay_Master_Log_File

    Der Name der Master-Binärlogdatei, die das aktuelle Ereignis enthält, welches gerade vom SQL-Thread ausgeführt wird.

  • Slave_IO_Running

    Gibt an, ob der I/O-Thread gestartet wurde und erfolgreich eine Verbindung mit dem Master herstellen konnte. Bei älteren MySQL-Versionen (vor 4.1.14 und 5.0.12) hat Slave_IO_Running den Wert YES, wenn der I/O-Thread gestartet wurde (und zwar auch dann, wenn noch keine Verbindung zum Master hergestellt wurde).

  • Slave_SQL_Running

    Gibt an, ob der SQL-Thread gestartet wurde.

  • Replicate_Do_DB, Replicate_Ignore_DB

    Liste der Datenbanken, die ggf. mit den Optionen --replicate-do-db und --replicate-ignore-db angegeben wurden.

  • Replicate_Do_Table, Replicate_Ignore_Table, Replicate_Wild_Do_Table, Replicate_Wild_Ignore_Table

    Liste der Tabellen, die ggf. mit den Optionen --replicate-do-table, --replicate-ignore-table, --replicate-wild-do-table und --replicate-wild-ignore_table angegeben wurden.

  • Last_Errno, Last_Error

    Nummer und Meldung des Fehlers, der von der zuletzt ausgeführten Abfrage zurückgegeben wurde. Die Fehlernummer 0 und der Leer-String als Meldung haben die Bedeutung „kein Fehler“. Wenn der Wert Last_Error nicht leer ist, erscheint er auch als Meldung im Fehlerlog des Slaves. Zum Beispiel:

    Last_Errno: 1051
    Last_Error: error 'Unknown table 'z'' on query 'drop table z'
    

    Die Meldung zeigt an, dass die Tabelle z auf dem Master vorhanden war und dort gelöscht wurde, dass sie aber auf dem Slave nicht existierte, weswegen die Anweisung DROP TABLE dort fehlschlug. (Dies kann beispielsweise passieren, wenn Sie vergessen, die Tabelle beim Einrichten der Replikation auf den Slave zu kopieren.)

  • Skip_Counter

    Der zuletzt verwendete Wert von SQL_SLAVE_SKIP_COUNTER.

  • Exec_Master_Log_Pos

    Die Position des letzten vom SQL-Thread ausgeführten Ereignisses aus dem Binärlog des Masters (Relay_Master_Log_File). (Relay_Master_Log_File, Exec_Master_Log_Pos) im Binärlog des Masters entspricht (Relay_Log_File, Relay_Log_Pos) im Relay-Log.

  • Relay_Log_Space

    Die Gesamtgröße aller vorhandenen Relay-Logs.

  • Until_Condition, Until_Log_File, Until_Log_Pos

    Der in der UNTIL-Klausel der START SLAVE-Anweisung angegebene Wert.

    Until_Condition kann folgende Werte haben:

    • None, sofern keine UNTIL-Klausel angegeben wurde.

    • Master, wenn der Slave bis zu einer angegebenen Position in den Binärlogs des Masters liest.

    • Relay, wenn der Slave bis zu einer angegebenen Position in seinen Binärlogs liest.

    Until_Log_File und Until_Log_Pos geben den Namen der Logdatei und die Position an. Diese Werte definieren den Punkt, an dem die Ausführung des SQL-Threads endet.

  • Master_SSL_Allowed, Master_SSL_CA_File, Master_SSL_CA_Path, Master_SSL_Cert, Master_SSL_Cipher, Master_SSL_Key

    Diese Felder geben (sofern vorhanden) die SSL-Parameter an, die vom Slave zur Verbindung mit dem Master verwendet werden.

    Master_SSL_Allowed kann folgende Werte haben:

    • Yes, wenn eine SSL-Verbindung zum Master zulässig ist.

    • No, wenn keine SSL-Verbindung zum Master zulässig ist.

    • Ignored, wenn eine SSL-Verbindung zwar zulässig ist, aber am Slave-Server die SSL-Unterstützung nicht aktiviert ist.

    Die Werte der übrigen SSL-spezifischen Felder entsprechen den Werten der Optionen --master-ca, --master-capath, --master-cert, --master-cipher und --master-key.

  • Seconds_Behind_Master

    Dieses Feld gibt an, wie „verspätet“ der Slave ist:

    • Wenn der Slave-SQL-Thread aktiv läuft (d. h. Änderungen verarbeitet), dann gibt dieses Feld die Anzahl der Sekunden an, die seit dem Zeitstempel des Ereignisses vergangen sind, das von diesem Thread zuletzt auf dem Master ausgeführt wurde.

    • Wenn der SQL-Thread den Slave-I/O-Thread eingeholt hat und untätig auf weitere Ereignisse vom I/O-Thread wartet, ist das Feld null.

    Im Endeffekt misst das Feld also den zeitlichen Unterschied zwischen dem Slave-SQL-Thread und dem Slave-I/O-Thread.

    Ist die Netzwerkverbindung zwischen Master und Slave sehr schnell, dann liegt der Slave-I/O-Thread recht nah am Master, d. h., das Feld erlaubt eine recht genaue Schätzung des zeitlichen Verarbeitungsabstandes zwischen Slave-SQL-Thread und dem Master. Ist das Netzwerk hingegen langsam, dann ist der Wert nicht sehr aussagekräftig: Der Slave-SQL-Thread kann recht häufig zum langsam lesenden Slave-I/O-Thread aufschließen, weswegen Seconds_Behind_Master oft den Wert 0 anzeigt – und zwar auch dann, wenn der I/O-Thread im Vergleich zum Master relativ stark verspätet ist. Anders gesagt, diese Spalte ist nur bei schnellen Netzwerken aussagekräftig.

    Diese Berechnung des zeitlichen Unterschieds funktioniert, obwohl Master und Slave keine identisch laufenden Uhren haben (der Unterschied wird ermittelt, wenn der Slave-I/O-Thread startet; danach wird davon ausgegangen, dass der Abstand konstant bleibt). Seconds_Behind_Master ist NULL (d. h. „unbekannt“), wenn der Slave-SQL-Thread nicht ausgeführt wird oder wenn der Slave-I/O-Thread nicht läuft oder nicht mit dem Master verbunden ist. Schläft beispielsweise der Slave-I/O-Thread für die mit der Option --master-connect-retry angegebene Anzahl von Sekunden, bevor er eine Wiederverbindung versucht, dann wird NULL angezeigt, weil der Slave nicht wissen kann, was der Master tut, und deswegen auch nicht zuverlässig weiß, wie spät es ist.

    Dieses Feld hat eine Einschränkung: Der Zeitstempel wird bei der Replikation beibehalten, d. h., wenn ein Master M1 seinerseits ein Slave von M0 ist, dann hat jedes Ereignis im Binärlog von M1, das der Replikation eines Ereignisses aus dem Binärlog von M0 entstammt, auch den Zeitstempel dieses Ereignisses. Dies erlaubt MySQL die erfolgreiche Replikation von TIMESTAMP. Der Nachteil für Seconds_Behind_Master besteht allerdings darin, dass, wenn M1 auch direkte Updates von Clients erhält, der Wert wahllos abweicht, weil das letzte Ereignis auf M1 mal von M0 stammt, mal aber auch der letzte Zeitstempel eines direkten Updates ist.

13.6.2.8. START SLAVE

START SLAVE [thread_type [, thread_type] ... ]
START SLAVE [SQL_THREAD] UNTIL
    MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos
START SLAVE [SQL_THREAD] UNTIL
    RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos

thread_type: IO_THREAD | SQL_THREAD

START SLAVE startet beide Slave-Threads. Der I/O-Thread liest Abfragen vom Master-Server und speichert sie im Relay-Log. Der SQL-Thread liest das Relay-Log und führt die Abfragen aus. START SLAVE erfordert die Berechtigung SUPER.

Wenn START SLAVE die Slave-Threads erfolgreich startet, wird kein Fehler zurückgegeben. Allerdings kann es auch in diesem Fall vorkommen, dass die Slave-Threads starten und kurz darauf wieder beendet werden (etwa weil sie keine Verbindung zum Master herstellen oder die Binärlogs nicht lesen konnten oder aus einem anderen Grund). START SLAVE warnt Sie davor nicht. Sie müssen das Fehlerlog des Slaves auf Fehlermeldungen prüfen, die von den Slave-Threads erzeugt wurden, oder sich mit SHOW SLAVE STATUS vergewissern, dass sie einwandfrei ausgeführt werden.

Sie können die Optionen IO_THREAD oder SQL_THREAD zur Anweisung hinzufügen, wenn Sie angeben wollen, welcher der Threads gestartet werden soll.

Eine UNTIL-Klausel kann hinzugefügt werden, um anzugeben, dass der Slave starten und laufen soll, bis der SQL-Thread einen gegebenen Punkt im Master-Binärlog oder den Slave-Relay-Logs erreicht. Wenn der SQL-Thread diesen Punkt erreicht, wird er beendet. Wird die Option SQL_THREAD in der Anweisung angegeben, dann startet nur der SQL-Thread. Andernfalls werden beide Slave-Threads gestartet. Läuft der SQL-Thread bereits, dann wird die Klausel UNTIL ignoriert, und eine Warnung wird ausgegeben.

Für eine UNTIL-Klausel müssen Sie sowohl einen Logdateinamen als auch eine Position angeben. Vermischen Sie die Optionen für Master- und Relay-Logs nicht.

Eine UNTIL-Bedingung wird von einer nachfolgenden STOP SLAVE-Anweisung, einer START SLAVE-Anweisung ohne UNTIL-Klausel oder einem Serverneustart zurückgesetzt.

Die UNTIL-Klausel kann nützlich sein, um die Replikation zu debuggen oder festzulegen, dass die Replikation bis genau zu dem Punkt fortfahren soll, an dem ein Slave eine Anweisung nicht mehr replizieren soll. Wurde beispielsweise versehentlich eine DROP TABLE-Anweisung auf dem Master ausgeführt, dann können Sie den Slave mit UNTIL anweisen, das Log nur bis unmittelbar vor diesem Punkt, aber nicht mehr weiter auszuführen. Um herauszufinden, was das Ereignis ist, verwenden Sie mysqlbinlog mit den Master-Logs oder den Slave-Relay-Logs oder setzen eine SHOW BINLOG EVENTS-Anweisung ab.

Wenn Sie UNTIL verwenden, damit der Slave-Prozess die Abfragen in Abschnitten repliziert, empfehlen wir den Start des Slaves mit der Option --skip-slave-start, damit der SQL-Thread nicht ausgeführt wird, wenn der Slave-Server startet. Es ist wahrscheinlich am besten, diese Option in einer Optionsdatei statt auf der Befehlszeile zu benutzen, damit die Klausel bei einem unerwarteten Serverneustart nicht vergessen wird.

Die SHOW SLAVE STATUS-Anweisung enthält Ausgabefelder, die die aktuellen Werte der UNTIL-Bedingung anzeigen.

In älteren Versionen von MySQL (vor 4.0.5) hieß diese Anweisung SLAVE START. Ihre Verwendung in dieser Form ist zwar in MySQL 5.1 aus Kompatibilitätsgründen noch akzeptabel, aber veraltet.

13.6.2.9. STOP SLAVE

STOP SLAVE [thread_type [, thread_type] ... ]

thread_type: IO_THREAD | SQL_THREAD

Beendet die Slave-Threads. STOP SLAVE erfordert die Berechtigung SUPER.

Wie START SLAVE kann diese Anweisung mit den Optionen IO_THREAD und SQL_THREAD verwendet werden, um den oder die zu beendenden Threads anzugeben.

In älteren Versionen von MySQL (vor 4.0.5) hieß diese Anweisung SLAVE STOP. Ihre Verwendung in dieser Form ist zwar in MySQL 5.1 aus Kompatibilitätsgründen noch akzeptabel, aber veraltet.

13.7. SQL-Syntax für vorbereitete Anweisungen

MySQL 5.1 unterstützt serverseitige vorbereitete Anweisungen. Diese Unterstützung nutzt das effiziente binäre Client/Server-Protokoll, welches in MySQL 4.1 implementiert wurde. Voraussetzung hierfür ist, dass Sie eine geeignete Client-Programmierschnittstelle verwenden. Geeignete Schnittstellen sind die C-API-Clientbibliothek von MySQL (für C-Programme), MySQL Connector/J (für Java-Programme) und MySQL Connector/NET. So bietet etwa die C-API eine Anzahl von Funktionsaufrufen, die eine API für vorbereitete Anweisungen darstellen. Siehe auch Abschnitt 24.2.4, „C-API: Prepared Statements“. Andere Sprachschnittstellen bieten Unterstützung für vorbereitete Anweisungen, die das binäre Protokoll verwenden, indem Sie eine Verbindung in die C-Clientbibliothek herstellen (z. B. die mysqli-Erweiterung in PHP 5.0).

Es gibt auch eine alternative SQL-Schnittstelle für vorbereitete Anweisungen. Diese ist zwar nicht so effizient wie die Verwendung eines binären Protokolls über eine API für vorbereitete Anweisungen, sie erfordert aber auch keine Programmierung, weil sie direkt auf SQL-Ebene verfügbar ist:

  • Sie können sie verwenden, wenn Ihnen keine Programmierschnittstelle zur Verfügung steht.

  • Sie können sie aus jedem Programm heraus verwenden, das Ihnen die Übermittlung von SQL-Anweisungen an den Server zur dortigen Ausführung gestattet (dies gilt beispielsweise für das mysql-Clientprogramm).

  • Sie können es auch dann verwenden, wenn der Client eine alte Version der Clientbibliothek einsetzt. Die einzige Voraussetzung besteht darin, dass Sie eine Verbindung mit einem Server herstellen können müssen, der aktuell genug ist, um die SQL-Syntax für vorbereitete Anweisungen zu unterstützen.

Die SQL-Syntax für vorbereitete Anweisungen ist zur Verwendung in Fällen wie den folgenden vorgesehen:

  • Sie wollen die Funktion vorbereiteter Anweisungen in Ihrer Anwendung testen, bevor Sie sie einkodieren.

  • Eine Anwendung hat Probleme mit der Ausführung vorbereiteter Anweisungen, und Sie wollen dem Problem interaktiv auf den Grund gehen.

  • Sie wollen einen Testfall erstellen, der ein Problem im Zusammenhang mit vorbereiteten Anweisungen beschreibt. Dieser soll als Grundlage eines Fehlerberichts dienen.

  • Sie müssen vorbereitete Anweisungen verwenden, haben aber keinen Zugang zu einer Programmierschnittstelle, die diese unterstützt.

Die SQL-Syntax für vorbereitete Anweisungen basiert auf drei SQL-Anweisungen:

  • PREPARE stmt_name FROM preparable_stmt

    Die Anweisung PREPARE bereitet eine Anweisung vor und weist ihr den Namen stmt_name zu, unter dem sie später referenziert werden kann. Die Groß-/Kleinschreibung wird bei Anweisungsnamen nicht unterschieden. preparable_stmt ist entweder ein String-Literal oder eine Benutzervariable, die den Text der Anweisung enthält. Der Text muss eine einzelne SQL-Anweisung (nicht mehrere Anweisungen) darstellen. In dieser Anweisung können Fragezeichen (‘?’) als Parameterkennzeichen verwendet werden: Sie geben an, wo bei der späteren Ausführung der Anweisung Datenwerte eingebunden werden. Fragezeichen sollten auch dann nicht in Anführungszeichen gesetzt werden, wenn Sie beabsichtigen, sie an String-Werte anzubinden. Parameterkennzeichen dürfen nur an Stellen verwendet werden, an denen Datenwerte eingefügt werden sollen, nicht jedoch für SQL-Schlüsselwörter, Bezeichner usw.

    Wenn eine vorbereitete Anweisung des angegebenen Namens bereits vorhanden ist, wird diese Namenszuweisung implizit aufgehoben, bevor die neue Anweisung vorbereitet wird. Das bedeutet, dass, wenn die neue Anweisung einen Fehler enthält und nicht vorbereitet werden kann, ein Fehler zurückgegeben wird; in diesem Fall gibt es keine Anweisung des betreffenden Namens mehr.

    Der Gültigkeitsbereich einer vorbereiteten Anweisung ist die Clientsitzung, innerhalb derer sie erstellt wird. Andere Clients sehen sie nicht.

  • EXECUTE stmt_name [USING @var_name [, @var_name] ...]

    Nach der Vorbereitung einer Anweisung können Sie sie mit einer EXECUTE-Anweisung ausführen, die den Namen der vorbereiteten Anweisung referenziert. Wenn die vorbereitete Anweisung Parameterkennzeichen enthält, müssen Sie eine USING-Klausel angeben, die die Benutzervariablen mit den Werten auflistet, welche für die Parameter eingesetzt werden sollen. Parameterwerte können nur über Benutzervariablen übergeben werden. Die USING-Klausel muss so viele Variablen übergeben, wie Parameterkennzeichen in der Anweisung vorhanden sind, und alle Variablennamen müssen korrekt sein.

    Sie können eine vorbereitete Anweisung mehrfach ausführen und dabei unterschiedliche Variablen übergeben oder die Variablen vor jeder Ausführung auf andere Werte setzen.

  • {DEALLOCATE | DROP} PREPARE stmt_name

    Um eine vorbereitete Anweisung aufzuheben, verwenden Sie die Anweisung DEALLOCATE PREPARE. Wenn Sie eine vorbereitete Anweisung auszuführen versuchen, nachdem Sie sie aufgehoben haben, wird ein Fehler erzeugt.

    Wenn Sie eine Clientsitzung beenden, ohne eine zuvor vorbereitete Anweisung aufzuheben, dann hebt der Server sie automatisch auf.

In vorbereiteten Anweisungen können die folgenden SQL-Anweisungen verwendet werden: CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE und die meisten SHOW-Anweisungen. Andere Anweisungen werden noch nicht unterstützt.

Die folgenden Beispiele zeigen zwei gleichwertige Arten der Vorbereitung einer Anweisung, die die Hypotenuse eines Dreiecks berechnet, bei dem zwei Seitenlängen gegeben sind.

Das erste Beispiel zeigt, wie man eine vorbereitete Anweisung unter Verwendung eines String-Literals erstellt, um den Text der Anweisung zu übergeben:

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|          5 |
+------------+
mysql> DEALLOCATE PREPARE stmt1;

Das zweite Beispiel ist ähnlich, übergibt den Text der Anweisung aber als Benutzervariable:

mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|         10 |
+------------+
mysql> DEALLOCATE PREPARE stmt2;

Die SQL-Syntax für vorbereitete Anweisungen erlaubt keine Verschachtelungen: Eine an PREPARE übergebene Anweisung darf selbst keine PREPARE-, EXECUTE- oder DEALLOCATE PREPARE-Anweisung sein.

Die SQL-Syntax für vorbereitete Anweisungen unterscheidet sich von der Verwendung von API-Aufrufen für vorbereitete Anweisungen. So können Sie beispielsweise mit der C-API-Funktion mysql_stmt_prepare() keine PREPARE-, EXECUTE- oder DEALLOCATE PREPARE-Anweisung vorbereiten.

Die SQL-Syntax für vorbereitete Anweisungen kann in gespeicherten Prozeduren, nicht aber in gespeicherten Funktionen oder Triggern verwendet werden.

Bei der Verwendung vorbereiteter Anweisungen können für die Argumente der LIMIT-Klausel Platzhalter eingesetzt werden. Siehe auch Abschnitt 13.2.7, „SELECT.

Kapitel 14. Speicher-Engines und Tabellentypen

Inhaltsverzeichnis

14.1. Die MyISAM-Speicher-Engine
14.1.1. MyISAM-Startoptionen
14.1.2. Für Indizes benötigter Speicherplatz
14.1.3. MyISAM-Tabellenformate
14.1.4. MyISAM-Tabellenprobleme
14.2. InnoDB-Tabellen
14.2.1. Überblick über InnoDB-Tabellen
14.2.2. Kontaktinformationen
14.2.3. Konfiguration
14.2.4. InnoDB: Startoptionen und Systemvariablen
14.2.5. InnoDB-Tablespace erzeugen
14.2.6. InnoDB-Tabellen erzeugen
14.2.7. Hinzufügen und Entfernen von InnoDB-Daten- und -Logdateien
14.2.8. Sichern und Wiederherstellen einer InnoDB-Datenbank
14.2.9. Eine InnoDB-Datenbank auf eine andere Maschine verschieben
14.2.10. InnoDB-Transaktionsmodell
14.2.11. Tipps zur Leistungssteigerung
14.2.12. Implementierung der Multiversionierung
14.2.13. Tabellen- und Indexstrukturen
14.2.14. Verwaltung von Speicherplatz für Dateien und von Festplattenein- und -ausgaben
14.2.15. InnoDB-Fehlerbehandlung
14.2.16. Beschränkungen von InnoDB-Tabellen
14.2.17. InnoDB-Troubleshooting
14.3. Die MERGE-Speicher-Engine
14.3.1. MERGE-Tabellenprobleme
14.4. Die MEMORY-Speicher-Engine
14.5. Die BDB-Speicher-Engine
14.5.1. Betriebssysteme, die von BDB unterstützt werden
14.5.2. BDB installieren
14.5.3. BDB-Startoptionen
14.5.4. Kennzeichen von BDB-Tabellen
14.5.5. Einschränkungen bei Verwendung von BDB-Tabellen
14.5.6. Fehler, die bei der Benutzung von BDB-Tabellen auftreten können
14.6. Die EXAMPLE-Speicher-Engine
14.7. Die FEDERATED-Speicher-Engine
14.7.1. Beschreibung der FEDERATED-Speicher-Engine
14.7.2. Benutzung von FEDERATED-Tabellen
14.7.3. Beschränkungen der FEDERATED-Speicher-Engine
14.8. Die ARCHIVE-Speicher-Engine
14.9. Die CSV-Speicher-Engine
14.10. Die BLACKHOLE-Speicher-Engine

MySQL unterstützt mehrere Speicher-Engines für die Arbeit mit unterschiedlichen Tabellentypen. MySQL kennt Speicher-Engines sowohl für transaktionssichere als auch für nicht-transaktionssichere Tabellen:

  • Mit MyISAM werden nicht-transaktionssichere Tabellen verwaltet. Dieser Tabellentyp kann Daten sehr schnell speichern und abrufen und bietet Volltext-Suchfähigkeiten. MyISAM wird in allen MySQL-Konfigurationen unterstützt und ist als Standard-Tabellentyp voreingestellt, sofern Sie in MySQL keinen anderen Default konfiguriert haben.

  • Die Speicher-Engine MEMORY stellt Tabellen im Arbeitsspeicher zur Verfügung. Mit der Speicher-Egnine MERGE lassen sich mehrere identische MyISAM-Tabellen wie eine einzige behandeln. WieMyISAM verwalten auch die Speicher-Engines MEMORY und MERGE nicht-transaktionssichere Tabellen. Beide sind ebenfalls standardmäßig in MySQL enthalten.

    Note: Die Speicher-Engine MEMORY hieß früher HEAP.

  • Die Speicher-Engines InnoDB und BDB stellen transaktionssichere Tabellen zur Verfügung. BDB ist in den Binärdistributionen von MySQL-Max für Betriebssysteme, die dieses unterstützen, enthalten. Außerdem ist InnoDB Standardbestandteil aller MySQL 5.1-Binärdistributionen. In Quelldistributionen können Sie diese Engines aktivieren oder deaktivieren, indem Sie MySQL nach Ihren Wünschen konfigurieren.

  • Die Speicher-Engine EXAMPLE ist ein „Sockel“-Modul, das eigentlich gar nichts tut. Sie können mit ihr zwar Tabellen anlegen, aber keine Daten speichern oder abrufen. Sie soll lediglich im MySQL-Quellcode als Beispiel zu dienen, um zu zeigen, wie man neue Speicher-Engines schreibt. Daher ist sie vor allem für Entwickler von Interesse.

  • NDB Cluster wird von MySQL Cluster als Speicher-Engine zur Implementierung von Tabellen genutzt, die über viele Computer partitioniert sind. Sie steht in den MySQL-Max 5.1- Binärdistributionen zur Verfügung. Dieses Speicher-Engine wird zurzeit nur von Linux, Solaris und Mac OS X unterstützt. In zukünftigen MySQL-Releases soll sie auch auf anderen Plattformen, wie etwa Windows, unterstützt werden.

  • Die Speicher-Engine ARCHIVE dient der Speicherung großer Datenmengen ohne Indizes mit einem sehr kleinen Speicherverbrauch.

  • Die Speicher-Engine CSV speichert Daten in Textdateien in Form von kommagetrennten Werten.

  • Die Speicher-Engine BLACKHOLE nimmt Daten entgegen, speichert sie jedoch nicht. Abfragen liefern immer eine leere Menge zurück.

  • Die Speicher-Engine FEDERATED speichert Daten in einer Remote-Datenbank. Gegenwärtig funktioniert sie nur mit MySQL unter Verwendung der MySQL-C-Client-API. In zukünftigen Releases soll sie auch mit anderen Datenquellen mit anderen Treibern oder Client-Verbindungsmethoden funktionieren.

In diesem Kapitel werden die Speicher-Engines von MySQL beschrieben. Eine Ausnahme bildet die Engine NDB Cluster, die in Kapitel 16, MySQL Cluster behandelt wird.

Wenn Sie eine neue Tabelle anlegen, können Sie die zu verwendende Speicher-Engine angeben, indem Sie der CREATE TABLE-Anweisung die Tabellenoption ENGINE oder TYPE hinzufügen:

CREATE TABLE t (i INT) ENGINE = INNODB;
CREATE TABLE t (i INT) TYPE = MEMORY;

Der ältere Begriff TYPE wird aus Gründen der Abwärtskompatibilität noch als Synonym für ENGINE akzeptiert, doch ENGINE ist der aktuelle Begriff, während TYPE mittlerweile veraltet ist.

Wenn Sie die Option ENGINE oder TYPE weglassen, wird die Standard-Speicher-Engine verwendet. Normalerweise ist dies MyISAM, doch mit der Server-Startoption --default-storage-engine oder --default-table-type oder der Systemvariablen storage_engine oder table_type können Sie auch etwas anderes einstellen.

Wird MySQL unter Windows mit dem MySQL Configuration Wizard installiert, kann die Speicher-Engine InnoDB anstelle der standardmäßigen MyISAM-Engine gewählt werden. Siehe Abschnitt 2.3.5.6, „Der Dialog zur Datenbankverwendung“.

Um eine Typkonvertierung von Tabellen vorzunehmen, geben Sie in einer ALTER TABLE-Anweisung den neuen Typ an:

ALTER TABLE t ENGINE = MYISAM;
ALTER TABLE t TYPE = BDB;

Siehe Abschnitt 13.1.5, „CREATE TABLE und Abschnitt 13.1.2, „ALTER TABLE.

Wenn Sie eine Speicher-Engine zu verwenden versuchen, die entweder gar nicht kompiliert oder zwar kompiliert, aber deaktiviert ist, legt MySQL stattdessen mit der Standard-Speicher-Engine eine Tabelle an, also normalerweise mit MyISAM. Dieses Verhalten ist praktisch, wenn Tabellen zwischen MySQL-Servern hin- und herkopiert werden, die verschiedene Speicher-Engines unterstützen. (So könnte beispielsweise in einer Replikation Ihr Masterserver aus Sicherheitsgründen transaktionssichere Speicher-Engines verwenden, während die Slaveserver aus Gründen der Schnelligkeit nur nicht-transaktionssichere einsetzen.)

Dass MySQL für Speicher-Engines, die nicht zur Verfügung stehen, automatisch die Standard-Speicher-Engine einsetzt, kann für Neulinge verwirrend sein. Es wird jedoch in einem solchen Fall immer eine Warnung ausgegeben.

Für neue Tabellen legt MySQL immer eine .frm-Datei zur Speicherung der Tabellen- und Spaltendefinitionen an. Der Index und die Daten der Tabelle können je nach Speicher-Engine in einer oder mehreren Dateien gespeichert sein. Der Server erstellt die .frm-Datei über der Ebene der Speicher-Engine. Einzelne Speicher-Engines legen zusätzliche Dateien an, die für die von ihnen verwalteten Tabellen erforderlich sind.

Eine Datenbank kann unterschiedliche Tabellentypen enthalten; die Tabellen müssen also nicht alle mit derselben Speicher-Engine angelegt werden.

Transaktionssichere Tabellen (TSTs) haben gegenüber den nicht-transaktionssicheren (NTSTs) mehrere Vorteile:

  • Sie sind sicherer. Selbst wenn MySQL abstürzt oder Hardware-Probleme auftreten, bekommen Sie Ihre Daten auf jeden Fall zurück, sei es durch die automatische Wiederherstellung, sei es aus einer Sicherungskopie plus dem Transaktionslog.

  • Sie können viele Anweisungen miteinander kombinieren und mit der COMMIT-Anweisung später alle gleichzeitig festschreiben (wenn Autocommit deaktiviert wurde).

  • Sie können Ihre Änderungen mit einem ROLLBACK verwerfen (wenn Autocommit deaktiviert wurde).

  • Schlägt ein Update fehl, werden alle Ihre Änderungen rückgängig gemacht. (Bei nicht-transaktionssicheren Tabellen sind alle einmal stattgefundenen Änderungen von Dauer.)

  • Transaktionssichere Speicher-Engines bieten bessere Nebenläufigkeit für Tabellen, in denen gleichzeitig mit Lese-Operationen viele Änderungen stattfinden.

Sie können transaktionssichere und nicht-transaktionssichere Tabellen in derselben Anweisung verwenden, um aus beiden das Beste herauszuholen. Allerdings sollten Sie nicht bei ausgeschaltetem Autocommit verschiedene Speicher-Engines durcheinanderwürfeln, auch wenn MySQL mehrere transaktionssichere Engines unterstützt, um die bestmöglichen Ergebnisse zu erzielen. Denn wenn Sie die Engines vermischen, werden Änderungen an nicht-transaktionssicheren Tabellen weiterhin festgeschrieben und können nicht mehr zurückgerollt werden. Informationen zu diesem und anderen Problemen, die in Transaktionen mit einem Mix von Speicher-Engines auftreten können, finden Sie unter Abschnitt 13.4.1, „BEGIN/COMMIT/ROLLBACK.

Nicht-transaktionssichere Tabellen haben mehrere Vorteile, die alle damit zusammenhängen, dass der Aufwand von Transaktionen entfällt:

  • Viel schneller

  • Weniger Speicherbedarf auf der Festplatte

  • Weniger Arbeitsspeicherbedarf für Updates

14.1. Die MyISAM-Speicher-Engine

MyISAM ist die Standard-Speicher-Engine. Sie baut auf dem älteren ISAM-Code auf, hat aber viele praktische Erweiterungen. (Beachten Sie, dass MySQL 5.1 ISAMnicht mehr unterstützt.)

Jede MyISAM-Tabelle wird in drei Dateien auf der Festplatte gespeichert. Die Namen der Dateien beginnen mit dem Tabellennamen und haben eine Erweiterung, die den Dateityp angibt. Eine .frm-Datei speichert das Tabellenformat. Die Datendatei besitzt die Erweiterung .MYD (MYData). Die Indexdatei hat die Erweiterung .MYI (MYIndex).

Um ausdrücklich zu sagen, dass Sie eine MyISAM-Tabelle möchten, verwenden Sie die Tabellenoption ENGINE:

CREATE TABLE t (i INT) ENGINE = MYISAM;

Der ältere Begriff TYPE wird aus Gründen der Abwärtskompatibilität noch als Synonym für ENGINE akzeptiert, doch ENGINE ist der aktuelle Begriff, während TYPE mittlerweile veraltet ist.

Normalerweise ist eine ENGINE-Angabe für die MyISAM-Speicher-Engine unnötig. MyISAM ist ohnehin die Standard-Engine, es sei denn, die Standardeinstellung wurden geändert. Um in solchen Situationen ganz sicherzugehen, dass MyISAM verwendet wird, sollten Sie explizit die Option ENGINE verwenden.

Zur Prüfung oder Reparatur von MyISAM-Tabellen setzen Sie den mysqlcheck-Client oder das Hilfsprogramm myisamchk ein. Überdies können Sie MyISAM-Tabellen mit myisampack komprimieren, dann belegen sie viel weniger Speicherplatz. Siehe auch Abschnitt 8.9, „mysqlcheck — Hilfsprogramm für die Wartung und Reparatur von Tabellen“, Abschnitt 5.10.4.1, „Benutzung von myisamchk für die Fehlerbeseitigung nach Abstürzen“, und Abschnitt 8.4, „myisampack — Erzeugung komprimierter, schreibgeschützter MyISAM Tabellen“.

Kennzeichen von MyISAM-Tabellen:

  • Alle Daten werden mit dem niederwertigen Byte zuerst gespeichert. Dadurch werden die Daten maschinen- und betriebssystemunabhängig. Die einzigen Voraussetzungen für die binäre Portierbarkeit der Daten sind, dass der Computer vorzeichenbehaftete Integers (Zweierkomplement) und das IEEE-Fließkommaformat verwendet. Diese Voraussetzungen werden von den üblichen Computern meist erfüllt. Nur bei Embedded-Systemen mit ihren manchmal seltsamen Prozessoren ist die Binärkompatibilität nicht immer gegeben.

    Die Verarbeitungsgeschwindigkeit leidet nicht sonderlich, wenn das niederwertige Byte zuerst gespeichert wird. Die Bytes in einer Tabellenzeile werden normalerweise nicht ausgerichtet und es macht zeitmäßig kaum einen Unterschied, ob ein unausgerichtetes Byte in der Reihenfolge oder gegen die Reihenfolge gelesen wird. Darüber hinaus ist der Server-Code, der die Spaltenwerte abruft, im Vergleich zu anderem Code nicht zeitkritisch.

  • Alle numerischen Schlüsselwerte werden mit dem höchstwertigen Byte zuerst gespeichert, um eine bessere Indexkompression zu ermöglichen.

  • Große Dateien (bis zu 63 Bit Dateilänge) werden für Datei- und Betriebssysteme, auf denen große Dateien möglich sind, unterstützt.

  • Eine MyISAM-Tabelle kann maximal 64 Indizes haben. Dies lässt sich jedoch durch Rekompilieren ändern: Ab der Version MySQL 5.1.4 können Sie den Build konfigurieren, indem Sie configure mit der Option --with-max-indexes=N aufrufen, wobei N die Höchstzahl der pro MyISAM-Tabelle zulässigen Indizes ist. N muss kleiner oder gleich 128 sein. In älteren Versionen als MySQL 5.1.4 müssen Sie die Quelle wechseln.

    Ein Index darf maximal 16 Spalten haben.

  • Die Höchstlänge für Schlüssel beträgt 1000 Bytes. Auch dies lässt sich durch Wechseln der Quelle und Rekompilieren ändern. Ist ein Schlüssel länger als 250 Bytes wird ein größerer als der standardmäßig 1024 Bytes große Schlüsselblock verwendet.

  • Werden Zeilen sortiert eingefügt (wie zum Beispiel mit einer AUTO_INCREMENT-Spalte), wird der Indexbaum aufgespalten, so dass der höchste Knoten nur einen Schlüssel enthält. So wird der Platz im Indexbaum besser ausgenutzt.

  • Intern wird eine AUTO_INCREMENT-Spalte pro Tabelle unterstützt. MyISAM aktualisiert diese Spalte bei INSERT- und UPDATE-Operationen automatisch. Das macht AUTO_INCREMENT-Spalten schneller (um mindestens 10%). Werte am Anfang der Folge werden nach ihrer Löschung nicht wiederverwendet. (Wenn eine AUTO_INCREMENT-Spalte als die letzte Spalte eines Mehrspalten-Indizes definiert ist, werden gelöschte Werte vom Anfang einer Folge doch wiederverwendet.) Der AUTO_INCREMENT-Wert kann mit ALTER TABLE oder myisamchk zurückgesetzt werden.

  • Zeilen mit dynamischer Größenanpassung werden bei einer Mischung von Lösch-, Änderungs- und Einfügeoperationen viel weniger stark fragmentiert, da aneinander grenzende gelöschte Blöcke automatisch zusammengefasst und Blöcke, deren Nachbarblock gelöscht werden, automatisch erweitert werden.

  • Hat eine Tabelle in der Mitte der Datendatei keine freien Blöcke, können Sie neue Zeilen mit INSERT einfügen, während gleichzeitig andere Threads die Tabelle lesen. (Man nennt dies "nebenläufige Einfügeoperationen".) Wird eine Zeile gelöscht oder werden in eine Zeile dynamischer Länge mehr Daten geschrieben, als sie zuvor enthalten hatte, kann ein freier Block entstehen. Wenn alle freien Blöcke aufgebraucht (ausgefüllt) wurden, werden zukünftige Einfügeoperationen wieder nebenläufig. Siehe Abschnitt 7.3.3, „Gleichzeitige Einfügevorgänge“.

  • Mit den Tabellenoptionen DATA DIRECTORY und INDEX DIRECTORY von CREATE TABLE können Sie die Daten- und die Indexdatei in unterschiedliche Verzeichnisse legen, um mehr Geschwindigkeit zu erzielen. Siehe Abschnitt 13.1.5, „CREATE TABLE.

  • BLOB- und TEXT-Spalten können indiziert werden.

  • NULL-Werte sind in indizierten Spalten zulässig. Hierfür werden 0 bis 1 Byte pro Schlüssel gebraucht.

  • Jede Zeichenspalte kann einen anderen Zeichensatz haben. Siehe Kapitel 10, Zeichensatz-Unterstützung.

  • In der MyISAM-Indexdatei gibt es ein Flag, das anzeigt, ob die Tabelle ordentlich geschlossen wurde. Wenn mysqld mit der Option --myisam-recover gestartet wird, werden MyISAM-Tabellen beim Öffnen automatisch überprüft und repariert, wenn sie nicht richtig geschlossen wurden.

  • myisamchk markiert Tabellen als geprüft, wenn Sie es mit der Option --update-state ausführen. myisamchk --fast prüft nur diejenigen Tabellen, die diese Markierung nicht tragen.

  • myisamchk --analyze speichert Statistikdaten sowohl für Teilschlüssel als auch für vollständige Schlüssel.

  • myisampack kann BLOB- und VARCHAR-Spalten packen.

MyISAM unterstützt auch folgende Funktionen:

  • Unterstützung für einen echten VARCHAR-Typ; eine VARCHAR-Spalte beginnt mit einer Längenangabe, die in einem oder zwei Byte(s) gespeichert ist.

  • Tabellen mit VARCHAR-Spalten können Zeilen mit fester oder dynamischer Länge haben.

  • Die Summe der Längen der VARCHAR-und CHAR-Spalten in einer Tabelle kann bis zu 64KB betragen.

  • Für UNIQUE kann ein berechneter Hash-Index verwendet werden. So ist UNIQUE für jede beliebige Spaltenkombination in einer Tabelle zulässig. (Allerdings können auf einem berechneten UNIQUE-Index keine Suchoperationen durchgeführt werden.)

Mehr zum Thema

14.1.1. MyISAM-Startoptionen

Die folgenden Optionen von mysqld können verwendet werden, um das Verhalten von MyISAM-Tabellen zu ändern. Weitere Informationen finden Sie unter Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

  • --myisam-recover=mode

    Stellt den Modus für die automatische Wiederherstellung von abgestürzten MyISAM-Tabellen ein.

  • --delay-key-write=ALL

    Zwischen den Schreibvorgängen werden die Schlüsselpuffer (Key-Buffer) für MyISAM-Tabellen nicht auf die Festplatte zurückgeschrieben.

    Note: Wenn Sie dies tun, sollten Sie auf MyISAM-Tabellen nicht von einem anderen Programm aus zugreifen (zum Beispiel von einem anderen MySQL-Server oder mit myisamchk), so lange die Tabellen in Gebrauch sind. Sonst riskieren Sie, dass der Index beschädigt wird. Diese Gefahr wird durch --external-locking nicht gebannt.

Die folgenden Systemvariablen beeinflussen das Verhalten von MyISAM-Tabellen. Weitere Informationen finden Sie unter Abschnitt 5.2.2, „Server-Systemvariablen“.

  • bulk_insert_buffer_size

    Die Größe des bei der Optimierung von Massen-Einfügeoperationen verwendeten Tree-Caches. Hinweis: Dieser Wert gilt pro Thread!

  • myisam_max_sort_file_size

    Zur Indexerstellung nicht die schnelle Index-Sortiermethode verwenden, wenn die temporäre Datei dadurch größer als dieser Wert würde. Hinweis: Dieser Parameter wird in Bytes angegeben.

  • myisam_sort_buffer_size

    Stellt die Puffergröße für die Wiederherstellung von Tabellen ein.

Wenn Sie mysqld mit der Option --myisam-recover starten, wird die automatische Wiederherstellung aktiviert. Wenn der Server eine MyISAM-Tabelle öffnet, prüft er, ob sie als abgestürzt gekennzeichnet ist oder die Zählervariable für Öffnungen von 0 verschieden ist und Sie den Server ohne externe Sperren betreiben. Trifft eine dieser Bedingungen zu, so geschieht folgendes:

  • Der Server überprüft die Tabelle auf Fehler.

  • Wenn der Server einen Fehler findet, versucht er eine schnelle Tabellenreparatur (mit Sortierung, aber ohne Neuerzeugung der Datendatei).

  • Scheitert die Reparatur wegen eines Fehlers in der Datendatei (zum Beispiel eines doppelten Schlüssels), versucht der Server erneut eine Reparatur, aber dieses Mal mit Neuerzeugung der Datendatei.

  • Scheitert auch diese Reparatur, versucht es der Server noch einmal mit der alten Reparaturmethode (zeilenweises Schreiben der Daten ohne Sortierung). Dieses Verfahren müsste in der Lage sein, jeden Fehler zu beheben und braucht nur wenig Festplattenspeicher.

Wenn die Wiederherstellung nicht alle Zeilen aus den zuvor abgeschlossenen Anweisungen wiederherstellen kann und Sie im Wert der Option --myisam-recover nicht FORCE angegeben haben, bricht die automatische Reparatur ab und schreibt folgende Fehlermeldung in das Fehler-Log:

Error: Couldn't repair table: test.g00pages

Wenn Sie FORCE angeben, wird stattdessen folgende Warnung in das Log geschrieben:

Warning: Found 344 of 354 rows when repairing ./test/g00pages

Beachten Sie: Wenn die automatische Wiederherstellung den Wert BACKUP enthält, legt der Wiederherstellungsprozess Dateien an, deren Namen die Form tbl_name-datetime.BAK haben. Sie benötigen ein cron-Skript, das diese Dateien automatisch von den Datenbankverzeichnissen auf die Sicherungsmedien verschiebt.

14.1.2. Für Indizes benötigter Speicherplatz

MyISAM-Tabellen verwenden B-Baum-Indizes. Die Größe der Indexdatei, summiert über alle Schlüssel, lässt sich mit der Formel (key_length+4)/0.67 ungefähr berechnen. Das gilt für den ungünstigsten Fall, dass alle Schlüssel in sortierter Reihenfolge eingefügt wurden und die Tabelle keine komprimierten Schlüssel besitzt.

String-Indizes werden Leerzeichen-komprimiert. Ist der erste Teil des Index ein String, so wird dieser zusätzlich präfixkomprimiert. Durch Leerzeichen-Kompression wird die Indexdatei kleiner als in den obigen Zahlen für den ungünstigsten Fall dargestellt, wenn eine Stringspalte viele Leerzeichen am Ende hat oder eine VARCHAR-Spalte ist, die nicht immer in voller Länge ausgenutzt wird. Eine Präfix-Kompression wird für Schlüssel eingesetzt, die mit einem String anfangen. Die Präfix-Kompression ist hilfreich, wenn mehrere Strings mit identischem Präfix vorhanden sind.

In MyISAM-Tabellen können Sie auch Zahlen präfixkomprimieren. Hierzu geben Sie beim Anlegen der Tabelle die Tabellenoption PACK_KEYS=1 an. Das hilft, wenn Sie viele Integer-Schlüssel mit identischem Präfix haben, wenn die Zahlen mit dem höchstwertigen Byte zuerst gespeichert werden.

14.1.3. MyISAM-Tabellenformate

MyISAM unterstützt drei verschiedene Speicherformate. Zwei davon, das feste und das dynamische Format, werden automatisch anhand des verwendeten Spaltentyps gewählt. Das dritte, komprimierte Format kann nur mit der Utility myisampack angelegt werden.

Wenn Sie CREATE TABLE oder ALTER TABLE für eine Tabelle verwenden, die keine BLOB- oder TEXT-Spalten besitzt, können Sie mit der Tabellenoption ROW_FORMAT ein FIXED- oder DYNAMIC-Format erzwingen.

Um Tabellen zu dekomprimieren, geben Sie ROW_FORMAT=DEFAULT mit ALTER TABLE zusammen an.

Unter Abschnitt 13.1.5, „CREATE TABLE finden Sie Informationen über ROW_FORMAT.

14.1.3.1. Kennzeichen statischer Tabellen (Tabellen fester Zeilenlänge)

Das statische (Festlängen-) Format ist für MyISAM-Tabellen voreingestellt. Es wird verwendet, wenn die Tabelle keine Spalten mit variabler Länge (VARCHAR-, VARBINARY-, BLOB- oder TEXT-Spalten) enthält. Jede Zeile wird dann mit einer festgelegten Anzahl von Bytes gespeichert.

Von den drei Speicherformaten, die MyISAM unterstützt, ist das statische Format das einfachste und sicherste (für Schäden am wenigsten anfällige). Außerdem bietet es wegen der Leichtigkeit, mit der die Zeilen der Datendatei auf der Festplatte gefunden werden, auch den schnellsten Festplattenzugriff. Um eine Zeile nach der Index-Zeilennummer nachzuschlagen, multiplizieren Sie die Nummer der Zeile mit ihrer Länge, um ihre Position zu ermitteln. Darüber hinaus ist es beim Durchsuchen einer Tabelle sehr einfach, mit jedem Festplattenzugriff eine konstante Anzahl Zeilen zu lesen.

Die Sicherheit erweist sich, wenn Ihr Computer abstürzt, während der MySQL-Server eine MyISAM-Datei mit festgelegtem Format schreibt. In einem solchen Fall kann myisamchk ganz leicht feststellen, wo die Zeilen beginnen und enden. Normalerweise ist es dadurch in der Lage, alle Zeilen außer der einen, die nur teilweise geschrieben wurde, zurückzugewinnen. Beachten Sie, dass MyISAM-Tabellenindizes immer anhand der Datenzeilen rekonstruiert werden können.

Kennzeichen von statischen Tabellen:

  • CHAR-Spalten werden mit Leerzeichen bis zur Spaltenbreite aufgefüllt. BINARY-Spalten werden mit 0x00-Bytes bis zur Spaltenbreite aufgefüllt.

  • Sie sind sehr schnell.

  • Sie lassen sich leicht zwischenspeichern.

  • Sie sind nach einem Absturz einfach zu rekonstruieren, da sich die Datensätze an festen Positionen befinden.

  • Eine Reorganisation der Tabellen ist nicht erforderlich, es sei denn, Sie löschen sehr viele Zeilen und möchten dem Betriebssystem den frei gewordenen Speicherplatz zurückgeben. Hierzu verwenden Sie OPTIMIZE TABLE oder myisamchk -r.

  • Sie belegen normalerweise mehr Speicher als dynamische Tabellen.

14.1.3.2. Kennzeichen dynamischer Tabellen

Ein dynamisches Speicherformat wird verwendet, wenn eine MyISAM-Tabelle Spalten variabler Länge enthält (VARCHAR-, VARBINARY-, BLOB- oder TEXT-Spalten), oder wenn die Tabelle mit der Tabellenoption ROW_FORMAT=DYNAMIC angelegt wurde.

Das dynamische Format ist ein wenig komplizierter als das statische, da jede Zeile einen Header mit einer Längenangabe besitzt. Eine Zeile kann fragmentiert (an nicht-benachbarten Orten gespeichert) werden, wenn sie aufgrund eines Updates länger wird.

Mit OPTIMIZE TABLE oder myisamchk -r lassen sich Tabellen defragmentieren. Wenn in einer Tabelle, die auch Spalten variabler Länge besitzt, Spalten mit festgelegter Länge vorliegen, die oft angesprochen oder geändert werden, so empfiehlt es sich, die Spalten mit variabler Länge in andere Tabellen auszulagern, um Fragmentierung zu verhindern.

Kennzeichen von dynamischen Tabellen:

  • Alle String-Spalten sind dynamisch, außer jenen, deren Länge weniger als vier beträgt.

  • Vor jeder Zeile steht eine Bitmap, die für String-Spalten angibt, welche Spalten den leeren String enthalten, und für numerische Spalten, welche Spalten den Wert null enthalten. Beachten Sie, dass dies keine Spalten mit NULL-Werten einbezieht. Wenn eine String-Spalte nach dem Entfernen angehängter Leerzeichen die Länge null hat oder eine numerischen Spalte den Wert Null hat, wird sie in der Bitmap markiert und nicht auf der Festplatte gespeichert. Nicht-leere Strings werden mit einem Längen-Byte plus dem String-Inhalt gespeichert.

  • Sie benötigen normalerweise weniger Festplattenplatz als Festlängen-Tabellen.

  • Jede Zeile belegt nur so viel Platz wie nötig. Doch wenn eine Zeile wächst, wird sie aufgespalten, was zu Fragmentierung führt. Wenn Sie zum Beispiel eine Zeile mit Daten aktualisieren, die ihre Länge anwachsen lassen, so wird sie fragmentiert. In diesem Fall kann es erforderlich sein, gelegentlich OPTIMIZE TABLE oder myisamchk -r auszuführen, um die Leistung zu verbessern. myisamchk -ei kann Ihnen Statistikdaten zu Ihrer Tabelle liefern.

  • Sie sind nach einem Absturz schwerer zu rekonstruieren als Tabellen fester Länge, da die Zeilen unter Umständen in viele Stücke fragmentiert sind und Links (Fragmente) verlorengegangen sein könnten.

  • Die erwartete Zeilenlänge für dynamische Zeilen wird mit folgendem Ausdruck berechnet:

    3
    + (number of columns + 7) / 8
    + (number of char columns)
    + (packed size of numeric columns)
    + (length of strings)
    + (number of NULL columns + 7) / 8
    

    Für jeden Link kommen 6 Bytes hinzu. Eine dynamische Zeile wird immer dann verknüpft (verlinkt), wenn ein Update sie verlängert. Da jeder neue Link mindestens 20 Bytes hat, passt die nächste Verlängerung wahrscheinlich noch in denselben Link mit hinein. Wenn nicht, wird ein neuer Link angelegt. Die Anzahl der Links lässt sich mit myisamchk -ed feststellen. Alle Links können mit OPTIMIZE TABLE oder myisamchk -r entfernt werden.

14.1.3.3. Kennzeichen komprimierter Tabellen

Das komprimierte Speicherformat ist ein nur-lesbares Format, das mit myisampack angelegt wird. Komprimierte Tabellen lassen sich mit myisamchk auch wieder dekomprimieren.

Kennzeichen von komprimierten Tabellen:

  • Sie belegen sehr wenig Platz auf der Festplatte. Dadurch wird der Speicherverbrauch minimiert, was bei der Verwendung langsamer Speichermedien (zum Beispiel CD-ROMs) praktisch ist.

  • Da jede Zeile separat komprimiert wird, funktioniert der Zugriff mit geringem Aufwand. Der Header für eine Zeile belegt ein bis drei Bytes, abhängig von der längsten Zeile der Tabelle. Jede Spalte wird anders komprimiert und normalerweise gibt es für jede Spalte einen unterschiedlichen Huffman-Baum. Einige der Kompressionsarten sind:

    • Suffix-Kompression (Komprimierung von Leerzeichen am Ende).

    • Präfix-Kompression (Komprimierung von Leerzeichen am Anfang).

    • Zahlen mit dem Wert Null werden in einem Bit gespeichert.

    • Wenn Werte in einer Integerspalte einen kleinen Wertebereich haben, wird die Spalte im kleinstmöglichen Typ gespeichert. So kann zum Beispiel eine BIGINT-Spalte (acht Bytes) als TINYINT-Spalte (ein Byte) gespeichert werden, wenn alle ihre Werte zwischen -128 und 127 betragen.

    • Hat eine Spalte nur eine kleine Menge möglicher Werte, wird ihr Datentyp in eine ENUM konvertiert.

    • Eine Spalte kann eine beliebige Kombination der oben beschriebenen Komprimierungen verwenden.

  • Kann für Spalten fester oder dynamischer Länge verwendet werden.

14.1.4. MyISAM-Tabellenprobleme

Zwar wurde das von MySQL für die Datenspeicherung genutzte Dateiformat ausführlich getestet, aber es können immer Umstände auftreten, durch die Datenbanktabellen beschädigt werden. Im Folgenden wird erklärt, wie es dazu kommt und wie man damit umgeht.

14.1.4.1. Beschädigte MyISAM-Tabellen

Obwohl das Tabellenformat MyISAM sehr zuverlässig ist (alle Änderungen, die eine SQL-Anweisung an einer Tabelle vornimmt, werden geschrieben, ehe die Anweisung zurückkehrt), können dennoch unter folgenden Umständen Tabellen beschädigt werden:

  • Der mysqld-Prozess wird mitten in einem Schreibvorgang abgebrochen.

  • Der Computer wird unerwartet heruntergefahren (zum Beispiel ausgeschaltet).

  • Ein Hardware-Versagen.

  • Während eine Tabelle gerade vom Server modifiziert wird, ändern Sie dieselbe Tabelle mit einem externen Programm (zum Beispiel myisamchk).

  • Ein Software-Bug im Code von MySQL oder MyISAM.

Die folgenden Symptome sind typisch für eine beschädigte Tabelle:

  • Beim Auswählen von Daten aus der Tabelle bekommen Sie folgende Fehlermeldung:

    Incorrect key file for table: '...'. Try to repair it
    
  • Anfragen können Zeilen in der Tabelle nicht finden oder liefern unvollständige Ergebnisse zurück.

Mit der CHECK TABLE-Anweisung können Sie die Integrität einer MyISAM-Tabelle überprüfen und mit REPAIR TABLE können Sie sie reparieren, wenn sie beschädigt ist. Wenn mysqld nicht läuft, können Sie eine Tabelle auch mit dem Befehlmyisamchk prüfen oder reparieren Siehe hierzu auch Abschnitt 13.5.2.3, „CHECK TABLE, Abschnitt 13.5.2.6, „REPAIR TABLE und Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“.

Werden Ihre Tabellen häufig beschädigt, so sollten Sie nach den Ursachen forschen. Am wichtigsten ist es, festzustellen, ob die Tabelle infolge eines Server-Absturzes beschädigt wurde. Das können Sie leicht daran erkennen, dass im Fehler-Log eine restarted mysqld-Nachricht jüngeren Datums gespeichert ist. Wenn ja, dann wurde die Tabelle wahrscheinlich durch den Absturz des Servers beschädigt. Andernfalls kann der Schaden auch im normalen Betrieb aufgetreten sein. Das wäre dann ein Bug. Versuchen Sie in diesem Fall, einen reproduzierbaren Testfall zu erstellen, der das Problem demonstriert. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“ und Abschnitt E.1.6, „Erzeugen eines Testfalls, wenn Sie Tabellenbeschädigung feststellen“.

14.1.4.2. Client benutzt Tabelle oder hat sie nicht korrekt geschlossen

Jede MyISAM-Indexdatei (.MYI-Datei) besitzt im Header einen Zähler, an dem sich erkennen lässt, ob eine Tabelle ordnungsgemäß geschlossen wurde. Liefert CHECK TABLE oder myisamchk folgende Warnung, so bedeutet dies, dass der Zähler nicht mehr synchron läuft:

clients are using or haven't closed the table properly

Diese Warnung bedeutet zwar nicht unbedingt, dass die Tabelle beschädigt ist, aber Sie sollten zumindest eine Überprüfung vornehmen.

Der Zähler funktioniert folgendermaßen:

  • Wenn eine Tabelle in MySQL zum ersten Mal geändert wird, wird ein Zähler im Header der Indexdateien inkrementiert.

  • Bei nachfolgenden Änderungen bleibt der Zähler gleich.

  • Wenn die letzte Instanz einer Tabelle geschlossen wird (wegen einer FLUSH TABLES-Operation oder weil im Tabellen-Cache kein Platz mehr ist), wird der Zähler dekrementiert, wenn die Tabelle an irgendeinem Punkt geändert wurde.

  • Wenn Sie die Tabelle reparieren oder prüfen und für gut befinden, wird der Zähler wieder auf Null zurückgesetzt.

  • Um Abstimmungsprobleme mit anderen Prozessen zu verhindern, welche die Tabelle ebenfalls überprüfen, wird der Zähler beim Schließen nicht dekrementiert, wenn er den Wert null hatte.

Anders ausgedrückt: Der Zähler kann unter folgenden Bedingungen nicht mehr synchron sein:

  • Eine MyISAM-Tabelle wird ohne vorheriges LOCK TABLES und FLUSH TABLES kopiert.

  • MySQL ist zwischen einer Änderung und dem endgültigen Schließen der Tabelle abgestürzt. (Beachten Sie, dass auch in diesem Fall die Tabelle immer noch in Ordnung sein kann, da MySQL zwischen zwei Anweisungen immer alles schreibt.)

  • Eine Tabelle wurde von myisamchk --recover oder myisamchk --update-state geändert, während sie gleichzeitig von mysqld benutzt wurde.

  • Mehrere mysqld-Server benutzen die Tabelle und einer von ihnen hat REPAIR TABLE oder CHECK TABLE auf ihr ausgeführt, während die anderen Server gerade auf sie zugriffen. In diesem Fall ist die Verwendung von CHECK TABLE sicher, obwohl Sie vielleicht von anderen Servern eine Warnung bekommen. REPAIR TABLE sollten Sie allerdings vermeiden, denn wenn ein Server die Datendatei durch eine neue ersetzt, können die anderen Server dies nicht wissen.

    Normalerweise sollte man ein Data Directory nicht mit mehreren Servern gemeinsam nutzen. Weitere Hinweise finden Sie unter Abschnitt 5.13, „Mehrere MySQL-Server auf derselben Maschine laufen lassen“.

14.2. InnoDB-Tabellen

14.2.1. Überblick über InnoDB-Tabellen

Mit InnoDB verfügt MySQL über eine transaktionssichere (ACID-konforme) Speicher-Engine mit Commit-, Rollback- und Datenwiederherstellungsfähigkeiten. InnoDB beherrscht sowohl Zeilensperren als auch, ähnlich wie Oracle, eine konsistente Leseoperation ohne Sperren für SELECT-Anweisungen. Diese Features verbessern die Mehrbenutzertauglichkeit und die Leistung. InnoDB benötigt keine Sperreneskalation da Zeilensperren sehr wenig Platz beanspruchen. Außerdem unterstützt InnoDB die FOREIGN KEY-Constraints. Sie können InnoDB-Tabellen nach Belieben mit Tabellen aus anderen MySQL-Speicher-Engines mischen, sogar in ein- und derselben Anweisung.

InnoDB wurde für maximale Leistung bei der Verarbeitung großer Datenmengen ausgelegt. Es gibt wohl keine andere festplattengestützte Speicher-Engine für relationale Datenbanken, die so effizient mit der CPU umgeht.

Die voll in den MySQL-Server integrierte InnoDB-Speicher-Engine hat ihren eigenen Bufferpool zur Speicherung von Daten und Indizes im Hauptspeicher. InnoDB speichert ihre Tabellen und Indizes in einem Tablespace, der aus mehreren Dateien (oder Festplattenpartitionen) bestehen kann. Darin unterscheidet sie sich beispielsweise von MyISAM, wo jede Tabelle in separaten Dateien untergebracht wird. InnoDB-Tabellen können beliebig groß sein, selbst auf Betriebssystemen, deren Dateigröße auf 2GB beschränkt ist.

InnoDB ist standardmäßig in Binärdistributionen enthalten. Der Windows Essentials-Installer macht InnoDB auf Windows zur Standard-Speicher-Engine für MySQL.

InnoDB wird in einer Vielzahl großer Produktionsdatenbanken eingesetzt, die hohe Anforderungen an die Leistung stellen. Die bekannte Internet-Newssite Slashdot.org läuft mit InnoDB. Mytrix speichert mehr als 1TB Daten in InnoDB und eine andere Site verarbeitet durchschnittlich 800 Inserts/Updates pro Sekunde auf InnoDB.

InnoDB unterliegt derselben GNU GPL License Version 2 (von Juni 1991) wie MySQL. Weitere Informationen über MySQL-Lizenzen finden Sie unter http://www.mysql.com/company/legal/licensing/.

Mehr zum Thema

14.2.2. Kontaktinformationen

Mit Innobase Oy, dem Produzenten der InnoDB-Engine können Sie wie folgt Kontakt aufnehmen:

      Web site: http://www.innodb.com/
      Email: 
      Phone: +358-9-6969 3250 (office)
      +358-40-5617367 (mobile)
      
      Innobase Oy Inc.
      World Trade Center Helsinki
      Aleksanterinkatu 17
      P.O.Box 800
      00101 Helsinki
      Finland
    

14.2.3. Konfiguration

Die Speicher-Engine InnoDB ist nach Voreinstellung aktiv. Wenn Sie keine InnoDB-Tabellen verwenden möchten, setzen Sie die Option skip-innodb in Ihre MySQL-Optionsdatei.

Hinweis: Mit InnoDB verfügt MySQL über eine transaktionssichere (ACID-konforme) Speicher-Engine mit Commit-, Rollback- und Datenwiederherstellungsfähigkeiten. Diese Fähigkeiten stehen jedoch nur dann zur Verfügung, wenn auch das zugrunde liegende Betriebssystem und die Hardware vorschriftsgemäß arbeiten.. Viele Betriebssysteme oder Festplatten-Subsysteme verzögern Schreiboperationen oder ordnen sie anders an, um die Leistung zu verbessern. Auf manchen Betriebssystemen kann sogar der Systemaufruf selbst, der eigentlich warten sollte, bis alle noch ungespeicherten Daten einer Datei auf die Platte zurückgeschrieben wurden — fsync() — bereits zurückkehren, ehe die Daten in einen dauerhaften Speicher geschrieben wurden. So kann zum Beispiel ein Betriebssystemabsturz oder ein Stromausfall Daten, die gerade erst committet wurden, zerstören, oder im schlimmsten Fall sogar die Datenbank schädigen, indem Schreiboperationen in die verkehrte Reihenfolge gestellt werden. Wenn Ihnen an der Integrität Ihrer Daten etwas liegt, sollten Sie das Verhalten bei Stromausfall testen, ehe Sie etwas in die Produktionsumgebung einführen. Auf Mac OS X 10.3 und höher verwendet InnoDB eine spezielle fcntl()-Methode, um Dateien auf die Festplatte zurückzuschreiben. Unter Linux empfiehlt es sich, den Write-Back-Cache zu deaktivieren.

Auf ATAPI-Festplatten kann es funktionieren, mit einem Befehl wie hdparm -W0 /dev/hda den Write-Back-Cache zu deaktivieren. Vorsicht! Manche Treiber oder Festplattencontroller sind nicht in der Lage, den Write-Back-Cache zu deaktivieren.

Zwei wichtige, von InnoDB verwalteten Festplattenressourcen sind die Tablespace-Datendateien und die Logdateien.

Hinweis: Wenn Sie Konfigurationsoptionen für InnoDB angeben, erzeugt MySQL eine sich selbst erweiternde, 10MB große Datendatei namens ibdata1 und zwei 5MB große Logdateien namens ib_logfile0 und ib_logfile1 im MySQL Data Directory. Um eine gute Performance zu erzielen, sollten Sie explizit die in den folgenden Beispielen erwähnten InnoDB-Parameter setzen, allerdings natürlich angepasst an Ihre Hardware und Systemanforderungen.

Die folgenden Beispiele haben nur repräsentativen Charakter. In Abschnitt 14.2.4, „InnoDB: Startoptionen und Systemvariablen“ erfahren Sie mehr über die Konfigurationsparameter für InnoDB.

Die InnoDB-Tablespace-Dateien richten Sie ein, indem Sie die Option innodb_data_file_path im [mysqld]-Abschnitt der Optionsdatei my.cnf einstellen. Auf Windows verwenden Sie stattdessen my.ini. Der innodb_data_file_path sollte eine Liste mit einer oder mehreren Datendatei-Spezifikationen sein. Mehrere Datendateien werden durch Semikola (‘;’) getrennt:

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

Eine Einstellung, die explizit einen Tablespace mit den Standardmerkmalen anlegt, wäre beispielsweise:

[mysqld]
innodb_data_file_path=ibdata1:10M:autoextend

Diese Einstellung konfiguriert eine einzige 10MB große Datendatei namens ibdata1, die sich selbsttätig erweitert. Da kein Verzeichnis vorgegeben ist, legt InnoDB sie im MySQL Data Directory an.

Größen geben Sie an, indem Sie das Suffix M für MB oder G für GB verwenden.

Ein Tablespace mit einer 50MB großen Datendatei fester Größe namens ibdata1 und einer 50MB großen, selbsterweiternden Datei namens ibdata2 im Data Directory kann folgendermaßen konfiguriert werden:

[mysqld]
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

Zur vollständigen Syntax einer Datendateispezifikation gehören Dateiname, Größe und mehrere optionale Attribute:

file_name:file_size[:autoextend[:max:max_file_size]]

autoextend und die folgenden Attribute können nur für die letzte Datendatei auf der Zeile innodb_data_file_path verwendet werden.

Wenn Sie die Option autoextend für die letzte Datendatei angeben, erweitert InnoDB diese Datei, sobald sie im Tablespace nicht mehr genug freien Platz hat, in Inkrementierungsschritten, die auf 8MB voreingestellt sind. Diese Einstellung kann in der Systemvariablen innodb_autoextend_increment geändert werden.

Wenn die Platte vollläuft, müssen Sie eine andere Datendatei oder Festplatte hinzufügen. Eine Anleitung zur Rekonfiguration vorhandener Tablespaces finden Sie in Abschnitt 14.2.7, „Hinzufügen und Entfernen von InnoDB-Daten- und -Logdateien“.

Da InnoDB die maximale Dateigröße des Dateisystems nicht kennt, müssen Sie aufpassen, wenn Ihr Dateisystem nur einen relativ kleinen Wert wie etwa 2GB zulässt. Eine Maximalgröße für eine selbsterweiternde Datendatei geben Sie mit dem Attribut max an. In der folgenden Konfiguration kann ibdata1 auf bis zu 500MB anwachsen:

[mysqld]
innodb_data_file_path=ibdata1:10M:autoextend:max:500M

InnoDB legt Ttablespace-Dateien standardmäßig im MySQL Data Directory an. Um ein anderes Verzeichnis anzugeben, verwenden Sie die Option innodb_data_home_dir. Wenn sie zum Beispiel zwei Dateien namens ibdata1 und ibdata2 im Verzeichnis /ibdata anlegen möchten, müssen Sie InnoDB wie folgt konfigurieren:

[mysqld]
innodb_data_home_dir = /ibdata
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

Hinweis: Da InnoDB keine Verzeichnisse erstellt, müssen Sie dafür sorgen, dass /ibdata existiert, ehe Sie den Server starten. Das gilt auch für Logdateiverzeichnisse, die Sie konfigurieren. Mit dem Unix- oder DOS-Befehl mkdir können Sie alle erforderlichen Verzeichnisse anlegen.

InnoDB bildet Verzeichnispfade für Datendateien, indem es den Wert von innodb_data_home_dir mit dem Namen der Datendatei verkettet, und wenn nötig ein Pfadtrennzeichen (Schrägstrich oder Backslash) zwischen die Werte setzt. Wenn die Option innodb_data_home_dir in my.cnf gar nicht auftaucht, ist der Standardwert das „Punkt“-Verzeichnis ./, also das MySQL Data Directory. (Der MySQL-Server macht das Data Directory zum aktuellen Arbeitsverzeichnis, wenn er seine Arbeit aufnimmt.)

Wenn Sie innodb_data_home_dir als leeren String angeben, können Sie absolute Pfade für die Datendateien angeben, die im Wert von innodb_data_file_path aufgeführt sind. Das folgende Beispiel ist äquivalent zu dem vorherigen:

[mysqld]
innodb_data_home_dir =
innodb_data_file_path=/ibdata/ibdata1:50M;/ibdata/ibdata2:50M:autoextend

Ein einfaches my.cnf-Beispiel. Angenommen, Sie haben einen Computer mit 128MB Arbeitsspeicher und einer Festplatte. Das folgende Beispiel zeigt mögliche Konfigurationsparameter in my.cnf oder my.ini für InnoDB, einschließlich des autoextend-Attributs. Das Beispiel passt zu den meisten Unix- und Windows-Benutzern, die ihre InnoDB-Datendateien und -Logdateien nicht auf mehrere Festplatten verteilen möchten. Es legt eine selbsterweiternde Datendatei namens ibdata1 und zwei InnoDB-Logdateien namens ib_logfile0 und ib_logfile1 im MySQL Data Directory an. Außerdem wird die kleine, archivierte InnoDB-Logdatei ib_arch_log_0000000000, die InnoDB automatisch erstellt, ins Data Directory gespeichert.

[mysqld]
# Hier können Sie Ihre übrigen MySQL-Server-Optionen angeben
# ...
# Datendateien müssen Daten und Indizes speichern können.
# Achten Sie auf ausreichend freien Plattenplatz.
innodb_data_file_path = ibdata1:10M:autoextend
#
# Bufferpool-Größe wird auf 50-80% vom Arbeitsspeicher eingestellt
innodb_buffer_pool_size=70M
innodb_additional_mem_pool_size=10M
#
# Logdateigröße wird auf 25% der Bufferpool-Größe eingestellt
innodb_log_file_size=20M
innodb_log_buffer_size=8M
#
innodb_flush_log_at_trx_commit=1

Achten Sie darauf, dass der MySQL-Server die richtigen Berechtigungen hat, um Dateien im Data Directory anlegen zu können. Generell benötigt der Server Zugriffsrecht auf jedes Verzeichnis, in dem er Daten- oder Logdateien anlegen soll.

Beachten Sie, dass Datendateien in manchen Dateisystemen höchstens 2GB groß sein dürfen. Die kombinierte Größe aller Logdateien muss unter 4GB liegen und die kombinierte Größe der Datendateien mindestens 10MB betragen.

Wenn Sie zum ersten Mal einen InnoDB-Tablespace anlegen, starten Sie den MySQL-Server am besten von der Kommandozeile. Da InnoDB dann Informationen über die Datenbankerstellung auf dem Bildschirm ausgibt, können Sie sehen, was geschieht. Wenn beispielsweise auf Windows mysqld-max im Verzeichnis C:\Program Files\MySQL\MySQL Server 5.1\bin liegt, können Sie folgendermaßen starten:

C:\> "C:\Program Files\MySQL\MySQL Server 5.1\bin\mysqld-max" --console

Wenn sie keine Serverausgabe an den Bildschirm schicken, müssen Sie im Fehlerlog nachschauen, welche Meldungen InnoDB beim Hochfahren ausgibt.

Unter Abschnitt 14.2.5, „InnoDB-Tablespace erzeugen“ sehen Sie ein Beispiel dafür, welche Informationen InnoDB anzeigt.

Die InnoDB-Optionen können Sie in die [mysqld]-Gruppe einer beliebigen Optionsdatei legen, die Ihr Server beim Hochfahren liest. Speicherorte für Optionsdateien werden in Abschnitt 4.3.2, „my.cnf-Optionsdateien“ beschrieben.

Wenn Sie MySQL auf Windows mit dem Installations- und Konfigurationsassistenten installiert haben, liegen die Optionen in der my.ini-Datei in Ihrem MySQL-Installationsverzeichnis. Siehe Abschnitt 2.3.5.14, „Speicherort der Datei my.ini.

Wenn Ihr PC einen Bootloader nutzt und C: nicht das Bootverzeichnis ist, haben Sie keine andere Möglichkeit, als die my.ini-Datei in Ihrem Windows-Verzeichnis zu benutzen (in der Regel C:\WINDOWS oder C:\WINNT). Verwenden Sie den Befehl SET auf der Kommandozeile eines Konsolenfensters, um den Wert von WINDIR auszugeben:

C:\> SET WINDIR
windir=C:\WINDOWS

Wenn Sie sicherstellen möchten, dass mysqld-Optionen nur aus einer bestimmten Datei liest, verwenden Sie --defaults-option beim Serverstart als erste Option auf der Kommandozeile:

mysqld --defaults-file=your_path_to_my_cnf

Ein fortgeschrittenesmy.cnf-Beispiel. Angenommen, Sie haben einen Linux-Computer mit 2GB RAM und drei 60GB-Festplatten mit den Verzeichnispfaden /, /dr2 und /dr3. Das folgende Beispiel zeigt, welche Konfigurationsparameter man in my.cnf für InnoDB setzen könnte.

[mysqld]
# Hier können Sie Ihre übrigen MySQL-Server-Optionen angeben
# ...
innodb_data_home_dir =
#
# Datendateien müssen Daten und Indizes speichern können.
innodb_data_file_path = /ibdata/ibdata1:2000M;/dr2/ibdata/ibdata2:2000M:autoextend
#
# Setzen Sie die Bufferpool-Größe auf 50-80% des Arbeitsspeichers,
# aber achten Sie darauf, dass für Linux x86 die gesamte Speichernutzung < 2GB ist.
innodb_buffer_pool_size=1G
innodb_additional_mem_pool_size=20M
innodb_log_group_home_dir = /dr3/iblogs
#
innodb_log_files_in_group = 2
#
# Setzen Sie die Logdateigröße auf circa 25% der Bufferpool-Größe
innodb_log_file_size=250M
innodb_log_buffer_size=8M
#
innodb_flush_log_at_trx_commit=1
innodb_lock_wait_timeout=50
#
# Kommentieren Sie die nächsten Zeilen aus, wenn Sie sie nutzen möchten
#innodb_thread_concurrency=5

In manchen Fällen steigt die Datenbank-Performance, wenn nicht alle Daten auf derselben physikalischen Platte liegen. Oft ist es gut für die Performance, wenn die Logdateien auf einer anderen Festplatte liegen. Das Beispiel zeigt, wie das geht: Es speichert zwei Dateien auf verschiedenen Festplatten und legt die Logdateien auf eine dritte Platte. InnoDB füllt den Tablespace beginnend mit der ersten Datendatei. Für einen schnelleren Zugriff können Sie auch rohe Festplattenpartitionen (Raw Devices) als InnoDB-Datendateien verwenden. Siehe Abschnitt 14.2.3.2, „Verwendung von Raw Devices für den Shared Tablespace“.

Warnung: Auf 32-Bit GNU/Linux x86 dürfen Sie die Arbeitsspeichernutzung nicht zu hoch einstellen. Wenn glibc den Prozess-Heap über die Thread-Stacks hinauswachsen lässt, stürzt der Server ab. Wenn der Wert des folgenden Ausdrucks 2GB erreicht oder übersteigt, ist Gefahr in Verzug:

innodb_buffer_pool_size
+ key_buffer_size
+ max_connections*(sort_buffer_size+read_buffer_size+binlog_cache_size)
+ max_connections*2MB

Jeder Thread benutzt einen Stack (oft 2MB, aber in den Binaries von MySQL AB nur 256KB) und im schlimmsten Fall auch sort_buffer_size + read_buffer_size zusätzlichen Arbeitsspeicher.

Indem Sie MySQL selbst kompilieren, können Sie bis zu 64GB physikalischen Speicher in 32-Bit Windows verwenden. Siehe Beschreibung von innodb_buffer_pool_awe_mem_mb in Abschnitt 14.2.4, „InnoDB: Startoptionen und Systemvariablen“.

Wie werden die anderen mysqld-Serverparameter eingestellt? Die folgenden Werte sind typisch und eignen sich für die meisten Nutzer:

[mysqld]
skip-external-locking
max_connections=200
read_buffer_size=1M
sort_buffer_size=1M
#
# Setzen Sie key_buffer auf 5 - 50% Ihres Arbeitsspeichers, je nachdem, wie
# oft Sie MyISAM-Tabellen benutzen, aber behalten Sie key_buffer_size + InnoDB
# buffer pool size < 80% Ihres Arbeitsspeichers
key_buffer_size=value

14.2.3.1. Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)

Sie können jede InnoDB-Tabelle und ihre Indizes in ihrer eigenen Datei speichern. Dieses Feature nennt man „Multi-Tablespaces“ da im Endeffekt jede Tabelle ihren eigenen Tablespace bekommt.

Multi-Tablespaces sind praktisch für Benutzer, die bestimmte Tabellen auf separate physikalische Platten verlagern oder Backups einzelner Tabellen rasch wiederherstellen möchten, ohne die Arbeit mit den übrigen InnoDB-Tabellen zu unterbrechen.

Aktivieren Sie Multi-Tablespaces mit folgender Zeile im [mysqld]-Abschnitt von my.cnf:

[mysqld]
innodb_file_per_table

Nach dem Server-Neustart speichert InnoDB jede neu erzeugte Tabelle in einer eigenen Datei tbl_name.ibd in dem Datenbankverzeichnis, zu dem die Tabelle gehört. Das ähnelt dem Vorgehen der MyISAM-Speicher-Engine, doch diese spaltet die Tabellen in eine Datendatei tbl_name.MYD und eine Indexdatei tbl_name.MYI. Mit InnoDB werden Daten und Indizes gemeinsam in der.ibd-Datei gespeichert. Die tbl_name.frm-Datei wird wie üblich angelegt.

Wenn Sie die innodb_file_per_table-Zeile aus my.cnf löschen und den Server neu starten, erzeugt InnoDB die Tabellen wieder in Shared Tablespace-Dateien.

innodb_file_per_table wirkt sich nur auf eine einzelne Tabellenerzeugung aus, und beeinflusst nicht den Zugriff auf bestehende Tabellen. Wenn Sie den Server mit dieser Option starten, werden neue Tabellen mit .ibd-Dateien angelegt, aber alte liegen immer noch im Shared Tablespace. Entfernen Sie die Option wieder und starten dann den Server neu, werden die neuen Tabellen im Shared Tablespace angelegt, aber Tabellen, die mit Multi-Tablespaces angelegt wurden, bleiben weiterhin zugänglich.

InnoDB benötigt immer den Shared Tablespace, da es sein internes Data Dictionary und seine Undo-Logs dort speichert. Die .ibd-Dateien reichen InnoDB zum Funktionieren nicht aus.

Hinweis: Sie können .ibd-Dateien genau wie MyISAM-Tabellendateien nach Belieben zwischen Datenbankverzeichnissen hin- und herschieben, weil die im Shared Tablespace von InnoDB gespeicherte Tabellendefinition den Datenbanknamen enthält und weil InnoDB die Konsistenz von Transaktions-IDs und Lognummern beibehalten muss.

Um eine .ibd-Datei und die zugehörige Tabelle von einer Datenbank in eine andere zu verlagern, verwenden Sie eine RENAME TABLE-Anweisung:

RENAME TABLE db1.tbl_name TO db2.tbl_name;

Wenn Sie über ein „sauberes“ Backup einer .ibd-Datei verfügen, können Sie diese in ihrer angestammten MySQL-Installation folgendermaßen wiederherstellen:

  1. Geben Sie folgende ALTER TABLE-Anweisung:

    ALTER TABLE tbl_name DISCARD TABLESPACE;
    

    Vorsicht: Diese Anweisung löscht die aktuelle .ibd-Datei.

  2. Speichern Sie die .ibd-Backup-Datei zurück in das richtige Datenbankverzeichnis.

  3. Geben Sie folgende ALTER TABLE-Anweisung:

    ALTER TABLE tbl_name IMPORT TABLESPACE;
    

Ein „sauberes“ Backup einer .ibd-Datei bedeutet in diesem Zusammenhang:

  • Keine schwebenden Transaktionen in der .ibd-Datei.

  • Keine noch nicht zusammengeführten Insert-Puffer-Einträge in der .ibd-Datei.

  • Purge hat alle zum Löschen vorgemerkten Indexeinträge aus der .ibd-Datei entfernt.

  • mysqld hat alle geänderten Seiten der .ibd-Datei aus dem Bufferpool in die Datei zurückgeschrieben.

Mit folgender Methode können Sie eine saubere .ibd-Backup-Datei anlegen:

  1. Beenden Sie alle Aktivitäten des mysqld-Servers und schreiben Sie alle Transaktionen fest.

  2. Warten Sie, bis SHOW ENGINE INNODB STATUS anzeigt, dass keine Transaktionen mehr in der Datenbank aktiv sind und der Status des Haupt-Threads von InnoDB den Wert Waiting for server activity angenommen hat. Dann können Sie die .ibd-Datei kopieren.

Eine andere Möglichkeit, an eine saubere Kopie einer .ibd-Datei zu kommen, ist die Verwendung eines kommerziellen InnoDB Hot Backup-Tools:

  1. Legen Sie mit InnoDB Hot Backup ein Backup der InnoDB-Installation an.

  2. Starten Sie einen zweiten mysqld-Server auf dem Backup und lassen Sie ihn die .ibd-Dateien im Backup säubern.

14.2.3.2. Verwendung von Raw Devices für den Shared Tablespace

Sie können auch rohe Festplattenpartitionen für die Datendateien im Shared Tablespace verwenden. So können sie ungepufferte E/A-Zugriffe ohne Dateisystem-Overhead auf Windows und einigen Unix-Systemen implementieren und die Performance dadurch steigern.

Wenn Sie eine neue Datendatei anlegen, müssen Sie in innodb_data_file_path das Schlüsselwort newraw direkt hinter die Größe der Datendatei setzen. Die Partition muss mindestens die angegebene Größe haben. Beachten Sie, dass 1MB in InnoDB 1024 × 1024 Bytes sind, während 1MB in Festplattenspezifikationen normalerweise 1.000.000 Bytes bedeutet.

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw

Wenn Sie den Server das nächste Mal starten, bemerkt InnoDB das Schlüsselwort newraw und initialisiert die neue Partition. Sie dürfen jetzt aber noch keine InnoDB-Tabellen ändern oder anlegen, sonst reinitialisiert InnoDB beim nächsten Serverstart die Partition und Ihre Änderungen gehen verloren. (Als Sicherheitsmaßnahme hindert InnoDB die Benutzer daran, irgendwelche Daten zu ändern, wenn eine Partition mit newraw definiert wurde.)

Nachdem InnoDB die neue Partition initialisiert hat, halten Sie den Server an und ändern newraw in der Datendateispezifikation in raw um:

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:5Graw;/dev/hdd2:2Graw

Wenn Sie nun den Server erneut starten, erlaubt InnoDB auch Änderungen.

Auf Windows können Sie eine Festplattenpartition folgendermaßen als Datendatei zuweisen:

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=//./D::10Gnewraw

Das //./ entspricht beim Zugriff auf physikalische Platten der Windows-Syntax \\.\.

Wenn Sie rohe Festplattenpartitionen benutzen, achten Sie bitte darauf, dass ihre Berechtigungseinstellungen dem vom MySQL-Server benutzten Konto auch Lese- und Schreiboperationen gestatten.

14.2.4. InnoDB: Startoptionen und Systemvariablen

Dieser Abschnitt beschreibt die Befehlsoptionen und Systemvariablen für InnoDB. Systemvariablen, die true oder false sein können, werden beim Serverstart entweder durch Nennung ihres Namens aktiviert oder mit dem Präfix skip- deaktiviert. Um beispielsweise InnoDB-Prüfsummen ein- oder auszuschalten, verwenden Sie --innodb_checksums oder --skip-innodb_checksums auf der Kommandozeile, oder innodb_checksums oder skip-innodb_checksums in einer Optionsdatei. Systemvariablen, die einen numerischen Wert annehmen, können als --var_name=value auf der Kommandozeile oder als var_name=value in Optionsdateien angegeben werden. Weitere Informationen über die Angabe von Optionen und Systemvariablen finden Sie unter Abschnitt 4.3, „Angabe von Programmoptionen“. Viele der Systemvariablen können zur Laufzeit geändert werden (siehe Abschnitt 5.2.3.2, „Dynamische Systemvariablen“).

InnoDB-Befehlsoptionen:

  • --innodb

    Aktiviert die InnoDB-Speicher-Engine, wenn der Server mit InnoDB-Unterstützung kompiliert wurde. Mit --skip-innodb können Sie InnoDB deaktivieren.

  • --innodb_status_file

    Veranlasst InnoDB, eine Datei namens <datadir>/innodb_status.<pid> im MySQL Data Directory anzulegen. InnoDB schreibt in regelmäßigen Abständen die Ausgabe von SHOW ENGINE INNODB STATUS in diese Datei.

InnoDB-Systemvariablen:

  • innodb_additional_mem_pool_size

    Die Größe des von InnoDB zum Speichern von Data Dictionary-Informationen und anderen internen Datenstrukturen verwendeten Arbeitsspeicherpools in Bytes. Je mehr Tabellen Ihre Anwendung hat, umso mehr Arbeitsspeicher müssen Sie hier zuweisen. Wenn InnoDB in diesem Pool der Speicher ausgeht, beginnt es, Arbeitsspeicher vom Betriebssystem abzuzweigen, und gibt Warnmeldungen in das MySQL-Fehlerlog aus. Der Standardwert beträgt 1MB.

  • innodb_autoextend_increment

    In Inkrementen dieser Größe (in MB) wächst ein selbsterweiternder Tablespace, wenn er vollläuft. Der Standardwert beträgt 8.

  • innodb_buffer_pool_awe_mem_mb

    Die Größe des Bufferpools (in MB), wenn er im AWE-Speicher liegt. Dies gilt jedoch nur für 32-Bit Windows. Wenn Ihr 32-Bit Windows-Betriebssystem über die so genannten „Address Windowing Extensions“ mehr als 4GB Arbeitsspeichergröße unterstützt, können Sie den InnoDB-Bufferpool im physikalischen AWE-Speicher mit dieser Variablen zuweisen. Der größtmögliche Wert der Variablen beträgt 63000. Ist er größer als 0, ist innodb_buffer_pool_size das Fenster im 32-Bit-Adressraum von mysqld, wobei InnoDB diesen AWE-Arbeitsspeicher abbildet. Ein guter Wert für innodb_buffer_pool_size ist 500MB.

    Um den AWE-Speicher nutzen zu können, müssen Sie MySQL neu kompilieren. Welche Projekteinstellungen derzeit dazu erforderlich sind, entnehmen Sie bitte der Quelldatei storage/innobase/os/os0proj.c.

  • innodb_buffer_pool_size

    Die Größe des Arbeitsspeicherpuffers in Bytes, den InnoDB zum Zwischenspeichern der Daten und Indizes seiner Tabellen benutzt. Je größer Sie diesen Wert einstellen, umso weniger Festplattenzugriffe sind für den Zugriff auf die Tabellendaten erforderlich. Für einen dedizierten Datenbankserver können Sie dies auf 80% des physikalischen Arbeitsspeichers heraufsetzen. Machen Sie ihn jedoch nicht zu groß, da ein Wettlauf um den physikalischen Speicher das Betriebssystem zum Paging veranlassen kann.

  • innodb_checksums

    InnoDB kann für alle von der Platte gelesenen Seiten eine Prüfsummenvalidierung verwenden, um eine zusätzliche Fehlertoleranz gegenüber Schäden an Hardware oder Datendateien zu gewährleisten. Diese Validierung ist standardmäßig eingeschaltet. Doch in einigen wenigen Fällen (zum Beispiel bei der Ausführung von Benchmarks) ist diese zusätzliche Sicherheitsvorkehrung überflüssig und kann mit --skip-innodb-checksums deaktiviert werden.

  • innodb_commit_concurrency

    Die Anzahl der Threads, die gleichzeitig committen können. Der Wert 0 schaltet die Nebenläufigkeitssteuerung aus.

  • innodb_concurrency_tickets

    Wie viele Threads gleichzeitig auf InnoDB zugreifen können, hängt von der Einstellung der innodb_thread_concurrency-Variablen ab. Ein Thread wird in eine Schlange gestellt, wenn er auf InnoDB zugreifen möchte und das Nebenläufigkeitslimit bereits erreicht ist. Wenn einem Thread der Eintritt in InnoDB erlaubt wird, bekommt eine Anzahl von „Freifahrscheine“, die der Anzahl der innodb_concurrency_tickets entspricht und kann InnoDB so lange nach Belieben betreten und verlassen, bis seine Freifahrscheine aufgebraucht sind. Danach wird der Thread wieder einer Prüfung unterzogen (und eventuell in die Schlange gestellt), wenn er das nächste Mal in InnoDB eintreten möchte.

  • innodb_data_file_path

    Die Pfade und Größen der einzelnen Datendateien. Der vollständige Verzeichnispfad zu den Datendateien entsteht, wenn innodb_data_home_dir mit den einzelnen, hier angegebenen Pfaden verkettet wird. Die Dateigrößen werden in MB oder GB (1024MB) durch Anfügen von M oder G an den Größenwert angegeben. Die Summe der Dateigrößen muss mindestens 10MB betragen. Wenn Sie keinen innodb_data_file_path angeben, wird standardmäßig eine einzige, selbsterweiternde, 10MB große Datendatei namens ibdata1 erzeugt. Wie groß die einzelnen Dateien werden können, entscheidet Ihr Betriebssystem. Auf Systemen, die große Dateien unterstützen, können Sie die Dateigröße auf mehr als 4GB setzen. Sie können auch rohe Festplattenpartitionen als Datendateien einsetzen. Siehe Abschnitt 14.2.3.2, „Verwendung von Raw Devices für den Shared Tablespace“.

  • innodb_data_home_dir

    Der gemeinsame Teil des Verzeichnispfads für alle InnoDB-Datendateien. Wenn Sie diesen Wert nicht einstellen, ist das MySQL Data Directory das Ziel. Geben Sie hier einen leeren String an, so können Sie in innodb_data_file_path absolute Dateipfade verwenden.

  • innodb_doublewrite

    Nach Voreinstellung speichert InnoDB alle Daten zweimal, nämlich zuerst in den Doublewrite-Puffer und dann in die eigentlichen Datendateien. Diese Variable ist standardmäßig eingeschaltet, kann aber mit der Option --skip-innodb_doublewrite ausgeschaltet werden, wenn Sie Benchmarks ausführen oder Ihnen eine Top-Performance so wichtig ist, dass Sie sich für Datenintegrität und mögliche Systemabstürze weniger interessieren.

  • innodb_fast_shutdown

    Wenn Sie diese Variable auf 0 setzen, führt InnoDB vor dem Herunterfahren eine vollständige Purge-Operation und Verschmelzung der Insert-Puffer durch. Diese Operationen können Minuten oder im Extremfall sogar Stunden in Anspruch nehmen. Setzen Sie diese Variable auf 1, übergeht InnoDB beim Herunterfahren diese Operationen. Der Standardwert ist 1. Wenn Sie ihn auf 2 setzen, leert InnoDB nur die Logs und fährt dann kalt herunter, wie bei einem Absturz von MySQL. Es geht zwar keine committete Transaktion verloren, aber nach dem nächsten Hochfahren wird eine Wiederherstellung gefahren. Den Wert 2 können Sie nicht auf NetWare verwenden.

  • innodb_file_io_threads

    Die Anzahl der Dateizugriffs-Threads in InnoDB. Normalerweise kann man den Standardwert 4 beibehalten, aber auf Windows kann eine größere Zahl die Festplattenzugriffe günstig beeinflussen. Auf Unix bleibt eine Erhöhung dieses Werts ohne Wirkung, da InnoDB immer den Standardwert verwendet.

  • innodb_file_per_table

    Wenn diese Variable eingeschaltet ist, erzeugt InnoDB jede neue Tabelle mit ihrer eigenen .ibd-Datei zum Speichern von Daten und Indizes, anstatt im Shared Tablespace. Nach Voreinstellung werden die Tabellen im Shared Tablespace angelegt. Siehe Abschnitt 14.2.3.1, „Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)“.

  • innodb_flush_log_at_trx_commit

    Hat innodb_flush_log_at_trx_commit den Wert 0, wird einmal pro Sekunde der Logpuffer in die Logdatei geschrieben und diese auf die Festplatte zurückgespeichert, doch beim Committen einer Transaktion wird nichts veranlasst. Ist der Wert 1 (der Standard), wird bei jedem Commit der Logpuffer in die Logdatei und diese auf die Festplatte geschrieben. Ist der Wert 2, wird der Puffer bei jedem Commit in die Datei übertragen, aber diese nicht beim Commit, sondern einmal pro Sekunde auf die Festplatte zurückgeschrieben. Beachten Sie jedoch, dass dieser Schreibvorgang aus Gründen der Prozessplanung in Wirklichkeit nicht unbedingt exakt einmal pro Sekunde stattfindet.

    Der Standardwert dieser Variablen, nämlich 1, ist für die ACID-Fähigkeit erforderlich. Ein anderer Wert als 1 kann zwar die Performance steigern, aber um den Preis, dass Sie bei einem Systemabsturz eine Sekunde an Transaktionen verlieren. Ist der Wert 0, kann jeder Absturz des mysqld-Prozesses die Transaktionen der letzten Sekunde ausradieren. Ist der Wert 2, würde dieser Datenverlust bei einem Betriebssystemabsturz oder Stromausfall eintreten. Da allerdings die Wiederherstellungsfunktion von InnoDB nicht beeinträchtigt wird, würde die Crash-Recovery unabhängig vom Wert dieser Variablen funktionieren. Beachten Sie jedoch, dass viele Betriebssysteme und einige Festplatten die Flush-to-Disk-Operation irreführen, indem sie mysqld weismachen, dass die Daten bereits auf die Festplatte geschrieben wurden, auch wenn das nicht der Fall ist. Die Dauerhaftigkeit von Transaktionen ist also selbst mit der Einstellung 1 nicht gewährleistet, und im schlimmsten Falle kann ein Stromausfall sogar die InnoDB-Datenbank beschädigen. Ein batteriegestützter Festplatten-Cache im SCSI-Festplattencontroller oder in der Festplatte selbst kann das Zurückschreiben von Dateien auf die Festplatte beschleunigen und die Operation sicherer machen. Außerdem können Sie mit dem Unix-Befehl hdparm das Caching von Festplatten-Schreibvorgängen in Hardware-Caches deaktivieren oder einen anderen Hardware-spezifischen Befehl verwenden.

  • innodb_flush_method

    Die Standardeinstellung fdatasync sorgt dafür, dass InnoDB Daten- und Logdateien mit fsync() auf die Festplatte schreibt. Die Einstellung O_DSYNC lässt InnoDB Logdateien mit O_SYNC öffnen und auf die Festplatte schreiben, aber für Datendateien fsync() verwenden. Die (auf einigen GNU/Linux-Versionen mögliche) Einstellung O_DIRECT veranlasst InnoDB, Datendateien mit O_DIRECT zu öffnen und Daten- und Logdateien mit fsync() auf die Festplatte schreiben. Beachten Sie, dass InnoDB die Funktion fsync() anstelle von fdatasync() benutzt und O_DSYNC nicht standardmäßig einsetzt, weil dies mit vielen Unix-Varianten bereits zu Problemen geführt hat. Diese Variable ist nur für Unix relevant. Auf Windows wird immer und unabänderlich async_unbuffered zum Zurückschreiben von Daten auf die Festplatte verwendet.

  • innodb_force_recovery

    Der Crash-Recovery-Modus. Warnung: Diese Variable sollte nur im Notall, wenn Tabellen aus einer beschädigten Datenbank gesichert werden sollen, auf 0 gesetzt werden! Die Bedeutung der möglichen Werte 1 bis 6 wird in Abschnitt 14.2.8.1, „Erzwingen einer InnoDB-Wiederherstellung (Recovery)“ erläutert. Als Sicherheitsmaßnahme verhindert InnoDB alle Änderungen an Daten, wenn diese Variable größer als 0 ist.

  • innodb_lock_wait_timeout

    Gibt an, wie viele Sekunden eine InnoDB-Transaktion auf eine Sperre wartet, ehe sie zurückgerollt wird. InnoDB entdeckt automatisch Transaktions-Deadlocks in seiner eigenen Sperrentabelle und macht dann die Transaktion rückgängig. InnoDB erkennt Sperren, die mit der LOCK TABLES-Anweisung gesetzt wurden. Die Standardeinstellung beträgt 50 Sekunden.

    Hinweis: Die größtmögliche Dauerhaftigkeit und Konsistenz in einer Replikationsumgebung mit InnoDB und Transaktionen erzielen Sie, wenn Sie in der my.cnf-Datei Ihres Masterservers innodb_flush_log_at_trx_commit=1 und sync_binlog=1 einstellen.

  • innodb_locks_unsafe_for_binlog

    Diese Variable steuert Next-Key-Locking in InnoDB-Suchoperationen und Index-Scans. Standardmäßig ist diese Variable 0 (deaktiviert) und das Next-Key-Locking somit eingeschaltet.

    Normalerweise benutzt InnoDB einen Algorithmus namens Next-Key-Locking. Zeilensperren funktionieren in InnoDB folgendermaßen: Wenn ein Tabellenindex durchsucht oder gescannt wird, errichtet InnoDB Shared oder exklusive Sperren auf allen gefundenen Indexeinträgen. Somit sind die Zeilensperren in Wirklichkeit Sperren auf Indexeinträgen. Diese Sperren betreffen auch die „Lücke“, die den Indexeinträgen vorausgeht. Wenn ein Benutzer eine Shared oder exklusive Sperre auf Eintrag R eines Index hat, können andere Benutzer keine neuen Indexeinträge unmittelbar vor R in diesen Index einfügen. Ist diese Variable eingeschaltet, wird Next-Key-Locking von InnoDB nicht nicht in Suchoperationen oder Index-Scans verwendet, wohl aber zur Sicherung von Fremdschlüssel-Constraints und Prüfung auf Schlüsselduplikate. Das Einschalten dieser Variablen kann Phantomprobleme verursachen: Angenommen, Sie möchten alle Kinder der child-Tabelle, die einen Identifier-Wert größer 100 haben, lesen und sperren, da Sie vorhaben, in den ausgewählten Zeilen später eine Spalte zu ändern:

    SELECT * FROM child WHERE id > 100 FOR UPDATE;
    

    Nehmen wir weiterhin an, auf der Spalte id ist ein Index definiert. Die Anfrage scannt diesen Index ab dem ersten Eintrag, in dem id größer als 100 ist. Wenn die auf den Indexeinträgen errichteten Sperren Einfügungen in den Lücken nicht ausschließen, kann ein anderer Client eine neue Zeile in die Tabelle einfügen. Wenn Sie dasselbe SELECT in derselben Transaktion ausführen, sehen Sie in der Ergebnismenge eine neue Zeile. Das führt auch dazu, dass InnoDB bei Einfügung neuer Elemente in die Datenbank keine Serialisierbarkeit garantieren kann. Folglich gewährleistet InnoDB bei Einschaltung dieser Variablen maximal die Isolationsebene READ COMMITTED. (Die Konfliktserialisierbarkeit ist aber nach wie vor garantiert.)

    Die Einschaltung dieser Variablen hat noch einen Zusatzeffekt: InnoDB sperrt in einem UPDATE oder DELETE nur die Zeilen, die aktualisiert bzw. gelöscht werden. Dadurch werden Deadlocks zwar sehr unwahrscheinlich, können aber immer noch auftreten. Beachten Sie, dass das Einschalten dieser Variablen nach wie vor nicht erlaubt, dass UPDATE andere, ähnliche Operationen (wie etwa ein anderes UPDATE) übernimmt, selbst dann nicht, wenn die beiden Operationen unterschiedliche Zeilen betreffen. Betrachten Sie das nächste Beispiel, das mit folgender Tabelle beginnt:

    CREATE TABLE A(A INT NOT NULL, B INT) ENGINE = InnoDB;
    INSERT INTO A VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
    COMMIT;
    

    Angenommen, ein Client führt folgende Anweisungen aus:

    SET AUTOCOMMIT = 0;
    UPDATE A SET B = 5 WHERE B = 3;
    

    Nehmen wir weiterhin an, dass danach ein anderer Client diese Anweisungen ausführt:

    SET AUTOCOMMIT = 0;
    UPDATE A SET B = 4 WHERE B = 2;
    

    In diesem Fall muss das zweite UPDATE auf ein Commit oder Rollback des ersten warten. Das erste UPDATE besitzt eine exklusive Sperre auf Zeile (2,3) und das zweite UPDATE versucht, während es die Zeilen scannt, für dieselbe Zeile ebenfalls eine Sperre zu erwerben, die es jedoch nicht bekommt. Das liegt daran, dass das zweite UPDATE zuerst eine exklusive Sperre auf einer Zeile erwirbt und dann feststellt ob diese Zeile zur Ergebnismenge gehört. Wenn nicht, gibt es die überflüssige Sperre wieder frei, sofern die Variable innodb_locks_unsafe_for_binlog eingeschaltet ist.

    Also führt InnoDB das UPDATE Nummer eins folgendermaßen aus:

    x-lock(1,2)
    unlock(1,2)
    x-lock(2,3)
    update(2,3) to (2,5)
    x-lock(3,2)
    unlock(3,2)
    x-lock(4,3)
    update(4,3) to (4,5)
    x-lock(5,2)
    unlock(5,2)
    

    Das zweite UPDATE führt InnoDB so aus:

    x-lock(1,2)
    update(1,2) to (1,4)
    x-lock(2,3) - wait for query one to commit or rollback
    
  • innodb_log_arch_dir

    Das Verzeichnis, in dem vollgeschriebene Logdateien archiviert werden, sofern die Archivierung von Logs eingeschaltet ist. Wenn ja, so sollte diese Variable auf denselben Wert wie innodb_log_group_home_dir gesetzt werden. Das ist jedoch nicht obligatorisch.

  • innodb_log_archive

    Gibt an, ob InnoDB-Archivdateien protokolliert werden sollen. Diese Variable ist nur aus historischen Gründen noch vorhanden, wird aber nicht benutzt. Da MySQL die Backup-Recovery anhand seiner eigenen Logdateien durchführt, gibt es keinen Anlass, InnoDB-Logdateien zu archivieren. Die Variable hat den Standardwert 0.

  • innodb_log_buffer_size

    Gibt in Bytes die Größe des Puffers an, den InnoDB benutzt, um Logdateien auf die Platte zu schreiben. Werte von 1MB bis 8MB sind hier annehmbar. Der Standardwert ist 1MB. Wenn Sie einen großen Logpuffer haben, können umfangreiche Transaktionen zuende laufen, ohne dass das Log vor dem Committen auf die Festplatte zurückgeschrieben werden muss. In einer Umgebung mit großen Transaktionen können Sie also Festplattenzugriffe reduzieren, indem Sie den Logpuffer vergrößern.

  • innodb_log_file_size

    Die Größe jeder Logdatei einer Loggruppe in Bytes. Die kombinierte Größe der Logdateien muss auf 32-Bit-Rechnren weniger als 4GB sein. Der Standard ist 5MB. Annehmbar sind Werte zwischen 1MB und 1/N-tel der Größe des Bufferpools, wobei N die Anzahl der Dateien in einer Loggruppe ist. Je größer der Wert, umso weniger Checkpoint-Flushing ist im Bufferpool erforderlich, was wiederum Plattenzugriffe spart. Allerdings haben große Logdateien auch zur Folge, dass die Recovery nach einem Absturz langsamer läuft.

  • innodb_log_files_in_group

    Die Anzahl der Logdateien in der Loggruppe. InnoDB benutzt die Dateien in zirkulärer Weise. Der (empfehlenswerte) Standardwert ist 2.

  • innodb_log_group_home_dir

    Der Verzeichnispfad zu den InnoDB-Logdateien. Er muss denselben Wert haben wie innodb_log_arch_dir. Wenn Sie keine InnoDB-Logvariablen angeben, werden nach Voreinstellung zwei 5MB große Dateien namens ib_logfile0 und ib_logfile1 im MySQL Data Directory angelegt.

  • innodb_max_dirty_pages_pct

    Ein Integer von 0 bis 100. Der Standardwert ist 90. Der Haupt-Thread in InnoDB versucht, Seiten aus dem Bufferpool derart zu schreiben, dass der Prozentsatz von noch nicht geschriebenen Seiten diesen Wert nicht übersteigt.

  • innodb_max_purge_lag

    Diese Variable gibt an, wie lange INSERT-, UPDATE- und DELETE-Operationen aufgeschoben werden, wenn die Purge-Operationen hinterher hinken (siehe Abschnitt 14.2.12, „Implementierung der Multiversionierung“). Der Standardwert ist 0 (keine Verzögerungen).

    Das Transaktionssystem von InnoDB pflegt eine Liste von Transaktionen, die Indexeinträge anhand von UPDATE- oder DELETE-Operationen zum Löschen vorgemerkt haben. Die Länge dieser Liste sei purge_lag. Wenn purge_lag den Wert innodb_max_purge_lag überschreitet, wird jede INSERT-, UPDATE- und DELETE-Operation um ((purge_lag/innodb_max_purge_lag)×10)–5 Millisekunden aufgeschoben. Diese Verzögerung wird alle zehn Sekunden am Anfang eines Purge-Batch berechnet. Die Operationen werden nicht aufgeschoben, wenn Purge nicht laufen kann, weil eine alte Consistent Read View die zu bereinigenden Zeilen sehen könnte.

    Eine typische Einstellung für eine problematische Arbeitslast wäre 1 Million, wenn die Transaktionen nur etwa 100 Bytes klein sind und wir 100MB unbereinigte Zeilen in unseren Tabellen gestatten können.

  • innodb_mirrored_log_groups

    Gibt an, wie viele identische Kopien von Loggruppen wir für die Datenbank bewahren. Zurzeit sollte dies auf 1 gesetzt werden.

  • innodb_open_files

    Diese Variable ist nur dann von Belang, wenn Sie Multi-Tablespaces in InnoDB benutzen. Sie gibt an, wie viele .ibd-Dateien InnoDB höchstens gleichzeitig offen halten kann. Der Mindestwert ist 10 und der Standardwert 300.

    Die für .ibd-Dateien verwendeten Dateideskriptoren sind ausschließlich für InnoDB da. Sie haben nichts mit der Serveroption --open-files-limit zu tun und beeinflussen nicht die Arbeit des Tabellen-Caches.

  • innodb_support_xa

    Die Einstellung ON oder 1 (der Standard) schaltet die InnoDB-Unterstützung für zweiphasigen Commit in XA-Transaktionen ein. Die Aktivierung von innodb_support_xa verursacht eine zusätzliche Schreiboperation auf der Platte zur Vorbereitung der Transaktion. Wenn Sie sich für XA nicht interessieren, können Sie diese Variable mit der Einstellung OFF oder 0 deaktivieren, was die Schreibvorgänge auf der Festplatte reduziert und die InnoDB-Performance erhöht.

  • innodb_sync_spin_loops

    Gibt an, wie oft ein Thread auf die Freigabe eines InnoDB-Mutex wartet, ehe er suspendiert wird.

  • innodb_table_locks

    InnoDB beachtet LOCK TABLES; MySQL kehrt von LOCK TABLE .. WRITE erst zurück, wenn alle anderen Threads alle ihre Sperren auf der Tabelle freigegeben haben. Der Standardwert 1 bedeutet, dass LOCK TABLES InnoDB veranlasst, eine Tabelle intern zu sperren. In Anwendungen mit AUTOCOMMIT=1 können die internen Tabellensperren von InnoDB Deadlocks verursachen. Sie können innodb_table_locks=0 in der Datei der Serveroptionen einstellen, um dieses Problem zu beheben.

  • innodb_thread_concurrency

    InnoDB versucht, die Anzahl der nebenläufigen Betriebssystem-Threads innerhalb von InnoDB kleiner oder gleich dem in dieser Variablen festgelegten Höchstwert zu halten. Wenn Sie Performance-Probleme haben und SHOW ENGINE INNODB STATUS zeigt, dass viele Threads auf Semaphoren warten, haben Sie es vielleicht mit Thread-„Überlastung“ zu tun. In diesem Fall setzen sie diese Variable herunter oder herauf. Wenn Ihr Computer über viele Prozessoren und Festplatten verfügt, können Sie diesen Wert heraufsetzen, um Ihre Ressourcen besser auszunutzen. Ein empfehlenswerter Wert ist die Summe der Prozessoren und Festplatten, über die Ihr System verfügt. Beträgt der Wert 500 oder mehr, wird die Nebenläufigkeitsprüfung deaktiviert. Der Standardwert ist 20 und die Nebenläufigkeitsprüfung wird deaktiviert, wenn er auf größer oder gleich 20 eingestellt wird.

  • innodb_thread_sleep_delay

    Gibt in Mikrosekunden an, wie lange InnoDB-Threads schlafen, bevor sie in die InnoDB-Schlange eintreten. Der Standardwert ist 10.000. Der Wert 0 schaltet den Schlaf aus.

  • sync_binlog

    Hat diese Variable einen positiven Wert, synchronisiert der MySQL-Server sein Binärlog nach jedem sync_binlogten Schreibvorgang mittels fdatasync() auf die Festplatte. Im Autocommit-Modus entsteht pro Anweisung und ansonsten pro Transaktion ein Eintrag ins Binärlog. Der Standardwert 0 veranlasst keine Festplatten-Synchronisierung. Der Wert 1 ist am sichersten, da bei einem Absturz nur maximal eine Anweisung/Transaktion aus dem Binärlog verloren geht. Er ist aber auch am langsamsten (sofern nicht die Festplatte einen batteriegestützten Cache hat; dies würde die Synchronisierung sehr schnell machen).

14.2.5. InnoDB-Tablespace erzeugen

Angenommen, Sie haben MySQL installiert und die notwendigen Konfigurationsparameter für InnoDB in die Konfigurationsdatei geschrieben. Bevor Sie MySQL nun starten, müssen Sie überprüfen, ob die Verzeichnisse vorhanden sind, die Sie für InnoDB-Daten- und Logdateien angegeben haben, und ob der MySQL-Server Zugriffsrechte für diese Verzeichnisse hat. InnoDB legt keine Verzeichnisse, sondern nur Dateien an. Prüfen Sie außerdem, ob Sie genug Platz auf der Festplatte haben, um die Daten- und Logdateien zu speichern.

Wenn Sie Ihren MySQL-Server mit eingeschaltetem InnoDB starten, führen Sie mysqld am besten auf der Kommandozeile und nicht mit dem Wrapper mysqld_safe oder als Windows-Dienst aus. Dann können Sie nämlich die Ausgabe von mysqld sehen und erkennen, was passiert. Auf Unix rufen Sie einfach nur mysqld auf und auf Windows verwenden Sie dafür die --console-Option.

Wenn Sie MySQL-Server zum ersten Mal starten, nachdem Sie InnoDB in Ihrer Optionsdatei konfiguriert haben, erzeugt InnoDB Ihre Daten- und Logdateien und gibt in etwa folgendes aus:

InnoDB: The first specified datafile /home/heikki/data/ibdata1
did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file /home/heikki/data/ibdata1 size to 134217728
InnoDB: Database physically writes the file full: wait...
InnoDB: datafile /home/heikki/data/ibdata2 did not exist:
new to be created
InnoDB: Setting file /home/heikki/data/ibdata2 size to 262144000
InnoDB: Database physically writes the file full: wait...
InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist:
new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile0 size
to 5242880
InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist:
new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile1 size
to 5242880
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
InnoDB: Started
mysqld: ready for connections

Jetzt hat InnoDB seinen Tablespace und seine Logdateien initialisiert. Sie können mit dem MySQL-Server über die üblichen MySQL-Clientprogramme wie mysql Verbindung aufnehmen. Wenn Sie den MySQL-Server mit mysqladmin shutdown herunterfahren, wird folgendes ausgegeben:

010321 18:33:34  mysqld: Normal shutdown
010321 18:33:34  mysqld: Shutdown Complete
InnoDB: Starting shutdown...
InnoDB: Shutdown completed

Sie können die Datendatei und Logverzeichnisse anschauen und die darin erstellten Dateien erkennen. Das Logverzeichnis enthält außerdem eine kleine Datei namens ib_arch_log_0000000000, die infolge der Datenbankerstellung entstanden ist, nachdem InnoDB die Logarchivierung abgeschaltet hat. Wenn MySQL erneut gestartet wird, sind die Daten- und Logdateien bereits vorhanden, sodass die Ausgabe viel knapper ausfällt:

InnoDB: Started
mysqld: ready for connections

Wenn Sie die innodb_file_per_table-Option in my.cnf hinzufügen, speichert InnoDB jede Tabelle in einer eigenen .ibd-Datei in demselben MySQL-Datenbankverzeichnis, in dem auch die .frm-Datei angelegt wurde. Siehe Abschnitt 14.2.3.1, „Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)“.

14.2.5.1. Falls etwas bei der Datenbankerzeugung schiefgeht

Wenn InnoDB während einer Dateioperation einen Betriebssystemfehler ausgibt, hat das Problem in der Regel eine der folgenden Ursachen:

  • Sie haben das InnoDB-Datendatei- oder Logverzeichnis nicht angelegt.

  • mysqld verfügt nicht über die notwendigen Berechtigungen, um Dateien in diesen Verzeichnissen anlegen zu können.

  • mysqld kann die richtige my.cnf- oder my.ini-Optionsdatei nicht lesen und weiß deshalb nicht, welche Optionen Sie angegeben haben.

  • Die Festplatte ist voll oder das Plattenkontingent überschritten.

  • Da Sie ein Unterverzeichnis angelegt haben, das genauso heißt wie die Datendatei, kann der Name nicht als Dateiname verwendet werden..

  • Ein Syntaxfehler hat sich in den Wert von innodb_data_home_dir oder innodb_data_file_path eingeschlichen.

Wenn InnoDB beim Versuch scheitert, seinen Tablespace oder seine Logdateien zu initialisieren, sollten Sie alle von InnoDB erzeugten Dateien löschen. Dazu gehören alle ibdata-Dateien und alle ib_logfile-Dateien. Falls Sie bereits InnoDB-Tabellen angelegt haben, müssen Sie auch die .frm-Dateien (und, wenn Sie Multi-Tablespaces benutzen, die .ibd-Dateien) aus den MySQL-Datenbankverzeichnissen löschen. Danach können Sie erneut versuchen, die InnoDB-Datenbank anzulegen. Am besten starten Sie den MySQL-Server von einer Kommandozeile, um erkennen zu können, was geschieht.

14.2.6. InnoDB-Tabellen erzeugen

Um eine InnoDB-Tabelle zu erzeugen, müssen Sie die ENGINE = InnoDB-Option in der CREATE TABLE-Anweisung angeben:

CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) ENGINE=InnoDB;

Der ältere Begriff TYPE wird als Synonym für ENGINE aus Gründen der Abwärtskompatibilität zwar weiter unterstützt, aber ENGINE ist der bessere Begriff, während TYPE veraltet ist.

Die Anweisung erzeugt eine Tabelle und einen Index auf der Spalte a im InnoDB-Tablespace, der aus den in my.cnf angegebenen Datendateien besteht. Außerdem legt MySQL die Datei customers.frm im Verzeichnis test an, das ein Unterverzeichnis des MySQL-Datenbankverzeichnisses ist. Intern fügt InnoDB in das Data Dictionary einen Eintrag für diese Tabelle ein, der den Datenbanknamen enthält. Wenn beispielsweise test die Datenbank ist, in der die customers-Tabelle angelegt wurde, heißt der Eintrag 'test/customers'. Das bedeutet, dass Sie in einer anderen Datenbank eine gleichnamige customers-Tabelle anlegen können, ohne dass es in InnoDB zu Namenskonflikten kommt.

Wieviel Platz im InnoDB-Tablespace noch frei ist, sagt Ihnen eine SHOW TABLE STATUS-Anweisung für irgendeine InnoDB-Tabelle. Der freie Platz im Tablespace wird im Abschnitt Comment der Ausgabe von SHOW TABLE STATUS angezeigt, beispielsweise:

SHOW TABLE STATUS FROM test LIKE 'customers'

Beachten Sie, dass die Statistikdaten, die SHOW für InnoDB-Tabellen anzeigt, nur Näherungswerte sind. Sie werden für die SQL-Optimierung eingesetzt. Doch die reservierten Größen für Tabellen und Indizes in Bytes werden präzise angegeben.

14.2.6.1. Benutzung von Transaktionen in InnoDB mit verschiedenen APIs

Standardmäßig startet jeder Client, der sich mit dem MySQL-Server verbindet, mit eingeschaltetem Autocommit-Modus. Das bedeutet, dass jede SQL-Anweisung direkt bei der Ausführung automatisch in der Datenbank festgeschrieben wird. Um Transaktionen zu verwenden, die aus mehreren Anweisungen bestehen, schalten Sie Autocommit mit der SQL-Anweisung SET AUTOCOMMIT = 0 aus und verwenden COMMIT und ROLLBACK, um Ihre Transaktionen zu committen oder zurückzurollen. Wenn Sie Autocommit eingeschaltet lassen möchten, können Sie Ihre Transaktionen zwischen START TRANSACTION und entweder COMMIT oder ROLLBACK einschließen. Das folgende Beispiel zeigt zwei Transaktionen: Die erste wird committet und die zweite zurückgerollt.

shell> mysql test

mysql> CREATE TABLE CUSTOMER (A INT, B CHAR (20), INDEX (A))
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO CUSTOMER VALUES (10, 'Heikki');
Query OK, 1 row affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SET AUTOCOMMIT=0;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO CUSTOMER VALUES (15, 'John');
Query OK, 1 row affected (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM CUSTOMER;
+------+--------+
| A    | B      |
+------+--------+
|   10 | Heikki |
+------+--------+
1 row in set (0.00 sec)
mysql>

In APIs wie PHP, Perl DBI, JDBC, ODBC oder der Standardschnittstelle für C-Aufrufe von MySQL können Sie Anweisungen zur Transaktionssteuerung wie etwa COMMIT wie alle anderen SQL-Anweisungen, beispielsweise SELECT oder INSERT, als Strings an den MySQL-Server senden. Manche APIs bieten auch eigene, spezielle Transaktionsfunktionen oder -methoden für Commit und Rollback.

14.2.6.2. MyISAM-Tabellen in InnoDB-Tabellen umwandeln

Wichtig: Bitte konvertieren Sie keine Systemtabellen von MySQL in der mysql-Datenbank (wie etwa user oder host) in den Typ InnoDB. Diese Operation wird nicht unterstützt. Die Systemtabellen müssen immer den Typ MyISAM haben.

Wenn Sie alle Tabellen (außer den Systemtabellen) als InnoDB-Tabellen anlegen möchten, fügen Sie einfach die Zeile default-storage-engine=innodb in den [mysqld]-Abschnitt Ihrer Serveroptionsdatei ein.

InnoDB kennt im Gegensatz zu MyISAM keine spezielle Optimierung für eine separate Indexerstellung. Daher lohnt es sich nicht, zuerst die Tabellen zu exportieren und importieren und danach die Indizes anzulegen. Der schnellste Weg, eine Tabelle in InnoDB zu ändern, besteht darin, die Einfügeoperationen direkt auf der InnoDB-Tabelle vorzunehmen. Verwenden Sie also ALTER TABLE … ENGINE=INNODB oder erzeugen Sie eine leere InnoDB-Tabelle mit denselben Definitionen und fügen Sie darin die Zeilen mit INSERT INTO … SELECT * FROM … ein.

Wenn Sie UNIQUE-Constraints auf Sekundärschlüsseln haben, können Sie einen Tabellenimport beschleunigen, indem Sie die Eindeutigkeitsprüfungen während der Importoperation vorübergehend abschalten:

SET UNIQUE_CHECKS=0;
... import operation ...
SET UNIQUE_CHECKS=1;

Bei großen Tabellen spart das eine Menge Festplattenzugriffe, da InnoDB dann seinen Insert-Puffer nutzen kann, um die Sekundärindexeinträge in einer Batch-Operation zu schreiben.

Um eine bessere Kontrolle über den Einfügungsprozess zu haben, ist es manchmal besser, Daten einer großen Tabelle in Stücken einzufügen:

INSERT INTO newtable SELECT * FROM oldtable
   WHERE yourkey > something AND yourkey <= somethingelse;

Wenn alle Datensätze eingefügt wurden, können Sie die Tabellen umbenennen.

Während der Konvertierung großer Tabellen sollten Sie den InnoDB-Bufferpool vergrößern, damit weniger Plattenzugriffe erforderlich sind. Reservieren Sie jedoch nicht mehr als 80% des physikalischen Arbeitsspeichers. Sie können auch die InnoDB-Logdateien vergrößern.

Achten Sie darauf, dass der Tablespace nicht vollläuft: InnoDB-Tabellen brauchen auf der Festplatte viel mehr Speicherplatz als MyISAM-Tabellen. Wenn einer ALTER TABLE-Operation der Platz ausgeht, startet sie ein Rollback, und das kann Stunden dauern, wenn es an die Festplatte gebunden ist. Bei Inserts nutzt InnoDB den Insert-Puffer, um Sekundärindexeinträge in Batches mit dem Index zusammenzuführen. Das spart viele Schreiboperationen auf der Festplatte. Da für den Rollback kein solcher Mechanismus existiert, kann dieser 30-mal länger als die Einfügeoperationen dauern.

Wenn ein Rollback-Prozess außer Kontrolle gerät und Sie keine wertvollen Daten in Ihrer Datenbank haben, ist es manchmal ratsam, den Datenbankprozess anzuhalten, anstatt Millionen von Lese/Schreiboperationen auf der Festplatte abzuwarten. Den gesamten Vorgang können Sie unter Abschnitt 14.2.8.1, „Erzwingen einer InnoDB-Wiederherstellung (Recovery)“ nachlesen.

14.2.6.3. Wie eine Auto-Increment-Spalte in InnoDB funktioniert

Wenn Sie eine AUTO_INCREMENT-Spalte für eine InnoDB-Tabelle definieren, enthält der Tabellen-Handle im InnoDB-Data Dictionary einen speziellen Zähler namens Auto-Increment-Zähler, der zur Zuweisung neuer Werte zu dieser Spalte benutzt wird. Dieser Zähler wird nur im Arbeitsspeicher und nicht auf der Festplatte gespeichert.

InnoDB initialisiert den Auto-Increment-Zähler für eine Tabelle T, die eine AUTO_INCREMENT-Spalte namens ai_col enthält, wie folgt: Nach dem Serverstart führt InnoDB für die erste Einfügung in die Tabelle T das Äquivalent folgender Anweisung aus:

SELECT MAX(ai_col) FROM T FOR UPDATE;

InnoDB inkrementiert den von der Anweisung abgerufenen Wert um eins und weist ihn der Spalte und dem Auto-Increment-Zähler für die Tabelle zu. Ist die Tabelle leer, verwendet InnoDB den Wert 1. Wenn ein Benutzer eine SHOW TABLE STATUS-Anweisung gibt, die Ausgabe für die Tabelle T anzeigt, und der Auto-Increment-Zähler noch nicht initialisiert wurde, nimmt InnoDB die Initialisierung vor, inkrementiert aber nicht den Wert und speichert ihn nicht für spätere Einfügeoperationen. Beachten Sie, dass für diese Initialisierung eine normale Schreiboperation mit exklusiver Sperre auf der Tabelle ausgeführt wird und die Sperre bis zum Ende der Transaktion aufrecht erhalten bleibt.

Genauso geht InnoDB vor, wenn ein Auto-Increment-Zähler für eine neu erzeugte Tabelle initialisiert wird.

Wenn ein Auto-Increment-Zähler initialisiert wurde und ein Benutzer nicht ausdrücklich einen Wert für eine AUTO_INCREMENT-Spalte angibt, inkrementiert InnoDB den Zähler um eins und weist der Spalte den neuen Wert zu. Wenn der Benutzer eine Zeile einfügt, die den Spaltenwert explizit angibt, und dieser Wert größer als der aktuelle Zähler ist, wird der Zähler auf den angegebenen Spaltenwert gesetzt.

Eventuell treten in der Abfolge der Werte einer AUTO_INCREMENT-Spalte Lücken auf, wenn Sie Transaktionen zurückrollen, die Nummern mithilfe des Zählers zugewiesen haben.

Wenn der Benutzer in einem INSERT den Wert NULL oder 0 für die AUTO_INCREMENT-Spalte angibt, behandelt InnoDB die betreffende Zeile, als wäre überhaupt kein Wert vorhanden, und generiert einen neuen Wert für sie.

Das Verhalten des Auto-Increment-Mechanismus ist nicht definiert, wenn ein Benutzer der Spalte einen negativen Wert zuweist, oder wenn der Wert die größte Ganzzahl übersteigt, die in dem angegebenen Integertyp gespeichert werden kann.

InnoDB benutzt für den Zugriff auf den Auto-Increment-Zähler eine spezielle AUTO-INC-Tabellensperre, die bis zum Ende der laufenden SQL-Anweisung (nicht der Transaktion) gehalten wird. Die spezielle Strategie zum Aufheben der Sperre wurde eingefügt, um die Nebenläufigkeit von Einfügeoperationen in Tabellen mit AUTO_INCREMENT-Spalten zu verbessern. Es können nicht zwei Transaktionen zugleich auf derselben Tabelle eine AUTO-INC-Sperre halten.

InnoDB nutzt den speicherresidenten Auto-Increment-Zähler so lange, wie der Server läuft. Wird der Server angehalten und neu gestartet, initialisiert InnoDB den Zähler bei der ersten INSERT-Operation auf der Tabelle neu, wie oben bereits beschrieben.

InnoDB unterstützt die Tabellenoption AUTO_INCREMENT = N in CREATE TABLE und ALTER TABLE-Anweisungen, um den Anfangswert des Zählers einzustellen oder seinen laufenden Wert zu ändern. Die Wirkung dieser Option wird durch einen Neustart des Servers aufgehoben, und zwar aus Gründen, die bereits weiter oben dargestellt wurden.

14.2.6.4. Fremdschlüssel-Beschränkungen

InnoDB unterstützt auch Fremdschlüssel-Constraints, die in InnoDB mit folgender Syntax definiert werden:

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name, ...)
    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

Für Fremdschlüsseldefinitionen gelten folgende Bedingungen:

  • Beide Tabellen müssen InnoDB-Tabellen sein und dürfen keine TEMPORARY-Tabellen sein.

  • In der referenzierenden Tabelle muss ein Index bestehen, in dem die Fremdschlüsselspalten als erste Spalten in derselben Reihenfolge aufgeführt sind. Ein solcher Index wird automatisch auf der referenzierenden Tabelle angelegt, wenn er noch nicht existiert.

  • In der referenzierten Tabelle muss ein Index bestehen, in dem die referenzierten Spalten als erste Spalten in derselben Reihenfolge aufgeführt sind.

  • Index-Präfixe auf Fremdschlüsselspalten werden nicht unterstützt. Dies hat unter anderem zur Folge, dass BLOB- und TEXT-Spalten nicht in einen Fremdschlüssel eingebunden werden können, da Indizes auf diesen Spalten immer ein Längenpräfix haben müssen.

  • Wenn die CONSTRAINT symbol-Klausel verwendet wird, muss der symbol-Wert in der ganzen Datenbank einzigartig sein. Ist die Klausel nicht angegeben, erstellt InnoDB den Namen automatisch.

InnoDB weist jede INSERT- oder UPDATE-Operation zurück, die versucht, einen Fremdschlüsselwert in einer Kindtabelle anzulegen, wenn kein passender Schlüsselwert in der Elterntabelle vorhanden ist. Was InnoDB mit einer INSERT- oder UPDATE-Operation anfängt, die versucht, in der Elterntabelle einen Schlüsselwert zu ändern oder zu löschen, zu dem in der Kindtabelle passende Zeilen vorhanden sind, hängt davon ab, welche Referenzaktion in den Teilklauseln ON UPDATE und ON DELETE der FOREIGN KEY-Klausel angegeben ist. Wenn der Benutzer versucht, in der Elterntabelle eine Zeile zu ändern oder zu löschen, zu der in der Kindtabelle eine oder mehr passende Zeilen vorhanden sind, bietet InnoDB fünf mögliche Optionen:

  • CASCADE: Bei Löschung/Änderung einer Zeile der Elterntabelle werden automatisch die zugehörigen Zeilen der Kindtabelle auch gelöscht oder geändert. Es gibt sowohl ON DELETE CASCADE als auch ON UPDATE CASCADE. Zwischen zwei Tabellen sollten Sie bitte nicht mehrere ON UPDATE CASCADE-Klauseln definieren, die auf derselben Spalte der Eltern- oder Kindtabelle arbeiten.

  • SET NULL: Bei Löschung/Änderung einer Zeile der Elterntabelle werden automatisch die zugehörigen Fremdschlüsselspalten der Kindtabelle auf NULL gesetzt. Das gilt nur, wenn die Fremdschlüsselspalten nicht als NOT NULL definiert sind. Sowohl ON DELETE SET NULL als auch ON UPDATE SET NULL wird unterstützt.

  • NO ACTION: Im Standard-SQL bedeutet NO ACTION tatsächlich keine Aktion in dem Sinne, dass jeder Versuch, einen Primärschlüssel zu löschen oder zu ändern, unterbunden wird, wenn es dazu einen Fremschlüsselwert in der referenzierten Tabelle gibt. InnoDB weist dann die Lösch- oder Änderungsoperation auf der Elterntabelle zurück.

  • RESTRICT weist die Lösch- oder Änderungsoperation auf der Elterntabelle zurück. NO ACTION und RESTRICT sind dasselbe wie ein Auslassen der ON DELETE- oder ON UPDATE-Klausel. (Manche Datenbanksysteme kennen verzögerte Prüfungen (deferred checks), zu denen auch NO ACTION gehört. Da in MySQL Fremdschlüssel-Constraints jedoch sofort geprüft werden, sind NO ACTION und RESTRICT hier dasselbe.)

  • SET DEFAULT: Diese Aktion wird zwar vom Parser anerkannt, aber InnoDB weist Tabellendefinitionen mit ON DELETE SET DEFAULT- oder ON UPDATE SET DEFAULT-Klauseln zurück.

Beachten Sie, dass InnoDB Fremdschlüsselreferenzen in einer Tabelle unterstützt. In solchen Fällen sind „Datensätze der Kindtabelle“ in Wirklichkeit abhängige Datensätze in derselben Tabelle.

Da InnoDB Indizes auf Fremdschlüsseln und referenzierten Schlüsseln verlangt, können Fremdschlüsselprüfungen schnell durchgeführt werden und erfordern keinen Tabellen-Scan. Der Index auf den Fremdschlüsseln wird automatisch angelegt. Das war in manchen älteren Versionen anders, wo Indizes explizit angelegt werden mussten, da sonst keine Fremdschlüssel-Constraints angelegt werden konnten.

Zusammengehörige Spalten im Fremdschlüssel und referenzierten Schlüssel müssen in InnoDB ähnliche Datentypen haben, damit sie sich ohne Typkonvertierung vergleichen lassen. Die Größe und das Vorzeichen von Integer-Typen müssen gleich sein. Die Länge von String-Typen muss nicht unbedingt identisch sein. Wenn Sie SET NULL verlangen, dürfen die Spalten der Kindtabelle nicht als NOT NULL deklariert sein.

Wenn MySQL die Fehlernummer 1005 aus einer CREATE TABLE-Anweisung meldet und die Fehlermeldung sich auf Fehlernummer 150 bezieht, schlug die Tabellenerstellung fehl, weil ein Fremdschlüssel-Constraint nicht wohlgeformt war. Wenn ein ALTER TABLE scheitert und auf Fehlernummer 150 verweist, bedeutet dies, dass eine Fremdschlüsseldefinition für die geänderte Tabelle nicht korrekt war. Die Anweisung SHOW ENGINE INNODB STATUS zeigt eine detaillierte Erklärung des letzten InnoDB-Fremdschlüsselfehlers im Server an.

Hinweis: InnoDB prüft Fremdschlüssel-Constraints nicht auf Fremdschlüsseln oder referenzierten Schlüsseln, die eine NULL-Spalte enthalten.

Hinweis: Trigger werden von kaskadierenden Fremdschlüsselaktionen derzeit nicht aktiviert.

Abweichung von SQL-Standards: Wenn mehrere Zeilen in der Elterntabelle denselben Referenzschlüsselwert haben verhält sich InnoDB bei Fremdschlüsselprüfungen so, als würden die anderen Zeilen der Elterntabelle, also die mit demselben Schlüsselwert, gar nicht vorhanden. Wenn Sie beispielsweise einen RESTRICT-Typ-Constraint definiert haben und es eine Kindzeile mit mehreren Elternzeilen gibt, verbietet InnoDB das Löschen irgendeiner dieser Elternzeilen.

InnoDB führt kaskadierende Operationen mit einem Depth-First-Algorithmus durch, beruhend auf Einträgen in den Indizes, die zu den Fremdschlüssel-Constraints gehören.

Abweichung von SQL-Standards: Ein FOREIGN KEY-Constraint, der einen Nicht-UNIQUE-Schlüssel referenziert, ist nicht Standard-SQL, sondern eine InnoDB-Erweiterung dieses Standards.

Abweichung von SQL-Standards: Wenn ON UPDATE CASCADE oder ON UPDATE SET NULL rekursiv dieselbe Tabelle ändert, die zuvor während der kaskadierenden Änderung auch bereits aktualisiert wurde, verhält es sich wie RESTRICT. Sie können also keine rückbezüglichen ON UPDATE CASCADE- oder ON UPDATE SET NULL-Operationen ausführen. Dadurch sollen Endlosschleifen wegen kaskadierender Updates verhindert werden. Andererseits ist ein rückbezügliches ON DELETE SET NULL jedoch möglich, nämlich als rückbezügliches ON DELETE CASCADE. Die maximale Schachtelungstiefe von kaskadierenden Operationen beträgt 15 Ebenen.

Abweichung von SQL-Standards: Wie immer in MySQL prüft InnoDB für jede SQL-Anweisung, die viele Zeilen einfügt, löscht oder ändert, die UNIQUE- und FOREIGN KEY-Constraints zeilenweise. Nach dem SQL-Standard sollte eigentlich eine verzögerte Prüfung vorgenommen werden, bei der Constraints erst nach der Verarbeitung der gesamten SQL-Anweisung geprüft werden. Bis die verzögerte Constraint-Prüfung auch in InnoDB implementiert ist, werden einige Dinge nicht möglich sein, etwa das Löschen eines Datensatzes, der sich über einen Fremdschlüssel auf sich selbst bezieht.

In dem folgenden einfachen Beispiel sind parent- und child-Tabellen über einen Einzelspalten-Fremdschlüssel verbunden:

CREATE TABLE parent (id INT NOT NULL,
                    PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
                   INDEX par_ind (parent_id),
                   FOREIGN KEY (parent_id) REFERENCES parent(id)
                     ON DELETE CASCADE
) ENGINE=INNODB;

Das folgende, komplexere Beispiel zeigt eine product_order-Tabelle, die Fremdschlüssel für zwei andere Tabellen besitzt. Ein Fremdschlüssel referenziert einen Zwei-Spalten-Index in der product-Tabelle und der andere einen Ein-Spalten-Index in der customer-Tabelle:

CREATE TABLE product (category INT NOT NULL, id INT NOT NULL,
                      price DECIMAL,
                      PRIMARY KEY(category, id)) ENGINE=INNODB;
CREATE TABLE customer (id INT NOT NULL,
                      PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE product_order (no INT NOT NULL AUTO_INCREMENT,
                      product_category INT NOT NULL,
                      product_id INT NOT NULL,
                      customer_id INT NOT NULL,
                      PRIMARY KEY(no),
                      INDEX (product_category, product_id),
                      FOREIGN KEY (product_category, product_id)
                        REFERENCES product(category, id)
                        ON UPDATE CASCADE ON DELETE RESTRICT,
                      INDEX (customer_id),
                      FOREIGN KEY (customer_id)
                        REFERENCES customer(id)) ENGINE=INNODB;

InnoDB ermöglicht es, mit ALTER TABLE einer Tabelle einen Fremdschlüssel-Constraint hinzuzufügen:

ALTER TABLE tbl_name
    ADD [CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name, ...)
    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

Bitte legen Sie immer zuerst die erforderlichen Indizes an. Sie können einer Tabelle mit ALTER TABLE auch einen rückbezüglichen Fremdschlüssel-Constraint hinzufügen.

InnoDB ermöglicht es überdies, mit ALTER TABLE Fremdschlüssel zu löschen:

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

Wenn die FOREIGN KEY-Klausel bei der Erzeugung des Fremdschlüssels einen CONSTRAINT-Namen enthielt, können Sie beim Löschen dieses Fremdschlüssels denselben Namen nennen. Ansonsten wird beim Anlegen des Fremdschlüssels intern ein fk_symbol-Wert generiert. Um zum Löschen eines Fremdschlüssels diesen Symbolwert zu ermitteln, dient die SHOW CREATE TABLE-Anweisung. Ein Beispiel:

mysql> SHOW CREATE TABLE ibtest11c\G
*************************** 1. row ***************************
       Table: ibtest11c
Create Table: CREATE TABLE `ibtest11c` (
  `A` int(11) NOT NULL auto_increment,
  `D` int(11) NOT NULL default '0',
  `B` varchar(200) NOT NULL default '',
  `C` varchar(175) default NULL,
  PRIMARY KEY  (`A`,`D`,`B`),
  KEY `B` (`B`,`C`),
  KEY `C` (`C`),
  CONSTRAINT `0_38775` FOREIGN KEY (`A`, `D`)
REFERENCES `ibtest11a` (`A`, `D`)
ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `0_38776` FOREIGN KEY (`B`, `C`)
REFERENCES `ibtest11a` (`B`, `C`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARSET=latin1
1 row in set (0.01 sec)

mysql> ALTER TABLE ibtest11c DROP FOREIGN KEY `0_38775`;

Sie können einen Fremdschlüssel nicht in separaten Klauseln derselben ALTER TABLE-Anweisung anlegen und löschen. Hierzu sind zwei getrennte Anweisungen erforderlich.

Der Parser von InnoDB gestattet es, für Tabellen- und Spaltenbezeichner in einer FOREIGN KEY … REFERENCES …-Klausel Backticks als Anführungszeichen zu verwenden. (Alternativ können doppelte Anführungszeichen gesetzt werden, wenn der SQL-Modus ANSI_QUOTES SQL eingeschaltet ist.) Außerdem berücksichtigt der InnoDB-Parser die Einstellung der Systemvariablen lower_case_table_names.

InnoDB gibt die Fremdschlüsseldefinitionen einer Tabelle im Rahmen der SHOW CREATE TABLE-Anweisung zurück:

SHOW CREATE TABLE tbl_name;

mysqldump erstellt ebenfalls die korrekten Definitionen der Tabellen in der Dump-Datei und vergisst dabei auch die Fremdschlüssel nicht.

Die Fremdschlüssel-Constraints einer Tabelle können wie folgt angezeigt werden:

SHOW TABLE STATUS FROM db_name LIKE 'tbl_name';

Die Fremdschlüssel-Constraints stehen in der Comment-Spalte der Ausgabe.

Bei den Fremdschlüsselprüfungen errichtet InnoDB Shared-Sperren auf Zeilenebene auf den relevanten Datensätzen der Kind- oder Elterntabellen. InnoDB prüft die Fremdschlüssel-Constraints sofort und nicht erst beim Committen der Transaktion.

Damit Dump-Dateien, die Fremdschlüsselbeziehungen haben, leichter geladen werden können bindet mysqldump automatisch in die Dump-Ausgabe eine Anweisung ein, die FOREIGN_KEY_CHECKS auf 0 setzt. So entstehen keine Probleme mit Tabellen, die beim Neuladen der Dump-Dateien eigentlich in einer bestimmten Reihenfolge geladen werden müssen. Diese Variable kann auch manuell gesetzt werden:

mysql> SET FOREIGN_KEY_CHECKS = 0;
mysql> SOURCE dump_file_name;
mysql> SET FOREIGN_KEY_CHECKS = 1;

So können Sie die Tabellen in beliebiger Reihenfolge importieren, wenn die Dump-Datei Tabellen enthält, die eigentlich gemäß ihrer Fremdschlüssel nicht richtig geordnet sind. Außerdem wird der Import beschleunigt. Auch in Fällen, wo Sie Fremdschlüssel-Constraints in LOAD DATA- und ALTER TABLE-Operationen ignorieren möchten, kann es sinnvoll sein, FOREIGN_KEY_CHECKS auf 0 zu setzen.

Mit InnoDB können Sie eine durch einen FOREIGN KEY-Constraint referenzierte Tabelle nur löschen, wenn SET FOREIGN_KEY_CHECKS=0 eingestellt wurde. Wenn Sie eine Tabelle löschen, werden die in ihrer Erzeugungsanweisung definierten Constraints mit gelöscht.

Wenn Sie eine gelöschte Tabelle wiederherstellen, muss ihre Definition zu den auf sie bezogenen Fremdschlüssel-Constraints passen. Sie muss die richtigen Spaltennamen und -typen sowie Indizes auf den referenzierten Schlüsseln haben. Ist dies nicht der Fall, gibt MySQL die Fehlernummer 1005 zurück und nennt die Fehlernummer 150 in der Fehlermeldung.

14.2.6.5. InnoDB und MySQL-Replikation

In MySQL funktioniert die Replikation mit InnoDB-Tabellen wie mit MyISAM-Tabellen. Es sind auch Replikationsumgebungen möglich, bei denen der Slave eine andere Speicher-Engine als der Master verwendet. So können Sie beispielsweise Änderungen, die auf dem Master an einer InnoDB-Tabelle vorgenommen werden, in einer MyISAM-Tabelle auf dem Slave replizieren.

Um einen neuen Slave für den Master einzurichten, müssen Sie den InnoDB-Tablespace und die Logdateien sowie die .frm-Dateien der InnoDB-Tabellen kopieren und diese Kopien auf den Slave übertragen. Wenn die Variable innodb_file_per_table eingeschaltet ist, müssen auch die .ibd-Dateien kopiert werden. Wie dies genau geht, erfahren Sie unter Abschnitt 14.2.8, „Sichern und Wiederherstellen einer InnoDB-Datenbank“.

Wenn Sie den Master oder einen vorhandenen Slave herunterfahren, können Sie ein kaltes Backup des InnoDB-Tablespace und der Logdateien erstellen und damit einen Slave einrichten. Um einen neuen Slave aufzusetzen, ohne gleich den Server herunterzufahren, können Sie das kommerzielle (also kostenpflichtige) Tool InnoDB Hot Backup verwenden.

Die InnoDB-Replikation wird mit der LOAD TABLE FROM MASTER-Anweisung eingerichtet, die allerdings nur mit MyISAM-Tabellen funktioniert. Dafür gibt es jedoch zwei Workarounds:

  • Sie können einen Tabellen-Dump auf dem Master vornehmen und die Dump-Datei in den Slave importieren.

  • Sie können auf dem Master ALTER TABLE tbl_name ENGINE=MyISAM einstellen, bevor Sie die Replikation mit LOAD TABLE tbl_name FROM MASTER starten, und danach die Master-Tabelle mit ALTER TABLE wieder in InnoDB konvertieren. Tun Sie das aber nicht mit Tabellen, die Fremdschlüsseldefinitionen haben, da diese Definitionen sonst verlorengehen.

Transaktionen, die auf dem Master scheitern, haben auf die Replikation keinerlei Auswirkungen. Die Replikation beruht in MySQL auf dem Binärlog, wo die SQL-Anweisungen, die Daten modifizieren, festgehalten werden. Eine Transaktion, die scheitert (beispielsweise wegen Verstoß gegen einen Fremdschlüssel-Constraint oder weil sie zurückgerollt wird), gelangt gar nicht ins Binärlog und ergo auch nicht auf die Slaves. Siehe Abschnitt 13.4.1, „BEGIN/COMMIT/ROLLBACK.

14.2.7. Hinzufügen und Entfernen von InnoDB-Daten- und -Logdateien

Dieser Abschnitt beschreibt, was Sie tun können, wenn Ihr InnoDB-Tablespace nicht mehr genug Platz hat oder Sie die Größe der Logdateien ändern möchten.

Am einfachsten lässt sich der InnoDB-Tablespace vergrößern, wenn er von Anfang an als selbsterweiternd konfiguriert wird. Hierzu geben Sie das autoextend-Attribut für die letzte Datendatei in der Tablespace-Definition an. Dann lässt InnoDB diese Datei automatisch in Inkrementen von 8MB anwachsen, wenn ihr der Platz ausgeht. Die Inkrement-Größe kann mit der Systemvariablen innodb_autoextend_increment in MB eingestellt werden.

Sie können Ihren Tablespace jedoch auch vergrößern, indem Sie eine weitere Datendatei hinzufügen. Hierzu müssen sie den MySQL-Server herunterfahren, der Tablespace-Konfiguration am Ende von innodb_data_file_path eine neue Datendatei hinzufügen, und den Server wieder neu starten.

Wenn die letzte Datendatei mit dem Schlüsselwort autoextend definiert worden ist, müssen Sie bei der Rekonfiguration des Tablespaces berücksichtigen, auf welches Maß diese letzte Datendatei angewachsen ist. Ermitteln Sie die Größe der Datendatei, runden Sie sie auf das nächste Vielfache von 1024 × 1024 bytes (= 1MB) ab und geben Sie diesen gerundeten Wert explizit in innodb_data_file_path an. Dann können Sie eine weitere Datendatei hinzufügen. Denken Sie daran, dass Sie nur die letzte Datendatei in innodb_data_file_path als selbsterweiternd definieren können.

Nehmen wir beispielsweise an, der Tablespace hat nur eine selbsterweiternde Datendatei namens ibdata1:

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:10M:autoextend

Diese Datei sei nun mit der Zeit auf 988MB angewachsen. Hier sehen Sie die Konfigurationszeile, nachdem die ursprüngliche Datendatei als nicht mehr selbsterweitend definiert und eine neue, selbsterweiternde Datendatei hinzugefügt wurde:

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend

Wenn Sie der Tablespace-Konfiguration eine neue Datei hinzufügen, achten Sie darauf, dass diese noch nicht existiert. InnoDB wird die Datei erzeugen und initialisieren, wenn der Server neu gestartet wird.

Gegenwärtig ist es nicht möglich, eine Datendatei aus dem Tablespace zu löschen. Wenn Sie Ihren Tablespace verkleinern möchten, gehen Sie folgendermaßen vor:

  1. Mit mysqldump erstellen Sie einen Dump aller InnoDB-Tabellen.

  2. Halten Sie den Server an.

  3. Löschen Sie alle vorhandenen Tablespace-Dateien.

  4. Konfigurieren Sie einen neuen Tablespace.

  5. Starten Sie den Server neu.

  6. Importieren Sie die Dump-Dateien.

Wenn Sie die Anzahl oder Größe Ihrer InnoDB-Logdateien ändern möchten, halten Sie den MySQL-Server an und achten darauf, dass er ohne Fehler herunterfährt (um zu gewährleisten, dass in den Logs keine Daten unvollendeter Transaktionen hängen bleiben). Dann kopieren Sie die Logdateien an einen sicheren Ort, nur für den Fall, dass beim Herunterfahren etwas schiefgeht und Sie den Tablespace wiederherstellen müssen. Löschen Sie die alten Logdateien aus dem Logdateiverzeichnis, ändern Sie die Logdateikonfiguration in my.cnf und starten Sie den MySQL-Server neu. mysqld erkennt beim Hochfahren, dass keine Logdateien vorhanden sind, und teilt Ihnen mit, dass neue angelegt werden.

14.2.8. Sichern und Wiederherstellen einer InnoDB-Datenbank

Der Schlüssel zu einem sicheren Datenbankmanagement sind regelmäßige Backups.

InnoDB Hot Backup ist ein Online-Backup-Tool mit dem Sie eine InnoDB-Datenbank bei laufendem Betrieb sichern können. InnoDB Hot Backup verlangt nicht, dass Sie die Datenbank herunterfahren, setzt keine Sperren und stört nicht die normale Datenbankverarbeitung. InnoDB Hot Backup ist ein kostenpflichtiges (kommerzielles) Add-on, das pro Jahr und pro MySQL-Server-Computer €390 kostet. Genauere Informationen und Screenshots finden Sie unter InnoDB Hot Backup home page.

Wenn Sie in der Lage sind, Ihren MySQL-Server herunterzufahren, können Sie auch ein Binär-Backup aller Dateien erstellen, die InnoDB zur Verwaltung seiner Tabellen benötigt. Gehen Sie folgendermaßen vor:

  1. Fahren Sie den MySQL-Server herunter und achten Sie darauf, dass dabei keine Fehler auftreten.

  2. Kopieren Sie alle Datendateien (ibdata-Dateien und .ibd-Dateien) an einen sicheren Ort.

  3. Kopieren Sie alle ib_logfile-Dateien an einen sicheren Ort.

  4. Kopieren Sie Ihre my.cnf-Konfigurationsdatei(en) an einen sicheren Ort.

  5. Kopieren Sie alle .frm-Dateien für Ihre InnoDB-Tabellen an einen sicheren Ort.

Da die Replikation mit InnoDB-Tabellen funktioniert, können Sie die Replikationsfähigkeiten von MySQL nutzen, um in Hochverfügbarkeitsumgebungen eine Kopie Ihrer Datenbank zu halten.

Zusätzlich zu den Binär-Backups sollten Sie auch regelmäßig mit mysqldump Dump-Kopien der Tabellen anlegen, da eine Binärdatei beschädigt werden kann, ohne dass man es merkt. Dump-Dateien hingegen werde in Textdateien gespeichert, die für Menschen lesbar sind. So lassen sich Schäden leichter erkennen. Außerdem ist die Gefahr einer ernsten Datenkorruption geringer, da das Format einfacher ist. mysqldump besitzt zudem die --single-transaction-Option, mit der Sie konsistente Snapshots anlegen können, ohne andere Clients auszusperren.

Um überhaupt in der Lage zu sein, eine InnoDB-Datenbank aus dem Binär-Backup wiederherzustellen, müssen Sie den MySQL-Server mit eingeschaltetem Binär-Logging betreiben. Dann können Sie das Binärlog auf die Datenbanksicherung übertragen, um eine Point-in-Time-Recovery zu fahren:

mysqlbinlog yourhostname-bin.123 | mysql

Um den MySQL-Server nach einem Absturz wiederherzustellen, müssen Sie ihn lediglich neu starten. InnoDB schaut automatisch in die Logs und versetzt die Datenbank wieder in den aktuellen Zustand (Roll-forward). InnoDB rollt unbestätigte Transaktionen, die zum Zeitpunkt des Absturzes anhängig waren, automatisch zurück. Während der Wiederherstellung zeigt mysqld so etwas wie dieses an:

InnoDB: Database was not shut down normally.
InnoDB: Starting recovery from log files...
InnoDB: Starting log scan based on checkpoint at
InnoDB: log sequence number 0 13674004
InnoDB: Doing recovery: scanned up to log sequence number 0 13739520
InnoDB: Doing recovery: scanned up to log sequence number 0 13805056
InnoDB: Doing recovery: scanned up to log sequence number 0 13870592
InnoDB: Doing recovery: scanned up to log sequence number 0 13936128
...
InnoDB: Doing recovery: scanned up to log sequence number 0 20555264
InnoDB: Doing recovery: scanned up to log sequence number 0 20620800
InnoDB: Doing recovery: scanned up to log sequence number 0 20664692
InnoDB: 1 uncommitted transaction(s) which must be rolled back
InnoDB: Starting rollback of uncommitted transactions
InnoDB: Rolling back trx no 16745
InnoDB: Rolling back of trx no 16745 completed
InnoDB: Rollback of uncommitted transactions completed
InnoDB: Starting an apply batch of log records to the database...
InnoDB: Apply batch completed
InnoDB: Started
mysqld: ready for connections

Wenn Ihre Datenbank beschädigt wurde oder Ihre Festplatte abstürzt, müssen Sie ein Backup zur Wiederherstellung verwenden. Sind Schäden aufgetreten, müssen Sie ein Backup suchen, das unbeschädigt ist. Nach der Wiederherstellung der Sicherungsdateien aus dem Backup müssen Sie mit mysqlbinlog und mysql die Änderungen, die nach dem Backup eingetreten sind, aus den Binärlogs anwenden.

In manchen Fällen, in denen Daten beschädigt wurden, reicht es aus, die beschädigten Tabellen zu dumpen, zu löschen und neu zu erzeugen. Mit der SQL-Anweisung CHECK TABLE finden Sie die meisten Schäden heraus, allerdings nicht jede nur denkbare Art von Datenkorruption. Der innodb_tablespace_monitor prüft die Integrität des Dateiraum-Managements in den Tablespace-Dateien.

Manchmal ist ein scheinbarer Datenbankschaden in Wirklichkeit ein Schaden, den das Betriebssystem an seinem eigenen Datei-Cache verursacht hat, während die Daten auf der Festplatte nach wie vor in Ordnung sind. Am besten versuchen Sie als Erstes, den Computer neu zu starten. So können Sie Fehler eliminieren, die nur scheinbar einen Schaden an Datenbankseiten verursachten.

14.2.8.1. Erzwingen einer InnoDB-Wiederherstellung (Recovery)

Wenn Schäden an Datenbankseiten vorhanden sind, sollten Sie Ihre Tabellen mit SELECT INTO OUTFILE dumpen. Normalerweise sind die meisten auf diese Weise geretteten Daten intakt. Trotzdem kann der Schaden dazu führen, dass SELECT * FROM tbl_name-Anweisungen oder InnoDB-Hintergrundoperationen abstürzen oder sich durchsetzen oder gar die Roll-forward-Recovery von InnoDB abstürzen lassen. Sie können einen Neustart von InnoDB erzwingen und gleichzeitig die Hintergrundoperationen anhalten, sodass ein Tabellen-Dump möglich ist. Zum Beispiel könnten Sie dem Abschnitt [mysqld] Ihrer Optionsdatei vor dem Server-Neustart folgende Zeile hinzufügen:

[mysqld]
innodb_force_recovery = 4

Weiter unten erfahren Sie, welche von null verschiedenen Werte innodb_force_recovery annehmen kann. Größere Werte schließen alle Sicherheitsmaßnahmen der kleineren Werte mit ein. Wenn Sie in der Lage sind, Ihre Tabellen mit einem Optionswert von höchstens 4 zu dumpen, können Sie davon ausgehen, dass nur wenige Daten auf einzelnen beschädigten Seiten verloren gegangen sind. Der Wert 6 ist schon drastischer: Hier bleiben Datenbankseiten in einem obsoleten Zustand zurück, was zu zusätzlichen Schäden in B-Bäumen und anderen Datenbankstrukturen führen kann.

  • 1 (SRV_FORCE_IGNORE_CORRUPT)

    Server soll auch dann weiter laufen, wenn er eine beschädigte Seite entdeckt. Versuchen Sie, SELECT * FROM tbl_name beschädigte Indexeinträge und Seiten überspringen zu lassen, da dies den Tabellen-Dump erleichtert.

  • 2 (SRV_FORCE_NO_BACKGROUND)

    Unterbindet den Haupt-Thread. Wenn während der Purge-Operation ein Absturz passiert, wird dieser Recovery-Wert das verhindern.

  • 3 (SRV_FORCE_NO_TRX_UNDO)

    Nach der Recovery keine Transaktionen zurückrollen.

  • 4 (SRV_FORCE_NO_IBUF_MERGE)

    Verhindert auch Merge-Operationen auf Insert-Puffern. Wenn diese einen Absturz herbeiführen würden werden sie nicht durchgeführt. Es wird keine Tabellenstatistik berechnet.

  • 5 (SRV_FORCE_NO_UNDO_LOG_SCAN)

    Beim Starten der Datenbank nicht in die Undo-Logs schauen: InnoDB behandelt dann auch unvollständige Transaktionen als abgeschlossen.

  • 6 (SRV_FORCE_NO_LOG_REDO)

    Keinen Roll-forward der Logs in Verbindung mit der Recovery durchführen.

Selbst bei einer erzwungenen Recovery können Sie Tabellen mit SELECT dumpen oder sie mit DROP löschen oder mit CREATE anlegen. Wenn Sie wissen, dass eine bestimmte Tabelle beim Zurückrollen einen Absturz verursacht, können Sie sie löschen. Oder Sie verwenden diese Option, um ein Rollback anzuhalten, das wegen eines gescheiterten Massen-Imports oder einer fehlgeschlagenen ALTER TABLE-Operation außer Kontrolle geraten ist. Sie können den mysqld-Prozess anhalten und innodb_force_recovery auf 3 setzen, um die Datenbank ohne den Rollback wieder ans Laufen zu bringen, und dann mit DROP die Tabelle löschen, die den Endlos-Rollback verursacht hatte.

Die Datenbank darf auf keine andere Weise mit einem von null verschiedenen innodb_force_recovery-Wert benutzt werden. Zur Sicherheit hindert InnoDB die Benutzer an INSERT-, UPDATE- und DELETE-Operationen, wenn innodb_force_recovery größer als 0 ist.

14.2.8.2. Checkpoints

InnoDB implementiert einen „fuzzy“ Checkpoint-Mechanismus. InnoDB schreibt Datenbankseiten, die geändert wurden, in kleinen Batches aus dem Bufferpool auf die Platte. Es ist nicht nötig, den Bufferpool in einem einzigen, großen Batch auf die Platte zu schreiben, da dies in der Praxis dazu führen würde, dass Benutzer während des Checkpointing-Prozesses keine SQL-Anweisungen erteilen können.

Bei einer Recovery sucht InnoDB ein Checkpoint-Label in den Logdateien, da es weiß, dass alle Datenbankmodifikationen, die diesem Label vorausgingen, im Disk-Image der Datenbank vorhanden sind. Dann scannt InnoDB die Logdateien von dem Checkpoint aus nach vorne durch und wendet die dort protokollierten Modifikationen auf die Datenbank an.

InnoDB schreibt Daten in rotierender Weise in seine Logdateien. Alle committeten Modifikationen, die dazu führen, dass Datenbankseiten im Bufferpool von den Images auf der Festplatte abweichen, müssen in den Logdateien vorhanden sein, falls InnoDB einmal eine Recovery durchführen muss. Wenn InnoDB eine Logdatei benutzt, muss es also dafür sorgen, dass die Datenbankseiten-Images auf der Platte die in der für die Recovery verwendeten Logdatei protokollierten Modifikationen enthalten. Mit anderen Worten muss InnoDB einen Checkpoint anlegen, wozu häufig modifizierte Datenbankseiten auf die Platte zurückgeschrieben werden müssen.

Dies erklärt auch, warum sehr große Logdateien die Plattenzugriffe beim Checkpointing reduzieren. Oft ist es sinnvoll, die Gesamtgröße der Logdateien auf die Größe des Bufferpools oder sogar einen noch höheren Wert einzustellen. Der Nachteil großer Logdateien: Die Recovery kann dann länger dauern, da mehr Informationen in die Datenbank eingebracht werden müssen.

14.2.9. Eine InnoDB-Datenbank auf eine andere Maschine verschieben

Auf Windows speichert InnoDB die Namen von Datenbanken und Tabellen intern immer in Kleinbuchstaben. Um Datenbanken in einem Binärformat von Unix auf Windows oder von Windows auf Unix zu verlagern, sollten Sie alle Tabellen- und Datenbanknamen auf Kleinschrift umstellen. Dies können Sie ganz bequem erreichen, indem Sie dem [mysqld]-Abschnitt Ihrer my.cnf- oder my.ini-Datei folgende Zeile hinzufügen, bevor Sie irgendwelche Datenbanken oder Tabellen erzeugen:

[mysqld]
lower_case_table_names=1

Wie MyISAM-Datendateien sind auch die Daten- und Logdateien von InnoDB auf allen Plattformen, die dasselbe Fließkommazahlenformat haben, binär kompatibel. Sie können eine InnoDB-Datenbank einfach verschieben, indem Sie alle in Abschnitt 14.2.8, „Sichern und Wiederherstellen einer InnoDB-Datenbank“ aufgelisteten relevanten Dateien kopieren. Wenn die Fließkommaformate unterschiedlich sind, aber keine FLOAT- oder DOUBLE-Datentypen in den Tabellen verwendet werden, ist die Prozedur dieselbe: Kopieren Sie einfach die relevanten Dateien. Sind aber sowohl die Formate unterschiedlich, als auch Fließkommawerte in den Tabellen vorhanden, so müssen Sie Ihre Tabellen mit mysqldump auf der einen Maschine dumpen und dann diese Dump-Dateien auf die andere Maschine übertragen.

Eine bessere Performance erzielen Sie, wenn Sie den Autocommit-Modus beim Datenimport abschalten, immer vorausgesetzt, der Tablespace hat genug Platz für das große Rollback-Segment, das Import-Transaktionen generieren. Den Commit-Befehl geben Sie nachträglich, wenn Sie eine Tabelle oder ein Tabellensegment importiert haben.

14.2.10. InnoDB-Transaktionsmodell

Das Transaktionsmodell von InnoDB soll die besten Eigenschaften einer Multiversionierungsdatenbank mit dem traditionellen zweiphasigen Sperren verbinden. InnoDB errichtet Sperren auf Zeilenebene und führt Anfragen standardmäßig als nicht-sperrende, konsistente Leseoperationen nach Art von Oracle aus. Die Sperrentabelle in InnoDB wird so platzsparend gespeichert, dass keine Sperreneskalation erforderlich ist: Einzelne Zeilen oder beliebige Teile der Zeilen in der Datenbank können von mehreren Benutzern gesperrt werden, ohne dass InnoDB der Speicherplatz ausgeht.

14.2.10.1. InnoDB-Sperrmodi

InnoDB implementiert zwei Arten von Standard-Zeilensperren:

  • Eine Shared-Sperre (S) erlaubt einer Transaktion, eine Zeile (ein Tupel) zu lesen.

  • Eine exklusive (X) Sperre erlaubt einer Transaktion, eine Zeile zu ändern oder zu löschen.

Wenn die Transaktion T1 eine Shared-Sperre (S) auf dem Tupel t hält, dann

  • kann einer Forderung einer anderen Transaktion T2 nach einer S-Sperre auf t sofort stattgegeben werden. Danach halten sowohl T1 als auch T2 eine S-Sperre auf t.

  • kann einer Forderung einer anderen Transaktion T2 nach einer X-Sperre auf t nicht sofort stattgegeben werden.

Wenn eine Transaktion T1 eine exklusive (X) Sperre auf Tupel t hält, kann einer Forderung einer anderen Transaktion T2 nach einer Sperre egal welchen Typs auf t nicht sofort stattgegeben werden. Transaktion T2 muss warten, bis Transaktion T1 ihre Sperre auf Tupel t wieder freigegeben hat.

Außerdem unterstützt InnoDB Multigranuläre Sperren: So können Zeilen und Tabellensperren koexistieren. Um Sperren auf mehreren Granularitätsebenen in die Praxis umzusetzen, gibt es die so genannten Intention Locks. Mithilfe dieser intendierten Sperren kann eine Transaktion anzeigen, welchen Sperrentyp (Shared oder exklusiv) sie später auf einer Zeile einer Tabelle benötigt. In InnoDB werden zwei Arten von Intention Locks verwendet (wir gehen davon aus, dass Transaktion T eine Sperre des angegebenen Typs auf Tabelle R) angefordert hat:

  • Intention Shared (IS): Transaktion T will S-Sperren einzelner Zeilen von Tabelle R erwerben.

  • Intention Exclusive (IX): Transaktion T will X-Sperren auf diesen Zeilen erwerben.

Das Protokoll für Intention Locking ist wie folgt:

  • Bevor eine Transaktion eine S-Sperre auf einer gegebenen Zeile errichten kann, muss sie eine IS- oder stärkere Sperre auf der Tabelle, zu der die Zeile gehört, erwerben.

  • Bevor eine Transaktion eine X-Sperre auf einer gegebenen Zeile errichten kann, muss sie eine IX-Sperre auf der Tabelle, zu der die Zeile gehört, erwerben.

Diese Regeln lassen sich gut in einer Matrix der Sperrtypenkompatibilität zusammenfassen:

 XIXSIS
XKonfliktKonfliktKonfliktKonflikt
IXKonfliktKompatibelKonfliktKompatibel
SKonfliktKonfliktKompatibelKompatibel
ISKonfliktKompatibelKompatibelKompatibel

Der Sperranforderung einer Transaktion wird stattgegeben, wenn die Sperre mit den bereits vorhandenen Sperren kompatibel ist. Ihr wird nicht stattgegeben, wenn die Sperre mit den vorhandenen in Konflikt treten würde. Dann muss die Transaktion abwarten, bis die andere Sperre, die den Konflikt verursachen würde, freigegeben wurde. Wenn eine Sperranforderung mit einer vorhandenen Sperre in Konflikt tritt und nicht gewährt werden kann, weil sie einen Deadlock verursachen würde, wird ein Fehler ausgelöst.

Somit können Intention Locks nichts blockieren, außer vielleicht Sperranforderungen für ganze Tabellen (beispielsweise LOCK TABLES … WRITE). IX und IS sollen vor allem anzeigen, dass jemand eine Tabellenzeile sperrt oder sperren wird.

Das folgende Beispiel zeigt, wie ein Fehler ausgelöst wird, wenn eine Sperranforderung einen Deadlock zur Folge haben würde. An dem Beispiel sind zwei Clients beteiligt, nämlich A und B.

Zuerst legt Client A eine Tabelle mit einer Zeile an und beginnt dann eine Transaktion. Inmitten der Transaktion erwirbt A eine S-Sperre auf der Zeile, indem er im Shared-Modus ein Select auf ihr ausführt:

mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (1.07 sec)

mysql> INSERT INTO t (i) VALUES(1);
Query OK, 1 row affected (0.09 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;
+------+
| i    |
+------+
|    1 |
+------+
1 row in set (0.10 sec)

Dann beginnt Client B eine Transaktion und versucht, die Zeile aus der Tabelle zu löschen:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM t WHERE i = 1;

Die Löschoperation macht eine X-Sperre erforderlich. Diese kann jedoch nicht erteilt werden, da sie mit der S-Sperre von Client A inkompatibel ist. So wird der Request in die Schlange der Sperranforderungen auf diese Zeile gestellt und Client B wird blockiert.

Endlich versucht Client A ebenfalls, die Zeile aus der Tabelle zu löschen:

mysql> DELETE FROM t WHERE i = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

Hier tritt der Deadlock auf, da Client A eine X-Sperre benötigt, um die Zeile sperren zu können. Diese Sperre kann jedoch nicht gewährt werden, da Client B schon vorher eine X-Sperre angefordert hatte, und nur noch darauf wartet, dass A seine S-Sperre freigibt. Doch auch die S-Sperre von A kann nicht auf eine X-Sperre hochgesetzt werden, da B schon vorher eine X-Sperre angefordert hatte. Infolgedessen meldet InnoDB dem Client A einen Fehler und gibt dessen Sperre frei. Jetzt kann der Sperranforderung von Client B stattgegeben werden und B löscht die Zeile aus der Tabelle.

14.2.10.2. InnoDB und AUTOCOMMIT

In InnoDB findet jegliche Benutzeraktivität in einer Transaktion statt. Wenn der Autocommit-Modus eingeschaltet ist, bildet jede SQL-Anweisung eine eigene Transaktion. Standardmäßig ist dieser Modus immer aktiv, wenn MySQL hochfährt.

Wird Autocommit mit SET AUTOCOMMIT = 0 ausgeschaltet, gehen wir davon aus, dass der Benutzer immer eine Transaktion offen hat. Eine COMMIT- oder ROLLBACK-Anweisung beendet die laufende Transaktion und eine neue beginnt. COMMIT bedeutet, dass die Änderungen, die in der aktuellen Transaktion vorgenommen wurden, in der Datenbank dauerhaft festgeschrieben und für andere Benutzer sichtbar gemacht werden. Eine ROLLBACK-Anweisung hingegen macht alle Änderungen in der aktuellen Transaktion rückgängig. Beide Anweisungen geben auch alle InnoDB-Sperren frei, die in der Transaktion gesetzt wurden.

Wenn auf einer Verbindung Autocommit eingeschaltet ist, kann der Benutzer dennoch Transaktionen aus mehreren Anweisungen ausführen, wenn er sie mit einem expliziten START TRANSACTION oder BEGIN einleitet und mit COMMIT oder ROLLBACK beendet.

14.2.10.3. InnoDB und TRANSACTION ISOLATION LEVEL

Was die Transaktionsisolationsebenen von SQL:1992 angeht, so hat InnoDB die Standardeinstellung REPEATABLE READ. InnoDB bietet alle vier Transaktionsisolationsebenen des SQL-Standards. Die Standardisolationsebene können Sie mit der --transaction-isolation-Option auf der Kommandozeile oder in einer Optionsdatei einstellen. So können Sie beispielsweise im [mysqld]-Abschnitt einer Optionsdatei folgendes eintragen:

[mysqld]
transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED
                         | REPEATABLE-READ | SERIALIZABLE}

Ein Benutzer kann die Isolationsebene für eine einzelne Session oder alle neuen Verbindungen mit der SET TRANSACTION-Anweisung einstellen, die folgende Syntax hat:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
                       {READ UNCOMMITTED | READ COMMITTED
                        | REPEATABLE READ | SERIALIZABLE}

Beachten Sie, dass in den Namen der Ebenen in der --transaction-isolation-Option Bindestriche verwendet werden, aber nicht in der SET TRANSACTION-Anweisung.

Standardmäßig wird die Isolationsebene immer für die nächste (noch nicht begonnene) Transaktion eingestellt. Mit dem Schlüsselwort GLOBAL stellt die Anweisung die Standard-Transaktionsebene global für alle neuen Verbindungen ein, die ab diesem Punkt aufgebaut werden (aber nicht für die schon bestehenden Verbindungen). Um dies zu tun, benötigen Sie die SUPER-Berechtigung. Das Schlüsselwort SESSION stellt die Standard-Transaktionsebene für alle zukünftigen Transaktionen auf aktuellen Verbindung ein.

Jeder Client kann die Session-Isolationsebene (sogar inmitten einer Transaktion), oder die Isolationsebene der nächsten Transaktion haben.

Ob die Transaktionsisolationsebene global oder für die einzelne Session eingestellt wurde, können Sie anhand der Systemvariablen tx_isolation mit folgenden Anweisungen ermitteln:

SELECT @@global.tx_isolation;
SELECT @@tx_isolation;

Für Zeilensperren verwendet InnoDB Next-Key-Locking. Das bedeutet, dass InnoDB zusätzlich zu den Indexeinträgen auch die „Lücke“ vor einem Indexeintrag sperrt, um zu verhindern, dass andere Benutzer gerade dort etwas einfügen. Eine Next-Key-Sperre ist eine Sperre, die nicht nur den Indexeintrag, sondern auch die Lücke vor diesem blockiert. Eine Gap-Sperre ist eine Sperre, die lediglich die Lücke vor einem Indexeintrag betrifft.

Im Folgenden werden die Isolationsebenen in InnoDB genauer erläutert:

  • READ UNCOMMITTED

    SELECT-Anweisungen werden ohne Sperren ausgeführt, wobei es jedoch möglich ist, dass eine ältere Version eines Eintrags verwendet wird. Also sind Leseoperationen mit dieser Isolationsebene nicht konsistent (man bezeichnet dies auch als „Dirty Read“). Ansonsten funktioniert diese Isolationsebene wie READ COMMITTED.

  • READ COMMITTED

    Eine Oracle-ähnliche Isolationsebene. Alle SELECT … FOR UPDATE- und SELECT … LOCK IN SHARE MODE-Anweisungen sperren nur die Indexeinträge und nicht die Lücken davor. So können neben den gesperrten Einträgen nach Belieben neue Datensätze eingefügt werden. UPDATE- und DELETE-Anweisungen, die einen eindeutigen Index mit einer eindeutigen Suchbedingung verwenden, können nur den gefundenen Indexeintrag, aber nicht die Lücke davor, sperren. In Bereichs-UPDATEs und DELETEs muss InnoDB Next-Key- oder Gap-Sperren setzen und Einfügungen anderer Benutzer in die Lücken, die in dem Bereich liegen, blockieren. Dies ist erforderlich, da die Replikation und Recovery von MysQL nur funktioniert, wenn keine „Phantomzeilen“ vorhanden sind.

    Konsistente Leseoperationen verhalten sich wie in Oracle: Jede konsistente Leseoperation, sogar innerhalb derselben Transaktion, setzt und liest ihren eigenen, frischen Snapshot. Siehe Abschnitt 14.2.10.4, „Konsistentes Lesen“.

  • REPEATABLE READ

    Die Standardisolationsebene von InnoDB. SELECT … FOR UPDATE-, SELECT … LOCK IN SHARE MODE-, UPDATE- und DELETE-Anweisungen, die einen eindeutigen Index mit einer eindeutigen Suchbedingung verwenden, sperren nur den gefundenen Indexeintrag, aber nicht die Lücke davor. Für andere Suchbedingungen setzen diese Operationen Next-Key-Locking ein oder sperren den durchsuchten Indexbereich mit Next-Key- oder Gap-Sperren und blockieren dadurch Einfügungen anderer Benutzer.

    In konsistenten Leseoperationen gibt es einen wichtigen Unterschied zur Isolationsebene READ COMMITTED: Alle konsistenten Leseoperationen innerhalb derselben Transaktion lesen denselben Snapshot, der von der ersten Leseoperation eingerichtet wurde. Daraus folgt: Wenn Sie mehrere einfache SELECT-Anweisungen innerhalb derselben Transaktion erteilen, sind diese SELECT-Anweisungen auch untereinander konsistent. Siehe Abschnitt 14.2.10.4, „Konsistentes Lesen“.

  • SERIALIZABLE

    Wie REPEATABLE READ, nur dass InnoDB implizit alle einfachen SELECT-Anweisungen zu SELECT … LOCK IN SHARE MODE committet.

14.2.10.4. Konsistentes Lesen

Bei einer konsistenten Leseoperation verwendet InnoDB Multiversionierung, um einer Anfrage einen Snapshot der Datenbank für einen bestimmten Zeitpunkt (Point-in-Time) zu präsentieren. Die Anfrage erkennt die Änderungen, die Transaktionen vor diesem Zeitpunkt vorgenommen hatten, aber keine Änderungen späterer oder noch unvollendeter Transaktionen. Die Ausnahme: Änderungen von früheren Anweisungen in derselben Transaktion sind für die Anweisung sichtbar.

Wenn Sie die Standardisolationsebene REPEATABLE READ benutzen, lesen alle konsistenten Leseoperationen innerhalb derselben Transaktion den Snapshot, der durch die erste Leseoperation in dieser Transaktion erzeugt wurde. Einen frischeren Snapshot für Ihre Anfragen erhalten Sie, indem Sie die laufende Transaktion committen und danach neue Anfragen absetzen.

Konsistentes Lesen ist der Standardmodus, in dem InnoDB SELECT-Anfragen auf den Isolationsebenenen READ COMMITTED und REPEATABLE READ verarbeitet. Konsistentes Lesen errichtet keine Sperren auf den benutzten Tabellen, sodass andere Benutzer diese Tabellen nach Belieben modifizieren können, während eine konsistente Leseoperation auf ihnen abläuft.

Beachten Sie, dass konsistente Leseoperationen nicht mit DROP TABLE und ALTER TABLE funktionieren. Mit DROP TABLE nicht, weil MySQL eine Tabelle, die gelöscht wurde, nicht mehr benutzen kann und InnoDB sie zerstört, und mit ALTER TABLE nicht, weil dieser Befehl innerhalb einer Transaktion ausgeführt wird, die eine neue Tabelle anlegt und Zeilen aus der alten Tabelle in sie einfügt. Wenn Sie die konsistente Leseoperation neu ausführen, kann sie die Zeilen der neuen Tabelle nicht erkennen, da sie in einer Transaktion eingefügt wurden, die in dem von der konsistenten Leseoperation verwendeten Snapshot nicht sichtbar war.

14.2.10.5. Lesevorgänge sperren

In manchen Fällen ist eine konsistente Leseoperation nicht das Richtige. Vielleicht möchten Sie ja eine neue Zeile in Ihre child-Tabelle einfügen und dabei sicherstellen, dass das Kind in der Tabelle parent auch wirklich ein Elternteil hat. Das folgende Beispiel zeigt, wie Sie referenzielle Integrität in Ihren Anwendungscode implementieren können.

Angenommen, Sie verwenden eine konsistente Leseoperation, um die Tabelle parent zu lesen, und sehen auch tatsächlich die Elternzeile des Kindes in der Tabelle. Können Sie die Kindzeile nun auch beruhigt in die Tabelle child einfügen? Nein, denn es kann ja sein, dass irgendein anderer Benutzer zwischenzeitlich die Elternzeile aus der Tabelle parent gelöscht hat, ohne dass Sie es merkten.

Die Lösung: Sie führen das SELECT in dem Sperrmodus LOCK IN SHARE MODE aus:

SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

Wird eine Leseoperation im Share-Modus ausgeführt, so liest sie die aktuellsten verfügbaren Daten und errichtet eine Shared-Sperre auf den Zeilen, die sie liest. Diese verhindert, dass andere Benutzer die Zeile ändern oder löschen. Wenn die Daten zu einer noch unvollendeten Transaktion einer anderen Clientverbindung gehören, warten wir, bis die Transaktion committet ist. wenn wir gesehen haben, dass die obige Anfrage den Parent 'Jones' zurückgibt, können wir unseren Eintrag beruhigt in die child-Tabelle einfügen und unsere Transaktion committen.

Betrachten wir ein anderes Beispiel: Wir haben in der Tabelle child_codes ein Zählerfeld eines Integer-Typs, das wir dazu benutzen, jedem Kind, das der child-Tabelle hinzugefügt wird, eine eindeutige Kennnummer zu geben. Da wäre es natürlich keine gute Idee, den Wert des Zählers mit einer konsistenten Leseoperation oder im Shared-Modus zu lesen, da zwei Datenbanknutzer dann vielleicht denselben Zählerwert sehen und einen Fehler wegen Schlüsselduplikaten auslösen, sofern sie versuchen, Kindeinträge mit derselben Nummer in die Tabelle einzufügen.

Hier ist LOCK IN SHARE MODE keine gute Lösung. Denn wenn zwei Benutzer gleichzeitig den Zähler lesen, könnte mindestens einer von ihnen in einen Deadlock geraten, wenn er versucht, den Zähler zu aktualisieren.

Hier haben Sie zwei gute Möglichkeiten, das Lesen und Inkrementieren des Zählers zu implementieren: (1) Sie inkrementierten zuerst den Zähler um 1 und führen erst dann die Leseoperation durch, oder (2) Sie lesen den Zähler zuerst im Sperrmodus FOR UPDATE und inkrementieren ihn danach. Der zweite Ansatz kann folgendermaßen implementiert werden:

SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;

Ein SELECT … FOR UPDATE liest die neuesten verfügbaren Daten und errichtet eine exklusive Sperre auf jeder Zeile, die es liest. Somit setzt es dieselben Sperren, die auch ein Searched SQL UPDATE auf den Zeilen erwerben würde.

Die obige Beschreibung ist nur ein Beispiel dafür, wie SELECT … FOR UPDATE funktioniert. In MySQL können Sie einen eindeutigen Identifier grundsätzlich mit nur einem einzigen Tabellenzugriff generieren:

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();

Die SELECT-Anweisung ruft nur die Identifier-Information ab (die für die aktuelle Verbindung spezifisch ist). Sie greift auf keine Tabellen zu.

Sperren von IN SHARE MODE- und FOR UPDATE-Leseoperationen werden freigegeben, wenn die Transaktion committet oder zurückgerollt wird.

14.2.10.6. Nächsten Schlüssel sperren: Wie das Phantom-Problem vermieden wird

In Zeilensperren verwendet InnoDB einen Algorithmus namens Next-Key-Locking. InnoDB sperrt Zeilen so, dass es beim Durchsuchen oder Scannen eines Tabellenindex Shared- oder exklusive Sperren auf den gefundenen Indexeinträgen errichtet. Also sind die Zeilensperren in Wirklichkeit Indexeintragssperren.

Die Sperren, die InnoDB auf Indexeinträgen errichtet, betreffen auch die „Lücke“ vor den Einträgen. Wenn ein Benutzer eine Shared- oder exklusive Sperre auf Eintrag R eines Index hält, kann kein anderer Benutzer unmittelbar vor R einen Eintrag in die Indexreihenfolge einfügen. Durch dieses so genannte „Gap-Locking“ wird das „Phantom-Problem“ gelöst. Angenommen, Sie wollten alle Kinder der child-Tabelle lesen und sperren, deren Identifier-Wert größer als 100 ist, um später eine Spalte in den ausgewählten Zeilen zu ändern:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

Angenommen, Sie haben einen Index auf der Spalte id. Die Anfrage scannt diesen Index ab dem ersten Eintrag, dessen id größer als 100 ist. Wenn die Sperren auf den Indexeinträgen Einfügungen in die Lücken nicht verhindern würden, könnte in der Zwischenzeit eine neue Zeile in die Tabelle eingefügt werden. Wenn Sie dasselbe SELECT in derselben Transaktion ein zweites Mal ausführten, hätten Sie plötzlich eine zusätzliche Zeile in der Ergebnismenge. Das verstößt aber gegen das Isolationsprinzip von Transaktionen: Eine Transaktion muss so ablaufen, dass sich die Daten, die sie liest, während ihrer Laufzeit nicht ändern können. Wenn wir eine Zeilenmenge als ein Datenelement betrachten, würde die neue „Phantomzeile“ dieses Isolationsprinzip verletzen.

Wenn InnoDB einen Index scannt, kann es auch die Lücke hinter dem letzten Eintrag im Index sperren. Genau dies geschieht auch im obigen Beispiel: Die von InnoDB gesetzten Sperren verhindern jede Einfügung in die Tabelle an Stellen, deren id größer als 100 ist.

Mit Next-Key-Locking können Sie eine Eindeutigkeitsprüfung in Ihrer Anwendung implementieren. Wenn Sie Ihre Daten im Share-Modus lesen und kein Duplikat der Zeile sehen, die Sie einfügen möchten, dann können Sie die Einfügung beruhigt ausführen und wissen, dass die Next-Key-Sperre auf dem Nachfolger Ihrer Zeile verhindert, dass in der Zwischenzeit jemand anders ein Duplikat Ihrer Zeile einfügt.

14.2.10.7. Ein Beispiel, wie konsistentes Lesen bei InnoDB funktioniert

Angenommen, Sie verwenden die Standardisolationsebene REPEATABLE READ. Wenn Sie eine konsistente Leseoperation ausführen (also eine normale SELECT-Anweisung), weist InnoDB Ihrer Transaktion einen Zeitpunkt zu, an dem Ihre Anfrage die Datenbank sieht. Wenn eine andere Transaktion nach diesem Zeitpunkt eine Zeile löscht und committet, können Sie dies nicht sehen. Einfügungen und Änderungen werden genauso behandelt.

Sie können Ihren Zeitpunkt aktualisieren, indem Sie Ihre Transaktion committen und eine neue SELECT-Anfrage starten.

Dies bezeichnet man als Nebenläufigkeitssteuerung mit Multiversionierung.

               User A                 User B

           SET AUTOCOMMIT=0;      SET AUTOCOMMIT=0;
time
|          SELECT * FROM t;
|          empty set
|                                 INSERT INTO t VALUES (1, 2);
|
v          SELECT * FROM t;
           empty set
                                  COMMIT;

           SELECT * FROM t;
           empty set

           COMMIT;

           SELECT * FROM t;
           ---------------------
           |    1    |    2    |
           ---------------------
           1 row in set

In diesem Beispiel sieht Benutzer A die von Benutzer B eingefügte Zeile erst dann, wenn sowohl B als auch A ihre Operationen committet haben, sodass der Zeitpunkt sich auf die Zeit nach dem Commit von B verschiebt.

Wenn Sie den „frischsten“ Zustand der Datenbank sehen möchten, stellen Sie entweder die Isolationsebene READ COMMITTED oder einen Locking-Read ein:

SELECT * FROM t LOCK IN SHARE MODE;

14.2.10.8. Sperren, die in InnoDB durch unterschiedliche SQL-Anweisungen gesetzt werden

Ein Locking Read, ein UPDATE oder ein DELETE errichten normalerweise Zeilensperren auf jedem Indexeintrag, der bei der Verarbeitung der SQL-Anfrage gescannt wird. Ob irgendwelche WHERE-Bedingungen in der Anfrage die Zeile eigentlich ausschließen würden, spielt keine Rolle. InnoDB merkt sich nicht die genaue WHERE-Bedigungn, sondern weiß nur, welche Indexbereiche gescannt werden. Die Sperren auf den Einträgen sind normalerweise Next-Key-Sperren, die auch Einfügungen in die „Lücke“ vor dem Eintrag blockieren.

Wenn exklusive Sperren errichtet werden, ruft InnoDB immer auch den geclusterten Indexeintrag ab und sperrt ihn.

Wenn Sie nicht die geeigneten Indizes für Ihre Anweisung haben und MySQL die gesamte Tabelle scannen muss, um die Anfrage zu verarbeiten, werden alle Tabellenzeilen und somit auch alle Einfügeoperationen anderer Benutzer auf der Tabelle gesperrt. Es ist also wichtig, gute Indizes anzulegen, damit Ihre Anfragen nicht unnötig viele Zeilen scannen müssen.

InnoDB setzt bestimmte Arten von Sperren wie folgt:

  • SELECT … FROM ist ein konsistenter Lesevorgang, der einen Snapshot der Datenbank betrachtet und nur dann Sperren errichtet, wenn die Transaktionsisolationsebene SERIALIZABLE ist. In diesem Fall werden Shared Next-Key-Sperren auf die gefundenen Indexeinträge gesetzt.

  • SELECT … FROM … LOCK IN SHARE MODE setzt Shared Next-Key-Sperren auf alle Indexeinträge, die der Lesevorgang findet.

  • SELECT … FROM … FOR UPDATE setzt exklusive Next-Key-Sperren auf alle Indexeinträge, die der Lesevorgang findet.

  • INSERT INTO … VALUES (…) setzt eine exklusive Sperre auf die eingefügte Zeile. Beachten Sie, dass diese Sperre keine Next-Key-Sperre ist und daher andere Benutzer nicht daran hindert, in die Lücke vor der neuen Zeile etwas einzufügen. Wenn ein Fehler wegen Schlüsselduplikaten auftritt, wird eine Shared-Sperre auf dem Duplikat-Indexeintrag gesetzt.

  • Bei der Initialisierung einer zuvor angegebenen AUTO_INCREMENT-Spalte auf einer Tabelle setzt InnoDB eine exklusive Sperre auf das Ende des mit dieser AUTO_INCREMENT-Spalte verbundenen Index. Für den Zugriff auf den Auto-Increment-Zähler nutzt InnoDB einen bestimmten Tabellensperrmodus namens AUTO-INC, mit dem die Sperre nur bis zum Ende der aktuellen SQL-Anweisung und nicht der gesamten Transaktion aufrecht erhalten bleibt. Siehe Abschnitt 14.2.10.2, „InnoDB und AUTOCOMMIT.

    InnoDB ruft den Wert einer initialisierten AUTO_INCREMENT-Spalte ab, ohne Sperren zu setzen.

  • INSERT INTO T SELECT … FROM S WHERE … errichtet eine exklusive Sperre (keine Next-Key-Sperre) auf jeder in T eingefügten Zeile. InnoDB erwirbt Shared Next-Key-Sperren auf S, wenn nicht innodb_locks_unsafe_for_binlog aktiviert ist. In diesem Fall durchsucht es S mit einer konsistenten Leseoperation. InnoDB muss im zweiten Fall Sperren setzen: Bei einer Roll-forward-Recovery von einem Backup muss jede SQL-Anweisung in genau derselben Weise wie ursprünglich ausgeführt werden.

  • CREATE TABLE … SELECT … führt das SELECT als konsistente Leseoperation oder mit Shared-Sperren durch, wie oben beschrieben.

  • REPLACE wird wie ein Insert ausgeführt, wenn keine Konflikte auf einem eindeutigen Schlüssel entstehen. Andernfalls wird eine exklusive Next-Key-Sperre auf der zu aktualisierenden Zeile errichtet.

  • UPDATE … WHERE … setzt eine exklusive Next-Key-Sperre auf jeden bei der Suche gefundenen Datensatz.

  • DELETE FROM … WHERE … setzt eine exklusive Next-Key-Sperre auf jeden bei der Suche gefundenen Datensatz.

  • Wenn ein FOREIGN KEY-Constraint auf einer Tabelle definiert ist, setzt jedes Insert, Update oder Delete, bei dem die Constraint-Bedingung geprüft werden muss, Shared-Zeilensperren auf die betrachteten Datensätze, um den Constraint zu überprüfen. InnoDB setzt diese Sperren auch dann, wenn der Constraint versagt.

  • LOCK TABLES setzt Tabellensperren, allerdings auf der MySQL-Ebene, die höher als die InnoDB-Ebene liegt. InnoDB weiß von den Tabellensperren, wenn innodb_table_locks=1 (die Standardeinstellung) und AUTOCOMMIT=0 eingestellt ist, und die MySQL-Ebene oberhalb von InnoDB weiß ebenso von den Zeilensperren. Sonst kann die automatische Deadlock-Erkennung von InnoDB keine Deadlocks erkennen, an denen solche Tabellensperren beteiligt sind. Außerdem wäre es dann möglich, eine Tabellensperre auf einer Tabelle zu errichten, in der ein anderer Benutzer gleichzeitig Zeilensperren hält, weil die höhere MySQL-Ebene diese Zeilensperren nicht kennt. Dies bedroht allerdings nicht die Transaktionsintegrität, wie in Abschnitt 14.2.10.10, „Blockierungserkennung und Rollback“ erläutert. Siehe auch Abschnitt 14.2.16, „Beschränkungen von InnoDB-Tabellen“.

14.2.10.9. Implizites Commit und Rollback von Transaktionen

Nach Voreinstellung beginnt MySQL jede Clientverbindung mit eingeschaltetem Autocommit. Dabei wird nach jeder fehlerfrei gelaufenen SQL-Anweisung ein Commit durchgeführt. Gibt die Anweisung einen Fehler zurück, so entscheidet die Art des Fehlers darüber, ob ein Commit oder ein Rollback ausgeführt wird. Siehe Abschnitt 14.2.15, „InnoDB-Fehlerbehandlung“.

Wenn Sie Autocommit ausgeschaltet haben und eine Verbindung schließen, ohne explizit die letzte Transaktion zu committen, rollt MySQL diese Transaktion zurück.

Jede der folgenden Anweisungen (und ihre Synonyme) beendet implizit eine Transaktion, als hätten Sie COMMIT gesagt:

  • ALTER FUNCTION, ALTER PROCEDURE, ALTER TABLE, BEGIN, CREATE DATABASE, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, DROP DATABASE, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP TABLE, LOAD MASTER DATA, LOCK TABLES, RENAME TABLE, SET AUTOCOMMIT=1, START TRANSACTION, TRUNCATE, UNLOCK TABLES.

  • UNLOCK TABLES committet eine Transaktion nur dann, wenn Tabellen gesperrt sind.

  • Die CREATE TABLE-Anweisung in InnoDB wird als eine einzelne Transaktion ausgeführt. Dies bedeutet, dass ein ROLLBACK vom Benutzer nicht die im Lauf der Transaktion erteilten CREATE TABLE-Anweisungen rückgängig macht.

Transaktionen können nicht geschachtelt werden. Dies ist eine Konsequenz des impliziten COMMIT, das jede laufende Transaktion ausführt, wenn Sie eine START TRANSACTION-Anweisung oder ein Synonym erteilen.

14.2.10.10. Blockierungserkennung und Rollback

InnoDB erkennt automatisch einen Deadlock von Transaktionen und rollt eine oder mehrere Transaktion(en) zurück, um den Deadlock aufzulösen. InnoDB versucht, für den Rollback kleine Transaktionen herauszusuchen, wobei die Größe einer Transaktion anhand der Anzahl der Zeilen bestimmt wird, die sie einfügt, ändert oder löscht.

InnoDB weiß von Tabellensperren, wenn innodb_table_locks=1 (die Standardeinstellung) und AUTOCOMMIT=0 eingestellt ist, und die MySQL-Ebene oberhalb von InnoDB weiß ebenso von den Zeilensperren. Sonst kann die automatische Deadlock-Erkennung von InnoDB keine Deadlocks erkennen, wenn eine von der MySQL-Anweisung LOCK TABLES gesetzte Tabellensperre oder eine von einer anderen Speicher-Engine als InnoDB gesetzte Sperre beteiligt ist. Solche Situationen müssen Sie durch Einstellen der Systemvariablen innodb_lock_wait_timeout beherrschen.

Wenn InnoDB eine Transaktion vollständig zurückrollt, werden alle von ihr gehaltenen Sperren freigegeben. Wird jedoch nur eine einzige SQL-Anweisung infolge eines Fehlers zurückgerollt, bleiben manche von ihr errichteten Sperren eventuell erhalten, da InnoDB Zeilensperren in einem Format speichert, an dem es später nicht mehr erkennen kann, welche Anweisung welche Sperren gesetzt hat.

14.2.10.11. Vom Umgang mit Deadlocks

Deadlocks in Transaktionsdatenbanken sind ein klassisches Problem. Gefährlich werden sie aber erst dann, wenn sie so häufig auftreten, dass bestimmte Transaktionen nicht mehr möglich sind. Normalerweise müssen Sie Ihre Anwendungen so erstellen, dass sie immer bereit sind, eine Transaktion neu zu starten, wenn sie wegen eines Deadlocks zurückgerollt wurde.

InnoDB benutzt automatische Zeilensperren. Deadlocks können sogar bei Transaktionen auftreten, die nur eine einzige Zeile einfügen oder löschen. Da diese Operationen nicht wirklich „atomar“ sind, errichten sie automatisch Sperren auf den (vielleicht mehreren) Indexeinträgen der eingefügten oder gelöschten Zeile.

Folgende Techniken helfen Ihnen, mit Deadlocks fertigzuwerden und ihre Zahl zu reduzieren:

  • SHOW ENGINE INNODB STATUS verrät Ihnen den Grund des letzten Deadlocks. Dies kann Ihnen helfen, Ihre Anwendung so zu tunen, dass Deadlocks vermieden werden.

  • Seien Sie immer bereit, eine Transaktion, die wegen eines Deadlocks scheiterte, neu zu starten. Deadlocks sind nichts Schlimmes. Versuchen Sie es einfach noch einmal.

  • Committen Sie Ihre Transaktionen oft. Kleine Transaktionen sind nicht so konfliktanfällig.

  • Wenn Sie Lesesperren (SELECT … FOR UPDATE oder … LOCK IN SHARE MODE) setzen, versuchen Sie, eine niedrigere Isolationsebene einzustellen, beispielsweise READ COMMITTED.

  • Greifen Sie in einer festgelegten Reihenfolge auf Ihre Tabellen und Zeilen zu. Dann bilden die Transaktionen ordentliche Schlangen und können sich nicht gegenseitig blockieren.

  • Versehen Sie Ihre Tabellen mit guten Indizes. Dann müssen Ihre Anfragen weniger Indexeinträge scannen und folglich auch weniger Sperren setzen. Mit EXPLAIN SELECT können Sie feststellen, welche Indizes nach Ansicht Ihres MySQL-Servers für Ihre Anfragen die besten sind.

  • Sperren Sie nicht so viel. Wenn Sie es sich leisten können, dass ein SELECT Daten aus einem älteren Snapshot zurückgibt, verzichten Sie auf die Klausel FOR UPDATE oder LOCK IN SHARE MODE. Die Isolationsebene READ COMMITTED ist gut geeignet, da jede konsistente Leseoperation innerhalb derselben Transaktion Daten aus einem eigenen, frischen Snapshot liest.

  • Wenn sonst nichts hilft, serialisieren Sie Ihre Transaktionen mit Tabellensperren. Um LOCK TABLES mit Transaktionstabellen wie etwa InnoDB-Tabellen zu verwenden, setzen Sie AUTOCOMMIT = 0 und rufen UNLOCK TABLES erst auf, nachdem Sie die Transaktion explizit committet haben. Wenn Sie beispielsweise in die Tabelle t1 schreiben und aus der Tabelle t2 lesen möchten, tun Sie dies wie folgt:

    SET AUTOCOMMIT=0;
    LOCK TABLES t1 WRITE, t2 READ, ...;
    ... do something with tables t1 and t2 here ...
    COMMIT;
    UNLOCK TABLES;
    

    Tabellensperren sorgen dafür, dass Ihre Transaktions brav Schlange stehen und Deadlocks vermieden werden.

  • Sie können Transaktionen auch serialisieren, indem Sie eine „Semaphoren“-Hilfstabelle mit nur einer einzigen Zeile anlegen. Sorgen Sie dafür, dass jede Transaktion diese Zeile aktualsieren muss, ehe sie auf andere Tabellen zugreifen darf. Auf diese Weise laufen alle Transaktionen nacheinander ab. Beachten Sie, dass der Deadlock-Erkennungsalgorithmus von InnoDB auch in diesem Falle funktioniert, da die serialisierende Sperre auf Zeilenebene arbeitet. Bei MySQL-Tabellensperren muss die Timeout-Methode eingesetzt werden, um Deadlocks aufzulösen.

  • In Anwendungen, die den LOCK TABLES-Befehl verwenden errichtet MySQL keine InnoDB-Tabellensperren, wenn AUTOCOMMIT=1.

14.2.11. Tipps zur Leistungssteigerung

  • Wenn das Unix-Tool top oder der Windows Task Manager zeigt, dass die CPU-Last unter 70% liegt, läuft Ihre Arbeit wahrscheinlich festplattengebunden ab. Vielleicht committen Sie zu oft Transaktionen oder Ihr Bufferpool ist zu klein. Diesen zu vergrößern könnte helfen, aber stellen sie ihn nicht auf 80% des physikalischen Speichers oder gar mehr ein.

  • Verpacken Sie mehrere Modifikationen in eine einzige Transaktion. InnoDB muss bei jedem Committ einer Transaktion, die etwas an der Datenbank änderte, die Logs auf die Festplatte zurückschreiben. Da diese meist mit einer Geschwindigkeit von höchstens 167 Umdrehungen/Sekunde rotiert, ist diese 167tel Sekunde auch für Committs die Obergrenze, wenn die Festplatte es nicht schafft, das Betriebssystem zu „überlisten“.

  • Wenn Sie es sich leisten können, im Falle eines Absturzes einige Ihrer zuletzt committeten Transaktionen zu verlieren, können Sie den innodb_flush_log_at_trx_commit-Parameter auf 0 setzen. InnoDB versucht ohnehin, das Log einmal pro Sekunde auf die Platte zu schreiben, auch wenn dies nicht immer klappt.

  • Machen Sie Ihre Logdateien groß, vielleicht genauso groß wie den Bufferpool. Wenn InnoDB die Logdateien vollgeschrieben hat, muss es den neuen Inhalt des Bufferpools in einem Checkpoint auf die Platte schreiben. Kleine Logdateien verursachen viele überflüssige Schreibvorgänge auf der Festplatte. Der Nachteil großer Logdateien ist die längere Recovery-Zeit.

  • Machen Sie auch den Logpuffer recht groß (etwa 8MB).

  • Verwenden Sie zur Speicherung von Strings variabler Länge oder wenn die Spalte NULL-Werte enthalten kann, VARCHAR statt CHAR als Datentyp. Eine CHAR(N)-Spalte speichert immer N Zeichen, selbst wenn der String kürzer oder sein Wert NULL ist. Kleinere Tabellen passen besser in den Bufferpool und reduzieren die Schreibvorgänge auf der Festplatte.

    Wenn Sie die Standardeinstellung row_format=compact für das Datensatzformat von MySQL 5.1 Zeichensätze variabler Länge wie etwa utf8 oder sjis verwenden, belegt CHAR(N) eine variable Menge Speicherplatz, allerdings mindestens N Bytes.

  • In manchen Versionen von GNU/Linux und Unix geht es erstaunlich langsam, Daten mit dem Unix-Aufruf fsync() (den InnoDB standardmäßig verwendet) und anderen, ähnlichen Methoden auf die Platte zu schreiben. Wenn Sie mit der Schreibleistung Ihrer Datenbank unzufrieden sind, setzen Sie den innodb_flush_method-Parameter auf O_DSYNC. Zwar scheint O_DSYNC auf den meisten Systemen die langsamere Variante zu sein, aber vielleicht ist es gerade auf Ihrem schneller.

  • Wenn Sie InnoDB auf Solaris 10 for x86_64 (AMD Opteron) einsetzen, ist es wichtig, alle zum Speichern von InnoDB-Dateien verwendeten Dateisysteme mit der forcedirectio-Option zu mounten (die standardmäßig auf Solaris 10/x86_64 nicht benutzt wird). Wenn Sie dies nicht tun, läuft InnoDB auf dieser Plattform sehr viel langsamer und hat eine geringere Performance.

    Wenn Sie InnoDB mit einem großen innodb_buffer_pool_size-Wert auf Solaris 2.6 und höher auf einer beliebigen Plattform (sparc/x86/x64/amd64) einsetzen, können Sie die Performance massiv steigern, indem Sie die InnoDB-Daten- und -Logdateien auf Raw Devices oder einem separaten UFS-Dateisystem mit Direkt-E/A speichern (und zwar mit der Mount-Option forcedirectio, siehe mount_ufs(1M)). Wer das Veritas-Dateisystem VxFS hat, sollte die Mount-Option convosync=direct setzen.

    Andere MySQL-Datendateien, wie etwa die für MyISAM-Tabellen, sollten nicht in einem Dateisystem mit Direkt-E/A abgelegt werden. Executables oder Bibliotheken dürfen niemals in einem Dateisystem mit Direkt-E/A abgelegt werden

  • Beim Datenimport in InnoDB müssen Sie darauf achten, dass MySQL nicht im Autocommit-Modus läuft, da dieser bei jedem Insert die Logs auf die Festplatte zurückschreibt. Um während der Import-Operation Autocommit auszuschalten, schließen Sie die Operation in SET AUTOCOMMIT und COMMIT-Anweisungen ein:

    SET AUTOCOMMIT=0;
    ... SQL import statements ...
    COMMIT;
    

    Mit der mysqldump-Option --opt erhalten Sie Dump-Dateien, die sich in eine InnoDB-Tabelle ganz schnell importieren lassen, selbst ohne den Import in die Anweisungen SET AUTOCOMMIT und COMMIT zu verpacken.

  • Hüten Sie sich vor umfangreichen Rollbacks von Masseneinfügeoperationen: InnoDB benutzt den Insert-Puffer zwar bei den Einfügungen, um Schreibvorgänge zu minimieren, aber nicht bei den zugehörigen Rollbacks. Ein festplattengebundener Rollback kann 30-mal so lange wie der zugehörige Insert brauchen. Dabei hilft es auch nichts, den Datenbankprozess anzuhalten, da der Rollback beim Hochfahren des Servers wieder von vorne beginnt. Die einzige Möglichkeit, einen außer Kontrolle geratenen Rollback aufzuhalten, besteht darin, den Bufferpool so groß anzusetzen, dass der Rollback CPU-gebunden und somit schneller läuft, oder eine spezielle Prozedur einzusetzen. Siehe Abschnitt 14.2.8.1, „Erzwingen einer InnoDB-Wiederherstellung (Recovery)“.

  • Hüten Sie sich auch vor anderen umfangreichen festplattengebundenen Operationen. Verwenden Sie zum Leeren einer Tabelle DROP TABLE und CREATE TABLE, aber nicht DELETE FROM tbl_name.

  • Mit dem mehrzeiligen INSERT können Sie den Kommunikationsaufwand zwischen Client und Server minimieren, wenn Sie viele Zeilen einfügen müssen:

    INSERT INTO yourtable VALUES (1,2), (5,5), ...;
    

    Dieser Tipp gilt übrigens für Einfügungen in alle möglichen Tabellen, nicht nur in InnoDB-Tabellen.

  • Wenn Sie UNIQUE-Constraints auf Sekundärschlüsseln haben, können Sie Tabellenimporte beschleunigen, indem Sie die Eindeutigkeitsprüfung während der Import-Session vorübergehend abschalten:

    SET UNIQUE_CHECKS=0;
    ... import operation ...
    SET UNIQUE_CHECKS=1;
    

    Bei großen Tabellen spart dies eine Menge Plattenzugriffe, da InnoDB seine Insert-Puffer dazu benutzen kann, Sekundärindexeinträge als Batch zu verarbeiten.

  • Wenn Ihre Tabellen FOREIGN KEY-Constraints haben, können Sie Tabellenimporte beschleunigen, indem Sie für die Dauer der Import-Session die Fremschlüsselprüfungen abschalten:

    SET FOREIGN_KEY_CHECKS=0;
    ... import operation ...
    SET FOREIGN_KEY_CHECKS=1;
    

    Bei großen Tabellen spart dies eine Menge Plattenzugriffe.

  • Wenn Sie oft wiederkehrende Anfragen auf Tabellen haben, die sich nur selten ändern, nutzen Sie den Query-Cache:

    [mysqld]
    query_cache_type = ON
    query_cache_size = 10M
    

14.2.11.1. Der InnoDB-Monitor

InnoDB hat Monitore, die Informationen über den internen Zustand von InnoDB ausgeben. Sie können jederzeit eine SHOW ENGINE INNODB STATUS-Anweisung erteilen, um die Ausgabe des InnoDB-Standardmonitors in Ihren SQL-Client zu holen. Diese Informationen sind nützlich für das Performance-Tuning. (Wenn Sie den interaktiven SQL-Client mysql benutzen, ist die Ausgabe einfacher zu lesen, wenn Sie das übliche Semikolon am Ende von Anweisungen durch \G ersetzen.) Die Sperrmodi von InnoDB werden in Abschnitt 14.2.10.1, „InnoDB-Sperrmodi“ erklärt.

mysql> SHOW ENGINE INNODB STATUS\G

Eine andere Möglichkeit, InnoDB-Monitore zu nutzen, besteht darin, sie in regelmäßigen Abständen Daten in die Standardausgabe des mysqld-Servers schreiben zu lassen. In diesem Fall wird keine Ausgabe an die Clients gesandt. Wenn sie eingeschaltet sind, geben InnoDB-Monitore etwa alle 15 Sekunden Daten aus. Die Server-Ausgabe wird normalerweise an das .err-Log im MySQL Data Directory geschickt. Diese Daten sind nützlich für das Performance-Tuning. Auf Windows müssen Sie den Server von einer Eingabeaufforderung in einem Konsolenfenster mit der --console-Option starten, wenn Sie die Ausgabe an das Fenster statt in das Fehlerlog schicken wollen.

Die Monitorausgabe enthält folgende Informationen:

  • Tabellen- und Zeilensperren, die von den aktiven Transaktionen gehalten werden

  • Wartende Sperranforderungen von Transaktionen (Lock Waits)

  • Auf Semaphoren wartende Threads

  • Noch schwebende E/A-Requests

  • Statistikdaten über den Bufferpool

  • Aktivitäten des InnoDB-Haupt-Threads zur Verschmelzung von Purge- und Insert-Puffern

Damit der InnoDB-Standardmonitor seine Daten an die Standardausgabe von mysqld sendet, geben Sie folgende SQL-Anweisung:

CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB;

Folgende Anweisung hält den Monitor an:

DROP TABLE innodb_monitor;

Die CREATE TABLE-Syntax ist nur eine Möglichkeit, über den SQL-Parser von MySQL einen Befehl an InnoDB zu übergeben. Es ist nur wichtig, dass der Tabellenname innodb_monitor und der Tabellentyp InnoDB ist. Die Tabellenstruktur ist für den InnoDB-Monitor nicht von Belang. (Diese Syntax kann beim Herunterfahren des Servers wichtig sein, der Monitor fährt bei einem Neustart des Servers nicht automatisch wieder hoch. Sie müssen die Monitortabelle löschen und eine neue CREATE TABLE-Anweisung geben, um den Monitor zu starten. Das kann sich in einem künftigen Release noch ändern.)

innodb_lock_monitor kann ähnlich eingesetzt werden. Dieser gleicht dem innodb_monitor, nur dass er außerdem viele Sperrinformationen gibt. Ein separater innodb_tablespace_monitor gibt eine Liste der angelegten Dateisegmente im Tablespace aus und validiert die Zuweisung der Datenstrukturen im Tablespace. Zusätzlich gibt es den innodb_table_monitor, mit dem Sie den Inhalt des internen Data Dictionary von InnoDB ausgeben können.

Hier sehen Sie eine Beispielausgabe des InnoDB-Monitors:

mysql> SHOW ENGINE INNODB STATUS\G
*************************** 1. row ***************************
Status:
=====================================
030709 13:00:59 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 18 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 413452, signal count 378357
--Thread 32782 has waited at btr0sea.c line 1477 for 0.00 seconds the
semaphore: X-lock on RW-latch at 41a28668 created in file btr0sea.c line 135
a writer (thread id 32782) has reserved it in mode wait exclusive
number of readers 1, waiters flag 1
Last time read locked in file btr0sea.c line 731
Last time write locked in file btr0sea.c line 1347
Mutex spin waits 0, rounds 0, OS waits 0
RW-shared spins 108462, OS waits 37964; RW-excl spins 681824, OS waits
375485
------------------------
LATEST FOREIGN KEY ERROR
------------------------
030709 13:00:59 Transaction:
TRANSACTION 0 290328284, ACTIVE 0 sec, process no 3195, OS thread id 34831
inserting
15 lock struct(s), heap size 2496, undo log entries 9
MySQL thread id 25, query id 4668733 localhost heikki update
insert into ibtest11a (D, B, C) values (5, 'khDk' ,'khDk')
Foreign key constraint fails for table test/ibtest11a:
,
  CONSTRAINT `0_219242` FOREIGN KEY (`A`, `D`) REFERENCES `ibtest11b` (`A`,
  `D`) ON DELETE CASCADE ON UPDATE CASCADE
Trying to add in child table, in index PRIMARY tuple:
 0: len 4; hex 80000101; asc ....;; 1: len 4; hex 80000005; asc ....;; 2:
 len 4; hex 6b68446b; asc khDk;; 3: len 6; hex 0000114e0edc; asc ...N..;; 4:
 len 7; hex 00000000c3e0a7; asc .......;; 5: len 4; hex 6b68446b; asc khDk;;
But in parent table test/ibtest11b, in index PRIMARY,
the closest match we can find is record:
RECORD: info bits 0 0: len 4; hex 8000015b; asc ...[;; 1: len 4; hex
80000005; asc ....;; 2: len 3; hex 6b6864; asc khd;; 3: len 6; hex
0000111ef3eb; asc ......;; 4: len 7; hex 800001001e0084; asc .......;; 5:
len 3; hex 6b6864; asc khd;;
------------------------
LATEST DETECTED DEADLOCK
------------------------
030709 12:59:58
*** (1) TRANSACTION:
TRANSACTION 0 290252780, ACTIVE 1 sec, process no 3185, OS thread id 30733
inserting
LOCK WAIT 3 lock struct(s), heap size 320, undo log entries 146
MySQL thread id 21, query id 4553379 localhost heikki update
INSERT INTO alex1 VALUES(86, 86, 794,'aA35818','bb','c79166','d4766t',
'e187358f','g84586','h794',date_format('2001-04-03 12:54:22','%Y-%m-%d
%H:%i'),7
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 48310 n bits 568 table test/alex1 index
symbole trx id 0 290252780 lock mode S waiting
Record lock, heap no 324 RECORD: info bits 0 0: len 7; hex 61613335383138;
asc aa35818;; 1:
*** (2) TRANSACTION:
TRANSACTION 0 290251546, ACTIVE 2 sec, process no 3190, OS thread id 32782
inserting
130 lock struct(s), heap size 11584, undo log entries 437
MySQL thread id 23, query id 4554396 localhost heikki update
REPLACE INTO alex1 VALUES(NULL, 32, NULL,'aa3572','','c3572','d6012t','',
NULL,'h396', NULL, NULL, 7.31,7.31,7.31,200)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 48310 n bits 568 table test/alex1 index
symbole trx id 0 290251546 lock_mode X locks rec but not gap
Record lock, heap no 324 RECORD: info bits 0 0: len 7; hex 61613335383138;
asc aa35818;; 1:
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 48310 n bits 568 table test/alex1 index
symbole trx id 0 290251546 lock_mode X locks gap before rec insert intention
waiting
Record lock, heap no 82 RECORD: info bits 0 0: len 7; hex 61613335373230;
asc aa35720;; 1:
*** WE ROLL BACK TRANSACTION (1)
------------
TRANSACTIONS
------------
Trx id counter 0 290328385
Purge done for trx's n:o < 0 290315608 undo n:o < 0 17
Total number of lock structs in row lock hash table 70
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 3491, OS thread id 42002
MySQL thread id 32, query id 4668737 localhost heikki
show innodb status
---TRANSACTION 0 290328384, ACTIVE 0 sec, process no 3205, OS thread id
38929 inserting
1 lock struct(s), heap size 320
MySQL thread id 29, query id 4668736 localhost heikki update
insert into speedc values (1519229,1, 'hgjhjgghggjgjgjgjgjggjgjgjgjgjgggjgjg
jlhhgghggggghhjhghgggggghjhghghghghghhhhghghghjhhjghjghjkghjghjghjghjfhjfh
---TRANSACTION 0 290328383, ACTIVE 0 sec, process no 3180, OS thread id
28684 committing
1 lock struct(s), heap size 320, undo log entries 1
MySQL thread id 19, query id 4668734 localhost heikki update
insert into speedcm values (1603393,1, 'hgjhjgghggjgjgjgjgjggjgjgjgjgjgggjgj
gjlhhgghggggghhjhghgggggghjhghghghghghhhhghghghjhhjghjghjkghjghjghjghjfhjf
---TRANSACTION 0 290328327, ACTIVE 0 sec, process no 3200, OS thread id
36880 starting index read
LOCK WAIT 2 lock struct(s), heap size 320
MySQL thread id 27, query id 4668644 localhost heikki Searching rows for
update
update ibtest11a set B = 'kHdkkkk' where A = 89572
------- TRX HAS BEEN WAITING 0 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 65556 n bits 232 table test/ibtest11a index
PRIMARY trx id 0 290328327 lock_mode X waiting
Record lock, heap no 1 RECORD: info bits 0 0: len 9; hex 73757072656d756d00;
asc supremum.;;
------------------
---TRANSACTION 0 290328284, ACTIVE 0 sec, process no 3195, OS thread id
34831 rollback of SQL statement
ROLLING BACK 14 lock struct(s), heap size 2496, undo log entries 9
MySQL thread id 25, query id 4668733 localhost heikki update
insert into ibtest11a (D, B, C) values (5, 'khDk' ,'khDk')
---TRANSACTION 0 290327208, ACTIVE 1 sec, process no 3190, OS thread id
32782
58 lock struct(s), heap size 5504, undo log entries 159
MySQL thread id 23, query id 4668732 localhost heikki update
REPLACE INTO alex1 VALUES(86, 46, 538,'aa95666','bb','c95666','d9486t',
'e200498f','g86814','h538',date_format('2001-04-03 12:54:22','%Y-%m-%d
%H:%i'),
---TRANSACTION 0 290323325, ACTIVE 3 sec, process no 3185, OS thread id
30733 inserting
4 lock struct(s), heap size 1024, undo log entries 165
MySQL thread id 21, query id 4668735 localhost heikki update
INSERT INTO alex1 VALUES(NULL, 49, NULL,'aa42837','','c56319','d1719t','',
NULL,'h321', NULL, NULL, 7.31,7.31,7.31,200)
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
151671 OS file reads, 94747 OS file writes, 8750 OS fsyncs
25.44 reads/s, 18494 avg bytes/read, 17.55 writes/s, 2.33 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf for space 0: size 1, free list len 19, seg size 21,
85004 inserts, 85004 merged recs, 26669 merges
Hash table size 207619, used cells 14461, node heap has 16 buffer(s)
1877.67 hash searches/s, 5121.10 non-hash searches/s
---
LOG
---
Log sequence number 18 1212842764
Log flushed up to   18 1212665295
Last checkpoint at  18 1135877290
0 pending log writes, 0 pending chkp writes
4341 log i/o's done, 1.22 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 84966343; in additional pool allocated 1402624
Buffer pool size   3200
Free buffers       110
Database pages     3074
Modified db pages  2674
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 171380, created 51968, written 194688
28.72 reads/s, 20.72 creates/s, 47.55 writes/s
Buffer pool hit rate 999 / 1000
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
Main thread process no. 3004, id 7176, state: purging
Number of rows inserted 3738558, updated 127415, deleted 33707, read 755779
1586.13 inserts/s, 50.89 updates/s, 28.44 deletes/s, 107.88 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

Einige Hinweise zu dieser Ausgabe:

  • Wenn der TRANSACTIONS-Teil Lock Waits meldet, ist Ihre Anwendung vielleicht durch Sperren blockiert. Die Ausgabe kann auch helfen, die Gründe für Transaktions-Deadlocks festzustellen.

  • Der SEMAPHORES-Teil meldet Threads, die auf Semaphoren warten, und Statistikdaten darüber, wie oft Threads einen Spin oder Wait auf einen Mutex oder eine Semaphpre einer Lese/Schreib-Sperre benötigt haben. Wenn viele Threads auf Semaphoren warten, kann dies am Festplatten-E/A liegen, oder auch an Verstopfungsproblemen in InnoDB. Verstopfungen können durch viele parallele Anfragen oder Probleme im Thread-Management des Betriebssystems bedingt sein. In solchen Situationen kann es helfen, innodb_thread_concurrency auf einen kleineren als den Standardwert zu setzen.

  • Der Abschnitt BUFFER POOL AND MEMORY verrät Ihnen, wie viele Seiten gelesen und geschrieben werden. Aus diesen Zahlen können Sie berechnen, wie viele Datendateizugriffe Ihre Anfragen gerade ausführen.

  • Der Abschnitt ROW OPERATIONS zeigt, was der Haupt-Thread gerade tut.

InnoDB sendet Diagnose-Ausgabe an stderr oder an Dateien anstatt an die stdout-Ausgabe oder Arbeitsspeicherpuffer fester Größe, um Puffer-Überläufe zu verhindern. Als Nebeneffekt wird die Ausgabe von SHOW ENGINE INNODB STATUS alle 15 Sekunden in eine Statusdatei im MySQL Data Directory geschrieben. Diese Datei heißt innodb_status.pid, wobei pid die Server-Prozess-ID ist. InnoDB entfernt diese Datei bei einem normalen Shutdown. Bei einem unnormalen Shutdown können Instanzen dieser Statusdateien überleben und müssen manuell gelöscht werden. Bevor Sie dies tun, sollten Sie allerdings hineinschauen, um zu sehen ob sie irgendwelche Hinweise auf die Ursache der unnormalen Shutdowns enthalten. Die Datei innodb_status.pid wird nur angelegt, wenn die Konfigurationsoption innodb_status_file=1 gesetzt ist.

14.2.12. Implementierung der Multiversionierung

Da InnoDB eine Speicher-Engine mit Multiversionierung ist, muss sie Informationen über ältere Versionen der Zeilen im Tablespace bewahren. Diese Informationen werden in einer Datenstruktur gespeichert, die wie in Oracle Rollback-Segment heißt.

Internally fügt InnoDB jeder Zeile, die in der Datenbank gespeichert wird, zwei Felder hinzu: ein 6 Byte großes Feld mit dem Transaktions-Identifier der letzten Transaktion, mit der die Zeile eingefügt oder geändert worden ist (eine Löschung wird intern wie eine Änderung behandelt, bei der ein bestimmtes Bit in der Zeile gesetzt wird, um sie als gelöscht zu kennzeichnen), und ein 7-Byte-Feld namens Rollpointer. Dieser zeigt auf einen Undo-Logeintrag, der in das Rollback-Segment geschrieben wurde. Wenn die Zeile geändert wurde, enthält dieser Undo-Logeintrag die Daten, die erforderlich sind, um ihren Inhalt von vor der Änderung wiederherzustellen.

InnoDB benutzt die Informationen aus dem Rollback-Segment, um die für ein Transaktions-Rollback erforderlichen Wiederherstellungsoperationen auszuführen. Außerdem dienen die Informationen der Erstellung älterer Versionen einer Zeile für eine konsistente Leseoperation.

Undo-Logs im Rollback-Segment sind in Insert- und Update-Undo-Logs getrennt. Insert-Undo-Logs werden nur für das Transaktions-Rollback gebraucht und können gelöscht werden, sobald die Transaktion committet wird. Update-Undo-Logs werden auch für konsistente Leseoperationen benutzt, können aber verworfen werden, wenn keine Transaktion mehr läuft, für die InnoDB einen Snapshot zugewiesen hat, der für eine konsistente Leseoperation die Daten des Update-Undo-Logs benötigen könnte, um eine ältere Version der Datenbankzeile wiederherzustellen.

Bitte denken Sie daran, Ihre Transaktionen regelmäßig zu committen, einschließlich derjenigen Transaktionen, die nur konsistente Leseoperationen ausgeben. Andernfalls kann InnoDB die Daten aus dem Update-Undo-Log nicht verwerfen und das Rollback-Segment kann so stark anwachsen, dass es Ihren Tablespace ganz ausfüllt.

Die physikalische Größe eines Undo-Logeintrags im Rollback-Segment ist normalerweise kleiner als die zugehörige eingefügte oder geänderte Zeile. Mit diesen Informationen können Sie berechnen, wie viel Platz für Ihr Rollback-Segment erforderlich ist.

In der Multiversionierung von InnoDB wird eine Zeile nicht sofort physikalisch aus der Datenbank entfernt, wenn Sie sie mit einer SQL-Anweisung löschen. Erst wenn InnoDB den für die Löschung erstellten Update-Undo-Logeintrag entfernen kann, kann es auch die Zeile und ihre Indexeinträge physikalisch aus der Datenbank entfernen. Diese Löschoperation bezeichnet man als Purge. Sie läuft sehr schnell, ungefähr genauso schnell wie die SQL-Löschanweisung.

In einem Szenario, in dem der Benutzer Zeilen in kleinen, ungefähr gleichen Batches aus der Tabelle löscht, kann es passieren, dass der Purge-Thread beginnt, hinterherzuhinken, und die Tabelle immer größer wird, wodurch sich alle Festplattenoperationen stark verlangsamen. Selbst Tabellen, die nur 10MB an brauchbaren Daten aufweisen, können mit allen „toten“ Zeilen auf 10GB anwachsen. In solchen Fällen wäre es gut, neue Zeilenoperationen zurückzufahren und dem Purge-Thread mehr Ressourcen zuzuweisen. Genau zu diesem Zweck gibt es die Systemvariable innodb_max_purge_lag. Weitere Informationen finden Sie unter Abschnitt 14.2.4, „InnoDB: Startoptionen und Systemvariablen“.

14.2.13. Tabellen- und Indexstrukturen

MySQL speichert seine Data Dictionary-Informationen über Tabellen in .frm-Dateien in Datenbankverzeichnissen. Das gilt für alle Speicher-Engines von MySQL. Doch jede InnoDB-Tabelle hat auch einen eigenen Eintrag im internen InnoDB-Data Dictionary innerhalb des Tablespace. Wenn MySQL eine Tabelle oder Datenbank löscht, muss es sowohl die .frm-Datei(en) als auch die zugehörigen Einträge im InnoDB-Data Dictionary löschen. Daher dürfen Sie auch InnoDB-Tabellen nicht einfach durch Verschieben der .frm-Dateien von einer Datenbank in die andere übertragen.

Jede InnoDB-Tabelle besitzt einen speziellen, so genannten geclusterten Index, der die Daten über die Zeilen speichert. Wenn Sie einen PRIMARY KEY auf Ihrer Tabelle definieren, ist der Index dieses Primärschlüssels der geclusterte Index.

Wenn Sie keinen PRIMARY KEY für Ihre Tabelle definieren, wählt MySQL den ersten UNIQUE-Index, der nur NOT NULL-Spalten hat, als Primärschlüssel aus, und InnoDB verwendet diesen als geclusterten Index. Wenn die Tabelle keinen solchen Index besitzt, wird intern von InnoDB ein geclusterter Index generiert, in dem die Zeilen nach der Zeilen-ID geordnet sind, die InnoDB den Zeilen derartiger Tabellen zuweist. Die Zeilen-ID ist ein 6-Byte-Feld, das monoton wächst, wenn neue Zeilen eingefügt werden. Somit stehen die nach Zeilen-ID geordneten Zeilen physikalisch in der Reihenfolge ihrer Einfügung.

Über einen geclusterten Index ist eine Zeile schnell zu erreichen, da die Zeilendaten auf derselben Seite liegen, zu der die Indexsuche hinführt. Wenn eine Tabelle groß ist, speichert die Clustered-Index-Architektur im Vergleich zu der traditionellen Lösung oft Plattenzugriffe. (In vielen Datenbanksystemen sind die Daten auf einer anderen Seite gespeichert als der Indexeintrag.)

In InnoDB enthalten die Datensätze in nicht-geclusterten Indizes (auch Sekundärindizes genannt) den Primärschlüsselwert für die Zeile. InnoDB benutzt diesen Primärschlüsselwert, um die Zeile in dem geclusterten Index zu suchen. Beachten Sie: Wenn der Primärschlüssel lang ist, brauchen die Sekundärindizes mehr Platz.

InnoDB vergleicht unterschiedlich lange CHAR- und VARCHAR-Strings, indem es die Längendifferenz im kürzeren String als mit Leerzeichen ausgefüllt betrachtet.

14.2.13.1. Physikalische Struktur eines Index

Alle InnoDB-Indizes sind B-Trees, wobei die Indexeinträge in den Blattseiten des Baums gespeichert werden. Die Standardgröße einer Indexseite beträgt 16KB. Wenn neue Einträge eingefügt werden, versucht InnoDB, 1/16 der Seite für zukünftige Einfügungen und Änderungen der Indexeinträge frei zu halten.

Wenn Indexeinträge in (auf- oder absteigender) sequenzieller Reihenfolge eingefügt werden, werden die Indexseiten zu 15/16 voll. Werden die Einträge in zufälliger Reihenfolge eingefügt, werden die Seiten nur zu 1/2 bis 15/16 voll. Wenn der Füllstand einer Indexseite unter 1/2 fällt, versucht InnoDB mit dem Indexbaum zu vereinbaren, dass die Seite freigegeben wird.

14.2.13.2. Einfügepufferung

In Datenbankanwendungen kommt es häufig vor, dass ein Primärschlüssel ein eindeutiger Identifier ist und neue Zeilen in der aufsteigenden Reihenfolge des Primärschlüssels eingefügt werden. So sind für Einfügungen in den geclusterten Index keine willkürlichen Lesezugriffe auf eine Festplatte erforderlich.

Dagegen sind Sekundärindizes normalerweise nicht-eindeutig und Einfügungen in sie finden in relativ willkürlicher Reihenfolge statt. Dies würde eine Menge willkürlicher E/A-Operationen auf der Festplatte erfordern, wenn es in InnoDB nicht einen speziellen Mechanismus gäbe.

Wenn ein Indexeintrag in einen nicht-eindeutigen Sekundärindex eingefügt werden soll, prüft InnoDB, ob dieser Sekundärindex im Bufferpool liegt. Wenn ja, führt InnoDB die Einfügung direkt auf der Indexseite durch. Wenn nicht, fügt InnoDB den Eintrag in eine spezielle Insert-Puffer-Struktur ein. Der Insert-Puffer wird so klein gehalten, dass er komplett in den Bufferpool passt und Einfügungen sehr schnell erledigt werden können.

Dieser Insert-Puffer wird regelmäßig mit den Sekundärindexbäumen in der Datenbank zusammengeführt. Oft können mehrere Einfügeoperationen auf derselben Seite des Indexbaums gleichzeitig zusammengeführt werden, was Festplattenzugriffe spart. Messungen haben ergeben, dass der Insert-Puffer Einfügungen in eine Tabelle bis zu 15-mal schneller laufen lässt.

Das Zusammenführen von Insert-Puffer-Daten kann auch dann weitergehen, nachdem die einfügende Transaktion committet wurde, ja sogar nach dem Herunterfahren und Neustart des Servers (siehe Abschnitt 14.2.8.1, „Erzwingen einer InnoDB-Wiederherstellung (Recovery)“).

Das Zusammenführen von Insert-Puffer-Daten kann viele Stunden dauern, wenn viele Sekundärindizes aktualisiert werden müssen und viele Zeilen eingefügt wurden. In dieser Zeit erhöht sich die E/A-Aktivität, sodass festplattengebundene Anfragen eventuell viel langsamer laufen. Eine andere, wichtige E/A-Hintergrundoperation ist der Purge-Thread (siehe Abschnitt 14.2.12, „Implementierung der Multiversionierung“).

14.2.13.3. Anpassungsfähige Hash-Indizes

Wenn eine Tabelle fast komplett in den Hauptspeicher passt, sind Hash-Indizes das schnellste Mittel, um Anfragen auszuführen. InnoDB hat einen Mechanismus, der Index-Suchen auf den Indizes einer Tabelle beobachtet. Wenn InnoDB bemerkt, dass Anfragen von einem Hash-Index profitieren könnten, baut es automatisch einen auf.

Beachten Sie, dass der Hash-Index immer auf einem vorhandenen B-Baum-Index der Tabelle aufbaut. InnoDB kann einen Hash-Index auf einem beliebig langen Präfix des für den B-Baum definierten Schlüssels aufbauen, je nachdem, welches Suchmuster InnoDB für den B-Baum-Index beachtet. Ein Hash-Index kann auch partiell sein: Es ist nicht notwendig, den gesamten B-Baum-Index im Bufferpool zu cachen. InnoDB baut Hash-Indizes nach Bedarf für diejenigen Indexseiten auf, die oft angesprochen werden.

In gewissem Sinne legt sich InnoDB durch den anpassungsfähigen Hash-Index-Mechanismus selbst auf einen großen Arbeitsspeicher hin aus und kommt dadurch der Architektur von Hauptspeicher-Datenbanken näher.

14.2.13.4. Physikalische Datensatzstruktur

Datensätze von InnoDB-Tabellen haben folgende Merkmale:

  • Jeder Indexeintrag hat einen sechs Bytes großen Header, der benutzt wird, um aufeinanderfolgende Datensätze zu verknüpfen, und auch in Zeilensperren zum Einsatz kommt.

  • Einträge im geclusterten Index enthalten Felder für alle benutzerdefinierten Spalten. Zusätzlich gibt es ein sechs Bytes großes Feld für die Transaktions-ID und ein sieben Bytes großes für den Rollpointer.

  • Wenn für eine Tabelle kein Primärschlüssel definiert wurde, enhält jeder geclusterte Indexeintrag auch ein sechs Bytes großes Feld mit der Zeilen-ID.

  • Jeder Sekundärindexeintrag enthält auch alle Felder, die für den geclusterten Indexschlüssel definiert worden sind.

  • Ein Datensatz enthält auch einen Zeiger auf die einzelnen Felder des Datensatzes. Wenn deren Gesamtlänge 128 Bytes nicht übersteigt, ist der Zeiger ein Byte, ansonsten zwei Bytes groß. Das Array dieser Zeiger bezeichnet man als Record Directory. Der Bereich, auf den sie zeigen, ist der Datenteil des Datensatzes.

  • Intern speichert InnoDB Zeichenspalten fester Breite, wie beispielsweise CHAR(10), in einem Format mit fester Länge. InnoDB kappt Leerzeichen am Ende von VARCHAR-Spalten.

  • Ein SQL-NULL-Wert reserviert 1 oder 2 Bytes im Record Directory und null Bytes im Datenteil des Eintrags, wenn er in einer Spalte mit variabler Länge gespeichert ist. In einer Spalte fester Länge reserviert er diese festgelegte Länge auch für NULL-Werte, damit eine Aktualisierung, die die Spalte von NULL auf einen anderen Wert setzt, vor Ort ohne Fragmentierung der Indexseite ausgeführt werden kann.

14.2.14. Verwaltung von Speicherplatz für Dateien und von Festplattenein- und -ausgaben

14.2.14.1. Festplattenein- und -ausgaben

InnoDB verwendet simulierte, asynchrone Festplattenein- und -ausgaben (E/A) und erzeugt mehrere Threads für E/A-Operationen wie beispielsweise Read-ahead.

Es gibt zwei Read-ahead-Heuristiken in InnoDB:

  • Beim sequenziellen Read-ahead schickt InnoDB, wenn es bemerkt, dass ein Segment im Tablespace ein sequenzielles Zugriffsmuster aufweist, im Voraus einen Batch Leseoperationen auf Datenbankseiten an das E/A-System.

  • Beim willkürlichen Read-ahead schickt InnoDB, wenn es bemerkt, dass ein Bereich im Tablespace im Begriff ist, vollständig in den Bufferpool eingelesen zu werden, die restlichen Leseoperationen an das E/A-System.

InnoDB verwendet eine neue Technik namens Doublewrite, um Dateien auf die Festplatte zurückzuschreiben. Dadurch wird die Recovery nach einem Betriebssystemabsturz oder einem Stromausfall sicherer und die Leistung der meisten Unix-Varianten besser, da nicht mehr so viele fsync()-Operationen nötig sind.

Doublewrite sorgt dafür, dass InnoDB Seiten nicht gleich in die Datendatei, sondern zuerst in einen zusammenhängenden Tablespace-Bereich namens Doublewrite-Puffer schreibt. Erst wenn dieser Vorgang abgeschlossen ist, werden die Seiten in ihre angestammten Plätze in der Datendatei geschrieben. Stürzt das Betriebssystem mitten im Schreiben einer Seite ab, kann InnoDB später bei der Recovery eine gute Kopie der Seite im Doublewrite-Puffer finden.

14.2.14.2. Speicherplatzverwaltung

Die in der Konfigurationsdatei definierten Datendateien bilden den Tablespace von InnoDB. Die Dateien werden einfach aneinander gehängt, um diesen Tablespace zu bilden. Es wird kein Striping verwendet. Zurzeit können Sie noch nicht bestimmen, an welche Stelle des Tablespaces Ihre Tabellen zugewiesen werden. Doch in einem neuen Tablespace wird der Platz beginnend mit der ersten Datendatei zugewiesen.

Der Tablespace besteht aus Datenbankseiten mit einer Standardgröße von 16KB. Die Seiten werden zu Extents von 64 aufeinander folgenden Seiten zusammengefasst. Die „Dateien“ eines Tablespace nennt man in InnoDB Segmente. Der Begriff „Rollback-Segment“ ist etwas irreführend, da er in Wirklichkeit viele Tablespace-Segmente umfasst.

Für jeden Index in InnoDB werden zwei Segmente zugewiesen. eines für Nicht-Blattknoten und das andere für Blattknoten des B-Baums. Dadurch wird eine bessere Abfolge der Blattknoten, die die eigentlichen Daten enthalten, erreicht.

Wenn ein Segment im Tablespace anwächst, weist ihm InnoDB die ersten 32 Seiten einzeln zu, und danach nur noch vollständige Extents. InnoDB kann einem großen Segment bis zu 4 Extents zugleich zuweisen, um eine gute Datensequenzialität zu gewährleisten.

Da manche Seiten im Tablespace Bitmaps anderer Seiten enthalten, können einige Extents eines InnoDB-Tablespace den Segmenten nicht als Ganzes, sondern nur in Form einzelner Seiten zugewiesen werden.

Wenn Sie mit einer SHOW TABLE STATUS-Anweisung fragen, wie viel Platz in einem Tablespace noch frei ist, meldet InnoDB nur die Extents, die darin definitiv noch nicht belegt sind. InnoDB reserviert immer einige Extents für die Reinigungsaufgaben und andere interne Zwecke. Diese reservierten Extents sind in dem freien Platz nicht inbegriffen.

Wenn Sie Daten aus einer Tabelle löschen, kontrahiert InnoDB die entsprechenden B-Baum-Indizes. Ob der frei gewordene Platz für ander Benutzer verfügbar wird, hängt davon ab, ob das Löschungsmuster einzelne Seiten oder ganze Extents des Tablespace freigibt. Wenn Sie eine Tabelle oder alle in ihr befindlichen Zeilen löschen, dann wird garantiert der Platz für andere Benutzer freigegeben, aber vergessen Sie nicht, dass gelöschte Zeilen physikalisch erst in einer (automatischen) Purge-Operation entfernt werden, wenn sie auch für Transaktions-Rollbacks und konsistente Leseoperationen nicht mehr gebraucht werden. (Siehe Abschnitt 14.2.12, „Implementierung der Multiversionierung“.)

14.2.14.3. Eine Tabelle defragmentieren

Wenn willkürliche Einfügungen oder Löschungen in den Indizes einer Tabelle vorgenommen werden, können diese Indizes fragmentiert werden. Fragmentierung bedeutet, dass die physikalische Reihenfolge der Indexseiten auf der Platte nicht der Reihenfolge des Index für die Datensätze der Seiten entspricht, oder dass viele ungenutzte Seiten in den 64-Seiten-Blöcken vorhanden sind, die dem Index zugewiesen wurden.

Ein Fragmentierungssymptom liegt vor, wenn eine Tabelle mehr Platz belegt, als sie „sollte“. Wieviel mehr, das ist in der Praxis schwer zu sagen. Alle InnoDB-Daten und -Indizes werden in B-Bäumen gespeichert und ihr Füllfaktor kann zwischen 50% und 100% variieren. Ein anderes Symptom für Fragmentierung wäre es, wenn ein Tabellenscan wie dieser mehr Zeit braucht, als er „sollte“:

SELECT COUNT(*) FROM t WHERE a_non_indexed_column <> 12345;

(In der obigen Anfrage „überlisten“ wir die SQL-Optimierung, damit sie statt des Sekundärindex den geclusterten Index durchsucht.) Die meisten Festplatten können 10 bis 50MB/s lesen. Anhand dieses Werts können sie einschätzen, wie schnell ein Tabellenscan eigentlich laufen sollte.

Index-Scans können schneller laufen, wenn Sie regelmäßig eine „Null“-ALTER TABLE-Operation durchführen:

ALTER TABLE tbl_name ENGINE=INNODB

Dies veranlasst MySQL, die Tabelle neu zu erstellen. Eine andere Möglichkeit für eine Defragmentierungsoperation wäre es, die Tabelle mit mysqldump in eine Textdatei zu dumpen, zu löschen und aus der Dump-Datei neu zu laden.

Wenn die Einfügungen in einen Index immer in aufsteigender Reihenfolge und Löschungen nur an seinem Ende stattfinden, garantiert der Dateiraumverwaltungs-Algorithmus von InnoDB, dass keine Fragmentierung in diesem Index auftreten kann.

14.2.15. InnoDB-Fehlerbehandlung

Die Fehlerbehandlung in InnoDB entspricht nicht immer dem SQL-Standard. Nach dem Standard müsste jeder Fehler, der während einer SQL-Anweisung auftritt, den Rollback dieser Anweisung zur Folge haben. InnoDB rollt jedoch manchmal nur einen Teil der Anweisung zurück, oder aber auch die ganze Transaktion. Die folgenden Einträge beschreiben die Fehlerbehandlung von InnoDB:

  • Wenn Ihr Tablespace vollläuft, tritt ein MySQL Table is full-Fehler auf und InnoDB rollt die SQL-Anweisung zurück.

  • Ein Transaktions-Deadlock lässt InnoDB die gesamte Transaktion zurückrollen. Im Fall eines Lock Wait Timeout rollt InnoDB nur die letzte SQL-Anweisung zurück.

    Wenn wegen eines Deadlocks oder Lock Wait Timeouts eine Transaktion zurückgerollt wird, so werden die in dieser Transaktion ausgeführten Anweisungen wirkungslos. Wenn jedoch die Startanweisung der Transaktion START TRANSACTION oder BEGIN war, so wird die Anweisung durch den Rollback nicht betroffen. Weitere SQL-Anweisungen werden dann zu einem Teil der Transaktion, bis ein COMMIT, ROLLBACK oder eine andere SQL-Anweisung eintritt, die einen impliziten Commit verursacht.

  • Ein Schlüsselduplikat-Fehler rollt die SQL-Anweisung zurück, wenn Sie nicht die IGNORE-Option in der Anweisung angegeben haben.

  • Ein row too long error rollt die SQL-Anweisung zurück.

  • Andere Fehler werden zumeist auf der MySQL-Ebene erkannt (also oberhalb der Ebene von InnoDB), und rollen die zugehörige SQL-Anweisung zurück. Sperren werden bei einem Rollback einer einzelnen SQL-Anweisung nicht freigegeben.

Während eines impliziten Rollback und während der Ausführung eines expliziten ROLLBACK-Befehls von SQL zeigt SHOW PROCESSLIST den Wert Rolling back in der State-Spalte der betreffenden Verbindung an.

14.2.15.1. InnoDB-Fehlercodes

Es folgt eine (nicht vollständige) Liste häufiger InnoDB-spezifischer Fehler, einschließlich ihrer Ursachen und Lösungsmöglichkeiten.

  • 1005 (ER_CANT_CREATE_TABLE)

    Tabelle kann nicht angelegt werden. Wenn die Fehlermeldung auf errno 150 verweist, schlug die Tabellenerzeugung fehl, weil ein Fremdschlüssel-Constraint nicht richtig gebildet wurde.

  • 1016 (ER_CANT_OPEN_FILE)

    Die InnoDB-Tabelle kann in den InnoDB-Datendateien nicht gefunden werden, obwohl die .frm-Datei für die Tabelle existiert. Siehe Abschnitt 14.2.17.1, „Troubleshooting von InnoDB bei Data Dictionary-Operationen“.

  • 1114 (ER_RECORD_FILE_FULL)

    InnoDB hat keine Platz im Tablespace mehr frei. Rekonfigurieren Sie den Tablespace, indem Sie eine neue Datendatei hinzufügen.

  • 1205 (ER_LOCK_WAIT_TIMEOUT)

    Lock Wait Timeout ist abgelaufen. Transaktion wurde zurückgerollt.

  • 1213 (ER_LOCK_DEADLOCK)

    Transaktions-Deadlock. Führen Sie die Transaktion erneut aus.

  • 1216 (ER_NO_REFERENCED_ROW)

    Sie versuchen, eine neue Zeile einzufügen, aber da es keine Elternzeile gibt, wird ein Fremdschlüssel-Constraint verletzt. Fügen Sie als Erstes die Elternzeile ein.

  • 1217 (ER_ROW_IS_REFERENCED)

    Sie versuchen, eine Elternzeile zu löschen, die Kinder hat, wodurch ein Fremdschlüssel-Constraint verletzt wird. Löschen Sie zuerst die Kinder.

14.2.15.2. Betriebssystembedingte Fehlercodes

Die Bedeutung einer Betriebssystem-Fehlernummer können Sie mit dem Programm perror ermitteln, das zur MySQL-Distribution gehört.

Die folgende Tabelle enthält eine Liste der häufigsten Systemfehlercodes von Linux. Eine vollständigere Aufstellung finden Sie unter Linux-Quellcode.

  • 1 (EPERM)

    Operation nicht gestattet

  • 2 (ENOENT)

    Datei oder Verzeichnis nicht vorhanden

  • 3 (ESRCH)

    Prozess nicht vorhanden

  • 4 (EINTR)

    Unterbrochener Systemaufruf

  • 5 (EIO)

    E/A-Fehler

  • 6 (ENXIO)

    Device oder Adresse nicht vorhanden

  • 7 (E2BIG)

    Argumenteliste zu lang

  • 8 (ENOEXEC)

    Exec-Format-Fehler

  • 9 (EBADF)

    Dateinummer stimmt nicht

  • 10 (ECHILD)

    Kein Kindprozess

  • 11 (EAGAIN)

    Versuchen Sie es erneut

  • 12 (ENOMEM)

    Kein Arbeitsspeicher mehr frei

  • 13 (EACCES)

    Berechtigung verweigert

  • 14 (EFAULT)

    Adresse stimmt nicht

  • 15 (ENOTBLK)

    Block-Device erforderlich

  • 16 (EBUSY)

    Device oder Ressource ist belegt

  • 17 (EEXIST)

    Datei vorhanden

  • 18 (EXDEV)

    Cross-Device-Link

  • 19 (ENODEV)

    Device nicht vorhanden

  • 20 (ENOTDIR)

    Ist kein Verzeichnis

  • 21 (EISDIR)

    Ist ein Verzeichnis

  • 22 (EINVAL)

    Ungültiges Argument

  • 23 (ENFILE)

    Dateitabellenüberlauf

  • 24 (EMFILE)

    Zu viele geöffnete Dateien

  • 25 (ENOTTY)

    Unpassender ioctl für Device

  • 26 (ETXTBSY)

    Textdatei belegt

  • 27 (EFBIG)

    Datei zu groß

  • 28 (ENOSPC)

    Device hat keinen Platz mehr frei

  • 29 (ESPIPE)

    Unzulässige Suche

  • 30 (EROFS)

    Schreibgeschütztes Dateisystem

  • 31 (EMLINK)

    Zu viele Links

Die folgende Tabelle enthält eine Liste häufiger Windows-Systemfehlercodes. Eine vollständigere Aufstellung finden Sie auf der Website von Microsoft.

  • 1 (ERROR_INVALID_FUNCTION)

    Funktion nicht korrekt

  • 2 (ERROR_FILE_NOT_FOUND)

    System kann die Datei nicht finden

  • 3 (ERROR_PATH_NOT_FOUND)

    System kann den Pfad nicht finden

  • 4 (ERROR_TOO_MANY_OPEN_FILES)

    System kann die Datei nicht öffnen

  • 5 (ERROR_ACCESS_DENIED)

    Zugriff verweigert

  • 6 (ERROR_INVALID_HANDLE)

    Ungültiger Handle

  • 7 (ERROR_ARENA_TRASHED)

    Speichersteuerungsblöcke wurden zerstört

  • 8 (ERROR_NOT_ENOUGH_MEMORY)

    Zu wenig Speicher, um diesen Befehl zu verarbeiten

  • 9 (ERROR_INVALID_BLOCK)

    Speichersteuerungsblock-Adresse ist ungültig

  • 10 (ERROR_BAD_ENVIRONMENT)

    Die Umgebung ist nicht korrekt

  • 11 (ERROR_BAD_FORMAT)

    Versuch, ein Programm mit einem unzulässigen Format zu laden

  • 12 (ERROR_INVALID_ACCESS)

    Zugriffscode ist ungültig

  • 13 (ERROR_INVALID_DATA)

    Daten sind ungültig

  • 14 (ERROR_OUTOFMEMORY)

    Nicht genug Speicher vorhanden, um die Operation auszuführen

  • 15 (ERROR_INVALID_DRIVE)

    System kann das angegebene Laufwerk nicht finden

  • 16 (ERROR_CURRENT_DIRECTORY)

    Verzeichnis kann nicht entfernt werden

  • 17 (ERROR_NOT_SAME_DEVICE)

    System kann die Datei nicht auf ein anderes Festplattenlaufwerk verlagern

  • 18 (ERROR_NO_MORE_FILES)

    Keine weiteren Dateien vorhanden

  • 19 (ERROR_WRITE_PROTECT)

    Schreibgeschütztes Speichermedium

  • 20 (ERROR_BAD_UNIT)

    System kann das angegebene Gerät nicht finden

  • 21 (ERROR_NOT_READY)

    Gerät ist nicht bereit

  • 22 (ERROR_BAD_COMMAND)

    Gerät erkennt den Befehl nicht

  • 23 (ERROR_CRC)

    Datenfehler (zyklische Redundanzprüfung)

  • 24 (ERROR_BAD_LENGTH)

    Das Programm hat einen Befehl gegeben, dessen Länge nicht stimmt

  • 25 (ERROR_SEEK)

    Das Laufwerk konnte einen bestimmten Bereich oder Track auf der Festplatte nicht finden

  • 26 (ERROR_NOT_DOS_DISK)

    Kein Zugriff auf die Platte oder Diskette

  • 27 (ERROR_SECTOR_NOT_FOUND)

    Das Laufwerk kann den angeforderten Sektor nicht finden

  • 28 (ERROR_OUT_OF_PAPER)

    Kein Papier im Drucker

  • 29 (ERROR_WRITE_FAULT)

    System kann auf das angegebene Gerät nicht schreiben

  • 30 (ERROR_READ_FAULT)

    System kann von dem angegebenen Gerät nicht lesen

  • 31 (ERROR_GEN_FAILURE)

    Ein mit dem System verbundenes Gerät funktioniert nicht

  • 32 (ERROR_SHARING_VIOLATION)

    Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess benutzt wird

  • 33 (ERROR_LOCK_VIOLATION)

    Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess teilweise gesperrt wurde

  • 34 (ERROR_WRONG_DISK)

    Verkehrte Diskette im Laufwerk. Legen Sie %2 (Volume-Seriennummer: %3) in Laufwerk %1 ein

  • 36 (ERROR_SHARING_BUFFER_EXCEEDED)

    Zu viele Dateien für gemeinsame Nutzung geöffnet

  • 38 (ERROR_HANDLE_EOF)

    Dateiende erreicht

  • 39 (ERROR_HANDLE_DISK_FULL)

    Festplatte ist voll

  • 87 (ERROR_INVALID_PARAMETER)

    Der Parameter ist verkehrt. (Wenn auf Windows dieser Fehler auftritt und innodb_file_per_table in einer Serveroptionsdatei eingeschaltet wurde, fügen Sie der Datei zusätzlich die Zeile innodb_flush_method=unbuffered hinzu.)

  • 112 (ERROR_DISK_FULL)

    Festplatte ist voll

  • 123 (ERROR_INVALID_NAME)

    Dateiname oder Verzeichnisname oder Volume-Label-Syntax ist verkehrt

  • 1450 (ERROR_NO_SYSTEM_RESOURCES)

    Systemressourcen reichen nicht, um den angefragten Service abzuschließen

14.2.16. Beschränkungen von InnoDB-Tabellen

  • Warnung: Konvertieren Sie niemals MySQL-Systemtabellen in der mysql-Datenbank aus dem MyISAM- in das InnoDB-Format! Diese Operation wird nicht unterstützt. Wenn Sie dies tun, kann MySQL erst dann wieder gestartet werden, wenn Sie die alten Systemtabellen aus einem Backup wiederhergestellt oder mit dem Skript mysql_install_db neu generiert haben.

  • Eine Tabelle darf nicht mehr als 1000 Spalten haben.

  • Die interne maximale Schlüssellänge beträgt 3500 Bytes, aber MySQL selbst schränkt dies auf 1024 Bytes ein.

  • Die maximale Zeilenlänge beträgt (außer bei VARCHAR-, BLOB- und TEXT-Spalten) etwas weniger als die Hälfte einer Datenbankseite, also rund 8000 Bytes. LONGBLOB- und LONGTEXT-Spalten müssen kleiner als 4GB und die maximale Länge einer Zeile (auch bei BLOB- und TEXT-Spalten) muss kleiner als 4GB sein. InnoDB speichert die ersten 768 Bytes einer VARCHAR-, BLOB- oder TEXT-Spalte in der Zeile und den Rest in separaten Seiten.

  • Obwohl InnoDB intern auch Zeilen von mehr als 65535 unterstützt, können Sie keine Zeile definieren, die VARCHAR-Spalten mit einer kombinierten Größe von mehr als 65535 enthält:

    mysql> CREATE TABLE t (a VARCHAR(8000), b VARCHAR(10000),
        -> c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
        -> f VARCHAR(10000), g VARCHAR(10000)) ENGINE=InnoDB;
    ERROR 1118 (42000): Row size too large. The maximum row size for the
    used table type, not counting BLOBs, is 65535. You have to change some
    columns to TEXT or BLOBs
    
  • Auf manchen älteren Betriebssystemen müssen Dateien kleiner als 2GB sein. Das ist zwar keine InnoDB-spezifische Beschränkung, aber wenn Sie einen großen Tablespace benötigen, müssen Sie diesen so konfigurieren, dass er mehrere kleine statt einer großen Datendatei enthält.

  • Die kombinierte Größe aller InnoDB-Logdateien muss unter 4GB liegen.

  • Die Mindestgröße eines Tablespace beträgt 10MB und seine Höchstgröße vier Milliarden Datenbankseiten (64TB). Dies ist auch die Maximalgröße für eine Tabelle.

  • InnoDB-Tabellen unterstützen keine FULLTEXT-Indizes.

  • ANALYZE TABLE ermittelt die Indexkardinalität (anhand der Cardinality-Spalte der Ausgabe von SHOW INDEX), indem er acht Zufallssprünge in jeden der Indexbäume unternimmt und die Schätzungen der Indexkardinalität entsprechend aktualisiert. Da dies nur Schätzungen sind, können unterschiedliche Ausführungen von ANALYZE TABLE unterschiedliche Zahlen ergeben. Dadurch läuft ANALYZE TABLE auf InnoDB-Tabellen zwar schnell, aber nicht zu 100% präzise, da es nicht alle Zeilen berücksichtigt.

    MySQL verwendet die Indexkardinalitäts-Schätzungen nur in der Optimierung von Joins. Ist ein Join nicht richtig optimiert, können Sie es mit ANALYZE TABLE versuchen. In den seltenen Fällen, da ANALYZE TABLE für Ihre Tabellen keine ausreichend guten Werte produziert, können Sie Ihre Anfragen mit FORCE INDEX ausführen und ihnen damit einen bestimmten Index aufzwingen, oder die Systemvariable max_seeks_for_key setzen, damit MySQL eher im Index nachschaut, als Tabellen zu scannen. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“ und Abschnitt A.6, „Probleme im Zusammenhang mit dem Optimierer“.

  • SHOW TABLE STATUS zeigt keine präzisen Statistikdaten über InnoDB-Tabellen an, wenn man von der physikalischen Größe absieht, die für sie reserviert ist. Die Zeilenzahl ist nur eine grobe Schätzung, die für die SQL-Optimierung genutzt wird.

  • InnoDB pflegt keinen internen Zähler für die Anzahl der Zeilen in einer Tabelle. (In der Praxis wäre das wegen der Multiversionierung auch etwas kompliziert.) Um eine SELECT COUNT(*) FROM t-Anweisung zu verarbeiten, muss InnoDB einen Index der Tabelle scannen. Das braucht Zeit, wenn der Index nicht komplett im Bufferpool liegt. Um schneller eine Zahl zu erhalten, müssen Sie selbst eine Zählertabelle erstellen und dafür sorgen, dass Ihre Anwendung sie bei Einfügungen und Löschungen aktualisiert. Wenn sich Ihre Tabelle nicht oft ändert, ist der MySQL-Anfragecache eine gute Lösung. SHOW TABLE STATUS kann ebenfalls eingesetzt werden, wenn Ihnen ein Näherungswert genügt. Siehe Abschnitt 14.2.11, „Tipps zur Leistungssteigerung“.

  • Auf Windows speichert InnoDB Datenbank- und Tabellennamen intern immer in Kleinbuchstaben. Um Datenbanken im Binärformat von Unix auf Windows oder umgekehrt zu übertragen, sollten Sie immer explizit klein geschriebene Namen für Datenbanken und Tabellen verwenden.

  • Für eine AUTO_INCREMENT-Spalte müssen Sie immer einen Index für die Tabelle definieren, der nur diese AUTO_INCREMENT-Spalte enthält. In MyISAM-Tabellen kann die AUTO_INCREMENT-Spalte auch Teil eines Mehrspaltenindex sein.

  • Wenn Sie den MySQL-Server neu starten, kann InnoDB einen alten Wert wiederverwenden, der für eine AUTO_INCREMENT-Spalte zwar angelegt, aber nie gespeichert wurde (also einen Wert, der während einer älteren Transaktion generiert wurde, die zurückgerollt worden ist).

  • Wenn einer AUTO_INCREMENT-Spalte die Werte ausgehen, bricht InnoDB einen BIGINT auf -9223372036854775808 und BIGINT UNSIGNED auf 1 um. Da jedoch BIGINT-Werte 64 Bits haben, würde es, selbst wenn Sie eine Million Zeilen pro Sekunde einfügten, immer noch fast dreihunderttausend Jahre dauern, bis BIGINT an seine Grenze stößt. Bei allen anderen Integerspalten würde ein Fehler wegen Schlüsselduplikat die Folge sein. MyISAM funktioniert ähnlich, da dies im Wesentlichen dem normalen MySQL-Verhalten und nicht dem einer bestimmten Speicher-Engine entspricht.

  • DELETE FROM tbl_name generiert die Tabelle nicht neu, sondern löscht eine nach der anderen alle Zeilen.

  • Unter bestimmten Gegebenheiten wird TRUNCATE tbl_name für eine InnoDB-Tabelle wie DELETE FROM tbl_name behandelt und setzt nicht den AUTO_INCREMENT-Zähler zurück. Siehe Abschnitt 13.2.9, „TRUNCATE.

  • In MySQL 5.1, erwirbt die MySQL-Operation LOCK TABLES zwei Sperren auf jeder Tabelle, wenn innodb_table_locks=1 (die Standardeinstellung). Zusätzlich zu einer Tabellensperre auf der MySQL-Ebene, errichtet es auch eine InnoDB-Tabellensperre. Ältere MySQL-Versionen errichteten keine InnoDB-Tabellensperren. Dieses alte Verhalten kann mit innodb_table_locks=0 eingestellt werden. Wenn keine InnoDB-Tabellensperre erworben wird, läuft LOCK TABLES auch dann, wenn einige Datensätze der Tabellen von anderen Transaktionen gesperrt sind.

  • Alle InnoDB-Sperren, die eine Transaktion hält, werden freigegeben, wenn die Transaktion committet oder abgebrochen wird. Also hat es wenig Sinn LOCK TABLES auf InnoDB-Tabellen im AUTOCOMMIT=1-Modus aufzurufen, da die InnoDB-Tabellensperren sofort freigegeben würden.

  • Manchmal wäre es nützlich, im Laufe einer Transaktion noch weitere Tabellen zu sperren. Doch leider führt LOCK TABLES in MySQL ein implizites COMMIT und UNLOCK TABLES aus. Es ist eine InnoDB-Variante von LOCK TABLES geplant, die auch inmitten einer Transaktion ausgeführt werden kann.

  • Die LOAD TABLE FROM MASTER-Anweisung zum Einrichten eines Slaveservers für die Replikation funktioniert noch nicht mit InnoDB-Tabellen. Als Workaround können Sie die Tabelle auf dem Master in MyISAM konvertieren, dann laden und hinterher die Mastertabelle wieder auf InnoDB umstellen. Dies geht jedoch nicht mit Tabellen, die InnoDB-spezifische Features wie etwa Fremdschlüssel verwenden.

  • Die Standardgröße für Datenbankseiten in InnoDB beträgt 16KB. Indem Sie den Code rekompilieren, können Sie Werte zwischen 8KB und 64KB einstellen. Sie müssen dazu die Werte von UNIV_PAGE_SIZE und UNIV_PAGE_SIZE_SHIFT in der Quelldatei univ.i ändern.

  • Trigger werden zurzeit noch nicht durch kaskadierende Fremdschlüsselaktionen aktiviert.

14.2.17. InnoDB-Troubleshooting

Die folgenden allgemeinen Richtlinien gelten für die Behebung von InnoDB-Problemen:

  • Wenn eine Operation scheitert oder Sie einen Bug vermuten, schauen Sie in das Fehlerlog des MySQL-Servers. es ist die Datei im Data Directory, die das Suffix .err trägt.

  • Für die Problembehebung führen Sie MySQL am besten an der Eingabeaufforderung aus, anstatt durch den mysqld_safe-Wrapper oder als Windows-Dienst. Dann können Sie erkennen, was mysqld auf die Konsole ausgibt, und verstehen besser, was vor sich geht. Auf Windows müssen Sie den Server mit der --console-Option starten, um die Ausgabe ans Konsolenfenster zu schicken.

  • Nutzen Sie die InnoDB-Monitore, um Informationen über ein Problem einzuholen (siehe Abschnitt 14.2.11.1, „Der InnoDB-Monitor“). Wenn es sich um ein Leistungsproblem handelt oder Ihr Server sich anscheinend aufgehängt hat, geben Sie mithilfe von innodb_monitor Informationen über den internen Zustand von InnoDB aus. Handelt es sich um ein Sperrenproblem, verwenden Sie innodb_lock_monitor. Hat das Problem mit der Erzeugung von Tabellen oder mit anderen Data Dictionary-Operationen zu tun, geben Sie mithilfe von innodb_table_monitor den Inhalt des InnoDB-internen Data Dictionary aus.

  • Wenn Sie Tabellenschäden vermuten, führen Sie auf der betreffenden Tabelle CHECK TABLE aus.

14.2.17.1. Troubleshooting von InnoDB bei Data Dictionary-Operationen

Ein besonderes Problem mit Tabellen besteht darin, dass der MySQL-Server Data Dictionary-Informationen in .frm-Dateien in Datenbankverzeichnissen ablegt, während InnoDB die Informationen auch in sein eigenes Data Dictionary innerhalb der Tablespace-Dateien speichert. Wenn Sie .frm-Dateien verschieben oder der Server inmitten einer Data Dictionary-Operation abstürzt, kann es geschehen, dass die Speicherorte der .frm-Dateien hinterher nicht mehr zu den Angaben im InnoDB-internen Data Dictionary passen.

Eine gescheiterte CREATE TABLE-Anweisung ist ein Symptom für ein nicht mehr synchrones Data Dictionary. Wenn dies passiert, schauen Sie im Fehlerlog des Servers nach. Wird dort behauptet, dass die Tabelle im InnoDB-internen Data Dictionary bereits existiert, so haben Sie in den InnoDB-Tablespace-Dateien, eine verwaiste Tabelle, zu der keine .frm-Datei gehört. Die Fehlermeldung sieht wie folgt aus:

InnoDB: Error: table test/parent already exists in InnoDB internal
InnoDB: data dictionary. Have you deleted the .frm file
InnoDB: and not used DROP TABLE? Have you used DROP DATABASE
InnoDB: for InnoDB tables in MySQL version <= 3.23.43?
InnoDB: See the Restrictions section of the InnoDB manual.
InnoDB: You can drop the orphaned table inside InnoDB by
InnoDB: creating an InnoDB table with the same name in another
InnoDB: database and moving the .frm file to the current database.
InnoDB: Then MySQL thinks the table exists, and DROP TABLE will
InnoDB: succeed.

Nach den Instruktionen der Fehlermeldung können Sie die verwaiste Tabelle löschen. Wenn Sie DROP TABLE immer noch nicht ausführen können, kann das Problem auch an der AutoVervollständigung von Namen durch den mysql-Client liegen. Um dieses zu verhindern, starten Sie den mysql-Client mit der --disable-auto-rehash-Option und versuchen noch einmal Ihr DROP TABLE. (Bei eingeschalteter Namensvervollständigung versucht mysql eine Liste von Tabellennamen zu erstellen. Das scheitert, wenn ein Problem wie das oben beschriebene auftritt.)

Ein anderes Symptom für ein nicht mehr synchrones Data Dictionary liegt vor, wenn MySQL meldet, dass eine .InnoDB-Datei nicht geöffnet werden kann:

ERROR 1016: Can't open file: 'child2.InnoDB'. (errno: 1)

Im Fehlerlog können Sie dann eine Nachricht wie diese vorfinden:

InnoDB: Cannot find table test/child2 from the internal data dictionary
InnoDB: of InnoDB though the .frm file for the table exists. Maybe you
InnoDB: have deleted and recreated InnoDB data files but have forgotten
InnoDB: to delete the corresponding .frm files of InnoDB tables?

Dies bedeutet, dass Sie eine verwaiste .frm-Datei haben, zu der es in InnoDB keine Tabelle gibt. Die verwaiste .frm-Datei können Sie dann manuell löschen.

Wenn MySQL mitten in einer ALTER TABLE-Operation abstürzt, haben Sie hinterher vielleicht eine verwaiste temporäre Tabelle im InnoDB-Tablespace. Mit innodb_table_monitor sehen Sie dann eine Tabelle namens #sql-... aufgeführt. Sie können SQL-Anweisungen auf Tabellen ausführen, deren Name das Zeichen ‘#’ enthält, wenn Sie den Namen in Backticks setzen. So können Sie die verwaiste Tabelle wie jede andere auch mit den zuvor beschriebenen Methoden löschen. Achtung: Um eine Datei in der Unix-Shell zu kopieren oder umzubenennen, müssen Sie den Dateinamen, wenn er ‘#’ enthält, in doppelte Anführungszeichen setzen.

14.3. Die MERGE-Speicher-Engine

Eine MERGE-Tabelle, auch bekannt als MRG_MyISAM, ist eine Sammlung identischer MyISAM-Tabellen, die als eine einzige Tabelle verwendet werden können. „Identisch“ bedeutet, dass alle Tabellen dieselben Spalten- und Indexdaten haben. Sie können keine MyISAM-Tabellen zusammenführen („mergen“) , in denen die Spalten oder Indizes in einer unterschiedlichen Reihenfolge stehen, oder die nicht genau gleich viele Spalten haben. Allerdings können alle MyISAM-Tabellen mit myisampack komprimiert werden. Siehe Abschnitt 8.4, „myisampack — Erzeugung komprimierter, schreibgeschützter MyISAM Tabellen“. Unterschiede in den Tabellenoptionen, wie beispielsweise AVG_ROW_LENGTH, MAX_ROWS oder PACK_KEYS spielen keine Rolle.

Wenn Sie eine MERGE-Tabelle anlegen, erzeugt MySQL auf der Festplatte zwei Dateien, deren Namen jeweils mit dem Tabellennamen beginnen und Erweiterungen haben, die den Dateityp angeben. Eine .frm-Datei speichert das Tabellenformat und eine .MRG-Datei enthält die Namen der Tabellen, die wie eine einzige benutzt werden sollen. Die Tabellen müssen nicht in derselben Datenbank vorliegen wie die MERGE-Tabelle selbst.

Mit MERGE-Tabellen können Sie die Anweisungen SELECT, DELETE, UPDATE und INSERT verwenden. Sie benötigen SELECT-, UPDATE- und DELETE-Rechte für die MyISAM-Tabellen, die Sie einer MERGE-Tabelle zuordnen möchten.

Wenn Sie die MERGE-Tabelle mit DROP löschen, löschen Sie damit nur die MERGE-Spezifikation. Die zugrunde liegenden Tabellen sind davon nicht betroffen.

Um eine MERGE-Tabelle anzulegen, müssen Sie in einer UNION=(list-of-tables) -Klausel angeben, welche MyISAM-Tabellen Sie als eine einzige benutzen möchten. Optional können Sie mit der Option INSERT_METHOD erreichen, dass Einfügeoperationen in der MERGE-Tabelle auf der ersten oder der letzten Tabelle der UNION-Liste stattfinden. Wenn Sie den Wert FIRST einsetzen, geschieht die Einfügung in der ersten, wenn Sie LAST einsetzen, in der letzten Tabelle. Wenn Sie die INSERT_METHOD-Option nicht oder nur mit dem Wert NO angeben, zieht jeder Versuch, Zeilen in die MERGE-Tabelle einzufügen, eine Fehlermeldung nach sich.

Das folgende Beispiel zeigt, wie eine MERGE-Tabelle angelegt wird:

mysql> CREATE TABLE t1 (
    ->    a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->    message CHAR(20)) ENGINE=MyISAM;
mysql> CREATE TABLE t2 (
    ->    a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->    message CHAR(20)) ENGINE=MyISAM;
mysql> INSERT INTO t1 (message) VALUES ('Testing'),('table'),('t1');
mysql> INSERT INTO t2 (message) VALUES ('Testing'),('table'),('t2');
mysql> CREATE TABLE total (
    ->    a INT NOT NULL AUTO_INCREMENT,
    ->    message CHAR(20), INDEX(a))
    ->    ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;

Der ältere Begriff TYPE wird aus Gründen der Abwärtskompatibilität noch als Synonym für ENGINE akzeptiert, doch ENGINE ist der aktuelle Begriff, während TYPE mittlerweile veraltet ist.

Beachten Sie, dass die Spalte a in den zugrunde liegenden MyISAM-Tabellen ein PRIMARY KEY ist, aber nicht in der MERGE-Tabelle. Dort ist diese Spalte zwar auch indiziert, aber nicht als PRIMARY KEY, da eine MERGE-Tabelle für die ihr zugrunde liegenden Tabellen keine Eindeutigkeit erzwingen kann.

Nachdem Sie die MERGE-Tabelle angelegt haben, können Sie Anfragen schreiben, die auf der Tabellengruppe als Ganzes operieren:

mysql> SELECT * FROM total;
+---+---------+
| a | message |
+---+---------+
| 1 | Testing |
| 2 | table   |
| 3 | t1      |
| 1 | Testing |
| 2 | table   |
| 3 | t2      |
+---+---------+

Beachten Sie, dass sich die .MRG-Datei direkt von außerhalb des MySQL-Servers bearbeiten lässt:

shell> cd /mysql-data-directory/current-database
shell> ls -1 t1 t2 > total.MRG
shell> mysqladmin flush-tables

Um eine Neuzuordnung einer MERGE-Tabelle zu einer anderen Gruppe von MyISAM-Tabellen zu erzielen, gibt es folgende Methoden:

  • Sie löschen die MERGE-Tabelle mit DROP und erstellen sie neu.

  • Sie ändern die Liste der zugrunde liegenden Tabellen mit ALTER TABLE tbl_name UNION=(...).

  • Sie ändern die .MRG-Datei und geben eine FLUSH TABLE-Anweisung für die MERGE-Tabelle und alle zugrunde liegenden Tabellen aus, damit die Speicher-Engine die neue Definitionsdatei lesen muss.

MERGE-Tabellen können bei der Lösung folgender Probleme behilflich sein:

  • Einfache Verwaltung einer Menge von Logtabellen. So können Sie zum Beispiel Daten verschiedener Monate in getrennte Tabellen laden, einige davon mit myisampack komprimieren und dann eine MERGE-Tabelle anlegen, um das Ganze als ein einziges Log zu verwenden.

  • Mehr Schnelligkeit. Sie können eine große, schreibgeschützte Tabelle nach bestimmten Kriterien aufspalten und die entstehenden Tabellen auf verschiedene Festplatten speichern. Mit einer MERGE-Tabelle aus diesen Einzeltabellen haben Sie schnelleren Zugriff als mit der großen Ursprungstabelle.

  • Effizienteres Suchen. Wenn Sie genau wissen, was Sie wollen, können Sie für manche Anfragen eine einzelne der aufgespaltenen Tabellen und für andere die MERGE- Tabelle benutzen. Sie können sogar eine Vielzahl verschiedener MERGE-Tabellen bilden, die zum Teil dieselben Einzeltabellen benutzen.

  • Reparaturen werden effizienter. Es ist einfacher, kleinere Tabellen zu reparieren, die einer MERGE-Tabelle zugeordnet sind, als eine einzige große Tabelle.

  • Viele Tabellen können wie eine einzige sofort zugeordnet werden. Eine MERGE-Tabelle benötigt keinen eigenen Index, da sie die Indizes der Einzeltabellen verwendet. Infolgedessen lassen sich Sammlungen von MERGE-Tabellen sehr schnell erstellen oder neu zuordnen. (Beachten Sie, dass Sie trotzdem bei der Erstellung einer MERGE-Tabelle die Indexdefinitionen angeben müssen auch wenn keine Indizes angelegt werden.)

  • Wenn Sie aus mehreren Tabellen nach Bedarf eine einzige, große Tabelle erstellen müssen, ist es günstiger, stattdessen eine MERGE-Tabelle anzulegen. Diese ist viel schneller und spart eine Menge Speicherplatz.

  • Mit MERGE-Tabellen können Sie die Dateigrößenbeschränkung Ihres Betriebssystems umgehen. Eine einzelne, große MyISAM-Tabelle würde durch dieses Limit begrenzt, aber eine Sammlung von kleineren MyISAM-Tabellen nicht.

  • Sie können einen Alias oder ein Synonym für eine MyISAM-Tabelle anlegen, indem Sie eine MERGE-Tabelle definieren, der nur diese eine Tabelle zugeordnet ist. Der Einfluss auf die Leistung dürfte kaum spürbar sein (nur ein paar indirekte Aufrufe und memcpy()-Aufrufe für jede Leseoperation).

Die Nachteile von MERGE-Tabellen sind:

  • Es dürfen nur identische MyISAM-Tabellen für eine MERGE-Tabelle benutzt werden.

  • Eine Reihe von MyISAM-Features steht für MERGE-Tabellen nicht zur Verfügung. Sie können zum Beispiel keine FULLTEXT-Indizes auf ihnen anlegen. (Es bleibt Ihnen natürlich unbenommen, FULLTEXT-Indizes auf den zugrunde liegenden MyISAM-Tabellen anzulegen, doch aber auf der MERGE-Tabelle können Sie keine Volltextsuche ausführen.)

  • Wenn die MERGE-Tabelle nicht-temporär ist, müssen auch die zugrunde liegenden MyISAM-Tabellen nicht-temporär sein. Ist die MERGE-Tabelle hingegen temporär, können die MyISAM-Tabellen eine beliebige Mixtur aus temporären und nicht-temporären Tabellen sein.

  • MERGE-Tabellen verwenden mehr Dateideskriptoren. Wenn 10 Clients eine MERGE-Tabelle ansprechen, die ihrerseits 10 Tabellen abbildet, benutzt der Server (10 × 10) + 10 Dateideskriptoren. (10 Datendateideskriptoren für jeden der 10 Clients und 10 Indexdateideskriptoren, die von den Clients gemeinsam genutzt werden.)

  • Lesevorgänge von Schlüsseln sind langsamer. Wenn Sie einen Schlüssel lesen, muss die MERGE-Speicher-Engine eine Leseoperation auf allen zugrunde liegenden Tabellen ausführen, um festzustellen, welche dem gegebenen Schlüssel am besten entspricht. Um den nächsten Schlüssel zu lesen, muss die MERGE-Speicher-Engine die Lesepuffer nach ihm durchsuchen. Erst wenn ein Schlüsselpuffer aufgebraucht ist, muss die Speicher-Engine den nächsten Schlüsselblock lesen. Das macht MERGE-Schlüssel in eq_ref-Suchen viel langsamer, aber nicht in ref-Suchen. Unter Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“ finden Sie weitere Informationen über eq_ref und ref.

Mehr zum Thema

14.3.1. MERGE-Tabellenprobleme

Folgende Probleme mit MERGE-Tabellen sind bekannt:

  • Wenn Sie mit ALTER TABLE versuchen, eine MERGE-Tabelle in eine andere Speicher-Engine umzuwandeln, geht die Zuordnung der zugrunde liegenden Tabellen verloren. Stattdessen werden die Zeilen der zugrunde liegenden MyISAM-Tabellen in die geänderte Tabelle kopiert, die dann die neue Speicher-Engine verwendet.

  • REPLACE funktioniert nicht.

  • DROP TABLE, ALTER TABLE, DELETE ohne WHERE-Klausel, REPAIR TABLE, TRUNCATE TABLE, OPTIMIZE TABLE oder ANALYZE TABLE dürfen auf keine Tabelle angewendet werden, die einer offenen MERGE-Tabelle zugeordnet ist. Wenn Sie dies tun, verweist die MERGE-Tabelle später weiterhin auf die Originaltabelle, was zu unerwarteten Ergebnissen führen kann. Am einfachsten können Sie dieses Problem umgehen, indem Sie mit einer FLUSH TABLES-Anweisung vor diesen Operationen dafür sorgen, dass keine MERGE-Tabellen offen bleiben.

  • Unter Windows funktioniert kein DROP TABLE auf einer Tabelle, die gerade von einer MERGE-Tabelle benutzt wird, da die Tabellenzuordnung der Speicher-Engine MERGE vor der oberen Schicht von MySQL verborgen wird. Da Windows das Löschen geöffneter Dateien nicht gestattet, müssen Sie zuerst alle MERGE-Tabellen auf die Festplatte zurückschreiben (mit FLUSH TABLES) oder die MERGE-Tabelle vor der anderen Tabelle löschen.

  • Eine MERGE-Tabelle kann keine Uniqueness Constraints über die gesamte Tabelle hinweg aufrecht erhalten. Wenn Sie ein INSERT ausführen, werden die Daten in die erste oder letzte der MyISAM-Tabellen geladen (je nach dem Wert der Option INSERT_METHOD). MySQL gewährleistet die Eindeutigkeit von Unique-Keys innerhalb dieser einen MyISAM-Tabelle, aber nicht für die gesamte Tabellengruppe.

  • Beim Anlegen einer MERGE-Tabelle wird nicht geprüft, ob die zugrunde liegenden Tabellen existieren und gleich strukturiert sind. Wenn die MERGE-Tabelle verwendet wird, prüft MySQL, ob alle zugeordneten Tabellen gleich lange Zeilen haben, aber narrensicher ist diese Überprüfung nicht. Legen Sie eine MERGE-Tabelle aus ungleichen MyISAM-Tabellen an, so müssen Sie sich auf ein paar seltsame Probleme gefasst machen.

  • Die Reihenfolge der Indizes in der MERGE-Tabelle und den ihr zugrunde liegenden Tabellen sollte gleich sein. Wenn Sie mit ALTER TABLE einer Tabelle, die in einer MERGE-Tabelle benutzt wird, einen UNIQUE-Index hinzufügen, und dann mit einem weiteren ALTER TABLE der MERGE-Tabelle einen nicht-eindeutigen Index geben, ist die Reihenfolge der Indizes unterschiedlich, wenn auch die zugrunde liegende Tabelle zuvor bereits einen nicht-eindeutigen Index hatte. (Dazu kommt es, weil ALTER TABLE UNIQUE-Indizes vor nicht-eindeutige Indizes setzt, um das schnelle Auffinden doppelter Schlüsselwerte zu erleichtern.) Infolgedessen können Anfragen von Tabellen mit solchen Indizes unerwartete Ergebnisse liefern.

14.4. Die MEMORY-Speicher-Engine

Die Speicher-Engine MEMORY legt Tabellen mit Inhalten an, die im Arbeitsspeicher gespeichert sind. Früher wurden sie als HEAP-Tabellen bezeichnet. Heute ist MEMORY der bevorzugte Ausdruck, auch wenn HEAP aus Gründen der Abwärtskompatibilität weiter unterstützt wird.

Zu jeder MEMORY-Tabelle gehört eine Festplattendatei. Der Dateiname beginnt mit dem Tabellennamen und hat die Erweiterung .frm, um anzuzeigen, dass hier die Tabellendefinition (frm = form) gespeichert ist.

Um explizit eine MEMORY-Tabelle anzulegen, geben Sie dies in der Tabellenoption ENGINE an:

CREATE TABLE t (i INT) ENGINE = MEMORY;

Der ältere Begriff TYPE wird aus Gründen der Abwärtskompatibilität noch als Synonym für ENGINE akzeptiert, doch ENGINE ist der aktuelle Begriff, während TYPE mittlerweile veraltet ist.

Wie der Name schon sagt, werden MEMORY-Tabellen im Arbeitsspeicher gespeichert und sie benutzen nach Voreinstellung einen gehashten Index. Das macht sie sehr schnell und nützlich für temporäre Tabellen. Wenn allerdings der Server abstürzt, gehen alle in MEMORY-Tabellen gespeicherten Daten verloren. Die Tabellen selbst bestehen weiter, da ihre Definitionen in .frm-Dateien auf der Festplatte gespeichert sind, doch ihre Daten sind fort, wenn der Server wieder hochfährt.

Das folgende Beispiel zeigt, wie eine MEMORY-Tabelle erzeugt, benutzt und gelöscht wird:

mysql> CREATE TABLE test ENGINE=MEMORY
    ->     SELECT ip,SUM(downloads) AS down
    ->     FROM log_table GROUP BY ip;
mysql> SELECT COUNT(ip),AVG(down) FROM test;
mysql> DROP TABLE test;

Kennzeichen von MEMORY-Tabellen:

  • Speicherplatz für MEMORY-Tabellen wird in kleinen Blöcken zugewiesen. Die Tabellen verwenden 100% dynamisches Hashing für Einfügeoperationen. Es werden keine Overflow- Bereiche und kein zusätzlicher Platz für Schlüssel oder für Freelists benötigt. Gelöschte Zeilen werden in eine verkettete Liste geschrieben und wiederverwendet, wenn neue Daten in die Tabelle eingefügt werden. MEMORY-Tabellen haben auch keine Probleme mit Löschen plus Einfügen, was normalerweise bei gehashten Tabellen häufig vorkommt.

  • MEMORY-Tabellen können bis zu 32 Indizes mit jeweils bis zu 16 Spalten und einer maximalen Schlüssellänge von 500 Bytes haben.

  • Die Speicher-Engine MEMORY implementiert sowohl HASH- als auch BTREE-Indizes. Mit einer USING-Klausel können Sie angeben, welchen von beiden Sie wünschen:

    CREATE TABLE lookup
        (id INT, INDEX USING HASH (id))
        ENGINE = MEMORY;
    CREATE TABLE lookup
        (id INT, INDEX USING BTREE (id))
        ENGINE = MEMORY;
    

    Die allgemeinen Merkmale von B-Baum- und Hash-Indizes werden in Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“ beschrieben.

  • Es darf keine nicht-eindeutigen Schlüssel auf eine MEMORY-Tabelle geben. (Dies ist ungebräuchlich für Implementierungen von Hash-Indizes.)

  • Wenn Sie einen Hash-Index auf einer MEMORY-Tabelle mit sehr vielen doppelten Schlüsseln haben (viele Indexeinträge enthalten denselben Wert), dann laufen Updates, die Schlüsselwerte betreffen, sowie sämtliche Löschoperationen deutlich langsamer. Wie viel langsamer, hängt von dem Ausmaß der Schlüsselduplikation ab (umgekehrt proportional zur Indexkardinalität). Um dieses Problem zu vermeiden, verwenden Sie einen BTREE-Index.

  • Indizierte Spalten können NULL-Werte enthalten.

  • MEMORY-Tabellen verwenden ein Speicherformat mit fester Zeilenlänge.

  • MEMORY-Tabellen dürfen keine BLOB- oder TEXT-Spalten enthalten.

  • MEMORY unterstützt AUTO_INCREMENT-Spalten.

  • INSERT DELAYED kann mit MEMORY-Tabellen verwendet werden. Siehe Abschnitt 13.2.4.2, „INSERT DELAYED.

  • MEMORY-Tabellen werden von allen Clients gemeinsam genutzt (wie jede andere nicht-TEMPORARY-Tabelle).

  • MEMORY-Tabellen speichern ihren Inhalt im Arbeitsspeicher, eine Eigenschaft, die sie mit internen Tabellen gemeinsam haben, die der Server bei der Verarbeitung von Anfragen nebenbei anlegt. Die beiden Tabellentypen unterscheiden sich jedoch darin, dass MEMORY-Tabellen im Gegensatz zu den internen Tabellen nicht von Speicherkonvertierung betroffen sind:

    • Wenn eine interne Tabelle zu groß wird, konvertiert der Server sie automatisch in eine Festplattentabelle. Deren maximale Größe wird durch die Systemvariable tmp_table_size festgelegt.

    • MEMORY-Tabellen werden nie in Festplattentabellen konvertiert. Um sicherzustellen, dass Sie nicht versehentlich den gesamten Arbeitsspeicher benutzen, können Sie die Systemvariable max_heap_table_size so einstellen, dass auch MEMORY-Tabellen einem Größenlimit unterliegen. Für einzelne Tabellen können Sie auch in der CREATE TABLE-Anweisung die Tabellenoption MAX_ROWS-Tabelle setzen.

  • Der Server benötigt genug Arbeitsspeicher, um alle MEMORY-Tabellen zu pflegen, die zur selben Zeit gebraucht werden.

  • Um den von einer MEMORY-Tabelle belegten Speicher wieder freizugeben, wenn sie nicht länger benötigt wird, führen Sie DELETE oder TRUNCATE TABLE aus oder löschen die Tabelle mit DROP TABLE.

  • Möchten Sie beim Starten des MySQL-Servers Daten in eine MEMORY-Tabelle laden, so können Sie die Option --init-file nutzen. In diese Datei können Sie Anweisungen wie INSERT INTO ... SELECT oder LOAD DATA INFILE setzen, um die Tabelle aus einer persistenten Datenquelle zu laden. Siehe Abschnitt 5.2.1, „Befehlsoptionen für mysqld, and Abschnitt 13.2.5, „LOAD DATA INFILE.

  • Wenn Sie Replikation benutzen, werden die MEMORY-Tabellen auf dem Masterserver auf Platte geschrieben, wenn dieser heruntergefahren und neu gestartet wird. Ein Slave merkt allerdings nicht, dass die Tabellen inzwischen leer sind, und gibt ihren alten Inhalt zurück, wenn Sie Daten von ihm abfragen. Wird eine MEMORY-Tabelle auf einem Master nach einem Neustart erstmals wieder genutzt, so wird automatisch eine DELETE-Anweisung in sein Binärlog geschrieben, um den Slave wieder mit ihm zu synchronisieren. Doch Vorsicht: Auch bei dieser Strategie hat der Slave in dem Zeitraum zwischen dem Neustart des Masters und seinem ersten Zugriff auf die Tabelle veraltete Daten im Speicher. Wenn Sie jedoch die MEMORY-Tabelle gleich beim Hochfahren des Masters mithilfe der Option --init-file wieder mit Inhalt füllen, ist gewährleistet, dass dieser Zeitraum auf Null schrumpft.

  • Der für eine Zeile in einer MEMORY-Tabelle benötigte Speicher lässt sich mit folgendem Ausdruck berechnen:

    SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) × 4)
    + SUM_OVER_ALL_HASH_KEYS(sizeof(char*) × 2)
    + ALIGN(length_of_row+1, sizeof(char*))
    

    ALIGN() ist ein Rundungsfaktor, der gewährleisten soll, dass die Zeilenlänge ein Vielfaches der char-Pointergröße ist. sizeof(char*) ist auf 32-Bit-Rechnern gleich 4 und auf 64-Bit-Rechnern gleich 8.

Mehr zum Thema

14.5. Die BDB-Speicher-Engine

Sleepycat Software hat für MySQL die transaktionssichere Speicher-Engine Berkeley DB, kurz BDB, bereitgestellt. BDB-Tabellen haben bessere Chancen, einen Absturz zu überstehen, und können darüber hinaus COMMIT- und ROLLBACK-Operationen auf Transaktionen durchführen.

BDB-Support ist in MySQL Quelldistributionen enthalten und in MySQL-Max-Binärdistributionen aktiviert. Die MySQL-Quelldistribution wird mit einer BDB-Distribution ausgeliefert, die durch einen Patch auf MySQL zugeschnitten ist. Für MySQL kann keine nicht-gepatchte Version von BDB verwendet werden.

MySQL AB arbeitet eng mit Sleepycat zusammen, um eine hochwertige MySQL/BDB-Schnittstelle zu gewährleisten. (Obgleich Berkeley DB selbst gründlich getestet und sehr zuverlässig ist, hat die MySQL-Schnittstelle immer noch Gamma-Qualität. Wir arbeiten weiter an ihrer Verbesserung und Optimierung.)

Wenn Probleme mit BDB-Tabellen auftreten, sind wir bestrebt, unseren Benutzern beim Isolieren des Problems zu helfen und reproduzierbare Testfälle zu erstellen. Alle derartigen Testfälle werden an Sleepycat weitergeleitet, wo man uns wiederum hilft, die Probleme zu finden und zu beheben. Da dieser Vorgang in zwei Phasen abläuft, kann die Behebung von Problemen mit BDB-Tabellen etwas länger dauern als bei anderen Speicher-Engines. Wir denken jedoch nicht, dass es mit diesem Vorgehen besondere Schwierigkeiten gibt, da der Berkeley DB-Code selbst noch in vielen anderen Anwendungen als MySQL läuft.

Allgemeine Informationen über Berkeley DB finden Sie auf der Sleepycat-Website http://www.sleepycat.com/.

14.5.1. Betriebssysteme, die von BDB unterstützt werden

Nach unserem derzeitigen Kenntnisstand funktioniert BDB mit folgenden Betriebssystemen:

  • Linux 2.x Intel

  • Sun Solaris (SPARC und x86)

  • FreeBSD 4.x/5.x (x86, sparc64)

  • IBM AIX 4.3.x

  • SCO OpenServer

  • SCO UnixWare 7.1.x

  • Windows NT/2000/XP

Die Speicher-Engine BDB funktioniert nicht auf folgenden Betriebssystemen:

  • Linux 2.x Alpha

  • Linux 2.x AMD64

  • Linux 2.x IA-64

  • Linux 2.x s390

  • Mac OS X

Hinweis: Diese Listen sind nicht vollständig. Sie werden bei Eintreffen neuer Informationen aktualisiert.

Wenn Sie MySQL aus der Quelle mit Unterstützung für BDB-Tabellen erstellen, aber beim Starten mit mysqld folgender Fehler auftritt, so bedeutet dies, dass Ihre Rechnerarchitektur die BDB-Speicher-Engine nicht unterstützt:

bdb: architecture lacks fast mutexes: applications cannot be threaded
Can't init databases

In diesem Fall müssen Sie MySQL ohne BDB-Unterstützung bauen oder den Server mit der Option --skip-bdb starten.

14.5.2. BDB installieren

Wenn Sie eine Binärversion von MySQL heruntergeladen haben, die Unterstützung für Berkeley DB bietet, befolgen Sie einfach die üblichen Installationsanweisungen für Binärdistributionen. (MySQL-Max-Distributionen umfassen BDB-Support.)

Erstellen Sie MySQL aus einer Quelldistribution, so können Sie BDB-Unterstützung aktivieren, indem Sie beim Aufruf von configure zusätzlich zu den anderen Optionen, die Sie normalerweise verwenden, die Option --with-berkeley-db einschalten. Laden Sie eine MySQL-Distribution der Version 5.1 herunter, gehen Sie in das oberste Verzeichnis und führen Sie folgenden Befehl aus:

shell> ./configure --with-berkeley-db [other-options]

Weitere Informationen, Abschnitt 5.3, „mysqld-max, ein erweiterter mysqld-Server“, siehe Abschnitt 2.7, „Installation von MySQL auf anderen Unix-ähnlichen Systemen“ und Abschnitt 2.8, „Installation der Quelldistribution“.

14.5.3. BDB-Startoptionen

Mit den folgenden mysqld-Optionen lässt sich das Verhalten der Speicher-Engine BDB ändern. Weitere Informationen siehe Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

  • --bdb-data-direct

    Schaltet für BDB-Datenbankdateien den Systempuffer aus, um doppeltes Cachen zu verhindern. Diese Option wurde in MySQL 5.1.4 hinzugefügt.

  • --bdb-home=path

    Das Basisverzeichnis für BDB-Tabellen. Es sollte dasselbe Verzeichnis sein, das auch für die --datadir-Option verwendet wird.

  • --bdb-lock-detect=method

    Die BDB-Methode zur Erkennung von Sperren. Der Wert der Option ist DEFAULT, OLDEST, RANDOM, YOUNGEST, MAXLOCKS, MINLOCKS, MAXWRITE oder MINWRITE.

  • --bdb-log-direct

    Schaltet für BDB-Datenbankdateien den Systempuffer aus, um doppeltes Cachen zu verhindern. Diese Option wurde in MySQL 5.1.4 hinzugefügt.

  • --bdb-logdir=file_name

    Das Verzeichnis für BDB-Logdateien.

  • --bdb-no-recover

    Berkeley DB nicht im Wiederherstellungsmodus starten.

  • --bdb-no-sync

    BDB-Logs nicht synchronisieren. Diese Option ist veraltet; bitte verwenden Sie stattdessen --skip-sync-bdb-logs (siehe Beschreibung von --sync-bdb-logs).

  • --bdb-shared-data

    Berkeley DB im Multi-Prozess-Modus starten. (Nicht beim Initialisieren von Berkeley DB DB_PRIVATE benutzen.)

  • --bdb-tmpdir=path

    Name des temporären Dateiverzeichnisses von BDB.

  • --skip-bdb

    BDB-Speicher-Engine nicht benutzen.

  • --sync-bdb-logs

    BDB-Logs synchronisieren. Diese Option ist standardmäßig aktiviert und kann mit --skip-sync-bdb-logs deaktiviert werden.

Mit --skip-bdb initialisiert MySQL nicht die BerkeleyDB-Bibliothek und spart deshalb viel Speicher. Natürlich können Sie BDB-Tabellen nicht benutzen, wenn Sie diese Option verwenden. Versuchen Sie dennoch, eine BDB-Tabelle anzulegen, so verwendet MySQL stattdessen die Standard-Speicher-Engine.

Normalerweise sollten Sie mysqld ohne die Option --bdb-no-recover starten, wenn Sie BDB-Tabellen benutzen möchten. Das kann jedoch Probleme verursachen, wenn Sie mysqld starten und die BDB-Logdateien beschädigt sind. Siehe Abschnitt 2.9.2.3, „Probleme mit dem Start des MySQL Servers“.

Mit der Variablen bdb_max_lock können Sie angeben, wie viele Sperren auf einer BDB-Tabelle höchstens aktiv sein dürfen. Der Standardwert beträgt 10.000. Sie können ihn heraufsetzen, wenn Fehler wie der folgende bei langen Transaktionen auftreten, oder wenn mysqld viele Zeilen betrachten muss, um eine Anfrage auszuführen:

bdb: Lock table is out of available locks
Got error 12 from ...

Außerdem sollten Sie die Variablen binlog_cache_size und max_binlog_cache_size ändern, wenn Sie große, aus mehreren Anweisungen bestehende Transaktionen ausführen. Siehe Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

See also Abschnitt 5.2.2, „Server-Systemvariablen“.

14.5.4. Kennzeichen von BDB-Tabellen

Jede BDB-Tabelle wird in zwei Dateien auf der Festplatte gespeichert. Die Namen dieser Dateien setzen sich aus dem Namen der Tabelle und einer Dateityperweiterung zusammen. Eine .frm-Datei speichert das Format und eine .db-Datei den Inhalt und die Indizes der Tabelle.

Um explizit deutlich zu machen, dass Sie eine BDB-Tabelle benötigen, verwenden Sie die Tabellenoption ENGINE:

CREATE TABLE t (i INT) ENGINE = BDB;

Der ältere Begriff TYPE wird aus Gründen der Abwärtskompatibilität noch als Synonym für ENGINE akzeptiert, doch ENGINE ist der aktuelle Begriff, während TYPE mittlerweile veraltet ist.

BerkeleyDB ist ein Synonym für BDB in der Tabellenoption ENGINE.

Die Speicher-Engine BDB ermöglicht transaktionssichere Tabellen. Wie diese benutzt werden, hängt vom Autocommit-Modus ab:

  • Arbeiten Sie mit eingeschaltetem Autocommit (der Standard), werden Änderungen an BDB-Tabellen sofort festgeschrieben (commit) und können nicht zurückgerollt werden.

  • Arbeiten Sie mit ausgeschaltetem Autocommit, werden die Änderungen erst permanent, nachdem Sie eine COMMIT-Anweisung ausgeführt haben. Stattdessen können Sie jedoch auch ein ROLLBACK ausführen, um die Änderungen zu widerrufen.

    Eine Transaktion wird mit START TRANSACTION oder BEGIN gestartet, um den Autocommit-Modus implizit auszusetzen, oder mit SET AUTOCOMMIT=0, um den Autocommit-Modus explizit auszuschalten.

Weitere Informationen über Transaktionen finden Sie unter Abschnitt 13.4.1, „BEGIN/COMMIT/ROLLBACK.

Die BDB-Speicher-Engine hat folgende Merkmale:

  • BDB-Tabellen können bis zu 31 Indizes pro Tabelle, 16 Spalten pro Index und 1024 Bytes pro Schlüssel haben.

  • MySQL erfordert einen Primärschlüssel in jeder BDB-Tabelle, um auf jede Zeile eindeutig verweisen zu können. Wenn Sie nicht explizit einenPRIMARY KEY deklarieren, erzeugt und wartet MySQL einen verborgenen Primärschlüssel. Dieser hat eine Länge von 5 Bytes und wird bei jedem Einfügeversuch um eins inkrementiert. Der Schlüssel erscheint nicht in der Ausgabe von SHOW CREATE TABLE oder DESCRIBE.

  • Der Primärschlüssel ist schneller als jeder andere Index, da er zusammen mit den Zeilendaten gespeichert wird. Da die anderen Indizes als Schlüsseldaten plus Primärschlüssel gespeichert werden, ist es wichtig, den Primärschlüssel möglichst kurz zu halten, um Plattenplatz zu sparen und eine höhere Geschwindigkeit zu erzielen.

    Dieses Verhalten ist ähnlich wie das von InnoDB, wo kürzere Primärschlüssel nicht nur im Primärindex, sondern auch in den Sekundärindizes Platz sparen.

  • Wenn alle Spalten, auf die Sie in einer BDB-Tabelle zugreifen, zu demselben Index oder zum Primärschlüssel gehören, kann MySQL die Anfrage ausführen, ohne auf die eigentliche Zeile zugreifen zu müssen. In einer MyISAM-Tabelle ist dies nur möglich, wenn die Spalten zu demselben Index gehören.

  • Sequenzielles Scannen ist bei BDB-Tabellen langsamer als bei MyISAM-Tabellen, da die Daten in BDB-Tabellen in B-Bäumen und nicht in einer separaten Datendatei gespeichert werden.

  • Schlüsselwerte werden nicht Präfix- oder Suffix-komprimiert wie Schlüsselwerte in MyISAM-Tabellen. Mit anderen Worten: Die Schlüsselinformationen benötigen in BDB-Tabellen etwas mehr Platz als in MyISAM-Tabellen.

  • Oft gibt es Löcher in der BDB-Tabelle, damit Sie neue Zeilen in der Mitte des Schlüsselbaums einfügen können. Das macht BDB-Tabellen etwas größer als MyISAM-Tabellen.

  • SELECT COUNT(*) FROM tbl_name ist bei BDB-Tabellen langsam, da in der Tabelle kein Zeilenzähler gepflegt wird.

  • Der Optimierer muss näherungsweise die Anzahl von Zeilen in der Tabelle kennen. MySQL löst dieses Problem, indem Einfügeoperationen gezählt werden, und unterhält diese in einem separaten Segment in jeder BDB-Tabelle. Wenn Sie nicht viele DELETE- oder ROLLBACK-Anweisungen ausführen, sollte diese Zahl ausreichend genau für den MySQL-Optimierer sein. Da MySQL die Zahl nur beim Schließen speichert, kann sie falsch sein, wenn MySQL unerwartet beendet wird. Das sollte kein schwerer Fehler sein, selbst wenn die Zahl nicht zu 100% korrekt ist. Man kann die Anzahl von Zeilen aktualisieren, indem man ANALYZE TABLE oder OPTIMIZE TABLE ausführt. Siehe Abschnitt 13.5.2.1, „ANALYZE TABLE und Abschnitt 13.5.2.5, „OPTIMIZE TABLE

  • Internes Sperren in BDB-Tabellen wird auf Seitenebene durchgeführt (page locking).

  • LOCK TABLES funktioniert bei BDB-Tabellen wie bei anderen Tabellen. Wenn Sie LOCK TABLES nicht benutzen, errichtet MySQL eine interne Sperre für Mehrfach-Schreibvorgänge auf der Tabelle (eine Sperre, die andere Schreibvorgänge nicht blockiert), um sicherzustellen, dass die Tabelle korrekt gesperrt ist, wenn ein anderer Thread eine Tabellensperre ausführt.

  • Um Transaktionen zurückrollen zu können, unterhält die BDB-Speicher-Engine Logdateien. Um maximale Performance zu erzielen, sollten Sie diese auf andere Festplatten platzieren als Ihre Datenbanken, indem Sie die Option --bdb-logdir verwenden.

  • MySQL macht jedes Mal, wenn eine neue BDB-Logdatei gestartet wird, einen Checkpoint und entfernt alle BDB-Logdateien, die nicht für aktuelle Transaktionen benötigt werden. Sie können auch jederzeit FLUSH LOGS laufen lassen, um einen Checkpoint für die Berkeley DB-Tabellen anzulegen.

    Für die Wiederherstellung nach Abstürzen sollten Sie Datensicherungen der Tabellen plus das Binärlog von MySQL benutzen. Siehe Abschnitt 5.10.1, „Datenbank-Datensicherungen“.

    Achtung: Wenn Sie alte Logdateien löschen, die noch in Gebrauch sind, ist BDB nicht in der Lage, Wiederherstellungen durchzuführen, und Sie könnten Daten verlieren, wenn etwas schief geht.

  • Die Anwendung muss stets darauf vorbereitet sein, Fälle zu handhaben, bei denen jegliche Änderung einer BDB-Tabelle zu einem automatischen Rollback führen kann und jegliches Lesen fehlschlagen kann, weil ein Deadlock auftritt.

  • Wenn die Platte bei einer BDB-Tabelle voll wird, wird ein Fehler gemeldet (wahrscheinlich Fehler 28) und die Transaktion sollte zurückgerollt werden. Im Gegensatz dazu wartet bei MyISAM-Tabellen der Server darauf, dass genügend Plattenplatz frei ist, ehe er fortfährt.

14.5.5. Einschränkungen bei Verwendung von BDB-Tabellen

Im Folgenden werden Einschränkungen aufgeführt, die Sie bei der Verwendung von BDB-Tabellen beachten müssen:

  • Jede BDB-Tabelle speichert in ihrer .db-Datei den Pfad, mit dem sie angelegt wurde. Dies wird getan, um die Erkennung von Sperren in Mehrbenutzerumgebungen zu ermöglichen, in denen Symlinks unterstützt werden. Infolgedessen ist es nicht möglich, BDB-Tabellendateien von einem Datenbankverzeichnis in ein anderes zu verlagern.

  • Wenn Sie BDB-Tabellen sichern, müssen Sie entweder mysqldump verwenden oder eine Sicherung anlegen, die Dateien für jede BDB-Tabelle (also die .frm- und die .db-Dateien) sowie die BDB-Logdateien speichert. Die Speicher-Engine BDB speichert unvollendete Transaktionen in ihren Logdateien und erfordert, dass diese beim Starten von mysqld präsent sind. Die BDB-Logs sind die Dateien im Data Directory, deren Namen die Form log.NNNNNNNNNN haben (zehn Ziffern).

  • Wenn eine Spalte, die NULL-Werte zulässt, einen eindeutigen Index hat, darf nur ein einziger NULL-Wert vorhanden sein. Im Gegensatz dazu erlauben andere Speicher-Engines auch mehrere NULL-Werte in Unique-Indizes.

14.5.6. Fehler, die bei der Benutzung von BDB-Tabellen auftreten können

  • Wenn Sie mysqld nach einem Upgrade starten und folgenden Fehler erhalten, so bedeutet dies, dass die neue Version von BDB das alte Logdateiformat nicht mehr unterstützt:

    bdb:  Ignoring log file: .../log.NNNNNNNNNN:
    unsupported log version #
    

    In diesem Fall müssen Sie alle BDB-Logs aus Ihrem Datenverzeichnis löschen (also die Dateien, deren Namen die Form log.NNNNNNNNNN haben) und mysqld neu starten. Außerdem sollten Sie mit mysqldump --opt Ihre BDB-Tabellen dumpen, löschen und dann aus der Dump-Datei rekonstruieren.

  • Wenn Sie bei ausgeschaltetem Autocommit eine BDB-Tabelle löschen, die in einer anderen Transaktion verwendet wird, wird vielleicht eine Fehlermeldung wie die folgende in Ihr MySQL-Fehlerlog geschrieben:

    001119 23:43:56  bdb:  Missing log fileid entry
    001119 23:43:56  bdb:  txn_abort: Log undo failed for LSN:
                           1 3644744: Invalid
    

    Das ist zwar nicht fatal, lässt sich aber auch nicht ganz einfach beheben. So lange dieses Problem noch nicht behoben ist, raten wir Ihnen, BDB-Tabellen nur bei eingeschaltetem Autocommit zu löschen.

14.6. Die EXAMPLE-Speicher-Engine

Die Speicher-Engine EXAMPLE ist eine Sockel-Engine, die eigentlich gar nichts tut, sondern einzig als Beispiel im MySQL-Quellcode dienen soll, um zu veranschaulichen, wie man neue Speicher-Engines erstellt. Sie ist vor allem für Entwickler von Interesse.

Die Speicher-Engine EXAMPLE ist in den MySQL-Max-Binärdistributionen enthalten. Wenn Sie MySQL von der Quelldistribution bauen, können Sie diese Speicher-Engine aktivieren, indem Sie configure mit der Option --with-example-storage-engine aufrufen.

Die Quelle für die EXAMPLE-Engine finden Sie im Verzeichnis storage/example der MySQL-Quelldistribution.

Wenn Sie eine EXAMPLE-Tabelle anlegen, erstellt der Server eine Tabellen-Formatdatei im Datenbankverzeichnis. Die Datei beginnt mit dem Tabellennamen und hat die Erweiterung .frm. Andere Dateien werden nicht erzeugt und Daten können in der Tabelle auch nicht gespeichert werden. Anfragen geben eine leere Ergebnismenge zurück.

mysql> CREATE TABLE test (i INT) ENGINE = EXAMPLE;
Query OK, 0 rows affected (0.78 sec)

mysql> INSERT INTO test VALUES(1),(2),(3);
ERROR 1031 (HY000): Table Speicher-Engine for 'test' doesn't have this option

mysql> SELECT * FROM test;
Empty set (0.31 sec)

Die Speicher-Engine EXAMPLE unterstützt keine Indizierung.

14.7. Die FEDERATED-Speicher-Engine

Die Speicher-Engine FEDERATED greift auf Daten in entfernten Datenbanktabellen (auf anderen Hosts) zu, nicht in lokalen Tabellen.

Die Speicher-Engine FEDERATED ist in MySQL-Max-Binärdistributionen enthalten. Wenn Sie MySQL von der Quelldistribution bauen, können Sie diese Speicher-Engine aktivieren, indem Sie configure mit der Option --with-federated-storage-engine aufrufen.

Die Quelle für die FEDERATED-Engine finden Sie im Verzeichnis sql einer MySQL-Quelldistribution.

Mehr zum Thema

14.7.1. Beschreibung der FEDERATED-Speicher-Engine

Wenn Sie eine FEDERATED-Tabelle anlegen, erzeugt der Server eine Tabellen-Formatdatei im Datenbankverzeichnis. Die Datei beginnt mit dem Tabellennamen und hat die Erweiterung .frm. Andere Dateien werden nicht angelegt, da die eigentlichen Daten in einer Remote-Tabelle vorliegen. Das steht im Gegensatz zu den Speicher-Engines für lokale Tabellen.

Für lokale Datenbanktabellen liegen auch die Datendateien lokal vor. Wenn Sie beispielsweise eine MyISAM-Tabelle namens users anlegen, erzeugt der MyISAM-Handler eine Datendatei namens users.MYD. Ein Handler für lokale Tabellen liest, ergänzt, löscht und aktualisiert Daten in lokalen Datendateien und die Zeilen werden in einem für den Handler spezifischen Format gespeichert. Um Datenzeilen zu lesen, muss der Handler die Daten in Spalten parsen, und um Zeilen zu schreiben, müssen die Spaltenwerte in das vom Handler benutzte Zeilenformat umgewandelt und in die lokale Datendatei geschrieben werden.

Doch bei der MySQL-Speicher-Engine FEDERATED existieren lokal keine Datendateien für eine Tabelle (es gibt beispielsweise keine .MYD-Datei). Stattdessen speichert eine entfernte Datenbank die Daten, die normalerweise in der Tabelle vorliegen würden. Der lokale Server verbindet sich mit einem entfernten Server und liest, löscht, aktualisiert und ergänzt die Daten in der entfernten Tabelle über eine MySQL-API. Abgefragt werden die Daten mit einer SELECT * FROM tbl_name-SQL-Anweisung. Um das Ergebnis zu lesen, werden die Zeilen eine nach der anderen mit der C-API-Funktion mysql_fetch_row() abgeholt. Danach werden die Spalten der SELECT-Ergebnismenge in das vom FEDERATED-Handler erwartete Format umgewandelt.

Der Informationsfluss ist wie folgt:

  1. Lokaler SQL-Aufruf

  2. MySQL-Handler-API (Daten im Format des Handlers)

  3. MySQL-Client-API (Daten werden in SQL-Aufrufe konvertiert)

  4. Remote-Datenbank -> MySQL-Client-API

  5. Ergebnismengen (sofern vorhanden) werden in Handler-Format konvertiert

  6. Handler-API -> Ergebniszeilen oder Zahl der betroffenen Zeilen werden lokal angegeben

14.7.2. Benutzung von FEDERATED-Tabellen

Das Verfahren zur Benutzung der FEDERATED-Tabellen ist sehr einfach. Normalerweise betreiben Sie zwei Server, entweder auf demselben oder auf verschiedenen Hosts. (Es ist möglich, allerdings nicht sehr sinnvoll, dass eine FEDERATED-Tabelle eine andere Tabelle verwendet, die von demselben Server verwaltet wird.)

Zuerst muss auf dem Remote-Server eine Tabelle liegen, auf die Sie mit einer FEDERATED-Tabelle zugreifen möchten. Angenommen, die entfernte Tabelle liegt in der Datenbank federated und ist folgendermaßen definiert:

CREATE TABLE test_table (
    id     INT(20) NOT NULL AUTO_INCREMENT,
    name   VARCHAR(32) NOT NULL DEFAULT '',
    other  INT(20) NOT NULL DEFAULT '0',
    PRIMARY KEY  (id),
    INDEX name (name),
    INDEX other_key (other)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1;

Im Beispiel wird eine MyISAM-Tabelle verwendet, aber es könnte auch eine andere Speicher-Engine benutzt werden.

Nun erstellen Sie eine FEDERATED-Tabelle auf dem lokalen Server, um auf die entfernte Tabelle zuzugreifen:

CREATE TABLE federated_table (
    id     INT(20) NOT NULL AUTO_INCREMENT,
    name   VARCHAR(32) NOT NULL DEFAULT '',
    other  INT(20) NOT NULL DEFAULT '0',
    PRIMARY KEY  (id),
    INDEX name (name),
    INDEX other_key (other)
)
ENGINE=FEDERATED
DEFAULT CHARSET=latin1
CONNECTION='mysql://root@remote_host:9306/federated/test_table';

(Hinweis: CONNECTION ersetzt COMMENT, was in früheren MySQL-Versionen verwendet wurde.)

Die Struktur dieser Tabelle muss der Struktur der entfernten Tabelle genau entsprechen, nur die Tabellenoption ENGINE ist FEDERATED und die Tabellenoption CONNECTION ist ein Verbindungsstring, welcher der FEDERATED-Engine sagt, wie sie sich mit dem entfernten Server verbinden kann.

Die FEDERATED-Engine erzeugt in der federated-Datenbank nur die test_table.frm-Datei.

Die Remote-Host-Daten geben an, mit welchem entfernten Server sich Ihr lokaler Server verbindet, und die Datenbank- und Tabelleninformationen geben an, welche entfernte Tabelle als Datenquelle verwendet werden soll. Da im vorliegenden Beispiel der entfernte Server als remote_host auf Port 9306 definiert ist, muss ein MySQL-Server auf dem Remote-Host laufen und auf Port 9306 lauschen.

Die allgemeine Form eines Verbindungsstrings in der Option CONNECTION ist:

scheme://user_name[:password]@host_name[:port_num]/db_name/tbl_name

Vorläufig wird nur mysql als Wert für scheme akzeptiert. Das Passwort und die Port-Nummer sind optional.

Im Folgenden sehen Sie einige Beispiele für Verbindungsstrings:

CONNECTION='mysql://username:password@hostname:port/database/tablename'
CONNECTION='mysql://username@hostname/database/tablename'
CONNECTION='mysql://username:password@hostname/database/tablename'

CONNECTION ist für die Angabe des Verbindungsstrings nicht optimal geeignet und wird wahrscheinlich irgendwann ersetzt. Für Anwendungen mit FEDERATED-Tabellen müssen Sie sich daher merken, dass diese Anwendungen modifiziert werden müssen, wenn sich das Format für die Verbindungsinformationen eines Tages ändert.

Da jedes Passwort, das Sie im Verbindungsstring angeben, als einfacher Text gespeichert wird, ist es für jeden Benutzer ersichtlich, der SHOW CREATE TABLE oder SHOW TABLE STATUS für die FEDERATED-Tabelle ausführen oder die TABLES-Tabelle in der INFORMATION_SCHEMA-Datenbank abfragen darf.

14.7.3. Beschränkungen der FEDERATED-Speicher-Engine

Die folgenden Features werden von der Speicher-Engine FEDERATED unterstützt bzw. nicht unterstützt:

  • In der vorliegenden Version muss der entfernte Server ein MySQL-Server sein. In Zukunft wird FEDERATED möglicherweise auch andere Datenbank-Engines unterstützen.

  • Die entfernte Tabelle, die von einer FEDERATED-Tabelle benutzt wird, muss vorhanden sein, bevor Sie mit FEDERATED versuchen, auf sie zuzugreifen.

  • Es ist möglich, mit einer FEDERATED-Tabelle auf eine andere zu verweisen, aber bitte achten Sie darauf, keine Endlosschleife zu erzeugen.

  • FEDERATED unterstützt keine Transaktionen.

  • Die FEDERATED-Engine kann nicht wissen, ob die entfernte Tabelle sich geändert hat. Der Grund dafür: Diese Tabelle muss wie eine Datendatei funktionieren, in die niemand anders als die Datenbank schreiben kann. Die Datenintegrität in der lokalen Tabelle könnte beschädigt werden, wenn sich in der entfernten Datenbank etwas ändert.

  • Die FEDERATED-Speicher-Engine unterstützt SELECT, INSERT, UPDATE, DELETE und Indizes. Nicht unterstützt werden ALTER TABLE, DROP TABLE oder andere Data Definition Language-Anweisungen. Die aktuelle Implementierung verwendet keine vorbereiteten Anweisungen (Prepared-Statements).

  • Die Implementierung verwendet SELECT, INSERT, UPDATE und DELETE, aber nicht HANDLER.

  • FEDERATED-Tabellen arbeiten nicht mit dem Anfragen-Cache.

Manche dieser Beschränkungen werden vielleicht in künftigen Versionen des FEDERATED-Handlers entfallen.

14.8. Die ARCHIVE-Speicher-Engine

Die Speicher-Engine ARCHIVE dient der Speicherung großer Datenmengen ohne Indizes mit einem sehr kleinen Speicherbedarf.

Die Speicher-Engine ARCHIVE ist in den Binärdistributionen von MySQL enthalten. Wenn Sie MySQL aus der Quelldistribution bauen, aktivieren Sie diese Speicher-Engine, indem Sie configure mit der Option --with-archive-storage-engine aufrufen.

Die Quelle für die ARCHIVE-Engine finden Sie im Verzeichnis storage/archive der MySQL-Quelldistribution.

Ob die ARCHIVE-Engine zur Verfügung steht, prüfen Sie mit folgender Anweisung:

mysql> SHOW VARIABLES LIKE 'have_archive';

Wenn Sie eine ARCHIVE-Tabelle anlegen, erzeugt der Server eine Tabellen-Formatdatei im Datenbankverzeichnis. Die Datei beginnt mit dem Tabellennamen und hat die Erweiterung.frm. Die Speicher-Engine legt noch weitere Dateien an, deren Namen alle mit dem Tabellennamen anfangen. Die Datendateien haben die Erweiterung .ARZ und die Metadatendateien die Erweiterung .ARM. Eine .ARN-Datei kann bei Optimierungsoperationen erscheinen.

Die ARCHIVE-Engine unterstützt INSERT und SELECT, aber nicht DELETE, REPLACE oder UPDATE. Sie unterstützt ORDER BY-Operationen, BLOB-Spalten und im Grunde alle Datentypen außer den raumbezogenen (Spatial-Daten) (siehe Abschnitt 18.4.1, „Raumbezogene Datentypen in MySQL“). Außerdem nutzt ARCHIVE Zeilensperren.

Seit MySQL 5.1.6 unterstützt ARCHIVE das AUTO_INCREMENT-Spaltenattribut. Die AUTO_INCREMENT-Spalten können einen eindeutigen oder einen nicht-eindeutigen Index haben. Der Versuch, einen Index auf einer anderen Spalte anzulegen, führt zu einem Fehler. Außerdem unterstützt ARCHIVE die Tabellenoption AUTO_INCREMENT in CREATE TABLE- und ALTER TABLE-Anweisungen. So kann der erste Wert der Folge für eine neue Tabelle angegeben oder für eine vorhandene Tabelle zurückgesetzt werden.

Seit MySQL 5.1.6 ignoriert die ARCHIVE-Engine BLOB-Spalten, wenn diese nicht angefordert werden, und übergeht sie beim Lesen. Früher bedeuteten die folgenden beiden Anweisungen denselben Aufwand, doch seit der Version 5.1.6 ist die zweite viel effizienter als die erste:

SELECT a, b, blob_col FROM archive_table;
SELECT a, b FROM archive_table;

Speicherung: Zeilen werden beim Einfügen komprimiert. ARCHIVE verwendet verlustfreie zlib-Datenkompression (siehe http://www.zlib.net/). Mit OPTIMIZE TABLE können Sie die Tabelle analysieren und in ein kleineres Format packen (einen Grund zur Verwendung von OPTIMIZE TABLE finden Sie weiter unten in diesem Abschnitt). Außerdem unterstützt diese Engine CHECK TABLE. Mehrere verschiedene Arten von Einfügungen sind möglich:

  • Eine INSERT-Anweisung schiebt die Zeilen einfach in einen Kompressionspuffer, der nach Bedarf auf die Platte zurückgeschrieben wird. Die Einfügung von Daten in den Puffer ist durch eine Sperre geschützt. Mit SELECT wird das Schreiben auf die Festplatte erzwungen, sofern nicht nur INSERT DELAYED-Einfügungen vorgekommen waren (diese werden nur nach Bedarf auf die Platte geschrieben). Siehe Abschnitt 13.2.4.2, „INSERT DELAYED.

  • Eine Massen-Einfügeoperation (bulk insert) wird erst nach ihrem Abschluss sichtbar, wenn nicht gleichzeitig andere Einfügungen auftreten: In diesem Fall wird sie teilweise sichtbar. Ein SELECT hat normalerweise nicht zur Folge, dass eine Massen-Einfügeoperation auf die Festplatte geschrieben wird, es sei denn, eine normale Einfügeoperation tritt auf, während die andere gerade geladen wird..

Anfragen: Bei Anfragen werden die Zeilen nach Bedarf dekomprimiert; es gibt keinen Zeilen-Cache. Eine SELECT-Operation führt einen kompletten Tabellen-Scan durch: Wenn ein SELECT auftritt, stellt es fest, wie viele Zeilen gerade zur Verfügung stehen und liest diese Anzahl Zeilen. SELECT wird als konsistente Leseoperation durchgeführt. Beachten Sie, dass viele SELECT-Anweisungen während einer Einfügeoperation die Datenkompression schwächt, es sei denn, Sie verwenden nur Massen- oder verzögerte Einfügungen. Eine bessere Kompression können Sie mit OPTIMIZE TABLE oder REPAIR TABLE erzielen. Die Anzahl der Zeilen, die SHOW TABLE STATUS für ARCHIVE-Tabellen meldet, ist immer korrekt. Siehe Abschnitt 13.5.2.5, „OPTIMIZE TABLE, Abschnitt 13.5.2.6, „REPAIR TABLE und Abschnitt 13.5.4.21, „SHOW TABLE STATUS.

Mehr zum Thema

14.9. Die CSV-Speicher-Engine

Die CSV-Speicher-Engine speichert Daten in Textdateien im Format von kommagetrennten Werten (Comma Separated Values, CSV).

Um diese Speicher-Engine zu aktivieren, verwenden Sie configure mit der Option --with-csv-storage-engine, wenn Sie MySQL bauen.

Die Speicher-Engine CSV ist in MySQL-Max- Binärdistributionen enthalten. Wenn Sie MySQL von einer Quelldistribution bauen, können Sie sie aktivieren, indem Sie configure mit der Option --with-csv-storage-engine aufrufen.

Die Quelle für die CSV-Engine finden Sie im Verzeichnis storage/csv einer MySQL- Quelldistribution.

Wenn Sie eine CSV-Tabelle anlegen, erstellt der Server eine Tabellen-Formatdatei im Datenbankverzeichnis. Die Datei beginnt mit dem Tabellennamen und hat die Erweiterung .frm. Außerdem legt die Speicher-Engine eine Datendatei an, deren Name mit dem Tabellennamen anfängt und die Erweiterung .CSV hat. Die Datendatei ist eine einfache Textdatei. Wenn Sie Daten in der Tabelle speichern, schreibt die Engine sie im CVS-Format in die Datei.

mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = CSV;
Query OK, 0 rows affected (0.12 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM test;
+------+------------+
| i    | c          |
+------+------------+
|    1 | record one |
|    2 | record two |
+------+------------+
2 rows in set (0.00 sec)

Wenn Sie die mit der obigen Anweisung im Datenbankverzeichnis erzeugte Datei test.CSV anschauen, müsste sie folgenden Inhalt haben:

"1","record one"
"2","record two"

Die Speicher-Engine CSV unterstützt keine Indizierung.

14.10. Die BLACKHOLE-Speicher-Engine

Die Speicher-Engine BLACKHOLE ist wie ein „Schwarzes Loch“, das Daten zwar entgegennimmt, aber nicht speichert. Anfragen geben immer eine leere Ergebnismenge zurück:

mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM test;
Empty set (0.00 sec)

Die Speicher-Engine BLACKHOLE ist in MySQL-Max- Binärdistributionen enthalten. Wenn Sie MySQL von einer Quelldistribution bauen, können Sie sie aktivieren, indem Sie configure mit der Option --with-blackhole-storage-engine aufrufen.

Die Quelle für die BLACKHOLE-Engine finden Sie im Verzeichnis sql einer MySQL- Quelldistribution.

Wenn Sie eine BLACKHOLE-Tabelle anlegen, erstellt der Server eine Tabellen-Formatdatei im Datenbankverzeichnis. Die Datei beginnt mit dem Tabellennamen und hat die Erweiterung .frm. Andere Dateien werden mit der Tabelle nicht verknüpft.

Die BLACKHOLE-Speicher-Engine unterstützt alle Arten von Indizes. Das bedeutet, dass Sie Indexdeklarationen in die Tabellendefinition aufnehmen können.

Ob BLACKHOLE zur Verfügung steht, prüfen Sie mit folgender Anweisung:

mysql> SHOW VARIABLES LIKE 'have_blackhole_engine';

Bei Einfügungen in eine BLACKHOLE-Tabelle werden keine Daten gespeichert, doch wenn das Binärlog aktiviert ist, werden die SQL-Anweisungen protokolliert (und auf die Slaveserver repliziert). Das kann als Wiederholungs- oder Filtermechanismus ganz nützlich sein. Nehmen wir zum Beispiel an, Ihre Anwendung benötigt Filterregeln auf der Slave-Seite, aber eine Übertragung sämtlicher Logdaten auf den Slave würde zu viel Traffic verursachen. In solchen Fällen kann auf dem Master-Host ein „Dummy“-Slave-Prozess mit BLACKHOLE als Speicher-Engine eingerichtet werden:

Replikation mit BLACKHOLE
        als Filter

Der Master schreibt in sein Binärlog und der als Slave fungierende „Dummy“-mysqld-Prozess wendet die gewünschte Kombination von replicate-do-*- und replicate-ignore-*-Regeln an und schreibt ein eigenes gefiltertes Binärlog. (Siehe Abschnitt 6.9, „Replikationsoptionen in my.cnf“.) Dieses gefilterte Log wird dann dem Slave zur Verfügung gestellt.

Da der Dummy-Prozess selbst gar keine Daten speichert, entsteht durch den zusätzlichen mysqld-Prozess auf dem Replikations-Master-Host kaum Verarbeitungs-Overhead. Dieser Mechanismus kann mit weiteren Replikations-Slaves wiederholt werden.

Andere mögliche Einsatzgebiete für BLACKHOLE sind:

  • Syntaxprüfung für Dump-Dateien.

  • Sie können den Overhead für Binärlogs messen, indem Sie die Performance eines BLACKHOLEs mit und ohne Binärlog vergleichen.

  • Da BLACKHOLE im Grunde eine „leere“ Speicher-Engine ist, könnte sie eingesetzt werden, um Leistungsengpässe ausfindig zu machen, die nicht mit der Speicher-Engine selbst zusammenhängen.

Seit MySQL 5.1.4 kann die BLACKHOLE-Engine mit Transaktionen umgehen, und zwar in dem Sinne, dass sie bestätigte Transaktionen in das Binärlog schreibt und zurückgerollte nicht.

Kapitel 15. Erstellung einer eigenen Speicher-Engine

Inhaltsverzeichnis

15.1. Einführung
15.2. Überblick
15.3. Quelldateien für Speicher-Engines erstellen
15.4. Erstellung des Handlerton
15.5. Die Erzeugung von Handlern
15.6. Definiton von Dateierweiterungen
15.7. Tabellen anlegen
15.8. Tabellen öffnen
15.9. Einfaches Tabellenscanning implementieren
15.9.1. Implementierung der Funktion store_lock()
15.9.2. Implementierung der Funktion external_lock()
15.9.3. Implementierung der Funktion rnd_init()
15.9.4. Implementierung der Funktion info()
15.9.5. Implementierung der Funktion extra()
15.9.6. Implementierung der Funktion rnd_next()
15.10. Tabellen schließen
15.11. INSERT-Unterstützung für Speicher-Engines
15.12. UPDATE-Unterstützung für Speicher-Engines
15.13. DELETE-Unterstützung für Speicher-Engines
15.14. Unterstützung für nichtsequenzielle Leseoperationen
15.14.1. Implementierung der Funktion position()
15.14.2. Implementierung der Funktion rnd_pos()
15.15. Unterstützung für Indizes
15.15.1. Überblick über Indizes
15.15.2. Indexinformationen während CREATE TABLE-Operationen erhalten
15.15.3. Erzeugen von Indexschlüsseln
15.15.4. Schlüsselinformationen parsen
15.15.5. Indexinformationen an den Optimierer liefern
15.15.6. Nutzung des Indexes vorbereiten mit index_init()
15.15.7. Aufräumen mit index_end()
15.15.8. Implementierung der Funktion index_read()
15.15.9. Implementierung der Funktion index_read_idx()
15.15.10. Implementierung der Funktion index_next()
15.15.11. Implementierung der Funktion index_prev()
15.15.12. Implementierung der Funktion index_first()
15.15.13. Implementierung der Funktion index_last()
15.16. Unterstützung für Transaktionen
15.16.1. Überblick über Transaktionen
15.16.2. Eine Transaktion starten
15.16.3. Implementierung von ROLLBACK
15.16.4. Implementierung von COMMIT
15.16.5. Unterstützung für Savepoints
15.17. Die API-Referenz
15.17.1. bas_ext
15.17.2. close
15.17.3. create
15.17.4. delete_row
15.17.5. delete_table
15.17.6. external_lock
15.17.7. extra
15.17.8. index_end
15.17.9. index_first
15.17.10. index_init
15.17.11. index_last
15.17.12. index_next
15.17.13. index_prev
15.17.14. index_read_idx
15.17.15. index_read
15.17.16. info
15.17.17. open
15.17.18. position
15.17.19. records_in_range
15.17.20. rnd_init
15.17.21. rnd_next
15.17.22. rnd_pos
15.17.23. start_stmt
15.17.24. store_lock
15.17.25. update_row
15.17.26. write_row

15.1. Einführung

Mit MySQL 5.1 hat die Firma MySQL AB eine Architektur für eine Pluggable Storage Engine eingeführt. Dadurch ist es jetzt möglich, neue Speicher-Engines zu erstellen und einem laufenden MySQL Server hinzuzufügen, ohne den Server selbst neu kompilieren zu müssen.

Durch diese Architektur wird es leichter, neue Speicher-Engines für MySQL zu entwickeln und einzusetzen.

Dieses Kapitel soll Ihnen als Leitfaden dienen und bei der Entwicklung einer Speicher-Engine für die neue Pluggable Storage Engine-Architektur helfen.

Mehr zum Thema

15.2. Überblick

Der MySQL Server ist modular aufgebaut:

Abbildung 15.1. MySQL-Architektur

MySQL-Architektur

Die Speicher-Engines übernehmen die Datenspeicherung und die Indexverwaltung für MySQL. Der MySQL Server kommuniziert mit den Speicher-Engines über eine klar definierte API.

Jede Speicher-Engine ist eine Klasse und jede Instanz dieser Klasse kommuniziert mit dem MySQL Server über ein spezielles Handler-Interface.

Für jeden Thread, der mit einer bestimmten Tabelle arbeiten muss, wird ein Handler angelegt. Zum Beispiel: Wenn drei Verbindungen alle mit derselben Tabelle zu arbeiten beginnen, müssen drei Handler-Instanzen erzeugt werden.

Sobald eine Handler-Instanz erzeugt wurde, erteilt der MySQL Server dem Handler Befehle, damit dieser Datenspeicherungs- und Abrufoperationen ausführt, wie beispielsweise eine Tabelle öffnen, Datensätze ändern und Indizes verwalten.

Selbst erstellte Speicher-Engines können progressiv aufgebaut werden: So könnte ein Entwickler mit einer nur-lesenden Engine beginnen und später Unterstützung für INSERT-, UPDATE- und DELETE-Operationen hinzufügen, um noch ein wenig später Indizierung, Transaktionen und andere fortgeschrittene Operationen zu implementieren.

15.3. Quelldateien für Speicher-Engines erstellen

Der einfachste Weg zur Implementierung einer neuen Speicher-Engine besteht darin, die EXAMPLE-Engine zu kopieren und zu modifizieren. Die Dateien ha_example.cc und ha_example.h liegen im Verzeichnis storage/example des MySQL 5.1-Quellbaums. Wie Sie an den Quellbaum von MySQL 5.1 gelangen, erfahren Sie unter Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“.

Beim Kopieren der Dateien ändern Sie deren Namen von ha_example.cc und ha_example.h in etwas für Ihre Speicher-Engine Passenderes ab, wie etwa ha_foo.cc und ha_foo.h.

Nach dem Kopieren und Umbenennen der Dateien müssen Sie EXAMPLE und example jeweils durch den Namen Ihrer Speicher-Engine ersetzen. Wenn Sie mit sed vertraut sind, können diese Schritte automatisch ausgeführt werden (in diesem Beispiel lautet der Name der Speicher-Engine „FOO“):

sed s/EXAMPLE/FOO/g ha_example.h | sed s/example/foo/g ha_foo.h
sed s/EXAMPLE/FOO/g ha_example.cc | sed s/example/foo/g ha_foo.cc

15.4. Erstellung des Handlerton

Der Handlerton (eine Abkürzung für „Handler Singleton“) definiert die Speicher-Engine und enthält Funktionszeiger auf diejenigen Funktionen, die für die Speicher-Engine als Ganzes gelten, im Gegensatz zu jenen Funktionen, die auf Tabellenebene arbeiten. Dazu gehören beispielsweise die Transaktionsfunktionen für Commits und Rollbacks.

Hier sehen Sie ein Beispiel aus der Speicher-Engine EXAMPLE.

handlerton example_hton= {
  "EXAMPLE",
  SHOW_OPTION_YES,
  "Example storage engine", 
  DB_TYPE_EXAMPLE_DB,
  NULL,    /* Initialisierung */
  0,       /* Slot */
  0,       /* Savepoint-Größe */
  NULL,    /* close_connection */
  NULL,    /* Savepoint */
  NULL,    /* Rollback zum Savepoint */
  NULL,    /* Savepoint freigeben */
  NULL,    /* Commit */
  NULL,    /* Rollback */
  NULL,    /* Prepare */
  NULL,    /* Recover */
  NULL,    /* commit_by_xid */
  NULL,    /* rollback_by_xid */
  NULL,    /* create_cursor_read_view */
  NULL,    /* set_cursor_read_view */
  NULL,    /* close_cursor_read_view */
  example_create_handler,    /* Neuen Handler anlegen */
  NULL,    /* Eine Datenbank löschen */
  NULL,    /* Panik-Aufruf */
  NULL,    /* Temporäre Latches freigeben */
  NULL,    /* Statistik aktualisieren */
  NULL,    /* Konsistenten Snapshot starten */
  NULL,    /* Logs auf die Platte schreiben */
  NULL,    /* Status anzeigen */
  NULL,    /* Replication Report Sent Binlog */
  HTON_CAN_RECREATE
};

Es folgt die Definition des Handlerton aus handler.h:

typedef struct
  {
    const char *name;
    SHOW_COMP_OPTION state;
    const char *comment;
    enum db_type db_type;
    bool (*init)();
    uint slot;
    uint savepoint_offset;
    int  (*close_connection)(THD *thd);
    int  (*savepoint_set)(THD *thd, void *sv);
    int  (*savepoint_rollback)(THD *thd, void *sv);
    int  (*savepoint_release)(THD *thd, void *sv);
    int  (*commit)(THD *thd, bool all);
    int  (*rollback)(THD *thd, bool all);
    int  (*prepare)(THD *thd, bool all);
    int  (*recover)(XID *xid_list, uint len);
    int  (*commit_by_xid)(XID *xid);
    int  (*rollback_by_xid)(XID *xid);
    void *(*create_cursor_read_view)();
    void (*set_cursor_read_view)(void *);
    void (*close_cursor_read_view)(void *);
    handler *(*create)(TABLE *table);
    void (*drop_database)(char* path);
    int (*panic)(enum ha_panic_function flag);
    int (*release_temporary_latches)(THD *thd);
    int (*update_statistics)();
    int (*start_consistent_snapshot)(THD *thd);
    bool (*flush_logs)();
    bool (*show_status)(THD *thd, stat_print_fn *print, enum ha_stat_type stat);
    int (*repl_report_sent_binlog)(THD *thd, char *log_file_name, my_off_t end_offset);
    uint32 flags;                                
  } handlerton;  

Es gibt insgesamt 30 Handlerton-Elemente, von denen aber nur wenige obligatorisch sind (insbesondere die ersten vier Elemente und die create()-Funktion).

  1. Der Name der Speicher-Engine. Dieser Name wird beim Anlegen von Tabellen verwendet (CREATE TABLE ... ENGINE = FOO;).

  2. Der Wert, der im Status-Feld angezeigt wird, wenn ein Benutzer den Befehl SHOW STORAGE ENGINES eingibt.

  3. Der Kommentar zur Speicher-Engine, eine Beschreibung, die durch den Befehl SHOW STORAGE ENGINES angezeigt wird.

  4. Ein Integer, der die Speicher-Engine im MySQL Server eindeutig bezeichnet. Die von den eingebauten Speicher-Engines benutzten Konstanten werden in der Datei handler.h definiert. Selbst erstellte Engines sollten DB_TYPE_CUSTOM verwenden.

  5. Ein Funktionszeiger auf die Initialisierungsfunktion der Speicher-Engine. Diese Funktion wird nur ein einziges Mal beim Starten des Servers aufgerufen, damit die Speicher-Engine-Klasse vor der Instanziierung der Handler die notwendigen Aufräumarbeiten erledigen kann.

  6. Der Slot. Jede Speicher-Engine hat ihren eigenen Speicherbereich (in Wirklichkeit ein Zeiger) im thd zur Speicherung von Verbindungsdaten für jede Verbindung. Angesprochen wird er mit thd->ha_data[foo_hton.slot]. Die Slot-Nummer wird von MySQL nach dem Aufruf von foo_init() initialisiert. Weitere Informationen über thd finden Sie unter Abschnitt 15.16.3, „Implementierung von ROLLBACK“.

  7. Der Savepoint-Offset. Um Daten pro Savepoint speichern zu können, besitzt die Speicher-Engine einen Speicherbereich in der angeforderten Größe (0, wenn kein Savepoint-Speicher notwendig ist).

    Der Savepoint-Offset muss als fester Wert mit der Größe des benötigten Speichers initialisiert werden, um Daten pro Savepoint speichern zu können. Nach foo_init wird er auf einen Offset des Savepoint-Speicherbereichs umgestellt und muss nicht mehr von der Speicher-Engine verwendet werden.

    Mehr zum Thema unter Abschnitt 15.16.5.1, „Den Savepoint-Offset angeben“.

  8. Transaktionssichere Speicher-Engines bereinigen den ihrem Slot zugewiesenen Speicher.

  9. Ein Funktionszeiger auf die Handler-Funktion savepoint_set(). Dieser wird genutzt, um einen Savepoint anzulegen und in dem entsprechend großen zugewiesenen Arbeitsspeicherbereich abzulegen.

    Mehr zum Thema unter Abschnitt 15.16.5.2, „Implementierung der Funktion savepoint_set.

  10. Ein Funktionszeiger auf die Handler-Funktion rollback_to_savepoint(). Dieser wird verwendet, um während einer Transaktion zu einem Savepoint zurückzukehren. Er wird nur für Speicher-Engines angelegt, die Savepoints unterstützen.

    Mehr zum Thema unter Abschnitt 15.16.5.3, „Implementierung der Funktion savepoint_rollback().

  11. Ein Funktionszeiger auf die Handler-Funktion release_savepoint(). Er wird verwendet, um die Ressourcen eines Savepoints während einer Transaktion freizugeben. Der Zeiger wird optional für Speicher-Engines, die Savepoints unterstützen, angelegt.

    Mehr zum Thema unter Abschnitt 15.16.5.4, „Implementierung der Funktion savepoint_release().

  12. Ein Funktionszeiger auf die Handler-Funktion commit(). Wird verwendet, um eine Transaktion festzuschreiben. Er wird nur für Speicher-Engines angelegt, die Savepoints unterstützen.

    Mehr zum Thema unter Abschnitt 15.16.4, „Implementierung von COMMIT“.

  13. Ein Funktionszeiger auf die Handler-Funktion rollback(). Wird verwendet, um eine Transaktion zurückzurollen. Er wird nur für Speicher-Engines angelegt, die Savepoints unterstützen.

    Mehr zum Thema unter Abschnitt 15.16.3, „Implementierung von ROLLBACK“.

  14. Erforderlich für transaktionssichere XA-Speicher-Engines. Bereitet eine Transaktion auf das Commit vor.

  15. Erforderlich für transaktionssichere XA-Speicher-Engines. Gibt eine Liste von Transaktionen zurück, die sich im vorbereiteten Zustand befinden.

  16. Erforderlich für transaktionssichere XA-Speicher-Engines. Schreibt die Transaktion XID fest.

  17. Erforderlich für transaktionssichere XA-Speicher-Engines. Rollt die Transaktion XID zurück.

  18. Wird beim Anlegen eines Cursors aufgerufen, damit die Speicher-Engine eine konsistente Read-View erzeugen kann.

  19. Wird aufgerufen, um auf eine bestimmte konsistente Read-View umzustellen.

  20. Wird aufgerufen, um eine bestimmte Read-View zu schließen.

  21. OBLIGATORISCH . Erzeugt eine Handler-Instanz und gibt sie zurück.

    Mehr zum Thema unter Abschnitt 15.5, „Die Erzeugung von Handlern“.

  22. Wird verwendet, wenn die Speicher-Engine beim Löschen eines Schemas besondere Maßnahmen ergreifen muss (wie zum Beispiel eine Speicher-Engine, die Tablespaces verwendet).

  23. Bereinigungsfunktion, die nach dem Herunterfahren oder Abstürzen eines Servers aufgerufen wird.

  24. InnoDB-spezifische Funktion.

  25. InnoDB-spezifische Funktion, die beim Start von SHOW ENGINE InnoDB STATUS aufgerufen wird.

  26. Funktion, die aufgerufen wird, um einen konsistenten Read zu beginnen.

  27. Wird aufgerufen, um anzuzeigen, dass die Logs auf einem zuverlässigen Speichermedium gespeichert werden sollen.

  28. Liefert für Menschen lesbare Statusinformationen über die Speicher-Engine für SHOW ENGINE foo STATUS.

  29. InnoDB-spezifische Funktion, die zur Replikation verwendet wird.

  30. Handlerton-Flags, welche die Fähigkeiten der Speicher-Engine anzeigen. Die möglichen Werte sind in sql/handler.h definiert und werden hier noch einmal aufgeführt:

    #define HTON_NO_FLAGS                 0
    #define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0)
    #define HTON_ALTER_NOT_SUPPORTED     (1 << 1)
    #define HTON_CAN_RECREATE            (1 << 2)
    #define HTON_FLUSH_AFTER_RENAME      (1 << 3)
    #define HTON_NOT_USER_SELECTABLE     (1 << 4)
    

    HTON_ALTER_NOT_SUPPORTED zeigt an, dass die Speicher-Engine keine ALTER TABLE-Anweisungen annehmen kann. Die FEDERATED-Speicher-Engine ist ein Beispiel dafür.

    HTON_FLUSH_AFTER_RENAME zeigt an, dass FLUSH LOGS nach der Umbenennung einer Tabelle aufgerufen werden muss.

    HTON_NOT_USER_SELECTABLE bedeutet, dass die Speicher-Engine nicht angezeigt werden darf, wenn ein Benutzer SHOW STORAGE ENGINES aufruft. Wird für System-Speicher-Engines wie zum Beispiel die Dummy-Engine für Binärlogs verwendet.

15.5. Die Erzeugung von Handlern

Als Erstes muss die Speicher-Engine den Methodenaufruf zur Erzeugung einer neuen Handler-Instanz unterstützen.

Vor dem Handlerton muss in der Quelldatei der Speicher-Engine ein Funktions-Header für die Instanziierungsfunktion definiert werden. Hier ist ein Beispiel aus der CSV-Engine:

static handler* tina_create_handler(TABLE *table);

Wie Sie sehen, nimmt die Funktion einen Zeiger auf die Tabelle entgegen, welche der Handler verwalten soll, und liefert das Handler-Objekt zurück.

Wenn der Funktions-Header definiert ist, wird die Funktion durch einen Funktionszeiger im create()-handlerton-Element angesprochen, um anzuzeigen, dass sie für die Erzeugung neuer Handler-Instanzen zuständig ist.

Das folgende Beispiel zeigt die Instanziierungsfunktion der Speicher-Engine MyISAM:

static handler *myisam_create_handler(TABLE *table)
  {
    return new ha_myisam(table);
  }

Dieser Aufruf arbeitet mit dem Konstruktor der Speicher-Engine. Das folgende Beispiel stammt von der Storage-Engine FEDERATED:

ha_federated::ha_federated(TABLE *table_arg)
  :handler(&federated_hton, table_arg),
  mysql(0), stored_result(0), scan_flag(0),
  ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
  {}

Und hier ist ein weiteres Beispiel mit der Storage-Engine EXAMPLE:

ha_example::ha_example(TABLE *table_arg)
  :handler(&example_hton, table_arg)
  {}  

Die zusätzlichen Elemente im FEDERATED-Beispiel sind Handler-Initialisierungen. Die erforderliche Minimalimplementierung ist die handler()-Initialisierung aus dem EXAMPLE-Beispiel.

15.6. Definiton von Dateierweiterungen

Die Speicher-Engines sind notwendig, damit der MySQL Server eine Liste von Erweiterungen bekommt, die von der betreffenden Engine für eine gegebene Tabelle sowie ihre Daten und Indizes benutzt werden können.

Erweiterungen werden in Form eines mit Null endenden String-Arrays erwartet. Das folgende Array wird von der CSV-Engine verwendet:

static const char *ha_tina_exts[] = {
  ".CSV",
  NullS
};

Dieses Array wird zurückgegeben, wenn die Funktion bas_ext() aufgerufen wird:

const char **ha_tina::bas_ext() const
{
  return ha_tina_exts;
}

Wenn Sie MySQL über die verwendeten Erweiterungen informieren, müssen Sie keine DROP TABLE-Funktionalität implementieren. Der MySQL Server nimmt Ihnen dies ab, indem er die Tabelle schließt und alle Dateien mit den von Ihnen angegebenen Erweiterungen löscht.

15.7. Tabellen anlegen

Wenn Sie einen Handler erzeugt haben, werden Sie normalerweise als Nächstes eine Tabelle anlegen.

Hierzu muss Ihre Speicher-Engine die virtuelle Funktion create() implementieren:

virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0;

Diese Funktion sollte alle notwendigen Dateien erzeugen, muss jedoch nicht die Tabelle öffnen. Darum wird sich später der MySQL Server kümmern.

Der Parameter *name ist der Tabellenname und der Parameter *form ist eine TABLE-Struktur, welche die Tabelle definiert und den Inhalt der zuvor bereits vom MySQL Server angelegten tablename.frm-Datei vergleicht. Die Datei tablename.frm darf nicht von Speicher-Engines geändert werden.

Der Parameter *info ist eine Struktur, die Informationen über die CREATE TABLE-Anweisung enthält, mit welcher die Tabelle angelegt wurde. Diese in handler.h definierte Struktur geben wir hier für Sie wieder:

typedef struct st_ha_create_information
{
    CHARSET_INFO *table_charset, *default_table_charset;
    LEX_STRING connect_string;
    const char *comment,*password;
    const char *data_file_name, *index_file_name;
    const char *alias;
    ulonglong max_rows,min_rows;
    ulonglong auto_increment_value;
    ulong table_options;
    ulong avg_row_length;
    ulong raid_chunksize;
    ulong used_fields;
    SQL_LIST merge_list;
    enum db_type db_type;
    enum row_type row_type;
    uint null_bits;                       /* NULL-Bits am Anfang des Datensatzes */
    uint options;				/* OR von HA_CREATE_-Optionen */
    uint raid_type,raid_chunks;
    uint merge_insert_method;
    uint extra_size;                      /* Länge des zusätzlichen Datensegments */
    bool table_existed;                /* 1 in create, falls Tabelle bereits vorhanden */
    bool frm_only;                        /* 1, wenn kein ha_create_table() */
    bool varchar;                         /* 1, wenn die Tabelle eine VARCHAR-Spalte hat */
} HA_CREATE_INFO;

Eine einfache Speicher-Engine kann den Inhalt von *form and *info ignorieren, denn im Grunde genügt es, die von der Speicher-Engine benutzten Datendateien anzulegen und gegebenenfalls zu initialisieren (vorausgesetzt, die Speicher-Engine arbeitet mit Dateien).

Das folgende Beispiel zeigt die Implementierung der Speicher-Engine CSV:

int ha_tina::create(const char *name, TABLE *table_arg,
  HA_CREATE_INFO *create_info)
{
    char name_buff[FN_REFLEN];
    File create_file;
    DBUG_ENTER("ha_tina::create");
  
    if ((create_file= my_create(fn_format(name_buff, name, "", ".CSV",
          MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
          O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
    DBUG_RETURN(-1);
  
    my_close(create_file,MYF(0));
 
    DBUG_RETURN(0);
}

Im obigen Beispiel kümmert sich die CSV-Engine gar nicht um die *table_arg- oder *create_info-Parameter, sondern legt einfach die erforderlichen Datendateien an, schließt sie wieder und kehrt zurück.

Die Funktionen my_create und my_close sind Hilfsfunktionen. Ihre Definition steht in src/include/my_sys.h.

15.8. Tabellen öffnen

Ehe auf der Tabelle irgendwelche Lese- oder Schreiboperationen ausgeführt werden, ruft der MySQL Server die Methode handler::open() auf, um die Datendateien und (sofern vorhanden) die Indexdateien der Tabelle zu öffnen.

int open(const char *name, int mode, int test_if_locked);

Der erste Parameter ist der Name der zu öffnenden Tabelle und der zweite legt fest, welche Datei geöffnet oder welche Operation ausgeführt werden soll. Die Werte sind in handler.h definiert und werden hier noch einmal wiedergegeben:

O_RDONLY  -  Mit nur-lesendem Zugriff öffnen
O_RDWR    -  Mit Lese-/Schreibzugriff öffnen

Die letzte Option legt fest, ob der Handler auf eine Tabellensperre achten soll, bevor er die Tabelle öffnet. Folgende Möglichkeiten stehen zur Verfügung:

#define HA_OPEN_ABORT_IF_LOCKED   0   /* der Default */
#define HA_OPEN_WAIT_IF_LOCKED    1
#define HA_OPEN_IGNORE_IF_LOCKED  2
#define HA_OPEN_TMP_TABLE         4   /* es ist eine temporäre Tabelle */
#define HA_OPEN_DELAY_KEY_WRITE   8   /* nicht den Index aktualisieren */
#define HA_OPEN_ABORT_IF_CRASHED  16
#define HA_OPEN_FOR_REPAIR        32  /* auch öffnen, wenn sie abgestürzt ist */  

Die Speicher-Engine muss in der Regel irgendeine Art von Zugriffskontrolle implementieren, um in einer Multithread-Umgebung Schäden an der Tabelle zu verhüten. Ein Beispiel für die Implementierung von Dateisperren finden Sie in den Methoden get_share() und free_share() von sql/examples/ha_tina.cc.

15.9. Einfaches Tabellenscanning implementieren

Die simpelsten Speicher-Engines implementieren nur-lesende Tabellenscans. Solche Engines können eingesetzt werden, um SQL-Anfragen auf Logs oder anderen Datendateien zu unterstützen, die außerhalb von MySQL mit Daten gefüllt werden.

Die Implementierung der Methoden in diesem Absatz ist der erste Schritt zu anspruchsvolleren Speicher-Engines.

Im Folgenden sehen Sie, welche Methoden beim Scan einer neunzeiligen Tabelle der CSV-Engine aufgerufen werden:

ha_tina::store_lock
ha_tina::external_lock
ha_tina::info
ha_tina::rnd_init
ha_tina::extra - ENUM HA_EXTRA_CACHE   Cache record in HA_rrnd()
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::extra - ENUM HA_EXTRA_NO_CACHE   End caching of records (def)
ha_tina::external_lock
ha_tina::extra - ENUM HA_EXTRA_RESET   Reset database to after open

15.9.1. Implementierung der Funktion store_lock()

Die Funktion store_lock() wird vor allen Lese- und Schreibvorgängen aufgerufen.

Bevor die Sperre dem Tabellensperren-Handler hinzugefügt wird, ruft mysqld die Funktion store_lock() mit den erforderlichen Sperren auf. Die Funktion kann das Ausmaß der Sperrung ändern, also beispielsweise eine blockierende Schreibsperre in eine nichtblockierende umwandeln, die Sperre ignorieren (wenn keine MySQL-Tabellensperren benutzt werden sollen) oder Sperren für viele Tabellen hinzufügen (wie es bei Verwendung eines MERGE-Handlers getan wird).

Berkeley DB stuft beispielsweise blockierende Tabellensperren vom Typ TL_WRITE zu nichtblockierenden TL_WRITE_ALLOW_WRITE-Sperren herab (ein Hinweis darauf, dass zwar WRITE-Operationen stattfinden, aber dennoch andere lesende und schreibende Prozesse zugelassen sind).

Auch beim Aufheben von Sperren wird store_lock() aufgerufen. In diesem Fall muss in der Regel nichts weiter veranlasst werden.

Wenn store_lock das Argument TL_IGNORE bekommt, bedeutet das, dass MySQL vom Handler verlangt, dasselbe Ausmaß der Sperrung wie beim letzten Mal zu speichern.

Die möglichen Sperrentypen sind in includes/thr_lock.h definiert und werden hier noch einmal aufgeführt:

enum thr_lock_type
{
         TL_IGNORE=-1,
         TL_UNLOCK,			             /* SPERREN AUFHEBEN */
 	  TL_READ,			               /* Lesesperre */
 	  TL_READ_WITH_SHARED_LOCKS,  
         TL_READ_HIGH_PRIORITY,      /* Hat Priorität vor TL_WRITE. Nebenläufige Einfügeoperationen zulässig*/
         TL_READ_NO_INSERT, 		     /* READ, nebenläufige Einfügeoperationen unzulässig */
         TL_WRITE_ALLOW_WRITE, 		   /*	Schreibsperre, aber andere Threads dürfen lesen/schreiben. */
         TL_WRITE_ALLOW_READ,        /*	Schreibsperre, aber andere Threads dürfen lesen/schreiben. */
         TL_WRITE_CONCURRENT_INSERT, /* WRITE-Sperre, die von nebenläufigen Einfügeoperationen benutzt wird. */
         TL_WRITE_DELAYED,  		     /* Schreibvorgang, der von INSERT DELAYED verwendet wird.  READ-Sperren zulässig */
         TL_WRITE_LOW_PRIORITY,	     /* WRITE-Sperre mit geringerer Priorität als TL_READ */
         TL_WRITE,          		     /* Normale WRITE-Sperre */
         TL_WRITE_ONLY               /* Jede neue Sperranforderung wird mit einem Fehler abgebrochen*/
};  

Der tatsächliche Umgang mit Sperren hängt von der Implementierung Ihrer Sperren ab. Sie können alle, einige oder gar keine der geforderten Sperrentypen implementieren und eigene Methoden verwenden, wo es Ihnen passend erscheint. Im Folgenden sehen Sie eine Minimalimplementierung für eine Speicher-Engine, die keine Sperren herabstufen muss:

THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
                                     THR_LOCK_DATA **to,
                                     enum thr_lock_type lock_type)
{
   if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
     lock.type=lock_type;
   *to++= &lock;
   return to;
}  

Eine komplexere Implementierung finden Sie unter ha_berkeley::store_lock() und ha_myisammrg::store_lock().

15.9.2. Implementierung der Funktion external_lock()

Die Funktion external_lock() wird am Anfang einer Anweisung und bei jedem LOCK TABLES aufgerufen.

Beispiele für die Verwendung der Funktion external_lock() finden Sie in den Dateien sql/ha_innodb.cc und sql/ha_berkeley.cc, doch die meisten Speicher-Engines können auch einfach 0 zurückgeben, wie es auch die Speicher-Engine EXAMPLE tut:

int ha_example::external_lock(THD *thd, int lock_type)
{
   DBUG_ENTER("ha_example::external_lock");
   DBUG_RETURN(0);
}

15.9.3. Implementierung der Funktion rnd_init()

Die Funktion, die vor jedem Tabellenscan aufgerufen wird, ist rnd_init(). Sie wird verwendet, um einen Tabellenscan vorzubereiten, indem sie Zähler und Zeiger wieder auf den Anfang der Tabelle zurücksetzt.

Das folgende Beispiel verwendet die Speicher-Engine CSV:

  int ha_tina::rnd_init(bool scan)
{
      DBUG_ENTER("ha_tina::rnd_init");
 
      current_position= next_position= 0;
      records= 0;
      chain_ptr= chain;
 
      DBUG_RETURN(0);
}  

Hat der Parameter scan den Wert true, durchsucht MySQL die Tabelle sequenziell; hat er den Wert false, werden willkürliche Leseoperationen auf Zufallspositionen durchgeführt.

15.9.4. Implementierung der Funktion info()

Vor einem Tabellenscan wird die Funktion info() aufgerufen, um zusätzliche Tabelleninformationen für den Optimierer zu beschaffen.

Diese Informationen werden dem Optimierer nicht über Rückgabewerte geliefert, sondern durch Zuweisung bestimmter Eigenschaften der Klasse der Speicher-Engine. Diese Eigenschaften liest der Optimierer, bevor der Aufruf von info() zurückkehrt.

Viele der von info() gesetzten Werte werden nicht nur vom Optimierer genutzt, sondern auch von der SHOW TABLE STATUS-Anweisung.

In sql/handler.h werden alle öffentlichen Eigenschaften vollständig aufgeführt. Einige der gebräuchlichsten werden hier noch einmal wiedergegeben:

ulonglong data_file_length;		/* Länge der Datendatei */
  ulonglong max_data_file_length;	/* Länge der Datendatei */
ulonglong index_file_length;
ulonglong max_index_file_length;
ulonglong delete_length;		/* Freie Bytes */
ulonglong auto_increment_value;
ha_rows records;			/* Datensätze in der Tabelle */
ha_rows deleted;			/* Gelöschte Datensätze */
ulong raid_chunksize;
ulong mean_rec_length;		/* Physikalische Länge der Datensätze */
time_t create_time;			/* Erstellungszeitpunkt der Tabelle */
time_t check_time;
time_t update_time;  

Die für einen Tabellenscan wichtigste Eigenschaft ist records: Sie gibt an, wie viele Datensätze die Tabelle hat. Zeigt die Speicher-Engine null oder eine Zeile in der Tabelle an, verhält sich der Optimierer anders, als wenn die Tabelle zwei oder mehr Zeilen hat. Daher ist es wichtig, vor einem Scan von Tabellen, deren Größe nicht genau bekannt ist (wie zum Beispiel in Fällen, wo die Daten aus einer externen Quelle kommen), einen Wert größer gleich zwei zurückzugeben.

15.9.5. Implementierung der Funktion extra()

Vor manchen Operationen wird die Funktion extra() aufgerufen, um der Speicher-Engine zusätzliche Hinweise zu geben, wie sie bestimmte Operationen auszuführen hat.

Die Implementierung der Hinweise im Aufruf von extra ist nicht obligatorisch. Die meisten Speicher-Engines geben hier 0 zurück:

int ha_tina::extra(enum ha_extra_function operation)
{
   DBUG_ENTER("ha_tina::extra");
   DBUG_RETURN(0);
}

15.9.6. Implementierung der Funktion rnd_next()

Nach der Tabelleninitialisierung ruft der MySQL Server die Handler-Funktion rnd_next() für jede zu untersuchende Zeile einmal auf, bis seine Suchbedingung erfüllt oder das Ende der Datei erreicht ist. Im letzteren Fall gibt er HA_ERR_END_OF_FILE zurück.

Die Funktion rnd_next() nimmt einen Byte-Array-Parameter namens *buf entgegen. Dieser *buf-Parameter muss mit dem Inhalt der Tabellenzeile im internen Format von MySQL gefüllt sein.

Der Server verwendet drei Datenformate: Zeilen mit fester Länge, Zeilen mit variabler Länge und variabel lange Zeilen mit BLOB-Zeigern. In jedem der Formate erscheinen die Spalten in derselben Reihenfolge wie in der CREATE TABLE-Anweisung. (Die Tabellendefinition wird in der .frm-Datei gespeichert und Optimierer und Handler können beide die Metadaten der Tabelle aus derselben Quelle holen, nämlich aus ihrer TABLE-Struktur.)

Jedes Format beginnt mit einer „NULL-Bitmap“, die für jede nullfähige Spalte ein Bit enthält. Eine Tabelle mit 8 nullfähigen Spalten hat somit eine 1 Byte große Bitmap, während eine Tabelle mit 9 bis 16 nullfähigen Spalten eine 2 Byte große Bitmap besitzt, und so weiter. Eine Ausnahme bilden die Tabellen mit fester Breite: Da sie ein zusätzliches Startbit haben, würde eine solche Tabelle mit 8 nullfähigen Spalten dennoch eine 2 Byte große Bitmap aufweisen.

Hinter der NULL-Bitmap kommen nacheinander die Spalten an die Reihe. Jede Spalte hat die in Kapitel 11, Datentypen, angegebene Größe. Im Server sind die Spaltendatentypen in der Datei sql/field.cc definiert. In einem Format mit fester Zeilenbreite werden die Spalten einfach nacheinander angeordnet. In einem Format mit variabler Zeilenlänge werden die VARCHAR-Spalten mit einer Länge von 1 oder 2 Byte, gefolgt von einem Zeichen-String, kodiert. In einer variabel langen Zeile mit BLOB-Spalten wird jeder BLOB in zwei Teilen dargestellt: Zuerst kommt ein Integer, der die tatsächliche Länge des BLOB darstellt, und dann ein Zeiger auf den Speicherplatz des BLOB.

Beispiele für die Konvertierung (oder das „Packen“) von Zeilen finden Sie ab der Funktion rnd_next() in jedem Tabellen-Handler. So zeigt beispielsweise in ha_tina.cc der Code von find_current_row(), wie die TABLE-Struktur (auf welche die Tabelle verweist) und ein String-Objekt namens Buffer genutzt werden können, um Zeichendaten aus einer CSV-Datei zu packen. Um eine Zeile auf die Platte zurückzuspeichern, ist die umgekehrte Konvertierung erforderlich: Die Zeilen müssen dann aus dem internen Format wieder zurückkonvertiert werden.

Das folgende Beispiel stammt wieder aus der Speicher-Engine CSV:

int ha_tina::rnd_next(byte *buf)
{
   DBUG_ENTER("ha_tina::rnd_next");
 
   statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status);
 
   current_position= next_position;
   if (!share->mapped_file)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
   if (HA_ERR_END_OF_FILE == find_current_row(buf) )
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
   records++;
   DBUG_RETURN(0);
}  

Die Funktion find_current_row() übernimmt die Konvertierung aus dem internen Zeilenformat in ein CSV-Zeilenformat:

int ha_tina::find_current_row(byte *buf)
{
   byte *mapped_ptr= (byte *)share->mapped_file + current_position;
   byte *end_ptr;
   DBUG_ENTER("ha_tina::find_current_row");
 
   /* EOF soll als Newline gelten*/
   if ((end_ptr=  find_eoln(share->mapped_file, current_position,
                            share->file_stat.st_size)) == 0)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
   for (Field **field=table->field ; *field ; field++)
   {
     buffer.length(0);
     mapped_ptr++; // Inkrementiere hinter dem ersten Anführungszeichen
     for(;mapped_ptr != end_ptr; mapped_ptr++)
     {
       // Ist notwendig, um Zeilenvorschübe zu konvertieren!
       if (*mapped_ptr == '"' &&
           (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) ||
            (mapped_ptr == end_ptr -1 )))
       {
         mapped_ptr += 2; // Gehe hinter das , und das "
         break;
       }
       if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
       {
         mapped_ptr++;
         if (*mapped_ptr == 'r')
           buffer.append('\r');
         else if (*mapped_ptr == 'n' )
           buffer.append('\n');
         else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
           buffer.append(*mapped_ptr);
         else  /* Dies kann nur bei einer extern erzeugten Datei passieren */
         {
           buffer.append('\\');
           buffer.append(*mapped_ptr);
         }
       }
       else
         buffer.append(*mapped_ptr);
     }
     (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
   }
   next_position= (end_ptr - share->mapped_file)+1;
   /* Vielleicht \N für null verwenden? */
   memset(buf, 0, table->s->null_bytes); /* Nullen werden nicht implementiert! */
 
   DBUG_RETURN(0);
}  

15.10. Tabellen schließen

Wenn der MySQL Server eine Tabelle nicht mehr benötigt, ruft er die Methode close() auf, um Zeiger auf Dateien zu schließen und andere Ressourcen freizugeben.

Speicher-Engines, die Methoden für einen gemeinsamen Zugriff verwenden, wie sie in CSV und anderen Beispiel-Engines vorkommen, müssen sich selbst aus der share-Struktur entfernen:

int ha_tina::close(void)
 {
   DBUG_ENTER("ha_tina::close");
   DBUG_RETURN(free_share(share));
 }  

Speicher-Engines mit eigenem Share Management-System sollten alle notwendigen Methoden einsetzen, um die Handler-Instanz aus der Freigabe (Share) für die Tabelle zu entfernen, die in ihrem Handler geöffnet ist.

15.11. INSERT-Unterstützung für Speicher-Engines

Wenn Ihre Speicher-Engine Lesefähigkeiten bekommen hat, ist als Nächstes die Unterstützung für INSERT-Anweisungen an der Reihe. Beherrscht Ihre Speicher-Engine INSERT, so kann sie auch mit WORM(write once, read many)-Anwendungen wie etwa dem Protokollieren und Archivieren von Daten zur späteren Analyse umgehen.

Alle INSERT-Operationen werden von der Funktion write_row() erledigt:

int ha_foo::write_row(byte *buf)

Der Parameter *buf enthält die einzufügende Zeile im internen Format von MySQL. Eine simple Speicher-Engine könnte einfach an das Ende der Datendatei gehen und den Inhalt des Puffers direkt dort anfügen (das würde auch das Lesen von Zeilen vereinfachen, da man die Zeile lesen und direkt an den Puffer-Parameter der Funktion rnd_next() übergeben könnte).

Der Prozess zum Schreiben einer Zeile ist genau das Gegenteil vom Leseprozess: Er nimmt die Daten im internen Zeilenformat von MySQL und schreibt sie in die Datendatei. Das folgende Beispiel stammt von der Speicher-Engine MyISAM:

int ha_myisam::write_row(byte * buf)
{
  statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status);

  /* Zeitstempel-Spalte, falls vorhanden, auf die aktuelle Zeit setzen */
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
    table->timestamp_field->set_time();
 
  /*
    Wenn eine auto_increment-Spalte vorhanden ist und wir eine geänderte oder neue Zeile laden,
    muss der auto_increment-Wert im Datensatz aktualisiert werden.
  */
  if (table->next_number_field && buf == table->record[0])
    update_auto_increment();
  return mi_write(file,buf);
}

Im obigen Beispiel sind drei Dinge bemerkenswert: Die Tabellenstatistik für Schreiboperationen wird aktualisiert, der Zeitstempel wird vor dem eigentlichen Schreibvorgang aktualisiert und die AUTO_INCREMENT-Werte werden hochgesetzt.

15.12. UPDATE-Unterstützung für Speicher-Engines

Der MySQL Server führt UPDATE-Anweisungen aus, indem er so lange (Tabelle, Index, Bereich usw.) scannt, bis er eine Zeile findet, die zu der WHERE-Klausel der UPDATE-Anweisung passt. Dann ruft er die Funktion update_row() auf:

int ha_foo::update_row(const byte *old_data, byte *new_data)

Der Parameter *old_data enthält die Daten, die vor dem Update in der Zeile gespeichert waren, während der Parameter *new_data den neuen Zeileninhalt enthält (im internen Zeilenformat von MySQL).

Wie ein Update durchgeführt wird, hängt vom Zeilenformat und der Speicherimplementierung ab. Manche Speicher-Engines ersetzen Daten direkt, während andere Implementierungen die vorhandene Zeile löschen und die neue Zeile am Ende der Datendatei anfügen.

Speicher-Engines ohne Indizierung können den Inhalt des Parameters *old_data ignorieren und müssen sich nur mit dem Pufferinhalt *new_data abgeben. Engines mit Transaktionsunterstützung müssen unter Umständen die Puffer vergleichen, um für ein mögliches späteres Rollback herauszufinden, welche Änderungen vorgenommen wurden.

Enthält die zu ändernde Tabelle Zeitstempelspalten, muss die Funktion update_row() auch diese Zeitstempel aktualisieren. Das folgende Beispiel stammt von der Speicher-Engine CSV:

int ha_tina::update_row(const byte * old_data, byte * new_data)
{
   int size;
   DBUG_ENTER("ha_tina::update_row");
 
   statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
 		      &LOCK_status);
 
   if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
     table->timestamp_field->set_time();
 
   size= encode_quote(new_data);
 
   if (chain_append())
     DBUG_RETURN(-1);
 
   if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
     DBUG_RETURN(-1);
   DBUG_RETURN(0);
}

Beachten Sie, wie in diesem Beispiel der Zeitstempel eingestellt wurde.

15.13. DELETE-Unterstützung für Speicher-Engines

Der MySQL Server verwendet für DELETE-Anweisungen denselben Ansatz wie für UPDATE-Anweisungen: Er geht mithilfe der Funktion rnd_next() zu der Zeile, die gelöscht werden soll, und ruft dann die Funktion delete_row() auf:

int ha_foo::delete_row(const byte *buf)

Der Parameter *buf enthält den Inhalt der zu löschenden Zeile. Speicher-Engines ohne Indizierung können diesen Parameter ignorieren, aber Speicher-Engines mit Transaktionsunterstützung müssen die gelöschten Daten für ein späteres Rollback speichern.

Das folgende Beispiel stammt von der CSV-Engine:

int ha_tina::delete_row(const byte * buf)
{
   DBUG_ENTER("ha_tina::delete_row");
   statistic_increment(table->in_use->status_var.ha_delete_count,
                       &LOCK_status);
 
   if (chain_append())
     DBUG_RETURN(-1);
  
   --records;
 
   DBUG_RETURN(0);
}

Das Wichtige an diesem Beispiel sind die Aktualisierung der delete_count-Statistik und die Zeilenzählung.

15.14. Unterstützung für nichtsequenzielle Leseoperationen

Speicher-Engines können nicht nur Tabellenscanning implementieren, sondern auch Funktionen für ein nichtsequenzielles Lesen. Der MySQL Server nutzt diese Funktionen für bestimmte Sortieroperationen.

15.14.1. Implementierung der Funktion position()

Die Funktion position() wird nach jedem rnd_next()-Aufruf benötigt, wenn die Daten neu geordnet werden müssen:

void ha_foo::position(const byte *record)

Der Inhalt von *record ist Ihre Sache; was Sie auch immer als Inhalt einsetzen, wird in einem späteren Abruf der Zeile zurückgeliefert. Die meisten Speicher-Engines speichern irgendeine Art von Offset oder Primärschlüsselwert.

15.14.2. Implementierung der Funktion rnd_pos()

Die Funktion rnd_pos() verhält sich ähnlich wie rnd_next(), hat aber einen zusätzlichen Parameter:

int ha_foo::rnd_pos(byte * buf, byte *pos)

Dieser *pos-Parameter enthält die Position, die zuvor mit der Funktion position() ermittelt wurde.

Eine Speicher-Engine muss die Zeile an der angegebenen Position ausfindig machen und durch *buf im internen Zeilenformat von MySQL zurückgeben.

15.15. Unterstützung für Indizes

Sobald eine Engine über einfache Lese- und Schreiboperationen verfügt, muss als Nächstes Unterstützung für Indizes her. Ohne Indizes ist die Leistung einer Speicher-Engine äußerst mager.

Dieser Abschnitt beschreibt, welche Methoden implementiert werden müssen, damit eine Speicher-Engine Indizes unterstützt.

15.15.1. Überblick über Indizes

Indexunterstützung für eine Speicher-Engine bedeutet zweierlei: Informationen an den Optimierer zu geben und indexbezogene Methoden zu implementieren. Die Informationen, die der Optimierer erhält, helfen ihm zu entscheiden, welchen Index er verwenden soll oder ob er die Indizierung beiseite lassen und stattdessen einen Tabellenscan durchführen soll.

Die Indexmethoden lesen entweder Zeilen, die zu einem Schlüssel passen, scannen eine Zeilenmenge in der Reihenfolge ihrer Indizes oder lesen Informationen direkt aus dem Index.

Das folgende Beispiel zeigt die Funktionsaufrufe während einer UPDATE-Anfrage, die einen Index nutzt, wie beispielsweise in UPDATE foo SET ts = now() WHERE id = 1:

ha_foo::index_init
ha_foo::index_read
ha_foo::index_read_idx
ha_foo::rnd_next
ha_foo::update_row  

Zusätzlich zu Methoden, die Indizes lesen, benötigt Ihre Speicher-Engine auch Methoden, die neue Indizes erstellen und Tabellenindizes auf dem Laufenden halten, wenn Zeilen hinzugefügt, modifiziert oder entfernt werden.

15.15.2. Indexinformationen während CREATE TABLE-Operationen erhalten

Speicher-Engines mit Indexunterstützung sollten die Indexinformationen möglichst während einer CREATE TABLE-Operation beschaffen und zur späteren Verwendung speichern. Der Grund: Die Indexinformationen sind beim Anlegen der Tabelle und des Indexes am einfachsten zu bekommen und lassen sich später nicht mehr so leicht abrufen.

Die Daten des Tabellenindexes liegen in der key_info-Struktur des TABLE-Arguments der create()-Funktion vor.

In der key_info-Struktur gibt es ein flag, welches das Verhalten des Indexes definiert:

#define HA_NOSAME             1  /* Keine Doppeleinträge vorhanden   */
  #define HA_PACK_KEY           2  /* String zu vorigem Schlüssel packen */
#define HA_AUTO_KEY           16
#define HA_BINARY_PACK_KEY    32 /* Alle Schlüssel zu vorigem Schlüssel packen */
#define HA_FULLTEXT          128 /* Volltextsuche            */
#define HA_UNIQUE_CHECK      256 /* Schlüssel auf Eindeutigkeit prüfen    */
#define HA_SPATIAL          1024 /* Raumbezogene Suche          */
#define HA_NULL_ARE_EQUAL   2048 /* Gleichheitsvergleich für NULL in Schlüssel möglich   */
#define HA_GENERATED_KEY    8192 /* Automatisch generierter Schlüssel    */

Zusätzlich zum flag ist ein Enumerator namens algorithm vorhanden, der den gewünschten Indextyp angibt:

enum ha_key_alg {
  HA_KEY_ALG_UNDEF=     0,  /* Nicht angegeben (alte Datei)     */
  HA_KEY_ALG_BTREE=     1,  /* B-Tree, ist der Standard          */
  HA_KEY_ALG_RTREE=     2,  /* R-Tree, für raumbezogenes Suchen */
  HA_KEY_ALG_HASH=      3,  /* HASH-Schlüssel (HEAP-Tabellen)      */
  HA_KEY_ALG_FULLTEXT=  4   /* FULLTEXT (MyISAM-Tabellen)     */
};

Zusätzlich zum flag und algorithm ist ein Array von key_part-Elementen vorhanden, welche die einzelnen Teile eines zusammengesetzten Schlüssels beschreiben.

Diese Schlüsselteile definieren das zu dem jeweiligen Teil gehörende Feld, geben an, ob der Schlüssel gepackt werden soll, und verraten den Datentyp und die Länge des Indexteils. Unter ha_myisam.cc finden Sie ein Beispiel dafür, wie diese Daten geparst werden.

Als Alternative kann eine Speicher-Engine auch dem Beispiel von ha_berkeley.cc folgen und bei jeder Operation Indexinformationen aus der TABLE-Struktur des Handlers lesen.

15.15.3. Erzeugen von Indexschlüsseln

Bei jeder Schreiboperation auf Tabellen (INSERT, UPDATE, DELETE) muss die Speicher-Engine ihre internen Indexdaten aktualisieren.

Die hierzu verwendete Methode variiert von Engine zu Engine und hängt davon ab, welche Methode zum Speichern des Indexes verwendet wird.

Im Allgemeinen muss die Speicher-Engine die in Funktionen wie write_row(), delete_row() und update_row() übergebenen Zeilendaten mit den Indexinformationen der Tabelle kombinieren, um festzustellen, welche Indexdaten geändert werden müssen, und die notwendigen Modifikationen vorzunehmen.

Mit welcher Methode Zeile und Index zusammengebracht werden, hängt von dem Ansatz Ihrer Speicherung ab. Die Speicher-Engine BerkeleyDB speichert den Primärschlüssel der Zeile im Index, während andere Engines oft nur den Zeilen-Offset speichern.

15.15.4. Schlüsselinformationen parsen

Viele der Indexmethoden übergeben ein Byte-Array namens *key, welches den zu lesenden Indexeintrag in einem Standardformat angibt. Ihre Speicher-Engine muss die Informationen des Schlüssels extrahieren und in ihr internes Indexformat übersetzen, um die zum Index gehörige Zeile zu ermitteln.

Die im Schlüssel vorliegenden Daten werden mit einer Iteration durch den Schlüssel beschafft. Ihr Format ist so, wie es in table->key_info[index]->key_part[part_num] definiert wurde. Das folgende Beispiel aus ha_berkeley.cc zeigt, wie die Speicher-Engine BerkeleyDB einen in *key definierten Schlüssel in ihr internes Format konvertiert:

/*
Erzeuge aus einem ungepackten MySQL-Schlüssel (wie dem, der von index_read() übermittelt wird) einen gepackten.
  
Anhand dieses Schlüssels wird eine Zeile gelesen
*/
  
DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
                                                const byte *key_ptr, uint key_length)
{
  KEY *key_info=table->key_info+keynr;
  KEY_PART_INFO *key_part=key_info->key_part;
  KEY_PART_INFO *end=key_part+key_info->key_parts;
  DBUG_ENTER("bdb:pack_key");
  
  bzero((char*) key,sizeof(*key));
  key->data=buff;
  key->app_private= (void*) key_info;
  
  for (; key_part != end && (int) key_length > 0 ; key_part++)
  {
      uint offset=0;
      if (key_part->null_bit)
      {
          if (!(*buff++ = (*key_ptr == 0)))         // Für NULL wird 0 gespeichert
          {
              key_length-= key_part->store_length;
              key_ptr+=   key_part->store_length;
              key->flags|=DB_DBT_DUPOK;
              continue;
          }
          offset=1;                                 // Daten liegen unter key_ptr+1
      }
      buff=key_part->field->pack_key_from_key_image(buff,(char*) key_ptr+offset,
      key_part->length);
      key_ptr+=key_part->store_length;
      key_length-=key_part->store_length;
  }
  key->size= (buff  - (char*) key->data);
  DBUG_DUMP("key",(char*) key->data, key->size);
  DBUG_RETURN(key);
}

15.15.5. Indexinformationen an den Optimierer liefern

Damit die Indizierung wirkungsvoll eingesetzt wird, müssen Speicher-Engines dem Optimierer Informationen über die Tabelle und ihre Indizes liefern. Anhand dieser Informationen wird entschieden, ob und, wenn ja, welcher Index genutzt werden soll.

15.15.5.1. Implementierung der Funktion info()

Durch Aufruf der Funktion handler::info() fordert der Optimierer die Aktualisierung der Tabellendaten an. Die Funktion info() hat keinen Rückgabewert; stattdessen wird erwartet, dass die Speicher-Engine eine Reihe von öffentlichen Variablen setzt, die der Server dann nach Bedarf auslesen kann. Diese Werte werden auch für bestimmte SHOW-Ausgaben wie beispielsweise SHOW TABLE STATUS und für INFORMATION_SCHEMA eingesetzt.

Alle Variablen sind optional, sollten aber nach Möglichkeit ausgefüllt werden:

  • records – Die Anzahl der Zeilen in der Tabelle. Wenn Sie nicht schnell eine genaue Zahl liefern können, sollten Sie diesen Wert auf größer als 1 setzen, damit der Optimierer nicht für Tabellen mit null oder einer Zeile in Aktion treten muss.

  • deleted – Die Anzahl der gelöschten Zeilen in der Tabelle. Dient der Ermittlung von Tabellenfragmentation, wo sie vorliegt.

  • data_file_length – Die Größe der Datendatei in Bytes. Hilft dem Optimierer, den Aufwand von Leseoperationen zu berechnen.

  • index_file_length – Die Größe der Indexdatei in Bytes. Hilft dem Optimierer, den Aufwand von Leseoperationen zu berechnen.

  • mean_rec_length – Die Durchschnittslänge einer einzelnen Zeile in Bytes.

  • scan_time – I/O-Aufwand für den Versuch eines vollständigen Tabellenscans.

  • delete_length – (keine Beschreibung verfügbar)

  • check_time – (keine Beschreibung verfügbar)

Bei der Berechnung von Werten geht Geschwindigkeit vor Genauigkeit, da es keinen Sinn hat, viel Zeit zu vertrödeln, um dem Optimierer den schnellsten Weg aufzuzeigen. Schätzungen innerhalb einer Größenordnung sind normalerweise ausreichend.

15.15.5.2. Implementierung der Funktion records_in_range

Die Funktion records_in_range() wird vom Optimierer aufgerufen, um besser entscheiden zu können, welcher Index einer Tabelle für eine Anfrage oder einen Join benutzt werden soll. Sie ist folgendermaßen definiert:

ha_rows ha_foo::records_in_range(uint inx, key_range *min_key, key_range *max_key)

Der Parameter inx ist der zu prüfende Index. Der Parameter *min_key gibt das untere und der Parameter *max_key das obere Ende des Bereichs an.

min_key.flag kann einen der folgenden Werte haben:

  • HA_READ_KEY_EXACT - Schlüssel in den Bereich einbeziehen

  • HA_READ_AFTER_KEY - Schlüssel nicht in den Bereich einbeziehen

max_key.flag kann einen der folgenden Werte haben:

  • HA_READ_BEFORE_KEY - Schlüssel nicht in den Bereich einbeziehen

  • HA_READ_AFTER_KEY - Alle 'end_key'-Werte in den Bereich einbeziehen

Folgende Rückgabewerte sind zulässig:

  • 0 - Keine passenden Schlüssel im gegebenen Bereich vorhanden

  • number > 0 - Es gibt ungefähr number passende Zeilen im Bereich

  • HA_POS_ERROR - Fehler im Indexbaum

Bei der Berechnung der Werte geht Geschwindigkeit vor Genauigkeit.

15.15.6. Nutzung des Indexes vorbereiten mit index_init()

Die Funktion index_init() wird vor Benutzung eines Indexes aufgerufen, damit die Speicher-Engine die notwendigen Vorbereitungen oder Optimierungen vornehmen kann:

int ha_foo::index_init(uint keynr, bool sorted)

Da die meisten Speicher-Engines keine besonderen Vorbereitungen treffen, wird in diesem Fall eine Standardimplementierung verwendet, wenn die Methode nicht explizit in der Engine implementiert ist:

int handler::index_init(uint idx) { active_index=idx; return 0; }

15.15.7. Aufräumen mit index_end()

Die Funktion index_end() ist das Gegenstück zu index_init(). Ihre Aufgabe ist es, hinter index_init() wieder aufzuräumen.

Wenn eine Speicher-Engine index_init() nicht implementiert, muss sie auch index_end() nicht implementieren.

15.15.8. Implementierung der Funktion index_read()

Die Funktion index_read() wird verwendet, um eine Zeile anhand eines Schlüssels abzufragen:

int ha_foo::index_read(byte * buf, const byte * key, uint key_len, enum ha_rkey_function find_flag)

Der Parameter *buf ist ein Byte-Array, in dem die Speicher-Engine die Zeile speichert, die zu dem Indexschlüssel *key gehört. Der Parameter key_len gibt bei Präfixvergleichen die Länge des Präfixes an und find_flag ist ein Enumerator, der das Suchverhalten bestimmt.

Der zu verwendende Index wird vorher im Aufruf von index_init() festgelegt und dann in der Handler-Variablen active_index gespeichert.

Folgende Werte sind für find_flag zulässig:

HA_READ_KEY_EXACT
HA_READ_KEY_OR_NEXT
HA_READ_PREFIX_LAST          
HA_READ_PREFIX_LAST_OR_PREV
HA_READ_BEFORE_KEY
HA_READ_AFTER_KEY
HA_READ_KEY_OR_NEXT
HA_READ_KEY_OR_PREV    

Speicher-Engines müssen den Parameter *key in ihr spezifisches Format konvertieren. Danach verwenden sie ihn, um anhand von find_flag die passende Zeile zu finden und im internen Zeilenformat von MySQL in *buf zu speichern. Weitere Informationen über das interne Zeilenformat finden Sie unter Abschnitt 15.9.6, „Implementierung der Funktion rnd_next().

Die Speicher-Engine muss nicht nur die passende Zeile zurückgeben, sondern auch einen Cursor setzen, um sequenzielle Index-Reads zu unterstützen.

Ist der Parameter *key null, liest die Speicher-Engine den ersten Schlüssel im Index.

15.15.9. Implementierung der Funktion index_read_idx()

Die Funktion index_read_idx() gleicht index_read() mit dem Unterschied, dass index_read_idx() noch einen weiteren keynr-Parameter akzeptiert:

int ha_foo::index_read_idx(byte * buf, uint keynr, const byte * key,
                        uint key_len, enum ha_rkey_function find_flag)  

Der Parameter keynr gibt den zu lesenden Index an, während bei index_read der Index bereits eingestellt ist.

Wie mit index_read() muss auch hier die Speicher-Engine die zum Schlüssel gehörige Zeile gemäß dem find_flag zurückgeben und für zukünftige Leseoperationen einen Cursor setzen.

15.15.10. Implementierung der Funktion index_next()

Die Funktion index_next() wird zum Durchsuchen des Indexes benutzt:

int ha_foo::index_next(byte * buf)

Im Parameter *buf wird die Zeile gespeichert, die entsprechend dem internen Cursor, den die Speicher-Engine bei Operationen wie index_read() und index_first() gesetzt hatte, dem nächsten passenden Schlüsselwert entspricht.

15.15.11. Implementierung der Funktion index_prev()

Die Funktion index_prev() wird für umgekehrtes Indexscanning verwendet:

int ha_foo::index_prev(byte * buf)

Im Parameter *buf wird die Zeile gespeichert, die entsprechend dem internen Cursor, den die Speicher-Engine bei Operationen wie index_read() und index_last() gesetzt hatte, dem vorherigen passenden Schlüsselwert entspricht.

15.15.12. Implementierung der Funktion index_first()

Die Funktion index_first() wird für das Indexscanning verwendet:

int ha_foo::index_first(byte * buf)

Im Parameter *buf wird die Zeile gespeichert, die dem ersten Schlüsselwert im Index entspricht.

15.15.13. Implementierung der Funktion index_last()

Die Funktion index_last() wird für das umgekehrte Indexscanning verwendet:

int ha_foo::index_last(byte * buf)

Im Parameter *buf wird die Zeile gespeichert, die dem letzten Schlüsselwert im Index entspricht.

15.16. Unterstützung für Transaktionen

In diesem Abschnitt sind Methoden beschrieben, die implementiert werden müssen, damit eine Speicher-Engine Transaktionen unterstützen kann.

Bitte beachten Sie, dass das Transaktionsmanagement eine komplizierte Sache sein kann, zu der auch Methoden zur Zeilenversionierung und Redo-Logs gehören, die den Rahmen dieser Dokumentation sprengen würden. Hier wird lediglich beschrieben, welche Methoden notwendig sind, und nicht, wie diese implementiert werden. Implementierungsbeispiele finden Sie in ha_innodb.cc und ha_berkeley.cc.

15.16.1. Überblick über Transaktionen

Transaktionen werden nicht explizit auf der Ebene der Speicher-Engines, sondern implizit durch Aufrufe der Funktion start_stmt() oder external_lock() gestartet. Falls bei Aufruf dieser Funktionen bereits eine Transaktion läuft, wird diese nicht ersetzt.

Die Speicher-Engine speichert Transaktionsinformationen in ihrem pro Verbindung zugewiesenen Arbeitsspeicher und registriert die Transaktion beim MySQL Server, damit dieser später COMMIT- und ROLLBACK-Operationen ausführen kann.

Die Speicher-Engine muss irgendeine Art von Versionierung oder Protokollierung implementieren, damit alle Operationen, die im Rahmen der Transaktion ausgeführt werden, wieder zurückgerollt werden können.

Nach getaner Arbeit ruft der MySQL Server entweder die commit()-Funktion oder die im Handlerton der Speicher-Engine definierte rollback()-Funktion auf.

15.16.2. Eine Transaktion starten

Die Speicher-Engine startet eine Transaktion, wenn die Funktion start_stmt() oder external_lock() aufgerufen wird.

Ist noch keine Transaktion aktiv, muss die Speicher-Engine eine neue beginnen und beim MySQL Server registrieren, damit später ROLLBACK oder COMMIT aufgerufen werden kann.

15.16.2.1. Eine Transaktion mit start_stmt() starten

Die erste Funktion, die eine Transaktion beginnen kann, ist start_stmt().

Das folgende Beispiel zeigt, wie eine Speicher-Engine eine Transaktion registrieren könnte:

int my_handler::start_stmt(THD *thd, thr_lock_type lock_type) 
{
  int error= 0;
  my_txn *txn= (my_txn *) thd->ha_data[my_handler_hton.slot];
  
  if (txn == NULL)
  {
    thd->ha_data[my_handler_hton.slot]= txn= new my_txn;
  }
  if (txn->stmt == NULL && !(error= txn->tx_begin()))
  {
    txn->stmt= txn->new_savepoint();
    trans_register_ha(thd, FALSE, &my_handler_hton);
  }
  return error;
}

THD ist die aktuelle Clientverbindung. Sie speichert zustandsrelevante Daten für den aktuellen Client, wie beispielsweise seine Identität, Netzwerkverbindung und andere Verbindungsdaten.

thd->ha_data[my_handler_hton.slot] ist ein Zeiger in thd auf die verbindungsspezifischen Daten dieser Speicher-Engine. In diesem Beispiel wird er verwendet, um den Transaktionskontext zu speichern.

Ein weiteres Beispiel für die Implementierung von start_stmt() finden Sie in ha_innodb.cc.

15.16.2.2. Eine Transaktion mit external_lock() starten

MySQL ruft zu Beginn jeder Anweisung für jede zu verwendende Tabelle handler::external_lock() auf. Somit wird immer dann, wenn eine Tabelle zum ersten Mal angesprochen wird, implizit eine Transaktion gestartet.

Da noch keine Sperren vorhanden sind, werden alle Tabellen, die möglicherweise zwischen dem Anfang und dem Ende einer Anweisung verwendet werden könnten, gesperrt, bevor die Ausführung der Anweisung beginnt. Für alle diese Tabellen wird handler::external_lock() aufgerufen. Wenn also ein INSERT einen Trigger abfeuert, der eine gespeicherte Prozedur aufruft, die eine gespeicherte Funktion aufruft usw., werden alle von Trigger, gespeicherter Prozedur, Funktion usw. verwendeten Tabellen schon zu Beginn des INSERT gesperrt. Und wenn ein Konstrukt wie das folgende vorliegt, dann werden beide Tabellen gesperrt:

IF
.. verwende eine Tabelle
ELSE
  .. verwende eine andere Tabelle

Außerdem gilt: Wenn ein Benutzer LOCK TABLES eingibt, ruft MySQL handler::external_lock nur ein einziges Mal auf. In diesem Fall führt MySQL handler::start_stmt() zu Beginn der Anweisung aus.

Das folgende Beispiel zeigt, wie eine Speicher-Engine eine Transaktion starten und Sperranforderungen dabei berücksichtigen kann:

int my_handler::external_lock(THD *thd, int lock_type) 
{
  int error= 0;
  my_txn *txn= (my_txn *) thd->ha_data[my_handler_hton.slot];
  
  if (txn == NULL)
  {
    thd->ha_data[my_handler_hton.slot]= txn= new my_txn;
  }
  
  if (lock_type != F_UNLCK)
  {
    bool all_tx= 0;
    if (txn->lock_count == 0)
    {
      txn->lock_count= 1;
      txn->tx_isolation= thd->variables.tx_isolation;
  
      all_tx= test(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK));
    }
  
    if (all_tx)
    {
      txn->tx_begin();
      trans_register_ha(thd, TRUE, &my_handler_hton);
    }
    else
    if (txn->stmt == 0)
    {
      txn->stmt= txn->new_savepoint();
      trans_register_ha(thd, FALSE, &my_handler_hton);
    }
  }
  else
  {
    if (txn->stmt != NULL)
    {
      /* Schreibe Transaktion fest, wenn Autocommit-Modus eingeschaltet */
      my_handler_commit(thd, FALSE);
  
      delete txn->stmt; // Lösche Savepoint
      txn->stmt= NULL;
    }
  }
  
  return error;
}

Jede Speicher-Engine muss immer zu Beginn einer Transaktion trans_register_ha() aufrufen. Die Funktion trans_register_ha() registriert eine Transaktion beim MySQL Server, um spätere COMMIT- und ROLLBACK-Operationen möglich zu machen.

Ein weiteres Implementierungsbeispiel für external_lock() finden Sie in ha_innodb.cc.

15.16.3. Implementierung von ROLLBACK

Von den beiden wichtigsten Transaktionsoperationen ist ROLLBACK am schwierigsten zu implementieren. Alle Operationen, die während der Transaktion auftraten, müssen rückgängig gemacht werden, damit sämtliche Zeilen wieder den unveränderten Zustand vor der Transaktion zurückerhalten.

Um ROLLBACK zu unterstützen, benötigen Sie eine Funktion, die folgender Definition entspricht:

int  (*rollback)(THD *thd, bool all);

Der Name dieser Funktion wird dann im rollback-Eintrag (dem 13.) des Handlerton aufgeführt.

Der Parameter THD zeigt an, welche Transaktion zurückgerollt werden soll, und bool all legt fest, ob die gesamte Transaktion oder nur die letzte Anweisung rückgängig gemacht werden soll.

Die Implementierungsdetails von ROLLBACK sind von Engine zu Engine unterschiedlich. Beispiele finden Sie in ha_innodb.cc und ha_berkeley.cc.

15.16.4. Implementierung von COMMIT

Bei einer Commit-Operation werden alle während einer Transaktion vorgenommenen Änderungen festgeschrieben, sodass eine Rollback-Operation danach nicht mehr möglich ist. Je nachdem, welche Transaktionsisolation verwendet wurde, werden die Änderungen dann zum ersten Mal für andere Threads sichtbar.

Zur Unterstützung von COMMIT benötigen Sie eine Funktion, die wie folgt definiert ist:

int  (*commit)(THD *thd, bool all);

Der Name dieser Funktion wird dann im commit-Eintrag (dem 12.) des Handlerton aufgeführt.

Der Parameter THD zeigt an, welche Transaktion festgeschrieben werden soll, und bool all legt fest, ob dies ein kompletter Commit ist oder nur das Ende einer zu einer Transaktion gehörenden Anweisung.

Die Implementierungsdetails von COMMIT sind von Engine zu Engine unterschiedlich. Beispiele finden Sie in ha_innodb.cc and ha_berkeley.cc.

Läuft der Server im Autocommit-Modus, so müsste die Speicher-Engine automatisch alle nur-lesenden Anweisungen wie beispielsweise SELECT festschreiben.

Das "Autocommitten" in einer Speicher-Engine funktioniert durch Zählen von Sperren. Jeder Aufruf von external_lock() inkrementiert den Zähler und jeder Aufruf von external_lock() mit dem Argument F_UNLCK dekrementiert ihn. Fällt die Anzahl der Sperren auf null, wird ein Commit ausgelöst.

15.16.5. Unterstützung für Savepoints

Zuerst sollte der Implementierer wissen, wie viele Bytes erforderlich sind, um die Savepoint-Daten zu speichern. Diese Anzahl sollte eine feste Größe und möglichst nicht zu groß sein, da der MySQL Server Platz zum Speichern des Savepoints für alle Speicher-Engines und jeden benannten Savepoint zuweisen muss.

Der Implementierer sollte die Daten in dem von mysqld zuvor zugewiesenen Platz speichern und den Inhalt dieses zugewiesenen Speichers auch nutzen, um Rollback- oder Savepoint-Freigabeoperationen auszuführen.

Wenn ein COMMIT oder ROLLBACK eintritt (wobei bool all auf true gesetzt ist), werden alle Savepoints freigegeben. Wenn die Speicher-Engine Ressourcen für Savepoints zuweist, sollte sie diese freigeben.

Die folgenden Handlerton-Elemente müssen implementiert werden, damit Savepoints unterstützt werden können (es sind die Elemente 7, 9, 10 und 11):

uint savepoint_offset;
int  (*savepoint_set)(THD *thd, void *sv);
int  (*savepoint_rollback)(THD *thd, void *sv);
int  (*savepoint_release)(THD *thd, void *sv);

15.16.5.1. Den Savepoint-Offset angeben

Das siebte Element des Handlertons ist der savepoint_offset:

uint savepoint_offset;

Der savepoint_offset muss mit einer festen Größe initialisiert werden, die ausreicht, um die Savepoint zu speichernden Informationen aufzunehmen.

15.16.5.2. Implementierung der Funktion savepoint_set

Die Funktion savepoint_set() wird immer dann aufgerufen, wenn ein Benutzer den Befehl SAVEPOINT gibt:

int  (*savepoint_set)(THD *thd, void *sv);

Der Parameter *sv verweist auf einen uninitialisierten Speicherbereich, dessen Größe in savepoint_offset definiert wurde.

Wenn savepoint_set() aufgerufen wird, muss die Speicher-Engine Savepoint-Informationen in sv speichern, damit der Server die Transaktion später bis zu dem Savepoint zurückrollen oder die Ressourcen des Savepoints wieder freigeben kann.

15.16.5.3. Implementierung der Funktion savepoint_rollback()

Die Funktion savepoint_rollback() wird immer dann aufgerufen, wenn ein Benutzer die ROLLBACK TO SAVEPOINT-Anweisung erteilt:

int  (*savepoint_rollback) (THD *thd, void *sv);

Der Parameter *sv verweist auf den Speicherbereich, der zuvor an die Funktion savepoint_set() übergeben wurde.

15.16.5.4. Implementierung der Funktion savepoint_release()

Die Funktion savepoint_release() wird immer dann aufgerufen, wenn ein Benutzer die Anweisung RELEASE SAVEPOINT verwendet:

int  (*savepoint_release) (THD *thd, void *sv);

Der Parameter *sv verweist auf den Speicherbereich, der zuvor an die Funktion savepoint_set() übergeben wurde.

15.17. Die API-Referenz

15.17.1. bas_ext

Zweck

Definiert die von der Speicher-Engine verwendeten Dateierweiterungen.

Zusammenfassung

virtual const char ** bas_ext (); 
 ;

Beschreibung

Dies ist die Methode bas_ext. Sie wird aufgerufen, um dem MySQL Server die Liste der von der Speicher-Engine verwendeten Dateierweiterungen in Form eines mit null endenden String-Arrays mitzuteilen.

Indem sie eine Liste der Dateierweiterungen angeben, können Speicher-Engines in vielen Fällen auf die Funktion delete_table() verzichten, da der MySQL Server alle Verweise auf die Tabelle schließt und alle Dateien mit den angegebenen Erweiterungen löscht.

Parameter

Diese Funktion hat keine Parameter.

Rückgabewerte

  • Der Rückgabewert ist ein auf null endendes String-Array mit den Dateierweiterungen der Speicher-Engine. Das folgende Beispiel stammt von der Engine CSV:

    static const char *ha_tina_exts[] =
     {
       ".CSV",
       NullS
     };
    

Verwendung

static const char *ha_tina_exts[] =
 {
   ".CSV",
   NullS
 };
        
const char **ha_tina::bas_ext() const
 {
   return ha_tina_exts;
 }  

Standardimplementierung

static const char *ha_example_exts[] = {
   NullS
 };
 
const char **ha_example::bas_ext() const
 {
   return ha_example_exts;
 }

15.17.2. close

Zweck

Schließt eine geöffnete Tabelle.

Zusammenfassung

virtual int close (void); 
 void ;

Beschreibung

Dies ist die Methode close.

Schließt eine Tabelle. Ein guter Zeitpunkt, um die zugewiesenen Ressourcen wieder freizugeben.

Wird von sql_base.cc, sql_select.cc und table.cc aufgerufen. In sql_select.cc wird diese Methode nur zum Schließen temporärer Tabellen oder bei der Konvertierung einer temporären in eine MyISAM-Tabelle verwendet. Wegen sql_base.cc schauen Sie unter close_data_tables() nach.

Parameter

  • void

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Ein Beispiel von der CSV-Engine:

int ha_example::close(void)
{
  DBUG_ENTER("ha_example::close");
  DBUG_RETURN(free_share(share));
}

15.17.3. create

Zweck

Legt eine neue Tabelle an.

Zusammenfassung

virtual int create (name,  
 form,  
 info); 
const char * name ;
TABLE * form ;
HA_CREATE_INFO * info ;

Beschreibung

Dies ist die Methode create.

create() wird aufgerufen, um eine Tabelle anzulegen. Der Variablenname ist dann der Name der Tabelle. Wenn Sie create() aufrufen, brauchen Sie die Tabelle nicht zu öffnen. Auch die .frm-Datei ist dann bereits angelegt, sodass ein Aufruf von adjusting create_info nicht mehr zu empfehlen ist.

Wird von handler.cc in Form von ha_create_table() aufgerufen.

Parameter

  • name

  • form

  • info

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Beispiel von der Speicher-Engine CSV:

int ha_tina::create(const char *name, TABLE *table_arg,
                    HA_CREATE_INFO *create_info)
{
  char name_buff[FN_REFLEN];
  File create_file;
  DBUG_ENTER("ha_tina::create");

  if ((create_file= my_create(fn_format(name_buff, name, "", ".CSV",
                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
                              O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
    DBUG_RETURN(-1);

  my_close(create_file,MYF(0));

  DBUG_RETURN(0);
}          

15.17.4. delete_row

Zweck

Löscht eine Zeile.

Zusammenfassung

virtual int delete_row (buf); 
const byte * buf ;

Beschreibung

Dies ist die Methode delete_row.

buf enthält eine Kopie der zu löschenden Zeile. Der Server verwendet diese Funktion, unmittelbar nachdem die aktuelle Zeile aufgerufen wurde (von einer vorangegangenen rnd_next()-Funktion oder einem Indexaufruf). Wenn Sie einen Zeiger auf die letzte Zeile bewahren oder auf einen Primärschlüssel zugreifen können, wird das Löschen viel einfacher. Denken Sie daran, dass der Server aufeinander folgende Löschungen nicht garantiert. ORDER BY-Klauseln können verwendet werden.

Wird in sql_acl.cc und sql_udf.cc aufgerufen, um interne Tabelleninformationen zu verwalten. Wird auch in sql_delete.cc, sql_insert.cc und sql_select.cc benutzt. In sql_select wird diese Funktion zum Entfernen von Duplikaten eingesetzt, während sie in insert für REPLACE-Aufrufe verwendet wird.

Parameter

  • buf

Rückgabewerte

Keine Rückgabewerte.

Verwendung

(kein Beispiel verfügbar)

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.5. delete_table

Zweck

Alle Dateien löschen, die eine von bas_ext() gemeldete Erweiterung haben.

Zusammenfassung

virtual int delete_table (name); 
const char * name ;

Beschreibung

Dies ist die Methode delete_table.

Dient dem Löschen einer Tabelle. Wenn delete_table() aufgerufen wird, sind alle offenen Verweise auf diese Tabelle geschlossen (und auch Ihre globalen, gemeinsam genutzten Verweise freigegeben) worden. Der Variablenname ist der Name der Tabelle. Zuvor angelegte Dateien müssen an diesem Punkt gelöscht werden.

Wenn Sie diese Funktion nicht implementieren, wird die Standardfunktion delete_table() von handler.cc aufgerufen, die alle Dateien mit den von bas_ext() zurückgegebenen Erweiterungen löscht. Man kann davon ausgehen, dass der Handler unter Umständen mehr Erweiterungen zurückgibt, als für die Datei tatsächlich verwendet wurden.

Wird von handler.cc durch delete_table und ha_create_table() aufgerufen. Wird beim Erzeugen einer Tabelle nur dann eingesetzt, wenn das table_flag HA_DROP_BEFORE_CREATE für die Speicher-Engine angegeben wurde.

Parameter

  • name: Basisname der Tabelle

Rückgabewerte

  • 0, wenn mindestens eine Datei von base_ext erfolgreich gelöscht und keine anderen Fehler als ENOENT gemeldet wurden.

  • #: Fehler

Verwendung

Die meisten Speicher-Engines brauchen diese Funktion nicht zu implementieren.

15.17.6. external_lock

Zweck

Sorgt bei Transaktionen für das Sperren der Tabellen.

Zusammenfassung

virtual int external_lock (thd,  
 lock_type); 
THD * thd ;
int lock_type ;

Beschreibung

Dies ist die Methode external_lock.

Im Abschnitt „locking functions for mysql“ in lock.cc finden Sie weitere lesenswerte Hinweise zu diesem Thema.

Sperrt eine Tabelle. Wenn Sie eine Speicher-Engine implementieren, die mit Transaktionen umgehen kann, schauen Sie in ha_berkely.cc nach, wie Sie am besten vorgehen. Ansonsten können Sie hier auch einen Aufruf von flock() in Erwägung ziehen.

Wird von lock.cc durch lock_external() und unlock_external() sowie von sql_table.cc durch copy_data_between_tables() aufgerufen.

Parameter

  • thd

  • lock_type

Rückgabewerte

Keine Rückgabewerte.

Standardimplementierung

{ return 0; }

15.17.7. extra

Zweck

Übergibt Hinweise („Hints“) vom Server an die Speicher-Engine.

Zusammenfassung

virtual int extra (operation); 
enum ha_extra_function operation ;

Beschreibung

Dies ist die Methode extra.

extra() wird aufgerufen, wenn der Server einen Hinweis an die Speicher-Engine senden will. Die Engine MyISAM implementiert die meisten Hinweise. ha_innodb.cc enthält die vollständigste Liste dieser Hinweise.

Parameter

  • operation

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Die meisten Speicher-Engines geben einfach 0 zurück.

{ return 0; }

Standardimplementierung

Sie können Ihrer Speicher-Engine auch die Standardeinstellung geben, keinen dieser Hinweise zu implementieren.

{ return 0; }

15.17.8. index_end

Zweck

Zeigt das Ende eines Indexscans an und gibt die hierfür belegten Ressourcen frei.

Zusammenfassung

virtual int index_end (); 
  ;

Beschreibung

Dies ist die Methode index_end, die normalerweise als Gegenstück zu index_init verwendet wird und alle für den Indexscan verwendeten Ressourcen wieder freigibt.

Parameter

Diese Funktion hat keine Parameter.

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Gibt alle zugewiesenen Ressourcen frei und liefert 0 zurück.

Standardimplementierung

{ active_index=MAX_KEY; return 0; }

15.17.9. index_first

Zweck

Fragt die erste Zeile eines Indexes ab und gibt sie zurück.

Zusammenfassung

virtual int index_first (buf); 
byte * buf ;

Beschreibung

Dies ist die Methode index_first.

index_first() fragt nach dem ersten Schlüssel im Index.

Wird von opt_range.cc, opt_sum.cc, sql_handler.cc und sql_select.cc aufgerufen.

Parameter

  • buf - Ein Byte-Array, in welches die Zeile geladen wird.

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Die Implementierung hängt von der verwendeten Indexmethode ab.

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.10. index_init

Zweck

Teilt der Speicher-Engine mit, dass ein Indexscan bevorsteht, damit diese die benötigten Ressourcen zuweist.

Zusammenfassung

virtual int index_init (idx,  
 sorted); 
uint  idx ;
bool  sorted ;

Beschreibung

Dies ist die Methode index_init. Diese Funktion wird vor einem Indexscan aufgerufen, damit die Speicher-Engine Gelegenheit hat, Ressourcen zuzuweisen und Vorbereitungen zu treffen.

Parameter

  • idx

  • sorted

Rückgabewerte

  • (nicht verfügbar)

Verwendung

Diese Funktion kann 0 zurückgeben, wenn keine Vorbereitung erforderlich ist.

Standardimplementierung

{ active_index=idx; return 0; }

15.17.11. index_last

Zweck

Gibt die letzte Zeile des Indexes zurück.

Zusammenfassung

virtual int index_last (buf); 
byte * buf ;

Beschreibung

Dies ist die Methode index_last.

index_last() fragt nach dem letzten Schlüssel im Index.

Wird von opt_range.cc, opt_sum.cc, sql_handler.cc und sql_select.cc aufgerufen.

Parameter

  • buf - Ein Byte-Array, in welches die zugehörige Zeile geladen wird.

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Geht zur letzten Zeile im Index und lädt den zugehörigen Datensatz in den Puffer.

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.12. index_next

Zweck

Gibt die nächste Zeile im Index zurück.

Zusammenfassung

virtual int index_next (buf); 
byte * buf ;

Beschreibung

Dies ist die Methode index_next.

Wird verwendet, um sich im Index nach vorne zu arbeiten.

Parameter

  • buf

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Geht mithilfe eines Zeigers oder Cursors immer zum nächsten Index weiter und schreibt die zugehörige Zeile in den Puffer.

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.13. index_prev

Zweck

Geht zur vorherigen Zeile im Index.

Zusammenfassung

virtual int index_prev (buf); 
byte * buf ;

Beschreibung

Dies ist die Methode index_prev.

Wird verwendet, um sich rückwärts durch den Index zu arbeiten.

Parameter

  • buf

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Geht zur vorigen Zeile im Index und schreibt diese in den Puffer.

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.14. index_read_idx

Zweck

Sucht anhand eines Schlüssels eine Zeile und schreibt sie in den Puffer.

Zusammenfassung

virtual int index_read_idx (buf,  
 index,  
 key,  
 key_len,  
 find_flag); 
byte * buf ;
uint index ;
const byte * key ;
uint key_len ;
enum ha_rkey_function find_flag ;

Beschreibung

Dies ist die Methode index_read_idx.

Setzt einen Indexcursor auf den im Schlüssel angegebenen Indexwert und holt, sofern vorhanden, die zugehörige Zeile ab. Wird nur verwendet, um ganze Schlüssel zu lesen.

Parameter

  • buf

  • index

  • key

  • key_len

  • find_flag

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Findet die zum Schlüssel gehörige Zeile und gibt sie in den bereitgestellten Puffer zurück.

15.17.15. index_read

Zweck

Sucht anhand eines Schlüssels eine Zeile und kehrt zurück.

Zusammenfassung

virtual int index_read (buf,  
 key,  
 key_len,  
 find_flag); 
byte * buf ;
const byte * key ;
uint key_len ;
enum ha_rkey_function find_flag ;

Beschreibung

Dies ist die Methode index_read.

Setzt einen Indexcursor auf den im Handle angegebenen Indexwert und holt, sofern vorhanden, die zugehörige Zeile ab. Ist der Schlüsselwert null, beginnt die Funktion beim ersten Schlüssel des Indexes.

Parameter

  • buf

  • key

  • key_len

  • find_flag

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

(kein Beispiel verfügbar)

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.16. info

Zweck

Lässt die Speicher-Engine Statistikdaten ausgeben.

Zusammenfassung

virtual void info (uint); 
 uint ;

Beschreibung

Dies ist die Methode info.

::info() gibt Informationen an den Optimierer zurück. Zurzeit implementiert dieser Tabellen-Handler die meisten erforderlichen Felder noch nicht. Auch SHOW nutzt diese Daten. Ein weiterer Hinweis ist der, dass Sie voraussichtlich Folgendes in Ihren Code schreiben müssen: if (records < 2) records = 2;. Denn sonst führt der Server auch in Fällen, wo nur ein einziger Datensatz vorhanden ist, Optimierungen durch. Wenn Sie die Anzahl der Datensätze bei einem Tabellenscan nicht kennen, sollten Sie records auf zwei einstellen, damit Sie so viele Datensätze zurückgeben können, wie Sie benötigen. Neben records gibt es noch einige weitere Variablen einzustellen, nämlich: deleted data_file_length, index_file_length, delete_length check_time. Weitere Informationen finden Sie unter den öffentlichen Variablen in handler.h.

Wird in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_show.cc, sql_show.ccsql_show.cc, sql_show.cc, sql_table.cc, sql_union.cc und sql_update.cc aufgerufen.

Parameter

  • uint

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Dieses Beispiel stammt von der Speicher-Engine CSV:

void ha_tina::info(uint flag)
{
  DBUG_ENTER("ha_tina::info");
  /* Ist zwar gelogen, aber der Optimierer soll keine mit null oder 1 Datensatz anfassen */
  if (records < 2)
    records= 2;
  DBUG_VOID_RETURN;
}          

15.17.17. open

Zweck

Öffnet eine Tabelle.

Zusammenfassung

virtual int open (name,  
 mode,  
 test_if_locked); 
const char * name ;
int mode ;
uint test_if_locked ;

Beschreibung

Dies ist die Methode open.

Wird zum Öffnen von Tabellen verwendet. Der Name ist der Name der Datei. Eine Tabelle wird dann geöffnet, wenn es nötig ist, zum Beispiel, wenn eine SELECT-Anfrage für die Tabelle eintrifft. (Die Tabellen werden jedoch nicht für jede Anfrage geöffnet und geschlossen, sondern zwischenzeitlich im Cache gelagert.)

Wird von handler.cc durch handler::ha_open() aufgerufen. Der Server öffnet alle Tabellen mit einem Aufruf der Funktion ha_open(), die dann die Handler-spezifische open()-Funktion aufruft.

Ein Handler-Objekt wird im Rahmen seiner Initialisierung geöffnet, bevor es für normale Anfragen verwendet wird (nicht immer vor Metadatenänderungen.) Wenn das Objekt geöffnet wurde, wird es auch vor dem Löschen wieder geschlossen.

Dies ist die Methode open. Sie wird aufgerufen, um eine Datenbanktabelle zu öffnen.

Der erste Parameter ist der Name der zu öffnenden Tabelle und der zweite legt fest, welche Datei geöffnet oder welche Operation ausgeführt werden soll. Die Werte sind in handler.h definiert und werden hier für Sie noch einmal aufgeführt:

#define HA_OPEN_KEYFILE		  1
#define HA_OPEN_RNDFILE		  2
#define HA_GET_INDEX		    4
#define HA_GET_INFO		      8	    /* nach dem Öffnen ha_info() aufrufen */
#define HA_READ_ONLY		    16	  /* Datei schreibgeschützt öffnen */
#define HA_TRY_READ_ONLY	  32    /* Wenn Schreibzugriff nicht möglich, schreibgeschützten versuchen */
#define HA_WAIT_IF_LOCKED	  64	  /* Bei vorhandener Sperre mit dem Öffnen warten */
#define HA_ABORT_IF_LOCKED	128	  /* Bei vorhandener Sperre das Öffnen überspringen*/
#define HA_BLOCK_LOCK		    256	  /* Entsperren, wenn einige Datensätze gelesen werden */
#define HA_OPEN_TEMPORARY	  512

Die letzte Option gibt an, ob der Handler auf Sperren auf der Tabelle achten soll, ehe er sie öffnet.

In der Regel wird Ihre Speicher-Engine auch irgendeine Form von Zugriffskontrolle implementieren müssen, damit in einer Multithread-Umgebung keine Dateien beschädigt werden. Ein Beispiel für die Implementierung von Dateisperren finden Sie in den Methoden get_share() und free_share() von sql/examples/ha_tina.cc.

Parameter

  • name

  • mode

  • test_if_locked

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Dieses Beispiel stammt von der Speicher-Engine CSV:

int ha_tina::open(const char *name, int mode, uint test_if_locked)
{
DBUG_ENTER("ha_tina::open");

if (!(share= get_share(name, table)))
DBUG_RETURN(1);
thr_lock_data_init(&share->lock,&lock,NULL);
ref_length=sizeof(off_t);

DBUG_RETURN(0);
}

15.17.18. position

Zweck

Liefert dem MySQL Server die Position/den Offset der zuletzt gelesenen Zeile.

Zusammenfassung

virtual void position (record); 
const byte * record ;

Beschreibung

Dies ist die Methode position.

position() wird nach jedem rnd_next() aufgerufen, wenn die Daten geordnet werden müssen. Um die Position zu speichern, können Sie so etwas wie das Folgende tun: my_store_ptr(ref, ref_length, current_position);

Der Server benutzt ref zum Speichern von Daten. In den obigen Fällen ist ref_length die Größe, die erforderlich ist, um die current_position zu speichern. ref ist nur ein Byte-Array, das vom Server gepflegt wird. Wenn Sie Offsets verwenden, um Zeilen zu kennzeichnen, dann sollte current_position der Offset sein. Wenn ein Primärschlüssel verwendet wird, wie in BDB, dann muss current_position ein Primärschlüssel sein.

Wird aufgerufen von filesort.cc, sql_select.cc, sql_delete.cc und sql_update.cc.

Parameter

  • record

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Gibt für die letzte Zeile einen Offset oder einen Schlüssel für den Datenabruf zurück.

15.17.19. records_in_range

Zweck

Gibt eine Einschätzung, wie viele Datensätze in dem angegebenen Bereich liegen.

Zusammenfassung

virtual ha_rows records_in_range (inx,  
 min_key,  
 max_key); 
uint inx ;
key_range * min_key ;
key_range * max_key ;

Beschreibung

Dies ist die Methode records_in_range.

Wenn Sie dieser Funktion einen Start- und einen End-Schlüssel übergeben, schätzt sie ein, wie viele Zeilen zwischen diesen beiden Schlüsseln liegen. end_key kann auch leer sein; in diesem Fall wird ermittelt, ob start_key irgendwelchen Zeilen entspricht.

Wird vom Optimierer genutzt, um den Aufwand zu ermitteln, den die Benutzung eines bestimmten Indexes verursachen würde.

Wird von opt_range.cc durch check_quick_keys() aufgerufen.

Parameter

  • inx

  • min_key

  • max_key

Rückgabewerte

Gibt die ungefähre Anzahl der Zeilen zurück.

Verwendung

Ermittelt näherungsweise die Anzahl der Zeilen zwischen den beiden Schlüsselwerten und kehrt zurück.

Standardimplementierung

{ return (ha_rows) 10; }

15.17.20. rnd_init

Zweck

Initialisiert einen Handler für den Tabellenscan.

Zusammenfassung

virtual int rnd_init (scan); 
bool scan ;

Beschreibung

Dies ist die Methode rnd_init.

rnd_init() wird aufgerufen, wenn das System von der Speicher-Engine einen Tabellenscan verlangt.

Anders als index_init() kann rnd_init() zweimal aufgerufen werden, ohne dass zwischendurch rnd_end() erforderlich ist (macht nur Sinn, wenn scan=1). Der zweite Aufruf sollte dann den neuen Tabellenscan vorbereiten (wenn z. B. rnd_init() den Cursor zuweist, sollte der zweite Aufruf diesen an den Tabellenanfang setzen; so muss er nicht erneut freigegeben und wieder zugewiesen werden).

Wird von filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc und sql_update.cc aufgerufen.

Parameter

  • scan

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Dieses Beispiel stammt von der Speicher-Engine CSV:

int ha_tina::rnd_init(bool scan)
{
  DBUG_ENTER("ha_tina::rnd_init");

  current_position= next_position= 0;
  records= 0;
  chain_ptr= chain;
  DBUG_RETURN(0);
}          

15.17.21. rnd_next

Zweck

Liest die nächste Zeile einer Tabelle und gibt sie an den Server zurück.

Zusammenfassung

virtual int rnd_next (buf); 
byte * buf ;

Beschreibung

Dies ist die Methode rnd_next.

Diese Methode wird für jede Zeile des Tabellenscans aufgerufen. Am Ende der Datensätze sollten Sie HA_ERR_END_OF_FILE zurückgeben. Die Zeilendaten werden in den Puffer geladen. Die Feldstruktur für die Tabelle ist der Schlüssel, um Daten so in den Puffer zu schreiben, dass der Server sie verstehen kann.

Wird von filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc und sql_update.cc aufgerufen.

Parameter

  • buf

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Dieses Beispiel stammt von der Speicher-Engine ARCHIVE:

int ha_archive::rnd_next(byte *buf)
{
  int rc;
  DBUG_ENTER("ha_archive::rnd_next");

  if (share->crashed)
      DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
 
  if (!scan_rows)
    DBUG_RETURN(HA_ERR_END_OF_FILE);
  scan_rows--;

  statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
		      &LOCK_status);
    current_position= gztell(archive);
  rc= get_row(archive, buf);
 
  if (rc != HA_ERR_END_OF_FILE)
    records++;

  DBUG_RETURN(rc);
}

15.17.22. rnd_pos

Zweck

Gibt eine Zeile anhand ihrer Position zurück.

Zusammenfassung

virtual int rnd_pos (buf,  
 pos); 
byte * buf ;
byte * pos ;

Beschreibung

Dies ist die Methode rnd_pos.

Diese Methode findet Zeilen, die zuvor anhand ihrer Position gekennzeichnet wurden. Ist nützlich für große Sortieraufgaben.

Ähnlich wie rnd_next, liefert jedoch eine Position zurück, um die Zeile zu ermitteln. Die Position hat den in ref gespeicherten Typ. Mit ha_get_ptr(pos,ref_length) können Sie den Schlüssel oder den Positionswert abrufen, den Sie beim Aufruf von position() gespeichert hatten. Wird von filesort.cc, records.cc, sql_insert.cc, sql_select.cc und sql_update.cc aufgerufen.

Parameter

  • buf

  • pos

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Findet die Zeile anhand eines Positionswerts und schreibt sie in den bereitgestellten Puffer.

15.17.23. start_stmt

Zweck

Wird zu Beginn einer Anweisung für Transaktionszwecke aufgerufen.

Zusammenfassung

virtual int start_stmt (thd,  
 lock_type); 
THD * thd ;
thr_lock_type lock_type ;

Beschreibung

Dies ist die Methode start_stmt.

Wenn eine Tabelle gesperrt wird, wird eine Anweisung gestartet, indem start_stmt anstelle von external_lock aufgerufen wird.

Parameter

  • thd

  • lock_type

Rückgabewerte

Diese Funktion hat keine Rückgabewerte.

Verwendung

Falls nicht bereits eine Transaktion läuft, werden durch diese Funktion die Vorkehrungen für den Beginn einer Transaktion getroffen.

Standardimplementierung

{return 0;}

15.17.24. store_lock

Zweck

Dient dem Errichten und Freigeben von Tabellensperren.

Zusammenfassung

virtual THR_LOCK_DATA ** store_lock (thd,  
 to,  
 lock_type); 
THD * thd ;
THR_LOCK_DATA ** to ;
enum thr_lock_type lock_type ;

Beschreibung

Dies ist die Methode store_lock.

Der Methode handler::store_lock() liegt folgende Idee zugrunde:

Die Anweisung entscheidet darüber, welche Sperren auf einer Tabelle erforderlich sind. Für Updates/Deletes/Inserts bekommen wir WRITE-Sperren und für SELECTs usw. Lesesperren.

Bevor die Sperre dem Tabellensperren-Handler übergeben wird, ruft mysqld die Funktion store_lock mit den erforderlichen Sperren auf. Diese Funktion kann die Sperrebene modifizieren, etwa den blockierenden Schreibmodus in einen nichtblockierenden umwandeln, die Sperre ignorieren (wenn wir die MySQL-Tabellensperren gar nicht einsetzen möchten) oder Sperren für viele Tabellen hinzufügen (zum Beispiel bei Verwendung eines MERGE-Handlers).

Berkeley DB stuft beispielsweise blockierende Tabellensperren vom Typ TL_WRITE zu nichtblockierenden TL_WRITE_ALLOW_WRITE-Sperren herab (ein Zeichen dafür, dass wir zwar Schreiboperationen vornehmen, aber dennoch andere Lese- und Schreibvorgänge zulassen).

store_lock() wird auch bei der Freigabe von Sperren aufgerufen. In diesem Fall muss normalerweise nichts weiter getan werden.

Wenn store_lock() das Argument TL_IGNORE bekommt, so bedeutet dies, dass MySQL den Handler dasselbe Ausmaß der Sperrung wie beim letzten Mal speichern lässt.

Wird von lock.cc durch get_lock_data() aufgerufen.

Parameter

  • thd

  • to

  • lock_type

Rückgabewerte

Keine Rückgabewerte.

Verwendung

Das folgende Beispiel stammt von der Speicher-Engine ARCHIVE:

/* 
  Das folgende Beispiel zeigt die Einrichtung von Zeilensperren.
*/
THR_LOCK_DATA **ha_archive::store_lock(THD *thd,
                                       THR_LOCK_DATA **to,
                                       enum thr_lock_type lock_type)
{
  if (lock_type == TL_WRITE_DELAYED)
    delayed_insert= TRUE;
  else
    delayed_insert= FALSE;

  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) 
  {
    /* 
      Hier kommen wir zum Kern der Zeilensperre.
      Wenn TL_UNLOCK gesetzt ist
      Wenn kein LOCK TABLE oder DISCARD/IMPORT
      TABLESPACE erfolgt, dann sollen mehrere Schreib-Threads zulässig sein 
    */

    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
         lock_type <= TL_WRITE) && !thd->in_lock_tables
        && !thd->tablespace_op)
      lock_type = TL_WRITE_ALLOW_WRITE;

    /* 
      In Anfragen wie INSERT INTO t1 SELECT ... FROM t2 ...
      würde MySQL die Sperre TL_READ_NO_INSERT für t2 verwenden und dies
      würde mit  der Sperre TL_WRITE_ALLOW_WRITE in Konflikt treten, da alle Inserts
      in t2 blockiert werden. Also konvertieren wir die Sperre in eine normale Lesesperre, um nebenläufige
      Einfügungen in t2 zuzulassen. 
    */

    if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) 
      lock_type = TL_READ;

    lock.type=lock_type;
  }

  *to++= &lock;
 
  return to;
}

Im Folgenden sehen Sie die Minimalimplementierung für eine Speicher-Engine, die keine Sperren herabstufen muss:

THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
                                    THR_LOCK_DATA **to,
                                    enum thr_lock_type lock_type)
{
   /* Achtung: Wenn die Sperre den Typ TL_IGNORE hat, wird lock.type nicht aktualisiert,
      sondern die vorherige Ebene beibehalten*/
   if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
     lock.type=lock_type;
    /* Das Herz der Methode store_lock() und ihr Daseinszweck: 
      das (möglicherweise geänderte) Ausmaß der Sperrung im zugewiesenen Speicher festzuhalten */
     *to++= &lock;
     return to;
}

Komplexere Implementierungen finden Sie unter ha_berkeley::store_lock() und ha_myisammrg::store_lock().

15.17.25. update_row

Zweck

Ändert den Inhalt einer vorhandenen Zeile.

Zusammenfassung

virtual int update_row (old_data,  
 new_data); 
const byte * old_data ;
byte * new_data ;

Beschreibung

Dies ist die Methode update_row.

old_data speichert den alten und new_data den neuen Datensatz der Zeile.

Der Server kann Änderungen anhand einer Reihenfolge vornehmen, wenn eine ORDER BY-Klausel verwendet wurde. Eine aufeinander folgende Ordnung ist nicht garantiert.

Zurzeit kann new_data keine aktualisierten auto_increment- oder timestamp-Felder aufnehmen. Dies können Sie jedoch zum Beispiel folgendermaßen erreichen: if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); if (table->next_number_field && record == table->record[0]) update_auto_increment();.

Wird von sql_select.cc, sql_acl.cc, sql_update.cc und sql_insert.cc aufgerufen.

Parameter

  • old_data

  • new_data

Rückgabewerte

Keine Rückgabewerte.

Verwendung

(kein Beispiel verfügbar)

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

15.17.26. write_row

Zweck

Fügt einer Tabelle eine neue Zeile hinzu.

Zusammenfassung

virtual int write_row (buf); 
byte * buf ;

Beschreibung

Dies ist die Methode write_row.

write_row() fügt eine Zeile ein. Gegenwärtig wird bei Massenladeoperationen kein extra()-Hinweis gegeben. buf ist ein Byte-Array mit Daten und hat die Länge table->s->reclength

Mithilfe der Feldinformationen können Sie die Daten aus dem nativen Byte-Array-Typ extrahieren, zum Beispiel wie in: for (Field **field=table->field ; *field ; field++) { ... }.

BLOBs erfordern eine Sonderbehandlung:

    
for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields ; ptr != end ; ptr++) 
  { 
        char *data_ptr; 
        uint32 size= ((Field_blob*)table->field[*ptr])->get_length();
        ((Field_blob*)table->field[*ptr])->get_ptr(&data_ptr); 
        ... 
  }

In ha_tina.cc wird gezeigt, wie alle Daten als Strings extrahiert werden. In ha_berkeley.cc finden Sie ein Beispiel, wie die Daten intakt gespeichert werden, indem man sie für den Berkeley-eigenen nativen Speichermechanismus "verpackt".

Siehe Hinweis zu update_row() über auto_increments und timestamps. Dieser Fall lässt sich auch auf write_row() übertragen.

Wird von item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc und sql_update.cc verwendet.

Parameter

  • buf - Ein Byte-Array mit Daten

Rückgabewerte

Keine Rückgabewerte.

Verwendung

(kein Beispiel verfügbar)

Standardimplementierung

{ return  HA_ERR_WRONG_COMMAND; }

Kapitel 16. MySQL Cluster

Inhaltsverzeichnis

16.1. MySQL Cluster: Überblick
16.2. MySQL Cluster: grundlegende Konzepte
16.2.1. MySQL Cluster: Knoten, Knotengruppen, Repliken und Partitionen
16.3. Einfache Schritt-für-Schritt-Anleitung für mehrere Computer
16.3.1. Hardware, Software und Netzwerk
16.3.2. Installation auf mehreren Computern
16.3.3. Konfiguration im Mehrcomputerbetrieb
16.3.4. Erster Start
16.3.5. Beispieldaten einladen und Abfragen ausführen
16.3.6. Sicheres Herunterfahren und Neustarten
16.4. MySQL Cluster: Konfiguration
16.4.1. MySQL Cluster vom Quellcode bauen
16.4.2. Installation der Software
16.4.3. Schnelle Testeinrichtung von MySQL Cluster
16.4.4. Konfigurationsdatei
16.5. Prozessverwaltung in MySQL Cluster
16.5.1. Verwendung des MySQL Server-Prozesses für MySQL Cluster
16.5.2. ndbd, der Speicher-Engine-Node-Prozess
16.5.3. ndb_mgmd, der Management-Server-Prozess
16.5.4. ndb_mgm, der Management-Client-Prozess
16.5.5. Befehlsoptionen für MySQL Cluster-Prozesse
16.6. Management von MySQL Cluster
16.6.1. MySQL Cluster: Startphasen
16.6.2. Befehle des Management-Clients
16.6.3. Ereignisberichte, die MySQL Cluster erzeugt
16.6.4. Einbenutzermodus
16.6.5. Online-Backup eines MySQL Clusters
16.7. Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster
16.7.1. Konfiguration von MySQL Cluster für SCI Sockets
16.7.2. Auswirkungen der Cluster-Interconnects verstehen
16.8. Bekannte Beschränkungen von MySQL Cluster
16.9. MySQL Cluster: Roadmap für die Entwicklung
16.9.1. MySQL Cluster: Änderungen in MySQL 5.0
16.9.2. MySQL 5.1 Roadmap für die Entwicklung von MySQL Cluster
16.10. MySQL Cluster: FAQ
16.11. MySQL Cluster: Glossar

MySQL Cluster ist eine hochverfügbare und hochredundante Version von MySQL, die für verteilte Umgebungen geschaffen wurde. Die Speicher-Engine NDB Cluster ermöglicht den Betrieb mehrerer MySQL Server in einem Cluster. Diese Speicher-Engine ist in den Binär-Releases von MySQL 5.1 und in den RPMs verfügbar, die mit den meisten modernen Linux-Distributionen kompatibel sind. (Wenn Sie RPM-Dateien installieren, müssen Sie darauf achten, sowohl die mysql-server- als auch die mysql-max-RPMs zu installieren, um MySQL Cluster zu ermöglichen.)

Gegenwärtig ist MySQL Cluster für Linux, Mac OS X und Solaris verfügbar. (Manche Anwender haben MySQL Cluster auch auf FreeBSD mit Erfolg installieren können, doch dieses System wird von der MySQL AB noch nicht offiziell unterstützt.) Wir arbeiten daran, Cluster auf allen von MySQL unterstützten Betriebssystemen einschließlich Windows lauffähig zu machen, und werden diese Seite aktualisieren, wenn ein neues Betriebssystem hinzukommt.

Dieses Kapitel ändert sich noch laufend; sein Inhalt wird immer wieder an den aktuellen Stand von MySQL Cluster angepasst. Weitere Informationen über MySQL Cluster finden Sie auf der Website von MySQL AB unter http://www.mysql.com/products/cluster/.

Mehr zum Thema

16.1. MySQL Cluster: Überblick

MySQL Cluster ist eine Technologie für das Clustering von speicherresidenten Datenbanken in einem Share-Nothing-System. Mit der Share-Nothing-Architektur kann das System auf sehr preiswerter Hardware laufen und es gibt keine besonderen Anforderungen an Hardware oder Software. Überdies ist kein Single Point of Failure vorhanden, da jede Komponente ihren eigenen Arbeitsspeicher und ihre Festplatte hat.

MySQL Cluster integriert den normalen MySQL Server in eine speicherresidente geclusterte Speicher-Engine namens NDB. In unserer Dokumentation bezeichnet der Begriff NDB den Teil des Setups, der für die jeweilige Speicher-Engine spezifisch ist, während mit „MySQL Cluster“ die Kombination aus MySQL und der Speicher-Engine NDB gemeint ist.

Ein MySQL Cluster besteht aus mehreren Computern, auf denen jeweils eine Anzahl Prozesse laufen, darunter MySQL Server, Datenknoten für NDB Cluster, Management-Server und (möglicherweise) besondere Programme für den Datenzugriff. Im Folgenden wird gezeigt, wie diese Komponenten in einem Cluster zueinander in Beziehung stehen:

Komponenten von MySQL Cluster

Alle diese Programme arbeiten zusammen, um ein MySQL Cluster zu bilden. Wenn in der Speicher-Engine NDB Cluster Daten gespeichert werden, werden die Tabellen in den Datenknoten untergebracht. Auf solche Tabellen können alle anderen MySQL Server im Cluster direkt zugreifen. Wenn also beispielsweise ein Gehaltsabrechnungsprogramm Daten in einem Cluster speichert und eine Anwendung das Gehalt eines Mitarbeiters ändert, können alle anderen MySQL Server, die diese Daten abfragen, sofort die Änderung erkennen.

Die in den Datenknoten für MySQL Cluster abgelegten Daten können gespiegelt werden. Der Cluster kann also mit Fehlern in einzelnen Datenknoten gut umgehen; die einzige Auswirkung wäre die, dass einige wenige Transaktionen abbrechen, weil sie ihren Transaktionsstatus verlieren. Da Anwendungen, die Transaktionen vornehmen, auch mit dem Scheitern einer Transaktion umgehen können, dürfte dies kein Problem sein.

Mit der Einführung von MySQL Cluster in die Open-Source-Szene stellt die MySQL AB jedem, der es benötigt, eine hochverfügbare, leistungsfähige und skalierbare geclusterte Datenverwaltung zur Verfügung.

16.2. MySQL Cluster: grundlegende Konzepte

NDB ist eine hochverfügbare speicherresidente Speicher-Engine mit Fähigkeiten für die Datenpersistenz.

Die Speicher-Engine NDB kann mit mehreren Optionen für Ausfallsicherung und Lastverteilung konfiguriert werden, doch am einfachsten ist es, das System mit der Speicher-Engine auf der Cluster-Ebene zu starten. Die Speicher-Engine NDB von MySQL Cluster enthält vollständige Daten, deren Abhängigkeiten sich lediglich auf andere Daten in demselben Cluster beziehen.

Im Folgenden erfahren Sie, wie man einen MySQL Cluster einrichtet, der aus der Speicher-Engine NDB und einigen MySQL Servern besteht.

Der Cluster-Teil von MySQL Cluster ist gegenwärtig unabhängig von den MySQL Servern konfiguriert. In MySQL Cluster wird jeder Teil des Clusters als ein Knoten betrachtet.

Hinweis: In vielen Zusammenhängen wird der Begriff „Knoten“ für einen Computer verwendet, doch im Zusammenhang mit MySQL Cluster ist damit ein Prozess gemeint. Auf einem einzigen Computer, dem so genannten Cluster-Host, können also beliebig viele Knoten existieren.

Es gibt drei Arten von Cluster-Knoten und eine Minimalkonfiguration von MySQL besteht aus drei Knoten, je einem von jeder Art:

  • dem Management-Knoten (MGM-Knoten): Dieser verwaltet andere Knoten im MySQL Cluster, indem er zum Beispiel Konfigurationsdaten zur Verfügung stellt, Knoten startet und anhält, eine Sicherung ausführt usw. Da dieser Knotentyp die Konfiguration der anderen Knoten managt, sollten Knoten dieses Typs immer als Erste, vor allen anderen Knoten, gestartet werden. Ein MGM-Knoten wird mit dem Befehl ndb_mgmd gestartet.

  • dem Datenknoten: Dies ist der Knotentyp, der die Daten des Clusters speichert. Die Anzahl der Datenknoten beträgt Replikas mal Anzahl Fragmente. Wenn Sie beispielsweise zwei Replikas mit je zwei Fragmenten haben, benötigen Sie vier Datenknoten. Noch mehr Replikas sind nicht notwendig. Ein Datenknoten wird mit dem Befehl ndbd gestartet.

  • dem SQL-Knoten: Mit diesem Knotentyp wird auf die Cluster-Daten zugegriffen. In MySQL Cluster ist ein Client-Knoten ein traditioneller MySQL Server, der die Speicher-Engine NDB Cluster nutzt. Ein SQL-Knoten wird normalerweise mit dem Befehl mysqld --ndbcluster gestartet, oder auch mit mysqld und der Option ndbcluster in der my.cnf-Datei.

Eine kurze Einführung in die Beziehungen zwischen Knoten, Knotengruppen, Replikas und Partitionen in MySQL Cluster finden Sie in Abschnitt 16.2.1, „MySQL Cluster: Knoten, Knotengruppen, Repliken und Partitionen“.

Um einen Cluster zu konfigurieren, müssen Sie jeden Einzelnen seiner Knoten konfigurieren und individuelle Kommunikationsverbindungen zwischen den Knoten einrichten. Der Entwurf von MySQL Cluster zielt gegenwärtig darauf ab, dass die Speicherknoten alle denselben Bedarf an Prozessorleistung, Speicherplatz und Bandbreite haben. Um überdies nur an einer einzigen Stelle konfigurieren zu müssen, liegen sämtliche Konfigurationen für den gesamten Cluster in nur einer Konfigurationsdatei.

Der Management-Server (MGM-Knoten) verwaltet die Konfigurationsdatei und das Log für den Cluster. Da sich jeder Knoten im Cluster seine Konfigurationsdaten vom Management-Server holt, muss der Knoten feststellen können, wo der Management-Server zu finden ist. Wenn interessante Ereignisse in den Datenknoten eintreten, übermitteln die Knoten Informationen über diese Ereignisse an den Management-Server, der diese Daten dann an das Cluster-Log überträgt.

Darüber hinaus können beliebig viele Cluster-Clientprozesse oder -anwendungen ablaufen. Von diesen gibt es zwei Arten:

  • Standard-MySQL-Clients: Diese unterscheiden sich von MySQL Cluster nur insofern, als sie eben nicht geclustert sind. Also können Sie auch von vorhandenen MySQL-Anwendungen, die in PHP, Perl, C, C++, Java, Python, Ruby usw. geschrieben wurden, auf MySQL Cluster zugreifen.

  • Management-Clients: Diese Clients verbinden sich mit dem Management-Server und kennen Befehle, um Knoten elegant zu starten oder abzubrechen, das Message-Tracing ein- und auszuschalten (nur in den Debugversionen), Knotenversionen und -status anzuzeigen, Sicherungen zu starten oder anzuhalten usw.

16.2.1. MySQL Cluster: Knoten, Knotengruppen, Repliken und Partitionen

In diesem Abschnitt wird beschrieben, wie MySQL Cluster mehrfach vorhandene Daten für die Speicherung aufteilt.

Die Konzepte, die im Folgenden mit kurzen Definitionen aufgelistet werden, sind für das Verständnis dieses Themas unerlässlich:

  • (Daten-)Knoten: Ein ndbd-Prozess, der eine Replik speichert, also eine Kopie der Partition (siehe unten), die der Knotengruppe, zu welcher dieser Knoten gehört, zugewiesen wurde.

    Normalerweise liegt jeder Datenknoten auf einem anderen Computer. Es ist jedoch möglich, mehrere Datenknoten auf einem einzigen Computer unterzubringen, wenn dieser über mehrere Prozessoren verfügt. In solchen Fällen kann pro physikalische CPU eine ndbd-Instanz laufen. (Beachten Sie, dass ein Prozessor mit mehreren Zentraleinheiten immer noch ein einzelner Prozessor ist.)

    Die Begriffe „Knoten“ und „Datenknoten“ werden im Zusammenhang mit ndbd-Prozessen synonym verwendet. Wenn Management-Knoten (ndb_mgmd -Prozesse) und SQL-Knoten (mysqld-Prozesse) gemeint sind, wird dies im Text ausdrücklich gesagt.

  • Knotengruppe: Eine Knotengruppe besteht aus einem oder mehreren Knoten und speichert eine Partition oder eine Menge von Replikas (siehe nächster Eintrag).

    Hinweis: Gegenwärtig müssen alle Gruppen in einem Cluster gleich viele Knoten haben.

  • Partition: Ein Teil der in einem Cluster gespeicherten Daten. Es gibt so viele Cluster-Partitionen, wie Knotengruppen im Cluster vorliegen, und jede Knotengruppe ist dafür verantwortlich, mindestens eine Kopie der ihr zugewiesenen Partition (also mindestens eine Replik) aufzubewahren, die dem Cluster zur Verfügung steht.

  • Replik: Eine Kopie einer Cluster-Partition. Jeder Knoten in einer Knotengruppe speichert eine Replik. Wird gelegentlich auch als Partitionsreplik bezeichnet.

Das folgende Diagramm zeigt einen MySQL Cluster mit vier Datenknoten in zwei Knotengruppen zu je zwei Knoten. Beachten Sie, dass hier nur die Datenknoten gezeigt werden, obwohl ein funktionierender Cluster einen ndb_mgm-Prozess für das Cluster-Management und mindestens einen SQL-Knoten für den Zugriff auf die im Cluster gespeicherten Daten benötigt.

Ein MySQL Cluster mit zwei Knotengruppen zu
          je zwei Knoten

Die in diesem Cluster gespeicherten Daten sind auf vier Partitionen verteilt, die mit 0, 1, 2 und 3 nummeriert sind. Jede Partition wird – in mehrfachen Kopien – in derselben Knotengruppe gespeichert. Partitionen werden auf unterschiedlichen Knotengruppen gespeichert:

  • Partition 0 wird in Knotengruppe 0 gespeichert; eine primäre Replik (oder primäre Kopie) wird auf Knoten 1 gespeichert, und eine Backup-Replik (Backup-Kopie der Partition) auf Knoten 2.

  • Partition 1 wird auf der anderen Knotengruppe gespeichert (Knotengruppe 1); die primäre Replik dieser Partition ist auf Knoten 3 und die Backup-Repli befindet sich auf Knoten 4.

  • Partition 2 wird auf Knotengruppe 0 gespeichert. Die Platzierung ihrer beiden Repliken ist jedoch genau umgekehrt wie bei Partition 0: Bei Partition 2 wird die primäre Replik auf Knoten 2 und die Backup-Replik auf Knoten 1 gespeichert.

  • Partition 3 wird auf Knotengruppe 1 gespeichert, und die Platzierung ihrer beiden Repliken ist umgekehrt wie bei Partition 1. Mit anderen Worten befindet sich ihre primäre Replik auf Knoten 4 und die Backup-Replik auf Knoten 3.

Für den Dauerbetrieb eines MySQL Clusters bedeutet dies: Solange jede Knotengruppe des Clusters mindestens einen funktionierenden Knoten hat, ist der Cluster im Besitz einer vollständigen Kopie sämtlicher Daten und bleibt funktionstüchtig. Dies wird im nächsten Diagramm veranschaulicht.

Für die Aufrechterhaltung eines
          2x2-Clusters erforderliche Knoten

In diesem Beispiel, in dem der Cluster aus zwei Knotengruppen mit je zwei Knoten besteht, genügt eine beliebige Kombination mindestens eines Knotens aus Gruppe A und mindestens eines weiteren Knotens aus Gruppe B, um den Cluster „am Leben“ zu halten (wie es die Pfeile im Diagramm zeigen). Wenn jedoch beide Knoten einer Knotengruppe versagen, genügen die verbleibenden beiden Knoten nicht, um den Betrieb aufrechtzuerhalten (dies zeigen die mit X markierten Pfeile). In beiden Fällen hat der Cluster eine vollständige Partition verloren und kann somit nicht mehr auf alle Cluster-Daten Zugriff geben.

16.3. Einfache Schritt-für-Schritt-Anleitung für mehrere Computer

Dieser Abschnitt ist eine „Anleitung“, welche in Grundzügen beschreibt, wie man einen MySQL Cluster plant, installiert, konfiguriert und ausführt. Die Beispiele in Abschnitt 16.4, „MySQL Cluster: Konfiguration“, bieten zwar ausführlichere Informationen über verschiedene Cluster-Optionen und Konfigurationen, aber auch mit dem hier gezeigten Verfahren erhalten Sie einen brauchbaren MySQL Cluster, der ein Minimum an Verfügbarkeit und Datensicherheit bietet.

Dieser Abschnitt behandelt Hardware- und Softwarevoraussetzungen, Netzwerkfragen, die Installation eines MySQL Clusters, die Konfiguration, das Starten, Anhalten und Neustarten eines Clusters, das Laden einer Beispieldatenbank sowie die Ausführung von Anfragen.

Grundvoraussetzungen

Diese Anleitung setzt Folgendes voraus:

  1. Der Cluster hat vier Knoten, von denen jeder auf einem separaten Host residiert und eine feste Netzwerkadresse in einem typischen Ethernet besitzt, wie es hier gezeigt wird:

    KnotenIP-Adresse
    Management(MGM)-Knoten192.168.0.10
    MySQL Server(SQL)-Knoten192.168.0.20
    Datenknoten (NDBD-Knoten) "A"192.168.0.30
    Datenknoten (NDBD-Knoten) "B"192.168.0.40

    Dies wird möglicherweise im nachfolgenden Diagramm klarer:

    MySQL Cluster-Setup für mehrere
            Computer

    Hinweis: Im Interesse der Einfachheit (und Zuverlässigkeit) verwendet diese Anleitung nur numerische IP-Adressen. Wenn jedoch in Ihrem Netzwerk DNS-Namensauflösung verfügbar ist, können Sie anstelle von IP-Adressen in der Cluster-Konfiguration auch Hostnamen verwenden. Alternativ können Sie in der Datei /etc/hosts oder der in Ihrem Betriebssystem verwendeten Entsprechung eine andere Möglichkeit für das Host-Lookup einrichten (soweit verfügbar).

  2. Jeder Host in unserem Szenario ist ein Intel-PC, auf dem eine normale generische Linux-Distribution in einer Standardkonfiguration auf der Festplatte installiert ist und keine unnötigen Dienste laufen. Das Kernbetriebssystem mit seinen Standard-TCP/IP-Netzwerkfähigkeiten müsste ausreichen. Der Einfachheit halber setzen wir des Weiteren voraus, dass die Dateisysteme auf allen Hosts gleich eingerichtet sind. Anderenfalls müssen Sie diese Anleitungen entsprechend anpassen.

  3. Auf jedem Computer sind Standard-Ethernet-Karten mit 100 Mbps oder 1 Gigabit samt Treibern installiert und alle vier Hosts sind durch eine Standardvorrichtung für Ethernet-Netzwerke, wie beispielsweise einen Switch, miteinander verbunden. (Alle Computer sollten Netzwerkkarten mit demselben Datendurchsatz verwenden, d. h., die vier Computer haben entweder 100-Mbps-Karten oder 1-Gbps-Karten.) MySQL Cluster funktioniert zwar auch in einem 100-Mbps-Netzwerk, aber ein 1-Gigabit-Ethernet bietet deutlich mehr Leistung.

    Beachten Sie, dass MySQL Cluster nicht für den Einsatz in einem Netzwerk mit weniger als 100 Mbps Datendurchsatz gedacht ist. Aus diesem und anderen Gründen werden Sie keinen Erfolg haben, wenn Sie versuchen, einen MySQL Cluster in einem öffentlichen Netzwerk wie dem Internet zu betreiben. Das ist auch nicht empfehlenswert.

  4. Für unsere Beispieldaten verwenden wir die Datenbank world, die Sie von der Website der MySQL AB herunterladen können. Da diese Datenbank relativ wenig Speicherplatz belegt, gehen wir davon aus, dass jeder Computer 256 Mbyte RAM besitzt. Dies dürfte ausreichen, um das Betriebssystem auszuführen, den NDB-Prozess zu hosten und die Datenbank (die Datenknoten) zu speichern.

Auch wenn wir uns in dieser Anleitung auf ein Linux-Betriebssystem beziehen, lassen sich die hier geschilderten Instruktionen und Verfahren auch auf Solaris oder Mac OS X leicht übertragen. Außerdem setzen wir voraus, dass Sie bereits wissen, wie man eine Minimalinstallation durchführt und das Betriebssystem für den Netzwerkbetrieb konfiguriert, oder dass Sie sich in diesen Fragen notfalls an anderer Stelle kundig machen können.

Im nächsten Abschnitt werden Hardware-, Software- und Netzwerkvoraussetzungen für MySQL Cluster etwas eingehender behandelt. (Siehe Abschnitt 16.3.1, „Hardware, Software und Netzwerk“.)

16.3.1. Hardware, Software und Netzwerk

Eine Stärke von MySQL Cluster besteht darin, dass das System auf handelsüblicher Hardware läuft und in dieser Hinsicht keine besonderen Ansprüche stellt – abgesehen von einem großen Arbeitsspeicher, da im Betrieb sämtliche Daten dort gespeichert werden. (Dies wird sich allerdings noch ändern, da in einem künftigen Release von MySQL Cluster eine Datenspeicherung auf Festplatte angestrebt wird.) Natürlich wird die Leistung umso besser, je mehr und je schnellere CPUs eingesetzt werden. Der Speicherbedarf für Cluster-Prozesse ist relativ gering.

Auch an die Software stellt Cluster eher geringe Anforderungen. Die Host-Betriebssysteme benötigen keine ungewöhnlichen Module, Dienste, Anwendungen oder Konfigurationen, um MySQL Cluster zu unterstützen. Für Mac OS X oder Solaris reicht sogar die Standardinstallation völlig aus. Für Linux dürfte gleichfalls die Standardinstallation hinreichend sein. Die Anforderungen an MySQL-Software lassen sich ebenfalls leicht erfüllen: Sie benötigen lediglich einen Produktions-Release von MySQL-max 5.1. Um Cluster-Unterstützung zu bekommen, müssen Sie die -max-Version von MySQL einsetzen, brauchen MySQL jedoch nicht selbst zu kompilieren. In dieser Anleitung setzen wir voraus, dass Sie die passende -max-Binärversion zu Ihrem Betriebssystem Linux, Solaris oder Mac OS X verwenden, die unter den Softwaredownloads von MySQL unter http://dev.mysql.com/downloads/ erhältlich ist.

Für die Kommunikation zwischen den Knoten unterstützt Cluster TCP/IP-Netzwerke in einer beliebigen Standardtopologie, wofür jeder Host als Minimum eine Standard-Ethernet-Karte mit 100 Mbps plus Switch, Hub oder Router benötigt, um die Netzwerkkonnektivität für den Cluster als Ganzes herzustellen. Wir raten Ihnen dringend, MySQL Cluster in einem eigenen Subnetz zu betreiben, auf das keine Computer zugreifen, die nicht an dem Cluster partizipieren. Dafür gibt es folgende Gründe:

  • Sicherheit: Die Kommunikation zwischen Cluster-Knoten ist in keiner Weise verschlüsselt oder abgeschirmt. Die einzige Möglichkeit, Datenübertragungen in einem MySQL Cluster zu schützen, besteht darin, den Cluster in einem geschützten Netzwerk auszuführen. Wenn Sie MySQL Cluster für Webanwendungen nutzen möchten, muss der Cluster unbedingt hinter Ihrer Firewall sitzen und nicht etwa in der demilitarisierten Zone Ihres Netzwerks (DMZ) oder an einer anderen Stelle.

  • Effizienz: Wenn Sie einen MySQL Cluster in einem privaten oder geschützten Netzwerk einrichten, kann er über die Bandbreite zwischen den Cluster-Hosts alleine verfügen. Indem Sie für Ihren MySQL Cluster einen getrennten Switch verwenden, schützen Sie die Cluster-Daten vor unbefugtem Zugriff und gewährleisten überdies, dass die Cluster-Knoten von den Interferenzen durch Datenübertragungen zwischen anderen Computern im Netzwerk verschont bleiben. Die Zuverlässigkeit können Sie durch doppelte Switches und doppelte Karten erhöhen; so scheidet das Netzwerk als Single Point of Failure aus. Viele Gerätetreiber unterstützen eine Ausfallsicherung für solche Kommunikationsverbindungen.

Es ist auch möglich, das sehr schnelle Scalable Coherent Interface (SCI) mit MySQL Cluster zu kombinieren, aber obligatorisch ist es nicht. Unter Abschnitt 16.7, „Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster“, erfahren Sie mehr über dieses Protokoll und seine Verwendung mit MySQL Cluster.

16.3.2. Installation auf mehreren Computern

Auf jedem Hostcomputer für MySQL Cluster, der Speicher- oder SQL-Knoten ausführt, muss MySQL als -max-Binärversion installiert sein. Für Management-Knoten muss zwar nicht die Binärversion von MySQL Server installiert werden, wohl aber die Binärversionen von MGM Server Daemon und vom Client (ndb_mgmd und ndb_mgm). In diesem Abschnitt erfahren Sie alles Notwendige, um für jede Art von Cluster-Knoten die richtige Binärversion zu installieren.

MySQL AB bietet vorkompilierte Binärversionen, die Cluster unterstützen und die Sie generell nicht selbst kompilieren müssen. Der erste Schritt zur Installation jedes Cluster-Hosts besteht also darin, die Datei mysql-max-5.1.5-alpha-pc-linux-gnu-i686.tar.gz aus dem MySQL-Downloadbereich herunterzuladen. Wir gehen davon aus, dass Sie diese Datei in das Verzeichnis /var/tmp jedes Computers legen. (Sollten Sie doch eine maßgeschneiderte Binärversion benötigen, schauen Sie bitte unter Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“, nach.)

RPMs gibt es auch für 32-Bit- und 64-Bit-Linux-Systeme. Die von den RPMs installierten -max-Binaries unterstützen die Speicher-Engine NDBCluster. Wenn Sie diese anstelle der Binärdateien einsetzen möchten, müssen Sie allerdings beide Packages - -server und -max - auf allen Computern installieren, die Cluster-Knoten hosten sollen. (Unter Abschnitt 2.4, „MySQL unter Linux installieren“, erfahren Sie mehr darüber, wie man MySQL mithilfe der RPMs installiert.) Nach der Installation von RPM müssen Sie noch den Cluster konfigurieren, wie in Abschnitt 16.3.3, „Konfiguration im Mehrcomputerbetrieb“, beschrieben.

Hinweis: Nach Abschluss der Installation dürfen Sie noch nicht die Binaries starten. Wie Sie das tun, zeigen wir Ihnen, nachdem sämtliche Knoten konfiguriert sind.

Speicherung und Installation des SQL-Knotens

Auf allen drei Computern, die Speicher- oder SQL-Knoten hosten sollen, müssen Sie als root-User folgende Schritte ausführen:

  1. Sie müssen in den Dateien /etc/passwd und /etc/group nachschauen (oder die Tools nutzen, die Ihr Betriebssystem zur Verwaltung von Benutzern und Gruppen zur Verfügung stellt), um festzustellen, ob auf dem System bereits eine mysql-Gruppe und ein mysql-Benutzer vorhanden ist. Manche Betriebssystem-Distributionen legen diese bei ihrer Installation bereits an. Wenn sie noch nicht vorhanden sind, legen Sie eine neue mysql-Benutzergruppe an und fügen dieser dann einen mysql-Benutzer hinzu:

    shell> groupadd mysql
    shell> useradd -g mysql mysql
    

    Die Syntax für useradd und groupadd kann auf verschiedenen Unix-Versionen etwas abweichen. Es ist auch möglich, dass die Befehle etwas andere Namen haben, wie etwa adduser und addgroup.

  2. Dann wechseln Sie in das Verzeichnis mit der heruntergeladenen Datei, packen das Archiv aus und erzeugen einen Symlink auf die Executable mysql-max. Beachten Sie, dass die tatsächlichen Datei- und Verzeichnisnamen je nach MySQL-Version unterschiedlich sind.

    shell> cd /var/tmp
    shell> tar -xzvf -C /usr/local/bin mysql-max-5.1.5-alpha-pc-linux-gnu-i686.tar.gz
    shell> ln -s /usr/local/bin/mysql-max-5.1.5-alpha-pc-linux-gnu-i686 mysql
    
  3. Nun gehen Sie in das Verzeichnis mysql und führen das mitgelieferte Skript aus, das die Systemdatenbanken anlegt:

    shell> cd mysql
    shell> scripts/mysql_install_db --user=mysql
    
  4. Nun stellen Sie die Berechtigungen für den MySQL Server und die Datenverzeichnisse ein:

    shell> chown -R root .
    shell> chown -R mysql data
    shell> chgrp -R mysql .
    

    Beachten Sie, dass das Datenverzeichnis auf jedem Computer, auf dem ein Datenknoten residiert, unter /usr/local/mysql/data liegt. Dieses Wissen werden wir nutzen, wenn wir den Management-Knoten konfigurieren. (Siehe Abschnitt 16.3.3, „Konfiguration im Mehrcomputerbetrieb“.)

  5. Kopieren Sie das MySQL-Startskript in das passende Verzeichnis, sorgen Sie dafür, dass es ausführbar ist, und stellen Sie ein, dass es beim Hochfahren des Betriebssystems läuft:

    shell> cp support-files/mysql.server /etc/rc.d/init.d/
    shell> chmod +x /etc/rc.d/init.d/mysql.server
    shell> chkconfig --add mysql.server
    

    Hier legen wir die Verknüpfungen zu den Startskripten mit dem Befehl chkconfig von Red Hat an. Bitte wählen Sie das für Ihr Betriebssystem jeweils passende Mittel aus, etwa update-rc.d für Debian.

Die obigen Schritte müssen auf jedem Computer, der einen Speicher- oder SQL-Knoten hostet, separat ausgeführt werden.

Installation des Management-Knotens

Um den Management(MGM)-Knoten installieren zu können, muss die mysqld-Binary nicht installiert sein. Nur die Binärversionen für den MGM-Server und -Client sind erforderlich. Diese finden Sie im heruntergeladenen -max-Archiv. Wir gehen wieder davon aus, dass Sie die Datei in das Verzeichnis /var/tmp gespeichert haben.

Die folgenden Schritte müssen Sie als root-User Ihres Systems ausführen (das heißt nach Ausführung von sudo, su root oder dem für Ihr System passenden Befehl zur vorübergehenden Einrichtung von Administratorrechten). Dann installieren Sie auf dem Host des Cluster-Management-Knotens ndb_mgmd und ndb_mgm wie folgt:

  1. Gehen Sie in das Verzeichnis /var/tmp und extrahieren Sie ndb_mgm und ndb_mgmd aus dem Archiv in ein passendes Verzeichnis wie beispielsweise /usr/local/bin:

    shell> cd /var/tmp
    shell> tar -zxvf mysql-max-5.1.5-alpha-pc-linux-gnu-i686.tar.gz \
             /usr/local/bin '*/bin/ndb_mgm*'
    
  2. Gehen Sie in das Verzeichnis, in das Sie die Dateien entpackt haben, und machen Sie beide ausführbar:

    shell> cd /usr/local/bin
    shell> chmod +x ndb_mgm*
    

In Abschnitt 16.3.3, „Konfiguration im Mehrcomputerbetrieb“, werden wir Konfigurationsdateien für alle Knoten unseres Beispiel-Clusters erstellen und schreiben.

16.3.3. Konfiguration im Mehrcomputerbetrieb

Für unseren MySQL Cluster mit vier Knoten und vier Hosts müssen wir vier Konfigurationsdateien schreiben, je eine pro Knoten/Host.

  • Jeder Datenknoten oder SQL-Knoten benötigt eine my.cnf-Datei, die zwei Informationen liefert: einen connectstring, der dem Knoten sagt, wo er den MGM-Knoten findet, und eine Leitung, die den MySQL Server auf diesem Host (dem Computer mit dem Datenknoten) anweist, im NDB-Modus zu laufen.

    Mehr zum Thema Verbindungs-Strings erfahren Sie unter Abschnitt 16.4.4.2, „MySQL Cluster: connectstring.

  • Der Management-Knoten benötigt eine config.ini-Datei, die ihm sagt, wie viele Replikas er pflegen soll, wie viel Speicher er für die Daten und Indizes auf jedem Datenknoten reservieren soll, wo er die Datenknoten suchen soll, wo er die Daten für jeden Datenknoten auf Platte speichern soll und wo er SQL-Knoten finden kann.

Konfiguration der Speicher- und SQL-Knoten

Die für die Datenknoten erforderliche my.cnf-Datei ist ganz einfach. Diese Konfigurationsdatei sollte im Verzeichnis /etc liegen und kann mit jedem Editor bearbeitet werden. (Wenn die Datei noch nicht existiert, legen Sie sie bitte an.) Zum Beispiel:

shell> vi /etc/my.cnf

Hier legen wir die Datei zwar mit vi an, aber Sie können auch jeden anderen Editor benutzen.

Für jeden Daten- und SQL-Knoten in unserem Beispiel-Cluster sollte die my.cnf-Datei folgendermaßen aussehen:

# Optionen für den mysqld-Prozess:
[MYSQLD]                        
ndbcluster                      # NDB-Engine ausführen
ndb-connectstring=192.168.0.10  # Speicherort des MGM-Knotens

# Optionen für den ndbd-Prozess:
[MYSQL_CLUSTER]                 
  ndb-connectstring=192.168.0.10  # Speicherort des MGM-Knotens

Wenn Sie diese Daten eingegeben haben, speichern Sie die Datei und schließen den Editor. Dies tun Sie für die Hosts der Datenknoten „A“ und „B“ sowie für den Host des SQL-Knotens.

Konfiguration des Management-Knotens

Der erste Schritt zur Konfiguration des MGM-Knotens besteht darin, das Verzeichnis für die Konfigurationsdatei und dann die Datei selbst anzulegen. Zum Beispiel (immer als root-User):

shell> mkdir /var/lib/mysql-cluster
shell> cd /var/lib/mysql-cluster
shell> vi config.ini

Für unseren Beispiel-Cluster sieht die config.ini-Datei folgendermaßen aus:

# Optionen, die ndbd-Prozesse auf allen Datenknoten betreffen:
[NDBD DEFAULT]    
NoOfReplicas=2    # Anzahl der Replikas
DataMemory=80M    # So viel Speicher wird für Datenknoten reserviert
  IndexMemory=18M   # So viel Speicher wird für Indizes reserviert
                  # Für DataMemory und IndexMemory haben wir die Standardwerte
                  # eingesetzt. Da die "world"-Datenbank nur
                  # circa 500 Kbyte belegt, dürfte dies für unseren Beispiel-Cluster
                  # mehr als ausreichend sein.

# TCP/IP options:
[TCP DEFAULT]     
portnumber=2202   # Dies ist der Standardwert. Sie können jedoch
                  # jeden Port benutzen, der auf allen Hosts im Cluster frei ist.
                  # Hinweis: Ab MySQL 5.0 ist es ratsam, keine
                  # Portnummer anzugeben, sondern einfach
                  # die Verwendung des Standardwerts zu gestatten

# Optionen für den Management-Prozess:
[NDB_MGMD]                      
hostname=192.168.0.10           # Hostname oder IP-Adresse des MGM-Knotens
datadir=/var/lib/mysql-cluster  # Verzeichnis der Logdateien für MGM-Knoten

# Optionen für Datenknoten "A":
[NDBD]                          
                                # (ein [NDBD]-Abschnitt pro Datenknoten)
hostname=192.168.0.30           # Hostname oder IP-Adresse
datadir=/usr/local/mysql/data   # Verzeichnis für die Datendateien dieses Knotens

  # Optionen für Datenknoten "B":
[NDBD]                          
  hostname=192.168.0.40           # Hostname oder IP-Adresse
  datadir=/usr/local/mysql/data   # Verzeichnis für die Datendateien dieses Knotens

  # Optionen für SQL-knoten:
[MYSQLD]                        
  hostname=192.168.0.20           # Hostname oder IP-Adresse
                                # (Weitere mysqld-Verbindungen können
                                # für diverse Zwecke, z. B. Ausführung von  
                                #  ndb_restore, für diesen Knoten angegeben werden.)

(Hinweis: Die Datenbank world kann von http://dev.mysql.com/doc/ heruntergeladen werden, wo sie unter „Examples.“ aufgeführt ist.)

Wenn alle Konfigurationsdateien angelegt und diese minimalen Optionen angegeben sind, können Sie den Cluster starten und sich vergewissern, dass alle Prozesse laufen. Wie das geht, erfahren Sie in Abschnitt 16.3.4, „Erster Start“.

Detailliertere Informationen über die verfügbaren Konfigurationsparameter von MySQL Cluster und ihre Verwendung finden Sie unter Abschnitt 16.4.4, „Konfigurationsdatei“, und Abschnitt 16.4, „MySQL Cluster: Konfiguration“. Wie Sie MySQL Cluster für die Erstellung von Datensicherungen konfigurieren, erfahren Sie unter Abschnitt 16.6.5.4, „Konfiguration für Cluster-Backup“.

Hinweis: Der Standardport für Cluster-Management-Knoten ist 1186 und der Standardport für Datenknoten ist 2202. Seit MySQL 5.0.3 wurde diese Einschränkung aufgehoben und der Cluster weist automatisch Ports für Datenknoten aus dem Vorrat der freien Ports zu.

16.3.4. Erster Start

Den Cluster nach erfolgter Konfiguration zu starten ist nicht schwer. Jeder Cluster-Knoten-Prozess muss separat und auf dem Knoten-Host gestartet werden. Zwar können die Knoten in beliebiger Reihenfolge gestartet werden, aber es empfiehlt sich, als Erstes den Management-Knoten, dann die Speicherknoten und zum Schluss die SQL-Knoten zu starten:

  1. Auf dem Management-Host setzen Sie folgenden Befehl in der System-Shell ab, um den MGM-Knoten-Prozess zu starten:

    shell> ndb_mgmd -f /var/lib/mysql-cluster/config.ini
    

    Beachten Sie, dass Sie ndb_mgmd mithilfe der Option -f oder --config-file mitteilen müssen, wo er seine Konfigurationsdatei finden kann. (Einzelheiten siehe Abschnitt 16.5.3, „ndb_mgmd, der Management-Server-Prozess“.)

  2. Auf jedem Datenknoten-Host geben Sie folgenden Befehl, um den ndbd-Prozess zum ersten Mal zu starten:

    shell> ndbd --initial
    

    Es ist äußerst wichtig, dass der Parameter --initial nur beim ersten Start von ndbd oder bei einem Neustart nach einer Sicherungs-/Wiederherstellungsoperation oder einer Konfigurationsänderung verwendet wird. Denn die Option --initial veranlasst den Knoten, alle für die Wiederherstellung erforderlichen Dateien zu löschen, die von vorherigen ndbd-Instanzen angelegt wurden, einschließlich der Dateien des Redo-Logs.

  3. Wenn Sie MySQL auf dem Cluster-Host, wo der SQL-Knoten residieren soll, von RPM-Dateien installiert haben, können (und sollten) Sie das in /etc/init.d installierte Startskript nutzen, um den MySQL Server-Prozess auf dem SQL-Knoten zu starten. Beachten Sie, dass Sie die -max-Server-RPM zusätzlich zur Standardserver-RPM installieren müssen, um die Binärversion von -max-Server ausführen zu können.

Wenn alles geklappt hat und der Cluster korrekt eingerichtet wurde, sollte er nun funktionsbereit sein. Dies können Sie testen, indem Sie den Management-Knoten-Client ndb_mgm aufrufen. Die Ausgabe sollte ungefähr dem Folgenden entsprechen, wobei jedoch je nach der verwendeten MySQL-Version kleinere Abweichungen möglich sind:

shell> ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm> SHOW
Connected to Management Server at: localhost:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2    @192.168.0.30  (Version: 5.1.5-alpha, Nodegroup: 0, Master)
id=3    @192.168.0.40  (Version: 5.1.5-alpha, Nodegroup: 0)

[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.168.0.10  (Version: 5.1.5-alpha)

[mysqld(SQL)]   1 node(s)
id=4   (Version: 5.1.5-alpha)

Hinweis: Wenn Sie eine ältere Version von MySQL verwenden, wird der SQL-Knoten möglicherweise als [mysqld(API)] bezeichnet. Das ist eine ältere Lesart, die mittlerweile abgeschafft wurde.

Nun können Sie im MySQL Cluster mit Datenbanken, Tabellen und Daten arbeiten. Unter Abschnitt 16.3.5, „Beispieldaten einladen und Abfragen ausführen“, finden Sie eine kurze Beschreibung.

16.3.5. Beispieldaten einladen und Abfragen ausführen

Der Umgang mit Daten im MySQL Cluster ist ganz ähnlich wie in einer MySQL-Konfiguration ohne Cluster. Nur auf zwei Dinge muss man achten:

  • Damit eine Tabelle im Cluster repliziert wird, muss die Speicher-Engine NDB Cluster mit der Option ENGINE=NDB oder der Tabellenoption ENGINE=NDBCLUSTER eingeschaltet sein. Dies können Sie tun, wenn Sie die Tabelle anlegen:

    CREATE TABLE tbl_name ( ... ) ENGINE=NDBCLUSTER;
    

    Alternativ können Sie eine bereits vorhandene Tabelle, die eine andere Speicher-Engine verwendet, mit ALTER TABLE auf NDB Cluster umstellen:

    ALTER TABLE tbl_name ENGINE=NDBCLUSTER;
    
  • Jede NDB-Tabelle muss einen Primärschlüssel haben. Wenn der Benutzer beim Anlegen der Tabelle keinen definiert, wird von der Speicher-Engine NDB Cluster automatisch ein verborgener Primärschlüssel generiert. (Hinweis: Dieser verborgene Schlüssel belegt Platz wie jeder andere Tabellenindex auch. Nicht selten treten Speicherplatzprobleme auf, wenn diese automatisch angelegten Indizes untergebracht werden müssen.)

Wenn Sie aus der Ausgabe von mysqldump Tabellen aus einer vorhandenen Datenbank importieren, können Sie das SQL-Skript mit einem Editor öffnen und die Option ENGINE für alle Anweisungen einstellen, in denen Tabellen angelegt werden, oder eine eventuell vorhandene ENGINE- (oder TYPE-)Option ersetzen. Nehmen wir an, Sie haben die Beispieldatenbank world auf einem anderen MySQL Server liegen, der MySQL Cluster nicht unterstützt, und Sie möchten die Tabelle City exportieren:

shell> mysqldump --add-drop-table world City > city_table.sql

Die resultierende city_table.sql-Datei enthält die folgende Anweisung zur Erzeugung einer Tabelle (und die notwendigen INSERT-Anweisungen, um die Tabellendaten zu importieren):

DROP TABLE IF EXISTS `City`;
CREATE TABLE `City` (
  `ID` int(11) NOT NULL auto_increment,
  `Name` char(35) NOT NULL default '',
  `CountryCode` char(3) NOT NULL default '',
  `District` char(20) NOT NULL default '',
  `Population` int(11) NOT NULL default '0',
  PRIMARY KEY  (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `City` VALUES (1,'Kabul','AFG','Kabol',1780000);
INSERT INTO `City` VALUES (2,'Qandahar','AFG','Qandahar',237500);
INSERT INTO `City` VALUES (3,'Herat','AFG','Herat',186800);
(restliche INSERT-Anweisungen ausgelassen)

Sie müssen gewährleisten, dass MySQL die Speicher-Engine NDB für diese Tabelle verwendet. Dazu ändern Sie die Tabellendefinition vor dem Import in die Cluster-Datenbank. Die Definition der Tabelle City würde zum Beispiel folgendermaßen modifiziert:

DROP TABLE IF EXISTS `City`;
CREATE TABLE `City` (
  `ID` int(11) NOT NULL auto_increment,
  `Name` char(35) NOT NULL default '',
  `CountryCode` char(3) NOT NULL default '',
  `District` char(20) NOT NULL default '',
  `Population` int(11) NOT NULL default '0',
  PRIMARY KEY  (`ID`)
) ENGINE=NDBCLUSTER DEFAULT CHARSET=latin1;

INSERT INTO `City` VALUES (1,'Kabul','AFG','Kabol',1780000);
INSERT INTO `City` VALUES (2,'Qandahar','AFG','Qandahar',237500);
INSERT INTO `City` VALUES (3,'Herat','AFG','Herat',186800);
(remaining INSERT statements omitted)

Dies müssen Sie mit der Definition jeder Tabelle tun, die in die geclusterte Datenbank importiert werden soll. Am einfachsten erreichen Sie dies, indem Sie in der Datei mit den Tabellendefinitionen alle Vorkommen von TYPE=MyISAM oder ENGINE=MyISAM durch ENGINE=NDBCLUSTER ersetzen. Wenn Sie die Datei nicht ändern möchten, können Sie die Tabellen auch mit der unveränderten Datei anlegen und dann ihren Typ mit ALTER TABLE ändern. Die Einzelheiten erfahren Sie in einem späteren Abschnitt.

Wenn wir davon ausgehen, dass Sie bereits eine Datenbank namens world auf dem SQL-Knoten des Clusters angelegt haben, können Sie nun city_table.sql mit dem Kommandozeilen-Client mysql lesen und die entsprechende Tabelle in der üblichen Weise mit Daten füllen:

shell> mysql world < city_table.sql

Dieser Befehl muss unbedingt auf dem Host ausgeführt werden, auf welchem der SQL-Knoten läuft (in diesem Fall auf der Maschine mit der IP-Adresse 192.168.0.20).

Um eine Kopie der gesamten world-Datenbank auf dem SQL-Knoten anzulegen, führen Sie mysqldump auf dem ungeclusterten Server aus, um die Datenbank in die Datei world.sql im Verzeichnis /usr/local/mysql/data zu exportieren. Danach importieren Sie diese Datei folgendermaßen in den SQL-Knoten des Clusters:

shell> cd /usr/local/mysql/data
shell> mysql world < world.sql

Wenn Sie die Datei an einer anderen Stelle speichern, müssen Sie die obigen Anleitungen entsprechend abändern.

Sie müssen wissen, dass NDB Cluster in MySQL 5.1 nicht die selbstständige Erkennung von Datenbanken unterstützt (siehe Abschnitt 16.8, „Bekannte Beschränkungen von MySQL Cluster“). Mit anderen Worten: Sobald Sie die Datenbank world und ihre Tabellen auf einem Datenknoten angelegt haben, müssen Sie die Anweisung CREATE SCHEMA world mit nachfolgendem FLUSH TABLES auf jedem SQL-Knoten im Cluster erteilen. Nur dann kann der Knoten die Datenbank erkennen und ihre Tabellendefinitionen lesen.

SELECT-Anfragen werden auf dem SQL-Knoten genau wie auf jedem anderen MySQL Server ausgeführt. Um Anfragen auf der Kommandozeile auszuführen, müssen Sie sich zuerst wie üblich in den MySQL Monitor einloggen (das Passwort von root am Enter password:-Prompt eingeben):

shell> mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 5.1.5-alpha

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>

Wir verwenden einfach das root-Konto des MySQL Servers und gehen davon aus, dass Sie bei der Installation des MySQL Servers die Standardsicherheitsvorkehrungen getroffen und ein starkes root-Passwort eingerichtet haben. Mehr darüber lesen Sie unter Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“.

Bitte achten Sie darauf, dass Cluster-Knoten, wenn sie aufeinander zugreifen, nicht von dem MySQL-Berechtigungssystem Gebrauch machen. Die Einrichtung oder Änderung von MySQL-Benutzerkonten (einschließlich root) wirkt sich nur auf Anwendungen aus, die auf den SQL-Knoten zugreifen, aber nicht auf die Interaktion zwischen den Knoten.

Wenn Sie die ENGINE-Klauseln in den Tabellendefinitionen vor dem Import des SQL-Skripts nicht geändert hatten, sollten Sie nun folgende Anweisungen ausführen:

mysql> USE world;
mysql> ALTER TABLE City ENGINE=NDBCLUSTER;
mysql> ALTER TABLE Country ENGINE=NDBCLUSTER;
mysql> ALTER TABLE CountryLanguage ENGINE=NDBCLUSTER;

Auch die Auswahl einer Datenbank und die Ausführung einer SELECT-Anfrage auf einer Tabelle dieser Datenbank sowie das Schließen des MySQL Monitors funktionieren wie üblich:

mysql> USE world;
mysql> SELECT Name, Population FROM City ORDER BY Population DESC LIMIT 5;
+-----------+------------+
| Name      | Population |
+-----------+------------+
| Bombay    |   10500000 |
| Seoul     |    9981619 |
| São Paulo |    9968485 |
| Shanghai  |    9696300 |
| Jakarta   |    9604900 |
+-----------+------------+
5 rows in set (0.34 sec)

mysql> \q
Bye

shell>

Anwendungen, die MySQL nutzen, können ihre Standard-APIs auch für den Zugriff auf NDB-Tabellen verwenden. Bitte denken Sie jedoch daran, dass Ihre Anwendung auf den SQL-Knoten zugreifen muss, und nicht auf den MGM- oder die Speicherknoten. Das folgende kleine Beispiel zeigt, wie die obige SELECT-Anweisung mithilfe der mysqli-Erweiterung von PHP 5 ausgeführt wird, die auf einem Webserver irgendwo anders im Netzwerk läuft:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type"
        content="text/html; charset=iso-8859-1">
  <title>SIMPLE mysqli SELECT</title>
</head>
<body>
<?php
  # Verbindung zum SQL-Knoten:
  $link = new mysqli('192.168.0.20', 'root', 'root_password', 'world');
  # Die Parameter für den mysqli-Konstruktor sind:
  #  Host, User, Passwort, Datenbank

  if( mysqli_connect_errno() )
    die("Connect failed: " . mysqli_connect_error());

  $query = "SELECT Name, Population
            FROM City
            ORDER BY Population DESC
            LIMIT 5";

  # wenn keine Fehler auftreten...
  if( $result = $link->query($query) )
  {
?>
<table border="1" width="40%" cellpadding="4" cellspacing ="1">
  <tbody>
  <tr>
    <th width="10%">City</th>
    <th>Population</th>
  </tr>
<?
    # dann zeige Ergebnisse an...
    while($row = $result->fetch_object())
      printf(<tr>\n  <td align=\"center\">%s</td><td>%d</td>\n</tr>\n",
              $row->Name, $row->Population);
?>
  </tbody
</table>
<?
  # ...und prüfe, wie viele Zeilen abgerufen wurden
    printf("<p>Affected rows: %d</p>\n", $link->affected_rows);
  }
  else
    # anderenfalls sag uns, was schief gegangen ist
    echo mysqli_error();

  # gib die Ergebnismenge und das mysqli-Verbindungsobjekt frei
  $result->close();
  $link->close();
?>
</body>
</html>

Wir setzen voraus, dass der Prozess, der auf dem Webserver läuft, die IP-Adresse des SQL-Knotens erreichen kann.

In gleicher Weise können Sie die MySQL C-API, Perl-DBI, Python-mysql oder die eigenen Connectors der MySQL AB einsetzen, um die Aufgaben der Datendefinition und Datenbearbeitung genau so zu erledigen, wie Sie es auch normalerweise mit MySQL tun.

16.3.6. Sicheres Herunterfahren und Neustarten

Um den Cluster herunterzufahren, geben Sie folgenden Befehl in eine Shell auf dem Host des MGM-Knotens ein:

shell> ndb_mgm -e shutdown

Hier wird die Option -e verwendet, um einen Befehl von der Shell an den ndb_mgm-Client zu übergeben. Siehe auch Abschnitt 4.3.1, „Befehlszeilenoptionen für mysqld“. Mit diesem Befehl werden ndb_mgm, ndb_mgmd und alle eventuell laufenden ndbd-Prozesse geräuschlos beendet. SQL-Knoten können mit mysqladmin shutdown und anderen Methoden heruntergefahren werden.

Folgende Befehle starten den Cluster neu:

  • Auf dem Management-Host (in unserem Beispiel 192.168.0.10):

    shell> ndb_mgmd -f /var/lib/mysql-cluster/config.ini
    
  • Auf jedem der Daten-Hosts (192.168.0.30 und 192.168.0.40):

    shell> ndbd
    

    Denken Sie daran, dass Sie diesen Befehl nicht mit der Option --initial aufrufen dürfen, wenn Sie einen NDBD-Knoten ganz normal neu starten.

  • Auf dem SQL-Host (192.168.0.20):

    shell> mysqld &
    

Mehr über Datensicherungen im Cluster erfahren Sie unter Abschnitt 16.6.5.2, „Verwendung des Management-Servers zur Erzeugung von Backups“.

Um den Cluster aus einer Datensicherung wiederherzustellen, benötigen Sie den Befehl ndb_restore, der in Abschnitt 16.6.5.3, „Wiederherstellung aus einem Cluster-Backup“, erklärt wird.

Weitere Informationen über die Konfiguration von MySQL Cluster finden Sie unter Abschnitt 16.4, „MySQL Cluster: Konfiguration“.

16.4. MySQL Cluster: Konfiguration

Ein MySQL Server in einem MySQL Cluster unterscheidet sich nur in einer Hinsicht von einem normalen (ungeclusterten) MySQL Server: Er verwendet die Speicher-Engine NDB Cluster. Diese Engine wird auch einfach als NDB bezeichnet, beide Namen sind synonym.

Um nicht überflüssig Ressourcen zu reservieren, ist die NDB-Engine in der Standardkonfiguration des Servers ausgeschaltet. Um sie einzuschalten, müssen Sie die Serverkonfigurationsdatei my.cnf ändern oder den Server mit der Option --ndbcluster hochfahren.

Da der MySQL Server Teil des Clusters ist, muss auch er wissen, wie er einen MGM-Knoten erreicht, von dem er sich die Cluster-Konfigurationsdaten besorgen kann. Nach Voreinstellung sucht er den MGM-Knoten auf dem localhost. Wenn Sie jedoch einen anderen Ort angeben müssen, so können Sie dies in der Datei my.cnf oder auf der Kommandozeile des MySQL Servers tun. Bevor die Speicher-Engine NDB genutzt werden kann, müssen mindestens ein MGM-Knoten sowie die erforderlichen Datenknoten funktionieren.

16.4.1. MySQL Cluster vom Quellcode bauen

Die Speicher-Engine NDB für den Cluster-Betrieb ist als Binärdistribution für Linux, Mac OS X und Solaris erhältlich. Wir arbeiten daran, Cluster auf allen von MySQL unterstützten Betriebssystemen einschließlich Windows funktionsfähig zu machen.

Wenn Sie einen Build von einem Source Tarball oder dem MySQL 5.1 BitKeeper Tree bevorzugen, achten Sie darauf, configure mit der Option --with-ndbcluster auszuführen. Sie können jedoch auch das Build-Skript BUILD/compile-pentium-max laufen lassen. Beachten Sie, dass dieses Skript OpenSSL enthält: Damit der Build fehlerfrei läuft, müssen Sie also entweder OpenSSL besitzen oder sich besorgen oder compile-pentium-max umkonfigurieren, um dieses Erfordernis herauszunehmen. Sie können natürlich auch einfach die Standardinstruktionen für das Kompilieren Ihrer eigenen Binaries befolgen und dann die üblichen Tests und Installationsprozeduren durchführen. Siehe Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“.

16.4.2. Installation der Software

In den folgenden Abschnitten wird vorausgesetzt, dass Sie mit der Installation von MySQL bereits vertraut sind. Daher behandeln wir hier nur die Unterschiede zwischen der Konfiguration eines geclusterten und eines ungeclusterten MySQL Servers. (Wenn Sie genauere Informationen benötigen, schauen Sie unter Kapitel 2, Installation von MySQL, nach.)

Am einfachsten ist die Cluster-Konfiguration, wenn alle Management- und Datenknoten bereits laufen. Dies ist wohl der langwierigste Teil der Konfiguration. Dagegen ist die Bearbeitung der Datei my.cnf ziemlich einfach und dieser Abschnitt wird lediglich beschreiben, wo die Konfiguration von der des ungeclusterten MySQL Servers abweicht.

16.4.3. Schnelle Testeinrichtung von MySQL Cluster

Um sich mit den Grundlagen vertraut zu machen, beschreiben wir zuerst die denkbar einfachste Konfiguration eines funktionsfähigen MySQL Clusters. Danach müssten Sie in der Lage sein, die von Ihnen gewünschte Startkonfiguration aus den Informationen der anderen zum Thema gehörenden Teile dieses Kapitels zu erschließen.

Zuerst müssen Sie ein Konfigurationsverzeichnis wie beispielsweise /var/lib/mysql-cluster anlegen, indem Sie folgenden Befehl als System-root-User ausführen:

shell> mkdir /var/lib/mysql-cluster

In diesem Verzeichnis legen Sie eine Datei namens config.ini an, die folgende Daten enthält. Bitte setzen Sie für HostName und DataDir die für Ihr System passenden Werte ein.

# Die Datei "config.ini" zeigt eine Minimalkonfiguration, bestehend aus 1 Datenknoten,
# 1 Management-Server und 3 MySQL Servern.
# Die leeren Default-Abschnitte sind nicht erforderlich und werden nur der
# Vollständigkeit halber gezeigt.
# Die Datenknoten müssen einen Hostnamen angeben, nicht aber die MySQL Server.
# Wenn Sie den Hostnamen Ihres Computers nicht wissen, verwenden Sie localhost.
# Der Parameter DataDir hat ebenfalls einen Standardwert, sollte aber besser
# explizit gesetzt werden.
# Hinweis: DB, API und MGM sind Aliase für NDBD, MYSQLD und NDB_MGMD
# DB und API sind veraltet und sollten in neuen
# Installationen nicht mehr benutzt werden.
[NDBD DEFAULT]
NoOfReplicas= 1

[MYSQLD DEFAULT]
[NDB_MGMD DEFAULT]
[TCP DEFAULT]

[NDB_MGMD]
HostName= myhost.example.com

[NDBD]
HostName= myhost.example.com
DataDir= /var/lib/mysql-cluster

[MYSQLD]
[MYSQLD]
[MYSQLD]

Sie können jetzt den Management-Server ndb_mgmd starten. Da dieser standardmäßig versucht, die Datei config.ini in seinem aktuellen Arbeitsverzeichnis zu lesen, müssen Sie in das Verzeichnis wechseln, in dem die Datei sich befindet, und dann ndb_mgmd aufrufen:

shell> cd /var/lib/mysql-cluster
shell> ndb_mgmd

Danach starten Sie einen einzelnen DB-Knoten mit dem Befehl ndbd. Wenn Sie ndbd zum allerersten Mal für einen DB-Knoten starten, müssen Sie die Option --initial einsetzen:

shell> ndbd --initial

Bei allen weiteren Starts von ndbd müssen Sie die --initial-Option unbedingt weglassen:

shell> ndbd

Der Grund, weshalb die Option --initial bei weiteren Neustarts nicht wieder benutzt werden darf, ist der, dass sie ndbd veranlasst, alle vorhandenen Daten- und Logdateien (und alle Metadaten für Tabellen) dieses Datenknotens zu löschen und neu zu erzeugen. Die einzige Ausnahme von dieser Regel, --initial nur für den allerersten Aufruf von ndbd zu verwenden, tritt dann ein, wenn der Cluster neu gestartet und nach dem Hinzufügen neuer Datenknoten aus den Sicherungsdateien wiederhergestellt wird.

Nach Voreinstellung sucht ndbd den Management-Server auf localhost am Port 1186.

Hinweis: Wenn Sie MySQL von einem Binary Tarball installiert haben, müssen Sie den Pfad der ndb_mgmd- und ndbd-Server explizit angeben. (Normalerweise befinden sich die beiden in /usr/local/mysql/bin.)

Zum Schluss gehen Sie in das MySQL-Datenverzeichnis (normalerweise /var/lib/mysql oder /usr/local/mysql/data) und sorgen dafür, dass die Datei my.cnf die Option enthält, die zur Aktivierung der Speicher-Engine NDB erforderlich ist:

[mysqld]
ndbcluster

Jetzt können Sie den MySQL Server wie gewöhnlich starten:

shell> mysqld_safe --user=mysql &

Warten Sie einen Augenblick, um sich zu vergewissern, dass der MySQL Server richtig läuft. Wenn Sie die Meldung mysql ended sehen, schauen Sie in die .err-Datei des Servers, um den Fehler zu finden.

Wenn so weit alles geklappt hat, können Sie den Server nun geclustert starten. Verbinden Sie sich mit dem Server und schauen Sie nach, ob die Speicher-Engine NDBCLUSTER aktiviert ist:

shell> mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 5.1.5-alpha-Max

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> SHOW ENGINES\G
...
*************************** 12. row ***************************
Engine: NDBCLUSTER
Support: YES
Comment: Clustered, fault-tolerant, memory-based tables
*************************** 13. row ***************************
Engine: NDB
Support: YES
Comment: Alias for NDBCLUSTER
...

Die Zeilennummern der obigen Ausgabe können auf Ihrem System je nach Ihrer Serverkonfiguration abweichen.

Versuchen Sie nun, eine NDBCLUSTER-Tabelle anzulegen:

shell> mysql
mysql> USE test;
Database changed

mysql> CREATE TABLE ctest (i INT) ENGINE=NDBCLUSTER;
Query OK, 0 rows affected (0.09 sec)

mysql> SHOW CREATE TABLE ctest \G
*************************** 1. row ***************************
       Table: ctest
Create Table: CREATE TABLE `ctest` (
  `i` int(11) default NULL
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Um zu prüfen, ob Ihre Knoten richtig eingerichtet sind, starten Sie den Management-Client:

shell> ndb_mgm

Innerhalb des Management-Clients geben Sie den Befehl SHOW ein, um einen Statusbericht über den Cluster zu erhalten:

NDB> SHOW
Cluster Configuration
---------------------
[ndbd(NDB)]     1 node(s)
id=2    @127.0.0.1  (Version: 3.5.3, Nodegroup: 0, Master)

[ndb_mgmd(MGM)] 1 node(s)
id=1    @127.0.0.1  (Version: 3.5.3)

[mysqld(API)]   3 node(s)
id=3    @127.0.0.1  (Version: 3.5.3)
id=4 (not connected, accepting connect from any host)
id=5 (not connected, accepting connect from any host)

Nun haben Sie mit Erfolg einen funktionierenden MySQL Cluster eingerichtet. In diesen Cluster können Sie jetzt aus jeder Tabelle, die mit ENGINE=NDBCLUSTER oder seinem Alias ENGINE=NDB angelegt wurde, Daten laden.

16.4.4. Konfigurationsdatei

Um MySQL Cluster zu konfigurieren, müssen Sie mit zwei Dateien arbeiten:

  • my.cnf: Hier sind Optionen für alle Executables im MySQL Cluster angegeben. Diese Datei, die Ihnen aus der früheren Arbeit mit MySQL bereits vertraut sein dürfte, muss jeder ausführbaren Datei im Cluster zugänglich sein.

  • config.ini: Diese Datei wird nur vom Management-Server im MySQL Cluster gelesen, der dann die in ihr enthaltenen Informationen an alle Prozesse im Cluster weiterleitet. config.ini enthält eine Beschreibung für jeden am Cluster beteiligten Knoten. Dazu gehören Konfigurationsparameter für Datenknoten sowie Konfigurationsparameter für Verbindungen zwischen sämtlichen Knoten im Cluster.

Wir arbeiten permanent daran, die Cluster-Konfiguration zu verbessern und diesen Prozess zu vereinfachen. Auch wenn wir uns dabei um Abwärtskompatibilität bemühen, können auch gelegentlich inkompatible Änderungen vorkommen. In solchen Fällen teilen wir den Benutzern von Cluster im Voraus mit, wenn eine Änderung nicht abwärtskompatibel ist. Wenn Sie auf eine noch undokumentierte Änderung dieser Art stoßen sollten, melden Sie sie bitte der MySQL-Bugs-Datenbank nach dem in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschriebenen Verfahren.

16.4.4.1. Beispielkonfiguration eines MySQL Clusters

Um MySQL Cluster zu unterstützen, müssen Sie die Datei my.cnf so ändern, wie es im folgenden Beispiel gezeigt wird. Bitte verwechseln Sie die hier angegebenen Optionen nicht mit denen aus den config.ini-Dateien. Sie können diese Parameter auch auf der Kommandozeile angeben, wenn Sie die Executables aufrufen.

# my.cnf
# Beispiel für Ergänzungen der my.cnf für MySQL Cluster
# (gilt für MySQL 5.1)

# ndbcluster-Speicher-Engine aktivieren und Verbindungs-String für
# Management-Server-Host anlegen (Standardport ist 1186)
[mysqld]
ndbcluster
ndb-connectstring=ndb_mgmd.mysql.com


  # Verbindungs-String für Management-Server-Host anlegen (Standardport ist 1186)
[ndbd]
connect-string=ndb_mgmd.mysql.com

  # Verbindungs-String für Management-Server-Host anlegen (Standardport ist 1186)
[ndb_mgm]
connect-string=ndb_mgmd.mysql.com

# Speicherort für Cluster-Konfigurationsdatei
[ndb_mgmd]
config-file=/etc/config.ini

(Weitere Informationen über Connectstrings finden Sie unter Abschnitt 16.4.4.2, „MySQL Cluster: connectstring.)

# my.cnf
# Beispiel für Ergänzungen der my.cnf für MySQL Cluster
# (funktioniert auf allen Versionen)

 # ndbcluster-Speicher-Engine aktivieren und Verbindungs-String für
 # Management-Server-Host anlegen (Standardport ist 1186
[mysqld]
ndbcluster
ndb-connectstring=ndb_mgmd.mysql.com:1186

Sie können in der Cluster-my.cnf-Datei auch einen separaten [mysql_cluster]-Abschnitt für Einstellungen einrichten, die von allen Executables gelesen und benutzt werden:

# Cluster-spezifische Einstellungen
[mysql_cluster]
ndb-connectstring=ndb_mgmd.mysql.com:1186

Die Konfigurationsdatei heißt nach Voreinstellung config.ini. Sie wird von ndb_mgmd beim Starten gelesen und kann an jedem beliebigen Ort gespeichert sein. Ihr Speicherort und ihr Name werden mit --config-file=path_name auf der Kommandozeile für ndb_mgmd angegeben. Wenn die Konfigurationsdatei nicht angegeben wurde, versucht ndb_mgmd nach Voreinstellung, eine Datei namens config.ini im aktuellen Arbeitsverzeichnis zu lesen.

Gegenwärtig hat die Konfiguration ein INI-Format: Sie besteht also aus Abschnitten mit Abschnittsüberschriften (in eckigen Klammern), gefolgt von den jeweiligen Parameternamen und -werten. Sie weicht insofern vom Standard-INI-Format ab, als der Name und Wert eines Parameters auch durch einen Doppelpunkt (‘:’) und nicht nur durch das Gleichheitszeichen (‘=’) getrennt sein können und die Abschnitte nicht eindeutig durch einen Abschnittsnamen identifiziert sind. Stattdessen werden eindeutige Abschnitte (wie zum Beispiel zwei verschiedene Knoten desselben Typs) durch eine eindeutige ID gekennzeichnet, die innerhalb des Abschnitts als Parameter angegeben ist.

Für die meisten Parameter sind Standardwerte definiert. Diese können auch in config.ini angegeben sein. Um einen Abschnitt für Standardwerte anzulegen, fügen Sie dem Abschnittsnamen einfach DEFAULT hinzu. Zum Beispiel enthält ein [NDBD]-Abschnitt Parameter für einen bestimmten Datenknoten, während ein[NDBD DEFAULT]-Abschnitt Parameter enthält, die für sämtliche Datenknoten gelten. Wir nehmen an, dass alle Datenknoten denselben Speicherplatz belegen. Um sie alle zu konfigurieren, legen Sie also einen [NDBD DEFAULT]-Abschnitt mit einer DataMemory-Zeile an, in welcher der Speicherplatz für die Datenknoten angegeben ist.

Die Konfigurationsdatei muss mindestens die Computer und Knoten eines Clusters aufführen und sagen, auf welchem Computer welcher Knoten residiert. Im Folgenden sehen Sie ein Beispiel einer einfachen Konfigurationsdatei für einen Cluster, der aus einem Management-Server, zwei Datenknoten und zwei MySQL Servern besteht:

# Datei "config.ini" - 2 Datenknoten und 2 SQL-Knoten
# Diese Datei wird in das Startverzeichnis von ndb_mgmd (dem
# Management-Server gelegt.)
# Der erste MySQL Server kann von jedem Host gestartet werden, der zweite
# nur vom Host mysqld_5.mysql.com

[NDBD DEFAULT]
NoOfReplicas= 2
DataDir= /var/lib/mysql-cluster

[NDB_MGMD]
Hostname= ndb_mgmd.mysql.com
DataDir= /var/lib/mysql-cluster

[NDBD]
HostName= ndbd_2.mysql.com

[NDBD]
HostName= ndbd_3.mysql.com

[MYSQLD]
[MYSQLD]
HostName= mysqld_5.mysql.com

Beachten Sie, dass jeder Knoten seinen eigenen Abschnitt in config.ini hat. Da der vorliegende Cluster zwei Datenknoten hat, enthält die Konfigurationsdatei zwei [NDBD]-Abschnitte, in denen diese Knoten definiert sind.

In der config.ini-Konfigurationsdatei können sechs verschiedene Abschnitte benutzt werden:

  • [COMPUTER]: Definiert die Cluster-Hosts.

  • [NDBD]: Definiert die Daten des Clusters nodes.

  • [MYSQLD]: Definiert die MySQL Server-Knoten des Clusters server nodes.

  • [MGM] or [NDB_MGMD]: Definiert den Management-Server-Knoten des Clusters.

  • [TCP]: Definiert die TCP/IP-Verbindungen zwischen den Knoten im Cluster, wobei TCP/IP das Standardverbindungsprotokoll ist.

  • [SHM]: Definiert Shared-Memory-Verbindungen zwischen Knoten. Früher stand dieser Verbindungtyp nur in Binaries zur Verfügung, die mit der Option --with-ndb-shm gebaut wurden. In MySQL 5.1-Max ist er nach Voreinstellung eingeschaltet, allerdings befindet sich diese Lösung noch in der Erprobungsphase.

Für jeden Abschnitt können Sie auch DEFAULT-Werte definieren. Cluster-Parameternamen unterscheiden im Gegensatz zu den Parametern in my.cnf oder my.ini nicht zwischen Groß- und Kleinschreibung.

16.4.4.2. MySQL Cluster: connectstring

Mit Ausnahme des MySQL Cluster-Management-Servers (ndb_mgmd) benötigt jeder zu einem MySQL Cluster gehörige Knoten einen Verbindungs-String (Connectstring), der auf den Standort des Management-Servers verweist. Dieser Verbindungs-String wird zum Einrichten einer Verbindung mit dem Management-Server und, je nach der Rolle des Knotens im Cluster, auch für die Erfüllung anderer Aufgaben benötigt. Ein Verbindungs-String hat folgende Syntax:

<connectstring> :=
    [<nodeid-specification>,]<host-specification>[,<host-specification>]

<nodeid-specification> := node_id

<host-specification> := host_name[:port_num]

node_id ist ein Integer größer 1, der einen Knoten in config.ini bezeichnet. host_name ist ein String, der einen gültigen Internethostnamen oder eine IP-Adresse angibt. port_num ist ein Integer, der auf eine TCP/IP-Portnummer verweist.

example 1 (long):    "nodeid=2,myhost1:1100,myhost2:1100,192.168.0.3:1200"
example 2 (short):   "myhost1"

Alle Knoten verwenden localhost:1186 als Standardwert für den Verbindungs-String, wenn kein anderer angegeben wird. Wenn port_num aus dem Verbindungs-String weggelassen wird, ist 1186 der Standardport. Dieser sollte im Netzwerk immer frei sein, da er von der IANA genau diesen Zweck zugewiesen bekam (siehe http://www.iana.org/assignments/port-numbers for details).

Durch Auflistung mehrerer <host-specification>-Werte können Sie redundante Management-Server angeben. Ein Cluster-Knoten wird dann versuchen, der Reihe nach mehrere Management-Server auf jedem Host zu kontaktieren, bis er eine Verbindung einrichten kann.

Der Verbindungs-String kann auf verschiedene Weisen angegeben werden:

  • Jede Executable hat ihre eigene Kommandozeilenoption, um den Management-Server beim Starten anzugeben. (In der Dokumentation finden Sie die jeweilige Executable.)

  • Sie können auch die Verbindungs-Strings für alle Knoten des Clusters zugleich einrichten, indem Sie sie in den [mysql_cluster]-Abschnitt der my.cnf-Datei des Management-Servers schreiben.

  • Aus Gründen der Abwärtskompatibilität stehen auch zwei weitere Optionen mit gleicher Syntax zur Verfügung:

    1. Sie können die Umgebungsvariable NDB_CONNECTSTRING auf den Verbindungs-String einstellen.

    2. Sie können den Verbindungs-String für jede Executable in eine Textdatei namens Ndb.cfg schreiben und diese Datei in das Startverzeichnis der Executable legen.

    Diese beiden Möglichkeiten sind jedoch inzwischen veraltet und sollten für neuere Installationen nicht mehr verwendet werden.

Wir empfehlen, den Verbindungs-String entweder auf der Kommandozeile oder in der Datei my.cnf für jede Executable anzugeben.

16.4.4.3. Festlegung der Computer, aus denen ein MySQL Cluster besteht

Die einzige Bedeutung des Abschnitts [COMPUTER] besteht darin, nicht für jeden Knoten im System Hostnamen definieren zu müssen. Alle hier angegebenen Parameter sind obligatorisch.

  • Id

    Ein Integer-Wert, der auf einen anderswo in der Konfigurationsdatei angegebenen Hostcomputer verweist.

  • HostName

    Der Hostname oder die IP-Adresse des Computers.

16.4.4.4. Festlegung des MySQL Cluster-Management-Servers

Im Abschnitt [NDB_MGMD] wird das Verhalten des Management-Servers konfiguriert. [MGM] kann auch als Alias verwendet werden; beide Abschnittsnamen sind äquivalent. Alle Parameter in der folgenden Liste sind optional; wenn man sie weglässt, werden Standardwerte verwendet. Hinweis: Wenn weder der Parameter ExecuteOnComputer noch ein HostName angegeben ist, wird localhost für beide als Default eingesetzt.

  • Id

    Jeder Knoten im Cluster hat eine eindeutige Identität, die durch einen Integer-Wert zwischen 1 und 63 (einschließlich) dargestellt wird. Alle Nachrichten im Cluster sprechen den Knoten mit dieser ID an.

  • ExecuteOnComputer

    Bezieht sich auf einen der im Abschnitt [COMPUTER] aufgeführten Computer.

  • PortNumber

    Die Nummer des Ports, auf welchem der Management-Server auf Konfigurationsanforderungen und Management-Befehle lauscht.

  • LogDestination

    Dieser Parameter gibt an, wohin die Logdaten für den Cluster gesandt werden: an CONSOLE, SYSLOG oder FILE:

    • CONSOLE gibt das Log an stdout aus:

      CONSOLE
      
    • SYSLOG sendet das Log an syslog, wobei einer der folgenden Werte verwendet wird: auth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, syslog, user, uucp, local0, local1, local2, local3, local4, local5, local6 oder local7.

      Hinweis: Nicht jedes Betriebssystem unterstützt alle diese Werte.

      SYSLOG:facility=syslog
      
    • FILE sendet die Ausgabe des Cluster-Logs an eine normale Datei auf demselben Computer. Folgende Werte können angegeben werden:

      • filename: Der Name der Logdatei.

      • maxsize: Die Maximalgröße (in Bytes), auf welche die Datei anwachsen kann, ehe das Log in einer neuen Datei fortgesetzt wird. Wenn dies geschieht, wird die alte Logdatei umbenannt, indem ein .N an ihren Dateinamen angefügt wird, wobei N die nächste laufende Nummer ist, die noch nicht für diesen Dateinamen eingesetzt wurde.

      • maxfiles: Die maximale Anzahl der Logdateien.

      FILE:filename=cluster.log,maxsize=1000000,maxfiles=6
      

      In der folgenden Form können auch mehrere Logdestinationen, jeweils durch Semikola getrennt, angegeben werden:

      CONSOLE;SYSLOG:facility=local0;FILE:filename=/var/log/mgmd
      

      Der Parameter FILE hat folgenden Standardwert: FILE:filename=ndb_node_id_cluster.log,maxsize=1000000,maxfiles=6. node_id ist dabei die ID des Knotens.

  • ArbitrationRank

    Mit diesem Parameter wird angegeben, welche Knoten als Arbitrator fungieren können. Nur MGM- und SQL-Knoten können Arbitrator sein. Der ArbitrationRank can take ist einer der folgenden Werte:

    • 0: Dieser Knoten wird nie als Arbitrator eingesetzt.

    • 1: Da dieser Knoten eine hohe Priorität hat, wird er eher als Knoten mit niedriger Priorität als Arbitrator eingesetzt.

    • 2: Ein Knoten mit niedriger Priorität, der als Arbitrator nur eingesetzt wird, wenn kein Knoten mit höherer Priorität für diesen Zweck verfügbar ist.

    Normalerweise sollte der Management-Server als Arbitrator konfiguriert werden, indem sein ArbitrationRank auf 1 (den Default) und der Rang aller SQL-Knoten auf 0 gesetzt wird.

  • ArbitrationDelay

    Ein Integer-Wert, der angibt, um wie viele Millisekunden die Antworten des Management-Servers auf Arbitration-Requests verzögert werden. Der Standardwert 0 muss normalerweise nicht geändert werden.

  • DataDir

    Das Verzeichnis, in dem die Ausgabedateien des Management-Servers gespeichert werden. Dazu gehören die Cluster-Logdateien, die Prozess-Ausgabedateien und die Prozess-ID (PID)-Datei des Daemons. (Für die Logdateien können Sie auch einen anderen Speicherort einstellen, indem Sie, wie weiter oben in diesem Abschnitt beschrieben, den Parameter FILE für die LogDestination einstellen.)

16.4.4.5. Festlegen von MySQL Cluster-Datenknoten

Im Abschnitt [NDBD] wird das Verhalten der Datenknoten des Clusters konfiguriert. Es gibt eine Vielzahl Parameter für die Größen von Puffern und Pools, für Timeout-Werte und so weiter. Die einzigen obligatorischen Parameter sind:

  • entweder ExecuteOnComputer oder HostName

  • der Parameter NoOfReplicas

Diese obligatorischen Parameter müssen im Abschnitt [NDBD DEFAULT] definiert werden.

Die meisten Parameter für Datenknoten werden im Abschnitt [NDBD DEFAULT] gesetzt. Nur die Parameter, von denen explizit gesagt wird, dass sie lokale Werte einstellen können, dürfen im [NDBD]-Abschnitt geändert werden. HostName, Id und ExecuteOnComputer müssen unbedingt im lokalen [NDBD]-Abschnitt definiert sein.

Datenknoten identifizieren

Der Wert Id (der Datenknoten-Bezeichner) kann entweder auf der Kommandozeile beim Starten des Knotens oder in der Konfigurationsdatei zugewiesen werden.

An jeden Parameter kann als Suffix K, M oder G angehängt werden, um Einheiten von 1.024, 1.024 × 1.024 oder 1.024 × 1.024 × 1.024 anzugeben. (So bedeutet beispielsweise 100K 100 × 1.024 = 102.400.) In Parameternamen und -werten wird zwischen Groß- und Kleinschreibung unterschieden.

  • Id

    Diese Knoten-ID ist die Adresse des Knotens für alle internen Nachrichten im Cluster. Sie ist ein Integer zwischen 1 und 63 einschließlich. Jeder Knoten im Cluster muss eine eindeutige Identität haben.

  • ExecuteOnComputer

    Bezieht sich auf einen der Computer (Hosts), die im Abschnitt COMPUTER definiert sind.

  • HostName

    Die Angabe dieses Parameters wirkt sich ähnlich wie die Angabe von ExecuteOnComputer aus: Er definiert den Hostnamen des Computers, auf dem der Speicherknoten liegen soll. Wenn Sie einen anderen Hostnamen als localhost angeben möchten, müssen Sie entweder diesen Parameter oder ExecuteOnComputer verwenden.

  • ServerPort (OBSOLETE)

    Jeder Knoten im Cluster verbindet sich mit anderen Computern über einen Port. Dieser Port wird beim Einrichten der Verbindung auch für Nicht-TCP-Transporter verwendet. Der Standardport wird dynamisch in einer Weise zugewiesen, die gewährleistet, dass keine zwei Knoten auf demselben Computer die gleiche Portnummer bekommen. Daher dürfte es sich normalerweise erübrigen, einen Wert für diesen Parameter zu setzen.

  • NoOfReplicas

    Dieser globale Parameter kann nur im Abschnitt [NDBD DEFAULT] eingestellt werden und definiert, wie viele Replikas jeder Tabelle im Cluster gespeichert werden. Außerdem gibt dieser Parameter die Größe der Knotengruppen an. Eine Knotengruppe ist eine Menge von Knoten, die alle dieselben Informationen speichern.

    Knotengruppen werden implizit gebildet. Die erste Knotengruppe besteht aus der Menge der Datenknoten mit den niedrigsten Knoten-IDs, die nächste aus der Menge der Datenknoten mit den zweitniedrigsten IDs und so weiter. Nehmen wir als Beispiel an, wir hätten 4 Datenknoten und die NoOfReplicas wurde auf 2 gesetzt. Die vier Datenknoten haben die IDs 2, 3, 4 und 5. Dann besteht die erste Gruppe aus den Knoten 2 und 3 und die zweite Gruppe aus den Knoten 4 und 5. Es ist wichtig, den Cluster so zu konfigurieren, dass Knoten derselben Gruppe nicht auf demselben Computer liegen, da ein einziger Hardwareabsturz dann den gesamten Cluster zerstören würde.

    Wenn keine Knoten-IDs angegeben werden, entscheidet die Reihenfolge der Datenknoten über ihre Zugehörigkeit zu einer Knotengruppe. Egal ob explizit zugewiesen oder nicht, die SHOW-Ausgabe auf dem Management-Client zeigt die Knotengruppen an.

    NoOfReplicas hat keinen Standardwert, der größtmögliche Wert beträgt 4.

  • DataDir

    Dieser Parameter gibt das Verzeichnis für die Trace-Dateien, Logdateien, PID-Dateien und Fehlerlogs an.

  • FileSystemPath

    Dieser Parameter gibt an, in welchem Verzeichnis alle Dateien gespeichert werden, die für Metadaten, REDO-Logs, UNDO-Logs und Datendateien angelegt werden. Nach Voreinstellung ist dies das in DataDir angegebene Verzeichnis. Hinweis: Dieses Verzeichnis muss existieren, bevor der ndbd-Prozess gestartet wird.

    Die empfohlene Verzeichnishierarchie für MySQL Cluster beginnt mit dem Verzeichnis /var/lib/mysql-cluster, unter dem dann ein Verzeichnis für das Dateisystem des Knotens angelegt wird. Der Name dieses Unterverzeichnisses enthält die Knoten-ID. Wenn beispielsweise die Knoten-ID die 2 ist, heißt das Unterverzeichnis ndb_2_fs.

  • BackupDataDir

    Dieser Parameter sagt, in welches Verzeichnis die Sicherungsdateien gespeichert werden. Wird nichts angegeben, ist ein Verzeichnis namens BACKUP unter dem im Parameter FileSystemPath angegebenen Speicherort das Standardverzeichnis (siehe oben.)

Data Memory und Index Memory

DataMemory und IndexMemory sind [NDBD]-Parameter, in denen die Größe der Speichersegmente festgelegt wird, welche die tatsächlichen Datensätze und ihre Indizes speichern. Für die Einstellung dieser Parameter müssen Sie unbedingt wissen, wie DataMemory und IndexMemory verwendet werden, da diese Werte normalerweise an die tatsächliche Speichernutzung des Clusters angepasst werden müssen:

  • DataMemory

    Dieser Parameter besagt, wie viel Speicherplatz (in Bytes) für die Speicherung der Datenbankeinträge zur Verfügung stehen muss. Da im Arbeitsspeicher der gesamte hier angegebene Speicherplatz zugewiesen wird, ist es extrem wichtig, dass der physikalische Arbeitsspeicher des Computers groß genug ist, um diesen auch unterbringen zu können.

    Der durch DataMemory zugewiesene Speicher wird sowohl für die Datensätze als auch für ihre Indizes verwendet. Jeder Datensatz hat zurzeit noch eine feste Größe (sogar VARCHAR-Spalten werden als Spalten fester Breite gespeichert). Für jeden Datensatz gibt es einen Overhead von 16 Byte. Zusätzlich wird noch weiterer Platz für jeden Datensatz zugewiesen, da er in einer 32-Kbyte-Seite mit 128 Byte Seiten-Overhead gespeichert wird (siehe unten). Zudem wird für jede Seite ein wenig Platz verschwendet, da jeder Datensatz in ein- und derselben Seite gespeichert werden muss. Die Maximalgröße eines Datensatzes beträgt gegenwärtig 8.052 Byte.

    Der in DataMemory definierte Speicherplatz wird auch zur Unterbringung von Indizes genutzt, die rund 10 Byte pro Datensatz belegen. Jede Tabellenzeile wird im geordneten Index dargestellt. Oft nehmen Anwender fälschlich an, dass alle Indizes in dem Speicher des IndexMemory abgelegt werden, doch dies ist nicht der Fall: Nur Primärschlüssel und eindeutige Hash-Indizes nutzen diesen Speicher, während geordnete Indizes den von DataMemory zugewiesenen Speicher belegen. Wenn Sie jedoch einen Primärschlüssel oder einen eindeutigen Hash-Index anlegen, wird zugleich auf denselben Schlüsseln auch ein geordneter Index erzeugt, sofern Sie nicht in der Indexanweisung USING HASH gesagt haben. Dies können Sie prüfen, indem Sie ndb_desc -d db_name table_name im Management-Client ausführen.

    Der für das DataMemory zugewiesene Speicherplatz besteht aus 32-Kbyte-Seiten, die den Tabellenfragmenten zugeordnet werden. Jede Tabelle wird normalerweise in ebenso viele Fragmente partitioniert, wie der Cluster Datenknoten hat. Also sind für jeden Knoten so viele Fragmente vorhanden, wie in NoOfReplicas eingestellt sind. Gegenwärtig ist es nicht möglich, eine einmal zugewiesene Seite dem Pool der freien Seiten zurückzugeben, außer man löscht die Tabelle. Auch durch eine Knotenwiederherstellung wird die Partition kleiner, da alle Datensätze in leere Partitionen anderer Live-Knoten geschrieben werden.

    Der Speicherplatz im DataMemory enthält auch UNDO-Informationen: Bei jedem Update wird eine Kopie des unveränderten Datensatzes in das DataMemory geschrieben. Außerdem wird jede Kopie in den geordneten Tabellenindizes referenziert. Eindeutige Hash-Indizes werden nur aktualisiert, wenn die eindeutigen Indexspalten sich ändern. In diesem Fall wird ein neuer Eintrag in die Indextabelle eingefügt und der alte beim Committen gelöscht. Aus diesem Grunde ist es auch notwendig, genug Speicherplatz zu reservieren, um selbst die größten Transaktionen von Anwendungen, die diesen Cluster nutzen, noch behandeln zu können. Wenige große Transaktionen auszuführen ist jedenfalls nicht besser, als viele kleine zu verwenden. Dafür gibt es folgende Gründe:

    • Große Transaktionen sind nicht schneller als kleinere.

    • Wenn eine Transaktion scheitert, müssen bei großen Transaktionen mehr Operationen wiederholt werden, weil sie verloren gegangen sind.

    • Große Transaktionen belegen mehr Speicherplatz.

    Der Standardwert für das DataMemory beträgt 80 Mbyte und der Mindestwert 1 Mbyte. Es gibt keinen Höchstwert, aber in der Praxis muss die Maximalgröße natürlich so angepasst werden, dass der Prozess nicht anfängt, auf die Platte zu schreiben, wenn das Limit erreicht wird. Dieses Limit hängt von der Größe des auf dem Computer verfügbaren physikalischen Arbeitsspeichers ab sowie von der Frage, wie viel Speicher das Betriebssystem einem einzelnen Prozess zuweisen kann. 32-Bit-Betriebssysteme sind generell auf 2 bis 4 Gbyte pro Prozess beschränkt, während 64-Bit-Betriebssysteme mehr Speicher verwenden können. Aus diesem Grunde eignen sich 64-Bit-Systeme für große Datenbanken besser. Überdies ist es möglich, mehrere ndbd-Prozesse pro Computer auszuführen. Dies kann bei Maschinen mit mehreren CPUs Vorteile bringen.

  • IndexMemory

    Dieser Parameter gibt an, wie viel Speicher für Hash-Indizes in MySQL Cluster benutzt wird. Hash-Indizes werden immer für Primärschlüsselindizes, eindeutige Indizes und Unique-Constraints verwendet. Achtung: Wenn Sie einen Primärschlüssel und einen eindeutigen Index definieren, werden zwei Indizes angelegt, von denen einer ein Hash-Index ist, der für alle Tupel-Zugriffe, für die Sperren und für die Durchsetzung von Unique-Constraints verwendet wird.

    Die Größe des Hash-Indexes beträgt 25 Byte pro Datensatz plus die Größe des Primärschlüssels. Für Primärschlüssel, die mehr als 32 Byte belegen, werden weitere 8 Byte addiert.

    Der Standardwert für IndexMemory beträgt 18 Mbyte, der Mindestwert 1 Mbyte.

Das folgende Beispiel zeigt, wie Speicher für eine Tabelle zugewiesen wird. Betrachten Sie folgende Tabellendefinition:

CREATE TABLE example (
  a INT NOT NULL,
  b INT NOT NULL,
  c INT NOT NULL,
  PRIMARY KEY(a),
  UNIQUE(b)
) ENGINE=NDBCLUSTER;

Für jeden Datensatz sind 12 Byte Daten plus 12 Byte Overhead zugewiesen. Wenn keine Spalten dabei sind, die Nullwerte annehmen können, so spart dies 4 Byte Overhead. Außerdem gibt es auf den Spalten a und b zwei geordnete Indizes, die jeweils ungefähr 10 Byte pro Datensatz belegen. Auf der Basistabelle ist ein Primärschlüssel-Hash-Index definiert, der rund 29 Byte pro Datensatz beansprucht. Der Unique-Constraint ist durch eine separate Tabelle implementiert, die b als Primärschlüssel und a als eine Spalte verwendet. Diese andere Tabelle belegt weitere 29 Byte Indexspeicher pro Datensatz in der example-Tabelle zuzüglich 8 Byte für die Datensatzdaten und 12 Byte für den Overhead.

Also benötigen wir für eine Million Datensätze 58 Mbyte für den Indexspeicher, um die Hash-Indizes für den Primärschlüssel und den Unique-Constraint unterbringen zu können. Außerdem benötigen wir 64 Mbyte für die Datensätze der Basistabelle und die Tabelle mit dem eindeutigen Index plus die beiden Tabellen mit dem geordneten Index.

Wie Sie sehen, belegen Hash-Indizes nicht eben wenig Speicherplatz, bieten aber als Ausgleich einen sehr schnellen Datenzugriff. In MySQL Cluster werden sie außerdem für Unique-Constraints verwendet.

Gegenwärtig ist Hashing der einzige Partitionierungsalgorithmus und geordnete Indizes sind lokal für jeden Knoten. Also können geordnete Indizes im Allgemeinen nicht für die Handhabung von Unique-Constraints eingesetzt werden.

Ein wichtiger Punkt sowohl für das IndexMemory als auch für das DataMemory ist der, dass die Gesamtgröße der Datenbank die Summe sämtlicher Daten- und Indexspeicher für jede Knotengruppe ist. Da alle Knotengruppen verwendet werden, um replizierte Informationen zu speichern, kommen bei vier Knoten mit zwei Replikas zwei Knotengruppen zustande. Also stehen jedem Datenknoten insgesamt 2 × DataMemory an Datenspeicher zur Verfügung.

Das DataMemory und das IndexMemory sollten unbedingt für alle Knoten auf denselben Wert eingestellt werden. Da die Daten über alle Knoten im Cluster gleichmäßig verteilt sind, kann für jeden Knoten im Cluster maximal nur so viel Speicher zur Verfügung stehen wie für den kleinsten Knoten im Cluster.

Die Werte für DataMemory und IndexMemory können zwar geändert werden, doch ist es riskant, einen von beiden herunterzusetzen: Wenn Sie dies tun, kann es leicht passieren, dass ein Knoten oder sogar der gesamte MySQL Cluster aus Mangel an Arbeitsspeicher nicht mehr starten kann. Das Heraufsetzen dieser Werte ist zwar schon eher akzeptabel, aber solche Upgrades sollten ebenso wie jeder Softwareupgrade durchgeführt werden: Zuerst wird die Konfigurationdatei geändert, dann der Management-Server neu hochgefahren und zum Schluss werden nacheinander alle Datenknoten gestartet.

Durch Updates wird nicht mehr Indexspeicherplatz belegt. Einfügungen treten sofort in Kraft, aber Löschungen von Zeilen werden erst dann tatsächlich wirksam, wenn die Transaktion committed wird.

Transaktionsparameter

Die nächsten drei [NDBD]-Parameter sind wichtig, weil sie die Anzahl der Paralleltransaktionen und die Größe der Transaktionen festlegen, die das System bewältigen kann. MaxNoOfConcurrentTransactions stellt ein, wie viele parallele Transaktionen in einem Knoten möglich sind. MaxNoOfConcurrentOperations sagt, wie viele Datensätze gleichzeitig geändert oder gesperrt werden können.

Beide Parameter (besonders MaxNoOfConcurrentOperations) werden von den meisten Anwendern an ihre spezifischen Anforderungen angepasst und nicht auf den Standardwerten belassen. Der Standardwert ist auf Systeme ausgelegt, die nur kleine Transaktionen fahren, um zu gewährleisten, dass diese nicht übermäßig Speicher belegen.

  • MaxNoOfConcurrentTransactions

    Für jede aktive Transaktion im Cluster muss ein Datensatz in einem der Cluster-Knoten stehen. Die Aufgabe, Transaktionen zu koordinieren, teilen sich die Knoten untereinander auf. Die Gesamtzahl der Transaktionsdatensätze im Cluster ist gleich der Anzahl der Transaktionen in einem gegebenen Knoten mal der Anzahl der Knoten im Cluster.

    Transaktionsdatensätze werden einzelnen MySQL Servern zugewiesen. Normalerweise ist pro Verbindung mindestens ein Transaktionsdatensatz zugewiesen, der eine beliebige Tabelle in dem Cluster benutzen kann. Daher sollten Sie dafür sorgen, dass in einem Cluster mehr Transaktionsdatensätze als nebenläufige Verbindungen zu allen MySQL Servern im Cluster vorhanden sind.

    Dieser Parameter muss für alle Cluster-Knoten auf denselben Wert gesetzt werden.

    Dieser Parameter sollte nie geändert werden, da dadurch ein Cluster abstürzen kann. Wenn ein Knoten abstürzt, erstellt ein anderer Knoten (nämlich der älteste überlebende) den Status aller Transaktionen, die im Augenblick des Crashs in dem abgestürzten Knoten abliefen. Daher ist es wichtig, dass dieser Knoten so viele Transaktionsdatensätze wie der abgestürzte Knoten hat.

    Der Standardwert ist 4096.

  • MaxNoOfConcurrentOperations

    Diesen Parameter sollte man immer an die Größe und Anzahl der Transaktionen anpassen. Wenn Ihre Transaktionen immer nur wenige Operationen ausführen und nicht viele Datensätze betreffen, besteht kein Anlass, diesen Parameter auf einen hohen Wert zu setzen. Doch für große Transaktionen mit vielen Datensätzen sollten Sie ihn heraufsetzen.

    Für jede Transaktion, die Cluster-Daten ändert, werden sowohl im Transaktionskoordinator als auch in den Knoten, wo die eigentlichen Änderungen eintreten, Aufzeichnungen gemacht. Diese Einträge enthalten Statusinformationen, die erforderlich sind, um die UNDO-Datensätze für Rollback, Lock Queues und andere Sätze zu erhalten.

    Dieser Parameter sollte auf die Anzahl der in Transaktionen gleichzeitig zu ändernden Datensätze, dividiert durch die Anzahl der Datenknoten im Cluster, gesetzt werden. In einem Cluster, der 4 Datenknoten hat und 1.000.000 nebenläufige Updates bewältigen soll, beträgt dieser Wert 1.000.000 / 4 = 250.000.

    Auch durch Leseanfragen, die Sperren setzen, werden Operationseinträge erzeugt. Für diese wird in den einzelnen Knoten etwas mehr Speicherplatz reserviert, um mit Fällen umgehen zu können, in denen die Verteilung über die Knoten nicht perfekt ist.

    Wenn Abfragen den eindeutigen Hash-Index verwenden, gibt es sogar zwei Operationseinträge pro Transaktionsdatensatz. Der erste stellt den Lesevorgang in der Indextabelle dar und der zweite betrifft die Operation auf der Basistabelle.

    Der Standardwert ist 32768.

    Dieser Parameter steuert in Wirklichkeit zwei separat konfigurierbare Werte. Der erste gibt an, wie viele Operationseinträge mit dem Transaktionskoordinator gesetzt werden, und der zweite, wie viele Operationseinträge lokal in der Datenbank gemacht werden.

    Eine sehr große Transaktion auf einem Cluster mit 8 Knoten erfordert im Transaktionskoordinator so viele Operationseinträge, wie es Lese-, Änderungs- und Einfügungsoperationen in der Transaktion gibt. Dabei werden die Operationseinträge allerdings über alle 8 Knoten verteilt. Also sollten die beiden Teile getrennt konfiguriert werden, wenn das System auf eine einzelne sehr große Transaktion vorbereitet werden soll. Anhand von MaxNoOfConcurrentOperations wird immer berechnet, wie viele Operationseinträge es in dem Teil des Knotens gibt, wo der Transaktionskoordinator sitzt.

    Zudem ist es wichtig, eine ungefähre Vorstellung des Speicherbedarfs für die Operationseinträge zu haben: Diese belegen pro Eintrag ungefähr 1 Kbyte.

  • MaxNoOfLocalOperations

    Nach Voreinstellung wird dieser Parameter zu 1,1 × MaxNoOfConcurrentOperations berechnet. Dies eignet sich für Systeme mit vielen simultanen Transaktionen, die jedoch alle nicht sehr umfangreich sind. Wenn Sie immer nur eine einzige, dafür aber sehr große Transaktion und zudem viele Knoten haben, sollten Sie den Standardwert dieses Parameters mit einem geeigneteren überschreiben.

Temporärer Speicher für Transaktionen

Die nächste Gruppe von [NDBD]-Parametern entscheidet über die temporäre Speicherung, die zur Ausführung einer Anweisung in einer Cluster-Transaktion verwendet wird. Alle Datensätze werden freigegeben, wenn die Anweisung abgeschlossen ist und der Cluster auf den Commit- oder Rollback-Befehl wartet.

Die Standardwerte für diese Parameter sind für die meisten Situationen passend. Wenn Sie jedoch Transaktionen auf sehr vielen Zeilen oder mit sehr vielen Operationen ausführen müssen, müssen Sie diese Werte eventuell heraufsetzen, um eine bessere Parallelverarbeitung im System zu ermöglichen. Sollten Ihre Transaktionen dagegen relativ klein sein, so können Sie durch Reduzieren dieser Werte Speicherplatz sparen.

  • MaxNoOfConcurrentIndexOperations

    Für Anfragen, die einen eindeutigen Hash-Index verwenden, wird während der Ausführungsphase eine weitere Gruppe von Operationseinträgen erstellt. Dieser Parameter stellt die Größe dieses Pools an Einträgen ein. Also wird dieser Eintrag nur während der Ausführung eines Teils einer Anfrage zugewiesen. Sobald dieser Teil abgeschlossen ist, wird der Eintrag wieder freigegeben. Der Zustand, in dem Transaktionen abgebrochen oder committet werden, wird von den normalen Operationseinträgen behandelt, deren Pool-Größe durch den Parameter MaxNoOfConcurrentOperations eingestellt wird.

    Dieser Parameter hat den Standardwert 8192. Nur in seltenen Fällen, in denen extrem hoher Parallelismus auftritt und eindeutige Hash-Indizes verwendet werden, kann es erforderlich sein, diesen Wert zu erhöhen. Auch ein kleinerer Wert ist möglich und kann Speicherplatz sparen, wenn der DBA sich sicher ist, dass für den Cluster kein besonders hoher Parallelismus erforderlich ist.

  • MaxNoOfFiredTriggers

    Der Standardwert von MaxNoOfFiredTriggers ist 4000 und dürfte für die meisten Situationen ausreichen. In manchen Fällen kann er sogar heruntergesetzt werden, wenn der DBA sich sicher ist, dass in dem Cluster kein besonderer Parallelismus auftritt.

    Wenn eine Operation ausgeführt wird, wird ein Datensatz angelegt, der einen eindeutigen Hash-Index beeinflusst. Eine Einfügung oder Löschung eines Eintrags in einer Tabelle mit eindeutigen Hash-Indizes oder eine Aktualisierung einer Spalte, die Teil eines eindeutigen Hash-Indexes ist, löst eine entsprechende Einfügung oder Löschung in der Indextabelle aus. Der resultierende Eintrag wird verwendet, um diese Indextabellenoperation zu repräsentieren, so lange die Originaloperation, die ihn veranlasste, noch nicht abgeschlossen ist. Diese Operation ist zwar kurzlebig, kann aber dennoch viele Einträge in ihrem Pool benötigen, wenn viele parallele Schreiboperationen auf einer Basistabelle stattfinden, die eine Reihe von eindeutigen Hash-Indizes enthält.

  • TransactionBufferMemory

    Dieser Parameter betrifft den Speicher zum Nachvollziehen von Operationen, die bei der Aktualisierung von Indextabellen und beim Lesen von eindeutigen Indizes auftreten. In diesem Arbeitsspeicherbereich werden die Schlüssel- und Spalteninformationen für diese Operationen gespeichert. Nur in seltenen Fällen muss dieser Parameter auf einen anderen als seinen Standardwert gesetzt werden.

    Normale Lese- und Schreiboperationen nutzen einen ähnlichen Puffer, der sogar noch kurzfristiger arbeitet. Der zur Übersetzungszeit benutzte Parameter ZATTRBUF_FILESIZE (aus ndb/src/kernel/blocks/Dbtc/Dbtc.hpp) ist auf 4.000 × 128 Byte (500 Kbyte) eingestellt. Ein ähnlicher Puffer für die Schlüsselinformationen, nämlich ZDATABUF_FILESIZE (ebenfalls in Dbtc.hpp), bietet 4.000 × 16 = 62,5 Kbyte Speicherplatz. Dbtc ist das Modul, welches sich um die Transaktionskoordination kümmert.

Scans und Datenpuffer

Das Modul Dblqh hat noch weitere [NDBD]-Parameter (in ndb/src/kernel/blocks/Dblqh/Dblqh.hpp), die sich auf Lese- und Änderungsoperationen auswirken. Hierzu gehören die ZATTRINBUF_FILESIZE, die auf 10.000 × 128 Byte (1250 Kbyte) voreingestellt ist, und ZDATABUF_FILE_SIZE mit dem Standardwert 10.000 * 16 Byte (rund 156 Kbyte) Speicherplatz im Puffer. Bisher haben weder Anwender noch die Ergebnisse unserer umfangreichen Tests je eine Erhöhung dieser Compile-Time-Limits nahe gelegt.

Der Standardwert für TransactionBufferMemory ist 1 Mbyte.

  • MaxNoOfConcurrentScans

    Dieser Parameter stellt ein, wie viele parallele Scans im Cluster ausgeführt werden können. Jeder Transaktionskoordinator kann so viele parallele Scans bewältigen, wie dieser Parameter festlegt. Jede Scananfrage wird durch paralleles Scannen aller Partitionen ausgeführt. Jeder Partitionsscan verwendet einen Scandatensatz in dem Knoten, auf dem sich die Partition befindet, wobei die Anzahl der Einträge der Wert dieses Parameters mal die Anzahl der Knoten ist. Der Cluster sollte in der Lage sein, MaxNoOfConcurrentScans nebenläufige Scans auf allen Knoten im Cluster zu bewältigen.

    Scans werden tatsächlich in zwei Fällen ausgeführt: erstens wenn kein Hash-Index oder geordneter Index für die Ausführung der Anfrage vorliegt; in diesem Fall wird die Anfrage mithilfe eines vollständigen Tabellenscans ausgeführt. Zweitens, wenn für die Anfrage zwar kein Hash-Index, aber ein geordneter Index vorhanden ist, denn die Verwendung eines geordneten Indexes erfordert zusätzlich einen parallelen Bereichsscan. Da die Reihenfolge nur auf den lokalen Partitionen beibehalten wird, muss der Indexscan auf allen Partitionen ausgeführt werden.

    Der Standardwert von MaxNoOfConcurrentScans ist 256 und der Höchstwert beträgt 500.

    Dieser Parameter gibt an, wie viele Scans im Transaktionskoordinator möglich sind. Wenn keine Anzahl für lokale Scandatensätze vorgegeben ist, wird sie als MaxNoOfConcurrentScans mal der Anzahl der Datenknoten im System berechnet.

  • MaxNoOfLocalScans

    Gibt die Anzahl der lokalen Scandatensätze an, wenn viele Scans nicht vollständig parallelisiert sind.

  • BatchSizePerLocalScan

    Dieser Parameter wird genutzt, um zu berechnen, wie viele Sperrdatensätze erforderlich sind, um viele nebenläufige Scanoperationen zu handhaben.

    Der Standardwert beträgt 64; dieser Wert steht in enger Verbindung zur in den SQL-Knoten definierten ScanBatchSize.

  • LongMessageBuffer

    Dies ist ein interner Puffer für die Weitergabe von Nachrichten in oder zwischen Knoten. Der Wert muss zwar wahrscheinlich nie geändert werden, ist aber dennoch konfigurierbar. Sein Standardwert beträgt 1 Mbyte.

Logging und Checkpointing

Die folgenden [NDBD]-Paramater steuern das Verhalten in Bezug auf Logs und Checkpoints.

  • NoOfFragmentLogFiles

    Dieser Parameter stellt die Größe der REDO-Logdateien des Knotens ein. REDO-Logdateien sind ringförmig organisiert, wobei es außerordentlich wichtig ist, dass die erste und die letzte Logdatei (auch „Head“ und „Tail“ genannt) nicht aufeinander treffen. Wenn sich diese beiden zu stark annähern, fängt der Knoten an, alle Transaktionen abzubrechen, in denen Updates vorkommen, da kein Platz für neue Logeinträge mehr vorhanden ist.

    Ein REDO-Logeintrag wird erst gelöscht, wenn seit seiner Einfügung drei lokale Checkpoints erreicht wurden. Die Häufigkeit der Checkpoints wird durch eigene Konfigurationsparameter festgelegt, die an anderer Stelle in diesem Kapitel beschrieben werden.

    Der Standardparameterwert beträgt 8, also 8 mal 4 16-Mbyte-Dateien oder insgesamt 512 Mbyte. Mit anderen Worten: Der Speicher für die REDO-Logs muss in Blöcken zu 64 Mbyte zugewiesen werden. In Szenarien, in denen viele Updates erforderlich sind, kann es erforderlich werden, den Wert von NoOfFragmentLogFiles sogar auf 300 oder noch mehr zu setzen, um genügend Platz für die REDO-Logs zu schaffen.

    Wenn das Checkpointing zu langsam läuft und so viele Schreibvorgänge in der Datenbank stattfinden, dass die Logdateien voll laufen und der Logtail nicht abgetrennt werden kann, ohne die Wiederherstellung zu gefährden, können Änderungstransaktionen mit dem internen Fehlercode 410 (Out of log file space temporarily) abgebrochen werden. Dies dauert so lange, bis ein Checkpoint abgeschlossen ist und der Logtail vorrücken kann.

  • MaxNoOfSavedMessages

    Dieser Parameter stellt ein, wie viele Trace-Dateien maximal gespeichert werden, ehe die alten überschrieben werden. Trace-Dateien werden angelegt, wenn der Knoten aus irgendeinem Grund abstürzt.

    Der Standardwert sind 25 Trace-Dateien.

Metadatenobjekte

Die folgenden [NDBD]-Parameter legen die Größen der Pools für Metadatenobjekte fest, also wie viele Attribute, Tabellen, Indizes und Trigger-Objekte maximal für die Indizes, Ereignisse und Replikation zwischen Clustern zur Verfügung stehen. Beachten Sie, dass diese Werte lediglich „Richtwerte“ für den Cluster sind. Werden sie nicht gesetzt, so treten die unten angegebenen Standardwerte in Kraft.

  • MaxNoOfAttributes

    Gibt an, wie viele Attribute im Cluster definiert werden können.

    Der Standardwert beträgt 1.000 und der kleinstmögliche Wert 32. Einen Höchstwert gibt es nicht. Jedes Attribut belegt rund 200 Byte Speicherplatz pro Knoten, da alle Metadaten vollständig auf den Servern repliziert werden.

    Bei der Einstellung von MaxNoOfAttributes müssen Sie sich schon im Voraus klar machen, wie viele ALTER TABLE-Anweisungen Sie wohl in Zukunft ausführen möchten. Denn wenn Sie ALTER TABLE auf einer Cluster-Tabelle ausführen, werden dreimal so viele Attribute wie in der Originaltabelle verwendet. Wenn eine Tabelle beispielsweise 100 Attribute benötigt und Sie in der Lage sein möchten, diese Tabelle später noch zu ändern, müssen Sie den Wert von MaxNoOfAttributes auf 300 setzen. Wenn wir voraussetzen, dass Sie alle gewünschten Tabellen ohne irgendwelche Probleme anlegen können, sollten Sie MaxNoOfAttributes sicherheitshalber doppelt so viele Attribute hinzufügen, wie die größte Tabelle besitzt. Außerdem sollten Sie nach der Konfiguration des Parameters mit einem echten ALTER TABLE prüfen, ob diese Zahl ausreicht. Wenn die Anweisung scheitert, müssen Sie MaxNoOfAttributes um ein anderes Vielfaches des ursprünglichen Werts erhöhen und erneut testen.

  • MaxNoOfTables

    Für jede Tabelle, jeden eindeutigen Hash-Index und jeden geordneten Index wird ein Tabellenobjekt zugewiesen. Dieser Parameter stellt ein, wie viele Tabellenobjekte der Cluster insgesamt maximal haben kann.

    Für jedes Attribut vom Typ BLOB wird eine zusätzliche Tabelle verwendet, um einen Großteil der BLOB-Daten zu speichern. Auch diese Tabellen müssen beim Festlegen der Gesamtzahl der Tabellen berücksichtigt werden.

    Dieser Parameter ist standardmäßig auf 128 eingestellt. Sein Mindestwert beträgt 8 und sein Höchstwert 1600. Jedes Tabellenobjekt belegt rund 20 Kbyte pro Knoten.

  • MaxNoOfOrderedIndexes

    Für jeden geordneten Index im Cluster wird ein Objekt zugewiesen, das beschreibt, was hier indiziert wird und in welchen Speichersegmenten. Nach Voreinstellung ist jeder so definierte Index ein geordneter Index. Jeder eindeutige Index und jeder Primärschlüssel besitzt sowohl einen geordneten als auch einen Hash-Index.

    Dieser Parameter hat den Standardwert 128. Jedes Objekt belegt ungefähr 10 Kbyte pro Knoten.

  • MaxNoOfUniqueHashIndexes

    Für jeden eindeutigen Index, der kein Primärschlüssel ist, wird eine spezielle Tabelle zugewiesen, die den eindeutigen Schlüssel auf den Primärschlüssel der indizierten Tabelle abbildet. Nach Voreinstellung wird außerdem für jeden eindeutigen Index ein geordneter Index definiert. Wenn Sie dies verhindern möchten, müssen Sie beim Definieren des eindeutigen Indexes die Option USING HASH angeben.

    Der Standardwert ist 64. Jeder Index belegt ungefähr 15 Kbyte pro Knoten.

  • MaxNoOfTriggers

    Für jeden eindeutigen Hash-Index werden interne Update-, Insert- und Delete-Trigger zugewiesen. (Das bedeutet, dass für jeden solchen Index drei Trigger erzeugt werden.) Ein geordneter Index erfordert dagegen nur ein einziges Trigger-Objekt. Auch Datensicherungen benötigen drei Trigger-Objekte für jede normale Tabelle im Cluster.

    Hinweis: Wenn Replikation zwischen Clustern unterstützt wird, sind auch dafür interne Trigger erforderlich.

    Dieser Parameter stellt die Höchstzahl der Trigger-Objekte im Cluster ein.

    Der Standardwert ist 768.

  • MaxNoOfIndexes

    Dieser Parameter ist in MySQL 5.1 veraltet. Bitte verwenden Sie stattdessen MaxNoOfOrderedIndexes und MaxNoOfUniqueHashIndexes.

    Dieser Parameter wird nur von eindeutigen Hash-Indizes verwendet. Für jeden derartigen Index, der im Cluster definiert ist, muss ein Datensatz in diesem Pool vorhanden sein.

    Der Standardwert dieses Parameters ist 128.

Boolesche Parameter

Das Verhalten der Datenknoten hängt auch von einigen booleschen [NDBD]-Parametern ab. Um diese Parameter auf TRUE einzustellen, setzen Sie sie auf 1 oder Y, und um sie auf FALSE einzustellen, setzen Sie sie auf 0 oder N.

  • LockPagesInMainMemory

    Viele Betriebssysteme, darunter auch Solaris und Linux, können einen Prozess im Arbeitsspeicher sperren und dadurch verhindern, dass er auf die Festplatte schreibt. Das kann dabei helfen, die Echtzeitfähigkeiten eines Clusters zu bewahren.

    Dieses Feature ist nach Voreinstellung deaktiviert.

  • StopOnError

    Dieser Parameter zeigt an, ob ein ndbd-Prozess anhalten oder automatisch neu starten soll, wenn eine Fehlerbedingung auftritt.

    Dieses Feature ist nach Voreinstellung aktiviert.

  • Diskless

    Wenn Tabellen im MySQL Cluster als diskless definiert werden, werden für sie weder Checkpoints auf der Festplatte noch Logeinträge erstellt. Solche Tabellen existieren nur im Hauptspeicher. Infolgedessen überleben weder die Tabellen selbst noch die in ihnen enthaltenen Datensätze einen Absturz. Allerdings können Sie im Diskless-Modus ndbd auch auf einem Computer ohne Festplatte ausführen.

    Wichtig: Dieses Feature lässt den gesamten Cluster im Diskless-Modus laufen.

    Wenn dieses Feature aktiviert ist, werden zwar Datensicherungen ausgeführt, aber keine wirklichen Sicherungsdaten gespeichert.

    Diskless ist nach Voreinstellung deaktiviert.

  • RestartOnErrorInsert

    Dieses Feature ist nur beim Bauen der Debugversion zugänglich, wo es möglich ist, zu Testzwecken Fehler in die Ausführung einzelner Codeblöcke einzubauen.

    Dieses Feature ist nach Voreinstellung deaktiviert.

Timeouts, Intervalle und Auslagerung von Daten auf die Festplatte

Mehrere [NDBD]-Parameter stehen zur Verfügung, um Timeouts und Intervalle zwischen verschiedenen Aktionen in Cluster-Datenknoten festzulegen. Die Timeout-Werte werden, sofern nicht explizit etwas anderes gesagt wird, in Millisekunden angegeben.

  • TimeBetweenWatchDogCheck

    Damit der Haupt-Thread nicht in einer Endlosschleife gefangen bleiben kann, wird er durch einen so genannten „Wachhund“ (engl. Watchdog) überprüft. Dieser Parameter gibt an, wie viele Millisekunden zwischen den Prüfungen verstreichen. Wenn der Prozess nach drei Prüfungen immer noch in demselben Zustand verharrt, wird er vom Watchdog-Thread beendet.

    Dieser Parameter lässt sich leicht ändern, sei es zu experimentellen Zwecken oder um ihn an die lokalen Bedingungen anzupassen. Er kann auch für jeden Knoten separat gesetzt werden, wofür es allerdings keinen vernünftigen Grund gibt.

    Der Standard-Timeout-Wert beträgt 4.000 Millisekunden (4 Sekunden).

  • StartPartialTimeout

    Dieser Parameter legt fest, wie lange der Cluster auf das Hochfahren aller Speicherknoten wartet, bevor die Initialisierungsroutine für den Cluster aufgerufen wird. Dieser Timeout-Wert soll nach Möglichkeit verhindern, dass ein Cluster nur teilweise hochgefahren wird.

    Der Standardwert beträgt 30.000 Millisekunden (30 Sekunden). Mit 0 wird der Timeout ausgeschaltet, sodass der Cluster nur starten kann, wenn alle Knoten zur Verfügung stehen.

  • StartPartitionedTimeout

    Wenn der Cluster nach dem Abwarten von StartPartialTimeout Millisekunden startbereit ist, sich aber möglicherweise immer noch in einem partitionierten Zustand befindet, wartet er ab, bis auch dieser Timeout verstrichen ist.

    Der Standardwert für diesen Timeout beträgt 60.000 Millisekunden (60 Sekunden).

  • StartFailureTimeout

    Wenn ein Datenknoten seine Startsequenz in der durch diesen Parameter gesetzten Zeit nicht abgeschlossen hat, scheitert sein Start. Wenn Sie den Parameter auf 0 setzen, gibt es keinen Timeout für den Datenknoten.

    Der Standardwert beträgt 60.000 Millisekunden (60 Sekunden). Für Datenknoten mit extrem großen Datenmengen sollten Sie diesen Parameter heraufsetzen. Wenn ein Speicherknoten beispielsweise mehrere Gigabytes an Daten enthält, könnten sogar 10 bis 15 Minuten (600.000 bis 1.000.000 Millisekunden) für einen Neustart des Knotens erforderlich sein.

  • HeartbeatIntervalDbDb

    Heartbeats (Herzschläge) sind eines der wichtigsten Mittel, um herauszufinden, ob Knoten abgestürzt sind. Dieser Parameter zeigt an, wie oft Heartbeat-Signale gesandt und empfangen werden sollten. Wenn drei aufeinander folgende Heartbeats ausgefallen sind, wird der Knoten für tot erklärt. Also beträgt die maximale Zeitspanne für die Entdeckung eines Scheiterns mit dem Heartbeat-Mechanismus das Vierfache des Heartbeat-Intervalls.

    Das Standardintervall für Heartbeats dauert 1.500 Millisekunden (1,5 Sekunden). Dieser Parameter darf nicht drastisch verändert werden und sollte für alle Knoten ähnlich eingestellt werden. Wenn ein Knoten 5.000-Millisekunden-Intervalle und der beobachtende Knoten 1.000 Millisekunden verwendet, wird der mit den längeren Intervallen natürlich sehr schnell für tot erklärt. Dieser Parameter kann während eines Online-Softwareupgrades geändert werden, allerdings nur in kleinen Inkrementen.

  • HeartbeatIntervalDbApi

    Jeder Datenknoten sendet Heartbeat-Signale an jeden MySQL Server (SQL-Knoten), um sich zu vergewissern, dass der Kontakt noch besteht. Wenn ein MySQL Server seinen Heartbeat nicht rechtzeitig absendet, wird er als „tot“ erklärt und alle seine laufenden Transaktionen werden beendet und seine Ressourcen freigegeben. Ein SQL-Knoten kann sich erst wieder verbinden, wenn alle von der vorherigen MySQL-Instanz angestoßenen Aktivitäten abgeschlossen wurden. Es gilt dasselbe Kriterium der drei Heartbeats wie unter HeartbeatIntervalDbDb beschrieben.

    Das Standardintervall beträgt 1.500 Millisekunden (1,5 Sekunden). Dieses Intervall kann zwischen einzelnen Datenknoten variieren, da jeder Speicherknoten die mit ihm verbundenen MySQL Server unabhängig von allen anderen Datenknoten beobachtet.

  • TimeBetweenLocalCheckpoints

    Dieser Parameter ist insofern eine Ausnahmeerscheinung, als er nicht eine Wartezeit vor dem Starten eines neuen lokalen Checkpoints angibt, sondern gewährleisten soll, dass keine lokalen Checkpoints in einem Cluster ausgeführt werden, in dem nur relativ wenige Updates auftreten. In den meisten Clustern mit hohen Update-Raten wird ein neuer lokaler Checkpoint normalerweise unmittelbar nach Abschluss des vorherigen gestartet.

    Der Umfang aller seit dem Start des vorherigen lokalen Checkpoints ausgeführten Schreiboperationen wird addiert. Dieser Parameter ist ebenfalls außergewöhnlich, da er als Basis-2-Logarithmus der Anzahl der 4-Byte-Wörter spezifiziert ist. Der Standardwert von 20 bedeutet also Schreiboperationen im Umfang von 4 Mbyte (4 × 220), 21 würde 8 Mbyte bedeuten, und so weiter bis zum Maximalwert 31, der 8 Gbyte Schreiboperationen entsprechen würde.

    Alle Schreiboperationen im Cluster werden addiert. Wenn TimeBetweenLocalCheckpoints auf 6 oder weniger gesetzt wird, bedeutet dies, dass pausenlos lokale Checkpoints ausgeführt werden, unabhängig von der Arbeitslast des Clusters.

  • TimeBetweenGlobalCheckpoints

    Wenn eine Transaktion committet wird, dann im Hauptspeicher in allen Knoten, auf denen die Daten gespiegelt werden. Doch die Transaktionslog-Einträge werden durch den Commit-Befehl nicht auf die Platte zurückgeschrieben. Denn wenn die Transaktion auf mindestens zwei autonomen Hostcomputern sicher committet wurde, müsste dies ausreichen, um die Haltbarkeit der Daten zu gewährleisten.

    Wichtig ist außerdem, dass das System auch im schlimmsten Fall, nämlich dem Absturz eines kompletten Clusters, die Oberhand behält. Um das zu gewährleisten, werden alle Transaktionen, die in einem gegebenen Zeitraum stattfinden, in einen globalen Checkpoint geladen. Diesen kann man sich als eine Menge von committeten und auf die Festplatte geschriebenen Transaktionen vorstellen. Mit anderen Worten: Transaktionen werden im Rahmen des Commit-Prozesses in eine globale Checkpoint-Gruppe gelegt. Später werden die Logeinträge dieser Gruppe auf die Festplatte zurückgeschrieben und die gesamte Transaktionsgruppe auf allen Computern im Cluster sicher auf die Festplatte geschrieben.

    Dieser Parameter legt das Zeitintervall zwischen den globalen Checkpoints fest. Der Standardwert beträgt 2.000 Millisekunden.

  • TimeBetweenInactiveTransactionAbortCheck

    Um Timeouts zu behandeln, wird für jede Transaktion einmal pro in diesem Parameter angegebenem Intervall ein Timer nachgeschaut. Wenn also dieser Parameter auf 1.000 Millisekunden gesetzt ist, wird einmal pro Sekunde jede Transaktion auf einen Timeout überprüft.

    Der Standardwert beträgt 1.000 Millisekunden (1 Sekunde).

  • TransactionInactiveTimeout

    Dieser Parameter gibt an, wie viel Zeit maximal zwischen zwei Operationen einer Transaktion verstreichen darf, ehe die Transaktion abgebrochen wird.

    Der Standardwert dieses Parameters ist null (kein Timeout). Für eine Echtzeitdatenbank, die gewährleisten muss, dass keine Transaktion irgendwelche Sperren zu lange aufrechterhält, sollte dieser Parameter auf einen sehr kleinen Wert gesetzt werden. Die Maßeinheit sind Millisekunden.

  • TransactionDeadlockDetectionTimeout

    Wenn ein Knoten eine Abfrage ausführt, zu der eine Transaktion gehört, wartet er auf Antwort von den anderen Knoten des Clusters, ehe er fortfährt. Bleibt eine Antwort aus, kann das folgende Gründe haben:

    • Der Knoten ist „tot“.

    • Die Operation steckt in einer Warteschlange von Sperranforderungen.

    • Der Knoten, der die Aktion ausführen sollte, könnte heftig überlastet sein.

    Dieser Timeout-Parameter legt fest, wie lange der Transaktionskoordinator darauf wartet, dass ein anderer Knoten die Anfrage ausführt, ehe er die Transaktion abbricht. Er ist wichtig, um den Absturz eines Knotens behandeln oder Deadlocks feststellen zu können. Wenn Sie ihn zu hoch setzen, können Situationen mit gescheiterten Knoten oder Deadlocks unangenehme Konsequenzen haben.

    Der Standardwert für den Timeout beträgt 1.200 Millisekunden (1,2 Sekunden).

  • NoOfDiskPagesToDiskAfterRestartTUP

    Wenn ein lokaler Checkpoint ausgeführt wird, schreibt der Algorithmus alle Datenseiten auf die Festplatte zurück. Wenn Sie dies aber einfach ohne irgendwelche Moderation so rasch wie möglich tun, riskieren Sie eine Überlastung von Prozessoren, Netzwerken und Platten. Um die Schreibgeschwindigkeit zu steuern, gibt dieser Parameter an, wie viele Seiten pro 100 Millisekunden geschrieben werden dürfen. In diesem Zusammenhang ist eine „Seite“ als 8 Kbyte definiert. Dieser Parameter wird in Einheiten von 80 Kbyte pro Sekunde angegeben; wenn Sie also NoOfDiskPagesToDiskAfterRestartTUP auf den Wert 20 setzen, werden bei einem lokalen Checkpoint 1,6 Mbyte an Datenseiten pro Sekunde auf die Platte geschrieben. Dieser Wert umfasst auch die Erstellung der UNDO-Logs für die Datenseiten. Folglich setzt dieser Parameter die Obergrenze für Schreibvorgänge aus dem Data Memory. Für die UNDO-Logeinträge für Indexseiten ist der Parameter NoOfDiskPagesToDiskAfterRestartACC da. (Mehr über Indexseiten können Sie im Eintrag IndexMemory nachlesen.)

    Kurz: Dieser Parameter gibt an, wie schnell lokale Checkpoints ausgeführt werden. Er arbeitet zusammen mit NoOfFragmentLogFiles, DataMemory und IndexMemory.

    Der Standardwert ist 40 (3,2 Mbyte Datenseiten pro Sekunde).

  • NoOfDiskPagesToDiskAfterRestartACC

    Dieser Parameter verwendet dieselbe Maßeinheit wie NoOfDiskPagesToDiskAfterRestartTUP und verhält sich auch ganz ähnlich, setzt jedoch die Obergrenze für das Schreiben von Indexseiten aus dem Index Memory.

    Der Standardwert dieses Parameters beträgt 20 (1,6 Mbyte Index Memory pro Sekunde).

  • NoOfDiskPagesToDiskDuringRestartTUP

    Dieser Parameter funktioniert ähnlich wie NoOfDiskPagesToDiskAfterRestartTUP und NoOfDiskPagesToDiskAfterRestartACC, allerdings im Hinblick auf lokale Checkpoints, die in einem Knoten bei dessen Neustart ausgeführt werden. Ein lokaler Checkpoint wird immer bei jeglichem Neustart eines Knotens ausgeführt. Während eines Knoten-Neustarts können Daten schneller als in anderen Situationen auf die Platte geschrieben werden, da zu diesem Zeitpunkt im Knoten noch weniger andere Aktivitäten stattfinden.

    Dieser Parameter bezieht sich auf die Seiten, die aus dem Data Memory geschrieben werden.

    Der Standardwert beträgt 40 (3,2 Mbyte pro Sekunde).

  • NoOfDiskPagesToDiskDuringRestartACC

    Gibt an, wie viele Seiten des Index Memorys während des lokalen Checkpointings beim Neustart eines Knotens auf die Festplatte geschrieben werden können.

    Wie bei NoOfDiskPagesToDiskAfterRestartTUP und NoOfDiskPagesToDiskAfterRestartACC werden auch für diesen Parameter die Werte als 8-Kbyte-Seiten angegeben, die pro 100 Millisekunden geschrieben werden (80 Kbyte/Sekunde).

    Der Standardwert beträgt 20 (1,6 Mbyte pro Sekunde).

  • ArbitrationTimeout

    Dieser Parameter legt fest, wie lange Datenknoten darauf warten sollen, dass der Arbitrator auf eine Arbitration-Nachricht antwortet. Wird dieser Wert überschritten, kann man davon ausgehen, dass sich das Netzwerk aufgespalten hat.

    Der Standardwert beträgt 1000 Millisekunden (1 Sekunde).

Buffering und Logging

Es stehen auch mehrere [NDBD]-Konfigurationsparameter zur Verfügung, die den früheren Compile-Time-Parametern entsprechen. Mit ihnen kann der fortgeschrittene Anwender die von Knotenprozessen genutzten Ressourcen besser steuern und diverse Puffergrößen seinen Bedürfnissen anpassen.

Diese Puffer werden als Frontends für das Dateisystem verwendet, wenn Logeinträge auf die Platte geschrieben werden. Wenn der Knoten im Diskless-Modus läuft, können diese Parameter ungestraft auf ihre Mindestwerte gesetzt werden, da die Dateisystem-Abstraktionsschicht der Speicher-Engine NDB das Schreiben auf der Festplatte „vorgaukelt“.

  • UndoIndexBuffer

    Der UNDO-Indexpuffer, dessen Größe mit diesem Parameter eingestellt wird, wird während eines lokalen Checkpoints benutzt. Das Recovery-Schema der Speicher-Engine NDB beruht auf der Konsistenz der Checkpoints und einem funktionierenden REDO-Log. Um einen konsistenten Checkpoint zu erhalten, ohne gleich sämtliche Schreibvorgänge im System zu blockieren, ist während der Erstellung des lokalen Checkpoints das UNDO-Logging eingeschaltet. UNDO-Logging wird immer nur auf einem einzigen Tabellenfragment eingeschaltet. Diese Optimierung ist möglich, da die Tabellen vollständig im Hauptspeicher liegen.

    Der UNDO-Indexpuffer wird für die Änderungen am Primärschlüssel-Hash-Index benutzt. Einfügungen und Löschungen führen zu Umstellungen im Hash-Index. Die Speicher-Engine NDB schreibt UNDO-Logeinträge, die alle physikalischen Änderungen einer Indexseite zuordnen, sodass sie beim Systemstart rückgängig gemacht werden können. Außerdem protokolliert sie zu Beginn eines lokalen Checkpoints alle aktiven Einfügeoperationen für jedes Fragment.

    Lese- und Änderungsoperationen setzen Sperrbits und aktualisieren einen Header im Hash-Indexeintrag. Diese Änderungen behandelt der Page-Writing-Algorithmus so, dass sichergestellt ist, dass diese Operationen kein UNDO-Logging benötigen.

    Dieser Puffer ist nach Voreinstellung auf 2 Mbyte gesetzt. Sein Mindestwert 1 Mbyte dürfte für die meisten Anwendungen ausreichen. Für Anwendungen, die besonders große oder zahlreiche Einfüge- und Löschoperationen in Verbindung mit großen Transaktionen und umfangreichen Primärschlüsseln vornehmen, kann es erforderlich sein, diesen Puffer zu vergrößern. Wenn er zu klein ist, meldet die Speicher-Engine NDB den internen Fehlercode 677 (Index UNDO buffers overloaded).

  • UndoDataBuffer

    Dieser Parameter stellt die Größe des UNDO-Datenpuffers ein, der ähnlich wie der UNDO-Indexpuffer funktioniert, aber für das Data Memory statt des Index Memorys verwendet wird. Dieser Puffer wird in der lokalen Checkpoint-Phase eines Fragments für Einfüge-, Lösch- und Änderungsoperationen benötigt.

    Da UNDO-Logeinträge immer größer werden, je mehr Operationen protokolliert werden, ist auch dieser Puffer größer als sein Gegenstück für das Index Memory, nämlich nach Voreinstellung 16 Mbyte.

    Dieser Speicher kann für manche Anwendungen unnötig groß sein. In solchen Fällen können Sie den Wert bis auf das Minimum von 1 Mbyte heruntersetzen.

    Es ist nur selten erforderlich, diesen Puffer zu vergrößern. Wenn es dennoch einmal getan werden muss, so sollten Sie vorher prüfen, ob Ihre Festplatten die Last der Updates in der Datenbank überhaupt bewältigen können. Wenn nicht genügend Platz auf der Festplatte vorhanden ist, können Sie dies auch durch das Vergrößern dieses Puffers nicht ändern.

    Wenn dieser Puffer zu klein ist und verstopft, meldet die Speicher-Engine NDB den internen Fehlercode 891 (Data UNDO buffers overloaded).

  • RedoBuffer

    Auch alle Update-Aktivitäten müssen protokolliert werden. Das REDO-Log ermöglicht es, die Updates bei einem späteren Neustart des Systems erneut laufen zu lassen. Der Recovery-Algorithmus von NDB verwendet einen „Fuzzy“-Checkpoint der Daten in Verbindung mit dem UNDO-Log und wendet dann das REDO-Log an, um alle Änderungen bis zum Wiederherstellungspunkt erneut aufzuspielen.

    RedoBuffer stellt die Größe des Puffers ein, in den das REDO-Log geschrieben wird, und hat den Standardwert 8 Mbyte. Sein Mindestwert beträgt 1 Mbyte.

    Ist dieser Puffer zu klein, meldet die Speicher-Engine NDB den Fehlercode 1221 (REDO log buffers overloaded).

Für das Cluster-Management ist es sehr wichtig, die Anzahl der Logmeldungen steuern zu können, die für verschiedene Ereignistypen an stdout gesandt werden. Für jede Art von Ereignis gibt es 16 mögliche Berichtsebenen (mit den Nummern 0 bis 15). Wird die Berichtsebene für eine gegebene Ereigniskategorie auf 15 gesetzt, so bedeutet dies, dass alle Ereignisberichte dieser Kategorie an stdout geschickt werden; wird es auf 0 gesetzt, so werden in dieser Kategorie keine Ereignisse gemeldet.

Nach Voreinstellung wird nur die Startnachricht an stdout geschickt, während die übrigen Ereignisberichtsebenen auf 0 gesetzt sind. Der Grund: Diese Meldungen werden auch an das Cluster-Log des Management-Servers geschickt.

Dieselben Ebenen können Sie auch für den Management-Client einstellen, um festzulegen, welche Ereignisebenen im Cluster-Log protokolliert werden.

  • LogLevelStartup

    Die Berichtsebene für Ereignisse, die beim Starten des Prozesses eintreten.

    Die Standardebene ist 1.

  • LogLevelShutdown

    Die Berichtsebene für Ereignisse, die beim sanften Herunterfahren eines Knotens gemeldet werden.

    Die Standardebene ist 0.

  • LogLevelStatistic

    Die Berichtsebene für statistische Ereignisse wie beispielsweise die Anzahl der Lesevorgänge auf Primärschlüsseln, die Anzahl der Änderungen oder Einfügungen, Informationen über die Pufferausnutzung und so weiter.

    Die Standardebene ist 0.

  • LogLevelCheckpoint

    Die Berichtsebene für Ereignisse, die bei lokalen und globalen Checkpoints generiert werden.

    Die Standardebene ist 0.

  • LogLevelNodeRestart

    Die Berichtsebene für Ereignisse, die beim Neustart eines Knotens generiert werden.

    Die Standardebene ist 0.

  • LogLevelConnection

    Die Berichtsebene für Ereignisse, die von Verbindungen zwischen Cluster-Knoten generiert werden.

    Die Standardebene ist 0.

  • LogLevelError

    Die Berichtsebene für Ereignisse, die von Fehlern und Warnungen vom Cluster insgesamt generiert werden. Diese Fehler bringen zwar nicht gleich einen Knoten zum Absturz, sind es aber dennoch wert, gemeldet zu werden.

    Die Standardebene ist 0.

  • LogLevelInfo

    Die Berichtsebene für Ereignisse, die zur Information über den Allgemeinzustand des Clusters generiert werden.

    Die Standardebene ist 0.

Sicherungsparameter

In diesem Abschnitt geht es um [NDBD]-Parameter zur Definition von Speicherpuffern für die Ausführung von Online-Sicherungen.

  • BackupDataBufferSize

    Bei der Erstellung einer Datensicherung werden zwei Puffer verwendet, um die Daten auf die Festplatte zu schreiben: Der Puffer für Sicherungsdaten (Backup Data-Puffer) nimmt Daten auf, die beim Scannen der Tabellen eines Knotens aufgezeichnet wurden. Wenn dieser Puffer bis zu dem in BackupWriteSize (siehe unten) angegebenen Stand gefüllt ist, werden die Seiten auf die Festplatte geschrieben. Während Daten auf die Platte zurückgeschrieben werden, kann der Datensicherungsprozess weiter diesen Puffer mit Daten füllen, bis ihm der Platz ausgeht. Wenn dies geschieht, macht der Sicherungsprozess eine Pause mit seinen Scans, bis einige Schreibvorgänge auf der Platte so weit abgeschlossen sind, dass Speicher freigegeben wurde und das Scannen fortgesetzt werden kann.

    Der Standardwert ist 2 Mbyte.

  • BackupLogBufferSize

    Der Backup Log-Puffer spielt eine ähnliche Rolle wie der Backup Data-Puffer, wird jedoch verwendet, um ein Log aller während einer Datensicherung ausgeführten Schreibvorgänge auf Tabellen zu generieren. Diese Seiten werden nach demselben Prinzip wie bei der Datensicherung „Datenpuffer“ geschrieben, nur dass hier die Sicherung scheitert, wenn der Platz im Backup Log-Puffer ausgeht. Aus diesem Grund muss der Backup Log-Puffer unbedingt groß genug sein, um die von Schreibaktivitäten während der Datensicherung verursachte Belastung aushalten zu können. Siehe auch Abschnitt 16.6.5.4, „Konfiguration für Cluster-Backup“.

    Der Standardwert dieses Parameters müsste für die meisten Anwendungen ausreichen. Eine Sicherung scheitert eher schon einmal durch zu langsame Schreibvorgänge auf der Platte als durch einen vollen Backup Log-Puffer. Wenn das Festplatten-Teilsystem für die Last der von Anwendungen verursachten Schreibvorgänge unzureichend konfiguriert ist, kann auch der Cluster die gewünschten Operationen nicht ausführen.

    Cluster-Knoten sollten so konfiguriert werden, dass der Engpass eher im Prozessor liegt als in den Festplatten oder Netzwerkverbindungen.

    Der Standardwert ist 2 Mbyte.

  • BackupMemory

    Dieser Parameter ist einfach die Summe von BackupDataBufferSize und BackupLogBufferSize.

    Der Standardwert ist 2 Mbyte + 2 Mbyte = 4 Mbyte.

  • BackupWriteSize

    Dieser Parameter spezifiziert die Größe der Meldungen, die von den Backup Log- und Backup Data-Puffern auf die Festplatte geschrieben werden.

    Der Standardwert ist 32 Kbyte.

16.4.4.6. Festlegung von SQL-Nodes in einem MySQL Cluster

Die [MYSQLD]-Abschnitte in der config.ini-Datei definieren das Verhalten der MySQL Server (SQL-Knoten), die für den Zugriff auf Cluster-Daten eingesetzt werden. Keiner dieser Parameter ist obligatorisch. Wenn kein Computer- oder Hostname angegeben ist, kann jeder Host diesen SQL-Knoten benutzen.

  • Id

    Der Wert Id wird verwendet, um den Knoten in allen Cluster-internen Nachrichten zu identifizieren. Es ist ein Integer zwischen 1 und 63 einschließlich, der unter allen Knoten-IDs im Cluster einzigartig sein muss.

  • ExecuteOnComputer

    Bezieht sich auf einen der Computer (Hosts), die in einem [COMPUTER]-Abschnitt der Konfigurationsdatei genannt sind.

  • ArbitrationRank

    Dieser Parameter gibt an, welche Knoten als Arbitrator fungieren können. Sowohl MGM- als auch SQL-Knoten können Arbitrator sein. Der Wert 0 bedeutet, dass der betreffende Knoten nie Arbitrator sein kann, 1 gibt ihm die höchste Priorität als Arbitrator und 2 verleiht ihm eine niedrige Priorität. In einer normalen Konfiguration wird der Management-Server als Arbitrator eingesetzt, indem sein ArbitrationRank auf 1 (den Default) und die der SQL-Knoten auf 0 gesetzt werden.

  • ArbitrationDelay

    Wird dieser Parameter auf irgendeinen anderen Wert als 0 (den Standardwert) gesetzt, so werden die Antworten des Arbitrators auf Arbitration-Requests um diese Anzahl Millisekunden verzögert. Normalerweise ist es nicht nötig, diesen Wert zu ändern.

  • BatchByteSize

    Für Anfragen, die in vollständige Tabellenscans oder Indexbereichsscans übersetzt werden, ist es aus Performancegründen wichtig, die Datensätze in Stapeln (Batches) der richtigen Größe abzuholen. Diese richtige Größe kann man sowohl als eine Anzahl von Datensätzen (BatchSize) als auch in Bytes (BatchByteSize) einstellen. Die tatsächliche Batch-Größe wird von beiden Parametern eingeschränkt.

    Je nachdem, wie dieser Parameter eingestellt ist, kann die Geschwindigkeit von Anfragen um 40 Prozent variieren. In künftigen Releases wird MySQL Server anhand des Anfragetyps fundierte Annahmen über die Batch-Größe treffen.

    Dieser Parameter wird in Bytes angegeben und hat den Standardwert 32 Kbyte.

  • BatchSize

    Dieser Parameter wird als Anzahl von Datensätzen angegeben und ist standardmäßig auf 64 eingestellt. Seine Maximalgröße beträgt 992.

  • MaxScanBatchSize

    Die Batch-Größe ist die Größe jedes Batchs von jedem Datenknoten. Die meisten Scans werden parallel ausgeführt, damit der MySQL Server nicht von vielen Knoten parallel zu viele Daten übermittelt bekommt. Dieser Parameter setzt eine Obergrenze der gesamten Batch-Größe quer über alle Knoten.

    Standardmäßig ist dieser Parameter auf 256 Kbyte eingestellt; seine Maximalgröße beträgt 16 Mbyte.

16.4.4.7. MySQL Cluster: TCP/IP-Verbindungen

TCP/IP ist der Standardtransportmechanismus zur Einrichtung von Verbindungen in MySQL Cluster. Normalerweise ist es nicht nötig, Verbindungen zu definieren, da Cluster automatisch zwischen allen Datenknoten untereinander, zwischen allen Datenknoten und allen MySQL Server-Knoten sowie zwischen allen Datenknoten und dem Management-Server Verbindungen einrichtet. (Die einzige Ausnahme von dieser Regel wird unter Abschnitt 16.4.4.8, „MySQL Cluster: TCP/IP-Verbindungen mittels direkter Verbindungen“, beschrieben.) [TCP]-Abschnitte in der config.ini-Datei definieren explizit TCP/IP-Verbindungen zwischen Knoten im Cluster.

Es ist nur dann notwendig, eine Verbindung zu definieren, wenn die Standardverbindungsparameter außer Kraft gesetzt werden sollen. In diesem Fall müssen mindestens NodeId1, NodeId2 und die zu ändernden Parameter angegeben werden.

Die Standardwerte dieser Parameter können Sie auch ändern, indem Sie sie im [TCP DEFAULT]-Abschnitt setzen.

  • NodeId1, NodeId2

    Um eine Verbindung zwischen zwei Knoten zu identifizieren, müssen ihre Knoten-IDs im [TCP]-Abschnitt der Konfigurationsdatei angegeben werden. Dabei handelt es sich um dieselben eindeutigen Id-Werte für einzelne Knoten, wie in Abschnitt 16.4.4.6, „Festlegung von SQL-Nodes in einem MySQL Cluster“, beschrieben.

  • SendBufferMemory

    TCP-Transporter speichern alle Nachrichten in einem Puffer, ehe sie den Sendeaufruf an das Betriebssystem starten. Wenn dieser Puffer 64 Kbyte erreicht, wird sein Inhalt übersandt; das Gleiche geschieht, wenn eine Runde Nachrichten ausgeführt worden ist. Um mit vorübergehenden Überlastungen umgehen zu können, ist es auch möglich, einen größeren Send-Puffer zu definieren. Seine Standardgröße beträgt 256 Kbyte.

  • SendSignalId

    Um ein Diagramm mit verteilten Nachrichen nachvollziehen zu können, muss jede Nachricht genau identifiziert sein. Wenn dieser Parameter Y ist, werden die Message-IDs über das Netzwerk transportiert. In der Standardeinstellung ist dieses Feature ausgeschaltet.

  • Checksum

    Dieser boolesche Parameter ist standardmäßig deaktiviert. (Um ihn zu aktivieren, setzen Sie ihn auf Y oder 1, um ihn zu deaktivieren, auf N oder 0.) Wird er aktiviert, so werden für alle Nachrichten, ehe sie in den Send-Puffer geladen werden, Prüfsummen berechnet. Dadurch wird gewährleistet, dass die Nachrichten nicht durch den Transportmechanismus oder beim Warten im Send-Puffer geschädigt werden.

  • PortNumber (OBSOLET)

    Dieser Parameter gab früher einmal die Nummer des Ports an, auf dem das System nach Verbindungen anderer Knoten lauschte. Der Parameter sollte nicht mehr benutzt werden.

  • ReceiveBufferMemory

    Gibt die Größe des Puffers zum Empfangen von Daten von dem TCP/IP-Socket an. Es ist kaum jemals erforderlich, den Standardwert von 64 Kbyte zu ändern, es sei denn, um Speicher zu sparen.

16.4.4.8. MySQL Cluster: TCP/IP-Verbindungen mittels direkter Verbindungen

Um einen Cluster mit Direktverbindungen zwischen den Datenknoten einzurichten, müssen Sie explizit die Crossover-IP-Adressen der Datenknoten angeben, die so im [TCP]-Abschnitt der config.ini-Datei des Clusters verbunden werden.

Im folgenden Beispiel planen wir einen Cluster mit mindestens vier Hosts, nämlich einem Management-Server, einem SQL-Knoten und zwei Datenknoten. Der Cluster als Ganzes residiert im Subnetz 172.23.72.* eines LANs. Zusätzlich zu den normalen Netzwerkverbindungen existiert eine Direktverbindung zwischen den beiden Datenknoten über ein standardmäßiges Crossover-Kabel. Die beiden können direkt über IP-Adressen im Adressbereich 1.1.0.* miteinander kommunizieren:

# Management-Server
[NDB_MGMD]
Id=1
HostName=172.23.72.20

# SQL-Knoten
[MYSQLD]
Id=2
HostName=172.23.72.21

# Datenknoten
[NDBD]
Id=3
HostName=172.23.72.22

[NDBD]
Id=4
HostName=172.23.72.23

# TCP/IP-Verbindungen
[TCP]
NodeId1=3
NodeId2=4
HostName1=1.1.0.1
HostName2=1.1.0.2

Direktverbindungen zwischen Datenknoten können die Gesamtleistung des Clusters steigern, da die Datenknoten auf diese Weise ein Ethernet-Gerät wie etwa einen Switch, Hub oder Router umgehen können, was die Latenzzeit im Cluster reduziert. Wichtig: Um von solchen Direktverbindungen zwischen mehr als zwei Datenknoten maximal zu profitieren, benötigen Sie eine Direktverbindung jedes Datenknotens mit jedem anderen Datenknoten derselben Knotengruppe.

16.4.4.9. MySQL Cluster: Shared Memory-Verbindungen

MySQL Cluster versucht, den Shared Memory Transporter zu nutzen und wenn möglich automatisch zu konfigurieren, vor allem, wenn mehrere Knoten gleichzeitig auf demselben CLuster-Host laufen. (In sehr frühen Versionen von MySQL Cluster funktionierten Shared Memory-Segmente nur, wenn die -max-Binärversion mit der Option --with-ndb-shm gebaut wurde.) In den [SHM]-Abschnitten der config.ini-Datei werden Shared Memory-Verbindungen zwischen Knoten im Cluster explizit definiert. Wenn explizit Shared Memory als Verbindungsmethode konfiguriert ist, müssen mindestens auch NodeId1, NodeId2 und ShmKey definiert sein. Alle anderen Parameter müssten mit ihren Standardeinstellungen im Normalfall gut funktionieren.

Wichtig: Die Funktionalität von SHM befindet sich noch im Experimentierstadium. Sie wird offiziell von keinem MySQL-Release bis einschließlich 5.1 unterstützt. Sie müssen also entweder nach eigenem Ermessen oder anhand von Informationen aus unseren kostenlosen Ressourcen (Foren, Mailinglisten) entscheiden, ob dieses Feature in Ihrem speziellen Fall richtig ans Laufen gebracht werden kann.

  • NodeId1, NodeId2

    Um eine Verbindung zwischen zwei Knoten identifizieren zu können, müssen Sie für jeden von ihnen einen Knotenbezeichner verwenden, etwa NodeId1 und NodeId2.

  • ShmKey

    Bei der Einrichtung von Shared Memory-Segmenten wird das für die Kommunikation zu verwendende Segment durch eine Knoten-ID (einen Integer) eindeutig identifiziert. Einen Standardwert gibt es nicht.

  • ShmSize

    Jede SHM-Verbindung hat ein Shared Memory-Segment, in welchem die Nachrichten zwischen den Knoten vom Absender gespeichert und vom Empfänger gelesen werden. Die Größe dieses Segments wird durch ShmSize festgelegt und beträgt nach Voreinstellung 1 Mbyte.

  • SendSignalId

    Um den Pfad einer verteilten Nachricht zurückverfolgen zu können, benötigt jede Nachricht einen eindeutigen Bezeichner. Wird dieser Parameter auf Y gesetzt, werden auch Message-IDs über das Netzwerk transportiert. Nach Voreinstellung ist dieses Feature deaktiviert.

  • Checksum

    Dieser boolesche Parameter ist standardmäßig ausgeschaltet (er kann Y oder N sein). Wird er eingeschaltet, werden für alle Nachrichten Prüfsummen berechnet, ehe sie in den Puffer gelegt werden.

    Dieses Feature verhindert, dass Nachrichten beschädigt werden, während sie im Puffer warten. Außerdem wirkt es als Versicherung gegen Datenkorruption auf dem Transportweg.

16.4.4.10. MySQL Cluster: SCI-Transportverbindungen

In [SCI]-Abschnitten der config.ini-Datei werden explizit SCI (Scalable Coherent Interface)-Verbindungen zwischen Cluster-Knoten definiert. Die Verwendung von SCI Transportern in MySQL Cluster wird nur dann unterstützt, wenn die MySQL-Max-Binaries mit der Option --with-ndb-sci=/your/path/to/SCI gebaut wurden. Der path sollte auf ein Verzeichnis verweisen, das zumindest lib- und include-Verzeichnisse mit SISCI-Bibliotheken und Header-Dateien enthält. (Mehr zum Thema SCI finden Sie unter Abschnitt 16.7, „Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster“.)

Darüber hinaus erfordert SCI spezielle Hardware.

Wir raten Ihnen dringend, SCI Transporter nur für die Kommunikation zwischen ndbd-Prozessen zu verwenden. Beachten Sie bitte auch, dass SCI Transporter dazu führen, dass die ndbd-Prozesse niemals schlafen. Aus diesem Grund sollten SCI Transporter nur auf Computern eingesetzt werden, die mindestens zwei CPUs ausschließlich für ndbd-Prozesse reserviert haben. Es muss mindestens eine CPU pro ndbd-Prozess vorhanden sein, und mindestens eine CPU muss für die Betriebssystemaktivitäten übrig bleiben.

  • NodeId1, NodeId2

    Um eine Verbindung zwischen zwei Knoten genau identifizieren zu können, müssen beide Knoten einen Bezeichner haben, etwa NodeId1 und NodeId2.

  • Host1SciId0

    Die SCI-Knoten-ID für den ersten Cluster-Knoten (den mit der Bezeichnung NodeId1).

  • Host1SciId1

    Man kann SCI Transporter zur Ausfallsicherung zwischen zwei SCI-Karten einsetzen, die dann allerdings separate Netzwerke zwischen den Knoten verwenden sollten. Dieser Parameter definiert die Knoten-ID und die zweite SCI-Karte für den ersten Knoten.

  • Host2SciId0

    Dieser Parameter identifiziert die SCI-Knoten-ID für den zweiten Cluster-Knoten (den mit der Bezeichnung NodeId2).

  • Host2SciId1

    Wenn zur Ausfallsicherung zwei SCI-Karten eingesetzt werden, identifiziert dieser Parameter die zweite SCI-Karte für den zweiten Knoten.

  • SharedBufferSize

    Jeder SCI Transporter hat ein Shared Memory-Segment für die Kommunikation zwischen den Knoten. Für die meisten Anwendungen müsste es ausreichen, die Größe dieses Segments auf dem Standardwert 1 Mbyte zu belassen. Ein kleinerer Wert kann bei vielen parallelen Einfügeoperationen Probleme verursachen; wenn der Shared Buffer zu klein ist, kann überdies der gesamte ndbd-Prozess abstürzen.

  • SendLimit

    Ein kleiner Puffer vor den SCI-Medien speichert Nachrichten, ehe sie über das SCI-Netzwerk verschickt werden. Nach Voreinstellung ist er 8 Kbyte groß. Unsere Benchmarks weisen zwar die beste Performance bei 64 Kbyte aus, aber 16 Kbyte kommen schon bis auf wenige Prozente an diesen Höchstwert heran, und es gibt wenig Anlass, über den Wert von 8 Kbyte hinauszugehen.

  • SendSignalId

    Um eine verteilte Nachricht zurückverfolgen zu können, benötigt jede Nachricht einen eindeutigen Bezeichner. Wird dieser Parameter auf Y gesetzt, werden auch Message-IDs über das Netzwerk transportiert. Nach Voreinstellung ist dieses Feature deaktiviert.

  • Checksum

    Dieser boolesche Parameter ist standardmäßig deaktiviert. Wird Checksum aktiviert, so werden für alle Nachrichten, ehe sie in den Send-Puffer geladen werden, Prüfsummen berechnet. Dadurch wird gewährleistet, dass die Nachrichten nicht durch den Transportmechanismus oder beim Warten im Send-Puffer geschädigt werden.

16.5. Prozessverwaltung in MySQL Cluster

Um die Verwaltung von MySQL Cluster zu verstehen, müssen Sie vier wichtige Prozesse kennen: In den folgenden Abschnitten dieses Kapitels werden wir feststellen, welche Rollen diese Prozesse in einem Cluster spielen, wie sie benutzt werden und welche Startoptionen für sie zur Verfügung stehen:

16.5.1. Verwendung des MySQL Server-Prozesses für MySQL Cluster

mysqld ist der traditionelle MySQL Server-Prozess. Um ihn mit MySQL Cluster zu verwenden, muss mysqld mit Unterstützung für die Speicher-Engine NDB Cluster gebaut werden, wie sie in den -max-Binaries von http://dev.mysql.com/downloads/ bereits vorkompiliert ist. Wenn Sie MySQL von der Quellversion bauen, müssen Sie configure mit der Option --with-ndbcluster aufrufen, um NDB Cluster-Unterstützung zu erhalten.

Wenn die mysqld-Binary mit Cluster-Unterstützung erstellt wurde, ist die Speicher-Engine NDB Cluster nach Voreinstellung immer noch ausgeschaltet. Um sie zu aktivieren, haben Sie zwei Möglichkeiten:

  • Sie können --ndbcluster als Startoption auf der Kommandozeile setzen, wenn Sie mysqld starten.

  • Sie können in den Abschnitt [mysqld] Ihrer my.cnf-Datei eine Zeile mit dem Eintrag ndbcluster einsetzen.

Eine einfache Möglichkeit, zu überprüfen, ob Ihr Server mit der Speicher-Engine NDB Cluster läuft, besteht darin, im MySQL Monitor (mysql) die SHOW ENGINES-Anweisung zu geben. Dann müsste der Wert YES als Support-Wert in der Zeile für NDBCLUSTER stehen. Steht dort ein NO oder ist diese Zeile in der Ausgabe gar nicht vorhanden, so ist Ihre laufende MySQL-Version nicht NDB-fähig. Wenn in dieser Zeile der Wert DISABLED steht, müssen Sie die NDB-Unterstützung in einer der beiden oben beschriebenen Weisen aktivieren.

Um Cluster-Konfigurationsdaten lesen zu können, benötigt der MySQL Server mindestens drei Informationen:

  • die eigene Cluster-Knoten-ID des MySQL Servers

  • den Hostnamen oder die IP-Adresse für den Management-Server (MGM-Knoten)

  • die Nummer des TCP/IP-Ports, auf dem er sich mit dem Management-Server verbinden kann

Da Knoten-IDs dynamisch zugewiesen werden können, müssen sie nicht unbedingt explizit angegeben werden.

Der mysqld-Parameter ndb-connectstring gibt den Verbindungs-String an, entweder auf der Kommandozeile beim Starten von mysqld oder in der Datei my.cnf. Der Verbindungs-String enthält den Hostnamen oder die IP-Adresse, unter der der Management-Server zu erreichen ist, sowie den verwendeten TCP/IP-Port.

Im folgenden Beispiel ist ndb_mgmd.mysql.com der Management-Server-Host und 1186 der Port, auf dem dieser auf Cluster-Nachrichten lauscht:

shell> mysqld --ndb-connectstring=ndb_mgmd.mysql.com:1186

Mehr über Verbindungs-Strings erfahren Sie unter Abschnitt 16.4.4.2, „MySQL Cluster: connectstring.

Mit diesen Informationen wird der MySQL Server zum vollwertigen Mitglied des Clusters. (Manchmal bezeichnen wir einen mysqld-Prozess, der auf diese Weise ausgeführt wird, auch als SQL-Knoten.) Er kennt dann alle Cluster-Datenknoten und ihren Status und wird Verbindungen zu ihnen einrichten. In diesem Fall ist er in der Lage, jeden Datenknoten als Transaktionskoordinator zu benutzen und Knotendaten zu lesen und zu ändern.

16.5.2. ndbd, der Speicher-Engine-Node-Prozess

ndbd ist der Prozess, der alle Tabellendaten behandelt, die mit der Speicher-Engine NDB Cluster gespeichert sind. Dieser Prozess kann einen Speicherknoten auch in die Lage versetzen, verteilte Transaktionen, Knoten-Recovery, Checkpointing auf der Festplatte, Online-Sicherung und ähnliche Aufgaben zu erfüllen.

In einem MySQL Cluster kümmern sich mehrere ndbd-Prozesse gemeinsam um die Behandlung der Daten. Diese Prozesse können auf demselben Computer/Host oder auf verschiedenen Computern ausgeführt werden. Die Beziehungen zwischen Datenknoten und Cluster-Hosts ist komplett konfigurierbar.

ndbd generiert einige Logdateien, die in einem im DataDir-Abschnitt der Konfigurationsdatei config.ini genannten Verzeichnis abgelegt werden. Diese Logdateien sind unten aufgeführt. Beachten Sie, dass node_id der eindeutige Bezeichner des Knotens ist. So ist beispielsweise ndb_2_error.log das Fehlerlog, das der Speicherknoten mit der Knoten-ID 2 generiert.

  • ndb_node_id_error.log ist eine Datei mit Aufzeichnungen aller Crashes, die dem angegebenen ndbd-Prozess begegnet sind. Jeder Datensatz in dieser Datei enthält einen kurzen Fehler-String und eine Referenz auf eine Trace-Datei für den betreffenden Crash. Ein typischer Eintrag könnte folgendermaßen aussehen:

    Date/Time: Saturday 30 July 2004 - 00:20:01
    Type of error: error
    Message: Internal program error (failed ndbrequire)
    Fault ID: 2341
    Problem data: DbtupFixAlloc.cpp
    Object of reference: DBTUP (Line: 173)
    ProgramName: NDB Kernel
    ProcessID: 14909
    TraceFile: ndb_2_trace.log.2
    ***EOM***
    

    Hinweis: Sie müssen immer daran denken, dass der letzte Eintrag in der Fehlerlogdatei nicht unbedingt der neueste ist (das wäre sogar höchst unwahrscheinlich). Eintragungen im Fehlerlog sind nicht chronologisch, sondern spiegeln die Reihenfolge der Trace-Dateien wider, wie sie in der Datei ndb_node_id_trace.log.next (siehe unten) festgelegt ist. Daher werden Fehlerlogeinträge zyklisch und nicht sequenziell überschrieben.

  • ndb_node_id_trace.log.trace_id ist eine Trace-Datei, die genau beschreibt, was unmittelbar vor Eintreten des Fehlers geschah. Diese Information ist nützlich für die Analysen des MySQL Cluster-Entwicklungsteams.

    Sie können konfigurieren, wie viele von diesen Trace-Dateien erzeugt werden, ehe die alten überschrieben werden. trace_id ist eine Zahl, die mit jeder sukzessiven Trace-Datei um eins erhöht wird.

  • Die Datei ndb_node_id_trace.log.next behält im Auge, welche Trace-Datei-Nummer als Nächste zugewiesen wird.

  • Die Datei ndb_node_id_out.log enthält die Datenausgabe des ndbd-Prozesses. Diese Datei wird nur angelegt, wenn ndbd als Daemon gestartet wird.

  • Die Datei ndb_node_id.pid enthält die Prozess-ID des ndbd-Prozesses, wenn dieser als Daemon gestartet wird. Sie fungiert auch als Sperrdatei, damit keine Knoten mit demselben Bezeichner gestartet werden.

  • Die Datei ndb_node_id_signal.log ist nur in Debugversionen von ndbd vorhanden, wo es möglich ist, alle ein- und ausgehenden sowie internen Nachrichten mit ihren Daten im ndbd-Prozess nachzuvollziehen.

Bitte verwenden Sie kein mit NFS gemountetes Verzeichnis, da dies in manchen Umgebungen Probleme verursachen kann, wobei die Sperre auf der .pid-Datei auch nach dem Ende des Prozesses in Kraft bleibt.

Um ndbd starten zu können, ist es unter Umständen notwendig, den Hostnamen des Management-Servers und den Port anzugeben, auf dem er lauscht. Optional können Sie auch die ID des Knotens angeben, den der Prozess benutzen soll.

shell> ndbd --connect-string="nodeid=2;host=ndb_mgmd.mysql.com:1186"

Mehr zu diesem Thema finden Sie unter Abschnitt 16.4.4.2, „MySQL Cluster: connectstring. Abschnitt 16.5.5, „Befehlsoptionen für MySQL Cluster-Prozesse“, beschreibt weitere Optionen für ndbd.

Wenn der ndbd-Prozess startet, werden in Wirklichkeit zwei Prozesse initiiert: Der erste heißt „Engelprozess“ und hat nur die Aufgabe, zu entdecken, wenn die Ausführung des Prozesses beendet ist, und dann den ndbd-Prozess neu zu starten, wenn er so konfiguriert ist. Wenn Sie also versuchen, ndbd mit dem Unix-Befehl kill anzuhalten, müssen Sie beide Prozesse anhalten, und zwar den Engelprozess als ersten. Einen ndbd-Prozess stoppen Sie am besten, indem Sie den Management-Client benutzen, um den Prozess von dort aus anzuhalten.

Der Ausführungsprozess verwendet nur einen einzigen Thread für das Lesen, Schreiben und Scannen der Daten sowie alle anderen Aktivitäten. Dieser Thread ist asynchron implementiert, damit er Tausende von nebenläufigen Aktivitäten leicht bewältigen kann. Zusätzlich überwacht ein Wachhund-Thread diesen Ausführungs-Thread, um sicherzustellen, dass dieser nicht in einer Endlosschleife stecken bleibt. Ein Pool von Threads kümmert sich um die Dateiein- und -ausgaben, wobei jeder Thread für eine geöffnete Datei zuständig ist. Auch die Transporter im ndbd-Prozess können für ihre Transporterverbindungen Threads nutzen. In einem System, das viele Operationen - darunter auch Updates - ausführt, kann der ndbd-Prozess bis zu 2 CPUs mit Beschlag belegen, wenn ihm dies erlaubt ist. Auf einem Mehrprozessorcomputer ist es empfehlenswert, mehrere ndbd-Prozesse für die verschiedenen Knotengruppen zu verwenden.

16.5.3. ndb_mgmd, der Management-Server-Prozess

Der Management-Server ist der Prozess, der die Cluster-Konfigurationsdatei liest und diese Informationen auf alle Knoten im Cluster verteilt, die nach ihnen fragen. Außerdem pflegt er ein Log der Cluster-Aktivitäten. Management-Clients können sich mit dem Management-Server verbinden und den Status des Clusters überprüfen.

Es ist nicht unbedingt erforderlich, beim Start des Management-Servers einen Verbindungs-String anzugeben. Wenn Sie allerdings mehrere Management-Server einsetzen, ist ein solcher String notwendig und jeder Knoten im Cluster muss explizit seine Knoten-ID angeben.

Weitere Informationen über die Verwendung von Verbindungs-Strings finden Sie unter Abschnitt 16.4.4.2, „MySQL Cluster: connectstring. Abschnitt 16.5.5, „Befehlsoptionen für MySQL Cluster-Prozesse“, beschreibt andere Optionen für ndb_mgmd.

Die folgenden Dateien werden von ndb_mgmd in seinem Startverzeichnis angelegt oder benutzt, und sie werden gemäß den Angaben in der Konfigurationsdatei config.ini in das DataDir übernommen. In der nachfolgenden Liste ist node_id der eindeutige Knotenbezeichner.

  • config.ini ist die Konfigurationsdatei für den Cluster insgesamt. Diese Datei wird vom Benutzer angelegt und vom Management-Server gelesen. In Abschnitt 16.4, „MySQL Cluster: Konfiguration“, ist die Einrichtung dieser Datei beschrieben.

  • Das Ereignislog des Clusters ist ndb_node_id_cluster.log. Dort werden Ereignisse festgehalten, die beispielsweise beim Starten und Beenden von Checkpoints, beim Starten von Knoten oder beim Absturz eines Knotens auftreten, und es wird das Ausmaß der Arbeitsspeichernutzung protokolliert. Eine vollständige Liste der Cluster-Ereignisse samt Beschreibungen finden Sie unter Abschnitt 16.6, „Management von MySQL Cluster“.

    Wenn das Cluster-Log auf eine Million Byte angewachsen ist, wird die Datei in ndb_node_id_cluster.log.seq_id umbenannt, wobei seq_id die laufende Nummer der Cluster-Logdatei ist. (Ein Beispiel: Sind bereits Dateien mit den laufenden Nummern 1, 2 und 3 vorhanden, bekommt die nächste Logdatei die Nummer 4.)

  • Die Datei ndb_node_id_out.log wird für stdout und stderr genutzt, wenn der Management-Server als Daemon läuft.

  • ndb_node_id.pid ist die Prozess-ID-Datei, wenn der Management-Server als Daemon läuft.

16.5.4. ndb_mgm, der Management-Client-Prozess

Der Management-Client-Prozess ist eigentlich nicht erforderlich, um den Cluster zu betreiben. Sein Wert liegt in der Bereitstellung von Befehlen zur Überprüfung des Cluster-Status, zum Starten von Datensicherungen und zur Ausführung anderer administrativer Funktionen. Der Management-Client greift über eine C-API auf den Management-Server zu. Fortgeschrittene Benutzer können über diese API auch dedizierte Management-Prozesse programmieren, die sich um ähnliche Aufgaben kümmern wie ndb_mgm.

Um den Management-Client zu starten, müssen Sie den Hostnamen und die Portnummer des Management-Servers angeben:

shell> ndb_mgm [host_name [port_num]]

Ein Beispiel:

shell> ndb_mgm ndb_mgmd.mysql.com 1186

Der Standardhostname ist localhost und der Standardport ist 1186.

Mehr über die Verwendung von ndb_mgm lesen Sie unter Abschnitt 16.5.5.4, „Befehlsoptionen für ndb_mgm, und Abschnitt 16.6.2, „Befehle des Management-Clients“.

16.5.5. Befehlsoptionen für MySQL Cluster-Prozesse

Alle MySQL Cluster-Executables (außer mysqld) nehmen die in diesem Abschnitt aufgeführten Optionen entgegen. Benutzer älterer Versionen von MySQL Cluster sollten berücksichtigen, dass einige dieser Optionen gegenüber MySQL 4.1 Cluster geändert wurden, um sie miteinander und mit mysqld zu vereinheitlichen. Die Option --help zeigt Ihnen die Liste der unterstützten Optionen an.

Die folgenden Abschnitte beschreiben Optionen, die für einzelne NDB-Programme spezifisch sind.

  • --help --usage, -?

    Gibt eine kurze Liste mit Beschreibungen der verfügbaren Befehlsoptionen aus.

  • --connect-string=connect_string, -c connect_string

    connect_string stellt den Verbindungs-String für den Management-Server als Befehlsoption ein.

    shell> ndbd --connect-string="nodeid=2;host=ndb_mgmd.mysql.com:1186"
    
  • --debug[=options]

    Diese Option kann nur für Versionen verwendet werden, die mit Debugging kompiliert wurden. Sie aktiviert die Ausgabe von Debugaufrufen in derselben Weise wie für den mysqld-Prozess.

  • --execute=command -e command

    Kann einen Befehl von der System-Shell an die Cluster-Executable schicken. Die beiden folgenden Befehle:

    shell> ndb_mgm -e show
    

    oder

    shell> ndb_mgm --execute="SHOW"
    

    sind äquivalent zu

    NDB> SHOW;
    

    Analog funktionieren die Optionen --execute und -e mit dem Kommandozeilen-Client von mysql. Siehe auch Abschnitt 4.3.1, „Befehlszeilenoptionen für mysqld“.

  • --version, -V

    Gibt die Versionsnummer des ndbd-Prozesses aus. Dabei handelt es sich um die Nummer der MySQL Cluster-Version. Diese ist wichtig, da nicht alle Versionen zusammen benutzt werden können. Der MySQL Cluster-Prozess prüft beim Hochfahren, ob die Versionen der verwendeten Binaries überhaupt in demselben Cluster nebeneinander existieren können. Das ist auch beim Online-Softwareupgrade von MySQL Cluster von Bedeutung.

16.5.5.1. MySQL Cluster-spezifische Befehlsoptionen für mysqld

  • --ndb-connectstring=connect_string

    Wenn die Speicher-Engine NDB Cluster benutzt wird, gibt diese Option an, welcher Management-Server die Daten für die Cluster-Konfiguration verteilt.

  • --ndbcluster

    Die Speicher-Engine NDB Cluster ist für die Benutzung von MySQL Cluster erforderlich. Wenn eine mysqld-Binary die Speicher-Engine NDB Cluster unterstützt, ist diese Engine nach Voreinstellung deaktiviert. Mit der Option --ndbcluster wird sie aktiviert und mit --skip-ndbcluster explizit deaktiviert.

16.5.5.2. Befehlsoptionen für ndbd

Optionen für alle NDB-Programme finden Sie unter Abschnitt 16.5.5, „Befehlsoptionen für MySQL Cluster-Prozesse“.

  • --daemon, -d

    Lässt ndbd als Daemon-Prozess laufen. Dies ist das Standardverhalten. Die Option --nodaemon kann verwendet werden, wenn der Prozess nicht als Daemon laufen soll.

  • --initial

    Lässt ndbd einen Initialstart durchführen. Beim Initialstart werden alle Dateien gelöscht, die von früheren ndbd-Instanzen zu Wiederherstellungszwecken angelegt wurden. Außerdem rekonstruiert diese Option die Recovery-Logdateien. Beachten Sie, dass dieser Prozess auf manchen Betriebssystemen viel Zeit braucht.

    Ein --initial-Start soll nur beim allerersten Hochfahren des ndbd-Prozesses ausgeführt werden, da er alle Dateien aus dem Cluster-Dateisystem löscht und alle Recovery-Logdateien wiederherstellt. Von dieser Regel gibt es zwei Ausnahmen:

    • Ein Softwareupgrade, bei dem Dateiinhalte geändert worden sind.

    • Der Neustart eines Knotens mit einer neuen Version von ndbd.

    • Als letztes Mittel, wenn aus irgendeinem Grund der Neustart eines Knotens oder des Systems immer wieder scheitert. In diesem Fall müssen Sie jedoch berücksichtigen, dass der Knoten nun nicht mehr zur Wiederherstellung von Daten taugt, da seine Datendateien zerstört wurden.

    Diese Option wirkt sich auf keine Sicherungsdateien aus, die von dem betroffenen Knoten bereits erzeugt worden sind.

  • --nodaemon

    Veranlasst, dass ndbd nicht als Daemon-Prozess startet. Dies ist nützlich, wenn Sie ndbd debuggen und die Ausgabe auf den Bildschirm umleiten möchten.

  • --nostart

    Lässt ndbd nicht automatisch starten. Wenn diese Option benutzt wird, verbindet sich ndbd mit dem Management-Server, holt sich von diesem Konfigurationsdaten und initialisiert Kommunikationsobjekte. Die Ausführung wird jedoch erst dann gestartet, wenn der Management-Server es ausdrücklich verlangt, indem er dem Management-Client einen ausdrücklichen Befehl dafür gibt.

16.5.5.3. Befehlsoptionen für ndb_mgmd

Optionen, die allen NDB-Programmen gemeinsam sind, finden Sie unter Abschnitt 16.5.5, „Befehlsoptionen für MySQL Cluster-Prozesse“.

  • --config-file=file_name, -f file_name,

    Sagt dem Management-Server, welches seine Konfigurationsdatei ist. Diese Option muss gesetzt werden; ihr Standardwert ist config.ini.

    Achtung: Diese Option kann auch als -c file_name angegeben werden, aber diese Abkürzung ist veraltet und soll nicht in neueren Installationen verwendet werden.

  • --daemon, -d

    Lässt ndb_mgmd als Daemon-Prozess starten. Dies ist das Standardverhalten.

  • --nodaemon

    Lässt ndb_mgmd nicht als Daemon-Prozess starten.

16.5.5.4. Befehlsoptionen für ndb_mgm

Optionen, die allen NDB-Programmen gemeinsam sind, finden Sie unter Abschnitt 16.5.5, „Befehlsoptionen für MySQL Cluster-Prozesse“.

  • --try-reconnect=number

    Wenn die Verbindung zum Management-Server abbricht, versucht der Knoten alle 5 Sekunden, sich erneut zu verbinden, bis er damit Erfolg hat. Mit dieser Option können Sie die Anzahl der Verbindungsversuche auf number begrenzen. Danach gibt der Knoten auf und meldet einen Fehler.

16.6. Management von MySQL Cluster

Zur Verwaltung eines MySQL Clusters gehören diverse Aufgaben, darunter an erster Stelle das Konfigurieren und Starten von MySQL Cluster. Dies wird in Abschnitt 16.4, „MySQL Cluster: Konfiguration“ und Abschnitt 16.5, „Prozessverwaltung in MySQL Cluster“, beschrieben.

In den folgenden Abschnitten wird beschrieben, wie man einen laufenden MySQL Cluster verwaltet.

Im Wesentlichen gibt es zwei Methoden, um einen laufenden MySQL Cluster aktiv zu verwalten. Die erste: Sie können Befehle in den Management-Client eingeben, um den Cluster-Status zu prüfen, die Logebenen zu ändern, Datensicherungen zu starten und anzuhalten und Knoten hoch- oder herunterzufahren. Die zweite Methode: Sie prüfen den Inhalt des Cluster-Logs ndb_node_id_cluster.log im DataDir-Verzeichnis des Management-Servers. (Denken Sie daran, dass node_id der eindeutige Bezeichner des Knotens ist, dessen Aktivität protokolliert wird.) Das Cluster-Log enthält Ereignisberichte, die von ndbd generiert wurden. Es ist auch möglich, Cluster-Logeinträge an ein Unix-Systemlog zu senden.

16.6.1. MySQL Cluster: Startphasen

Dieser Abschnitt beschreibt die Schritte zum Starten eines Clusters.

Wie Sie hier sehen, gibt es mehrere Starttypen und -modi:

  • Initialstart: Der Cluster startet mit einem sauberen Dateisystem auf allen Knoten. Dies geschieht entweder, wenn der Cluster zum allerersten Mal gestartet wird, oder wenn er mit der Option --initial neu gestartet wird.

  • Neustart des Systems: Der Cluster startet und liest die in den Datenknoten gespeicherten Daten. Dies geschieht, wenn der Cluster, nachdem er nach Benutzung heruntergefahren wurde, den Betrieb an dem Punkt wieder aufnehmen soll, an dem er sich verabschiedet hatte.

  • Neustart eines Knotens: Dies ist der Online-Neustart eines Cluster-Knotens, während der Cluster selbst noch läuft.

  • Initialer Knoten-Neustart: Dies ist im Grunde dasselbe wie der Neustart eines Knotens, nur dass der Knoten hier neu initialisiert und mit einem sauberen Dateisystem hochgefahren wird.

Vor dem Starten muss jeder Datenknoten (ndbd-Prozess) initialisiert werden. Hierzu gehören folgende Schritte:

  1. eine Knoten-ID besorgen

  2. die Konfigurationsdaten beschaffen

  3. die Ports für die Kommunikation zwischen den Knoten zuweisen

  4. Hauptspeicher gemäß den Vorgaben der Konfigurationsdatei reservieren

Nachdem die Datenknoten initialisiert sind, kann der Startprozess des Clusters fortfahren. Dabei macht der Cluster folgende Stadien durch:

  • Stadium 0

    Das Dateisystem des Clusters wird geleert. Dieses Stadium tritt nur dann ein, wenn der Cluster mit der Option --initial gestartet wurde.

  • Stadium 1

    Nun werden die Cluster-Verbindungen eingerichtet, die Kommunikationskanäle zwischen den Knoten zugewiesen und die Heartbeats des Clusters gestartet.

  • Stadium 2

    Der Arbitratorknoten wird ausgewählt. Wenn es sich um einen Neustart des Systems handelt, ermittelt der Cluster den letzten wiederherstellbaren globalen Checkpoint.

  • Stadium 3

    Eine Reihe von internen Cluster-Variablen wird initialisiert.

  • Stadium 4

    Für einen Initialstart oder initialen Knoten-Neustart werden die Redo-Logdateien angelegt. Die Anzahl dieser Dateien ist gleich NoOfFragmentLogFiles.

    Bei einem System-Neustart:

    • werden das oder die Schema(ta) gelesen,

    • werden die Daten aus dem lokalen Checkpoint und den Redo-Logs gelesen,

    • werden alle Redo-Informationen angewendet, bis der letzte wiederherstellbare globale Checkpoint erreicht wurde.

    Für einen Knoten-Neustart muss der Logtail des Redo-Logs gefunden werden.

  • Stadium 5

    Wenn es sich um einen Initialstart handelt, werden die internen Systemtabellen SYSTAB_0 und NDB$EVENTS angelegt.

    Bei einem Knoten-Neustart oder initialen Knoten-Neustart:

    1. wird der Knoten in die Transaktions-Behandlungsoperationen einbezogen.

    2. wird das Knotenschema mit dem des Masters verglichen und synchronisiert,

    3. werden die in INSERT-Form von den anderen Datenknoten der Knotengruppe dieses Knotens empfangenen Daten synchronisiert.

    4. In allen Fällen wird gewartet, bis der Arbitrator bestimmt, dass ein lokaler Checkpoint vollständig ist.

  • Stadium 6

    Interne Variablen werden aktualisiert.

  • Stadium 7

    Interne Variablen werden aktualisiert.

  • Stadium 8

    Bei einem Neustart eines Systems werden alle Indizes neu aufgebaut.

  • Stadium 9

    Interne Variablen werden aktualisiert.

  • Stadium 10

    Bei einem Knoten-Neustart oder initialen Knoten-Neustart können sich an diesem Punkt APIs mit dem Knoten verbinden und Ereignisse empfangen.

  • Stadium 11

    Bei einem Knoten-Neustart oder initialen Knoten-Neustart wird an diesem Punkt die Lieferung von Ereignissen an den Knoten übergeben, der dem Cluster beitritt. Dieser neue Knoten übernimmt dann die Verantwortung für die Lieferung seiner primären Daten an die Abonnenten.

Nachdem dieser Prozess für einen Initialstart oder Neustart eines Systems abgeschlossen ist, wird die Transaktionsunterstützung aktiviert. Bei einem Knoten-Neustart oder initialen Knoten-Neustart bedeutet das Ende des Startprozesses, dass der Knoten nun als Transaktionskoordinator fungieren kann.

16.6.2. Befehle des Management-Clients

Ein Cluster kann nicht nur durch die zentrale Konfigurationsdatei, sondern auch über eine Kommandozeilenschnittstelle kontrolliert werden, die im Management-Client ndb_mgm zur Verfügung steht. Diese ist die wichtigste Administrationsschnittstelle für den Betrieb eines Clusters.

Befehle für die Ereignislogs stehen in Abschnitt 16.6.3, „Ereignisberichte, die MySQL Cluster erzeugt“, und Befehle für die Erstellung von Datensicherungen und die Wiederherstellung aus Datensicherungen in Abschnitt 16.6.5, „Online-Backup eines MySQL Clusters“.

Der Management-Client kennt folgende Grundbefehle. In der nachfolgenden Liste steht node_id entweder für eine Datenbankknoten-ID oder für das Schlüsselwort ALL, das bedeutet, dass der Befehl für alle Datenknoten des Clusters gilt.

  • HELP

    Zeigt Informationen über die verfügbaren Befehle an.

  • SHOW

    Zeigt Informationen über den Cluster-Status an.

    Achtung: In einem Cluster, in dem mehrere Management-Knoten in Gebrauch sind, zeigt dieser Befehl nur über diejenigen Datenknoten Informationen an, die gerade mit dem aktuellen Management-Server verbunden sind.

  • node_id START

    Startet den Datenknoten, der durch die node_id identifiziert ist (oder alle Datenknoten).

  • node_id STOP

    Stoppt den Datenknoten, der durch die node_id identifiziert ist (oder alle Datenknoten).

  • node_id RESTART [-N] [-I]

    Startet den Datenknoten neu, der durch die node_id identifiziert ist (oder alle Datenknoten).

  • node_id STATUS

    Zeigt Statusinformationen über den Datenknoten an, der durch die node_id identifiziert ist (oder über alle Datenknoten).

  • ENTER SINGLE USER MODE node_id

    Geht in den Einbenutzermodus, wobei nur der MySQL Server, der durch die Knoten-ID node_id identifiziert ist, auf die Datenbank zugreifen darf.

  • EXIT SINGLE USER MODE

    Verlässt den Einbenutzermodus, sodass alle SQL-Knoten (also alle laufenden mysqld-Prozesse) auf die Datenbank zugreifen können.

  • QUIT

    Beendet den Management-Client.

  • SHUTDOWN

    Fährt alle Cluster-Knoten außer den SQL-Knoten herunter und beendet den Management-Client.

16.6.3. Ereignisberichte, die MySQL Cluster erzeugt

In diesem Abschnitt geht es um die Ereignislog-Typen, die MySQL Cluster zur Verfügung stellt, und um die darin protokollierten Ereignisarten.

MySQL Cluster stellt zwei Typen von Ereignislogs zur Verfügung: das Cluster-Log mit Ereignissen, die von allen Cluster-Knoten generiert werden, und die Knoten-Logs, die lokal für die einzelnen Datenknoten geführt werden.

Die vom Cluster-Ereignislogging generierte Ausgabe kann mehrere Ziele haben: eine Datei, die Konsole des Management-Servers oder auch syslog. Die Ausgabe des Knoten-Ereignisloggings wird in das Konsolenfenster des Datenknotens geschrieben.

Beide Typen von Ereignislogs können auf die Protokollierung verschiedener Ereignisse eingestellt werden.

Hinweis: Das Cluster-Log ist das Log, das für die meisten Anwendungen empfohlen wird, da es Informationen über einen ganzen Cluster in einer einzigen Datei zur Verfügung stellt. Die Knoten-Logs sind nur für die Anwendungsentwicklung oder für das Debugging von Anwendungscode gedacht.

Protokollierbare Ereignisse können nach drei verschiedenen Kriterien unterschieden werden:

  • Kategorie (Category): Diese kann einer der folgenden Werte sein: STARTUP, SHUTDOWN, STATISTICS, CHECKPOINT, NODERESTART, CONNECTION, ERROR oder INFO.

  • Priorität (Priority): Diese wird in Ganzzahlen von 1 bis 15 einschließlich angegeben, wobei 1 „am wichtigsten“ und 15 „am unwichtigsten“ bedeutet.

  • Ernsthaftigkeit (Severity Level): Dies kann einer der folgenden Werte sein: ALERT, CRITICAL, ERROR, WARNING, INFO oder DEBUG.

Sowohl Cluster- als auch Knoten-Log können anhand dieser Eigenschaften gefiltert werden.

16.6.3.1. Loggen von Management-Befehlen

Die folgenden Management-Befehle beziehen sich auf das Cluster-Log:

  • CLUSTERLOG ON

    Schaltet das Cluster-Log ein.

  • CLUSTERLOG OFF

    Schaltet das Cluster-Log aus.

  • CLUSTERLOG INFO

    Gibt Informationen über die Einstellungen des Cluster-Logs.

  • node_id CLUSTERLOG category=threshold

    Protokolliert category-Ereignisse mit einer Priorität kleiner oder gleich threshold im Cluster-Log.

  • CLUSTERLOG FILTER severity_level

    Schaltet Cluster-Logging von Ereignissen des angegebenen severity_level ein oder aus.

Die folgende Tabelle beschreibt die Standardeinstellung (für alle Datenknoten) für den Kategorie-Schwellenwert des Cluster-Logs. Ist die Priorität eines Ereignisses kleiner oder gleich dem Prioritäts-Schwellenwert, wird es in das Cluster-Log aufgenommen.

Beachten Sie, dass die Ereignisse pro Datenknoten gemeldet werden und dass der Schwellenwert (Threshold) für verschiedene Knoten unterschiedlich eingestellt werden kann.

KategorieStandardschwellenwert (alle Datenknoten)
STARTUP7
SHUTDOWN7
STATISTICS7
CHECKPOINT7
NODERESTART7
CONNECTION7
ERROR15
INFO7

Die Schwellenwerte dienen dazu, die Ereignisse innerhalb der Kategorien zu filtern. So wird beispielsweise ein STARTUP-Ereignis mit der Priorität 3 erst protokolliert, wenn der Schwellenwert für STARTUP auf 3 oder noch niedriger eingestellt wird. Ist der Schwellenwert 3, werden nur Ereignisse mit der Prioritätszahl drei oder kleiner als drei protokolliert.

Die folgende Tabelle zeigt die Ernsthaftigkeit (den Severity-Level) von Ereignissen. (Hinweis: Diese Abstufungen entsprechen den Ebenen des Unix-syslog, mit Ausnahme von LOG_EMERG und LOG_NOTICE, die nicht verwendet bzw. zugeordnet werden.)

1ALERTEine Bedingung, die unverzüglich behoben werden muss, wie beispielsweise eine beschädigte Systemdatenbank
2CRITICALKritische Bedingungen, wie beispielsweise Gerätefehler oder unzureichende Ressourcen
3ERRORBedingungen, die korrigiert werden sollten, wie beispielsweise Konfigurationsfehler
4WARNINGBedingungen, die zwar keine Fehler darstellen, aber eine Sonderbehandlung erfordern könnten
5INFOMeldungen zu Informationszwecken
6DEBUGDebugging-Meldungen, die für die Entwicklung von NDB Cluster verwendet werden

Die Ernsthaftigkeitsebenen für Ereignisse können ein- oder ausgeschaltet werden (mit CLUSTERLOG FILTER, siehe oben). Wenn eine Ernsthaftigkeitsebene eingeschaltet ist, werden alle Ereignisse, deren Priorität kleiner oder gleich dem Schwellenwert für die betreffende Kategorie ist, protokolliert. Wenn die Ernsthaftigkeitsebene ausgeschaltet ist, werden Ereignisse, die auf dieser Ebene liegen, nicht protokolliert.

16.6.3.2. Logereignisse

Ein Ereignisbericht in den Ereignislogs hat folgendes Format:

datetime [string] severity -- message

Zum Beispiel:

09:19:30 2005-07-24 [NDB] INFO -- Node 4 Start phase 4 completed

Der folgende Abschnitt beschreibt alle Ereignisse, die gemeldet werden können, geordnet nach Kategorien und innerhalb der Kategorie nach Ernsthaftigkeit.

GCP und LCP bedeuten in den Ereignisbeschreibungen „Global Checkpoint“ und „Local Checkpoint“.

CONNECTION-Ereignisse

Diese Ereignisse hängen mit Verbindungen zwischen Cluster-Knoten zusammen.

EreignisPrioritätErnsthaftigkeitBeschreibung
DB nodes connected8INFODatenknoten verbunden
DB nodes disconnected8INFOVerbindung zum Datenknoten getrennt
Communication closed8INFOSQL-Knoten oder Datenknoten-Verbindung geschlossen
Communication opened8INFOVerbindung zum SQL- oder Datenknoten geöffnet

CHECKPOINT-Ereignisse

Die folgenden Logmeldungen hängen mit Checkpoints zusammen.

EreignisPrioritätErnsthaftigkeitBeschreibung
LCP stopped in calc keep GCI0ALERTLCP gestoppt
Local checkpoint fragment completed11INFOLCP auf einem Fragment abgeschlossen
Global checkpoint completed10INFOGCP fertig
Global checkpoint started9INFOStart eines GCP: REDO-Log wird auf Platte geschrieben
Local checkpoint completed8INFOLCP normal abgeschlossen
Local checkpoint started7INFOStart eines LCP: Daten auf Platte geschrieben
Report undo log blocked7INFOUNDO-Logging blockiert; Puffer läuft fast über

STARTUP-Ereignisse

Die folgenden Ereignisse werden als Reaktion auf den Erfolg oder Misserfolg beim Starten eines Knotens oder des Clusters generiert. Außerdem geben sie Informationen über den Fortschritt des Startprozesses einschließlich Informationen über Logging-Aktivitäten.

EreignisPrioritätErnsthaftigkeitBeschreibung
Internal start signal received STTORRY15INFOBlöcke, die nach Ende des Neustarts empfangen wurden
Undo records executed15INFO(Beschreibung nicht verfügbar)
New REDO log started10INFOGCI behält X, neuester wiederherstellbarer GCI Y
New log started10INFOLog-Teil X, Beginn bei MB Y, Ende bei MB Z
Node has been refused for inclusion in the cluster8INFOKnoten kann wegen eines Konfigurationsfehlers nicht in den Cluster einbezogen werden, Kommunikation kann nicht hergestellt werden oder anderes Problem
DB node neighbors8INFOZeigt benachbarte Datenknoten
DB node start phase X completed4INFOEine Startphase eines Datenknotens ist abgeschlossen
Node has been successfully included into the cluster3INFOZeigt den Knoten, Manager-Knoten und dynamische ID an
DB node start phases initiated1INFONDB Cluster-Knoten starten
DB node all start phases completed1INFOGestartete NDB Cluster-Knoten
DB node shutdown initiated1INFOHerunterfahren des Datenknotens hat begonnen
DB node shutdown aborted1INFODatenknoten kann nicht normal heruntergefahren werden

NODERESTART-Ereignisse

Die folgenden Ereignisse werden beim Neustart eines Knotens generiert und geben Aufschluss über den Erfolg oder Misserfolg des Neustart-Prozesses.

EreignisPrioritätErnsthaftigkeitBeschreibung
Node failure phase completed8ALERTMeldet den Abschluss von Node Failure-Phasen
Node has failed, node state was X8ALERTMeldet das Scheitern eines Knotens
Report arbitrator results2ALERTArbitration-Versuche können 8 mögliche Ergebnisse haben:
  • Arbitration-Überprüfung fehlgeschlagen – weniger als 1/2 Knoten übrig

  • Arbitration-Überprüfung erfolgreich – Knotengruppen-Mehrheit

  • Arbitration-Überprüfung fehlgeschlagen – Knotengruppen fehlen

  • Netzwerkpartitionierung – Arbitration erforderlich

  • Arbitration-Überprüfung erfolgreich – bestätigt durch Antwort von Knoten X

  • Arbitration fehlgeschlagen – negative Antwort von Knoten X

  • Netzwerkpartitionierung – kein Arbitrator verfügbar

  • Netzwerkpartitionierung – kein Arbitrator konfiguriert

Completed copying a fragment10INFO 
Completed copying of dictionary information8INFO 
Completed copying distribution information8INFO 
Starting to copy fragments8INFO 
Completed copying all fragments8INFO 
GCP takeover started7INFO 
GCP takeover completed7INFO 
LCP takeover started7INFO 
LCP takeover completed (state = X)7INFO 
Report whether an arbitrator is found or not6INFODie Suche nach einem Arbitrator kann 7 mögliche Ergebnisse haben:
  • Management-Server startet Arbitration-Thread neu [state=X]

  • Arbitrator-Knoten X in Vorbereitung [ticket=Y]

  • Arbitrator-Knoten X empfangen [ticket=Y]

  • Arbitrator-Knoten X gestartet [ticket=Y]

  • Arbitrator-Knoten X verloren – Prozess fehlgeschlagen [state=Y]

  • Arbitrator-Knoten X verloren – Prozess beendet [state=Y]

  • Arbitrator-Knoten X verloren Fehlermeldung [state=Y]

STATISTICS-Ereignisse

Die folgenden Ereignisse sind statistischer Natur. Sie melden beispielsweise die Anzahl der Transaktionen oder anderer Operationen, die Datenmengen, die von einzelnen Knoten gesendet oder empfangen wurden, oder die Speicherauslastung.

EreignisPrioritätErnsthaftigkeitBeschreibung
Report job scheduling statistics9INFOMittelwerte der internen Job-Planungsstatistik
Sent number of bytes9INFODurchschnittliche Anzahl der an Knoten X gesandten Bytes
Received number of bytes9INFODurchschnittliche Anzahl der von Knoten X empfangenen Bytes
Report transaction statistics8INFOAnzahl von Transaktionen, Commits, Leseoperationen, Simple Reads, Schreiboperationen, nebenläufigen Operationen, Attributinformationen und Abbrüchen
Report operations8INFOAnzahl der Operationen
Report table create7INFO 
Memory usage5INFOAusnutzung von Data und Index Memory (80 %, 90 % und 100 %)

ERROR-Ereignisse

Diese Ereignisse betreffen Fehler und Warnungen im Cluster. Ihr Auftreten ist ein Hinweis auf eine größere Fehlfunktion oder ein Versagen.

EreignisPrioritätErnsthaftigkeitBeschreibung
Dead due to missed heartbeat8ALERTDer Knoten X wird für „tot“ erklärt, weil kein Heartbeat empfangen wurde
Transporter errors2ERROR 
Transporter warnings8WARNING 
Missed heartbeats8WARNINGBeim Knoten X sind Y Heartbeats ausgefallen
General warning events2WARNING 

INFO-Ereignisse

Diese Ereignisse liefern allgemeine Informationen über den Zustand des Clusters und die mit seiner Wartung zusammenhängenden Aktivitäten, wie beispielsweise Logging und die Übermittlung von Heartbeats.

EreignisPrioritätErnsthaftigkeitBeschreibung
Sent heartbeat12INFOHeartbeat, der an den Knoten X gesandt wurde
Create log bytes11INFOLogteil, Logdatei, MB
General information events2INFO 

16.6.4. Einbenutzermodus

Im Einbenutzermodus kann der Datenbankadministrator den Zugriff auf das Datenbanksystem auf einen einzigen MySQL Server (SQL-Knoten) beschränken. Beim Eintritt in den Einbenutzermodus werden alle Verbindungen zu allen anderen MySQL Servern geräuschlos geschlossen und alle laufenden Transaktionen abgebrochen. Es dürfen keine neuen Transaktionen gestartet werden.

Sobald der Cluster im Einbenutzermodus läuft, hat nur noch der eine angegebene SQL-Knoten Zugriff auf die Datenbank.

Mit dem Befehl ALL STATUS können Sie sehen, wann der Cluster in den Einbenutzermodus gegangen ist.

Beispiel:

ndb_mgm> ENTER SINGLE USER MODE 5

Wenn dieser Befehl ausgeführt worden und der Cluster in den Einbenutzermodus eingetreten ist, ist der SQL-Knoten mit der ID 5 der einzige zugelassene Benutzer des Clusters.

Der im obigen Befehl angegebene Knoten muss ein MySQL Server-Knoten sein. Jeder Versuch, einen anderen Knotentyp anzugeben, wird zurückgewiesen.

Hinweis: Wenn der obige Befehl aufgerufen wird, werden alle auf dem angegebenen Knoten laufenden Transaktionen abgebrochen, die Verbindung wird geschlossen und der Server muss neu gestartet werden.

Der Befehl EXIT SINGLE USER MODE stellt den Status der Datenknoten des Clusters vom Einbenutzer- auf den normalen Modus um. MySQL Server, die auf eine Verbindung mit dem Cluster warten (d. h. darauf, dass der Cluster bereit ist und wieder zur Verfügung steht), erhalten wieder die Erlaubnis, eine Verbindung herzustellen. Der als Einbenutzer-SQL-Knoten gekennzeichnete MySQL Server läuft während und nach der Zustandsänderung weiter (sofern er immer noch verbunden ist).

Beispiel:

NDB> EXIT SINGLE USER MODE

Im Einbenutzermodus gibt es zwei empfohlene Vorgehensweisen für den Umgang mit einem Knoten-Absturz:

  • Methode 1:

    1. Sie beenden alle Einbenutzertransaktionen.

    2. Sie geben den Befehl EXIT SINGLE USER MODE ein.

    3. Sie starten die Datenknoten des Clusters neu.

  • Methode 2:

    Sie starten die Datenbankknoten neu, bevor Sie in den Einbenutzermodus gehen.

16.6.5. Online-Backup eines MySQL Clusters

Dieser Abschnitt beschreibt, wie eine Datenbanksicherung erstellt und wie die Datenbank später aus einer Sicherung wiederhergestellt wird.

16.6.5.1. Backup-Konzepte für MySQL Cluster

Eine Datensicherung ist eine Momentaufnahme der Datenbank zu einem gegebenen Zeitpunkt. Sie besteht aus drei Hauptteilen:

  • Metadaten: die Namen und Definitionen aller Datenbanktabellen

  • Tabellendatensätze: die Daten, die in den Datenbanktabellen zum Zeitpunkt der Datensicherung tatsächlich gespeichert waren

  • Transaktionslog: ein sequenzieller Logeintrag, der Ihnen sagt, wie und wann Daten in der Datenbank gespeichert wurden

Jeder dieser Teile wird auf allen Knoten gespeichert, deren Daten gesichert werden. Während der Datensicherung speichert jeder Knoten diese drei Teile in drei Dateien auf der Festplatte:

  • BACKUP-backup_id.node_id.ctl

    Eine Steuerungsdatei mit Steuerungsinformationen und Metadaten. Jeder Knoten speichert dieselben Tabellendefinitionen (für alle Tabellen im Cluster) in seiner eigenen Version dieser Datei.

  • BACKUP-backup_id-0.node_id.data

    Eine Datendatei mit den Tabellendaten, die pro Fragment gespeichert werden. Das bedeutet, dass verschiedene Knoten während der Datensicherung verschiedene Fragmente speichern. Die Datei eines Knotens fängt immer mit einem Header an, auf dem die Tabelle steht, zu welcher die Datensätze gehören. Nach der Liste der Datensätze folgt ein Footer mit einer Prüfsumme für alle Datensätze.

  • BACKUP-backup_id.node_id.log

    Eine Logdatei mit Datensätzen von committeten Transaktionen. Nur Transaktionen auf Tabellen, die in der Sicherung gespeichert sind, werden im Log festgehalten. Die gesicherten Knoten speichern unterschiedliche Datensätze, da unterschiedliche Knoten unterschiedliche Datenbankfragmente hosten.

Im obigen Listing ist backup_id der Bezeichner für die Sicherung und node_id der eindeutige Bezeichner für den Knoten, welcher die Datei anlegt.

16.6.5.2. Verwendung des Management-Servers zur Erzeugung von Backups

Ehe Sie eine Datensicherung starten, müssen Sie sich vergewissern, dass der Cluster dafür richtig konfiguriert ist. (Siehe Abschnitt 16.6.5.4, „Konfiguration für Cluster-Backup“.)

Um mit dem Management-Server eine Sicherung vorzunehmen, tun Sie Folgendes:

  1. Sie starten den Management-Server (ndb_mgm).

  2. Sie führen den Befehl START BACKUP aus.

  3. Der Management-Server wird mit der Nachricht Start of backup ordered antworten. Dies bedeutet, dass er den Request an den Cluster übermittelt, aber noch keine Reaktion empfangen hat.

  4. Der Management-Server antwortet mit Backup backup_id started, wobei backup_id wieder der eindeutige Bezeichner für diese Sicherung ist. (Dieser Bezeichner wird auch im Cluster-Log gespeichert, wenn nichts anderes konfiguriert wurde.) Dies bedeutet, dass der Cluster den Backup-Request empfangen und verarbeitet hat. Es bedeutet jedoch nicht, dass die Sicherung abgeschlossen ist.

  5. Der Management-Server signalisiert durch die Nachricht Backup backup_id completed, dass die Datensicherung abgeschlossen ist.

Um eine laufende Sicherung abzubrechen, gehen Sie folgendermaßen vor:

  1. Sie starten den Management-Server.

  2. Sie führen den Befehl ABORT BACKUP backup_id aus. Die Zahl backup_id ist der Backup-Bezeichner, der in der Antwort des Management-Servers beim Starten der Datensicherung angegeben wurde (in der Nachricht Backup backup_id started).

  3. Der Management-Server quittiert den Abbruchbefehl mit einem Abort of backup backup_id ordered. Beachten Sie, dass er bisher noch keine wirkliche Antwort auf diesen Request erhalten hat.

  4. Nach dem Abbruch der Datensicherung meldet der Management-Server Backup backup_id has been aborted for reason XYZ. Dies bedeutet, dass der Cluster die Datensicherung beendet hat und alle mit ihr verbundenen Dateien aus dem Dateisystem des Clusters gelöscht wurden.

Es ist auch möglich, eine laufende Datensicherung von der System-Shell aus mit folgendem Befehl abzubrechen:

shell> ndb_mgm -e "ABORT BACKUP backup_id"

Hinweis: Wenn zum Zeitpunkt des Abbruchbefehls keine Sicherung mit der backup_id läuft, erstattet der Management-Server darüber keine explizite Meldung. Immerhin wird der ungültige Abbruchbefehl jedoch im Cluster-Log erwähnt.

16.6.5.3. Wiederherstellung aus einem Cluster-Backup

Das Programm zur Cluster-Wiederherstellung ist als separate Kommandozeilen-Utility namens ndb_restore implementiert. Es liest die angelegten Sicherungsdateien und fügt die darin gespeicherten Informationen in die Datenbank ein. Das Wiederherstellungsprogramm muss für jeden Satz von Sicherungsdateien einmal ausgeführt werden, also so viele Male, wie Datenbankknoten zum Zeitpunkt der Datensicherung ausgeführt wurden.

Wenn Sie das Wiederherstellungsprogramm ndb_restore erstmals ausführen, müssen Sie auch die Metadaten rekonstruieren. Mit anderen Worten: Sie müssen die Datenbanktabellen wiederherstellen. (Beachten Sie, dass der Cluster eine leere Datenbank haben müsste, wenn die Wiederherstellung der Sicherung beginnt.) Das Wiederherstellungsprogramm fungiert als API zum Cluster und erfordert daher eine freie Verbindung zum Cluster. Ob diese vorhanden ist, sagt Ihnen der ndb_mgm-Befehl SHOW (den Sie mit ndb_mgm -e SHOW auf der System-Shell absetzen können). Mit der Option -c connectstring können Sie den MGM-Knoten angeben (mehr zu Verbindungs-Strings erfahren Sie unter Abschnitt 16.4.4.2, „MySQL Cluster: connectstring). Die Sicherungsdateien müssen in dem Verzeichnis liegen, welches dem Wiederherstellungsprogramm als Argument übergeben wird.

Es ist möglich, eine Datenbanksicherung mit einer anderen Konfiguration als die Erzeugung der Datenbank zu fahren. Nehmen wir beispielsweise an, dass eine Sicherung mit der ID 12, die in einem Cluster mit zwei Datenbankknoten mit den Knoten-IDs 2 und 3 angelegt wurde, in einem Cluster mit vier Knoten wiederhergestellt werden soll. Dazu muss der Befehl ndb_restore zweimal ausgeführt werden: einmal für jeden Datenbankknoten in dem Cluster, in dem die Sicherung durchgeführt wurde.

Hinweis: Schneller geht die Wiederherstellung, wenn sie parallel ausgeführt wird, vorausgesetzt, es stehen genügend Cluster-Verbindungen zur Verfügung. Allerdings müssen die Datendateien immer vor den Logs angewendet werden.

16.6.5.4. Konfiguration für Cluster-Backup

Vier Konfigurationsparameter sind für die Datensicherung äußerst wichtig:

  • BackupDataBufferSize

    Gibt an, wie viel Arbeitsspeicher für das Puffern von Daten zur Verfügung steht, ehe diese auf die Platte geschrieben werden.

  • BackupLogBufferSize

    Gibt an, wie viel Arbeitsspeicher für das Puffern von Logeinträgen zur Verfügung steht, ehe diese auf die Platte geschrieben werden.

  • BackupMemory

    Gibt an, wie viel Arbeitsspeicher in einem Datenbankknoten insgesamt für Datensicherungen reserviert ist. Dieser Wert sollte die Summe des zugewiesenen Speichers für Backup-Datenpuffer plus Backup-Logpuffer sein.

  • BackupWriteSize

    Die Blockgröße, in der Daten auf die Platte geschrieben werden. Gilt sowohl für Backup-Datenpuffer als auch für Backup-Logpuffer.

Genauere Einzelheiten über diese Parameter finden Sie unter Abschnitt 16.4, „MySQL Cluster: Konfiguration“.

16.6.5.5. Backup: Troubleshooting

Wenn auf einen Backup-Request ein Fehlercode zurückgegeben wird, liegt dies wahrscheinlich an unzureichendem Arbeits- oder Festplattenspeicher. Sie sollten sich vergewissern, dass für die Datensicherung genügend Hauptspeicher zur Verfügung steht und dass auch auf der Festplattenpartition, die von der Datensicherung genutzt wird, ausreichend Platz ist.

NDB unterstützt keine Repeatable Reads, was zu Problemen mit dem Wiederherstellungsprozess führen kann. Zwar ist der Sicherungsprozess selbst „heiß“, aber die Wiederherstellung eines MySQL Clusters aus einer Datensicherung ist eben nicht zu 100 % ein „heißer“ Prozess. Dies liegt daran, dass für die Dauer des Wiederherstellungsprozesses laufende Transaktionen Non-Repeatable Reads von der rekonstruierten Datenbank erhalten. Das bedeutet, dass der Zustand der Daten inkonsistent ist, während die Wiederherstellung noch läuft.

16.7. Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster

Schon bevor im Jahre 1996 mit dem Entwurf von NDB Cluster begonnen wurde, war offensichtlich, dass die Kommunikation zwischen Knoten im Netzwerk eines der Hauptprobleme in der Konstruktion von parallelen Datenbanken sein würde. Daher wurde NDB Cluster schon von Anfang an für mehrere verschiedene Datentransportmechanismen ausgelegt. In diesem Manual verwenden wir für diese den Oberbegriff Transporter.

Zurzeit unterstützt die MySQL Cluster-Codebasis vier verschiedene Transporter. Die meisten Anwender nutzen heutzutage TCP/IP über Ethernet, da diese Technik allgegenwärtig ist. Zudem ist TCP/IP der mit Abstand am besten getestete Transporter in MySQL Cluster.

Wir arbeiten daran, sicherzustellen, dass die Kommunikation mit dem ndbd-Prozess in möglichst großen „Happen“ abgewickelt wird, da dies für alle Arten der Datenübermittlung nur vorteilhaft ist.

Wer es wünscht, kann die Leistung sogar noch stärker steigern, indem er Direktverbindungen zwischen Clustern (Interconnects) verwendet. Es gibt zwei Möglichkeiten, diese zu errichten: entweder mit einem selbst definierten Transporter oder mit Socketimplementierungen, die den TCP/IP-Stapel bis zu einem gewissen Grade umgehen. Wir haben beide Techniken mit der SCI(Scalable Coherent Interface)-Technologie von Dolphin ausprobiert.

16.7.1. Konfiguration von MySQL Cluster für SCI Sockets

In diesem Abschnitt zeigen wir, wie man einen Cluster, der für normale TCP/IP-Kommunikation konfiguriert ist, auf SCI Sockets umstellt. Diese Dokumentation beruht auf der SCI Sockets-Version 2.3.0 auf dem Stand vom 1. Oktober 2004.

Voraussetzungen:

Alle Computer, die SCI Sockets nutzen sollen, müssen mit SCI-Karten ausgerüstet sein.

SCI Sockets können mit jeder beliebigen Version von MySQL Cluster benutzt werden. Es sind keine besonderen Builds erforderlich, da diese Technologie die ganz normalen Socketaufrufe verwendet, die in MySQL Cluster bereits zur Verfügung stehen. Allerdings werden SCI Sockets zurzeit nur von den Linux-Kernels 2.4 und 2.6 unterstützt. SCI Transporter wurden erfolgreich auch auf anderen Betriebssystemen getestet; wir selbst haben sie bisher allerdings nur auf Linux 2.4 erprobt.

Für SCI Sockets sind im Wesentlichen vier Dinge erforderlich:

  • Sie müssen die SCI Socket-Bibliotheken erstellen.

  • Sie müssen die Kernel-Bibliotheken von SCI Socket installieren.

  • Sie müssen eine oder zwei Konfigurationsdateien installieren.

  • Die Kernel-Bibliothek von SCI Socket muss entweder für den gesamten Computer oder für die Shell, in der MySQL Cluster-Prozesse gestartet werden, aktiviert sein.

Dieser Prozess muss für jeden Computer im Cluster wiederholt werden, auf dem SCI Sockets für die Kommunikation zwischen Knoten eigesetzt werden sollen.

Um SCI Sockets einsetzen zu können, müssen Sie zwei Packages beschaffen:

  • das Quellcode-Package mit den DIS-Support-Bibliotheken für die SCI Sockets-Bibliotheken

  • das Quellcode-Package für die SCI Socket-Bibliotheken selbst

Diese stehen gegenwärtig nur im Quellcodeformat zur Verfügung. Die neuesten Versionen dieser Packages (zu dem Zeitpunkt, da dies geschrieben wurde) sind DIS_GPL_2_5_0_SEP_10_2004.tar.gz und SCI_SOCKET_2_3_0_OKT_01_2004.tar.gz. Diese oder neuere Versionen finden Sie unter http://www.dolphinics.no/support/downloads.html.

Installation der Packages

Wenn Sie die Bibliotheks-Packages bekommen haben, müssen Sie sie als Erstes in die passenden Verzeichnisse entpacken, wobei die SCI Sockets-Bibliotheken in ein Verzeichnis unterhalb des DIS-Codes gelegt werden müssen. Als Nächstes müssen Sie die Bibliotheken erstellen. Das folgende Beispiel zeigt, mit welchen Befehlen dies auf Linux/x86 getan wird:

shell> tar xzf DIS_GPL_2_5_0_SEP_10_2004.tar.gz
shell> cd DIS_GPL_2_5_0_SEP_10_2004/src/
shell> tar xzf ../../SCI_SOCKET_2_3_0_OKT_01_2004.tar.gz
shell> cd ../adm/bin/Linux_pkgs
shell> ./make_PSB_66_release

Diese Bibliotheken können auch für einige 64-Bit-Prozessoren erstellt werden. Um sie für Opteron-CPUs mit den 64-Bit-Erweiterungen einzurichten, führen Sie make_PSB_66_X86_64_release statt make_PSB_66_release aus. Wird der Build auf einem Itanium-Computer ausgeführt, verwenden Sie den Befehl make_PSB_66_IA64_release. Die X86-64-Variante müsste auf Intel EM64T-Architekturen funktionieren, wurde aber (unseres Wissens) noch nicht getestet.

Wenn der Build-Prozess abgeschlossen ist, liegen die kompilierten Bibliotheken in einer gezippten tar-Datei namens DIS-<operating-system>-time-date. Nun muss das Package noch am richtigen Ort installiert werden. In diesem Beispiel legen wir die Installation in das Verzeichnis /opt/DIS. (Hinweis: Wahrscheinlich müssen Sie die Anweisungen als Systembenutzer root ausführen.)

shell> cp DIS_Linux_2.4.20-8_181004.tar.gz /opt/
shell> cd /opt
shell> tar xzf DIS_Linux_2.4.20-8_181004.tar.gz
shell> mv DIS_Linux_2.4.20-8_181004 DIS

Netzwerkkonfiguration

Nun, da alle Bibliotheken und Binaries am richtigen Platz sind, müssen Sie noch dafür sorgen, dass die SCI-Karten die richtigen Knoten-IDs im SCI-Adressraum haben.

Außerdem müssen Sie eine Entscheidung über die Netzwerkstruktur treffen, ehe Sie fortfahren. In diesem Zusammenhang sind drei Arten von Netzwerkstrukturen möglich:

  • ein einfacher, eindimensionaler Ring

  • ein oder mehrere SCI-Switches mt einem Ring pro Switch-Port

  • ein zwei- oder dreidimensionaler Torus

Jede dieser Netzwerktopologien hat ihre eigene Methode, um Knoten-IDs zu liefern. Alle diese Methoden werden im Folgenden kurz erklärt.

Ein einfacher Ring verwendet IDs, die von Null verschiedene Vielfache von 4 sind: 4, 8, 12, ...

Die nächste Möglichkeit verwendet SCI-Switches. Ein SCI-Switch hat 8 Ports, von denen jeder einen Ring unterstützen kann. Sie müssen dafür sorgen, dass verschiedene Ringe verschiedene ID-Räume benutzen. In einer typischen Konfiguration nutzt der erste Port Knoten-IDs unter 64 (4 – 60), der nächste Port die nächsten 64 Knoten-IDs (68–124), und so weiter, sodass die Knoten-IDs 452–508 dem 8. Port zugewiesen werden.

Zwei- und dreidimensionale Torus-Netzwerktopologien nehmen Rücksicht darauf, wo der einzelne Knoten in welcher Dimension angesiedelt ist, indem sie für jeden Knoten in der ersten Dimension um 4 hochzählen, für jeden in der zweiten Dimension um 64 und (wenn vorhanden) für jeden in der dritten Dimension um 1024. Auf der Website von Dolphin finden Sie Genaueres zum Thema.

In unseren Tests haben wir Switches verwendet, obwohl die meisten großen Cluster-Installationen 2- oder 3-dimensionale Torusstrukturen verwenden. Switches haben den Vorteil, dass man mit dualen SCI-Karten und dualen Switches relativ einfach ein redundantes Netzwerk aufbauen kann, wobei die durchschnittlichen Ausfallzeiten im SCI-Netzwerk im Bereich von 100 Mikrosekunden liegen. Dies wird von dem SCI Transporter in MySQL Cluster unterstützt und auch für die SCI Socket-Implementierung zurzeit entwickelt.

Auch für den 2D-/3D-Torus ist eine Ausfallsicherung möglich, doch hierfür ist es erforderlich, an alle Knoten neue Routing-Indizes auszusenden. Dies nimmt allerdings nur circa 100 Millisekunden Zeit in Anspruch, was für die meisten Hochverfügbarkeitssysteme noch akzeptabel sein dürfte.

Indem Sie die Cluster-Datenknoten in der geswitchten Architektur sorgfältig platzieren, können Sie mit 2 Switches eine Struktur aufbauen, in der 16 Computer miteinander verbunden sind und nie mehr als einer von ihnen durch einen einzelnen Fehler ausfallen kann. Mit 32 Computern und 2 Switches können Sie den Cluster so konfigurieren, dass ein einzelner Absturz nie mehr als 2 Knoten betreffen kann und dass darüber hinaus bekannt wird, um welches Knotenpaar es sich handelt. Indem Sie diese beiden Knoten dann in separate Knotengruppen verlegen, können Sie sogar eine „sichere“ MySQL Cluster-Installation bekommen.

Um die Knoten-ID für eine SCI-Karte zu setzen, geben Sie folgenden Befehl im Verzeichnis /opt/DIS/sbin ein. In diesem Beispiel ist -c 1 die Nummer der SCI-Karte (diese ist immer 1, wenn nur eine Karte in den Computer eingebaut ist), -a 0 ist der Adapter 0 und 68 ist die Knoten-ID:

shell> ./sciconfig -c 1 -a 0 -n 68

Wenn mehrere SCI-Karten in demselben Computer eingebaut sind, können Sie mit folgendem Befehl ermitteln, welche Karte welchen Steckplatz hat (wir gehen wieder davon aus, dass /opt/DIS/sbin das aktuelle Arbeitsverzeichnis ist):

shell> ./sciconfig -c 1 -gsn

So erhalten Sie die Seriennummer der SCI-Karte. Diesen Vorgang wiederholen Sie dann mit -c 2 und so weiter für jede Karte im Computer. Sobald Sie jede Karte einem Steckplatz zugeordnet haben, können Sie für alle Karten Knoten-IDs einrichten.

Sobald die notwendigen Bibliotheken und Binaries installiert und die SCI-Knoten-IDs gesetzt sind, ordnen Sie als Nächstes die Hostnamen oder IP-Adressen den SCI-Knoten-IDs zu. Dies tun Sie in der Konfigurationsdatei für SCI Sockets, die normalerweise unter /etc/sci/scisock.conf gespeichert sein müsste. In dieser Datei ist jeder SCI-Knoten-ID über die jeweilige SCI-Karte der Hostname oder die IP-Adresse zugeordnet, mit der sie kommunizieren soll. Hier sehen Sie ein sehr einfaches Beispiel für eine solche Konfigurationsdatei:

#host           #nodeId
alpha           8
beta            12
192.168.10.20   16

Sie können die Konfiguration auch so einschränken, dass sie nur für einen Teil der verfügbaren Ports für diese Hosts gilt. Hierfür können Sie eine zusätzliche Konfigurationsdatei namens /etc/sci/scisock_opt.conf verwenden:

#-key                        -type        -values
EnablePortsByDefault                yes
EnablePort                  tcp           2200
DisablePort                 tcp           2201
EnablePortRange             tcp           2202 2219
DisablePortRange            tcp           2220 2231

Treiberinstallation

Wenn die Konfigurationsdateien eingerichtet sind, können die Treiber installiert werden.

Als Erstes installieren Sie die Treiber der unteren Ebene und dann den SCI Socket-Treiber:

shell> cd DIS/sbin/
shell> ./drv-install add PSB66
shell> ./scisocket-install add

Auf Wunsch kann die Installation mit einem Skript überprüft werden, das nachschaut, ob auf alle Knoten in den SCI Socket-Konfigurationsdateien Zugriff besteht:

shell> cd /opt/DIS/sbin/
shell> ./status.sh

Wenn Sie auf einen Fehler stoßen und die SCI Socket-Konfiguration ändern müssen, so tun Sie dies mit ksocketconfig:

shell> cd /opt/DIS/util
shell> ./ksocketconfig -f

Das Setup testen

Mit dem Testprogramm latency_bench können Sie sich vergewissern, dass auch tatsächlich die SCI Sockets benutzt werden. Mit der Serverkomponente dieses Dienstprogramms können sich die Clients mit dem Server verbinden, um die Verbindungslatenz zu überprüfen. Wenn Sie die Latenz beobachten, haben Sie schnell heraus, ob SCI aktiviert ist oder nicht. (Hinweis: Bevor Sie latency_bench sagen, müssen Sie die Umgebungsvariable LD_PRELOAD so einstellen, wie es weiter unten in diesem Abschnitt gezeigt wird.)

Um einen Server einzurichten, tun Sie Folgendes:

shell> cd /opt/DIS/bin/socket
shell> ./latency_bench -server

Um einen Client zu betreiben, führen Sie latency_bench erneut aus, diesmal allerdings mit der Option -client:

shell> cd /opt/DIS/bin/socket
shell> ./latency_bench -client server_hostname

Die SCI Socket-Konfiguration sollte nun abgeschlossen und MySQL Cluster bereit für die Nutzung von SCI Sockets und SCI Transporter sein (siehe Abschnitt 16.4.4.10, „MySQL Cluster: SCI-Transportverbindungen“).

Den Cluster starten

Der nächste Schritt besteht darin, MySQL Cluster zu starten. Um SCI Sockets einzuschalten, müssen Sie die Umgebungsvariable LD_PRELOAD einstellen, bevor Sie ndbd, mysqld und ndb_mgmd laufen lassen. Diese Variable sollte auf die Kernel-Bibliothek von SCI Sockets verweisen.

Folgendermaßen wird ndbd in einer Bash-Shell gestartet:

bash-shell> export LD_PRELOAD=/opt/DIS/lib/libkscisock.so
bash-shell> ndbd

In einer tcsh-Umgebung erreichen Sie dasselbe mit:

tcsh-shell> setenv LD_PRELOAD=/opt/DIS/lib/libkscisock.so
tcsh-shell> ndbd

Hinweis: MySQL Cluster kann nur die Kernel-Variante von SCI Sockets nutzen.

16.7.2. Auswirkungen der Cluster-Interconnects verstehen

Der ndbd-Prozess hat eine Reihe von einfachen Konstrukten, um auf die Daten in einem MySQL Cluster zuzugreifen. Wir haben eine ganz einfache Benchmark erstellt, um die jeweilige Leistung dieser Konstrukte zu testen und herauszufinden, wie sich die verschiedenen Verbindungen zwischen den Knoten auf diese Leistung auswirken.

Es gibt vier Zugriffsmethoden:

  • Zugriff über Primärschlüssel

    Das ist der Zugriff auf einen Datensatz über seinen Primärschlüssel. Im einfachsten Fall wird immer nur auf einen einzigen Datensatz zugegriffen, was bedeutet, dass dieser eine einzige Request den vollen Aufwand verursacht, der erforderlich ist, um mehrere TCP/IP-Nachrichten und Kontextwechsel zu bewältigen. Wenn dagegen mehrere Primärschlüsselzugriffe in einem Stapel versandt werden, teilen sich diese Zugriffe die Kosten der notwendigen TCP/IP-Nachrichten und Kontextwechsel. Wenn die TCP/IP-Nachrichten an verschiedene Ziele gehen, müssen allerdings zusätzliche TCP/IP-Nachrichten eingerichtet werden.

  • Zugriff über eindeutigen Schlüssel

    Zugriffe über eindeutige (unique) Schlüssel ähneln den Primärschlüsselzugriffen, allerdings mit dem Unterschied, dass sie als Leseoperation auf einer Indextabelle mit nachgeschaltetem Primärschlüsselzugriff auf die Tabelle funktionieren. Allerdings wird nur ein einziger Request vom MySQL Server abgeschickt und der Lesevorgang auf der Indextabelle wird von ndbd ausgeführt. Auch diese Art von Requests profitiert von der Stapelverarbeitung.

  • Vollständiger Tabellenscan

    Wenn für einen Tabellen-Lookup keine Indizes vorhanden sind, wird ein vollständiger Tabellenscan ausgeführt. Dieser wird als ein einziger Request an den ndbd-Prozess gesandt, der dann den Tabellenscan in eine Menge von parallelen Scans auf alle ndbd-Prozesse im Cluster verteilt. In künftigen Versionen von MySQL Cluster wird ein SQL-Knoten in der Lage sein, manche dieser Scans herauszufiltern.

  • Bereichsscan mit geordnetem Index

    Wenn ein geordneter Index verwendet wird, führt dieser eine Art vollständigen Tabellenscan aus, scannt aber nur die Datensätze in dem Intervall, welches die vom MySQL Server (SQL-Knoten) übermittelte Anfrage angibt. Alle Partitionen werden parallel gescannt, wenn alle gebundenen Indexattribute alle Attribute im Partitionierungsschlüssel enthalten.

Um die Grundleistung dieser Zugriffsmethoden testen zu können, haben wir eine Reihe von Benchmarks entwickelt. Eine davon, nämlich testReadPerf, testet einzeln und im Stapel übersandte Zugriffe über Primärschlüssel oder eindeutige Schlüssel. Diese Benchmark misst auch den Setup-Aufwand von Bereichsscans, indem sie Scans ausführt, die einen einzelnen Datensatz zurückliefern. Eine andere Variante dieser Benchmark holt mit einem Bereichsscan eine Menge von Datensätzen ab.

So können wir die Kosten eines einzelnen Schlüsselzugriffs und eines einzelnen Datensatzscans ermitteln und zusätzlich festellen, wie sich die Kommunikationsmedien bei welcher Zugriffsmethode auswirken.

In unseren Tests haben wir die Basis-Benchmarks sowohl für einen normalen Transporter mit TCP/IP-Sockets als auch für eine ähnliche Umgebung mit SCI Sockets ermittelt. Die Zahlen in der folgenden Tabelle gelten für kleinere Abfragen mit 20 Datensätzen pro Zugriff. Die Differenz zwischen seriellem und Stapelzugriff access schrumpft um den Faktor 3 bis 4, wenn stattdessen 2-Kbyte-Datensätze verwendet werden. SCI Sockets wurden nicht mit 2-Kbyte-Datensätzen getestet. Die Tests wurden auf einem Cluster mit 2 Datenknoten gefahren, der auf zwei Computern mit je zwei CPUs (AMD MP1900+-Prozessoren) residiert.

ZugriffsartTCP/IP-SocketsSCI Socket
Serieller Primärschlüsselzugriff400 Mikrosekunden160 Mikrosekunden
Primärschlüsselzugriff im Stapel28 Mikrosekunden22 Mikrosekunden
Serieller Zugriff auf eindeutigen Schlüssel500 Mikrosekunden250 Mikrosekunden
Stapelzugriff auf eindeutigen Schlüssel70 Mikrosekunden36 Mikrosekunden
Indizierter eq-bound1.250 Mikrosekunden750 Mikrosekunden
Indexbereich24 Mikrosekunden12 Mikrosekunden

In einer anderen Testreihe haben wir die Leistung der SCI Sockets der des SCI Transporters und diese beiden wiederum der Leistung eines TCP/IP-Transporters gegenübergestellt. Alle diese Tests verwendeten Primärschlüsselzugriffe, entweder seriell und mit mehreren Threads oder mit mehreren Threads und im Stapel.

Die Tests haben gezeigt, dass SCI Sockets um rund 100 % schneller waren als TCP/IP. Der SCI Transporter war in den meisten Fällen schneller als SCI Sockets. Ein bemerkenswerter Fall trat bei einem Testprogramm mit vielen Threads auf: Hier zeigte sich, dass der SCI Transporter keine gute Leistung brachte, wenn er für den mysqld-Prozess benutzt wird.

Insgesamt zeigen unsere Tests, dass SCI Sockets in den meisten Benchmarks rund 100 % schneller sind als TCP/IP, außer in seltenen Fällen, in denen es nicht auf die Geschwindigkeit der Kommunikation ankommt. Dies kann der Fall sein, wenn die meiste Verarbeitungszeit für Scanfilter verbraucht wird oder wenn sehr große Stapel von Primärschlüsselzugriffen zustande kommen. In diesem Fall macht die CPU-Last der ndbd-Prozesse einen großen Teil des Aufwands aus.

Eine Verwendung des SCI Transporters anstelle von SCI Sockets ist nur für die Kommunikation zwischen ndbd-Prozessen interessant. Der SCI Transporter ist jedoch auch eine Option, wenn eine CPU für den ndbd-Prozess dediziert werden kann, da der SCI Transporter dafür sorgen kann, dass dieser Prozess niemals schläft. Außerdem ist es wichtig, zu gewährleisten, dass die Priorität des ndbd-Prozesses so eingestellt wird, dass er auch nach langem Laufen seine Priorität nicht einbüßt. Dies kann in Linux 2.6 durch das Sperren von Prozessen in CPUs getan werden. Wenn eine solche Konfiguration machbar ist, legt der ndbd-Prozess im Vergleich zu einer Lösung mit SCI Sockets um 10 bis 70 % zu. (Die größeren Zahlen kommen bei Updates und möglicherweise auch bei Parallelscans zustande.)

Es gibt noch mehrere andere optimierte Socketimplementierungen für Computer-Cluster, darunter Myrinet, Gigabit Ethernet, Infiniband und die VIA-Schnittstelle. Wir haben MySQL Cluster bisher jedoch nur mit SCI Sockets getestet. Unter Abschnitt 16.7.1, „Konfiguration von MySQL Cluster für SCI Sockets“, erfahren Sie, wie Sie SCI Sockets mit normalem TCP/IP für MySQL Cluster einrichten.

16.8. Bekannte Beschränkungen von MySQL Cluster

In diesem Abschnitt finden Sie eine Liste bekannter Einschränkungen in den MySQL Cluster-Releases der 5.1.x-Serie im Vergleich zu den Features, die beim Einsatz der Speicher-Engines MyISAM und InnoDB zur Verfügung stehen. Es ist zurzeit nicht geplant, diese Einschränkungen in den nächsten Releases von MySQL 5.1 zu beseitigen, aber wir werden versuchen, in der darauf folgenden Serie von Releases Lösungen für diese Probleme zu finden. Wenn Sie in der MySQL-Bugs-Datenbank http://bugs.mysql.com unter der Kategorie „Cluster“ nachschauen, erfahren Sie, welche bekannten Bugs (soweit sie mit „5.1“ markiert sind) in den nächsten Releases von MySQL 5.1 behoben werden sollen.

Die hier aufgeführte Liste sollte unter den soeben genannten Bedingungen komplett sein. Falls Ihnen irgendwelche Diskrepanzen auffallen, können Sie diese an die MySQL-Bugs-Datenbank melden, wie es unter Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschrieben ist. Wenn wir nicht planen, das Problem in MySQL 5.1 zu beheben, werden wir es mit auf die Liste setzen.

  • Nichtkonforme Syntax (führt zu Fehlern bei der Ausführung vorhandener Anwendungen):

    • Textindizes werden nicht unterstützt.

    • Geometrische Datentypen (WKT und WKB) werden in NDB-Tabellen in MySQL 5.1 unterstützt, aber raumbezogene (spatial) Indizes nicht.

    • Es ist nicht möglich, Partitionen von NDB-Tabellen mit ALTER TABLE ... DROP PARTITION zu löschen. Die anderen Partitionierungserweiterungen für ALTER TABLE, nämlich ADD PARTITION, REORGANIZE PARTITION und COALESCE PARTITION, werden für Cluster-Tabellen unterstützt, aber Kopieren usw. ist nicht optimiert. Siehe auch Abschnitt 17.3.1, „Verwaltung von RANGE- und LIST-Partitionen“, und Abschnitt 13.1.2, „ALTER TABLE.

      Seit MySQL 5.1.6 werden alle Cluster-Tabellen standardmäßig nach KEY partitioniert, wobei der Primärschlüssel der Tabelle als Partitionierungsschlüssel verwendet wird. Ist für die Tabelle nicht explizit ein Primärschlüssel definiert, wird automatisch von der Speicher-Engine NDB ein „verborgener“ Primärschlüssel erzeugt und benutzt. Mehr zu diesem und verwandten Themen finden Sie unter Abschnitt 17.2.4, „KEY-Partitionierung“.

  • Nichtkonforme Grenzwerte oder Verhalten (kann bei der Ausführung vorhandener Anwendungen zu Fehlern führen):

    • Transaktionsbehandlung:

      • NDB Cluster unterstützt als einzige Ebene der Transaktionsisolation READ COMMITTED.

      • Ein teilweises Zurückrollen von Transaktionen ist nicht möglich. Ein Fehler wegen eines doppelten Schlüssels oder etwas Ähnlichem führt dazu, dass die gesamte Transaktion zurückgerollt wird.

      • Wichtig: Wenn ein SELECT auf einer Cluster-Tabelle eine Spalte des Typs BLOB, TEXT oder VARCHAR enthält, wird die Transaktionsisolationsebene READ COMMITTED in einen Lesevorgang mit Lesesperre umgewandelt. Dies wird getan, um die Konsistenz zu garantieren, da Teile der in solchen Spalten gespeicherten Werte in Wirklichkeit aus einer anderen Tabelle gelesen werden.

    • Es gibt eine Reihe von harten Grenzwerten, die konfigurierbar sind, aber der im Cluster verfügbare Hauptspeicher setzt auf jeden Fall Grenzen. Die vollständige Liste der Konfigurationsparameter finden Sie in Abschnitt 16.4.4, „Konfigurationsdatei“. Die meisten dieser Parameter können online aktualisiert werden. Die erwähnten festen Grenzen sind:

      • Jeweiliger Arbeitsspeicher für Datenbank und Index (DataMemory und IndexMemory).

      • Wie viele Transaktionen höchstens ausgeführt werden können, ist im Konfigurationsparameter MaxNoOfConcurrentOperations festgelegt. Beachten Sie, das Massenladeoperationen, TRUNCATE TABLE, und ALTER TABLE als Sonderfälle mit mehreren Transaktionen abgearbeitet werden und daher nicht dieser Einschränkung unterliegen.

      • Verschiedene Grenzwerte für Tabellen und Indizes. So wird beispielsweise die Höchstzahl der geordneten Indizes pro Tabelle durch MaxNoOfOrderedIndexes festgesetzt.

    • Datenbank-, Tabellen- und Attributnamen dürfen in NDB-Tabellen nicht so lang sein wie bei anderen Tabellen-Handlern. Attributnamen werden auf 31 Zeichen gekappt. Wenn sie dann nicht mehr eindeutig sind, gibt es einen Fehler. Datenbank- und Tabellennamen können insgesamt 122 Zeichen lang sein. (Das bedeutet, dass ein Name einer NDB Cluster-Tabelle maximal 122 Zeichen minus die Länge des Namens der Datenbank haben kann, zu welcher die Tabelle gehört.)

    • Alle Zeilen von Cluster-Tabellen haben eine feste Länge. Wenn also (zum Beispiel) eine Tabelle ein oder mehrere VARCHAR-Felder mit relativ kleinen Werten hat, brauchen diese bei der Speicher-Engine NDB mehr Speicherplatz als bei der Speicher-Engine MyISAM. (Mit anderen Worten, eine VARCHAR-Spalte belegt beispielsweise ebenso viel Speicher wie eine gleich große CHAR-Spalte.)

    • Die Höchstzahl der Tabellen in einer Cluster-Datenbank ist auf 1.792 beschränkt.

    • Die Höchstzahl der Attribute pro Tabelle ist auf 128 beschränkt.

    • Die maximal zulässige Größe einer Zeile ist 8 Kbyte, nicht inbegriffen die in BLOB-Spalten gespeicherten Daten.

    • Die Höchstzahl der Attribute pro Schlüssel beträgt 32.

  • Nicht unterstützte Features (verursachen keinen Fehler, werden aber nicht unterstützt oder verlangt):

    • Das Fremdschlüsselkonstrukt wird, genau wie in MyISAM-Tabellen, ignoriert.

    • Savepoints und Rollbacks zu Savepoints werden, genau wie in MyISAM-Tabellen, ignoriert.

  • Probleme im Zusammenhang mit Leistung und Einschränkungen:

    • Aufgrund des sequenziellen Zugriffs hat die NDB-Speicher-Engine Leistungsprobleme mit Anfragen. Auch ist es aufwändiger als mit MyISAM oder InnoDB, viele Bereichsscans auszuführen.

    • Die Records in range-Statistik wird nicht unterstützt, sodass sich in einigen Fällen ungünstige Anfragenpläne ergeben. Als Workaround empfehlen sich USE INDEX oder FORCE INDEX.

    • Sie können keine mit USING HASH erzeugten eindeutigen Hash-Indizes für den Zugriff auf eine Tabelle verwenden, wenn NULL als Teil des Schlüssels angegeben ist.

    • MySQL Cluster unterstützt keine permanenten Commits auf der Platte. Commits werden repliziert, aber es gibt keine Garantie dafür, dass die Logs beim Committen auf die Platte zurückgeschrieben werden.

  • Fehlende Features:

    • Die einzige Isolationsebene, die unterstützt wird, ist READ COMMITTED. (InnoDB unterstützt READ COMMITTED, READ COMMITTED, REPEATABLE READ und SERIALIZABLE.) Unter Abschnitt 16.6.5.5, „Backup: Troubleshooting“, können Sie nachlesen, wie sich dies auf die Sicherung und Wiederherstellung von Cluster-Datenbanken auswirkt.

    • Es gibt keine dauerhaften Commits auf der Platte. Die Commits werden repliziert, aber es gibt keine Garantie dafür, dass die Logs beim Committen auf die Platte zurückgeschrieben werden.

  • Probleme mit mehreren MySQL Servern (betreffen nicht MyISAM oder InnoDB):

    • ALTER TABLE sperrt nicht vollständig, wenn mehrere MySQL Server betrieben werden (keine verteilte Tabellensperre).

    • MySQL-Replikation funktioniert nicht richtig, wenn Updates auf mehreren MySQL Servern ausgeführt werden. Wenn jedoch das Datenbank-Partitionierungsschema auf Anwendungsebene durchgeführt wird und keine Transaktionen über diese Partitionen hinweg stattfinden, kann die Replikation funktionieren.

    • Das selbstständige Erkennen von Datenbanken wird nicht für mehrere MySQL Server unterstützt, die auf denselben MySQL Cluster zugreifen. Die selbstständige Erkennung von Tabellen wird dagegen in diesen Fälllen unterstützt. Wenn also eine Datenbank namens db_name mit einem einzigen MySQL Server angelegt oder importiert wurde, müssen Sie für jeden weiteren Server, der auf denselben MySQL Cluster zugreift, eine CREATE SCHEMA db_name-Anweisung erteilen. Wenn dies für einen gegebenen MySQL Server erledigt ist, müsste dieser in der Lage sein, die Datenbanktabellen ohne Fehler zu erkennen.

  • Probleme, die ausschließlich MySQL Cluster betreffen (nicht MyISAM oder InnoDB):

    • Alle Cluster-Computer müssen dieselbe Architektur haben. Das bedeutet, dass alle Knoten-Hosts konsistent entweder big-endian oder little-endian sein müssen. Beispielsweise darf es keinen Management-Knoten auf einem Power-PC geben, der einen Datenknoten auf einer x86-Maschine regelt. Diese Einschränkung gilt nicht für Computer, die einfach nur mysql ausführen, oder andere Clients, die vielleicht auf die SQL-Knoten des Clusters zugreifen.

    • Es sind keine Online-Schemaänderungen mit ALTER TABLE oder CREATE INDEX möglich, da NDB Cluster nicht die selbstständige Erkennung solcher Änderungen unterstützt. (Sie können jedoch eine Tabelle importieren oder anlegen, die eine andere Speicher-Engine nutzt, und diese dann mit ALTER TABLE tbl_name ENGINE=NDBCLUSTER in eine NDB-Tabelle umwandeln. In solchen Fällen müssen Sie eine FLUSH TABLES-Anweisung geben, um den Cluster zu zwingen, die Änderung aufzugreifen.)

    • Es ist nicht möglich, Knoten online hinzuzufügen oder zu löschen (der Cluster muss in solchen Fällen neu gestartet werden).

    • Wenn mehrere Management-Server verwendet werden, gelten folgende Regeln:

      • Sie müssen den Knoten in Verbindungs-Strings explizite IDs geben, da die automatische Zuweisung von Knoten-IDs nicht über mehrere Management-Server hinweg funktioniert.

      • Sie müssen genau darauf achten, dass alle Management-Server gleich konfiguriert sind. Der Cluster wird dies nicht extra prüfen.

      • Damit die Management-Knoten voneinander wissen, müssen Sie alle Datenknoten neu starten, nachdem der Cluster eingerichtet ist. (Genaue Erläuterungen finden Sie unter Bug#13070.)

    • Einige Netzwerkschnittstellen für Datenknoten werden nicht unterstützt. Wenn Sie diese verwenden, bekommen Sie Probleme: Wenn ein Datenknoten abstürzt, wartet ein SQL-Knoten auf die Bestätigung, dass der Datenknoten nicht mehr läuft, bekommt aber keine, da eine andere Route zu dem betroffenen Datenknoten weiterhin offen bleibt. Im Endeffekt kann dies den ganzen Cluster unbenutzbar machen.

    • Die Höchstzahl der Datenknoten beträgt 48.

    • Die Gesamtzahl aller Knoten in einem MySQL Cluster beträgt 63. Das umfasst sämtliche MySQL Server (SQL-Knoten), Datenknoten und Management-Server.

    • Die Höchstzahl der Metadatenobjekte in MySQL 5.1 Cluster beträgt 20.320. Diese Obergrenze ist fest eingegeben.

16.9. MySQL Cluster: Roadmap für die Entwicklung

In diesem Abschnitt geht es um Änderungen an der Implementierung von MySQL Cluster in MySQL 5.1 im Vergleich zu MySQL 5.0. Außerdem werden wir unseren Fahrplan für künftige Verbesserungen an MySQL Cluster vorstellen, wie sie gegenwärtig für MySQL 5.2 vorgesehen sind.

Es gibt relativ wenig Änderungen zwischen der Implementierung von NDB Cluster in MySQL 5.0 und in 5.1, sodass der Upgrade relativ schnell und schmerzlos vonstatten gehen sollte.

Alle bedeutenden neuen Features, die für MySQL Cluster entwickelt werden sollen, kommen in den Baum von MySQL 5.1. Außerdem weisen wir weiter unten in diesem Abschnitt (siehe Abschnitt 16.9.2, „MySQL 5.1 Roadmap für die Entwicklung von MySQL Cluster“) darauf hin, was die Cluster in MySQL 5.1 voraussichtlich alles enthalten werden.

16.9.1. MySQL Cluster: Änderungen in MySQL 5.0

MySQL Cluster enthält in den Versionen 5.0.3-beta und folgende eine Reihe von neuen Features, die sicherlich interessant sein werden:

  • Pushdown-Bedingungen: Betrachten Sie folgende Anfrage:

    SELECT * FROM t1 WHERE non_indexed_attribute = 1;
    

    Diese Anfrage wird einen vollständigen Tabellenscan ausführen und die Bedingung wird in den Datenknoten des Clusters ausgewertet. Daher ist es nicht nötig, die Datensätze zur Auswertung durchs Netzwerk zu schicken. (Es werden also Funktionen und nicht Daten transportiert.) Bitte beachten Sie, dass dieses Feature gegenwärtig nach Voreinstellung deaktiviert ist (da die gründlicheren Tests noch nicht abgeschlossen sind), aber in den meisten Fällen bereits funktionieren müsste. Dieses Feature kann mit der Anweisung SET engine_condition_pushdown = On aktiviert werden. Alternativ können Sie mysqld so laufen lassen, dass das Feature eingeschaltet wird, indem Sie den MySQL Server mit der Option --engine-condition-pushdown starten.

    Ein Hauptvorteil dieser Änderung besteht darin, dass Anfragen parallel ausgeführt werden können. So laufen Anfragen auf nichtindizierten Spalten unter Umständen fünf- bis zehnmal schneller als zuvor, und dies mal der Anzahl der Datenknoten, da mehrere CPUs die Anfrage parallel bearbeiten können.

    Mit dem Befehl EXPLAIN können Sie ermitteln, wann Pushdown-Bedingungen verwendet werden. Siehe auch Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“.

  • Weniger Platzbedarf IndexMemory: In MySQL 5.1 belegt jeder Datensatz ungefähr 25 Byte Index Memory und jeder eindeutige Index 25 Byte pro Datensatz (und zusätzlich noch einigen Platz im Data Memory, da diese Datensätze in einer separaten Tabelle gespeichert werden). Das liegt daran, dass der Primärschlüssel nun nicht mehr im Index Memory gespeichert wird.

  • Der Anfragen-Cache ist für MySQL Cluster aktiviert: Mehr über die Konfiguration und Nutzung des Anfragen-Caches erfahren Sie unter Abschnitt 5.14, „MySQL-Anfragen-Cache“.

  • Neue Optimierungen: Eine Optimierung verdient eine gesonderte Erwähnung: Nämlich die, dass nun in manchen Anfragen ein Batched Read Interface verwendet wird. Betrachten Sie zum Beispiel folgende Anfrage:

    SELECT * FROM t1 WHERE primary_key IN (1,2,3,4,5,6,7,8,9,10);
    

    Diese Anfrage wird zwei- bis dreimal schneller bearbeitet als in den früheren Versionen von MySQL Cluster, da alle zehn Schlüssel-Lookups in einem einzigen Schwung statt immer nacheinander übersandt werden.

  • Obergrenze für einige Metadatenobjekte: In MySQL 5.1 kann jede Cluster-Datenbank bis zu 20.320 Metadatenobjekte enthalten, einschließlich Datenbanktabellen, Systemtabellen, Indizes und BLOBs.

16.9.2. MySQL 5.1 Roadmap für die Entwicklung von MySQL Cluster

Das Folgende ist ein Zustandsbericht über die neuesten Commits im MySQL 5.1-Quellbaum. Bitte beachten Sie, dass alle Entwicklungen an 5.1 sich noch laufend ändern können.

Gegenwärtig werden vier wichtige neue Features für MySQL 5.1 entwickelt:

  1. Integration von MySQL Cluster in die MySQL-Replikation: Dadurch wird es möglich, von jedem beliebigen MySQL Server im Cluster Updates zu veranlassen und dennoch weiterhin die MySQL-Replikation von einem der MySQL Server im Cluster erledigen zu lassen, wobei der Status auf der Slave-Seite immer mit dem Cluster konsistent bleibt, der als Master fungiert.

  2. Unterstützung für festplattenbasierte Datensätze: Datensätze auf Platte werden künftig unterstützt. Indizierte Felder mit Primärschlüssel-Hash-Index müssen zwar weiterhin im RAM gespeichert werden, aber alle anderen Felder können auf der Festplatte liegen.

  3. Datensätze variabler Länge: Eine VARCHAR(255)-Spalte belegt zurzeit unabhängig von dem tatsächlichen Inhalt des Datensatzes immer 260 Byte. In MySQL 5.1 Cluster-Tabellen wird nur der Teil der Spalte gespeichert, der tatsächlich von Datensatzdaten belegt ist. Dadurch kann der Speicherplatzbedarf für solche Spalten in vielen Fällen um maximal das Fünffache schrumpfen.

  4. Benutzerdefinierte Partitionierung: Die Benutzer können nun Partitionen anhand von Spalten definieren, die Teil des Primärschlüssels sind. Der MySQL Server kann feststellen, ob es möglich ist, einige der Partitionen aus der WHERE-Klausel auszuschließen. Eine Partitionierung anhand der KEY-, HASH-, RANGE- und LIST-Handler wird nun ebenso wie eine Teilpartitionierung möglich sein. Dieses Feature sollte auch für viele andere Handler und nicht nur für NDB Cluster zur Verfügung stehen.

Zusätzlich arbeiten wir daran, das 8-Kbyte-Limit auch für Zeilen in Cluster-Tabellen heraufzusetzen, die andere Spaltentypen als BLOB oder TEXT enthalten. Denn gegenwärtig sind die Zeilen noch auf diese Größe festgelegt und die Seitengröße beträgt 32.768 Byte (minus 128 Byte für den Zeilen-Header). Wenn wir also mehr als 8 Kbyte pro Datensatz gestatten, würde daher der übrige Platz (bis zu ungefähr 14.000 Byte) leer bleiben. In MySQL 5.1 wollen wir diese Einschränkung beseitigen, sodass nicht mehr der ganze Rest der Seite verschwendet wird, wenn mehr als 8 Kbyte für eine Zeile benötigt werden.

16.10. MySQL Cluster: FAQ

In diesem Abschnitt werden häufig gestellte Fragen über MySQL Cluster beantwortet.

  • Was ist „NDB“?

    Dies steht für „Network DataBase“.

  • Was macht es für einen Unterschied, ob ich Cluster oder Replikation nutze?

    Bei einer Replikation aktualisiert ein MySQL-Master-Server einen oder mehrere Slaves. Transaktionen werden nacheinander committet und eine langsame Transaktion kann dazu führen, dass der Slave hinter dem Master zurückbleibt. Das bedeutet: Wenn der Master abstürzt, kann es dazu kommen, dass der Slave die letzten paar Transaktionen nicht mitbekommen hat. Wird eine transaktionssichere Engine wie InnoDB benutzt, so wird eine Transaktion auf dem Slave entweder abgeschlossen oder gar nicht angewendet. Bei der Replikation ist jedoch nicht garantiert, dass alle Daten auf dem Master und dem Slave zu jedem Zeitpunkt konsistent sind. In MySQL Cluster hingegen sind immer alle Datenknoten synchron und eine Transaktion, die von irgendeinem Datenknoten committet wird, wird für alle Datenknoten committet. Wenn ein Datenknoten abstürzt, bleiben alle übrigen Datenknoten in einem konsistenten Zustand zurück.

    Kurz: Während die MySQL-Replikation standardmäßig asynchron ist, ist MySQL Cluster synchron.

    Wir planen, eine (asynchrone) Replikation für Cluster in MySQL 5.1 einzuführen. Dazu gehört auch die Fähigkeit, sowohl zwischen zwei Clustern als auch zwischen einem geclusterten und einem nichtgeclusterten MySQL Server zu replizieren.

  • Benötige ich ein spezielles Netzwerk für Cluster? (Wie kommunizieren Computer in einem Cluster?)

    MySQL Cluster ist für die Benutzung in einer Umgebung mit großer Bandbreite und über TCP/IP verbundene Computer ausgelegt. Die Leistung des Clusters hängt direkt von der Schnelligkeit der Verbindungen zwischen den Cluster-Computern ab. Die Mindestanforderung für die Konnektivität in einem Cluster ist ein typisches 100-Megabit-Ethernet-Netzwerk oder etwas Entsprechendes. Wir empfehlen Ihnen, nach Möglichkeit ein 1-Gigabit-Ethernet einzusetzen.

    Das schnellere SCI-Protokoll wird ebenfalls unterstützt, benötigt jedoch eine spezielle Hardware. Weitere Informationen über SCI finden Sie unter Abschnitt 16.7, „Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster“.

  • Wie viele Computer sind für einen Cluster erforderlich und warum?

    Für einen benutzbaren Cluster sind mindestens drei Computer notwendig. Empfohlen werden jedoch mindestens vier: je einer für den Management- und den SQL-Knoten und zwei, die als Speicherknoten dienen. Zwei Datenknoten sind wegen der Redundanz ratsam und der Management-Knoten muss auf einem eigenen Computer laufen, um auch beim Absturz eines Datenknotens weiterhin die Arbitrator-Funktion aufrechterhalten zu können.

  • Was tun die verschiedenen Computer in einem Cluster?

    Ein MySQL Cluster hat sowohl eine physikalische als auch eine logische Struktur, wobei die Computer die physikalischen Elemente sind. Die logischen oder funktionalen Elemente eines Clusters werden als Knoten bezeichnet und ein Computer, auf dem ein Cluster-Knoten läuft, wird Cluster-Host genannt. Im Idealfall gibt es einen Knoten pro Cluster-Host, allerdings können auf einem einzelnen Host auch mehrere Knoten laufen. Es gibt drei Knotentypen, von denen jeder im Cluster eine bestimmte Rolle spielt:

    • Management-Knoten (MGM-Knoten): Leistet Management-Dienste für den Cluster als Ganzes, darunter Hochfahren, Herunterfahren, Datensicherungen und Bereitstellung von Konfigurationsdaten für die anderen Knoten. Der Management-Knoten-Server ist in Form der Anwendung ndb_mgmd implementiert, und der Management-Client, der den MySQL Cluster über den MGM-Knoten kontrolliert, ist ndb_mgm.

    • Datenknoten: Speichert und repliziert Daten. Seine Funktionalität erhält der Datenknoten von einer Instanz des NDB-Datenknotenprozesses ndbd.

    • SQL-Knoten: Dieser ist einfach eine Instanz von MySQL Server (mysqld), die mit Unterstützung für die Speicher-Engine NDB Cluster gebaut und mit der Option --ndb-cluster gestartet wurde, welche die Engine aktiviert.

  • Mit welchen Betriebssystemen kann ich Cluster benutzen?

    MySQL Cluster wird offiziell für Linux, Mac OS X und Solaris unterstützt. Wir arbeiten daran, Cluster auch auf anderen Plattformen zu ermöglichen (einschließlich Windows), und haben uns das Ziel gesetzt, MySQL Cluster irgendwann auf allen Plattformen zu unterstützen, auf denen auch MySQL selbst läuft.

    Es könnte möglich sein, Cluster-Prozesse auch auf anderen Betriebssystemen auszuführen. Einige Anwender berichten, Cluster bereits erfolgreich auf FreeBSD betrieben zu haben. Allerdings können Cluster auf anderen als den hier erwähnten drei Betriebssystemen bestenfalls als Alpha-Software gelten. Ihre Zuverlässigkeit in einer Produktionsumgebung kann nicht garantiert werden und wird nicht von MySQL AB unterstützt.

  • Welche Hardwareanforderungen stellt MySQL Cluster?

    Cluster müssten auf jeder Plattform laufen, für die NDB-fähige Binaries zur Verfügung stehen. Natürlich wird die Leistung mit schnelleren CPUs und größerem Arbeitsspeicher besser, und 64-Bit-CPUs sind schneller als 32-Bit-Prozessoren. Die als Datenknoten verwendeten Computer müssen genug Arbeitsspeicher haben, um den Teil der Datenbank zu speichern, der auf diesem Datenknoten liegt (weitere Informationen siehe Wie viel RAM brauche ich?). Die Knoten können über ein normales TCP/IP-Netzwerk mit Standardhardware kommunizieren. Für die SCI-Unterstützung ist spezielle Netzwerkhardware erforderlich.

  • Wie viel RAM brauche ich? Kann überhaupt Festplattenspeicher benutzt werden?

    Zurzeit sind Cluster lediglich arbeitsspeicherresident, sodass alle Tabellendaten (einschließlich Indizes) im Arbeitsspeicher abgelegt werden. Wenn Ihre Daten 1 Gbyte Platz benötigen und Sie sie einmal im Cluster replizieren möchten, benötigen Sie dafür folglich 2 Gbyte Hauptspeicher. Hinzu kommt der Arbeitsspeicher, den das Betriebssystem und irgendwelche sonstigen Anwendungen belegen, die auf den Cluster-Computern laufen.

    Die folgende Formel liefert eine grobe Schätzung des für jeden Datenknoten im Cluster benötigten Arbeitsspeicherbedarfs:

    (SizeofDatabase × NumberOfReplicas × 1.1 ) / NumberOfDataNodes
    

    Um den Speicherbedarf genauer zu berechnen, müssen Sie für jede Tabelle in der Cluster-Datenbank den pro Zeile erforderlichen Speicher ermitteln (Einzelheiten siehe Abschnitt 11.5, „Speicherbedarf von Spaltentypen“) und diesen Wert mit der Zeilenzahl multiplizieren. Außerdem müssen Sie die Spaltenindizes wie folgt mit einkalkulieren:

    • Jeder Primärschlüssel oder Hash-Index auf einer NDBCluster-Tabelle benötigt 21–25 Byte pro Datensatz. Diese Indizes nutzen das IndexMemory.

    • Jeder geordnete Index belegt pro Datensatz 10 Byte Speicher im DataMemory.

    • Jeder Primärschlüssel oder eindeutige Schlüsselindex erzeugt auch einen geordneten Index, wenn er nicht mit USING HASH angelegt wurde. Mit anderen Worten: Ein ohne USING HASH angelegter Primärschlüssel oder eindeutiger Index auf einer Cluster-Tabelle belegt in MySQL 5.1 31–35 Byte Speicher pro Datensatz.

      Beachten Sie, dass Tabellenänderungen generell schneller laufen, wenn alle Primärschlüssel und eindeutigen Indizes auf MySQL Cluster-Tabellen mit USING HASH angelegt werden, da dann weniger Arbeitsspeicher erforderlich ist (weil keine geordneten Indizes erzeugt werden) und auch die Belastung der CPU geringer ist (weil weniger Indizes gelesen und womöglich geändert werden müssen).

    Sehr wichtig: Bitte denken Sie daran, dass jede MySQL Cluster-Tabelle einen Primärschlüssel haben muss. Die Speicher-Engine NDB legt automatisch einen Primärschlüssel an, wenn nicht bereits einer definiert wurde, und dieser Primärschlüssel wird ohne USING HASH erzeugt.

    Es gibt kein einfaches Mittel, um genau festzustellen, wann wie viel Arbeitsspeicher von Cluster-Indizes belegt wird, aber wenn 80 % des verfügbaren DataMemory oder IndexMemory voll sind, wird eine Warnung in das Cluster-Log geschrieben. Weitere Warnungen gibt es, wenn 85 %, 90 % usw. erreicht werden.

    Oft erreichen uns Fragen von Anwendern, die berichten, dass der Ladeprozess beim Laden von Daten in eine Cluster-Datenbank vorzeitig mit einer Fehlermeldung wie dieser abbricht:

    ERROR 1114: The table 'my_cluster_table' is full
    

    Wenn dies geschieht, haben Sie höchstwahrscheinlich nicht genügend RAM für alle Datentabellen und Indizes einschließlich des von der Speicher-Engine NDB geforderten Primärschlüssels, der automatisch erzeugt wird, wenn er in der Tabellendefinition fehlt.

    Außerdem müssen Sie berücksichtigen, dass alle Datenknoten gleich viel RAM haben sollten, da in einem Cluster kein Datenknoten mehr Speicher übrig hat als der an Speicher ärmste Datenknoten des Clusters. Mit anderen Worten: Wenn drei Computer Cluster-Datenknoten hosten und zwei davon 3 Gbyte RAM für Cluster-Daten übrig haben, während dem dritten nur 1 Gbyte verbleibt, können alle drei Datenknoten nur noch 1 Gbyte Speicher für den Cluster verwenden.

  • Da MySQL Cluster mit TCP/IP arbeitet: Bedeutet dies, dass ich den Cluster im Internet betreiben und einen oder mehrere Knoten remote halten kann?

    Es ist mehr als zweifelhaft, dass ein Cluster unter solchen Bedingungen noch eine zuverlässige Leistung bringen könnte, da MySQL Cluster unter der Grundannahme entworfen und implementiert wurde, dass der Cluster eine Hochgeschwindigkeitsverbindung wie in einem LAN mit 100 Mbps oder einem Gigabit-Ethernet (vorzugsweise Letzterem) nutzen kann. Die Leistung mit einer langsameren Verbindung werden wir weder testen noch irgendwie gewährleisten.

    Außerdem ist es außerordentlich wichtig, immer daran zu denken, dass die Kommunikation zwischen Knoten in einem MySQL Cluster nicht sicher ist. Die Datenübermittlungen werden weder verschlüsselt noch durch irgendeinen anderen Schutzmechanismus abgesichert. Die sicherste Konfiguration für einen Cluster ist ein privates Netzwerk hinter einer Firewall, ohne direkten Zugriff von außerhalb auf irgendwelche Cluster-Daten oder Management-Knoten. (Für SQL-Knoten sollten Sie dieselben Vorkehrungen treffen wie für jede andere Instanz des MySQL Servers.)

  • Muss ich für Cluster eine neue Programmiersprache oder Datenbank-Abfragesprache lernen?

    Nein. Für die Verwaltung und Konfiguration des Clusters selbst werden zwar einige spezielle Befehle benötigt, aber für die folgenden Operationen sind nur (My)SQL-Standardabfragen und Standardbefehle erforderlich:

    • Tabellen anlegen, ändern und löschen

    • Tabellendaten einfügen, ändern und löschen

    • Primärschlüssel oder eindeutige Indizes anlegen, ändern und löschen

    • SQL-Knoten (MySQL Server) konfigurieren und verwalten.

  • Wie kann ich herausfinden, was eine Fehlermeldung oder Warnung bedeutet, wenn ich Cluster benutze?

    Dafür gibt es zwei Möglichkeiten:

    • Sie können im mysql-Client direkt nachdem Sie den Fehler oder die Warnung bekommen haben, SHOW ERRORS oder SHOW WARNINGS aufrufen. Fehler und Warnungen werden auch im MySQL Query Browser angezeigt.

    • Sie können an einem Prompt der System-Shell perror --ndb error_code ausführen.

  • Ist MySQL Cluster transaktionssicher? Welche Isolationsebenen werden unterstützt?

    Ja. Für Tabellen, die mit der Speicher-Engine NDB angelegt wurden, werden Transaktionen unterstützt. In MySQL 5.1 kennen Cluster allerdings als einzige Ebene der Transaktionsisolation READ COMMITTED.

  • Welche Speicher-Engines unterstützt MySQL Cluster?

    Clustering wird in MySQL nur von der Speicher-Engine NDB unterstützt. Um eine Tabelle für Cluster-Knoten tauglich zu machen, muss sie also mit ENGINE=NDB (oder dem Äquivalent ENGINE=NDBCLUSTER) angelegt werden.

    (Es ist möglich, Tabellen mit anderen Speicher-Engines wie etwa MyISAM oder InnoDB auf einem MySQL Server anzulegen, der für Clustering verwendet wird, doch diese Nicht-NDB-Tabellen können nicht an dem Cluster beteiligt sein.)

  • Welche Versionen von MySQL unterstützen Cluster? Muss ich die Quellversionen kompilieren?

    Cluster wird in allen MySQL-max-Binaries der Release-Serie 5.1 unterstützt, mit den im folgenden Absatz genannten Ausnahmen. Ob Ihr Server NDB unterstützt, können Sie mit SHOW VARIABLES LIKE 'have_%' oder SHOW ENGINES herausfinden. (Mehr Informationen finden Sie unter Abschnitt 5.3, „mysqld-max, ein erweiterter mysqld-Server“.)

    Linux-Benutzer müssen wissen, dass NDB nicht in den Standard-RPMs für MySQL Server enthalten ist. Es gibt auch separate RPM-Packages für die Speicher-Engine NDB und die zugehörigen Management- und anderen Tools. Downloadsites für diese RPMs sind im Abschnitt für NDB RPM-Downloads der MySQL 5.1-Downloadseite angegeben. (Früher musste man die -max-Binaries verwenden, die als .tar.gz-Archive geliefert wurden. Auch dies ist immer noch möglich, aber nicht mehr nötig; heute können Sie den RPM-Manager Ihrer Linux-Distribution nutzen, wenn Sie es möchten.) NDB-Unterstützung bekommen Sie auch, indem Sie die -max-Binaries von der Quelle kompilieren, doch bloß um MySQL Cluster-Unterstützung zu bekommen, ist das nicht erforderlich. Um die neueste Binary, RPM oder Quelldistribution der MySQL 5.1-Serie herunterzuladen, gehen Sie zu http://dev.mysql.com/downloads/mysql/5.1.html.

  • Würde ich im Katastrophenfall, etwa wenn die ganze Stadt einen Stromausfall hat und zusätzlich meine unterbrechungsfreie Stromversorgung versagt, alle meine Daten verlieren?

    Da alle committeten Transaktionen protokolliert werden, ist es zwar möglich, dass einige Daten in einem solchen Katastrophenfall verloren gehen könnten, aber der Verlust dürfte sich in Grenzen halten. Der Datenverlust kann zusätzlich begrenzt werden, indem Sie die Anzahl der Operationen pro Transaktion reduzieren. (Es ist immer schlecht, zu viele Operationen in einer einzigen Transaktion auszuführen.)

  • Kann man in einem Cluster FULLTEXT-Indizes benutzen?

    FULLTEXT-Indizes werden zurzeit weder von NDB noch von irgendeiner anderen Speicher-Engine außer MyISAM unterstützt. Wir arbeiten daran, diese Fähigkeit in einem künftigen Release hinzuzufügen.

  • Kann ich mehrere Knoten auf einem einzigen Computer laufen lassen?

    Das ist möglich, aber nicht ratsam. Einer der Hauptgründe für ein Cluster ist die Redundanz. Um jedoch alle Vorteile der Redundanz zu gewährleisten, sollte jeder Knoten auf einem eigenen Computer laufen. Wenn Sie mehrere Knoten auf einem einzigen Computer betreiben und dieser abstürzt, verlieren Sie alle diese Knoten. Wenn man bedenkt, dass MySQL Cluster auf Standardhardware mit einem billigen (oder sogar kostenlosen) Betriebssystem laufen kann, dann lohnt es sich wohl, ein oder zwei zusätzliche Rechner anzuschaffen, um missionskritische Daten zu sichern. Überdies sind die Anforderungen an einen Cluster-Host, auf dem ein Management-Knoten läuft, minimal: Diese Aufgabe kann schon ein 200-MHz-Pentium bewältigen, wenn er genügend RAM für das Betriebssystem plus einen geringen Overhead für die ndb_mgmd- und ndb_mgm-Prozesse hat.

  • Kann ich einem Cluster Knoten hinzufügen, ohne ihn neu starten zu müssen?

    Zurzeit noch nicht. Allerdings ist ein Neustart alles, was Sie tun müssen, um einem Cluster neue MGM- oder SQL-Knoten hinzuzufügen. Wenn Sie Datenknoten hinzufügen, liegen die Dinge etwas komplizierter; dafür sind folgende Schritte nötig:

    1. Sie sichern alle Cluster-Daten.

    2. Sie fahren den Cluster und alle Cluster-Knoten-Prozesse vollständig herunter.

    3. Sie starten den Cluster mit der Startoption --initial neu.

    4. Sie stellen alle Cluster-Daten aus den Sicherungsdateien wieder her.

    In einer künftigen Release-Serie von MySQL Cluster hoffen wir, MySQL Cluster eine „heiße“ Rekonfigurationsfähigkeit implementieren zu können, um die Anforderungen an den Neustart des Clusters nach dem Hinzufügen neuer Knoten zu minimieren (wenn nicht gar zu eliminieren).

  • Muss ich irgendwelche Einschränkungen berücksichtigen, wenn ich Cluster benutze?

    Für NDB-Tabellen gelten in MySQL folgende Einschränkungen:

    • Sie unterstützen nicht alle Zeichensätze und Kollationen.

    • Sie unterstützen keine FULLTEXT-Indizes und Indexpräfixe. Nur vollständige Spalten können indiziert werden.

    • Sie unterstützen keine raumbezogenen Datentypen. Siehe auch Kapitel 18, Raumbezogene Erweiterungen in MySQL.

    • Sie unterstützen nur vollständige Rollbacks von Transaktionen. Teilweise Rollbacks und Rollbacks zu Savepoints werden nicht unterstützt.

    • Pro Tabelle dürfen maximal 128 Attribute verwendet werden und die Attributnamen dürfen nicht länger als 31 Zeichen sein. Für jede Tabelle beträgt die Höchstlänge für den Tabellen- plus Datenbanknamen 122 Zeichen.

    • Eine Tabellenzeile darf maximal 8 Kbyte lang sein, BLOBs nicht inbegriffen. Für die Zeilenzahl pro Tabelle gibt es keine festgesetzte Obergrenze. Die Größenbeschränkungen für Tabellen hängen von mehreren Faktoren ab, besonders von dem für jeden Datenknoten verfügbaren Arbeitsspeicher.

    • Die NDB-Engine unterstützt keine Fremdschlüssel-Constraints. Diese werden wie in MyISAM ignoriert.

    • Query-Caching wird nicht unterstützt.

    Weitere Informationen über Beschränkungen in Clustern finden Sie unter Abschnitt 16.8, „Bekannte Beschränkungen von MySQL Cluster“.

  • Wie importiere ich eine vorhandene MySQL-Datenbank in einen Cluster?

    Wie in jede andere Version von MySQL können Sie auch in MySQL Cluster Datenbanken importieren. Außer den im obigen Absatz erwähnten Beschränkungen gibt es nur eine einzige weitere Sonderbedingung: Alle Tabellen, die in den Cluster eingebracht werden sollen, müssen die Speicher-Engine NDB verwenden. Das bedeutet, dass die Tabellen mit ENGINE=NDB oder ENGINE=NDBCLUSTER angelegt werden müssen. Es ist auch möglich, bestehende Tabellen, die andere Speicher-Engines nutzen, mit ALTER TABLE in NDB Cluster zu konvertieren, aber dafür ist ein zusätzlicher Workaround notwendig. Einzelheiten siehe Abschnitt 16.8, „Bekannte Beschränkungen von MySQL Cluster“.

  • Wie kommunizieren Cluster-Knoten?

    Cluster-Knoten können über drei Protokolle miteinander kommunizieren: TCP/IP, SHM (Shared Memory) und SCI (Scalable Coherent Interface). Wo es zur Verfügung steht, wird nach Voreinstellung SHM für Knoten benutzt, die auf demselben Cluster-Host residieren. SCI ist ein sehr schnelles (1 Gigabit pro Sekunde und mehr) und hochverfügbares Protokoll, das beim Aufbau skalierbarer Mehrprozessorsysteme zum Einsatz kommt. Es erfordert spezielle Hardware und Treiber. Unter Abschnitt 16.7, „Verwendung von Hochgeschwindigkeits-Interconnects mit MySQL Cluster“, erfahren Sie mehr über SCI als Transportmechanismus in MySQL Cluster.

  • Was ist ein „Arbitrator“?

    Wenn ein oder mehrere Cluster-Knoten abstürzen, ist es möglich, dass nicht mehr alle Cluster-Knoten einander „sehen“ können. Es kann sogar passieren, dass zwei Knotenmengen durch eine Netzwerkpartitionierung voneinander isoliert werden, die man auch als „Split Brain“-Szenario bezeichnet. Eine solche Situation ist nicht wünschenswert, da jede der beiden Knotenmengen versuchen würde, den gesamten Cluster darzustellen.

    Wenn Cluster-Knoten abstürzen, gibt es zwei Möglichkeiten: Wenn mehr als 50 % der verbleibenden Knoten miteinander kommunizieren können, haben wir eine so genannte „Majority Rules“-Situation („die Mehrheit regiert“), und diese Knotenmenge wird dann als der Cluster betrachtet. Der Arbitrator kommt ins Spiel, wenn es einen Gleichstand zwischen den Knoten gibt: In solchen Fällen wird die Knotenmenge, zu welcher der Arbitrator gehört, als der Cluster betrachtet, und die anderen Knoten werden heruntergefahren.

    Diese Darstellung ist etwas vereinfachend. Eine genauere Erkärung, die auch Knotengruppen berücksichtigt, folgt:

    Wenn alle Knoten in mindestens einer Knotengruppe am Leben sind, entstehen keine Probleme mit Netzwerkpartitionierung, da kein einzelner Teil des Clusters einen funktionsfähigen Cluster bilden kann. Das eigentliche Problem entsteht, wenn in keiner Knotengruppe alle Knoten mehr am Leben sind. In diesem Fall wird eine Netzwerkpartitionierung, das so genannte „Split-Brain“-Szenario, möglich. Dann ist ein Arbitrator (engl. für „Schiedsrichter“) gefordert. Alle Cluster-Knoten betrachten denselben Knoten, normalerweise den Management-Knoten, als Arbitrator. Es ist jedoch möglich, stattdessen einen der MySQL Server im Cluster als Arbitrator zu konfigurieren. Der Arbitrator gestattet, dass die erste Knotenmenge mit ihm Kontakt aufnimmt, und fährt die andere Knotenmenge herunter. Die Wahl des Arbitrators wird durch den Konfigurationsparameter ArbitrationRank für MySQL Server- und Management-Server-Knoten gesteuert. (Einzelheiten siehe Abschnitt 16.4.4.4, „Festlegung des MySQL Cluster-Management-Servers“.) Beachten Sie außerdem, dass der Arbitrator an sich keine großen Anforderungen an den als Arbitrator ausgewählten Host stellt, er muss also nicht besonders schnell sein oder einen besonders großen Arbeitsspeicher haben, um für diese Aufgabe geeignet zu sein.

  • Welche Datentypen unterstützt MySQL Cluster?

    MySQL Cluster unterstützt alle üblichen MySQL-Datentypen, ausgenommen die raumbezogenen, die zur Spatial-Erweiterung von MySQL gehören. (Siehe Kapitel 18, Raumbezogene Erweiterungen in MySQL.) Darüber hinaus gibt es bei NDB-Tabellen einige Abweichungen im Hinblick auf Indizes. Hinweis: MySQL Cluster-Tabellen (also Tabellen, die mit ENGINE=NDBCLUSTER angelegt wurden) haben nur Zeilen mit fester Breite. Das bedeutet beispielsweise, dass ein Datensatz mit einer VARCHAR(255)-Spalte Speicher für 255 Zeichen belegt (wie Zeichensatz und die Kollation der Tabelle es erfordern), unabhängig davon, wie viele Zeichen tatsächlich in der Spalte gespeichert sind. Dieses Problem soll in einer künftigen Release-Serie von MySQL behoben werden.

    Mehr zu diesen Fragen lesen Sie unter Abschnitt 16.8, „Bekannte Beschränkungen von MySQL Cluster“.

  • Wie kann ich MySQL Cluster starten und anhalten?

    Jeder Knoten im Cluster muss separat gestartet werden, und zwar in folgender Reihenfolge:

    1. Sie starten den Management-Knoten mit dem Befehl ndb_mgmd.

    2. Sie starten jeden Datenknoten mit dem Befehl ndbd.

    3. Sie starten jeden MySQL Server (SQL-Knoten) mit dem Befehl mysqld_safe --user=mysql &.

    Jeder dieser Befehle muss in der System-Shell des Computers ausgeführt werden, auf dem der betreffende Knoten ausgeführt wird. Ob der Cluster läuft, können Sie prüfen, indem Sie den MGM-Management-Client ndb_mgm auf dem Computer aufrufen, auf dem der MGM-Knoten läuft.

  • Was passiert mit den Cluster-Daten, wenn der Cluster heruntergefahren wird?

    Die Daten, die in den Datenknoten des Clusters im Arbeitsspeicher liegen, werden auf die Platte geschrieben und beim nächsten Start des Clusters wieder in den Arbeitsspeicher geladen.

    Um den Cluster herunterzufahren, geben Sie folgenden Befehl in die Shell des MGM-Knoten-Hosts ein:

    shell> ndb_mgm -e shutdown
    

    Das beendet geräuschlos ndb_mgm, ndb_mgm und alle ndbd-Prozesse. MySQL Server, die als SQL-Knoten eines Clusters laufen, können mit mysqladmin shutdown angehalten werden.

    Weitere Informationen finden Sie unter Abschnitt 16.6.2, „Befehle des Management-Clients“, und Abschnitt 16.3.6, „Sicheres Herunterfahren und Neustarten“.

  • Ist es nützlich, mehr als einen Management-Knoten im Cluster zu haben?

    Das kann als Ausfallsicherung hilfreich sein. Zwar wird der Cluster immer nur von einem MGM-Knoten gesteuert, aber es ist möglich, einen MGM als Primärknoten und andere als Ausfallsicherung zu konfigurieren, für den Fall, dass der Primär-MGM-Knoten abstürzt.

  • Kann ich in einem Cluster unterschiedliche Hardware und Betriebssysteme mixen?

    Ja, aber nur wenn alle Computer und Betriebssysteme dieselbe "Endianness" haben (also entweder alle big-endian oder alle little-endian sind). Es ist auch möglich, auf verschiedenen Knoten verschiedene Releases von MySQL Cluster zu benutzen. Dies können wir jedoch nur im Rahmen einer laufenden Upgrade-Prozedur empfehlen.

  • Kann ich zwei Datenknoten auf einem einzigen Host betreiben? Oder zwei SQL-Knoten?

    Ja, möglich wäre das schon. Wenn Sie mehrere Datenknoten haben, muss jeder Knoten ein anderes Data Directory benutzen. Wenn Sie mehrere SQL-Knoten auf derselben Maschine laufen lassen wollen, muss jede mysqld-Instanz einen anderen TCP/IP-Port benutzen.

  • Kann ich Hostnamen mit MySQL Cluster benutzen?

    Ja, Sie können DNS und DHCP für Cluster-Hosts benutzen. Wenn Ihre Anwendung jedoch eine Verfügbarkeit von 99,999 Prozent benötigt, empfehlen wir feste IP-Adressen. Wenn Sie die Kommunikation zwischen Cluster-Hosts von Diensten wie DNS und DHCP abhängig machen, führen Sie damit zusätzliche Points of Failure ein. Je weniger es davon gibt, desto besser.

16.11. MySQL Cluster: Glossar

Die folgenden Begriffe sind wichtig für das Verständnis von MySQL Cluster oder haben in diesem Zusammenhang eine spezielle Bedeutung.

  • Cluster:

    Im generischen Sinne ist ein Cluster eine Menge von Computern, die als Einheit funktionieren und zusammenarbeiten, um eine einzelne Aufgabe zu erfüllen.

    NDB Cluster:

    Dies ist die Speicher-Engine, mit der MySQL eine auf mehrere Computer verteilte Implementierung von Datenspeicherung, -abruf und -verwaltung implementiert.

    MySQL Cluster:

    Eine Gruppe von Computern, die zusammenarbeiten und die Speicher-Engine NDB verwenden, um eine verteilte MySQL-Datenbank in einer Share-Nothing-Architektur mit arbeitsspeicherresidenter Speicherung zu ermöglichen.

  • Konfigurationsdateien:

    Textdateien mit Anweisungen und Informationen über den Cluster, seine Hosts und seine Knoten. Diese werden beim Hochfahren des Clusters von dessen Management-Knoten gelesen. Einzelheiten siehe Abschnitt 16.4.4, „Konfigurationsdatei“.

  • Datensicherung (Backup):

    Eine vollständige Kopie aller Cluster-Daten, Transaktionen und Logs, die auf der Festplatte oder einem anderen Langzeitspeicher abgelegt wird.

  • Wiederherstellung (Restore):

    Den Cluster in den Zustand zurückversetzen, der in der Datensicherung gespeichert ist.

  • Checkpoint:

    Im Allgemeinen: Wenn die Daten auf der Festplatte gespeichert werden, sagt man, dass ein Checkpoint erreicht wurde. Eher Cluster-spezifisch ausgedrückt, ein Checkpoint ist ein Zeitpunkt, zu dem alle committeten Transaktionen auf der Festplatte gespeichert werden. Im Hinblick auf die Speicher-Engine NDB gibt es zwei Arten von Checkpoints, die zusammen gewährleisten, dass eine konsistente View der Cluster-Daten bewahrt bleibt:

    • Lokaler Checkpoint (LCP):

      Dieser Checkpoint ist für einen einzelnen Knoten spezifisch; allerdings können LCPs mehr oder weniger nebenläufig in allen Knoten im Cluster stattfinden. Bei einem LCP, der normalerweise alle paar Minuten eintritt, werden alle Daten eines Knotens auf der Platte gespeichert. Das genaue Intervall variiert ebenso wie die vom Knoten gespeicherte Datenmenge, der Grad der Cluster-Aktivität und andere Faktoren.

    • Globaler Checkpoint (GCP):

      Ein GCP tritt alle paar Sekunden auf, wenn Transaktionen für alle Knoten synchronisiert werden und das Redo-Log auf die Festplatte geschrieben wird.

  • Cluster-Host:

    Ein Computer, der einen Teil eines MySQL Clusters bildet. Ein Cluster hat sowohl eine physikalische als auch eine logische Struktur. Physikalisch besteht er aus einigen Computern, den so genannten Cluster-Hosts (oder einfach nur Hosts). Siehe auch Knoten und Knotengruppe weiter unten.

  • Knoten:

    Eine logische oder funktionale Einheit eines MySQL Clusters, die machmal auch Cluster-Knoten genannt wird. Im Zusammenhang mit MySQL Cluster ist „Knoten“ eher ein Prozess als eine physikalische Komponente des Clusters. Für einen funktionierenden MySQL Cluster sind drei Arten von Knoten erforderlich:

    • Management(MGM)-Knoten:

      Verwaltet die anderen Knoten im MySQL Cluster. Er liefert die Konfigurationsdaten an andere Knoten, startet und stoppt sie, kümmert sich um Netzwerkpartitionierung, legt Sicherungen an und stellt Daten aus Sicherungen wieder her usw.

    • SQL-Knoten (MySQL Server):

      Instanzen des MySQL Servers, die als Frontend für Daten dienen, welche in den Datenknoten des Clusters liegen. Clients, die Daten speichern, abrufen oder ändern wollen, können auf einen SQL-Knoten wie auf jeden gewöhnlichen MySQL Server zugreifen, mit den üblichen Authentifizierungsmethoden und APIs. Die darunter liegende Verteilung der Daten auf Knotengruppen ist für Benutzer und Anwendungen nicht erkennbar. SQL-Knoten greifen auf die Datenbanken des Clusters als Ganzes zu, ohne sich um die Verteilung der Daten auf verschiedene Datenknoten oder Cluster-Hosts zu kümmern.

    • Datenknoten:

      Diese Knoten speichern die tatsächlichen Daten. Tabellendatenfragmente werden in einer Menge von Knotengruppen gespeichert, wobei jede Knotengruppe eine andere Teilmenge der Tabellendaten speichert. Jeder Knoten, der zu einer Knotengruppe gehört, speichert eine Replik des Fragments, für das die Knotengruppe zuständig ist. Zurzeit kann ein einzelner Cluster insgesamt bis zu 48 Datenknoten unterstützen.

    Mehrere Knoten können auf demselben Computer koexistieren. (Es ist sogar möglich, einen kompletten Cluster auf einer einzigen Maschine einzurichten, doch niemand würde dies in einer Produktionsumgebung tun.) Bitte merken Sie sich, dass sich der Begriff Host im Zusammenhang mit MySQL Cluster auf eine physikalische Komponente des Clusters bezieht, während mit Knoten eine logische oder funktionale Komponente (ein Prozess) gemeint ist.

    Hinweis auf veraltete Begriffe: In älteren Versionen der Dokumentation zu MySQL Cluster wurden Datenknoten manchmal als „Datenbankknoten“, „DB-Knoten“ oder „Speicherknoten“ und SQL-Knoten als „Client-Knoten“ oder „API-Knoten“ bezeichnet. Diese ältere Terminologie wurde verworfen, um keine Verwirrung zu stiften, und sollte daher nicht mehr benutzt werden.

  • Knotengruppe:

    Eine Menge von Datenknoten. Alle Datenknoten in einer Knotengruppe enthalten dieselben Daten (Fragmente) und alle Knoten einer Gruppe sollten auf verschiedenen Hosts residieren. Es ist möglich, zu steuern, welche Knoten zu welchen Gruppen gehören.

  • Knoten-Absturz:

    MySQL Cluster ist nicht darauf angewiesen, dass jeder einzelne Knoten im Cluster funktioniert. Der Cluster kann auch dann weiterlaufen, wenn ein oder mehrere Knoten abstürzen. Wie viele abgestürzte Knoten ein Cluster im Einzelfall verträgt, hängt von der Anzahl der Knoten und der Konfiguration des Clusters ab.

  • Knoten-Neustart:

    Der Prozess, einen abgestürzten Knoten wieder ans Laufen zu bringen.

  • Initialer Knoten-Neustart:

    Der Prozess, einen Cluster-Knoten zu starten, dessen Dateisystem entfernt wurde. Dies wird manchmal bei Softwareupgrades oder unter anderen Sonderbedingungen getan.

  • System-Crash (oder Systemabsturz):

    Dieser kann auftreten, wenn so viele Cluster-Knoten abgestürzt sind, dass der konsistente Zustand des Clusters nicht mehr garantiert werden kann.

  • System-Neustart:

    Der Neustart eines Clusters samt Reinitialisierung seines Zustands aus den Festplatten-Logs und Checkpoints. Ist nach einem geplanten oder außerplanmäßigen Shutdown des Clusters erforderlich.

  • Fragment:

    Ein Teil einer Datenbanktabelle. In der Speicher-Engine NDB wird eine Tabelle in Fragmente zerlegt und so gespeichert. Ein Fragment wird manchmal auch „Partition“ genannt, doch „Fragment“ ist der bessere Begriff. Tabellen werden in MySQL Cluster fragmentiert, um die Lastverteilung zwischen Computern und Knoten zu erleichtern.

  • Replik:

    Unter der Speicher-Engine NDB hat jedes Tabellenfragment eine Reihe von Replikas, die aus Redundanzgründen auf anderen Datenknoten gespeichert werden. Gegenwärtig kann es bis zu vier Replikas pro Fragment geben.

  • Transporter:

    Ein Protokoll für die Datenübermittlung zwischen Knoten. MySQL Cluster unterstützt zurzeit vier verschiedene Arten von Transporter-Verbindungen:

    • TCP/IP

      Dies ist natürlich das vertraute Netzwerkprotokoll, das auch die Grundlage von HTTP, FTP (usw.) im Internet bildet. TCP/IP kann sowohl für lokale als auch für Remote-Verbindungen eingesetzt werden.

    • SCI

      Scalable Coherent Interface ist ein Hochgeschwindigkeitsprotokoll, das zur Erstellung von Mehrprozessorsystemen und Anwendungen für die Parallelverarbeitung benutzt wird. Die Verwendung von SCI mit MySQL Cluster erfordert spezielle Hardware, wie in Abschnitt 16.7.1, „Konfiguration von MySQL Cluster für SCI Sockets“, beschrieben. Eine grundlegende Einführung in SCI finden Sie unter http://www.dolphinics.com/corporate/scitech.html.

    • SHM

      Shared memory-Segmente wie bei Unix. Wenn SHM unterstützt wird, wird es automatisch für die Verbindung von Knoten auf demselben Host verwendet. Wenn Sie mehr über dieses Thema erfahren möchten, lesen Sie am besten auf der Unix-Manpage fürshmop(2) nach.

    Hinweis: Der Cluster-Transporter ist für den Cluster intern. Anwendungen, die MySQL Cluster nutzen, kommunizieren mit SQL-Knoten wie mit jeder anderen Version von MySQL Server (über TCP/IP oder mittels Unix-Socketdateien oder der Named Pipes von Windows). Über die Standardclient-APIs von MySQL können Anfragen gesandt und Antworten abgerufen werden.

  • NDB:

    Die Abkürzung für Network Database, also die Speicher-Engine, mit der MySQL Cluster eingeschaltet wird. Diese Speicher-Engine unterstützt alle üblichen MySQL-Datentypen und SQL-Anweisungen und ist ACID-fähig. Außerdem bietet sie volle Transaktionsunterstützung (Commits und Rollbacks).

  • Share-Nothing-Architektur:

    Die ideale Architektur für einen MySQL Cluster. In einer richtigen Share-Nothing-Umgebung läuft jeder Knoten auf einem separaten Host. Das hat den Vorteil, dass ein einzelner Host oder Knoten kein Single Point of Failure oder Leistungsengpass für das Gesamtsystem sein kann.

  • Speicherresident:

    Alle Daten, die in den Datenknoten gespeichert sind, hält der Hostcomputer dieses Knotens im Arbeitsspeicher. Für jeden Datenknoten im Cluster muss daher RAM in der Größenordnung Datenbankgröße mal Anzahl Replikas geteilt durch Anzahl der Datenknoten vorgehalten werden. Wenn also die Datenbank 1 Gbyte belegt und Sie den Cluster mit vier Replikas und acht Datenknoten einrichten möchten, ist pro Knoten mindestens 500 Mbyte Arbeitsspeicher erforderlich. Beachten Sie, dass dazu noch der Speicherbedarf für das Betriebssystem und die anderen Anwendungen kommt, die vielleicht auf dem Host laufen.

  • Tabelle:

    Wie es bei relationalen Datenbanken üblich ist, ist eine „Tabelle“ eine Menge identisch strukturierter Datensätze. In MySQL Cluster wird eine Datenbanktabelle auf einem Datenknoten in Form einer Reihe von Fragmenten gespeichert, wobei jedes Fragment auf anderen Datenknoten repliziert wird. Die Menge der Datenknoten, welche dieselben Fragmente replizieren, nennt man Knotengruppe.

  • Cluster-Programme:

    Kommandozeilenprogramme, die zum Ausführen, Konfigurieren und Administrieren von MySQL Cluster erforderlich sind. Hierzu gehören beide Server-Daemons:

    • ndbd:

      Der Datenknoten-Daemon (führt einen Datenknoten-Prozess aus)

    • ndb_mgmd:

      Der Management-Server-Daemon (führt einen Management-Server-Prozess aus)

    und Clientprogramme:

    • ndb_mgm:

      Der Management-Client (stellt die Schnittstelle zur Ausführung von Management-Befehlen zur Verfügung)

    • ndb_waiter:

      Prüft den Status aller Knoten in einem Cluster

    • ndb_restore:

      Stellt Cluster-Daten aus einer Datensicherung wieder her

    Mehr über diese Programme und ihre Verwendung erfahren Sie unter Abschnitt 16.5, „Prozessverwaltung in MySQL Cluster“.

  • Ereignislog:

    MySQL Cluster protokolliert Ereignisse nach Kategorie (Starten, Herunterfahren, Fehler, Checkpoints usw.), Priorität und Ernsthaftigkeit. Eine vollständige Liste aller protokollierungsfähigen Ereignisse finden Sie unter Abschnitt 16.6.3, „Ereignisberichte, die MySQL Cluster erzeugt“. Es gibt zwei Arten von Ereignislogs:

    • Cluster-Log:

      Zeichnet alle gewünschten protokollierbaren Ereignisse für den Cluster als Ganzes auf.

    • Knoten-Log:

      Ein separates Log, das für jeden einzelnen Knoten gepflegt wird.

    Unter normalen Umständen ist es notwendig und hinreichend, nur das Cluster-Log zu pflegen und zu untersuchen. In die Knoten-Logs schauen Sie nur bei der Anwendungsentwicklung und beim Debuggen hinein.

Kapitel 17. Partitionierung

In diesem Kapitel geht es um die in MySQL 5.1 implementierten Formen der Partitionierung. Eine Einführung in Partitionierung und Partitionierungskonzepte finden Sie in Abschnitt 17.1, „Überblick über die Partitionierung in MySQL“. MySQL 5.1 unterstützt mehrere Formen der Partitionierung, die in Abschnitt 17.2, „Partitionstypen“, beschrieben werden, sowie der Teilpartitionierung (auch als zusammengesetzte Partitionierung bezeichnet), die in Abschnitt 17.2.5, „Unterpartitionen“, beschrieben werden. Wie Partitionen in partitionierten Tabellen hinzugefügt, entfernt oder geändert werden, erfahren Sie in Abschnitt 17.3, „Partitionsverwaltung“. Tabellenwartungsbefehle für partitionierte Tabellen behandeln wir in Abschnitt 17.3.3, „Wartung von Partitionen“.

Wichtig: Partitionierte Tabellen, die mit den MySQL-Versionen vor 5.1.6 angelegt wurden, können von einem MySQL Server der Version 5.1.6 oder höher nicht gelesen werden. Außerdem kann die INFORMATION_SCHEMA.TABLES-Tabelle nicht benutzt werden, wenn solche Tabellen auf einem Server liegen, der mit der Version 5.1.6 oder höher betrieben wird. Wenn Sie partitionierte Tabellen haben, die mit MySQL 5.1.5 oder früher angelegt wurden, lesen Sie unbedingt die Zusatzinformationen und empfohlenen Workarounds in Abschnitt D.1.1, „Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)“, nach, bevor Sie auf MySQL 5.1.6 oder höher aufrüsten.

Die Partitionierungsimplementierung in MySQL 5.1 befindet sich noch in der Entwicklung und ist noch nicht bereit für Produktionsumgebungen. Etwas Ähnliches gilt für den Inhalt dieses Kapitels: Manche der hier beschriebenen Features sind in Wirklichkeit noch gar nicht implementiert, und andere funktionieren noch nicht ganz so wie beschrieben (beispielsweise die Optionen DATA DIRECTORY und INDEX DIRECTORY für Partitionen, die noch unter dem Bug#13520 leiden). Wir haben versucht, diese Abweichungen im vorliegenden Kapitel kenntlich zu machen. Bitte schauen Sie in folgende Quellen hinein, bevor Sie uns Bugreports schicken:

  • MySQL Partitioning Forum

    Dies ist das offizielle Diskussionsforum für alle, die sich für die Partitionierungstechnologie von MySQL interessieren oder damit arbeiten. Hier finden Sie Ankündigungen und Aktualisierungen von MySQL-Entwicklern und anderen. Das Forum wird von den Mitgliedern des Partitioning Development and Documentation-Teams geleitet.

  • Partitioning Bug Reports

    Eine Liste aller Partitionierungs-Bugs, die an unser Bugs-System gemeldet wurden, unabhängig von Alter, Ernsthaftigkeit und aktuellem Status. Es ist möglich, diese Liste nach diversen Kritierien zu filtern. Eventuell können Sie auch auf die MySQL Bugs System Home Page gehen und nach Bugs fahnden, die für Sie von besonderem Interesse sind.

  • Mikael Ronström's Blog

    Der MySQL Partitioning Architect und Lead Developer Mikael Ronström stellt hier häufig Artikel ein, die seine Arbeit mit MySQL Partitioning und MySQL Cluster betreffen.

  • PlanetMySQL

    Eine News-Site über MySQL mit Blogs, die für jeden MySQL-Nutzer interessant sein dürften. Wir raten Ihnen, hier Links zu den Blogs der Nutzer herauszusuchen, die mit der Partitionierung in MySQL arbeiten, oder Ihr eigenes Blog eintragen zu lassen.

Die Alpha-Binaries von MySQL 5.1 stehen nun unter http://dev.mysql.com/downloads/mysql/5.1.html zum Herunterladen zur Verfügung. Die Quelle für die aktuellsten Bugfixes und neuen Features im Zusammenhang mit Partitionierung finden Sie allerdings in unserem BitKeeper-Repository. Um Partitionierung zu ermöglichen, müssen Sie den Server mit der Option --with-partition kompilieren. Weitere Informationen über den MySQL-Build finden Sie unter Abschnitt 2.8, „Installation der Quelldistribution“. Wenn Sie Probleme mit dem Kompilieren eines partitionierungsfähigen MySQL 5.1-Build haben, schauen Sie in das MySQL Partitioning Forum und fragen Sie dort um Hilfe, falls nicht bereits eine Lösung für Ihr Problem veröffentlicht wurde.

17.1. Überblick über die Partitionierung in MySQL

Dieser Abschnitt gibt einen Überblick über Partitionierungskonzepte in MySQL 5.1.

Beschränkungen der Partitionierung und die Grenzen des Features erfahren Sie unter Abschnitt 17.4, „Beschränkungen und Grenzen der Partitionierung“.

Der SQL-Standard enthält kaum Anleitungen in Bezug auf die physikalischen Aspekte der Datenspeicherung. Die Sprache SQL ist dafür ausgelegt, unabhängig von Datenstrukturen, Medien sowie den einem Schema zugrunde liegenden Tabellen, Zeilen oder Spalten zu funktionieren. Allerdings haben die meisten modernen Datenbankmanagementsysteme auch irgendwelche Möglichkeiten entwickelt, um festzustellen, an welchem Ort (Dateisystem, Hardware oder beides) bestimmte Daten physikalisch gespeichert werden. In MySQL unterstützte die Speicher-Engine InnoDB lange Zeit Tablespaces und der MySQL Server konnte schon vor der Einführung von Partitionierung so konfiguriert werden, dass er für die Speicherung unterschiedlicher Datenbanken verschiedene physikalische Verzeichnisse verwendete (unter Abschnitt 7.6.1, „Symbolische Verknüpfungen“, werden die Gründe dafür erklärt).

Mit der Partitionierung wird dieses Konzept noch einen Schritt weitergeführt: Hiermit können Sie verschiedene Teile einzelner Tabellen über ein Dateisystem verteilen, und zwar nach Regeln, die Sie im Großen und Ganzen nach Ihren Bedürfnissen festlegen. So werden verschiedene Teile einer Tabelle im Endeffekt als getrennte Tabellen an verschiedenen Stellen gespeichert. Die vom Benutzer gewählte Regel, nach welcher die Daten aufgeteilt werden, bezeichnet man als Partitionierungsfunktion. Diese kann in MySQL der Modulus sein, ein einfacher Vergleich mit einer Menge von Wertebereichen oder Wertelisten, oder auch eine interne oder lineare Hash-Funktion. Die Funktion wird je nach dem vom Benutzer angegebenen Partitionierungstyp ausgewählt und nimmt den Wert eines ebenfalls vom Benutzer gelieferten Ausdrucks als Parameter entgegen. Dieser Ausdruck kann der Wert einer Integer-Spalte sein oder auch eine Funktion, die auf einer oder mehreren Spalten arbeitet und einen Integer zurückgibt. Der Wert dieses Ausdrucks wird an die Partitionierungsfunktion übergeben, die ihrerseits die Nummer der Partition, in welcher dieser spezielle Datensatz gespeichert werden soll, als Integer zurückgibt. Diese Funktion muss nichtkonstant und nichtzufällig sein. Sie darf keine Anfragen enthalten, kann aber jedweden in MySQL zulässigen SQL-Ausdruck enthalten, wenn dieser nur einen positiven Integer kleiner MAXVALUE zurückgibt (dies ist der größtmögliche positive Integer). Beispiele für Partitionierungsfunktionen finden Sie in den Abschnitten über Partitionierungstypen weiter unten in diesem Kapitel (siehe Abschnitt 17.2, „Partitionstypen“) sowie in den Beschreibungen zur Partitionierungssyntax in Abschnitt 13.1.5, „CREATE TABLE.

Dies bezeichnet man als horizontale Partitionierung: Verschiedene Zeilen einer Tabelle können unterschiedlichen physikalischen Partitionen zugewiesen werden. MySQL 5.1 kennt keine vertikale Partitionierung, bei der verschiedene Tabellenspalten auf verschiedene physikalische Partitionen gespeichert würden. Es gibt auch noch keinerlei Pläne, vertikale Partitionierung in MySQL 5.1 einzuführen.

Partitionierungsunterstützung ist in den -max-Releases von MySQL 5.1 enthalten (d. h., dass die 5.1--max-Binaries mit der Option --with-partition erstellt werden). Wenn die MySQL-Binary mit Partitionierungsunterstützung gebaut wird, muss nichts weiter unternommen werden, um diese zu aktivieren (es sind beispielsweise keine speziellen Einträge in der my.cnf-Datei erforderlich). Ob Ihr MySQL Server Partitionierung unterstützt, verrät Ihnen der Befehl SHOW VARIABLES:

mysql> SHOW VARIABLES LIKE '%partition%';

+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| have_partitioning | YES   |
+-------------------+-------+
1 row in set (0.00 sec)

Wenn Sie in der Ausgabe Ihres ensprechenden SHOW VARIABLES-Befehls nicht wie hier eine have_partitioning-Variable mit dem Wert YES zu sehen bekommen, dann unterstützt Ihre MySQL-Version keine Partitionierung.

Vor MySQL 5.1.6 hieß diese Variable have_partition_engine (Bug#16718).

Um partitionierte Tabellen zu erstellen, können Sie jede vom MySQL Server unterstützte Speicher-Engine einsetzen; die MySQL-Partitionierungs-Engine läuft in ihrer eigenen Schicht und kann mit allen diesen Speicher-Engines umgehen. In MySQL 5.1 müssen alle Partitionen derselben partitionierten Tabelle auch dieselbe Speicher-Engine benutzen. Sie können beispielsweise nicht für die eine Partition MyISAM und für die andere InnoDB benutzen. Allerdings hindert nichts Sie daran, verschiedene Speicher-Engines für verschiedene partitionierte Tabellen auf demselben MySQL Server oder sogar in derselben Datenbank zu benutzen.

Um eine bestimmte Speicher-Engine für eine partitionierte Tabelle zu verwenden, müssen Sie lediglich die passende [STORAGE] ENGINE-Option einstellen, wie Sie es auch bei einer nichtpartitionierten Tabelle tun würden. Allerdings müssen Sie daran denken, dass [STORAGE] ENGINE (und andere Tabellenoptionen) in einer CREATE TABLE-Anweisung vor den Partitionierungsoptionen stehen müssen. Das folgende Beispiel zeigt, wie man eine Tabelle anlegt, die per Hash in 6 Partitionen zerlegt wird und die Speicher-Engine InnoDB verwendet:

CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
    ENGINE=INNODB
    PARTITION BY HASH(MONTH(tr_date))
    PARTITIONS 6;

(Beachten Sie, dass jede PARTITION-Klausel auch eine [STORAGE] ENGINE-Option enthalten kann, die jedoch in MySQL 5.1 wirkungslos bleibt.)

Es ist durchaus möglich, auch partitionierte temporäre Tabellen zu erstellen, doch diese haben nur so lange wie die aktuelle MySQL-Session Bestand. Dasselbe gilt für nichtpartitionierte temporäre Tabellen.

Hinweis: Eine Partitionierung betrifft alle Daten und Indizes einer Tabelle. Sie können weder die Daten ohne ihre Indizes partitionieren noch die Indizes ohne die Daten, ebenso wenig, wie Sie nur einen Teil einer Tabelle partitionieren können.

Die Daten und Indizes jeder Partition können mit den Optionen DATA DIRECTORY und INDEX DIRECTORY der PARTITION-Klausel der CREATE TABLE-Anweisung, mit der die partitionierte Tabelle angelegt wird, einem bestimmten Verzeichnis zugewiesen werden. Überdies können Sie mit MAX_ROWS und MIN_ROWS festlegen, wie viele Zeilen höchstens bzw. mindestens in jeder Partition gespeichert werden dürfen. Genaueres über diese Optionen erfahren Sie unter Abschnitt 17.3, „Partitionsverwaltung“. Hinweis: Dieses Feature läuft zurzeit wegen Bug#13250 nicht; dies dürfte jedoch behoben sein, wenn die ersten 5.1-Binaries zur Verfügung gestellt werden.

Eine Partitionierung hat folgende Vorteile:

  • In einer einzigen Tabelle können mehr Daten gespeichert werden, als auf eine einzelne Festplatte oder Dateisystempartition passen.

  • Unnütz gewordene Daten lassen sich oft einfacher aus der Tabelle entfernen, wenn man nur eine Partition löschen muss, die ebendiese Daten enthält. Umgekehrt lassen sich in einigen Fällen Daten auch einfacher hinzufügen, indem man einfach eine neue Partition speziell für diese Daten erschafft.

Normalerweise bietet eine Partitionierung auch noch die in der folgenden Liste aufgeführten Vorteile. Diese Features sind zwar in MySQL Partitioning noch nicht implementiert, stehen aber ganz oben auf unserer Prioritätenliste. Wir hoffen, sie im Produktionsrelease der Version 5.1 bereits einbringen zu können.

  • Manche Anfragen lassen sich dadurch optimieren, dass die Daten, die auf eine WHERE-Klausel zutreffen, auf bestimmten Partitionen gespeichert werden können, wodurch die restlichen Partitionen von der Suche ausgeschlossen bleiben. Da Partitionen nach der Erstellung einer partitionierten Tabelle geändert werden können, sind Sie in der Lage, Ihre Daten so zu reorganisieren, dass häufige Anfragen schneller verarbeitet werden, als es im ursprünglichen Partitionierungsschema der Fall war.

  • Anfragen mit Aggregatfunktionen wie SUM() und COUNT() lassen sich leicht parallelisieren. Ein einfaches Beispiel einer solchen Anfrage wäre SELECT salesperson_id, COUNT(orders) as order_total FROM sales GROUP BY salesperson_id;. Mit „parallelisieren“ ist gemeint, dass die Anfrage auf allen Partitionen gleichzeitig ausgeführt werden kann und das Endergebnis dann die Summe der Resultate der einzelnen Partitionen ist.

  • Da Suchoperationen auf mehrere Festplatten verteilt werden können, wird ein größerer Durchsatz an Anfragen erzielt.

Bitte schauen Sie regelmäßig im englischsprachingen Handbuch, Kapitel „Partitions, nach aktuellen Entwicklungen in der Implementierung der Partitionierung in MySQL 5.1, da diese Entwicklung noch nicht abgeschlossen ist.

17.2. Partitionstypen

Dieser Abschnitt beschreibt die in MySQL 5.1 verfügbaren Arten der Partitionierung, nämlich:

  • RANGE-Partitionierung (Bereichspartitionierung): Weist den Partitionen Zeilen zu, je nachdem, ob ihre Spaltenwerte in einen bestimmten Wertebereich fallen. Siehe Abschnitt 17.2.1, „RANGE-Partitionierung“.

  • LIST-Partitionierung (Listenpartitionierung): Ähnelt der Bereichspartitionierung, nur dass hier die Partition anhand der Frage ausgewählt wird, ob sich die Spaltenwerte in einer Menge eigenständiger Werte wiederfinden. Siehe Abschnitt 17.2.2, „LIST-Partitionierung“.

  • HASH-Partitionierung: Hierbei wird eine Partition anhand des Rückgabewerts eines benutzerdefinierten Ausdrucks ausgewählt, der auf Spaltenwerten der Zeilen operiert, die in die Tabelle eingefügt werden sollen. Die Funktion kann jeden in MySQL zulässigen Ausdruck enthalten, der einen nichtnegativen Integer ergibt. Siehe Abschnitt 17.2.3, „HASH-Partitionierung“.

  • KEY-Partitionierung (Schlüsselpartitionierung): Ähnelt der Hash-Partitionierung, aber mit dem Unterschied, dass nur bestimmte auszuwertende Spalten übergeben werden und der MySQL Server seine eigene Hash-Funktion liefert. Die Spalte(n) dürfen nur Integer-Werte enthalten. Siehe Abschnitt 17.2.4, „KEY-Partitionierung“.

Bitte vergessen Sie nicht: Egal welche Art von Partitionierung Sie verwenden, Partitionen werden immer automatisch der Reihe nach bei ihrer Erstellung durchnummeriert, und zwar beginnend mit 0. Wenn eine neue Zeile in eine partitionierte Tabelle eingefügt wird, wird die richtige Partition anhand dieser laufenden Nummern gefunden. Wenn beispielsweise Ihre Tabellen 4 Partitionen nutzen, so habe diese Partitionen die Nummern 0, 1, 2 und 3. Bei einer RANGE- oder LIST-Partitionierung müssen Sie gewährleisten, dass für jede Partitionsnummer auch eine Partition definiert ist. Bei einer HASH-Partitionierung muss die verwendete benutzerdefinierte Funktion einen Integer größer 0 zurückgeben. Bei einer KEY-Partitionierung wird dieses Problem automatisch von der Hash-Funktion gelöst, die der MySQL Server intern einsetzt.

Partitionsnamen halten sich generell an dieselben Regeln, die auch für andere MySQL-Bezeichner gelten, wie beispielsweise die für Tabellen und Datenbanken. Allerdings müssen Sie daran denken, dass Partitionsnamen nicht zwischen Groß- und Kleinschreibung unterscheiden. So würde beispielsweise die folgende CREATE TABLE-Anweisung scheitern:

mysql> CREATE TABLE t2 (val INT)
    -> PARTITION BY LIST(val)(
    ->     PARTITION mypart VALUES IN (1,3,5),
    ->     PARTITION MyPart VALUES IN (2,4,6)
    -> );
ERROR 1488 (HY000): All partitions must have unique names in the table

Der Fehler liegt daran, dass MySQL keinen Unterschied zwischen den Partitionsnamen mypart und MyPart erkennen kann.

In den folgenden Abschnitten geben wir nicht immer alle nur denkbaren Syntaxvarianten zur Erstellung der Partitionstypen an. Diese Informationen können Sie unter Abschnitt 13.1.5, „CREATE TABLE, nachschlagen.

17.2.1. RANGE-Partitionierung

Wenn eine Tabelle nach Wertebereichen partitioniert wird, enthält später jede Partition die Zeilen, für die der Partitionierungsausdruck einen Wert hat, der in einem bestimmten Wertebereich liegt. Die Wertebereiche sollten aneinander grenzen, aber sich nicht überschneiden, und sie sollten mit dem VALUES LESS THAN-Operator definiert werden. Bei den nächsten Beispielen gehen wir davon aus, dass wie unten beschrieben eine Tabelle für die Personaldaten einer Kette von 20 Videotheken (mit den Nummern 1 bis 20) eingerichtet wird:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
);

Diese Tabelle kann je nach Bedarf auf unterschiedliche Weise nach Bereichen partitioniert werden. Eine Möglichkeit wäre es, die store_id-Spalte zu verwenden. Sie könnten die Tabelle beispielsweise mit einer PARTITION BY RANGE-Klausel auf 4 Partitionen verteilen:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN (21)
);

In diesem Partitionierungsschema werden die Angestelltendaten der Zweigstellen 1 bis 5 in Partition p0 gespeichert, die Angestelltendaten der Zweigstellen 6 bis 10 in Partition p1 und so weiter. Beachten Sie, dass die Partitionen der Reihe nach von der niedrigsten bis zur höchsten Nummer definiert werden. Dies verlangt die Syntax von PARTITION BY RANGE, die in dieser Hinsicht einer switch ... case-Anweisung in C oder Java ähnelt.

Es ist einfach, festzustellen, dass eine neue Zeile mit den Daten (72, 'Michael', 'Widenius', '1998-06-25', NULL, 13) in die Partition p2 eingefügt wurde, doch was geschieht, wenn die Videothekenkette eine 21. Zweigstelle eröffnen möchte? In dem vorliegenden Schema gibt es keine Regeln für Zeilen mit einer store_id größer 20. Daher wird ein Fehler gemeldet, weil der Server nicht weiß, wohin damit. Dieses Verhalten können Sie mit einem so genannten „Catchall“ verhindern: einer VALUES LESS THAN-Klausel in der CREATE TABLE-Anweisung, die für alle Werte Vorsorge trifft, die den größten explizit angegebenen Wert übersteigen:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

MAXVALUE ist der größte mögliche Integer-Wert. Nun werden alle Zeilen, deren store_id-Spaltenwert größer oder gleich dem größten definierten Wert 16 ist, in Partition p3 gespeichert. Irgendwann einmal, wenn die Anzahl der Zweigstellen auf 25, 30 oder mehr angewachsen ist, können Sie mit einer ALTER TABLE-Anweisung neue Partitionen für die Zweigstellen 21 bis 25, 26 bis 30 und so weiter hinzufügen (Einzelheiten zur Vorgehensweise finden Sie unter Abschnitt 17.3, „Partitionsverwaltung“.)

In ähnlicher Weise können Sie die Tabelle auf der Grundlage von Job-Codes partitionieren, d. h. anhand der Werte der Spalte job_code. Nehmen wir beispielsweise an, reguläre (in der Filiale arbeitende) Angestellte haben einen zweistelligen Job-Code, Büro- und Support-Mitarbeiter einen dreistelligen und Manager einen vierstelligen. Dann könnten Sie Ihre partitionierte Tabelle folgendermaßen definieren:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)
);

In diesem Beispiel würden die Daten der Filialmitarbeiter in der Partition p0, die der Büro- und Support-Mitarbeiter in der Partition p1 und die der Manager in der Partition p2 gespeichert.

In VALUES LESS THAN-Klauseln kann auch ein Ausdruck verwendet werden, allerdings nur mit der Maßgabe, dass MySQL in der Lage sein muss, den Rückgabewert dieses Ausdrucks in einem LESS THAN (<)-Vergleich auszuwerten; der Wert des Ausdrucks darf also nicht NULL sein. Dies ist der Grund, weshalb die Spalten hired, separated, job_code und store_id der Tabelle employees als NOT NULL definiert wurden.

Anstatt die Tabellendaten anhand der Zweigstellennummer zu verteilen, können Sie auch einen Ausdruck verwenden, der auf den beiden DATE-Spalten basiert. Nehmen wir beispielsweise an, Sie möchten die Tabelle nach dem Jahr partitionieren, in welchem die Mitarbeiter das Unternehmen verlassen, also nach dem Wert der Spalte YEAR(separated). Folgende CREATE TABLE-Anweisung würde ein solches Partitionierungsschema implementieren:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY RANGE ( YEAR(separated) ) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

In diesem Schema werden die Daten der Mitarbeiter, die das Unternehmen vor 1991 verließen, in der Partition p0 gespeichert, die Daten derjenigen, die zwischen 1991 und 1995 gingen, in Partition p1, die Daten derjenigen, die zwischen 1996 und 2000 gingen, in Partition p2 und die Daten derjenigen, die nach 2000 gingen, in Partition p3.

Eine Bereichspartitionierung ist in folgenden Fällen besonders nützlich:

  • Sie möchten oder müssen „alte“ Daten löschen. Wenn Sie das soeben gezeigte Partitionierungsschema umsetzen, brauchen Sie nur noch ALTER TABLE employees DROP PARTITION p0; aufzurufen, um alle Datensätze der Angestellten zu löschen, die vor 1991 das Unternehmen verlassen haben. (Weitere Informationen finden Sie unter Abschnitt 13.1.2, „ALTER TABLE, und Abschnitt 17.3, „Partitionsverwaltung“.) Wenn Sie eine Tabelle mit sehr vielen Zeilen haben, kann diese Vorgehensweise sehr viel effizienter als eine DELETE-Anfrage wie etwa DELETE FROM employees WHERE YEAR(separated) <= 1990; sein.

  • Sie möchten eine Spalte benutzen, die Datums- oder Uhrzeitwerte oder Werte aus einer anderen Wertfolge enthält.

  • Es werden oft Anfragen ausgeführt, die direkt von einer für die Partitionierung der Tabelle verwendeten Spalte abhängen. So kann MySQL beispielsweise bei einer Anfrage wie SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_id; ganz schnell herausfinden, dass nur die Partition p2 durchsucht werden muss, da die restlichen Partitionen gar keine zu der WHERE-Klausel passenden Einträge enthalten können. Hinweis: Dies Optimierung wurde in den Quelldateien von MySQL 5.1 zwar noch nicht aktiviert, aber wir arbeiten daran.

17.2.2. LIST-Partitionierung

Die Listenpartitionierung in MySQL ähnelt in vieler Hinsicht der Bereichspartitionierung. Wie bei dieser muss jede Partition explizit definiert werden. Der Hauptunterschied besteht darin, dass bei einer Listenpartitionierung die einzelnen Partitionen anhand der Frage gebildet werden, ob ein Spaltenwert in einer von mehreren Wertelisten vorkommt, während bei der Bereichspartitionierung gefragt wird, ob er in einer von mehreren Wertefolgen vorkommt. Diese Form der Partitionierung nehmen Sie mit PARTITION BY LIST(expr) vor, wobei expr ein Spaltenwert oder ein auf einem Spaltenwert basierender Ausdruck ist, der einen Integer zurückgibt. Die einzelnen Partitionen werden sodann durch VALUES IN (value_list) definiert, wobei value_list eine kommagetrennte Liste von Integern ist.

Hinweis: In MySQL 5.1 kann der Spaltenwert bei einer LIST-Partitionierung nur mit einer Integer-Liste verglichen werden.

Im Gegensatz zu Bereichspartitionen müssen Listenpartitionen nicht in einer bestimmten Reihenfolge definiert werden. Genauere Hinweise zur Syntax finden Sie unter Abschnitt 13.1.5, „CREATE TABLE.

In den nachfolgenden Beispielen gehen wir davon aus, dass die Grunddefinition der zu partitionierenden Tabelle die der nachfolgenden CREATE TABLE-Anweisung ist:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
);

(Dies ist dieselbe Tabelle, die auch als Grundlage der Beispiele in Abschnitt 17.2.1, „RANGE-Partitionierung“, diente.)

Angenommen, wir haben eine Kette von 20 Videotheken, die auf 4 Franchisenehmer verteilt ist, wie in der folgenden Tabelle gezeigt:

RegionStore ID Numbers
North3, 5, 6, 9, 17
East1, 2, 10, 11, 19, 20
West4, 12, 13, 14, 18
Central7, 8, 15, 16

Um diese Tabelle so zu partitionieren, dass jeweils die Zweigstellen einer Region zusammenhängend gespeichert werden, könnten Sie die folgende CREATE TABLE-Anweisung einsetzen:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LIST(store_id) (
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
);

Nun ist es ganz einfach, regionale Angestelltendaten in die Tabelle zu laden oder aus ihr zu löschen. Nehmen wir beispielsweise an, alle Zweigstellen der Region West werden an ein anderes Unternehmen verkauft. Dann könnten alle Angestelltendaten der Zweigstellen dieser Region mit der Anfrage ALTER TABLE employees DROP PARTITION pWest; gelöscht werden, die viel schneller als die entsprechende DELETE-Anfrage DELETE FROM employees WHERE store_id IN (4,12,13,14,18); ausgeführt wird.

Wichtig: Wenn Sie versuchen, eine Zeile einzufügen, deren Spaltenwert (oder Rückgabewert für den Partitionierungsausdruck) in den Listen mit den Partitionierungswerten nicht vorkommt, scheitert die INSERT-Anfrage mit einer Fehlermeldung. So würde beispielsweise die folgende Anfrage bei dem oben skizzierten Schema einer LIST-Partitionierung fehlschlagen:

INSERT INTO employees VALUES 
    (224, 'Linus', 'Torvalds', '2002-05-01', '2004-10-12', 42, 21);

Dieser Fehler tritt ein, da der store_id-Spaltenwert 21 in keiner der Wertelisten auftritt, die zur Definition der Partitionen pNorth, pEast, pWest und pCentral angegeben wurden. Es ist wichtig zu wissen, dass für Listenpartitionen keine „Catchall“-Definition wie VALUES LESS THAN MAXVALUE existiert, um Werte unterzubringen, die in keiner der Wertelisten auftauchen. Mit anderen Worten: Jeder Partitionierungswert muss in einer der Wertelisten vorhanden sein.

Wie die RANGE-Partitionierung kann auch die LIST-Partitionierung mit einer Hash- oder Schlüsselpartitionierung kombiniert werden, um eine zusammengesetzte Partitionierung (Teilpartitionierung) zu bilden. Siehe Abschnitt 17.2.5, „Unterpartitionen“.

17.2.3. HASH-Partitionierung

Eine Partitionierung nach HASH wird hauptsächlich eingesetzt, um eine gleichmäßige Verteilung der Daten auf eine im Voraus festgelegte Anzahl von Partitionen zu erzielen. Bei einer Bereichs- oder Listenpartitionierung müssen Sie explizit angeben, in welcher Partition Spaltenwerte gespeichert werden sollen, während MySQL Ihnen dies bei einer Hash-Partitionierung abnimmt. Hier müssen Sie lediglich einen Spaltenwert oder einen auf einem Spaltenwert basierenden Ausdruck für den Hash angeben und sagen, auf wie viele Partitionen die partitionierte Tabelle verteilt werden soll.

Um eine Tabelle mit einer HASH-Partitionierung aufzuteilen, müssen Sie an die CREATE TABLE-Anweisung eine PARTITION BY HASH (expr)-Klausel anfügen, wobei expr ein Ausdruck ist, der einen Integer zurückgibt. Das kann auch einfach der Name einer Spalte sein, die einen der Integer-Typen von MySQL hat. Zusätzlich wird normalerweise noch eine PARTITIONS num-Klausel angefügt, wobei num ein nichtnegativer Integer ist und angibt, auf wie viele Partitionen die Tabelle verteilt werden soll.

Die folgende Anweisung erzeugt beispielsweise eine Tabelle, die einen Hash der Spalte store_id verwendet und auf 4 Partitionen verteilt wird:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;

Wenn Sie keine PARTITIONS-Klausel verwenden, ist die Anzahl der Partitionen nach Voreinstellung 1. Ausnahme: Bei NDB Cluster-Tabellen ist die vorgegebene Anzahl der Partitionen gleich der Anzahl der Datenknoten im Cluster, eventuell berichtigt um eine MAX_ROWS-Einstellung, um zu gewährleisten, dass alle Zeilen in die Partitionen hineinpassen. (Siehe Kapitel 16, MySQL Cluster.)

Wenn Sie das Schlüsselwort PARTITIONS ohne darauf folgende Zahlenangabe verwenden, wird ein Syntaxfehler ausgelöst.

Sie können für expr auch einen SQL-Ausdruck einsetzen, der einen Integer zurückliefert. Wenn Sie Ihre Tabelle beispielsweise anhand des Einstellungsjahres der Angestellten partitionieren möchten, gehen Sie folgendermaßen vor:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;

Sie können für expr alle Funktionen und Ausdrücke verwenden, die in MySQL zulässig sind, vorausgesetzt, der Rückgabewert ist ein nichtkonstanter, nichtzufälliger Integer. (Mit anderen Worten: Der Wert soll variieren, aber deterministisch sein.) Sie müssen allerdings daran denken, dass dieser Ausdruck jedes Mal, wenn eine Zeile eingefügt, aktualisiert oder eventuell auch gelöscht wird, ausgewertet werden muss. Das bedeutet, dass komplexe Ausdrücke die Leistung beeinträchtigen können, insbesondere, wenn Operationen ausgeführt werden, die viele Zeilen auf einmal betreffen (wie etwa Masseneinfügungen).

Am effizientesten sind Hash-Funktionen, die nur eine einzige Tabellenspalte bearbeiten und deren Wert mit dem Spaltenwert konsistent zu- oder abnimmt, da hierdurch ein „Pruning“ von Partitionsbereichen möglich wird. D. h.: Je enger sich der Wert des Ausdrucks an dem Wert der zugrunde liegenden Spalte orientiert, umso effizienter kann MySQL ihn für die Hash-Partitionierung einsetzen.

Wenn beispielsweise date_col eine Spalte vom Typ DATE ist, dann ändert sich der Ausdruck TO_DAYS(date_col) unmittelbar mit dem Wert von date_col, da jede Änderung des Werts von date_col auch den Wert des Ausdrucks ändert, und zwar in völlig konsistenter Form. Der Ausdruck YEAR(date_col) ändert sich bei date_col-Änderungen nicht ganz so unmittelbar wie TO_DAYS(date_col), da nicht jede Änderung in date_col eine entsprechende Änderung in YEAR(date_col) nach sich zieht. Dennoch ist auch YEAR(date_col) ein guter Kandidat für eine Hash-Funktion, da es sich direkt mit einem Teil von date_col ändert und nicht die Gefahr besteht, dass eine Änderung von date_col zu einer unverhältnismäßigen Änderung von YEAR(date_col) führt.

Nehmen wir dagegen an, Sie hätten eine Spalte namens int_col vom Typ INT. Nun betrachten Sie den Ausdruck POW(5-int_col,3) + 6. Dieser wäre ganz schlecht als Hash-Funktion geeignet, da nicht garantiert ist, dass Änderungen von int_col proportionale Änderungen im Wert des Ausdrucks nach sich ziehen. Wenn Sie den Wert von int_col um einen gegebenen Betrag ändern, können dadurch ganz unterschiedliche Änderungen im Wert des Ausdrucks eintreten. Ändern Sie beispielsweise int_col von 5 in 6, so ändert sich der Wert des Ausdrucks um -1, ändern Sie dagegen int_col von 6 in 7, so ändert sich der Wert des Ausdrucks um -7.

Mit anderen Worten: Je enger der Graph des Spaltenwerts im Verhältnis zum Wert des Ausdrucks einer geraden Linie folgt, wie sie durch die Gleichung y=nx vorgegeben ist, wenn n eine von null verschiedene Konstante ist, umso besser eignet sich der Ausdruck für das Hashing. Denn je weniger linear ein Ausdruck ist, umso ungleichmäßiger werden die Daten auf die Partitionen verteilt, die dieser Ausdruck anlegt.

Theoretisch ist bei Ausdrücken, an denen mehrere Spaltenwerte beteiligt sind, auch Pruning möglich, aber es kann schwierig und langwierig sein, herauszufinden, welche dieser Ausdrücke nun wirklich für Pruning geeignet sind. Daher sind Hashing-Ausdrücke mit mehreren Spalten nicht sonderlich zu empfehlen.

Wenn PARTITION BY HASH verwendet wird, ermittelt MySQL anhand des Modulus des Ergebnisses der Benutzerfunktion, welche von num Partitionen verwendet wird. Anders ausgedrückt: Für einen Ausdruck expr wird der Datensatz in der Partition N gespeichert, wobei N = MOD(expr, num) ist. Nehmen wir beispielsweise an, Tabelle t1 ist folgendermaßen definiert, sodass sie 4 Partitionen hat:

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4;

Wenn Sie in t1 einen Datensatz einfügen, dessen col3-Wert '2005-09-15' ist, dann wird die Partition, in der er gespeichert wird, folgendermaßen ermittelt:

MOD(YEAR('2005-09-01'),4)
=  MOD(2005,4)
=  1

MySQL 5.1 unterstützt auch eine Variante der HASH-Partitionierung namens lineares Hashing, die einen komplexen Algorithmus einsetzt, um neu in eine partitionierte Tabelle eingefügte Zeilen zu platzieren. Eine Beschreibung dieses Algorithmus finden Sie unter Abschnitt 17.2.3.1, „LINEAR HASH-Partitionierung“.

Die Benutzerfunktion wird bei jeder Einfügung oder Aktualisierung und unter Umständen auch bei einer Löschung eines Datensatzes ausgewertet.

Hinweis: Wenn die Tabelle, die partitioniert werden soll, einen UNIQUE-Schlüssel hat, müssen Spalten, die als Argumente an die HASH-Benutzerfunktion oder die column_list des KEYs übergeben werden, Teil dieses Schlüssels sein.

17.2.3.1. LINEAR HASH-Partitionierung

MySQL unterstützt auch lineares Hashing, das sich vom regulären Hashing insofern unterscheidet, als es einen linearen Zweierpotenz-Algorithmus verwendet, während das reguläre Hashing den Modulus des Werts der Hashing-Funktion benutzt.

Der einzige syntaktische Unterschied zwischen der linearen und der regulären Hash-Partitionierung besteht darin, dass der PARTITION BY-Klausel das Schlüsselwort LINEAR hinzugefügt wird:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LINEAR HASH( YEAR(hired) )
PARTITIONS 4;

Wenn Sie einen Ausdruck expr haben, wird beim linearen Hashing der Datensatz in Partition Nummer N von num Partitionen gespeichert, wobei N nach dem folgenden Algorithmus abgeleitet ist:

  1. Finde die nächste Zweierpotenz größer num. Wir nennen diesen Wert V; er kann folgendermaßen berechnet werden:

    V = POWER(2, CEILING(LOG(2, num)))
    

    (Nehmen wir beispielsweise an, num sei 13. Dann ist LOG(2,13) gleich 3.7004397181411. CEILING(3.7004397181411) ist 4 und V = POWER(2,4), was 16 ergibt.)

  2. Setze N = F(column_list) & (V - 1).

  3. Wobei N >= num:

    • Setze V = CEIL(V / 2)

    • Setze N = N & (V - 1)

Angenommen, die Tabelle t1, die lineare Hash-Partitionierung nutzt und 6 Partitionen hat, wird mit folgender Anweisung angelegt:

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY LINEAR HASH( YEAR(col3) )
    PARTITIONS 6;

Nehmen wir weiterhin an, Sie möchten in t1 zwei Datensätze einfügen, in denen die Spalte col3 die Werte '2003-04-14' und '1998-10-19' aufweist. Die Partitionsnummer für die erste dieser Spalten wird folgendermaßen ermittelt:

V = POWER(2, CEILING( LOG(2,7) )) = 8
N = YEAR('2003-04-14') & (8 - 1)
   = 2003 & 7
   = 3

(3 >= 6 is FALSE: record stored in partition #3)

Die Partitionsnummer für den zweiten Eintrag wird berechnet mit:

V = 8
N = YEAR('1998-10-19') & (8-1)
  = 1998 & 7
  = 6

(6 >= 6 is TRUE: additional step required)

N = 6 & CEILING(5 / 2)
  = 6 & 3
  = 2

(2 >= 6 is FALSE: record stored in partition #2)

Der Vorteil einer linearen Hash-Partitionierung besteht darin, dass sich Partitionen weit schneller hinzufügen, löschen, zusammenführen und aufspalten lassen. Das kann ein Segen sein, wenn man mit Tabellen arbeiten muss, die extrem große Datenmengen (Terabytes) enthalten. Der Nachteil ist, dass die Daten wahrscheinlich nicht so gleichmäßig auf die Partitionen verteilt werden wie bei der normalen Hash-Partitionierung.

17.2.4. KEY-Partitionierung

Die Partitionierung durch Schlüssel gleicht der Partitionierung durch Hash, nur dass dort, wo die Hash-Partitionierung einen benutzerdefinierten Ausdruck verwendet, die Schlüsselpartitionierung eine vom MySQL Server gelieferte Hash-Funktion einsetzt. MySQL Cluster verwendet zu diesem Zweck MD5(); für Tabellen, die andere Speicher-Engines benutzen, setzt der Server seine eigene interne Hash-Funktion ein, die auf demselben Algorithmus wie PASSWORD() beruht.

Die Syntaxregeln für CREATE TABLE ... PARTITION BY KEY sind dieselben wie bei der Erstellung einer Hash-partitionierten Tabelle. Die Hauptunterschiede sind:

  • Statt HASH wird KEY eingesetzt.

  • KEY nimmt nur eine Liste mit einem oder mehreren Spaltennamen entgegen. Seit MySQL 5.1.5 müssen die Spalten, die als Partitionierungsschlüssel eingesetzt werden, den Primärschlüssel der Tabelle (sofern sie einen hat) ganz oder teilweise abdecken.

    Seit MySQL 5.1.6 nimmt KEY eine Liste mit null oder mehr Spaltennamen entgegen. Wenn kein Spaltenname als Partitionierungsschlüssel angegeben ist, wird der Primärschlüssel der Tabelle verwendet. Die folgende CREATE TABLE-Anweisung gilt beispielsweise in MySQL 5.1.6 oder höher:

    CREATE TABLE k1 (   
        id INT NOT NULL PRIMARY KEY,   
        name VARCHAR(20) 
    ) 
    PARTITION BY KEY() 
    PARTITIONS 2;
    

    In diesem Fall ist der Partitionierungsschlüssel die Spalte id, auch wenn das in der Ausgabe von SHOW CREATE TABLE oder in der Spalte PARTITION_EXPRESSION der Tabelle INFORMATION_SCHEMA.PARTITIONS nicht erkennbar ist.

    Hinweis: Seit MySQL 5.1.6 werden außerdem Tabellen, die die Speicher-Engine NDB Cluster verwenden, implizit mit KEY partitioniert, wobei auch hier wieder der Primärschlüssel der Tabelle als Partitionierungsschlüssel dient. Nehmen wir als Beispiel die Tabelle, die mit folgender Anweisung erzeugt wird:

    CREATE TABLE kndb (   
        id INT NOT NULL PRIMARY KEY,   
        name VARCHAR(20) NOT NULL 
    )
    ENGINE=NDBCLUSTER;
    

    Obwohl die Anweisung keine PARTITION BY-Klausel enthält, zeigt die Ausgabe von SHOW CREATE TABLE kndb Folgendes an:

    CREATE TABLE `kndb` (   
        `id` int(11) NOT NULL,   
        `name` varchar(20) NOT NULL.
        PRIMARY KEY  (`id`) 
    )
    ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY ();
    

    Falls die Cluster-Tabelle keinen expliziten Primärschlüssel hat, wird der „verborgene“ Primärschlüssel, den die Speicher-Engine NDB automatisch für jede Cluster-Tabelle generiert, als Partitionierungsschlüssel eingesetzt.

    Wichtig: Auf einer schlüsselpartitionierten Tabelle, die eine andere Speicher-Engine als NDB CLuster verwendet, können Sie keine ALTER TABLE DROP PRIMARY KEY-Anweisung ausführen, ansonsten tritt der Fehler ERROR 1466 (HY000): Field in list of fields for partition function not found in table ein. Dieses Problem betrifft keine MySQL CLuster-Tabellen, die durch KEY partitioniert werden: In solchen Fällen wird die Tabelle reorganisiert, wobei der „verborgene“ Primärschlüssel als neuer Partitionierungsschlüssel der Tabelle verwendet wird. Siehe Kapitel 16, MySQL Cluster.

Es ist auch möglich, eine Tabelle durch linearen Schlüssel zu partitionieren. Hier sehen Sie ein einfaches Beispiel:

CREATE TABLE tk (
    col1 INT NOT NULL,
    col2 CHAR(5),
    col3 DATE
) 
PARTITION BY LINEAR KEY (col1)
PARTITIONS 3;

Die Verwendung von LINEAR hat auf die KEY-Partitionierung denselben Effekt wie auf die HASH-Partitionierung, wobei die Partitionsnummer mit einem Zweierpotenz-Algorithmus anstatt mit Modulo-Arithmetik abgeleitet wird. Eine Beschreibung dieses Algorithmus und seiner Implikationen finden Sie unter Abschnitt 17.2.3.1, „LINEAR HASH-Partitionierung“.

17.2.5. Unterpartitionen

Teilpartitionierung, auch als zusammengesetzte Partitionierung bezeichnet, ist die weitere Unterteilung von Partitionen einer partitionierten Tabelle. Betrachten Sie als Beispiel die folgende CREATE TABLE-Anweisung:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH(TO_DAYS(purchased))
    SUBPARTITIONS 2 (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (2000),
        PARTITION p2 VALUES LESS THAN MAXVALUE
    );

Die Tabelle ts hat 3 RANGE-Partitionen. Jede dieser Partitionen, also p0, p1 und p2, ist ihrerseits in 2 Teilpartitionen unterteilt. Im Endeffekt ist die gesamte Tabelle auf 3 * 2 = 6 Partitionen verteilt. Durch die PARTITION BY RANGE-Klausel speichern allerdings die ersten beiden dieser Partitionen nur Datensätze, die in der purchased-Spalte einen Wert kleiner als 1990 aufweisen.

In MySQL 5.1 können Sie Tabellen, die durch RANGE oder LIST partitioniert werden, noch weiter aufteilen. Teilpartitionen können entweder die HASH- oder die KEY-Partitionierung verwenden. Dies bezeichnet man auch als zusammengesetzte Partitionierung.

Außerdem ist es möglich, Teilpartitionen explizit mit SUBPARTITION-Klauseln zu definieren, um Optionen für einzelne Teilpartitionen angeben zu können. So könnte man dieselbe ts-Tabelle wie im vorigen Beispiel auch wortreicher erzeugen:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0,
            SUBPARTITION s1
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s2,
            SUBPARTITION s3
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s4,
            SUBPARTITION s5
        )
    );

An dieser Syntax ist Folgendes bemerkenswert:

  • Jede Partition muss dieselbe Anzahl Teilpartitionen haben.

  • Wenn Sie mit SUBPARTITION explizit Teilpartitionen für eine Partition einer partitionierten Tabelle definieren, müssen Sie sie für alle anderen auch definieren. Die folgende Anweisung wird scheitern:

    CREATE TABLE ts (id INT, purchased DATE)
        PARTITION BY RANGE( YEAR(purchased) )
        SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
            PARTITION p0 VALUES LESS THAN (1990) (
                SUBPARTITION s0,
                SUBPARTITION s1
            ),
            PARTITION p1 VALUES LESS THAN (2000),
            PARTITION p2 VALUES LESS THAN MAXVALUE (
                SUBPARTITION s2,
                SUBPARTITION s3
            )
        );
    

    Die Anweisung würde sogar dann fehlschlagen, wenn sie eine SUBPARTITIONS 2-Klausel enthielte.

  • Jede SUBPARTITION-Klausel muss (mindestens) den Namen für die Teilpartition enthalten. Ansonsten können Sie alle Optionen setzen, die Sie wünschen, oder aber die Teilpartition mit den Standardeinstellungen anlegen.

  • Teilpartitionsnamen müssen innerhalb einer Partition eindeutig sein, aber nicht innerhalb der Tabelle als Ganzes. So ist beispielsweise die folgende CREATE TABLE-Anweisung zulässig:

    CREATE TABLE ts (id INT, purchased DATE)
        PARTITION BY RANGE( YEAR(purchased) )
        SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
            PARTITION p0 VALUES LESS THAN (1990) (
                SUBPARTITION s0,
                SUBPARTITION s1
            ),
            PARTITION p1 VALUES LESS THAN (2000) (
                SUBPARTITION s0,
                SUBPARTITION s1
            ),
            PARTITION p2 VALUES LESS THAN MAXVALUE (
                SUBPARTITION s0,
                SUBPARTITION s1
            )
        );
    

Teilpartitionen können bei extrem großen Tabellen helfen, die Daten und Indizes über viele Festplatten zu verteilen. Angenommen, Sie haben 6 Festplatten als /disk0, /disk1, /disk2 und so weiter gemountet. Nun schauen Sie sich folgendes Beispiel an:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0 
                DATA DIRECTORY = '/disk0/data' 
                INDEX DIRECTORY = '/disk0/idx',
            SUBPARTITION s1 
                DATA DIRECTORY = '/disk1/data' 
                INDEX DIRECTORY = '/disk1/idx'
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s0 
                DATA DIRECTORY = '/disk2/data' 
                INDEX DIRECTORY = '/disk2/idx',
            SUBPARTITION s1 
                DATA DIRECTORY = '/disk3/data' 
                INDEX DIRECTORY = '/disk3/idx'
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s0 
                DATA DIRECTORY = '/disk4/data' 
                INDEX DIRECTORY = '/disk4/idx',
            SUBPARTITION s1 
                DATA DIRECTORY = '/disk5/data' 
                INDEX DIRECTORY = '/disk5/idx'
        )
    );

In diesem Fall wird für die Daten und die Indizes jedes RANGE eine eigene Festplatte genutzt. Es sind aber auch viele andere Varianten möglich; ein anderes Beispiel wäre:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH(TO_DAYS(purchased)) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0a 
                DATA DIRECTORY = '/disk0' 
                INDEX DIRECTORY = '/disk1',
            SUBPARTITION s0b 
                DATA DIRECTORY = '/disk2' 
                INDEX DIRECTORY = '/disk3'
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s1a 
                DATA DIRECTORY = '/disk4/data' 
                INDEX DIRECTORY = '/disk4/idx',
            SUBPARTITION s1b 
                DATA DIRECTORY = '/disk5/data' 
                INDEX DIRECTORY = '/disk5/idx'
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s2a,
            SUBPARTITION s2b
        )
    );

Hier wird nach folgenden Regeln gespeichert:

  • Da Zeilen mit purchased-Daten aus der Zeit vor 1990 sehr viel Platz belegen, werden sie auf vier Arten aufgeteilt, wobei jeweils eine eigene Festplatte den Daten und Indizes jeder der beiden Teilpartitionen (s0a und s0b) der Partition p0 gewidmet ist. Mit anderen Worten:

    • Die Daten für die Teilpartition s0a werden auf /disk0 gespeichert.

    • Die Indizes für die Teilpartition s0a werden auf /disk1 gespeichert.

    • Die Daten für die Teilpartition s0b werden auf /disk2 gespeichert.

    • Die Indizes für die Teilpartition s0b werden auf /disk3 gespeichert.

  • Die Zeilen mit den Daten der Jahre 1990 bis 1999 (Partition p1) belegen nicht so viel Speicher wie die Daten von vor 1990. So werden sie auf zwei Festplatten (/disk4 und /disk5) verteilt, nicht auf vier, wie wir es mit den alten in p0 gespeicherten Daten getan haben:

    • Die Daten und Indizes der ersten Teilpartition von p1 (s1a) werden auf /disk4 gespeichert, und zwar die Daten im Verzeichnis /disk4/data und die Indizes im Verzeichnis /disk4/idx.

    • Die Daten und Indizes der zweiten Teilpartition von p1 (s1b) werden auf /disk5 gespeichert, und zwar die Daten im Verzeichnis /disk5/data und die Indizes im Verzeichnis /disk5/idx.

  • Die Zeilen der Daten, die die Jahre ab 2000 betreffen (Partition p2), nehmen noch weniger Speicherplatz in Anspruch als die beiden anderen Datumsbereiche. Zurzeit reicht der Standardspeicherort noch für sie aus.

    Wenn später einmal die Verkaufsdaten für die mit dem Jahr 2000 beginnende Dekade so umfangreich werden, dass der Standardspeicherort nicht mehr ausreicht, können die entsprechenden Zeilen mit einer ALTER TABLE ... REORGANIZE PARTITION-Anweisung verschoben werden. Wie das geht, erfahren Sie unter Abschnitt 17.3, „Partitionsverwaltung“.

17.2.6. Wie die MySQL-Partitionierung NULL-Werte handhabt

Die Partitionierung in MySQL gestattet durchaus auch einen Partitionierungsausdruck mit dem Wert NULL, sei es nun ein Spaltenwert oder der Wert eines vom Benutzer angegebenen Ausdrucks. Normalerweise behandelt MySQL NULL in solchen Fällen als null. Wenn Sie dieses Verhalten unterbinden möchten, müssen Sie Tabellen so entwerfen, dass sie keine Nullwerte erlauben, indem Sie die Spalten als NOT NULL deklarieren.

In diesem Abschnitt geben wir einige Beispiele, die zeigen sollen, wie MySQL NULL-Werte verarbeitet, wenn die passende Partition für eine Zeile ermittelt werden soll.

Wenn Sie eine Zeile in eine RANGE- oder LIST-partitionierte Tabelle einfügen und der Spaltenwert, der zur Bestimmung der Partition herangezogen wird, NULL ist, so wird dieser Wert als 0 interpretiert. Betrachten Sie beispielsweise die folgenden beiden Tabellen:

mysql> CREATE TABLE tnlist (
    ->     id INT,
    ->     name VARCHAR(5)
    -> )
    -> PARTITION BY LIST(id) (
    ->     PARTITION p1 VALUES IN (0),
    ->     PARTITION p2 VALUES IN (1)
    -> );
Query OK, 0 rows affected (0.09 sec)

mysql> CREATE TABLE tnrange (
    ->     id INT,
    ->     name VARCHAR(5)
    -> )
    -> PARTITION BY RANGE(id) (
    ->     PARTITION p1 VALUES LESS THAN (1),
    ->     PARTITION p2 VALUES LESS THAN MAXVALUE
    -> );
Query OK, 0 rows affected (0.09 sec)

mysql> INSERT INTO tnlist VALUES (NULL, 'bob');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tnrange VALUES (NULL, 'jim');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tnlist;
+------+------+
| id   | name |
+------+------+
| NULL | bob  |
+------+------+
1 row in set (0.00 sec)

mysql> SELECT * FROM tnrange;
+------+------+
| id   | name |
+------+------+
| NULL | jim  |
+------+------+
1 row in set (0.00 sec)

In beiden Tabellen war die Spalte id nicht als NOT NULL deklariert, kann also NULL-Werte annehmen. Dass die Zeilen in den p1-Partitionen der Tabellen gespeichert wurden, können Sie überprüfen, indem Sie diese Partitionen löschen und dann die SELECT-Anweisungen erneut ausführen:

mysql> ALTER TABLE tnlist DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec)

mysql> ALTER TABLE tnrange DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec)

mysql> SELECT * FROM tnlist;
Empty set (0.00 sec)

mysql> SELECT * FROM tnrange;
Empty set (0.00 sec)

Bei einer HASH- oder KEY-Partitionierung wird ein Partitionierungsausdruck, der NULL ergibt, so behandelt, als sei sein Rückgabewert null. Dieses Verhalten können wir überprüfen, indem wir betrachten, wie sich die Erstellung einer HASH-partitionierten Tabelle, in die eine Zeile mit den entsprechenden Daten geladen wird, auf das Dateisystem auswirkt. Angenommen, Sie haben eine Tabelle namens tnhash in der Datenbank test mit folgender Anweisung angelegt:

CREATE TABLE tnhash (
    id INT,
    name VARCHAR(5)
)
PARTITION BY HASH(id)
PARTITIONS 2;

Wenn wir eine RPM-Installation von MySQL auf Linux zugrunde legen, erzeugt diese Anweisung zwei .MYD-Dateien in /var/lib/mysql/test, die in der bash-Shell wie folgt angezeigt werden können:

/var/lib/mysql/test> ls *.MYD -l
-rw-rw----  1 mysql mysql 0 2005-11-04 18:41 tnhash#P#p0.MYD
-rw-rw----  1 mysql mysql 0 2005-11-04 18:41 tnhash#P#p1.MYD

(Hinweis: Vor MySQL 5.1.5 hätten diese Dateien tnhash_p0.MYD und tnhash_p1.MYD geheißen. Unter Abschnitt D.1.1, „Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)“, und Bug#13437 finden Sie weitere Informationen darüber, wie sich diese Änderung auf Upgrades auswirkt.)

Beachten Sie, dass die beiden Dateien 0 Byte groß sind. Fügen Sie nun in tnhash eine Zeile ein, die in der Spalte id den Wert NULL aufweist, und überprüfen Sie, ob die Zeile tatsächlich eingefügt wurde:

mysql> INSERT INTO tnhash VALUES (NULL, 'sam');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tnhash;
+------+------+
| id   | name |
+------+------+
| NULL | sam  |
+------+------+
1 row in set (0.01 sec)

Bitte erinnern Sie sich, dass für einen Integer N der Wert von NULL MOD N immer NULL ist. Dieses Ergebnis wird behandelt, um 0 als die korrekte Partition festzulegen. Wenn wir nun wieder in die System-Shell gehen (wobei weiterhin bash zugrunde gelegt wird), können wir erkennen, dass der Wert in die erste Partition (die nach Voreinstellung p0 heißt) eingefügt wurde, indem wir die Datendateien erneut auflisten:

var/lib/mysql/test> ls *.MYD -l
-rw-rw----  1 mysql mysql 20 2005-11-04 18:44 tnhash#P#p0.MYD
-rw-rw----  1 mysql mysql  0 2005-11-04 18:41 tnhash#P#p1.MYD

Wie Sie sehen, hat die INSERT-Anweisung nur die Datei tnhash_p0.MYD modifiziert, deren Umfang auf der Platte angewachsen ist, ohne auf die andere Datendatei Einfluss zu nehmen.

Nehmen wir nun an, wir hätten folgende Tabelle:

CREATE TABLE tndate (
    id INT,
    dt DATE
)
PARTITION BY RANGE( YEAR(dt) ) (
    PARTITION p0 VALUES LESS THAN (1990),
    PARTITION p1 VALUES LESS THAN (2000),
    PARTITION p2 VALUES LESS THAN MAXVALUE
);

Wie andere MySQL-Funktionen gibt auch YEAR(NULL) den Wert NULL zurück. Eine Zeile, die in der dt-Spalte den Wert NULL hat, wird behandelt, als wäre der Partitionierungsausdruck in Wirklichkeit 0, und folglich in die Partition p0 eingefügt.

17.3. Partitionsverwaltung

MySQL 5.1 bietet eine Reihe von Möglichkeiten, um partitionierte Tabellen zu modifizieren. Man kann Partitionen hinzufügen, löschen, umdefinieren, zusammenführen oder aufspalten. Alle diese Aktionen werden mit den Partitionierungserweiterungen des ALTER TABLE-Befehls ausgeführt (zur Syntax siehe Abschnitt 13.1.2, „ALTER TABLE). Darüber hinaus können Sie sich Informationen über partitionierte Tabellen und Partitionen beschaffen. Diese Themen werden in den nachfolgenden Abschnitten behandelt.

Hinweis: In MySQL 5.1 müssen alle Partitionen einer partitionierten Tabelle die gleiche Anzahl von Teilpartitionen haben. Nach dem Anlegen der Tabelle ist es nicht mehr möglich, die Teilpartitionierung zu ändern.

Die Anweisung ALTER TABLE ... PARTITION BY ... funktioniert seit MySQL 5.1.6; zuvor in MySQL 5.1 wurde ihre Syntax zwar als gültig akzeptiert, aber Auswirkungen hatte sie keine.

Um das Partitionierungsschema einer Tabelle zu ändern, müssen Sie nur dem ALTER TABLE-Befehl eine partition_options-Klausel hinzufügen. Diese Klausel hat dieselbe Syntax, die auch in CREATE TABLE zur Erstellung einer partitionierten Tabelle verwendet wird, und beginnt immer mit den Schlüsselwörtern PARTITION BY. Angenommen, Sie haben eine nach Bereichen partitionierte Tabelle mit folgender CREATE TABLE-Anweisung angelegt:

CREATE TABLE trb3 (id INT, name VARCHAR(50), purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (1995),
        PARTITION p2 VALUES LESS THAN (2000),
        PARTITION p3 VALUES LESS THAN (2005)
    );

Um aus dieser Tabelle eine schlüsselpartitionierte Tabelle mit zwei Partitionen zu machen, wobei der Wert der Spalte id die Grundlage für den Schlüssel liefert, können Sie folgende Anweisung geben:

ALTER TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2;

Auf die Struktur der Tabelle hat dies dieselben Auswirkungen wie eine Löschung und Rekonstruktion mit CREATE TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2;.

17.3.1. Verwaltung von RANGE- und LIST-Partitionen

Da das Hinzufügen und Löschen von Partitionen für Bereichs- und Listenpartitionen ganz ähnlich behandelt wird, fassen wir die Verwaltung dieser beiden Partitionierungsarten im vorliegenden Abschnitt zusammen. Über den Umgang mit Hash- oder schlüsselpartitionierten Tabellen erfahren Sie unter Abschnitt 17.3.2, „Verwaltung von HASH- und KEY-Partitionen“, Genaueres. Weil das Löschen einer RANGE- oder LIST--Partition einfacher ist als das Hinzufügen, beginnen wir mit dem Löschen.

Um eine Partition aus einer RANGE- oder LIST-partitionierten Tabelle zu löschen, verwenden Sie den ALTER TABLE-Befehl mit einer DROP PARTITION-Klausel. Das folgende sehr einfach gehaltene Beispiel geht davon aus, dass Sie mit den folgenden CREATE TABLE- und INSERT-Anweisungen bereits eine nach Bereich partitionierte Tabelle angelegt und mit 10 Datensätzen bevölkert haben:

mysql> CREATE TABLE tr (id INT, name VARCHAR(50), purchased DATE)
    ->     PARTITION BY RANGE( YEAR(purchased) ) (
    ->         PARTITION p0 VALUES LESS THAN (1990),
    ->         PARTITION p1 VALUES LESS THAN (1995),
    ->         PARTITION p2 VALUES LESS THAN (2000),
    ->         PARTITION p3 VALUES LESS THAN (2005)
    ->     );
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO tr VALUES
    ->     (1, 'desk organiser', '2003-10-15'),
    ->     (2, 'CD player', '1993-11-05'),
    ->     (3, 'TV set', '1996-03-10'),
    ->     (4, 'bookcase', '1982-01-10'),
    ->     (5, 'exercise bike', '2004-05-09'),
    ->     (6, 'sofa', '1987-06-05'),
    ->     (7, 'popcorn maker', '2001-11-22'),
    ->     (8, 'aquarium', '1992-08-04'),
    ->     (9, 'study desk', '1984-09-16'),
    ->     (10, 'lava lamp', '1998-12-25');
Query OK, 10 rows affected (0.01 sec)                  

Welche Daten in die Partition p2 geladen wurden, sehen Sie hier:

mysql> SELECT * FROM tr
    -> WHERE purchased BETWEEN '1995-01-01' AND '1999-12-31';
+------+-----------+------------+
| id   | name      | purchased  |
+------+-----------+------------+
|    3 | TV set    | 1996-03-10 |
|   10 | lava lamp | 1998-12-25 |
+------+-----------+------------+
2 rows in set (0.00 sec)

Um nun die Partition p2 zu löschen, führen Sie folgenden Befehl aus:

mysql> ALTER TABLE tr DROP PARTITION p2;
Query OK, 0 rows affected (0.03 sec)

Hinweis: Die Speicher-Engine NDB Cluster in MySQL 5.1 kennt kein ALTER TABLE ... DROP PARTITION. Doch immerhin unterstützt sie die anderen in diesem Kapitel beschriebenen Partitionierungserweiterungen der ALTER TABLE-Anweisung.

Es ist sehr wichtig, sich zu merken, dass Sie beim Löschen einer Partition alle darin gespeicherten Daten mit löschen. Dies erkennen Sie, wenn Sie die obige SELECT-Anfrage erneut ausführen:

mysql> SELECT * FROM tr WHERE purchased 
    -> BETWEEN '1995-01-01' AND '1999-12-31';
Empty set (0.00 sec)

Wenn Sie alle Daten aus allen Partitionen löschen, aber die Tabellendefinition und ihr Partitionierungsschema erhalten möchten, verwenden Sie den Befehl TRUNCATE TABLE. (Siehe auch Abschnitt 13.2.9, „TRUNCATE.)

Wenn Sie die Partitionierung einer Tabelle ändern möchten, ohne Daten zu verlieren, verwenden Sie stattdessen ALTER TABLE ... REORGANIZE PARTITION. Weiter unten oder in Abschnitt 13.1.2, „ALTER TABLE, finden Sie Informationen über REORGANIZE PARTITION.

Wenn Sie nun einen SHOW CREATE TABLE-Befehl ausführen, können Sie sehen, wie sich die Partitionierung der Tabelle geändert hat:

mysql> SHOW CREATE TABLE tr\G
*************************** 1. row ***************************
       Table: tr
Create Table: CREATE TABLE `tr` (
  `id` int(11) default NULL,
  `name` varchar(50) default NULL,
  `purchased` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
PARTITION BY RANGE ( YEAR(purchased) ) (
  PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM, 
  PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM, 
  PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM
)
1 row in set (0.01 sec)

Wenn Sie nun in die geänderte Tabelle Zeilen einfügen, die in der Spalte purchased Werte zwischen '1995-01-01' und '2004-12-31' einschließlich aufweisen, werden diese Zeilen in der Partition p3 gespeichert. Dies können Sie folgendermaßen überprüfen:

mysql> INSERT INTO tr VALUES (11, 'pencil holder', '1995-07-12');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tr WHERE purchased 
    -> BETWEEN '1995-01-01' AND '2004-12-31';
+------+----------------+------------+
| id   | name           | purchased  |
+------+----------------+------------+
|   11 | pencil holder  | 1995-07-12 |
|    1 | desk organiser | 2003-10-15 |
|    5 | exercise bike  | 2004-05-09 |
|    7 | popcorn maker  | 2001-11-22 |
+------+----------------+------------+
4 rows in set (0.00 sec)

mysql> ALTER TABLE tr DROP PARTITION p3;
Query OK, 0 rows affected (0.03 sec)

mysql> SELECT * FROM tr WHERE purchased 
    -> BETWEEN '1995-01-01' AND '2004-12-31';
Empty set (0.00 sec)

Beachten Sie, dass die Anzahl der Zeilen, die aus der Tabelle mit ALTER TABLE ... DROP PARTITION gelöscht wurden, vom Server nicht so gemeldet wird, wie es bei einer entsprechenden DELETE-Anweisung der Fall wäre.

Zum Löschen von LIST-Partitionen wird genau dieselbe ALTER TABLE ... DROP PARTITION-Syntax verwendet wie zum Löschen von RANGE-Partitionen. Allerdings unterscheiden sich die Auswirkungen, die dieses auf den späteren Gebrauch der Tabelle hat, in einer wichtigen Hinsicht: In die Tabelle können nun keine Zeilen mehr eingefügt werden, die irgendwelche in der Werteliste der gelöschten Partition vorkommenden Werte aufweisen. (Ein Beispiel finden Sie unter Abschnitt 17.2.2, „LIST-Partitionierung“.)

Um einer zuvor partitionierten Tabelle eine neue Bereichs- oder Listenpartition hinzuzufügen, verwenden Sie die ALTER TABLE ... ADD PARTITION-Anweisung. Für Tabellen, die nach RANGE partitioniert werden, können Sie mit dieser Anweisung einen neuen Wertebereich am Anfang oder Ende der Liste der vorhandenen Partitionen hinzufügen. Angenommen, Sie haben eine partitionierte Tabelle mit Mitgliedsdaten Ihrer Organisation wie folgt definiert:

CREATE TABLE members (
    id INT, 
    fname VARCHAR(25),
    lname VARCHAR(25), 
    dob DATE
)
PARTITION BY RANGE( YEAR(dob) ) (
    PARTITION p0 VALUES LESS THAN (1970),
    PARTITION p1 VALUES LESS THAN (1980),
    PARTITION p2 VALUES LESS THAN (1990)
);

Nehmen wir nun weiterhin an, das Mindestalter der Mitglieder ist 16 Jahre. Da es bereits auf Ende 2005 zugeht, stellen Sie fest, dass Sie demnächst Mitglieder aufnehmen müssen, die 1990 geboren wurden, und in den darauf folgenden Jahren wiederum Mitglieder, die noch später zur Welt kamen. Mit folgender Anweisung können Sie die members-Tabelle so umändern, dass auch Mitglieder zulässig sind, die in den Jahren 1990 bis 1999 geboren wurden:

ALTER TABLE ADD PARTITION (PARTITION p3 VALUES LESS THAN (2000));

Wichtig: Tabellen, die nach Bereich partitioniert wurden, können Sie mit dem Befehl ADD PARTITION nur am oberen Ende der Wertebereichsliste neue Partitionen hinzufügen. Wenn Sie versuchen, auf diesem Weg Partitionen zwischen oder vor vorhandenen Partitionen einzufügen, wird folgender Fehler generiert:

mysql> ALTER TABLE members
     >     ADD PARTITION (
     >     PARTITION p3 VALUES LESS THAN (1960));
ERROR 1463 (HY000): VALUES LESS THAN value must be strictly increasing for each partition

In ähnlicher Weise können Sie auch einer LIST-partitionierten Tabelle neue Partitionen hinzufügen. Nehmen wir als Beispiel folgende Tabelle:

CREATE TABLE tt (
    id INT, 
    data INT
)
PARTITION BY LIST(data) (
    PARTITION p0 VALUES IN (5, 10, 15),
    PARTITION p1 VALUES IN (6, 12, 18)
);

Mit der folgenden Anweisung können Sie eine neue Partition für Zeilen einrichten, deren data-Spalten die Werte 7, 14 und 21 aufweisen:

ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21));

Achtung: Sie können keine neue LIST-Partition hinzufügen, die irgendwelche bereits in den Wertelisten bestehender Partitionen enthaltenen Werte aufweist. Wenn Sie dieses versuchen, wird ein Fehler gemeldet:

mysql> ALTER TABLE tt ADD PARTITION 
     >     (PARTITION np VALUES IN (4, 8, 12));
ERROR 1465 (HY000): Multiple definition of same constant in list partitioning

Da Zeilen mit dem Wert 12 in der data-Spalte bereits der Partition p1 zugewiesen sind, können Sie nicht in Tabelle tt eine neue Partition anlegen, die ebenfalls 12 in ihrer Werteliste hat. Wenn Sie dies dennoch tun müssen, löschen Sie zuerst p1 und fügen dann np und danach eine neue p1 mit einer modifizierten Definition hinzu. Allerdings würden dadurch, wie zuvor bereits gesagt, alle in p1 gespeicherten Daten verloren gehen, was im Allgemeinen nicht der angestrebte Effekt ist. Eine andere Lösung könnte so aussehen, dass Sie eine Kopie der Tabelle mit der neuen Partitionierung anlegen, dann die Daten mit einer CREATE TABLE ... SELECT ... hineinkopieren und schließlich die alte Tabelle löschen und die neue umbenennen. Wenn Sie es mit großen Datenmengen zu tun haben, könnte dies allerdings eine zeitraubende Angelegenheit werden, die dort, wo Hochverfügbarkeit gewährleistet werden muss, vielleicht vollends unmöglich ist.

Seit MySQL 5.1.6 können Sie mehrere Partitionen in einer einzigen ALTER TABLE ... ADD PARTITION-Anweisung anlegen:

CREATE TABLE employees (
  id INT NOT NULL,
  fname VARCHAR(50) NOT NULL,
  lname VARCHAR(50) NOT NULL,
  hired DATE NOT NULL
)
PARTITION BY RANGE( YEAR(hired) ) (
  PARTITION p1 VALUES LESS THAN (1991),
  PARTITION p2 VALUES LESS THAN (1996),
  PARTITION p3 VALUES LESS THAN (2001),
  PARTITION p4 VALUES LESS THAN (2005)
);

ALTER TABLE employees ADD PARTITION (
    PARTITION p5 VALUES LESS THAN (2010), 
    PARTITION p6 VALUES LESS THAN MAXVALUE
);

Zum Glück bietet die Implementierung der Partitionierung in MySQL Möglichkeiten, Partitionen ohne Datenverlust umzudefinieren. Betrachten wir zunächst eine Reihe von einfachen Beispielen zur RANGE-Partitionierung. Bitte erinnern Sie sich an die members-Tabelle, die nun folgendermaßen definiert ist:

mysql> SHOW CREATE TABLE members\G
*************************** 1. row ***************************
       Table: members
Create Table: CREATE TABLE `members` (
  `id` int(11) default NULL,
  `fname` varchar(25) default NULL,
  `lname` varchar(25) default NULL,
  `dob` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
PARTITION BY RANGE ( YEAR(dob) ) (
  PARTITION p0 VALUES LESS THAN (1970) ENGINE = MyISAM, 
  PARTITION p1 VALUES LESS THAN (1980) ENGINE = MyISAM, 
  PARTITION p2 VALUES LESS THAN (1990) ENGINE = MyISAM.
  PARTITION p3 VALUES LESS THAN (2000) ENGINE = MyISAM
)

Angenommen, Sie möchten alle Zeilen der Mitglieder, die vor 1960 geboren wurden, in eine separate Partition speichern. Wir wir bereits sahen, ist dies mit der Anweisung ALTER TABLE ... ADD PARTITION nicht möglich. Sie können jedoch eine andere Partitionierungserweiterung von ALTER TABLE benutzen, um dies zu erreichen:

ALTER TABLE members REORGANIZE PARTITION p0 INTO (
    PARTITION s0 VALUES LESS THAN (1960),
    PARTITION s1 VALUES LESS THAN (1970)
);

Im Endeffekt spaltet dieser Befehl die Partition p0 in zwei neue Partitionen s0 und s1 auf. Außerdem werden die bisher in p0 gespeicherten Daten nach den Regeln der beiden PARTITION ... VALUES ...-Klauseln auf die neuen Partitionen verteilt, sodass s0 nur Datensätze aufnimmt, deren YEAR(dob)-Wert kleiner als 1960 ist, und s1 nur Datensätze, deren YEAR(dob)-Wert größer oder gleich 1960, aber kleiner als 1970 ist.

Sie können auch mit einer REORGANIZE PARTITION-Klausel benachbartete Partitionen verschmelzen. Mit dem folgenden Befehl stellen Sie die members-Tabelle wieder auf ihre vorherige Partitionierung um:

ALTER TABLE members REORGANIZE PARTITION s0,s1 INTO (
    PARTITION p0 VALUES LESS THAN (1970)
);

Wenn Sie Partitionen mit REORGANIZE PARTITION aufteilen oder zusammenführen, gehen keine Daten verloren. Bei der Ausführung dieser Anweisung verschiebt MySQL alle Datensätze, die zuvor in den Partitionen s0 und s1 gespeichert waren, wieder in die Partition p0.

REORGANIZE PARTITION hat folgende allgemeine Syntax:

ALTER TABLE tbl_name 
    REORGANIZE PARTITION partition_list 
    INTO (partition_definitions);

tbl_name ist hier der Name der partitionierten Tabelle und partition_list ist eine kommagetrennte Liste mit den Namen einer oder mehrerer vorhandener Partitionen, die geändert werden sollen. partition_definitions ist eine kommagetrennte Liste neuer Partitionsdefinitionen, für die dieselben Regeln gelten, wie die partition_definitions einer CREATE TABLE-Anweisung (siehe Abschnitt 13.1.5, „CREATE TABLE). Doch REORGANIZE PARTITION kann noch mehr, als nur Partitionen aufspalten oder zusammenführen: Mit demselben Befehl können Sie auch beispielsweise aus den vier Partitionen der members-Tabelle zwei machen:

ALTER TABLE members REORGANIZE PARTITION p0,p1,p2,p3 INTO (
    PARTITION m0 VALUES LESS THAN (1980),
    PARTITION m1 VALUES LESS THAN (2000)
);

REORGANIZE PARTITION ist auch für LIST-partitionierte Tabellen geeignet. Greifen wir noch einmal das Problem auf, wie man eine neue Partition zu der listenpartitionierten Tabelle tt hinzufügen könnte. Der Versuch scheiterte, weil die neue Partition einen Wert hatte, der bereits in den Wertelisten der vorhandenen Partitionen auftauchte. Dies können wir umgehen, indem wir eine Partition hinzufügen, deren Liste nur zulässige Werte enthält, und dann die neue und die vorhandenen Partitionen so umorganisieren, dass der konfliktbeladene Wert aus der Werteliste der alten in die Werteliste der neuen Partition übertragen wird:

ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8));
ALTER TABLE tt REORGANIZE PARTITION p1,np INTO (
    PARTITION p1 VALUES IN (6, 18),
    PARTITION np VALUES in (4, 8, 12)
);

Die folgenden Punkte sind wichtig, wenn Sie ALTER TABLE ... REORGANIZE PARTITION zur Neupartitionierung von RANGE- oder LIST-partitionierten Tabellen einsetzen:

  • Für die PARTITION-Klauseln, mit denen das neue Partitionierungsschema festgelegt wird, gelten dieselben Regeln wie für die, die in einer CREATE TABLE-Anweisung benutzt werden.

    Zuallererst müssen Sie daran denken, dass das neue Partitionierungsschema keine sich überschneidenden Wertebereiche (RANGE-partitionierte Tabellen) bzw. keine Überschneidungen in den Wertemengen (LIST-partitionierte Tabellen) haben darf.

    Hinweis: Vor MySQL 5.1.4 konnten Sie die Namen vorhandener Partitionen nicht in der INTO-Klausel wiederverwenden, selbst wenn diese Partitionen gelöscht oder umdefiniert werden sollten. Weitere Informationen gibt es unter Abschnitt D.1.3, „Änderungen in Release 5.1.4 (21. Dezember 2005)“.

  • Die Kombination der Partitionen in der partition_definitions-Liste sollte insgesamt denselben Wertebereich oder dieselbe Wertemenge abdecken wie die Kombination der Partitionen, die in der partition_list aufgeführt sind.

    In der members-Tabelle, die in diesem Abschnitt als Beispiel dient, decken zum Beispiel die Partitionen p1 und p2 zusammen die Jahre 1980 bis 1999 ab. Daher muss jede Neuorganisation dieser beiden Partitionen insgesamt denselben Zeitraum in Jahren abdecken.

  • In RANGE-partitionierten Tabellen können Sie nur benachbarte Partitionen reorganisieren, da keine Bereichspartitionen übersprungen werden dürfen.

    Sie können beispielsweise die members-Tabelle nicht mit einer Anweisung reorganisieren, die mit ALTER TABLE members REORGANIZE PARTITION p0,p2 INTO ... anfängt, da p0 die Jahre vor 1970 und p2 die Jahre von 1990 bis einschließlich 1999 umfasst und somit die beiden Partitionen nicht benachbart sind.

  • Sie können REORGANIZE PARTITION nicht einsetzen, um den Partitionierungstyp einer Tabelle zu ändern, also beispielsweise nicht aus RANGE-Partitionen HASH-Partitionen oder umgekehrt machen. Auch können Sie diesen Befehl nicht verwenden, um den Partitionierungsausdruck oder die Partitionierungsspalte zu ändern. Um dieses zu tun, ohne die Tabelle löschen und rekonstruieren zu müssen, verwenden Sie ALTER TABLE ... PARTITION BY .... Zum Beispiel:

    ALTER TABLE members 
        PARTITION BY HASH( YEAR(dob) )
        PARTITIONS 8;
    

    Hinweis: In MySQL 5.1 5.1.5-alpha ist ALTER TABLE ... PARTITION BY ... noch nicht implementiert. Stattdessen müssen Sie die Tabelle entweder löschen und mit der gewünschten Partitionierung neu erzeugen oder, wenn Sie die Daten der Tabelle bewahren möchten, mit CREATE TABLE ... SELECT ... die neue Tabelle anlegen und die Daten aus der alten herüberkopieren, um anschließend die alte Tabelle zu löschen und in einem letzten Schritt die neue Tabelle umzubenennen, wenn dies gewünscht wird.

17.3.2. Verwaltung von HASH- und KEY-Partitionen

Die Partitionierung von Hash- oder schlüsselpartitionierten Tabellen lässt sich in ähnlicher Weise ändern, wobei sich Tabellen mit diesen beiden Formen der Partitionierung in mehrerer Hinsicht von bereichs- oder listenpartitionierten Tabellen unterscheiden. Daher werden in diesem Abschnitt nur Änderungen von Hash- oder schlüsselpartitionierten Tabellen behandelt. Das Hinzufügen und Löschen der Partitionen von bereichs- oder listenpartitionierten Tabellen wird in Abschnitt 17.3.1, „Verwaltung von RANGE- und LIST-Partitionen“, beschrieben.

Sie können Partitionen aus HASH- oder KEY-partitionierten Tabellen nicht genauso löschen wie aus RANGE- oder LIST-partitionierten Tabellen. Doch zum Zusammenführen von HASH- oder KEY-partitionierten Tabellen können Sie ebenfalls den ALTER TABLE ... COALESCE PARTITION-Befehl verwenden. Angenommen, Sie haben eine Tabelle mit Kundendaten, die in 12 Partitionen aufgeteilt ist. Diese clients-Tabelle ist folgendermaßen definiert:

CREATE TABLE clients (
    id INT,
    fname VARCHAR(30),
    lname VARCHAR(30),
    signed DATE
)
PARTITION BY HASH( MONTH(signed) )
PARTITIONS 12;

Um die Anzahl der Partitionen von 12 auf 6 zu reduzieren, führen Sie folgenden ALTER TABLE-Befehl aus:

mysql> ALTER TABLE clients COALESCE PARTITION 6;
Query OK, 0 rows affected (0.02 sec)

COALESCE funktioniert genauso gut mit HASH-, KEY-, LINEAR HASH- oder LINEAR KEY-partitionierten Tabellen. Hier sehen Sie ein ähnliches Beispiel wie oben, allerdings dieses Mal mit einer Tabelle, die nach LINEAR KEY partitioniert ist:

mysql> CREATE TABLE clients_lk (
    ->     id INT,
    ->     fname VARCHAR(30),
    ->     lname VARCHAR(30),
    ->     signed DATE
    -> )
    -> PARTITION BY LINEAR KEY(signed)
    -> PARTITIONS 12;
Query OK, 0 rows affected (0.03 sec)

mysql> ALTER TABLE clients_lk COALESCE PARTITION 6;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

COALESCE kann nicht verwendet werden, um die Anzahl der Partitionen zu erhöhen. Ein Versuch, dies zu tun, verursacht folgenden Fehler:

mysql> ALTER TABLE clients COALESCE PARTITION 18;
ERROR 1478 (HY000): Cannot remove all Partitionen, use DROP TABLE instead

Um die Anzahl der Partitionen der clients-Tabelle von 12 auf 18 zu erhöhen, erteilen Sie folgende ALTER TABLE ... ADD PARTITION-Anweisung:

ALTER TABLE clients ADD PARTITION PARTITIONS 18;

Hinweis: ALTER TABLE ... REORGANIZE PARTITION kann nicht für HASH- oder KEY-partitionierte Tabellen verwendet werden.

17.3.3. Wartung von Partitionen

Hinweis: Die Befehle, die dieser Abschnitt beschreibt, sind in MySQL 5.1 noch nicht implementiert. Sie werden vor allem vorgestellt, um Feedback von Benutzern zu bekommen, die die Software während des Entwicklungszyklus der Version 5.1 vor der Produktionsreife testen. (Mit anderen Worten: Bitte schicken Sie uns keine Bugreports mit dem Hinweis, dass diese Befehle nicht funktionieren.) Die Informationen in diesem Abschnitt ändern sich noch ständig, da die Entwicklung der Partitionierung für MySQL 5.1 weitergeht. Wir werden den Abschnitt aktualisieren, wenn Partitionierungsfeatures implementiert oder verbessert werden.

MySQL 5.1 ermöglicht viele Wartungsarbeiten im Bereich der Partitionierung. MySQL unterstützt für partitionierte Tabellen nicht die Befehle CHECK TABLE, OPTIMIZE TABLE, ANALYZE TABLE oder REPAIR TABLE. Dagegen können Sie jedoch eine Reihe von Erweiterungen des ALTER TABLE-Befehls einsetzen, um diese Operationen auf einer oder mehreren Partitionen direkt auszuführen. Diese Erweiterungen sind im Folgenden dargestellt:

  • Partitionen neu erstellen: Legt die Partition neu an, hat denselben Effekt wie das Löschen und anschließende Wiedereinfügen aller in der Partition gespeicherten Datensätze. Kann bei der Defragmentierung nützlich sein.

    Beispiel:

    ALTER TABLE t1 REBUILD PARTITION (p0, p1);
    
  • Partitionen optimieren: Wenn Sie viele Zeilen aus einer Partition gelöscht oder viele Änderungen an einer partitionierten Tabelle mit Zeilen variabler Länge (VARCHAR-, BLOB- oder TEXT-Spalten) vorgenommen haben, können Sie mit ALTER TABLE ... OPTIMIZE PARTITION unbenutzten Speicherplatz zurückholen und die Datendatei der Partition defragmentieren.

    Beispiel:

    ALTER TABLE t1 OPTIMIZE PARTITION (p0, p1);
    

    Wenn Sie auf einer Partition OPTIMIZE PARTITION ausführen, ist dies dasselbe, als würden Sie CHECK PARTITION, ANALYZE PARTITION und REPAIR PARTITION aufrufen.

  • Partitionen analysieren: Liest und speichert die Schlüsselverteilungen für Partitionen.

    Beispiel:

    ALTER TABLE t1 ANALYZE PARTITION (p3);
  • Partitionen reparieren: Repariert beschädigte Partitionen.

    Beispiel:

    ALTER TABLE t1 REPAIR PARTITION (p0,p1);
    
  • Partitionen überprüfen: Sie können Partitionen in ganz ähnlicher Weise auf Fehler untersuchen, wie Sie es mit CHECK TABLE für nicht partitionierte Tabellen machen würden.

    Beispiel:

    ALTER TABLE trb3 CHECK PARTITION (p1);
    

    Dieser Befehl sagt Ihnen, ob die Daten oder Indizes in Partition p1 der Tabelle t1 beschädigt sind. Wenn dies der Fall ist, können Sie die Partition mit ALTER TABLE ... REPAIR PARTITION wieder reparieren.

Diese Aufgaben können Sie auch lösen, indem Sie mysqlcheck oder myisamchk auf den separaten .MYI-Dateien ausführen, die bei der Partitionierung einer Tabelle generiert werden. Siehe Abschnitt 8.9, „mysqlcheck — Hilfsprogramm für die Wartung und Reparatur von Tabellen“. (Diese Möglichkeit steht auch bereits im Pre-Alpha-Code zur Verfügung.)

17.3.4. Abruf von Informationen über Partitionen

Dieser Abschnitt beschreibt, wie Sie sich Informationen über bestehende Partitionen beschaffen können. Da sich diese Funktionalität noch in der Planung befindet, sind die folgenden Ausführungen zurzeit nur eine Absichtserklärung über die Dinge, die wir in MySQL 5.1 implementieren wollen.

Wie bereits an anderer Stelle in diesem Kapitel gesagt, zeigt die Ausgabe von SHOW CREATE TABLE auch eine PARTITION BY-Klausel an, mit der eine partitionierte Tabelle angelegt wurde. Zum Beispiel:

mysql> SHOW CREATE TABLE trb3\G
*************************** 1. row ***************************
       Table: trb3
Create Table: CREATE TABLE `trb3` (
  `id` int(11) default NULL,
  `name` varchar(50) default NULL,
  `purchased` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
PARTITION BY RANGE (YEAR(purchased)) (
  PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM, 
  PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM, 
  PARTITION p2 VALUES LESS THAN (2000) ENGINE = MyISAM, 
  PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM
)
1 row in set (0.00 sec)

Hinweis: In frühen MySQL 5.1-Releases wurde die PARTITIONS-Klausel nicht für Tabellen angezeigt, die nach HASH oder KEY partitioniert waren. Dies wurde in MySQL 5.1.6 behoben.

SHOW TABLE STATUS funktioniert auch für partitionierte Tabellen und hat dieselbe Ausgabe wie für nichtpartitionierte Tabellen, nur dass die Spalte Engine immer den Wert 'PARTITION' hat. (Mehr über diesen Befehl erfahren Sie in Abschnitt 13.5.4.21, „SHOW TABLE STATUS.)

Informationen über Partitionen liefert Ihnen auch das INFORMATION_SCHEMA, zu dem auch eine PARTITIONS-Tabelle gehört. Siehe Abschnitt 22.19, „Die Tabelle INFORMATION_SCHEMA PARTITIONS.

Seit MySQL 5.1.5 können Sie mit EXPLAIN PARTITIONS herausfinden, welche Partitionen einer partitionierten Tabelle an einer SELECT-Anfrage beteiligt sind. Das Schlüsselwort PARTITIONS fügt der Ausgabe von EXPLAIN eine partitions-Spalte hinzu, in der die Partitionen aufgeführt sind, in denen die Anfrage Datensätze erkannt hat.

Angenommen, Sie haben eine Tabelle trb1, die folgendermaßen definiert und mit Daten gefüllt ist:

CREATE TABLE trb1 (id INT, name VARCHAR(50), purchased DATE)
    PARTITION BY RANGE(id)
    (
        PARTITION p0 VALUES LESS THAN (3),
        PARTITION p1 VALUES LESS THAN (7),
        PARTITION p2 VALUES LESS THAN (9),
        PARTITION p3 VALUES LESS THAN (11)
    );

INSERT INTO trb1 VALUES
    (1, 'desk organiser', '2003-10-15'),
    (2, 'CD player', '1993-11-05'),
    (3, 'TV set', '1996-03-10'),
    (4, 'bookcase', '1982-01-10'),
    (5, 'exercise bike', '2004-05-09'),
    (6, 'sofa', '1987-06-05'),
    (7, 'popcorn maker', '2001-11-22'),
    (8, 'aquarium', '1992-08-04'),
    (9, 'study desk', '1984-09-16'),
    (10, 'lava lamp', '1998-12-25');

Mit folgendem Befehl können Sie sich darüber informieren, welche Partitionen in einer Anfrage wie SELECT * FROM trb1; benutzt werden:

mysql> EXPLAIN PARTITIONS SELECT * FROM trb1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: trb1
   partitions: p0,p1,p2,p3
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10
        Extra: Using filesort

In diesem Fall wurden 4 vier Partitionen durchsucht. Wenn Sie der Anfrage jedoch eine einschränkende Bedingung hinzufügen, die den Partitionierungsschlüssel enthält, können Sie erkennen, dass nur diejenigen Partitionen gescannt werden, die passende Werte enthalten:

mysql> EXPLAIN PARTITIONS SELECT * FROM trb1 WHERE id < 5\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: trb1
   partitions: p0,p1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10
        Extra: Using where

EXPLAIN PARTITIONS informiert über verwendete und mögliche Schlüssel ebenso wie die standardmäßige EXPLAIN SELECT-Anweisung:

mysql> ALTER TABLE trb1 ADD PRIMARY KEY (id);
Query OK, 10 rows affected (0.03 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> EXPLAIN PARTITIONS SELECT * FROM trb1 WHERE id < 5\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: trb1
   partitions: p0,p1
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 7
        Extra: Using where

Beachten Sie jedoch folgende Restriktionen von EXPLAIN PARTITIONS:

  • Sie dürfen die Schlüsselwörter PARTITIONS und EXTENDED nicht zusammen in derselben EXPLAIN ... SELECT-Anweisung benutzen, sonst verursachen Sie einen Syntaxfehler.

  • Der Befehl EXPLAIN PARTITIONS liefert nur dann brauchbare Ergebnisse, wenn er zur Untersuchung von Anfragen auf RANGE- oder LIST-partitionierten Tabellen verwendet wird. (Bei KEY- oder HASH-partitionierten Tabellen listet der Befehl einfach alle Partitionen in der partitions-Spalte seiner Ausgabe auf.)

    Wenn Sie mit EXPLAIN PARTITIONS eine Anfrage auf einer nichtpartitionierten Tabelle untersuchen, wird zwar kein Fehler ausgelöst, aber der Wert der partitions-Spalte ist dann immer NULL.

  • EXPLAIN PARTITIONS funktioniert zurzeit nur mit Tabellen, die auf einer Integer-Spalte partitioniert werden.

17.4. Beschränkungen und Grenzen der Partitionierung

Dieser Abschnitt beschreibt die gegenwärtigen Restriktionen der MySQL-Partitionierungsunterstützung:

  • Partitionierte Tabellen unterstützen keine Fremdschlüssel. Dies schließt auch Tabellen ein, die mit der Speicher-Engine InnoDB arbeiten.

  • Partitionierte Tabellen können zwar jede beliebige Speicher-Engine von MySQL benutzen, aber alle Partitionen und Teilpartitionen der Tabelle (wenn vorhanden) müssen dieselbe Engine verwenden.

    Wir hoffen, diese Beschränkung in einem künftigen MySQL-Release aufzuheben.

  • Ein Partitionierungsschlüssel muss entweder eine Integer-Spalte oder ein Ausdruck sein, der einen Integer ergibt. In jedem Fall muss der verwendete Wert nichtnegativ sein. Zurzeit sind auch NULL-Werte zulässig, aber dies wird sich noch ändern.

  • Teilpartitionen können nur HASH- oder KEY-Partitionierung verwenden.

Kapitel 18. Raumbezogene Erweiterungen in MySQL

Mit den raumbezogenen Erweiterungen von MySQL lassen sich geographische Features erstellen, speichern und analysieren. Diese Features stehen für MyISAM-, InnoDB-, NDB-, BDB- und ARCHIVE-Tabellen zur Verfügung. (Da jedoch die ARCHIVE-Engine keine Indizes unterstützt, können raumbezogene Spalten in ARCHIVE nicht indiziert werden. Auch in MySQL Cluster sind keine Indizes auf raumbezogenen Spalten möglich.

Dieses Kapitel behandelt folgende Themen:

  • Grundlagen der raumbezogenen Erweiterungen im Geodatenmodell OpenGIS

  • Datenformate zur Darstellung raumbezogener Daten

  • Wie raumbezogene Daten in MySQL verwendet werden

  • Indizierung raumbezogener Daten

  • MySQLs Abweichungen von der OpenGIS-Spezifikation

Mehr zum Thema

  • Das Open Geospatial Consortium veröffentlicht das OpenGIS® Simple Features Specifications For SQL: ein Dokument, das mehrere Konzepte vorstellt, wie ein auf SQL basierendes relationales Datenbanksystem auch raumbezogene Daten unterstützen könnte. Diese Spezifikation finden Sie auf der Website des OGC unter http://www.opengis.org/docs/99-049.pdf.

  • Wenn Sie Fragen oder sonstige Anliegen hinsichtlich der raumbezogenen Erweiterungen zu MySQL haben, können Sie diese im GIS-Forum zur Diskussion stellen: http://forums.mysql.com/list.php?23.

18.1. Einführung in die raumbezogenen Funktionen von MySQL

MySQL implementiert raumbezogene Erweiterungen nach der Spezifikation des Open Geospatial Consortium (OGC). Dabei handelt es sich um ein internationales Konsortium von mehr als 250 Unternehmen, Behörden und Universitäten, die alle an der Entwicklung von öffentlich zugänglichen, konzeptionellen Lösungen für alle Arten von Programmen arbeiten, welche mit der Verwaltung raumbezogener Daten zu tun haben. Das OGC betreibt eine Website unter http://www.opengis.org/.

Im Jahre 1997 veröffentlichte das Open Geospatial Consortium die OpenGIS® Simple Features Specifications For SQL, ein Dokument, das mehrere Konzepte vorstellt, wie ein SQL-RDBMS raumbezogene Daten unterstützen könnte. Diese Spezifikation finden Sie auf der Website des OGC unter http://www.opengis.org/docs/99-049.pdf. Sie enthält wichtige Zusatzinformationen zu diesem Kapitel.

MySQL implementiert einen Teil der vom OGC empfohlenen SQL with Geometry Types-Umgebung. Gemeint ist damit eine SQL-Umgebung, die um eine Reihe von geometrischen Typen erweitert wurde. Eine SQL-Spalte, die einen geometrischen Wert hat, wird als Spalte geometrischen Typs implementiert. Die Spezifikation beschreibt eine Reihe von geometrischen Typen für SQL sowie Funktionen, die mit diesen Typen arbeiten können, um geometrische Werte zu erzeugen und zu analysieren.

Ein geographisches Feature ist irgendetwas, das irgendwo auf der Welt einen Standort hat. Hierzu gehören:

  • ein Gegenstand, wie zum Beispiel ein Berg, ein Teich oder eine Stadt

  • ein Raum, wie beispielsweise ein Postleitzahlengebiet oder die Tropen

  • ein klar definierter Ort, wie zum Beispiel eine Straßenkreuzung als der Schnittpunkt zweier Straßen

In manchen Dokumenten werden geographische Features als geospatiale Features bezeichnet.

Auch das Wort Geometrie bezeichnet ein geographisches Feature. Ursprünglich wurde der Begriff Geometrie für die Vermessung der Erde verwendet. Eine weitere Bedeutung bekam das Wort in der Kartographie, wo es die geometrischen Merkmale bezeichnet, die Kartographen für ihr Abbild der Welt verwenden.

Im vorliegenden Kapitel werden die Begriffe geographisches Feature, geospatiales Feature, Feature und Geometrie synonym eingesetzt. Am häufigsten verwenden wir das Wort Geometrie im Sinne von einem Punkt oder einer Menge von Punkten, die irgendetwas auf der Welt darstellen, das sich an einem Ort befindet.

18.2. Das OpenGIS-Geometriemodell

Die Geometrietypen, die das OGC in seiner SQL with Geometry Types-Umgebung vorschlägt, beruhen auf dem OpenGIS Geometry Model. In diesem Modell hat jedes geometrische Objekt folgende allgemeine Eigenschaften:

  • Es ist verbunden mit einem Georeferenzsystem, welches den Koordinatenraum beschreibt, in dem das Objekt definiert ist.

  • Es gehört zu einer Geometrieklasse.

18.2.1. Hierarchie der Geometrieklassen

Die Geometrieklassen definieren folgende Hierarchie:

  • Geometry (nichtinstanziierbar)

    • Point (instanziierbar)

    • Curve (nichtinstanziierbar)

      • LineString (instanziierbar)

        • Line

        • LinearRing

    • Surface (nichtinstanziierbar)

      • Polygon (instanziierbar)

    • GeometryCollection (instanziierbar)

      • MultiPoint (instanziierbar)

      • MultiCurve (nichtinstanziierbar)

        • MultiLineString (instanziierbar)

      • MultiSurface (nichtinstanziierbar)

        • MultiPolygon (instanziierbar)

Von nichtinstanziierbaren Klassen können keine Objekte erzeugt werden, von instanziierbaren Klassen hingegen sehr wohl. Alle Klassen haben Eigenschaften und instanziierbare Klassen können darüber hinaus Zusicherungen machen (Regeln, nach denen gültige Klasseninstanzen definiert sind).

Geometry ist die abstrakte Basisklasse. Die instanziierbaren Unterklassen von Geometry dürfen nur null-, eins- und zweidimensionale geometrische Objekte haben, die in einem zweidimensionalen Koordinatenraum vorkommen. Alle instanziierbaren Geometrieklassen sind so definiert, dass gültige Instanzen dieser Klassen topologisch geschlossen sein müssen (d. h., in allen definierten Geometrien ist ihre jeweilige Grenze enthalten).

Die Basisklasse Geometry hat die Unterklassen Point, Curve, Surface und GeometryCollection:

  • Point stellt nulldimensionale Objekte dar.

  • Curve stellt eindimensionale Objekte dar und hat die Unterklasse LineString, die ihrerseits die Unterklassen Line und LinearRing hat.

  • Surface ist für zweidimensionale Objekte da und hat die Unterklasse Polygon.

  • GeometryCollection besitzt die spezialisierten null-, eins- und zweidimensionalen Collection-Klassen namens MultiPoint, MultiLineString und MultiPolygon zur Modellierung von Geometrien aus Points, LineStrings oder Polygons. MultiCurve und MultiSurface sind abstrakte Oberklassen, die Collection-Interfaces für den Umgang mit Curves und Surfaces realisieren.

Geometry, Curve, Surface, MultiCurve und MultiSurface sind nichtinstanziierbare Klassen. Sie definieren eine Menge von gemeinsamen Methoden für ihre Unterklassen und sind dazu da, erweitert zu werden.

Point, LineString, Polygon, GeometryCollection, MultiPoint, MultiLineString und MultiPolygon sind instanziierbare Klassen.

18.2.2. Die Klasse Geometry

Geometry ist die Wurzelklasse der Hierarchie. Sie ist eine nichtinstanziierbare Klasse, besitzt jedoch eine Reihe von Eigenschaften, die alle Klassen gemeinsam haben, welche aus einer Unterklasse von Geometry erzeugt wurden. Diese Eigenschaften werden in der folgenden Liste aufgeführt. Bestimmte Unterklassen haben ihre eigenen, ganz speziellen Eigenschaften, die weiter unten beschrieben werden.

Geometrie-Eigenschaften

Ein Geometriewert hat folgende Eigenschaften:

  • Den Typ. Jeder Geometriewert gehört zu einer der instanziierbaren Klassen der Hierarchie.

  • Seinen SRID (Spatial Reference Identifier). Dieser Wert steht für das Georeferenzsystem, welches den Koordinatenraum beschreibt, in dem das Geometrieobjekt definiert ist.

    In MySQL ist der SRID-Wert ein einfacher Integer, der mit dem Geometriewert verbunden ist. Allen Berechnungen liegt die euklidische (planare) Geometrie zugrunde.

  • Seine Koordinaten in seinem Georeferenzsystem, dargestellt als Zahlen mit doppelter Genauigkeit (8 Byte). Alle nichtleeren Geometrien enthalten mindestens ein Koordinatenpaar (x,y). Leere Geometrien enthalten keine Koordinaten.

    Koordinaten hängen mit dem SRID zusammen. So kann zum Beispiel in unterschiedlichen Koordinatensystemen der Abstand zwischen zwei Objekten verschieden sein, selbst dann, wenn die Objekte dieselben Koordinaten haben, da der Abstand in einem planaren Koordinatensystem und der Abstand in einem geozentrischen System (die Koordinaten auf der Erdoberfläche) zwei verschiedene Dinge sind.

  • Seinen Innenbereich, seine Grenze und seinen Außenbereich.

    Jede Geometrie hat irgendeine Position im Raum. Der Außenbereich ist der Raum, welcher nicht von der Geometrie belegt wird, und der Innenbereich der Raum, der von ihr bedeckt ist. Die Grenze ist die Schnittstelle zwischen Innenbereich und Außenbereich der Geometrie.

  • Sein MBR (Minimum Bounding Rectangle, dt.: kleinstes einschließendes Rechteck), auch Envelope genannt. Dies ist die begrenzende Geometrie, die durch die kleinsten und größten (x,y)-Koordinaten gebildet wird:

    ((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
    
  • Ob der Wert einfach (simple) oder nicht einfach (non-simple) ist. Geometriewerte der Typen LineString, MultiPoint und MultiLineString sind entweder einfach oder nicht einfach. Jeder Typ hat seine eigenen Zusicherungen darüber, ob er einfach oder nicht einfach ist.

  • Ob der Wert geschlossen oder nicht geschlossen ist. Geometriewerte der Typen (LineString, MultiString) sind entweder geschlossen oder nicht geschlossen. Jeder Typ hat seine eigenen Zusicherungen darüber, ob er geschlossen oder nicht geschlossen ist.

  • Ob der Wert leer oder nichtleer ist. Eine Geometrie ist leer, wenn sie keine Punkte enthält. Außenbereich, Innenbereich und Grenze einer leeren Geometrie sind nicht definiert (d. h., sie werden durch einen NULL-Wert dargestellt). Eine leere Geometrie ist per Definition immer einfach und hat die Fläche 0.

  • Seine Dimension. Eine Geometrie kann die Dimension –1, 0, 1 oder 2 haben:

    • –1 für eine leere Geometrie.

    • 0 für eine Geometrie ohne Länge und ohne Fläche.

    • 1 für eine Geometrie mit einer von null verschiedenen Länge und der Fläche null.

    • 2 für eine Geometrie mit einer von null verschiedenen Fläche.

    Point-Objekte haben die Dimension null. LineString-Objekte haben die Dimension 1. Polygon-Objekte haben die Dimension 2. MultiPoint-, MultiLineString- und MultiPolygon-Objekte haben dieselben Dimensionen wie die Elemente, aus denen sie bestehen.

18.2.3. Die Klasse Point

Ein Point ist eine Geometrie, die einen einzigen Punkt im Koordinatenraum darstellt.

Beispiele für Point

  • Stellen Sie sich eine Weltkarte in großem Maßstab mit vielen Städten vor. Die Städte könnte man mit Point-Objekten darstellen.

  • Auf einem Stadtplan könnte ein Point-Objekt eine Bushaltestelle darstellen.

Eigenschaften von Point

  • Wert der x-Koordinate.

  • Wert der y-Koordinate.

  • Ein Point ist als eine nulldimensionale Geometrie definiert.

  • Die Grenze eines Points ist die leere Menge.

18.2.4. Die Klasse Curve

Eine Curve ist eine eindimensionale Geometrie, die in der Regel durch eine Abfolge von Punkten dargestellt wird. Spezielle Unterklassen von Curve definieren die Art der Interpolation zwischen den Punkten. Curve ist eine nichtinstanziierbare Klasse.

Eigenschaften von Curve

  • Eine Curve hat die Koordinaten ihrer Punkte.

  • Eine Curve ist als eindimensionale Geometrie definiert.

  • Eine Curve ist einfach, wenn sie nicht zweimal durch denselben Punkt geht.

  • Eine Curve ist geschlossen, wenn ihr Anfangs- gleich ihrem Endpunkt ist.

  • Die Grenze einer geschlossenen Curve ist leer.

  • Die Grenze einer nicht geschlossenen Curve besteht aus ihren beiden Endpunkten.

  • Eine Curve, die einfach und geschlossen ist, ist ein LinearRing.

18.2.5. Die Klasse LineString

Ein LineString ist eine Curve mit linearer Interpolation zwischen den Punkten.

Beispiele für LineString

  • Auf einer Weltkarte könnten LineString-Objekte Flüsse darstellen.

  • Auf einem Stadtplan könnten LineString-Objekte Straßen darstellen.

Eigenschaften von LineString

  • Ein LineString hat Segmentkoordinaten, die durch jeweils aufeinander folgende Punktpaare definiert sind.

  • Ein LineString ist eine Line, wenn er aus genau zwei Punkten besteht.

  • Ein LineString ist ein LinearRing, wenn er sowohl geschlossen als auch einfach ist.

18.2.6. Die Klasse Surface

Eine Surface ist eine zweidimensionale Geometrie. Sie ist eine nichtinstanziierbare Klasse. Ihre einzige instanziierbare Unterklasse ist Polygon.

Eigenschaften von Surface

  • Eine Surface ist als zweidimensionale Geometrie definiert.

  • Die OpenGIS-Spezifikation definiert eine einfache Surface als eine Geometrie, die aus einem einzelnen „Patch“ besteht, zu dem eine einzige Außengrenze und null oder mehr Innengrenzen gehören.

  • Die Grenze einer einfachen Surface ist die Menge der geschlossenen Kurven, die ihrer Außen- und Innengrenze entsprechen.

18.2.7. Die Klasse Polygon

Ein Polygon ist eine planare Surface, die eine mehrseitige Geometrie darstellt. Sie ist definiert durch eine einzige Außengrenze und null oder mehr Innengrenzen, wobei jede Innengrenze ein Loch im Polygon darstellt.

Beispiele für Polygon

  • Auf einer Regionalkarte könnten Polygon-Objekte Wälder, Landkreise usw. darstellen.

Zusicherungen von Polygon

  • Die Grenze eines Polygon besteht aus einer Menge von LinearRing-Objekten (d. h. LineString-Objekten, die sowohl einfach als auch geschlossen sind), die seine Außen- und seine Innengrenze bilden.

  • Ein Polygon wird nicht von Ringen geschnitten. Ringe können in der Grenze eines Polygon zwar einen Point berühren, aber nur als Tangente.

  • Ein Polygon hat keine geschnittenen Linien, Zacken (Spikes) oder Lücken (Punctures).

  • Der Innenbereich eines Polygon ist eine Menge verbundener Punkte.

  • Ein Polygon kann Löcher haben. Der Außenbereich eines Polygon mit Löchern ist unzusammenhängend. Jedes Loch definiert einen zusammenhängenden Bestandteil des Außenbereichs.

Aufgrund dieser Zusicherungen ist ein Polygon eine einfache Geometrie.

18.2.8. Die Klasse GeometryCollection

Eine GeometryCollection ist eine Sammlung aus einer oder mehreren Geometrien beliebiger Klassen.

Alle Elemente einer GeometryCollection müssen dasselbe Georeferenzsystem (also dasselbe Koordinatensystem) haben. Andere Beschränkungen für die Elemente einer GeometryCollection gibt es nicht, auch wenn die in den folgenden Abschnitten vorgestellten Unterklassen von GeometryCollection nicht alles aufnehmen. Folgende Einschränkungen können für Mitglieder dieser Klasse gelten:

  • Einschränkung des Elementtyps (so kann zum Beispiel ein MultiPoint nur Point-Elemente enthalten)

  • Einschränkung der Dimensionen

  • Einschränkung der räumlichen Überschneidung von Elementen

18.2.9. Die Klasse MultiPoint

Ein MultiPoint ist eine Ansammlung von Point-Geometrien. Die Punkte sind nicht verbunden oder geordnet.

Beispiele für MultiPoint

  • Auf einer Weltkarte könnte ein MultiPoint eine Kette kleiner Inseln darstellen.

  • Auf einem Stadtplan könnte ein MultiPoint Fahrkartenverkaufsstellen darstellen.

Eigenschaften von MultiPoint

  • Ein MultiPoint ist eine nulldimensionale Geometrie.

  • Ein MultiPoint ist einfach, wenn keine zwei seiner Point-Werte gleich sind (dieselben Koordinatenwerte haben).

  • Die Grenze eines MultiPoint ist die leere Menge.

18.2.10. Die Klasse MultiCurve

Eine MultiCurve ist eine Ansammlung von Curve-Geometrien. MultiCurve ist eine nichtinstanziierbare Klasse.

Eigenschaften von MultiCurve

  • Eine MultiCurve ist eine eindimensionale Geometrie.

  • Eine MultiCurve ist genau dann einfach, wenn alle ihre Elemente einfach sind. Die einzigen Überschneidungen von zwei Elementen können an Punkten auftreten, die auf den Grenzen beider Elemente liegen.

  • Eine MultiCurve-Grenze erhalten Sie durch Anwendung der „Mod 2 Union Rule“ (auch „Ungleich-Gleich-Regel“ genannt): Ein Punkt liegt auf der Grenze einer MultiCurve, wenn er auf den Grenzen einer ungeraden Anzahl von MultiCurve-Elementen liegt.

  • Eine MultiCurve ist geschlossen, wenn alle ihre Elemente geschlossen sind.

  • Die Grenze einer geschlossenen MultiCurve ist immer leer.

18.2.11. Die Klasse MultiLineString

Ein MultiLineString ist eine Ansammlung von MultiCurve-Geometrien, die aus LineString-Elementen besteht.

Beispiele für MultiLineString

  • Auf einer Regionalkarte könnte ein MultiLineString ein Flusssystem oder ein Straßennetz darstellen.

18.2.12. Die Klasse MultiSurface

Eine MultiSurface ist eine Ansammlung von Geometrien, die aus Oberflächenelementen besteht. MultiSurface ist eine nichtinstanziierbare Klasse. Ihre einzige instanziierbare Unterklasse ist MultiPolygon.

Zusicherungen von MultiSurface

  • Der Innenbereich von zwei MultiSurface-Oberflächen darf sich nicht überschneiden.

  • Die Grenzen von zwei MultiSurface-Elementen dürfen sich höchstens an einer endlichen Anzahl von Punkten überschneiden.

18.2.13. Die Klasse MultiPolygon

Ein MultiPolygon ist ein MultiSurface-Objekt, das aus Polygon-Elementen besteht.

Beispiele für MultiPolygon

  • Auf einer Regionalkarte könnte ein MultiPolygon eine Seenplatte darstellen.

Zusicherungen fürMultiPolygon

  • Ein MultiPolygon hat keine zwei Polygon-Elemente, deren Innenbereiche sich überschneiden.

  • Ein MultiPolygon hat keine zwei Polygon-Elemente, die sich überschneiden (diese Überschneidung wurde auch bereits durch die vorige Zusicherung untersagt) oder sich an einer unendlichen Anzahl von Punkten berühren.

  • Ein MultiPolygon darf keine geschnittenen Linien, Zacken oder Lücken haben. Ein MultiPolygon ist eine regelmäßige, geschlossene Punktmenge.

  • Ein MultiPolygon mit mehreren Polygonen hat einen unzusammenhängenden Innenbereich. Die Anzahl der zusammenhängenden Bestandteile des Innenbereichs eines MultiPolygon ist gleich der Anzahl seiner Polygone.

Eigenschaften von MultiPolygon

  • Ein MultiPolygon ist eine zweidimensionale Geometrie.

  • Die Grenze eines MultiPolygon besteht aus einer Menge von geschlossenen Kurven (LineString-Werten), die den Grenzen seiner Polygon-Elemente entsprechen.

  • Jede Curve auf der Grenze des MultiPolygon liegt auf der Grenze von genau einem Polygon-Element.

  • Jede Curve auf der Grenze eines Polygon-Elements liegt auf der Grenze des MultiPolygon.

18.3. Unterstützte raumbezogene Datenformate

Dieser Abschnitt beschreibt die raumbezogenen Standarddatenformate, mit denen Geometrieobjekte in Datenbankanfragen dargestellt werden. Diese sind:

  • Well-Known Text(WKT)-Format

  • Well-Known Binary(WKB)-Format

Intern speichert MySQL Geometriewerte in einem Format, das weder WKT noch WKB gleicht.

18.3.1. Well-Known Text(WKT)-Format

Die Well-Known Text(WKT)-Darstellung von Geometrien wurde geschaffen, um Geometriedaten in ASCII-Format austauschen zu können.

Beispiele für WKT-Darstellung von Geometrieobjekten:

  • Ein Point:

    POINT(15 20)
    

    Beachten Sie, dass Punktkoordinaten ohne Komma dazwischen angegeben werden.

  • Ein LineString mit vier Punkten:

    LINESTRING(0 0, 10 10, 20 25, 50 60)
    

    Beachten Sie, dass zwischen den Punktkoordinatenpaaren jeweils ein Komma steht.

  • Ein Polygon mit einem äußeren und einem inneren Ring:

    POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))
    
  • Ein MultiPoint mit drei Point-Werten:

    MULTIPOINT(0 0, 20 20, 60 60)
    
  • Ein MultiLineString mit zwei LineString-Werten:

    MULTILINESTRING((10 10, 20 20), (15 15, 30 15))
    
  • Ein MultiPolygon mit zwei Polygon-Werten:

    MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((5 5,7 5,7 7,5 7, 5 5)))
    
  • Eine GeometryCollection, die aus zwei Point-Werten und einem LineString besteht:

    GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))
    

Eine Backus-Naur-Grammatik mit den formalen Produktionsregeln zum Schreiben von WKT-Werten finden Sie in der OpenGIS-Spezifikation, auf die zu Beginn dieses Kapitels bereits verwiesen wurde.

18.3.2. Well-Known Binary(WKB)-Format

Die Well-Known Binary(WKB)-Darstellung für Geometriewerte ist in der OpenGIS-Spezifikation sowie im ISO-Standard SQL/MM Part 3: Spatial definiert.

Mit der WKB-Darstellung werden Geometriedaten als Binärströme übermittelt. Diese sind BLOB-Werte, die geometrische WKB-Informationen enthalten.

WKB verwendet Ein-Byte-Integer ohne Vorzeichen, Vier-Byte-Integer ohne Vorzeichen und Acht-Byte-Zahlen mit doppelter Genauigkeit (IEEE 754 format). Ein Byte sind acht Bits.

So besteht beispielsweise ein WKB-Wert, der POINT(1 1) darstellt, aus der folgenden Reihe von 21 Byte (hier jeweils durch zwei Hexadezimalziffern dargestellt):

0101000000000000000000F03F000000000000F03F

Diese Folge lässt sich in folgende Bestandteile zerlegen:

Byte order : 01
WKB type   : 01000000
X          : 000000000000F03F
Y          : 000000000000F03F

Die Bestandteile werden folgendermaßen dargestellt:

  • Die Byte-Reihenfolge kann 0 (Little-Endian-Speicherung) oder 1 (Big-Endian-Speicherung) sein. Diese Byte-Reihenfolgen bezeichnet man auch als Network Data Representation (NDR) bzw. External Data Representation (XDR).

  • Der WKB-Typ ist ein Code, der den Geometrietyp angibt. Seine Werte von 1 bis 7 bedeuten Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon und GeometryCollection.

  • Ein Point-Wert hat x- und y-Koordinaten, die jeweils als Wert mit doppelter Genauigkeit dargestellt sind.

Die WKB-Werte für komplexere Geometriewerte werden durch komplexere Datenstrukturen dargestellt. Diese sind in der OpenGIS-Spezifikation genauer beschrieben.

18.4. Erzeugen einer MySQL-Datenbank mit raumbezogenen Werten

Der folgende Abschnitt beschreibt die Datentypen für raumbezogene Daten in MySQL und die Funktionen zur Erstellung und Abfrage raumbezogener Werte.

18.4.1. Raumbezogene Datentypen in MySQL

Die Datentypen von MySQL entsprechen den Klassen von OpenGIS. Einige dieser Typen speichern einzelne Geometriewerte:

  • GEOMETRY

  • POINT

  • LINESTRING

  • POLYGON

GEOMETRY kann Geometriewerte jeden Typs speichern. Die anderen Einzelwerttypen (POINT, LINESTRING und POLYGON) können nur Werte eines bestimmten Geometrietyps aufnehmen.

Die anderen Datentypen speichern Sammlungen von Werten:

  • MULTIPOINT

  • MULTILINESTRING

  • MULTIPOLYGON

  • GEOMETRYCOLLECTION

GEOMETRYCOLLECTION kann eine Ansammlung von Objekten beliebigen Typs speichern. Die anderen Collection-Typen (MULTIPOINT, MULTILINESTRING, MULTIPOLYGON und GEOMETRYCOLLECTION) können nur Werte eines bestimmten Geometrietyps aufnehmen.

18.4.2. Erzeugung raumbezogener Werte

Dieser Abschnitt beschreibt, wie raumbezogene Werte mithilfe der Well-Known Text- und Well-Known Binary-Funktionen des OpenGIS-Standards und mit MySQL-spezifischen Funktionen erzeugt werden.

18.4.2.1. Erzeugung von Geometriewerten mit WKT-Funktionen

MySQL stellt eine Reihe von Funktionen zur Verfügung, die als Eingabeparameter eine Well-Known Text-Darstellung und optional einen Georeferenzsystembezeichner (Spatial Reference System Identifier, SRID) annehmen und die entsprechende Geometrie zurückliefern.

GeomFromText() nimmt einen WKT eines beliebigen Geometrietyps als erstes Argument entgegen. Eine Implementierung stellt auch typspezifische Konstruktorfunktionen zur Erzeugung von Geometriewerten jedes Geometrietyps zur Verfügung.

  • GeomCollFromText(wkt[,srid]), GeometryCollectionFromText(wkt[,srid])

    Erzeugt einen GEOMETRYCOLLECTION-Wert anhand seiner WKT-Darstellung und seines SRID.

  • GeomFromText(wkt[,srid]), GeometryFromText(wkt[,srid])

    Erzeugt einen Geometriewert irgendeines Typs anhand seiner WKT-Darstellung und seines SRID.

  • LineFromText(wkt[,srid]), LineStringFromText(wkt[,srid])

    Erzeugt einen LINESTRING-Wert anhand seiner WKT-Darstellung und seines SRID.

  • MLineFromText(wkt[,srid]), MultiLineStringFromText(wkt[,srid])

    Erzeugt einen MULTILINESTRING-Wert anhand seiner WKT-Darstellung und seines SRID.

  • MPointFromText(wkt[,srid]), MultiPointFromText(wkt[,srid])

    Erzeugt einen MULTIPOINT-Wert anhand seiner WKT-Darstellung und seines SRID.

  • MPolyFromText(wkt[,srid]), MultiPolygonFromText(wkt[,srid])

    Erzeugt einen MULTIPOLYGON-Wert anhand seiner WKT-Darstellung und seines SRID.

  • PointFromText(wkt[,srid])

    Erzeugt einen POINT-Wert anhand seiner WKT-Darstellung und seines SRID.

  • PolyFromText(wkt[,srid]), PolygonFromText(wkt[,srid])

    Erzeugt einen POLYGON-Wert anhand seiner WKT-Darstellung und seines SRID.

Die OpenGIS-Spezifikation definiert auch die folgenden optionalen Funktionen, die MySQL nicht implementiert. Diese Funktionen erzeugen Polygon- oder MultiPolygon-Werte anhand der WKT-Darstellung einer Sammlung von Ringen oder geschlossenen LineString-Werten. Diese Werte können sich schneiden.

  • BdMPolyFromText(wkt,srid)

    Erzeugt einen MultiPolygon-Wert aus einem MultiLineString-Wert im WKT-Format, der eine beliebige Sammlung geschlossener LineString-Werte enthält.

  • BdPolyFromText(wkt,srid)

    Erzeugt einen Polygon-Wert aus einem MultiLineString-Wert im WKT-Format, der eine beliebige Sammlung geschlossener LineString-Werte enthält.

18.4.2.2. Erzeugung von Geometriewerten mit WKB-Funktionen

MySQL kennt Funktionen, die als Eingabeparameter einen BLOB annehmen, welcher eine Well-Known Binary-Darstellung und optional auch einen Georeferenzsystembezeichner (SRID) entgegennehmen. Sie geben die entsprechende Geometrie zurück.

GeomFromWKB() nimmt eine WKB eines beliebigen Geometrietyps als erstes Argument entgegen. Es gibt auch eine Implementierung für typspezifische Konstruktionsfunktionen, die Geometriewerte der einzelnen Geometrietypen erzeugen.

  • GeomCollFromWKB(wkb[,srid]), GeometryCollectionFromWKB(wkb[,srid])

    Erzeugt einen GEOMETRYCOLLECTION-Wert anhand seiner WKB-Darstellung und seines SRID.

  • GeomFromWKB(wkb[,srid]), GeometryFromWKB(wkb[,srid])

    Erzeugt einen Geometriewert beliebigen Typs anhand seiner WKB-Darstellung und seines SRID.

  • LineFromWKB(wkb[,srid]), LineStringFromWKB(wkb[,srid])

    Erzeugt einen LINESTRING-Wert anhand seiner WKB-Darstellung und seines SRID.

  • MLineFromWKB(wkb[,srid]), MultiLineStringFromWKB(wkb[,srid])

    Erzeugt einen MULTILINESTRING-Wert anhand seiner WKB-Darstellung und seines SRID.

  • MPointFromWKB(wkb[,srid]), MultiPointFromWKB(wkb[,srid])

    Erzeugt einen MULTIPOINT-Wert anhand seiner WKB-Darstellung und seines SRID.

  • MPolyFromWKB(wkb[,srid]), MultiPolygonFromWKB(wkb[,srid])

    Erzeugt einen MULTIPOLYGON-Wert anhand seiner WKB-Darstellung und seines SRID.

  • PointFromWKB(wkb[,srid])

    Erzeugt einen POINT-Wert anhand seiner WKB-Darstellung und seines SRID.

  • PolyFromWKB(wkb[,srid]), PolygonFromWKB(wkb[,srid])

    Erzeugt einen POLYGON-Wert anhand seiner WKB-Darstellung und seines SRID.

Die OpenGIS-Spezifikation beschreibt überdies optionale Funktionen zur Erstellung von Polygon- oder MultiPolygon-Werten anhand der WKB-Darstellung einer Ansammlung von Ringen oder geschlossenen LineString-Werten. Diese Werte dürfen sich schneiden. MySQL implementiert diese Funktionen nicht:

  • BdMPolyFromWKB(wkb,srid)

    Erzeugt einen MultiPolygon-Wert aus einem MultiLineString-Wert im WKB-Format, der eine willkürliche Sammlung geschlossener LineString-Werte enthält.

  • BdPolyFromWKB(wkb,srid)

    Erzeugt einen Polygon-Wert aus einem MultiLineString-Wert im WKB-Format, der eine willkürliche Sammlung geschlossener LineString-Werte enthält.

18.4.2.3. Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen

MySQL stellt einige nichtstandardmäßige Funktionen zur Erstellung von WKB-Darstellungen aus Geometriewerten zur Vefügung. Die Funktionen in diesem Abschnitt sind MySQL-Erweiterungen zur OpenGIS-Spezifikation. Die Ergebnisse dieser Funktionen sind BLOB-Werte, die WKB-Darstellungen von Geometriewerten ohne SRID enthalten. Die Ergebnisse dieser Funktionen lassen sich als erstes Argument einer beliebigen Funktion der Funktionsfamilie GeomFromWKB() einsetzen.

  • GeometryCollection(g1,g2,...)

    Erzeugt eine WKB-GeometryCollection. Ist eines der Argumente keine wohlgeformte WKB-Darstellung einer Geometrie, ist der Rückgabewert NULL.

  • LineString(pt1,pt2,...)

    Erzeugt einen WKB-LineString-Wert aus mehreren WKB-Point-Argumenten. Ist eines der Argumente kein WKB-Point, ist der Rückgabewert NULL. Ist die Anzahl der Point-Argumente kleiner als zwei, ist der Rückgabewert NULL.

  • MultiLineString(ls1,ls2,...)

    Erzeugt einen WKB-MultiLineString-Wert aus WKB-LineString-Argumenten. Ist eines der Argumente kein WKB-LineString, ist der Rückgabewert NULL.

  • MultiPoint(pt1,pt2,...)

    Erzeugt einen WKB-MultiPoint-Wert aus WKB-Point-Argumenten. Ist eines der Argumente kein WKB-Point, ist der Rückgabewert NULL.

  • MultiPolygon(poly1,poly2,...)

    Erzeugt einen WKB-MultiPolygon-Wert aus einer Menge von WKB-Polygon-Argumenten. Ist eines der Argumente kein WKB-Polygon, ist der Rückgabewert NULL.

  • Point(x,y)

    Erzeugt einen WKB-Point anhand seiner Koordinaten.

  • Polygon(ls1,ls2,...)

    Erzeugt einen WKB-Polygon-Wert aus einer Anzahl von WKB-LineString-Argumenten. Wenn eines der Argumente nicht die WKB-Darstellung eines LinearRings ist (d. h. kein geschlossener und einfacher LineString), dann ist der Rückgabewert NULL.

18.4.3. Erzeugung raumbezogener Spalten

MySQL kennt eine standardisierte Möglichkeit, raumbezogene Spalten für Geometrietypen anzulegen, beispielsweise mit CREATE TABLE oder ALTER TABLE. Gegenwärtig werden raumbezogene Spalten für MyISAM-, InnoDB-, NDB-, BDB- und ARCHIVE-Tabellen unterstützt. Bitte lesen Sie auch die Anmerkungen über raumbezogene Indizes unter Abschnitt 18.6.1, „Erzeugung raumbezogener Indizes“.

  • Um eine Tabelle mit einer raumbezogenen Spalte anzulegen, verwenden Sie die CREATE TABLE-Anweisung:

    CREATE TABLE geom (g GEOMETRY);
    
  • Mit ALTER TABLE können Sie raumbezogene Spalten in eine vorhandene Tabelle einfügen oder aus ihr löschen:

    ALTER TABLE geom ADD pt POINT;
    ALTER TABLE geom DROP pt;
    

18.4.4. Füllen raumbezogener Spalten

Nachdem Sie raumbezogene Spalten eingerichtet haben, können Sie raumbezogene Daten hineinschreiben.

Die Werte sollten in einem internen Geometrieformat gespeichert werden, aber sie können aus dem Well-Known Text(WKT)- oder Well-Known Binary(WKB)-Format in dieses Format konvertiert werden. Die folgenden Beispiele zeigen, wie man Geometriewerte in eine Tabelle einfügt, indem man WKT-Werte in ein internes Geometrieformat konvertiert:

  • Die Konvertierung wird direkt in der INSERT-Anweisung ausgeführt:

    INSERT INTO geom VALUES (GeomFromText('POINT(1 1)'));
    
    SET @g = 'POINT(1 1)';
    INSERT INTO geom VALUES (GeomFromText(@g));
    
  • Die Konvertierung findet vor dem INSERT statt:

    SET @g = GeomFromText('POINT(1 1)');
    INSERT INTO geom VALUES (@g);
    

Die folgenden Beispiele fügen komplexere Geometrien in eine Tabelle ein:

SET @g = 'LINESTRING(0 0,1 1,2 2)';
INSERT INTO geom VALUES (GeomFromText(@g));

SET @g = 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))';
INSERT INTO geom VALUES (GeomFromText(@g));

SET @g =
'GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
INSERT INTO geom VALUES (GeomFromText(@g));

In diesen Beispielen wurden die Geometriewerte immer mit GeomFromText() erzeugt. Sie können jedoch auch typspezifische Funktionen benutzen:

SET @g = 'POINT(1 1)';
INSERT INTO geom VALUES (PointFromText(@g));

SET @g = 'LINESTRING(0 0,1 1,2 2)';
INSERT INTO geom VALUES (LineStringFromText(@g));

SET @g = 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))';
INSERT INTO geom VALUES (PolygonFromText(@g));

SET @g =
'GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
INSERT INTO geom VALUES (GeomCollFromText(@g));

Wenn eine Clientanwendung WKB-Darstellungen von Geometriewerten benutzen will, ist sie selbst dafür verantwortlich, wohlgeformte WKB-Daten in Anfragen an den Server zu senden. Diese Anforderung lässt sich allerdings auf mehrere Arten erfüllen. Zum Beispiel:

  • Indem man einen POINT(1 1)-Wert mit der Syntax eines Hexadezimal-Literals sendet:

    mysql> INSERT INTO geom VALUES
        -> (GeomFromWKB(0x0101000000000000000000F03F000000000000F03F));
    
  • Eine ODBC-Anwendung kann eine WKB-Darstellung senden, indem sie sie an einen Platzhalter mit einem Argument vom Typ BLOB bindet:

    INSERT INTO geom VALUES (GeomFromWKB(?))
    

    Andere Programmierschnittstellen können ähnliche Platzhaltermechanismen zur Verfügung stellen.

  • In einem C-Programm können Sie einen Binärwert durch mysql_real_escape_string() mit Escape-Zeichen versehen und das Ergebnis in einen Abfragestring laden, der an den Server geschickt wird. Siehe hierzu Abschnitt 24.2.3.52, „mysql_real_escape_string().

18.4.5. Abfragen raumbezogener Daten

In einer Tabelle gespeicherte Geometriewerte können im internen Format abgefragt werden. Sie können sie jedoch auch in das WKT- oder WKB-Format konvertieren.

  • Raumbezogene Daten im internen Format abrufen:

    Der Abruf von Geometriewerten im internen Format kann nützlich sein, wenn diese Daten zwischen Tabellen übertragen werden sollen:

    CREATE TABLE geom2 (g GEOMETRY) SELECT g FROM geom;
    
  • Raumbezogene Daten im WKT-Format abrufen:

    Die Funktion AsText() konvertiert eine Geometrie aus einem internen Format in einen WKT-String.

    SELECT AsText(g) FROM geom;
    
  • Raumbezogene Daten im WKB-Format abrufen:

    Die Funktion AsBinary() konvertiert eine Geometrie aus dem internen Format in einen BLOB, der den WKB-Wert enthält.

    SELECT AsBinary(g) FROM geom;
    

18.5. Analyse raumbezogener Informationen

Nachdem Sie die raumbezogenen Spalten mit Werten gefüllt haben, können diese abgefragt und analysiert werden. MySQL kennt eine Reihe von Funktionen, um diverse Operationen auf raumbezogenen Daten durchzuführen. Diese Funktionen lassen sich nach den jeweiligen Operationen, die sie ausführen, in vier große Kategorien einteilen:

  • Funktionen, die Geometrien zwischen verschiedenen Formaten konvertieren

  • Funktionen, die Zugriff auf qualitative oder quantitative Eigenschaften einer Geometrie geben

  • Funktionen, die Beziehungen zwischen zwei Geometrien beschreiben

  • Funktionen, die aus vorhandenen Geometrien neue erzeugen

Funktionen zur Analyse raumbezogener Daten können in vielen Zusammenhängen eingesetzt werden:

  • in einem interaktiven SQL-Programm wie beispielsweise mysql oder MySQL Query Browser

  • in Anwendungsprogrammen, die in irgendeiner Sprache mit MySQL-Client-API geschrieben sind

18.5.1. Umwandlungsfunktionen für das Geometrieformat

MySQL unterstützt die folgenden Funktionen zur Konvertierung von Geometriewerten zwischen einem internen Format und dem WKT- oder WKB-Format:

  • AsBinary(g)

    Konvertiert einen Wert aus einem internen Geometrieformat in seine WKB-Darstellung und gibt das binäre Ergebnis zurück.

    SELECT AsBinary(g) FROM geom;
    
  • AsText(g)

    Konvertiert einen Wert aus einem internen Geometrieformat in seine WKT-Darstellung und gibt den Ergebnisstring zurück.

    mysql> SET @g = 'LineString(1 1,2 2,3 3)';
    mysql> SELECT AsText(GeomFromText(@g));
    +--------------------------+
    | AsText(GeomFromText(@g)) |
    +--------------------------+
    | LINESTRING(1 1,2 2,3 3)  |
    +--------------------------+
    
  • GeomFromText(wkt[,srid])

    Konvertiert einen String-Wert aus seiner WKT-Darstellung in ein internes Geometrieformat und gibt das Ergebnis zurück. Es werden auch einige typspezifische Funktionen unterstützt, wie beispielsweise PointFromText() und LineFromText(). Siehe Abschnitt 18.4.2.1, „Erzeugung von Geometriewerten mit WKT-Funktionen“.

  • GeomFromWKB(wkb[,srid])

    Konvertiert einen Binärwert von seiner WKB-Darstellung in ein internes Geometrieformat und gibt das Ergebnis zurück. Es werden auch einige typspezifische Funktionen unterstützt, wie beispielsweise PointFromWKB() und LineFromWKB(). Siehe Abschnitt 18.4.2.2, „Erzeugung von Geometriewerten mit WKB-Funktionen“.

18.5.2. Geometry-Funktionen

Jede Funktion dieser Gruppe nimmt einen Geometriewert als Argument entgegen und gibt eine quantitative oder qualitative Eigenschaft der Geometrie zurück. Manche Funktionen schränken den Typ ihres Arguments ein. Solche Funktionen geben NULL zurück, wenn das Argument den verkehrten Geometrietyp hat. So liefert beispielsweise Area() den Wert NULL, wenn der Objekttyp weder Polygon noch MultiPolygon ist.

18.5.2.1. Allgemeine Geometriefunktionen

Die im vorliegenden Abschnitt aufgeführten Funktionen schränken den Typ ihres Arguments nicht ein. Sie nehmen Geometriewerte jedes Typs entgegen.

  • Dimension(g)

    Gibt die inhärente Dimension des Geometriewerts g zurück. Das Ergebnis kann –1, 0, 1 oder 2 sein. Was diese Werte bedeuten, lesen Sie in Abschnitt 18.2.2, „Die Klasse Geometry.

    mysql> SELECT Dimension(GeomFromText('LineString(1 1,2 2)'));
    +------------------------------------------------+
    | Dimension(GeomFromText('LineString(1 1,2 2)')) |
    +------------------------------------------------+
    |                                              1 |
    +------------------------------------------------+
    
  • Envelope(g)

    Gibt das Minimum Bounding Rectangle (MBR) des Geometriewerts g zurück. Das Ergebnis wird als Polygon-Wert geliefert.

    Das Polygon ist durch die Eckpunkte seines Begrenzungskastens definiert:

    POLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
    
    mysql> SELECT AsText(Envelope(GeomFromText('LineString(1 1,2 2)')));
    +-------------------------------------------------------+
    | AsText(Envelope(GeomFromText('LineString(1 1,2 2)'))) |
    +-------------------------------------------------------+
    | POLYGON((1 1,2 1,2 2,1 2,1 1))                        |
    +-------------------------------------------------------+
    
  • GeometryType(g)

    Liefert den Namen des Geometrietyps, zu welchem das betreffende Geometrieobjekt g gehört, als String zurück. Es ist der Name einer instanziierbaren Unterklasse von Geometry.

    mysql> SELECT GeometryType(GeomFromText('POINT(1 1)'));
    +------------------------------------------+
    | GeometryType(GeomFromText('POINT(1 1)')) |
    +------------------------------------------+
    | POINT                                    |
    +------------------------------------------+
    
  • SRID(g)

    Liefert die Integer-Kennung des Georeferenzsystems des Geometriewerts g.

    In MySQL ist der SRID-Wert ein einfacher Integer, der mit dem Geometriewert verbunden ist. Alle Berechnungen werden auf der Grundlage der euklidischen (planaren) Geometrie ausgeführt.

    mysql> SELECT SRID(GeomFromText('LineString(1 1,2 2)',101));
    +-----------------------------------------------+
    | SRID(GeomFromText('LineString(1 1,2 2)',101)) |
    +-----------------------------------------------+
    |                                           101 |
    +-----------------------------------------------+
    

Die OpenGIS-Spezifikation definiert außerdem folgende Funktionen, die von MySQL nicht implementiert werden:

  • Boundary(g)

    Gibt eine Geometrie zurück, die der Abschluss der kombinatorischen Grenze des Geometriewerts g ist.

  • IsEmpty(g)

    Liefert 1, wenn der Geometriewert g die leere Geometrie ist, 0, wenn er nichtleer ist, und –1, wenn das Argument NULL ist. Eine leere Geometrie ist die leere Punktmenge.

  • IsSimple(g)

    Zurzeit ist diese noch ein Platzhalter und sollte nicht benutzt werden. Wenn sie implementiert ist, wird sie das im nächsten Absatz beschriebene Verhalten haben.

    Liefert 1, wenn der Geometriewert g keine anormalen geometrischen Punkte hat, indem er sich beispielsweise selbst schneidet oder tangiert. IsSimple() gibt 0 zurück, wenn das Argument nicht einfach ist, und –1, wenn es NULL ist.

    In den Beschreibungen der instanziierbaren geometrischen Klassen weiter oben in diesem Kapitel werden auch die konkreten Bedingungen genannt, unter denen eine Instanz der betreffenden Klasse als nichteinfach gilt. (Siehe Abschnitt 18.2.1, „Hierarchie der Geometrieklassen“.)

18.5.2.2. Point-Funktionen

Ein Point besteht aus einer x- und einer y-Koordinate, die Sie mit den folgenden Funktionen beschaffen können:

  • X(p)

    Gibt die x-Koordinate des Punkts p als Zahl mit doppelter Genauigkeit zurück.

    mysql> SET @pt = 'Point(56.7 53.34)';
    mysql> SELECT X(GeomFromText(@pt));
    +----------------------+
    | X(GeomFromText(@pt)) |
    +----------------------+
    |                 56.7 |
    +----------------------+
    
  • Y(p)

    Gibt die y-Koordinate des Punkts p als Zahl mit doppelter Genauigkeit zurück.

    mysql> SET @pt = 'Point(56.7 53.34)';
    mysql> SELECT Y(GeomFromText(@pt));
    +----------------------+
    | Y(GeomFromText(@pt)) |
    +----------------------+
    |                53.34 |
    +----------------------+
    

18.5.2.3. LineString-Funktionen

Ein LineString besteht aus Point-Werten. Sie können bestimmte Punkte eines LineString extrahieren, die Anzahl seiner Punkte abfragen oder seine Länge ermitteln.

  • EndPoint(ls)

    Gibt den Point zurück, der der Endpunkt des LineString-Werts ls ist.

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql> SELECT AsText(EndPoint(GeomFromText(@ls)));
    +-------------------------------------+
    | AsText(EndPoint(GeomFromText(@ls))) |
    +-------------------------------------+
    | POINT(3 3)                          |
    +-------------------------------------+
    
  • GLength(ls)

    Liefert die Länge des LineString-Werts ls in seinem zugehörigen Georeferenzsystem als Zahl mit doppelter Genauigkeit.

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql> SELECT GLength(GeomFromText(@ls));
    +----------------------------+
    | GLength(GeomFromText(@ls)) |
    +----------------------------+
    |            2.8284271247462 |
    +----------------------------+
    

    Der Name der Funktion GLength() ist ein nichtstandardmäßiger Name. Sie entspricht der OpenGIS-Funktion Length().

  • NumPoints(ls)

    Liefert die Anzahl der Point-Objekte im LineString-Wert ls.

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql> SELECT NumPoints(GeomFromText(@ls));
    +------------------------------+
    | NumPoints(GeomFromText(@ls)) |
    +------------------------------+
    |                            3 |
    +------------------------------+
    
  • PointN(ls,N)

    Liefert den N-ten Point im Linestring-Wert ls. Die Punkte werden beginnend mit 1 nummeriert.

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql> SELECT AsText(PointN(GeomFromText(@ls),2));
    +-------------------------------------+
    | AsText(PointN(GeomFromText(@ls),2)) |
    +-------------------------------------+
    | POINT(2 2)                          |
    +-------------------------------------+
    
  • StartPoint(ls)

    Gibt den Point zurück, der der Anfangspunkt des LineString-Werts ls ist.

    mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
    mysql> SELECT AsText(StartPoint(GeomFromText(@ls)));
    +---------------------------------------+
    | AsText(StartPoint(GeomFromText(@ls))) |
    +---------------------------------------+
    | POINT(1 1)                            |
    +---------------------------------------+
    

Die OpenGIS-Spezifikation definiert darüber hinaus die folgende von MySQL nicht implementierte Funktion:

  • IsRing(ls)

    Gibt 1 zurück, wenn der LineString-Wert ls geschlossen ist (d. h., wenn sein StartPoint() und EndPoint() denselben Wert haben) und er gleichzeitig einfach ist (denselben Punkt nicht mehrmals berührt). Gibt 0 zurück, wenn ls kein Ring ist, und –1, wenn er NULL ist.

18.5.2.4. MultiLineString-Funktionen

  • GLength(mls)

    Gibt die Länge des MultiLineString-Werts mls als Zahl mit doppelter Genauigkeit zurück. Die Länge von mls ist gleich der Summe der Längen seiner Elemente.

    mysql> SET @mls = 'MultiLineString((1 1,2 2,3 3),(4 4,5 5))';
    mysql> SELECT GLength(GeomFromText(@mls));
    +-----------------------------+
    | GLength(GeomFromText(@mls)) |
    +-----------------------------+
    |             4.2426406871193 |
    +-----------------------------+
    

    GLength() ist ein nichtstandardmäßiger Name. Die Funktion entspricht der OpenGIS-Funktion Length().

  • IsClosed(mls)

    Gibt 1 zurück, wenn der MultiLineString-Wert mls geschlossen ist (d. h., wenn StartPoint() und EndPoint() für jeden LineString in mls gleich sind). Gibt 0 zurück, wenn mls nicht geschlossen ist, und –1, wenn er NULL ist.

    mysql> SET @mls = 'MultiLineString((1 1,2 2,3 3),(4 4,5 5))';
    mysql> SELECT IsClosed(GeomFromText(@mls));
    +------------------------------+
    | IsClosed(GeomFromText(@mls)) |
    +------------------------------+
    |                            0 |
    +------------------------------+
    

18.5.2.5. Polygon-Funktionen

  • Area(poly)

    Gibt die Fläche des Polygon-Werts poly, gemessen in seinem Georeferenzsystem, als Zahl mit doppelter Genauigkeit zurück.

    mysql> SET @poly = 'Polygon((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))';
    mysql> SELECT Area(GeomFromText(@poly));
    +---------------------------+
    | Area(GeomFromText(@poly)) |
    +---------------------------+
    |                         4 |
    +---------------------------+
    
  • ExteriorRing(poly)

    Gibt den äußeren Ring des Polygon-Werts poly als LineString zurück.

    mysql> SET @poly =
        -> 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';
    mysql> SELECT AsText(ExteriorRing(GeomFromText(@poly)));
    +-------------------------------------------+
    | AsText(ExteriorRing(GeomFromText(@poly))) |
    +-------------------------------------------+
    | LINESTRING(0 0,0 3,3 3,3 0,0 0)           |
    +-------------------------------------------+
    
  • InteriorRingN(poly,N)

    Gibt den N-ten inneren Ring des Polygon-Werts poly als LineString zurück. Die Ringe werden beginnend mit 1 nummeriert.

    mysql> SET @poly =
        -> 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';
    mysql> SELECT AsText(InteriorRingN(GeomFromText(@poly),1));
    +----------------------------------------------+
    | AsText(InteriorRingN(GeomFromText(@poly),1)) |
    +----------------------------------------------+
    | LINESTRING(1 1,1 2,2 2,2 1,1 1)              |
    +----------------------------------------------+
    
  • NumInteriorRings(poly)

    Gibt die Anzahl der inneren Ringe des Polygon-Werts poly zurück.

    mysql> SET @poly =
        -> 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';
    mysql> SELECT NumInteriorRings(GeomFromText(@poly));
    +---------------------------------------+
    | NumInteriorRings(GeomFromText(@poly)) |
    +---------------------------------------+
    |                                     1 |
    +---------------------------------------+
    

18.5.2.6. MultiPolygon-Funktionen

  • Area(mpoly)

    Gibt die Fläche des MultiPolygon-Werts mpoly, gemessen in seinem Georeferenzsystem, als Zahl mit doppelter Genauigkeit zurück.

    mysql> SET @mpoly =
        -> 'MultiPolygon(((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1)))';
    mysql> SELECT Area(GeomFromText(@mpoly));
    +----------------------------+
    | Area(GeomFromText(@mpoly)) |
    +----------------------------+
    |                          8 |
    +----------------------------+
    

Die OpenGIS-Spezifikation definiert auch die folgenden von MySQL nicht implementierten Funktionen:

  • Centroid(mpoly)

    Gibt den mathematischen Schwerpunkt des MultiPolygon-Werts mpoly als Point zurück. Es ist nicht garantiert, dass das Ergebnis auf dem MultiPolygon liegt.

  • PointOnSurface(mpoly)

    Gibt einen Point-Wert zurück, der unter Garantie auf dem MultiPolygon-Wert mpoly liegt.

18.5.2.7. GeometryCollection-Funktionen

  • GeometryN(gc,N)

    Gibt die N-te Geometrie im GeometryCollection-Wert des gc-Werts zurück. Die Geometrien werden beginnend mit 1 nummeriert.

    mysql> SET @gc = 'GeometryCollection(Point(1 1),LineString(2 2, 3 3))';
    mysql> SELECT AsText(GeometryN(GeomFromText(@gc),1));
    +----------------------------------------+
    | AsText(GeometryN(GeomFromText(@gc),1)) |
    +----------------------------------------+
    | POINT(1 1)                             |
    +----------------------------------------+
    
  • NumGeometries(gc)

    Gibt die Anzahl der Geometrien im GeometryCollection-Wert gc zurück.

    mysql> SET @gc = 'GeometryCollection(Point(1 1),LineString(2 2, 3 3))';
    mysql> SELECT NumGeometries(GeomFromText(@gc));
    +----------------------------------+
    | NumGeometries(GeomFromText(@gc)) |
    +----------------------------------+
    |                                2 |
    +----------------------------------+
    

18.5.3. Funktionen, die neue geometrische Objekte aus bestehenden erzeugen

18.5.3.1. Geometriefunktionen, die neue Geometrien erzeugen

In Abschnitt 18.5.2, „Geometry-Funktionen“, werden mehrere Funktionen beschrieben, die aus vorhandenen Geometrien neue erstellen. Dort können Sie die Beschreibungen folgender Funktionen nachlesen:

  • Envelope(g)

  • StartPoint(ls)

  • EndPoint(ls)

  • PointN(ls,N)

  • ExteriorRing(poly)

  • InteriorRingN(poly,N)

  • GeometryN(gc,N)

18.5.3.2. Raumbezogene Operatoren

OpenGIS stellt auch noch einige weitere Funktionen vor, die Geometrien erzeugen können. Diese sind so entworfen, dass sie raumbezogene Operatoren implementieren.

Diese Funktionen sind in MySQL nicht implementiert, könnten aber in zukünftigen Releases einbezogen werden.

  • Buffer(g,d)

    Gibt eine Geometrie zurück, die alle Punkte darstellt, deren Abstand vom Geometriewert g kleiner oder gleich dem Abstand von d ist.

  • ConvexHull(g)

    Gibt eine Geometrie zurück, die die konvexe Hülle des Geometriewerts g darstellt.

  • Difference(g1,g2)

    Gibt eine Geometrie zurück, die die Differenz zwischen den Punktmengen der Geometriewerte g1 und g2 angibt.

  • Intersection(g1,g2)

    Gibt eine Geometrie zurück, die die Schnittmenge der Punktmengen der Geometriewerte g1 und g2 darstellt.

  • SymDifference(g1,g2)

    Gibt eine Geometrie zurück, die die symmetrische Punktmengendifferenz zwischen den Geometriewerten g1 und g2 darstellt.

  • Union(g1,g2)

    Gibt eine Geometrie zurück, die die Vereinigungsmenge der Punktmengen der Geometriewerte g1 und g2 darstellt.

18.5.4. Funktionen zum Testen raumbezogener Beziehungen zwischen geometrischen Objekten

Die Funktionen in diesen Abschnitten nehmen zwei Geometrien als Eingabeparameter und liefern eine qualitative oder quantitative Beziehung zwischen diesen zurück.

18.5.5. Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)

MySQL kennt mehrere Funktionen, um Beziehungen zwischen den kleinsten begrenzenden Rechtecken (Minimal Bounding Rectangles, MBRs) zweier Geometrien g1 und g2 zu testen. Der Rückgabewert 1 bedeutet wahr (true) und 0 bedeutet falsch (false).

  • MBRContains(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob das Minimum Bounding Rectangle von g1 das Minimum Bounding Rectangle von g2 enthält oder nicht.

    mysql> SET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');
    mysql> SET @g2 = GeomFromText('Point(1 1)');
    mysql> SELECT MBRContains(@g1,@g2), MBRContains(@g2,@g1);
    ----------------------+----------------------+
    | MBRContains(@g1,@g2) | MBRContains(@g2,@g1) |
    +----------------------+----------------------+
    |                    1 |                    0 |
    +----------------------+----------------------+
    
  • MBRDisjoint(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob die Minimum Bounding Rectangles der beiden Geometrien g1 und g2 disjunkt sind (sich nicht überschneiden) oder nicht.

  • MBREqual(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob die Minimum Bounding Rectangles der beiden Geometrien g1 und g2 gleich sind oder nicht.

  • MBRIntersects(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob die Minimum Bounding Rectangles der beiden Geometrien g1 und g2 sich schneiden oder nicht.

  • MBROverlaps(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob die Minimum Bounding Rectangles der beiden Geometrien g1 und g2 sich überlappen oder nicht.

  • MBRTouches(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob die Minimum Bounding Rectangles der beiden Geometrien g1 und g2 sich berühren oder nicht.

  • MBRWithin(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob das Minimum Bounding Rectangle von g1 innerhalb des Minimum Bounding Rectangles von g2 liegt.

    mysql> SET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');
    mysql> SET @g2 = GeomFromText('Polygon((0 0,0 5,5 5,5 0,0 0))');
    mysql> SELECT MBRWithin(@g1,@g2), MBRWithin(@g2,@g1);
    +--------------------+--------------------+
    | MBRWithin(@g1,@g2) | MBRWithin(@g2,@g1) |
    +--------------------+--------------------+
    |                  1 |                  0 |
    +--------------------+--------------------+
    

18.5.6. Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen

Die OpenGIS-Spezifikation definiert die folgenden Funktionen, um die Beziehungen zwischen zwei Geometriewerten g1 und g2 zu testen.

MySQL implementiert diese Funktionen zurzeit noch nicht entsprechend der Spezifikation. Die, die implementiert werden, geben dasselbe Ergebnis wie die entsprechenden MBR-basierten Funktionen zurück. Dazu gehören neben Distance() und Related() auch die anderen Funktionen der folgenden Liste.

Diese Funktionen könnten in zukünftigen Releases auch mit voller anstatt nur mit MBR-basierter Unterstützung für raumbezogene Analyse implementiert werden.

Der Rückgabewert 1 bedeutet wahr (true) und 0 bedeutet falsch (false).

  • Contains(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 g2 vollständig enthält oder nicht.

  • Crosses(g1,g2)

    Gibt 1 zurück, wenn g1 g2 räumlich kreuzt. Gibt NULL zurück, wenn g1 ein Polygon oder MultiPolygon ist oder wenn g2 ein Point oder ein MultiPoint ist. Gibt ansonsten 0 zurück.

    Mit räumlich kreuzen ist eine räumliche Beziehung zwischen zwei Geometrien gemeint, die folgende Eigenschaften besitzt:

    • Die beiden Geometrien schneiden sich.

    • Ihre Überschneidung hat eine Geometrie zum Ergebnis, deren Dimension um eins kleiner ist als die maximale Dimension der beiden Geometrien.

    • Ihre Schnittmenge ist mit keiner der beiden Geometrien identisch.

  • Disjoint(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 räumlich disjunkt von g2 ist (sich nicht überschneidet) oder nicht.

  • Distance(g1,g2)

    Liefert den kürzesten Abstand zwischen zwei Punkten der beiden Geometrien als Zahl mit doppelter Genauigkeit.

  • Equals(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 und g2 räumlich gleich sind oder nicht.

  • Intersects(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 sich räumlich mit g2 überschneidet oder nicht.

  • Overlaps(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 sich räumlich mit g2 überlappt oder nicht. Von räumlich überlappen spricht man, wenn sich zwei Geometrien schneiden und ihre Schnittmenge eine Geometrie ergibt, die nicht gleich einer der beiden gegebenen Geometrien ist, aber dieselbe Dimension hat.

  • Related(g1,g2,pattern_matrix)

    Gibt 1 oder 0 zurück, je nachdem, ob die räumliche Beziehung, die durch pattern_matrix vorgegeben ist, zwischen g1 und g2 existiert oder nicht. Gibt –1 zurück, wenn die Argumente NULL sind. Die Mustermatrix (pattern_matrix) ist ein String. Ihre Spezifikation wird hier notiert werden, wenn die Funktion implementiert wurde.

  • Touches(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 g2 räumlich berührt oder nicht. Von einer räumlichen Berührung zweier Geometrien spricht man, wenn ihre Innenbereiche sich nicht schneiden, aber die Grenze der einen entweder die Grenze oder den Innenbereich der anderen schneidet.

  • Within(g1,g2)

    Gibt 1 oder 0 zurück, je nachdem, ob g1 räumlich innerhalb von g2 liegt oder nicht.

18.6. Optimierung der raumbezogenen Analyse

Suchoperationen in nichtraumbezogenen Datenbanken lassen sich mit Indizes optimieren. Dies gilt ebenso für raumbezogene Datenbanken. Es wurden bereits viele mehrdimensionale Indexmethoden entworfen, um auch die Suche nach raumbezogenen Daten zu optimieren. Die typischsten Methoden sind:

  • Punktabfragen, die alle Objekte suchen, welche einen gegebenen Punkt enthalten.

  • Bereichsabfragen, die alle Objekte suchen, welche einen gegebenen Bereich überlappen.

MySQL verwendet R-Trees mit quadratischem Split zum Indizieren raumbezogener Spalten. Ein raumbezogener Index wird anhand des MBRs einer Geometrie erstellt. Für die meisten Geometrien ist das MBR das kleinste die Geometrie umschließende Rechteck. Für einen horizontalen oder vertikalen Linestring ist das MBR ein auf eine Linie zusammengeschnurrtes Rechteck. Für einen Punkt ist das MBR ein Rechteck, das auf den Punkt zusammengeschrumpft ist.

Es ist auch möglich, normale Indizes auf raumbezogenen Spalten anzulegen. Hierzu müssen Sie einem (nichtraumbezogenen) Index auf einer raumbezogenen Spalte (ausgenommen POINT-Spalten) ein Präfix geben.

18.6.1. Erzeugung raumbezogener Indizes

MySQL kann raumbezogene Indizes mit einer ähnlichen Syntax anlegen, wie sie auch für normale Indizes verwendet wird, allerdings erweitert um das Schlüsselwort SPATIAL. Zurzeit müssen raumbezogene Spalten, die indiziert werden, als NOT NULL deklariert werden. Die folgenden Beispiele zeigen, wie man raumbezogene Indizes anlegen kann:

  • Mit CREATE TABLE:

    CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g));
    
  • Mit ALTER TABLE:

    ALTER TABLE geom ADD SPATIAL INDEX(g);
    
  • Mit CREATE INDEX:

    CREATE SPATIAL INDEX sp_index ON geom (g);
    

Auf MyISAM-Tabellen legt SPATIAL INDEX einen R-Tree-Index an, aber auf Tabellen mit anderen Speicher-Engines, die raumbezogene Indizierung unterstützen, erzeugt SPATIAL INDEX einen B-Tree-Index. Ein B-Tree-Index auf raumbezogenen Werten ist nützlich für das Nachschlagen konkreter Werte, aber nicht für Bereichsscans.

Gelöscht werden raumbezogene Indizes mit ALTER TABLE oder DROP INDEX:

  • Mit ALTER TABLE:

    ALTER TABLE geom DROP INDEX g;
    
  • Mit DROP INDEX:

    DROP INDEX sp_index ON geom;
    

Beispiel: Angenommen, eine Tabelle namens geom enthält mehr als 32.000 Geometrien, die alle in der Spalte g vom Typ GEOMETRY gespeichert sind. Die Tabelle hat außerdem eine AUTO_INCREMENT-Spalte namens fid zum Speichern der Objekt-IDs.

mysql> DESCRIBE geom;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| fid   | int(11)  |      | PRI | NULL    | auto_increment |
| g     | geometry |      |     |         |                |
+-------+----------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> SELECT COUNT(*) FROM geom;
+----------+
| count(*) |
+----------+
|    32376 |
+----------+
1 row in set (0.00 sec)

Mti folgender Anweisung definieren Sie einen raumbezogenen Index auf der Spalte g:

mysql> ALTER TABLE geom ADD SPATIAL INDEX(g);
Query OK, 32376 rows affected (4.05 sec)
Records: 32376  Duplicates: 0  Warnings: 0

18.6.2. Verwendung eines raumbezogenen Indizes

Der Optimierer untersucht, ob die verfügbaren raumbezogenen Indizes für Suchoperationen im Rahmen von Anfragen zu gebrauchen sind, die eine Funktion wie MBRContains() oder MBRWithin() in der WHERE-Klausel haben. Die folgende Anfrage findet alle Objekte, die sich im gegebenen Rechteck befinden:

mysql> SET @poly =
    -> 'Polygon((30000 15000,31000 15000,31000 16000,30000 16000,30000 15000))';
mysql> SELECT fid,AsText(g) FROM geom WHERE
    -> MBRContains(GeomFromText(@poly),g);
+-----+---------------------------------------------------------------+
| fid | AsText(g)                                                     |
+-----+---------------------------------------------------------------+
|  21 | LINESTRING(30350.4 15828.8,30350.6 15845,30333.8 15845,30 ... |
|  22 | LINESTRING(30350.6 15871.4,30350.6 15887.8,30334 15887.8, ... |
|  23 | LINESTRING(30350.6 15914.2,30350.6 15930.4,30334 15930.4, ... |
|  24 | LINESTRING(30290.2 15823,30290.2 15839.4,30273.4 15839.4, ... |
|  25 | LINESTRING(30291.4 15866.2,30291.6 15882.4,30274.8 15882. ... |
|  26 | LINESTRING(30291.6 15918.2,30291.6 15934.4,30275 15934.4, ... |
| 249 | LINESTRING(30337.8 15938.6,30337.8 15946.8,30320.4 15946. ... |
|   1 | LINESTRING(30250.4 15129.2,30248.8 15138.4,30238.2 15136. ... |
|   2 | LINESTRING(30220.2 15122.8,30217.2 15137.8,30207.6 15136, ... |
|   3 | LINESTRING(30179 15114.4,30176.6 15129.4,30167 15128,3016 ... |
|   4 | LINESTRING(30155.2 15121.4,30140.4 15118.6,30142 15109,30 ... |
|   5 | LINESTRING(30192.4 15085,30177.6 15082.2,30179.2 15072.4, ... |
|   6 | LINESTRING(30244 15087,30229 15086.2,30229.4 15076.4,3024 ... |
|   7 | LINESTRING(30200.6 15059.4,30185.6 15058.6,30186 15048.8, ... |
|  10 | LINESTRING(30179.6 15017.8,30181 15002.8,30190.8 15003.6, ... |
|  11 | LINESTRING(30154.2 15000.4,30168.6 15004.8,30166 15014.2, ... |
|  13 | LINESTRING(30105 15065.8,30108.4 15050.8,30118 15053,3011 ... |
| 154 | LINESTRING(30276.2 15143.8,30261.4 15141,30263 15131.4,30 ... |
| 155 | LINESTRING(30269.8 15084,30269.4 15093.4,30258.6 15093,30 ... |
| 157 | LINESTRING(30128.2 15011,30113.2 15010.2,30113.6 15000.4, ... |
+-----+---------------------------------------------------------------+
20 rows in set (0.00 sec)

Mit EXPLAIN können Sie prüfen, wie diese Anfrage ausgeführt wird (die Spalte id wurde entfernt, damit die Ausgabe besser auf die Seite passt):

mysql> SET @poly =
    -> 'Polygon((30000 15000,31000 15000,31000 16000,30000 16000,30000 15000))';
mysql> EXPLAIN SELECT fid,AsText(g) FROM geom WHERE
    -> MBRContains(GeomFromText(@poly),g)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: geom
         type: range
possible_keys: g
          key: g
      key_len: 32
          ref: NULL
         rows: 50
        Extra: Using where
1 row in set (0.00 sec)

So prüfen Sie, was ohne raumbezogenen Index passieren würde:

mysql> SET @poly =
    -> 'Polygon((30000 15000,31000 15000,31000 16000,30000 16000,30000 15000))';
mysql> EXPLAIN SELECT fid,AsText(g) FROM g IGNORE INDEX (g) WHERE
    -> MBRContains(GeomFromText(@poly),g)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: geom
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 32376
        Extra: Using where
1 row in set (0.00 sec)

Wenn Sie die SELECT-Anweisung ohne den raumbezogenen Index ausführen, erhalten Sie zwar dasselbe Ergebnis, aber die Ausführungszeit verlängert sich von 0,00 auf 0,46 Sekunden:

mysql> SET @poly =
    -> 'Polygon((30000 15000,31000 15000,31000 16000,30000 16000,30000 15000))';
mysql> SELECT fid,AsText(g) FROM geom IGNORE INDEX (g) WHERE
    -> MBRContains(GeomFromText(@poly),g);
+-----+---------------------------------------------------------------+
| fid | AsText(g)                                                     |
+-----+---------------------------------------------------------------+
|   1 | LINESTRING(30250.4 15129.2,30248.8 15138.4,30238.2 15136. ... |
|   2 | LINESTRING(30220.2 15122.8,30217.2 15137.8,30207.6 15136, ... |
|   3 | LINESTRING(30179 15114.4,30176.6 15129.4,30167 15128,3016 ... |
|   4 | LINESTRING(30155.2 15121.4,30140.4 15118.6,30142 15109,30 ... |
|   5 | LINESTRING(30192.4 15085,30177.6 15082.2,30179.2 15072.4, ... |
|   6 | LINESTRING(30244 15087,30229 15086.2,30229.4 15076.4,3024 ... |
|   7 | LINESTRING(30200.6 15059.4,30185.6 15058.6,30186 15048.8, ... |
|  10 | LINESTRING(30179.6 15017.8,30181 15002.8,30190.8 15003.6, ... |
|  11 | LINESTRING(30154.2 15000.4,30168.6 15004.8,30166 15014.2, ... |
|  13 | LINESTRING(30105 15065.8,30108.4 15050.8,30118 15053,3011 ... |
|  21 | LINESTRING(30350.4 15828.8,30350.6 15845,30333.8 15845,30 ... |
|  22 | LINESTRING(30350.6 15871.4,30350.6 15887.8,30334 15887.8, ... |
|  23 | LINESTRING(30350.6 15914.2,30350.6 15930.4,30334 15930.4, ... |
|  24 | LINESTRING(30290.2 15823,30290.2 15839.4,30273.4 15839.4, ... |
|  25 | LINESTRING(30291.4 15866.2,30291.6 15882.4,30274.8 15882. ... |
|  26 | LINESTRING(30291.6 15918.2,30291.6 15934.4,30275 15934.4, ... |
| 154 | LINESTRING(30276.2 15143.8,30261.4 15141,30263 15131.4,30 ... |
| 155 | LINESTRING(30269.8 15084,30269.4 15093.4,30258.6 15093,30 ... |
| 157 | LINESTRING(30128.2 15011,30113.2 15010.2,30113.6 15000.4, ... |
| 249 | LINESTRING(30337.8 15938.6,30337.8 15946.8,30320.4 15946. ... |
+-----+---------------------------------------------------------------+
20 rows in set (0.46 sec)

In künftigen Releases könnten raumbezogene Indizes vielleicht auch zur Optimierung anderer Funktionen genutzt werden. Siehe Abschnitt 18.5.4, „Funktionen zum Testen raumbezogener Beziehungen zwischen geometrischen Objekten“.

18.7. MySQL-Konformität und Kompatibilität

Folgende GIS-Features werden von MySQL noch nicht implementiert:

  • Zusätzliche Metadaten-Views

    Die OpenGIS-Spezifikationen empfehlen mehrere zusätzliche Views für Metadaten, beispielsweise eine System-View namens GEOMETRY_COLUMNS mit einer Beschreibung der Geometriespalten, wobei für jede Geometriespalte der Datenbank eine Zeile angezeigt wird.

  • Die OpenGIS-Funktion Length() für LineString und MultiLineString muss in MySQL zurzeit noch unter dem Namen GLength() aufgerufen werden.

    Das Problem besteht darin, dass es eine SQL-Funktion namens Length() gibt, die die Länge von String-Werten berechnet, und dass es manchmal nicht zu unterscheiden ist, ob diese Funktion nun im Zusammenhang mit Text oder mit raumbezogenen Daten aufgerufen wird. Wir werden dies entweder auf irgendeine Weise lösen oder einen anderen Namen für die Funktion finden.

Kapitel 19. Gespeicherte Prozeduren und Funktionen

MySQL 5.1 kennt auch gespeicherte Routinen (Prozeduren und Funktionen). Eine gespeicherte Prozedur ist eine Menge von SQL-Anweisungen, die auf dem Server gespeichert werden kann. So müssen Clients nicht immer wieder die jeweiligen Einzelanweisungen ausführen, sondern können stattdessen die gespeicherte Prozedur aufrufen.

In folgenden Situationen sind gespeicherte Routinen besonders nützlich:

  • Wenn mehrere Clientanwendungen in verschiedenen Sprachen geschrieben sind oder auf verschiedenen Plattformen laufen, aber dieselben Datenbankoperationen ausführen müssen.

  • Wenn Sicherheit sehr wichtig ist. Banken verwenden zum Beispiel für alle häufigen Operationen gespeicherte Prozeduren und Funktionen. Das gewährleistet eine konsistente und sichere Umgebung sowie eine korrekte Protokollierung jeder einzelnen Operation. In einer solchen Umgebung haben Anwendungen und Benutzer keinen Direktzugriff auf die Datenbanktabellen, sondern können nur bestimmte gespeicherte Routinen ausführen.

Gespeicherte Routinen bieten eine bessere Leistung, da weniger Informationen zwischen Server und Client übermittelt werden müssen. Der Nachteil ist der, dass die Belastung des Datenbankservers steigt, weil mehr Arbeit auf der Serverseite und weniger Arbeit auf der Seite des Clients (der Anwendungen) erledigt werden muss. Dies müssen Sie berücksichtigen, wenn viele Clientcomputer (wie beispielsweise Webserver) von nur einem oder sehr wenigen Datenbankservern bedient werden.

Mit gespeicherten Routinen sind Funktionsbibliotheken im Datenbankserver möglich. Dieses Feature haben auch moderne Anwendungssprachen, die einen solchen Entwurf intern umsetzen (zum Beispiel durch Klassen). Auch jenseits von Datenbankanwendungen bringen diese Features der Anwendungssprachen dem Programmierer Vorteile.

MySQL verwendet die Syntax für gespeicherte Routinen gemäß dem SQL:2003-Standard, den auch DB2 von IBM nutzt.

Die Implementierung gespeicherter Routinen in MySQL ist noch nicht abgeschlossen. Unterstützt wird allein die in diesem Kapitel beschriebene Syntax. Beschränkungen und Erweiterungen werden an geeigneter Stelle geschildert. Eine weitergehende Behandlung der Restriktionen, die für die Verwendung gespeicherter Routinen gelten, finden Sie in Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“.

Das Binärlogging für gespeicherte Routinen wird in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“ beschrieben.

19.1. Gespeicherte Routinen und die Berechtigungstabellen

Für gespeicherte Routinen muss die Tabelle proc in der mysql-Datenbank vorhanden sein. Diese Tabelle wird schon bei der Installationsprozedur von MySQL 5.1 angelegt. Wenn Sie von einer älteren Version auf MySQL 5.1 aufrüsten, achten Sie bitte darauf, Ihre Berechtigungstabellen zu aktualisieren, damit die Tabelle proc vorhanden ist. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Nach Anweisungen, die gespeicherte Routinen erzeugen, ändern oder löschen, bearbeitet der Server die Tabelle mysql.proc. Eine manuelle Manipulation dieser Tabelle wird der Server nicht bemerken.

Im Berechtigungssystem von MySQL werden gespeicherte Routinen folgendermaßen behandelt:

  • Das CREATE ROUTINE-Recht ist erforderlich, um gespeicherte Routinen zu erzeugen.

  • Das ALTER ROUTINE-Recht wird benötigt, um gespeicherte Routinen zu ändern oder zu löschen. Dieses Recht wird automatisch dem Erzeuger einer Routine erteilt.

  • Das EXECUTE-Recht ist notwendig, um gespeicherte Routinen auszuführen, wird aber ebenfalls dem Erzeuger einer Routine automatisch erteilt. Das voreingestellte SQL SECURITY-Merkmal einer Routine ist DEFINER und erlaubt es Benutzern, mit denen die Routine verbunden ist, und die darüber hinaus Datenbankzugriff haben, die Routine auszuführen.

19.2. Syntax gespeicherter Prozeduren

Eine gespeicherte Routine ist entweder eine Prozedur oder eine Funktion. Gespeicherte Routinen werden mit den Anweisungen CREATE PROCEDURE und CREATE FUNCTION angelegt. Eine Prozedur wird mit einer CALL-Anweisung aufgerufen und kann nur über Ausgabevariablen Werte zurückgeben. Eine Funktion kann innerhalb einer Anweisung aufgerufen werden - wie jede andere Funktion auch (also durch Nennung ihres Namens) - und einen Skalarwert zurückliefern. Gespeicherte Routinen können andere gespeicherte Routinen aufrufen.

Eine gespeicherte Prozedur oder Funktion steht mit einer bestimmten Datenbank in Zusammenhang. Das hat Folgen:

  • Wenn die Routine aufgerufen wird, wird implizit ein USE db_name ausgeführt (und wieder rückgängig gemacht, wenn die Routine endet). USE-Anweisungen sind in gespeicherten Routinen nicht zulässig.

  • Den Namen einer Routine können Sie mit einem Datenbanknamen qualifizieren, etwa wenn Sie eine Routine benutzen möchten, die nicht in der aktuellen Datenbank vorliegt. Um beispielsweise eine Prozedur p oder eine Funktion f aus der Datenbank test aufzurufen, können Sie CALL test.p() oder test.f() sagen.

  • Wird eine Datenbank gelöscht, so werden alle ihre gespeicherten Routinen mitgelöscht.

MySQL unterstützt die praktischen Erweiterungen, die eine Nutzung der regulären SELECT-Anweisungen innerhalb von gespeicherten Prozeduren ermöglichen (also ohne Cursors oder lokale Variablen). Die Ergebnismenge einer solchen Anfrage wird einfach direkt an den Client gesandt. Da mehrere SELECT-Anweisungen mehrere Ergebnismengen generieren, muss der Client eine MySQL-Clientbibliothek verwenden, die mehrere Ergebnismengen unterstützt. Das bedeutet, dass er die Clientbibliothek einer MySQL-Version benötigt, die mindestens so jung ist wie 4.1. Außerdem sollte der Client die Option CLIENT_MULTI_STATEMENTS angeben, wenn er sich verbindet. C-Programme können dies mit der C-API-Funktion mysql_real_connect() tun (siehe Abschnitt 24.2.3.51, „mysql_real_connect()).

Die folgenden Abschnitte beschreiben die Syntax, mit der gespeicherte Prozeduren und Funktionen erzeugt, geändert und aufgerufen werden.

19.2.1. CREATE PROCEDURE und CREATE FUNCTION

CREATE PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body

CREATE FUNCTION sp_name ([func_parameter[,...]])
    RETURNS type
    [characteristic ...] routine_body
    
proc_parameter:
    [ IN | OUT | INOUT ] param_name type
    
func_parameter:
    param_name type

type:
    Any valid MySQL data type

characteristic:
    LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'

routine_body:
    Valid SQL procedure statement

Diese Anweisungen erzeugen gespeicherte Routinen. Um sie nutzen zu können, ist das CREATE ROUTINE-Recht erforderlich. Wenn Binärlogging eingeschaltet ist, kann für die CREATE FUNCTION-Anweisung auch das SUPER-Recht erforderlich sein, wie in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“, beschrieben. MySQL erteilt dem Erzeuger einer Routine automatisch das ALTER ROUTINE- und das EXECUTE-Recht.

Nach Voreinstellung wird die Routine mit der Standarddatenbank verbunden. Um sie explizit mit einer bestimmten Datenbank zu verbinden, geben Sie bei der Erzeugung der Routine den Namen der Datenbank in der Form db_name.sp_name an.

Wenn der Name der Routine gleichlautend mit dem Namen einer eingebauten SQL-Funktion ist, müssen Sie zwischen dem Namen und der nachfolgenden Klammer ein Leerzeichen setzen, wenn Sie die Routine definieren, sonst tritt ein Syntaxfehler ein. Das gilt auch, wenn Sie die Routine zu einem späteren Zeitpunkt aufrufen. Aus diesem Grund raten wir Ihnen, keine Namen vorhandener SQL-Funktionen für Ihre eigenen gespeicherten Routinen zu verwenden.

Der SQL-Modus IGNORE_SPACE gilt für eingebaute Funktionen und nicht für gespeicherte Routinen. Es ist immer zulässig, Leerzeichen hinter den Namen einer Routine zu setzen, egal ob IGNORE_SPACE eingeschaltet ist oder nicht.

Die Parameterliste in runden Klammern muss immer vorhanden sein. Wenn keine Parameter übergeben werden, muss eine leere Parameterliste () verwendet werden. Jeder Parameter ist nach Voreinstellung ein IN-Parameter. Um einen Parameter anderslautend zu definieren, setzen Sie das Schlüsselwort OUT oder INOUT vor den Parameternamen.

Hinweis: Als IN, OUT oder INOUT können nur PROCEDURE-Parameter definiert werden. (FUNCTION-Parameter gelten immer als IN-Parameter.)

Jeder Parameter kann mit jedem zulässigen Datentyp deklariert werden, nur das Attribut COLLATE darf nicht verwendet werden.

Die RETURNS-Klausel kann nur für eine FUNCTION angegeben werden; hier ist sie sogar obligatorisch. Sie gibt den Rückgabetyp der Funktion an. Der Funktionsrumpf muss eine RETURN value-Anweisung enthalten.

Der routine_body besteht aus einer gültigen SQL-Prozeduranweisung. Diese kann eine einfache Anweisung wie etwa ein SELECT oder INSERT sein, sie kann aber auch eine zusammengesetzte Anweisung mit BEGIN und END sein. Die Syntax zusammengesetzter Anweisungen wird in Abschnitt 19.2.5, „BEGIN ... END-Syntax für komplexe Anweisungen“, erläutert. Zusammengesetzte Anweisungen können Deklarationen, Schleifen und andere Anweisungen mit Kontrollstrukturen enthalten. Die Syntax dieser Anweisungen wird weiter unten in diesem Kapitel erklärt, beispielsweise unter Abschnitt 19.2.6, „Syntax der DECLARE-Anweisung“, und Abschnitt 19.2.10, „Konstrukte für die Ablaufsteuerung“.

Die CREATE FUNCTION-Anweisung diente in früheren MySQL-Versionen der Unterstützung von UDFs (User-defined Functions, benutzerdefinierte Funktionen). Siehe auch Abschnitt 26.3, „Hinzufügen neuer Funktionen zu MySQL“. UDFs werden weiterhin unterstützt, obwohl inzwischen auch die gespeicherten Funktionen existieren. Eine UDF kann man als externe gespeicherte Funktion betrachten. Bitte beachten Sie jedoch, dass gespeicherte Funktionen denselben Namensraum wie UDFs benutzen.

Eine Prozedur oder Funktion gilt als „deterministisch“, wenn sie für gleiche Eingabeparameter immer gleiche Resultate erzeugt; ansonsten ist sie „nichtdeterministisch“. Wenn in der Definition der Routine weder DETERMINISTIC noch NOT DETERMINISTIC steht, ist die Voreinstellung NOT DETERMINISTIC.

Im Zusammenhang mit Replikation wird eine Routine durch Verwendung der Funktion NOW() (oder ihrer Synonyme) oder RAND() nicht unbedingt nichtdeterministisch. Für NOW() enthält das Binärlog den Zeitstempel und repliziert korrekt. RAND() repliziert ebenfalls richtig, sofern es in einer Routine nur ein einziges Mal aufgerufen wird. (Den Ausführungszeitstempel der Routine und den Zufallszahlen-Seed können Sie als implizite Eingaben betrachten, die auf Master und Slave identisch sind.)

Zurzeit wird das DETERMINISTIC-Merkmal vom Optimierer zwar akzeptiert, aber noch nicht benutzt. Wenn jedoch Binärlogging eingeschaltet ist, nimmt dieses Merkmal Einfluss darauf, welche Routinendefinitionen von MySQL akzeptiert werden. Siehe Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“.

Einige Merkmale informieren über das Wesen der von der Routine verwendeten Daten. CONTAINS SQL weist darauf hin, dass die Routine keine Anweisungen zum Lesen oder Schreiben von Daten enthält. NO SQL bedeutet, dass sie keine SQL-Anweisungen enthält. READS SQL DATA kennzeichnet Routinen mit lesenden, aber ohne schreibende Anweisungen und MODIFIES SQL DATA Routinen mit Anweisungen, die Daten schreiben können. CONTAINS SQL ist der Standardwert, wenn kein anderes dieser Merkmale explizit angegeben ist. Die Merkmale haben nur beratenden Charakter. Sie schränken den Server nicht ein, wenn es darum geht, welche Arten von Anweisungen ausgeführt werden dürfen oder nicht.

Das Merkmal SQL SECURITY gibt an, ob die Routine mit den Berechtigungen des Benutzers, der sie erzeugte, oder des Benutzers, der sie aufruft, ausgeführt werden soll. Der Standardwert ist DEFINER. Dieses Feature ist neu in SQL:2003. Der Erzeuger oder Aufrufer muss die Zugriffsberechtigung auf die Datenbank haben, mit der die Routine verbunden ist. Um die Routine auszuführen, ist das EXECUTE-Recht erforderlich. Der Benutzer, der diese Berechtigung haben muss, kann nur entweder der Erzeuger oder der Aufrufer sein, je nachdem, wie SQL SECURITY eingestellt ist.

MySQL speichert die Einstellung der Systemvariablen sql_mode, die gerade in Kraft ist, wenn eine Routine erzeugt wird, und führt diese Routine dann immer mit dieser Einstellung aus.

Beim Aufruf der Routine wird ein implizites USE db_name ausgeführt (und wieder rückgängig gemacht, wenn die Routine endet). USE-Anweisungen sind in gespeicherten Routinen nicht erlaubt.

Der Server verwendet den Datentyp eines Routinenparameters oder Funktionsrückgabewerts wie folgt. Diese Regeln gelten auch für lokale Laufzeitvariablen, die mit der DECLARE-Anweisung angelegt wurden (Abschnitt 19.2.7.1, „Lokale DECLARE-Variablen“).

  • Zuweisungen werden auf Datentypinkompatibilitäten und Überlauf überprüft. Konvertierungs- und Überlaufprobleme werden mit Warnungen oder im Strict-Modus sogar mit Fehlern quittiert.

  • Für Zeichendatentypen gilt: Wenn in der Deklaration eine CHARACTER SET-Klausel steht, wird der angegebene Zeichensatz mit seiner Standardkollation verwendet. Fehlt eine solche Klausel, werden der Zeichensatz und die Kollation der Datenbank benutzt. (Diese sind durch die Systemvariablen character_set_database und collation_database vorgegeben.)

  • Parametern oder Variablen können nur Skalarwerte zugewiesen werden. Eine Anweisung wie etwa SET x = (SELECT 1, 2) wäre ungültig.

Die COMMENT-Klausel ist eine MySQL-Erweiterung und kann zur Beschreibung der gespeicherten Routine genutzt werden. Diese Information wird mit den Anweisungen SHOW CREATE PROCEDURE und SHOW CREATE FUNCTION angezeigt.

In MySQL dürfen Routinen auch DDL-Anweisungen wie beispielsweise CREATE und DROP enthalten. Darüber hinaus dürfen gespeicherte Prozeduren (nicht aber gespeicherte Funktionen) in MySQL auch Transaktionsanweisungen in SQL enthalten, wie etwa COMMIT. Gespeicherte Funktionen dürfen keine Anweisungen enthalten, die explizit oder implizit ein Commit oder Rollback ausführen. Eine Unterstützung für diese Anweisungen wird vom SQL-Standard auch gar nicht verlangt, der Standard besagt lediglich, dass jeder DBMS-Hersteller selbst entscheiden kann, ob er sie erlauben will oder nicht.

Gespeicherte Routinen dürfen kein LOAD DATA INFILE enthalten.

Anweisungen, die eine Ergebnismenge zurückgeben, dürfen nicht innerhalb einer gespeicherten Funktion verwendet werden. Dazu gehören auch SELECT-Anweisungen, soweit sie nicht mithilfe einer INTO-Klausel Spaltenwerte in Variablen laden, sowie SHOW und andere Anweisungen wie beispielsweise EXPLAIN. Anweisungen, für die zur Definitionszeit festgelegt werden kann, dass sie eine Ergebnismenge zurückliefern, lösen einen Not allowed to return a result set from a function-Fehler aus (ER_SP_NO_RETSET_IN_FUNC). Anweisungen, für die nur zur Laufzeit festgelegt werden kann, dass sie eine Ergebnismenge zurückliefern, lösen einen PROCEDURE %s can't return a result set in the given context-Fehler aus (ER_SP_BADSELECT).

Das folgende Beispiel zeigt eine einfache gespeicherte Prozedur mit einem OUT-Parameter. Das Beispiel verwendet den mysql-Clientbefehl delimiter, um das Begrenzungszeichen für die Anweisung von ; in // zu ändern, während die Prozedur definiert wird. So kann das Begrenzungszeichen ; im Prozedurrumpf an den Server durchgereicht werden, ohne von mysql selbst interpretiert zu werden.

mysql> delimiter //

mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
    -> BEGIN
    ->   SELECT COUNT(*) INTO param1 FROM t;
    -> END;
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @a;
+------+
| @a   |
+------+
| 3    |
+------+
1 row in set (0.00 sec)

Wenn Sie den Befehl delimiter benutzen, geben Sie bitte nicht das Backslash-Zeichen (‘\’) an, da es das Escape-Symbol für MySQL ist.

Das folgende Beispiel zeigt eine Funktion, die einen Parameter entgegennimmt, eine Operation mit einer SQL-Funktion ausführt und das Ergebnis zurückliefert. In diesem Fall ist es nicht nötig, delimiter zu benutzen, da die Funktionsdefinition keine ;-Zeichen als interne Anweisungstrennzeichen enthält:

mysql> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50)
    -> RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world!  |
+----------------+
1 row in set (0.00 sec)

Eine gespeicherte Funktion gibt einen Wert zurück, dessen Datentyp in ihrer RETURNS-Klausel angegeben ist. Wenn die RETURN-Anweisung einen Wert eines anderen Typs zurückgibt, wird dieser mit Gewalt in den richtigen Typ umgewandelt. Wenn eine Funktion beispielsweise einen Rückgabewert vom Typ ENUM oder SET hat, die RETURN-Anweisung jedoch einen Integer zurückgibt, so liefert die Funktion den String für das entsprechende ENUM-Element oder die Menge der SET-Elemente.

19.2.2. ALTER PROCEDURE und ALTER FUNCTION

ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]

characteristic:
    { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'

Mit dieser Anweisung können die Merkmale einer gespeicherten Prozedur oder Funktion geändert werden. Hierzu benötigen Sie das ALTER ROUTINE-Recht für die betreffende Routine. (Diese Berechtigung wird dem Erzeuger einer Routine automatisch erteilt.) Wenn Binärlogging eingeschaltet ist, kann für die ALTER FUNCTION-Anweisung unter Umständen auch die SUPER-Berechtigung erforderlich werden, wie in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“, beschrieben.

In einer einzigen ALTER PROCEDURE- oder ALTER FUNCTION-Anweisung können auch mehrere Änderungen verlangt werden.

19.2.3. DROP PROCEDURE und DROP FUNCTION

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

Diese Anweisung löscht eine gespeicherte Prozedur oder Funktion in dem Sinne, dass die darin genannte Routine von dem Server entfernt wird. Hierzu benötigen Sie das ALTER ROUTINE-Recht für die betreffende Routine. (Diese Berechtigung wird dem Erzeuger einer Routine automatisch erteilt.)

Die IF EXISTS-Klausel ist eine MySQL-Erweiterung. Sie verhindert, dass ein Fehler auftritt, wenn die Prozdur oder Funktion nicht existiert. Es wird eine Warnung ausgegeben, die mit SHOW WARNINGS angezeigt werden kann.

19.2.4. Syntax der CALL-Anweisung

CALL sp_name([parameter[,...]])

Die CALL-Anweisung ruft eine mit CREATE PROCEDURE erstellte Prozedur auf.

CALL kann Werte mithilfe von OUT- oder INOUT-Parametern an den Aufrufer zurückgeben. Außerdem kann CALL die Anzahl der betroffenen Zeilen „zurückgeben“, wenn auf der SQL-Ebene die Funktion ROW_COUNT() oder auf der C-Ebene die Funktion mysql_affected_rows() aus der C-API aufgerufen wird.

19.2.5. BEGIN ... END-Syntax für komplexe Anweisungen

[begin_label:] BEGIN
    [statement_list]
END [end_label]

Die BEGIN ... END-Syntax wird für zusammengesetzte Anweisungen verwendet, die in gespeicherten Routinen und Triggern auftreten können. Eine zusammengesetzte Anweisung enthält mehrere Anweisungen, die zwischen den Schlüsselwörtern BEGIN und END stehen. Die statement_list ist eine Liste mit einer oder mehreren Anweisungen. Jede Anweisung der statement_list muss durch ein Semikolon (;) abgegrenzt werden. Beachten Sie, dass eine statement_list optional ist, sodass auch eine leere zusammengesetzte Anweisung (BEGIN END) zulässig wäre.

Um überhaupt mehrere Anweisungen verbinden zu können, muss ein Client in der Lage sein, Strings von Anweisungen zu senden, die durch das Trennzeichen ; abgegrenzt sind. Dafür sorgt der Kommandozeilen-Client mysql mit dem Befehl delimiter. Wenn Sie das Begrenzungszeichen für Anweisungen von ; auf etwas anderes umstellen (beispielsweise ein //), dann kann ; auch im Rumpf der Routine verwendet werden. Ein Beispiel finden Sie in Abschnitt 19.2.1, „CREATE PROCEDURE und CREATE FUNCTION.

Eine zusammengesetzte Anweisung kann auch beschriftet sein. Ein end_label kann allerdings nur verwendet werden, wo auch ein begin_label vorhanden ist. Wo beide vorhanden sind, müssen sie identisch sein.

Die optionale Klausel [NOT] ATOMIC wird noch nicht unterstützt. Dies bedeutet, dass am Anfang eines Anweisungsblocks kein Transaktions-Savepoint gesetzt wird und dass eine BEGIN-Klausel in diesem Kontext keinen Einfluss auf die aktuelle Transaktion hat.

19.2.6. Syntax der DECLARE-Anweisung

Die DECLARE-Anweisung definiert Elemente als lokal in einer Routine:

Die Anweisungen SIGNAL und RESIGNAL werden zurzeit nicht unterstützt.

DECLARE ist nur in einer zusammengesetzten Anweisung mit BEGIN ... END zulässig und muss ganz am Anfang vor allen anderen Anweisungen stehen.

Deklarationen müssen in einer bestimmten Reihenfolge stehen. Cursors müssen vor Handlern und Variablen und Bedingungen vor Cursors und Handlern deklariert werden.

19.2.7. Variablen in gespeicherten Routinen

Auch Variablen können in einer Routine deklariert und benutzt werden.

19.2.7.1. Lokale DECLARE-Variablen

DECLARE var_name[,...] type [DEFAULT value]

Diese Anweisung deklariert lokale Variablen. Um der Variablen einen Standardwert beizugeben, schreiben Sie eine DEFAULT-Klausel in die Deklaration. Der Wert kann auch als Ausdruck angegeben werden, er muss nicht unbedingt eine Konstante sein. Ist keine DEFAULT-Klausel vorhanden, ist der Anfangswert der Variablen NULL.

Lokale Variablen werden im Hinblick auf Datentyp und Speicherüberlauf wie Routinenparameter behandelt. Siehe auch Abschnitt 19.2.1, „CREATE PROCEDURE und CREATE FUNCTION.

Eine lokale Variable gilt innerhalb des BEGIN ... END-Blocks, in dem sie deklariert ist. Die Variable kann auch in Blöcken verwendet werden, die in den deklarierenden Block eingeschachtelt sind, sofern dort nicht eine Variable mit demselben Namen deklariert ist.

19.2.7.2. Variable SET-Anweisung

SET var_name = expr [, var_name = expr] ...

Die SET-Anweisung in gespeicherten Routinen ist eine erweiterte Version der allgemeinen SET-Anweisung. Die Variablen können in einer Routine deklarierte Variablen oder globale Systemvariablen sein.

Die SET-Anweisung in gespeicherten Routinen ist als Teil der bereits existierenden SET-Syntax implementiert. Diese ermöglicht nämlich eine erweiterte Syntax mit SET a=x, b=y, ..., wobei verschiedene Variablentypen (lokal deklarierte Variablen sowie globale und Session-Servervariablen) vermischt werden können. Das ermöglicht auch Kombinationen von lokalen Variablen und einigen Optionen, die nur für Systemvariablen sinnvoll sind. In diesem Fall werden die Optionen zwar erkannt, aber ignoriert.

19.2.7.3. SELECT ... INTO-Anweisung

SELECT col_name[,...] INTO var_name[,...] table_expr

Diese SELECT-Syntax speichert die ausgewählten Spalten direkt in Variablen. Daher kann nur eine einzige Zeile abgerufen werden.

SELECT id,data INTO x,y FROM test.t1 LIMIT 1;

Bei den Namen von Benutzervariablen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Siehe Abschnitt 9.3, „Benutzerdefinierte Variablen“.

Wichtig: In SQL dürfen Variablennamen und Spaltennamen nicht gleich sein. Wenn eine SQL-Anweisung wie etwa ein SELECT ... INTO eine Spalte und eine mit demselben Namen deklarierte lokale Variable benutzt, interpretiert MySQL in der gegenwärtigen Version diese Referenz als den Namen der Variablen. So wird beispielsweise xname in der folgenden Anweisung als die Variable und nicht als die Spalte mit dem Namen xname interpretiert:

CREATE PROCEDURE sp1 (x VARCHAR(5))
  BEGIN
    DECLARE xname VARCHAR(5) DEFAULT 'bob';
    DECLARE newname VARCHAR(5);
    DECLARE xid INT;
    
    SELECT xname,id INTO newname,xid 
      FROM table1 WHERE xname = xname;
    SELECT newname;
  END;

Wenn diese Prozedur aufgerufen wird, gibt die Variable newname immer den Wert 'bob' zurück, egal welchen Wert die Spalte table1.xname auch immer haben mag.

Siehe auch Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“.

19.2.8. Bedingungen und Handler

Manche Bedingungen erfordern eine Sonderbehandlung, darunter Bedingungen, die Fehler oder den allgemeinen Kontrollfluss innerhalb einer Routine steuern.

19.2.8.1. DECLARE-Bedingungen

DECLARE condition_name CONDITION FOR condition_value

condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | mysql_error_code

Diese Anweisung spezifiziert Bedingungen, die speziell behandelt werden müssen. Sie verbindet einen Namen mit einer Fehlerbedingung. Dieser Name kann danach in einer DECLARE HANDLER-Anweisung eingesetzt werden. Siehe Abschnitt 19.2.8.2, „DECLARE-Handler“.

Ein condition_value kann ein SQLSTATE-Wert oder ein MySQL-Fehlercode sein.

19.2.8.2. DECLARE-Handler

DECLARE handler_type HANDLER FOR condition_value[,...] statement

handler_type:
    CONTINUE
  | EXIT
  | UNDO

condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | condition_name
  | SQLWARNING
  | NOT FOUND
  | SQLEXCEPTION
  | mysql_error_code

Die DECLARE ... HANDLER-Anweisung deklariert Handler, die jeweils eine oder mehrere Bedingungen behandeln können. Wenn eine dieser Bedingungen eintritt, wird das angegebene statement ausgeführt. statement kann eine einfache Anweisung sein (beispielsweise SET var_name = value) oder auch eine zusammengesetzte Anweisung in einem BEGIN ... END-Block (siehe Abschnitt 19.2.5, „BEGIN ... END-Syntax für komplexe Anweisungen“).

Ein CONTINUE-Handler lässt die Ausführung der aktuellen Routine nach der Ausführung der Handler-Anweisung weiterlaufen. Ein EXIT-Handler dagegen beendet die Ausführung für die zusammengesetzte BEGIN ... END-Anweisung, in der er deklariert ist. (Das gilt selbst dann, wenn die Bedingung in einem inneren Block eintritt.) Eine Anweisung des Typs UNDO-Handler wird zurzeit noch nicht unterstützt.

Wenn eine Bedingung eintritt, für die kein Handler deklariert wurde, ist die Standardaktion ein EXIT.

Ein condition_value kann einer der folgenden Werte sein:

  • Ein SQLSTATE-Wert oder MySQL-Fehlercode.

  • Ein zuvor mit DECLARE ... CONDITION deklarierter Bedingungsname. Siehe Abschnitt 19.2.8.1, „DECLARE-Bedingungen“.

  • SQLWARNING ist eine Abkürzung für alle SQLSTATE-Codes, die mit 01 beginnen.

  • NOT FOUND ist eine Abkürzung für alle SQLSTATE-Codes, die mit 02 beginnen.

  • SQLEXCEPTION ist eine Abkürzung für alle SQLSTATE-Codes, die nicht unter SQLWARNING oder NOT FOUND fallen.

Beispiel:

mysql> CREATE TABLE test.t (s1 int,primary key (s1));
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter //

mysql> CREATE PROCEDURE handlerdemo ()
    -> BEGIN
    ->   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
    ->   SET @x = 1;
    ->   INSERT INTO test.t VALUES (1);
    ->   SET @x = 2;
    ->   INSERT INTO test.t VALUES (1);
    ->   SET @x = 3;
    -> END;
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x//
    +------+
    | @x   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)

Dieses Beispiel verbindet einen Handler mit der Bedingung SQLSTATE 23000, die bei doppelten Schlüsselwerten eintritt. Beachten Sie, dass @x die 3 ist: Dies zeigt, dass MySQL die Prozedur bis zum Ende ausgeführt hat. Wäre die Zeile DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; nicht vorhanden, hätte MySQL den Standardweg (EXIT) eingeschlagen, nachdem das zweite INSERT an dem PRIMARY KEY-Constraint gescheitert ist, und SELECT @x hätte eine 2 zurückgegeben.

Wenn Sie eine Bedingung ignorieren möchten, können Sie einen CONTINUE-Handler für sie deklarieren und mit einem leeren Block verbinden. Zum Beispiel:

DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

19.2.9. Cursor

Einfache Cursors werden in gespeicherten Prozeduren und Funktionen unterstützt. Die Syntax ist dieselbe wie in eingebettetem SQL. Gegenwärtig sind Cursors asensitiv, nur-lesend und nicht scrollbar. Asensitiv bedeutet, dass der Server eine Kopie der Ergebnistabelle anfertigen kann, aber nicht muss.

Cursors müssen vor Handlern und Variablen und Bedingungen vor Cursors und Handlern deklariert werden.

Beispiel:

CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE a CHAR(16);
  DECLARE b,c INT;
  DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
  DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;

  OPEN cur1;
  OPEN cur2;

  REPEAT
    FETCH cur1 INTO a, b;
    FETCH cur2 INTO c;
    IF NOT done THEN
       IF b < c THEN
          INSERT INTO test.t3 VALUES (a,b);
       ELSE
          INSERT INTO test.t3 VALUES (a,c);
       END IF;
    END IF;
  UNTIL done END REPEAT;

  CLOSE cur1;
  CLOSE cur2;
END

19.2.9.1. Deklaration von Cursorn

DECLARE cursor_name CURSOR FOR select_statement

Diese Anweisung deklariert einen Cursor. Es können zwar mehrere Cursors in einer Routine deklariert werden, aber in einem gegebenen Block muss jeder Cursor einen eindeutigen Namen haben.

Die SELECT-Anweisung darf keine INTO-Klausel haben.

19.2.9.2. Cursor-OPEN-Anweisung

OPEN cursor_name

Diese Anweisung öffnet einen zuvor deklarierten Cursor.

19.2.9.3. Das Cursor-Statement FETCH

FETCH cursor_name INTO var_name [, var_name] ...

Diese Anweisung holt die nächste Zeile ab (sofern eine existiert). Hierzu verwendet sie den angegebenen, geöffneten Cursor und schiebt den Zeiger im Cursor um eins weiter.

19.2.9.4. Cursor-Statement CLOSE

CLOSE cursor_name

Diese Anweisung schließt einen zuvor geöffneten Cursor.

Wenn ein Cursor nicht explizit geschlossen wurde, wird er am Ende der zusammengesetzten Anweisung geschlossen, in der er deklariert ist.

19.2.10. Konstrukte für die Ablaufsteuerung

Die Konstrukte IF, CASE, LOOP, WHILE, REPLACE ITERATE und LEAVE sind vollständig implementiert.

Viele dieser Konstrukte können andere Anweisungen enthalten, wie die Grammatikspezifikationen in den nachfolgenden Abschnitten zeigen. Solche Konstrukte können auch geschachtelt werden. So kann beispielsweise eine IF-Anweisung eine WHILE-Schleife enthalten, die ihrerseits eine CASE-Anweisung enthält.

FOR-Schleifen werden zurzeit nicht unterstützt.

19.2.10.1. IF-Anweisung

IF search_condition THEN statement_list
    [ELSEIF search_condition THEN statement_list] ...
    [ELSE statement_list]
END IF

IF implementiert ein einfaches Bedingungskonstrukt. Wenn die search_condition zutrifft, wird die zugehörige SQL-Anweisungsliste ausgeführt. Trifft keine search_condition zu, wird die Anweisungsliste aus der ELSE-Klausel ausgeführt. Jede statement_list besteht aus einer oder mehreren Anweisungen.

Hinweis: Es gibt auch eine IF()-Funktion, die sich von der hier beschriebenen IF-Anweisung unterscheidet. Siehe Abschnitt 12.2, „Ablaufsteuerungsfunktionen“.

19.2.10.2. CASE-Anweisung

CASE case_value
    WHEN when_value THEN statement_list
    [WHEN when_value THEN statement_list] ...
    [ELSE statement_list]
END CASE

Oder:

CASE
    WHEN search_condition THEN statement_list
    [WHEN search_condition THEN statement_list] ...
    [ELSE statement_list]
END CASE

Die CASE-Anweisung für gespeicherte Routinen implementiert ein komplexes Bedingungskonstrukt. Wenn die search_condition zutrifft, wird die zugehörige SQL-Anweisungsliste ausgeführt. Trifft keine search_condition zu, wird die Anweisungsliste aus der ELSE-Klausel ausgeführt. Jede statement_list besteht aus einer oder mehreren Anweisungen.

Hinweis: Die Syntax der hier gezeigten CASE-Anweisung, die in gespeicherten Routinen zum Einsatz kommt, unterscheidet sich von der Syntax des CASE-Ausdrucks von SQL, die in Abschnitt 12.2, „Ablaufsteuerungsfunktionen“, beschrieben wird. Die CASE-Anweisung darf keine ELSE NULL-Klausel haben und wird mit END CASE anstelle von END abgeschlossen.

19.2.10.3. LOOP-Anweisung

[begin_label:] LOOP
    statement_list
END LOOP [end_label]

LOOP implementiert ein einfaches Schleifenkonstrukt, das eine wiederholte Ausführung der aus einer oder mehreren Anweisungen bestehenden Anweisungsliste ermöglicht. Die Anweisungen werden in der Schleife so lange wiederholt, bis die Schleife abgebrochen wird. Dies geschieht normalerweise mit der LEAVE-Anweisung.

Eine LOOP-Anweisung kann auch beschriftet sein. Ein end_label kann allerdings nur verwendet werden, wo auch ein begin_label vorhanden ist. Wo beide vorhanden sind, müssen sie identisch sein.

19.2.10.4. LEAVE-Anweisung

LEAVE label

Diese Anweisung beendet ein beschriftetes Konstrukt zur Flusskontrolle. Sie kann in einem BEGIN ... END-Block oder in Schleifenkonstrukten (LOOP, REPEAT, WHILE) verwendet werden.

19.2.10.5. ITERATE-Anweisung

ITERATE label

ITERATE kann nur in LOOP-, REPEAT- und WHILE-Anweisungen auftreten. ITERATE bedeutet „Durchlaufe die Schleife noch einmal“.

Beispiel:

CREATE PROCEDURE doiterate(p1 INT)
BEGIN
  label1: LOOP
    SET p1 = p1 + 1;
    IF p1 < 10 THEN ITERATE label1; END IF;
    LEAVE label1;
  END LOOP label1;
  SET @x = p1;
END

19.2.10.6. REPEAT-Anweisung

[begin_label:] REPEAT
    statement_list
UNTIL search_condition
END REPEAT [end_label]

Die Anweisungsliste in einer REPEAT-Anweisung wird wiederholt, bis die Suchbedingung search_condition zutrifft. Somit geht ein REPEAT immer mindestens einmal in die Schleife. Die statement_list besteht aus einer oder mehreren Anweisungen.

Eine REPEAT-Anweisung kann auch beschriftet sein. Ein end_label kann allerdings nur verwendet werden, wo auch ein begin_label vorhanden ist. Wo beide vorhanden sind, müssen sie identisch sein.

Beispiel:

mysql> delimiter //

mysql> CREATE PROCEDURE dorepeat(p1 INT)
    -> BEGIN
    ->   SET @x = 0;
    ->   REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> CALL dorepeat(1000)//
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x//
+------+
| @x   |
+------+
| 1001 |
+------+
1 row in set (0.00 sec)

19.2.10.7. WHILE-Anweisung

[begin_label:] WHILE search_condition DO
    statement_list
END WHILE [end_label]

Die Anweisungsliste in einer WHILE-Anweisung wird wiederholt, solange die search_condition zutrifft. Die statement_list besteht aus einer oder mehreren Bedingungen.

Eine WHILE-Anweisung kann auch beschriftet sein. Ein end_label kann allerdings nur verwendet werden, wo auch ein begin_label vorhanden ist. Wo beide vorhanden sind, müssen sie identisch sein.

Beispiel:

CREATE PROCEDURE dowhile()
BEGIN
  DECLARE v1 INT DEFAULT 5;

  WHILE v1 > 0 DO
    ...
    SET v1 = v1 - 1;
  END WHILE;
END

19.3. Gespeicherte Prozeduren, Funktionen, Trigger und Replikation: häufig gestellte Fragen

  • Funktionieren die gespeicherten Prozeduren von MySQL 5.1 mit Replikation?

    Ja. Standardaktionen, die in gespeicherten Prozeduren und Funktionen ausgeführt werden, werden von einem MySQL-Master-Server auf einen Slave-Server repliziert. Es gibt einige wenige Beschränkungen, die in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“ genauer ausgeführt werden.

  • Werden gespeicherte Prozeduren und Funktionen, die auf einem Master-Server angelegt wurden, auf einen Slave repliziert?

    Ja, gespeicherte Prozeduren und Funktionen, die mit normalen DDL-Anweisungen auf einem Master-Server angelegt wurden, werden auf einen Slave repliziert, sodass die Objekte auf beiden Servern vorhanden sind. ALTER- und DROP-Anweisungen für gespeicherte Prozeduren und Funktionen werden ebenfalls repliziert.

  • Wie werden Aktionen repliziert, die innerhalb von gespeicherten Prozeduren und Funktionen stattfinden?

    MySQL zeichnet jedes DML-Ereignis auf, das in einer gespeicherten Prozedur auftritt, und repliziert diese Einzelaktionen auf einen Slave-Server. Die eigentlichen Aufrufe der gespeicherten Prozeduren werden nicht repliziert.

    Gespeicherte Funktionen, die Daten ändern, werden als Funktionsaufrufe ins Log geschrieben, und nicht als die DML-Ereignisse, die innerhalb der Funktionen stattfinden.

  • Gibt es spezielle Sicherheitsanforderungen, um gespeicherte Prozeduren und Funktionen mit Replikation zu benutzen?

    Ja. Da ein Slave-Server das Recht hat, jede Anweisung auszuführen, die er aus dem Binärlog seines Masters liest, gibt es besondere Sicherheitsvorkehrungen für die Verwendung von gespeicherten Prozeduren mit Replikation. Wenn Replikation oder Binärlogging im Allgemeinen (für die Point-of-Time-Recovery) aktiv ist, haben MySQL-DBAs zwei Sicherheitsoptionen:

    • Option 1: Ein Benutzer, der eine gespeicherte Funktion anlegen möchte, muss das SUPER-Recht besitzen.

    • Option 2: Alternativ kann ein DBA die Systemvariable log_bin_trust_function_creators auf 1 setzen. Dann kann jeder, der über die Standardberechtigung CREATE ROUTINE verfügt, gespeicherte Funktionen erstellen.

  • Welche Beschränkungen gelten für die Replikation von Aktionen gespeicherter Prozeduren und Funktionen?

    Nichtdeterministische (zufällige) oder zeitabhängige Aktionen, die in gespeicherten Prozeduren eingebettet sind, werden eventuell nicht richtig repliziert. Nach dem Zufallsprinzip entstandene Ergebnisse sind von Natur aus unvorhersehbar und lassen sich nicht genau reproduzieren. Somit spiegeln Zufallsaktionen, die auf einen Slave repliziert werden, nicht die Aktionen des Masters wider. Wenn Sie gespeicherte Funktionen als DETERMINISTIC deklarieren oder die Systemvariable log_bin_trust_function_creators auf 0 setzen, können keine Operationen mit Zufallswerten aufgerufen werden.

    Auch zeitabhängige Aktionen lassen sich nicht auf einen Slave replizieren, da das Timing solcher Aktionen in einer gespeicherten Prozedur nicht durch das für die Replikation eingesetzte Binärlog reproduzierbar ist. Dieses zeichnet nur DML-Ereignisse auf und berücksichtigt keine Zeiteinschränkungen.

    Auch in nichttransaktionssicheren Tabellen, mit denen bei größeren DML-Aktionen (wie beispielsweise Massen-Einfügeoperationen) Fehler auftreten, können Replikationsprobleme entstehen, wenn ein Master aufgrund der DML-Aktivität teilweise aktualisiert wurde, während der Slave wegen eines Fehlers diese Änderung nicht mitgemacht hat. Dies kann man umgehen, indem man die DML-Aktionen einer Funktion mit dem Schlüsselwort IGNORE ausführt, damit Änderungen auf dem Master, die Fehler auslösen, ignoriert und Änderungen, die keine Fehler auslösen, auf den Slave repliziert werden.

  • Beeinträchtigen die vorgenannten Beschränkungen die Fähigkeit von MySQL, eine Point-in-Time-Recovery durchzuführen?

    Dieselben Beschränkungen, die sich auf die Replikation auswirken, wirken sich auch auf die Point-in-Time-Recovery aus.

  • Was unternimmt MySQL, um diese Beschränkungen auszuräumen?

    Ab MySQL 5.1.5 können Sie zwischen anweisungs- und zeilenbasierter Replikation wählen. Die ursprüngliche Implementierung der Replikation beruht auf dem anweisungsbasierten Binärlogging. Zeilenbasiertes Binärlogging löst die oben beschriebenen Probleme. Mehr zum Thema finden Sie unter Abschnitt 6.3, „Zeilenbasierte Replikation“.

  • Funktionieren Trigger mit Replikation?

    Trigger und Replikation funktionieren in MySQL 5.1 genau wie in den meisten anderen Datenbank-Engines: Aktionen, die auf einem Master mithilfe von Triggern ausgeführt werden, werden nicht auf einen Slave-Server repliziert. Dagegen müssen Trigger auf Tabellen, die auf einem MySQL-Master-Server liegen, auch auf den entsprechenden Tabellen des MySQL-Slave-Servers angelegt werden, um auf den Slaves ebenso wie auf dem Master aktiviert werden zu können.

  • Wie werden Trigger-Aktionen auf einem Master ausgeführt, der auf einen Slave repliziert wurde?

    Erstens müssen die Trigger, die auf dem Master vorhanden sind, auf dem Slave-Server rekonstruiert werden. Wenn dies erledigt ist, läuft die Replikation so ab wie bei jeder anderen DML-Standardanweisung, die an einer Replikation beteiligt ist. Betrachten Sie als Beispiel die Tabelle EMP mit dem Insert-Trigger AFTER, die auf einem MySQL-Master-Server liegt. Dieselbe EMP-Tabelle mit demselben AFTER-Insert-Trigger liegt auch auf dem Slave-Server. Der Replikationsfluss verliefe folgendermaßen:

  1. Eine INSERT-Anweisung für EMP wird abgesetzt.

  2. Der AFTER-Trigger auf EMP wird aktiviert.

  3. Die INSERT-Anweisung wird in das Binärlog geschrieben.

  4. Der Replikations-Slave nimmt die INSERT-Anweisung für EMP auf und führt sie aus.

  5. Der AFTER-Trigger auf EMP, der auf dem Slave existiert, wird aktiviert.

19.4. Binärloggen gespeicherter Routinen und Trigger

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 func_name()-Anweisung in das Binärlog geschrieben, wenn die Funktion eine Änderung vornimmt. Angenommen, folgende Funktionen werden auf dem Master ausgeführt:

    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 „Namenvar_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.

Kapitel 20. Trigger

Ein Trigger ist ein benanntes Datenbankobjekt, das mit einer Tabelle verbunden ist und aktiviert wird, wenn für diese Tabelle ein bestimmtes Ereignis eintritt. So legen beispielsweise die folgenden Anweisungen eine Tabelle und einen INSERT-Trigger an. Der Trigger addiert die Werte, die in eine der Tabellenspalten geladen werden:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
Query OK, 0 rows affected (0.03 sec)

mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.06 sec)

Dieses Kapitel beschreibt die Syntax, mit der Trigger angelegt und gelöscht werden, und zeigt einige Anwendungsbeispiele für sie. Über die Beschränkungen für Trigger finden Sie in Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“, genauere Hinweise. Informationen über Binärlogging in Bezug auf Trigger finden Sie unter Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“.

20.1. CREATE TRIGGER

CREATE
    [DEFINER = { user | CURRENT_USER }]
    TRIGGER trigger_name trigger_time trigger_event
    ON tbl_name FOR EACH ROW trigger_stmt

Diese Anweisung erzeugt einen neuen Trigger. Ein Trigger ist ein benanntes Datenbankobjekt, das mit einer Tabelle verbunden ist und aktiviert wird, wenn für diese Tabelle ein bestimmtes Ereignis eintritt. Gegenwärtig ist zur Ausführung von CREATE TRIGGER das TRIGGER-Recht für die Tabelle erforderlich, zu welcher der Trigger gehört. (Vor MySQL 5.1.6 war für diese Anweisung das SUPER-Recht notwendig.)

Der Trigger wird mit der Tabelle tbl_name verbunden, die eine permanante Tabelle sein muss. Mit einer als TEMPORARY definierten Tabelle oder View lässt sich kein Trigger verbinden.

Wenn der Trigger aktiviert wird, legt die DEFINER-Klausel fest, welche Rechte angewendet werden. Genaueres erfahren Sie weiter unten in diesem Kapitel.

Die trigger_time ist der Zeitpunkt der Trigger-Aktion. Sie kann BEFORE oder AFTER sein, je nachdem, ob der Trigger sich vor oder nach der Anweisung einschaltet, die ihn aktivierte.

Das trigger_event gibt an, welche Art von Anweisung den Trigger aktiviert. Das trigger_event kann eines der folgenden Ereignisse sein:

  • INSERT: Der Trigger wird immer dann aktiviert, wenn eine neue Zeile in die Tabelle eingefügt wird, beispielsweise mit INSERT-, LOAD DATA- und REPLACE-Anweisungen.

  • UPDATE: Der Trigger wird immer dann aktiviert, wenn eine Zeile in der Tabelle geändert wird, beispielsweise mit UPDATE-Anweisungen.

  • DELETE: Der Trigger wird immer dann aktiviert, wenn eine Zeile aus der Tabelle gelöscht wird, beispielsweise mit DELETE- und REPLACE-Anweisungen.

Es ist wichtig, zu verstehen, dass das trigger_event weniger eine Art von SQL-Anweisung ist, die den Trigger aktiviert, als vielmehr eine Art von Tabellenoperation. So wird beispielsweise ein INSERT-Trigger nicht nur von INSERT-Anweisungen, sondern auch von LOAD DATA-Anweisungen aktiviert, weil beide Anweisungen Zeilen in eine Tabelle einfügen.

Ein potenziell verwirrendes Beispiel dafür ist die Syntax von INSERT INTO ... ON DUPLICATE KEY UPDATE ...: Für jede Zeile wird ein BEFORE INSERT-Trigger aktiviert, gefolgt entweder von einem AFTER INSERT-Trigger oder von dem Triggerpaar aus BEFORE UPDATE und AFTER UPDATE, je nachdem, ob ein doppelter Schlüssel für die Zeile vorlag oder nicht.

Es dürfen keine zwei Trigger einer Tabelle dieselbe Aktionszeit und dasselbe Trigger-Ereignis haben. Zum Beispiel können Sie keine zwei BEFORE UPDATE-Trigger für eine Tabelle definieren. Sie können jedoch einen BEFORE UPDATE- und einen BEFORE INSERT-Trigger oder einen BEFORE UPDATE- und einen AFTER UPDATE-Trigger definieren.

trigger_stmt ist die Anweisung, die ausgeführt wird, wenn der Trigger in Aktion tritt. Wenn Sie mehrere Anweisungen ausführen möchten, verwenden Sie das Konstrukt BEGIN ... END für zusammengesetzte Anweisungen. So können Sie auch dieselben Anweisungen wie in gespeicherten Routinen verwenden. Siehe auch Abschnitt 19.2.5, „BEGIN ... END-Syntax für komplexe Anweisungen“.

Hinweis: Zurzeit werden Trigger nicht von kaskadierenden Fremdschlüsselaktionen aktiviert. Dieser Mangel wird jedoch so bald wie möglich behoben.

In MySQL 5.1 können Sie Trigger schreiben, die Direktverweise auf Tabellennamen enthalten, wie der Trigger testref im folgenden Beispiel:

CREATE TABLE test1(a1 INT);
CREATE TABLE test2(a2 INT);
CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE test4(
  a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  b4 INT DEFAULT 0
);

DELIMITER |

CREATE TRIGGER testref BEFORE INSERT ON test1
  FOR EACH ROW BEGIN
    INSERT INTO test2 SET a2 = NEW.a1;
    DELETE FROM test3 WHERE a3 = NEW.a1;  
    UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
  END;
|

DELIMITER ;

INSERT INTO test3 (a3) VALUES 
  (NULL), (NULL), (NULL), (NULL), (NULL), 
  (NULL), (NULL), (NULL), (NULL), (NULL);

INSERT INTO test4 (a4) VALUES 
  (0), (0), (0), (0), (0), (0), (0), (0), (0), (0);

Angenommen, Sie setzen die folgenden Werte in die Tabelle test1 ein, wie hier gezeigt:

mysql> INSERT INTO test1 VALUES 
    -> (1), (3), (1), (7), (1), (8), (4), (4);
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

Die Daten in den vier Tabellen stellen sich dann folgendermaßen dar:

mysql> SELECT * FROM test1;
+------+
| a1   |
+------+
|    1 |
|    3 |
|    1 |
|    7 |
|    1 |
|    8 |
|    4 |
|    4 |
+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM test2;
+------+
| a2   |
+------+
|    1 |
|    3 |
|    1 |
|    7 |
|    1 |
|    8 |
|    4 |
|    4 |
+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM test3;
+----+
| a3 |
+----+
|  2 |
|  5 |
|  6 |
|  9 |
| 10 |
+----+
5 rows in set (0.00 sec)

mysql> SELECT * FROM test4;
+----+------+
| a4 | b4   |
+----+------+
|  1 |    3 |
|  2 |    0 |
|  3 |    1 |
|  4 |    2 |
|  5 |    0 |
|  6 |    0 |
|  7 |    1 |
|  8 |    1 |
|  9 |    0 |
| 10 |    0 |
+----+------+
10 rows in set (0.00 sec)

Die Spalten der Subjekttabelle (der Tabelle, zu welcher der Trigger gehört) können Sie mit den Aliasnamen OLD und NEW ansprechen. OLD.col_name bezieht sich auf eine Spalte mit einer vorhandenen Zeile, bevor diese geändert oder gelöscht wurde, und NEW.col_name auf die Spalte mit einer neu eingefügten oder geänderten Zeile.

Die DEFINER-Klausel gibt an, welches MySQL-Konto zur Prüfung der Zugriffsberechtigungen bei Aktivierung des Triggers herangezogen wird. Wenn ein user-Wert angegeben ist, dann als MySQL-Konto im Format 'user_name'@'host_name' (dasselbe Format wird auch in der GRANT-Anweisung verwendet). Die Werte user_name und host_name sind beide obligatorisch. CURRENT_USER kann auch als CURRENT_USER() angegeben werden. Der Standardwert für DEFINER ist der Benutzer, der die CREATE TRIGGER-Anweisung ausführt. (Dies ist dasselbe wie DEFINER = CURRENT_USER.)

Wenn Sie die DEFINER-Klausel angeben, dürfen Sie den Wert auf kein anderes als Ihr eigenes Konto einstellen, wenn Sie nicht über das SUPER-Recht verfügen. Die zulässigen Werte für den DEFINER-Benutzer richten sich nach folgenden Regeln:

  • Wenn Sie nicht das SUPER-Recht haben, ist der einzig zulässige user-Wert Ihr eigenes Konto, das entweder buchstäblich oder über CURRENT_USER angegeben werden kann. Auf ein anderes Konto können Sie den DEFINER nicht einstellen.

  • Wenn Sie das SUPER-Recht haben, können Sie jeden gültigen Kontonamen angeben, der syntaktisch zulässig ist. Existiert das Konto in Wirklichkeit nicht, wird eine Warnung ausgegeben.

Hinweis: In älteren Versionen als MySQL 5.1.6 wird das SUPER-Recht für die Benutzung von CREATE TRIGGER verlangt, sodass für diese älteren Releases nur die zweite der oben genannten Regeln gilt. Seit der Version 5.1.6 ist SUPER nur noch erforderlich, wenn der DEFINER auf etwas anderes als das eigene Konto eingestellt werden soll.

MySQL prüft Trigger-Berechtigungen folgendermaßen:

  • Zur CREATE TRIGGER-Zeit muss der Benutzer, der die Anweisung gibt, das TRIGGER-Recht besitzen. (Vor MySQL 5.1.6 war sogar das SUPER-Recht erforderlich.)

  • Zum Zeitpunkt der Trigger-Aktivierung werden die Berechtigungen mit denen des DEFINER-Benutzers verglichen. Dieser benötigt folgende Berechtigungen:

    • Das TRIGGER-Recht (vor MySQL 5.1.6 das SUPER-Recht).

    • Das SELECT-Recht für die Subjekttabelle, wenn mit OLD.col_name oder NEW.col_name in der Trigger-Definition auf Tabellenspalten verwiesen wird.

    • Das UPDATE-Recht für die Subjekttabelle, wenn ihre Spalten Ziel von SET NEW.col_name = value-Zuweisungen in der Trigger-Definition sind.

    • Zusätzlich alle anderen Rechte, die normalerweise für die vom Trigger ausgeführten Anweisungen erforderlich sind.

20.2. DROP TRIGGER

DROP TRIGGER [schema_name.]trigger_name

Diese Anweisung löscht einen Trigger. Der Schemaname (Datenbank) ist optional. Wird kein Schema angegeben, wird der Trigger aus dem Standardschema gelöscht. DROP TRIGGER wurde in MySQL 5.0.2 hinzugefügt und erfordert das TRIGGER-Recht für die Tabelle, zu welcher der Trigger gehört. (Vor MySQL 5.1.6 war für diese Anweisung das SUPER-Recht erforderlich.)

Hinweis: Wenn Sie von einer älteren MySQL-Version als MySQL 5.0.10 auf 5.0.10 oder neuer aufrüsten (einschließlich aller MySQL 5.1-Releases), müssen Sie alle Trigger vor dem Upgrade löschen und danach wieder neu erstellen. DROP TRIGGER funktioniert nach dem Upgrade nicht mehr. Unter Abschnitt 2.10.1, „Upgrade von MySQL 5.0“, wird eine empfehlenswerte Upgrade-Prozedur beschrieben.

20.3. Verwendung von Triggern

Dieser Abschnitt beschreibt die Verwendung von Triggern in MySQL 5.1 sowie einige Einschränkungen für die Nutzung von Triggern. Weitere Beschränkungen im Zusammenhang mit Triggern sind in Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“, geschildert.

Ein Trigger ist ein benanntes Datenbankobjekt, das mit einer Tabelle verbunden ist und aktiviert wird, wenn für diese Tabelle ein bestimmtes Ereignis eintritt. Trigger werden beispielsweise verwendet, um Werte zu überprüfen, die in eine Tabelle eingesetzt werden sollen, oder um Berechnungen mit Werten auszuführen, die zu einem Update gehören.

Ein Trigger ist mit einer Tabelle verbunden und wird aktiviert, wenn eine INSERT-, DELETE- oder UPDATE-Anweisung für diese Tabelle ausgeführt wird. Ein Trigger kann so eingestellt werden, dass er entweder vor oder nach der auslösenden Anweisung aktiviert wird. So können Sie beispielsweise veranlassen, dass ein Trigger jeweils vor jeder Zeilenlöschung oder nach jeder Zeilenänderung aktiviert wird.

Ein Trigger wird mit CREATE TRIGGER erstellt und mit DROP TRIGGER gelöscht. Die Syntax dieser Anweisungen wird unter Abschnitt 20.1, „CREATE TRIGGER, und Abschnitt 20.2, „DROP TRIGGER, erklärt.

Das folgende einfache Beispiel verbindet einen Trigger mit einer Tabelle für den Fall von INSERT-Anweisungen. Er fungiert als Sammelbecken, um die Werte zu addieren, die in eine der Tabellenspalten eingefügt werden.

Die folgenden Anweisungen legen eine Tabelle und einen Trigger für sie an:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;

Die CREATE TRIGGER-Anweisung erzeugt einen Trigger namens ins_sum, der mit der account-Tabelle verbunden ist. Außerdem enthält sie Klauseln, um die Aktivierungszeit des Triggers, das Trigger-Ereignis und die eigentlichen Trigger-Aktionen festzulegen:

  • Das Schlüsselwort BEFORE zeigt die Aktivierungszeit des Triggers an. Hier sollte der Trigger in Aktion treten, bevor eine Zeile in die Tabelle eingefügt wird. Das zweite hier zulässige Schlüsselwort ist AFTER.

  • Das Schlüsselwort INSERT zeigt das Ereignis an, welches den Trigger aktiviert. In unserem Beispiel lassen INSERT-Anweisungen den Trigger aktiv werden. Sie können jedoch auch Trigger für DELETE- und UPDATE-Anweisungen anlegen.

  • Hinter dem FOR EACH ROW steht, welche Anweisung jedes Mal ausgeführt werden soll, wenn der Trigger in Aktion tritt, was in diesem Fall für jede von der auslösenden Anweisung betroffene Zeile einmal passiert. Die Trigger-Anweisung in diesem Beispiel ist ein einfaches SET, das die Werte, die in die amount-Spalte eingefügt werden, sammelt. Die Anweisung nennt die Spalte NEW.amount und meint damit „den Wert, der in die neue Zeile der Spalte amount eingesetzt werden soll“.

Um den Trigger verwenden zu können, setzen Sie die Variable, welche die Werte sammelt, auf null, führen eine INSERT-Anweisung aus und schauen, welchen Wert die Variable danach hat:

mysql> SET @sum = 0;
mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
mysql> SELECT @sum AS 'Total amount inserted';
+-----------------------+
| Total amount inserted |
+-----------------------+
| 1852.48               |
+-----------------------+

In diesem Fall hat @sum nach Ausführung der INSERT-Anweisung den Wert 14.98 + 1937.50 - 100, also 1852.48.

Gelöscht wird der Trigger mit der DROP TRIGGER-Anweisung. Wenn der Trigger nicht im Standardschema definiert ist, müssen Sie außerdem den Schemanamen dazusetzen:

mysql> DROP TRIGGER test.ins_sum;

Da Trigger-Namen im Schema-Namensraum liegen, müssen alle Trigger innerhalb eines Schemas eindeutige Namen haben. Trigger in unterschiedlichen Schemata können dagegen gleich heißen.

Zusätzlich zu dem Erfordernis, dass Trigger-Namen in einem Schema eindeutig sein müssen, gibt es noch weitere Einschränkungen betreffend die Typen der Trigger. Insbesondere dürfen keine zwei Trigger einer Tabelle dieselbe Aktivierungszeit und dasselbe Aktivierungsereignis haben. Sie können also nicht zwei BEFORE INSERT-Trigger oder zwei AFTER UPDATE-Trigger für dieselbe Tabelle definieren. Normalerweise dürfte diese Beschränkung jedoch keine Rolle spielen, da ein Trigger auch so definiert werden kann, dass er mehrere Anweisungen in einem BEGIN ... END-Block als zusammengesetzte Anweisung hinter dem FOR EACH ROW ausführt. (Weiter unten in diesem Abschnitt finden Sie ein Beispiel dazu.)

Mit den Schlüsselwörtern OLD und NEW können Sie auf Spalten zugreifen, die von einem Trigger betroffen sind. (Die Groß- und Kleinschreibung spielt für OLD und NEW keine Rolle.) In einem INSERT-Trigger kann nur NEW.col_name benutzt werden, da keine alte Zeile vorhanden ist, und in einem DELETE-Trigger nur OLD.col_name, da keine neue Zeile vorhanden ist. In einem UPDATE-Trigger können sowohl OLD.col_name für den Verweis auf Tabellenzeilen vor der Änderung als auch NEW.col_name für einen Verweis auf die geänderten Zeilen verwendet werden.

Ein Spaltenname mit OLD ist schreibgeschützt. Sie können ihn benutzen (sofern Sie das SELECT-Recht für ihn haben), aber nicht ändern. Ein Spaltenname mit NEW kann mit dem entsprechenden SELECT-Recht angesprochen werden. In einem BEFORE-Trigger können Sie auch seinen Wert mit SET NEW.col_name = value ändern, sofern Sie das UPDATE-Recht dafür haben. Dies bedeutet, dass Sie einen Trigger einsetzen können, um die Werte zu ändern, die in eine neue Zeile eingefügt oder mit denen eine Zeile aktualisiert wird.

In einem BEFORE-Trigger ist der NEW-Wert für eine AUTO_INCREMENT-Spalte 0 und nicht die automatisch generierte laufende Nummer, die angelegt wird, wenn der neue Datensatz tatsächlich eingefügt wird.

OLD und NEW sind MySQL-Erweiterungen für Trigger.

Mit dem BEGIN ... END-Konstrukt können Sie einen Trigger definieren, der mehrere Anweisungen ausführt. Innerhalb des BEGIN-Blocks können Sie auch eine andere für gespeicherte Routinen zulässige Syntax verwenden, wie beispielsweise Bedingungsanweisungen und Schleifen. Doch wie für gespeicherte Routinen gilt auch für Trigger: Wenn Sie das mysql-Programm verwenden, um einen Trigger für mehrere Anweisungen zu definieren, muss das Trennzeichen für die mysql-Anweisung auf etwas anderes eingestellt werden, damit das Begrenzungszeichen ; für Anweisungen in der Trigger-Definition zur Verfügung steht. Dies wird im folgenden Beispiel deutlich, in dem ein UPDATE-Trigger definiert wird, der für jede Zeilenänderung den neuen Wert prüft und diesen so modifiziert, dass er im Bereich zwischen 0 und 100 liegt. Dieser Trigger muss ein BEFORE-Trigger sein, da der Wert überprüft werden muss, bevor er in die Zeile eingesetzt wird:

mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
    -> FOR EACH ROW
    -> BEGIN
    ->     IF NEW.amount < 0 THEN
    ->         SET NEW.amount = 0;
    ->     ELSEIF NEW.amount > 100 THEN
    ->         SET NEW.amount = 100;
    ->     END IF;
    -> END;//
mysql> delimiter ;

Unter Umständen ist es einfacher, eine gespeicherte Prozedur separat zu definieren und dann im Trigger mit einer einfachen CALL-Anweisung aufzurufen. Dies ist auch dann von Vorteil, wenn Sie dieselbe Routine in mehreren Triggern aufrufen möchten.

In Anweisungen, die ein aktivierter Trigger ausführt, ist nicht alles erlaubt:

  • Der Trigger darf nicht mit einer CALL-Anweisung gespeicherte Prozeduren aufrufen, die Daten an den Client zurückgeben oder dynamisches SQL nutzen. (Gespeicherte Prozeduren dürfen jedoch an den Trigger Daten über OUT- oder INOUT-Parameter zurückgeben.)

  • Der Trigger darf keine Anweisungen benutzen, die explizit oder implizit eine Transaktion starten oder beenden, wie etwa START TRANSACTION, COMMIT oder ROLLBACK.

Mit Fehlern bei der Ausführung eines Triggers geht MySQL folgendermaßen um:

  • Bei einem Fehler in einem BEFORE-Trigger wird die Operation auf der betreffenden Zeile nicht ausgeführt.

  • Ein AFTER-Trigger wird nur ausgeführt, wenn der BEFORE-Trigger (wenn vorhanden) und die Zeilenoperation beide erfolgreich waren.

  • Ein Fehler während eines BEFORE- oder AFTER-Triggers lässt die gesamte Anweisung scheitern, durch die der Trigger aufgerufen wurde.

  • Wenn auf einer Transaktionstabelle ein Trigger (und mit ihm die gesamte Anweisung) scheitert, müssen alle durch diese Anweisung verursachten Änderungen zurückgerollt werden. Da ein solcher Rollback bei Tabellen, die nicht an einer Transaktion beteiligt sind, unmöglich ist, bleiben dort alle bis zu dem Fehler eingetretenen Änderungen wirksam, obwohl die Anweisung eigentlich gescheitert ist.

Kapitel 21. Views

Views (auch veränderbare) stehen in MySQL Server 5.1 zur Verfügung.

Dieses Kapitel behandelt folgende Themen:

  • Erzeugen von Views mit CREATE VIEW und Ändern von Views mit ALTER VIEW

  • Löschen von Views mit DROP VIEW

  • Anzeigen der Metadaten von Views mit SHOW CREATE VIEW

Die Beschränkungen für den Einsatz von Views werden in Abschnitt I.4, „Beschränkungen bei Views“, behandelt.

Um Views nach einem Upgrade von einer älteren Version auf MySQL 5.1 benutzen zu können, sollten Sie auch Ihre Berechtigungstabellen aktualisieren, damit sie die View-Berechtigungen enthalten. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

21.1. ALTER VIEW

ALTER
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    [DEFINER = { user | CURRENT_USER }]
    [SQL SECURITY { DEFINER | INVOKER }]
    VIEW view_name [(column_list)]
    AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

Diese Anweisung ändert die Definition einer vorhandenen View. Die Syntax ähnelt der von CREATE VIEW. Siehe auch Abschnitt 21.2, „CREATE VIEW. Für diese Anweisung benötigen Sie für die View die Berechtigungen CREATE VIEW und DROP und zusätzlich die Spaltenberechtigungen, die in der SELECT-Anweisung verlangt werden.

21.2. CREATE VIEW

CREATE
    [OR REPLACE]
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    [DEFINER = { user | CURRENT_USER }]
    [SQL SECURITY { DEFINER | INVOKER }]
    VIEW view_name [(column_list)]
    AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

Diese Anweisung legt eine neue View an oder ersetzt eine vorhandene, wenn die OR REPLACE-Klausel angegeben wurde. Das select_statement ist eine SELECT-Anweisung, welche die Definition der View liefert. Diese SELECT-Anweisung kann sich auf Basistabellen oder andere Views beziehen.

Diese Anweisung erfordert das CREATE VIEW-Recht für die View sowie Spaltenrechte für die in der SELECT-Anweisung referenzierten Spalten. Für Spalten, die anderswo in der SELECT-Anweisung angesprochen werden, benötigen Sie das SELECT-Recht. Wenn die OR REPLACE-Klausel angegeben wurde, benötigen Sie überdies das DROP-Recht für die View.

Eine View gehört zu einer Datenbank. Nach Voreinstellung wird eine neue View immer in der Standarddatenbank angelegt. Um sie explizit in einer bestimmten Datenbank anzulegen, geben Sie bei ihrer Erzeugung ihren Namen als db_name.view_name an.

mysql> CREATE VIEW test.v AS SELECT * FROM t;

Da Basistabellen und Views in einer Datenbank denselben Namensraum teilen, darf eine Datenbank nicht eine Basistabelle und eine View gleichen Namens enthalten.

Views müssen eindeutige Spaltennamen ohne Doppelnennungen haben, genau wie Basistabellen. Nach Voreinstellung werden die Namen von Spalten, die mit der SELECT-Anweisung abgefragt werden, auch als Spaltennamen für die View genutzt. Wenn Sie explizite Namen für die View-Spalten einsetzen möchten, können Sie optional eine column_list-Klausel mit einer Liste von kommagetrennten Bezeichnern angeben. Die Anzahl der Namen in der column_list muss gleich der Anzahl der von der SELECT-Anweisung abgefragten Spalten sein.

Die von der SELECT-Anweisung abgefragten Spalten können einfache Verweise auf Tabellenspalten sein, oder auch Ausdrücke mit Funktionen, Konstantenwerten, Operatoren und so weiter.

Wird der Name einer Tabelle oder View in einer SELECT-Anweisung nicht weiter qualifiziert, wird davon ausgegangen, dass er sich auf die Standarddatenbank bezieht. Eine View kann jedoch auch auf Tabellen oder Views in anderen Datenbanken Bezug nehmen, wenn sie die Namen dieser Tabellen oder Views mit dem Namen der betreffenden Datenbank qualifiziert.

Eine View kann aus vielen Arten von SELECT-Anweisungen angelegt werden. Sie kann Basistabellen oder andere Views verwenden, ebenso wie Joins, UNION und Unterabfragen. Die SELECT-Anweisung muss nicht unbedingt Tabellen verwenden. Das folgende Beispiel definiert eine View, die zwei Spalten aus einer anderen Tabelle und darüber hinaus einen aus diesen beiden Spalten berechneten Ausdruck abfragt:

mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty  | price | value |
+------+-------+-------+
|    3 |    50 |   150 |
+------+-------+-------+

Für die Definition einer View gelten folgende Beschränkungen:

  • Die SELECT-Anweisung darf in der FROM-Klausel keine Unterabfrage enthalten.

  • Die SELECT-Anweisung darf keine System- oder Benutzervariablen verwenden.

  • Die SELECT-Anweisung darf keine Parameter enthalten, die vorbereitete Anweisungen sind.

  • Innerhalb einer gespeicherten Routine darf die Definition keine Routinenparameter oder lokalen Variablen referenzieren.

  • Eine Tabelle oder View, die in der Definition angegeben wird, muss auch vorhanden sein. Nach der Erzeugung der View kann allerdings eine Tabelle oder View, die in der Definition angesprochen wird, gelöscht werden. Um eine View-Definition auf derartige Probleme hin zu untersuchen, verwenden Sie die CHECK TABLE-Anweisung.

  • Die Definition darf weder eine TEMPORARY-Tabelle referenzieren noch eine TEMPORARY-View erzeugen.

  • Die in der View-Definition verwendeten Tabellen müssen vorhanden sein.

  • Sie dürfen mit einer View keinen Trigger verbinden.

Eine ORDER BY-Klausel in einer View-Definition ist zwar erlaubt, wird aber ignoriert, wenn Sie eine View mit einer SELECT-Anweisung abfragen, die eine eigene ORDER BY-Klausel hat.

Die sonstigen Optionen oder Klauseln in der Definition werden den Optionen und Klauseln der Anweisung hinzugefügt, welche die View referenziert, allerdings mit undefiniertem Ergebnis. Wenn beispielsweise eine View-Definition eine LIMIT-Klausel enthält und Sie diese View mit einer Anweisung abfragen, die ihre eigene LIMIT-Klausel hat, ist nicht definiert, welche der beiden Klauseln gilt. Dasselbe gilt für Optionen wie ALL, DISTINCT oder SQL_SMALL_RESULT, die auf das Schlüsselwort SELECT folgen, sowie für Klauseln wie INTO, FOR UPDATE, LOCK IN SHARE MODE und PROCEDURE.

Wenn Sie eine View anlegen und dann die Verarbeitungsumgebung für Anfragen ändern, indem Sie Systemvariablen umstellen, kann sich dies auf die Ergebnisse der View auswirken:

mysql> CREATE VIEW v AS SELECT CHARSET(CHAR(65)), COLLATION(CHAR(65));
Query OK, 0 rows affected (0.00 sec)

mysql> SET NAMES 'latin1';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM v;
+-------------------+---------------------+
| CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
+-------------------+---------------------+
| latin1            | latin1_swedish_ci   |
+-------------------+---------------------+
1 row in set (0.00 sec)

mysql> SET NAMES 'utf8';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM v;
+-------------------+---------------------+
| CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
+-------------------+---------------------+
| utf8              | utf8_general_ci     |
+-------------------+---------------------+
1 row in set (0.00 sec)

Die DEFINER- und die SQL SECURITY-Klausel geben an, in welchem Sicherheitskontext die Zugriffsberechtigungen zum Zeitpunkt des Aufrufs der View geprüft werden. Diese Klauseln kamen in MySQL 5.1.2 neu hinzu.

CURRENT_USER kann auch als CURRENT_USER() angegeben werden.

In einer gespeicherten Routine, die mit dem Merkmal SQL SECURITY DEFINER definiert ist, gibt CURRENT_USER den Erzeuger der Routine zurück. Dies wirkt sich auch auf eine innerhalb einer solchen Routine definierte View aus, wenn in der View-Definition der DEFINER als CURRENT_USER angegeben ist.

Nach Voreinstellung ist der DEFINER der Benutzer, der die CREATE VIEW-Anweisung ausführt. (Dies ist dasselbe wie DEFINER = CURRENT_USER.) Wird ein user-Wert angegeben, dann als MySQL-Konto im Format 'user_name'@'host_name' (dasselbe Format, das auch in der GRANT-Anweisung verwendet wird. Die Werte user_name und host_name sind beide erforderlich.

Wenn Sie die DEFINER-Klausel angeben, können Sie keinen anderen Benutzer als sich selbst einsetzen, sofern Sie nicht über das SUPER-Recht verfügen. Die folgenden Regeln legen fest, welche Werte für DEFINER zulässig sind:

  • Wenn Sie nicht das SUPER-Recht haben, ist der einzig zulässige Wert für user Ihr eigenes Konto, das Sie entweder wörtlich oder mit CURRENT_USER angeben können. Auf ein anderes Konto dürfen Sie den DEFINER nicht einstellen.

  • Wenn Sie über das SUPER-Recht verfügen, dürfen Sie jeden Kontonamen angeben, wenn er nur syntaktisch korrekt ist. Sollte das angegebene Konto nicht existieren, wird eine Warnung ausgegeben.

Mit dem Merkmal SQL SECURITY wird festgelegt, welches MySQL-Konto zur Prüfung von Zugriffsberechtigungen für die View herangezogen wird, wenn diese ausgeführt wird. Hier ist das Merkmal DEFINER oder INVOKER zulässig, um anzuzeigen, dass die View von ihrem Erzeuger oder ihrem Aufrufer ausgeführt werden darf. Der Standardwert für SQL SECURITY ist DEFINER.

Seit MySQL 5.1.2 (der Version, in der die Klauseln DEFINER und SQL SECURITY erstmals implementiert waren) werden die Berechtigungen für Views folgendermaßen geprüft:

  • Zum Definitionszeitpunkt einer View benötigt ihr Erzeuger die Berechtigungen zum Zugriff auf die von seiner View benutzten Objekte der obersten Ebene. Wenn in der Definition einer View beispielsweise eine gespeicherte Funktion angesprochen wird, können nur die Berechtigungen zum Aufruf dieser Funktion geprüft werden. Die Berechtigungen, die erforderlich sind, wenn die Funktion läuft, können erst bei ihrer Ausführung geprüft werden: Für unterschiedliche Aufrufe der Funktion können unterschiedliche Ausführungspfade in ihr eingeschlagen werden.

  • Bei der Ausführung der View werden die Berechtigungen für die von ihr benutzten Objekte mit den Berechtigungen ihres Erzeugers oder Aufrufers verglichen, je nachdem, ob das Merkmal SQL SECURITY als DEFINER oder INVOKER angegeben ist.

  • Wenn die Ausführung einer View die Ausführung einer gespeicherten Funktion verursacht, werden die Berechtigungen für Anweisungen im Rahmen dieser Funktion je nachdem überprüft, ob die Funktion das SQL SECURITY-Merkmal DEFINER oder INVOKER hat. Ist das Sicherheitsmerkmal DEFINER, läuft die Funktion mit den Berechtigungen ihres Erzeugers; ist es INVOKER, läuft die Funktion mit den Berechtigungen, die durch das SQL SECURITY-Merkmal der View vorgegeben sind.

Vor MySQL 5.1.2 (also vor der Implementierung der DEFINER- und der SQL SECURITY-Klausel) wurden die Berechtigungen für die in einer View benutzten Objekte bei der Erzeugung dieser View geprüft.

Beispiel: Eine View könnte von einer gespeicherten Funktion abhängen, die ihrerseits andere gespeicherte Routinen aufruft. So ruft zum Beispiel die folgende View eine gespeicherte Funktion namens f() auf:

CREATE VIEW v AS SELECT * FROM t WHERE t.id = f(t.name);

Angenommen, f() enthält eine Anweisung wie diese:

IF name IS NULL then
  CALL p1();
ELSE
  CALL p2();
END IF;

Die Berechtigungen zur Ausführung von Anweisungen innerhalb von f() müssen geprüft werden, wenn f() ausgeführt wird. Dies könnte je nach dem Ausführungspfad für f() bedeuten, dass entweder die Berechtigungen für p1() oder die für p2() gebraucht werden. Diese Berechtigungen müssen zur Laufzeit geprüft werden, und der Benutzer, der sie besitzen muss, wird anhand des SQL SECURITY-Werts der Funktion f() und der View v bestimmt.

Die DEFINER- und die SQL SECURITY-Klausel für Views sind Erweiterungen des SQL-Standards. Im Standard-SQL werden Views nach den Regel für SQL SECURITY INVOKER behandelt.

Wenn Sie eine View aufrufen, die vor MySQL 5.0.13/5.1.2 erzeugt wurde, wird sie behandelt, als sei sie mit einer SQL SECURITY INVOKER-Klausel und Ihrem eigenen Konto als DEFINER angelegt worden. Da jedoch der tatsächliche Erzeuger unbekannt ist, gibt MySQL eine Warnung aus. Um die Warnung abzuschalten, genügt es, die View mit einer DEFINER-Klausel erneut zu definieren.

Die optionale ALGORITHM-Klausel ist ebenfalls eine MySQL-Erweiterung des Standard-SQL. ALGORITHM kann drei Werte annehmen: MERGE, TEMPTABLE oder UNDEFINED. Wenn keine ALGORITHM-Klausel angegeben wurde, ist der Standardalgorithmus UNDEFINED. Der Algorithmus nimmt Einfluss darauf, wie MySQL die View verarbeitet.

Ist MERGE der Algorithmus, wird der Text der Anweisung, in welcher die View benutzt wird, mit der View-Definition verschmolzen, sodass Teile der View-Definition die entsprechenden Teile der Anweisung ersetzen.

Wenn TEMPTABLE als Algorithmus eingestellt wurde, werden die Ergebnisse der View in eine temporäre Tabelle geladen, die dann zur Ausführung der Anweisung genutzt wird.

Ist der Algorithmus UNDEFINED, sucht sich MySQL den passenden Algorithmus selbst aus. Wo immer es möglich ist, wird MERGE gegenüber TEMPTABLE bevorzugt, da MERGE normalerweise effizienter ist und eine View bei Verwendung einer temporären Tabelle unveränderbar wird.

Ein Grund, explizit TEMPTABLE zu verlangen, wäre der, dass Sperren auf zugrunde liegenden Tabellen aufgehoben werden können, nachdem die temporäre Tabelle angelegt wurde und bevor sie benutzt wird, um die Verarbeitung der Anweisung abzuschließen. So könnte eine schnellere Freigabe der Sperre als mit dem MERGE-Algorithmus erreicht werden, um andere Clients, die die View benötigen, nicht so lange zu blockieren.

Es gibt drei Gründe, als View-Algorithmus UNDEFINED einzustellen:

  • Keine ALGORITHM-Klausel in der CREATE VIEW-Anweisung.

  • Die CREATE VIEW-Anweisung enthält eine explizite ALGORITHM = UNDEFINED-Klausel.

  • Für eine View, die nur mit einer temporären Tabelle verarbeitet werden kann, wurde ALGORITHM = MERGE angegeben. In diesem Fall generiert MySQL eine Warnung und stellt den Algorithmus auf UNDEFINED ein.

Wie bereits gesagt, werden durch den MERGE-Algorithmus die entsprechenden Teile einer View-Definition mit Teilen der die View referenzierenden Anweisung zusammengeführt. Die folgenden Beispiele sollen die Funktionsweise des MERGE-Algorithmus kurz verdeutlichen. Die Beispiele legen eine View namens v_merge zugrunde, die folgendermaßen definiert ist:

CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2) AS
SELECT c1, c2 FROM t WHERE c3 > 100;

Beispiel 1: Angenommen, wir geben folgende Anweisung:

SELECT * FROM v_merge;

MySQL würde diese Anweisung wie folgt bearbeiten:

  • v_merge wird t

  • * wird vc1, vc2, was c1, c2 entspricht.

  • Die WHERE-Klausel der View wird hinzugefügt.

Im Ergebnis wird folgende Anweisung ausgeführt:

SELECT c1, c2 FROM t WHERE c3 > 100;

Beispiel 2: Dieses Mal ist unsere Anweisung wie folgt:

SELECT * FROM v_merge WHERE vc1 < 100;

Diese Anweisung wird ähnlich wie die vorherige behandelt, nur dass hier vc1 < 100 zu c1 < 100 wird und die WHERE-Klausel der View der WHERE-Klausel der Anweisung mit einem AND hinzugefügt wird (und runde Klammern sicherstellen, dass die Teile der Klausel in der richtigen Reihenfolge ausgeführt werden). Infolgedessen wird folgende Anweisung ausgeführt:

SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);

Letztlich hat die Anweisung eine WHERE-Klausel in der folgenden Form:

WHERE (select WHERE) AND (view WHERE)

Der MERGE-Algorithmus erfordert eine Eins-zu-eins-Beziehung zwischen den Zeilen der View und den Zeilen der zugrunde liegenden Tabelle. Wenn diese Beziehung nicht gilt, muss stattdessen eine temporäre Tabelle benutzt werden. Die Eins-zu-eins-Beziehung fehlt, wenn die View eines der folgenden Konstrukte enthält:

  • Aggregatfunktionen (SUM(), MIN(), MAX(), COUNT() usw.)

  • DISTINCT

  • GROUP BY

  • HAVING

  • UNION oder UNION ALL

  • wenn die View nur Literalwerte verwendet (in diesem Fall gibt es gar keine zugrunde liegende Tabelle)

Manche Views sind veränderbar und können somit in Anweisungen wie UPDATE, DELETE oder INSERT genutzt werden, um die Inhalte der zugrunde liegenden Tabelle zu ändern. Damit eine View veränderbar ist, muss eine Eins-zu-eins-Beziehung zwischen den Zeilen der View und den Zeilen der zugrunde liegenden Tabelle existieren. Es gibt also eine Reihe von Konstrukten, durch die eine View nicht mehr veränderbar wird. Hierzu gehören folgende:

  • Aggregatfunktionen (SUM(), MIN(), MAX(), COUNT() usw.)

  • DISTINCT

  • GROUP BY

  • HAVING

  • UNION oder UNION ALL

  • eine Unterabfrage in der Select-Liste

  • Join

  • eine unveränderbare View in der FROM-Klausel

  • eine Unterabfrage in der WHERE-Klausel, die eine Tabelle in der FROM-Klausel referenziert.

  • wenn die View nur Literalwerte verwendet (in diesem Fall gibt es gar keine zugrunde liegende Tabelle)

  • ALGORITHM = TEMPTABLE (die Verwendung einer temporären Tabelle macht eine View immer unveränderbar)

Was Einfügungen betrifft (also die Veränderbarkeit mit INSERT-Anweisungen), so ist eine veränderbare View für Einfügungen nutzbar, wenn ihre Spalten zusätzlich folgende Anforderungen erfüllen:

  • Ein Spaltenname darf nicht mehrfach auftreten.

  • Die View muss alle Spalten der Basistabelle enthalten, die keinen Standardwert haben.

  • Die View-Spalten müssen einfache Spaltenreferenzen und keine abgeleiteten Spalten sein. Eine abgeleitete Spalte ist eine Spalte, die nicht einfach benannt werden kann, sondern von einem Ausdruck abgeleitet wird, wie in den folgenden Beispielen:

    3.14159
    col1 + 3
    UPPER(col2)
    col3 / col4
    (subquery)
    

Eine View mit einer Mischung von einfachen Spaltenreferenzen und abgeleiteten Spalten ist nicht für Einfügungen geeignet, kann aber veränderbar sein, wenn nur diejenigen Spalten geändert werden, die nicht abgeleitet sind. Betrachten Sie folgende View:

CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;

Diese col2 ist von einem Ausdruck abgeleitet. Sie ist jedoch veränderbar, wenn das Update nicht versucht, col2 zu verändern. Das folgende Update ist erlaubt:

UPDATE v SET col1 = 0;

Dagegen ist das nun folgende Update unzulässig, weil es versucht, eine abgeleitete Spalte zu ändern:

UPDATE v SET col2 = 0;

Manchmal kann eine View aus mehreren Tabellen veränderbar sein, sofern sie mit dem MERGE-Algorithmus verarbeitet wird. Damit das funktioniert, muss die View einen Inner Join verwenden (keinen Outer Join und keine UNION). Außerdem kann nur eine einzige Tabelle in der View-Definition verändert werden, sodass die SET-Klausel nur Spalten aus dieser einen Tabelle der View aufführen darf. Views, die UNION ALL verwenden, sind selbst dann nicht erlaubt, wenn sie theoretisch veränderbar wären, da die Implementierung für ihre Verarbeitung temporäre Tabellen einsetzt.

Bei einer veränderbaren View mit mehreren Tabellen kann auch INSERT funktionieren, sofern nur eine einzelne der Tabellen angesprochen wird. DELETE ist jedoch nicht möglich.

Die WITH CHECK OPTION-Klausel kann für eine veränderbare View benutzt werden, um Einfügungen oder Änderungen an Zeilen zu verhindern, für welche das select_statement in der WHERE-Klausel nicht gilt.

In einer WITH CHECK OPTION-Klausel einer veränderbaren View legen die Schlüsselwörter LOCAL und CASCADED den Rahmen der Überprüfungen fest, wenn die View auf Grundlage einer anderen View definiert wurde. Das Schlüsselwort LOCAL schränkt die CHECK OPTION auf die View ein, die gerade definiert wird, während CASCADED dafür sorgt, dass sich die Prüfungen auch auf die zugrunde liegenden Views erstrecken. Wenn keines der beiden Schlüsselwörter angegeben ist, ist CASCADED der Standard. Betrachten Sie folgende Definitionen für die nachfolgende Tabelle und die Views:

mysql> CREATE TABLE t1 (a INT);
mysql> CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2
    -> WITH CHECK OPTION;
mysql> CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0
    -> WITH LOCAL CHECK OPTION;
mysql> CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0
    -> WITH CASCADED CHECK OPTION;

Hier werden die Views v2 und v3 mit einer anderen View namens v1 definiert. Da v2 die Check-Option LOCAL hat, werden Einfügungen nur anhand der Vorgaben für v2 getestet, während die View v3 mit ihrer Prüfoption CASCADED für Einfügungen hier nicht nur die eigenen, sondern auch die Prüfoptionen der zugrunde liegenden Views berücksichtigen muss. Die folgende Anweisung veranschaulicht die Unterschiede:

mysql> INSERT INTO v2 VALUES (2);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO v3 VALUES (2);
ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'

Die Veränderbarkeit von Views wird durch die Systemvariable updatable_views_with_limit beeinflusst. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

21.3. DROP VIEW

DROP VIEW [IF EXISTS]
    view_name [, view_name] ...
    [RESTRICT | CASCADE]

DROP VIEW löscht eine oder mehrere Views. Hierfür benötigen Sie für jede View das DROP-Recht.

Die IF EXISTS-Klausel verhindert Fehler aufgrund nicht existierender Views. Wenn diese Klausel angegeben ist, wird für jede View, die nicht existiert, eine NOTE generiert. Siehe auch Abschnitt 13.5.4.25, „SHOW WARNINGS.

RESTRICT und CASCADE werden zwar geparst, aber nicht beachtet.

21.4. SHOW CREATE VIEW

SHOW CREATE VIEW view_name

Mit der folgenden CREATE VIEW-Anweisung wird die gegebene View erzeugt.

mysql> SHOW CREATE VIEW v;
+------+----------------------------------------------------+
| View | Create View                                        |
+------+----------------------------------------------------+
| v    | CREATE VIEW `test`.`v` AS select 1 AS `a`,2 AS `b` |
+------+----------------------------------------------------+

Informationen über View-Objekte erhalten Sie auch über ihr INFORMATION_SCHEMA, das eine VIEWS-Tabelle enthält. Siehe Abschnitt 22.15, „Die Tabelle INFORMATION_SCHEMA VIEWS.

Kapitel 22. Die Datenbank INFORMATION_SCHEMA

INFORMATION_SCHEMA gibt Zugriff auf Datenbank-Metadaten.

Metadaten sind Informationen über Daten, also beispielsweise der Name einer Datenbank oder Tabelle, der Datentyp einer Spalte, oder Zugriffsberechtigungen. Manchmal werden diese Informationen auch als Data Dictionary oder Systemkatalog bezeichnet.

INFORMATION_SCHEMA ist die Informationsdatenbank, also der Ort, an dem Informationen über alle anderen auf dem betreffenden MySQL Server gepflegten Datenbanken gespeichert werden. Im INFORMATION_SCHEMA gibt es eine Reihe von schreibgeschützten Tabellen. Da diese in Wirklichkeit keine Basistabellen, sondern Views sind, werden Sie keine Dateien sehen, die mit ihnen verbunden sind.

Ein Beispiel:

mysql> SELECT table_name, table_type, engine
    -> FROM information_schema.tables
    -> WHERE table_schema = 'db5'
    -> ORDER BY table_name DESC;
+------------+------------+--------+
| table_name | table_type | engine |
+------------+------------+--------+
| v56        | VIEW       | NULL   |
| v3         | VIEW       | NULL   |
| v2         | VIEW       | NULL   |
| v          | VIEW       | NULL   |
| tables     | BASE TABLE | MyISAM |
| t7         | BASE TABLE | MyISAM |
| t3         | BASE TABLE | MyISAM |
| t2         | BASE TABLE | MyISAM |
| t          | BASE TABLE | MyISAM |
| pk         | BASE TABLE | InnoDB |
| loop       | BASE TABLE | MyISAM |
| kurs       | BASE TABLE | MyISAM |
| k          | BASE TABLE | MyISAM |
| into       | BASE TABLE | MyISAM |
| goto       | BASE TABLE | MyISAM |
| fk2        | BASE TABLE | InnoDB |
| fk         | BASE TABLE | InnoDB |
+------------+------------+--------+
17 rows in set (0.01 sec)

Erklärung: Die Anweisung verlangt eine Liste aller Tabellen der Datenbank db5 in umgekehrter alphabetischer Reihenfolge, wobei jeweils nur drei Informationen angezeigt werden sollen: der Name der Tabelle, ihr Typ und ihre Speicher-Engine.

Jeder MySQL-Benutzer hat das Recht, auf diese Tabellen zuzugreifen, allerdings nur auf diejenigen Tabellenzeilen, die sich auf Objekte beziehen, für welche er die richtigen Zugriffsberechtigungen hat.

Die Anweisung SELECT ... FROM INFORMATION_SCHEMA ist als ein konsistenteres Mittel gedacht, Zugriff auf die Informationen zu gewähren, welche die verschiedenen von MySQL unterstützten SHOW-Anweisungen geben (SHOW DATABASES, SHOW TABLES usw.). Die Verwendung von SELECT hat im Vergleich zu SHOW folgende Vorteile:

  • Sie entspricht den Codd'schen Regeln: Jeglicher Zugriff geht auf Tabellen.

  • Niemand muss eine neue Anweisungssyntax lernen. Da jeder bereits weiß, wie SELECT funktioniert, müssen lediglich die Objektnamen gelernt werden.

  • Der Implementierer muss sich nicht um Schlüsselwörter Gedanken machen.

  • Es sind Millionen Varianten für die Ausgabe möglich, nicht nur eine. So erhält man mehr Flexibilität für Anwendungen, die immer wieder andere Metadaten benötigen.

  • Die Migration ist einfacher, da auch alle anderen DBMS so arbeiten.

Da jedoch SHOW bei den Angestellten und Nutzern von MySQL so beliebt ist und eine Abschaffung dieser Anweisung Verwirrung stiften könnte, genügen die Vorteile der konventionellen Syntax nicht als Grund, auf SHOW ganz zu verzichten. Stattdessen gibt es sogar Verbesserungen an SHOW in MySQL 5.1. Diese werden in Abschnitt 22.22, „Erweiterungen der SHOW-Anweisungen“, genauer beschrieben.

Es gibt keinen Unterschied zwischen den Berechtigungen, die für SHOW-Anweisungen erforderlich sind, und jenen, die zur Datenabfrage aus dem INFORMATION_SCHEMA benötigt werden. In beiden Fällen müssen Sie irgendeine Berechtigung für ein Objekt besitzen, um Informationen über es anzeigen zu lassen.

Die Implementierung der INFORMATION_SCHEMA-Tabellenstrukturen in MySQL entspricht dem ANSI/ISO SQL:2003-Standard Teil 11 Schemata. Unser Ziel ist es, möglichst weitgehend dem SQL:2003-Core-Feature F021 Basic information schema zu entsprechen.

Benutzer von SQL Server 2000 (auch dieses System befolgt den Standard) werden vielleicht starke Ähnlichkeiten bemerken. Allerdings hat MySQL viele Spalten weggelassen, die für unsere Implementierung keine Rolle spielen, und stattdessen andere, MySQL-spezifische Spalten hinzugefügt. Dazu gehört die Spalte ENGINE in der Tabelle INFORMATION_SCHEMA.TABLES.

Zwar verwenden die anderen DBMS unterschiedliche Namen, wie etwa syscat oder system, aber der Standardname lautet INFORMATION_SCHEMA.

Letztlich haben wir eine Datenbank namens INFORMATION_SCHEMA vor uns, auch wenn der Server kein Datenbankverzeichnis hierfür anlegt. Es ist möglich, INFORMATION_SCHEMA mit einer USE-Anweisung als Standarddatenbank einzustellen, allerdings können die Tabelleninhalte nur gelesen werden. Einfügungen, Änderungen oder Löschungen in den Tabellen sind ausgeschlossen.

Die folgenden Abschnitte beschreiben die Tabellen und Spalten von INFORMATION_SCHEMA. Zu jeder Spalte gibt es drei Informationen:

  • Der „Standard Name“ gibt den SQL-Standardnamen der Spalte an.

  • SHOW name“ ist der entsprechende Feldname in der nächstgelegenen SHOW-Anweisung (sofern vorhanden).

  • Remarks“ sind eventuelle Zusatzinformationen. Wenn dieses Feld den Wert NULL hat, bedeutet dies, dass der Wert der Spalte immer NULL lautet.

Um keine Namen zu verwenden, die im Standard oder in DB2, SQL Server oder Oracle reserviert sind, haben wir die Namen der als „MySQL extension“ markierten Spalten geändert. (So wurde beispielsweise in der Tabelle TABLES aus COLLATION eine TABLE_COLLATION.) Siehe auch die Liste der reservierten Wörter am Ende dieses Artikels: http://www.dbazine.com/gulutzan5.shtml.

Die Definition für Zeichenspalten (beispielsweise TABLES.TABLE_NAME) ist im Allgemeinen VARCHAR(N) CHARACTER SET utf8, wobei N mindestens 64 ist.

Jeder Abschnitt gibt an, welche SHOW-Anweisung einer SELECT-Anweisung entspricht, die Informationen aus dem INFORMATION_SCHEMA abfragt, sofern eine solche Anweisung existiert.

Hinweis: Zurzeit fehlen noch einige Spalten und andere stehen in der verkehrten Reihenfolge. Wir arbeiten daran und werden die Dokumentation bei Änderungen aktualisieren.

22.1. Die Tabelle INFORMATION_SCHEMA SCHEMATA

Da ein Schema eine Datenbank ist, liefert die Tabelle SCHEMATA Informationen über Datenbanken.

Standard NameSHOW nameRemarks
CATALOG_NAME-NULL
SCHEMA_NAME Database
DEFAULT_CHARACTER_SET_NAME  
DEFAULT_COLLATION_NAME  
SQL_PATH NULL

Die folgenden Anweisungen sind äquivalent:

SELECT SCHEMA_NAME AS `Database`
  FROM INFORMATION_SCHEMA.SCHEMATA
  [WHERE SCHEMA_NAME LIKE 'wild']

SHOW DATABASES
  [LIKE 'wild']

22.2. Die Tabelle INFORMATION_SCHEMA TABLES

Die Tabelle TABLES informiert über die Tabellen in der Datenbank.

Standard NameSHOW nameRemarks
TABLE_CATALOG NULL
TABLE_SCHEMATable_... 
TABLE_NAMETable_... 
TABLE_TYPE  
ENGINEEngineMySQL extension
VERSIONVersionMySQL extension
ROW_FORMATRow_formatMySQL extension
TABLE_ROWSRowsMySQL extension
AVG_ROW_LENGTHAvg_row_lengthMySQL extension
DATA_LENGTHData_lengthMySQL extension
MAX_DATA_LENGTHMax_data_lengthMySQL extension
INDEX_LENGTHIndex_lengthMySQL extension
DATA_FREEData_freeMySQL extension
AUTO_INCREMENTAuto_incrementMySQL extension
CREATE_TIMECreate_timeMySQL extension
UPDATE_TIMEUpdate_timeMySQL extension
CHECK_TIMECheck_timeMySQL extension
TABLE_COLLATIONCollationMySQL extension
CHECKSUMChecksumMySQL extension
CREATE_OPTIONSCreate_optionsMySQL extension
TABLE_COMMENTCommentMySQL extension

Hinweise:

  • TABLE_SCHEMA und TABLE_NAME sind in einer SHOW-Anzeige ein einziges Feld, beispielsweise Table_in_db1.

  • Der TABLE_TYPE sollte BASE TABLE oder VIEW sein. Wenn die Tabelle eine temporäre ist, ist TABLE_TYPE = TEMPORARY. (Da es keine temporären Views gibt, ist dies eindeutig.)

  • Die Spalte TABLE_ROWS ist NULL, wenn die Tabelle in der INFORMATION_SCHEMA-Datenbank vorliegt. Bei InnoDB-Tabellen ist die Zeilenzahl nur eine ungefähre Schätzung, die für die SQL-Optimierung benötigt wird.

  • Es ist kein Standardzeichensatz der Tabelle vorgegeben, doch TABLE_COLLATION kommt einem Standardzeichensatz nahe, da die Namen von Kollationen mit dem Namen eines Zeichensatzes anfangen.

Die folgenden Anweisungen sind äquivalent:

SELECT table_name FROM INFORMATION_SCHEMA.TABLES
  [WHERE table_schema = 'db_name']
  [WHERE|AND table_name LIKE 'wild']

SHOW TABLES
  [FROM db_name]
  [LIKE 'wild']

22.3. Die Tabelle INFORMATION_SCHEMA COLUMNS

Die Tabelle COLUMNS informiert über die Spalten der Tabellen.

Standard NameSHOW nameRemarks
TABLE_CATALOG NULL
TABLE_SCHEMA  
TABLE_NAME  
COLUMN_NAMEField 
ORDINAL_POSITION see notes
COLUMN_DEFAULTDefault 
IS_NULLABLENull 
DATA_TYPEType 
CHARACTER_MAXIMUM_LENGTHType 
CHARACTER_OCTET_LENGTH  
NUMERIC_PRECISIONType 
NUMERIC_SCALEType 
CHARACTER_SET_NAME  
COLLATION_NAMECollation 
COLUMN_TYPETypeMySQL extension
COLUMN_KEYKeyMySQL extension
EXTRAExtraMySQL extension
COLUMN_COMMENTCommentMySQL extension

Hinweise:

  • In der SHOW-Anweisung werden unter Type Werte von mehreren verschiedenen COLUMNS-Spalten wiedergegeben.

  • ORDINAL_POSITION is notwendig, da Sie vielleicht eines Tages ORDER BY ORDINAL_POSITION verwenden werden. Im Gegensatz zu SHOW verwendet ein SELECT keine automatische Reihenfolge.

  • CHARACTER_OCTET_LENGTH sollte gleich CHARACTER_MAXIMUM_LENGTH sein, außer bei Multibytezeichensätzen.

  • CHARACTER_SET_NAME kann von Collation abgeleitet werden. Wenn Sie beispielsweise SHOW FULL COLUMNS FROM t verlangen und in der Collation-Spalte den Wert latin1_swedish_ci entdecken, ist der Zeichensatz das, was vor dem ersten Unterstrich steht: latin1.

Die folgenden Anweisungen sind nahezu äquivalent:

SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE table_name = 'tbl_name'
  [AND table_schema = 'db_name']
  [AND column_name LIKE 'wild']

SHOW COLUMNS
  FROM tbl_name
  [FROM db_name]
  [LIKE 'wild']

22.4. Die Tabelle INFORMATION_SCHEMA STATISTICS

Die STATISTICS-Tabelle liefert Ihnen Informationen über Tabellenindizes.

Standard NameSHOW nameRemarks
TABLE_CATALOG NULL
TABLE_SCHEMA = Database
TABLE_NAMETable 
NON_UNIQUENon_unique 
INDEX_SCHEMA = Database
INDEX_NAMEKey_name 
SEQ_IN_INDEXSeq_in_index 
COLUMN_NAMEColumn_name 
COLLATIONCollation 
CARDINALITYCardinality 
SUB_PARTSub_partMySQL extension
PACKEDPackedMySQL extension
NULLABLENullMySQL extension
INDEX_TYPEIndex_typeMySQL extension
COMMENTCommentMySQL extension

Hinweise:

  • Eine Standardtabelle für Indizes gibt es nicht. Die obige Liste entspricht dem, was SQL Server 2000 als sp_statistics zurückliefert, nur dass wir den Namen QUALIFIER durch CATALOG und OWNER durch SCHEMA ersetzt haben.

    Es ist offensichtlich, dass die obige Tabelle und die Ausgabe von SHOW INDEX dieselbe Abstammung haben. Daher besteht bereits eine enge Korrelation.

Die folgenden Anweisungen sind äquivalent:

SELECT * FROM INFORMATION_SCHEMA.STATISTICS
  WHERE table_name = 'tbl_name'
  [AND table_schema = 'db_name']

SHOW INDEX
  FROM tbl_name
  [FROM db_name]

22.5. Die Tabelle INFORMATION_SCHEMA USER_PRIVILEGES

Die Tabelle USER_PRIVILEGES informiert über globale Berechtigungen. Diese Information stammt aus der Berechtigungstabelle mysql.user.

Standard NameSHOW nameRemarks
GRANTEE 'user_name'@'host_name' value
TABLE_CATALOG NULL
PRIVILEGE_TYPE  
IS_GRANTABLE  

Hinweis:

  • Dies ist keine Standardtabelle. Sie entnimmt ihre Werte der Tabelle mysql.user.

22.6. Die Tabelle INFORMATION_SCHEMA SCHEMA_PRIVILEGES

Die Tabelle SCHEMA_PRIVILEGES liefert Informationen über Schema-(Datenbank-)Berechtigungen. Diese Informationen stammen aus der Berechtigungstabelle mysql.db.

Standard NameSHOW nameRemarks
GRANTEE 'user_name'@'host_name' value
TABLE_CATALOG NULL
TABLE_SCHEMA  
PRIVILEGE_TYPE  
IS_GRANTABLE  

Hinweis:

  • Dies ist ebenfalls keine Standardtabelle. Ihre Werte erhält sie aus der Tabelle mysql.db.

22.7. Die Tabelle INFORMATION_SCHEMA TABLE_PRIVILEGES

Die Tabelle TABLE_PRIVILEGES liefert Informationen über Tabellenberechtigungen. Diese Informationen stammen aus der Berechtigungstabelle mysql.tables_priv.

Standard NameSHOW nameRemarks
GRANTEE 'user_name'@'host_name' value
TABLE_CATALOG NULL
TABLE_SCHEMA  
TABLE_NAME  
PRIVILEGE_TYPE  
IS_GRANTABLE  

Die folgenden Anweisungen sind nicht äquivalent:

SELECT ... FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES

SHOW GRANTS ...

Der PRIVILEGE_TYPE kann einen (und nur einen) der folgenden Werte annehmen: SELECT, INSERT, UPDATE, REFERENCES, ALTER, INDEX, DROP, CREATE VIEW.

22.8. Die Tabelle INFORMATION_SCHEMA COLUMN_PRIVILEGES

Die COLUMN_PRIVILEGES-Tabelle liefert Informationen über Spaltenberechtigungen. Diese Informationen entstammen der Berechtigungstabelle mysql.columns_priv.

Standard NameSHOW nameRemarks
GRANTEE 'user_name'@'host_name' value
TABLE_CATALOG NULL
TABLE_SCHEMA  
TABLE_NAME  
COLUMN_NAME  
PRIVILEGE_TYPE  
IS_GRANTABLE  

Hinweise:

  • SHOW FULL COLUMNS gibt alle Berechtigungen in einem einzigen Feld und kleingeschrieben aus, beispielsweise als select,insert,update,references. In COLUMN_PRIVILEGES steht nur eine einzige großgeschriebene Berechtigung pro Zeile.

  • PRIVILEGE_TYPE kann einen (und nur einen) der folgenden Werte haben: SELECT, INSERT, UPDATE, REFERENCES.

  • Wenn der Benutzer das GRANT OPTION-Recht hat, sollte IS_GRANTABLE den Wert YES haben, andernfalls NO. In der Ausgabe ist GRANT OPTION nicht als separate Berechtigung aufgeführt.

Die folgenden Anweisungen sind nicht äquivalent:

SELECT ... FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES

SHOW GRANTS ...

22.9. Die Tabelle INFORMATION_SCHEMA CHARACTER_SETS

Die CHARACTER_SETS-Tabelle gibt Informationen über die verfügbaren Zeichensätze.

Standard NameSHOW nameRemarks
CHARACTER_SET_NAMECharset 
DEFAULT_COLLATE_NAMEDefault collation 
DESCRIPIONDescriptionMySQL extension
MAXLENMaxlenMySQL extension

Hinweis:

  • Wir haben der Ausgabe von SHOW CHARACTER SET zwei Spalten hinzugefügt, die nicht zum Standard gehören, nämlich Description und Maxlen.

Die folgenden Anweisungen sind äquivalent:

SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
  [WHERE name LIKE 'wild']

SHOW CHARACTER SET
  [LIKE 'wild']

22.10. Die Tabelle INFORMATION_SCHEMA COLLATIONS

Die COLLATIONS-Tabelle informiert über die Kollationen der jeweiligen Zeichensätze.

Standard NameSHOW nameRemarks
COLLATION_NAMECollation 

Hinweis:

  • Wir haben in der Ausgabe von SHOW COLLATION fünf nicht zum Standard gehörende Spalten hinzugefügt, nämlich Charset, Id, Default, Compiled und Sortlen.

Die folgenden Anweisungen sind äquivalent:

SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLLATIONS
  [WHERE collation_name LIKE 'wild']

SHOW COLLATION
  [LIKE 'wild']

22.11. Die Tabelle INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY

Die COLLATION_CHARACTER_SET_APPLICABILITY-Tabelle zeigt an, welcher Zeichensatz für welche Kollation gilt. Die Spalten sind äquivalent zu den ersten beiden Feldern, die SHOW COLLATION anzeigt.

Standard NameSHOW nameRemarks
COLLATION_NAMECollation 
CHARACTER_SET_NAMECharset 

22.12. Die Tabelle INFORMATION_SCHEMA TABLE_CONSTRAINTS

Die TABLE_CONSTRAINTS-Tabelle zeigt an, welche Tabellen Constraints unterliegen.

Standard NameSHOW nameRemarks
CONSTRAINT_CATALOG NULL
CONSTRAINT_SCHEMA  
CONSTRAINT_NAME  
TABLE_SCHEMA  
TABLE_NAME  
CONSTRAINT_TYPE  

Hinweise:

  • Der Wert von CONSTRAINT_TYPE kann UNIQUE, PRIMARY KEY oder FOREIGN KEY sein.

  • Die Informationen über UNIQUE und PRIMARY KEY gleichen ungefähr dem, was SHOW INDEX im Feld Key_name ausgibt, wenn das Feld Non_unique den Wert 0 hat.

  • Die Spalte CONSTRAINT_TYPE kann einen der folgenden Werte enthalten: UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK. Sie ist eine CHAR-Spalte (keine ENUM-Spalte). Der CHECK-Wert wird erst zur Verfügung stehen, wenn wir CHECK unterstützen.

22.13. Die Tabelle INFORMATION_SCHEMA KEY_COLUMN_USAGE

Die KEY_COLUMN_USAGE-Tabelle beschreibt, welche Schlüsselspalten Constraints haben.

Standard NameSHOW nameRemarks
CONSTRAINT_CATALOG NULL
CONSTRAINT_SCHEMA  
CONSTRAINT_NAME  
TABLE_CATALOG  
TABLE_SCHEMA  
TABLE_NAME  
COLUMN_NAME  
ORDINAL_POSITION  
POSITION_IN_UNIQUE_CONSTRAINT  
REFERENCED_TABLE_SCHEMA  
REFERENCED_TABLE_NAME  
REFERENCED_COLUMN_NAME  

Hinweise:

  • Ist der Constraint ein Fremdschlüssel, so ist dies die Spalte des Fremdschlüssels und nicht die Spalte, auf die er verweist.

  • Der Wert von ORDINAL_POSITION gibt die Position der Spalte im Constraint und nicht in der Tabelle wieder. Die Spaltenpositionen werden beginnend mit 1 durchnummeriert.

  • Der Wert von POSITION_IN_UNIQUE_CONSTRAINT ist NULL für Unique- und Fremdschlüssel-Constraints. Bei Fremdschlüssel-Constraints ist es die Ordinalposition im Schlüssel der referenzierten Tabelle.

    Nehmen wir beispielsweise an, wir hätten zwei Tabellen namens t1 und t3, die wie folgt definiert sind:

    CREATE TABLE t1
    (
        s1 INT,
        s2 INT,
        s3 INT,
        PRIMARY KEY(s3)
    ) ENGINE=InnoDB;
    
    CREATE TABLE t3
    (
        s1 INT,
        s2 INT,
        s3 INT,
        KEY(s1),
        CONSTRAINT CO FOREIGN KEY (s2) REFERENCES t1(s3)
    ) ENGINE=InnoDB;
    

    Für diese beiden Tabellen hat die Tabelle KEY_COLUMN_USAGE zwei Zeilen:

    • eine Zeile mit CONSTRAINT_NAME = 'PRIMARY', TABLE_NAME = 't1', COLUMN_NAME = 's3', ORDINAL_POSITION = 1, POSITION_IN_UNIQUE_CONSTRAINT = NULL

    • eine Zeile mit CONSTRAINT_NAME = 'CO', TABLE_NAME = 't3', COLUMN_NAME = 's2', ORDINAL_POSITION = 1, POSITION_IN_UNIQUE_CONSTRAINT = 1

22.14. Die Tabelle INFORMATION_SCHEMA ROUTINES

Die ROUTINES-Tabelle informiert über gespeicherte Routinen (sowohl Prozeduren als auch Funktionen). Die ROUTINES-Tabelle enthält zurzeit keine benutzerdefinierten Funktionen (UDFs).

Die Spalte „mysql.proc name“ gibt die mysql.proc-Tabellenspalte an, die der INFORMATION_SCHEMA.ROUTINES-Tabellenspalte entspricht (sofern vorhanden).

Standard Namemysql.proc nameRemarks
SPECIFIC_NAMEspecific_name 
ROUTINE_CATALOG NULL
ROUTINE_SCHEMAdb 
ROUTINE_NAMEname 
ROUTINE_TYPEtype{PROCEDURE|FUNCTION}
DTD_IDENTIFIER (data type descriptor)
ROUTINE_BODY SQL
ROUTINE_DEFINITIONbody 
EXTERNAL_NAME NULL
EXTERNAL_LANGUAGElanguageNULL
PARAMETER_STYLE SQL
IS_DETERMINISTICis_deterministic 
SQL_DATA_ACCESSsql_data_access 
SQL_PATH NULL
SECURITY_TYPEsecurity_type 
CREATEDcreated 
LAST_ALTEREDmodified 
SQL_MODEsql_modeMySQL extension
ROUTINE_COMMENTcommentMySQL extension
DEFINERdefinerMySQL extension

Hinweise:

  • MySQL berechnet die EXTERNAL_LANGUAGE wie folgt:

    • Wenn mysql.proc.language='SQL', so hat EXTERNAL_LANGUAGE den Wert NULL.

    • Ansonsten ist EXTERNAL_LANGUAGE das, was in mysql.proc.language aufgeführt ist. Da wir jedoch noch keine externen Sprachen eingerichtet haben, ist dies immer NULL.

22.15. Die Tabelle INFORMATION_SCHEMA VIEWS

Die VIEWS-Tabelle informiert über Views in Datenbanken. Für den Zugriff auf diese Tabelle ist die SHOW VIEW-Berechtigung nötig.

Standard NameSHOW nameRemarks
TABLE_CATALOG NULL
TABLE_SCHEMA  
TABLE_NAME  
VIEW_DEFINITION  
CHECK_OPTION  
IS_UPDATABLE  
DEFINER  
SECURITY_TYPE  

Hinweise:

  • Die Spalte VIEW_DEFINITION enthält im Wesentlichen das, was auch SHOW CREATE VIEW im Feld Create Table anzeigt. Übergehen Sie die Wörter vor dem SELECT und hinter WITH CHECK OPTION. Angenommen, die Anweisung lautete ursprünglich:

    CREATE VIEW v AS
      SELECT s2,s1 FROM t
      WHERE s1 > 5
      ORDER BY s1
      WITH CHECK OPTION;
    

    Dann sieht die View-Definition folgendermaßen aus:

    SELECT s2,s1 FROM t WHERE s1 > 5 ORDER BY s1
    
  • Die Spalte CHECK_OPTION hat immer den Wert NONE.

  • Die Spalte IS_UPDATABLE ist bei veränderbaren Views YES und bei unveränderbaren NO.

  • Die Spalte DEFINER gibt an, wer die View angelegt hat. SECURITY_TYPE hat den Wert DEFINER oder INVOKER.

22.16. Die Tabelle INFORMATION_SCHEMA TRIGGERS

Die TRIGGERS-Tabelle informiert über Trigger. Zugriff bekommt nur, wer die SUPER-Berechtigung vorweisen kann.

Standard NameSHOW nameRemarks
TRIGGER_CATALOG NULL
TRIGGER_SCHEMA  
TRIGGER_NAMETrigger 
EVENT_MANIPULATIONEvent 
EVENT_OBJECT_CATALOG NULL
EVENT_OBJECT_SCHEMA  
EVENT_OBJECT_TABLETable 
ACTION_ORDER 0
ACTION_CONDITION NULL
ACTION_STATEMENTStatement 
ACTION_ORIENTATION ROW
ACTION_TIMINGTiming 
ACTION_REFERENCE_OLD_TABLE NULL
ACTION_REFERENCE_NEW_TABLE NULL
ACTION_REFERENCE_OLD_ROW OLD
ACTION_REFERENCE_NEW_ROW NEW
CREATED NULL (0)
SQL_MODE  
DEFINER  

Hinweise:

  • Die Spalten TRIGGER_SCHEMA und TRIGGER_NAME zeigen den Namen der Datenbank an, in welcher der Trigger auftritt, und den Namen des Triggers.

  • Die Spalte EVENT_MANIPULATION hat entweder den Wert 'INSERT', 'DELETE' oder 'UPDATE'.

  • Wie in Kapitel 20, Trigger, bereits gesagt, ist jeder Trigger mit genau einer Tabelle verbunden. Die Spalte EVENT_OBJECT_SCHEMA zeigt die Datenbank an, zu der die Tabelle gehört, und EVENT_OBJECT_TABLE enthält den Namen der Tabelle.

  • Die Anweisung ACTION_ORDER zeigt an, an welcher Ordinalposition die Aktion des Triggers in der Liste aller ähnlichen Trigger auf derselben Tabelle steht. Dieser Wert ist gegenwärtig immer 0, da auf einer Tabelle nicht mehr als ein Trigger mit derselben EVENT_MANIPULATION und demselben ACTION_TIMING zulässig ist.

  • Die Spalte ACTION_STATEMENT enthält die Anweisung, die bei Aufruf des Triggers ausgeführt wird. Dies ist dasselbe wie der Text in der Statement-Spalte der Ausgabe von SHOW TRIGGERS. Beachten Sie, dass dieser Text UTF-8-kodiert ist.

  • Die Spalte ACTION_ORIENTATION enthält immer den Wert 'ROW'.

  • Die Spalte ACTION_TIMING enthält entweder den Wert 'BEFORE' oder 'AFTER'.

  • Die Spalten ACTION_REFERENCE_OLD_ROW und ACTION_REFERENCE_NEW_ROW enthalten den alten und den neuen Spaltenbezeichner. Dies bedeutet, dass ACTION_REFERENCE_OLD_ROW immer den Wert 'OLD' und ACTION_REFERENCE_NEW_ROW immer den Wert 'NEW' hat.

  • Die Spalte SQL_MODE zeigt, welcher SQL-Servermodus bei der Erstellung des Triggers in Kraft war (und somit auch für jeden Aufruf dieses Triggers in Kraft bleibt, egal welcher SQL-Servermodus gerade eingestellt sein mag). Diese Spalte hat denselben Wertebereich wie die Systemvariable sql_mode. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  • Die Spalte DEFINER kam in MySQL 5.1.2 neu hinzu. Der DEFINER ist der, der den Trigger definiert hat.

  • Die folgenden Spalten haben immer den Wert NULL: TRIGGER_CATALOG, EVENT_OBJECT_CATALOG, ACTION_CONDITION, ACTION_REFERENCE_OLD_TABLE, ACTION_REFERENCE_NEW_TABLE und CREATED.

Ein Beispiel mit dem in Abschnitt 20.3, „Verwendung von Triggern“, definierten Trigger ins_sum:

mysql> SELECT * FROM INFORMATION_SCHEMA.TRIGGERS\G
*************************** 1. row ***************************
           TRIGGER_CATALOG: NULL
            TRIGGER_SCHEMA: test
              TRIGGER_NAME: ins_sum
        EVENT_MANIPULATION: INSERT
      EVENT_OBJECT_CATALOG: NULL
       EVENT_OBJECT_SCHEMA: test
        EVENT_OBJECT_TABLE: account
              ACTION_ORDER: 0
          ACTION_CONDITION: NULL
          ACTION_STATEMENT: SET @sum = @sum + NEW.amount
        ACTION_ORIENTATION: ROW
             ACTION_TIMING: BEFORE
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
  ACTION_REFERENCE_OLD_ROW: OLD
  ACTION_REFERENCE_NEW_ROW: NEW
                   CREATED: NULL
                  SQL_MODE:
                   DEFINER: me@localhost

Siehe auch Abschnitt 13.5.4.23, „SHOW TRIGGERS.

22.17. Die Tabelle INFORMATION_SCHEMA PLUGINS

Die PLUGINS-Tabelle informiert über Server-Plug-Ins.

NameSHOW nameRemarks
PLUGIN_NAME  
PLUGIN_VERSION  
PLUGIN_STATUS  
PLUGIN_TYPE  
PLUGIN_TYPE_VERSION  
PLUGIN_LIBRARY  
PLUGIN_LIBRARY_VERSION  
PLUGIN_AUTHOR  
PLUGIN_DESCRIPTION  

Hinweis:

  • Die PLUGINS-Tabelle gibt es seit MySQL 5.1.5.

22.18. Die Tabelle INFORMATION_SCHEMA ENGINES

Die ENGINES-Tabelle informiert über Speicher-Engines.

NameSHOW nameRemarks
ENGINEEngine 
SUPPORTSupport 
COMMENTComment 
TRANSACTIONSTransactions 
XAXA 
SAVEPOINTSSavepoints 

Hinweis:

  • Die ENGINES-Tabelle gibt es seit MySQL 5.1.5.

Siehe auch Abschnitt 13.5.4.9, „SHOW ENGINES.

22.19. Die Tabelle INFORMATION_SCHEMA PARTITIONS

Die PARTITIONS-Tabelle informiert über Tabellenpartitionen.

NameSHOW nameRemarks
TABLE_CATALOG  
TABLE_SCHEMA  
TABLE_NAME  
PARTITION_NAME  
SUBPARTITION_NAME  
PARTITION_ORDINAL_POSITION  
SUBPARTITION_ORDINAL_POSITION  
PARTITION_METHOD  
SUBPARTITION_METHOD  
PARTITION_EXPRESSION  
SUBPARTITION_EXPRESSION  
PARTITION_DESCRIPTION  
TABLE_ROWS  
AVG_ROW_LENGTH  
DATA_LENGTH  
MAX_DATA_LENGTH  
INDEX_LENGTH  
DATA_FREE  
CREATE_TIME  
UPDATE_TIME  
CHECK_TIME  
CHECKSUM  
PARTITION_COMMENT  
NODEGROUP  
TABLESPACE_NAME  

Hinweise:

  • Die PARTITIONS-Tabelle gibt es seit MySQL 5.1.6.

  • Wichtig: Wenn nach einem Upgrade auf MySQL 5.1.6 oder höher noch irgendwelche partitionierten Tabellen vorhanden sind, die in einer älteren MySQL-Version als MySQL 5.1.6 angelegt wurden, so ist auf der PARTITIONS-Tabelle kein SELECT, SHOW oder DESCRIBE möglich. Bitte lesen Sie Abschnitt D.1.1, „Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)“, bevor Sie von MySQL 5.1.5 oder einer älteren Version auf MySQL 5.1.6 oder höher aufrüsten.

22.20. Die Tabelle INFORMATION_SCHEMA EVENTS

Die EVENTS-Tabelle informiert über Ereignisplaner-Ereignisse.

NameSHOW nameRemarks
EVENT_CATALOG  
EVENT_SCHEMA  
EVENT_NAME  
DEFINER  
EVENT_BODY  
EVENT_TYPE  
EXECUTE_AT  
INTERVAL_VALUE  
INTERVAL_FIELD  
SQL_MODE  
STARTS  
ENDS  
STATUS  
ON_COMPLETION  
CREATED  
LAST_ALTERED  
LAST_EXECUTED  
EVENT_COMMENT  

Hinweis:

  • Die EVENTS-Tabelle gibt es seit MySQL 5.1.6.

22.21. Weitere INFORMATION_SCHEMA-Tabellen

Wir haben vor, noch weitere INFORMATION_SCHEMA-Tabellen zu implementieren. Insbesondere sehen wir die Notwendigkeit einer PARAMETERS- und einer REFERENTIAL_CONSTRAINTS-Tabelle.

22.22. Erweiterungen der SHOW-Anweisungen

Einige Erweiterungen von SHOW-Anweisungen gehören zur Implementierung des INFORMATION_SCHEMA:

  • SHOW kann Informationen über die Struktur des INFORMATION_SCHEMA selbst liefern.

  • Einige SHOW-Anweisungen können eine WHERE-Klausel haben. Dadurch können Sie flexibler angeben, welche Zeilen angezeigt werden sollen.

Da INFORMATION_SCHEMA eine Informationsdatenbank ist, wird ihr Name von der SHOW DATABASES-Anweisung ebenfalls ausgegeben. Ebenso können Sie auch SHOW TABLES auf dem INFORMATION_SCHEMA verwenden, um eine Liste seiner Tabellen zu erhalten:

mysql> SHOW TABLES FROM INFORMATION_SCHEMA;
+---------------------------------------+
| Tables_in_information_schema          |
+---------------------------------------+
| CHARACTER_SETS                        |
| COLLATIONS                            |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS                               |
| COLUMN_PRIVILEGES                     |
| ENGINES                               |
| EVENTS                                |
| KEY_COLUMN_USAGE                      |
| PARTITIONS                            |
| PLUGINS                               |
| ROUTINES                              |
| SCHEMATA                              |
| SCHEMA_PRIVILEGES                     |
| STATISTICS                            |
| TABLES                                |
| TABLE_CONSTRAINTS                     |
| TABLE_PRIVILEGES                      |
| TRIGGERS                              |
| USER_PRIVILEGES                       |
| VIEWS                                 |
+---------------------------------------+
19 rows in set (0.03 sec)

SHOW COLUMNS und DESCRIBE können Informationen über die Spalten der einzelnen INFORMATION_SCHEMA-Tabellen liefern.

Mehrere SHOW-Anweisungen wurden um eine WHERE-Klausel erweitert:

SHOW CHARACTER SET
SHOW COLLATION
SHOW COLUMNS
SHOW DATABASES
SHOW FUNCTION STATUS
SHOW KEYS
SHOW OPEN TABLES
SHOW PROCEDURE STATUS
SHOW STATUS
SHOW TABLE STATUS
SHOW TABLES
SHOW VARIABLES

Wenn eine WHERE-Klausel vorhanden ist, wird sie mit den von SHOW ausgewiesenen Spaltennamen verglichen. So liefert beispielsweise die Anweisung SHOW CHARACTER SET folgende Ausgabespalten:

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset  | Description                 | Default collation   | Maxlen |
+----------+-----------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese    | big5_chinese_ci     |      2 |
| dec8     | DEC West European           | dec8_swedish_ci     |      1 |
| cp850    | DOS West European           | cp850_general_ci    |      1 |
| hp8      | HP West European            | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian       | koi8r_general_ci    |      1 |
| latin1   | cp1252 West European        | latin1_swedish_ci   |      1 |
| latin2   | ISO 8859-2 Central European | latin2_general_ci   |      1 |
...

Wenn Sie eine WHERE-Klausel mit SHOW CHARACTER SET verbinden würden, würden Sie auf diese Spaltennamen Bezug nehmen. Die folgende Anweisung zeigt beispielsweise Informationen über Zeichensätze an, deren Standardkollation den String 'japanese' enthält:

mysql> SHOW CHARACTER SET WHERE `Default collation` LIKE '%japanese%';
+---------+---------------------------+---------------------+--------+
| Charset | Description               | Default collation   | Maxlen |
+---------+---------------------------+---------------------+--------+
| ujis    | EUC-JP Japanese           | ujis_japanese_ci    |      3 |
| sjis    | Shift-JIS Japanese        | sjis_japanese_ci    |      2 |
| cp932   | SJIS for Windows Japanese | cp932_japanese_ci   |      2 |
| eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci |      3 |
+---------+---------------------------+---------------------+--------+

Die folgende Anweisung zeigt die Multibytezeichensätze an:

mysql> SHOW CHARACTER SET WHERE Maxlen > 1;
+---------+---------------------------+---------------------+--------+
| Charset | Description               | Default collation   | Maxlen |
+---------+---------------------------+---------------------+--------+
| big5    | Big5 Traditional Chinese  | big5_chinese_ci     |      2 |
| ujis    | EUC-JP Japanese           | ujis_japanese_ci    |      3 |
| sjis    | Shift-JIS Japanese        | sjis_japanese_ci    |      2 |
| euckr   | EUC-KR Korean             | euckr_korean_ci     |      2 |
| gb2312  | GB2312 Simplified Chinese | gb2312_chinese_ci   |      2 |
| gbk     | GBK Simplified Chinese    | gbk_chinese_ci      |      2 |
| utf8    | UTF-8 Unicode             | utf8_general_ci     |      3 |
| ucs2    | UCS-2 Unicode             | ucs2_general_ci     |      2 |
| cp932   | SJIS for Windows Japanese | cp932_japanese_ci   |      2 |
| eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci |      3 |
+---------+---------------------------+---------------------+--------+

Kapitel 23. Präzisionsberechnungen

MySQL 5.1 bietet Unterstützung für Präzisionsberechnungen: eine Verarbeitung numerischer Werte, die extrem genaue Ergebnisse und eine sehr gute Kontrolle über ungültige Werte garantiert. Präzisionsberechnungen beruhen auf zwei Features:

  • SQL-Modi, die steuern, wie streng der Server mit ungültigen Daten umgeht

  • die MySQL-Bibliothek für Festkommaarithmetik

Diese Features haben mehrere Auswirkungen auf numerische Operationen:

  • Präzisionsberechnungen: In Berechnungen mit genauen Zahlen werden keine Fließkommafehler eingebaut. Stattdessen wird eine genaue Anzahl Stellen (Precision) verwendet. So wird zum Beispiel eine Zahl wie .0001 nicht als Näherungswert, sondern als genauer Wert verstanden, und wenn man ihn 10.000 Mal addiert, erhält man genau 1 als Ergebnis und keinen Wert, der bloß „annähernd“ gleich 1 ist.

  • Wohldefiniertes Rundungsverhalten: Bei genauen Zahlen orientiert sich das Ergebnis von ROUND() am Argument der Funktion und nicht an Umgebungsfaktoren wie etwa der Funktionsweise der zugrunde liegenden C-Bibliothek.

  • Plattformunabhängigkeit: Operationen mit genauen numerischen Werten gleichen sich auf allen Plattformen, wie beispielsweise Windows und Unix.

  • Kontrolle über den Umgang mit ungültigen Werten: Überlauf und Division durch null können erkannt und als Fehler behandelt werden. So können Sie beispielsweise einen Wert, der für eine Spalte zu groß ist, als Fehler behandeln, anstatt ihn auf den Datentyp der Spalte zurechtschustern zu lassen. Ebenso können Sie eine Division durch null als Fehler erkennen, anstatt ihn als Operation mit einem NULL-Ergebnis zu handhaben. Durch die Einstellung der Systemvariablen sql_mode bestimmen Sie selbst, welchen Weg Sie einschlagen.

Ein wichtiges Ergebnis all dieser Features ist, dass MySQL 5.1 dem SQL-Standard sehr nahe kommt.

Die folgenden Ausführungen betreffen mehrere Aspekte der Funktionsweise von Präzisionsberechnungen (einschließlich möglicher Inkompatibilitäten mit älteren Anwendungen). Zum Schluss geben wir einige Beispiele, um zu zeigen, wie präzise MySQL 5.1 numerische Operationen ausführt. Wie man mit der Systemvariablen sql_mode den SQL-Modus einstellt, erfahren Sie unter Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

23.1. Typen numerischer Werte

In Operationen mit genauen Werten sind Präzisionsberechnungen mit genauen numerischen Datentypen (DECIMAL und Integer-Typen) und genauen numerischen Literalen möglich. Näherungsweise Datentypen und Zahlenliterale werden weiterhin als Fließkommazahlen behandelt.

Genaue numerische Literale haben einen ganzzahligen oder einen Bruchteilsanteil oder beides. Sie können ein Vorzeichen besitzen. Beispiele: 1, .2, 3.4, -5, -6.78, +9.10.

Näherungsweise numerische Literale werden in der wissenschaftlichen Schreibweise mit Mantisse und Exponent dargestellt. Beides kann auch vorzeichenbehaftet sein. Beispiele: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.

Zwei Zahlen, die ähnlich aussehen, müssen nicht unbedingt beide genaue Werte oder beide Näherungswerte sein. So ist beispielsweise 2.34 eine genaue (Festkomma-)Zahl, während 2.34E0 eine näherungsweise (Fließkomma-)Zahl ist.

Der Datentyp DECIMAL ist ein Festkommatyp und Berechnungen mit diesem Typ sind genau. In MySQL hat DECIMAL mehrere Synonyme: NUMERIC, DEC, FIXED. Auch die Integer-Typen sind genaue Datentypen.

Die Datentypen FLOAT und DOUBLE sind Fließkommatypen und Berechnungen mit diesen Typen sind Näherungen. In MySQL haben FLOAT und DOUBLE die Synonyme DOUBLE PRECISION und REAL.

23.2. Änderungen beim Datentyp DECIMAL

In diesem Abschnitt werden die Merkmale des Datenyps DECIMAL (und seiner Synonyme) in MySQL 5.1 vorgestellt. Dabei werden besonders folgende Themen angesprochen:

  • die Höchstzahl der Stellen

  • das Speicherformat

  • der Speicherbedarf

  • die nicht zum Standard gehörende MySQL-Erweiterung für den oberen Bereich der DECIMAL-Spalten

Auf mögliche Inkompatibilitäten mit Anwendungen, die für ältere Versionen von MySQL geschrieben wurden, weisen wir an geeigneter Stelle in diesem Abschnitt hin.

Die Deklarationssyntax für eine DECIMAL-Spalte lautet DECIMAL(M,D). Die Argumente haben in MySQL 5.1 folgende Wertebereiche:

  • M ist die Höchstzahl der Stellen (die Genauigkeit) und liegt zwischen 1 und 65. (Ältere Versionen von MySQL hatten hier einen zulässigen Wertebereich von 1 bis 254.)

  • D ist die Anzahl der Stellen rechts vom Dezimalpunkt (die Dezimalstellen) mit dem Wertebereich 0 bis 30. D darf nicht größer als M sein.

Dass M maximal 65 beträgt, führt dazu, dass Berechnungen mit DECIMAL-Werten auf bis zu 65 Stellen genau sind. Da diese maximale Genauigkeit von 65 Stellen auch für genaue numerische Literale gilt, hat sich der maximale Wertebereich solcher Literale geändert. (In älteren MySQL-Versionen konnten Dezimalwerte bis zu 254 Stellen haben, aber die Berechnungen wurden als Fließkommaoperationen ausgeführt und waren daher Näherungen und nicht genau.)

Werte für DECIMAL-Spalten werden in MySQL 5.1 in einem Binärformat gespeichert, das Dezimalstellen in 4 Byte hineinpackt. Der Speicherbedarf für den ganzzahligen Teil und den Bruchteil wird separat ermittelt. Ein Vielfaches von 9 Stellen belegt 4 Byte und eventuelle Reststellen belegen einen Bruchteil von 4 Byte. Da beispielsweise die Spalte DECIMAL(18,9) auf jeder Seite des Dezimalpunkts 9 Stellen hat, belegen ihr ganzzahliger und ihr Dezimalteil jeweils 4 Byte. Eine DECIMAL(20,10)-Spalte hat dagegen auf jeder Seite des Dezimalpunkts 10 Stellen. Jeder Teil belegt also 4 Byte für die ersten 9 Stellen und 1 Byte für die Reststelle.

Folgende Tabelle zeigt den Speicherbedarf für Reststellen an:

ReststellenAnzahl Bytes
00
11
21
32
42
53
63
74
84
94

Im Gegensatz zu älteren Versionen von MySQL (vor 5.0.3) speichern DECIMAL-Spalten in MySQL 5.1 keine Stelle für ein vorangestelltes +-Zeichen oder vorangestellte 0-Ziffern. Wenn Sie +0003.1 in eine DECIMAL(5,1)-Spalte speichern, so wird diese Zahl einfach als 3.1 gespeichert. Anwendungen, die das frühere Speicherverhalten benötigen, müssen umgeschrieben werden, um sie an diese Änderung anzupassen.

DECIMAL-Spalten können in MySQL 5.1 keine Werte speichern, die größer sind als in der Spaltendefinition angegeben. So lässt beispielsweise eine DECIMAL(3,0)-Spalte Werte von -999 bis 999 zu und eine DECIMAL(M,D)-Spalte erlaubt höchstens MD Stellen auf der linken Seite des Dezimalpunkts. Das ist nicht kompatibel mit Anwendungen, die sich auf die älteren Versionen von MySQL stützen, welche eine zusätzliche Stelle für das +-Zeichen speicherten.

Der SQL-Standard verlangt für NUMERIC(M,D)-Werte eine Genauigkeit von exakt M Stellen und für DECIMAL(M,D)-Werte eine Genauigkeit von mindestens M Stellen (es darf auch mehr sein). In MySQL sind DECIMAL(M,D) und NUMERIC(M,D) dasselbe und haben beide eine Genauigkeit von exakt M Stellen.

Genauere Informationen über die Portierung von Anwendungen, die sich auf die frühere Behandlung des Datentyps DECIMAL stützen, finden Sie unter MySQL-Referenzhandbuch für die Version 5.0.

23.3. Behandlung von Ausdrücken

In Präzisionsberechnungen werden genaue Zahlen möglichst immer so verwendet, wie sie angegeben sind. Beispielsweise werden Zahlen in Vergleichsoperationen genau wie vorgegeben verwendet, ohne jede Änderung. Im strikten SQL-Modus wird eine Zahl, die mit INSERT in eine Spalte mit einem genauen Datentyp (DECIMAL oder Integer) geladen wird, mit ihrem genauen Wert eingefügt, wenn sie im Wertebereich der Spalte liegt. Wird die Zahl abgerufen, ist ihr Wert immer noch derselbe, der eingefügt wurde. (Ohne den Strict-Modus kann ein Wert bei INSERT-Operationen auch abgeschnitten werden.)

Die Handhabung numerischer Ausdrücke hängt davon ab, welche Art von Werten die Ausdrücke enthalten:

  • Enthält ein Ausdruck Näherungswerte, so ist der gesamte Ausdruck eine Näherung und wird mit Fließkommaarithmetik ausgewertet.

  • Enthält der Ausdruck keine Näherungswerte, sind nur genaue Werte vorhanden. Enthält irgendein genauer Wert einen Bruchteilsanteil (also einen Wert, der hinter dem Dezimalpunkt steht), so wird er mit genauer Arithmetik als DECIMAL ausgewertet und hat eine Genauigkeit von 65 Stellen. (Was mit „genau“ gemeint ist, hängt von den Grenzen dessen ab, was im Binärformat dargestellt werden kann. So kann beispielsweise 1.0/3.0 in Dezimalschreibweise als die Näherung .333..., aber nicht als genaue Zahl dargestellt werden. Daher wird (1.0/3.0)*3.0 nicht als genau 1.0 ausgewertet.)

  • Andernfalls enthält der Ausdruck nur Integer-Werte. Der Ausdruck ist somit genau und wird mit Integer-Arithmetik ausgewertet. Seine Genauigkeit ist dieselbe wie BIGINT (64 Bits).

Wenn ein numerischer Ausdruck Strings enthält, so werden diese in Fließkommawerte mit doppelter Genauigkeit umgewandelt und es entsteht ein näherungsweiser Ausdruck.

Einfügungen in numerische Spalten werden durch den SQL-Modus beeinflusst, der mit der Systemvariablen sql_mode eingestellt wird. (Siehe Abschnitt 1.9.2, „Auswahl der SQL-Modi“.) In den nachfolgenden Ausführungen werden der Strict-Modus (der durch die Werte STRICT_ALL_TABLES oder STRICT_TRANS_TABLES eingeschaltet wird) und ERROR_FOR_DIVISION_BY_ZERO verwendet. Um alle Restriktionen einzuschalten, können Sie auch einfach den TRADITIONAL-Modus wählen, der beide Strict-Modi und ERROR_FOR_DIVISION_BY_ZERO umfasst:

mysql> SET sql_mode='TRADITIONAL';

Wird eine Zahl in eine Spalte eines genauen Datentyps (DECIMAL oder Integer) eingefügt, so wird sie mit ihrem genauen Wert in die Spalte geladen, wenn sie im zulässigen Wertebereich dieser Spalte liegt.

Hat ihr Dezimalteil zu viele Stellen, wird sie gerundet und eine Warnung ausgegeben. Gerundet wird, wie es unter Rundungsverhalten beschrieben ist.

Hat die Zahl in ihrem ganzzahligen Teil zu viele Stellen, ist sie zu groß und wird folgendermaßen behandelt:

  • Wenn der Strict-Modus nicht eingeschaltet ist, wird der Wert auf den nächsten zulässigen Wert abgeschnitten und eine Warnung generiert.

  • Ist der Strict-Modus aktiviert, tritt ein Überlauffehler ein.

Da ein Speicherunterlauf nicht erkannt wird, ist die Behandlung eines Unterlaufs nicht definiert.

Nach Voreinstellung kommt bei einer Division durch null das Ergebnis NULL heraus und keine Warnung. Haben Sie jedoch den SQL-Modus ERROR_FOR_DIVISION_BY_ZERO aktiviert, geht MySQL mit einer Division durch null ganz anders um:

  • Wenn der Strict-Modus eingeschaltet ist, wird eine Warnung ausgegeben.

  • Bei eingeschaltetem Strict-Modus sind Einfügungen und Aktualisierungen, bei denen eine Division durch null vorkommt, verboten, und ein Fehler wird gemeldet.

Mit anderen Worten: Einfügungen und Aktualisierungen, in denen Ausdrücke mit einer Division durch null vorkommen, können als Fehler behandelt werden, allerdings nur dann, wenn zusätzlich zum Strict-Modus ERROR_FOR_DIVISION_BY_ZERO eingeschaltet ist.

Nehmen wir als Beispiel folgende Anweisung:

INSERT INTO t SET i = 1/0;

Nun sehen Sie, was bei unterschiedlichen Kombinationen von Strict und ERROR_FOR_DIVISION_BY_ZERO passiert:

sql_mode WertErgebnis
'' (Default)Keine Warnung, kein Fehler; i wird auf NULL gesetzt.
strictKeine Warnung, kein Fehler; i wird auf NULL gesetzt.
ERROR_FOR_DIVISION_BY_ZEROWarnung, aber kein Fehler; i wird auf NULL gesetzt.
strict,ERROR_FOR_DIVISION_BY_ZEROFehlerbedingung, keine Zeile eingefügt.

Werden Strings in numerische Spalten eingefügt, findet folgende Zahlenkonvertierung statt, wenn der String keinen numerischen Inhalt hat:

  • Ein String, der nicht mit einer Zahl anfängt, kann nicht als Zahl verwendet werden. Im Strict-Modus wird ein Fehler und ansonsten eine Warnung generiert. Das schließt auch den leeren String ein.

  • Ein mit einer Zahl beginnender String kann konvertiert werden, wobei jedoch der nachfolgende, nichtnumerische Teil abgeschnitten wird. Wenn der abgeschnittene Teil etwas anderes als Leerzeichen enthält, wird im Strict-Modus ein Fehler und ansonsten eine Warnung generiert.

23.4. Rundungsverhalten

Dieser Abschnitt beschreibt das Rundungsverhalten in Präzisionsberechnungen für die Funktion ROUND() und Einfügungen in DECIMAL-Spalten.

Die Funktion ROUND() rundet genaue und näherungsweise Argumente unterschiedlich:

  • Genaue Zahlen rundet ROUND() nach dem Grundsatz „Ab der Hälfte wird aufgerundet“. Dabei wird eine positive Zahl mit einem Dezimalteil von .5 oder mehr auf den nächsten Integer aufgerundet und eine negative Zahl mit einem Dezimalteil von .5 oder mehr auf den nächsten Integer abgerundet. (Mit anderen Worten: Die Zahl wird von null weggerundet.) Ein Wert mit einem Dezimalteil kleiner .5 wird dagegen auf den nächsten Integer abgerundet, wenn er positiv ist, und auf den nächsten Integer aufgerundet, wenn er negativ ist.

  • Das Ergebnis für Näherungswerte hängt von der C-Bibliothek ab. Auf vielen Systemen bedeutet dies, dass ROUND() nach der Regel „Runde auf die nächste gerade Zahl“ vorgeht: Ein Wert mit Bruchteilsanteil wird auf den nächsten geraden Integer gerundet.

Das folgende Beispiel verdeutlicht die Unterschiede einer Rundung von genauen und näherungsweisen Werten:

mysql> SELECT ROUND(2.5), ROUND(25E-1);
+------------+--------------+
| ROUND(2.5) | ROUND(25E-1) |
+------------+--------------+
| 3          |            2 |
+------------+--------------+

Da Einfügungen in eine DECIMAL-Spalte einen genauen Datentyp zum Ziel haben, wird immer nach der Regel „Runde auf die nächste gerade Zahl“ gerundet, egal ob der einzufügende Wert ein genauer oder ein Näherungswert ist:

mysql> CREATE TABLE t (d DECIMAL(10,0));
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t VALUES(2.5),(2.5E0);
Query OK, 2 rows affected, 2 warnings (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 2

mysql> SELECT d FROM t;
+------+
| d    |
+------+
| 3    |
| 3    |
+------+

23.5. Beispiele für Präzisionsberechnungen

Dieser Abschnitt zeigt Beispiele für die Ergebnisse von Anfragen mit Präzisionsberechnungen in MySQL 5.1.

Beispiel 1. Zahlen werden möglichst mit ihrem genauen Wert wie vorgegeben benutzt:

mysql> SELECT .1 + .2 = .3;
+--------------+
| .1 + .2 = .3 |
+--------------+
|            1 |
+--------------+

Bei Fließkommawerten sind die Ergebnisse Näherungen:

mysql> SELECT .1E0 + .2E0 = .3E0;
+--------------------+
| .1E0 + .2E0 = .3E0 |
+--------------------+
|                  0 |
+--------------------+

Eine andere Möglichkeit, den Unterschied in der Behandlung von genauen und Näherungswerten zu zeigen, besteht darin, eine kleine Zahl immer wieder zu einer Summe zu addieren. Betrachten Sie folgende gespeicherte Prozedur, die zu einer Variablen tausendmal den Wert .0001 addiert.

CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE d DECIMAL(10,4) DEFAULT 0;
  DECLARE f FLOAT DEFAULT 0;
  WHILE i < 10000 DO
    SET d = d + .0001;
    SET f = f + .0001E0;
    SET i = i + 1;
  END WHILE;
  SELECT d, f;
END;

Logischerweise sollte die Summe für d und f beide Male 1 ergeben, aber in Wirklichkeit ist dies nur bei der Dezimalberechnung der Fall. In der Fließkommaberechnung wird ein Fehler eingeführt:

+--------+------------------+
| d      | f                |
+--------+------------------+
| 1.0000 | 0.99999999999991 |
+--------+------------------+

Beispiel 2. Multiplikationen werden mit der durch den SQL-Standard vorgegebenen Anzahl Dezimalstellen ausgeführt: Für zwei Zahlen X1 und X2, die S1 beziehungsweise S2 Dezimalstellen haben, entsteht ein Ergebnis mit S1 + S2 Dezimalstellen:

mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
| 0.0001    |
+-----------+

Beispiel 3. Das Rundungsverhalten ist wohldefiniert:

So ist das Rundungsverhalten (beispielsweise der Funktion ROUND()) unabhängig von der Implementierung der zugrunde liegenden C-Bibliothek, sodass die Ergebnisse plattformübergreifend konsistent sind.

DECIMAL-Spalten und genaue Zahlen werden nach der Regel „Ab der Hälfte wird aufgerundet“ behandelt: Werte mit einem Dezimalteil von .5 oder mehr werden, wie das nächste Beispiel zeigt, immer von null weg auf den nächstgelegenen Integer aufgerundet:

mysql> SELECT ROUND(2.5), ROUND(-2.5);
+------------+-------------+
| ROUND(2.5) | ROUND(-2.5) |
+------------+-------------+
| 3          | -3          |
+------------+-------------+

Dagegen stützt sich die Rundung von Fließkommawerten auf die C-Bibliothek, die auf vielen Systemen nach dem Grundsatz „Runde auf die nächste gerade Zahl“ verfährt. Auf solchen Systemen werden Werte mit einem Bruchteilsanteil auf die nächste gerade Zahl gerundet:

mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0);
+--------------+---------------+
| ROUND(2.5E0) | ROUND(-2.5E0) |
+--------------+---------------+
|            2 |            -2 |
+--------------+---------------+

Beispiel 4. Wenn Sie im Strict-Modus einen zu großen Wert einfügen, führt dies zu einem Überlauf und verursacht einen Fehler. Der Wert wird nicht auf ein zulässiges Maß zurechtgestutzt.

Läuft MySQL jedoch nicht im Strict-Modus, wird der Wert abgeschnitten, bis er passt:

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t SET i = 128;
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SELECT i FROM t;
+------+
| i    |
+------+
|  127 |
+------+
1 row in set (0.00 sec)

Immerhin wird eine Überlaufbedingung registriert, wenn der Strict-Modus eingeschaltet ist:

mysql> SET sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 128;
ERROR 1264 (22003): Out of range value adjusted for column 'i' at row 1

mysql> SELECT i FROM t;
Empty set (0.00 sec)

Beispiel 5: Sind der Strict-Modus und ERROR_FOR_DIVISION_BY_ZERO eingeschaltet, verursacht eine Division durch null einen Fehler, anstatt das Ergebnis NULL nach sich zu ziehen.

Im nichtstrikten Modus hat die Division durch null das Ergebnis NULL:

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 1 / 0;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT i FROM t;
+------+
| i    |
+------+
| NULL |
+------+
1 row in set (0.03 sec)

Sind jedoch die richtigen SQL-Modi eingeschaltet, verursacht eine Division durch null immer einen Fehler:

mysql> SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 1 / 0;
ERROR 1365 (22012): Division by 0

mysql> SELECT i FROM t;
Empty set (0.01 sec)

Beispiel 6. Vor MySQL 5.0.3 (also vor der Einführung von Präzisionsberechnungen) wurden sowohl genaue als auch näherungsweise Literale in Fließkommazahlen mit doppelter Genauigkeit umgewandelt:

mysql> SELECT VERSION();
+------------+
| VERSION()  |
+------------+
| 4.1.18-log |
+------------+
1 row in set (0.01 sec)

mysql> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
Query OK, 1 row affected (0.07 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> DESCRIBE t;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a     | double(3,1) |      |     | 0.0     |       |
| b     | double      |      |     | 0       |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.04 sec)

Seit MySQL 5.0.3 werden näherungsweise Literale zwar immer noch in Fließkommazahlen konvertiert, genaue hingegen werden als DECIMAL behandelt:

mysql> SELECT VERSION();
+-----------------+
| VERSION()       |
+-----------------+
| 5.1.6-alpha-log |
+-----------------+
1 row in set (0.11 sec)

mysql> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> DESCRIBE t;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type                  | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| a     | decimal(2,1) unsigned | NO   |     | 0.0     |       |
| b     | double                | NO   |     | 0       |       |
+-------+-----------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

Beispiel 7. Wenn das Argument einer Aggregatfunktion ein genauer numerischer Typ ist, ist ihr Ergebnis ebenfalls ein genauer numerischer Typ, und zwar mit mindestens so vielen Dezimalstellen, wie das Argument hatte.

Betrachten Sie folgende Anweisungen:

mysql> CREATE TABLE t (i INT, d DECIMAL, f FLOAT);
mysql> INSERT INTO t VALUES(1,1,1);
mysql> CREATE TABLE y SELECT AVG(i), AVG(d), AVG(f) FROM t;

Vor MySQL 5.0.3 (also vor der Einführung von Präzisionsberechnungen in MySQL) sähe das Ergebnis folgendermaßen aus:

mysql> DESCRIBE y;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| AVG(i) | double(17,4) | YES  |     | NULL    |       |
| AVG(d) | double(17,4) | YES  |     | NULL    |       |
| AVG(f) | double       | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+

Das Resultat ist ein Double-Wert, egal welchen Typ das Argument hatte.

Mit MySQL 5.0.3 hat sich dies geändert:

mysql> DESCRIBE y;
+--------+---------------+------+-----+---------+-------+
| Field  | Type          | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| AVG(i) | decimal(14,4) | YES  |     | NULL    |       |
| AVG(d) | decimal(14,4) | YES  |     | NULL    |       |
| AVG(f) | double        | YES  |     | NULL    |       |
+--------+---------------+------+-----+---------+-------+

Hier entsteht nur für das Fließkommaargument ein Ergebnis vom Typ Double. Argumente mit genauen Typen haben genaue Ergebnisse.

Kapitel 24. APIs und Bibliotheken

Inhaltsverzeichnis

24.1. libmysqld, die eingebettete MySQL Server-Bibliothek
24.1.1. Überblick über die eingebettete MySQL Server-Bibliothek
24.1.2. Programme mit libmysqld kompilieren
24.1.3. Einschränkungen bei der Benutzung des eingebetteten MySQL Servers
24.1.4. Optionen des eingebetteten Servers
24.1.5. Ein einfaches Embedded Server-Beispiel
24.1.6. Lizenzierung des eingebetteten Servers
24.2. MySQL-C-API
24.2.1. C-API: Datentypen
24.2.2. C-API: Funktionsüberblick
24.2.3. C-API: Funktionsbeschreibungen
24.2.4. C-API: Prepared Statements
24.2.5. C-API: Prepared Statement-Datentypen
24.2.6. C-API Prepared Statements: Funktionsüberblick
24.2.7. C-API Prepared Statements: Funktionsbeschreibungen
24.2.8. C-API: Probleme bei Prepared Statements
24.2.9. C-API: Behandlung der Ausführung mehrerer Anweisungen
24.2.10. C-API: Behandlung von Datums- und Zeitwerten
24.2.11. C-Threaded-Funktionsbeschreibungen
24.2.12. C Embedded Server: Funktionsbeschreibungen
24.2.13. Häufige Fragen und Probleme bei der Benutzung der C-API
24.2.14. Clientprogramme bauen
24.2.15. Wie man einen Thread-Client herstellt
24.3. MySQLs PHP-API
24.3.1. Allgemeine Probleme mit MySQL und PHP
24.4. MySQLs Perl-API
24.5. MySQL-C++-APIs
24.5.1. Borland C++
24.6. MySQL-Python-APIs
24.7. MySQL-Tcl-APIs
24.8. MySQL-Eiffel-Wrapper
24.9. MySQL-Hilfsprogramme für die Programmentwicklung
24.9.1. msql2mysql — Umwandeln von mSQL-Programmen für die Benutzung mit MySQL
24.9.2. mysql_config — Kompilieroptionen zum Kompilieren von Clients erhalten

In diesem Kapitel erfahren Sie, welche APIs für MySQL zur Verfügung stehen, wo Sie sie bekommen und wie Sie sie benutzen. Die C-API wird am gründlichsten behandelt, da sie von dem MySQL-Team entwickelt wurde und die Grundlage der meisten anderen APIs bildet. Außerdem behandelt das vorliegende Kapitel die libmysqld-Bibliothek (den Embedded Server) sowie einige Programme, die für Anwendungsentwickler nützlich sind.

24.1. libmysqld, die eingebettete MySQL Server-Bibliothek

24.1.1. Überblick über die eingebettete MySQL Server-Bibliothek

Die MySQL Embedded Server-Bibliothek ermöglicht es, einen kompletten MySQL Server innerhalb einer Clientanwendung auszuführen. Die Hauptvorteile davon sind erhöhte Geschwindigkeit und eine einfachere Verwaltung eingebetteter Anwendungen.

Die Embedded Server-Bibliothek basiert auf der Client/Server-Version von MySQL, die in C/C++ geschrieben ist. Folglich ist auch der Embedded Server in C/C++ verfasst. In anderen Sprachen steht kein Embedded Server zur Verfügung.

Die API für die Embedded-MySQL-Version und die Client/Server-Version von MySQL sind identisch. Um eine alte Threaded-Anwendung auf die Embedded-Bibliothek umzustellen, müssen Sie normalerweise nur Aufrufe an folgende Funktionen hinzufügen:

FunktionWann aufrufen
mysql_server_init()Sollte vor jeder anderen MySQL-Funktion aufgerufen werden, am besten am Anfang der main()-Funktion.
mysql_server_end()Sollte vor dem Beenden des Programms aufgerufen werden.
mysql_thread_init()Sollte in jedem Thread aufgerufen werden, mit dem Sie auf MySQL zugreifen.
mysql_thread_end()Sollte vor pthread_exit() aufgerufen werden.

Dann müssen Sie Ihren Code mit libmysqld.a statt mit libmysqlclient.a verlinken.

Die mysql_server_xxx()-Funktionen sind auch in libmysqlclient.a enthalten, damit Sie zwischen der Embedded und der Client/Server-Version umstellen können, indem Sie Ihre Anwendung einfach mit der richtigen Bibliothek verknüpfen. Siehe Abschnitt 24.2.12.1, „mysql_server_init().

Ein Unterschied zwischen dem Embedded und dem Standalone-Server besteht darin, dass die Authentifizierung für Verbindungen im Embedded Server standardmäßig deaktiviert ist. Um sie auch für den Embedded Server zu benutzen, geben Sie die Option --with-embedded-privilege-control an, wenn Sie configure aufrufen, um Ihre MySQL-Distribution zu konfigurieren.

24.1.2. Programme mit libmysqld kompilieren

Um eine libmysqld-Bibliothek zu erhalten, sollten Sie MySQL mit der Option --with-embedded-server konfigurieren. Siehe Abschnitt 2.8.2, „Typische configure-Optionen“.

Wenn Sie Ihr Programm mit libmysqld verknüpfen, müssen Sie auch die systemspezifischen pthread-Bibliotheken und einige andere vom MySQL Server verwendeten Bibliotheken einbinden. Die vollständige Liste der Bibliotheken können Sie mit dem Befehl mysql_config --libmysqld-libs abrufen.

Sie müssen die richtigen Flags zum Kompilieren und Verlinken eines Threaded-Programms benutzen, auch wenn Sie in Ihrem Code nicht direkt irgendwelche Thread-Funktionen aufrufen.

Um ein C-Programm so zu kompilieren, dass es alle notwendigen Dateien enthält, um die MySQL Server-Bibliothek in eine kompilierte Version eines Programms einzubinden, verwenden Sie den C-Compiler von GNU (gcc). Dem Compiler müssen Sie die Speicherorte diverser Dateien mitteilen und Anweisungen geben, wie er das Programm kompilieren soll. Das folgende Beispiel zeigt, wie ein Programm auf der Kommandozeile kompiliert werden könnte:

gcc mysql_test.c -o mysql_test -lz \
`/usr/local/mysql/bin/mysql_config --include --libmysqld-libs`

Unmittelbar hinter dem Befehl gcc steht der Name der unkompilierten Datei des C-Programms. Darauf folgt die Option -o, die anzeigt, dass der nachfolgende Dateiname der Name ist, den der Compiler der Ausgabedatei, also dem kompilierten Programm, geben soll. Die nächste Codezeile teilt dem Compiler die Speicherorte der Include-Dateien und Bibliotheken sowie andere Einstellungen für das System mit, auf dem das Programm kompiliert wird. Wegen eines Problems mit mysql_config wird hier die Option -lz (für die Komprimierung) hinzugefügt. Der mysql_config-Teil ist in Backticks statt in einfache Anführungszeichen eingefasst.

24.1.3. Einschränkungen bei der Benutzung des eingebetteten MySQL Servers

Für den Embedded Server gelten folgende Beschränkungen:

  • Keine Unterstützung für ISAM-Tabellen (hauptsächlich, um die Bibliothek kleiner zu halten).

  • Keine benutzerdefinierten Funktionen (UDFs).

  • Kein Stack Trace bei einem Core Dump.

  • Kein interner RAID-Support. (Dieser ist normalerweise überflüssig, da die meisten modernen Betriebssysteme große Dateien unterstützen.)

  • Sie können ihn nicht als Master oder Slave einrichten (keine Replikation).

  • Auf Systemen mit wenig Arbeitsspeicher sind sehr große Ergebnismengen unter Umständen unbenutzbar.

  • Von außen über Sockets oder TCP/IP kann sich kein Prozess mit dem Embedded Server verbinden. Allerdings kann er sich mit einer zwischengeschalteten Anwendung verbinden, die ihrerseits für diesen Remote Client oder externen Prozess Verbindung mit dem Embedded Server aufnimmt.

Manche dieser Beschränkungen können Sie ändern, indem Sie die Include-Datei mysql_embed.h bearbeiten und MySQL neu kompilieren.

24.1.4. Optionen des eingebetteten Servers

Alle Optionen für den mysqld-Server-Daemon können auch für eine Embedded Server-Bibliothek benutzt werden. Serveroptionen können in einem Array als Argument an die Funktion mysql_server_init() übergeben werden, die den Server initialisiert. Oder sie werden in einer Optionsdatei wie my.cnf übergeben. Um eine Optionsdatei für ein C-Programm anzugeben, verwenden Sie die Option --defaults-file als eines der Elemente des zweiten Arguments der mysql_server_init()-Funktion. Weitere Informationen über die mysql_server_init()-Funktion finden Sie in Abschnitt 24.2.12.1, „mysql_server_init().

Optionsdateien erleichtern das Umschalten zwischen einer Client/Server-Anwendung und einer mit Embedded MySQL. Die gemeinsamen Optionen fassen Sie in der [server]-Gruppe zusammen. Diese werden dann von beiden MySQL-Versionen gelesen. Client/Server-spezifische Optionen gehören in den [mysqld]-Abschnitt. Optionen für die MySQL Embedded Server-Bibliothek speichern Sie im Abschnitt [embedded] und anwendungsspezifische Optionen in einem Abschnitt namens [ApplicationName_SERVER]. Siehe Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

24.1.5. Ein einfaches Embedded Server-Beispiel

Die folgenden beiden Beispielprogramme müssten unverändert auf Linux oder FreeBSD laufen. Für andere Betriebssysteme sind kleinere Anpassungen erforderlich, hauptsächlich für die Dateipfade. Die Beispiele sollen genügend Einzelheiten vermitteln, um das Problem zu verdeutlichen, aber ohne den ganzen Ballast, der für eine echte Anwendung notwendig wäre. Das erste Beispiel ist ganz einfach, das zweite ein wenig fortgeschrittener, da es eine Fehlerprüfung enthält. Das erste wird gefolgt von einem Kommandozeileneintrag, mit dem man es kompilieren kann. Unter dem zweiten wird stattdessen eine GNU-Makefile für die Kompilierung angegeben.

Beispiel 1

test1_libmysqld.c

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "mysql.h"

MYSQL *mysql;
MYSQL_RES *results;
MYSQL_ROW record;

static char *server_options[] = { "mysql_test", "--defaults-file=my.cnf" };
int num_elements = sizeof(server_options)/ sizeof(char *);

static char *server_groups[] = { "libmysqld_server", "libmysqld_client" };

int main(void)
{
   mysql_server_init(num_elements, server_options, server_groups);
   mysql = mysql_init(NULL);
   mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "libmysqld_client");
   mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);

   mysql_real_connect(mysql, NULL,NULL,NULL, "database1", 0,NULL,0);

   mysql_query(mysql, "SELECT column1, column2 FROM table1");

   results = mysql_store_result(mysql);

   while((record = mysql_fetch_row(results))) {
      printf("%s - %s \n", record[0], record[1]);
   }

   mysql_free_result(results);
   mysql_close(mysql);
   mysql_server_end();

   return 0;
}

Das Programm wird mit folgender Kommandozeile kompiliert:

gcc test1_libmysqld.c -o test1_libmysqld -lz \
 `/usr/local/mysql/bin/mysql_config --include --libmysqld-libs`

Beispiel 2

Um das Beispiel auszuprobieren, legen Sie ein Verzeichnis namens test2_libmysqld auf derselben Ebene wie das MySQL-Quellverzeichnis an. Speichern Sie die Quelldatei test2_libmysqld.c und die GNUmakefile in dieses Verzeichnis und führen Sie GNU make innerhalb des test2_libmysqld-Verzeichnisses aus.

test2_libmysqld.c

/*
 * Ein einfacher Beispielclient, der die MySQL Embedded Server-Bibliothek benutzt
*/

#include <mysql.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

MYSQL *db_connect(const char *dbname);
void db_disconnect(MYSQL *db);
void db_do_query(MYSQL *db, const char *query);

const char *server_groups[] = {
  "test2_libmysqld_SERVER", "embedded", "server", NULL
};

int
main(int argc, char **argv)
{
  MYSQL *one, *two;

  /* mysql_server_init() muss vor allen anderen mysql-* Funktionen aufgerufen werden.
   *
   * Sie können die Funktion mysql_server_init(0, NULL, NULL) benutzen; sie initialisiert
   * den Server mit groups = {
   *   "server", "embedded", NULL
   *  }.
   *
   * Eventuell setzen Sie Folgendes in Ihre $HOME/.my.cnf-Datei:

[test2_libmysqld_SERVER]
language = /path/to/source/of/mysql/sql/share/english

   * Natürlich können Sie argc und argv auch ändern, ehe Sie sie an
   * diese Funktion übergeben. Oder Sie erstellen neue, ganz nach Bedarf.
   * Doch alle Argumente in argv (außer dem Programmnamen
   * argv[0]) sollten gültige Optionen
   * für den MySQL Server sein.
   *
   * Wenn Sie diesen Client mit der normalen mysqlclient-Bibliothek verlinken,
   * ist diese Funktion lediglich ein Funktionsrumpf, der nichts weiter tut.
   */
  mysql_server_init(argc, argv, (char **)server_groups);

  one = db_connect("test");
  two = db_connect(NULL);

  db_do_query(one, "SHOW TABLE STATUS");
  db_do_query(two, "SHOW DATABASES");

  mysql_close(two);
  mysql_close(one);

  /* Dies muss nach allen anderen mysql-Funktionen aufgerufen werden. */
  mysql_server_end();

  exit(EXIT_SUCCESS);
}

static void
die(MYSQL *db, char *fmt, ...)
{
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  va_end(ap);
  (void)putc('\n', stderr);
  if (db)
    db_disconnect(db);
  exit(EXIT_FAILURE);
}

MYSQL *
db_connect(const char *dbname)
{
  MYSQL *db = mysql_init(NULL);
  if (!db)
    die(db, "mysql_init failed: no memory");
  /*
   * Beachten Sie, dass Client und Server verschiedene Gruppennamen verwenden.
   * Das ist wichtig, da der Server nicht die Optionen des Clients und dieser nicht die Optionen
   * des Servers akzeptiert.
   */
  mysql_options(db, MYSQL_READ_DEFAULT_GROUP, "test2_libmysqld_CLIENT");
  if (!mysql_real_connect(db, NULL, NULL, NULL, dbname, 0, NULL, 0))
    die(db, "mysql_real_connect failed: %s", mysql_error(db));

  return db;
}

void
db_disconnect(MYSQL *db)
{
  mysql_close(db);
}

void
db_do_query(MYSQL *db, const char *query)
{
  if (mysql_query(db, query) != 0)
    goto err;

  if (mysql_field_count(db) > 0)
  {
    MYSQL_RES   *res;
    MYSQL_ROW    row, end_row;
    int num_fields;

    if (!(res = mysql_store_result(db)))
      goto err;
    num_fields = mysql_num_fields(res);
    while ((row = mysql_fetch_row(res)))
    {
      (void)fputs(">> ", stdout);
      for (end_row = row + num_fields; row < end_row; ++row)
        (void)printf("%s\t", row ? (char*)*row : "NULL");
      (void)fputc('\n', stdout);
    }
    (void)fputc('\n', stdout);
    mysql_free_result(res);
  }
  else
    (void)printf("Affected rows: %lld\n", mysql_affected_rows(db));

  return;

err:
  die(db, "db_do_query failed: %s [%s]", mysql_error(db), query);
}

GNUmakefile

# Dies setzt voraus, dass die MySQL-Software in /usr/local/mysql installiert ist
inc      := /usr/local/mysql/include/mysql
lib      := /usr/local/mysql/lib

# Wenn Sie die MySQL-Software noch nicht installiert haben, versuchen Sie dies:
#inc      := $(HOME)/mysql-5.1/include
#lib      := $(HOME)/mysql-5.1/libmysqld

CC       := gcc
CPPFLAGS := -I$(inc) -D_THREAD_SAFE -D_REENTRANT
CFLAGS   := -g -W -Wall
LDFLAGS  := -static
# Sie können -lmysqld in -lmysqlclient ändern, um die
# Client/Server-Bibliothek zu benutzen
LDLIBS    = -L$(lib) -lmysqld -lz -lm -lcrypt

ifneq (,$(shell grep FreeBSD /COPYRIGHT 2>/dev/null))
# FreeBSD
LDFLAGS += -pthread
else
# Linux vorausgesetzt
LDLIBS += -lpthread
endif

# Dies funktioniert für einfache Testprogramme mit nur einer einzigen Datei
sources := $(wildcard *.c)
objects := $(patsubst %c,%o,$(sources))
targets := $(basename $(sources))

all: $(targets)

clean:
        rm -f $(targets) $(objects) *.core

24.1.6. Lizenzierung des eingebetteten Servers

Wir ermutigen jeden Entwickler, freie Software zu fördern, indem er seinen Code unter der GPL oder einer ähnlichen Lizenz herausgibt. Wer dazu nicht in der Lage ist, kann eine kommerzielle Lizenz für den MySQL-Code von MySQL AB kaufen. Einzelheiten finden Sie unter http://www.mysql.com/company/legal/licensing/.

24.2. MySQL-C-API

Der C-API-Code wird mit MySQL zusammen ausgeliefert. Er ist in der mysqlclient-Bibliothek inbegriffen und ermöglicht C-Programmen den Zugriff auf die Datenbank.

Viele Clients der MySQL-Quelldistribution sind in C geschrieben. Wenn Sie Beispiele für die Nutzung der C-API suchen, schauen Sie sich diese Clients an. Zu finden sind sie im Verzeichnis clients der MySQL-Quelldistribution.

Die meisten anderen Client-APIs (alle außer Connector/J und Connector/NET) nutzen die mysqlclient-Bibliothek zur Kommunikation mit dem MySQL Server. Das bedeutet, dass Sie beispielsweise viele derselben Umgebungsvariablen einsetzen können, die auch andere Clientprogramme verwenden, da sie in der Bibliothek referenziert werden. Eine Liste dieser Variablen finden Sie unter Kapitel 8, Client- und Hilfsprogramme.

Der Client hat eine Größenbeschränkung für den Kommunikationspuffer. Für den Puffer werden anfangs 16 Kbyte reserviert, die jedoch automatisch bis hin zur Maximalgröße (16 Mbyte) ausgeweitet werden. Da Puffergrößen nur aufgrund der Nachfrage erhöht werden, werden allein dadurch, dass Sie die voreingestellte Maximalgröße erhöhen, keine größeren Ressourcen belegt. Die Überprüfung dieser Größe ist im Grunde nur eine Prüfung auf fehlerhafte Anweisungen und Kommunikationspakete.

Der Kommunikationspuffer muss groß genug sein, um eine einzelne SQL-Anweisung (für die Übertragung von Client zu Server) und eine Zeile der Rückgabedaten (für die Übertragung von Server zu Client) zu speichern. Der Kommunikationspuffer jedes Threads wird bis zum Größenlimit dynamisch vergrößert, um jede Anfrage oder Zeile handhaben zu können. Wenn Sie beispielsweise BLOB-Werte mit bis zu 16 Mbyte Daten haben, benötigen Sie für den Kommunikationspuffer ein Limit von mindestens 16 Mbyte (sowohl im Server als auch im Client). Das voreingestellte Limit im Client beträgt 16 Mbyte, aber im Server nur 1 Mbyte. Sie können es erhöhen, indem Sie den Wert des Parameters max_allowed_packet beim Serverstart heraufsetzen. Siehe Abschnitt 7.5.2, „Serverparameter feineinstellen“.

Der MySQL Server lässt jeden Kommunikationspuffer nach jeder Anfrage auf net_buffer_length zusammenschrumpfen. Bei Clients wird ein mit einer Verbindung zusammenhängender Puffer erst beim Schließen der Verbindung verkleinert, wenn der Arbeitsspeicher des Clients zurückgeholt wird.

Zur Programmierung mit Threads siehe Abschnitt 24.2.15, „Wie man einen Thread-Client herstellt“. Zur Erstellung einer Standalone-Anwendung, die "Server" und "Client" in demselben Programm enthält (und nicht mit einem externen MySQL Server kommuniziert), siehe Abschnitt 24.1, „libmysqld, die eingebettete MySQL Server-Bibliothek“.

24.2.1. C-API: Datentypen

  • MYSQL

    Diese Struktur ist ein Handle für eine einzelne Datenbankverbindung. Sie wird für fast alle MySQL-Funktionen benutzt. Bitte versuchen Sie nicht, eine Kopie einer MYSQL-Struktur anzulegen. Es ist nicht garantiert, dass eine solche Kopie benutzbar ist.

  • MYSQL_RES

    Diese Struktur stellt das Ergebnis einer Anfrage dar, die Zeilen liefert (SELECT, SHOW, DESCRIBE, EXPLAIN). Die Rückgabedaten aus der Anfrage wird im weiteren Verlauf dieses Abschnitts als Ergebnismenge bezeichnet.

  • MYSQL_ROW

    Eine typsichere Darstellung einer Datenzeile. Sie ist zurzeit als Array gezählter Byte-Strings implementiert. (Diese dürfen nicht als auf null endende Strings behandelt werden, wenn die Feldwerte Binärdaten enthalten könnten, da solche Werte intern Nullbytes enthalten können.) Die Zeilen werden mit mysql_fetch_row() abgerufen.

  • MYSQL_FIELD

    Diese Struktur enthält Informationen über ein Feld, wie beispielsweise seinen Namen, seinen Typ und seine Größe. Ihre Bestandteile werden hier genauer erklärt. Die MYSQL_FIELD-Strukturen von Feldern erhalten Sie, indem Sie wiederholt mysql_fetch_field() aufrufen. Die Werte der Felder sind nicht Teil dieser Struktur, sondern in einer MYSQL_ROW-Struktur enthalten.

  • MYSQL_FIELD_OFFSET

    Dies ist eine typsichere Darstellung eines Offsets in einer MySQL-Feldliste. (Wird von mysql_field_seek() benutzt.) Offsets sind Feldnummern innerhalb einer Zeile. Sie werden beginnend mit null gezählt.

  • my_ulonglong

    Dieser Typ wird für die Anzahl der Zeilen und für mysql_affected_rows(), mysql_num_rows() und mysql_insert_id() genutzt. Er hat einen Wertebereich von 0 bis 1.84e19.

    Auf manchen Systemen können Werte vom Typ my_ulonglong nicht ausgegeben werden. In einem solchen Fall konvertieren Sie diesen in einen unsigned long und verwenden das Ausgabeformat %lu. Beispiel:

    printf ("Number of rows: %lu\n", (unsigned long) mysql_num_rows(result));
    

Die MYSQL_FIELD-Struktur hat folgende Bestandteile:

  • char * name

    Der Name des Felds als auf null endender String. Wenn dem Feld mit einer AS-Klausel ein Aliasname gegeben wurde, ist der Wert von name der Alias.

  • char * org_name

    Der Name des Felds als auf null endender String. Aliasnamen werden ignoriert.

  • char * table

    Der Name der Tabelle, die dieses Feld enthält, wenn es nicht ein berechnetes Feld ist. Für berechnete Felder ist der table-Wert ein leerer String. Wenn der Tabelle mit einer AS-Klausel ein Aliasname gegeben wurde, ist der Wert von name der Alias.

  • char * org_table

    Der Name der Tabelle als auf null endender String. Aliasnamen werden ignoriert.

  • char * db

    Der Name der Datenbank, aus der das Feld stammt, als auf null endender String. Ist das Feld ein berechnetes Feld, ist db ein leerer String.

  • char * catalog

    Der Katalogname. Dieser Wert ist immer "def".

  • char * def

    Der Standardwert dieses Felds als auf null endender String. Wird nur gesetzt, wenn Sie mysql_list_fields() verwenden.

  • unsigned long length

    Die Feldbreite gemäß Tabellendefinition.

  • unsigned long max_length

    Die maximale Breite des Felds für die Ergebnismenge (die Länge des längsten Feldwerts der Zeilen, die sich tatsächlich gerade in der Ergebnismenge befinden). Wenn Sie mysql_store_result() oder mysql_list_fields() benutzen, enthält dieser Wert die Höchstlänge für das Feld. Wenn Sie mysql_use_result() aufrufen, ist der Wert dieser Variablen null.

  • unsigned int name_length

    Die Länge von name.

  • unsigned int org_name_length

    Die Länge von org_name.

  • unsigned int table_length

    Die Länge von table.

  • unsigned int org_table_length

    Die Länge von org_table.

  • unsigned int db_length

    Die Länge von db.

  • unsigned int catalog_length

    Die Länge von catalog.

  • unsigned int def_length

    Die Länge von def.

  • unsigned int flags

    Verschiedene Bit-Flags für das Feld. Im Wert von flags können null oder mehr der folgenden Bits gesetzt sein:

    Flag-WertFlag-Beschreibung
    NOT_NULL_FLAGFeld kann nicht NULL sein
    PRI_KEY_FLAGFeld ist Teil eines Primärschlüssels
    UNIQUE_KEY_FLAGFeld ist Teil eines eindeutigen Schlüssels
    MULTIPLE_KEY_FLAGFeld ist Teil eines nichteindeutigen Schlüssels
    UNSIGNED_FLAGFeld hat das Attribut UNSIGNED
    ZEROFILL_FLAGFeld hat das Attribut ZEROFILL
    BINARY_FLAGFeld hat das Attribut BINARY
    AUTO_INCREMENT_FLAGFeld hat das Attribut AUTO_INCREMENT
    ENUM_FLAGFeld ist eine ENUM (veraltet)
    SET_FLAGFeld ist ein SET (veraltet)
    BLOB_FLAGFeld ist ein BLOB oder TEXT (veraltet)
    TIMESTAMP_FLAGFeld ist ein TIMESTAMP (veraltet)

    Die Flags BLOB_FLAG, ENUM_FLAG, SET_FLAG, und TIMESTAMP_FLAG sind veraltet, da sie keinen Attribut-, sondern einen Feldtyp angeben. Es ist besser, den field->type mit MYSQL_TYPE_BLOB, MYSQL_TYPE_ENUM, MYSQL_TYPE_SET oder MYSQL_TYPE_TIMESTAMP zu vergleichen.

    Das folgende Beispiel zeigt eine typische Verwendung des flags-Werts:

    if (field->flags & NOT_NULL_FLAG)
        printf("Field can't be null\n");
    

    Mit den folgenden Makros können Sie den booleschen Status des flags-Werts nachschauen:

    Flag-StatusBeschreibung
    IS_NOT_NULL(flags)Ist wahr, wenn dieses Feld als NOT NULL definiert ist
    IS_PRI_KEY(flags)Ist wahr, wenn dieses Feld ein Primärschlüssel ist
    IS_BLOB(flags)Ist wahr, wenn dieses Feld ein BLOB oder TEXT ist (veraltet; bitte testen Sie stattdessen field->type)
  • unsigned int decimals

    Die Anzahl der Dezimalstellen für numerische Felder.

  • unsigned int charset_nr

    Die Nummer des Zeichensatzes für das Feld.

  • enum enum_field_types type

    Der Typ des Felds. Der type-Wert kann eines der MYSQL_TYPE_-Symbole aus der folgenden Tabelle sein.

    TypwertTypbeschreibung
    MYSQL_TYPE_TINYTINYINT-Feld
    MYSQL_TYPE_SHORTSMALLINT-Feld
    MYSQL_TYPE_LONGINTEGER-Feld
    MYSQL_TYPE_INT24MEDIUMINT-Feld
    MYSQL_TYPE_LONGLONGBIGINT-Feld
    MYSQL_TYPE_DECIMALDECIMAL- oder NUMERIC-Feld
    MYSQL_TYPE_NEWDECIMALDECIMAL- oder NUMERIC-Typ für Präzisionsberechnungen
    MYSQL_TYPE_FLOATFLOAT-Feld
    MYSQL_TYPE_DOUBLEDOUBLE- oder REAL-Feld
    MYSQL_TYPE_BITBIT-Feld
    MYSQL_TYPE_TIMESTAMPTIMESTAMP-Feld
    MYSQL_TYPE_DATEDATE-Feld
    MYSQL_TYPE_TIMETIME-Feld
    MYSQL_TYPE_DATETIMEDATETIME-Feld
    MYSQL_TYPE_YEARYEAR-Feld
    MYSQL_TYPE_STRINGCHAR- oder BINARY-Feld
    MYSQL_TYPE_VAR_STRINGVARCHAR- oder VARBINARY-Feld
    MYSQL_TYPE_BLOBBLOB- oder TEXT-Feld (die Maximallänge wird mit max_length ermittelt)
    MYSQL_TYPE_SETSET-Feld
    MYSQL_TYPE_ENUMENUM-Feld
    MYSQL_TYPE_GEOMETRYFeld eines raumbezogenen Typs
    MYSQL_TYPE_NULLFeld mit NULL-Typ
    MYSQL_TYPE_CHARVeraltet; verwenden Sie stattdessen MYSQL_TYPE_TINY

    Mit dem Makro IS_NUM() können Sie testen, ob ein Feld einen numerischen Typ hat. Wenn Sie den type-Wert an IS_NUM() übergeben und TRUE zurückgeliefert wird, ist das Feld numerisch:

    if (IS_NUM(field->type))
        printf("Field is numeric\n");
    

24.2.2. C-API: Funktionsüberblick

Die Funktionen der C-API werden im Folgenden zusammengefasst und in einem späteren Abschnitt genauer beschrieben. Siehe hierzu Abschnitt 24.2.3, „C-API: Funktionsbeschreibungen“.

FunktionBeschreibung
mysql_affected_rows()Liefert die Anzahl der mit dem letzten UPDATE, DELETE oder INSERT geänderten/gelöschten/eingefügten Zeilen
mysql_autocommit()Schaltet Autocommit ein oder aus
mysql_change_user()Ändert den Benutzer und die Datenbank für eine offene Verbindung
mysql_charset_name()Liefert den Namen des Standardzeichensatzes für die Verbindung
mysql_close()Schließt eine Serververbindung
mysql_commit()Committet die Transaktion.
mysql_connect()Verbindet sich mit einem MySQL Server. Diese Funktion ist veraltet; verwenden Sie stattdessen mysql_real_connect().
mysql_create_db()Legt eine Datenbank an. Diese Funktion ist veraltet; verwenden Sie stattdessen die SQL-Anweisung CREATE DATABASE.
mysql_data_seek()Sucht in der Ergebnismenge einer Anfrage eine beliebige Datenzeile
mysql_debug()Führt ein DBUG_PUSH mit dem angegebenen String durch
mysql_drop_db()Löscht eine Datenbank. Diese Funktion ist veraltet; verwenden Sie stattdessen die SQL-Anweisung DROP DATABASE.
mysql_dump_debug_info()Lässt den Server Debugginginformationen in das Log schreiben
mysql_eof()Stellt fest, ob die letzte Zeile einer Ergebnismenge gelesen wurde. Diese Funktion ist veraltet; verwenden Sie stattdessen mysql_errno() oder mysql_error().
mysql_errno()Liefert die Fehlernummer für die zuletzt aufgerufene MySQL-Funktion
mysql_error()Liefert die Fehlermeldung für die zuletzt aufgerufene MySQL-Funktion
mysql_escape_string()Versieht Sonderzeichen in einem String, der in einer SQL-Anweisung benutzt werden soll, mit Escape-Symbolen
mysql_fetch_field()Liefert den Typ des nächsten Tabellenfelds.
mysql_fetch_field_direct()Liefert den Typ des Tabellenfelds mit der gegebenen Feldnummer
mysql_fetch_fields()Liefert ein Array aller Feldstrukturen
mysql_fetch_lengths()Liefert die Längen aller Spalten der aktuellen Zeile
mysql_fetch_row()Holt die nächste Zeile der Ergebnismenge ab
mysql_field_seek()Setzt den Spalten-Cursor auf eine gegebene Spalte
mysql_field_count()Liefert die Anzahl der Ergebnisspalten der letzten Anweisung
mysql_field_tell()Liefert die Position des Feld-Cursors, der für das letzte mysql_fetch_field() verwendet wurde
mysql_free_result()Gibt den von einer Ergebnismenge belegten Speicher frei
mysql_get_client_info()Liefert Versionsinformationen für den Client als String
mysql_get_client_version()Liefert Versionsinformationen für den Client als Integer
mysql_get_host_info()Liefert einen String, der die Verbindung beschreibt
mysql_get_server_version()Liefert die Versionsnummer des Servers als Integer.
mysql_get_proto_info()Liefert die Protokollversion der Verbindung
mysql_get_server_info()Liefert die Versionsnummer des Servers
mysql_info()Liefert Informationen über die zuletzt ausgeführte Anfrage
mysql_init()Holt oder initialisiert eine MYSQL-Struktur
mysql_insert_id()Liefert die für eine AUTO_INCREMENT-Spalte von der vorhergehenden Anfrage generierte ID
mysql_kill()Hält einen gegebenen Thread an
mysql_library_end()Finalisiert die MySQL-C-API-Bibliothek
mysql_library_init()Initialisiert die MySQL-C-API-Bibliothek
mysql_list_dbs()Liefert Datenbanknamen, die mit einem einfachen regulären Ausdruck übereinstimmen
mysql_list_fields()Liefert Feldnamen, die mit einem einfachen regulären Ausdruck übereinstimmen
mysql_list_processes()Liefert eine Liste der aktuellen Server-Threads
mysql_list_tables()Liefert Tabellennamen, die mit einem einfachen regulären Ausdruck übereinstimmen
mysql_more_results()Prüft, ob noch weitere Ergebnisse vorhanden sind
mysql_next_result()Liefert/initiiert das nächste Ergebnis für Mehrfachanweisungen
mysql_num_fields()Liefert die Anzahl der Spalten einer Ergebnismenge
mysql_num_rows()Liefert die Anzahl der Zeilen einer Ergebnismenge
mysql_options()Stellt Verbindungsoptionen für mysql_connect() ein
mysql_ping()Prüft, ob die Serververbindung funktioniert, und baut bei Bedarf eine neue Verbindung auf
mysql_query()Führt eine SQL-Anfrage aus, die als auf null endender String angegeben ist.
mysql_real_connect()Verbindet sich mit einem MySQL Server
mysql_real_escape_string()Versieht Sonderzeichen in einem String, der in einer SQL-Anweisung benutzt werden soll, mit Escape-Symbolen, wobei der aktuelle Zeichensatz der Verbindung berücksichtigt wird
mysql_real_query()Führt eine als abgezählter String angegebene SQL-Anfrage aus
mysql_refresh()Schreibt Tabellen und Caches auf die Platte zurück oder setzt sie zurück
mysql_reload()Lässt den Server die Berechtigungstabellen neu laden
mysql_rollback()Rollt die Transaktion zurück
mysql_row_seek()Findet einen Zeilen-Offset in einer Ergebnismenge anhand des Rückgabewerts von mysql_row_tell()
mysql_row_tell()Liefert die Position des Zeilen-Cursors
mysql_select_db()Wählt eine Datenbank aus
mysql_server_end()Finalisiert die Embedded Server-Bibliothek
mysql_server_init()Initialisiert die Embedded Server-Bibliothek
mysql_set_server_option()Setzt eine Option für die Verbindung (wie multi-statements)
mysql_sqlstate()Liefert den SQLSTATE-Fehlercode für den letzten Fehler
mysql_shutdown()Fährt den Datenbankserver herunter
mysql_stat()Liefert den Serverstatus als String
mysql_store_result()Holt eine vollständige Ergebnismenge auf den Client
mysql_thread_id()Liefert die aktuelle Thread-ID
mysql_thread_safe()Liefert 1, wenn die Clients als Thread-sicher kompiliert wurden
mysql_use_result()Initiiert einen zeilenweisen Abruf der Ergebnismenge
mysql_warning_count()Liefert die Anzahl der Warnungen für die vorangehende SQL-Anweisung

Anwendungsprogramme sollten sich an folgende Vorgehensweise halten, wenn sie mit MySQL zusammenarbeiten wollen:

  1. Sie initialisieren die MySQL-Bibliothek durch Aufruf von mysql_library_init(). Die Bibliothek kann entweder die mysqlclient-C-Clientbibliothek oder die mysqld-Embedded Server-Bibliothek sein, je nachdem, ob die Anwendung mit dem Flag -libmysqlclient oder -libmysqld verlinkt worden ist.

  2. Sie initialisieren einen Verbindungs-Handler durch Aufruf von mysql_init() und verbinden sich durch mysql_real_connect() mit dem Server.

  3. Sie geben ihre SQL-Anweisungen und verarbeiten die Ergebnisse. (Im Folgenden wird genauer beschrieben, wie dies getan wird.)

  4. Sie schließen die Verbindung zum MySQL Server durch Aufruf von mysql_close().

  5. Sie beenden die Nutzung der MySQL-Bibliothek durch Aufruf von mysql_library_end().

mysql_library_init() und mysql_library_end() werden aufgerufen, um die MySQL-Bibliothek richtig zu initialisieren und zu finalisieren. Für Anwendungen, die mit der Clientbibliothek verlinkt sind, bietet diese Funktionen eine verbesserte Speicherverwaltung. Wenn Sie mysql_library_end() nicht aufrufen, bleibt weiterhin ein Arbeitsspeicherblock reserviert. (Zwar belegt die Anwendung deswegen nicht mehr Speicher, aber bestimmte Detektoren für Speicherlecks würden sich beschweren.) Für Anwendungen, die mit dem Embedded Server verlinkt sind, starten und stoppen diese Aufrufe den Server.

mysql_library_init() und mysql_library_end() sind in Wirklichkeit #define-Symbole und somit äquivalent zu mysql_server_init() und mysql_server_end(), aber die anderen Namen betonen stärker, dass diese Funktionen immer vor und nach der Benutzung einer MySQL-Bibliothek aufgerufen werden müssen, egal ob die Anwendung die mysqlclient- oder die mysqld-Bibliothek verwendet. In älteren MySQL-Versionen können Sie stattdessen mysql_server_init() und mysql_server_end() aufrufen.

Sie können den Aufruf von mysql_library_init() auch weglassen, da mysql_init() diese Funktion automatisch aufruft, wenn es notwendig ist.

Um sich mit dem Server zu verbinden, initialisieren Sie mit mysql_init() einen Verbindungs-Handler und rufen mysql_real_connect() mit diesem Handler (sowie anderen Informationen, wie zum Beispiel Hostname, Benutzername und Passwort) auf. Beim Verbinden setzt mysql_real_connect() das reconnect-Flag (ein Teil der MYSQL-Struktur) auf den Wert 1, wenn die API-Version älter als 5.0.3 ist, oder auf 0, wenn sie neuer ist. Wenn dieses Flag den Wert 1 hat, bedeutet dies: Falls eine Anweisung wegen Verbindungsabbruchs nicht ausgeführt werden kann, versucht das System, sich erneut mit dem Server zu verbinden, ehe es aufgibt. Seit MySQL 5.0.13 können Sie das Verhalten in Bezug auf Neuverbindungen mit der Option MYSQL_OPT_RECONNECT von mysql_options() steuern. Wenn Sie die Verbindung nicht mehr benötigen, beenden Sie sie mit mysql_close().

Während eine Verbindung aktiv ist, kann der Client SQL-Anweisungen mit mysql_query() oder mysql_real_query() an den Server senden. Der Unterschied ist der, dass mysql_query() die Anfrage als auf null endenden String erwartet, während mysql_real_query() mit einem abgezählten String rechnet. Wenn der String Binärdaten enthält (die auch Nullbytes umfassen können), müssen Sie mysql_real_query() verwenden.

Für alle Nicht-SELECT-Anfragen (beispielsweise INSERT, UPDATE, DELETE) können Sie die Anzahl der betroffenen Zeilen durch mysql_affected_rows() ermitteln.

Bei SELECT-Anfragen rufen Sie die betroffenen Zeilen als Ergebnismenge ab. (Beachten Sie, dass manche Anweisungen insofern SELECT-ähnlich sind, als sie Zeilen zurückliefern. Dazu gehören SHOW, DESCRIBE und EXPLAIN. Diese sollten ebenso wie SELECT-Anweisungen behandelt werden.)

Ein Client hat zwei Möglichkeiten, mit Ergebnismengen umzugehen: Erstens kann er die gesamte Ergebnismenge in einem Schwung abholen, indem er mysql_store_result() aufruft. Diese Funktion holt sich vom Server alle von der Anfrage gelieferten Zeilen und speichert sie auf dem Client. Die zweite Möglichkeit besteht darin, die Ergebnismenge mit mysql_use_result() zeilenweise abzurufen. Diese Funktion initialisiert den Datenabruf, holt aber die Zeilen vom Server nicht wirklich ab.

In beiden Fällen greifen Sie mit mysql_fetch_row() auf die Zeilen zu. Mit mysql_store_result() greift sich mysql_fetch_row() Zeilen, die vom Server bereits abgeholt worden sind. Mit mysql_use_result() ruft mysql_fetch_row() die jeweilige Zeile selbst vom Server. Informationen über den Umfang der Daten in den Zeilen liefert Ihnen mysql_fetch_lengths().

Wenn Sie mit einer Ergebnismenge fertig sind, geben Sie mit mysql_free_result() ihren Arbeitsspeicher wieder frei.

Die beiden Abrufmechanismen ergänzen einander. Clientprogramme sollten den Ansatz verfolgen, der für ihre Zwecke am besten geeignet ist. In der Praxis wird mysql_store_result() von den Clients häufiger verwendet.

mysql_store_result() hat einen Vorteil. Da bereits alle Zeilen auf den Client geladen wurden, können Sie nicht nur der Reihe nach auf sie zugreifen, sondern sich mit mysql_data_seek() oder mysql_row_seek() in der Ergebnismenge vor- und zurückbewegen und auf eine andere Zeilenposition in der Ergebnismenge gehen. Sie können überdies mit mysql_num_rows() herausfinden, wie viele Zeilen die Ergebnismenge hat. Allerdings kann mysql_store_result() bei großen Ergebnismengen auch viel Speicher belegen, wodurch die Gefahr von out-of-memory-Bedingungen wächst.

mysql_use_result() hat den Vorteil, dass der Client nicht so viel Arbeitsspeicher für die Ergebnismenge benötigt, da er immer nur eine einzige Zeile speichern muss (und durch den geringeren Aufwand bei der Zuweisung kann mysql_use_result() überdies schneller sein). Die Nachteile: Sie müssen jede Zeile schnell verarbeiten, um den Server nicht aufzuhalten, und Sie haben keinen beliebigen Zugriff auf die Ergebnismenge (sondern können nur sequenziell auf die Zeilen zugreifen). Außerdem kennen Sie die Anzahl der Zeilen in der Ergebnismenge erst, wenn Sie sie alle abgeholt haben. Hinzu kommt, dass Sie sämtliche Zeilen abholen müssen, und zwar selbst dann, wenn Sie mitten in der Verarbeitung die gesuchten Informationen bereits gefunden haben.

Den Clients ermöglicht diese API, auf Anweisungen in angemessener Form zu reagieren (also die Zeilen nur nach Bedarf abzuholen), ohne zu wissen, ob die Anweisung ein SELECT ist. Dies erreichen Sie, indem Sie mysql_store_result() nach jeder mysql_query() (oder mysql_real_query()) aufrufen. Wenn der Ergebnismengenaufruf Erfolg hat, war die Anweisung ein SELECT und Sie können die Zeilen einlesen. Schlägt der Ergebnismengenaufruf fehl, so ermitteln Sie mit mysql_field_count(), ob überhaupt ein Ergebnis zu erwarten war. Wenn mysql_field_count() null zurückliefert, ergab die Anweisung keine Daten (war also ein INSERT, UPDATE, DELETE oder etwas Ähnliches), von denen man auch keine Rückgabezeilen erwarten konnte. Wenn mysql_field_count() einen von null verschiedenen Wert hat, hätte die Anweisung eigentlich Zeilen zurückgeben sollen, hat es aber nicht getan. Dies deutet auf eine fehlgeschlagene SELECT-Anweisung hin. Ein Beispiel finden Sie unter mysql_field_count().

Sowohl mysql_store_result() als auch mysql_use_result() liefern Ihnen Informationen über die Felder, aus denen die Ergebnismenge besteht (die Anzahl der Felder, ihre Namen und Typen und so weiter). Sie können auf die Feldinformationen in der Zeile sequenziell zugreifen, indem Sie wiederholt mysql_fetch_field() aufrufen, oder anhand der Feldnummer, indem Sie mysql_fetch_field_direct() aufrufen. Die aktuelle Cursor-Position für das Feld können Sie durch mysql_field_seek() ändern. Wenn Sie den Feld-Cursor verstellen, wirkt sich das auf nachfolgende mysql_fetch_field()-Aufrufe aus. Sie können die Feldinformationen auch alle auf einmal abholen, indem Sie mysql_fetch_fields() aufrufen.

Um Fehler zu entdecken und zu melden, gibt Ihnen MySQL über die Funktionen mysql_errno() und mysql_error() Zugriff auf Fehlerinformationen. Diese Funktionen geben den Fehlercode oder die Fehlermeldung für die zuletzt aufgerufene Funktion zurück, die mit oder ohne Erfolg gelaufen sein kann. So können Sie ermitteln, wann welcher Fehler aufgetreten ist.

24.2.3. C-API: Funktionsbeschreibungen

24.2.3.1. mysql_affected_rows()
24.2.3.2. mysql_autocommit()
24.2.3.3. mysql_change_user()
24.2.3.4. mysql_character_set_name()
24.2.3.5. mysql_close()
24.2.3.6. mysql_commit()
24.2.3.7. mysql_connect()
24.2.3.8. mysql_create_db()
24.2.3.9. mysql_data_seek()
24.2.3.10. mysql_debug()
24.2.3.11. mysql_drop_db()
24.2.3.12. mysql_dump_debug_info()
24.2.3.13. mysql_eof()
24.2.3.14. mysql_errno()
24.2.3.15. mysql_error()
24.2.3.16. mysql_escape_string()
24.2.3.17. mysql_fetch_field()
24.2.3.18. mysql_fetch_field_direct()
24.2.3.19. mysql_fetch_fields()
24.2.3.20. mysql_fetch_lengths()
24.2.3.21. mysql_fetch_row()
24.2.3.22. mysql_field_count()
24.2.3.23. mysql_field_seek()
24.2.3.24. mysql_field_tell()
24.2.3.25. mysql_free_result()
24.2.3.26. mysql_get_character_set_info()
24.2.3.27. mysql_get_client_info()
24.2.3.28. mysql_get_client_version()
24.2.3.29. mysql_get_host_info()
24.2.3.30. mysql_get_proto_info()
24.2.3.31. mysql_get_server_info()
24.2.3.32. mysql_get_server_version()
24.2.3.33. mysql_hex_string()
24.2.3.34. mysql_info()
24.2.3.35. mysql_init()
24.2.3.36. mysql_insert_id()
24.2.3.37. mysql_kill()
24.2.3.38. mysql_library_end()
24.2.3.39. mysql_library_init()
24.2.3.40. mysql_list_dbs()
24.2.3.41. mysql_list_fields()
24.2.3.42. mysql_list_processes()
24.2.3.43. mysql_list_tables()
24.2.3.44. mysql_more_results()
24.2.3.45. mysql_next_result()
24.2.3.46. mysql_num_fields()
24.2.3.47. mysql_num_rows()
24.2.3.48. mysql_options()
24.2.3.49. mysql_ping()
24.2.3.50. mysql_query()
24.2.3.51. mysql_real_connect()
24.2.3.52. mysql_real_escape_string()
24.2.3.53. mysql_real_query()
24.2.3.54. mysql_refresh()
24.2.3.55. mysql_reload()
24.2.3.56. mysql_rollback()
24.2.3.57. mysql_row_seek()
24.2.3.58. mysql_row_tell()
24.2.3.59. mysql_select_db()
24.2.3.60. mysql_set_character_set()
24.2.3.61. mysql_set_server_option()
24.2.3.62. mysql_shutdown()
24.2.3.63. mysql_sqlstate()
24.2.3.64. mysql_ssl_set()
24.2.3.65. mysql_stat()
24.2.3.66. mysql_store_result()
24.2.3.67. mysql_thread_id()
24.2.3.68. mysql_use_result()
24.2.3.69. mysql_warning_count()

In den folgenden Beschreibungen meint ein Parameter oder Rückgabewert von NULL einen NULL-Wert im Sinne der Programmiersprache C und keinen NULL-Wert von MySQL.

Funktionen, die einen Wert liefern, geben normalerweise einen Zeiger oder einen Integer zurück. Wenn nichts anderes angegeben ist, liefern Funktionen, die einen Zeiger zurückgeben, bei Erfolg einen von NULL verschiedenen Wert und bei Misserfolg einen NULL-Wert, und Funktionen, die einen Integer liefern, geben bei Erfolg null und bei Misserfolg einen von null verschiedenen Wert zurück. Beachten Sie, dass „von null verschieden“ genau das meint, was es sagt: Sofern die Funktionsbeschreibung nichts Abweichendes festlegt, können Sie diesen Wert mit nichts anderem als null vergleichen:

if (result)                   /* richtig */
    ... error ...

if (result < 0)               /* falsch */
    ... error ...

  if (result == -1)             /* falsch */
    ... error ...

Wenn eine Funktion einen Fehler zurückliefert, finden Sie im Unterabschnitt Fehler der jeweiligen Funktionsbeschreibung eine Liste der möglichen Fehlertypen. Welcher dieser Fehler auftrat, ermitteln Sie mit mysql_errno(). Eine String-Darstellung des Fehlers erhalten Sie durch mysql_error().

24.2.3.1. mysql_affected_rows()

my_ulonglong mysql_affected_rows(MYSQL *mysql)

Beschreibung

Liefert die Anzahl der vom letzten UPDATE aktualisierten, vom letzten DELETE gelöschten oder vom letzten INSERT eingefügten Zeilen. Kann für UPDATE-, DELETE- oder INSERT-Anweisungen direkt nach mysql_query() aufgerufen werden. Bei SELECT-Anweisungen funktioniert mysql_affected_rows() genau wie mysql_num_rows().

Rückgabewerte

Ein Integer größer null zeigt die Anzahl der betroffenen oder abgerufenen Zeilen an. Null bedeutet, dass mit dem UPDATE keine Zeilen aktualisiert wurden, dass keine Zeilen zu der WHERE-Klausel der Anfrage gepasst haben oder die Anfrage noch gar nicht ausgeführt worden ist. -1 bedeutet, dass die Anfrage einen Fehler zurückgeliefert hat oder, bei einer SELECT-Anfrage, dass mysql_affected_rows() vor mysql_store_result() aufgerufen wurde. Da mysql_affected_rows() einen vorzeichenlosen Wert liefert, können Sie -1 feststellen, indem Sie den Rückgabewert mit (my_ulonglong)-1 vergleichen (oder mit (my_ulonglong)~0; das ist dasselbe).

Fehler

Keine.

Beispiel

mysql_query(&mysql,"UPDATE products SET cost=cost*1.25 WHERE group=10");
printf("%ld products updated",(long) mysql_affected_rows(&mysql));

Wenn Sie bei einer Verbindung mit mysqld das Flag CLIENT_FOUND_ROWS angeben, liefert mysql_affected_rows() die Anzahl der Zeilen, die die WHERE-Klausel von UPDATE-Anweisungen erkannt hat.

Beachten Sie, dass mysql_affected_rows() bei Verwendung eines REPLACE-Befehls 2 liefert, wenn die neue Zeile eine alte ersetzt, da hier eine Zeile eingefügt wird, nachdem das Duplikat gelöscht worden ist.

Wenn Sie mit INSERT ... ON DUPLICATE KEY UPDATE eine Zeile einfügen, liefert mysql_affected_rows() den Wert 1, wenn die Zeile als neue Zeile eingefügt wurde, und 2, wenn eine vorhandene Zeile geändert wurde.

24.2.3.2. mysql_autocommit()

my_bool mysql_autocommit(MYSQL *mysql, my_bool mode)

Beschreibung

Schaltet den Autocommit-Modus ein, wenn mode 1 ist, und aus, wenn mode 0 ist.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

Keine.

24.2.3.3. mysql_change_user()

my_bool mysql_change_user(MYSQL *mysql, const char *user, const char *password, const char *db)

Beschreibung

Wechselt auf der durch mysql angegebenen Verbindung den Benutzer und macht die in db angegebene zur (aktuellen) Standarddatenbank. In nachfolgenden Anfragen ist diese Datenbank dann der Standardbezugsrahmen für Tabellenverweise, die nicht explizit eine Datenbank angeben.

mysql_change_user() scheitert, wenn der Benutzer sich nicht authentifizieren kann oder keine Berechtigung zur Nutzung der Datenbank hat. In diesem Fall werden Benutzer und Datenbank nicht geändert.

Der Parameter db kann auf NULL gesetzt werden, wenn keine Standarddatenbank vorgegeben werden soll.

Dieser Befehl veranlasst immer ein ROLLBACK aller laufenden Transaktionen, schließt alle temporären Tabellen, hebt Tabellensperren auf und setzt den Status so zurück, als hätte jemand eine ganz neue Verbindung aufgebaut. Das geschieht sogar dann, wenn der Benutzer nicht wechselt.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

Dieselben wie bei mysql_real_connect().

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

  • ER_UNKNOWN_COM_ERROR

    Der MySQL Server implementiert diesen Befehl gar nicht (wahrscheinlich ein älterer Server).

  • ER_ACCESS_DENIED_ERROR

    Benutzer oder Passwort ist falsch.

  • ER_BAD_DB_ERROR

    Die Datenbank existiert nicht.

  • ER_DBACCESS_DENIED_ERROR

    Der Benutzer hat keine Zugriffsrechte auf die Datenbank.

  • ER_WRONG_DB_NAME

    Der Datenbankname war zu lang.

Beispiel

if (mysql_change_user(&mysql, "user", "password", "new_database"))
{
   fprintf(stderr, "Failed to change user.  Error: %s\n",
           mysql_error(&mysql));
}

24.2.3.4. mysql_character_set_name()

const char *mysql_character_set_name(MYSQL *mysql)

Beschreibung

Gibt den Standardzeichensatz für die aktuelle Verbindung zurück.

Rückgabewerte

Der Standardzeichensatz.

Fehler

Keine.

24.2.3.5. mysql_close()

void mysql_close(MYSQL *mysql)

Beschreibung

mysql_close() schließt eine zuvor geöffnete Verbindung und gibt den Verbindungs-Handle frei, den mysql benutzt hat, wenn der Handle automatisch von mysql_init() oder mysql_connect() zugewiesen worden war.

Rückgabewerte

Keine.

Fehler

Keine.

24.2.3.6. mysql_commit()

my_bool mysql_commit(MYSQL *mysql)

Beschreibung

Committet die laufende Transaktion.

Was diese Funktion tut, hängt von dem Wert der Systemvariablen completion_type ab. Wenn der completion_type 2 ist, gibt der Server nach Beendigung der Transaktion Ressourcen frei und schließt die Clientverbindung. Das Clientprogramm sollte mysql_close() aufrufen, um die Verbindung von der Clientseite aus zu schließen.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

Keine.

24.2.3.7. mysql_connect()

MYSQL *mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd)

Beschreibung

Diese Funktion ist veraltet. Stattdessen sollte mysql_real_connect() verwendet werden.

mysql_connect() versucht, eine Verbindung zu einer auf dem host laufenden MySQL-Datenbank-Engine herzustellen. mysql_connect() muss erfolgreich gelaufen sein, ehe Sie irgendeine der anderen API-Funktionen ausführen können, ausgenommen mysql_get_client_info().

Die Parameter haben dieselbe Bedeutung wie die entsprechenden Parameter für mysql_real_connect(), mit dem Unterschied, dass der Verbindungsparameter NULL sein kann. In diesem Fall weist die C-API automatisch Speicher für die Verbindungsstruktur zu und gibt ihn wieder frei, wenn Sie mysql_close() aufrufen. Der Nachteil: Sie können keine Fehlermeldung abrufen, wenn die Verbindung scheitert. (Um von mysql_errno() oder mysql_error() Fehlerinformationen zu bekommen, müssen Sie einen gültigen MYSQL-Zeiger zur Verfügung stellen.)

Rückgabewerte

Dieselben wie für mysql_real_connect().

Fehler

Dieselben wie für mysql_real_connect().

24.2.3.8. mysql_create_db()

int mysql_create_db(MYSQL *mysql, const char *db)

Beschreibung

Legt die im db-Parameter genannte Datenbank an.

Diese Funktion ist veraltet. Bitte verwenden Sie stattdessen mysql_query(), um eine SQL-CREATE DATABASE-Anweisung zu geben.

Rückgabewerte

Null, wenn die Datenbank erfolgreich angelegt wurde, und ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

if(mysql_create_db(&mysql, "my_database"))
{
   fprintf(stderr, "Failed to create new database.  Error: %s\n",
           mysql_error(&mysql));
}

24.2.3.9. mysql_data_seek()

void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset)

Beschreibung

Findet eine beliebige Zeile in einer Ergebnismenge. Der offset-Wert ist eine Zeilennummer zwischen 0 und mysql_num_rows(result)-1.

Da für diese Funktion erforderlich ist, dass die Ergebnismengenstruktur die gesamte Ergebnismenge enthält, kann mysql_data_seek() nur in Verbindung mit mysql_store_result() und nicht mit mysql_use_result() verwendet werden.

Rückgabewerte

Keine.

Fehler

Keine.

24.2.3.10. mysql_debug()

void mysql_debug(const char *debug)

Beschreibung

Führt DBUG_PUSH auf dem gegebenen String aus. mysql_debug() benutzt die Fred Fish-Debugbibliothek. Um diese Funktion benutzen zu können, müssen Sie die Clientbibliothek mit Debuggingunterstützung kompilieren. Siehe Abschnitt E.1, „Einen MySQL-Server debuggen“ und Abschnitt E.2, „Einen MySQL-Client debuggen“.

Rückgabewerte

Keine.

Fehler

Keine.

Beispiel

Dieser Aufruf lässt die Clientbibliothek eine Trace-Datei iin /tmp/client.trace auf dem Clientcomputer generieren:

mysql_debug("d:t:O,/tmp/client.trace");

24.2.3.11. mysql_drop_db()

int mysql_drop_db(MYSQL *mysql, const char *db)

Beschreibung

Löscht die im db-Parameter angegebene Datenbank.

Diese Funktion ist veraltet. Bitte benutzen Sie stattdessen mysql_query(), um eine SQL-DROP DATABASE-Anweisung zu erteilen.

Rückgabewerte

Null, wenn die Datenbank erfolgreich gelöscht wurde. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

if(mysql_drop_db(&mysql, "my_database"))
  fprintf(stderr, "Failed to drop the database: Error: %s\n",
          mysql_error(&mysql));

24.2.3.12. mysql_dump_debug_info()

int mysql_dump_debug_info(MYSQL *mysql)

Beschreibung

Weist den Server an, Debugginginformationen in das Log zu schreiben. Damit dies funktioniert, benötigt der Benutzer das SUPER-Recht.

Rückgabewerte

Null, wenn der Befehl Erfolg hatte. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.13. mysql_eof()

my_bool mysql_eof(MYSQL_RES *result)

Beschreibung

Diese Funktion ist veraltet. mysql_errno() oder mysql_error() können stattdessen verwendet werden.

mysql_eof() stellt fest, ob die letzte Zeile einer Ergebnismenge gelesen worden ist.

Wenn Sie eine Ergebnismenge mit einem erfolgreichen Aufruf von mysql_store_result() abrufen, empfängt der Client die gesamte Menge mit einer einzigen Operation. Der Rückgabewert NULL von mysql_fetch_row() bedeutet in diesem Fall immer, dass das Ende der Ergebnismenge erreicht wurde, sodass sich mysql_eof() erübrigt. In Verbindung mit mysql_store_result() liefert mysql_eof() immer TRUE.

Wenn Sie dagegen den Abruf einer Ergebnismenge mit mysql_use_result() initiieren, werden die Zeilen eine nach der anderen mit wiederholten mysql_fetch_row()-Aufrufen vom Server geholt. Da bei diesem Prozess ein Verbindungsfehler auftreten kann, bedeutet eine NULL-Rückgabe von mysql_fetch_row() nicht unbedingt, dass ganz normal das Ende der Ergebnismenge erreicht wurde. In diesem Fall können Sie mit mysql_eof() feststellen, was tatsächlich geschah. mysql_eof() liefert einen von null verschiedenen Wert, wenn das Ende der Ergebnismenge erreicht wurde, und null, wenn ein Fehler auftrat.

Eigentlich ist mysql_eof() älter als die MySQL-Standardfehlerfunktionen mysql_errno() und mysql_error(). Da diese Fehlerfunktionen dieselben Informationen liefern, bevorzugen wir sie gegenüber der veralteten Funktion mysql_eof(). (Eigentlich geben sie sogar mehr Informationen, da mysql_eof() nur einen booleschen Wert zurückgibt, während die Fehlerfunktionen auch den Grund für einen Fehler verraten.)

Rückgabewerte

Null, wenn kein Fehler auftrat. Ein von null verschiedener Wert, wenn das Ende der Ergebnismenge erreicht wurde.

Fehler

Keine.

Beispiel

Das folgende Beispiel zeigt, wie sich mysql_eof() einsetzen lässt:

mysql_query(&mysql,"SELECT * FROM some_table");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result)))
{
    // Tu etwas mit den Daten
}
if(!mysql_eof(result))  // mysql_fetch_row() scheiterte wegen eines Fehlers
{
    fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}

Sie können jedoch denselben Effekt auch mit den Standardfehlerfunktionen von MySQL erzielen:

mysql_query(&mysql,"SELECT * FROM some_table");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result)))
{
  // Tu etwas mit den Daten
}
  if(mysql_errno(&mysql))  // mysql_fetch_row() scheiterte wegen eines Fehlers
{
    fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}

24.2.3.14. mysql_errno()

unsigned int mysql_errno(MYSQL *mysql)

Beschreibung

Für die von mysql angegebene Verbindung liefert mysql_errno() den Fehlercode zu der zuletzt aufgerufenen API-Funktion, die mit Erfolg gelaufen oder gescheitert sein kann. Der Rückgabewert null bedeutet, dass kein Fehler auftrat. Die Nummern der Clientfehlermeldungen sind in der MySQL-Header-Datei errmsg.h aufgelistet. Die Nummern der Serverfehlermeldungen stehen in der Datei mysqld_error.h. Außerdem werden die Fehler in Anhang B, Fehlercodes und -meldungen, aufgeführt.

Beachten Sie, dass manche Funktionen, wie etwa mysql_fetch_row(), keine mysql_errno() setzen, wenn sie Erfolg haben.

Als Faustregel gilt: Alle Funktionen, die vom Server Informationen abfragen müssen, setzen mysql_errno() zurück, wenn sie Erfolg hatten.

Rückgabewerte

Ein Fehlercodewert für den letzten mysql_xxx()-Aufruf, wenn dieser gescheitert ist. Null bedeutet, dass kein Fehler auftrat.

Fehler

Keine.

24.2.3.15. mysql_error()

const char *mysql_error(MYSQL *mysql)

Beschreibung

Für die durch mysql angegebene Verbindung liefert mysql_error() einen auf null endenden String mit der Fehlermeldung für die zuletzt aufgerufene API-Funktion, die gescheitert ist. Wenn keine Funktion gescheitert ist, kann der Rückgabewert von mysql_error() auch der vorherige Fehler oder ein leerer String sein, der anzeigt, dass kein Fehler auftrat.

Als Faustregel gilt: Alle Funktionen, die vom Server Informationen abfragen müssen, setzen mysql_errno() zurück, wenn sie Erfolg hatten.

Für Funktionen, die mysql_errno() zurücksetzen, sind die beiden folgenden Tests äquivalent:

if(mysql_errno(&mysql))
{
    // Ein Fehler ist aufgetreten
}

if(mysql_error(&mysql)[0] != '\0')
{
  // Ein Fehler ist aufgetreten
}

Sie können die Sprache für die Fehlermeldungen des Clients ändern, indem Sie die MySQL-Clientbibliothek neu kompilieren. Zurzeit haben Sie die Auswahl zwischen Fehlermeldungen in mehreren verschiedenen Sprachen. Siehe Abschnitt 5.11.2, „Nicht englische Fehlermeldungen“.

Rückgabewerte

Ein auf null endender Zeichen-String, der den Fehler beschreibt. Ein leerer String, wenn kein Fehler auftrat.

Fehler

Keine.

24.2.3.16. mysql_escape_string()

Bitte verwenden Sie stattdessen mysql_real_escape_string()!

Diese Funktion gleicht mysql_real_escape_string(), mit dem Unterschied, dass mysql_real_escape_string() einen Verbindungs-Handler als erstes Argument entgegennimmt und den String entsprechend dem aktuellen Zeichensatz mit Escape-Zeichen versieht. mysql_escape_string() nimmt kein Verbindungsargument an und berücksichtigt auch nicht den aktuellen Zeichensatz.

24.2.3.17. mysql_fetch_field()

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)

Beschreibung

Liefert die Definition einer Spalte einer Ergebnismenge in Form einer MYSQL_FIELD-Struktur. Um Informationen über alle Spalten der Ergebnismenge zu erhalten, rufen Sie diese Funktion wiederholt auf. mysql_fetch_field() liefert NULL, wenn keine weiteren Felder mehr übrig sind.

Mit jeder neuen SELECT-Anfrage wird mysql_fetch_field() so zurückgesetzt, dass sie wieder Informationen über das erste Feld liefert. Auch mysql_field_seek() nimmt Einfluss darauf, welches Feld mysql_fetch_field() zurückgibt.

Wenn Sie mit mysql_query() ein SELECT auf einer Tabelle ausgeführt haben, ohne jedoch mysql_store_result() zu benutzen, dann liefert MySQL, wenn Sie mit mysql_fetch_field() die Länge eines BLOB-Felds erfragen, die Standardlänge eines Blob-Werts (8 Kbyte). (Die Größe von 8 Kbyte wird gewählt, weil MySQL die maximale Länge für den BLOB nicht kennt. Irgendwann soll dies einmal konfigurierbar gemacht werden.) Wenn Sie die Ergebnismenge abgeholt haben, enthält field->max_length die Länge des längsten Werts dieser Spalte für diese konkrete Anfrage.

Rückgabewerte

Die MYSQL_FIELD-Struktur der aktuellen Spalte. NULL, wenn keine Spalten mehr übrig sind.

Fehler

Keine.

Beispiel

MYSQL_FIELD *field;

while((field = mysql_fetch_field(result)))
{
    printf("field name %s\n", field->name);
}

24.2.3.18. mysql_fetch_field_direct()

MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int fieldnr)

Beschreibung

Wenn man ihr die Feldnummer fieldnr einer Spalte aus einer Ergebnismenge übergibt, liefert die Funktion die Felddefinition dieser Spalte als MYSQL_FIELD-Struktur. Mit dieser Funktion können Sie die Definition einer beliebigen Spalte abfragen. Der Wert von fieldnr sollte zwischen 0 und mysql_num_fields(result)-1 liegen.

Rückgabewerte

Die MYSQL_FIELD-Struktur für die angegebene Spalte.

Fehler

Keine.

Beispiel

unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *field;

num_fields = mysql_num_fields(result);
for(i = 0; i < num_fields; i++)
{
    field = mysql_fetch_field_direct(result, i);
    printf("Field %u is %s\n", i, field->name);
}

24.2.3.19. mysql_fetch_fields()

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)

Beschreibung

Gibt ein Array mit allen MYSQL_FIELD-Strukturen für eine Ergebnismenge zurück. Jede Struktur liefert die Felddefinition für eine Spalte der Ergebnismenge.

Rückgabewerte

Ein Array von MYSQL_FIELD-Strukturen für alle Spalten einer Ergebnismenge.

Fehler

Keine.

Beispiel

unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *fields;

num_fields = mysql_num_fields(result);
fields = mysql_fetch_fields(result);
for(i = 0; i < num_fields; i++)
{
   printf("Field %u is %s\n", i, fields[i].name);
}

24.2.3.20. mysql_fetch_lengths()

unsigned long *mysql_fetch_lengths(MYSQL_RES *result)

Beschreibung

Gibt die Länge der Spalten der aktuellen Zeile einer Ergebnismenge zurück. Wenn Sie planen, Feldwerte zu kopieren, sind diese Längenangaben auch für die Optimierung hilfreich, da Sie sich dadurch den Aufruf von strlen() ersparen können. Wenn die Ergebnismenge Binärdaten enthält, müssen Sie sogar diese Funktion zur Ermittlung der Datenlänge einsetzen, da strlen() für Felder mit Nullwerten verkehrte Ergebnisse liefert.

Die Länge von leeren Spalten und Spalten mit NULL-Werten ist null. Unter der Beschreibung von mysql_fetch_row() erfahren Sie, wie Sie diese beiden Fälle unterscheiden können.

Rückgabewerte

Ein Array von vorzeichenlosen Long-Integers, das die Größen der Spalten angibt (ausschließlich eventueller Nullzeichen am Ende). Ist NULL, wenn ein Fehler auftrat.

Fehler

mysql_fetch_lengths() ist nur für die aktuelle Zeile der Ergebnismenge gültig. Diese Funktion liefert NULL, wenn Sie sie vor mysql_fetch_row() oder nach dem Abruf aller Ergebniszeilen aufrufen.

Beispiel

MYSQL_ROW row;
unsigned long *lengths;
unsigned int num_fields;
unsigned int i;

row = mysql_fetch_row(result);
if (row)
{
    num_fields = mysql_num_fields(result);
    lengths = mysql_fetch_lengths(result);
    for(i = 0; i < num_fields; i++)
    {
         printf("Column %u is %lu bytes in length.\n", i, lengths[i]);
    }
}

24.2.3.21. mysql_fetch_row()

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

Beschreibung

Ruft die nächste Zeile einer Ergebnismenge ab. Nach mysql_store_result() aufgerufen, liefert mysql_fetch_row() den Wert NULL, wenn keine weiteren Zeilen mehr abzuholen sind. Nach mysql_use_result() aufgerufen, liefert mysql_fetch_row() den Wert NULL, wenn keine Zeilen mehr vorliegen oder wenn ein Fehler auftrat.

mysql_num_fields(result) gibt die Anzahl der Werte in einer Zeile an. Wenn row den Rückgabewert eines mysql_fetch_row()-Aufrufs speichert, können Sie mit row[0] bis row[mysql_num_fields(result)-1] die Zeiger auf die Werte dieser Zeile ansprechen. NULL-Werte in der Zeile werden durch NULL-Zeiger angezeigt.

Die Längen der Feldwerte der Zeile können Sie sich mit mysql_fetch_lengths() beschaffen. Leere Felder und Felder mit NULL haben beide die Länge null. Sie können sie unterscheiden, indem Sie sich den Zeiger auf den Feldwert anschauen: Ist er NULL, speichert das Feld den Wert NULL; andernfalls ist es leer.

Rückgabewerte

Eine MYSQL_ROW-Struktur für die nächste Zeile oder NULL, wenn keine weiteren Zeilen mehr vorliegen oder ein Fehler aufgetreten ist.

Fehler

Beachten Sie, dass der Fehler zwischen zwei Aufrufen von mysql_fetch_row() nicht zurückgesetzt wird.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;

num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
   unsigned long *lengths;
   lengths = mysql_fetch_lengths(result);
   for(i = 0; i < num_fields; i++)
   {
       printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
   }
   printf("\n");
}

24.2.3.22. mysql_field_count()

unsigned int mysql_field_count(MYSQL *mysql)

Beschreibung

Liefert die Anzahl der Spalten für die jüngste Anfrage auf dieser Verbindung.

Normalerweise benutzen Sie diese Funktion, wenn mysql_store_result() den Wert NULL zurückgegeben hat (und Sie deshalb keinen Zeiger auf die Ergebnismenge haben). In diesem Fall können Sie mit mysql_field_count() feststellen, ob mysql_store_result() ein nichtleeres Ergebnis hätte produzieren müssen. So kann das Clientprogramm die richtigen Maßnahmen ergreifen, ohne zu wissen, ob die Anfrage eine SELECT- (oder SELECT-ähnliche) Anweisung war. Wie dies funktioniert, zeigt das folgende Beispiel.

Siehe Abschnitt 24.2.13.1, „Warum gibt mysql_store_result() manchmal NULL zurück, nachdem mysql_query() Erfolg zurückgegeben hat?“.

Rückgabewerte

Ein vorzeichenloser Integer, der die Anzahl der Spalten einer Ergebnismenge angibt.

Fehler

Keine.

Beispiel

MYSQL_RES *result;
unsigned int num_fields;
unsigned int num_rows;

if (mysql_query(&mysql,query_string))
{
    // Fehler
}
else // Anfrage erfolgreich, Rückgabedaten können verarbeitet werden
{
    result = mysql_store_result(&mysql);
    if (result)  // Es sind Zeilen vorhanden
    {
        num_fields = mysql_num_fields(result);
        // Hole Zeilen ab und rufe dann mysql_free_result(result) auf
    }
    else  // mysql_store_result() gab nichts zurück. Hätte es sollen?
    {
        if(mysql_field_count(&mysql) == 0)
        {
            // Anfrage liefert keine Daten
            // (Es war kein SELECT)
            num_rows = mysql_affected_rows(&mysql);
        }
        else // mysql_store_result() hätte Daten zurückgeben müssen
        {
            fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
        }
    }
}

Eine Alternative wäre es, den Aufruf von mysql_field_count(&mysql) durch mysql_errno(&mysql) zu ersetzen. In diesem Fall schauen Sie direkt in mysql_store_result() nach einem Fehler, anstatt aus dem Wert von mysql_field_count() zu erschließen, ob die Anweisung ein SELECT war.

24.2.3.23. mysql_field_seek()

MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

Beschreibung

Setzt den Feld-Cursor auf den gegebenen Offset. Der nächste mysql_fetch_field()-Aufruf fragt die Felddefinition der mit diesem Offset verbundenen Spalte ab.

Um den Zeilenanfang zu suchen, übergeben Sie den offset-Wert null.

Rückgabewerte

Der vorherige Wert des Feld-Cursors.

Fehler

Keine.

24.2.3.24. mysql_field_tell()

MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *result)

Beschreibung

Liefert die Position des Feld-Cursors, der für den letzten mysql_fetch_field()-Aufruf verwendet wurde. Dieser Wert kann als Argument für mysql_field_seek() dienen.

Rückgabewerte

Der aktuelle Offset des Feld-Cursors.

Fehler

Keine.

24.2.3.25. mysql_free_result()

void mysql_free_result(MYSQL_RES *result)

Beschreibung

Gibt den Speicher frei, der einer Ergebnismenge durch mysql_store_result(), mysql_use_result(), mysql_list_dbs() und so weiter zugewiesen wurde. Wenn Sie mit einer Ergebnismenge fertig sind, müssen Sie ihren Speicher mit mysql_free_result() wieder freigeben.

Versuchen Sie nicht mehr, auf eine Ergebnismenge zuzugreifen, nachdem Sie sie freigegeben haben.

Rückgabewerte

Keine.

Fehler

Keine.

24.2.3.26. mysql_get_character_set_info()

void mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs)

Beschreibung

Diese Funktion liefert Informationen über den Standardzeichensatz des Clients. Dieser kann mit der Funktion mysql_set_character_set() geändert werden.

Diese Funktion kam in MySQL 5.0.10 hinzu.

Beispiel

if (!mysql_set_character_set(&mysql, "utf8"))
{
    MY_CHARSET_INFO cs;
    mysql_get_character_set_info(&mysql, &cs);
    printf("character set information:\n");
    printf("character set name: %s\n", cs.name);
    printf("collation name: %s\n", cs.csname);
    printf("comment: %s\n", cs.comment);
    printf("directory: %s\n", cs.dir);
    printf("multi byte character min. length: %d\n", cs.mbminlen);
    printf("multi byte character max. length: %d\n", cs.mbmaxlen);
}

24.2.3.27. mysql_get_client_info()

char *mysql_get_client_info(void)

Beschreibung

Liefert einen String, der die Version der Clientbibliothek darstellt.

Rückgabewerte

Ein Zeichen-String, der die Version der MySQL-Clientbibliothek darstellt.

Fehler

Keine.

24.2.3.28. mysql_get_client_version()

unsigned long mysql_get_client_version(void)

Beschreibung

Liefert einen Integer, der die Version der Clientbibliothek darstellt. Der Wert hat das Format XYYZZ, wobei X die Hauptversion, YY der Release-Level und ZZ die Versionsnummer innerhalb des Releases ist. So bedeutet beispielsweise der Wert 40102 die Clientbibliotheksversion 4.1.2.

Rückgabewerte

Ein Integer, der die Version der MySQL-Clientbibliothek angibt.

Fehler

Keine.

24.2.3.29. mysql_get_host_info()

char *mysql_get_host_info(MYSQL *mysql)

Beschreibung

Liefert einen String, der den benutzten Verbindungstyp einschließlich des Hostnamens des Servers beschreibt.

Rückgabewerte

Ein Zeichen-String, der den Hostnamen des Servers und den Verbindungstyp darstellt.

Fehler

Keine.

24.2.3.30. mysql_get_proto_info()

unsigned int mysql_get_proto_info(MYSQL *mysql)

Beschreibung

Liefert die Protokollversion der aktuellen Verbindung.

Rückgabewerte

Ein vorzeichenloser Integer, der die Protokollversion der aktuellen Verbindung darstellt.

Fehler

Keine.

24.2.3.31. mysql_get_server_info()

char *mysql_get_server_info(MYSQL *mysql)

Beschreibung

Liefert einen String, der die Versionsnummer des Servers darstellt.

Rückgabewerte

Ein Zeichen-String, der die Versionsnummer des Servers darstellt.

Fehler

Keine.

24.2.3.32. mysql_get_server_version()

unsigned long mysql_get_server_version(MYSQL *mysql)

Beschreibung

Liefert die Versionsnummer des Servers als Integer.

Rückgabewerte

Eine Zahl, welche die MySQL Server-Version in folgendem Format darstellt:

major_version*10000 + minor_version *100 + sub_version

So wird beispielsweise 5.1.5 als 50105 zurückgegeben.

Diese Funktion ist nützlich, um in Clientprogrammen schnell herauszufinden, ob eine versionsspezifische Serverfähigkeit geboten wird.

Fehler

Keine.

24.2.3.33. mysql_hex_string()

unsigned long mysql_hex_string(char *to, const char *from, unsigned long length)

Beschreibung

Diese Funktion dient der Erstellung eines gültigen SQL-Strings, den Sie in einer SQL-Anweisung benutzen können. Siehe Abschnitt 9.1.1, „Strings“.

Der String in from ist im Hexadezimalformat verschlüsselt, wobei jedes Zeichen als zwei Hexadezimalziffern kodiert ist. Das Ergebnis wird in to eingesetzt und ein Nullbyte als Abschlusszeichen angehängt.

Der String, auf den from verweist, muss length Bytes lang sein. Den to-Puffer müssen Sie mindestens mit einer Länge von length*2+1 Bytes zuweisen. Wenn mysql_hex_string() zurückkehrt, ist der Inhalt von to ein auf null endender String. Der Rückgabewert ist die Länge des kodierten Strings ohne das abschließende Nullzeichen.

Der Rückgabewert kann in eine SQL-Anweisung in einem der Formate 0xvalue oder X'value' eingesetzt werden. Allerdings enthält der Rückgabewert nicht das 0x oder X'...'. Der Aufrufer muss dieses Element selbst beisteuern, je nachdem, für welches er sich entscheidet.

Beispiel

char query[1000],*end;

end = strmov(query,"INSERT INTO test_table values(");
end = strmov(end,"0x");
end += mysql_hex_string(end,"What's this",11);
end = strmov(end,",0x");
end += mysql_hex_string(end,"binary data: \0\r\n",16);
*end++ = ')';

if (mysql_real_query(&mysql,query,(unsigned int) (end - query)))
{
   fprintf(stderr, "Failed to insert row, Error: %s\n",
           mysql_error(&mysql));
}

Die im Beispiel verwendete Funktion strmov() stammt aus der mysqlclient-Bibliothek und funktioniert wie strcpy(), liefert jedoch einen Zeiger auf die abschließende Null des ersten Parameters.

Rückgabewerte

Die Länge des in to eingesetzten Werts ohne die abschließende Null.

Fehler

Keine.

24.2.3.34. mysql_info()

char *mysql_info(MYSQL *mysql)

Beschreibung

Holt einen String mit Informationen über die zuletzt ausgeführte Anfrage ab, aber nur für die hier aufgeführten Anweisungen. Für andere Anweisungen liefert mysql_info() die Funktion NULL. Das Format des Strings hängt von der Art der Anfrage ab, wie hier beschrieben. Die Zahlen dienen nur der Veranschaulichung; der String enthält Werte, die für die Anfrage passend sind.

  • INSERT INTO ... SELECT ...

    String-Format: Records: 100 Duplicates: 0 Warnings: 0

  • INSERT INTO ... VALUES (...),(...),(...)...

    String-Format: Records: 3 Duplicates: 0 Warnings: 0

  • LOAD DATA INFILE ...

    String-Format: Records: 1 Deleted: 0 Skipped: 0 Warnings: 0

  • ALTER TABLE

    String-Format: Records: 3 Duplicates: 0 Warnings: 0

  • UPDATE

    String-Format: Rows matched: 40 Changed: 40 Warnings: 0

Beachten Sie, dass mysql_info() bei INSERT ... VALUES lediglich für die mehrzeilige Form der Anweisung (also dann, wenn mehrere Wertelisten angegeben werden) einen von NULL verschiedenen Wert liefert.

Rückgabewerte

Ein Zeichen-String mit Zusatzinformationen über die zuletzt ausgeführte Anfrage. NULL, wenn keine Informationen über die Anfrage zur Verfügung stehen.

Fehler

Keine.

24.2.3.35. mysql_init()

MYSQL *mysql_init(MYSQL *mysql)

Beschreibung

Reserviert oder initialisiert ein geeignetes MYSQL-Objekt für mysql_real_connect(). Wenn mysql ein NULL-Zeiger ist, reserviert, initialisiert und liefert die Funktion ein neues Objekt. Andernfalls wird das Objekt initialisiert und seine Adresse zurückgegeben. Wenn mysql_init() ein neues Objekt zuweist, wird dieses wieder freigegeben, wenn mysql_close() zum Schließen der Verbindung aufgerufen wird.

Rückgabewerte

Ein initialisierter MYSQL*-Handle. NULL, wenn nicht genügend Speicher zur Zuweisung eines neuen Objekts verfügbar war.

Fehler

Wenn der Speicher nicht ausreichte, wird NULL zurückgegeben.

24.2.3.36. mysql_insert_id()

my_ulonglong mysql_insert_id(MYSQL *mysql)

Beschreibung

Liefert den von der vorherigen INSERT- oder UPDATE-Anweisung für eine AUTO_INCREMENT-Spalte generierten Wert. Verwenden Sie diese Funktion, wenn Sie eine INSERT-Anweisung auf einer Tabelle mit einem AUTO_INCREMENT-Feld ausgeführt haben.

Genauer gesagt: mysql_insert_id() wird unter folgenden Bedingungen aktualisiert:

  • INSERT-Anweisungen, die einen Wert in einer AUTO_INCREMENT-Spalte speichern, und zwar unabhängig davon, ob der Wert automatisch durch Speichern der Spezialwerte NULL oder 0 in der Spalte generiert oder ob ein expliziter, nichtspezieller Wert gespeichert wurde.

  • Bei einer mehrzeiligen INSERT-Anweisung liefert mysql_insert_id() den ersten automatisch generierten AUTO_INCREMENT-Wert. Wurde kein solcher Wert generiert, liefert die Funktion den letzten explizit in die AUTO_INCREMENT-Spalte eingefügten Wert.

  • INSERT-Anweisungen, die einen AUTO_INCREMENT-Wert generieren, indem sie LAST_INSERT_ID(expr) in eine Spalte einfügen.

  • INSERT-Anweisungen, die einen AUTO_INCREMENT-Wert generieren, indem sie eine Spalte auf LAST_INSERT_ID(expr) setzen.

  • Der Wert von mysql_insert_id() wird nicht von Anweisungen wie SELECT beeinflusst, die eine Ergebnismenge zurückgeben.

  • Wenn die obige Anweisung einen Fehler zurückgab, ist der Wert von mysql_insert_id() undefiniert.

Beachten Sie, dass mysql_insert_id() den Wert 0 liefert, wenn die Anweisung keinen AUTO_INCREMENT-Wert verwendet. Wenn Sie den Wert zur späteren Benutzung speichern möchten, müssen Sie unmittelbar nach der Anweisung, die den Wert generiert, mysql_insert_id() aufrufen.

Der Wert von mysql_insert_id() wird nur von Anweisungen beeinflusst, die innerhalb der aktuellen Clientverbindung gegeben werden, aber nicht durch Anweisungen von anderen Clients.

Siehe Abschnitt 12.10.3, „Informationsfunktionen“.

Bitte beachten Sie auch, dass der Wert der SQL-Funktion LAST_INSERT_ID() immer den zuletzt generierten AUTO_INCREMENT-Wert enthält. Dieser wird zwischen zwei Anweisungen nicht zurückgesetzt, da der Wert dieser Funktion im Server gespeichert ist. Ein weiterer Unterschied ist der, dass LAST_INSERT_ID() nicht aktualisiert wird, wenn Sie eine AUTO_INCREMENT-Spalte auf einen bestimmten Wert setzen, der kein Spezialwert ist.

Der Grund für den Unterschied zwischen LAST_INSERT_ID() und mysql_insert_id() besteht darin, dass LAST_INSERT_ID() in Skripten einfach zu benutzen sein soll, während mysql_insert_id() versucht, etwas genauere Informationen über die Vorgänge in der AUTO_INCREMENT-Spalte zu liefern.

Rückgabewerte

Siehe oben.

Fehler

Keine.

24.2.3.37. mysql_kill()

int mysql_kill(MYSQL *mysql, unsigned long pid)

Beschreibung

Lässt den Server den Thread pid anhalten.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.38. mysql_library_end()

void mysql_library_end(void)

Beschreibung

Dies ist ein Synonym für die mysql_server_end()-Funktion.

Informationen zur Verwendung finden Sie unter Abschnitt 24.2.2, „C-API: Funktionsüberblick“.

24.2.3.39. mysql_library_init()

int mysql_library_init(int argc, char **argv, char **groups)

Beschreibung

Dies ist ein Synonym für die mysql_server_init()-Funktion. Siehe Abschnitt 24.2.12.1, „mysql_server_init().

Informationen zur Verwendung finden Sie unter Abschnitt 24.2.2, „C-API: Funktionsüberblick“.

24.2.3.40. mysql_list_dbs()

MYSQL_RES *mysql_list_dbs(MYSQL *mysql, const char *wild)

Beschreibung

Liefert eine Ergebnismenge mit Namen von Datenbanken auf dem Server, die mit dem einfachen regulären Ausdruck im Parameter wild übereinstimmen. wild kann die Wildcard-Zeichen ‘%’ oder ‘_’ enthalten oder aber ein NULL-Zeiger sein, der auf alle Datenbanken passt. Ein Aufruf von mysql_list_dbs() ist dasselbe wie die Anfrage SHOW databases [LIKE wild].

Sie müssen die Ergebnismenge mit mysql_free_result() wieder freigeben.

Rückgabewerte

Bei einem Erfolg eine MYSQL_RES-Ergebnismenge und bei einem Fehler der Wert NULL.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.41. mysql_list_fields()

MYSQL_RES *mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)

Beschreibung

Liefert eine Ergebnismenge mit Namen von Feldern aus der gegebenen Tabelle, die mit dem einfachen regulären Ausdruck im Parameter wild übereinstimmen. wild kann die Wildcard-Zeichen ‘%’ oder ‘_’ enthalten oder aber ein NULL-Zeiger sein, der auf alle Felder passt. Ein Aufruf von mysql_list_fields() ist dasselbe wie die Anfrage SHOW COLUMNS FROM tbl_name [LIKE wild].

Wir empfehlen, SHOW COLUMNS FROM tbl_name anstelle von mysql_list_fields() zu benutzen.

Sie müssen die Ergebnismenge mit mysql_free_result() freigeben.

Rückgabewerte

Bei Erfolg eine MYSQL_RES-Ergebnismenge und bei einem Fehler der Wert NULL.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.42. mysql_list_processes()

MYSQL_RES *mysql_list_processes(MYSQL *mysql)

Beschreibung

Gibt eine Ergebnismenge mit einer Beschreibung der laufenden Server-Threads zurück. Dieselben Informationen erhalten Sie auch mit mysqladmin processlist oder der Anfrage SHOW PROCESSLIST.

Sie müssen die Ergebnismenge mit mysql_free_result() freigeben.

Rückgabewerte

Bei Erfolg eine MYSQL_RES-Ergebnismenge und bei einem Fehler der Wert NULL.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.43. mysql_list_tables()

MYSQL_RES *mysql_list_tables(MYSQL *mysql, const char *wild)

Beschreibung

Liefert eine Ergebnismenge mit Namen von Tabellen aus der aktuellen Datenbank, die mit dem einfachen regulären Ausdruck im Parameter wild übereinstimmen. wild kann die Wildcard-Zeichen ‘%’ oder ‘_’ enthalten oder aber ein NULL-Zeiger sein, der auf alle Tabellen passt. Ein Aufruf von mysql_list_tables() ist dasselbe wie die Anfrage SHOW tables [LIKE wild].

Sie müssen die Ergebnismenge mit mysql_free_result() freigeben.

Rückgabewerte

Bei Erfolg eine MYSQL_RES-Ergebnismenge und bei einem Fehler der Wert NULL.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.44. mysql_more_results()

my_bool mysql_more_results(MYSQL *mysql)

Beschreibung

Gibt TRUE zurück, wenn noch weitere Ergebnisse der aktuellen Anfrage vorliegen und die Anwendung mysql_next_result() aufrufen muss, um diese Ergebnisse abzuholen.

Rückgabewerte

TRUE (1), wenn noch weitere Ergebnisse existieren. FALSE (0), wenn keine Ergebnisse mehr vorhanden sind.

In den meisten Fällen können Sie stattdessen mit mysql_next_result() testen, ob noch Ergebnisse übrig sind, und den Abruf der Daten initiieren, wenn dies der Fall ist.

Siehe Abschnitt 24.2.9, „C-API: Behandlung der Ausführung mehrerer Anweisungen“, und Abschnitt 24.2.3.45, „mysql_next_result().

Fehler

Keine.

24.2.3.45. mysql_next_result()

int mysql_next_result(MYSQL *mysql)

Beschreibung

Wenn noch Anfrageergebnisse vorliegen, liest mysql_next_result() die nächsten Ergebnisse und gibt den Status an die Anwendung zurück.

Sie müssen für die vorherige Anfrage mysql_free_result() aufrufen, falls diese eine Ergebnismenge zurückgegeben hat.

Nach einem Aufruf von mysql_next_result() hat die Verbindung denselben Status, als hätten Sie mysql_real_query() oder mysql_query() für die nächste Anfrage aufgerufen. Das bedeutet, dass Sie mysql_store_result(), mysql_warning_count(), mysql_affected_rows() und so weiter aufrufen können.

Wenn mysql_next_result() einen Fehler zurückgibt, werden andere Anweisungen ausgeführt und es liegen keine Ergebnisse mehr zum Abruf bereit.

Siehe Abschnitt 24.2.9, „C-API: Behandlung der Ausführung mehrerer Anweisungen“.

Rückgabewerte

RückgabewertBeschreibung
0Erfolg, und es gibt noch mehr Ergebnisse.
-1Erfolg, und es gibt keine Ergebnisse mehr.
>0Ein Fehler ist aufgetreten

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt, beispielsweise wenn Sie es versäumt haben, mysql_use_result() für die vorherige Ergebnismenge aufzurufen.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.46. mysql_num_fields()

unsigned int mysql_num_fields(MYSQL_RES *result)

Um stattdessen ein MYSQL*-Argument zu übergeben, sagen Sie unsigned int mysql_field_count(MYSQL *mysql).

Beschreibung

Liefert die Anzahl der Spalten einer Ergebnismenge.

Beachten Sie, dass Sie die Anzahl der Spalten entweder aus einem Zeiger auf eine Ergebnismenge oder aus einem Verbindungs-Handle erfahren können. Den Verbindungs-Handle verwenden Sie, wenn mysql_store_result() oder mysql_use_result() den Wert NULL zurückgegeben hat (sodass kein Zeiger auf die Ergebnismenge zur Verfügung steht). In diesem Fall können Sie mit mysql_field_count() ermitteln, ob mysql_store_result() eigentlich ein nichtleeres Ergebnis hätte liefern sollen. So kann das Clientprogramm geeignete Maßnahmen ergreifen, ohne zu wissen, ob die Anfrage eine SELECT- (oder SELECT-ähnliche) Anweisung war. Das Beispiel zeigt, wie man dies macht.

Siehe Abschnitt 24.2.13.1, „Warum gibt mysql_store_result() manchmal NULL zurück, nachdem mysql_query() Erfolg zurückgegeben hat?“.

Rückgabewerte

Ein vorzeichenloser Integer, der die Anzahl der Spalten einer Ergebnismenge angibt.

Fehler

Keine.

Beispiel

MYSQL_RES *result;
unsigned int num_fields;
unsigned int num_rows;

if (mysql_query(&mysql,query_string))
{
    // Fehler
}
else // Anfrage erfolgreich, Rückgabedaten werden verarbeitet
{
    result = mysql_store_result(&mysql);
    if (result)  // Es liegen Zeilen vor
    {
        num_fields = mysql_num_fields(result);
        // Zeilen abrufen und dann mysql_free_result(result) aufrufen
    }
    else  // mysql_store_result() gab nichts zurück, hätte es sollen?
    {
        if (mysql_errno(&mysql))
        {
           fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
        }
        else if (mysql_field_count(&mysql) == 0)
        {
            // Anfrage liefert keine Daten
            // (war kein SELECT)
            num_rows = mysql_affected_rows(&mysql);
        }
    }
}

Wenn Sie wissen, dass Ihre Anfrage eine Ergebnismenge hätte zurückgeben müssen, können Sie alternativ den Aufruf von mysql_errno(&mysql) durch eine Prüfung ersetzen, die feststellt, ob mysql_field_count(&mysql) gleich 0 ist. Das geschieht nur, wenn etwas schief gegangen ist.

24.2.3.47. mysql_num_rows()

my_ulonglong mysql_num_rows(MYSQL_RES *result)

Beschreibung

Liefert die Anzahl der Zeilen in der Ergebnismenge.

Die Verwendung von mysql_num_rows() hängt davon ab, ob Sie die Ergebnismenge mit mysql_store_result() oder mysql_use_result() zurückgeben. Wenn Sie mysql_store_result() benutzen, kann mysql_num_rows() direkt aufgerufen werden, aber wenn Sie mysql_use_result() benutzen, gibt mysql_num_rows() erst dann den richtigen Wert zurück, wenn alle Zeilen der Ergebnismenge abgeholt worden sind.

Rückgabewerte

Die Anzahl der Zeilen in der Ergebnismenge.

Fehler

Keine.

24.2.3.48. mysql_options()

int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg)

Beschreibung

Kann verwendet werden, um zusätzliche Verbindungsoptionen einzustellen und das Verhalten einer Verbindung zu beeinflussen. Diese Funktion kann auch mehrmals aufgerufen werden, um mehrere Optionen zu setzen.

mysql_options() sollte nach mysql_init() und vor mysql_connect() oder mysql_real_connect() aufgerufen werden.

Das option-Argument ist die einzustellende Option und das arg-Argument ist ihr Wert. Ist die Option ein Integer, so sollte arg auf den Wert dieses Integers verweisen.

Mögliche Optionswerte:

OptionArgumenttypFunktion
MYSQL_INIT_COMMANDchar *Befehl, der bei Verbindung mit dem MySQL Server auszuführen ist. Wird bei Neuverbindungen automatisch erneut ausgeführt.
MYSQL_OPT_COMPRESSNicht verwendetKomprimiertes Client/Server-Protokoll soll verwendet werden.
MYSQL_OPT_CONNECT_TIMEOUTunsigned int *Verbindungs-Timeout in Sekunden.
MYSQL_OPT_GUESS_CONNECTIONNicht verwendetFür eine mit libmysqld verlinkte Anwendung, kann die Bibliothek hiermit erschließen, ob ein Embedded Server oder ein Remote Server verwendet wird. „Erschließen“ bedeutet: Wenn ein Hostname angegeben ist, der nicht auf localhost lautet, wird ein Remote-Server benutzt. Dieses voreingestellte Verhalten kann mit MYSQL_OPT_USE_EMBEDDED_CONNECTION und MYSQL_OPT_USE_REMOTE_CONNECTION außer Kraft gesetzt werden. Die Option wird von Anwendungen, die mit libmysqlclient verlinkt sind, ignoriert.
MYSQL_OPT_LOCAL_INFILEOptionaler Zeiger auf uintWenn kein Zeiger angegeben ist oder wenn der Zeiger auf ein unsigned int != 0 verweist, wird der Befehl LOAD LOCAL INFILE eingeschaltet.
MYSQL_OPT_NAMED_PIPENicht verwendetZur Verbindung mit einem MySQL Server auf NT werden Named Pipes benutzt.
MYSQL_OPT_PROTOCOLunsigned int *Der zu verwendende Protokolltyp. Er sollte einer der Enumerationswerte von mysql_protocol_type sein, die in mysql.h definiert sind.
MYSQL_OPT_READ_TIMEOUTunsigned int *Timeout-Leseoperationen auf dem Server (funktioniert zurzeit nur für Windows und mit TCP/IP-Verbindungen).
MYSQL_OPT_RECONNECTmy_bool *Aktiviert/deaktiviert die automatische Neuverbindung mit dem Server, wenn die Verbindung abgebrochen war. Die Neuverbindung ist seit MySQL 5.0.3 standardmäßig ausgeschaltet. Diese Option ist neu in 5.0.13 und bietet die Möglichkeit, das Verhalten in Bezug auf Neuverbindungen explizit vorzugeben.
MYSQL_OPT_SET_CLIENT_IPchar *Für eine Anwendung, die mit libmysqld verlinkt ist (wobei libmysqld mit Authentifizierungsunterstützung kompiliert wurde), bedeutet dies, dass bei der Authentifizierung davon ausgegangen wird, dass sich der Benutzer von der (als String) angegebenen IP-Adresse aus verbindet. Bei Anwendungen, die mit libmysqlclient verlinkt sind, wird diese Option ignoriert.
MYSQL_OPT_USE_EMBEDDED_CONNECTIONNicht verwendetFür eine Anwendung, die mit libmysqld verlinkt ist, zwingt dies zur Benutzung des Embedded Servers für die Verbindung. Bei Anwendungen, die mit libmysqlclient verlinkt sind, wird diese Option ignoriert.
MYSQL_OPT_USE_REMOTE_CONNECTIONNicht verwendetFür eine Anwendung, die mit libmysqld verlinkt ist, zwingt dies zur Benutzung eines Remote-Servers für die Verbindung. Bei Anwendungen, die mit libmysqlclient verlinkt sind, wird diese Option ignoriert.
MYSQL_OPT_USE_RESULTNicht verwendetDiese Option wird nicht benutzt.
MYSQL_OPT_WRITE_TIMEOUTunsigned int *Timeout für Schreiboperationen auf dem Server (funktioniert zurzeit nur für Windows und mit TCP/IP-Verbindungen).
MYSQL_READ_DEFAULT_FILEchar *Leseoptionen werden aus der angegebenen Optionsdatei statt aus my.cnf entnommen.
MYSQL_READ_DEFAULT_GROUPchar *Leseoptionen werden aus der angegebenen Gruppe aus my.cnf oder aus der Datei, die in MYSQL_READ_DEFAULT_FILE angegeben wurde, entnommen.
MYSQL_REPORT_DATA_TRUNCATIONmy_bool *Aktiviert oder deaktiviert die Meldung von Fehlern wegen des Abschneidens von Daten für vorbereitete Anweisungen mit MYSQL_BIND.error. (Standardeinstellung: Deaktiviert.)
MYSQL_SECURE_AUTHmy_bool*Gibt an, ob eine Verbindung mit einem Server aufgebaut wird, der nicht das Passwort-Hashing von MySQL 4.1.1 und höher unterstützt.
MYSQL_SET_CHARSET_DIRchar*Der Pfad zu dem Verzeichnis, das die Dateien mit den Zeichensatzdefinitionen enthält.
MYSQL_SET_CHARSET_NAMEchar*Der Name des Zeichensatzes, der als Standard zu verwenden ist.
MYSQL_SHARED_MEMORY_BASE_NAMEchar*Der Name des Shared Memory-Objekts für die Serverkommunikation. Sollte dasselbe sein wie die Option --shared-memory-base-name für den mysqld-Server, mit dem Sie sich verbinden möchten.

Beachten Sie, dass immer die client-Gruppe gelesen wird, wenn Sie MYSQL_READ_DEFAULT_FILE oder MYSQL_READ_DEFAULT_GROUP benutzen.

Die angegebene Gruppe in der Optionsdatei kann folgende Optionen enthalten:

OptionBeschreibung
connect-timeoutVerbindungs-Timeout in Sekunden. Bei Linux wird dieser Timeout auch verwendet, wenn das System auf die erste Antwort vom Server wartet.
compressVerwendung des komprimierten Client/Server-Protokolls.
databaseWenn im Verbindungsbefehl keine Datenbank angegeben wurde, wird diese verwendet.
debugDebuggingoptionen.
disable-local-infileDeaktiviert LOAD DATA LOCAL.
hostStandardhostname.
init-commandBefehl, der bei Verbindung mit dem MySQL Server ausgeführt wird. Wird bei Neuverbindung automatisch erneut ausgeführt.
interactive-timeoutDasselbe wie CLIENT_INTERACTIVE mit mysql_real_connect(). Siehe Abschnitt 24.2.3.51, „mysql_real_connect().
local-infile[=(0|1)]Wenn kein Argument oder argument != 0 vorhanden ist, wird LOAD DATA LOCAL aktiviert.
max_allowed_packetMaximalgröße der Pakete, die der Client vom Server lesen kann.
multi-resultsMehrfachergebnismengen von Mehrfachanweisungen oder mehrfach gespeicherten Prozeduren sind zulässig.
multi-statementsClient darf mehrere Anweisungen in einem einzigen String senden (getrennt durch ‘;’).
passwordStandardpasswort.
pipeZur Verbindung mit einem MySQL Server auf NT werden Named Pipes benutzt.
protocol={TCP|SOCKET|PIPE|MEMORY}Das Protokoll für die Serververbindung.
portStandardportnummer.
return-found-rowsLässt mysql_info() bei einem UPDATE die gefundenen anstatt der aktualisierten Zeilen zurückgeben.
shared-memory-base-name=nameShared Memory-Name für die Serververbindung (Standardwert ist "MYSQL").
socketStandardsocketdatei.
userStandardbenutzer.

Beachten Sie, dass timeout zwar durch connect-timeout ersetzt, aber timeout in MySQL 5.1.5-alpha aus Gründen der Abwärtskompatibilität immer noch unterstützt wird.

Weitere Informationen über Optionsdateien finden Sie unter Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

Rückgabewerte

Bei Erfolg null und bei Verwendung einer unbekannten Option ein von null verschiedener Wert.

Beispiel

MYSQL mysql;

mysql_init(&mysql);
mysql_options(&mysql,MYSQL_OPT_COMPRESS,0);
mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"odbc");
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
{
    fprintf(stderr, "Failed to connect to database: Error: %s\n",
          mysql_error(&mysql));
}

Dieser Code veranlasst den Client, das komprimierte Client/Server-Protokoll zu verwenden und die zusätzlichen Optionen aus dem Abschnitt odbc der Datei my.cnf zu lesen.

24.2.3.49. mysql_ping()

int mysql_ping(MYSQL *mysql)

Beschreibung

Prüft, ob die Serververbindung funktioniert. Wenn die Verbindung abgebrochen ist, wird automatisch eine Neuverbindung versucht.

Mit dieser Funktion können Clients, die geraume Zeit untätig waren, prüfen, ob der Server die Verbindung geschlossen hat, und sich notfalls neu verbinden.

Rückgabewerte

Null, wenn die Serververbindung noch steht, und ein von null verschiedener Wert, wenn ein Fehler auftrat. Ein von null verschiedener Wert bedeutet nicht unbedingt, dass der MySQL Server selbst abgestürzt ist, sondern kann auch bedeuten, dass die Verbindung aus anderen Gründen abgebrochen ist, etwa wegen eines Netzwerkproblems.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.50. mysql_query()

int mysql_query(MYSQL *mysql, const char *query)

Beschreibung

Führt die SQL-Anfrage in dem auf null endenden String query aus. Normalerweise muss der String eine einzige SQL-Anweisung ohne abschließendes Semikolon (‘;’) oder \g enthalten. Wenn die Ausführung von Mehrfachanweisungen aktiviert wurde, kann der String auch mehrere, durch Semikola getrennte Anweisungen enthalten. Siehe Abschnitt 24.2.9, „C-API: Behandlung der Ausführung mehrerer Anweisungen“.

mysql_query() darf nicht für Anfragen mit Binärdaten verwendet werden. Hierfür müssen Sie stattdessen mysql_real_query() aufrufen. (Binärdaten können das Zeichen ‘\0’ enthalten, das mysql_query() als Ende des Anfrage-Strings interpretiert.)

Wenn Sie wissen möchten, ob die Anfrage eine Ergebnismenge liefern sollte, können Sie dies mit mysql_field_count() überprüfen. Siehe Abschnitt 24.2.3.22, „mysql_field_count().

Rückgabewerte

Null, wenn die Anfrage Erfolg hatte. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.51. mysql_real_connect()

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)

Beschreibung

mysql_real_connect() versucht, eine Verbindung zu einer MySQL-Datenbank-Engine auf host herzustellen. mysql_real_connect() muss erfolgreich zum Abschluss kommen, ehe Sie irgendwelche anderen API-Funktionen ausführen können, die eine gültige MYSQL-Verbindungs-Handle-Struktur erfordern.

Die Parameter werden folgendermaßen angegeben:

  • Der erste Parameter sollte die Adresse einer bestehenden MYSQL-Struktur sein. Bevor Sie mysql_real_connect() aufrufen können, müssen Sie die MYSQL-Struktur mit mysql_init() initialisieren. Mit dem mysql_options()-Aufruf können Sie viele Verbindungsoptionen ändern. Siehe Abschnitt 24.2.3.48, „mysql_options().

  • Der Wert von host ist entweder ein Hostname oder eine IP-Adresse. Wenn host der Wert NULL oder der String "localhost" ist, wird eine Verbindung mit dem lokalen Host zugrunde gelegt. Wenn das Betriebssystem Sockets (Unix) oder Named Pipes (Windows) unterstützt, werden diese anstelle von TCP/IP für die Serververbindung benutzt.

  • Der Parameter user enthält die MySQL-Kennung für die Anmeldung des Benutzers. Wenn user NULL oder der leere String "" ist, wird der aktuelle Benutzer vorausgesetzt. Bei Unix ist dies der aktuelle Login-Name und bei Windows ODBC muss der aktuelle Benutzername explizit angegeben werden. Siehe Abschnitt 25.1.3.2, „Konfiguration einer MyODBC-DSN unter Windows“.

  • Der Parameter passwd enthält das Passwort für den user. Wenn passwd NULL ist, werden nur diejenigen Einträge der user-Tabelle, die ein leeres Passwortfeld aufweisen, auf Übereinstimmung mit dem Benutzer überprüft. Dadurch kann der Datenbankadministrator das Berechtigungssystem von MySQL so einrichten, dass die Benutzer je nachdem, ob sie ein Passwort angegeben haben oder nicht, unterschiedliche Rechte bekommen.

    Hinweis: Versuchen Sie nicht, das Passwort zu verschlüsseln, ehe Sie mysql_real_connect() aufrufen. Die Passwortverschlüsselung wird automatisch von der Client-API vorgenommen.

  • db ist der Datenbankname. Wenn db nicht NULL ist, stellt die Verbindung diesen Wert als Standarddatenbank ein.

  • Wenn port nicht 0 ist, wird dieser Wert als Portnummer für die TCP/IP-Verbindung benutzt. Beachten Sie, dass der Parameter host den Verbindungstyp definiert.

  • Wenn unix_socket nicht NULL ist, gibt der String den Socket oder die Named Pipe für die Verbindung an. Beachten Sie, dass der Parameter host den Verbindungstyp definiert.

  • Der Wert von client_flag ist normalerweise 0, kann aber auf eine Kombination der folgenden Flags eingestellt werden, um bestimmte Features einzuschalten:

    Flag-NameFlag-Beschreibung
    CLIENT_COMPRESSVerwendet das komprimierte Protokoll.
    CLIENT_FOUND_ROWSLiefert die Anzahl der gefundenen (erkannten) anstatt der Anzahl der betroffenen Zeilen.
    CLIENT_IGNORE_SPACEErlaubt Leerzeichen hinter Funktionsnamen. Macht alle Funktionsnamen zu reservierten Wörtern.
    CLIENT_INTERACTIVEErlaubt interactive_timeout Sekunden (anstatt wait_timeout Sekunden) Müßiggang, bevor die Verbindung geschlossen wird. Die wait_timeout-Variable der Client-Session wird auf den Wert der Session-Variablen interactive_timeout gesetzt.
    CLIENT_LOCAL_FILESErmöglicht LOAD DATA LOCAL.
    CLIENT_MULTI_STATEMENTSTeilt dem Server mit, dass der Client mehrere Anweisungen (durch ‘;’ getrennt) in einem einzigen String senden darf. Ist dieses Flag nicht gesetzt, ist die Ausführung von Mehrfachanweisungen nicht möglich.
    CLIENT_MULTI_RESULTSTeilt dem Server mit, dass der Client mehrere Ergebnismengen von Mehrfachanweisungen oder mehrfachen gespeicherten Prozeduren behandeln kann. Wird automatisch gesetzt, wenn CLIENT_MULTI_STATEMENTS eingestellt ist.
    CLIENT_NO_SCHEMAVerbietet die db_name.tbl_name.col_name-Syntax. Dies gilt für ODBC. Der Parser löst bei Verwendung dieser Syntax einen Fehler aus, was für die Fehlerdiagnose in manchen ODBC-Programmen nützlich ist.
    CLIENT_ODBCDer Client ist ein ODBC-Client. Damit wird mysqld ODBC-freundlicher.
    CLIENT_SSLVerwendet SSL (verschlüsseltes Protokoll). Diese Option sollte nicht von Anwendungsprogrammen gesetzt werden, sondern intern in der Clientbibliothek. Verwenden Sie stattdessen mysql_ssl_set() vor dem Aufruf von mysql_real_connect().

Manche Parameterwerte können einer Optionsdatei entnommen werden, anstatt sie explizit im Aufruf von mysql_real_connect() zu setzen. Um dies zu tun, rufen Sie mysql_options() mit der Option MYSQL_READ_DEFAULT_FILE oder MYSQL_READ_DEFAULT_GROUP auf, bevor Sie mysql_real_connect() verwenden. Danach geben Sie im Aufruf von mysql_real_connect() den Wert „no-value“ für jeden Parameter an, der seinen Wert aus einer Optionsdatei holen soll:

  • Für host geben Sie NULL oder den leeren String ("") an.

  • Für user geben Sie NULL oder den leeren String ("") an.

  • Für passwd geben Sie NULL an. (Ein leerer String als Passwortwert kann im mysql_real_connect()-Aufruf nicht durch einen Wert aus einer Optionsdatei überschrieben werden, da der leere String ausdrücklich besagt, dass das MySQL-Konto ein leeres Passwort besitzen muss.)

  • Für db geben Sie NULL oder den leeren String ("") an.

  • Für port geben Sie den Wert 0 an.

  • Für unix_socket geben Sie den Wert NULL an.

Wenn in der Optionsdatei für einen Parameter kein Wert gefunden wird, wird sein Standardwert gemäß der Beschreibung weiter oben in diesem Abschnitt verwendet.

Rückgabewerte

Ein MYSQL*-Verbindungs-Handle, wenn die Verbindung erfolgreich eingerichtet wurde, und NULL, wenn der Verbindungsversuch keinen Erfolg hatte. Der Rückgabewert für eine erfolgreiche Verbindung ist derselbe wie der Wert des ersten Parameters.

Fehler

  • CR_CONN_HOST_ERROR

    Verbindung zum MySQL Server konnte nicht hergestellt werden.

  • CR_CONNECTION_ERROR

    Verbindung zum lokalen MySQL Server konnte nicht hergestellt werden.

  • CR_IPSOCK_ERROR

    Es konnte kein IP-Socket hergestellt werden.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SOCKET_CREATE_ERROR

    Es konnte kein Unix-Socket erzeugt werden.

  • CR_UNKNOWN_HOST

    Die IP-Adresse des Hostnamens konnte nicht gefunden werden.

  • CR_VERSION_ERROR

    Bei einem Versuch einer Verbindungsaufnahme zwischen einem Server und einer Clientbibliothek, die eine andere Protokollversion verwendet, wurde eine Diskrepanz der Protokolle festgestellt. Das kann geschehen, wenn Sie eine sehr alte Clientbibliothek zur Verbindung mit einem neuen Server verwenden, der nicht mit der Option --old-protocol gestartet wurde.

  • CR_NAMEDPIPEOPEN_ERROR

    Es konnte keine Named Pipe für Windows hergestellt werden.

  • CR_NAMEDPIPEWAIT_ERROR

    Es konnte nicht auf eine Named Pipe auf Windows gewartet werden.

  • CR_NAMEDPIPESETSTATE_ERROR

    Es konnte kein Pipe-Handler auf Windows beschafft werden.

  • CR_SERVER_LOST

    Wenn connect_timeout > 0 und es mehr als connect_timeout Sekunden dauerte, eine Verbindung mit dem Server herzustellen, oder wenn der Server während der Ausführung des Befehls init-command abgestürzt ist.

Beispiel

MYSQL mysql;

mysql_init(&mysql);
mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
{
    fprintf(stderr, "Failed to connect to database: Error: %s\n",
          mysql_error(&mysql));
}

Wenn Sie mysql_options() aufrufen, liest die MySQL-Bibliothek die Abschnitte [client] und [your_prog_name] in der Datei my.cnf. So ist gewährleistet, dass Ihr Programm auch dann funktioniert, wenn jemand MySQL in nichtstandardmäßiger Weise eingerichtet hat.

Beachten Sie, dass mysql_real_connect() beim Einrichten einer Verbindung das Flag reconnect (ein Teil der MYSQL-Struktur) bei API-Versionen vor 5.0.3 auf 1 und bei neueren Versionen auf 0 setzt. Hat das Flag den Wert 1, versucht sich das System erneut mit dem Server zu verbinden, wenn eine Anweisung wegen einer abgebrochenen Verbindung nicht ausgeführt werden konnte. Seit MySQL 5.0.13 können Sie das Verhalten in Bezug auf Neuverbindungen mit der Option MYSQL_OPT_RECONNECT zu mysql_options() steuern.

24.2.3.52. mysql_real_escape_string()

unsigned long mysql_real_escape_string(MYSQL *mysql, char *to, const char *from, unsigned long length)

Beachten Sie, dass mysql eine gültige, offene Verbindung sein muss. Diese ist erforderlich, da das Escape-Verhalten von dem Zeichensatz des Servers abhängt.

Beschreibung

Diese Funktion wird verwendet, um einen gültigen SQL-String zu erzeugen, den Sie in einer SQL-Anweisung benutzen können. Siehe Abschnitt 9.1.1, „Strings“.

Der String in from ist als SQL-String mit Escape-Zeichen unter Berücksichtigung des aktuellen Zeichensatzes der Verbindung kodiert. Das Ergebnis wird in to platziert und ein abschließendes Nullbyte angehängt. Kodierte Zeichen sind NUL (ASCII 0), ‘\n’, ‘\r’, ‘\’, ‘'’, ‘"’ und Strg-Z (siehe Abschnitt 9.1, „Literale: wie Strings und Zahlen geschrieben werden“). (Streng genommen verlangt MySQL ein Escape-Zeichen im Anfrage-String nur für den Backslash und die Sorte Anführungszeichen, in welche der String eingefasst ist. Diese Funktion setzt auch die anderen Zeichen in Anführungszeichen, damit sie in Logdateien leichter zu lesen sind.)

Der String, auf den from verweist, muss length Bytes lang sein. Den Puffer für to müssen Sie mit einer Länge von mindestens length*2+1 Bytes zuweisen. (Im schlimmsten Fall braucht vielleicht jedes Zeichen 2 Byte für die Kodierung und am Ende muss noch Platz für das Nullbyte vorhanden sein.) Wenn mysql_real_escape_string() zurückkehrt, ist der Inhalt von to ein auf null endender String. Der Rückgabewert ist die Länge des kodierten Strings ohne das abschließende Nullzeichen.

Wenn Sie den Zeichensatz für die Verbindung umstellen müssen, sollten Sie die Funktion mysql_set_character_set() anstelle einer SET NAMES- (oder SET CHARACTER SET-)Anweisung verwenden. mysql_set_character_set() arbeitet wie SET NAMES, beeinflusst aber auch den von mysql_real_escape_string() verwendeten Zeichensatz. Das tut SET NAMES nicht.

Beispiel

char query[1000],*end;

end = strmov(query,"INSERT INTO test_table values(");
*end++ = '\'';
end += mysql_real_escape_string(&mysql, end,"What's this",11);
*end++ = '\'';
*end++ = ',';
*end++ = '\'';
end += mysql_real_escape_string(&mysql, end,"binary data: \0\r\n",16);
*end++ = '\'';
*end++ = ')';

if (mysql_real_query(&mysql,query,(unsigned int) (end - query)))
{
   fprintf(stderr, "Failed to insert row, Error: %s\n",
           mysql_error(&mysql));
}

Die im Beispiel verwendete strmov()-Funktion gehört zur mysqlclient-Bibliothek und funktioniert wie strcpy(), gibt jedoch einen Zeiger auf die abschließende Null des ersten Parameters zurück.

Rückgabewerte

Die Länge des in to gesetzten Werts ohne das abschließende Nullzeichen.

Fehler

Keine.

24.2.3.53. mysql_real_query()

int mysql_real_query(MYSQL *mysql, const char *query, unsigned long length)

Beschreibung

Führt die SQL-Anfrage aus, auf die query verweist. Diese sollte ein length Bytes langer String sein. Normalerweise muss der String eine einzelne SQL-Anweisung ohne abschließendes Semikolon (‘;’) oder \g enthalten. Wenn Mehrfachanweisungen aktiviert sind, kann der String auch mehrere durch Semikola getrennte Anweisungen enthalten. Siehe Abschnitt 24.2.9, „C-API: Behandlung der Ausführung mehrerer Anweisungen“.

Sie müssen mysql_real_query() anstelle von mysql_query() benutzen, wenn Ihre Anfragen Binärdaten enthalten, da diese das ‘\0’-Zeichen enthalten können. Überdies ist die Funktion mysql_real_query() schneller als mysql_query(), da sie nicht strlen() auf dem Anfrage-String aufruft.

Wenn Sie wissen möchten, ob die Anfrage eigentlich eine Ergebnismenge zurückliefern sollte, können Sie dies mit mysql_field_count() überprüfen. Siehe Abschnitt 24.2.3.22, „mysql_field_count().

Rückgabewerte

Null, wenn die Anfrage Erfolg hatte. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.54. mysql_refresh()

int mysql_refresh(MYSQL *mysql, unsigned int options)

Beschreibung

Diese Funktionen leeren Tabellen oder Caches oder setzen Replikationsserver-Informationen zurück. Der Benutzer, der die Verbindung innehat, benötigt hierzu das RELOAD-Recht.

Das options-Argument ist eine Bitmaske, die sich aus einer beliebigen Kombination von folgenden Werten zusammensetzt. Mehrere Werte können mit OR verknüpft werden, um mehrere Operationen mit einem einzigen Aufruf zu erledigen.

  • REFRESH_GRANT

    Aktualisiert die Berechtigungstabellen, wie FLUSH PRIVILEGES.

  • REFRESH_LOG

    Leert die Logs, wie FLUSH LOGS.

  • REFRESH_TABLES

    Leert den Tabellen-Cache, wie FLUSH TABLES.

  • REFRESH_HOSTS

    Leert den Host-Cache, wie FLUSH HOSTS.

  • REFRESH_STATUS

    Setzt die Statusvariablen zurück, wie FLUSH STATUS.

  • REFRESH_THREADS

    Leert den Thread-Cache.

  • REFRESH_SLAVE

    Setzt auf einem Slave-Replikationsserver die Informationen über den Master-Server zurück und startet den Slave neu, wie RESET SLAVE.

  • REFRESH_MASTER

    Entfernt auf einem Master-Replikationsserver die im Binärlogindex aufgeführten Binärlogdateien und schneidet die Indexdatei ab, wie RESET MASTER.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.55. mysql_reload()

int mysql_reload(MYSQL *mysql)

Beschreibung

Veranlasst den MySQL Server, die Berechtigungstabellen neu zu laden. Der verbundene Benutzer benötigt hierzu das RELOAD-Recht.

Diese Funktion ist veraltet. Bitte benutzen Sie stattdessen mysql_query(), um die SQL-Anweisung FLUSH PRIVILEGES zu erteilen.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.56. mysql_rollback()

my_bool mysql_rollback(MYSQL *mysql)

Beschreibung

Rollt die aktuelle Transaktion zurück.

Was diese Funktion tut, hängt von dem Wert der Systemvariablen completion_type ab. Wenn der Wert von completion_type 2 ist, gibt der Server nach dem Abschluss der Transaktion Ressourcen frei und schließt die Clientverbindung. Das Clientprogramm sollte mysql_close() aufrufen, um die Verbindung auf der Clientseite zu schließen.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

Keine.

24.2.3.57. mysql_row_seek()

MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset)

Beschreibung

Setzt den Zeilen-Cursor auf eine beliebige Zeile in der Ergebnismenge einer Anfrage. Der offset-Wert ist ein Zeilen-Offset. Dieser sollte ein von mysql_row_tell() oder mysql_row_seek() zurückgegebener Wert sein. Er ist keine Zeilennummer; wenn Sie eine Zeile einer Ergebnismenge anhand ihrer Nummer suchen möchten, müssen Sie stattdessen mysql_data_seek() aufrufen.

Da für diese Funktion erforderlich ist, dass die Ergebnismengenstruktur das gesamte Anfrageergebnis enthält, kann mysql_row_seek() nur in Verbindung mit mysql_store_result() und nicht mit mysql_use_result() benutzt werden.

Rückgabewerte

Der vorherige Wert des Zeilen-Cursors. Dieser Wert kann an einen nachfolgenden mysql_row_seek()-Aufruf übergeben werden.

Fehler

Keine.

24.2.3.58. mysql_row_tell()

MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result)

Beschreibung

Gibt die aktuelle Position des Zeilen-Cursors für den letzten mysql_fetch_row()-Aufruf zurück. Dieser Wert kann als Argument an mysql_row_seek() übergeben werden.

Verwenden Sie mysql_row_tell() bitte nur nach mysql_store_result() und nicht nach mysql_use_result().

Rückgabewerte

Der aktuelle Offset des Zeilen-Cursors.

Fehler

Keine.

24.2.3.59. mysql_select_db()

int mysql_select_db(MYSQL *mysql, const char *db)

Beschreibung

Macht die Datenbank db zur Standarddatenbank auf der durch mysql angegebenen Verbindung. In den nachfolgenden Anfragen ist diese Datenbank der Standard für Tabellenreferenzen, die keine explizite Datenbankbezeichnung enthalten.

mysql_select_db() funktioniert nur, wenn der verbundene Benutzer mit der Berechtigung, die Datenbank zu nutzen, authentifiziert werden kann.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.60. mysql_set_character_set()

int mysql_set_character_set(MYSQL *mysql, char *csname)

Beschreibung

Diese Funktion stellt den Standardzeichensatz für die laufende Verbindung ein. Der String csname ist ein gültiger Zeichensatzname. Die Sortierreihenfolge der Verbindung wird die Standardsortierreihenfolge dieses Zeichensatzes. Die Funktion arbeitet wie die SET NAMES-Anweisung, stellt jedoch auch den Wert von mysql->charset ein und beeinflusst dadurch den von mysql_real_escape_string() verwendeten Zeichensatz.

Diese Funktion wurde in MySQL 5.0.7 hinzugefügt.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Beispiel

MYSQL mysql;

mysql_init(&mysql);
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
{
    fprintf(stderr, "Failed to connect to database: Error: %s\n",
          mysql_error(&mysql));
}

if (!mysql_set_charset_name(&mysql, "utf8")) 
{
    printf("New client character set: %s\n", mysql_character_set_name(&mysql));
}

24.2.3.61. mysql_set_server_option()

int mysql_set_server_option(MYSQL *mysql, enum enum_mysql_set_option option)

Beschreibung

Aktiviert oder deaktiviert eine Verbindungsoption. option kann einen der folgenden Werte haben:

MYSQL_OPTION_MULTI_STATEMENTS_ONSchaltet Unterstützung für Mehrfachanweisungen ein.
MYSQL_OPTION_MULTI_STATEMENTS_OFFSchaltet Unterstützung für Mehrfachanweisungen aus.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • ER_UNKNOWN_COM_ERROR

    Der Server unterstützte mysql_set_server_option() nicht (das ist der Fall, wenn der Server älter als 4.1.1 ist) oder er unterstützte die Option nicht, die man versuchte, einzustellen.

24.2.3.62. mysql_shutdown()

int mysql_shutdown(MYSQL *mysql, enum enum_shutdown_level shutdown_level)

Beschreibung

Veranlasst den Datenbankserver, herunterzufahren. Der Benutzer der Verbindung muss dieSHUTDOWN-Rechte besitzen. MySQL 5.1 Server unterstützen nur eine einzige Art von Shutdown; der shutdown_level muss der SHUTDOWN_DEFAULT sein. Wir planen, noch weitere Shutdown-Level einzuführen, um eine Wahlmöglichkeit zu eröffnen. Dynamisch verlinkte Executables, die mit älteren Versionen der libmysqlclient-Header kompiliert wurden und mysql_shutdown() aufrufen, müssen mit der älteren dynamischen Bibliothek libmysqlclient benutzt werden.

Der Shutdown-Prozess wird in Abschnitt 5.2.6, „Herunterfahren des MySQL Servers“, beschrieben.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.63. mysql_sqlstate()

const char *mysql_sqlstate(MYSQL *mysql)

Beschreibung

Gibt einen auf null endenden String mit dem SQLSTATE-Fehlercode für den letzten Fehler zurück. Der Fehlercode besteht aus fünf Zeichen. '00000' bedeutet „kein Fehler“. Die Werte sind durch ANSI-SQL und ODBC spezifiziert. Eine Liste der möglichen Werte finden Sie unter Anhang B, Fehlercodes und -meldungen.

Beachten Sie, dass sich nicht alle MySQL-Fehler SQLSTATE-Fehlercodes zuordnen lassen. Der Wert 'HY000' (allgemeiner Fehler) wird für Fehler verwendet, die nicht zuzuordnen sind.

Rückgabewerte

Ein auf null endender Zeichen-String mit dem SQLSTATE-Fehlercode.

Siehe auch

Siehe Abschnitt 24.2.3.14, „mysql_errno(), Abschnitt 24.2.3.15, „mysql_error(), und Abschnitt 24.2.7.26, „mysql_stmt_sqlstate().

24.2.3.64. mysql_ssl_set()

int mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher)

Beschreibung

mysql_ssl_set() richtet sichere SSL-Verbindungen ein. Diese Funktion muss vor mysql_real_connect() aufgerufen werden.

mysql_ssl_set() arbeitet nur, wenn in der Clientbibliothek die OpenSSL-Unterstützung aktiviert ist.

mysql ist der Verbindungs-Handler, der von mysql_init() zurückgegeben wird. Die anderen Parameter sind folgendermaßen spezifiziert:

  • key ist der Pfad zur Schlüsseldatei.

  • cert ist der Pfad zur Zertifikatsdatei.

  • ca ist der Pfad zur Certificate-Authority-Datei.

  • capath ist der Pfad zu einem Verzeichnis, das vertrauenswürdige SSL-CA-Zertifikate im Pem-Format enthält.

  • cipher ist eine Liste der zulässigen Chiffren für die SSL-Verschlüsselung.

Ungenutzte SSL-Parameter können mit NULL angegeben werden.

Rückgabewerte

Diese Funktion liefert immer 0. Wenn SSL verkehrt eingerichtet ist, gibt mysql_real_connect() bei Verbindungsversuchen einen Fehler zurück.

24.2.3.65. mysql_stat()

char *mysql_stat(MYSQL *mysql)

Beschreibung

Gibt einen Zeichen-String mit ähnlichen Informationen wie der Befehl mysqladmin status zurück. Dazu gehört die Uptime in Sekunden und die Anzahl der laufenden Threads, Fragen, Reloads und offenen Tabellen.

Rückgabewerte

Ein Zeichen-String, der den Serverstatus beschreibt. NULL, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.66. mysql_store_result()

MYSQL_RES *mysql_store_result(MYSQL *mysql)

Beschreibung

Sie müssen mysql_store_result() oder mysql_use_result() für jede Anfrage aufrufen, die erfolgreich Daten abruft (SELECT, SHOW, DESCRIBE, EXPLAIN, CHECK TABLE, und so weiter).

Für andere Anfragen brauchen Sie mysql_store_result() oder mysql_use_result() nicht zu verwenden, aber es schadet auch nichts und bringt keine spürbaren Leistungseinbußen, wenn Sie in jedem Fall mysql_store_result() aufrufen. Sie können erkennen, ob die Anfrage eine Ergebnismenge hatte oder nicht, indem Sie prüfen, ob mysql_store_result() 0 zurückgibt (darüber später mehr).

Wenn Sie wissen möchten, ob die Anfrage eine Ergebnismenge zurückgeben müsste, prüfen Sie dies mit mysql_field_count(). Siehe Abschnitt 24.2.3.22, „mysql_field_count().

mysql_store_result() liest das gesamte Anfrageergebnis auf den Client ein, weist eine MYSQL_RES-Struktur zu und setzt das Resultat in diese Struktur ein.

mysql_store_result() liefert einen Nullzeiger, wenn die Anfrage keine Ergebnismenge zurückgab (also beispielsweise eine INSERT-Anweisung war).

mysql_store_result() liefert auch einen Nullzeiger, wenn die Ergebnismenge nicht gelesen werden konnte. Ein Fehler ist aufgetreten, wenn mysql_error() einen nichtleeren String oder einen von null verschiedenen Wert liefert oder wenn mysql_field_count() null zurückgibt.

Eine leere Ergebnismenge bedeutet, dass keine Zeilen zurückgegeben wurden. (Eine leere Ergebnismenge ist etwas anderes als ein Nullzeiger als Rückgabewert.)

Wenn Sie mysql_store_result() aufgerufen und ein Ergebnis erhalten haben, das kein Nullzeiger ist, können Sie mit mysql_num_rows() ermitteln, wie viele Zeilen die Ergebnismenge hat.

Sie können mit mysql_fetch_row() Zeilen aus der Ergebnismenge abrufen oder mit mysql_row_seek() und mysql_row_tell() die aktuelle Zeilenposition in der Ergebnismenge ermitteln oder einstellen.

Wenn Sie mit der Ergebnismenge fertig sind, rufen Sie mysql_free_result() auf.

Siehe Abschnitt 24.2.13.1, „Warum gibt mysql_store_result() manchmal NULL zurück, nachdem mysql_query() Erfolg zurückgegeben hat?“.

Rückgabewerte

Eine MYSQL_RES-Ergebnisstruktur mit den Resultaten. NULL, wenn ein Fehler auftrat.

Fehler

Die Funktion mysql_store_result() setzt mysql_error() und mysql_errno() zurück, wenn sie erfolgreich gelaufen ist.

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.67. mysql_thread_id()

unsigned long mysql_thread_id(MYSQL *mysql)

Beschreibung

Gibt die Thread-ID der aktuellen Verbindung zurück. Dieser Wert kann als Argument für mysql_kill() verwendet werden, um den Thread anzuhalten.

Wenn die Verbindung abgebrochen ist und Sie sich mit mysql_ping() erneut zu verbinden versuchen, ändert sich die Thread-ID. Daher sollten Sie keine Thread-ID zur späteren Benutzung speichern, sondern sie erst dann erfragen, wenn Sie sie benötigen.

Rückgabewerte

Die Thread-ID der aktuellen Verbindung.

Fehler

Keine.

24.2.3.68. mysql_use_result()

MYSQL_RES *mysql_use_result(MYSQL *mysql)

Beschreibung

Sie müssen mysql_store_result() oder mysql_use_result() für jede Anfrage aufrufen, die erfolgreich Daten abruft (SELECT, SHOW, DESCRIBE, EXPLAIN).

mysql_use_result() initiiert den Abruf einer Ergebnismenge, lädt sie jedoch im Gegensatz zu mysql_store_result() nicht komplett auf den Client herunter. Stattdessen wird jede Zeile einzeln mit einem Aufruf von mysql_fetch_row() abgefragt. So wird ein Anfrageergebnis direkt vom Server gelesen, ohne es in einer temporären Tabelle oder in einem lokalen Puffer zwischenzuspeichern. Das geht schneller und belegt weniger Speicher als mysql_store_result(). Der Client weist nur für die aktuelle Zeile Speicher zu und reserviert einen Kommunikationspuffer, der bis zur Größe von max_allowed_packet Bytes anwachsen kann.

Demgegenüber sollten Sie mysql_use_result() nicht verwenden, wenn Sie jede Zeile auf der Clientseite aufwändig vearbeiten oder die Ausgabe an einen Bildschirm senden, in den der Benutzer ^S (Stop Scroll) eintippen kann. Dies würde den Server sperren und verhindern, dass andere Threads Tabellen aktualisieren können, aus denen die Daten abgerufen werden.

Wenn Sie mit mysql_use_result() arbeiten, müssen Sie mysql_fetch_row() so oft ausführen, bis ein NULL-Wert zurückgeliefert wird. Sonst werden die nicht abgerufenen Zeilen zu einem Teil der Ergebnismenge der nächsten Anfrage. Wenn Sie dies vergessen, meldet die C-API den Fehler Commands out of sync; you can't run this command now!

Die Funktionen mysql_data_seek(), mysql_row_seek(), mysql_row_tell(), mysql_num_rows() oder mysql_affected_rows() können nicht mit einer Ergebnisrückgabe von mysql_use_result() benutzt werden. Ebenso wenig können Sie andere Anfragen absetzen, bevor die Funktion mysql_use_result() ihre Arbeit beendet hat. (Immerhin liefert mysql_num_rows() ein akkurates Ergebnis, wenn Sie alle Zeilen abgeholt haben.)

Sie müssen mysql_free_result() aufrufen, wenn Sie mit der Ergebnismenge fertig sind.

Bei Verwendung des Embedded Servers libmysqld geht der Vorteil des geringen Speicherbedarfs verloren, da die Speicherbelegung inkrementell mit jeder abgeholten Zeile anwächst, bis Sie mysql_free_result() aufrufen.

Rückgabewerte

Eine MYSQL_RES-Ergebnisstruktur. NULL, wenn ein Fehler auftrat.

Fehler

mysql_use_result() setzt bei Erfolg mysql_error() und mysql_errno() zurück.

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.3.69. mysql_warning_count()

unsigned int mysql_warning_count(MYSQL *mysql)

Beschreibung

Gibt die Anzahl der während der Ausführung der vorangegangenen SQL-Anweisung ausgelösten Warnungen zurück.

Rückgabewerte

Die Anzahl der Warnungen.

Fehler

Keine.

24.2.4. C-API: Prepared Statements

Das Client/Server-Protokoll von MySQL ermöglicht auch vorbereitete Anweisungen. Diese nutzen die Datenstruktur eines MYSQL_STMT-Anweisungs-Handles, der von der Initialisierungsfunktion mysql_stmt_init() zurückgegeben wird. Die vorbereitete Ausführung ist ein effizientes Mittel, um eine Anweisung mehrmals laufen zu lassen. Zuerst wird sie geparst, um sie auf die Ausführung vorzubereiten, und später wird sie einmal oder mehrmals mithilfe des von der Initialisierungsfunktion zurückgelieferten Anweisungs-Handles benutzt.

Die vorbereitete Ausführung ist für Anweisungen, die mehrmals laufen, schneller als eine direkte Ausführung, da die Anfrage nur ein einziges Mal geparst werden muss. Bei einer direkten Ausführung muss die Anfrage dagegen jedes Mal von Neuem geparst werden. Eine vorbereitete Ausführung kann außerdem die Netzwerklast reduzieren, da bei jeder Ausführung der vorbereiteten Anweisung lediglich die Parameterdaten übermittelt werden müssen.

Ein weiterer Vorteil vorbereiteter Anweisungen besteht darin, dass sie ein Binärprotokoll benutzen, das den Datentransfer zwischen Client und Server effizienter gestaltet.

Die folgenden Anweisungen können als vorbereitete Anweisungen verwendet werden: CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE und die meisten SHOW-Anweisungen. Andere Anweisungen werden in MySQL 5.1 nicht unterstützt.

24.2.5. C-API: Prepared Statement-Datentypen

Vorbereitete Anweisungen nutzen hauptsächlich die Datenstrukturen MYSQL_STMT und MYSQL_BIND. Eine dritte Datenstruktur, nämlich MYSQL_TIME, wird zur Übertragung von Temporaldaten verwendet.

  • MYSQL_STMT

    Diese Struktur stellt eine vorbereitete Anweisung dar. Eine Anweisung wird mit der Funktion mysql_stmt_init() angelegt, die einen Anweisungs-Handle liefert (d. h. einen Zeiger auf MYSQL_STMT). Der Handle wird für alle folgenden mit der Anweisung verbundenen Funktionen benutzt, bis Sie ihn mit mysql_stmt_close() wieder schließen.

    Die MYSQL_STMT-Struktur hat keine Bestandteile für Anwendungen. Legen Sie bitte auch keine Kopie einer MYSQL_STMT-Struktur an, da nicht garantiert werden kann, dass eine solche Kopie benutzbar sein wird.

    Mehrere Anweisungs-Handles können mit einer einzigen Verbindung verknüpft werden. Wie viele Handles möglich sind, hängt von den Systemressourcen ab.

  • MYSQL_BIND

    Diese Struktur wird sowohl für die Eingabe einer Anweisung (der Datenwerte, die an den Server gesandt werden) als auch für ihre Ausgabe verwendet (die Ergebnisse, die vom Server zurückkommen). Für die Eingabe wird sie mit mysql_stmt_bind_param() benutzt, um die Parameterwerte an die Puffer zu binden, die mysql_stmt_execute() verwenden. Für die Ausgabe wird sie mit mysql_stmt_bind_result() benutzt, um die Ergebnismengenpuffer zu binden, die zum Abholen der Zeilen mit mysql_stmt_fetch() verwendet werden.

    Die MYSQL_BIND-Struktur enthält folgende Bestandteile zur Nutzung durch Anwendungsprogramme. Jeder Bestandteil wird sowohl für die Ein- als auch für die Ausgabe verwendet, allerdings manchmal zu unterschiedlichen Zwecken, je nachdem, in welche Richtung die Daten übertragen werden.

    • enum enum_field_types buffer_type

      Der Puffertyp. Die zulässigen buffer_type-Werte werden weiter unten in diesem Abschnitt aufgeführt. Für die Eingabe zeigt buffer_type an, welchen Werttyp Sie mit einem Anweisungsparameter verbinden. Für die Ausgabe zeigt er an, welchen Werttyp Sie in einem Ergebnispuffer erwarten.

    • void *buffer

      Für die Eingabe ist dies ein Zeiger auf den Puffer, in welchem die Parameterwerte einer Anweisung gespeichert werden. Für die Ausgabe ist es ein Zeiger auf den Puffer, in welchen die Spaltenwerte einer Ergebnismenge zurückgeliefert werden. Für numerische Datentypen sollte buffer auf eine Variable des korrekten C-Typs verweisen. (Wenn Sie die Variable mit einer Spalte verbinden, die das UNSIGNED-Attribut hat, sollte sie ein unsigned-C-Typ sein. Ob die Variable ein Vorzeichen hat oder nicht, geben Sie mithilfe des weiter unten beschriebenen Strukturbestandteils is_unsigned an.) Für Datums- und Uhrzeittypen sollte buffer auf eine MYSQL_TIME-Struktur verweisen. Für Zeichen- und Binär-String-Typen sollte buffer auf einen Zeichenpuffer verweisen.

    • unsigned long buffer_length

      Die tatsächliche Größe von *buffer in Bytes. Dies zeigt an, wie viele Daten maximal in dem Puffer gespeichert werden können. Für Zeichen und binäre C-Daten ist der buffer_length-Wert die Länge von *buffer, wenn er mit mysql_stmt_bind_param() gebraucht wird, beziehungsweise die Höchstzahl der Datenbytes, die in den Puffer zu laden sind, wenn er mit mysql_stmt_bind_result() gebraucht wird.

    • unsigned long *length

      Ein Zeiger auf eine unsigned long-Variable, die angibt, wie viele Bytes tatsächlich in *buffer gespeichert sind. length wird für Zeichen- oder Binärdaten in C verwendet. Zum Binden der Eingabeparameterdaten verweist length auf eine unsigned long-Variable, welche die Länge des in *buffer gespeicherten Parameterwerts angibt. Diese wird von mysql_stmt_execute() benutzt. Zum Binden der Ausgabewerte speichert mysql_stmt_fetch() die Länge des Rückgabespaltenwerts in der Variablen, auf die length verweist.

      length wird bei numerischen und temporalen Datentypen ignoriert, weil die Länge des Datenwerts anhand des Werts von buffer_type ermittelt wird.

    • my_bool *is_null

      Dies verweist auf eine my_bool-Variable, die TRUE ist, wenn ein Wert NULL ist, und FALSE, wenn er nicht NULL ist. Für die Eingabe setzen Sie *is_null auf TRUE, wenn Sie mitteilen möchten, dass Sie einen NULL-Wert als Anweisungsparameter übergeben. Für die Ausgabe wird dieser Wert nach dem Abruf einer Zeile der Ergebnismenge immer dann auf TRUE gesetzt, wenn der Spaltenwert, den die Anweisung zurückliefert, NULL ist.

      is_null ist ein Zeiger auf einen booleschen Wert anstatt auf einen booleschen Skalar. Daher kann er auf folgende Weise eingesetzt werden:

      • Wenn Ihre Datenwerte immer NULL sind, verwenden Sie MYSQL_TYPE_NULL, um die Spalte zu binden.

      • Wenn Ihre Datenwerte immer NOT NULL sind, stellen Sie ein: is_null = (my_bool*) 0.

      • In allen anderen Fällen sollten Sie is_null auf die Adresse einer my_bool-Variablen einstellen und deren Wert zwischen den Ausführungen jeweils so einstellen, dass sie anzeigt, ob Datenwerte NULL oder NOT NULL sind.

    • my_bool is_unsigned

      Dies wird für Integer-Typen benutzt (die den Typcodes MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG und MYSQL_TYPE_LONGLONG entsprechen.) is_unsigned sollte für vorzeichenlose Typen auf TRUE und für vorzeichenbehaftete auf FALSE gesetzt werden.

    • my_bool error

      Für die Ausgabe wird dieser Strukturbestandteil zur Meldung von Fehlern wegen abgeschnittener Datenwerte eingesetzt. Sie müssen diese Meldungen aktivieren, indem Sie mysql_options() mit der Option MYSQL_REPORT_DATA_TRUNCATION aufrufen. Wenn dies aktiviert ist, liefert mysql_stmt_fetch() die MYSQL_DATA_TRUNCATED-Meldungen und error ist in den MYSQL_BIND-Strukturen für Parameter, deren Datenwerte abgeschnitten wurden, TRUE. Beim Abschneiden geht ein Vorzeichen oder eine signifikante Ziffer verloren oder ein String hat nicht in eine Spalte gepasst.

    Um eine MYSQL_BIND-Struktur zu verwenden, müssen Sie zur Initialisierung ihren Inhalt auf null setzen und dann die soeben beschriebenen Bestandteile in geeigneter Weise einstellen. Wenn Sie beispielsweise ein Array von drei MYSQL_BIND-Strukturen deklarieren und initialisieren möchten, verfahren Sie folgendermaßen:

    MYSQL_BIND    bind[3];
    memset(bind, 0, sizeof(bind));
    
  • MYSQL_TIME

    Diese Struktur sendet und empfängt Daten vom Typ DATE, TIME, DATETIME und TIMESTAMP direkt an den bzw. von dem Server. Dies tut sie, indem der buffer_type-Teil einer MYSQL_BIND-Struktur auf einen der temporalen Datentypen und der buffer auf eine MYSQL_TIME-Struktur eingestellt wird.

    Die MYSQL_TIME-Struktur enthält folgende Bestandteile:

    • unsigned int year

      Das Jahr.

    • unsigned int month

      Der Monat des Jahres.

    • unsigned int day

      Der Tag des Monats.

    • unsigned int hour

      Die Stunde des Tages.

    • unsigned int minute

      Die Minute der Stunde.

    • unsigned int second

      Die Sekunde der Minute.

    • my_bool neg

      Ein boolesches Flag, das angibt, ob der Zeitwert negativ ist.

    • unsigned long second_part

      Ein Sekundenbruchteil. Dieser Teil wird zurzeit nicht benutzt.

    Es werden nur diejenigen Teile einer MYSQL_TIME-Struktur benutzt, die auf einen gegebenen Temporalwerttyp anwendbar sind: Die Elemente year, month und day werden für DATE-, DATETIME- und TIMESTAMP-Werte gebraucht und die Elemente hour, minute und second für TIME-, DATETIME- und TIMESTAMP-Werte. Siehe Abschnitt 24.2.10, „C-API: Behandlung von Datums- und Zeitwerten“.

Die folgende Tabelle zeigt die zulässigen Werte an, die im buffer_type-Teil von MYSQL_BIND-Strukturen angegeben werden können. Sie dokumentiert auch, welche SQL-Typen am ehesten den buffer_type-Werten entsprechen, sowie den entsprechenden C-Typ für numerische und temporale Typen.

buffer_type WertSQL-TypC-Typ
MYSQL_TYPE_BITBIT
MYSQL_TYPE_TINYTINYINTchar
MYSQL_TYPE_SHORTSMALLINTshort int
MYSQL_TYPE_LONGINTint
MYSQL_TYPE_LONGLONGBIGINTlong long int
MYSQL_TYPE_FLOATFLOATfloat
MYSQL_TYPE_DOUBLEDOUBLEdouble
MYSQL_TYPE_TIMETIMEMYSQL_TIME
MYSQL_TYPE_DATEDATEMYSQL_TIME
MYSQL_TYPE_DATETIMEDATETIMEMYSQL_TIME
MYSQL_TYPE_TIMESTAMPTIMESTAMPMYSQL_TIME
MYSQL_TYPE_STRINGCHAR 
MYSQL_TYPE_VAR_STRINGVARCHAR 
MYSQL_TYPE_TINY_BLOBTINYBLOB/TINYTEXT 
MYSQL_TYPE_BLOBBLOB/TEXT 
MYSQL_TYPE_MEDIUM_BLOBMEDIUMBLOB/MEDIUMTEXT 
MYSQL_TYPE_LONG_BLOBLONGBLOB/LONGTEXT 

Eine implizite Typumwandlung ist in beiden Richtungen möglich.

24.2.6. C-API Prepared Statements: Funktionsüberblick

Die Funktionen für vorbereitete Anweisungen werden hier zusammengefasst und im Weiteren genauer beschrieben. Siehe Abschnitt 24.2.7, „C-API Prepared Statements: Funktionsbeschreibungen“.

FunktionBeschreibung
mysql_stmt_affected_rows()Liefert die Anzahl der Änderungen, Löschungen und Einfügungen in Zeilen durch eine vorbereitete UPDATE-, DELETE- oder INSERT-Anweisung.
mysql_stmt_attr_get()Holt den Wert eines Attributs für eine vorbereitete Anweisung.
mysql_stmt_attr_set()Setzt ein Attribut für eine vorbereitete Anweisung.
mysql_stmt_bind_param()Verbindet Anwendungsdatenpuffer mit den Parametermarkern einer vorbereiteten SQL-Anweisung.
mysql_stmt_bind_result()Verbindet Anwendungsdatenpuffer mit den Spalten der Ergebnismenge.
mysql_stmt_close()Gibt den von einer vorbereiteten Anweisung benutzten Speicher frei.
mysql_stmt_data_seek()Sucht nach einer beliebigen Zeilennummer in der Ergebnismenge einer Anweisung.
mysql_stmt_errno()Liefert die Fehlernummer für die letzte Ausführung einer Anweisung.
mysql_stmt_error()Liefert die Fehlermeldung für die letzte Ausführung einer Anweisung.
mysql_stmt_execute()Führt die vorbereitete Anweisung aus.
mysql_stmt_fetch()Holt die nächste Datenzeile aus der Ergebnismenge und liefert Daten für alle gebundenen Spalten.
mysql_stmt_fetch_column()Holt Daten einer Spalte aus der aktuellen Zeile der Ergebnismenge.
mysql_stmt_field_count()Liefert die Anzahl der Ergebnisspalten für die letzte Anweisung.
mysql_stmt_free_result()Gibt die für den Anweisungs-Handle zugewiesenen Ressourcen frei.
mysql_stmt_init()Weist der MYSQL_STMT-Struktur Speicher zu und initialisiert sie.
mysql_stmt_insert_id()Liefert die für eine AUTO_INCREMENT-Spalte von einer vorbereiteten Anweisung generierte ID.
mysql_stmt_num_rows()Liefert die Gesamtzahl der Zeilen in der gepufferten Ergebnismenge der Anweisung.
mysql_stmt_param_count()Liefert die Anzahl der Parameter in einer vorbereiteten SQL-Anweisung.
mysql_stmt_param_metadata()Liefert Parametermetadaten in Form einer Ergebnismenge.
mysql_stmt_prepare()Bereitet einen SQL-String zur Ausführung vor.
mysql_stmt_reset()Setzt die Anweisungspuffer im Server zurück.
mysql_stmt_result_metadata()Liefert Metadaten zu einer vorbereiteten Anweisung in Form einer Ergebnismenge.
mysql_stmt_row_seek()Sucht einen Zeilen-Offset in der Ergebnismenge einer Anweisung und verwendet dazu den Rückgabewert von mysql_stmt_row_tell().
mysql_stmt_row_tell()Liefert die Zeilen-Cursor-Position der Anweisung.
mysql_stmt_send_long_data()Sendet lange Daten stückweise an den Server.
mysql_stmt_sqlstate()Liefert den SQLSTATE-Fehlercode für die letzte Anweisungsausführung.
mysql_stmt_store_result()Lädt die gesamte Ergebnismenge auf den Client herunter.

Rufen Sie zuerst mysql_stmt_init() auf, um einen Anweisungs-Handle zu erzeugen, dann mysql_stmt_prepare, um die Anweisung vorzubereiten, dann mysql_stmt_bind_param(), um die Parameterdaten zu liefern, und zum Schluss mysql_stmt_execute(), um die Anweisung auszuführen. Sie können den mysql_stmt_execute()-Aufruf wiederholen, indem Sie die Parameterwerte in den jeweiligen von mysql_stmt_bind_param() zur Verfügung gestellten Puffern ändern.

Ist die Anweisung ein SELECT oder eine andere Anweisung, die eine Ergebnismenge erstellt, liefert mysql_stmt_prepare() zu dieser Ergebnismenge auch Metadaten in Form einer von mysql_stmt_result_metadata() zurückgegebenen MYSQL_RES-Ergebnismenge.

Sie können die Ergebnispuffer mit mysql_stmt_bind_result() zur Verfügung stellen, sodass mysql_stmt_fetch() automatisch Daten an diese Puffer liefert. Dabei handelt es sich um einen zeilenweisen Datenabruf.

Sie können auch die Text- oder Binärdaten mit mysql_stmt_send_long_data() stückweise an den Server senden. Siehe Abschnitt 24.2.7.25, „mysql_stmt_send_long_data().

Wenn die Anweisungsausführung abgeschlossen ist, muss der Anweisungs-Handle mit mysql_stmt_close() geschlossen werden, damit alle seine Ressourcen freigegeben werden können.

Wenn Sie mit mysql_stmt_result_metadata() Metadaten zur Ergebnismenge einer SELECT-Anweisung beschafft haben, müssen Sie mit mysql_free_result() auch diese Metadaten freigeben.

Ausführungsschritte

Um eine Anweisung zur Nutzung in einer Anwendung vorzubereiten und auszuführen, müssen Sie Folgendes tun:

  1. Mit msyql_stmt_init() erzeugen Sie einen Handle für eine vorbereitete Anweisung. Um die Anweisung auf dem Server vorzubereiten, müssen Sie die Funktion mysql_stmt_prepare() aufrufen und ihr einen String mit der SQL-Anweisung übergeben.

  2. Wenn die Anweisung eine Ergebnismenge erstellt, müssen Sie die Metadaten dieser Ergebnismenge mit mysql_stmt_result_metadata() abholen. Die Metadaten liegen selbst ebenfalls in Form einer Ergebnismenge vor, allerdings einer anderen als der, die die Rückgabezeilen der Anfrage enthält. Die Metadatenergebnismenge gibt an, wie viele Spalten das Ergebnis enthält, und gibt Informationen über jede dieser Spalten.

  3. Die Parameterwerte setzen Sie mit mysql_stmt_bind_param(). Alle Parameter müssen gesetzt werden. Andernfalls gibt die Anweisungsausführung einen Fehler zurück oder liefert unerwartete Resultate.

  4. Mit einem Aufruf von mysql_stmt_execute() führen Sie die Anweisung aus.

  5. Wenn die Anweisung eine Ergebnismenge erstellt, binden Sie die Datenpuffer zum Abruf der Zeilenwerte mit mysql_stmt_bind_result().

  6. Laden Sie die Daten zeilenweise durch wiederholten Aufruf von mysql_stmt_fetch() in die Puffer herunter, bis keine weiteren Zeilen mehr vorliegen.

  7. Wiederholen Sie die Schritte 3 bis 6 so oft wie nötig, indem Sie die Parameterwerte ändern und die Anweisung erneut ausführen.

Bei einem Aufruf von mysql_stmt_prepare() tut das MySQL-Client/Server-Protokoll Folgendes:

  • Der Server parst die Anweisung und sendet den Okay-Status an den Client, indem er eine Anweisungs-ID zuweist. Außerdem sendet er, falls die Anweisung eine Ergebnismenge liefert, die Gesamtzahl der Parameter, eine Zeilenzahl und die Metadaten. Die Syntax und Semantik der Anweisung werden auf dem Server während dieses Aufrufs überprüft.

  • Der Client verwendet diese Anweisungs-ID für weitere Operationen, damit der Server die Anweisung in seinem Anweisungspool wiederfinden kann.

Bei einem Aufruf von mysql_stmt_execute() geht das MySQL-Client/Server-Protokoll folgendermaßen vor:

  • Der Client nutzt den Anweisungs-Handle und sendet die Parameterdaten an den Server.

  • Der Server findet die Anweisung anhand der vom Client übergebenen ID wieder, ersetzt die Parametermarker mit den frisch gelieferten Daten und führt die Anweisung aus. Wenn die Anweisung eine Ergebnismenge erstellt, sendet der Server die Daten an den Client zurück, ansonsten sendet er einen Okay-Status und die Gesamtzahl der geänderten, gelöschten oder eingefügten Zeilen.

Bei einem Aufruf von mysql_stmt_fetch() geht das MySQL-Client/Server-Protokoll folgendermaßen vor:

  • Der Client liest die Daten zeilenweise aus dem Paket ein und setzt sie in die Datenpuffer der Anwendung, indem er die notwendigen Typkonvertierungen vornimmt. Hat der Anwendungsdatenpuffer denselben Typ wie das vom Server zurückgegebene Feld, ist die Konvertierung einfach.

Wenn ein Fehler auftritt, können Sie den Anweisungsfehlercode, die Fehlermeldung und den SQLSTATE-Wert mit den Funktionen mysql_stmt_errno(), mysql_stmt_error() und mysql_stmt_sqlstate() erhalten.

Protokollierung vorbereiteter Anweisungen

Für vorbereitete Anweisungen, die mit den C-API-Funktionen mysql_stmt_prepare() und mysql_stmt_execute() ausgeführt werden, schreibt der Server Prepare- und Execute-Zeilen in das allgemeine Anfragenlog, damit Sie hinterher wissen, wann Anweisungen vorbereitet und ausgeführt wurden.

Angenommen, Sie bereiten eine Anweisung folgendermaßen vor und führen sie aus:

  1. Sie rufen mysql_stmt_prepare() auf, um den Anweisungs-String "SELECT ?" vorzubereiten.

  2. Sie rufen mysql_stmt_bind_param() auf, um den Wert 3 an den Parameter der vorbereiteten Anweisung zu binden.

  3. Sie rufen mysql_stmt_execute() auf, um die vorbereitete Anweisung auszuführen.

Aufgrund dieser Funktionsaufrufe schreibt der Server folgende Zeilen in das allgemeine Anfragenlog:

Prepare  [1] SELECT ?
Execute  [1] SELECT 3

Jede Prepare- und Execute-Zeile im Log wird mit einem [N]-Anweisungsbezeichner markiert, damit Sie nachvollziehen können, welche vorbereitete Anweisung gerade protokolliert wird. N ist ein positiver Integer. Wenn mehrere vorbereitete Anweisungen zugleich für den Client aktiv sind, kann N größer als 1 sein. Jede Execute-Zeile zeigt eine vorbereitete Anweisung nach Einsetzung der Datenwerte in die ?-Parameter an.

Versionshinweise: Prepare-Zeilen werden vor MySQL 4.1.10 ohne [N] angezeigt. Execute-Zeilen werden vor MySQL 4.1.10 überhaupt nicht angezeigt.

24.2.7. C-API Prepared Statements: Funktionsbeschreibungen

Um Anfragen vorzubereiten und auszuführen, verwenden Sie die Funktionen, die in den folgenden Abschnitten genauer beschrieben werden.

Beachten Sie, dass alle Funktionen, die mit der MYSQL_STMT-Struktur arbeiten, mit dem Präfix mysql_stmt_ anfangen.

Um einen MYSQL_STMT-Handle anzulegen, verwenden Sie die mysql_stmt_init()-Funktion.

24.2.7.1. mysql_stmt_affected_rows()

my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt)

Beschreibung

Diese Funktion gibt die Gesamtzahl der von der zuletzt ausgeführten Anweisung geänderten, gelöschten oder eingefügten Zeilen zurück. Für UPDATE-, DELETE- oder INSERT-Anweisungen kann sie unmittelbar nach mysql_stmt_execute() aufgerufen werden. Für SELECT-Anweisungen arbeitet mysql_stmt_affected_rows() genau wie mysql_num_rows().

Rückgabewerte

Ein Integer größer null zeigt die Anzahl der betroffenen oder abgerufenen Zeilen an. Null zeigt für eine UPDATE-Anweisung an, dass keine Zeilen aktualisiert wurden, für eine WHERE-Klausel in der Anfrage, dass keine Zeilen gepasst haben, oder ansonsten, dass die Anfrage noch gar nicht ausgeführt wurde. -1 bedeutet, dass die Anfrage einen Fehler zurückgeliefert hat oder, bei einer SELECT-Anfrage, dass mysql_stmt_affected_rows() vor mysql_stmt_store_result() aufgerufen wurde. Da mysql_stmt_affected_rows() einen vorzeichenlosen Wert liefert, können Sie -1 überprüfen, indem Sie den Rückgabewert mit (my_ulonglong)-1 (oder dem Äquivalent (my_ulonglong)~0) vergleichen.

Weitere Informationen über den Rückgabewert finden Sie unter Abschnitt 24.2.3.1, „mysql_affected_rows().

Fehler

Keine.

Beispiel

Ein Anwendungsbeispiel für mysql_stmt_affected_rows() finden Sie im Beispiel von Abschnitt 24.2.7.10, „mysql_stmt_execute().

24.2.7.2. mysql_stmt_attr_get()

int mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type option, void *arg)

Beschreibung

Kann genutzt werden, um den aktuellen Wert eines Anweisungsattributs abzufragen.

Das option-Argument ist die abzufragende Option; das arg sollte auf eine Variable mit dem Optionswert verweisen. Wenn die Option ein Integer ist, sollte arg auf den Wert dieses Integers verweisen.

Eine Liste aller Optionen und Optionstypen finden Sie unter Abschnitt 24.2.7.3, „mysql_stmt_attr_set().

Rückgabewerte

0, wenn alles okay ist. Ein von null verschiedener Wert, wenn option unbekannt ist.

Fehler

Keine.

24.2.7.3. mysql_stmt_attr_set()

int mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type option, const void *arg)

Beschreibung

Kann genutzt werden, um das Verhalten einer vorbereiteten Anweisung zu beeinflussen. Diese Funktion kann auch mehrmals aufgerufen werden, um mehrere Optionen zu setzen.

Das option-Argument ist die Option, die Sie einstellen möchten, und arg ist ihr Wert. Wenn die Option ein Integer ist, muss arg auf den Wert eines Integers verweisen.

Mögliche option-Werte:

OptionArgumenttypFunktion
STMT_ATTR_UPDATE_MAX_LENGTHmy_bool *Wenn 1: Metadaten zum Update MYSQL_FIELD->max_length in mysql_stmt_store_result().
STMT_ATTR_CURSOR_TYPEunsigned long *Typ des Cursors, der bei Aufruf von mysql_stmt_execute() für die Anweisung geöffnet wird. *arg kann CURSOR_TYPE_NO_CURSOR (Standardwert) oder CURSOR_TYPE_READ_ONLY sein.
STMT_ATTR_PREFETCH_ROWSunsigned long *Anzahl der Zeilen, die mit einem Cursor gleichzeitig vom Server geholt werden. *arg liegt zwischen 1 und dem Maximalwert von unsigned long. Der Standardwert ist 1.

Wenn Sie die Option STMT_ATTR_CURSOR_TYPE mit CURSOR_TYPE_READ_ONLY verwenden, wird ein Cursor für die Anweisung geöffnet, sobald Sie mysql_stmt_execute() aufrufen. Existiert bereits ein geöffneter Cursor aus einem früheren mysql_stmt_execute()-Aufruf, schließt die Option diesen Cursor, bevor ein neuer geöffnet wird. Die Funktion mysql_stmt_reset() schließt auch offene Cursors, bevor sie die Anweisung zur erneuten Ausführung vorbereitet. mysql_stmt_free_result() schließt ebenfalls einen eventuell noch offenen Cursor.

Wenn Sie einen Cursor für eine vorbereitete Anweisung öffnen, ist mysql_stmt_store_result() überflüssig, da diese Funktion die Ergebnismenge auf der Clientseite puffern lässt.

Die Option STMT_ATTR_CURSOR_TYPE wurde in MySQL 5.0.2 hinzugefügt. Die Option STMT_ATTR_PREFETCH_ROWS wurde in MySQL 5.0.6 hinzugefügt.

Rückgabewerte

0, wenn alles okay ist. Ein von null verschiedener Wert, wenn option unbekannt ist.

Fehler

Keine.

Beispiel

Das folgende Beispiel öffnet einen Cursor für eine vorbereitete Anweisung und setzt die Anzahl der in einem Schwung abzuholenden Zeilen auf 5:

MYSQL_STMT *stmt;
int rc;
unsigned long type;
unsigned long prefetch_rows = 5;

stmt = mysql_stmt_init(mysql);
type = (unsigned long) CURSOR_TYPE_READ_ONLY;
rc = mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
/* ... prüfe Rückgabewert... */
rc = mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS,
                         (void*) &prefetch_rows);
  /* ... prüfe Rückgabewert ... */

24.2.7.4. mysql_stmt_bind_param()

my_bool mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)

Beschreibung

Die Funktion mysql_stmt_bind_param() bindet Daten an die Parametermarker in der SQL-Anweisung, die an mysql_stmt_prepare() übergeben wurde. Zur Übergabe der Daten verwendet sie MYSQL_BIND-Strukturen. bind ist die Adresse eines Arrays von MYSQL_BIND-Strukturen. Die Clientbibliothek erwartet, dass das Array für jeden ‘?’-Parametermarker in der Anfrage einen Wert enthält.

Angenommen, Sie bereiten folgende Anweisung vor:

INSERT INTO mytbl VALUES(?,?,?)

Wenn Sie die Parameter binden, muss das Array von MYSQL_BIND-Strukturen drei Elemente enthalten. Es kann wie folgt deklariert werden:

MYSQL_BIND bind[3];

Die Bestandteile jedes MYSQL_BIND-Elements, das gesetzt werden muss, sind in Abschnitt 24.2.5, „C-API: Prepared Statement-Datentypen“, beschrieben.

Rückgabewerte

Null, wenn das Binden erfolgreich verlief. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_INVALID_BUFFER_USE

    Zeigt an, ob lange Daten beim Binden stückweise an einen Puffer übergeben werden, der kein String- oder Binärpuffer ist.

  • CR_UNSUPPORTED_PARAM_TYPE

    Die Konvertierung wird nicht unterstützt. Eventuell ist der buffer_type-Wert unzulässig oder hat keinen der unterstützten Typen.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

Wie man mysql_stmt_bind_param() verwendet, sehen Sie im Beispiel von Abschnitt 24.2.7.10, „mysql_stmt_execute().

24.2.7.5. mysql_stmt_bind_result()

my_bool mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)

Beschreibung

mysql_stmt_bind_result() bindet Spalten der Ergebnismenge an Daten- und Längenpuffer. Wenn Daten mit mysql_stmt_fetch() abgeholt werden, setzt das MySQL-Client/Server-Protokoll die Daten für gebundene Spalten in die angegebenen Puffer ein.

Alle Spalten müssen an ihre Puffer gebunden sein, bevor mysql_stmt_fetch() aufgerufen wird. bind ist die Adresse eines Arrays von MYSQL_BIND-Strukturen. Die Clientbibliothek erwartet, dass dieses Array für jede Spalte der Ergebnismenge ein Element enthält. Wenn Sie es versäumen, Spalten an MYSQL_BIND-Strukturen zu binden, ignoriert mysql_stmt_fetch() einfach den Datenabruf. Die Puffer sollten groß genug sein, um die Datenwerte speichern zu können, da dieses Protokoll die Daten nicht stückweise zurückgeben kann.

Eine Spalte kann jederzeit gebunden oder neu gebunden werden, auch dann, wenn eine Ergebnismenge teilweise abgeholt wurde. Die neue Bindung tritt beim nächsten Aufruf von mysql_stmt_fetch() in Kraft. Nehmen wir an, eine Anwendung bindet die Spalten in einer Ergebnismenge und ruft mysql_stmt_fetch() auf. Das Client/Server-Protokoll liefert die Daten in die gebundenen Puffer. Wenn die Anwendung nun aber die Spalten an andere Puffer bindet, schreibt das Protokoll die Daten erst beim nächsten Aufruf von mysql_stmt_fetch() in diese anderen Puffer.

Um eine Spalte zu binden, ruft eine Anwendung mysql_stmt_bind_result() auf und übergibt den Typ, die Adresse und die Adresse des Längenpuffers. Die Bestandteile der MYSQL_BIND-Elemente sollten so eingestellt werden wie in Abschnitt 24.2.5, „C-API: Prepared Statement-Datentypen“, beschrieben.

Rückgabewerte

Null, wenn das Binden erfolgreich verlief. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_UNSUPPORTED_PARAM_TYPE

    Die Konvertierung wird nicht unterstützt. Möglicherweise ist der buffer_type-Wert unzulässig oder hat keinen Typ, der unterstützt wird.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

Die Verwendung von mysql_stmt_bind_result() wird im Beispiel von Abschnitt 24.2.7.11, „mysql_stmt_fetch(), gezeigt.

24.2.7.6. mysql_stmt_close()

my_bool mysql_stmt_close(MYSQL_STMT *)

Beschreibung

Schließt die vorbereitete Anweisung. Außerdem gibt mysql_stmt_close() den Anweisungs-Handle von stmt frei.

Wenn die aktuelle Anweisung noch ausstehende oder ungelesene Ergebnisse hat, werden sie durch diese Funktion annulliert, damit die nächste Anfrage ausgeführt werden kann.

Rückgabewerte

Null, wenn die Anweisung erfolgreich freigegeben wurde. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

Die Anwendung von mysql_stmt_close() sehen Sie im Beispiel zu Abschnitt 24.2.7.10, „mysql_stmt_execute().

24.2.7.7. mysql_stmt_data_seek()

void mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset)

Beschreibung

Findet eine beliebige Zeile in einer Ergebnismenge einer Anweisung. Der offset-Wert ist eine Zeilennummer zwischen 0 und mysql_stmt_num_rows(stmt)-1.

Für diese Funktion ist erforderlich, dass die Ergebnismengenstruktur der Anweisung das gesamte Ergebnis der zuletzt ausgeführten Anfrage enthält. Daher kann mysql_stmt_data_seek() nur in Verbindung mit mysql_stmt_store_result() eingesetzt werden.

Rückgabewerte

Keine.

Fehler

Keine.

24.2.7.8. mysql_stmt_errno()

unsigned int mysql_stmt_errno(MYSQL_STMT *stmt)

Beschreibung

Für die durch stmt spezifizierte Anweisung liefert mysql_stmt_errno() den Fehlercode der zuletzt aufgerufenen Anweisungs-API-Funktion, die erfolgreich laufen oder scheitern kann. Null wird zurückgegeben, wenn kein Fehler auftrat. Die Nummern der Clientfehlermeldungen sind in der MySQL-Header-Datei errmsg.h aufgeführt. Die Nummern der Serverfehlermeldungen finden Sie in mysqld_error.h. Außerdem sind die Fehler in Anhang B, Fehlercodes und -meldungen, aufgelistet.

Rückgabewerte

Der Wert eines Fehlercodes. Null, wenn kein Fehler auftrat.

Fehler

Keine.

24.2.7.9. mysql_stmt_error()

const char *mysql_stmt_error(MYSQL_STMT *stmt)

Beschreibung

Für die durch stmt spezifizierte Anweisung liefert mysql_stmt_error() einen auf null endenden String mit der Fehlermeldung für die zuletzt aufgerufene Anweisungs-API-Funktion, die erfolgreich laufen oder scheitern kann. Ein leerer String ("") wird zurückgegeben, wenn kein Fehler auftrat. Das bedeutet, dass die beiden folgenden Tests äquivalent sind:

if (mysql_stmt_errno(stmt))
{
  // Ein Fehler trat auf
}

if (mysql_stmt_error(stmt)[0])
{
  // Ein Fehler trat auf
}

Die Sprache der Clientfehlermeldungen kann sich durch Rekompilieren der MySQL-Clientbibliothek ändern. Zurzeit haben Sie die Wahl zwischen Fehlermeldungen in mehreren verschiedenen Sprachen.

Rückgabewerte

Ein Zeichen-String, der den Fehler beschreibt. Ein leerer String, wenn kein Fehler auftrat.

Fehler

Keine.

24.2.7.10. mysql_stmt_execute()

int mysql_stmt_execute(MYSQL_STMT *stmt)

Beschreibung

mysql_stmt_execute() führt die vorbereitete Anfrage aus, die zu dem Anweisungs-Handle gehört. Die aktuellen Werte der gebundenen Parametermarker werden bei diesem Aufruf an den Server geschickt, und der Server ersetzt die Marker durch die frisch gelieferten Daten.

Wenn die Anweisung ein UPDATE, DELETE oder INSERT ist, erfahren Sie durch einen Aufruf von mysql_stmt_affected_rows(), wie viele Zeilen geändert, gelöscht oder eingefügt wurden. Ist es eine Anweisung wie SELECT, die eine Ergebnismenge generiert, müssen Sie zuerst mit mysql_stmt_fetch() die Daten abholen, bevor Sie irgendwelche Funktionen aufrufen, um die Anfrage zu verarbeiten. Weitere Informationen über den Abruf von Ergebnissen finden Sie in Abschnitt 24.2.7.11, „mysql_stmt_fetch().

Für Anweisungen, die eine Ergebnismenge generieren, können Sie verlangen, dass mysql_stmt_execute() einen Cursor öffnet, indem Sie vor Ausführung der Anweisung mysql_stmt_attr_set() aufrufen. Wenn Sie eine Anweisung mehrmals ausführen, schließt mysql_stmt_execute() einen eventuell noch offenen Cursor, ehe es einen neuen öffnet.

Rückgabewerte

Null, wenn die Ausführung Erfolg hatte. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

Das folgende Beispiel zeigt, wie eine Tabelle mithilfe von mysql_stmt_init(), mysql_stmt_prepare(), mysql_stmt_param_count(), mysql_stmt_bind_param(), mysql_stmt_execute() und mysql_stmt_affected_rows() angelegt und mit Daten gefüllt wird. Die mysql-Variable sei ein gültiger Verbindungs-Handle.

#define STRING_SIZE 50

#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table"
#define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 INT,\
                                                 col2 VARCHAR(40),\
                                                 col3 SMALLINT,\
                                                 col4 TIMESTAMP)"
#define INSERT_SAMPLE "INSERT INTO test_table(col1,col2,col3) VALUES(?,?,?)"

MYSQL_STMT    *stmt;
MYSQL_BIND    bind[3];
my_ulonglong  affected_rows;
int           param_count;
short         small_data;
int           int_data;
char          str_data[STRING_SIZE];
unsigned long str_length;
my_bool       is_null;

if (mysql_query(mysql, DROP_SAMPLE_TABLE))
{
  fprintf(stderr, " DROP TABLE failed\n");
  fprintf(stderr, " %s\n", mysql_error(mysql));
  exit(0);
}

if (mysql_query(mysql, CREATE_SAMPLE_TABLE))
{
  fprintf(stderr, " CREATE TABLE failed\n");
  fprintf(stderr, " %s\n", mysql_error(mysql));
  exit(0);
}

/* Bereite eine INSERT-Anfrage mit 3 Parametern vor */
/* (Die TIMESTAMP-Spalte ist nicht benannt; der Server */
/*  stellt sie auf das aktuelle Datum und die Uhrzeit ein.) */
stmt = mysql_stmt_init(mysql);
if (!stmt)
{
  fprintf(stderr, " mysql_stmt_init(), out of memory\n");
  exit(0);
}
if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE)))
{
  fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}
fprintf(stdout, " prepare, INSERT successful\n");

/* Hole die Zahl der Parameter aus der Anweisung */
param_count= mysql_stmt_param_count(stmt);
fprintf(stdout, " total parameters in INSERT: %d\n", param_count);

if (param_count != 3) /* Validiere Parameterzahl */
{
  fprintf(stderr, " invalid parameter count returned by MySQL\n");
  exit(0);
}

/* Binde die Daten für alle 3 Parameter */

memset(bind, 0, sizeof(bind));

/* INTEGER PARAM */
/* Da dies ein Zahlentyp ist, muss buffer_length nicht angegeben werden */
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (char *)&int_data;
bind[0].is_null= 0;
bind[0].length= 0;

/* STRING PARAM */
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= (char *)str_data;
bind[1].buffer_length= STRING_SIZE;
bind[1].is_null= 0;
bind[1].length= &str_length;

/* SMALLINT PARAM */
bind[2].buffer_type= MYSQL_TYPE_SHORT;
bind[2].buffer= (char *)&small_data;
bind[2].is_null= &is_null;
bind[2].length= 0;

/* Binde die Puffer */
if (mysql_stmt_bind_param(stmt, bind))
{
  fprintf(stderr, " mysql_stmt_bind_param() failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

/* Gib Datenwerte für die erste Zeile an */
int_data= 10;             /* Integer */
strncpy(str_data, "MySQL", STRING_SIZE); /* String  */
str_length= strlen(str_data);

/* INSERT SMALLINT-Daten als NULL */
is_null= 1;

/* Führe die INSERT-Anweisung aus - 1*/
if (mysql_stmt_execute(stmt))
{
  fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

/* Hole Gesamtzahl der betroffenen Zeilen */
affected_rows= mysql_stmt_affected_rows(stmt);
fprintf(stdout, " total affected rows(insert 1): %lu\n",
                (unsigned long) affected_rows);

if (affected_rows != 1) /* validiere betroffene Zeilen */
{
  fprintf(stderr, " invalid affected rows by MySQL\n");
  exit(0);
}

/* Gib Datenwerte für zweite Zeile an und führe Anweisung erneut aus */
int_data= 1000;
strncpy(str_data, "The most popular Open Source database", STRING_SIZE);
str_length= strlen(str_data);
small_data= 1000;         /* smallint */
is_null= 0;               /* Zurücksetzen */

/* Führe die INSERT-Anweisung aus - 2*/
if (mysql_stmt_execute(stmt))
{
  fprintf(stderr, " mysql_stmt_execute, 2 failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

  /* Hole Gesamtzahl der betroffenen Zeilen */
affected_rows= mysql_stmt_affected_rows(stmt);
fprintf(stdout, " total affected rows(insert 2): %lu\n",
                (unsigned long) affected_rows);

  if (affected_rows != 1) /* validiere betroffene Zeilen */
{
  fprintf(stderr, " invalid affected rows by MySQL\n");
  exit(0);
}

/* Schließe die Anweisung */
if (mysql_stmt_close(stmt))
{
  fprintf(stderr, " failed while closing the statement\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

Hinweis: Vollständigere Beispiele für die Nutzung von Funktionen für vorbereitete Anweisungen finden Sie in der Datei tests/mysql_client_test.c. Diese liegt in der MySQL-Quelldistribution und im BitKeeper-Quellarchiv.

24.2.7.11. mysql_stmt_fetch()

int mysql_stmt_fetch(MYSQL_STMT *stmt)

Beschreibung

Die Funktion mysql_stmt_fetch() liefert die nächste Zeile der Ergebnismenge und kann nur aufgerufen werden, während die Ergebnismenge besteht, also nach einem mysql_stmt_execute()-Aufruf, der eine Ergebnismenge produziert, oder nach einem mysql_stmt_store_result()-Aufruf, der im Anschluss an mysql_stmt_execute() die gesamte Ergebnismenge puffert.

Die Funktion mysql_stmt_fetch() liefert Zeilendaten über alle Spalten der aktuellen Zeilenmenge an die in mysql_stmt_bind_result() gebundenen Puffer. Die Längen werden an den length-Zeiger zurückgegeben.

Alle Spalten müssen von der Anwendung gebunden werden, ehe mysql_stmt_fetch() aufgerufen werden kann.

Ist ein abgerufener Datenwert NULL, ist der *is_null-Wert der zugehörigen MYSQL_BIND-Struktur TRUE (1). Andernfalls werden die Daten und ihre Länge in die Elemente *buffer und *length zurückgegeben, und zwar basierend auf dem von der Anwendung angegebenen Puffertyp. Jeder numerische und temporale Typ hat eine festgelegte Länge, wie in der folgenden Tabelle angegeben. Die Länge von String-Typen hängt von der Länge des tatsächlichen Datenwerts ab, wie in data_length angegeben.

TypLänge
MYSQL_TYPE_TINY1
MYSQL_TYPE_SHORT2
MYSQL_TYPE_LONG4
MYSQL_TYPE_LONGLONG8
MYSQL_TYPE_FLOAT4
MYSQL_TYPE_DOUBLE8
MYSQL_TYPE_TIMEsizeof(MYSQL_TIME)
MYSQL_TYPE_DATEsizeof(MYSQL_TIME)
MYSQL_TYPE_DATETIMEsizeof(MYSQL_TIME)
MYSQL_TYPE_STRINGdata_length
MYSQL_TYPE_BLOBdata_length

Rückgabewerte

RückgabewertBeschreibung
0Erfolg, die Daten wurden in die Anwendungsdatenpuffer geladen.
1Fehler. Den Fehlercode und die Fehlermeldung erhalten Sie von mysql_stmt_errno() und mysql_stmt_error().
MYSQL_NO_DATAKeine weiteren Zeilen/Daten vorhanden.
MYSQL_DATA_TRUNCATEDDaten wurden abgeschnitten.

MYSQL_DATA_TRUNCATED-Meldungen werden nur zurückgegeben, wenn dies mit mysql_options() eingestellt wurde. Um bei einer Rückgabe dieses Werts festzustellen, welche Daten abgeschnitten wurden, schauen Sie sich die error-Bestandteile der MYSQL_BIND-Parameterstrukturen an.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

  • CR_UNSUPPORTED_PARAM_TYPE

    Der Puffertyp ist MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME oder MYSQL_TYPE_TIMESTAMP, aber der Datentyp ist nicht DATE, TIME, DATETIME oder TIMESTAMP.

  • Alle anderen Fehler wegen nicht unterstützter Konvertierungen werden von mysql_stmt_bind_result() zurückgegeben.

Beispiel

Das folgende Beispiel zeigt, wie man Daten aus einer Tabelle mit mysql_stmt_result_metadata(), mysql_stmt_bind_result() und mysql_stmt_fetch() abholt. (Es wird erwartet, dass mit diesem Beispiel die beiden Zeilen abgerufen werden, die in Abschnitt 24.2.7.10, „mysql_stmt_execute(), eingefügt wurden.) Die Variable mysql sei ein gültiger Verbindungs-Handle.

#define STRING_SIZE 50

#define SELECT_SAMPLE "SELECT col1, col2, col3, col4 FROM test_table"

MYSQL_STMT    *stmt;
MYSQL_BIND    bind[4];
MYSQL_RES     *prepare_meta_result;
MYSQL_TIME    ts;
unsigned long length[4];
int           param_count, column_count, row_count;
short         small_data;
int           int_data;
char          str_data[STRING_SIZE];
my_bool       is_null[4];

/* SELECT-Anfrage vorbereiten, um Daten aus test_table zu holen*/
stmt = mysql_stmt_init(mysql);
if (!stmt)
{
  fprintf(stderr, " mysql_stmt_init(), out of memory\n");
  exit(0);
}
if (mysql_stmt_prepare(stmt, SELECT_SAMPLE, strlen(SELECT_SAMPLE)))
{
  fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}
fprintf(stdout, " prepare, SELECT successful\n");

/* Hole Zahl der Parameter aus der Anweisung */
param_count= mysql_stmt_param_count(stmt);
fprintf(stdout, " total parameters in SELECT: %d\n", param_count);

if (param_count != 0) /* validiere Zahl der Parameter */
{
  fprintf(stderr, " invalid parameter count returned by MySQL\n");
  exit(0);
}

/* Hole Metainformationen zur Ergebnismenge */
prepare_meta_result = mysql_stmt_result_metadata(stmt);
if (!prepare_meta_result)
{
  fprintf(stderr,
         " mysql_stmt_result_metadata(), returned no meta information\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

/* Hole Gesamtzahl der Spalten in der Anfrage */
column_count= mysql_num_fields(prepare_meta_result);
fprintf(stdout, " total columns in SELECT statement: %d\n", column_count);

if (column_count != 4) /* Validiere Spaltenzahl*/
{
  fprintf(stderr, " invalid column count returned by MySQL\n");
  exit(0);
}

/* Führe die SELECT-Anfrage aus */
if (mysql_stmt_execute(stmt))
{
  fprintf(stderr, " mysql_stmt_execute(), failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

/* Binde die Ergebnispuffer für alle 4 Spalten, bevor sie abgeholt werden */

memset(bind, 0, sizeof(bind));

/* INTEGER COLUMN */
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (char *)&int_data;
bind[0].is_null= &is_null[0];
bind[0].length= &length[0];

/* STRING COLUMN */
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= (char *)str_data;
bind[1].buffer_length= STRING_SIZE;
bind[1].is_null= &is_null[1];
bind[1].length= &length[1];

/* SMALLINT COLUMN */
bind[2].buffer_type= MYSQL_TYPE_SHORT;
bind[2].buffer= (char *)&small_data;
bind[2].is_null= &is_null[2];
bind[2].length= &length[2];

/* TIMESTAMP COLUMN */
bind[3].buffer_type= MYSQL_TYPE_TIMESTAMP;
bind[3].buffer= (char *)&ts;
bind[3].is_null= &is_null[3];
bind[3].length= &length[3];

/* Binde die Ergebnispuffer */
if (mysql_stmt_bind_result(stmt, bind))
{
  fprintf(stderr, " mysql_stmt_bind_result() failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

/* Alle Ergebnisse auf dem Client zwischenspeichern */
if (mysql_stmt_store_result(stmt))
{
  fprintf(stderr, " mysql_stmt_store_result() failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

/* Alle Zeilen abholen */
row_count= 0;
fprintf(stdout, "Fetching results ...\n");
while (!mysql_stmt_fetch(stmt))
{
  row_count++;
  fprintf(stdout, "  row %d\n", row_count);

  /* Spalte 1 */
  fprintf(stdout, "   column1 (integer)  : ");
  if (is_null[0])
    fprintf(stdout, " NULL\n");
  else
    fprintf(stdout, " %d(%ld)\n", int_data, length[0]);

  /* Spalte 2 */
  fprintf(stdout, "   column2 (string)   : ");
  if (is_null[1])
    fprintf(stdout, " NULL\n");
  else
    fprintf(stdout, " %s(%ld)\n", str_data, length[1]);

  /* Spalte 3 */
  fprintf(stdout, "   column3 (smallint) : ");
  if (is_null[2])
    fprintf(stdout, " NULL\n");
  else
    fprintf(stdout, " %d(%ld)\n", small_data, length[2]);

  /* Spalte 4 */
  fprintf(stdout, "   column4 (timestamp): ");
  if (is_null[3])
    fprintf(stdout, " NULL\n");
  else
    fprintf(stdout, " %04d-%02d-%02d %02d:%02d:%02d (%ld)\n",
                     ts.year, ts.month, ts.day,
                     ts.hour, ts.minute, ts.second,
                     length[3]);
  fprintf(stdout, "\n");
}

/* Abgeholte Zeilen validieren */
fprintf(stdout, " total rows fetched: %d\n", row_count);
if (row_count != 2)
{
  fprintf(stderr, " MySQL failed to return all rows\n");
  exit(0);
}

/* Vorbereitete Ergebnismetadaten freigeben */
mysql_free_result(prepare_meta_result);


/* Anweisung schließen */
if (mysql_stmt_close(stmt))
{
  fprintf(stderr, " failed while closing the statement\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

24.2.7.12. mysql_stmt_fetch_column()

int mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, unsigned int column, unsigned long offset)

Beschreibung

Holt eine Spalte aus der aktuellen Zeile der Ergebnismenge. bind sagt, in welchen Puffer die Daten geschrieben werden sollen. Dieser sollte wie für mysql_stmt_bind_result() eingestellt sein. column gibt an, welche Spalte abgefragt wird. Die erste Spalte hat die Nummer 0. offset ist der Offset im Datenwert, wo der Datenabruf beginnen soll. Dieser kann genutzt werden, um die Daten stückweise abzuholen. Der Anfang des Werts hat den Offset 0.

Rückgabewerte

Null, wenn der Wert erfolgreich abgeholt wurde. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_INVALID_PARAMETER_NO

    Ungültige Spaltennummer.

  • CR_NO_DATA

    Das Ende der Ergebnismenge wurde schon erreicht.

24.2.7.13. mysql_stmt_field_count()

unsigned int mysql_stmt_field_count(MYSQL_STMT *stmt)

Beschreibung

Liefert die Anzahl der Spalten für die letzte Anweisung des Anweisungs-Handlers. Dieser Wert ist für Anweisungen wie INSERT oder DELETE, die keine Ergebnismengen produzieren, null.

mysql_stmt_field_count() kann nach der Vorbereitung einer Anweisung mit mysql_stmt_prepare() aufgerufen werden.

Rückgabewerte

Ein vorzeichenloser Integer, der die Anzahl der Spalten in einer Ergebnismenge angibt.

Fehler

Keine.

24.2.7.14. mysql_stmt_free_result()

my_bool mysql_stmt_free_result(MYSQL_STMT *stmt)

Beschreibung

Gibt den Speicher für die Ergebnismenge frei, die von der Ausführung der vorbereiteten Anweisung erstellt wurde. Wenn noch ein Cursor für die Anweisung geöffnet ist, wird er von mysql_stmt_free_result() geschlossen.

Rückgabewerte

Null, wenn die Ergebnismenge erfolgreich freigegeben wurde, und ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

(nicht verfügbar)

24.2.7.15. mysql_stmt_init()

MYSQL_STMT *mysql_stmt_init(MYSQL *mysql)

Beschreibung

Erzeugt einen MYSQL_STMT-Handle. Der Handle sollte mit mysql_stmt_close(MYSQL_STMT *) wieder freigegeben werden.

Rückgabewerte

Bei Erfolg ein Zeiger auf eine MYSQL_STMT-Struktur. Bei einem Speicherüberlauf NULL.

Fehler

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

24.2.7.16. mysql_stmt_insert_id()

my_ulonglong mysql_stmt_insert_id(MYSQL_STMT *stmt)

Beschreibung

Gibt den Wert zurück, der für eine AUTO_INCREMENT-Spalte von der vorbereiteten INSERT- oder UPDATE-Anweisung generiert wurde. Diese Funktion verwenden Sie nach Ausführung einer vorbereiteten INSERT-Anweisung auf einer Tabelle, die ein AUTO_INCREMENT-Feld enthält.

Siehe auch Abschnitt 24.2.3.36, „mysql_insert_id().

Rückgabewerte

Der Wert der AUTO_INCREMENT-Spalte, der automatisch generiert oder während der Ausführung einer vorbereiteten Anweisung explizit gesetzt wurde, oder der Wert, der von der Funktion LAST_INSERT_ID(expr) generiert wurde. Wenn die Anweisung keinen AUTO_INCREMENT-Wert setzt, ist der Rückgabewert undefiniert.

Fehler

Keine.

24.2.7.17. mysql_stmt_num_rows()

my_ulonglong mysql_stmt_num_rows(MYSQL_STMT *stmt)

Beschreibung

Liefert die Anzahl der Zeilen in der Ergebnismenge.

mysql_stmt_num_rows() können Sie nur benutzen, wenn Sie die gesamte Ergebnismenge im Anweisungs-Handle mit mysql_stmt_store_result() gepuffert haben.

Wenn Sie mysql_stmt_store_result() verwenden, können Sie mysql_stmt_num_rows() sofort aufrufen.

Rückgabewerte

Die Anzahl der Zeilen in der Ergebnismenge.

Fehler

Keine.

24.2.7.18. mysql_stmt_param_count()

unsigned long mysql_stmt_param_count(MYSQL_STMT *stmt)

Beschreibung

Liefert die Anzahl der Parametermarker in der vorbereiteten Anweisung.

Rückgabewerte

Ein vorzeichenloser Long-Integer, der die Anzahl der Parameter in einer Anweisung darstellt.

Fehler

Keine.

Beispiel

Wie man mysql_stmt_param_count() einsetzt, sehen Sie im Beispiel zu Abschnitt 24.2.7.10, „mysql_stmt_execute().

24.2.7.19. mysql_stmt_param_metadata()

MYSQL_RES *mysql_stmt_param_metadata(MYSQL_STMT *stmt)

Diese Funktion tut zurzeit gar nichts.

Beschreibung

Rückgabewerte

Fehler

24.2.7.20. mysql_stmt_prepare()

int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)

Beschreibung

Wenn man ihr den von mysql_stmt_init() gelieferten Anweisungs-Handle übergibt, bereitet diese Funktion die SQL-Anweisung vor, auf die der String query verweist, und liefert einen Statuswert. Die Länge des Strings sollte im length-Argument angegeben werden. Der String muss aus einer einzigen SQL-Anweisung bestehen. Bitte fügen Sie am Ende der Anweisung kein Semikolon (‘;’) oder \g an.

Die Anwendung kann einen oder mehrere Parametermarker in die SQL-Anweisung einbinden, indem sie die Fragezeichen (‘?’) an den passenden Stellen in den SQL-String einbettet.

Die Marker sind nur an bestimmten Stellen in den SQL-Anweisungen erlaubt, beispielsweise in der VALUES()-Liste einer INSERT Anweisung (um Spaltenwerte für eine Zeile vorzugeben) oder um einen Vergleichswert zum Vergleich mit einer Spalte einer WHERE-Klausel anzugeben. Sie dürfen jedoch nicht für Bezeichner (wie etwa Tabellen- oder Spaltennamen) oder für die Operanden eines Binäroperators wie etwa des Gleichheitszeichens = benutzt werden. Die zweite Beschränkung ist notwendig, weil es ansonsten unmöglich wäre, den Parametertyp festzustellen. Generell sind Parameter nur in Data Manipulation Language(DML)-Anweisungen und nicht in Data Definition Language(DDL)-Anweisungen zulässig.

Die Parametermarker müssen mit mysql_stmt_bind_param() an die Anwendungsvariablen gebunden werden, bevor die Anweisung ausgeführt wird.

Rückgabewerte

Null, wenn die Anweisung erfolgreich vorbereitet wurde, und ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Wenn die Vorbereitung gescheitert ist (d. h., wenn mysql_stmt_prepare() nicht null zurückliefert), können Sie die Fehlermeldung mit mysql_stmt_error() abrufen.

Beispiel

Wie mysql_stmt_prepare() eingesetzt wird, erfahren Sie im Beispiel von Abschnitt 24.2.7.10, „mysql_stmt_execute().

24.2.7.21. mysql_stmt_reset()

my_bool mysql_stmt_reset(MYSQL_STMT *stmt)

Beschreibung

Setzt die vorbereitete Anweisung auf dem Client und Server in den Zustand zurück, den sie nach der Vorbereitung hatte. Wird vor allen Dingen genutzt, um die mit mysql_stmt_send_long_data() übersandten Daten zurückzusetzen und eventuell noch offene Anweisungs-Cursors zu schließen.

Um die Anweisung mit einer anderen Anfrage erneut vorzubereiten, rufen Sie mysql_stmt_prepare() auf.

Rückgabewerte

Null, wenn die Anweisung erfolgreich zurückgesetzt wurde, und ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.7.22. mysql_stmt_result_metadata()

MYSQL_RES *mysql_stmt_result_metadata(MYSQL_STMT *stmt)

Beschreibung

Wenn an mysql_stmt_prepare() eine Anweisung übergeben wird, die eine Ergebnismenge produziert, liefert mysql_stmt_result_metadata() die Metadaten zu dieser Ergebnismenge in Form eines Zeigers auf eine MYSQL_RES-Struktur, die genutzt werden kann, um solche Daten wie etwa die Gesamtzahl der Felder und Informationen über einzelne Felder zu verarbeiten. Dieser Ergebnismengenzeiger kann als Argument an API-Feldfunktionen übergeben werden, die Metadaten von Ergebnismengen verarbeiten, wie zum Beispiel:

  • mysql_num_fields()

  • mysql_fetch_field()

  • mysql_fetch_field_direct()

  • mysql_fetch_fields()

  • mysql_field_count()

  • mysql_field_seek()

  • mysql_field_tell()

  • mysql_free_result()

Die Ergebnismengenstruktur sollte nach Abschluss der Verarbeitung freigegeben werden, indem man sie an mysql_free_result() übergibt. Auf dieselbe Weise wird eine Ergebnismenge aus einem mysql_store_result()-Aufruf freigegeben.

Die von mysql_stmt_result_metadata() zurückgegebene Ergebnismenge enthält nur Metadaten und keine Ergebniszeilen. Diese rufen Sie ab, indem Sie den Anweisungs-Handle in Verbindung mit mysql_stmt_fetch() benutzen.

Rückgabewerte

Eine MYSQL_RES-Ergebnisstruktur oder NULL, wenn keine Metainformationen über die vorbereitete Anfrage existieren.

Fehler

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

Die Benutzung von mysql_stmt_result_metadata() wird aus dem Beispiel von Abschnitt 24.2.7.11, „mysql_stmt_fetch(), ersichtlich.

24.2.7.23. mysql_stmt_row_seek()

MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset)

Beschreibung

Setzt den Zeilen-Cursor auf eine beliebige Zeile in der Ergebnismenge einer Anweisung. Der offset-Wert ist ein Zeilen-Offset. Dieser sollte ein Rückgabewert von mysql_stmt_row_tell() oder von mysql_stmt_row_seek() sein. Er ist keine Zeilennummer; wenn Sie in einer Ergebnismenge eine Zeile anhand ihrer Nummer ausfindig machen möchten, verwenden Sie stattdessen mysql_stmt_data_seek().

Da für diese Funktion erforderlich ist, dass die Ergebnismengenstruktur die gesamte Ergebnismenge der Anfrage enthält, kann mysql_stmt_row_seek() nur in Verbindung mit mysql_stmt_store_result() benutzt werden.

Rückgabewerte

Der vorherige Wert des Zeilen-Cursors. Dieser Wert kann an einen nachfolgenden mysql_stmt_row_seek()-Aufruf übergeben werden.

Fehler

Keine.

24.2.7.24. mysql_stmt_row_tell()

MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT *stmt)

Beschreibung

Gibt die aktuelle Position des Zeilen-Cursors für die letzte mysql_stmt_fetch()-Operation zurück. Dieser Wert kann als Argument für mysql_stmt_row_seek() verwendet werden.

mysql_stmt_row_tell() sollte nur nach mysql_stmt_store_result() benutzt werden.

Rückgabewerte

Der aktuelle Offset des Zeilen-Cursors.

Fehler

Keine.

24.2.7.25. mysql_stmt_send_long_data()

my_bool mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int parameter_number, const char *data, unsigned long length)

Beschreibung

Ermöglicht es einer Anwendung, Parameterdaten in Stücken (oder „Chunks“) an den Server zu schicken. Diese Funktion kann mehrmals aufgerufen werden, um die Teile eines Zeichen- oder Binärdatenwerts für eine Spalte zu übergeben. Die Werte müssen den Datentyp TEXT oder BLOB haben.

parameter_number gibt an, mit welchem Parameter die Daten verbunden werden sollen. Die Parameter werden beginnend mit 0 nummeriert. data ist ein Zeiger auf einen Puffer, der die zu übermittelnden Daten enthält, und length ist die Anzahl der Bytes im Puffer.

Hinweis: Der nächste Aufruf von mysql_stmt_execute() ignoriert den Bind-Puffer für alle Parameter, die seit dem letzten mysql_stmt_execute() oder mysql_stmt_reset() mit mysql_stmt_send_long_data() benutzt worden sind.

Wenn Sie die gesendeten Daten zurücksetzen/vergessen möchten, tun Sie dies mit mysql_stmt_reset(). Siehe Abschnitt 24.2.7.21, „mysql_stmt_reset().

Rückgabewerte

Null, wenn die Daten erfolgreich an den Server gesandt wurden. Ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

Beispiel

Das folgende Beispiel zeigt, wie die Daten für eine TEXT-Spalte stückchenweise übermittelt werden. Es fügt den Datenwert 'MySQL - The most popular Open Source database' in die Spalte text_column ein. Die Variable mysql sei ein gültiger Verbindungs-Handle.

#define INSERT_QUERY "INSERT INTO test_long_data(text_column) VALUES(?)"

MYSQL_BIND bind[1];
long       length;

smtt = mysql_stmt_init(mysql);
if (!stmt)
{
  fprintf(stderr, " mysql_stmt_init(), out of memory\n");
  exit(0);
}
if (mysql_stmt_prepare(stmt, INSERT_QUERY, strlen(INSERT_QUERY)))
{
  fprintf(stderr, "\n mysql_stmt_prepare(), INSERT failed");
  fprintf(stderr, "\n %s", mysql_stmt_error(stmt));
  exit(0);
}
 memset(bind, 0, sizeof(bind));
 bind[0].buffer_type= MYSQL_TYPE_STRING;
 bind[0].length= &length;
 bind[0].is_null= 0;

/* Binde die Puffer */
if (mysql_stmt_bind_param(stmt, bind))
{
  fprintf(stderr, "\n param bind failed");
  fprintf(stderr, "\n %s", mysql_stmt_error(stmt));
  exit(0);
}

 /* Liefere Daten stückweise an den Server */
 if (!mysql_stmt_send_long_data(stmt,0,"MySQL",5))
{
  fprintf(stderr, "\n send_long_data failed");
  fprintf(stderr, "\n %s", mysql_stmt_error(stmt));
  exit(0);
}

 /* Sende das nächste Datenstück */
 if (mysql_stmt_send_long_data(stmt,0," - The most popular Open Source database",40))
{
  fprintf(stderr, "\n send_long_data failed");
  fprintf(stderr, "\n %s", mysql_stmt_error(stmt));
  exit(0);
}

 /* Führe nun die Anfrage aus */
 if (mysql_stmt_execute(stmt))
{
  fprintf(stderr, "\n mysql_stmt_execute failed");
  fprintf(stderr, "\n %s", mysql_stmt_error(stmt));
  exit(0);
}

24.2.7.26. mysql_stmt_sqlstate()

const char *mysql_stmt_sqlstate(MYSQL_STMT *stmt)

Beschreibung

Für die Anweisung stmt liefert mysql_stmt_sqlstate() einen auf null endenden String mit dem SQLSTATE-Fehlercode für die zuletzt aufgerufene Funktion der API für vorbereitete Anweisungen, die Erfolg haben oder scheitern kann. Der Fehlercode besteht aus fünf Zeichen. "00000" bedeutet „kein Fehler“. Die Werte sind durch ANSI-SQL und ODBC vorgegeben. Eine Liste der möglichen Werte finden Sie unter Anhang B, Fehlercodes und -meldungen.

Beachten Sie, dass noch nicht alle MySQL-Fehler SQLSTATE-Codes zugeordnet sind. Für Fehler, die sich nicht zuordnen lassen, wird der Wert "HY000" (allgemeiner Fehler) verwendet.

Rückgabewerte

Ein auf null endender Zeichen-String, der den SQLSTATE-Fehlercode enthält.

24.2.7.27. mysql_stmt_store_result()

int mysql_stmt_store_result(MYSQL_STMT *stmt)

Beschreibung

Sie können mysql_stmt_store_result() für jede Anweisung aufrufen, die eine Ergebnismenge erstellt (SELECT, SHOW, DESCRIBE, EXPLAIN), sofern Sie die gesamte Ergebnismenge im Client puffern wollen, damit der nachfolgende mysql_stmt_fetch()-Aufruf die gepufferten Daten zurückgibt.

Es ist zwar nicht nötig, mysql_stmt_store_result() für andere Anweisungen aufzurufen, aber es schadet auch nichts und hat keine spürbaren Leistungseinbußen zur Folge. Ob die Anweisung eine Ergebnismenge erzeugt hat, können Sie ermitteln, indem Sie nachschauen, ob mysql_stmt_result_metadata() den Wert NULL zurückgibt. Weitere Informationen gibt es unter Abschnitt 24.2.7.22, „mysql_stmt_result_metadata().

Hinweis: MySQL berechnet nach Voreinstellung nicht die MYSQL_FIELD->max_length für alle Spalten in mysql_stmt_store_result(), da dieser Rechenaufwand mysql_stmt_store_result() deutlich verlangsamen würde und die meisten Anwendungen auf max_length gut verzichten können. Wenn Sie max_length aktualisieren möchten, können Sie dies mit mysql_stmt_attr_set(MYSQL_STMT, STMT_ATTR_UPDATE_MAX_LENGTH, &flag) ermöglichen. Siehe Abschnitt 24.2.7.3, „mysql_stmt_attr_set().

Rückgabewerte

Null, wenn die Ergebnisse erfolgreich gepuffert wurden, und ein von null verschiedener Wert, wenn ein Fehler auftrat.

Fehler

  • CR_COMMANDS_OUT_OF_SYNC

    Befehle wurden in der falschen Reihenfolge ausgeführt.

  • CR_OUT_OF_MEMORY

    Speicherüberlauf.

  • CR_SERVER_GONE_ERROR

    Der MySQL Server ist nicht mehr verfügbar.

  • CR_SERVER_LOST

    Die Serververbindung brach während der Anfrage ab.

  • CR_UNKNOWN_ERROR

    Ein unbekannter Fehler ist aufgetreten.

24.2.8. C-API: Probleme bei Prepared Statements

Im Folgenden werden einige bekannte Probleme mit vorbereiteten Anweisungen angesprochen:

  • TIME, TIMESTAMP und DATETIME unterstützen keine Sekundenbruchteile (beispielsweise von DATE_FORMAT().

  • Beim Konvertieren eines Integers in einen String wird ZEROFILL in vorbereiteten Anweisungen in manchen Fällen umgesetzt, ohne dass der MySQL Server die vorangestellten Nullen ausgibt (beispielsweise bei MIN(number-with-zerofill)).

  • Wird im Client eine Fließkommazahl in einen String konvertiert, können die rechten Ziffern des konvertierten Werts leicht vom Originalwert abweichen.

  • Vorbereitete Anweisungen verwenden nicht den Query Cache, auch dann nicht, wenn eine Anfrage keine Platzhalter enthält. Siehe Abschnitt 5.14.1, „Wie der Anfragen-Cache funktioniert“.

24.2.9. C-API: Behandlung der Ausführung mehrerer Anweisungen

MySQL 5.1 unterstützt die Ausführung von Mehrfachanweisungen, die in einem einzigen Anfrage-String angegeben werden. Um diese Fähigkeit auf einer gegebenen Verbindung nutzen zu können, müssen Sie die Option CLIENT_MULTI_STATEMENTS im Parameter flags der Funktion mysql_real_connect() angeben, wenn Sie die Verbindung öffnen. Sie können dies jedoch mit mysql_set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON) auch für eine laufende Verbindung tun.

Nach Voreinstellung geben mysql_query() und mysql_real_query() nur den ersten Anfragestatus zurück; der Status der nachfolgenden Anfragen kann mit mysql_more_results() und mysql_next_result() verarbeitet werden.

/* Richte Serververbindung mit der Option CLIENT_MULTI_STATEMENTS ein */
mysql_real_connect(..., CLIENT_MULTI_STATEMENTS);

/* Führe mehrere Anfragen aus */
mysql_query(mysql,"DROP TABLE IF EXISTS test_table;\
                   CREATE TABLE test_table(id INT);\
                   INSERT INTO test_table VALUES(10);\
                   UPDATE test_table SET id=20 WHERE id=10;\
                   SELECT * FROM test_table;\
                   DROP TABLE test_table");
do
{
  /* Verarbeite alle Ergebnisse */
  ...
  printf("total affected rows: %lld", mysql_affected_rows(mysql));
  ...
  if (!(result= mysql_store_result(mysql)))
  {
     printf(stderr, "Got fatal error processing query\n");
     exit(1);
  }
  process_result_set(result); /* Clientfunktion */
  mysql_free_result(result);
} while (!mysql_next_result(mysql));

Die Fähigkeit zu Mehrfachanweisungen kann mit mysql_query() oder mysql_real_query() genutzt werden, aber nicht mit der Schnittstelle für vorbereitete Anweisungen. Handles für vorbereitete Anweisungen sind so definiert, dass sie nur mit Strings funktionieren, die lediglich eine einzelne Anweisung enthalten.

24.2.10. C-API: Behandlung von Datums- und Zeitwerten

Das Binärprotokoll ermöglicht das Senden und Empfangen von Datums- und Uhrzeitwerten (DATE, TIME, DATETIME und TIMESTAMP) mithilfe der MYSQL_TIME-Struktur. Die Bestandteile dieser Struktur werden in Abschnitt 24.2.5, „C-API: Prepared Statement-Datentypen“, beschrieben.

Um temporale Datenwerte zu senden, legen Sie eine vorbereitete Anweisung mit mysql_stmt_prepare() an und richten die Temporalparameter, bevor Sie die Anweisung mit mysql_stmt_execute() ausführen, folgendermaßen ein:

  1. In der MYSQL_BIND-Struktur, die mit dem Datenwert verbunden ist, stellen Sie den buffer_type-Teil auf den Typ, der die Art des zu sendenden Temporalwerts angibt. Für DATE-, TIME-, DATETIME- oder TIMESTAMP-Werte setzen Sie buffer_type auf MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME oder MYSQL_TYPE_TIMESTAMP.

  2. Stellen Sie den buffer-Teil der MYSQL_BIND-Struktur auf die Adresse der MYSQL_TIME-Struktur ein, in die Sie den Temporalwert übergeben.

  3. Füllen Sie die Bestandteile der MYSQL_TIME-Struktur aus, die sich für den Typ des zu übergebenden Temporalwerts eignen.

Binden Sie mit mysql_stmt_bind_param() die Parameterdaten an die Anweisung. Dann können Sie mysql_stmt_execute() aufrufen.

Abgerufen werden die Temporalwerte ganz ähnlich, nur dass Sie beim Abruf den buffer_type-Teil auf den Typ des Werts einstellen, den Sie empfangen wollen, und den buffer-Teil auf die Adresse einer MYSQL_TIME-Struktur, in die der Rückgabewert eingesetzt werden soll. Mit mysql_bind_results() binden Sie die Puffer an die Anweisung, nachdem Sie mysql_stmt_execute() aufgerufen haben und bevor Sie die Ergebnisse abholen.

Das folgende einfache Beispiel fügt DATE-, TIME- und TIMESTAMP-Daten ein. Die mysql-Variable sei ein gültiger Verbindungs-Handle.

  MYSQL_TIME  ts;
  MYSQL_BIND  bind[3];
  MYSQL_STMT  *stmt;

  strmov(query, "INSERT INTO test_table(date_field, time_field,
                                        timestamp_field) VALUES(?,?,?");

  stmt = mysql_stmt_init(mysql);
  if (!stmt)
  {
    fprintf(stderr, " mysql_stmt_init(), out of memory\n");
    exit(0);
  }
  if (mysql_stmt_prepare(mysql, query, strlen(query)))
  {
    fprintf(stderr, "\n mysql_stmt_prepare(), INSERT failed");
    fprintf(stderr, "\n %s", mysql_stmt_error(stmt));
    exit(0);
  }

  /* Richte Eingabepuffer für alle 3 Parameter ein */
  bind[0].buffer_type= MYSQL_TYPE_DATE;
  bind[0].buffer= (char *)&ts;
  bind[0].is_null= 0;
  bind[0].length= 0;
  ...
  bind[1]= bind[2]= bind[0];
  ...

  mysql_stmt_bind_param(stmt, bind);

  /* Liefere die Daten für die ts-Struktur*/
  ts.year= 2002;
  ts.month= 02;
  ts.day= 03;

  ts.hour= 10;
  ts.minute= 45;
  ts.second= 20;

  mysql_stmt_execute(stmt);
  ..

24.2.11. C-Threaded-Funktionsbeschreibungen

Wenn Sie einen Threaded Client erstellen möchten, verwenden Sie folgende Funktionen. Siehe Abschnitt 24.2.15, „Wie man einen Thread-Client herstellt“.

24.2.11.1. my_init()

void my_init(void)

Beschreibung

Diese Funktion muss einmalig vor dem Aufruf jeder anderen MySQL-Funktion in einem Programm aufgerufen werden. Sie initialisiert einige globale Variablen, die MySQL benötigt. Wenn Sie eine Thread-sichere Clientbibliothek benutzen, wird auch für diesen Thread mysql_thread_init() aufgerufen.

Diese Funktion wird automatisch von mysql_init(), mysql_library_init(), mysql_server_init() und mysql_connect() aufgerufen.

Rückgabewerte

Keine.

24.2.11.2. mysql_thread_init()

my_bool mysql_thread_init(void)

Beschreibung

Diese Funktion muss für jeden erzeugten Thread aufgerufen werden, um Thread-spezifische Variablen zu initialisieren.

Die Funktion wird automatisch von my_init() und mysql_connect() aufgerufen.

Rückgabewerte

Null bei Erfolg und ein von null verschiedener Wert bei einem Fehler.

24.2.11.3. mysql_thread_end()

void mysql_thread_end(void)

Beschreibung

Diese Funktion muss vor pthread_exit() benutzt werden, um den von mysql_thread_init() zugewiesenen Speicher wieder freizugeben.

Beachten Sie, dass diese Funktion nicht automatisch von der Clientbibliothek aufgerufen wird. Sie muss explizit aufgerufen werden, um ein Speicherleck zu verhindern.

Rückgabewerte

Keine.

24.2.11.4. mysql_thread_safe()

unsigned int mysql_thread_safe(void)

Beschreibung

Diese Funktion zeigt an, ob der Client als Thread-sicher kompiliert wurde.

Rückgabewerte

1, wenn der Client Thread-sicher ist, andernfalls 0.

24.2.12. C Embedded Server: Funktionsbeschreibungen

Wenn Sie es Ihrer Anwendung ermöglichen wollen, mit der MySQL Embedded Server-Bibliothek verknüpft zu werden, müssen Sie die Funktionen mysql_server_init() und mysql_server_end() benutzen. Siehe Abschnitt 24.1, „libmysqld, die eingebettete MySQL Server-Bibliothek“.

Für eine bessere Speicherverwaltung sollten allerdings auch Programme, die mit -lmysqlclient statt -lmysqld verknüpft sind, Aufrufe enthalten, um die Benutzung der Bibliothek zu beginnen und zu beenden. Hierzu dienen die Funktionen mysql_library_init() und mysql_library_end(). Diese sind in Wirklichkeit #define-Symbole und somit äquivalent zu mysql_server_init() und mysql_server_end(), aber die anderen Namen betonen stärker, dass diese Funktionen immer vor und nach der Benutzung einer MySQL-C-API-Bibliothek aufgerufen werden müssen, egal ob die Anwendung libmysqlclient oder libmysqld verwendet. Weitere Informationen finden Sie unter Abschnitt 24.2.2, „C-API: Funktionsüberblick“.

24.2.12.1. mysql_server_init()

int mysql_server_init(int argc, char **argv, char **groups)

Beschreibung

Diese Funktion muss in einem Programm, das den Embedded Server benutzt, einmalig vor jeder anderen MySQL-Funktion aufgerufen werden. Sie startet den Server und initialisiert eventuelle Subsysteme (mysys, InnoDB und so weiter), die der Server benötigt. Wird diese Funktion nicht aufgerufen, führt der nächste mysql_init()-Aufruf mysql_server_init() aus. Wenn Sie das mit MySQL gelieferte DBUG-Paket benutzen, sollten Sie die Funktion nach my_init() aufrufen.

Die Argumente argc und argv entsprechen den Argumenten von main(). Das erste Element von argv wird ignoriert (es enthält typischerweise den Namen des Programms). Der Bequemlichkeit halber kann argc den Wert 0 (null) haben, wenn keine Kommandozeilenargumente für den Server vorhanden sind. Da mysql_server_init() die Argumente kopiert, kann argv oder groups nach dem Aufruf getrost zerstört werden.

Wenn Sie sich mit einem externen Server verbinden möchten, ohne den Embedded Server zu starten, müssen Sie einen negativen Wert für argc angeben.

Die mit NULL endende Liste der Strings in groups wählt die Gruppen aus den Optionsdateien aus, die aktiv sein sollen. Siehe Abschnitt 4.3.2, „my.cnf-Optionsdateien“. Der Bequemlichkeit halber kann groups den Wert NULL haben. In diesem Fall sind die Gruppen [server] und [embedded] aktiv.

Beispiel

#include <mysql.h>
#include <stdlib.h>

static char *server_args[] = {
  "this_program",       /* Dieser String wird nicht benutzt */
  "--datadir=.",
  "--key_buffer_size=32M"
};
static char *server_groups[] = {
  "embedded",
  "server",
  "this_program_SERVER",
  (char *)NULL
};

int main(void) {
  if (mysql_server_init(sizeof(server_args) / sizeof(char *),
                        server_args, server_groups))
    exit(1);

  /* Hier werden MySQL-API-Funktionen benutzt */

  mysql_server_end();

  return EXIT_SUCCESS;
}

Rückgabewerte

0, wenn alles okay ist, 1, wenn ein Fehler auftrat.

24.2.12.2. mysql_server_end()

void mysql_server_end(void)

Beschreibung

Diese Funktion muss unbedingt einmalig im Programm aufgerufen werden, und zwar nach allen anderen MySQL-Funktionen. Sie fährt den Embedded Server herunter.

Rückgabewerte

Keine.

24.2.13. Häufige Fragen und Probleme bei der Benutzung der C-API

24.2.13.1. Warum gibt mysql_store_result() manchmal NULL zurück, nachdem mysql_query() Erfolg zurückgegeben hat?

Es ist möglich, dass mysql_store_result() nach einem erfolgreichen Aufruf von mysql_query() den Wert NULL zurückgibt. Wenn dies geschieht, so bedeutet es, dass eine der folgenden Bedingungen eingetreten ist:

  • Es gab einen Fehler in malloc() (beispielsweise, wenn die Ergebnismenge zu groß war).

  • Die Daten konnten nicht gelesen werden (ein Verbindungsfehler).

  • Die Anfrage hat keine Daten geliefert (beispielsweise wenn sie ein INSERT, UPDATE oder DELETE war).

Sie können immer mit mysql_field_count() prüfen, ob die Anweisung eine nichtleere Ergebnismenge hätte produzieren sollen. Wenn mysql_field_count() null liefert, ist das Ergebnis leer und es handelte sich um eine Anweisung, die keine Werte zurückgibt (beispielsweise ein INSERT oder DELETE). Wenn mysql_field_count() einen von null verschiedenen Wert liefert, hätte die Anweisung eigentlich ein nichtleeres Ergebnis zurückgeben müssen. Ein Beispiel finden Sie in der Beschreibung der mysql_field_count()-Funktion.

Ob ein Fehler auftrat, verrät Ihnen mysql_error() oder mysql_errno().

24.2.13.2. Welche Ergebnisse kann ich von einer Anfrage bekommen?

Zusätzlich zu der Frage, ob eine Anfrage eine Ergebnismenge zurückgibt, können Sie auch die folgenden Informationen herausfinden:

  • mysql_affected_rows() liefert die Anzahl der von der letzten Anfrage betroffenen Zeilen, wenn die Anfrage ein INSERT, UPDATE oder DELETE war.

    Für eine schnelle Rekonstruktion verwenden Sie TRUNCATE TABLE.

  • mysql_num_rows() liefert die Anzahl der Zeilen in einer Ergebnismenge. Bei mysql_store_result() kann mysql_num_rows() aufgerufen werden, sobald mysql_store_result() zurückkehrt. Bei mysql_use_result() kann mysql_num_rows() erst aufgerufen werden, nachdem alle Zeilen mit mysql_fetch_row() abgeholt worden sind.

  • mysql_insert_id() liefert die ID, welche die letzte Anfrage, die eine Zeile in eine Tabelle mit einem AUTO_INCREMENT-Index eingefügt hat, generierte. Siehe Abschnitt 24.2.3.36, „mysql_insert_id().

  • Manche Anfragen (LOAD DATA INFILE ..., INSERT INTO ... SELECT ..., UPDATE) geben weitere Informationen zurück. Das Ergebnis erhalten Sie von mysql_info(). In der Beschreibung zu mysql_info() erfahren Sie, welches String-Format diese Funktion liefert. mysql_info() gibt einen NULL-Zeiger zurück, wenn keine weiteren Informationen mehr vorliegen.

24.2.13.3. Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?

Wenn Sie einen Datensatz in eine Tabelle mit einer AUTO_INCREMENT-Spalte einfügen, können Sie den in dieser Spalte gespeicherten Wert mit der Funktion mysql_insert_id() erhalten.

In Ihren C-Anwendungen können Sie überprüfen, ob ein Wert in einer UTO_INCREMENT-Spalte gespeichert wurde. Hierzu führen Sie folgenden Code aus (der voraussetzt, dass Sie sich vom Erfolg der Anweisung überzeugt haben). Der Code ermittelt, ob die Anfrage ein INSERT mit einem AUTO_INCREMENT-Index war:

if ((result = mysql_store_result(&mysql)) == 0 &&
    mysql_field_count(&mysql) == 0 &&
    mysql_insert_id(&mysql) != 0)
{
    used_id = mysql_insert_id(&mysql);
}

Weitere Informationen finden Sie unter Abschnitt 24.2.3.36, „mysql_insert_id().

Wurde ein neuer AUTO_INCREMENT-Wert generiert, so können Sie diesen auch erhalten, indem Sie die SELECT LAST_INSERT_ID()-Anweisung mit mysql_query() ausführen und den Wert aus der Ergebnismenge dieser Anweisung abfragen.

Für LAST_INSERT_ID() wird die zuletzt generierte ID für jede Verbindung im Server gespeichert. Sie wird von keinem anderen Client geändert, noch nicht einmal dann, wenn Sie eine andere AUTO_INCREMENT-Spalte mit einem nichtmagischen Wert aktualisieren (also einem Wert, der nicht NULL und nicht 0 ist).

Wenn Sie die für eine Tabelle generierte ID benutzen und in eine andere Tabelle einfügen möchten, erledigen Sie dies mit SQL-Anweisungen wie diesen:

INSERT INTO foo (auto,text)
    VALUES(NULL,'text');              # generiert ID durch Einfügen von NULL
INSERT INTO foo2 (id,text)
    VALUES(LAST_INSERT_ID(),'text');  # benutzt ID in einer zweiten Tabelle

Beachten Sie, dass mysql_insert_id() den Wert liefert, der in einer AUTO_INCREMENT-Spalte gespeichert war, egal ob dieser Wert automatisch durch Speichern von NULL oder 0 generiert oder als expliziter Wert angegeben wurde. LAST_INSERT_ID() liefert nur automatisch generierte AUTO_INCREMENT-Werte. Wenn Sie einen expliziten Wert, der nicht NULL oder 0 ist, speichern, so beeinflusst dieser nicht den Rückgabewert von LAST_INSERT_ID().

24.2.13.4. Probleme beim Linken mit der C-API

Beim Verlinken mit der C-API können folgende Fehler auf manchen Systemen auftreten:

gcc -g -o client test.o -L/usr/local/lib/mysql -lmysqlclient -lsocket -lnsl

Undefined        first referenced
 symbol          in file
floor            /usr/local/lib/mysql/libmysqlclient.a(password.o)
ld: fatal: Symbol referencing errors. No output written to client

Wenn dies auf Ihrem System geschieht, müssen Sie die Mathe-Bibliothek einbinden, indem Sie -lm am Ende der Compile/link-Zeile hinzufügen.

24.2.14. Clientprogramme bauen

Wenn Sie MySQL-Clients kompilieren, die Sie selbst geschrieben oder von einem Fremdhersteller bekommen haben, müssen diese im Link-Befehl mit den -lmysqlclient -lz-Optionen verknüpft werden. Eventuell müssen Sie auch die Option -L angeben, um dem Linker mitzuteilen, wo er die Bibliothek finden kann. Wenn die Bibliothek beispielsweise in /usr/local/mysql/lib installiert ist, müssen Sie im Link-Befehl -L/usr/local/mysql/lib -lmysqlclient -lz verwenden.

Für Clients, die MySQL-Header-Dateien benutzen, müssen Sie eventuell beim Kompilieren die Option -I (zum Beispiel -I/usr/local/mysql/include) einstellen, damit der Compiler die Header-Dateien finden kann.

Um das Kompilieren von MySQL-Programmen auf Unix zu erleichtern, haben wir das mysql_config-Skript für Sie erstellt. Siehe hierzu Abschnitt 24.9.2, „mysql_config — Kompilieroptionen zum Kompilieren von Clients erhalten“.

Mit dem Skript können Sie einen MySQL-Client wie folgt kompilieren:

CFG=/usr/local/mysql/bin/mysql_config
sh -c "gcc -o progname `$CFG --cflags` progname.c `$CFG --libs`"

sh -c ist erforderlich, damit die Shell die Ausgabe von mysql_config nicht als ein einziges Wort behandelt.

24.2.15. Wie man einen Thread-Client herstellt

Die Clientbibliothek ist beinahe Thread-sicher. Das größte Problem besteht darin, dass die Subroutinen in net.c, die Daten aus Sockets lesen, nicht gegen Interrupts gesichert sind. Dies wurde mit dem Hintergedanken so eingerichtet, dass Sie vielleicht einen eigenen Alarm installieren möchten, der einen langen Lesevorgang auf einem Server abbrechen kann. Wenn Sie Interrupt-Handler für den SIGPIPE-Interrupt installieren, sollte die Arbeit auf dem Socket Thread-sicher sein.

Um zu verhindern, dass das Programm abbricht, sobald eine Verbindung endet, blockiert MySQL SIGPIPE beim ersten Aufruf von mysql_server_init(), mysql_init() oder mysql_connect(). Wenn Sie einen eigenen SIGPIPE-Handler benutzen möchten, sollten Sie als Erstes mysql_server_init() aufrufen und dann Ihren Handler installieren.

In den älteren Binaries, die auf unserer Website angeboten werden (http://www.mysql.com/), werden die Clientbibliotheken normalerweise nicht mit der Thread-sicheren Option kompiliert (ausgenommen die Windows-Binaries, die standardmäßig Thread-sicher kompiliert werden). Neuere Binärdistributionen sollten sowohl eine normale als auch eine Thread-sichere Clientbibliothek besitzen.

Um einen Threaded Client zu erstellen, den Sie mit anderen Threads unterbrechen und auf dem Sie Timeouts für die Kommunikation mit dem MySQL Server einstellen können, verwenden Sie die Bibliotheken -lmysys, -lmystrings und -ldbug sowie den net_serv.o-Code, den auch der Server benutzt.

Wenn Sie keine Interrupts oder Timeouts benötigen, kompilieren Sie einfach eine Thread-sichere Clientbibliothek (mysqlclient_r) und benutzen diese. Siehe Abschnitt 24.2, „MySQL-C-API“. In diesem Fall müssen Sie sich über die net_serv.o-Objektdatei oder die anderen MySQL-Bibliotheken keine Gedanken machen.

Wenn Sie einen Threaded Client mit Timeouts und Interrupts benutzen möchten, sind die Routinen in der Datei thr_alarm.c sehr gut geeignet. Benutzen Sie Routinen aus der mysys-Bibliothek, so müssen Sie nur daran denken, my_init() immer als Erstes aufzurufen! Siehe Abschnitt 24.2.11, „C-Threaded-Funktionsbeschreibungen“.

Alle Funktionen außer mysql_real_connect() sind standardmäßig Thread-sicher. Die folgenden Hinweise beschreiben, wie man eine Thread-sichere Clientbibliothek kompiliert und in Thread-sicherer Weise benutzt. (Eigentlich gelten die folgenden Hinweise zu mysql_real_connect() auch für mysql_connect(), aber da mysql_connect() veraltet ist, sollten Sie ohnehin nur mit mysql_real_connect() arbeiten.)

Um mysql_real_connect() Thread-sicher zu machen, müssen Sie die Clientbibliothek mit folgendem Befehl neu kompilieren:

shell> ./configure --enable-thread-safe-client

Dies erzeugt die Thread-sichere Clientbibliothek libmysqlclient_r. (Immer vorausgesetzt, dass Ihr Betriebssytem über eine Thread-sichere gethostbyname_r()-Funktion verfügt.) Diese Bibliothek ist pro Verbindung Thread-sicher. Zwei Threads können also dieselbe Verbindung nutzen, allerdings mit folgenden Schwachstellen:

  • Zwei Threads können einem MySQL Server nicht gleichzeitig über dieselbe Verbindung eine Anfrage senden. Sie müssen vor allem gewährleisten, dass zwischen mysql_query() und mysql_store_result() kein anderer Thread dieselbe Verbindung benutzt.

  • Viele Threads können auf unterschiedliche Ergebnismengen zugreifen, die mit mysql_store_result() abgerufen werden.

  • Wenn Sie dagegen mysql_use_result benutzen, müssen Sie dafür sorgen, dass so lange kein anderer Thread dieselbe Verbindung benutzt, bis die Ergebnismenge wieder geschlossen wurde. Allerdings ist mysql_store_result() ohnehin die bessere Lösung für Threaded Clients, die sich dieselbe Verbindung teilen.

  • Wenn Sie mehrere Threads auf derselben Verbindung einsetzen möchten, müssen Sie die mysql_query()- und mysql_store_result()-Aufrufkombinationen mit einer Mutex-Sperre umgeben. Sobald mysql_store_result() fertig ist, kann die Sperre aufgehoben werden und andere Threads können Anfragen an dieselbe Verbindung schicken.

  • Wenn Sie mit POSIX-Threads programmieren, können Sie mit pthread_mutex_lock() und pthread_mutex_unlock() eine Mutex-Sperre errichten und wieder freigeben.

Folgendes ist wichtig, wenn Sie einen Thread andere MySQL-Funktionen aufrufen lassen als die, welche die Verbindung zur MySQL-Datenbank eingerichtet haben:

Wenn Sie mysql_init() oder mysql_connect() aufrufen, legt MySQL eine Thread-spezifische Variable für den Thread an, die (unter anderem) von der Debugbibliothek genutzt wird.

Wenn Sie eine MySQL-Funktion aufrufen, bevor der Thread mysql_init() oder mysql_connect() aufgerufen hat, wurden die Thread-spezifischen Variablen für den Thread noch nicht angelegt und Sie riskieren, dass es früher oder später zu einem Core Dump kommt.

Damit alles reibunbslos funktioniert, müssen Sie Folgendes tun:

  1. Rufen Sie my_init() am Anfang Ihres Programms auf, wenn dieses vor mysql_real_connect() noch eine andere MySQL-Funktion aufruft.

  2. Rufen Sie im Thread-Handler mysql_thread_init() auf, ehe Sie irgendeine MySQL-Funktion benutzen.

  3. Im Thread müssen Sie mysql_thread_end() vor pthread_exit() aufrufen. Das gibt den Speicher frei, den MySQL für Thread-spezifische Variablen reserviert hat.

Eventuell werden Fehler aufgrund von undefinierten Symbolen gemeldet, wenn Sie Ihren Client mit libmysqlclient_r verlinken. In den meisten Fällen liegt dies daran, dass Sie vergessen haben, auf der Link/compile-Zeile die Thread-Bibliotheken einzubinden.

24.3. MySQLs PHP-API

PHP ist eine serverseitige, in HTML eingebettete Skriptsprache zur Erstellung von dynamischen Webseiten. Sie steht für die meisten Betriebssysteme und Webserver zur Verfügung und kann auf die meisten gebräuchlichen Datenbanken zugreifen, darunter auch MySQL. PHP kann als separates Programm ausgeführt oder als Modul in den Apache-Webserver kompiliert werden.

PHP stellt zwei verschiedene MySQL-API-Erweiterungen zur Verfügung:

  • mysql: Diese Erweiterung ist für PHP 4 und 5 verfügbar und für MySQL-Versionen gedacht, die älter als MySQL 4.1 sind. Die Erweiterung unterstützt weder das verbesserte Authentifizierungsprotokoll von MySQL 5.1, noch vorbereitete Anweisungen oder Mehrfachanweisungen. Wenn Sie diese Erweiterung mit MySQL 5.1 benutzen möchten, müssen Sie den MySQL Server wahrscheinlich mit der Option --old-passwords konfigurieren (siehe Abschnitt A.2.3, „Client does not support authentication protocol). Diese Erweiterung ist auf der PHP-Website unter http://php.net/mysql dokumentiert.

  • mysqli (eine Abkürzung für „MySQL, Improved“) ist eine Erweiterung, die nur in PHP 5 verfügbar ist. Sie ist für die Benutzung mit MySQL 4.1.1 und höher gedacht. Diese Erweiterung unterstützt das Authentifizierungsprotokoll von MySQL 5.1 sowie die APIS für vorbereitete Anweisungen und Mehrfachanweisungen (Prepared Statements und Multiple Statements). Überdies hat diese Erweiterung eine moderne Schnittstelle für die objektorientierte Programmierung zu bieten. Die Dokumentation der Erweiterung mysqli finden Sie unter http://php.net/mysqli. Außerdem ist unter http://www.zend.com/php5/articles/php5-mysqli.php ein hilfreicher Fachartikel zu lesen.

Die PHP-Distribution und -Dokumentation stehen auf der PHP-Website zur Verfügung.

24.3.1. Allgemeine Probleme mit MySQL und PHP

  • Error: Maximum Execution Time Exceeded: Dies ist ein PHP-Limit. Gehen Sie in die Datei php.ini und setzen Sie die maximale Ausführungszeit von 30 Sekunden auf einen höheren Wert, wie Sie ihn benötigen. Außerdem ist es keine schlechte Idee, den pro Skript verfügbaren Arbeitsspeicher von 8 auf 16 Mbyte zu verdoppeln.

  • Fatal error: Call to unsupported or undefined Funktion mysql_connect() in ...: Dies bedeutet, dass Ihre PHP-Version nicht mit MySQL-Unterstützung kompiliert wurde. Sie können entweder ein dynamisches MySQL-Modul kompilieren und in PHP laden oder PHP mit integrierter MySQL-Unterstützung rekompilieren. Dieser Prozess wird im PHP-Handbuch genauer erläutert.

  • Error: Undefined reference to 'uncompress': Dies bedeutet, dass die Clientbibliothek mit Unterstützung für ein komprimiertes Client/Server-Protokoll kompiliert wurde. Dies beheben Sie, indem Sie die Option -lz als Letztes beim Verlinken mit -lmysqlclient hinzufügen.

  • Error: Client does not support authentication protocol: Dieser Fehler tritt am häufigsten auf, wenn Sie versuchen, die ältere mysql-Erweiterung mit MySQL 4.1.1 oder höher zu verwenden. Mögliche Lösungen: Sie können auf MySQL 4.0 umstellen, auf PHP 5 und die neuere mysqli umschalten oder den MySQL Server mit der Option --old-passwords konfigurieren. (Siehe auch Abschnitt A.2.3, „Client does not support authentication protocol.)

Wer noch mit älterem PHP4-Code arbeitet, kann eine Kompatibilitätsschicht für die alte und neue MySQL-Bibliothek verwenden, wie beispielsweise: http://www.coggeshall.org/oss/mysql2i.

24.4. MySQLs Perl-API

Das DBI-Modul von Perl stellt eine generische Schnittstelle für den Datenbankzugriff zur Verfügung. Sie können ein DBI-Skript schreiben, das ohne Änderungen mit vielen verschiedenen Datenbank-Engines funktioniert. Um DBI nutzen zu können, müssen Sie das DBI-Modul sowie für jeden Servertyp, auf den Sie zugreifen möchten, ein DataBase Driver (DBD)-Modul kompilieren. Das Treibermodul für MySQL ist DBD::mysql.

Perl DBI ist die empfohlene Schnittstelle für Perl. Sie ersetzt eine ältere Schnittstelle namens mysqlperl, die nun als obsolet gelten kann.

Installationsanleitungen für Perl DBI-Support finden Sie in Abschnitt 2.13, „Anmerkungen zur Perl-Installation“.

DBI-Informationen stehen auf der Kommandozeile, online oder gedruckt zur Verfügung:

  • Wenn Sie die Module DBI und DBD::mysql installiert haben, können Sie Informationen über diese Module mit dem Befehl perldoc auf der Kommandozeile abfragen:

    shell> perldoc DBI
    shell> perldoc DBI::FAQ
    shell> perldoc DBD::mysql
    

    Sie können diese Informationen auch mit pod2man, pod2html und so weiter in andere Formate übersetzen.

  • Online-Informationen über Perl DBI stehen auf der DBI-Website unter http://dbi.perl.org/ zur Verfügung. Diese Site hostet auch eine allgemeine Mailingliste zu DBI. MySQL AB hostet überdies eine spezielle DBD::mysql-Mailingliste; siehe Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

  • Was das gedruckte Wort angeht, so ist das offizielle DBI-Buch Programming the Perl DBI (Alligator Descartes und Tim Bunce, O'Reilly & Associates, 2000). Informationen über dieses Buch finden Sie auf der DBI-Website http://dbi.perl.org/.

    Informationen, die speziell die Benutzung von DBI mit MySQL in den Mittelpunkt stellen, finden Sie unter MySQL and Perl for the Web (Paul DuBois, New Riders, 2001). Die Website zu diesem Buch ist http://www.kitebird.com/mysql-perl/.

24.5. MySQL-C++-APIs

MySQL++ ist eine MySQL-API für C++. Warren Young hat dieses Projekt übernommen. Weitere Informationen finden Sie unter http://www.mysql.com/products/mysql++/.

24.5.1. Borland C++

Sie können die MySQL Windows-Quelldatei mit Borland C++ 5.02 kompilieren. (Zur Windows-Quelldatei gehören nur Projekte für Microsoft VC++; Projektdateien für Borland C++ müssen Sie sich selbst beschaffen.)

Ein bekanntes Problem mit Borland C++ ist, dass er eine andere Strukturanordnung als VC++ verwendet. Daher bekommen Sie Probleme, wenn Sie versuchen, mit Borland C++ die standardmäßigen libmysql.dll-Bibliotheken zu benutzen (die mit VC++ kompiliert wurden). Um dies zu vermeiden, rufen Sie mysql_init() nur mit NULL als Argument auf und verwenden keine vorab zugewiesene MYSQL-Struktur.

24.6. MySQL-Python-APIs

MySQLdb stellt für Python eine MySQL-Unterstützung zur Verfügung, die mit der Python-DB-API-Version 2.0 harmoniert. Diese finden Sie unter http://sourceforge.net/projects/mysql-python/.

24.7. MySQL-Tcl-APIs

MySQLtcl ist eine einfache API, um mit der Programmiersprache Tcl auf einen MySQL-Datenbankserver zugreifen zu können. Zu finden ist sie unter http://www.xdobry.de/mysqltcl/.

24.8. MySQL-Eiffel-Wrapper

Eiffel MySQL ist eine Schnittstelle zum MySQL-Datenbankserver für die von Michael Ravits geschriebene Programmiersprache Eiffel. Diese finden Sie unter http://efsa.sourceforge.net/archive/ravits/mysql.htm.

24.9. MySQL-Hilfsprogramme für die Programmentwicklung

Dieser Abschnitt beschreibt einige Utilities, die Ihnen bei der Entwicklung von MySQL-Programmen helfen können.

  • msql2mysql

    Ein Shell-Skript, das mSQL-Programme in MySQL konvertiert. Es kann zwar nicht jeden Fall behandeln, ist aber für die Konvertierung ein guter Anfang.

  • mysql_config

    Ein Shell-Skript, das die zur Kompilierung von MySQL-Programmen notwendigen Optionswerte erstellt.

24.9.1. msql2mysql — Umwandeln von mSQL-Programmen für die Benutzung mit MySQL

Anfangs wurde die MySQL-C-API ganz ähnlich wie die API für das Datenbanksystem mSQL entwickelt. Daher lassen sich mSQL-Programme oft relativ einfach für die Benutzung mit MySQL konvertieren, indem man einfach nur die Namen der C-API-Funktionen ändert.

Die Utility msql2mysql wandelt mSQL-C-API-Funktionsaufrufe in ihre MySQL-Entsprechungen um. Da msql2mysql die Eingabedatei an Ort und Stelle konvertiert, sollten Sie vorher eine Kopie des Originals anlegen. Sie können msql2mysql beispielsweise wie folgt verwenden:

shell> cp client-prog.c client-prog.c.orig
shell> msql2mysql client-prog.c
client-prog.c converted

Danach untersuchen Sie client-prog.c und nehmen, so weit notwendig, abschließende Überarbeitungen vor.

msql2mysql verwendet zum Ersetzen der Funktionsnamen die Utility replace. Siehe Abschnitt 8.17, „replace — Hilfsprogramm für String-Ersetzungen“.

24.9.2. mysql_config — Kompilieroptionen zum Kompilieren von Clients erhalten

mysql_config gibt Ihnen nützliche Informationen zum Kompilieren des MySQL-Clients und zur Verbindung mit MySQL.

mysql_config unterstützt die folgenden Optionen:

  • --cflags

    Compiler-Flags zum Auffinden von Include-Dateien und wichtige Compiler-Flags und Defines, die zum Kompilieren der libmysqlclient-Bibliothek verwendet werden.

  • --include

    Compiler-Optionen zum Auffinden von MySQL-Include-Dateien. (Beachten Sie, dass normalerweise statt dieser Option die Option --cflags benutzt wird.)

  • --libmysqld-libs, ---embedded

    Bibliotheken und Optionen, die zum Verlinken mit dem MySQL Embedded Server erforderlich sind.

  • --libs

    Bibliotheken und Optionen, die zum Verlinken mit der MySQL-Clientbibliothek erforderlich sind.

  • --libs_r

    Bibliotheken und Optionen, die zum Verlinken mit der Thread-sicheren MySQL-Clientbibliothek erforderlich sind.

  • --port

    Die Standard-TCP/IP-Portnummer, die beim Konfigurieren von MySQL definiert wird.

  • --socket

    Die Standard-Unix-Socket-File, die beim Konfigurieren von MySQL definiert wird.

  • --version

    Versionsnummer für die MySQL-Distribution.

Wenn Sie mysql_config ohne Optionen aufrufen, zeigt der Befehl eine Liste aller von ihm unterstützten Optionen samt ihrer Werte an:

shell> mysql_config
Usage: /usr/local/mysql/bin/mysql_config [options]
Options:
  --cflags         [-I/usr/local/mysql/include/mysql -mcpu=pentiumpro]
  --include        [-I/usr/local/mysql/include/mysql]
  --libs           [-L/usr/local/mysql/lib/mysql -lmysqlclient -lz
                    -lcrypt -lnsl -lm -L/usr/lib -lssl -lcrypto]
  --libs_r         [-L/usr/local/mysql/lib/mysql -lmysqlclient_r
                    -lpthread -lz -lcrypt -lnsl -lm -lpthread]
  --socket         [/tmp/mysql.sock]
  --port           [3306]
  --version        [4.0.16]
  --libmysqld-libs [-L/usr/local/mysql/lib/mysql -lmysqld -lpthread -lz
                    -lcrypt -lnsl -lm -lpthread -lrt]

Sie können mysql_config in einer Kommandozeile benutzen, um den Wert, den dieser Befehl für eine bestimmte Option anzeigt, einzubinden. Um beispielsweise ein MySQL-Clientprogramm zu kompilieren, verwenden Sie mysql_config folgendermaßen:

shell> CFG=/usr/local/mysql/bin/mysql_config
shell> sh -c "gcc -o progname `$CFG --cflags` progname.c `$CFG --libs`"

Wenn Sie mysql_config auf diese Weise benutzen, achten Sie darauf, es in Backtick-Zeichen einzuschließen (‘`’). So weiß die Shell, dass sie dies ausführen und die Ausgabe in den umgebenden Befehl einsetzen muss.

Kapitel 25. Connectors

Dieses Kapitel beschreibt MySQL Connectors, Treiber, die für Clientprogramme Verbindungsmöglichkeiten zu MySQL bereitstellen.

25.1. MySQL Connector/ODBC

MySQL Connector/ODBC ist der Name einer Familie von MySQL-ODBC-Treibern (auch MyODBC-Treiber genannt), die Zugriff auf eine MySQL-Datenbank mithilfe der Open Database Connectivity (ODBC)-API geben, die Industriestandard ist. Die vorliegende Referenz behandelt die API-Version Connector/ODBC 3.51, die ODBC 3.5x-konformen Zugriff auf eine MySQL-Datenbank gibt.

Das Manual für ältere MyODBC-Versionen als 3.51 finden Sie in der entsprechenden Binär- oder Quelldistribution.

Weitere Informationen über den ODBC-API-Standard und seine Verwendung finden Sie unter http://www.microsoft.com/data/.

Der Teil dieser Referenz, der sich mit Anwendungsentwicklung beschäftigt, setzt gute Vorkenntnisse in C, allgemeine DBMS-Kenntnisse und nicht zuletzt auch die Vertrautheit mit MySQL voraus. Weitere Informationen über die Funktionalität und Syntax von MySQL finden Sie unter http://dev.mysql.com/doc/.

MyODBC muss in der Regel nur auf Windows-Rechnern installiert werden. Für Unix und Mac OS X kann das native MySQL-Netzwerk oder eine Named Pipe zur Kommunikation mit der MySQL-Datenbank benutzt werden. Eventuell benötigen Sie jedoch MyODBC für Unix oder Mac OS X, wenn Sie eine Anwendung haben, die für die Datenbankkommunikation eine ODBC-Schnittstelle benötigt. Solche Anwendungen sind beispielsweise ColdFusion, Microsoft Office und Filemaker Pro.

Wenn Sie den MyODBC-Connector auf einem Unix-Host benutzen, müssen Sie auch einen ODBC-Manager installieren.

Fragen, die dieses Dokument nicht beantwortet, richten Sie bitte per E-Mail an .

25.1.1. Einführung in MyODBC

ODBC (Open Database Connectivity) gibt Clientprogrammen Zugriffsmöglichkeiten auf eine breite Palette von Datenbanken oder Datenquellen. ODBC ist eine standardisierte API, die Verbindungen zu SQL-Datenbankservern ermöglicht. Sie wurde nach den Vorgaben der SQL Access Group entwickelt und definiert Funktionsaufrufe, Fehlercodes und Datentypen, die für die Entwicklung datenbankunabhängiger Anwendungen eingesetzt werden können. ODBC wird normalerweise dort genutzt, wo Datenbankunabhängigkeit oder paralleler Zugriff auf verschiedene Datenquellen erforderlich ist.

Mehr über ODBC können Sie unter http://www.microsoft.com/data/ nachlesen.

25.1.1.1. MyODBC-Versionen

Zurzeit sind zwei Versionen von MyODBC erhältlich:

  • MyODBC 5.0, gegenwärtig noch in der Beta-Phase, wurde geschaffen, um die Funktionalität des MyODBC 3.51-Treibers zu erweitern und sämtliche Funktionen des MySQL Servers 5.0 zu unterstützen, einschließlich gespeicherter Prozeduren und Views. Anwendungen für MyODBC 3.51 werden auch mit MyODBC 5.0 funktionieren, zusätzlich jedoch auch die neuen Funktionen nutzen können. Die Features und Funktionalität des MyODBC 5.0-Treibers sind zurzeit noch nicht Gegenstand des vorliegenden Guides.

  • MyODBC 3.51 ist das aktuelle Release des 32-Bit-ODBC-Treibers, auch MySQL ODBC 3.51-Treiber genannt. Diese Version wurde gegenüber dem älteren MyODBC 2.50-Treiber verbessert. Sie unterstützt den ODBC 3.5x-Spezifikationslevel 1 (die gesamte Core-API + Features von Level 2), damit weiterhin auch die gesamte Funktionalität für den ODBC-Zugriff auf MySQL geboten werden kann.

  • MyODBC 2.50 ist die frühere Version des 32-Bit-ODBC-Treibers von der MySQL AB und beruht auf dem ODBC 2.50-Spezifikationslevel 0 (mit den Features von Level 1 und 2). Über den MyODBC 2.50-Treiber informiert diese Referenz nur zu Vergleichszwecken.

Hinweis: Ab diesem Abschnitt liegt das Hauptaugenmerk dieser Referenz auf dem MyODBC 3.51-Treiber. Weitere Informationen über den MyODBC-Treiber 2.50 finden Sie in der Dokumentation zu den Installationspaketen dieser Version. Wenn ein konkretes Thema (ein Fehler oder ein bekanntes Problem) nur die Version 2.50 betrifft, wird es unter Umständen zur Orientierung hier ebenfalls behandelt.

25.1.1.2. Allgemeine Informationen über ODBC und MyODBC

Open Database Connectivity (ODBC) ist eine allgemein anerkannte Programmierschnittstelle (API) für den Datenbankzugriff. Sie beruht auf den Call-Level Interface(CLI)-Spezifikationen von X/Open und ISO/IEC für Datenbank-APIs und benutzt als Sprache für den Datenbankzugriff die Structured Query Language (SQL).

Eine Übersicht über die von MyODBC unterstützten ODBC-Funktionen finden Sie unter Abschnitt 25.1.5.1, „MyODBC: API-Referenz“. Allgemeine Informationen über ODBC gibt es unter http://www.microsoft.com/data/.

25.1.1.2.1. MyODBC-Architektur

Die MyODBC-Architektur basiert auf den im folgenden Diagramm gezeigten fünf Komponenten:

MyODBC-Architektur
  • Anwendung:

    Die Anwendung (Application) nutzt die ODBC-API, um auf die Daten auf dem MySQL Server zuzugreifen. Die ODBC-API ihrerseits kommuniziert mit dem Treiber-Manager (Driver Manager). Die Anwendung kommuniziert mit dem Treiber-Manager über normale ODBC-Aufrufe und kümmert sich nicht darum, wie und wo die Daten gespeichert sind oder wie das System für den Datenzugriff konfiguriert ist. Alles, was sie wissen muss, ist der Data Source Name (DSN).

    Einige Aufgaben müssen von allen Anwendungen erledigt werden, egal auf welche Weise sie ODBC nutzen:

    • Sie müssen den MySQL Server auswählen und sich mit ihm verbinden.

    • Sie müssen SQL-Anweisungen zur Ausführung übermitteln.

    • Sie müssen die Ergebnisse (sofern vorhanden) abholen.

    • Sie müssen Fehler verarbeiten.

    • Sie müssen die Transaktion, zu der die SQL-Anweisung gehört, committen oder zurückrollen.

    • Sie müssen die Verbindung zum MySQL Server trennen.

    Da die meiste Arbeit im Zusammenhang mit dem Datenzugriff mit SQL verrichtet wird, besteht die Hauptaufgabe von Anwendungen, die ODBC nutzen, in der Übermittlung von SQL-Anweisungen und dem Abruf der dadurch erzeugten Ergebnisse.

  • Treiber-Manager:

    Der Treiber-Manager ist eine Bibliothek zur Verwaltung der Kommunikation zwischen Anwendung und Treiber(n). Er kümmert sich um folgende Aufgaben:

    • Er löst Data Source Names (DSN) auf. Der DSN ist ein Konfigurations-String, der einen Datenbanktreiber, einen Datenbank-Host und optional auch Authentifizierungsdaten enthält und der ODBC-Anwendung eine Datenbankverbindung über eine standardisierte Referenz ermöglicht.

      Da der DSN die Informationen für die Datenbankverbindung enthält, kann sich jede ODBC-fähige Anwendung über dieselbe DSN-Referenz mit der Datenquelle verbinden. Dadurch ist es nicht mehr nötig, jede Anwendung, die Zugriff auf eine konkrete Datenbank benötigt, separat zu konfigurieren. Stattdessen instruieren Sie die Anwendung, einen vorkonfigurierten DSN zu verwenden.

    • Er lädt und entlädt den Treiber, der für den Zugriff auf eine bestimmte Datenbank notwendig ist, wie im DSN definiert. Wenn Sie zum Beispiel einen DSN für die Verbindung mit einer MySQL-Datenbank konfiguriert haben, lädt der Treiber-Manager den MyODBC-Treiber, damit die ODBC-API mit dem MySQL-Host kommunizieren kann.

    • Er verarbeitet ODBC-Funktionsaufrufe oder übergibt sie zur Verarbeitung an den Treiber.

  • MyODBC-Treiber:

    Der MyODBC-Treiber ist eine Bibliothek, die Funktionen implementiert, welche von der ODBC-API unterstützt werden. Er verarbeitet ODBC-Funktionsaufrufe, übermittelt SQL-Requests an den MySQL Server und liefert die Ergebnisse an die Anwendung zurück. Wenn nötig, modifiziert der Treiber den von der Anwendung übermittelten Request so, dass er der MySQL-Syntax entspricht.

  • DSN-Konfiguration:

    Die ODBC-Konfigurationsdatei speichert die Treiber- und Datenbankinformationen, die für die Serververbindung erforderlich sind. Der Treiber-Manager nutzt sie, um festzustellen, welcher Treiber laut der Definition im DSN geladen werden muss. Der Treiber liest daraus die Verbindungsparameter anhand des angegebenen DSN. Weitere Informationen finden Sie unter Abschnitt 25.1.3, „MyODBC: Konfiguration“.

  • MySQL Server:

    Die MySQL-Datenbank, in der die Informationen gespeichert sind. Die Datenbank wird für Abfragen als Datenquelle und für Einfügungen und Änderungen als Ziel für die Daten genutzt.

25.1.1.2.2. ODBC-Treiber-Manager

Ein ODBC-Treiber-Manager ist eine Bibliothek zur Verwaltung der Kommunikation zwischen einer ODBC-fähigen Anwendung und Treibern. Seine Hauptfunktionen sind:

  • Data Source Names (DSN) auflösen

  • Treiber laden und entladen

  • ODBC-Funktionsaufrufe verarbeiten oder zur Verarbeitung an den Treiber weiterleiten

Bei Windows und Mac OS X sind ODBC-Treiber-Manager im Betriebssystem enthalten. Die meisten Implementierungen von ODBC-Treiber-Managern umfassen auch eine Administrationsanwendung, um die Konfiguration von DSN und Treibern zu vereinfachen. Beispiele und Informationen zu diesen Managern, einschließlich der ODBC-Treiber-Manager von Unix, sind im Folgenden aufgelistet:

  • Microsoft Windows ODBC-Treiber-Manager (odbc32.dll), http://www.microsoft.com/data/.

  • Mac OS X enthält den ODBC Administrator, eine GUI-Anwendung, die einen vereinfachten Konfigurationsmechanismus für den iODBC-Treiber-Manager von Unix zur Verfügung stellt. Sie können DSN- und Treiber-Informationen entweder über den ODBC-Administrator oder durch die iODBC-Konfigurationsdateien in Erfahrung bringen. Das bedeutet auch, dass Sie die ODBC Administrator-Konfigurationen mit dem Befehl iodbctest testen können. http://www.apple.com.

  • unixODBC-Treiber-Manager für Unix (libodbc.so). Siehe weitere Informationen unter http://www.unixodbc.org. Ab der Version unixODBC 2.1.2 ist der MyODBC-Treiber 3.51 im Installationspaket des unixODBC-Treiber-Managers enthalten.

  • Über den iODBC-ODBC-Treiber-Manager für Unix (libiodbc.so) finden Sie weitere Informationen unter http://www.iodbc.org.

25.1.2. Installation von MyODBC

Die MyODBC-Treiber können Sie mit zwei verschiedenen Methoden installieren, nämlich entweder als Binär- oder als Quellinstallation. Die Binärinstallation ist die einfachste. Eine Quellinstallation dürfte nur auf Plattformen notwendig sein, für die kein Binärinstallationspaket zur Verfügung steht oder wenn Sie den Installationsprozess oder die MyODBC-Treiber vor der Installation modifizieren möchten.

25.1.2.1. Woher man MyODBC bekommt

Die MySQL AB vertreibt alle ihre Produkte unter der General Public License (GPL). Die neueste Version der MyODBC-Binär- und Quelldateien erhalten Sie auf der Website von MySQL AB unter http://dev.mysql.com/downloads/.

Weitere Informationen über MyODBC finden Sie unter http://www.mysql.com/products/myodbc/.

Über die Lizenzen können Sie sich unter http://www.mysql.com/company/legal/licensing/ informieren.

25.1.2.2. Unterstützte Plattformen

MyODBC kann auf allen von MySQL unterstützten Plattformen verwendet werden, als da sind:

  • Windows 95, 98, Me, NT, 2000, XP und 2003

  • Alle Unix-ähnlichen Betriebssysteme, darunter AIX, Amiga, BSDI, DEC, FreeBSD, HP-UX 10/11, Linux, NetBSD, OpenBSD, OS/2, SGI Irix, Solaris, SunOS, SCO OpenServer, SCO UnixWare, Tru64 Unix

  • Mac OS X und Mac OS X Server

Wenn für eine bestimmte Plattform keine Binärdistribution verfügbar ist, schlagen Sie bitte Abschnitt 25.1.2.4, „MyODBC von einer Quelldistribution installieren“, nach, um den Treiber aus dem Originalquellcode zu erstellen. Die Binärdateien, die Sie aus diesem Code erstellen, könnten Sie dann MySQL zugänglich machen, indem Sie eine E-Mail an schicken. So können auch andere diese Binärdateien nutzen.

25.1.2.3. MyODBC von einer Binärdistribution installieren

Am einfachsten lässt sich MyODBC von einer Binärdistribution installieren. Wenn Sie mehr Kontrolle über den Treiber oder das Installationsverzeichnis bekommen oder einzelne Elemente des Treibers an Ihre Bedürfnisse anpassen möchten, müssen Sie ihn aus den Quelldateien erstellen. Siehe hierzu Abschnitt 25.1.2.4, „MyODBC von einer Quelldistribution installieren“.

25.1.2.3.1. Installation von MyODBC aus einer Binärdistribution unter Windows

Bevor Sie die MyODBC-Treiber auf Windows installieren, sollten Sie sicherstellen, dass Ihre Microsoft Data Access Components (MDAC) auf dem neuesten Stand sind. Die aktuellste Version erhalten Sie auf der Website Microsoft Data Access and Storage.

Für die Windows-Installation stehen drei Distributionstypen zur Verfügung. Der Inhalt ist immer derselbe; nur die Installationsmethode ist unterschiedlich.

25.1.2.3.1.1. Windows MyODBC-Treiber mit einem Installer installieren

Die Installer-Programme bieten ein sehr einfaches Mittel zur Installation der MyODBC-Treiber. Wenn Sie den gezippten Installer heruntergeladen haben, müssen Sie die Installer-Anwendung noch auspacken. Der grundlegende Installationsprozess ist für beide Installer derselbe.

Um die Installation abzuschließen, gehen Sie folgendermaßen vor:

  1. Setzen Sie einen Doppelklick auf den extrahierten Installer oder die heruntergeladene MSI-Datei.

  2. Dadurch wird der MySQL Connector/ODBC 3.51 - Setup Wizard gestartet. Klicken Sie auf Next, um den Installationsprozess zu starten.

    MyODBC Windows Installer -
                  Begrüßung
  3. Nun wählen Sie den Installationstyp. Die typische Installation liefert die Standarddateien, die für eine ODBC-Verbindung mit einer MySQL-Datenbank benötigt werden. Die Complete-Option installiert sämtliche verfügbaren Dateien einschließlich Debugging und Hilfsprogrammen. Wir empfehlen, eine dieser beiden Optionen zu nutzen. Danach klicken Sie auf Next und machen mit Schritt 5 weiter.

    Sie können auch eine benutzerdefinierte (Custom) Installation verlangen, bei der Sie die zu installierenden Komponenten selbst auswählen können. Wenn Sie diese Methode ausgewählt haben, klicken Sie auf Next und gehen zu Schritt 4.

    MyODBC Windows Installer -
                  Installationsart wählen
  4. Wenn Sie sich für eine benutzerdefinierte Installation entschieden haben, wählen Sie in den Popup-Fenstern aus, welche Komponenten Sie installieren möchten, und klicken dann auf Next, um die notwendigen Dateien zu installieren.

    MyODBC Windows Installer -
                  Benutzerdefinierte Installation
  5. Wenn die Dateien auf Ihren Computer kopiert worden sind, ist die Installation abgeschlossen. Klicken Sie auf Finish, um den Installer zu schließen.

    MyODBC Windows Installer -
                  Fertigstellung der Installation

Nun ist die Installation fertig und Sie können beginnen, Ihre ODBC-Verbindungen gemäß Abschnitt 25.1.3, „MyODBC: Konfiguration“, zu konfigurieren.

25.1.2.3.1.2. Windows MyODBC-Treiber mit dem DLL-Zip-Archiv installieren

Wenn Sie das DLL-Paket als Zip-Archiv heruntergeladen haben, müssen Sie die einzelnen Dateien, die für MyODBC erforderlich sind, manuell installieren. Nach dem Auspacken der Installationsdateien können Sie dies entweder selbst tun, indem Sie jede notwendige Anweisung einzeln ausführen, oder die mitgelieferte Batch-Datei für eine Installation in den Standardverzeichnissen nutzen.

Installation mithilfe der Batch-Datei:

  1. Extrahieren Sie das MyODBC Zipped DLL-Paket.

  2. Öffnen Sie ein Befehlseingabefenster.

  3. Gehen Sie in das Verzeichnis, das beim Extrahieren des MyODBC Zipped DLL-Pakets angelegt wurde.

  4. Führen Sie Install.bat aus:

    C:\> Install.bat

    Dieser Befehl kopiert die notwendigen Dateien in das Standardverzeichnis und registriert dann den MyODBC-Treiber beim Windows ODBC-Manager.

Wenn Sie die Dateien in ein anderes Verzeichnis kopieren möchten, etwa um unterschiedliche Versionen des MyODBC-Treibers auf demselben Computer auszuführen oder zu testen, dann müssen Sie die Dateien manuell kopieren. Allerdings kann man nur davon abraten, sie in ein anderes als das Standardverzeichnis zu installieren. Um die Dateien von Hand in das Standardinstallationsverzeichnis zu kopieren, verfahren Sie folgendermaßen:

  1. Extrahieren Sie das MyODBC Zipped DLL-Paket.

  2. Öffnen Sie ein Befehlseingabefenster.

  3. Gehen Sie in das Verzeichnis, das beim Extrahieren des MyODBC Zipped DLL-Pakets angelegt wurde.

  4. Kopieren Sie die Bibliotheksdateien in ein passendes Verzeichnis. Standardmäßig werden sie in das Systemverzeichnis von Windows kopiert, nämlich \Windows\System32:

    C:\> copy lib\myodbc3S.dll \Windows\System32
    C:\> copy lib\myodbc3S.lib \Windows\System32
    C:\> copy lib\myodbc3.dll \Windows\System32
    C:\> copy lib\myodbc3.lib \Windows\System32
  5. Kopieren Sie die MyODBC-Tools. Diese müssen in ein Verzeichnis gesetzt werden, das im System-PATH liegt. Standardmäßig werden sie in das Systemverzeichnis von Windows installiert, nämlich \Windows\System32:

    C:\> copy bin\myodbc3i.exe \Windows\System32
    C:\> copy bin\myodbc3m.exe \Windows\System32
    C:\> copy bin\myodbc3c.exe \Windows\System32
  6. Optional können Sie auch die Hilfedateien kopieren. Damit diese im Hilfe-System zugänglich sind, müssen sie im Windows-Systemverzeichnis installiert werden:

    C:\> copy doc\*.hlp \Windows\System32
  7. Zum Schluss registrieren Sie den MyODBC-Treiber beim ODBC-Manager:

    C:\> myodbc3i -a -d -t"MySQL ODBC 3.51 Driver;\
      DRIVER=myodbc3.dll;SETUP=myodbc3S.dll"

    Wenn Sie die Dateien nicht im Standardverzeichnis installiert haben, müssen Sie bei diesem Befehl die Verweise auf die DLL-Dateien und den Ort des Befehls entsprechend ändern.

25.1.2.3.1.3. Umgang mit Installationsfehlern

Auf Windows wird eventuell folgender Fehler gemeldet, wenn Sie versuchen, den älteren MyODBC 2.50-Treiber zu installieren:

An error occurred while copying C:\WINDOWS\SYSTEM\MFC30.DLL. 
Restart Windows and try installing again (before running any
applications which use ODBC)

Dieser Fehler tritt auf, wenn eine andere Anwendung gerade das ODBC-System benutzt. Windows erlaubt Ihnen dann vielleicht nicht, die Installation abzuschließen. In den meisten Fällen können Sie jedoch mit einem Klick auf Ignorieren fortfahren, den Rest der MyODBC-Dateien zu kopieren, und das Ergebnis der Installation sollte funktionieren. Wenn nicht, so fahren Sie Ihren Computer im „abgesicherten Modus“ wieder hoch. Diesen Modus steuern Sie an, indem Sie beim Booten, unmittelbar bevor Windows gestartet wird, auf F8 drücken. Installieren Sie sodann die MyODBC-Treiber und starten Sie den Computer im Normalmodus neu.

25.1.2.3.2. Installation von MyODBC aus einer Binärdistribution unter Unix

Es gibt zwei Methoden, um MyODBC auf Unix von einer Binärdistribution zu installieren. Für die meisten Unix-Umgebungen wird die Tarball-Distribution benötigt. Für Linux-Systeme steht außerdem eine RPM-Distribution zur Verfügung.

25.1.2.3.2.1. Installation von MyODBC aus einer beinären Tarball-Distribution

Um den Treiber von einer Tarball-Distribution zu installieren (die Datei .tar.gz), laden Sie die neueste Treiberversion für Ihr Betriebssystem herunter und halten sich an die folgenden Schritte (gezeigt wird das Vorgehen mit einer Linux-Version des Tarballs):

shell> su root
shell> gunzip MyODBC-3.51.11-i686-pc-linux.tar.gz
shell> tar xvf MyODBC-3.51.11-i686-pc-linux.tar
shell> cd MyODBC-3.51.11-i686-pc-linux

Lesen Sie die Installationsanweisungen in der Datei INSTALL-BINARY und führen Sie folgende Befehle aus.

shell> cp libmyodbc* /usr/local/lib
shell> cp odbc.ini /usr/local/etc
shell> export ODBCINI=/usr/local/etc/odbc.ini

Dann fahren Sie mit Abschnitt 25.1.3.4, „Konfiguration einer MyODBC-DSN unter Unix“, fort, um den DSN für MyODBC zu konfigurieren. Weitere Informationen finden Sie in der Datei INSTALL-BINARY aus Ihrer Distribution.

25.1.2.3.2.2. Installation von MyODBC aus einer RPM-Distribution

Um MyODBC von einer RPM-Distribution auf Linux zu installieren oder zu aktualisieren, laden Sie einfach die RPM-Distribution der neuesten MyODBC-Version herunter und halten sich an die nachfolgenden Anleitungen. Zuerst müssen Sie mit su root der root-User werden und dann können Sie die RPM-Datei installieren.

Wenn es sich um eine Erstinstallation handelt:

shell> su root
 shell> rpm -ivh MyODBC-3.51.12.i386.rpm

Wenn der Treiber bereits existiert und nur aktualisiert werden soll:

shell> su root
shell> rpm -Uvh MyODBC-3.51.12.i386.rpm

Falls ein Fehler in den Abhängigkeiten der MySQL-Clientbibliothek libmysqlclient gemeldet wird, übergehen Sie ihn einfach, indem Sie die Option --nodeps einstellen, und sorgen dafür, dass die gemeinsame MySQL-Clientbibliothek im Pfad oder mit LD_LIBRARY_PATH eingestellt ist.

So werden die Treiberbibliotheken und zugehörigen Dokumente in /usr/local/lib und /usr/share/doc/MyODBC installiert. Machen Sie nun weiter mit Abschnitt 25.1.3.4, „Konfiguration einer MyODBC-DSN unter Unix“.

Um den Treiber zu deinstallieren, müssen Sie als root einen rpm-Befehl ausführen:

shell> su root
shell> rpm -e MyODBC
25.1.2.3.3. MyODBC auf Mac OS X installieren

Mac OS X basiert auf dem Betriebssystem FreeBSD. Normalerweise können Sie den MySQL-Netzwerkanschluss benutzen, um sich mit MySQL Servern auf anderen Hosts zu verbinden. Die Installation des MyODBC-Treibers versetzt Sie in die Lage, sich mit MySQL-Datenbanken auf jeder beliebigen Plattform über die ODBC-Schnittstelle zu verbinden. Den MyODBC-Treiber müssen Sie nur dann installieren, wenn Ihre Anwendung eine ODBC-Schnittstelle benötigt. Zu den Anwendungen, die ODBC (und somit auch den MyODBC-Treiber) erfordern oder nutzen können, gehören ColdFusion, Filemaker Pro, 4th Dimension und viele andere mehr.

Mac OS X enthält einen eigenen ODBC-Manager, der auf dem iODBC-Manager basiert. Mac OS X hat ein Administrationstool, das die Administration von ODBC-Treibern und die Konfiguration erleichtert, wobei die zugrunde liegenden iODBC-Konfigurationsdateien aktualisiert werden.

25.1.2.3.3.1. MyODBC-Treiber installieren

MyODBC kann auf einem Mac OS X oder Mac OS X Server mithilfe der Binärdistribution installiert werden. Dieses Paket steht als komprimierte Disk Image-Datei (.dmg) zur Verfügung. Um MyODBC mit dieser Methode zu installieren, verfahren Sie wie folgt:

  1. Laden Sie die Datei auf Ihren Computer herunter und führen Sie einen Doppelklick auf die Image-Datei aus.

  2. Dort finden Sie ein Installer-Paket (mit der Erweiterung .pkg). Mit einem Doppelklick auf diese Datei starten Sie den Mac OS X-Installer.

  3. Wenn Sie die Grußbotschaft sehen, klicken Sie auf Continue, um den Installationsprozess zu starten.

    MyODBC Mac OS X Installer -
                  Grußbildschirm des Installers
  4. Bitte nehmen Sie sich ein wenig Zeit, um die wichtigen Informationen (Important Information) zu lesen, denn sie enthalten eine Anleitung für den weiteren Installationsprozess. Wenn Sie eine Verbindung zu einer MySQL-Datenbank testen möchten, müssen Sie den Standort Ihres MySQL Servers kennen und einen Benutzernamen und ein Passwort haben, um einen zum Testen der Installation geeigneten DSN zu erhalten. Ein solcher Test ist jedoch nicht erforderlich, um die Installation abzuschließen. Wenn Sie die Hinweise gelesen und die notwendigen Informationen gesammelt haben, klicken Sie auf Continue.

    MyODBC Mac OS X Installer - Wichtige
                  Informationen
  5. MyODBC-Treiber unterliegen der GNU General Public License. Bitte lesen Sie die Lizenz, wenn Sie sie noch nicht kennen, ehe Sie mit der Installation fortfahren. Mit einem Klick auf Continue akzeptieren Sie die Lizenz (hier werden Sie noch einmal zur Bestätigung aufgefordert) und setzen die Installation fort.

    MyODBC Mac OS X Installer -
                  Lizenz
  6. Wählen Sie ein Installationsverzeichnis für die MyODBC-Treiber und die ODBC Administrator-Anwendung. Sie müssen die Dateien auf einem Laufwerk mit einem Betriebssystem installieren, sodass Sie unter Umständen nicht viele Auswahlmöglichkeiten haben. Wählen Sie das Laufwerk, das Sie benutzen möchten, und klicken Sie auf Continue.

    MyODBC Mac OS X Installer -
                  Zielverzeichnis wählen
  7. Der Installer wählt automatisch die Dateien aus, die auf Ihrem Computer installiert werden müssen. Um fortzufahren, klicken Sie auf Install. Der Installer kopiert nun die erforderlichen Dateien auf Ihren Computer. Eine Fortschrittsanzeige informiert Sie über den Installationsfortschritt.

    MyODBC Mac OS X Installer -
                  Installationstyp
  8. Nach Abschluss der Installation sehen Sie ein Fenster wie das unten abgebildete. Klicken Sie auf Close, um den Installer zu beenden.

    MyODBC Mac OS X Installer -
                  Installation abgeschlossen

25.1.2.4. MyODBC von einer Quelldistribution installieren

Wenn Sie MyODBC von einer Quelldistribution installieren, haben Sie mehr Einfluss auf den Inhalt und das Installationsverzeichnis der MyODBC-Komponenten. Außerdem können Sie dann MyODBC auch auf Plattformen installieren, für die keine vorkompilierte Binärversion verfügbar ist.

MyODBC-Quelldateien erhalten Sie entweder als Download oder über das Revisionskontrollsystem, das die MyODBC-Entwickler benutzen.

25.1.2.4.1. Installation von MyODBC aus einer Quelldistribution unter Windows

Auf Windows müsste eine Quellinstallation von MyODBC nur dann nötig sein, wenn Sie die Quelle oder die Installation ändern möchten. Wenn Sie unsicher sind, ob Sie von Quelldateien installieren sollten, verwenden Sie besser die Binärinstallation, die in Abschnitt 25.1.2.3.1, „Installation von MyODBC aus einer Binärdistribution unter Windows“, beschrieben ist.

Für eine Quellinstallation von MyODBC auf Windows sind verschiedene Tools und Pakete erforderlich:

  • MDAC, Microsoft Data Access SDK von http://www.microsoft.com/data/.

  • Ein geeigneter C-Compiler, wie etwa Microsoft Visual C++ oder der C-Compiler von Microsoft Visual Studio.

  • Ein kompatibles make-Tool. In den Beispielen dieses Abschnitts wird nmake von Microsoft eingesetzt.

  • MySQL-Clientbibliotheken und Include-Dateien von MySQL 4.0.0 oder höher (vorzugsweise MySQL 4.0.16 oder höher). Diese sind notwendig, weil MyODBC neue Aufrufe und Strukturen verwendet, die erst ab dieser Version der Bibliothek vorhanden sind. Die MySQL-Clientbibliotheken und Include-Dateien erhalten Sie von http://dev.mysql.com/downloads/.

25.1.2.4.1.1. Bauen von MyODBC 3.51

MyODBC-Quelldistributionen enthalten Makefiles, für die nmake oder die make-Utility notwendig ist. Die Distribution enthält Makefile, um die Release-Version, und Makefile_debug, um Debugging-Versionen der Treiberbibliotheken und DLLs zu bauen.

Den Treiber bauen Sie wie folgt:

  1. Sie laden die Quelldateien herunter und extrahieren sie in einen Ordner. Dann gehen Sie in dieses Verzeichnis. Der folgende Befehl geht davon aus, dass der Ordner myodbc3-src heißt:

    C:\> cd myodbc3-src
    
  2. Sie editieren Makefile, um den Pfad der MySQL-Clientbibliotheken und -Header-Dateien anzugeben. Dann erstellen und installieren Sie mit folgenden Befehlen die Release-Version:

    C:\> nmake -f Makefile
    C:\> nmake -f Makefile install
    

    nmake -f Makefile erstellt die Release-Version des Treibers und speichert die Binärdateien in einem Unterverzeichnis namens Release.

    nmake -f Makefile install installiert (kopiert) die Treiber-DLLs und Bibliotheken (myodbc3.dll, myodbc3.lib) in Ihr Systemverzeichnis.

  3. Die Debugversion wird mit Makefile_Debug anstelle von Makefile erstellt:

    C:\> nmake -f Makefile_debug
    C:\> nmake -f Makefile_debug install
    
  4. Um den Treiber sauber neu zu installieren, geben Sie Folgendes ein:

    C:\> nmake -f Makefile clean
    C:\> nmake -f Makefile install
    

Hinweis

  • Achten Sie darauf, in den Makefiles den richtigen Pfad zu den MySQL-Clientbibliotheken und Header-Dateien anzugeben. (Hierzu müssen Sie die Variablen MYSQL_LIB_PATH und MYSQL_INCLUDE_PATH einstellen.) Der Standardpfad zur Header-Datei ist voraussichtlich C:\mysql\include und der Standardpfad zur Bibliothek lautet C:\mysql\lib\opt für Release-DLLs und C:\mysql\lib\debug für Debugging-Versionen.

  • Mehr über die Verwendung von nmake erfahren Sie unter http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vcce4/html/evgrfRunningNMAKE.asp.

  • Wenn Sie den Subversion-Baum zum Kompilieren verwenden, bekommen alle Windows-spezifischen Makefiles den Namen Win_Makefile*.

25.1.2.4.1.2. Testen

Wenn die Treiberbibliotheken in das Systemverzeichnis kopiert/installiert worden sind, können Sie anhand der Beispiele aus dem Unterverzeichnis samples testen, ob die Bibliotheken korrekt erstellt wurden:

C:\> cd samples
C:\> nmake -f Makefile all
25.1.2.4.1.3. Bauen von MyODBC 2.50

Die Quelldistribution MyODBC 2.50 enthält auch VC-Workspace-Dateien. Sie können den Treiber mit diesen Dateien (.dsp und .dsw) direkt bauen, indem Sie sie von Microsoft Visual Studio 6.0 oder höher laden.

25.1.2.4.2. Installation von MyODBC aus einer Quelldistribution unter Unix

Folgende Tools werden benötigt, um MySQL auf Unix aus der Quelldistribution zu erstellen:

  • Ein funktionierender ANSI C++-Compiler. gcc 2.95.2 oder höher, egcs 1.0.2 oder höher oder egcs 2.91.66, SGI C++ und SunPro C++ sind Beispiele für funktionierende Compiler.

  • Ein gutes make-Programm. Das make von GNU ist immer empfehlenswert und manchmal sogar obligatorisch.

  • MySQL-Clientbibliotheken und Include-Dateien von MySQL 4.0.0 oder höher (vorzugweise MySQL 4.0.16 oder höher). Diese sind notwendig, weil MyODBC neue Aufrufe und Strukturen benutzt, die erst ab dieser Version der Bibliothek zur Verfügung stehen. Sie erhalten die MySQL-Clientbibliotheken und Include-Dateien unter http://dev.mysql.com/downloads/.

    Wenn Sie einen eigenen MySQL Server und/oder Clientbibliotheken aus den Quelldateien gebaut haben, müssen Sie bei der Erstellung der Bibliotheken configure mit der Option --enable-thread-safe-client verwendet haben.

    Außerdem müssen Sie sich vergewissern, dass die Bibliothek libmysqlclient als Shared Library gebaut und installiert wurde.

  • Ein kompatibler ODBC-Manager muss installiert sein. Von MyODBC ist bekannt, dass es mit den Managern iODBC und unixODBC funktioniert. Siehe auch Abschnitt 25.1.1.2.2, „ODBC-Treiber-Manager“.

  • Wenn Sie einen Zeichensatz verwenden, der nicht in die MySQL-Clientbibliothek kompiliert ist, müssen Sie die MySQL-Zeichendefinitionen aus dem Verzeichnis charsets in SHAREDIR installieren (nach Voreinstellung ist dies /usr/local/mysql/share/mysql/charsets). Wenn Sie den MySQL Server auf demselben Computer installiert haben, müssten die Zeichendefinitionen vorhanden sein. Mehr über Unterstützung von Zeichensätzen erfahren Sie unter Kapitel 10, Zeichensatz-Unterstützung.

Wenn Sie alle erforderlichen Dateien beisammen haben, extrahieren Sie die Quelldateien in ein getrenntes Verzeichnis. Danach führen Sie configure aus und erstellen mit make die Bibliothek.

25.1.2.4.2.1. Typische configure-Optionen

Das configure-Skript gibt Ihnen viel Einfluss auf die Konfiguration Ihres MyODBC-Builds. Diesen Einfluss üben Sie aus, indem Sie auf der Kommandozeile Optionen für configure benutzen. Außerdem können Sie configure mit gewissen Umgebungsvariablen beeinflussen. Eine Liste der Optionen und Umgebungsvariablen für configure liefert Ihnen folgender Befehl:

shell> ./configure --help

Die gebräuchlichsten Optionen für configure werden im Folgenden beschrieben:

  1. Um MyODBC zu kompilieren, müssen Sie den Pfad zu den Include- und Bibliotheksdateien des MySQL-Clients mit der Option --with-mysql-path=DIR angeben, wobei DIR das Verzeichnis ist, in dem MySQL installiert wurde.

    Die Optionen zum Kompilieren von MySQL ermitteln Sie, indem Sie DIR/bin/mysql_config ausführen.

  2. Geben Sie den Standardpfad für die Header- und Bibliotheksdateien für Ihren ODBC-Treiber-Manager an (iODBC oder unixODBC).

    • Wenn Sie iODBC benutzen, aber nicht im Standardverzeichnis (/usr/local) installiert haben, müssen Sie eventuell die Option --with-iodbc=DIR angeben, wobei DIR das Verzeichnis ist, in dem iODBC installiert wurde.

      Liegen die iODBC-Header nicht unter DIR/include, können Sie ihren Speicherort mit der Option --with-iodbc-includes=INCDIR angeben.

      Dies gilt auch für Bibliotheken. Wenn sie nicht unter DIR/lib zu finden sind, können Sie die Option --with-iodbc-libs=LIBDIR verwenden.

    • Wenn Sie unixODBC nutzen, verwenden Sie die Option --with-unixODBC=DIR (Groß- und Kleinschreibung beachten!), damit configure standardmäßig nach unixODBC statt nach iODBC sucht. DIR ist das Verzeichnis, wo unixODBC installiert ist.

      Wenn die unixODBC-Header und Bibliotheken nicht in DIR/include und DIR/lib liegen, müssen Sie die Optionen --with-unixODBC-includes=INCDIR und --with-unixODBC-libs=LIBDIR einstellen.

  3. Vielleicht möchten Sie ein anderes Installationspräfix als /usr/local vorgeben. Wenn Sie zum Beispiel die MyODBC-Treiber in /usr/local/odbc/lib installieren möchten, setzen Sie die Option --prefix=/usr/local/odbc.

Zum Schluss sieht der Konfigurationsbefehl in etwa wie folgt aus:

shell> ./configure --prefix=/usr/local \
         --with-iodbc=/usr/local \
         --with-mysql-path=/usr/local/mysql
25.1.2.4.2.2. Zusätzliche Konfigurationsoptionen

Es gibt noch mehr Optionen, die Sie einstellen müssen oder können, wenn Sie den MyODBC-Treiber vor dem Build konfigurieren.

  • Um den Treiber mit den Thread-sicheren Clientbibliotheken von MySQL, libmysqlclient_r.so oder libmysqlclient_r.a, zu verlinken, geben Sie folgende configure-Option an:

    --enable-thread-safe
    

    Deaktiviert (die Standardeinstellung) wird dies wie folgt:

    --disable-thread-safe
    

    Diese Option ermöglicht die Erstellung der Thread-sicheren Treiberbibliothek libmyodbc3_r.so durch das Verlinken mit der Thread-sicheren MySQL-Clientbibliothek libmysqlclient_r.so (die Erweiterungen hängen vom Betriebssystem ab).

    Wenn das Kompilieren mit der Thread-sicheren Option scheitert, dann möglicherweise deshalb, weil auf dem betreffenden System die richtigen Thread-Bibliotheken nicht gefunden werden konnten. Stellen Sie den Wert von LIBS also auf die für Ihr System passende Thread-Bibliothek ein.

    LIBS="-lpthread" ./configure ..
    
  • Die gemeinsam genutzte und die statische Version von MyODBC werden mit folgenden Optionen aktiviert und deaktiviert:

    --enable-shared[=yes/no]
    --disable-shared
    --enable-static[=yes/no]
    --disable-static
    
  • Nach Voreinstellung werden alle Binärdistributionen ohne Debugging gebaut (mit --without-debug konfiguriert).

    Um Debugging-Informationen zu erhalten, erstellen Sie den Treiber aus der Quellversion und stellen die Option --with-debug ein, wenn Sie configure ausführen.

  • Diese Option steht nur für Quellbäume aus dem Subversion-Repository zur Verfügung, nicht für Quelldistributionen, die als Package geliefert werden.

    Nach Voreinstellung wird der Treiber mit der Option --without-docs gebaut. Wenn Sie die Dokumentation einrichten möchten, führen Sie configure folgendermaßen aus:

    --with-docs
    
25.1.2.4.2.3. Bauen und Kompilieren

Um die Treiberbibliotheken zu bauen, müssen Sie nur make laufen lassen.

shell> make

Wenn Fehler auftreten, berichtigen Sie sie und fahren im Build-Prozess fort. Ist der Build nicht möglich, senden Sie eine ausführliche E-Mail an , um sich Hilfe zu holen.

25.1.2.4.2.4. Bauen von gemeinsam genutzten (shared) Bibliotheken

Auf den meisten Plattformen werden .so (shared) Client-Bibliotheken standardmäßig nicht gebaut oder unterstützt. Grund dafür sind die schlechten Erfahrungen, die wir beim Erstellen von Shared Libraries gemacht haben.

In solchen Fällen müssen Sie die MySQL-Distribution herunterladen und mit folgenden Optionen konfigurieren:

--without-server --enable-shared

Um den Treiber mit Shared Libraries zu erstellen, müssen Sie die Option --enable-shared für configure angeben. Standardmäßig ist diese Option für configure nicht aktiviert.

Wenn Sie den Treiber mit --disable-shared konfiguriert haben, können Sie aus den statischen Bibliotheken die .so-Datei mit folgenden Befehlen erstellen:

shell> cd MyODBC-3.51.01
shell> make
shell> cd driver
shell> CC=/usr/bin/gcc \
          $CC -bundle -flat_namespace -undefined error \
          -o .libs/libmyodbc3-3.51.01.so \
          catalog.o connect.o cursor.o dll.o error.o execute.o \
          handle.o info.o misc.o myodbc3.o options.o prepare.o \
          results.o transact.o utility.o \
          -L/usr/local/mysql/lib/mysql/ \
          -L/usr/local/iodbc/lib/ \
          -lz -lc -lmysqlclient -liodbcinst

Aus -liodbcinst müssen Sie -lodbcinst machen, wenn Sie unixODBC anstelle von iODBC nutzen. Die Bibliothekspfade müssen Sie dann auch entsprechend konfigurieren.

So wird die Datei libmyodbc3-3.51.01.so erstellt und in das Verzeichnis .libs gelegt. Diese Datei kopieren Sie in das Installationsverzeichnis der MyODBC-Bibliotheken (/usr/local/lib) oder in das lib-Verzeichnis unter dem Installationsverzeichnis, das Sie mit --prefix vorgegeben haben.

shell> cd .libs
shell> cp libmyodbc3-3.51.01.so /usr/local/lib
shell> cd /usr/local/lib
shell> ln -s libmyodbc3-3.51.01.so libmyodbc3.so

Die Thread-sichere Treiberbibliothek bauen Sie mit:

shell> CC=/usr/bin/gcc \
          $CC -bundle -flat_namespace -undefined error
          -o .libs/libmyodbc3_r-3.51.01.so
          catalog.o connect.o cursor.o dll.o error.o execute.o
          handle.o info.o misc.o myodbc3.o options.o prepare.o
          results.o transact.o utility.o
          -L/usr/local/mysql/lib/mysql/
          -L/usr/local/iodbc/lib/
          -lz -lc -lmysqlclient_r -liodbcinst
25.1.2.4.2.5. Installation der Treiberbibliotheken

Mit folgendem Befehl installieren Sie die Treiberbibliotheken:

shell> make install

Damit wird eines der folgenden Bibliotheken-Sets installiert:

Für MyODBC 3.51:

  • libmyodbc3.so

  • libmyodbc3-3.51.01.so, wobei 3.51.01 die Treiberversion ist

  • libmyodbc3.a

Für Thread-sicheres MyODBC 3.51:

  • libmyodbc3_r.so

  • libmyodbc3-3_r.51.01.so

  • libmyodbc3_r.a

Für MyODBC 2.5.0:

  • libmyodbc.so

  • libmyodbc-2.50.39.so, wobei 2.50.39 die Treiberversion ist

  • libmyodbc.a

Mehr über den Build-Prozess erfahren Sie in der Datei INSTALL, die mit der Quelldistribution mitgeliefert wird. Achtung: Wenn Sie den make-Befehl von Sun verwenden, können Fehler entstehen. Das gmake von GNU dagegen müsste auf allen Plattformen funktionieren.

25.1.2.4.2.6. Testen von MyODBC unter Unix

Um die einfachen Beispiele in der von Ihnen gebauten Distribution mit den Bibliotheken auszuführen, geben Sie folgenden Befehl ein:

shell> make test

Ehe Sie Tests laufen lassen, legen Sie den DSN 'myodbc3' in odbc.ini an und stellen die Umgebungsvariable ODBCINI auf die korrekte odbc.ini-Datei ein. Dann läuft der MySQL Server. Eine odbc.ini-Beispieldatei wird mit der Treiberdistribution mitgeliefert.

Sie können das Skript samples/run-samples auch so umschreiben, dass es die gewünschten DSN-, UID- und PASSWORD-Werte als Kommandozeilenargumente für jedes Beispiel übergibt.

25.1.2.4.2.7. Bauen von MyODBC aus dem Quellcode unter Mac OS X

Um den Treiber auf Mac OS X (Darwin) zu erstellen, verwenden Sie folgendes configure-Beispiel:

shell> ./configure --prefix=/usr/local
          --with-unixODBC=/usr/local
          --with-mysql-path=/usr/local/mysql
          --disable-shared
          --enable-gui=no
          --host=powerpc-apple

Dieser Befehl setzt voraus, dass unixODBC und MySQL in den Standardverzeichnissen installiert wurden. Ist dies nicht der Fall, müssen Sie die Konfiguration entsprechend ändern.

Auf Mac OS X werden mit der Option --enable-shared die .dylib-Dateien standardmäßig erstellt. Die .so-Dateien können Sie folgendermaßen bauen:

shell> make
shell> cd driver
shell> CC=/usr/bin/gcc \
          $CC -bundle -flat_namespace -undefined error
          -o .libs/libmyodbc3-3.51.01.so *.o
          -L/usr/local/mysql/lib/
          -L/usr/local/iodbc/lib
          -liodbcinst -lmysqlclient -lz -lc

Die Thread-sichere Treiberbibliothek bauen Sie mit:

shell> CC=/usr/bin/gcc \
          $CC -bundle -flat_namespace -undefined error
          -o .libs/libmyodbc3-3.51.01.so *.o
          -L/usr/local/mysql/lib/
          -L/usr/local/iodbc/lib
          -liodbcinst -lmysqlclienti_r -lz -lc -lpthread

Aus -liodbcinst müssen Sie -lodbcinst machen, wenn Sie unixODBC anstelle von iODBC nutzen. Die Bibliothekspfade müssen Sie dann auch entsprechend konfigurieren.

In der Apple-Version von GCC sind cc und gcc in Wirklichkeit symbolische Links zu gcc3.

Kopieren Sie diese Bibliothek in das Verzeichnis $prefix/lib und richten Sie einen symbolischen Link auf libmyodbc3.so ein.

Mit folgendem Befehl überprüfen Sie die Ausgabeeigenschaften für die gemeinsam genutzten Bibliotheken:

shell> otool -LD .libs/libmyodbc3-3.51.01.so
25.1.2.4.2.8. Bauen von MyODBC aus dem Quellcode unter HP-UX

Zur Erstellung des Treibers auf HP-UX 10.x or 11.x nutzen Sie folgendes configure-Beispiel:

Wenn cc verwendet wird:

shell> CC="cc" \
          CFLAGS="+z" \
          LDFLAGS="-Wl,+b:-Wl,+s" \
          ./configure --prefix=/usr/local
          --with-unixodbc=/usr/local
          --with-mysql-path=/usr/local/mysql/lib/mysql
          --enable-shared
          --enable-thread-safe

Wenn gcc verwendet wird:

shell> CC="gcc" \
          LDFLAGS="-Wl,+b:-Wl,+s" \
          ./configure --prefix=/usr/local
          --with-unixodbc=/usr/local
          --with-mysql-path=/usr/local/mysql
          --enable-shared
          --enable-thread-safe

Haben Sie den Treiber gebaut, so überprüfen Sie seine Attribute mit chatr .libs/libmyodbc3.sl, um festzustellen, ob der Pfad der MySQL-Clientbibliothek mit der Umgebungsvariablen SHLIB_PATH hätte eingestellt werden müssen. Bei statischen Versionen können Sie alle Optionen, die gemeinsam genutzte Bibliotheken betreffen, ignorieren und configure mit der --disable-shared-Option laufen lassen.

25.1.2.4.2.9. MyODBC unter AIX aus dem Quellcode bauen

Um den Treiber auf AIX zu bauen, gehen Sie nach folgendem configure-Beispiel vor:

shell> ./configure --prefix=/usr/local
          --with-unixodbc=/usr/local
          --with-mysql-path=/usr/local/mysql
          --disable-shared
          --enable-thread-safe

Hinweis: Weitere Informationen über das Bauen und Einrichten statischer und gemeinsam genutzter Bibliotheken auf unterschiedlichen Plattformen finden Sie unter Using static and shared libraries across platforms'.

25.1.2.4.3. Installation von MyODBC aus dem Entwicklungsquellbaum

Achtung: Bitte lesen Sie den folgenden Abschnitt nur dann, wenn Sie daran interessiert sind, uns zu helfen oder Code zu testen. Wenn Sie MySQL Connector/ODBC lediglich auf Ihrem System ans Laufen bringen möchten, benutzen Sie bitte eine Standard-Release-Distribution.

Um auf den Quellbaum von MyODBC zugreifen zu können, müssen Sie Subversion installiert haben. Subversion ist kostenlos unter http://subversion.tigris.org/ erhältlich.

Folgende Tools sind erforderlich, um MyODBC von den Quellbäumen erstellen zu können:

  • autoconf 2.52 (oder neuer)

  • automake 1.4 (oder neuer)

  • libtool 1.4 (oder neuer)

  • m4

Den aktuellsten Quellbaum in der Entwicklung finden Sie unter unseren öffentlichen Subversion-Bäumen unter http://dev.mysql.com/tech-resources/sources.html.

Um die Connector/ODBC-Quelldateien auszuchecken, gehen Sie in das Verzeichnis, in welches Sie den zu speichernden MyODBC-Baum kopieren möchten, und geben folgenden Befehl ein:

shell> svn co http://svn.mysql.com/svnpublic/connector-odbc3

Danach dürfte eine Kopie des gesamten MyODBC-Quellbaums im Verzeichnis connector-odbc3 vorliegen. Auf Unix oder Linux erstellen Sie den Build aus diesen Quelldateien wie folgt:

shell> cd connector-odbc3
shell> aclocal
shell> autoheader
shell> autoconf
shell> automake;
shell> ./configure  # Hier geben Sie Ihre Optionen an
shell> make

Weitere Informationen über den Build finden Sie in der Datei INSTALL, die in demselben Verzeichnis liegt. Über configure-Optionen können Sie unter Abschnitt 25.1.2.4.2.1, „Typische configure-Optionen“, Genaueres erfahren.

Nach dem Build führen Sie make install aus, um den MyODBC 3.51-Treiber auf Ihrem System zu installieren.

Wenn Sie bis make vorgedrungen sind, aber die Distribution sich nicht kompilieren lässt, schicken Sie bitte einen Bericht an .

Auf Windows können Sie zur Erstellung des Treibers die Windows-Makefiles WIN-Makefile und WIN-Makefile_debug benutzen. Weiteres erfahren Sie unter Abschnitt 25.1.2.4.1, „Installation von MyODBC aus einer Quelldistribution unter Windows“.

Nach dem ersten Auschecken, mit dem Sie den Quellbaum heruntergeladen haben, sollten Sie regelmäßig svn update laufen lassen, um Ihre Quelldateien mit den neuesten Versionen zu aktualisieren.

25.1.3. MyODBC: Konfiguration

Bevor Sie eine Verbindung zu einer MySQL-Datenbank über den MyODBC-Treiber einrichten können, müssen Sie einen ODBC-Data Source Name (DSN) konfigurieren. Der DSN verbindet die diversen Konfigurationsparameter, die zur Kommunikation mit einer Datenbank erforderlich sind, mit einem bestimmten Namen. Um mit der Datenbank zu kommunizieren, verwenden Sie in einer Anwendung den DSN, anstatt die einzelnen Parameter in der Anwendung selbst zu konfigurieren. DSN-Informationen können benutzer- oder systemspezifisch sein, oder sie können in einer gesonderten Datei angegeben werden. Die Namen der ODBC-Datenquellen werden je nach Plattform und ODBC-Treiber unterschiedlich konfiguriert.

25.1.3.1. Namen für Datenquellen (DSN)

Mit einem Data Source Name sind die Konfigurationsparameter für die Kommunikation mit einer bestimmten Datenbank verbunden. Normalerweise besteht ein DSN aus folgenden Parametern:

  • Name
  • Hostname
  • Datenbankname
  • Login-Name
  • Passwort

Zusätzlich können verschiedene ODBC-Treiber, darunter auch MyODBC, weitere treiberspezifische Optionen und Parameter haben.

Es gibt drei DSN-Typen:

  • Ein System-DSN ist eine globale DSN-Definition, die jedem Benutzer und jeder Anwendung auf einem bestimmten System zur Verfügung steht. Ein System-DSN kann normalerweise nur von einem Systemadministrator konfiguriert werden, oder aber von einem Benutzer, der die speziellen Berechtigungen zur Erstellung von System-DSNs hat.

  • Ein User-DSN ist für einen einzelnen Benutzer spezifisch und dient der Speicherung von Datenbankverbindungsinformationen, die dieser Benutzer regelmäßig verwendet.

  • Ein File-DSN definiert die DSN-Konfiguration in einer einfachen Datei. File-DSNs können von Benutzern und Computern gemeinsam genutzt werden und sind daher praktischer, wenn DSN-Informationen als Teil einer Anwendung auf mehreren Computern installiert oder verteilt werden sollen.

DSN-Informationen werden je nach Plattform und Umgebung an unterschiedlichen Speicherorten abgelegt.

25.1.3.2. Konfiguration einer MyODBC-DSN unter Windows

Mit dem ODBC-Datenquellen-Administrator von Windows können Sie DSNs anlegen, die Treiberinstallation überprüfen und ODBC-Systeme wie etwa Tracing (Ablaufverfolgung, dient dem Debugging) und Verbindungspooling einrichten.

Verschiedene Ausgaben und Versionen von Windows speichern den ODBC-Datenquellen-Administrator an verschiedenen Orten, je nach der verwendeten Windows-Version.

Den ODBC-Datenquellen-Administrator in Windows Server 2003 öffnen:

  1. Wählen Sie im Startmenü Verwaltung und klicken Sie auf Datenquellen (ODBC).

Den ODBC-Datenquellen-Administrator in Windows 2000 Server oder Windows 2000 Professional öffnen:

  1. Wählen Sie im Startmenü Einstellungen und klicken Sie auf Systemsteuerung.

  2. In der Systemsteuerung klicken Sie auf Verwaltung.

  3. In der Verwaltung klicken Sie auf Datenquellen (ODBC).

Den ODBC-Datenquellen-Administrator in Windows XP öffnen:

  1. Klicken Sie im Startmenü auf Systemsteuerung.

  2. In der Systemsteuerung klicken Sie, wenn die Kategorienansicht eingestellt ist, auf Leistung und Wartung und dann auf Verwaltung. Wenn Sie die Klassische Ansicht für die Systemsteuerung eingestellt haben, klicken Sie hier direkt auf Verwaltung.

  3. In der Verwaltung klicken Sie auf Datenquellen (ODBC).

Unabhängig von der Windows-Version müssten Sie nun das Fenster des ODBC-Datenquellen-Administrators vor sich sehen:

ODBC-Datenquellen-Administrator-Dialog

In Windows XP können Sie den Ordner Verwaltung Ihrem Startmenü hinzufügen, um den ODBC-Datenquellen-Administrator später leichter finden zu können:

  1. Klicken Sie mit rechts auf die Schaltfläche Start.

  2. Wählen Sie Eigenschaften.

  3. Klicken Sie auf Anpassen....

  4. Wählen Sie die Registerkarte Erweitert.

  5. Markieren Sie unter Startmenüelemente im Abschnitt Systemverwaltung den Punkt Im Menü "Alle Programme" anzeigen.

In Windows Server 2003 und Windows XP können Sie den ODBC-Datenquellen-Administrator auch dauerhaft Ihrem Startmenü hinzufügen. Hierzu suchen Sie wie oben beschrieben das Symbol Datenquellen (ODBC), klicken mit rechts darauf und wählen dann An Startmenü anheften.

25.1.3.2.1. Einen MyODBC-DSN auf Windows einrichten

Zum Hinzufügen und Konfigurieren einer neuen MyODBC-Datenquelle auf Windows benutzen Sie den ODBC-Datenquellen-Administrator:

  1. Öffnen Sie den ODBC-Datenquellen-Administrator.

  2. Um einen System-DSN hinzuzufügen (der allen Benutzern zugänglich ist), wählen Sie die Registerkarte System DSN. Einen Benutzer-DSN, der ausschließlich für den aktuellen Benutzer zur Verfügung steht, erstellen Sie mit einem Klick auf Hinzufügen....

  3. Sie müssen den ODBC-Treiber für diesen DSN auswählen.

    MySQL ODBC Driver
                Selection-Dialog

    Wählen Sie MySQL ODBC 3.51 Driver und klicken Sie dann auf Finish.

  4. Nun müssen Sie noch die spezifischen Felder für den DSN im Dialog Add Data Source Name anlegen.

    Add Data Source
                Name-Dialog

    Im Feld Data Source Name geben Sie den Namen der Datenquelle ein, auf die Sie zugreifen möchten. Das kann jeder gültige Name Ihrer Wahl sein.

  5. In das Feld Description geben Sie einen Text ein, der dabei hilft, die Verbindung zu identifizieren.

  6. In das Feld Server geben Sie den Namen des MySQL Serverhosts ein, auf den Sie zugreifen möchten. Nach Voreinstellung ist dies localhost.

  7. In das Feld User geben Sie den Benutzernamen für diese Verbindung ein.

  8. In das Feld Password geben Sie das Passwort für diese Verbindung ein.

  9. Im Popup-Fenster Database müsste automatisch eine Liste der Datenbanken erscheinen, auf die der Benutzer ein Zugriffsrecht hat.

  10. Mit einem Klick auf OK wird der DSN gespeichert.

Eine vollständige DSN-Konfiguration kann folgendermaßen aussehen:

Beispiel: MySQL ODBC DSN
            Configuration-Dialog
25.1.3.2.2. MyODBC-DSN-Konfiguration auf Windows überprüfen

Um die Verbindung mit den von Ihnen eingegebenen Parametern zu überprüfen, klicken Sie auf Test. Lässt sich die Verbindung problemlos einrichten, erscheint ein Dialog mit der Meldung Success; connection was made! (abhängig von den Spracheinstellungen auch auf Deutsch).

Wenn die Verbindung nicht zustande kam, können Sie Informationen über den Test und die Gründe seines Scheiterns mit einem Klick auf Diagnostics einholen. Es werden dann zusätzliche Fehlermeldungen angezeigt.

25.1.3.2.3. MyODBC-DSN-Konfigurationsoptionen

Sie können eine Reihe von Optionen für einen konkreten DSN einstellen, indem Sie im DSN-Konfigurationsdialog entweder eine der Registerkarten Connect Options oder Advanced anklicken.

Den Dialog Connect Options sehen Sie unten.

MyODBC-Verbindungsoptionen

Folgende drei Optionen können konfiguriert werden:

  • Port ist die Nummer des TCP/IP-Ports, der zur Kommunikation mit MySQL genutzt wird. Normalerweise wird nach Voreinstellung der Port 3306 verwendet. Wenn für Ihren Server ein anderer TCP/IP-Port konfiguriert ist, müssen Sie dessen Portnummer hier angeben.

  • Socket stellt den Namen oder Ort eines bestimmten Sockets oder einer Windows-Pipe ein, die für die Kommunikation mit MySQL benutzt wird.

  • Initial Statement definiert eine SQL-Anweisung, die beim Aufbau einer Verbindung zu MySQL ausgeführt wird. Das können Sie nutzen, um MySQL-Optionen für Ihre Verbindung anzugeben, etwa den Standardzeichensatz oder die Datenbank, die für diese Verbindung verwendet werden soll.

Auf der Registerkarte Advanced können Sie MyODBC-Verbindungsparameter einstellen. Informationen über die Bedeutung dieser Optionen finden Sie unter Abschnitt 25.1.3.5, „MyODBC: Verbindungsparameter“.

MyODBC: Erweiterter
            Verbindungsdialog
25.1.3.2.4. Fehler und ihre Behebung

Dieser Abschnitt beantwortet Fragen im Zusammenhang mit MyODBC-Verbindungen.

  • Beim Konfigurieren eines MyODBC-DSN tritt der Fehler Could Not Load Translator or Setup Library auf

    Weitere Informationen finden Sie im MS Knowledge Base Article(Q260558) . Bitte stellen Sie außerdem sicher, dass Sie die neueste gültige ctl3d32.dll in Ihrem Systemverzeichnis haben.

  • Auf Windows wird für eine optimale Performance die myodbc3.dll kompiliert. Wenn Sie MyODBC 3.51 debuggen möchten (etwa um Tracing zu ermöglichen), sollten Sie stattdessen myodbc3d.dll verwenden. Um diese Datei zu installieren, kopieren Sie myodbc3d.dll über die installierte myodbc3.dll-Datei. Achten Sie darauf, die Treiber-DLL auf die Release-Version zurückzustellen, wenn Sie mit dem Debuggen fertig sind, da die Debugging-Version Leistungsprobleme verursachen kann. Beachten Sie, dass die myodbc3d.dll-Datei in den MyODBC-Versionen 3.51.07 bis 3.51.11 nicht inbegriffen ist. Wenn Sie eine dieser Versionen benutzen, müssen Sie die DLL aus einer Vorversion herüberkopieren (zum Beispiel aus 3.51.06).

    Für MyODBC 2.50 werden stattdessen myodbc.dll und myodbcd.dll verwendet.

25.1.3.3. Konfiguration einer MyODBC-DSN unter Mac OS X

Um einen DSN unter Mac OS X zu konfigurieren, verwenden Sie den ODBC Administrator. Arbeiten Sie mit Mac OS X 10.2 oder älter, schauen Sie in Abschnitt 25.1.3.4, „Konfiguration einer MyODBC-DSN unter Unix“. Bitte wählen Sie aus, ob Sie einen User DSN oder einen System DSN anlegen möchten. Wenn Sie einen System DSN wollen, müssen Sie sich unter Umständen authentifizieren. Hierzu klicken Sie auf das Vorhängeschlosssymbol und geben einen Benutzernamen und ein Passwort mit Administratorrechten an.

  1. Öffnen Sie den ODBC Administrator im Utilities-Ordner im Verzeichnis Applications.

    ODBC Administrator Main
              Panel-Dialog
  2. Klicken Sie unter User DSN oder System DSN auf Add.

  3. Wählen Sie den MyODBC-Treiber und klicken Sie auf OK.

  4. Nun sehen Sie das Dialogfeld Data Source Name. Geben Sie hier den Data Source Name und eine optionale Beschreibung in das Feld Description für den DSN ein.

    ODBC Administrator Add
                DSN-Dialog

  5. Mit einem Klick auf Add fügen Sie dem Panel ein neues Schlüsselwort/Wert-Paar hinzu. Sie sollten mindestens vier solcher Paare konfigurieren, nämlich für die Verbindungsparameter server, username, password und database. Siehe Abschnitt 25.1.3.5, „MyODBC: Verbindungsparameter“.

  6. Mit einem Klick auf OK fügen Sie den DSN der Liste der konfigurierten Datenquellennamen hinzu.

Eine vollständige DSN-Konfiguration sieht in etwa folgendermaßen aus:

ODBC Administrator Sample
          DSN-Dialog

Sie können auch noch weitere ODBC-Optionen für Ihren DSN einrichten, indem Sie weitere Schlüsselwort/Wert-Paare anlegen und die entsprechenden Werte einstellen. Siehe hierzu Abschnitt 25.1.3.5, „MyODBC: Verbindungsparameter“.

25.1.3.4. Konfiguration einer MyODBC-DSN unter Unix

Unter Unix konfigurieren Sie DSN-Einträge direkt in der Datei odbc.ini. Hier sehen Sie eine typische odbc.ini-Datei, die myodbc und myodbc3 als DSN-Namen für MyODBC 2.50 und MyODBC 3.51 einrichtet:

;
;  odbc.ini configuration for MyODBC and MyODBC 3.51 drivers
;

[ODBC Data Sources]
myodbc      = MyODBC 2.50 Driver DSN
myodbc3     = MyODBC 3.51 Driver DSN

[myodbc]
Driver       = /usr/local/lib/libmyodbc.so
Description  = MyODBC 2.50 Driver DSN
SERVER       = localhost
PORT         =
USER         = root
Password     =
Database     = test
OPTION       = 3
SOCKET       =

[myodbc3]
Driver       = /usr/local/lib/libmyodbc3.so
Description  = MyODBC 3.51 Driver DSN
SERVER       = localhost
PORT         =
USER         = root
Password     =
Database     = test
OPTION       = 3
SOCKET       =

[Default]
Driver       = /usr/local/lib/libmyodbc3.so
Description  = MyODBC 3.51 Driver DSN
SERVER       = localhost
PORT         =
USER         = root
Password     =
Database     = test
OPTION       = 3
SOCKET       =

In Abschnitt 25.1.3.5, „MyODBC: Verbindungsparameter“, sind die möglichen Verbindungsparameter aufgelistet.

Hinweis: Wenn Sie unixODBC benutzen, können Sie den DSN mit folgenden Tools einrichten:

Gelegentlich tritt bei unixODBC folgender Fehler auf:

Data source name not found and no default driver specified

Wenn dies geschieht, müssen Sie sich vergewissern, dass die Umgebungsvariablen ODBCINI und ODBCSYSINI auf die richtige odbc.ini-Datei verweisen. Wenn beispielsweise Ihre odbc.ini-Datei unter /usr/local/etc liegt, müssen die Umgebungsvariablen folgendermaßen gesetzt werden:

export ODBCINI=/usr/local/etc/odbc.ini
export ODBCSYSINI=/usr/local/etc

25.1.3.5. MyODBC: Verbindungsparameter

Sie können die Parameter aus den folgenden Tabellen für MyODBC verwenden, wenn Sie einen DSN konfigurieren. Windows-Benutzer können diese Parameter bei der DSN-Konfiguration in den Feldern Optionen und Erweitert angeben. Welche Optionen für welche Felder und Kontrollkästchen da sind, ist der Tabelle zu entnehmen. Auf Unix und Mac OS X verwenden Sie den Parameternamen und -wert als Schlüsselwort/Wert-Paar. Alternativ können Sie diese Parameter in dem InConnectionString-Argument im Aufruf von SQLDriverConnect() einstellen.

ParameterStandardwertBemerkungen
userODBC (auf Windows)Der Benutzername für die MySQL-Verbindung.
serverlocalhostDer Hostname des MySQL Servers.
database Die Standarddatenbank.
option0Optionen für die Arbeitsweise von MyODBC. Siehe unten.
port3306Der TCP/IP-Port, der verwendet wird, wenn server nicht localhost ist.
stmt Eine Anweisung, die bei einer MySQL-Verbindung ausgeführt wird.
password Das Passwort für den user-Account auf dem server.
socket Die Unix-Socketdatei oder die Named Pipe von Windows, die für die Verbindung verwendet wird, wenn server der localhost ist.

Das Argument option teilt MyODBC mit, dass der Client nicht absolut ODBC-fähig ist. Auf Windows wählt man Optionen normalerweise aus, indem man die Kontrollkästchen im Verbindungsbildschirm markiert, aber ebenso gut kann man sie auch mit dem option-Argument angeben. Die folgenden Optionen werden in derselben Reihenfolge wie auf dem MyODBC-Verbindungsbildschirm aufgeführt:

WertWindows-KontrollkästchenBeschreibung
1Don't Optimized Column WidthDer Client kann nicht damit umgehen, dass MyODBC die echte Breite einer Spalte zurückgibt.
2Return Matching RowsDer Client kann nicht damit umgehen, dass MySQL den wirklichen Wert der betroffenen Zeilen zurückgibt. Wenn dieses Flag gesetzt ist, liefert MySQL stattdessen die „gefundenen Zeilen“. Damit dies funktioniert, benötigen Sie MySQL 3.21.14 oder höher.
4Trace Driver Calls To myodbc.logErstellt ein Debuglog in C:\myodbc.log auf Windows bzw. in /tmp/myodbc.log auf Unix-Varianten.
8Allow Big ResultsEs wird keine Größenbegrenzung für Ergebnisse und Parameter eingestellt.
16Don't Prompt Upon ConnectNicht zu Fragen auffordern, selbst wenn der Treiber dies tun würde.
32Enable Dynamic CursorAktiviert oder deaktiviert Unterstützung für dynamische Cursors. (Unzulässig in MyODBC 2.50.)
64Ignore # in Table NameIgnoriert Datenbanknamen in db_name.tbl_name.col_name.
128User Manager CursorsErzwingt Benutzung von ODBC-Manager-Cursors (experimentell).
256Don't Use Set LocaleDeaktiviert die Nutzung erweiterter Fetch-Operationen (experimentell).
512Pad Char To Full LengthCHAR-Spalten werden auf die volle Spaltenlänge aufgefüllt.
1024Return Table Names for SQLDescribeColSQLDescribeCol() gibt voll qualifizierte Spaltennamen zurück.
2048Use Compressed ProtocolVerwendet das komprimierte Client/Server-Protokoll.
4096Ignore Space After Function NamesLässt den Server Leerraum zwischen Funktionsname und ‘ (’ ignorieren (nötig für PowerBuilder). Macht alle Funktionsnamen zu Schlüsselwörtern.
8192Force Use of Named PipesVerbindung über Named Pipes mit einem mysqld-Server, der auf NT läuft.
16384Change BIGINT Columns to IntWandelt BIGINT-Spalten in INT-Spalten um (manche Anwendungen können mit BIGINT nicht umgehen).
32768No Catalog (exp)Gibt 'user' als Table_qualifier und Table_owner von SQLTables zurück (experimentell).
65536Read Options From my.cnfLiest Parameter aus den Gruppen [client] und [odbc] in my.cnf.
131072SafeFügt einige zusätzliche Sicherheitsprüfungen hinzu (eigentlich unnötig, aber ...).
262144Disable transactionDeaktiviert Transaktionen.
524288Save queries to myodbc.sqlErmöglicht Anweisungs-Logging in der Datei c:\myodbc.sql(/tmp/myodbc.sql) (nur im Debug-Modus aktiviert)
1048576Don't Cache Result (forward only cursors)Ergebnisse werden nicht lokal im Treiber zwischengespeichert, sondern vom Server gelesen (mysql_use_result()). Das geht nur bei Forward-only-Cursors. Diese Option ist wichtig für den Umgang mit großen Tabellen, wenn der Treiber nicht die ganze Ergebnismenge speichern soll.
2097152Force Use Of Forward Only CursorsErzwingt Forward-only-Cursors. Wenn Anwendungen den Standard-Cursor-Typ static/dynamic einstellen, aber der Treiber Ergebnismengen nicht im Cache speichern soll, gewährleistet diese Option das gewünschte Forward-only-Cursor-Verhalten.

Um mehrere Optionen auszuwählen, addieren Sie ihre Werte. Wenn Sie beispielsweise option auf 12 (4+8) setzen, bedeutet das Debugging ohne Paketlimits.

Die folgende Tabelle zeigt einige empfohlene option-Werte für unterschiedliche Konfigurationen:

KonfigurationOptionswert
Microsoft Access, Visual Basic3
Treiber-Tracing (Debug-Modus)4
Microsoft Access (mit verbesserten DELETE-Anfragen)35
Große Tabellen mit zu vielen Zeilen2049
Sybase PowerBuilder135168
Query-Logging (Debug-Modus)524288
Treiber-Tracing und Query-Logging (Debug-Modus)524292
Große Tabellen ohne Ergebnis-Caching3145731

25.1.3.6. Verbinden ohne vordefinierte DSN

Eine Verbindung zum MySQL Server können Sie mit SQLDriverConnect unter Angabe des DRIVER-Namens herstellen. Die folgenden Verbindungs-Strings gelten für MyODBC mit DSN-Less-Verbindungen:

Für MyODBC 2.50:

ConnectionString = "DRIVER={MySQL};\
                   SERVER=localhost;\
                   DATABASE=test;\
                   USER=venu;\
                   PASSWORD=venu;\
                   OPTION=3;"

Für MyODBC 3.51:

ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver};\
                   SERVER=localhost;\
                   DATABASE=test;\
                   USER=venu;\
                   PASSWORD=venu;\
                   OPTION=3;"

Wenn Ihre Programmiersprache Backslashes mit nachfolgendem Whitespace in ein Leerzeichen umwandelt, sollte der Verbindungs-String besser als ein einziger langer String oder als mehrere verkettete Strings ohne Leerraum dazwischen angegeben werden:

ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver};"
                   "SERVER=localhost;"
                   "DATABASE=test;"
                   "USER=venu;"
                   "PASSWORD=venu;"
                   "OPTION=3;"

Unter Abschnitt 25.1.3.5, „MyODBC: Verbindungsparameter“, finden Sie die möglichen Verbindungsparameter.

25.1.3.7. ODBC: Verbindungspooling

Verbindungspooling versetzt den ODBC-Treiber in die Lage, vorhandene Verbindungen zu einer gegebenen Datenbank aus einem Pool von Verbindungen wiederzuverwenden, anstatt sie bei jedem Zugriff auf die betreffende Datenbank wieder neu aufzubauen. Durch Verbindungspooling können Sie also die gesamte Leistung Ihrer Anwendung verbessern, da es weniger lange dauert, eine Verbindung zu einer im Pool befindlichen Datenbank zu öffnen.

Mehr über Verbindungspooling erfahren Sie unter http://support.microsoft.com/default.aspx?scid=kb;EN-US;q169470.

25.1.3.8. Erzeugen einer ODBC-Trace-Datei

Wenn Sie Schwierigkeiten oder Probleme mit MyODBC haben, erstellen Sie als Erstes eine Logdatei aus dem ODBC Manager und MyODBC. Dieses als Tracing bezeichnete Vorgehen wird durch den ODBC Manager ermöglicht. Tracing wird auf Windows, Mac OS X und Unix in unterschiedlicher Weise eingeschaltet.

25.1.3.8.1. Anschalten von ODBC-Tracing unter Windows

Trace-Option auf Windows aktivieren:

  1. Über die Registerkarte Tracing des Dialogfelde ODBC Data Source Administrator können Sie einstellen, wie ODBC-Funktionsaufrufe nachverfolgt werden.

    Tracing im
                ODBC-Datenquellen-Administrator
  2. Wenn Sie auf der Registerkarte Tracing das Tracing eingeschaltet haben, protokolliert der Treiber-Manager alle ODBC-Funktionsaufrufe für alle in der Folgezeit ausgeführten Anwendungen.

  3. ODBC-Funktionsaufrufe für Anwendungen, die vor Einschaltung des Tracings ausgeführt wurden, werden nicht protokolliert. Die ODBC-Funktionsaufrufe werden in einer von Ihnen vorgegebenen Logdatei festgehalten.

  4. Das Tracing hört erst auf, nachdem Sie auf Stop tracing now geklickt haben. Vergessen Sie nicht: Während das Tracing läuft, wächst die Logdatei immer weiter an. Überdies beeinträchtigt das Tracing die Leistung aller Ihrer ODBC-Anwendungen.

25.1.3.8.2. Anschalten von ODBC-Tracing unter Mac OS X

Um die Trace-Option unter Mac OS X 10.3 oder höher zu aktivieren, nutzen Sie die Registerkarte Tracing im ODBC Administrator .

  1. Öffnen Sie den ODBC Administrator.

  2. Wählen Sie die Registerkarte Tracing.

    Tracing-Dialog im ODBC
                Administrator
  3. Markieren Sie das Kontrollkästchen Enable Tracing.

  4. Geben Sie an, wo das Tracing-Log gespeichert werden soll. Wenn Sie die Daten an eine vorhandene Logdatei anfügen möchten, klicken Sie auf die Schaltfläche Choose....

25.1.3.8.3. Anschalten von ODBC-Tracing unter Unix

Um die Trace-Option unter Mac OS X 10.2 (oder früher) oder unter Unix einzuschalten, müssen Sie die trace-Option zur ODBC-Konfiguration hinzufügen:

  1. Unter Unix müssen Sie die Trace-Option explizit in die Datei ODBC.INI einfügen.

    Das Tracing setzen Sie auf ON oder OFF, indem Sie die Parameter TraceFile und Trace in odbc.ini wie folgt verwenden:

    TraceFile  = /tmp/odbc.trace
    Trace      = 1
    

    TraceFile gibt den Namen und vollständigen Pfad der Trace-Datei an und Trace wird auf ON oder OFF gesetzt. Sie können auch 1 oder YES für ON und 0 oder NO für OFF einsetzen. Wenn Sie ODBCConfig von unixODBC benutzen, müssen Sie die Tracing-Anleitung für unixODBC-Aufrufe unter HOWTO-ODBCConfig befolgen.

25.1.3.8.4. MyODBC-Log einschalten

Ein MyODBC-Log wird folgendermaßen erstellt:

  1. Unter Windows müssen Sie hierzu das Optionsflag Trace MyODBC im Bildschirm für die MyODBC-Verbindungs- und Konfigurationseinstellungen aktivieren. Das Log wird in die Datei C:\myodbc.log geschrieben. Wird die Trace-Option nicht berücksichtigt, wenn Sie zum obigen Bildschirm zurückkehren, so bedeutet dies, dass Sie nicht den myodbcd.dll-Treiber benutzen, siehe auch Abschnitt 25.1.3.2.4, „Fehler und ihre Behebung“.

    Wenn Sie Mac OS X, Unix oder eine Verbindung ohne DSN verwenden, müssen Sie im Verbindungs-String OPTION=4 angeben oder in den DSN das entsprechende Schlüsselwort/Wert-Paar aufnehmen.

  2. Starten Sie Ihre Anwendung und versuchen Sie, einen Absturz herbeizuführen. Dann schauen Sie in der MyODBC-Trace-Datei nach, was schief gegangen ist.

Wenn Sie Hilfe benötigen, um herauszufinden, wo das Problem liegt, schauen Sie in Abschnitt 25.1.7.1, „MyODBC: Community-Support“.

25.1.4. MyODBC-Beispiele

Wenn Sie einen DSN für den Zugriff auf eine Datenbank konfiguriert haben, hängt es von der jeweils verwendeten Anwendung oder Programmiersprache ab, wie diese Verbindung geöffnet und benutzt wird. Da ODBC eine standardisierte Schnittstelle ist, kann jede Anwendung oder Sprache, die ODBC unterstützt, den DSN nutzen und sich mit der konfigurierten Datenbank verbinden.

25.1.4.1. Grundlegende Schritte für die Verwendung von MyODBC für Applikationen

Anwendungen, die MyODBC benutzen, müssen Folgendes tun, um sich mit einem MySQL Server zu verbinden:

  • Den MyODBC-DSN konfigurieren

  • Verbindung zum MySQL Server aufbauen

  • Initialisierungsoperationen

  • SQL-Anweisungen ausführen

  • Ergebnisse abrufen

  • Transaktionen ausführen

  • Serververbindung trennen

Diese Schritte werden von den Anwendungen mit einigen Variationen ausgeführt. Das folgende Diagramm zeigt den grundsätzlichen Ablauf:

MyODBC-Programmierung:
          Flussdiagramm

25.1.4.2. Schritt-für-Schritt-Anleitung für das Verbinden zu einer MySQL-Datenbank mittels MyODBC

Eine typische Situation, in der MyODBC installiert würde, tritt ein, wenn man von einem Windows-Rechner aus auf eine Datenbank zugreifen möchte, die auf einem Linux- oder Unix-Host läuft.

Um ein Beispiel zu geben, wie man den Zugriff zwischen den beiden Computern einrichten könnte, zeigen wir im Folgenden die wichtigsten Schritte. Wir gehen davon aus, dass Sie sich vom System BETA aus mit dem Benutzernamen myuser und dem Passwort mypassword mit dem System ALPHA verbinden.

Auf dem System ALPHA (dem MySQL Server) sind folgende Schritte erforderlich:

  1. Sie starten den MySQL Server.

  2. Sie richten mit GRANT ein Konto mit dem Benutzernamen myuser ein, das sich vom System BETA aus mit dem Passwort myuser mit der Datenbank test verbinden darf:

    GRANT ALL ON test.* to 'myuser'@'BETA' IDENTIFIED BY 'mypassword';

    Genaueres über die Berechtigungen von MySQL lesen Sie unter Abschnitt 5.9, „MySQL-Benutzerkontenverwaltung“.

Auf dem System BETA (dem MyODBC-Client) gehen Sie folgendermaßen vor:

  1. Sie konfigurieren einen MyODBC-DSN mit den passenden Parametern für Server, Datenbank und Authentifizierungsdaten, wie Sie sie gerade auf dem System ALPHA eingerichtet haben.

    ParameterWertBemerkungen
    DSNremote_testDer Name der Verbindung
    SERVERALPHADie Adresse des Remote-Servers
    DATABASEtestDer Name der Standarddatenbank
    USERmyuserDer Benutzername, der für den Zugriff auf diese Datenbank konfiguriert wurde
    PASSWORDmypasswordDas Passwort für myuser
  2. Sie verbinden sich mit einer ODBC-fähigen Anwendung, wie etwa Microsoft Office, unter Verwendung des soeben angelegten DSN mit dem MySQL Server. Scheitert die Verbindung, so untersuchen Sie den Verbindungsprozess mit Tracing. Weitere Informationen finden Sie unter Abschnitt 25.1.3.8, „Erzeugen einer ODBC-Trace-Datei“.

25.1.4.3. MyODBC und ODBC-Werkzeuge von Drittanbietern

Wenn Sie Ihren MyODBC DSN konfiguriert haben, können Sie mit jeder Anwendung, die die ODBC-Schnittstelle unterstützt, auf die MySQL-Datenbank zugreifen, auch mit Programmiersprachen und Anwendungen von Drittanbietern. Dieser Abschnitt verrät Ihnen, wie man MyODBC mit verschiedenen ODBC-kompatiblen Tools und Anwendungen einsetzt, darunter Microsoft Word, Microsoft Excel und Adobe/Macromedia ColdFusion.

25.1.4.3.1. Applikationen, die mit MyODBC getestet wurden

MyODBC wurde mit folgenden Anwendungen getestet:

HerstellerAnwendungHinweise
AdobeColdFusionFrüher Macromedia ColdFusion
BorlandC++ Builder 
 Builder 4 
 Delphi 
Business ObjectsCrystal Reports 
ClarisFilemaker Pro 
CorelParadox 
Computer AssociatesVisual ObjectsAuch CAVO genannt
 AllFusion ERwin Data Modeler 
GuptaTeam DeveloperFrüher bekannt als Centura Team Developer; Gupta SQL/Windows
GensymG2-ODBC Bridge 
InlineiHTML 
LotusNotesVersionen 4.5 und 4.6
MicrosoftAccess 
 Excel 
 Visio Enterprise 
 Visual C++ 
 Visual Basic 
 ODBC.NETMit C#, Visual Basic, C++
 FoxPro 
 Visual Interdev 
OpenOffice.orgOpenOffice.org 
PerlDBD::ODBC 
Pervasive SoftwareDataJunction 
Sambar TechnologiesSambar Server 
SPSSSPSS 
SoftVelocityClarion 
SQLExpressSQLExpress for Xbase++ 
SunStarOffice 
SunSystemsVision 
SybasePowerBuilder 
 PowerDesigner 
theKompany.comData Architect 

Wenn Sie von anderen Anwendungen wissen, dass sie mit MyODBC funktionieren, melden Sie sie bitte per E-Mail an .

25.1.4.3.2. Verwendung von MyODBC mit Microsoft Word und Excel

Sie können Microsoft Word und Microsoft Excel nutzen, um auf Daten einer MySQL-Datenbank mithilfe von MyODBC zuzugreifen. In Microsoft Word ist diese Fähigkeit besonders nützlich, wenn Daten für einen Serienbrief importiert oder Tabellen und Daten in Reports eingebunden werden sollen. In Microsoft Excel können Sie Anfragen auf Ihrem MySQL Server verarbeiten und die Daten direkt in ein Excel-Arbeitsblatt importieren, wo sie dann in Form von Zeilen und Spalten dargestellt werden.

In beiden Anwendungen werden die Daten mit Microsoft Query abgefragt und importiert. Diese Anwendung kann eine Anfrage über eine ODBC-Quelle ausführen. Sie erstellen mit Microsoft Query die SQL-Anweisung, die ausgeführt werden soll, und wählen dabei die Tabellen, Felder, Auswahlkriterien und Sortierreihenfolge. Um beispielsweise Tabellendaten aus einer Tabelle der Testdatenbank World in ein Excel-Arbeitsblatt einzufügen und dazu die DSN-Beispiele aus Abschnitt 25.1.3, „MyODBC: Konfiguration“, zu verwenden, gehen Sie folgendermaßen vor:

  1. Sie legen ein neues Arbeitsblatt an.

  2. Sie wählen aus dem Menü Daten den Befehl Externe Daten importieren und dann Neue Abfrage erstellen.

  3. Microsoft Query fährt jetzt hoch. Als Erstes müssen Sie nun die Datenquelle auswählen, indem Sie einen vorhandenen Data Source Name aussuchen.

    Microsoft Query, Datenquelle
                auswählen
  4. Im Query-Assistenten müssen Sie die zu importierenden Spalten auswählen. Die Liste der Tabellen, die dem Benutzer über den konfigurierten DSN zur Verfügung stehen, wird links angezeigt, und die Spalten, die der Anfrage hinzugefügt werden, rechts. Die Spalten, die Sie wählen, entsprechen denen, die im ersten Abschnitt einer SELECT-Anfrage erscheinen. Klicken Sie auf Next, um fortzufahren.

    Microsoft Query, Spalten
                auswählen
  5. Die Spalten der Anfrage können Sie mit dem Filter Data -Dialog filtern (wie mit einer WHERE-Klausel) . Klicken Sie nun wieder auf Next.

    Microsoft Query, Daten
                filtern
  6. Wählen Sie eine (optionale) Sortierreihenfolge für die Daten. Dies entspricht einer ORDER BY-Klausel in einer SQL-Anfrage. Bis zu drei Felder können Sie auswählen, um die Rückgabedaten der Anfrage zu sortieren. Nun klicken Sie wieder auf Next.

    Microsoft Query,
                Sortierreihenfolge
  7. Nun wählen Sie das Zielobjekt für Ihre Anfrage, beispielsweise Microsoft Excel. Hier können Sie aussuchen, in welches Arbeitsblatt und welche Zelle die Daten eingefügt werden sollen. Sie können dann die Anfrage und Ergebnisse in Microsoft Query anzeigen lassen, wo Sie die SQL-Anfrage weiter bearbeiten und die Rückgabedaten weiter filtern und sortieren können; oder Sie erstellen aus der Anfrage einen OLAP Cube, der dann direkt in Microsoft Excel verwendet werden kann. Klicken Sie nun auf Finish.

    Microsoft Query, Zielobjekt
                auswählen

Mit demselben Verfahren können Sie Daten auch in ein Word-Dokument importieren, wo sie in Form einer Tabelle eingefügt werden. Dies kann für Serienbriefe genutzt werden (wo die Felddaten aus einer Word-Tabelle gelesen werden) oder auch zum Einbinden von Daten und Berichten in einen anderen Bericht oder ein Dokument.

25.1.4.3.3. Verwendung von MyODBC und Microsoft Access

Unter Verwendung von MyODBC können Sie MySQL-Datenbanken auch mit Microsoft Access benutzen. Die MySQL-Datenbank kann als Importquelle, als Exportquelle oder als verknüpfte Tabelle verwendet werden, die direkt in einer Access-Anwendung eingesetzt wird. So wird Access zu einem Frontend einer MySQL-Datenbank.

25.1.4.3.3.1. Export von Access-Daten nach MySQL

Um eine Tabelle mit Daten aus einer Access-Datenbank in MySQL zu importieren, verfahren Sie wie folgt:

  1. Wenn Sie eine Access-Datenbank oder ein Access-Projekt öffnen, erscheint ein Datenbankfenster. Hier können Sie mit Shortcuts neue Datenbankobjekte erzeugen oder vorhandene öffnen.

    Access-Datenbank
  2. Klicken Sie auf den Namen der zu exportierenden table oder query und wählen Sie dann im Menü Datei (File) den Befehl Exportieren (Export).

  3. Im Dialogfeld Export Object Type Objektname To wählen Sie im Feld Speichern unter (Save as) den Punkt ODBC Databases ():

    Auswahl einer
                  ODBC-Datenbank
  4. Im Dialogfeld Exportieren (Export) geben Sie einen Namen für die Datei ein (oder akzeptieren den Namensvorschlag) und wählen dann OK.

  5. Im Dialogfeld zur Auswahl der Datenquelle werden die definierten Datenquellen für alle auf Ihrem Computer installierten ODBC-Treiber aufgelistet. Klicken Sie hier auf die Registerkarte Dateidatenquelle oder Maschinendatenquelle und setzen Sie dann einen Doppelklick auf die MyODBC- oder MyODBC-3.51-Datenquelle, in die Sie Daten exportieren möchten. Wie eine neue Datenquelle für MyODBC definiert wird, erfahren Sie unter Abschnitt 25.1.3.2, „Konfiguration einer MyODBC-DSN unter Windows“.

Microsoft Access verbindet sich über diese Datenquelle mit dem MySQL Server und exportiert dann neue Tabellen und/oder Daten.

25.1.4.3.3.2. Importieren von MySQL-Daten in Access

Um einen Link oder eine oder mehrere Tabellen von MySQL in Access zu importieren, gehen Sie folgendermaßen vor:

  1. Sie öffnen eine Datenbank oder gehen in das Datenbankfenster und öffnen sie dort.

  2. Um Tabellen zu importieren, zeigen Sie im Datei-Menü auf Externe Daten abrufen und klicken dann auf Importieren. Um Tabellen zu verknüpfen, zeigen Sie im Dateimenü auf Externe Daten abrufen und klicken dann auf Tabellen verknüpfen.

  3. Im Dialogfeld Import (oder Verknüpfen) wählen Sie im Feld Dateityp den Eintrag ODBC Databases (). Das Dialogfeld Datenquelle wählen führt die definierten Datenquellen auf.

  4. Wenn für die gewünschte ODBC-Datenquelle eine Anmeldung erforderlich ist, geben Sie Ihren Benutzernamen und Ihr Passwort ein (sowie eventuell erforderliche Zusatzinformationen) und klicken dann auf OK.

  5. Microsoft Access verbindet sich mit dem MySQL Server über die ODBC-Datenquelle und zeigt die Liste der Tabellen an, die Sie importieren oder verknüpfen können.

  6. Klicken Sie nun alle Tabellen an, die Sie importieren oder verknüpfen möchten, und klicken Sie dann auf OK. Wenn Sie eine Tabelle verknüpfen, die keinen Index besitzt, über den Datensätze eindeutig identifiziert werden können, zeigt Microsoft Access eine Liste der Felder dieser verknüpften Tabelle an. Klicken Sie auf ein Feld oder eine Feldkombination, die Datensätze eindeutig identifiziert, und dann auf OK.

25.1.4.3.3.3. Verknüpfen von MySQL-Daten zu Access-Tabellen

Mit folgendem Verfahren können Sie Verknüpfungen anzeigen oder aktualisieren, wenn sich die Struktur oder der Speicherort einer verknüpften Tabelle geändert hat. Der Verknüpfungsassistent führt die Pfade aller Tabellen auf, die gerade verknüpft sind.

Verknüpfungen anzeigen oder aktualisieren:

  1. Öffnen Sie die Datenbank, die die Verknüpfungen zu den Tabellen enthält.

  2. Zeigen Sie im Menü Extras auf Add-ins (Datenbank-Utilities in Access 2000 oder höher) und klicken Sie dann auf Verknüpfungsassistent.

  3. Markieren Sie die Kontrollkästchen der Tabellen, deren Links Sie aktualisieren möchten.

  4. Mit einem Klick auf OK werden die Verknüpfungen aktualisiert.

Microsoft Access bestätigt eine erfolgreiche Aktualisierung oder zeigt, wenn die Tabelle nicht gefunden wurde, das Dialogfeld Neuen Speicherort wählen für <table name> an, in welchem Sie den neuen Speicherort der Tabelle eingeben können. Wenn mehrere der ausgewählten Tabellen an den neuen Speicherort verschoben wurden, durchsucht der Verknüpfungsassistent diesen Ort nach allen diesen Tabellen und aktualisiert die Verknüpfungen in einem einzigen Durchgang.

Pfad für mehrere verknüpfte Tabellen ändern:

  1. Öffnen Sie die Datenbank, die die Verknüpfungen zu den Tabellen enthält.

  2. Zeigen Sie im Menü Extras auf Add-ins (Datenbank-Utilities in Access 2000 oder höher) und klicken Sie dann auf Verknüpfungsassistent.

  3. Markieren Sie das Kontrollkästchen Bei neuem Speicherort immer nachfragen.

  4. Markieren Sie die Kontrollkästchen der Tabellen, deren Verknüpfungen Sie ändern möchten, und klicken Sie auf OK.

  5. Geben Sie im Dialogfeld Neuen Speicherort wählen für tabellenname den neuen Speicherort ein und klicken Sie auf Öffnen und dann auf OK.

25.1.4.4. MyODBC: Programmierbeispiele

Wenn ein geeigneter ODBC-Manager und der MyODBC-Treiber installiert sind, müsste jede Programmiersprache und Umgebung, die ODBC unterstützt, über MyODBC mit einer MySQL-Datenbank Verbindung aufnehmen können.

Dazu gehören auch (aber natürlich nicht nur) die Microsoft-Sprachen (Visual Basic, C# und Schnittstellen wie ODBC.NET) und Perl (über das DBI-Modul und den DBD::ODBC-Treiber).

25.1.4.4.1. Verwendung von MyODBC mit Visual Basic und ADO, DAO sowie RDO

Dieser Abschnitt zeigt einfache Beispiele für die Verwendung des MySQL ODBC 3.51-Treibers mit ADO, DAO und RDO.

25.1.4.4.1.1. ADO: rs.addNew, rs.delete und rs.update

Das folgende ADO(ActiveX Data Objects)-Beispiel legt eine Tabelle an (my_ado) und demonstriert die Verwendung von rs.addNew, rs.delete und rs.update.

Private Sub myodbc_ado_Click()

Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim fld As ADODB.Field
Dim sql As String

'connect to MySQL server using MySQL ODBC 3.51 Driver
Set conn = New ADODB.Connection
conn.ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver};"_
& "SERVER=localhost;"_
& " DATABASE=test;"_
& "UID=venu;PWD=venu; OPTION=3"

conn.Open

'create table
conn.Execute "DROP TABLE IF EXISTS my_ado"
conn.Execute "CREATE TABLE my_ado(id int not null primary key, name varchar(20)," _
& "txt text, dt date, tm time, ts timestamp)"

'direct insert
conn.Execute "INSERT INTO my_ado(id,name,txt) values(1,100,'venu')"
conn.Execute "INSERT INTO my_ado(id,name,txt) values(2,200,'MySQL')"
conn.Execute "INSERT INTO my_ado(id,name,txt) values(3,300,'Delete')"

Set rs = New ADODB.Recordset
rs.CursorLocation = adUseServer

'fetch the initial table ..
rs.Open "SELECT * FROM my_ado", conn
Debug.Print rs.RecordCount
rs.MoveFirst
Debug.Print String(50, "-") & "Initial my_ado Result Set " & String(50, "-")
For Each fld In rs.Fields
Debug.Print fld.Name,
Next
Debug.Print

Do Until rs.EOF
For Each fld In rs.Fields
Debug.Print fld.Value,
Next
rs.MoveNext
Debug.Print
Loop
rs.Close

'rs insert
rs.Open "select * from my_ado", conn, adOpenDynamic, adLockOptimistic
rs.AddNew
rs!Name = "Monty"
rs!txt = "Insert row"
rs.Update
rs.Close

'rs update
rs.Open "SELECT * FROM my_ado"
rs!Name = "update"
rs!txt = "updated-row"
rs.Update
rs.Close

'rs update second time..
rs.Open "SELECT * FROM my_ado"
rs!Name = "update"
rs!txt = "updated-second-time"
rs.Update
rs.Close

'rs delete
rs.Open "SELECT * FROM my_ado"
rs.MoveNext
rs.MoveNext
rs.Delete
rs.Close

'fetch the updated table ..
rs.Open "SELECT * FROM my_ado", conn
Debug.Print rs.RecordCount
rs.MoveFirst
Debug.Print String(50, "-") & "Updated my_ado Result Set " & String(50, "-")
For Each fld In rs.Fields
Debug.Print fld.Name,
Next
Debug.Print

Do Until rs.EOF
For Each fld In rs.Fields
Debug.Print fld.Value,
Next
rs.MoveNext
Debug.Print
Loop
rs.Close
conn.Close
End Sub
25.1.4.4.1.2. DAO: rs.addNew, rs.update und Scrolling

Das folgende DAO(Data Access Objects)-Beispiel legt die Tabelle my_dao an und demonstriert die Verwendung von rs.addNew, rs.update und Ergebnismengen-Scrolling.

Private Sub myodbc_dao_Click()

Dim ws As Workspace
Dim conn As Connection
Dim queryDef As queryDef
Dim str As String

'connect to MySQL using MySQL ODBC 3.51 Driver
Set ws = DBEngine.CreateWorkspace("", "venu", "venu", dbUseODBC)
str = "odbc;DRIVER={MySQL ODBC 3.51 Driver};"_
& "SERVER=localhost;"_
& " DATABASE=test;"_
& "UID=venu;PWD=venu; OPTION=3"
Set conn = ws.OpenConnection("test", dbDriverNoPrompt, False, str)

'Create table my_dao
Set queryDef = conn.CreateQueryDef("", "drop table if exists my_dao")
queryDef.Execute

Set queryDef = conn.CreateQueryDef("", "create table my_dao(Id INT AUTO_INCREMENT PRIMARY KEY, " _
& "Ts TIMESTAMP(14) NOT NULL, Name varchar(20), Id2 INT)")
queryDef.Execute

'Insert new records using rs.addNew
Set rs = conn.OpenRecordset("my_dao")
Dim i As Integer

For i = 10 To 15
rs.AddNew
rs!Name = "insert record" & i
rs!Id2 = i
rs.Update
Next i
rs.Close

'rs update..
Set rs = conn.OpenRecordset("my_dao")
rs.Edit
rs!Name = "updated-string"
rs.Update
rs.Close

'fetch the table back...
Set rs = conn.OpenRecordset("my_dao", dbOpenDynamic)
str = "Results:"
rs.MoveFirst
While Not rs.EOF
str = " " & rs!Id & " , " & rs!Name & ", " & rs!Ts & ", " & rs!Id2
Debug.Print "DATA:" & str
rs.MoveNext
Wend

'rs Scrolling
rs.MoveFirst
str = " FIRST ROW: " & rs!Id & " , " & rs!Name & ", " & rs!Ts & ", " & rs!Id2
Debug.Print str

rs.MoveLast
str = " LAST ROW: " & rs!Id & " , " & rs!Name & ", " & rs!Ts & ", " & rs!Id2
Debug.Print str

rs.MovePrevious
str = " LAST-1 ROW: " & rs!Id & " , " & rs!Name & ", " & rs!Ts & ", " & rs!Id2
Debug.Print str

'free all resources
rs.Close
queryDef.Close
conn.Close
ws.Close

End Sub
25.1.4.4.1.3. RDO: rs.addNew und rs.update

Das folgende RDO(Remote Data Objects)-Beispiel legt die Tabelle my_rdo an und demonstriert die Verwendung von rs.addNew und rs.update.

Dim rs As rdoResultset
Dim cn As New rdoConnection
Dim cl As rdoColumn
Dim SQL As String

'cn.Connect = "DSN=test;"
cn.Connect = "DRIVER={MySQL ODBC 3.51 Driver};"_
& "SERVER=localhost;"_
& " DATABASE=test;"_
& "UID=venu;PWD=venu; OPTION=3"

cn.CursorDriver = rdUseOdbc
cn.EstablishConnection rdDriverPrompt


'drop table my_rdo
SQL = "drop table if exists my_rdo"
cn.Execute SQL, rdExecDirect

'create table my_rdo
SQL = "create table my_rdo(id int, name varchar(20))"
cn.Execute SQL, rdExecDirect

'insert - direct
SQL = "insert into my_rdo values (100,'venu')"
cn.Execute SQL, rdExecDirect

SQL = "insert into my_rdo values (200,'MySQL')"
cn.Execute SQL, rdExecDirect

'rs insert
SQL = "select * from my_rdo"
Set rs = cn.OpenResultset(SQL, rdOpenStatic, rdConcurRowVer, rdExecDirect)
rs.AddNew
rs!id = 300
rs!Name = "Insert1"
rs.Update
rs.Close

'rs insert
SQL = "select * from my_rdo"
Set rs = cn.OpenResultset(SQL, rdOpenStatic, rdConcurRowVer, rdExecDirect)
rs.AddNew
rs!id = 400
rs!Name = "Insert 2"
rs.Update
rs.Close

'rs update
SQL = "select * from my_rdo"
Set rs = cn.OpenResultset(SQL, rdOpenStatic, rdConcurRowVer, rdExecDirect)
rs.Edit
rs!id = 999
rs!Name = "updated"
rs.Update
rs.Close

'fetch back...
SQL = "select * from my_rdo"
Set rs = cn.OpenResultset(SQL, rdOpenStatic, rdConcurRowVer, rdExecDirect)
Do Until rs.EOF
For Each cl In rs.rdoColumns
Debug.Print cl.Value,
Next
rs.MoveNext
Debug.Print
Loop
Debug.Print "Row count="; rs.RowCount

'close
rs.Close
cn.Close

End Sub
25.1.4.4.2. Verwendung von MyODBC mit .NET

Dieser Abschnitt zeigt einfache Beispiele für die Verwendung von MyODBC-Treibern mit ODBC.NET.

25.1.4.4.2.1. Verwendung von MyODBC mit ODBC.NET und C# (C sharp)

Das folgende Beispiel legt die Tabelle my_odbc_net an und demonstriert ihre Verwendung in C#.

/**
 * @sample    : mycon.cs
 * @purpose   : Demo sample for ODBC.NET using MyODBC
 * @author    : Venu, 
 *
 * (C) Copyright MySQL AB, 1995-2006
 *
 **/
          
/* Build-Befehl
 *
 *  csc /t:exe
 *      /out:mycon.exe mycon.cs
 *      /r:Microsoft.Data.Odbc.dll
 */
          
using Console = System.Console;
using Microsoft.Data.Odbc;
          
namespace myodbc3
{
  class mycon
  {
    static void Main(string[] args)
    {
      try
        {
          //Verbindungs-String für MyODBC 2.50
          /*string MyConString = "DRIVER={MySQL};" +
            "SERVER=localhost;" +
            "DATABASE=test;" +
            "UID=venu;" +
            "PASSWORD=venu;" +
            "OPTION=3";
          */
          //Verbindungs-String für MyODBC 3.51
          string MyConString = "DRIVER={MySQL ODBC 3.51 Driver};" +
            "SERVER=localhost;" +
            "DATABASE=test;" +
            "UID=venu;" +
            "PASSWORD=venu;" +
            "OPTION=3";
          
          //Verbindung zu MySQL mittels MyODBC
          OdbcConnection MyConnection = new OdbcConnection(MyConString);
          MyConnection.Open();
          
          Console.WriteLine("\n !!! success, connected successfully !!!\n");
          
          //Verbindungs-Informationen anzeigen
          Console.WriteLine("Connection Information:");
          Console.WriteLine("\tConnection String:" + 
                            MyConnection.ConnectionString);
          Console.WriteLine("\tConnection Timeout:" + 
                            MyConnection.ConnectionTimeout);
          Console.WriteLine("\tDatabase:" + 
                            MyConnection.Database);
          Console.WriteLine("\tDataSource:" + 
                            MyConnection.DataSource);
          Console.WriteLine("\tDriver:" + 
                            MyConnection.Driver);
          Console.WriteLine("\tServerVersion:" + 
                            MyConnection.ServerVersion);
          
          //Beispieltabelle anlegen
          OdbcCommand MyCommand = 
            new OdbcCommand("DROP TABLE IF EXISTS my_odbc_net",
                            MyConnection);
          MyCommand.ExecuteNonQuery();
          MyCommand.CommandText = 
            "CREATE TABLE my_odbc_net(id int, name varchar(20), idb bigint)";
          MyCommand.ExecuteNonQuery();
          
          //Insert
          MyCommand.CommandText = 
            "INSERT INTO my_odbc_net VALUES(10,'venu', 300)";
          Console.WriteLine("INSERT, Total rows affected:" + 
                            MyCommand.ExecuteNonQuery());;
          
          //Insert
          MyCommand.CommandText = 
            "INSERT INTO my_odbc_net VALUES(20,'mysql',400)";
          Console.WriteLine("INSERT, Total rows affected:" + 
                            MyCommand.ExecuteNonQuery());
          
          //Insert
          MyCommand.CommandText = 
            "INSERT INTO my_odbc_net VALUES(20,'mysql',500)";
          Console.WriteLine("INSERT, Total rows affected:" + 
                            MyCommand.ExecuteNonQuery());
          
          //Update
          MyCommand.CommandText = 
            "UPDATE my_odbc_net SET id=999 WHERE id=20";
          Console.WriteLine("Update, Total rows affected:" + 
                            MyCommand.ExecuteNonQuery());
          
          //COUNT(*)
          MyCommand.CommandText = 
            "SELECT COUNT(*) as TRows FROM my_odbc_net";
          Console.WriteLine("Total Rows:" + 
                            MyCommand.ExecuteScalar());
          
          //Fetch
          MyCommand.CommandText = "SELECT * FROM my_odbc_net";
          OdbcDataReader MyDataReader;
          MyDataReader =  MyCommand.ExecuteReader();
          while (MyDataReader.Read())
            {
              if(string.Compare(MyConnection.Driver,"myodbc3.dll") == 0) {
                //Nur von MyODBC 3.51 unterstützt
                Console.WriteLine("Data:" + MyDataReader.GetInt32(0) + " " +
                                  MyDataReader.GetString(1) + " " +
                                  MyDataReader.GetInt64(2)); 
              }
              else {
                //BIGINTs werden von MyODBC nicht unterstützt
                Console.WriteLine("Data:" + MyDataReader.GetInt32(0) + " " +
                                  MyDataReader.GetString(1) + " " +
                                  MyDataReader.GetInt32(2)); 
              }
            }
          
          //Alle Ressourcen schließen
          MyDataReader.Close();
          MyConnection.Close();
        }
      catch (OdbcException MyOdbcException) //Catch any ODBC exception ..
        {
          for (int i=0; i < MyOdbcException.Errors.Count; i++)
            {
              Console.Write("ERROR #" + i + "\n" +
                            "Message: " + 
                            MyOdbcException.Errors[i].Message + "\n" +
                            "Native: " + 
                            MyOdbcException.Errors[i].NativeError.ToString() + "\n" +
                            "Source: " + 
                            MyOdbcException.Errors[i].Source + "\n" +
                            "SQL: " + 
                            MyOdbcException.Errors[i].SQLState + "\n");
            }
        }
    }
  }
}
25.1.4.4.2.2. Verwendung von MyODBC mit ODBC.NET und Visual Basic

Das folgende Beispiel legt die Tabelle my_vb_net an und demonstriert ihre Verwendung in VB.

' @sample    : myvb.vb
' @purpose   : Demo sample for ODBC.NET using MyODBC
' @author    : Venu, 
'
' (C) Copyright MySQL AB, 1995-2006
'
'

'
' build command
'
' vbc /target:exe
'     /out:myvb.exe
'     /r:Microsoft.Data.Odbc.dll
'     /r:System.dll
'     /r:System.Data.dll
'

Imports Microsoft.Data.Odbc
Imports System

Module myvb
  Sub Main()
    Try

      'MyODBC 3.51 connection string
      Dim MyConString As String = "DRIVER={MySQL ODBC 3.51 Driver};" & _
      "SERVER=localhost;" & _
      "DATABASE=test;" & _
      "UID=venu;" & _
      "PASSWORD=venu;" & _
      "OPTION=3;"

      'Connection
      Dim MyConnection As New OdbcConnection(MyConString)
      MyConnection.Open()

      Console.WriteLine("Connection State::" & MyConnection.State.ToString)

      'Drop
      Console.WriteLine("Dropping table")
      Dim MyCommand As New OdbcCommand()
      MyCommand.Connection = MyConnection
      MyCommand.CommandText = "DROP TABLE IF EXISTS my_vb_net"
      MyCommand.ExecuteNonQuery()

      'Create
      Console.WriteLine("Creating....")
      MyCommand.CommandText = "CREATE TABLE my_vb_net(id int, name varchar(30))"
      MyCommand.ExecuteNonQuery()

      'Insert
      MyCommand.CommandText = "INSERT INTO my_vb_net VALUES(10,'venu')"
      Console.WriteLine("INSERT, Total rows affected:" & _
      MyCommand.ExecuteNonQuery())

      'Insert
      MyCommand.CommandText = "INSERT INTO my_vb_net VALUES(20,'mysql')"
      Console.WriteLine("INSERT, Total rows affected:" & _
      MyCommand.ExecuteNonQuery())

      'Insert
      MyCommand.CommandText = "INSERT INTO my_vb_net VALUES(20,'mysql')"
      Console.WriteLine("INSERT, Total rows affected:" & _
      MyCommand.ExecuteNonQuery())

      'Insert
      MyCommand.CommandText = "INSERT INTO my_vb_net(id) VALUES(30)"
      Console.WriteLine("INSERT, Total rows affected:" & _
                        MyCommand.ExecuteNonQuery())

      'Update
      MyCommand.CommandText = "UPDATE my_vb_net SET id=999 WHERE id=20"
      Console.WriteLine("Update, Total rows affected:" & _
      MyCommand.ExecuteNonQuery())

      'COUNT(*)
      MyCommand.CommandText = "SELECT COUNT(*) as TRows FROM my_vb_net"
      Console.WriteLine("Total Rows:" & MyCommand.ExecuteScalar())

      'Select
      Console.WriteLine("Select * FROM my_vb_net")
      MyCommand.CommandText = "SELECT * FROM my_vb_net"
      Dim MyDataReader As OdbcDataReader
      MyDataReader = MyCommand.ExecuteReader
      While MyDataReader.Read
        If MyDataReader("name") Is DBNull.Value Then
          Console.WriteLine("id = " & _
          CStr(MyDataReader("id")) & "  name = " & _
          "NULL")
        Else
          Console.WriteLine("id = " & _
          CStr(MyDataReader("id")) & "  name = " & _
          CStr(MyDataReader("name")))
        End If
      End While

      'Catch ODBC Exception
    Catch MyOdbcException As OdbcException
      Dim i As Integer
      Console.WriteLine(MyOdbcException.ToString)

      'Catch program exception
    Catch MyException As Exception
      Console.WriteLine(MyException.ToString)
    End Try
  End Sub

25.1.5. MyODBC-Referenz

Der vorliegende Abschnitt enthält Referenzmaterial für die MyODBC-API, zeigt die unterstützten Funktionen und Methoden, die MySQL-Spaltentypen und die entsprechenden nativen Typen in MyODBC sowie die von MyODBC zurückgegebenen Fehlercodes.

25.1.5.1. MyODBC: API-Referenz

Dieser Abschnitt fasst ODBC-Routinen nach Funktionalität zusammen.

Die vollständige Referenz zur ODBC-API finden Sie in der ODBC Programmer's Reference unter http://msdn.microsoft.com/library/en-us/odbc/htm/odbcabout_this_manual.asp.

Eine Anwendung kann die Funktion SQLGetInfo aufrufen, um Konformitätsinformationen über MyODBC einzuholen. Ob der Treiber eine bestimmte Funktion unterstützt, kann eine Anwendung mit SQLGetFunctions in Erfahrung bringen.

Hinweis: Zur Abwärtskompatibilität unterstützt der MyODBC 3.51-Treiber auch die veralteten Funktionen.

Die folgenden Tabellen zeigen die MyODBC-API-Funktionsaufrufe nach Aufgabenbereich:

Verbindung mit einer Datenquelle:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLAllocHandleNeinJaISO 92Beschafft einen Handle für Umgebung, Verbindung, Anweisung oder Deskriptor.
SQLConnectJaJaISO 92Verbindet sich mit einem konkreten Treiber über Data Source Name, Benutzername und Passwort.
SQLDriverConnectJaJaODBCVerbindet sich mit einem konkreten Treiber über einen Verbindungs-String oder verlangt, dass der Treiber-Manager und Treiber Verbindungsdialogfelder für den Benutzer anzeigen.
SQLAllocEnvJaJaVeraltetBeschafft einen vom Treiber zugewiesenen Umgebungs-Handle.
SQLAllocConnectJaJaVeraltetBeschafft einen Verbindungs-Handle

Informationen über einen Treiber und Datenquellen beschaffen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLDataSourcesNeinNeinISO 92Liefert eine Liste der verfügbaren Datenquellen, mit denen der Treiber-Manager umgehen kann.
SQLDriversNeinNeinODBCLiefert eine Liste der installierten Treiber und ihrer Attribute, mit denen der Treiber-Manager umgehen kann.
SQLGetInfoJaJaISO 92Liefert Informationen über einen spezifischen Treiber und eine Datenquelle.
SQLGetFunctionsJaJaISO 92Zeigt die unterstützten Treiberfunktionen an.
SQLGetTypeInfoJaJaISO 92Gibt Informationen über die unterstützten Datentypen.

Treiberattribute einstellen und abfragen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLSetConnectAttrNeinJaISO 92Setzt ein Verbindungsattribut.
SQLGetConnectAttrNeinJaISO 92Gibt den Wert eines Verbindungsattributs zurück.
SQLSetConnectOptionJaJaVeraltetSetzt eine Verbindungsoption.
SQLGetConnectOptionJaJaVeraltetGibt den Wert einer Verbindungsoption zurück.
SQLSetEnvAttrNeinJaISO 92Setzt ein Umgebungsattribut.
SQLGetEnvAttrNeinJaISO 92Gibt den Wert eines Umgebungsattributs zurück.
SQLSetStmtAttrNeinJaISO 92Setzt ein Anweisungsattribut.
SQLGetStmtAttrNeinJaISO 92Gibt den Wert eines Anweisungsattributs zurück.
SQLSetStmtOptionJaJaVeraltetSetzt eine Anweisungsoption.
SQLGetStmtOptionJaJaVeraltetGibt den Wert einer Anweisungsoption zurück.

Vorbereitung von SQL-Requests:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLAllocStmtJaJaVeraltetWeist einen Anweisungs-Handle zu.
SQLPrepareJaJaISO 92Bereitet eine SQL-Anweisung zur späteren Ausführung vor.
SQLBindParameterJaJaODBCWeist Speicher für einen Parameter in einer SQL-Anweisung zu.
SQLGetCursorNameJaJaISO 92Gibt den mit einem Anweisungs-Handle verbundenen Cursor-Namen zurück.
SQLSetCursorNameJaJaISO 92Gibt einen Cursor-Namen an.
SQLSetScrollOptionsJaJaODBCSetzt Optionen zur Steuerung des Cursor-Verhaltens.

Übermittlung von Requests:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLExecuteJaJaISO 92Führt eine vorbereitete Anweisung aus.
SQLExecDirectJaJaISO 92Führt eine Anweisung aus.
SQLNativeSqlJaJaODBCGibt den Text einer vom Treiber übersetzten SQL-Anweisung zurück.
SQLDescribeParamJaJaODBCGibt die Beschreibung eines bestimmten Parameters in einer Anweisung zurück.
SQLNumParamsJaJaISO 92Gibt die Anzahl der Parameter in einer Anweisung zurück.
SQLParamDataJaJaISO 92Wird in Verbindung mit SQLPutData verwendet, um Parameterdaten zur Ausführungszeit zu liefern. (Nützlich für lange Datenwerte.)
SQLPutDataJaJaISO 92Sendet einen Datenwert eines Parameters ganz oder teilweise. (Nützlich für lange Datenwerte.)

Ergebnisse und Ergebnisinformationen abrufen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLRowCountJaJaISO 92Meldet, wie viele Zeilen von einem Insert, Update oder Delete betroffen wurden.
SQLNumResultColsJaJaISO 92Meldet die Anzahl der Zeilen in der Ergebnismenge.
SQLDescribeColJaJaISO 92Beschreibt eine Spalte der Ergebnismenge.
SQLColAttributeNeinJaISO 92Beschreibt Attribute einer Spalte der Ergebniszeile.
SQLColAttributesJaJaVeraltetBeschreibt Attribute einer Spalte der Ergebniszeile.
SQLFetchJaJaISO 92Gibt mehrere Ergebniszeilen zurück.
SQLFetchScrollNeinJaISO 92Gibt scrollbare Ergebniszeilen zurück.
SQLExtendedFetchJaJaVeraltetGibt scrollbare Ergebniszeilen zurück.
SQLSetPosJaJaODBCSetzt einen Cursor in einen abgeholten Datenblock, sodass eine Anwendung Daten in der Zeilenmenge erneuern oder Daten in der Ergebnismenge aktualisieren oder löschen kann.
SQLBulkOperationsNeinJaODBCFührt Einfügungen oder Bookmarking als Massenoperationen aus, darunter Updates, Deletes und Datenabruf anhand von Bookmarks.

Fehler- oder Diagnosedaten abrufen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLErrorJaJaVeraltetGibt zusätzliche Fehler- oder Statusinformationen zurück.
SQLGetDiagFieldJaJaISO 92Gibt zusätzliche diagnostische Informationen zurück (ein einzelnes Feld der diagnostischen Datenstruktur).
SQLGetDiagRecJaJaISO 92Gibt zusätzliche diagnostische Informationen zurück (mehrere Felder der diagnostischen Datenstruktur).

Informationen über die Systemtabellen (Katalogfunktionen) der Datenquelle abrufen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLColumnPrivilegesJaJaODBCLiefert eine Liste von Spalten und zugehörigen Berechtigungen für eine oder mehr Tabellen.
SQLColumnsJaJaX/OpenLiefert eine Liste der Spaltennamen in den angegebenen Tabellen.
SQLForeignKeysJaJaODBCLiefert für eine angegebene Tabelle eine Liste der Spalten, die den Fremdschlüssel bilden (sofern vorhanden).
SQLPrimaryKeysJaJaODBCLiefert die Liste der Spalten, die den Primärschlüssel einer Tabelle bilden.
SQLSpecialColumnsJaJaX/OpenLiefert Informationen über die optimale Spaltenmenge zur eindeutigen Identifikation einer Zeile in einer angegebenen Tabelle oder die Spalten, die automatisch aktualisiert werden, wenn eine Transaktion einen Wert in der Zeile ändert.
SQLStatisticsJaJaISO 92Liefert Statistikdaten über eine einzelne Tabelle und die Liste der mit ihr verbundenen Indizes.
SQLTablePrivilegesJaJaODBCLiefert eine Liste der Tabellen und zugehörigen Berechtigungen.
SQLTablesJaJaX/OpenLiefert eine Liste der Tabellennamen, die in einer bestimmten Datenstruktur gespeichert sind.

Transaktionen ausführen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLTransactJaJaVeraltetSchreibt eine Transaktion fest (Commit) oder rollt sie zurück (Rollback).
SQLEndTranNeinJaISO 92Schreibt eine Transaktion fest (Commit) oder rollt sie zurück (Rollback).

Anweisungen abschließen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLFreeStmtJaJaISO 92Beendet die Anweisungsverarbeitung, verwirft noch anhängige Ergebnisse und gibt optional die Ressourcen frei, die mit dem Anweisungs-Handle verbunden waren.
SQLCloseCursorJaJaISO 92Schließt einen auf einem Anweisungs-Handle geöffneten Cursor.
SQLCancelJaJaISO 92Bricht eine SQL-Anweisung ab.

Verbindungen schließen:

 MyODBC  
Funktionsname2.503.51StandardZweck
SQLDisconnectJaJaISO 92Schließt die Verbindung.
SQLFreeHandleNeinJaISO 92Gibt einen Umgebungs-, Verbindungs-, Anweisungs- oder Deskriptor-Handle frei.
SQLFreeConnectJaJaVeraltetGibt einen Verbindungs-Handle frei.
SQLFreeEnvJaJaVeraltetGibt einen Umgebungs-Handle frei

25.1.5.2. MyODBC: Datentypen

Die folgende Tabelle zeigt, wie der Treiber die Datentypen des Servers den Standarddatentypen von SQL und C zuordnet:

Nativer WertSQL-TypC-Typ
bitSQL_BITSQL_C_BIT
tinyintSQL_TINYINTSQL_C_STINYINT
tinyint unsignedSQL_TINYINTSQL_C_UTINYINT
bigintSQL_BIGINTSQL_C_SBIGINT
bigint unsignedSQL_BIGINTSQL_C_UBIGINT
long varbinarySQL_LONGVARBINARYSQL_C_BINARY
blobSQL_LONGVARBINARYSQL_C_BINARY
longblobSQL_LONGVARBINARYSQL_C_BINARY
tinyblobSQL_LONGVARBINARYSQL_C_BINARY
mediumblobSQL_LONGVARBINARYSQL_C_BINARY
long varcharSQL_LONGVARCHARSQL_C_CHAR
textSQL_LONGVARCHARSQL_C_CHAR
mediumtextSQL_LONGVARCHARSQL_C_CHAR
charSQL_CHARSQL_C_CHAR
numericSQL_NUMERICSQL_C_CHAR
decimalSQL_DECIMALSQL_C_CHAR
integerSQL_INTEGERSQL_C_SLONG
integer unsignedSQL_INTEGERSQL_C_ULONG
intSQL_INTEGERSQL_C_SLONG
int unsignedSQL_INTEGERSQL_C_ULONG
mediumintSQL_INTEGERSQL_C_SLONG
mediumint unsignedSQL_INTEGERSQL_C_ULONG
smallintSQL_SMALLINTSQL_C_SSHORT
smallint unsignedSQL_SMALLINTSQL_C_USHORT
realSQL_FLOATSQL_C_DOUBLE
doubleSQL_FLOATSQL_C_DOUBLE
floatSQL_REALSQL_C_FLOAT
double precisionSQL_DOUBLESQL_C_DOUBLE
dateSQL_DATESQL_C_DATE
timeSQL_TIMESQL_C_TIME
yearSQL_SMALLINTSQL_C_SHORT
datetimeSQL_TIMESTAMPSQL_C_TIMESTAMP
timestampSQL_TIMESTAMPSQL_C_TIMESTAMP
textSQL_VARCHARSQL_C_CHAR
varcharSQL_VARCHARSQL_C_CHAR
enumSQL_VARCHARSQL_C_CHAR
setSQL_VARCHARSQL_C_CHAR
bitSQL_CHARSQL_C_CHAR
boolSQL_CHARSQL_C_CHAR

25.1.5.3. MyODBC: Fehlercodes

Die folgenden Tabellen führen die Fehlercodes auf, die der Treiber neben den Serverfehlern noch zurückliefert.

Nativer CodeSQLSTATE 2SQLSTATE 3Fehlermeldung
5000100001000General warning
5010100401004String data, right truncated
50201S0201S02Option value changed
50301S0301S03No rows updated/deleted
50401S0401S04More than one row updated/deleted
50501S0601S06Attempt to fetch before the result set returned the first row set
5060700107002SQLBindParameter not used for all parameters
5070700507005Prepared statement not a cursor-specification
5080700907009Invalid descriptor index
5090800208002Connection name in use
5100800308003Connection does not exist
5112400024000Invalid cursor state
5122500025000Invalid transaction state
51325S0125S01Transaction state unknown
5143400034000Invalid cursor name
515S1000HY000General driver defined error
516S1001HY001Memory allocation error
517S1002HY002Invalid column number
518S1003HY003Invalid application buffer type
519S1004HY004Invalid SQL data type
520S1009HY009Invalid use of null pointer
521S1010HY010Function sequence error
522S1011HY011Attribute can not be set now
523S1012HY012Invalid transaction operation code
524S1013HY013Memory management error
525S1015HY015No cursor name available
526S1024HY024Invalid attribute value
527S1090HY090Invalid string or buffer length
528S1091HY091Invalid descriptor field identifier
529S1092HY092Invalid attribute/option identifier
530S1093HY093Invalid parameter number
531S1095HY095Function type out of range
532S1106HY106Fetch type out of range
533S1117HY117Row value out of range
534S1109HY109Invalid cursor position
535S1C00HYC00Optional feature not implemented
021S0121S01Column count does not match value count
02300023000Integrity constraint violation
04200042000Syntax error or access violation
042S0242S02Base table or view not found
042S1242S12Index not found
042S2142S21Column already exists
042S2242S22Column not found
008S0108S01Communication link failure

25.1.6. Hinweise und Tipps zu MyODBC

Nun folgen einige allgemeine Hinweise und Tipps für die Verwendung von MyODBC in unterschiedlichen Umgebungen, Anwendungen und Tools. Die Hinweise basieren auf den Erfahrungen von MyODBC-Entwicklern und -Nutzern.

25.1.6.1. MyODBC: Allgemeine Funktionalität

In diesem Abschnitt geht es um häufig benutzte Abfragen und Funktionalitätsbereiche in MySQL und ihre Verwendung mit MyODBC.

25.1.6.1.1. Abruf von Auto-Increment-Werten

Den Wert einer Spalte, die nach einer INSERT-Anweisung AUTO_INCREMENT verwendet, kann man auf mehrere Weisen beschaffen. Um ihn unmittelbar nach dem INSERT abzurufen, verwendet man eine SELECT-Anfrage mit der LAST_INSERT_ID()-Funktion.

Mit MyODBC würden Sie hier zwei Anweisungen absetzen: die INSERT-Anweisung und die SELECT-Anfrage, die Ihnen den Auto-Increment-Wert liefert.

INSERT INTO tbl (auto,text) VALUES(NULL,'text');
SELECT LAST_INSERT_ID();

Wenn Sie den Wert nicht für Ihre Anwendung, aber für ein anderes INSERT benötigen, können Sie das Ganze auch mit folgenden beiden Anweisungen erledigen:

INSERT INTO tbl (auto,text) VALUES(NULL,'text');
INSERT INTO tbl2 (id,text) VALUES(LAST_INSERT_ID(),'text');

Manche ODBC-Anwendungen (darunter Delphi und Access) haben Schwierigkeiten, mit den oben gezeigten Methoden den Auto-Increment-Wert abzurufen. Hier bietet sich als Alternative folgende Anweisung an:

SELECT * FROM tbl WHERE auto IS NULL;

Siehe Abschnitt 24.2.13.3, „Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?“.

25.1.6.1.2. Unterstützung für dynamische Cursor

MyODBC 3.51 bietet zwar dynamic cursor-Unterstützung, aber nach Voreinstellung sind dynamische Cursors nicht aktiviert. In Windows schalten Sie diese Funktion ein, indem Sie das Kontrollkästchen Dynamische Cursor aktivieren im ODBC-Datenquellen-Administrator markieren.

Auf anderen Plattformen schalten Sie dynamische Cursors ein, indem Sie zu dem Wert von OPTION den Wert 32 addieren, wenn Sie den DSN anlegen.

25.1.6.1.3. MyODBC: Performanz

Der MyODBC-Treiber wurde auf eine sehr schnelle Leistung hin optimiert. Wenn Sie Probleme mit der Leistung von MyODBC haben oder viele Plattenzugriffe für einfache Anfragen auftreten, sollten Sie mehrere Dinge überprüfen:

  • Stellen Sie sicher, dass ODBC Tracing nicht eingeschaltet ist. Wenn das Tracing aktiv ist, zeichnet der ODBC-Manager massenhaft Daten in der Tracing-Datei auf. Unter Windows können Sie dies prüfen und das Tracing gegebenenfalls deaktivieren, indem Sie die Ablaufverfolgung im ODBC-Datenquellen-Administrator ausschalten. In Mac OS X überprüfen Sie das Tracing-Feld des ODBC Administrators. Siehe auch Abschnitt 25.1.3.8, „Erzeugen einer ODBC-Trace-Datei“.

  • Vergewissern Sie sich, dass Sie die Standardversion und nicht die Debugging-Version des Treibers benutzen. In der Debugging-Version werden zusätzliche Überprüfungen und Berichte ausgeführt.

  • Deaktivieren Sie die Trace- und Query-Logs des MyODBC-Treibers. Da diese für jeden DSN aktiviert sind, müssen Sie darauf achten, nur den DSN zu bearbeiten, den Sie in Ihrer Anwendung benutzen. Unter Windows deaktivieren Sie die MyODBC- und Query-Logs, indem Sie die DSN-Konfiguration modifizieren. Unter Mac OS X und Unix müssen Sie dafür sorgen, dass der Treiber-Trace (Optionswert 4) und das Anfragen-Logging (Optionswert 524288) ausgeschaltet sind.

25.1.6.1.4. Einstellen der ODBC-Zeitüberschreitung unter Windows

Wie Sie in Microsoft Windows ein Anfragen-Timeout einstellen, wenn Anfragen über eine ODBC-Verbindung ausgeführt werden, erfahren Sie in folgendem Artikel der Microsoft Knowledge Base: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B153756.

25.1.6.2. MyODBC: Applikationsspezifische Tipps

Die meisten Programme sollten mit MyODBC gut harmonieren, doch für die folgenden gibt es bestimmte Hinweise und Tipps zur Verbesserung der Arbeit mit MyODBC und dem betreffenden Programm.

Bei allen Anwendungen sollten Sie immer darauf achten, die jeweils neuesten Versionen von MyODBC-Treibern, ODBC-Manager und den von der Anwendung benutzten Bibliotheken und Schnittstellen einzusetzen. Wenn Sie beispielsweise unter Windows die neueste Version der Microsoft Data Access Components (MDAC) verwenden, wird die Kompatibilität mit ODBC im Allgemeinen und mit dem MyODBC-Treiber im Besonderen besser.

25.1.6.2.1. MyODBC mit Microsoft-Anwendungen einsetzen

Die meisten Microsoft-Anwendungen wurden mit MyODBC getestet, einschließlich Microsoft Office, Microsoft Access und den verschiedenen von ASP und Microsoft Visual Studio unterstützten Programmiersprachen.

Wenn Sie mit MyODBC Probleme haben, aber Ihr Programm auch mit OLEDB funktioniert, sollten Sie den OLEDB-Treiber ausprobieren.

25.1.6.2.1.1. Microsoft Access

Die Integration von Microsoft Access und MySQL können Sie mit MyODBC wie folgt verbessern:

  • Für alle Access-Versionen sollten Sie die MyODBC-Option Übereinstimmende Zeilen zurückgeben einschalten. Für Access 2.0 sollten Sie zusätzlich die Option Simulate ODBC 1.0 aktivieren.

  • Alle Tabellen, die für Aktualisierungen zur Verfügung stehen sollen, müssen eine TIMESTAMP-Spalte haben. Um die größtmögliche Portierbarkeit zu erzielen, sollten Sie keine Länge in der Spaltendeklaration angeben (dies wird von MySQL-Versionen vor 4.1 nicht unterstützt).

  • Jede MySQL-Tabelle, die mit Access benutzt werden soll, benötigt einen Primärschlüssel. Ist dieser nicht vorhanden, können neu eingefügte oder aktualisierte Zeilen als #DELETED# erscheinen.

  • Verwenden Sie nur DOUBLE-Float-Felder. Access kann keine Float-Werte mit einfacher Genauigkeit vergleichen. Infolgedessen können neu eingefügte oder aktualisierte Zeilen als #DELETED# erscheinen, oder Sie können Zeilen nicht finden oder aktualisieren.

  • Wenn Sie MyODBC zum Verknüpfen einer Tabelle verwenden, die eine BIGINT-Spalte hat, werden die Ergebnisse als #DELETED# angezeigt. Der Workaround hierfür ist:

    • Sie richten eine oder mehrere Dummy-Spalten mit dem Datentyp TIMESTAMP ein.

    • Sie wählen die Option Change BIGINT columns to INT im Verbindungsdialog vom ODBC DSN Administrator.

    • Sie löschen die Tabellenverknüpfung aus Access und legen sie neu an.

    Eventuell werden alte Einträge immer noch als #DELETED# angezeigt, während neu eingefügte/aktualisierte Einträge richtig angezeigt werden.

  • Wenn Sie nach dem Hinzufügen einer TIMESTAMP-Spalte immer noch den Fehler Another user has changed your data bekommen, können Sie sich mit folgendem Trick behelfen:

    Verwenden Sie keine table-Datenblattansicht, sondern legen Sie ein Formular mit den gewünschten Feldern an und benutzen dann die form-Datenblattansicht. Die Eigenschaft DefaultValue der TIMESTAMP-Spalte setzen Sie auf NOW(). Am besten verbergen Sie die TIMESTAMP-Spalte, um die Benutzer nicht zu verwirren.

  • In manchen Fällen generiert Access SQL-Anweisungen, die MySQL nicht versteht. Dann wählen Sie "Query|SQLSpecific|Pass-Through" aus dem Access-Menü.

  • Auf Windows NT meldet Access BLOB-Spalten als OLE OBJECTS. Wenn Sie stattdessen MEMO-Spalten wünschen, wandeln Sie mit einem ALTER TABLE die BLOB-Spalten in TEXT-Spalten um.

  • Access kommt nicht immer mit der DATE-Spalte von MySQL zurecht. Wenn Sie deswegen Probleme haben, ändern Sie die Spalten in DATETIME-Spalten um.

  • Access versucht, BYTE-Spalten als TINYINT statt als TINYINT UNSIGNED zu exportieren. Das führt zu Problemen, wenn die Spalte größere Werte als 127 enthält.

  • Wenn Sie in Access äußerst große (long) Tabellen gespeichert haben, kann es lange dauern, sie zu öffnen. Oder es geht Ihnen der virtuelle Speicher aus, sodass Sie einen ODBC Query Failed-Fehler bekommen und die Tabelle sich gar nicht mehr öffnen lässt. Dies können Sie mit folgenden Optionen beheben:

    • Return Matching Rows (2)

    • Allow BIG Results (8)

    In der Summe ergibt das 10 (OPTION=10).

Einige externe Fachbeiträge und Tipps zu Access, ODBC und MyODBC sind recht nützlich:

25.1.6.2.1.2. Microsoft Excel und Spaltentypen

Wenn Sie Probleme mit dem Importieren von Daten in Microsoft Excel haben, insbesondere bei numerischen Werten sowie Datums- und Uhrzeitwerten, so liegt das wahrscheinlich an einem Excel-Bug: Der Datentyp für Einfügungen in Arbeitsblatt-Zellen wird anhand des Spaltentyps der Quelldaten bestimmt. Das führt dazu, dass Excel den Inhalt nicht richtig identifiziert, was sich sowohl auf das Anzeigeformat als auch auf Berechnungen auswirkt.

Dies beheben Sie, indem Sie in Ihren Anfragen die CONCAT()-Funktion einsetzen. So zwingen Sie Excel, den Wert als String zu behandeln: Excel parst dann den String und erkennt die darin enthaltenen Daten richtig.

Dennoch können manche Daten dann immer noch falsch formatiert werden, auch wenn die Quelldaten unverändert bleiben. Die Excel-Option Zellen formatieren ändert das Format der angezeigten Informationen.

25.1.6.2.1.3. Microsoft Visual Basic

Um eine Tabelle aktualisieren zu können, müssen Sie zuerst einen Primärschlüssel für die Tabelle definieren.

Visual Basic mit ADO kann mit großen Integern nicht umgehen. Das führt dazu, dass manche Anfragen, wie etwa SHOW PROCESSLIST, nicht richtig funktionieren. Dies beheben Sie mit OPTION=16384 im ODBC-Verbindungs-String oder indem Sie im MyODBC-Verbindungsbildschirm die Option Change BIGINT columns to INT aktivieren. Zugleich sollten Sie dann auch die Option Return matching rows einschalten.

25.1.6.2.1.4. Microsoft Visual InterDev

Wenn Ihre Ergebnismenge einen BIGINT enthält, kann der Fehler [Microsoft][ODBC Driver Manager] Driver does not support this parameter auftreten. Versuchen Sie in diesem Fall, die Option Change BIGINT columns to INT im MyODBC-Verbindungsbildschirm einzuschalten.

25.1.6.2.1.5. Visual Objects

Wählen Sie bitte die Option Don't optimize column widths.

25.1.6.2.1.6. Microsoft ADO

Wenn Sie die ADO-API und MyODBC verwenden, müssen Sie auf einige Standardeigenschaften achten, die vom MySQL Server nicht unterstützt werden. Wenn Sie beispielsweise CursorLocation Property als adUseServer verwenden, bekommen Sie für die RecordCount Property das Ergebnis –1 heraus. Um den richtigen Wert zu erhalten, müssen Sie diese Eigenschaft auf adUseClient setzen, wie es im nachfolgenden VB-Code getan wird:

Dim myconn As New ADODB.Connection
Dim myrs As New Recordset
Dim mySQL As String
Dim myrows As Long

myconn.Open "DSN=MyODBCsample"
mySQL = "SELECT * from user"
myrs.Source = mySQL
Set myrs.ActiveConnection = myconn
myrs.CursorLocation = adUseClient
myrs.Open
myrows = myrs.RecordCount

myrs.Close
myconn.Close

Ein anderer Workaround besteht darin, eine SELECT COUNT(*)-Anweisung für ähnliche Abfragen zu verwenden, um die richtige Zeilenzahl zu erhalten.

Um die Anzahl der von einer bestimmten SQL-Anweisung in ADO betroffenen Zeilen zu ermitteln, setzen Sie die Eigenschaft RecordsAffected in der ADO-Execute-Methode. Mehr über Execute-Methoden erfahren Sie unter http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdmthcnnexecute.asp.

Weitere Informationen gibt es unter ActiveX Data Objects (ADO) Frequently Asked Questions.

25.1.6.2.1.7. MyODBC mit Active Server Pages (ASP) verwenden

Sie sollten die Option Return matching rows im DSN aktivieren.

Weitere Informationen über den Zugriff auf MySQL mit ASP und MyODBC finden Sie in folgenden Fachbeiträgen:

Eine Liste häufig gestellter Fragen (FAQ) zu ASP finden Sie unter http://support.microsoft.com/default.aspx?scid=/Support/ActiveServer/faq/data/adofaq.asp.

25.1.6.2.1.8. MyODBC mit Visual Basic (ADO, DAO and RDO) und ASP verwenden

Folgende Beiträge bieten Hilfe zu Visual Basic und ASP:

25.1.6.2.2. MyODBC mit Borland-Anwendungen verwenden

Für alle Borland-Anwendungen, in denen die Borland Database Engine (BDE) benutzt wird, gelten folgende Hinweise zur Verbesserung der Kompatibilität:

  • Aktualisieren Sie auf BDE 3.2 oder neuer.

  • Aktivieren Sie die Option Don't optimize column widths im DSN.

  • Aktivieren Sie die Option Return matching rows im DSN.

25.1.6.2.2.1. MyODBC mit Borland Builder 4 verwenden

Wenn Sie eine Anfrage starten, können Sie die Eigenschaft Active oder die Methode Open einsetzen. Das Starten mit Active verläuft so, dass automatisch eine SELECT * FROM ...-Anfrage abgesetzt wird. Das kann nach hinten losgehen, wenn Ihre Tabellen zu groß sind.

25.1.6.2.2.2. MyODBC mit Delphi verwenden

Der nachfolgende Delphi-Code kann sehr nützlich sein, um sowohl einen ODBC- als auch einen BDE-Eintrag für MyODBC zu erstellen. Für den BDE-Eintrag ist ein BDE Alias Editor erforderlich, den Sie kostenlos bei einer Delphi Super Page in Ihrer Nähe bekommen können (Danke an Bryan Brunton für dieses Programm):

fReg:= TRegistry.Create;
fReg.OpenKey('\Software\ODBC\ODBC.INI\DocumentsFab', True);
fReg.WriteString('Database', 'Documents');
fReg.WriteString('Description', ' ');
fReg.WriteString('Driver', 'C:\WINNT\System32\myodbc.dll');
fReg.WriteString('Flag', '1');
fReg.WriteString('Password', '');
fReg.WriteString('Port', ' ');
fReg.WriteString('Server', 'xmark');
fReg.WriteString('User', 'winuser');
fReg.OpenKey('\Software\ODBC\ODBC.INI\ODBC Data Sources', True);
fReg.WriteString('DocumentsFab', 'MySQL');
fReg.CloseKey;
fReg.Free;

Memo1.Lines.Add('DATABASE NAME=');
Memo1.Lines.Add('USER NAME=');
Memo1.Lines.Add('ODBC DSN=DocumentsFab');
Memo1.Lines.Add('OPEN MODE=READ/WRITE');
Memo1.Lines.Add('BATCH COUNT=200');
Memo1.Lines.Add('LANGDRIVER=');
Memo1.Lines.Add('MAX ROWS=-1');
Memo1.Lines.Add('SCHEMA CACHE DIR=');
Memo1.Lines.Add('SCHEMA CACHE SIZE=8');
Memo1.Lines.Add('SCHEMA CACHE TIME=-1');
Memo1.Lines.Add('SQLPASSTHRU MODE=SHARED AUTOCOMMIT');
Memo1.Lines.Add('SQLQRYMODE=');
Memo1.Lines.Add('ENABLE SCHEMA CACHE=FALSE');
Memo1.Lines.Add('ENABLE BCD=FALSE');
Memo1.Lines.Add('ROWSET SIZE=20');
Memo1.Lines.Add('BLOBS TO CACHE=64');
Memo1.Lines.Add('BLOB SIZE=32');

AliasEditor.Add('DocumentsFab','MySQL',Memo1.Lines);
25.1.6.2.2.3. MyODBC mit C++ Builder verwenden

Ist getestet mit BDE 3.0. Das einzige bekannte Problem ist: Wenn sich das Tabellenschema ändert, werden die Felder der Anfrage nicht aktualisiert. Allerdings erkennt BDE offenbar auch keine Primärschlüssel, sondern nur den Index mit dem Namen PRIMARY, was allerdings bisher noch keine Probleme verursacht hat.

25.1.6.2.3. MyODBC mit ColdFusion verwenden

Die folgenden Informationen wurden der ColdFusion-Dokumentation entnommen:

Anhand der folgenden Informationen konfigurieren Sie den ColdFusion Server für Linux für die Benutzung des unixODBC-Treibers mit MyODBC für MySQL-Datenquellen. Allaire hat sichergestellt, dass MyODBC 2.50.26 mit MySQL 3.22.27 und ColdFusion für Linux funktioniert. (Auch alle neueren Versionen müssten funktionieren.) Sie können MyODBC unter folgender Adresse herunterladen: http://dev.mysql.com/downloads/connector/odbc/.

Die ColdFusion-Version 4.5.1 ermöglicht es, die MySQL-Datenquelle mit ColdFusion Administrator zu laden. Allerdings wird der Treiber mit der ColdFusion-Version 4.5.1 nicht mitgeliefert. Bevor der MySQL-Treiber in der Dropdown-Liste der ODBC-Datenquellen auftaucht, müssen Sie den MyODBC-Treiber bauen und in /opt/coldfusion/lib/libmyodbc.so kopieren.

Das Contrib-Verzeichnis enthält das Programm mydsn-xxx.zip, mit dem Sie die DSN-Registrierungsdatei für den MyODBC-Treiber in ColdFusion-Anwendungen erstellen und entfernen können.

Weitere Informationen und Hinweise für die Benutzung von ColdFusion und MyODBC finden Sie auf folgenden externen Sites:

25.1.6.2.4. MyODBC mit OpenOffice verwenden

Open Office (http://www.openoffice.org) How-to: MySQL + OpenOffice. How-to: OpenOffice + MyODBC + unixODBC

25.1.6.2.5. MyODBC mit Sambar Server verwenden

Sambar Server (http://www.sambarserver.info) How-to: MyODBC + SambarServer + MySQL

25.1.6.2.6. MyODBC mit Pervasive Software DataJunction verwenden

Sie müssen dafür sorgen, dass VARCHAR statt ENUM ausgegeben wird, da ENUM in einer Weise exportiert wird, die MySQL Schwierigkeiten verursacht.

25.1.6.2.7. MyODBC mit SunSystems Vision verwenden

Aktivieren Sie bitte die Option Return matching rows.

25.1.6.3. MyODBC-Fehler und Lösungen

Im folgenden Abschnitt geht es um häufige Fehler und ihre Behebung oder Alternativlösungen. Wenn Sie danach immer noch Probleme haben, nutzen Sie bitte die MyODBC-Mailingliste unter Abschnitt 25.1.7.1, „MyODBC: Community-Support“.

Viele Probleme lassen sich bereits durch einen Upgrade der MyODBC-Treiber auf die neueste verfügbare Version beheben. Unter Windows müssen Sie auch darauf achten, immer die neueste Version der Microsoft Data Access Components (MDAC) zu installieren.

Fragen

  • 26.1.6.3.1: Sind MyODBC 2.50-Anwendungen kompatibel mit MyODBC 3.51?

  • 26.1.6.3.2: Bei Transaktionen kommt es gelegentlich zu folgendem Fehler:

    Transactions are not enabled
  • 26.1.6.3.3: Der folgende Fehler tritt bei der Übermittlung einer Anfrage auf:

    Cursor not found
  • 26.1.6.3.4: Access meldet Datensätze als #DELETED#, wenn Einträge in verknüpften Tabellen eingefügt oder geändert werden.

  • 26.1.6.3.5: Wie gehe ich mit Write Conflicts oder Row Location-Fehlern um?

  • 26.1.6.3.6: Beim Exportieren von Daten aus Access 97 in MySQL wird ein Syntax Error gemeldet.

  • 26.1.6.3.7: Beim Exportieren von Daten aus Microsoft DTS in MySQL wird ein Syntax Error gemeldet.

  • 26.1.6.3.8: Wenn Sie ODBC.NET mit MyODBC benutzen, wird beim Abrufen von leeren Strings (Strings der Länge 0) die SQL_NO_DATA-Exception ausgelöst.

  • 26.1.6.3.9: Wenn Sie SELECT COUNT(*) FROM tbl_name in Visual Basic und ASP benutzen, wird ein Fehler gemeldet.

  • 26.1.6.3.10: Bei Verwendung der ADO-Methode AppendChunk() oder GetChunk() wird der Fehler Multiple-step operation generated errors. Check each status value gemeldet.

  • 26.1.6.3.11: Access gibt beim Bearbeiten von Einträgen einer verknüpften Tabelle Another user had modified the record that you have modified zurück.

Fragen und Antworten

26.1.6.3.1: Sind MyODBC 2.50-Anwendungen kompatibel mit MyODBC 3.51?

Anwendungen, die auf MyODBC 2.50 basieren, müssten auch mit MyODBC 3.51 und späteren Versionen gut funktionieren. Wenn Sie feststellen, dass etwas mit der neuesten Version von MyODBC nicht mehr funktioniert, was mit einer älteren Version noch geklappt hat, schicken Sie uns bitte einen Bugreport. Siehe hierzu Abschnitt 25.1.7.2, „Melden von MyODBC-Problemen und -Fehlern“.

26.1.6.3.2: Bei Transaktionen kommt es gelegentlich zu folgendem Fehler:

Transactions are not enabled

Dies bedeutet, dass Sie auf einer MySQL-Tabelle, die keine Transaktionen unterstützt, eine Transaktion versuchen. Transaktionen werden in MySQL nur von den Speicher-Engines InnoDB und BDB unterstützt.

Bitte prüfen Sie Folgendes:

  • Vergewissern Sie sich, dass Ihr MySQL Server eine transaktionsfähige Speicher-Engine verwendet. SHOW ENGINES zeigt Ihnen die Liste der verfügbaren Engines an.

  • Vergewissern Sie sich, dass die Tabellen, die Sie zu aktualisieren versuchen, eine transaktionsfähige Speicher-Engine verwenden.

  • Achten Sie darauf, dass im DSN nicht die Option disable transactions eingeschaltet ist.

26.1.6.3.3: Der folgende Fehler tritt bei der Übermittlung einer Anfrage auf:

Cursor not found

Dies bedeutet, dass die Anwendung die ältere Version MyODBC 2.50 verwendet und den Cursor-Namen nicht explizit mit SQLSetCursorName gesetzt hat. Dies beheben Sie durch einen Upgrade auf die Version MyODBC 3.51.

26.1.6.3.4: Access meldet Datensätze als #DELETED#, wenn Einträge in verknüpften Tabellen eingefügt oder geändert werden.

Wenn die eingefügten oder geänderten Datensätze als #DELETED# erscheinen:

  • Wenn Sie Access 2000 benutzen, installieren Sie bitte die neueste Version (2.6 oder höher) der Microsoft MDAC (Microsoft Data Access Components) von http://www.microsoft.com/data/. Darin wird ein Access-Fehler behoben, der dazu führt, dass bei einem Export von Daten in MySQL die Tabellen- und Spaltennamen nicht angegeben werden. Eine andere Möglichkeit besteht darin, auf MyODBC 2.50.33 oder höher und auf MySQL 3.23.x oder höher aufzurüsten, da beide gemeinsam einen Workaround für dieses Problem enthalten.

    Außerdem sollten Sie das Microsoft Jet 4.0 Service Pack 5 (SP5) anwenden, das unter http://support.microsoft.com/default.aspx?scid=kb;EN-US;q239114 zur Verfügung steht. Damit werden einige Fälle behoben, bei denen Access-Zeilen als #DELETED# erscheinen.

    Hinweis: Wenn Sie MySQL 3.22 verwenden, müssen Sie den MDAC-Patch anwenden und MyODBC 2.50.32 oder 2.50.34 (oder höher) installieren, um dieses Problem zu umgehen.

  • Für alle Versionen von Access müssen Sie die Option MyODBC Return matching rows einschalten. Für Access 2.0 sollten Sie zusätzlich die Option Simulate ODBC 1.0 aktivieren.

  • Alle Tabellen, die später updatefähig sein sollen, müssen einen Timestamp enthalten.

  • Jede Tabelle sollte einen Primärschlüssel haben, sonst können neue oder aktualisierte Zeilen als #DELETED# erscheinen.

  • Verwenden Sie nur DOUBLE-Float-Felder. Access kann Float-Werte mit einfacher Genauigkeit nicht vergleichen. Dies führt dazu, dass neue oder aktualisierte Zeilen als #DELETED# erscheinen oder nicht zu finden sind.

  • Wenn Sie MyODBC zur Verknüpfung einer Tabelle benutzen, die eine BIGINT-Spalte hat, werden die Ergebnisse als #DELETED angezeigt. Hierfür gibt es folgenden Workaround:

    • Richten Sie eine zusätzliche Dummy-Spalte mit dem Datentyp TIMESTAMP ein.

    • Wählen Sie im Verbindungsdialog vom ODBC DSN Administrator die Option Change BIGINT columns to INT.

    • Löschen Sie die Tabellenverknüpfung von Access und erstellen Sie sie neu.

    Alte Einträge werden weiterhin als #DELETED# angezeigt, aber neue oder geänderte erscheinen in der richtigen Form.

26.1.6.3.5: Wie gehe ich mit Write Conflicts oder Row Location-Fehlern um?

Bei folgenden Fehlern sollten Sie die Option Return Matching Rows im DSN-Konfigurationsdialog einstellen oder OPTION=2 als Verbindungsparameter angeben:

Write Conflict. Another user has changed your data.

Row cannot be located for updating. Some values may have been changed
since it was last read.

26.1.6.3.6: Beim Exportieren von Daten aus Access 97 in MySQL wird ein Syntax Error gemeldet.

Dieser Fehler ist spezifisch für Access 97 und MyODBC-Versionen, die älter sind als 3.51.02. Rüsten Sie auf die neueste Version des MyODBC-Treibers auf.

26.1.6.3.7: Beim Exportieren von Daten aus Microsoft DTS in MySQL wird ein Syntax Error gemeldet.

Dieser Fehler tritt nur bei MySQL-Tabellen auf, in denen die Datentypen TEXT oder VARCHAR vorkommen. Rüsten Sie Ihren MyODBC-Treiber auf die Version 3.51.02 oder höher auf.

26.1.6.3.8: Wenn Sie ODBC.NET mit MyODBC benutzen, wird beim Abrufen von leeren Strings (Strings der Länge 0) die SQL_NO_DATA-Exception ausgelöst.

Hierfür gibt es einen Patch unter http://support.microsoft.com/default.aspx?scid=kb;EN-US;q319243.

26.1.6.3.9: Wenn Sie SELECT COUNT(*) FROM tbl_name in Visual Basic und ASP benutzen, wird ein Fehler gemeldet.

Dieser Fehler tritt auf, weil der Ausdruck COUNT(*) einen BIGINT zurückliefert, mit dem ADO nichts anfangen kann. Wählen Sie die Option Change BIGINT columns to INT (Optionswert 16384).

26.1.6.3.10: Bei Verwendung der ADO-Methode AppendChunk() oder GetChunk() wird der Fehler Multiple-step operation generated errors. Check each status value gemeldet.

Die Methoden GetChunk() und AppendChunk() von ADO funktionieren nicht richtig, wenn der Cursor-Standort mit adUseServer angegeben wird. Das beheben Sie, indem Sie adUseClient verwenden.

Ein einfaches Beispiel finden Sie unter http://www.dwam.net/iishelp/ado/docs/adomth02_4.htm.

26.1.6.3.11: Access gibt beim Bearbeiten von Einträgen einer verknüpften Tabelle Another user had modified the record that you have modified zurück.

Dies lässt sich meistens durch eine der folgenden Maßnahmen lösen:

  • Sie geben der Tabelle einen Primärschlüssel, falls sie noch keinen hat.

  • Sie geben der Tabelle einen Timestamp, falls sie noch keinen hat.

  • Sie verwenden Float-Felder nur mit doppelter Genauigkeit. Manche Programme können Floats mit einfacher Genauigkeit nicht vergleichen.

Wenn dies alles nichts hilft, legen Sie eine Logdatei für den ODBC-Manager (das Log, das Sie bekommen, wenn Sie eines von ODBCADMIN anfordern) sowie ein MyODBC-Log an. So können Sie vielleicht dem Fehler auf die Spur kommen. Anleitungen finden Sie unter Abschnitt 25.1.3.8, „Erzeugen einer ODBC-Trace-Datei“.

25.1.7. MyODBC-Support

Es gibt viele Stellen, an denen Sie sich Hilfe zu MyODBC holen können. Schauen Sie immer als Erstes in die MyODBC-Mailingliste oder das MyODBC-Forum. Unter Abschnitt 25.1.7.1, „MyODBC: Community-Support“ erfahren Sie, was zu tun ist, ehe Sie einen Bug oder ein Problem an MySQL melden.

25.1.7.1. MyODBC: Community-Support

MySQL AB stellt der Benutzergemeinde via Mailingliste Hilfe zur Verfügung. Bei MyODBC-Problemen helfen Ihnen erfahrene Nutzer in der Mailingliste weiter. Die Archive stehen online unter http://lists.mysql.com/myodbc zur Verfügung.

Wie Sie die MySQL-Mailinglisten abonnieren oder die Archive durchforsten können, erfahren Sie unter http://lists.mysql.com/. Siehe Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

Support von erfahrenen Benutzern bekommen Sie auch im MyODBC Forum sowie in den anderen MySQL-Foren unter http://forums.mysql.com. Siehe Abschnitt 1.7.2, „MySQL-Community-Support in den MySQL-Foren“.

25.1.7.2. Melden von MyODBC-Problemen und -Fehlern

Bei Schwierigkeiten oder Problemen mit MyODBC sollten Sie als Erstes eine Logdatei mit dem ODBC Manager (das Log, das Sie erhalten, wenn Sie eines von ODBC ADMIN anfordern) und für MyODBC anlegen. Wie das geht, erfahren Sie unter Abschnitt 25.1.3.8, „Erzeugen einer ODBC-Trace-Datei“.

Vielleicht finden Sie in der MyODBC-Trace-Datei die Fehlerursache. Der String >mysql_real_query im myodbc.log verrät Ihnen, welche Anweisungen abgesetzt wurden.

Außerdem können Sie versuchen, die Anweisungen aus dem mysql-Clientprogramm oder admndemo einzugeben. So können Sie herausfinden, ob das Problem an MyODBC oder MySQL liegt.

Wenn Sie feststellen, dass etwas schief geht, senden Sie bitte nur die relevanten Zeilen (maximal 40) an die myodbc-Mailingliste. Siehe auch Abschnitt 1.7.1, „Die MySQL-Mailinglisten“. Senden Sie bitte niemals die gesamte MyODBC- oder ODBC-Logdatei!

Im Idealfall sollte Ihre E-Mail folgende Informationen enthalten:

  • Betriebssystem und Version

  • MyODBC-Version

  • ODBC-Treiber-Manager-Typ und -Version

  • MySQL Server-Version

  • ODBC-Trace vom Treiber-Manager

  • MyODBC-Logdatei vom MyODBC-Treiber

  • ein einfaches, reproduzierbares Beispiel

Denken Sie daran: Je mehr Informationen Sie uns geben können, umso wahrscheinlicher ist es, dass wir eine Lösung finden!

Schauen Sie jedoch immer in das Archiv der MyODBC-Mailingliste, ehe Sie uns einen Fehler melden: http://lists.mysql.com/myodbc.

Wenn Sie nicht herausfinden können, wo das Problem liegt, können Sie als letztes Mittel ein Archiv im tar- oder Zip-Format anlegen, das eine MyODBC-Trace-Datei, die ODBC-Logdatei und eine README-Datei mit einer Problembeschreibung enthält. Diese können Sie an ftp://ftp.mysql.com/pub/mysql/upload/ senden. Nur MySQL-Ingenieure haben Zugriff auf die Dateien, die Sie hochladen, und wir gehen sehr diskret mit den Daten um.

Wenn Sie ein Programm schreiben können, welches das Problem demonstriert, fügen Sie es bitte ebenfalls dem Archiv hinzu.

Wenn das Programm mit einem anderen SQL-Server läuft, legen Sie bitte eine ODBC-Logdatei bei, in der genau dieselben SQL-Anweisungen ausgeführt werden, damit wir die Ergebnisse der beiden Systeme miteinander vergleichen können.

Wieder gilt: Je mehr Informationen Sie uns geben können, umso wahrscheinlicher ist es, dass wir eine Lösung finden.

25.1.7.3. Wie man einen MyODBC-Patch übermittelt

Einen Patch oder Lösungsvorschlag für vorhandenen Code oder bekannte Probleme übermitteln Sie bitte per E-Mail an .

25.1.7.4. Danksagungen

Die folgenden Entwickler haben an der Entwicklung von MyODBC und den MyODBC 3.51-Treibern von MySQL AB mitgearbeitet.

  • Michael (Monty) Widenius

  • Venu Anuganti

  • Peter Harvey

25.2. Connector/NET

Mit Connector/NET lassen sich .NET-Anwendungen entwickeln, die sichere und leistungsfähige Datenbankverbindungen mit MySQL benutzen. Connector/NET implementiert die erforderlichen ADO.NET-Schnittstellen und lässt sich in ADO.NET-fähige Tools integrieren. Die Entwickler können ihre Anwendungen in den .NET-Sprachen ihrer Wahl schreiben. Connector/NET ist ein vollständig verwalteter ADO.NET-Treiber, der zu 100 % in C# geschrieben wurde.

Connector/NET bietet volle Unterstützung für:

  • MySQL 5.0-Features (beispielsweise gespeicherte Prozeduren)

  • MySQL 4.1-Features (vorbereitete Anweisungen auf der Serverseite, Unicode, Shared Memory-Zugriff usw.)

  • große Pakete zum Senden und Empfangen von bis zu 2 Gbyte großen Zeilen und BLOBs

  • Protokollkompression zum Komprimieren des Datenstroms zwischen Client und Server

  • Verbindung über TCP/IP-Sockets, Named Pipes oder Shared Memory auf Windows

  • Verbindung über TCP/IP-Sockets oder Unix-Sockets auf Unix

  • Open Source Mono-Framework von Novell

  • vollständig verwaltet, benutzt keine MySQL-Clientbibliothek

Dieses Dokument soll den Benutzer zur Verwendung von Connector/NET anleiten und enthält eine vollständige Syntaxreferenz. Syntaxinformationen finden Sie auch in der Datei Documentation.chm in Ihrer Connector/NET-Distribution.

25.2.1. Versionen von Connector/NET

Gegenwärtig ist nur eine Version von Connector/NET erhältlich:

  • Connector/NET 1.0 bietet Unterstützung für die Features von MySQL 4.0 und MySQL 5.0 sowie volle Kompatibilität mit dem ADO.NET-Treiber.

25.2.2. Installation von Connector/NET

Connector/NET läuft auf jeder Plattform, die das .NET-Framework unterstützt. Das ist vor allem bei den neueren Versionen von Microsoft Windows der Fall, sowie bei Linux über das Open Source Mono-Framework (siehe http://www.mono-project.com).

Connector/NET können Sie von folgender Adresse herunterladen: http://dev.mysql.com/downloads/connector/net/1.0.html.

25.2.2.1. Installation von Connector/NET auf Windows

Auf Windows installieren Sie Connector/NET entweder mit einer Binärversion oder aus einer heruntergeladenen Zip-Datei mit den Connector/NET-Komponenten.

Vor der Installation müssen Sie sicherstellen, dass Ihr System aktuell ist und dass Sie die neueste Version von .NET besitzen.

25.2.2.1.1. Installation von Connector/NET mit dem Installer

Mit dem Installer gelingt die Installation von Connector/NET auf Windows am einfachsten. Er installiert den Quellcode, den Testcode und die vollständige Referenzdokumentation.

Connector/NET wird auf allen Windows-Betriebssystemen mit einem Windows-Installer (.msi-Installations-Package) installiert. Das MSI-Package liegt in einem ZIP-Archiv namens mysql-connector-net-version.zip, wobei version die Connector/NET-Version ist.

Connector/NET installieren Sie wie folgt:

  1. Führen Sie einen Doppelklick auf die aus der heruntergeladenen Zip-Datei extrahierte MSI-Installer-Datei aus. Mit einem Klick auf Next starten Sie die Installation.

    Connector/NET Windows Installer -
                Begrüßungsseite
  2. Sie müssen den gewünschten Installationstyp auswählen.

    Connector/NET Windows Installer -
                Installationstyp

    Für die meisten Fälle eignet sich die typische Installation. Klicken Sie also auf Typical und fahren Sie fort mit Schritt 5. Mit der vollständigen (Complete) Installation installieren Sie sämtliche verfügbaren Dateien. Hierzu klicken Sie auf die Schaltfläche Complete und machen dann mit Schritt 5 weiter. Wenn Sie eine benutzerdefinierte Installation bevorzugen und die zu installierenden Komponenten und Optionen selbst auswählen möchten, klicken Sie auf Custom und machen mit Schritt 3 weiter.

  3. Bei der benutzerdefinierten Installation können Sie die einzelnen zu installierenden Komponenten selbst aussuchen, einschließlich der Core-Interface-Komponente, der Dokumentation (einer CHM-Datei), Beispielen und des Quellcodes. Wählen Sie die zu installierenden Bestandteile aus und klicken Sie auf Next.

    Connector/NET Windows Installer -
                Benutzerdefinierte Installation
  4. Bei einer benutzerdefinierten Installation können Sie auch entscheiden, ob die Connector/NET-Komponente im Global Assembly Cache registriert werden soll. Dann steht Connector/NET allen Anwendungen zur Verfügung, nicht nur denen, die explizit auf Connector/NET verweisen. Sie können auch die Erzeugung von entsprechenden Symbolen im Startmenü aktivieren oder deaktivieren. Wenn Sie die notwendigen Optionen ausgewählt haben, klicken Sie wieder auf Next.

    Connector/NET Windows Installer -
                Setup-Optionen
  5. Zum Schluss haben Sie Gelegenheit, die Installation zu bestätigen. Klicken Sie auf Install, um die Dateien auf Ihren Computer zu übertragen und zu installieren.

    Connector/NET Windows Installer -
                Installation bestätigen
  6. Ist die Installation abgeschlossen, schließen Sie den Installer mit einem Klick auf Finish.

Wenn Sie nichts anderes eingestellt haben, wird Connector/NET C:\Program Files\MySQL\MySQL Connector Net X.X.X installiert, wobei X.X.X die installierte Version von Connector/NET ist. Neue Installationen werden die vorhandenen Versionen von Connector/NET nicht überschreiben.

Je nach Installationstyp werden einige oder alle der folgenden Komponenten installiert:

  • bin – Connector/NET MySQL-Bibliotheken für verschiedene Versionen der .NET-Umgebung

  • docs – enthält eine CHM der Connector/NET-Dokumentation

  • samples – Beispielcode und -anwendungen, die die Connector/NET-Komponente nutzen

  • src – der Quellcode für die Connector/NET-Komponente

25.2.2.1.2. Installation von Connector/NET aus dem Zip-Archiv

Wenn Sie Schwierigkeiten mit dem Installer haben, können Sie auch eine .zip-Datei ohne Installer herunterladen. Diese Datei heißt mysql-connector-net-version-noinstall.zip. Die darin enthaltenen Dateien extrahieren Sie in ein Verzeichnis Ihrer Wahl.

Die .zip-Datei enthält folgende Verzeichnisse:

  • bin - Connector/NET MySQL-Bibliotheken für verschiedene Versionen von .NET

  • doc – eine CHM-Version der Connector/NET-Dokumentation

  • Samples – Beispielcode und -anwendungen, die die Connector/NET-Komponente nutzen

  • mysqlclient – der Quellcode für die Connector/NET-Komponente

  • testsuite – Testsuite zur Funktionsprüfung der Connector/NET-Komponente.

25.2.2.1.3. Installation von Connector/NET auf Unix mit Mono

Es gibt keinen Installer für Connector/NET auf Unix, aber die Installation ist dennoch ganz einfach. Vorher müssen Sie gewährleisten, dass Sie über eine funktionierende Mono-Installation verfügen.

Installieren Sie Connector/NET bitte nur auf Unix, wenn Sie sich mit einem MySQL Server über Mono verbinden wollen. Möchten Sie Connector/NET in einer anderen Umgebung, wie beispielsweise Java oder Perl, installieren oder damit arbeiten, wählen Sie bitte eine passendere Komponente für die Verbindungen aus. Weitere Informationen finden Sie unter Kapitel 25, Connectors, oder Kapitel 24, APIs und Bibliotheken.

Um Connector/NET auf Unix/Mono zu installieren, gehen Sie folgendermaßen vor:

  1. Laden Sie mysql-connector-net-version-noinstall.zip herunter und extrahieren Sie den Inhalt.

  2. Kopieren Sie die Datei MySql.Data.dll in Ihren Installationsordner für das Mono-Projekt.

  3. Mit folgendem gacutil-Befehl registrieren Sie die Connector/NET-Komponente im Global Assembly Cache:

    shell> gacutil /i MySql.Data.dll

Nach der Installation sind an Anwendungen, die mit der Connector/NET-Komponente installiert wurden, keine weiteren Änderungen mehr erforderlich. Sie müssen allerdings darauf achten, die Connector/NET-Komponente mit der Kommandozeilenoption -r:MySqlData.dll beim Kompilieren Ihrer Anwendungen einzubinden.

25.2.2.2. Installation von Connector/NET aus der Quelldistribution

Vorsicht: Diesen Abschnitt sollten Sie nur lesen, wenn Sie uns beim Testen des neuen Codes unterstützen möchten. Wenn Sie lediglich Connector/NET auf Ihrem System zum Laufen bringen möchten, verwenden Sie am besten eine Standarddistribution.

Um auf den Connector/NET-Quellbaum zugreifen zu können, müssen Sie Subversion installieren. Sie erhalten Subversion kostenlos von http://subversion.tigris.org/.

Den aktuellsten Entwicklungsquellbaum erhalten Sie in unseren öffentlichen Subversion-Bäumen unter http://dev.mysql.com/tech-resources/sources.html.

Um die Quelldateien von Connector/NET auszuchecken, gehen Sie in das Verzeichnis, in welches Sie den Connector/NET-Baum kopieren möchten, und geben folgenden Befehl ein:

shell> svn co
http://svn.mysql.com/svnpublic/connector-net

Die Quelldateien enthalten auch ein Visual Studio-Projekt, das Sie nutzen können, um Connector/NET zu bauen.

25.2.3. Hinweise und Tipps zu Connector/NET

Dieser Abschnitt behandelt einige häufige Einsatzgebiete für Connector/NET, darunter den Umgang mit BLOBs und Datumswerten sowie die Kombination von Connector/NET mit gebräuchlichen Tools wie Crystal Reports.

25.2.3.1. MySQL-Verbindung mit Connector/NET

25.2.3.1.1. Einleitung

Jegliche Interaktion zwischen einer .NET-Anwendung und einem MySQL Server vollzieht sich durch ein MySqlConnection-Objekt. Also muss, ehe Sie mit dem Server kommunizieren können, zunächst ein MySqlConnection-Objekt erzeugt, konfiguriert und geöffnet werden.

Auch wenn die Klasse MySqlHelper benutzt wird, wird ein MySqlConnection-Objekt von dieser Hilfsklasse angelegt.

In diesem Abschnitt wird beschrieben, wie man über das MySqlConnection-Objekt mit MySQL Verbindung aufnimmt.

25.2.3.1.2. Verbindungs-String erstellen

Das MySqlConnection-Objekt ist für einen Verbindungs-String konfiguriert. Dieser String enthält mehrere, durch Semikola getrennte Schlüssel/Wert-Paare, die jeweils durch ein Gleichheitszeichen verbunden sind.

Sehen Sie hier ein Beispiel für einen Verbindungs-String:

    Server=127.0.0.1;Uid=root;Pwd=12345;Database=test;
    

In diesem Beispiel ist das MySqlConnection-Objekt so konfiguriert, dass es sich mit einem MySQL Server auf 127.0.0.1 verbindet und dazu den Benutzernamen root und das Passwort 12345 verwendet. Als Standarddatenbank für alle Anweisungen benutzen wir test.

Die folgenden Optionen werden typischerweise gesetzt (eine vollständige Liste der Optionen finden Sie in der nachfolgenden Tabelle):

  • Server: Der Name oder die Netzwerkadresse der MySQL-Instanz, mit der Verbindung aufgenommen werden soll. Der Standardwert ist localhost. Aliase sind host, Data Source, DataSource, Address, Addr und Network Address.

  • Uid: Das MySQL-Benutzerkonto, das für die Verbindung genutzt wird. Aliase sind User Id, Username und User name.

  • Pwd: Das Passwort für das verwendete MySQL-Konto. Der Alias Password kann ebenfalls gesetzt werden.

  • Database: Die Standarddatenbank, auf die alle Anweisungen angewendet werden. Der Standardwert lautet mysql, aber es kann auch der Alias Initial Catalog verwendet werden.

  • Port: Der Port, auf dem MySQL auf Verbindungen lauscht. Der Standardwert ist 3306. Wenn Sie hier -1 einsetzen, wird eine Named-Pipe-Verbindung verwendet.

Die folgende Tabelle führt die Namen für alle zulässigen Schlüsselwortwerte des ConnectionStrings auf.

NameStandardwertBeschreibung
Connect Timeout -oder- Connection Timeout15So viele Sekunden wird auf eine Serververbindung gewartet, ehe der Versuch abgebrochen und ein Fehler ausgelöst wird.
Host -oder- Server -oder- Data Source -oder- DataSource -oder- Address -oder- Addr -oder- Network AddresslocalhostName oder Netzwerkadresse der MySQL-Instanz, mit der Verbindung aufgenommen wird. Es können mehrere, durch & getrennte Hosts angegeben werden. Das kann praktisch sein, wenn mehrere MySQL Server für die Replikation konfiguriert wurden und Sie nicht wissen, mit welchem Server Sie sich verbinden. Da der Provider Schreibvorgänge auf der Datenbank nicht synchronisiert, müssen Sie mit dieser Option vorsichtig sein. In einer Unix-Umgebung mit Mono kann dies ein vollqualifizierter Pfad zu einer MySQL-Socketdatei sein. Dann wird der Unix-Socket anstelle des TCP/IP-Sockets benutzt. Da zurzeit nur ein einziger Socketname angegeben werden kann, wird der MySQL-Zugriff in einer Replikationsumgebung über Unix-Sockets aktuell noch nicht unterstützt.
Port3306Der Port, auf dem MySQL auf Verbindungen lauscht. Wenn Sie hier -1 angeben, wird eine Named-Pipe-Verbindung benutzt (nur Windows). Dieser Wert wird bei Verwendung von Unix-Socket ignoriert.
ProtocolsocketGibt an, welche Art von Serververbindung eingerichtet wird. Mögliche Werte sind: socket oder tcp für eine Socketverbindung, pipe für eine Named-Pipe-Verbindung, unix für eine Unix-Socketverbindung und memory für MySQL-Shared Memory
CharSet -oder- Character Set Der Zeichensatz, mit dem alle an den Server gesandten Anfragen kodiert werden. Ergebnismengen werden weiterhin in dem Zeichensatz der Rückgabedaten kodiert.
LoggingfalseIst diese Option true, werden diverse Informationen an die eingestellten TraceListeners ausgegeben.
Allow BatchtrueIst diese Option true, können mehrere SQL-Anweisungen mit einem einzigen Befehl ausgeführt werden. Hinweis: Seit MySQL 4.1.1 müssen Batch-Anweisungen durch das für den Server definierte Trennzeichen voneinander abgesetzt werden. Für frühere Versionen von MySQL ist ';' das Trennzeichen.
EncryptfalseIst diese Option true, wird für alle zwischen Client und Server übermittelten Daten SSL-Verschlüsselung verwendet, wenn auf dem Server ein Zertifikat installiert ist. Zulässige Werte sind true, false, yes und no. Hinweis: Dieser Parameter ist zurzeit wirkungslos.
Initial Catalog -oder- DatabasemysqlDer Name der Datenbank, die anfangs genutzt wird
Password -oder- pwd Das Passwort für das verwendete MySQL-Konto
Persist Security InfofalseIst diese Option false oder no (was dringend empfohlen wird), werden sicherheitsrelevante Daten wie beispielsweise das Passwort nicht mit der Verbindung zurückgegeben, wenn die Verbindung geöffnet ist oder jemals war. Mit dem Verbindungs-String werden auch alle darin enthaltenen Werte zurückgesetzt, einschließlich des Passworts. Zulässige Werte sind true, false, yes und no.
User Id -oder- Username -oder- Uid -oder- User name Das für das Login verwendete MySQL-Konto
Shared Memory NameMYSQLDer Name des Shared Memory-Objekts, das für die Kommunikation genutzt wird, wenn das Verbindungsprotokoll auf "memory" gesetzt wurde.
Allow Zero DatetimefalseStellen Sie dies auf true, wenn MySqlDataReader.GetValue() für Datums-/Uhrzeitspalten, die unzulässige Werte aufweisen, eine MySqlDateTime zurückgeben soll, und auf false, wenn nur für zulässige Werte ein DateTime-Objekt, aber für unzulässige eine Ausnahme zurückgegeben werden soll.
Convert Zero DatetimefalseIst diese Option true, geben MySqlDataReader.GetValue() und MySqlDataReader.GetDateTime() für Datums- oder Datums-/Uhrzeitspalten, die unzulässige Werte aufweisen, DateTime.MinValue zurück.
Old Syntax -oder- OldSyntaxfalseErlaubt '@' als Parameterkennzeichen. Mehr darüber in MySqlCommand. Dient nur der Kompatibilität. Zukünftig soll immer das Parameterkennzeichen '?' benutzt werden.
Pipe Name -oder- PipemysqlIst diese der Name einer Named Pipe, versucht MySqlConnection, diese zur Verbindung zu nutzen. Gilt nur für Windows.
25.2.3.1.3. Eine Verbindung öffnen

Sobald Sie den Verbindungs-String angelegt haben, können Sie ihn nutzen, um eine Verbindung zu einem MySQL Server damit aufzubauen.

Der folgende Code erzeugt ein MySqlConnection-Objekt, weist den Verbindungs-String zu und öffnet die Verbindung.

Visual Basic-Beispiel

Dim conn As New MySql.Data.MySqlClient.MySqlConnection
Dim myConnectionString as String

myConnectionString = "server=127.0.0.1;" _
            & "uid=root;" _
            & "pwd=12345;" _
            & "database=test;"

Try
  conn.ConnectionString = myConnectionString
  conn.Open()

Catch ex As MySql.Data.MySqlClient.MySqlException
  MessageBox.Show(ex.Message)
End Try
  

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
string myConnectionString;
    
myConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";
  
try
{
    conn = new MySql.Data.MySqlClient.MySqlConnection();
    conn.ConnectionString = myConnectionString;
    conn.Open();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show(ex.Message);
}

Sie können den Verbindungs-String auch an den Klassenkonstruktor von MySqlConnection übergeben:

Visual Basic-Beispiel

Dim myConnectionString as String

myConnectionString = "server=127.0.0.1;" _
              & "uid=root;" _
              & "pwd=12345;" _
              & "database=test;" 

Try
    Dim conn As New MySql.Data.MySqlClient.MySqlConnection(myConnectionString)
    conn.Open()
Catch ex As MySql.Data.MySqlClient.MySqlException
   MessageBox.Show(ex.Message)
End Try
  

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
string myConnectionString;

myConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

try
{
    conn = new MySql.Data.MySqlClient.MySqlConnection(myConnectionString);
    conn.Open();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show(ex.Message);
}

Sobald die Verbindung geöffnet ist, können auch andere Connector/NET-Klassen sie zur Kommunikation mit dem MySQL Server nutzen.

25.2.3.1.4. Behandlung von Verbindungsfehlern

Da eine Verbindung mit einem externen Server immer Unwägbarkeiten in sich birgt, muss Ihre .NET-Anwendung auch mit Fehlern umgehen können. Tritt bei der Verbindung ein Fehler auf, gibt die Klasse MySqlConnection ein MySqlException-Objekt zurück. Dieses Objekt hat zwei Eigenschaften, die für die Fehlerbehandlung interessant sind:

  • Message: eine Meldung, die die Ausnahme beschreibt

  • Number: die MySQL-Fehlernummer

Sie können die Reaktion Ihrer Anwendung auf Fehler auf der Basis der Fehlernummer gestalten. Die beiden Fehler, die bei Verbindungsproblemen am häufigsten auftreten, sind:

  • 0: Serververbindung nicht möglich

  • 1045: Benutzername und/oder Passwort ungültig

Der folgende Code zeigt, wie die Anwendung auf die jeweilige Fehlernummer reagieren kann:

Visual Basic-Beispiel

Dim myConnectionString as String

myConnectionString = "server=127.0.0.1;" _
          & "uid=root;" _
          & "pwd=12345;" _
          & "database=test;" 

Try
    Dim conn As New MySql.Data.MySqlClient.MySqlConnection(myConnectionString)
    conn.Open()
Catch ex As MySql.Data.MySqlClient.MySqlException
    Select Case ex.Number
        Case 0
            MessageBox.Show("Cannot connect to server. Contact administrator")
        Case 1045
            MessageBox.Show("Invalid username/password, please try again")
    End Select
End Try
  

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
string myConnectionString;

myConnectionString = "server=127.0.0.1;uid=root;" +  
    "pwd=12345;database=test;";

try
{
    conn = new MySql.Data.MySqlClient.MySqlConnection(myConnectionString);
    conn.Open();
}
    catch (MySql.Data.MySqlClient.MySqlException ex)
{
    switch (ex.Number)
    {
        case 0:
            MessageBox.Show("Cannot connect to server.  Contact administrator");
        case 1045:
            MessageBox.Show("Invalid username/password, please try again");
    }
}
  

Wichtig: Wenn Sie Datenbanken mit mehreren Sprachen verwenden, müssen Sie den jeweiligen Zeichensatz im Verbindungs-String angeben, sonst wird latin1 als Standardzeichensatz zugrunde gelegt. Ein Beispiel für die Angabe eines Zeichensatzes im Verbindungs-String folgt:

MySqlConnection myConnection = new MySqlConnection("server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;Charset=latin1;");

25.2.3.2. Connector/NET mit vorbereiteten Anweisungen verwenden

25.2.3.2.1. Einleitung

Seit MySQL 4.1 ist es möglich, vorbereitete Anweisungen mit Connector/NET zu verwenden. Diese können bei Anfragen, die immer wieder ausgeführt werden müssen, die Leistung massiv steigern.

Die vorbereitete Ausführung von Anweisungen ist viel schneller als die direkte Ausführung, da die Anfrage nur ein einziges Mal geparst werden muss. Bei einer Direktausführung müsste sie jedes Mal von neuem geparst werden. Außerdem kann die vorbereitete Ausführung die Netzwerklast reduzieren, da bei der Ausführung einer vorbereiteten Anweisung nur die Parameterdaten übermittelt werden müssen.

Ein weiterer Vorteil vorbereiteter Anweisungen ist die Verwendung eines Binärprotokolls, das die Datenübertragung zwischen Client und Server beschleunigt.

25.2.3.2.2. Anweisungen vorbereiten in Connector/NET

Um eine Anweisung vorzubereiten, erzeugen Sie ein Befehlsobjekt und stellen die Eigenschaft .CommandText auf Ihre Anfrage ein.

Nach dem Eintritt in die Anweisung rufen Sie die .Prepare-Methode des MySqlCommand-Objekts auf. Ist die Anweisung vorbereitet, fügen Sie die Parameter für die dynamischen Elemente der Anfrage hinzu.

Danach führen Sie die Anweisung mit .ExecuteNonQuery()-, .ExecuteScalar()- oder .ExecuteReader-Methoden aus.

Für jede weitere Ausführung müssen Sie nur noch die Parameterwerte einstellen und dann die Ausführungsmethode erneut aufrufen. Es ist nicht mehr erforderlich, die .CommandText-Eigenschaft zu setzen oder die Parameter umzudefinieren.

Visual Basic-Beispiel

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
  
conn.ConnectionString = strConnection

Try
   conn.Open()
   cmd.Connection = conn
 
   cmd.CommandText = "INSERT INTO myTable VALUES(NULL, ?number, ?text)"
   cmd.Prepare()

   cmd.Parameters.Add("?number", 1)
   cmd.Parameters.Add("?text", "One")

   For i = 1 To 1000
       cmd.Parameters["?number"].Value = i
       cmd.Parameters["?text"].Value = "A string value"

       cmd.ExecuteNonQuery()
     Next 
Catch ex As MySqlException
    MessageBox.Show("Error " & ex.Number & " has occurred: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
  

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
  
conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

conn.ConnectionString = strConnection;

try
{
    conn.Open();
    cmd.Connection = conn;

    cmd.CommandText = "INSERT INTO myTable VALUES(NULL, ?number, ?text)";
    cmd.Prepare();

    cmd.Parameters.Add("?number", 1);
    cmd.Parameters.Add("?text", "One");

    for (int i=1; i <= 1000; i++)
    {
        cmd.Parameters["?number"].Value = i;
        cmd.Parameters["?text"].Value = "A string value";

        cmd.ExecuteNonQuery();
    }
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

25.2.3.3. Zugriff auf gespeicherte Prozeduren mit Connector/NET

25.2.3.3.1. Einleitung

Seit der MySQL-Version 5 kennt der MySQL Server nun auch gespeicherte Prozeduren mit der Syntax von SQL 2003.

Eine gespeicherte Prozedur besteht in einer Reihe von SQL-Anweisungen, die im Server gespeichert werden können. fortan müssen die Clients keine individuellen Anweisungen mehr geben, sondern können stattdessen auf die gespeicherte Prozedur verweisen.

Gespeicherte Prozeduren können vor allem in folgenden Situationen nützlich sein:

  • Wenn mehrere Clientanwendungen in verschiedenen Sprachen für unterschiedliche Plattformen geschrieben wurden, aber dieselben Datenbankoperationen ausführen.

  • In Hochsicherheitsumgebungen. Banken nutzen beispielsweise für alle häufigen Operationen gespeicherte Prozeduren. So bleibt die Umgebung konsistent und sicher, und die Prozeduren sorgen dafür, dass jede Operation ordentlich protokolliert wird. In einer solchen Konstellation haben Anwendungen und Benutzer keinen Direktzugriff auf die Datenbanktabellen, sondern können lediglich bestimmte gespeicherte Prozeduren ausführen.

Connector/NET unterstützt den Aufruf von gespeicherten Prozeduren mit dem MySqlCommand-Objekt. Zur Übergabe von Daten in die und aus der gespeicherten Prozedur von MySQL dient die MySqlCommand.Parameters-Collection.

Hinweis:  Wenn Sie eine gespeicherte Prozedur aufrufen, setzt das Befehlsobjekt einen zusätzlichen SELECT-Aufruf ab, um die Parameter der gespeicherten Prozedur zu ermitteln. Sie müssen sicherstellen, dass der Benutzer, der die Prozedur aufruft, die SELECT-Berechtigung für die mysql.proc-Tabelle besitzt, um die Parameter überprüfen zu können. Sonst wird beim Aufruf der Prozedur ein Fehler ausgelöst.

Eine tiefer gehende Erörterung zu gespeicherten Prozeduren finden Sie in http://dev.mysql.com/doc/mysql/en/stored-procedures.html, aber nicht im vorliegenden Abschnitt.

Eine Beispielanwendung zur Verwendung von gespeicherten Prozeduren mit Connector/NET finden Sie im Samples-Verzeichnis Ihrer Connector/NET-Installation.

25.2.3.3.2. Erstellung von gespeicherten Prozeduren mit Connector/NET

In MySQL gibt es mehrere Möglichkeiten, gespeicherte Prozeduren anzulegen. Erstens können gespeicherte Prozeduren mit dem Kommandozeilen-Client mysql erzeugt werden, zweitens mit dem GUI-Client MySQL Query Browser und drittens mit der .ExecuteNonQuery-Methode des MySqlCommand-Objekts:

Visual Basic-Beispiel

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand

conn.ConnectionString = "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=test"

Try
    conn.Open()
    cmd.Connection = conn

    cmd.CommandText = "CREATE PROCEDURE add_emp(" _
        & "IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT) " _
        & "BEGIN INSERT INTO emp(first_name, last_name, birthdate) " _
        & "VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END"
 
    cmd.ExecuteNonQuery()
Catch ex As MySqlException
    MessageBox.Show("Error " & ex.Number & " has occurred: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

try
{
    conn.Open();
    cmd.Connection = conn;

    cmd.CommandText = "CREATE PROCEDURE add_emp(" +
        "IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT) " +
        "BEGIN INSERT INTO emp(first_name, last_name, birthdate) " +
        "VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END";

    cmd.ExecuteNonQuery();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Wenn Sie gespeicherte Prozeduren in Connector/NET anlegen, sind Sie, anders als beim Kommandozeilen- oder GUI-Client, nicht auf ein bestimmtes Trennzeichen festgelegt.

25.2.3.3.3. Aufruf einer gespeicherten Prozedur mit Connector/NET

Um eine gespeicherte Prozedur mit Connector/NET aufzurufen, erzeugen Sie ein MySqlCommand-Objekt und übergeben den Namen der Prozedur als .CommandText-Eigenschaft. Setzen Sie die .CommandType-Eigenschaft auf CommandType.StoredProcedure.

Auf die Angabe der gespeicherten Prozedur folgt für jeden ihrer Parameter ein MySqlCommand-Parameter. IN-Parameter werden mit ihrem Namen und dem Objekt, das ihren Wert enthält, definiert, und OUT-Parameter mit ihrem Namen und dem erwarteten Rückgabe-Datentyp. Alle Parameter müssen mit Richtung definiert werden.

Sind die Parameter angelegt, so kann die gespeicherte Prozedur mit der Methode MySqlCommand.ExecuteNonQuery() aufgerufen werden:

Visual Basic-Beispiel

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand

conn.ConnectionString = "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=test"

Try
    conn.Open()
    cmd.Connection = conn

    cmd.CommandText = "add_emp"
    cmd.CommandType = CommandType.StoredProcedure

    cmd.Parameters.Add("?lname", 'Jones')
    cmd.Parameters["?lname"].Direction = ParameterDirection.Input

    cmd.Parameters.Add("?fname", 'Tom')
    cmd.Parameters["?fname"].Direction = ParameterDirection.Input

    cmd.Parameters.Add("?bday", #12/13/1977 2:17:36 PM#)
    cmd.Parameters["?bday"].Direction = ParameterDirection.Input

    cmd.Parameters.Add("?empno", MySqlDbType.Int32)
    cmd.Parameters["?empno"].Direction = ParameterDirection.Output

    cmd.ExecuteNonQuery()

    MessageBox.Show(cmd.Parameters["?empno"].Value)
Catch ex As MySqlException
    MessageBox.Show("Error " & ex.Number & " has occurred: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

try
{
    conn.Open();
    cmd.Connection = conn;

    cmd.CommandText = "add_emp";
    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add("?lname", "Jones");
    cmd.Parameters["?lname"].Direction = ParameterDirection.Input;

    cmd.Parameters.Add("?fname", "Tom");
    cmd.Parameters["?fname"].Direction = ParameterDirection.Input;

    cmd.Parameters.Add("?bday", DateTime.Parse("12/13/1977 2:17:36 PM"));
    cmd.Parameters["?bday"].Direction = ParameterDirection.Input;

    cmd.Parameters.Add("?empno", MySqlDbType.Int32);
    cmd.Parameters["?empno"].Direction = ParameterDirection.Output;

    cmd.ExecuteNonQuery();

    MessageBox.Show(cmd.Parameters["?empno"].Value);
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
      "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Sobald die gespeicherte Prozedur aufgerufen wird, können die Werte ihrer Ausgabeparameter mit der .Value-Eigenschaft der MySqlConnector.Parameters-Collection abgerufen werden.

25.2.3.4. BLOB-Daten und Connector/NET

25.2.3.4.1. Einleitung

Häufig werden mit MySQL Binärdaten in BLOB-Spalten gespeichert. MySQL unterstützt vier verschiedene BLOB-Datentypen: TINYBLOB, BLOB, MEDIUMBLOB und LONGBLOB.

Die Daten einer BLOB-Spalte können mit Connector/NET angesprochen und mit clientseitigem Code manipuliert werden. Es gibt keine Sonderbedingungen für den Einsatz von Connector/NET mit BLOB-Daten.

In diesem Abschnitt werden wir einfache Codebeispiele vorstellen. Eine vollständige Musteranwendung finden Sie im Samples-Verzeichnis der Connector/NET-Installation.

25.2.3.4.2. Vorbereitung des MySQL Servers

Um MySQL für BLOB-Daten einsetzen zu können, müssen Sie als Erstes den Server konfigurieren. Zunächst werden wir eine Tabelle anlegen. Meine Dateitabellen haben normalerweise vier Spalten: Eine AUTO_INCREMENT-Spalte passender Größe (UNSIGNED SMALLINT) dient als Primärschlüssel, um die Datei zu identifizieren, eine VARCHAR-Spalte speichert den Dateinamen, eine UNSIGNED MEDIUMINT-Spalte hält die Größe der Datei fest und eine MEDIUMBLOB-Spalte enthält die Datei selbst. Für dieses Beispiel werde ich folgende Tabellendefinition einsetzen:

CREATE TABLE file(
file_id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
file_name VARCHAR(64) NOT NULL,
file_size MEDIUMINT UNSIGNED NOT NULL,
file MEDIUMBLOB NOT NULL);

Nach der Erstellung einer Tabelle muss eventuell die Systemvariable max_allowed_packet modifiziert werden, die festlegt, welche maximale Paketgröße (d. h. eine einzelne Zeile) an den MySQL Server geschickt werden kann. Nach Voreinstellung akzeptiert der Server nur 1 Mbyte als maximale Paketgröße von der Clientanwendung. Wenn Sie diesen Wert nicht überschreiten wollen, ist er in Ordnung, aber wenn doch, müssen Sie ihn heraufsetzen.

Die Option max_allowed_packet kann in den MySQL Administrator's Startup Variables eingestellt werden. Setzen Sie hierzu die Option Maximum allowed im Memory-Teil der Registerkarte Networking auf einen geeigneten Wert. Dann klicken Sie auf Apply Changes und starten den Server über den Service Control-Bildschirm des MySQL Administrators neu. Sie können diesen Wert allerdings auch direkt in der my.cnf-Datei einstellen (und die Zeile max_allowed_packet=xxM hinzufügen) oder die Syntax SET max_allowed_packet=xxM; in MySQL nutzen.

Bitte stellen Sie max_allowed_packet nicht zu hoch ein, da eine Übertragung von BLOB-Daten viel Zeit in Anspruch nehmen kann. Versuchen Sie, einen für Ihre Situation angemessenen Wert zu finden, und setzen Sie ihn notfalls später herauf.

25.2.3.4.3. Eine Datei in die Datenbank speichern

Um eine Datei in eine Datenbank zu schreiben, konvertieren wir die Datei zuerst in ein Byte-Array und übergeben dieses dann als Parameter an die INSERT-Anfrage.

Der folgende Code öffnet eine Datei mithilfe eines FileStream-Objekts, liest sie in ein Byte-Array ein und fügt sie in die Tabelle file ein:

Visual Basic-Beispiel

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand

Dim SQL As String

Dim FileSize As UInt32
Dim rawData() As Byte
Dim fs As FileStream

conn.ConnectionString = "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=test"

Try
    fs = New FileStream("c:\image.png", FileMode.Open, FileAccess.Read)
    FileSize = fs.Length
    
    rawData = New Byte(FileSize) {}
    fs.Read(rawData, 0, FileSize)
    fs.Close()
    
    conn.Open()
    
    SQL = "INSERT INTO file VALUES(NULL, ?FileName, ?FileSize, ?File)"
    
    cmd.Connection = conn
    cmd.CommandText = SQL
    cmd.Parameters.Add("?FileName", strFileName)
    cmd.Parameters.Add("?FileSize", FileSize)
    cmd.Parameters.Add("?File", rawData)
    
    cmd.ExecuteNonQuery()
    
    MessageBox.Show("File Inserted into database successfully!", _
    "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
    
    conn.Close()
Catch ex As Exception
    MessageBox.Show("There was an error: " & ex.Message, "Error", _
        MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
  

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

string SQL;
UInt32 FileSize;
byte[] rawData;
FileStream fs;

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

try
{
    fs = new FileStream(@"c:\image.png", FileMode.Open, FileAccess.Read);
    FileSize = fs.Length;

    rawData = new byte[FileSize];
    fs.Read(rawData, 0, FileSize);
    fs.Close();

    conn.Open();

    SQL = "INSERT INTO file VALUES(NULL, ?FileName, ?FileSize, ?File)";

    cmd.Connection = conn;
    cmd.CommandText = SQL;
    cmd.Parameters.Add("?FileName", strFileName);
    cmd.Parameters.Add("?FileSize", FileSize);
    cmd.Parameters.Add("?File", rawData);

    cmd.ExecuteNonQuery();

    MessageBox.Show("File Inserted into database successfully!",
        "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);

    conn.Close();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
 

Die Methode Read des FileStream-Objekts lädt die Datei in ein Byte-Array, über dessen Größe die Length-Eigenschaft des FileStream-Objekts entscheidet.

Nachdem das Byte-Array als Parameter des MySqlCommand-Objekts zugewiesen wurde, wird die ExecuteNonQuery-Methode aufgerufen und der BLOB in die file-Tabelle eingefügt.

25.2.3.4.4. Einen BLOB aus der Datenbank in eine Datei oder auf Festplatte einlesen

Sobald wir eine Datei in der file-Tabelle gespeichert haben, können wir sie mit der Klasse MySqlDataReader abrufen.

Der folgende Code ruft eine Zeile aus der Tabelle file ab und lädt die Daten dann in ein FileStream-Objekt, das auf die Festplatte geschrieben wird:

Visual Basic-Beispiel

Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myData As MySqlDataReader
Dim SQL As String
Dim rawData() As Byte
Dim FileSize As UInt32
Dim fs As FileStream

conn.ConnectionString = "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=test"

SQL = "SELECT file_name, file_size, file FROM file"

Try
    conn.Open()
    
    cmd.Connection = conn
    cmd.CommandText = SQL
    
    myData = cmd.ExecuteReader
    
    If Not myData.HasRows Then Throw New Exception("There are no BLOBs to save")
    
    myData.Read()
    
    FileSize = myData.GetUInt32(myData.GetOrdinal("file_size"))
    rawData = New Byte(FileSize) {}
    
    myData.GetBytes(myData.GetOrdinal("file"), 0, rawData, 0, FileSize)
    
    fs = New FileStream("C:\newfile.png", FileMode.OpenOrCreate, FileAccess.Write)
    fs.Write(rawData, 0, FileSize)
    fs.Close()
    
    MessageBox.Show("File successfully written to disk!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
    
    myData.Close()
    conn.Close()
Catch ex As Exception
    MessageBox.Show("There was an error: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
  

C#-Beispiel

MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataReader myData;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();

string SQL;
UInt32 FileSize;
byte[] rawData;
FileStream fs;

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

SQL = "SELECT file_name, file_size, file FROM file";

try
{
    conn.Open();

    cmd.Connection = conn;
    cmd.CommandText = SQL;

    myData = cmd.ExecuteReader();

    if (! myData.HasRows)
        throw new Exception("There are no BLOBs to save");

    myData.Read();

    FileSize = myData.GetUInt32(myData.GetOrdinal("file_size"));
    rawData = new byte[FileSize];

    myData.GetBytes(myData.GetOrdinal("file"), 0, rawData, 0, FileSize);

    fs = new FileStream(@"C:\newfile.png", FileMode.OpenOrCreate, FileAccess.Write);
    fs.Write(rawData, 0, FileSize);
    fs.Close();

    MessageBox.Show("File successfully written to disk!",
        "Success!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);

    myData.Close();
    conn.Close();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show("Error " + ex.Number + " has occurred: " + ex.Message,
        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
 

Nach dem Aufbau der Verbindung werden die Daten der file-Tabelle in ein MySqlDataReader-Objekt geladen. Die Methode GetBytes des MySqlDataReaders lädt den BLOB in ein Byte-Array, das dann mit einem FileStream-Objekt auf die Festplatte geschrieben wird.

Die Methode GetOrdinal des MySqlDataReaders kann den ganzzahligen Index einer benannten Spalte ermitteln. Wenn Sie GetOrdinal verwenden, vermeiden Sie Fehler, die bei einer Änderung der Spaltenreihenfolge in der SELECT-Anfrage entstehen könnten.

25.2.3.5. Connector/NET mit Crystal Reports

25.2.3.5.1. Einleitung

Crystal Reports ist ein Tool, das Windows-Anwendungsentwickler gerne für das Reporting und zur Dokumenterstellung einsetzen. In diesem Abschnitt erfahren Sie, wie man Crystal Reports XI mit MySQL und Connector/NET einsetzt.

25.2.3.5.2. Datenquelle anlegen

Wenn Sie in Crystal Reports einen Bericht anlegen, können Sie in zwei Weisen auf MySQL-Daten für den Bericht zugreifen.

Die erste Möglichkeit: Sie verwenden Connector/ODBC als ADO-Datenquelle, wenn Sie Ihren Bericht entwerfen. Sie können dann in der Datenbank stöbern und Tabellen und Felder mit Drag & Drop in den Bericht einbinden. Der Nachteil dieser Methode: Es ist zusätzliche Arbeit an Ihrer Anwendung erforderlich, um ein zu Ihrem Bericht passendes Dataset zu erzeugen.

Die zweite Möglichkeit: Sie erstellen ein Dataset in VB.NET und speichern Sie im XML-Format. Diese XML-Datei kann dann zur Berichterstellung eingesetzt werden. Das funktioniert zwar recht gut, wenn Sie den Bericht in Ihrer Anwendung anzeigen, ist aber zur Entwurfszeit unpraktisch, da Sie alle relevanten Spalten auswählen müssen, wenn Sie das Dataset anlegen. Vergessen Sie eine Spalte, so müssen Sie das gesamte Dataset neu anlegen, um die Spalte dem Bericht hinzuzufügen.

Mit dem folgenden Code erzeugen Sie aus einer Anfrage ein Dataset und schreiben es auf die Festplatte:

Visual Basic-Beispiel

Dim myData As New DataSet
Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter

conn.ConnectionString = "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=world"

Try
    conn.Open()
    cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " _ 
        & "country.name, country.population, country.continent " _
        & "FROM country, city ORDER BY country.continent, country.name"
    cmd.Connection = conn
    
    myAdapter.SelectCommand = cmd
    myAdapter.Fill(myData)
    
    myData.WriteXml("C:\dataset.xml", XmlWriteMode.WriteSchema)
Catch ex As Exception
    MessageBox.Show(ex.Message, "Report could not be created", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
 

C#-Beispiel

DataSet myData = new DataSet();
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
  "pwd=12345;database=test;";
  
try
{
  cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " +
  "country.name, country.population, country.continent " +
  "FROM country, city ORDER BY country.continent, country.name";
  cmd.Connection = conn;
  
  myAdapter.SelectCommand = cmd;
  myAdapter.Fill(myData);
  
  myData.WriteXml(@"C:\dataset.xml", XmlWriteMode.WriteSchema);
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
  MessageBox.Show(ex.Message, "Report could not be created",
  MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Die resultierende XML-Datei kann bei der Berichterstellung als ADO.NET XML-Datenquelle verwendet werden.

Wenn Sie Ihre Berichte mit Connector/ODBC erstellen möchten, können Sie diese Komponente von dev.mysql.com herunterladen.

25.2.3.5.3. Bericht erstellen

Für die meisten Zwecke müsste der Standard Report-Assistent für die ersten Schritte der Berichterstellung ausreichen. Um den Assistenten zu starten, öffnen Sie Crystal Reports und wählen aus dem Dateimenü die Option Neu > Standard Report.

Der Assistent fragt Sie dann nach einer Datenquelle. Wenn Sie Connector/ODBC verwenden, wählen Sie die Option OLEDB provider for ODBC aus dem OLE DB (ADO)-Baum statt aus dem ODBC (RDO)-Baum, wenn Sie die Datenquelle einstellen. Wenn Sie ein gespeichertes Dataset verwenden, wählen Sie die Option ADO.NET (XML) und gehen zu diesem Dataset.

Der Rest des Berichterstellungsprozesses läuft im Assistenten automatisch ab.

Nachdem der Bericht angelegt wurde, wählen Sie den Eintrag Report Options... aus dem Dateimenü. Deaktivieren Sie die Option Save Data With Report, damit keine gespeicherten Daten das Laden der Daten in Ihrer Anwendung behindern.

25.2.3.5.4. Bericht anzeigen

Um einen Bericht anzuzeigen, laden wir zuerst das Dataset hinein, in dem die benötigten Daten gespeichert sind, laden dann den Bericht und binden ihn an das Dataset. Zum Schluss übergeben wir den Bericht an den crViewer, damit er dem Benutzer angezeigt wird.

Folgendes müssen Sie in einem Projekt, das einen Bericht anzeigt, referenzieren:

  • CrytalDecisions.CrystalReports.Engine

  • CrystalDecisions.ReportSource

  • CrystalDecisions.Shared

  • CrystalDecisions.Windows.Forms

Der folgende Code geht davon aus, dass Sie Ihren Bericht mit einem Dataset angelegt haben, das wie in Abschnitt 25.2.3.5.2, „Datenquelle anlegen“, gezeigt gespeichert wurde, und dass Sie einen crViewer namens myViewer auf Ihrem Formular haben.

Visual Basic-Beispiel

Imports CrystalDecisions.CrystalReports.Engine
Imports System.Data
Imports MySql.Data.MySqlClient

Dim myReport As New ReportDocument
Dim myData As New DataSet
Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter

conn.ConnectionString = _
    "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=test"

Try
    conn.Open()
    
    cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " _ 
        & "country.name, country.population, country.continent " _
        & "FROM country, city ORDER BY country.continent, country.name"
    cmd.Connection = conn
    
    myAdapter.SelectCommand = cmd
    myAdapter.Fill(myData)
    
    myReport.Load(".\world_report.rpt")
    myReport.SetDataSource(myData)
    myViewer.ReportSource = myReport
Catch ex As Exception
    MessageBox.Show(ex.Message, "Report could not be created", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

C#-Beispiel

using CrystalDecisions.CrystalReports.Engine;
using System.Data;
using MySql.Data.MySqlClient;

ReportDocument myReport = new ReportDocument();
DataSet myData = new DataSet();
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

try
{
    cmd.CommandText = "SELECT city.name AS cityName, city.population AS CityPopulation, " +
        "country.name, country.population, country.continent " +
        "FROM country, city ORDER BY country.continent, country.name";
    cmd.Connection = conn;

    myAdapter.SelectCommand = cmd;
    myAdapter.Fill(myData);

    myReport.Load(@".\world_report.rpt");
    myReport.SetDataSource(myData);
    myViewer.ReportSource = myReport;
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show(ex.Message, "Report could not be created",
        MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Ein neues Dataset wird mit derselben Anfrage wie das zuvor gespeicherte angelegt. Sobald es mit Daten gefüllt ist, wird die Berichtsdatei mithilfe eines ReportDocuments geladen und an das Dataset gebunden. Das ReportDocument wird als ReportSource des crViewers übergeben.

Denselben Ansatz verfolgen wir, wenn ein Bericht mit Connector/ODBC aus einer einzelnen Tabelle erstellt wird. Das Dataset ersetzt die im Bericht verwendete Tabelle und der Bericht wird korrekt angezeigt.

Wird ein Bericht mit Connector/ODBC aus mehreren Tabellen erstellt, müssen wir in unserer Anwendung ein Dataset aus mehreren Tabellen anlegen. So kann jede Tabelle aus der Berichtsdatenquelle im Dataset durch einen Bericht ersetzt werden.

Um mehrere Tabellen in ein Dataset zu laden, sind mehrere SELECT-Anweisungen in unserem MySqlCommand-Objekt erforderlich. Diese SELECT-Anweisungen beruhen auf der SQL-Anfrage, die in Crystal Reports in der Option Show SQL Query des Datenbankmenüs angezeigt wird. Legen wir einmal folgende Anfrage zugrunde:

SELECT `country`.`Name`, `country`.`Continent`, `country`.`Population`, `city`.`Name`, `city`.`Population`
FROM `world`.`country` `country` LEFT OUTER JOIN `world`.`city` `city` ON `country`.`Code`=`city`.`CountryCode`
ORDER BY `country`.`Continent`, `country`.`Name`, `city`.`Name`

Diese Anfrage wird in zwei SELECT-Anfragen aufgespalten und mit folgendem Code angezeigt:

Visual Basic-Beispiel

Imports CrystalDecisions.CrystalReports.Engine
Imports System.Data
Imports MySql.Data.MySqlClient

Dim myReport As New ReportDocument
Dim myData As New DataSet
Dim conn As New MySqlConnection
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter

conn.ConnectionString = "server=127.0.0.1;" _
    & "uid=root;" _
    & "pwd=12345;" _
    & "database=world"

Try
    conn.Open()
    cmd.CommandText = "SELECT name, population, countrycode FROM city ORDER BY countrycode, name; " _
        & "SELECT name, population, code, continent FROM country ORDER BY continent, name"
    cmd.Connection = conn
    
    myAdapter.SelectCommand = cmd
    myAdapter.Fill(myData)
    
    myReport.Load(".\world_report.rpt")
    myReport.Database.Tables(0).SetDataSource(myData.Tables(0))
    myReport.Database.Tables(1).SetDataSource(myData.Tables(1))
    myViewer.ReportSource = myReport
Catch ex As Exception
    MessageBox.Show(ex.Message, "Report could not be created", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

C#-Beispiel

using CrystalDecisions.CrystalReports.Engine;
using System.Data;
using MySql.Data.MySqlClient;

ReportDocument myReport = new ReportDocument();
DataSet myData = new DataSet();
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

conn = new MySql.Data.MySqlClient.MySqlConnection();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

conn.ConnectionString = "server=127.0.0.1;uid=root;" +
    "pwd=12345;database=test;";

try
{
    cmd.CommandText = "SELECT name, population, countrycode FROM city ORDER " +
        "BY countrycode, name; SELECT name, population, code, continent FROM " +
        "country ORDER BY continent, name";
    cmd.Connection = conn;

    myAdapter.SelectCommand = cmd;
    myAdapter.Fill(myData);

    myReport.Load(@".\world_report.rpt");
    myReport.Database.Tables(0).SetDataSource(myData.Tables(0));
    myReport.Database.Tables(1).SetDataSource(myData.Tables(1));
    myViewer.ReportSource = myReport;
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
    MessageBox.Show(ex.Message, "Report could not be created",
        MessageBoxButtons.OK, MessageBoxIcon.Error);
}  
 

Die SELECT-Anfragen müssen unbedingt in alphabetischer Reihenfolge stehen, da der Bericht erwartet, dass seine Quelltabellen diese Reihenfolge haben. Für jede Tabelle im Bericht ist eine SetDataSource-Anweisung erforderlich.

Dieser Ansatz kann Performanceprobleme mit sich bringen, da Crystal Reports die Tabellen auf der Clientseite aneinander binden muss. Das braucht mehr Zeit als ein vordefiniertes, gespeichertes Dataset.

25.2.3.6. Datums- und Uhrzeitdaten in Connector/NET

25.2.3.6.1. Einleitung

MySQL und die .NET-Sprachen gehen unterschiedlich mit Datums- und Uhrzeitinformationen um: MySQL erlaubt Datumswerte, die von keinem .NET-Datentyp dargestellt werden können, wie etwa '0000-00-00 00:00:00'. Diese Unterschiede können Probleme verursachen, wenn man nicht richtig damit umgeht.

In diesem Abschnitt werden wir zeigen, wie Datums- und Uhrzeitinformationen mit Connector/NET korrekt behandelt werden.

25.2.3.6.2. Probleme bei Verwendung ungültiger Datumswerte

Die Unterschiede in der Datumsbehandlung können Probleme bereiten, wenn Entwickler ungültige Datumswerte verwenden. Ungültige MySQL-Datumswerte, einschließlich NULL-Datumswerten, lassen sich nicht in native DateTime-Objekte von .NET laden.

Daher können DataSet-Objekte von .NET nicht mit der Fill-Methode der Klasse MySqlDataAdapter gefüllt werden, da ungültige Datumswerte eine System.ArgumentOutOfRangeException verursachen würden.

25.2.3.6.3. Ungültige Datumswerte unterbinden

Datumsprobleme lassen sich am besten dadurch in den Griff bekommen, dass die Benutzer gar keine Möglichkeit erhalten, ungültige Datumswerte einzugeben. Dies lässt sich auf der Client- oder der Serverseite bewerkstelligen.

Um ungültige Datumswerte auf der Clientseite zu unterbinden, müssen Sie die Datumswerte nur immer mit der .NET-Klasse DateTime behandeln. Diese erlaubt nämlich nur gültige Datumswerte und stellt dadurch sicher, dass auch in Ihre Datenbank nur gültige Werte gelangen. Leider kann man sie jedoch nicht in einer gemischten Umgebung einsetzen, in der die Datenbank sowohl mit .NET- als auch mit Nicht-.NET-Code bearbeitet wird, da jede Anwendung ihre eigene Datumsvalidierung vornehmen muss.

Auf MySQL 5.0.2 und höher können Sie den neuen SQL-Modus traditional einstellen, um ungültige Datumswerte zu unterbinden. Informationen über diesen SQL-Modus erhalten Sie unter traditional, Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

25.2.3.6.4. Umgang mit ungültigen Datumswerten

Zwar raten wir von ungültigen Datumswerten in .NET-Anwendungen ausdrücklich ab, aber es ist immerhin möglich, ungültige Datumswerte über den Datentyp MySqlDateTime zu behandeln.

Der Datentyp MySqlDateTime unterstützt dieselben Datumswerte wie der MySQL Server. Standardmäßig gibt Connector/NET für gültige Datumswerte ein DateTime-Objekt von .NET und für ungültige Datumswerte einen Fehler zurück. Diese Voreinstellung können Sie jedoch so abändern, dass Connector/NET MySqlDateTime-Objekte für ungültige Datumswerte zurückliefert.

Damit Connector/NET für ungültige Datumswerte ein MySqlDateTime-Objekt zurückgibt, fügen Sie Ihrem Verbindungs-String folgende Zeile hinzu:

  Allow Zero Datetime=True
  

Bitte beachten Sie, dass die Verwendung der Klasse MySqlDateTime immer problematisch sein kann. Folgende Probleme sind bereits aufgetreten:

  1. Die Datenbindung an ungültige Datumswerte kann trotz allem Fehler verursachen (Null-Datumswerte wie 0000-00-00 scheinen jedoch keine Schwierigkeiten zu bereiten).

  2. Die ToString-Methode gibt ein Datum im MySQL-Standardformat zurück (zum Beispiel 2005-02-23 08:50:25). Dieses unterscheidet sich von dem ToString-Verhalten der .NET-Klasse DateTime.

  3. Die Klasse MySqlDateTime unterstützt NULL-Datumswerte, die .NET-Klasse DateTime hingegen nicht. Das kann Fehler verursachen, wenn Sie versuchen, eine MySQLDateTime in ein DateTime-Objekt zu konvertieren, ohne sie zuvor auf NULL zu prüfen.

Wegen dieser bekannten Probleme lautet der beste Rat: Verwenden Sie bitte nur gültige Datumswerte Ihrer Anwendung.

25.2.3.6.5. Umgang mit NULL-Datumswerten

Der .NET-Datentyp DateTime kann mit NULL-Werten nicht umgehen. Daher müssen Sie, wenn Sie Werte aus einer Anfrage an eine DateTime-Variable zuweisen, immer zuerst prüfen, ob nicht ein NULL-Wert vorliegt.

Wenn Sie einen MySqlDataReader verwenden, sollten Sie mit der Methode .IsDBNull überprüfen, ob ein NULL-Wert vorliegt, bevor Sie die Zuweisung vornehmen:

Visual Basic-Beispiel

If Not myReader.IsDBNull(myReader.GetOrdinal("mytime")) Then
    myTime = myReader.GetDateTime(myReader.GetOrdinal("mytime"))
Else
    myTime = DateTime.MinValue
End If
  

C#-Beispiel

if (! myReader.IsDBNull(myReader.GetOrdinal("mytime")))
    myTime = myReader.GetDateTime(myReader.GetOrdinal("mytime"));
else
    myTime = DateTime.MinValue;
  

NULL-Werte funktionieren nicht in einem Dataset und können ohne Sonderbehandlung an Formularelemente gebunden werden.

25.2.4. Support für Connector/NET

Den Entwicklern von Connector/NET ist die Meinung der Benutzer und ihr Beitrag zum Softwareentwicklungsprozess sehr wichtig. Wenn Sie bei Connector/NET ein Feature vermissen oder einen Fehler finden und einen Bugreport übermitteln müssen, richten Sie sich bitte nach den Hinweisen in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

25.2.4.1. Support von der Connector/NET-Community

25.2.4.2. Probleme und Fehler von Connector/NET melden

Wenn Sie Probleme mit Connector/NET haben, wenden Sie sich bitte zuerst an die Connector/NET-Community, siehe Abschnitt 25.2.4.1, „Support von der Connector/NET-Community“.

Zuerst versuchen Sie jedoch, SQL-Anweisungen und -Befehle vom mysql-Client oder admndemo abzusetzen. So können Sie erkennen, ob das Problem an Connector/NET oder MySQL liegt.

Wenn Sie ein Problem melden, geben Sie uns bitte per E-Mail folgende Informationen:

  • Betriebssystem und Version

  • Connector/NET-Version

  • MySQL Server-Version

  • Kopien von Fehlermeldungen oder anderen unerwarteten Ausgaben

  • Einfaches, reproduzierbares Beispiel

Achtung: Je mehr Informationen Sie uns geben können, umso wahrscheinlicher ist es, dass wir das Problem beheben können.

Wenn Sie der Auffassung sind, dass es sich um einen Bug handelt, senden Sie uns einen Bugreport über http://bugs.mysql.com/.

25.3. MySQL Connector/J

MySQL stellt für Clientprogramme, die in Java erstellt wurden, Verbindungsmöglichkeiten über einen JDBC-Treiber namens MySQL Connector/J zur Verfügung.

MySQL Connector/J ist ein JDBC-3.0-Treiber vom „Typ 4“, also reines Java. Er implementiert die Version 3.0 der JDBC-Spezifikation und kommuniziert mit dem MySQL-Server direkt über das MySQL-Protokoll.

JDBC ist zwar sehr hilfreich, doch wenn Sie nach der Lektüre der ersten Abschnitte dieses Kapitels noch nicht voll und ganz damit vertraut sind, sollten Sie mit JDBC alleine nur sehr einfache Probleme bearbeiten. Den Löwenanteil der wiederkehrenden Aufgaben sollten Sie mit einem der populären Persistence-Frameworks wie etwa Hibernate, Spring's JDBC Templates oder Ibatis SQL Maps erledigen und die Grundrenovierungen, die manchmal erforderlich sind, mit JDBC.

Dieser Abschnitt ist nicht als umfassendes JDBC-Tutorial konzipiert. Wenn Sie mehr über JDBC erfahren möchten, schauen Sie bitte in eines der folgenden Online-Tutorials, die mehr in die Tiefe gehen als die vorliegenden Ausführungen:

25.3.1. Connector/J-Versionen

Zurzeit stehen drei Versionen von MySQL Connector/J zur Verfügung:

  • Connector/J 3.0 stellt die Kernfunktionalität zur Verfügung und wurde für die Verbindung mit MySQL 3.x oder MySQL 4.1 geschaffen, obwohl es auch mit neueren Versionen von MySQL grundsätzlich kompatibel ist. Connector/J 3.0 unterstützt keine vorbereiteten Anweisungen auf der Serverseite und keine neuen Features der MySQL-Versionen nach 4.1.

  • Connector/J 3.1 dient der Verbindung mit MySQL 4.1- und MySQL 5.0-Servern und unterstützt alle Funktionen von MySQL 5.0 außer verteilten Transaktionen (XA).

  • Connector/J 5.0 unterstützt dieselben Funktionen wie Connector/J 3.1, aber zusätzlich auch verteilte Transaktionen (XA).

Die zurzeit empfohlene Version von Connector/J ist 5.0. Die vorliegende Anleitung bezieht sich auf alle drei Connector-Versionen und weist besonders darauf hin, wenn eine Einstellung nur für eine bestimmte Option gilt.

25.3.1.1. Unterstützte Java-Versionen

MySQL Connector/J unterstützt Java-2-JVMs, einschließlich:

  • JDK 1.2.x

  • JDK 1.3.x

  • JDK 1.4.x

  • JDK 1.5.x

Wenn Sie Connector/J mit der Quelldistribution aus den Quelldateien erstellen (siehe Abschnitt 25.3.2.4, „Installation vom Entwicklungsquellbaum“), dann müssen Sie JDK 1.4.x oder höher zum Kompilieren des Connectors einsetzen.

MySQL Connector/J funktioniert nicht mit JDK-1.1.x oder JDK-1.0.x

Wegen der Implementierung von java.sql.Savepoint funktioniert Connector/J 3.1.0 und höher nicht mit JDKs, die älter als 1.4 sind, es sei denn, Sie schalten die Klassenprüfung aus (-Xverify:none). Diese würde nämlich versuchen, die Klassendefinition für java.sql.Savepoint zu laden, obwohl der Treiber auf diese Klasse nur zugreift, wenn Savepoint-Funktionalität genutzt wird.

Auch die Caching-Funktionalität von Connector/J 3.1.0 oder höher steht für JVMs, die älter als 1.4.x sind, nicht zur Verfügung, da sie sich auf die Klasse java.util.LinkedHashMap stützt, die erstmals im JDK-1.4.0 eingeführt wurde.

25.3.2. Installation von Connector/J

Sie können Connector/J entweder aus der Binär- oder aus der Quelldistribution installieren. Die Binärdistribution ist die einfachste Methode, während die Quelldistribution mehr Anpassungen ermöglicht.

25.3.2.1. Connector/J aus einer Binärdistribution installieren

Am einfachsten installieren Sie Connector/J mit der Binärdistribution. Diese steht als Tar/Gzip- oder Zip-Datei zur Verfügung. Extrahieren Sie das Archiv in ein passendes Verzeichnis und stellen Sie optional Informationen über das verwendete Package zur Verfügung, indem Sie Ihren CLASSPATH ändern (siehe Abschnitt 25.3.2.2, „Treiber installieren und CLASSPATH konfigurieren“).

MySQL Connector/J wird als .zip- oder .tar.gz-Archiv vertrieben, das die Quell- und Klassendateien sowie das JAR-Archiv namens mysql-connector-java-[version]-bin.jar enthält. Seit Connector/J 3.1.8 ist auch ein Debug-Build des Treibers in einer Datei namens mysql-connector-java-[version]-bin-g.jar inbegriffen.

Ab der Version Connector/J 3.1.9 sind die .class-Dateien, die die JAR-Dateien bilden, nur als Teil der Treiber-JAR-Datei enthalten.

Den „Debug“-Build des Treibers sollten Sie bitte nur benutzen, wenn Sie dazu aufgefordert werden, um ein Problem oder einen Fehler an MySQL AB zu melden, da dieser Build nicht für Produktionsumgebungen geschaffen ist und sich nachteilig auf die Performance auswirkt. Die Debug-Binärdatei ist außerdem von der Aspect/J-Laufzeitbibliothek abhängig, die Sie in der zur Connector/J-Distribution gehörigen Datei src/lib/aspectjrt.jar finden.

Um die Distribution auspacken zu können, benötigen Sie ein geeignetes Hilfsprogramm (zum Beispiel WinZip für das .zip-Archiv und tar für das .tar.gz-Archiv). Da die Distribution lange Dateinamen enthalten kann, verwenden wir das GNU-Format für tar-Archive. Mit GNU tar (oder einer Anwendung, die das GNU-tar-Archivformat versteht) können Sie die .tar.gz-Variante der Distribution auspacken.

25.3.2.2. Treiber installieren und CLASSPATH konfigurieren

WennSie das Archiv der Distribution extrahiert haben, installieren Sie den Treiber, indem Sie Ihrem Klassenpfad mysql-connector-java-[version]-bin.jar hinzufügen. Hierzu schreiben Sie entweder den vollständigen Pfad in Ihre Umgebungsvariable CLASSPATH oder geben ihn direkt mit der Kommandozeilenoption -cp an, wenn Sie Ihre JVM starten.

Wenn Sie den Treiber mit dem JDBC DriverManager benutzen, verwenden Sie com.mysql.jdbc.Driver als die Klasse, die java.sql.Driver implementiert.

Die Umgebungsvariable CLASSPATH können Sie unter UNIX, Linux oder Mac OS X entweder lokal für einen Benutzer in seinem .profile oder in .login oder in einer anderen Login-Datei setzen. Sie kann aber auch global in der Datei /etc/profile eingestellt werden.

In einer C-Shell (csh, tcsh) würde der Connector/J-Treiber dem CLASSPATH folgendermaßen hinzugefügt:

shell> setenv CLASSPATH /path/to/mysql-connector-java-[version]-bin.jar:$CLASSPATH

In einer Bourne-kompatiblen Shell (sh, ksh, bash) würden Sie dieses tun:

export set CLASSPATH=/path/to/mysql-connector-java-[version]-bin.jar:$CLASSPATH

In Windows 2000, Windows XP und Windows Server 2003 muss die Umgebungsvariable in der Systemsteuerung eingestellt werden.

Wenn Sie MySQL Connector/J mit einem Anwendungsserver wie etwa Tomcat oder JBoss benutzen möchten, müssen Sie in der Herstellerdokumentation nachlesen, wie Klassenbibliotheken von Drittanbietern konfiguriert werden, da die meisten Anwendungsserver die Umgebungsvariable CLASSPATH ignorieren. Beispiele für die Konfiguration einiger J2EE-Anwendungsserver finden Sie in Abschnitt 25.3.5.2, „Connector/J mit J2EE und anderen Java-Frameworks einsetzen“. Die maßgebliche Quelle für die Konfiguration eines JDBC-Verbindungspools auf Ihrem konkreten Anwendungsserver ist jedoch dessen Dokumentation.

Wenn Sie Servlets oder JSPs entwickeln und Ihr Anwendungsserver J2EE-fähig ist, können Sie die .jar-Datei des Treibers in das Unterverzeichnis WEB-INF/lib Ihrer Webanwendungen legen, da dies der Standardspeicherort für Bibliotheken von Drittanbietern in J2EE-Webanwendungen ist.

Sie können auch die Klasse MysqlDataSource oder MysqlConnectionPoolDataSource im Package com.mysql.jdbc.jdbc2.optional verwenden, wenn Ihr J2EE-Anwendungsserver sie unterstützt oder benötigt. Ab Connector/J 5.0.0 ist über die Klasse com.mysql.jdbc.jdbc2.optional.MysqlXADataSource auch die Schnittstelle javax.sql.XADataSource implementiert, die in Verbindung mit dem MySQL-Server 5.0 verteilte XA-Transaktionen unterstützt.

Die diversen MysqlDataSource-Klassen unterstützen (über Standard-Set-Mutators) folgende Parameter:

  • user

  • password

  • serverName (siehe vorhergehenden Abschnitt über Ausfall-Hosts)

  • databaseName

  • port

25.3.2.3. Ältere Versionen aufrüsten

MySQL AB versucht, den Upgrade-Prozess so einfach wie möglich zu halten, doch wie bei jeder Software müssen gelegentlich in neuen Versionen neue Features unterstützt, vorhandene verbessert oder neue Standards erfüllt werden.

In diesem Abschnitt erfahren Benutzer, die von einer Connector/J-Version auf eine andere aufrüsten (oder, im Hinblick auf die JDBC-Funktionalität, auf eine neue Version des MySQL-Servers), worauf sie achten müssen.

25.3.2.3.1. Aufrüsten von MySQL Connector/J 3.0 auf 3.1

Connector/J 3.1 ist auf größtmögliche Abwärtskompatibilität mit Connector/J 3.0 ausgelegt. Größere Änderungen beschränken sich auf die neuen Funktionen von MySQL 4.1 und höher, darunter Unicode-Zeichensätze, vorbereitete Anweisungen auf der Serverseite, SQLState-Codes die in Fehlermeldungen vom Server zurückgegeben werden, und verschiedene Leistungsverbesserungen, die mit Konfigurationseigenschaften ein- und ausgeschaltet werden können.

  • Unicode-Zeichensätze — Informationen über dieses neue MySQL-Feature finden Sie im folgenden Abschnitt und in Kapitel 10, Zeichensatz-Unterstützung. Wenn Sie etwas falsch konfiguriert haben, merken Sie das in der Regel an einer Fehlermeldung wie Illegal mix of collations.

  • Vorbereitete Anweisungen auf der Serverseite — Connector/J 3.1 erkennt und nutzt vorbereitete Anweisungen auf der Serverseite automatisch, wenn sie verfügbar sind (MySQL -Server der Version 4.1.0 und höher).

    Seit Version 3.1.7 untersucht der Server alle Arten mit Connection.prepareStatement() vorbereiteter SQL-Anweisungen, um festzustellen, ob es sich um eine Anweisungsart handelte deren Vorbereitung auf der Serverseite unterstützt wird. Ist dies nicht der Fall, emuliert der Server sie als clientseitige vorbereitete Anweisung. Dieses Feature können Sie deaktivieren, indem Sie emulateUnsupportedPstmts=false in Ihren JDBC-URL einbinden.

    Wenn Ihre Anwendung Probleme mit vorbereiteten Anweisungen auf der Serverseite hat, können Sie auf den älteren Code für emulierte vorbereitete Anweisungen auf der Clientseite zurückgreifen, der immer noch für ältere MySQL-Server als 4.1.0 mit der Verbindungseigenschaft useServerPrepStmts=false unterstützt wird.

  • Datums- und Uhrzeitwerte, die nur aus Nullen bestehen (0000-00-00 ...) — Diese Werte lassen sich in Java nicht zuverlässig darstellen. Connector/J 3.0.x wandelte sie immer in NULL um, wenn sie aus einem ResultSet gelesen wurden.

    Connector/J 3.1 löst nach Voreinstellung eine Ausnahme aus, wenn diese Werte auftreten, da dies nach den Standards von JDBC und SQL das korrekte Verhalten ist. Sie können dieses Verhalten aber mit der Konfigurationseigenschaft zeroDateTimeBehavior ändern, die folgende Werte annehmen kann:

    • exception (der Standardwert) löst eine SQLException mit dem SQLState S1009 aus.

    • convertToNull gibt NULL anstelle des Datums zurück.

    • round rundet das Datum auf den nächstgelegenen Wert auf, also auf 0001-01-01.

    Ab Connector/J 3.1.7 lässt sich ResultSet.getString() mit der Eigenschaft noDatetimeStringSync=true von diesem Verhalten abkoppeln (der Standardwert ist false). Auf diese Weise können Sie den Wert mit den Nullen unverändert als String abrufen. Da dies allerdings jegliche Zeitzonenkonvertierungen ausschließt, erlaubt Ihnen der Treiber nicht, noDatetimeStringSync und useTimezone gleichzeitig einzuschalten.

  • Neue SQLState-Codes — Connector/J 3.1 benutzt die SQLState-Codes von SQL:1999, die vom MySQL-Server (sofern er dies unterstützt) zurückgegeben werden. Diese unterscheiden sich von den alten X/Open-Zustandscodes, die Connector/J 3.0 verwendet. Wenn der Treiber mit einem älteren MySQL-Server als MySQL 4.1.0 verbunden ist (die älteste Version, die SQLStates in Fehlercodes zurückliefert), verwendet er eine integrierte Zuordnung. Sie können auf die alte Zuordnung umschalten, indem Sie die Konfigurationseigenschaft useSqlStateCodes=false einstellen.

  • ResultSet.getString() — Wenn Sie ResultSet.getString() auf einer BLOB-Spalte aufrufen, wird nunmehr die Adresse ihres byte[]-Arrays anstelle einer Stringdarstellung des BLOBs zurückgegeben. Da BLOBs keinen Zeichensatz haben, können sie nicht ohne Datenverlust oder Schäden in java.lang.Strings konvertiert werden.

    Um in MySQL Strings mit LOB-Verhalten zu speichern, verwenden Sie einen der TEXT-Typen, die der Treiber alle als java.sql.Clob behandelt.

  • Debug-Builds — Seit Connector/J 3.1.8 wird ein Debug-Build des Treibers in einer Datei namens mysql-connector-java-[version]-bin-g.jar zusammen mit der normalen Binär-jar-Datei namens mysql-connector-java-[version]-bin.jar mitgeliefert.

    Seit Connector/J 3.1.9 liefern wir die .class-Dateien nur noch im Bundle aus, also nur in den JAR-Archiven zusammen mit dem Treiber.

    Den „Debug“-Build des Treibers sollten Sie bitte nur benutzen, wenn Sie dazu aufgefordert werden, um ein Problem oder einen Fehler an MySQL AB zu melden, da dieser Build nicht für Produktionsumgebungen geschaffen ist und sich nachteilig auf die Performance auswirkt. Die Debug-Binärdatei ist außerdem von der Aspect/J-Laufzeitbibliothek abhängig, die Sie in der zur Connector/J-Distribution gehörigen Datei src/lib/aspectjrt.jar finden.

25.3.2.3.2. JDBC-spezifische Probleme beim Upgrade auf MySQL Server 4.1 oder höher
  • Verwendung der UTF-8-Zeichencodes - Vor MySQL Server 4.1 wurde die UTF-8-Zeichencodierung vom Server nicht unterstützt. Der JDBC-Treiber dagegen konnte diese Codierung nutzen, sodass mehrere Zeichensätze in latin1-Tabellen auf dem Server gespeichert werden konnten.

    Seit MySQL-4.1 ist diese Funktionalität veraltet. Wenn Sie Anwendungen haben, die sich darauf stützen und sich nicht auf die Unterstützung der offiziellen Unicode-Zeichen in MySQL Server 4.1 oder höher aktualisieren lassen, müssen Sie folgende Eigenschaft in Ihren Verbindungs-URL aufnehmen:

    useOldUTF8Behavior=true

  • Vorbereitete Anweisungen auf der Serverseite - Connector/J 3.1 erkennt und nutzt vorbereitete Anweisungen auf der Serverseite automatisch, wenn sie verfügbar sind (MySQL -Server der Version 4.1.0 und höher). Wenn Ihre Anwendung Probleme mit vorbereiteten Anweisungen auf der Serverseite hat, können Sie auf den älteren Code für emulierte vorbereitete Anweisungen auf der Clientseite zurückgreifen, der immer noch für ältere MySQL-Server als 4.1.0 mit folgender Verbindungseigenschaft unterstützt wird:

    useServerPrepStmts=false

25.3.2.4. Installation vom Entwicklungsquellbaum

Caution.  Sie sollten diesen Abschnitt nur lesen, wenn Sie Interesse daran haben, uns beim Testen unseres neuen Codes behilflich zu sein. Wenn Sie MySQL Connector/J lediglich in funktionsfähiger Form auf Ihrem System einrichten wollen, sollten Sie einen Standard-Release verwenden.

Um MySQL Connector/J vom Entwicklungsquellbaum zu installieren, müssen folgende Voraussetzungen erfüllt sein:

  • Sie benötigen Subversion (erhältlich bei http://subversion.tigris.org/), um die Quelldateien aus unserem Repository auszuchecken .

  • Sie benötigen Apache Ant Version 1.6 oder höher (erhältlich bei http://ant.apache.org/).

  • Sie benötigen JDK-1.4.2 oder höher. Zwar kann MySQL Connector/J auch auf älteren JDKs installiert werden, aber um es von der Quelle zu kompilieren, ist mindestens JDK-1.4.2 erforderlich.

Das Subversion-Quellcode-Repository für MySQL Connector/J liegt unter http://svn.mysql.com/svnpublic/connector-j. Generell sollten Sie nicht gleich das ganze Repository auschecken, da es jeden Branch und Tag für MySQL Connector/J enthält und daher sehr groß ist.

Einen konkreten Branch von MySQL Connector/J checken Sie folgendermaßen aus:

  1. Zurzeit sind drei Branches von Connector/J aktiv: branch_3_0, branch_3_1 und branch_5_0. Checken Sie den neuesten Code aus dem gewünschten Branch mit folgendem Befehl aus (wobei [major] und [minor] durch die passenden Versionsnummern ersetzt werden müssen):

    shell> svn co »
    http://svn.mysql.com/svnpublic/connector-j/branches/branch_[major]_[minor]/connector-j

    Dies erzeugt im aktuellen Verzeichnis ein Unterverzeichnis namens connector-j, das die neuesten Quelldateien für den gewünschten Branch enthält.

  2. Wechseln Sie nun in das Verzeichnis connector-j, um es zu Ihrem aktuellen Arbeitsverzeichnis zu machen:

    shell> cd connector-j
  3. Mit folgendem Befehl können Sie den Treiber kompilieren und eine .jar-Datei für die Installation anlegen:

    shell> ant dist

    Dies erzeugt im aktuellen Verzeichnis ein build-Verzeichnis, in das die gesamte Ausgabe des Builds gespeichert wird. Unter dem build-Verzeichnis wird ein weiteres Verzeichnis angelegt, das die Versionsnummer der für den Build verwendeten Quelle enthält. Dieses Verzeichnis enthält die Quelldateien, die kompilierten .class-Dateien und eine .jar-Datei, die sich für die Installation eignet. Für andere mögliche Ziele, einschließlich einer kompletten Package-Distribution, geben Sie folgenden Befehl:

    shell> ant --projecthelp
  4. Nun wird eine neu erzeugte .jar-Datei, die den JDBC-Treiber enthält, in das Verzeichnis build/mysql-connector-java-[version] gelegt.

    Diesen neu erstellten JDBC-Treiber installieren Sie genau so, als sei es eine .jar-Datei, die Sie gemäß den Anleitungen in Abschnitt 25.3.2.2, „Treiber installieren und CLASSPATH konfigurieren“ von MySQL heruntergeladen haben.

25.3.4. Connector/J (JDBC)-Referenz

Dieser Abschnitt des Handbuchs enthält Referenzmaterial zu MySQL Connector/J, das zum Teil während des Build-Prozesses von Connector/J automatisch generiert wurde.

25.3.4.1. Driver/Datasource-Klassennamen, URL-Syntax und Konfigurationseigenschaften für Connector/J

Die Klasse, die java.sql.Driver in MySQL Connector/J implementiert, heißt com.mysql.jdbc.Driver. Der Klassenname org.gjt.mm.mysql.Driver eignet sich auch, um die Abwärtskompatibilität mit MM.MySQL zu bewahren. Verwenden Sie also diesen Klassennamen, wenn Sie den Treiber registrieren oder andere Software konfigurieren, die MySQL Connector/J benutzen soll.

Es folgt das JDBC-URL-Format für MySQL Connector/J, wobei die Elemente in den eckigen Klammern ([, ]) optional sind:

jdbc:mysql://[host][,failoverhost...][:port]/[database] »
[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...

Ist kein Hostname angegeben, wird der Standardwert 127.0.0.1 verwendet. Fehlt die Port-Angabe, wird 3306, die Standard-Portnummer für MySQL-Server eingesetzt.

jdbc:mysql://[host:port],[host:port].../[database] »
[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...

Wenn die Datenbank nicht angegeben ist, wird keine Verbindung mit einer Standarddatenbank aufgenommen. Sie müssen dann entweder die Methode setCatalog() auf dem Connection-Objekt aufrufen, oder in der SQL-Anweisung Tabellennamen mit dem Datenbanknamen vollständig qualifizieren (d.h. SELECT dbname.tablename.colname FROM dbname.tablename...). Bei der Verbindung keine Datenbank anzugeben ist jedoch normalerweise nur dann sinnvoll, wenn Sie Tools erstellen, die mit mehreren Datenbanken arbeiten sollen, wie beispielsweise GUI-Datenbankmanager.

MySQL Connector/J unterstützt Ausfallsicherungen. So kann der Treiber auf beliebig viele Slave-Hosts zurückgreifen und immer noch nur-lesende Anfragen ausführen. Die Ausfallsicherung tritt nur dann in Kraft, wenn für die Verbindung autoCommit(true) gilt, da bei laufenden Transaktionen kein zuverlässiges Umschalten möglich ist. Die meisten Anwendungsserver und Verbindungspools setzen autoCommit am Ende jeder Transaktion/Verbindungsnutzung auf true.

Die Ausfallsicherung verhält sich folgendermaßen:

  • Wenn die URL-Eigenschaft autoReconnect false ist, wird nur bei der Initialisierung einer Verbindung auf den Sekundär-Host umgeschaltet (sog. Failover), und auf den Primär-Host wird wieder zurückgeschaltet (sog. Failback), wenn der Treiber feststellt, dass dieser wieder zur Verfügung steht.

  • Wenn die URL-Eigenschaft autoReconnect true ist, wird auf den Sekundär-Host umgeschaltet, wenn der Treiber feststellt, das die Verbindung (vor der Ausführung jeglicher Anfrage) gescheitert ist, und wieder auf den Primär-Host zurückgeschaltet, wenn dieser wieder verfügbar ist (nach der Ausführung von queriesBeforeRetryMaster-Anfragen).

In beiden Fällen gilt: Wenn Sie mit einem "Sekundär"-Server verbunden sind, wird die Verbindung in einen nur-lesenden Zustand versetzt, sodass Anfragen, die Daten modifizieren würden, Ausnahmen auslösen (eine solche Anfrage wird niemals vom MySQL-Server verarbeitet).

Wie Connector/J eine Verbindung zu einem MySQL-Server einrichtet, ist in den Konfigurationseigenschaften definiert. Wenn nichts anderes gesagt wird, können die Eigenschaften für ein DataSource- oder für ein Connection-Objekt gesetzt werden.

Konfigurationseigenschaften können auf folgende Weisen eingestellt werden:

  • Mit den set*()-Methoden von MySQL-Implementierungen auf java.sql.DataSource (die bevorzugte Methode, wenn Implementierungen von java.sql.DataSource verwendet werden):

    • com.mysql.jdbc.jdbc2.optional.MysqlDataSource

    • com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource

  • Als Schlüssel/Wert-Paar in der java.util.Properties-Instanz, die an DriverManager.getConnection() oder Driver.connect() übergeben wird.

  • Als JDBC-URL-Parameter in dem an java.sql.DriverManager.getConnection(), java.sql.Driver.connect() oder MySQL-Implementierungen der setURL()-Methode von javax.sql.DataSource übergebenen URL.

    Hinweis.  Wenn Sie zur Konfiguration eines JDBC-URLs einen XML-Mechanismus verwenden, müssen sie den XML-Zeichenliteral &amp; auf andere Konfigurationsparameter einstellen, da das Ampersand in XML ein reserviertes Zeichen ist.

Die Eigenschaften werden in den folgenden Tabellen aufgeführt.

Verbindung/Authentifizierung. 

Name der EigenschaftDefinitionStandardwertSeit Version
userDer Benutzername für die Verbindung alle
passwordDas Passwort für die Verbindung alle
socketFactoryDer Name der Klasse, die der Treiber zur Einrichtung von Socket-Verbindungen zum Server benutzen soll. Diese Klasse muss die Schnittstelle com.mysql.jdbc.SocketFactory implementieren und einen öffentlichen, parameterlosen Konstruktor haben.com.mysql.jdbc.StandardSocketFactory3.0.3
connectTimeoutTimeout für Socket-Verbindung (in Millisekunden). 0 bedeutet: kein Timeout. Funktioniert nur mit JDK-1.4 oder höher. Standardwert ist 0.03.0.1
socketTimeoutTimeout für Socket-Operationen im Netzwerk. (Die Standardeinstellung 0 bedeutet: kein Timeout).03.0.1
useConfigsLade die kommagetrennte Liste der Konfigurationseigenschaften vor dem Parsen des URLs oder der Anwendung benutzerdefinierter Eigenschaften. Siehe Abschnitt 25.3.4.1, „Driver/Datasource-Klassennamen, URL-Syntax und Konfigurationseigenschaften für Connector/J“ 3.1.5
interactiveClientSetzt das Flag CLIENT_INTERACTIVE, damit MySQL das Verbindungs-Timeout gemäß INTERACTIVE_TIMEOUT anstelle von WAIT_TIMEOUT einstelltfalse3.1.0
propertiesTransformEine Implementierung von com.mysql.jdbc.ConnectionPropertiesTransform, die der Treiber benutzt, um an ihn übergebene URL-Eigenschaften zu modifizieren, ehe er versucht, eine Verbindung einzurichten 3.1.4
useCompressionVerwendung von zlib-Kompression zur Kommunikation mit dem Server (true/false)? Standardwert ist false.false3.0.17

Hochverfügbarkeit und Clustering. 

Name der EigenschaftDefinitionStandardwertSeit Version
autoReconnectSollte der Treiber alte und/oder tote Verbindungen wiederbeleben oder nicht? Wenn diese Eigenschaft aktiviert ist, löst der Treiber eine Ausnahme aus, wenn Anfragen, die zur laufenden Transaktion gehören, über eine alte oder tote Verbindung gesendet werden. Werden über die Verbindung jedoch Anfragen gesendet, die zu einer neuen Transaktion gehören, versucht der Server vor der nächsten Anfrage eine Neuverbindung. Von der Verwendung dieses Features wird abgeraten, da es Auswirkungen auf den Session-Zustand und die Datenkonsistenz hat, wenn Anwendungen nicht richtig mit SQLExceptions umgehen können. Es sollte nur verwendet werden, wenn die Anwendung nicht richtig konfiguriert werden kann, um SQLExceptions, die aus alten oder toten Verbindungen resultieren, richtig zu handhaben. Als Alternative können Sie eventuell die MySQL-Server-Variable "wait_timeout" auf einen höheren als den Standardwert von 8 Stunden setzen.false1.1
autoReconnectForPoolsVerwendung einer Neuverbindungsstrategie, die sich für Verbindungspools eignet (Standardwert ist 'false')false3.1.3
failOverReadOnlySoll die Verbindung 'read-only' gesetzt werden, wenn im autoReconnect-Modus ein Ausfall passiert?true3.0.12
reconnectAtTxEndSoll der Treiber am Ende jeder Transaktion eine Neuverbindung versuchen, wenn autoReconnect auf true gesetzt ist?false3.0.10
roundRobinLoadBalanceSollen Verbindungs-Hosts round-robin ausgewählt werden, wenn autoReconnect eingeschaltet und failoverReadonly auf false gesetzt ist?false3.1.2
queriesBeforeRetryMasterAnzahl der Anfragen, die bei einem Ausfall (Failover) abgesetzt werden, ehe wieder auf den Master zurückgegriffen wird (bei Verwendung von Multi-Host-Failover). Die Bedingung, die zuerst erfüllt wird, ('queriesBeforeRetryMaster' oder 'secondsBeforeRetryMaster') veranlasst einen neuen Verbindungsversuch mit dem Master. Standardwert ist 50.503.0.2
secondsBeforeRetryMasterWie lange soll der Treiber bei einem Ausfall warten, ehe er wieder eine Verbindung zum Masterserver versucht? Die Bedingung, die zuerst erfüllt wird, ('queriesBeforeRetryMaster' oder 'secondsBeforeRetryMaster') veranlasst einen neuen Verbindungsversuch mit dem Master. Zeitangabe in Sekunden, Standardwert ist 30303.0.2
resourceIdEin global eindeutiger Bezeichner für die Ressource, mit welcher diese Datenquelle oder Verbindung verbunden ist, wird für XAResource.isSameRM() verwendet, wenn der Treiber diesen Wert nicht anhand der Hostnamen im URL ermitteln kann 5.0.1

Sicherheit. 

Name der EigenschaftDefinitionStandardwertSeit Version
allowMultiQueriesErlaubt das Trennzeichen' ;', um mehrere Anfragen in einer einzigen Anweisung abzugrenzen. (true/false, Standardwert ist 'false')false3.1.1
useSSLSSL wird zur Kommunikation mit dem Server eingesetzt (true/false), Standardwert ist 'false'false3.0.2
requireSSLWird SSL-Verbindung verlangt, wenn useSSL=true? (Standardwert ist 'false').false3.1.0
allowUrlInLocalInfileSoll der Treiber URLs in 'LOAD DATA LOCAL INFILE'-Anweisungen zulassen?false3.1.4
paranoidMaßnahmen ergreifen, damit keine schutzwürdigen Informationen in Fehlermeldungen erscheinen und Datenstrukturen, die schutzwürdige Daten enthalten, nach Möglichkeit löschen? (Standardwert ist 'false')false3.0.1

Performance-Erweiterungen. 

Name der EigenschaftDefinitionStandardwertSeit Version
metadataCacheSizeDie Anzahl der Anfragen, für die cacheResultSetMetadata eintritt, wenn cacheResultSetMetaData auf 'true' gesetzt ist (Standardwert 50)503.1.1
prepStmtCacheSizeWie viele vorbereitete Anweisungen sollen gespeichert werden, wenn Caching von vorbereiteten Anweisungen eingeschaltet ist?253.0.10
prepStmtCacheSqlLimitWie lang darf eine SQL-Anweisung, deren Parse-Ergebnis der Treiber speichert, höchstens sein, wenn Caching von vorbereiteten Anweisungen eingeschaltet ist?2563.0.10
useCursorFetchWenn bei einer Anweisung MySQL > 5.0.2 und setFetchSize() > 0 gilt, soll diese Anweisung Zeilen mit Cursor-Fetching abholen?false5.0.0
blobSendChunkSizeDatenblöcke dieser Größe verwenden, wenn BLOB/CLOBs mit ServerPreparedStatements verschickt werden10485763.1.9
cacheCallableStmtsSoll der Treiber das Parsing-Stadium von CallableStatements cachen?false3.1.2
cachePrepStmtsSoll der Treiber das Parsing-Stadium von PreparedStatements von clientseitigen vorbereiteten Anweisungen sowie die Eignungsprüfung von serverseitigen vorbereiteten Anweisungen und die serverseitigen vorbereiteten Anweisungen selbst cachen?false3.0.10
cacheResultSetMetadataSoll der Treiber ResultSetMetaData für Statements und PreparedStatements cachen? (JDK-1.4+ erforderlich, true/false, Standardwert 'false')false3.1.1
cacheServerConfigurationSoll der Treiber die Ergebnisse von SHOW VARIABLES und SHOW COLLATION pro URL cachen?false3.1.5
defaultFetchSizeDer Treiber ruft setFetchSize(n) mit diesem Wert auf allen neu erstellten Anweisungen auf03.1.9
dontTrackOpenResourcesLaut JDBC-Spezifikation muss der Treiber automatisch Ressourcen verfolgen und schließen, doch wenn Ihre Anwendung nicht gut darin ist, explizit close() auf Anweisungen oder Ergebnismengen aufzurufen, kann dies zu Speicherverlust führen. Wenn Sie diese Eigenschaft auf true setzen, lockern Sie diese Einschränkung und erhöhen für bestimmte Anwendungen die Speichereffizienzfalse3.1.7
dynamicCalendarsSoll der Treiber den Standardkalender abrufen, oder ihn pro Verbindung/Session cachen?false3.1.5
elideSetAutoCommitsFür MySQL-4.1 oder neuer: Soll der Treiber 'set autocommit=n'-Anfragen nur absetzen, wenn der Server-Zustand nicht dem durch Connection.setAutoCommit(boolean) geforderten Zustand entspricht?false3.1.3
holdResultsOpenOverStatementCloseSoll der Treiber bei Statement.close() Ergebnismengen abschließen, wie es die JDBC-Spezifikation fordert?false3.1.7
locatorFetchBufferSizeWenn 'emulateLocators' auf 'true' gesetzt ist: Wie groß soll der Puffer sein, wenn BLOB-Daten für einen getBinaryInputStream abgeholt werden?10485763.2.1
rewriteBatchedStatementsSoll der Treiber Multiqueries verwenden (unabhängig von der Einstellung von allowMultiQueries) und vorbereitete INSERT-Anweisungen in Insert-Operationen mit mehreren Werten umformulieren, wenn executeBatch() aufgerufen wird? Beachten Sie, dass dies die Gefahr von SQL-Injection birgt, wenn Sie einfache java.sql.Statements verwenden und Ihr Code die Eingabewerte nicht richtig säubert. Für vorbereitete Anweisungen müssen Sie wissen, dass serverseitige vorbereitete Anweisungen gegenwärtig noch nicht von dieser Umformulierungsoption Gebrauch machen können. Wenn Sie PreparedStatement.set*Stream() ohne Angabe von Stream-Längen verwenden, kann darüber hinaus der Treiber die optimale Anzahl der Parameter pro Batch nicht ermitteln und meldet einen Fehler, dass das resultierende Paket zu groß wird. Statement.getGeneratedKeys() funktioniert für diese umformulierten Anweisungen nur dann, wenn der gesamte Batch INSERT-Anweisungen enthält.false3.1.13
useFastIntParsingInterne String->Integer-Konvertierungsroutinen verwenden, damit nicht zu viele Objekte angelegt werden?true3.1.4
useJvmCharsetConvertersImmer die in der JVM integrierten Zeichencodierungsroutinen verwenden, anstatt Lookup-Tabellen für Single-Byte-Zeichensätze zu benutzen? (Der Standardwert "true" ist für neuere JVMs geeignet)true5.0.1
useLocalSessionStateSoll der Treiber die internen Werte für Autocommit und Transaktionsisolation benutzen, die von Connection.setAutoCommit() und Connection.setTransactionIsolation() gesetzt werden, anstatt die Datenbank anzufragen?false3.1.7
useReadAheadInputSoll beim Lesen von Serverdaten der optimierte nicht-blockierende, gepufferte Eingabestrom verwendet werden?true3.1.5

Debugging/Profiling. 

Name der EigenschaftDefinitionStandardwertSeit Version
loggerName einer Klasse, die 'com.mysql.jdbc.log.Log' implementiert und zur Protokollierung von Nachrichten verwendet wird. (Standardwert ist 'com.mysql.jdbc.log.StandardLogger', eine Klasse, die in STDERR schreibt)com.mysql.jdbc.log.StandardLogger3.1.1
profileSQLAnfragen und ihre Ausführungs/Fetch-Zeiten werden im konfigurierten Logger verfolgt (true/false), Standardwert ist 'false'false3.1.0
reportMetricsIntervalMillisWenn 'gatherPerfMetrics' aktiviert ist: In welchen Abständen sollen diese Daten gesammelt werden (in Millisekunden)?300003.1.2
maxQuerySizeToLogDie maximale Länge einer Anfrage, die bei Profiling oder Tracing prokolliert wird20483.1.3
packetDebugBufferSizeDie Höchstzahl der Pakete, die gepuffert werden, wenn 'enablePacketDebug' true ist203.1.3
slowQueryThresholdMillisWenn 'logSlowQueries' eingeschaltet ist: Wie lange darf eine Anfrage (in ms) dauern, ehe sie als 'langsam' protokolliert wird?20003.1.2
useUsageAdvisorSoll der Treiber ins Log 'usage'-Warnungen schreiben, um eine korrekte und effiziente Nutzung von JDBC und MySQL Connector/J anzuraten (true/false, Standardwert ist 'false')?false3.1.1
autoGenerateTestcaseScriptSoll der Treiber ausgeführtes SQL einschließlich serverseitige vorbereitete Anweisungen in STDERR speichern?false3.1.9
dumpMetadataOnColumnNotFoundSoll der Treiber feldbezogene Metadaten einer Ergebnismenge in die Ausnahmemeldung schreiben, wenn ResultSet.findColumn() fehlschlägt?false3.1.13
dumpQueriesOnExceptionSoll der Treiber den Inhalt der an den Server gesandten Anfrage in der Meldung für SQLExceptions speichern?false3.1.3
enablePacketDebugWenn dies eingeschaltet ist, wird ein Ring-Puffer mit 'packetDebugBufferSize'-Paketen behalten und gespeichert, sofern in bestimmten Bereichen des Treibercodes Ausnahmen ausgelöst werdenfalse3.1.3
explainSlowQueriesWenn 'logSlowQueries' eingeschaltet ist: Soll der Treiber automatisch eine 'EXPLAIN'-Anweisung an den Server stellen und die Ergebnisse auf WARN-Level an das konfigurierte Log schicken?false3.1.2
logSlowQueriesSollen Anfragen protokolliert werden, die länger als 'slowQueryThresholdMillis' dauern?false3.1.2
traceProtocolSoll das Trace-Netzwerkprotokoll ins Log gespeichert werden?false3.1.2

Verschiedenes. 

Name der EigenschaftDefinitionStandardwertSeit Version
useUnicodeSoll der Treiber zur Behandlung von Strings Unicode-Zeichencodes verwenden? Dies sollte nur eingesetzt werden, wenn der Treiber die Zeichensatzzuordnung nicht ermitteln kann, oder wenn Sie versuchen, dem Treiber einen Zeichensatz 'aufzuzwingen', den MySQL nicht nativ unterstützt (wie UTF-8). true/false, Standardwert ist 'true'true1.1g
characterEncodingWenn 'useUnicode' auf true gesetzt ist: Welche Zeichencodierung soll der Treiber für den Umgang mit Strings verwenden? (Standardwert ist 'autodetect') 1.1g
characterSetResultsMit diesem Zeichensatz soll der Server Ergebnismengen zurückgeben. 3.0.13
connectionCollationWenn dies gesetzt ist, verwendet der Server die mit 'set collation_connection' eingestellte Sortierreihenfolge für Zeichen 3.0.13
sessionVariablesEine kommagetrennte Liste von Namen/Wert-Paaren, die als SET SESSION ... an den Server geschickt wird, wenn sich der Treiber verbindet 3.1.8
allowNanAndInfSoll der Treiber NaN- oder +/- INF-Werte in PreparedStatement.setDouble() zulassen?false3.1.5
autoClosePStmtStreamsSoll der Treiber automatisch .close() auf Streams/Readern aufrufen, die mit set*()-Methoden als Argumente übergeben wurden?false3.1.12
autoDeserializeSoll der Treiber in BLOB-Feldern gespeicherte Objekte automatisch erkennen und deserialisieren?false3.1.5
capitalizeTypeNamesSollen Typnamen in DatabaseMetaData groß geschrieben werden? (Ist normalerweise nur für WebObjects nützlich, true/false, Standardwert ist 'false')false2.0.7
clobCharacterEncodingDiese Zeichencodierung soll anstelle der für die Verbindung konfigurierten characterEncoding zum Senden und Abrufen von TEXT-, MEDIUMTEXT- und LONGTEXT-Werten verwendet werden. 5.0.0
clobberStreamingResultsSorgt dafür, dass ein 'streaming'-ResultSet automatisch geschlossenwird, und dass anhängige Daten, die immer vom Server eintreffen, verworfen werden, wenn eine andere Anfrage ausgeführt wird, bevor alle Daten vom Server eingelesen worden sind.false3.0.9
continueBatchOnErrorSoll der Treiber weiterhin Batch-Befehle ausführen, wenn eine Anweisung gescheitert ist? Laut JDBC-Spezifikation sind beide Möglichkeiten erlaubt (Standardwert ist 'true').true3.0.3
createDatabaseIfNotExistLegt die im URL angegebene Datenbank an, wenn sie noch nicht existiert, vorausgesetzt, der Benutzer hat die Berechtigung zum Anlegen von Datenbanken.false3.1.9
emptyStringsConvertToZeroSoll der Treiber erlauben, dass leere String-Felder in '0'-Werte konvertiert werden?true3.1.8
emulateLocatorsN/Afalse3.1.0
emulateUnsupportedPstmtsSoll der Treiber vorbereitete Anweisungen erkennen, die nicht vom Server unterstützt werden, und sie durch emulierte Versionen auf der Clientseite ersetzen?true3.1.7
ignoreNonTxTablesWarnungen wegen nicht-transaktionssicherer Tabellen beim Rollback ignorieren? (Standardwert ist 'false').false3.0.9
jdbcCompliantTruncationSoll der Treiber beim Kappen von Daten java.sql.DataTruncation-Ausnahmen auslösen, wie es die JDBC-Spezifikation verlangt, wenn er mit einem Server verbunden ist, der Warnungen unterstützt (MySQL 4.1.0 und neuer)?true3.1.2
maxRowsSo viele Zeilen werden maximal zurückgegeben (der Standardwert 0 bedeutet, dass alle Zeilen zurückgegeben werden).-1alle Versionen
noAccessToProcedureBodiesSoll der Treiber grundlegende Metadaten erstellen (alle Parameter werden als INOUT VARCHARs gemeldet), anstatt eine Ausnahme auszulösen, wenn er Prozedurparametertypen für CallableStatements ermitteln soll und der Benutzer nicht mit "SHOW CREATE PROCEDURE" auf die Prozdedurrümpfe zugreifen oder mysql.proc abfragen kann?false5.0.3
noDatetimeStringSyncNicht dafür sorgen, dass ResultSet.getDatetimeType().toString().equals(ResultSet.getString())false3.1.7
noTimezoneConversionForTimeTypeTIME-Werte nicht auf die Server-Zeitzone umstellen, wenn 'useTimezone'='true'false5.0.0
nullCatalogMeansCurrentWenn DatabaseMetadataMethods einen 'catalog'-Parameter abfragen, steht dann der Wert Null für den aktuellen Katalog? (Das ist zwar nicht JDBC-konform, entspricht aber dem Verhalten älterer Treiberversionen)true3.1.8
nullNamePatternMatchesAllSollen DatabaseMetaData-Methoden, die *pattern-Parameter entgegennehmen, Null ebenso wie '%' behandeln (ist zwar nicht JDBC-konform, aber ältere Treiberversionen akzeptierten diese Abweichung von der Spezifikation)true3.1.8
overrideSupportsIntegrityEnhancementFacilitySoll der Treiber für DatabaseMetaData.supportsIntegrityEnhancementFacility() auch dann "true" zurückgeben, wenn die Datenbank es nicht akzeptiert, um einen Workaround für Anwendungen (wie beispielsweise OpenOffice) zu ermöglichen, die verlangen, dass diese Methode "true" zurückgibt, um Unterstützung für Fremdschlüssel zu signalisieren, auch wenn die SQL-Spezifikation besagt, dass diese Facility noch viel mehr als nur Fremdschlüsselunterstützung umfasst?false3.1.12
pedanticDie JDBC-Spezifikation wortwörtlich befolgenfalse3.0.0
pinGlobalTxToPhysicalConnectionWenn XAConnections verwendet werden: Soll der Treiber gewährleisten, dass Operationen auf einer konkreten XID immer an dieselbe physikalische Verbindung weitergeleitet werden? So kann die XAConnection "XA START ... JOIN" auch nach dem Aufruf von "XA END" noch unterstützen.false5.0.1
processEscapeCodesForPrepStmtsSoll der Treiber Escape-Codes in vorbereiteten Anweisungen verarbeiten?true3.1.12
relaxAutoCommitWenn sich der Treiber mit einer MySQL-Version verbindet, die keine Transaktionen unterstützt: Sollen dennoch commit(), rollback() und setAutoCommit() erlaubt sein? (true/false, Standardwert ist 'false')?false2.0.13
retainStatementAfterResultSetCloseSoll sich der Treiber die Statement-Referenz in einem ResultSet merken, nachdem ResultSet.close() aufgerufen wurde? Dies ist nach JDBC-4.0 nicht mehr JDBC-konform.false3.1.11
rollbackOnPooledCloseSoll der Treiber rollback() aufrufen, wenn die logische Verbindung in einem Pool geschlossen wird?true3.0.15
runningCTS13Ermöglicht Workarounds für Fehler in der JDBC Compliance Testsuite Version 1.3 von Sunfalse3.1.7
serverTimezoneÜberschreibt die Erkennung/Zuordnung der Zeitzone. Wird verwendet, wenn sich die Zeitzone des Servers nicht auf die Java-Zeitzone abbilden lässt. 3.0.2
strictFloatingPointWird nur in älteren Versionen des Compliance Tests verwendetfalse3.0.0
strictUpdatesSoll der Treiber eine strenge Prüfung (aller ausgewählten Primärschlüssel) aktualisierbarer Ergebnismenge vornehmen? (true, false, Standardwert ist 'true')true3.0.4
tinyInt1isBitSoll der Treiber den Datentyp TINYINT(1) als BIT-Typ behandeln (da der Server insgeheim sowieso eine BIT -> TINYINT(1)-Konvertierung vornimmt, wenn er Tabellen anlegt)?true3.0.16
transformedBitIsBooleanWenn der Treiber TINYINT(1) in einen anderen Datentyp konvertiert: Soll er BOOLEAN anstelle von BIT verwenden (dient der zukünftigen Kompatibilität mit MySQL-5.0, da MySQL-5.0 einen BIT-Typ hat)?false3.1.9
ultraDevHackWenn nötig PreparedStatements für prepareCall() erstellen, da UltraDev nicht funktioniert und prepareCall() für alle Anweisungen aufruft? (true/false, Standardwert ist 'false')false2.0.3
useGmtMillisForDatetimesKonvertiert zwischen Session-Zeitzone und GMT vor der Erzeugung von Date- und Timestamp-Objekten ("false" ist veraltetes Verhalten, "true" ist eher JDBC-konform).false3.1.12
useHostsInPrivilegesDen Benutzern in DatabaseMetaData.getColumn/TablePrivileges() einen '@hostname' hinzufügen (true/false), Standardwert ist 'true'.true3.0.2
useInformationSchemaSoll der Treiber bei Verbindung mit MySQL-5.0.7 oder neuer die von DatabaseMetaData benötigten Informationen aus dem INFORMATION_SCHEMA ableiten?false5.0.0
useJDBCCompliantTimezoneShiftSoll der Treiber sich beim Konvertieren der Zeitzoneninformationen von TIME/TIMESTAMP/DATETIME-Werten für JDBC-Argumente, die ein java.util.Calendar-Argument nehmen an den JDBC-Standard halten? (Achtung, diese Option und die Konfigurationsoption "useTimezone=true" schließen sich gegenseitig aus.)false5.0.0
useOldUTF8BehaviorStellt das alte UTF-8-Verhalten ein, das der Treiber bei Kommunikation mit 4.0 und älteren Servern an den Tag legt.false3.1.6
useOnlyServerErrorMessagesKeine 'Standard'-SQLState-Fehlermeldungen den vom Server zurückgelieferten Fehlermeldungen voranstellen.true3.0.15
useServerPrepStmtsServerseitige vorbereitete Anweisungen verwenden, wenn der Server sie unterstützt? (Standardwert ist 'true').true3.1.0
useSqlStateCodesZustandscodes gemäß SQL-Standard anstelle der 'alten' X/Open/SQL-Zustandscodes verwenden? (true/false), Standardwert ist 'true'true3.1.3
useStreamLengthsInPrepStmtsStreamLength-Parameter in Aufrufen der PreparedStatement/ResultSet.setXXXStream()-Methode berücksichtigen? (true/false, Standardwert ist 'true')true3.0.2
useTimezoneDatums/Uhrzeittypen zwischen Client- und Server-Zeitzone konvertieren (true/false, Standardwert ist 'false')?false3.0.2
useUnbufferedInputKeinen BufferedInputStream zum Lesen von Daten auf dem Server verwendentrue3.0.11
yearIsDateTypeSoll der JDBC-Treiber den MySQL-Typ "YEAR" als java.sql.Date oder als SHORT behandeln?true3.1.9
zeroDateTimeBehaviorWas soll geschehen, wenn der Server auf DATETIME-Werte trifft, die ausschließlich aus Nullen bestehen (so stellt MySQL ungültige Datumswerte dar)? Zulässige Werte sind 'exception', 'round' und 'convertToNull'.exception3.1.4

Connector/J bietet auch MySQL-Zugriff über Named Pipes für Windows NT/2000/XP. Hierzu wird die NamedPipeSocketFactory als Plugin-Socket-Factory mithilfe der Eigenschaft socketFactory eingestellt. Wenn Sie keine namedPipePath-Eigenschaft einstellen, wird standardmäßig '\\.\pipe\MySQL' benutzt. Verwenden Sie die NamedPipeSocketFactory, so werden der Hostname und die Port-Nummer im JDBC-URL ignoriert. Sie können dieses Feature wie folgt einschalten:

socketFactory=com.mysql.jdbc.NamedPipeSocketFactory
        

Named Pipes funktinieren nur, wenn Sie sich mit dem MySQL-Server auf demselben Computer verbinden, auf dem auch der JDBC-Treiber eingesetzt wird. In einfachen Performance-Tests sieht es so aus, als sei der Zugriff über Named Pipes um 30%-50% schneller als der traditionelle TCP/IP-Zugriff.

Mit dem Beispielcode in com.mysql.jdbc.NamedPipeSocketFactory oder com.mysql.jdbc.StandardSocketFactory können Sie eigene Socket-Factories bauen.

25.3.4.2. Hinweise zur Implementierung der JDBC-API

MySQL Connector/J besteht alle Tests der öffentlich zugänglichen JDBC Compliance Testsuite von Sun. Doch an vielen Stellen sagt die JDBC-Spezifikation nicht genau, wie eine Funktionalität implementiert werden soll.

In diesem Abschnitt wird für jede Schnittstelle untersucht, wie sich Ihre Implementierungsentscheidungen auf die Verwendung von MySQL Connector/J auswirken können.

  • Blob

    Die BLOB-Implementierung erlaubt keine Modifikationen an Ort und Stelle (sondern nur in Kopien, die von der Methode DatabaseMetaData.locatorsUpdateCopies() angezeigt werden). Daher sollten Sie Änderungen mit der entsprechenden PreparedStatement.setBlob()- oder ResultSet.updateBlob()-Methode (für aktualisierbare Ergebnismengen) in die Datenbank zurückspeichern.

    Seit Connector/J version 3.1.0 können Sie Blobs mit Locators emulieren, indem Sie Ihrem JDBC-URL die Eigenschaft 'emulateLocators=true' hinzufügen. Sie müssen dann einen Spaltenalias einsetzen, wobei der Wert der Spalte auf den tatsächlichen Namen der Blob-Spalte in der SELECT-Anweisung gesetzt wird, die Sie zum Abrufen des Blob schreiben. Die SELECT-Anweisung darf nur eine einzige Tabelle referenzieren, die Tabelle muss einen Primärschlüssel haben, und das SELECT muss alle Spalten enthalten, die diesen Primärschlüssel ausmachen. Der Treiber wird dann das Laden der tatsächlichen Blob-Daten so lange aufschieben, bis Sie den Blob abrufen und auf ihm entsprechende Abrufmethoden aufrufen (getInputStream(), getBytes() usw.).

  • CallableStatement

    Seit Connector/J 3.1.1 werden über die Schnittstelle CallableStatement bei Verbindungen mit MySQL 5.0 oder neuer gespeicherte Prozeduren unterstützt. Die Methode getParameterMetaData() von CallableStatement wird gegenwärtig noch nicht unterstützt.

  • Clob

    Die CLOB-Implementierung erlaubt keine Modifikationen an Ort und Stelle (sondern nur in Kopien, die von der Methode DatabaseMetaData.locatorsUpdateCopies() angezeigt werden). Daher sollten Sie Änderungen mit der entsprechenden PreparedStatement.setClob()-Methode in die Datenbank zurückspeichern. Die JDBC-API kennt keine ResultSet.updateClob()-Methode.

  • Connection

    Im Gegensatz zu älteren Versionen von MM.MySQL wird die Methode isClosed() den Server nicht pingen, um festzustellen, ob er noch lebendig ist. Entsprechend der JDBC-Spezifikation gibt sie lediglich true zurück, wenn closed() auf der Verbindung aufgerufen worden ist. Wenn Sie feststellen möchten, ob die Verbindung noch steht, setzen Sie eine einfache Anfrage wie beispielsweise SELECT 1 ab. Ist die Verbindung ungültig geworden, löst der Treiber eine Ausnahme aus.

  • DatabaseMetaData

    Fremdschlüsselinformationen (getImportedKeys()/getExportedKeys() und getCrossReference()) sind nur für InnoDB-Tabellen erhältlich. Da der Server diese Informationen jedoch mit SHOW CREATE TABLE abruft, wird er auch andere Speicher-Engines unterstützen, die Fremdschlüssel kennen.

  • PreparedStatement

    PreparedStatements werden vom Treiber implementiert, da MySQL keine vorbereiteten Anweisungen kennt. Dahler implementiert der Treiber auch kein getParameterMetaData() oder getMetaData(), da er dann einen kompletten SQL-Parser im Client benötigen würde.

    Seit Version 3.1.0 verwendet MySQL Connector/J serverseitige vorbereitete Anweisungen und binär codierte Ergebnsmengen, wenn der Server diese ermöglicht.

    Seien Sie vorsichtig, wenn Sie eine serverseitige vorbereitete Anweisung mit großen Parametern verwenden, die mit setBinaryStream(), setAsciiStream(), setUnicodeStream(), setBlob() oder setClob() eingestellt werden. Wenn Sie die Anweisung erneut ausführen, aber dabei die großen auf kleine Parameter umstellen möchten, müssen Sie clearParameters() aufrufen und alle Parameter neu einstellen. Dies hat folgenden Grund:

    • Wenn der Parameter gesetzt ist, lässt der Treiber die großen Daten Band-extern in die vorbereitete Anweisung auf der Serverseite streamen (und zwar vor Ausführung der vorbereiteten Anweisung).

    • Wenn dies erledigt ist, wird der Stream, mit dem Daten auf der Clientseite gelesen wurden, geschlossen (genz JDBC-konform), und kann nicht mehr gelesen werden.

    • Wird der Parameter von groß auf klein umgestellt, muss der Treiber den serverseitigen Zustand der vorbereiteten Anweisung zurücksetzen, damit der neue Parameter den Platz des vorherigen, großen Werts einnehmen kann. Dadurch werden alle großen Daten, die bereits an den Server geschickt wurden, entfernt, sodass sie mit einer der Methoden setBinaryStream(), setAsciiStream(), setUnicodeStream(), setBlob() oder setClob() erneut gesandt werden müssen.

    Um einen Parameter von einem großen auf einen kleinen Typ umzustellen, müssen Sie folglich clearParameters() aufrufen und alle Parameter der vorbereiteten Anweisung neu einstellen, ehe diese wieder ausgeführt werden kann.

  • ResultSet

    Nach Voreinstellung werden ResultSets vollständig abgeholt und in den Arbeitsspeicher geladen. Meist ist dies am effizientesten und durch den Entwurf des MySQL-Netzwerkprotokolls auch am einfachsten zu implementieren. Wenn Sie jedoch mit ResultSets arbeiten, die viele Zeilen oder große Werte enthalten, und in Ihrer JVM keinen Heap-Space für den erforderlichen Arbeitsspeicher zuweisen können, können Sie den Treiber auch veranlassen, die Ergebnisse zeilenweise hereinströmen zu lassen.

    Um diese Funktionalität nutzen zu können, müssen Sie ein Statement-Objekt wie folgt erzeugen:

    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                  java.sql.ResultSet.CONCUR_READ_ONLY);
    stmt.setFetchSize(Integer.MIN_VALUE);

    Die Kombination aus einer forward-only, nur-lesenden Ergebnismenge der Größe Integer.MIN_VALUE ist für den Treiber das Signal, die Ergebnismengen zeilenweise hereinströmen zu lassen. Danach werden auch alle weiteren mit dieser Anweisung abgerufenen Ergebnismengen zeilenweise eingelesen.

    Dieser Ansatz hat einige Tücken. Sie müssen alle Zeilen der Ergebnismenge lesen (oder sie schließen), ehe Sie auf der Verbindung weitere Anfragen absetzen können. Sonst wird eine Ausnahme ausgelöst.

    Die Sperren, die diese Anweisungen halten, können frühestens freigegeben werden, wenn die Anweisung abgeschlossen ist. (Dies gilt für MyISAM-Tabellensperren ebenso wie für die Zeilensperren einiger anderer Speicher-Engines, wie etwa InnoDB.)

    Wenn die Anweisung zu einer Transaktion gehört, werden die Sperren erst freigegeben, wenn die Transaktion fertig ist (was impliziert, dass auch die Anweisung zuerst fertig sein muss). Wie in den meisten anderen Datenbanken auch, sind Anweisungen erst dann abgeschlossen, wenn alle Ergebnisse gelesen wurden, oder die aktive Ergebnismenge der Anweisung geschlossen worden ist.

    Daher sollten Sie Streaming-Ergebnisse immer so schnell wie möglich lesen, wenn die von der Anweisung referenzierten Tabellen weiterhin nebenläufig zugänglich sein sollen.

  • ResultSetMetaData

    Die Methode isAutoIncrement() funktioniert nur mit MySQL 4.0 und neuer.

  • Statement

    Wenn Sie ältere JDBC-Treiberversionen als 3.2.1 in Verbindung mit älteren älteren Server-Versionen als 5.0.3 benutzen, hat die Methode "setFetchSize()" keine andere Wirkung, als das Ergebnismengen-Streaming umzuschalten, wie oben beschrieben.

    MySQL unterstützt keine SQL-Cursors und der JDBC-Treiber emuliert sie auch nicht. Daher hat "setCursorName()" keine Wirkung.

25.3.4.3. Datentypen von Java, JDBC und MySQL

MySQL Connector/J ist flexibel in Bezug auf die Konvertierung von MySQL- und Java-Datentypen.

Generell lässt sich jeder MySQL-Datentyp in einen java.lang.String und jeder numerische Typ in einen numerischen Java-Typ umwandeln, wobei jedoch Rundungen, Überlauf oder Genauigkeitsverluste eintreten können.

Seit Connector/J 3.1.0 gibt der JDBC-Treiber Warnungen oder DataTruncation-Ausnahmen im Einklang mit der JDBC-Spezifikation aus, wenn Sie dies nicht ausdrücklich unterbinden, indem Sie die Eigenschaft jdbcCompliantTruncation auf false setzen.

Die in der folgenden Tabelle aufgeführten Konvertierungen funktionieren garantiert:

Verbindungseigenschaften - Diverse. 

Diese MySQL-Datentypenlassen sich immer in diese Java-Typen konvertieren
CHAR, VARCHAR, BLOB, TEXT, ENUM, and SETjava.lang.String, java.io.InputStream, java.io.Reader, java.sql.Blob, java.sql.Clob
FLOAT, REAL, DOUBLE PRECISION, NUMERIC, DECIMAL, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINTjava.lang.String, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Double, java.math.BigDecimal
DATE, TIME, DATETIME, TIMESTAMPjava.lang.String, java.sql.Date, java.sql.Timestamp

Hinweis: Wenn Sie einen numerischen Java-Typ auswählen, der weniger genau oder groß als der MySQL-Typ ist, aus oder in welchen Sie konvertieren, kann es zu Rundungsverhalten, Überlauf oder Genauigkeitsverlust kommen.

Die Methode ResultSet.getObject() nimmt folgende Konvertierungen zwischen MySQL- und Java-Typen vor, wobei sie sich möglichst an die JDBC-Spezifikation hält:

Konvertierung von MySQL- in Java-Typen für ResultSet.getObject(). 

MySQL-TypnameRückgabe als Java-Klasse
BIT(1) (neu in MySQL-5.0)java.lang.Boolean
BIT( > 1) (neu in MySQL-5.0)byte[]
TINYINTjava.lang.Boolean, wenn die Konfigurationseigenschaft tinyInt1isBit auf true gesetzt ist (der Standardwert) und die Speichergröße 1 ist, andernfalls java.lang.Integer.
BOOL, BOOLEANSiehe TINYINT weiter oben, da diese Typen zurzeit Aliase für TINYINT(1) sind.
SMALLINT[(M)] [UNSIGNED]java.lang.Integer (egal ob UNSIGNED oder nicht)
MEDIUMINT[(M)] [UNSIGNED]java.lang.Integer, wenn UNSIGNED java.lang.Long
INT,INTEGER[(M)] [UNSIGNED]java.lang.Integer, wenn UNSIGNED java.lang.Long
BIGINT[(M)] [UNSIGNED]java.lang.Long, wenn UNSIGNED java.math.BigInteger
FLOAT[(M,D)]java.lang.Float
DOUBLE[(M,B)]java.lang.Double
DECIMAL[(M[,D])]java.math.BigDecimal
DATEjava.sql.Date
DATETIMEjava.sql.Timestamp
TIMESTAMP[(M)]java.sql.Timestamp
TIMEjava.sql.Time
YEAR[(2|4)]java.sql.Date (Datum wird um Mitternacht auf 1. Januar umgestellt)
CHAR(M)java.lang.String (wenn der Zeichensatz für die Spalte BINARY ist, wird byte[] zurückgegeben).
VARCHAR(M) [BINARY]java.lang.String (wenn der Zeichensatz für die Spalte BINARY ist, wird byte[] zurückgegeben).
BINARY(M)byte[]
VARBINARY(M)byte[]
TINYBLOBbyte[]
TINYTEXTjava.lang.String
BLOBbyte[]
TEXTjava.lang.String
MEDIUMBLOBbyte[]
MEDIUMTEXTjava.lang.String
LONGBLOBbyte[]
LONGTEXTjava.lang.String
ENUM('value1','value2',...)java.lang.String
SET('value1','value2',...)java.lang.String

25.3.4.4. Zeichensätze und Unicode

Alle vom JDBC-Treiber zum Server geschickten Strings werden automatisch vom nativen Java-Unicode in die Zeichencodierung des Clients konvertiert, einschließlich aller mit Statement.execute(), Statement.executeUpdate() und Statement.executeQuery() übermittelten Anfragen, sowie aller PreparedStatement - und CallableStatement - Parameter mit Ausnahme der Parameter, die mit setBytes(), setBinaryStream(), setAsciiStream(), setUnicodeStream() und setBlob() eingestellt wurden.

Vor MySQL Server 4.1 unterstützte Connector/J eine einzige Zeichencodierung pro Verbindung. Diese konnte entweder automatisch aus der Severkonfiguration erschlossen oder vom Benutzer mit den Eigenschaften useUnicode und "characterEncoding" eingestellt werden.

Seit MySQL Server 4.1 unterstützt Connector/J eine einzige Zeichencodierung zwischen Client und Server, aber beliebig viele Zeichencodierungen für Daten, die vom Server in ResultSets an den Client zurückgeliefert werden.

Die Zeichencodierung zwischen Client und Server wird automatisch beim Verbindungsaufbau ermittelt. Die vom Treiber verwendete Codierung wird auf dem Server mit der Systemvariablen character_set (für ältere Server-Versionen als 4.1.0) oder character_set_server (für Server-Versionen ab 4.1.0 ) eingestellt. Weitere Informationen finden Sie unter Abschnitt 10.3.1, „Serverzeichensatz und -sortierfolge“.

Um die automatische Erkennung der Codierung auf der Clientseite außer Kraft zu setzen, setzen Sie die Eigenschaft characterEncoding in den für die Server-Verbindung verwendeten URL.

Zeichencodierungen auf der Clientseite geben Sie bitte mit Java-Namen an. In der folgenden Tabelle werden die Java-Namen der MySQL-Zeichensätze aufgeführt:

Übersetzung der Zeichencodierungen von MySQL in Java. 

Zeichensatzname in MySQLName der Zeichencodierung in Java
usa7US-ASCII
big5Big5
gbkGBK
sjisSJIS (oder Cp932 oder MS932 für MySQL Server < 4.1.11)
cp932Cp932 oder MS932 (MySQL Server > 4.1.11)
gb2312EUC_CN
ujisEUC_JP
euc_krEUC_KR
latin1ISO8859_1
latin1_deISO8859_1
german1ISO8859_1
danishISO8859_1
latin2ISO8859_2
czechISO8859_2
hungarianISO8859_2
croatISO8859_2
greekISO8859_7
hebrewISO8859_8
latin5ISO8859_9
latvianISO8859_13
latvian1ISO8859_13
estoniaISO8859_13
dosCp437
pclatin2Cp852
cp866Cp866
koi8_ruKOI8_R
tis620TIS620
win1250Cp1250
win1250chCp1250
win1251Cp1251
cp1251Cp1251
win1251ukrCp1251
cp1257Cp1257
macromanMacRoman
macceMacCentralEurope
utf8UTF-8
ucs2UnicodeBig

Warnung.  Verwenden Sie niemals die Anfrage 'set names' mit Connector/J, da der Treiber dann nicht erkennt, dass der Zeichensatz geändert wurde, und weiterhin den Zeichensatz verwendet, den er beim Einrichten der Verbindung gefunden hat.

Wenn Sie ermöglichen möchten, dass mehrere Zeichensätze vom Client gesendet werden können, verwenden Sie bitte die UTF-8-Codierung. Diese können Sie einstellen, indem Sie entweder utf8 als Standardzeichensatz des Servers angeben, oder den JDBC-Treiber mit der Eigenschaft characterEncoding zur Benutzung von UTF-8 veranlassen.

25.3.4.5. Sichere Verbindungen mit SSL

SSL in MySQL Connector/J verschlüsselt alle Daten (außer dem Handshake am Anfang) zwischen dem JDBC-Treiber und dem Server. Allerdings dauert die Verarbeitung von Anfragen, je nach ihrer Größe und dem Umfang der Rückgabedaten, bei Einschaltung von SSL 36% bis 50% länger.

Damit die SSL-Unterstützung funktioniert, ist folgendes erforderlich:

Sie müssen als Erstes das CA-Zertifikat des MySQL-Servers in einen Java-Truststore importieren. Ein Beispiel eines CA-Zertifikats für MySQL-Server finden Sie im Unterverzeichnis SSL der MySQL-Quelldistribution. Anhand dieses Zertifikats wird SSL feststellen, ob Sie mit einem sicheren MySQL-Server kommunizieren.

Um mit dem Java-keytool einen Truststore im aktuellen Verzeichnis anzulegen und das CA-Zertifikat des Servers (cacert.pem) zu importieren, gehen Sie wie unten beschrieben vor (vorausgesetzt, das keytool liegt in Ihrem Pfad). (Das keytool müsste im Unterverzeichnis bin Ihres JDK oder JRE zu finden sein):

shell> keytool -import -alias mysqlServerCACert -file cacert.pem -keystore truststore
        

Keytool antwortet mit folgenden Informationen:

Enter keystore password:  *********
Owner: EMAILADDRESS=walrus@example.com, CN=Walrus, O=MySQL AB, L=Orenburg, ST=Some
-State, C=RU
Issuer: EMAILADDRESS=walrus@example.com, CN=Walrus, O=MySQL AB, L=Orenburg, ST=Som
e-State, C=RU
Serial number: 0
Valid from: Fri Aug 02 16:55:53 CDT 2002 until: Sat Aug 02 16:55:53 CDT 2003
Certificate fingerprints:
         MD5:  61:91:A0:F2:03:07:61:7A:81:38:66:DA:19:C4:8D:AB
         SHA1: 25:77:41:05:D5:AD:99:8C:14:8C:CA:68:9C:2F:B8:89:C3:34:4D:6C
Trust this certificate? [no]:  yes
Certificate was added to keystore

Dann müssen sie ein Client-Zertifikat generieren, damit der MySQL-Server weiß, dass er es mit einem sicheren Client zu tun hat:

 shell> keytool -genkey -keyalg rsa -alias mysqlClientCertificate -keystore keystore 

Das Keytool fragt Sie nach folgenden Informationen und erstellt einen Keystore namens keystore im aktuellen Verzeichnis.

Bitte geben Sie die passenden Informationen für Ihre Situation ein:

Enter keystore password:  *********
What is your first and last name?
  [Unknown]:  Matthews
What is the name of your organizational unit?
  [Unknown]:  Software Development
What is the name of your organization?
  [Unknown]:  MySQL AB
What is the name of your City or Locality?
  [Unknown]:  Flossmoor
What is the name of your State or Province?
  [Unknown]:  IL
What is the two-letter country code for this unit?
  [Unknown]:  US
Is <CN=Matthews, OU=Software Development, O=MySQL AB,
 L=Flossmoor, ST=IL, C=US> correct?
  [no]:  y

Enter key password for <mysqlClientCertificate>
        (RETURN if same as keystore password):

Damit JSSE den Keystore und den Truststore auch benutzt, müssen Sie zum Schluss die folgenden Systemeigenschaften einstellen, wenn Sie Ihre JVM starten. Ersetzen Sie dabei path_to_keystore_file durch den vollständigen Pfad zu der von Ihnen angelegten Keystore-Datei und path_to_truststore_filedurch den vollständigen Pfad zu der von Ihnen angelegten Truststore-Datei und benutzen Sie für jede Eigenschaft die passenden Passwortwerte.

-Djavax.net.ssl.keyStore=path_to_keystore_file
-Djavax.net.ssl.keyStorePassword=*********
-Djavax.net.ssl.trustStore=path_to_truststore_file
-Djavax.net.ssl.trustStorePassword=********* 

Außerdem müssen Sie in den Verbindungsparametern für SQL Connector/JuseSSL auf true setzen, indem Sie entweder useSSL=true in Ihren URL einfügen, oder die Eigenschaft useSSL in dem java.util.Properties-Objekt, das Sie an DriverManager.getConnection() übergeben, auf true einstellen.

Das Funktionieren von SSL können Sie testen, indem Sie JSSE-Debugging (wie unten beschrieben) einschalten und nach folgenden Key-Ereignissen Ausschau halten:

...
 *** ClientHello, v3.1
 RandomCookie:  GMT: 1018531834 bytes = { 199, 148, 180, 215, 74, 12, 54, 244, 0, 168, 55, 103, 215, 64, 16, 138, 225, 190, 132, 153, 2, 217, 219, 239, 202, 19, 121, 78 }
 Session ID:  {}
 Cipher Suites:  { 0, 5, 0, 4, 0, 9, 0, 10, 0, 18, 0, 19, 0, 3, 0, 17 }
 Compression Methods:  { 0 }
 ***
 [write] MD5 and SHA1 hashes:  len = 59
 0000: 01 00 00 37 03 01 3D B6   90 FA C7 94 B4 D7 4A 0C  ...7..=.......J.
 0010: 36 F4 00 A8 37 67 D7 40   10 8A E1 BE 84 99 02 D9  6...7g.@........
 0020: DB EF CA 13 79 4E 00 00   10 00 05 00 04 00 09 00  ....yN..........
 0030: 0A 00 12 00 13 00 03 00   11 01 00                 ...........
 main, WRITE:  SSL v3.1 Handshake, length = 59
 main, READ:  SSL v3.1 Handshake, length = 74
 *** ServerHello, v3.1
 RandomCookie:  GMT: 1018577560 bytes = { 116, 50, 4, 103, 25, 100, 58, 202, 79, 185, 178, 100, 215, 66, 254, 21, 83, 187, 190, 42, 170, 3, 132, 110, 82, 148, 160, 92 }
 Session ID:  {163, 227, 84, 53, 81, 127, 252, 254, 178, 179, 68, 63, 182, 158, 30, 11, 150, 79, 170, 76, 255, 92, 15, 226, 24, 17, 177, 219, 158, 177, 187, 143}
 Cipher Suite:  { 0, 5 }
 Compression Method: 0
 ***
 %% Created:  [Session-1, SSL_RSA_WITH_RC4_128_SHA]
 ** SSL_RSA_WITH_RC4_128_SHA
 [read] MD5 and SHA1 hashes:  len = 74
 0000: 02 00 00 46 03 01 3D B6   43 98 74 32 04 67 19 64  ...F..=.C.t2.g.d
 0010: 3A CA 4F B9 B2 64 D7 42   FE 15 53 BB BE 2A AA 03  :.O..d.B..S..*..
 0020: 84 6E 52 94 A0 5C 20 A3   E3 54 35 51 7F FC FE B2  .nR..\ ..T5Q....
 0030: B3 44 3F B6 9E 1E 0B 96   4F AA 4C FF 5C 0F E2 18  .D?.....O.L.\...
 0040: 11 B1 DB 9E B1 BB 8F 00   05 00                    ..........
 main, READ:  SSL v3.1 Handshake, length = 1712
 ...

JSSE bietet Debugging (in STDOUT), wenn Sie die Systemeigenschaft -Djavax.net.debug=all einstellen. So erfahren Sie, welche Keystores und Truststores benutzt werden und was während des SSL-Handshakes und beim Austauschen des Zertifikats passiert. Dies ist nützlich, wenn eine SSL-Verbindung einmal nicht erfolgreich aufgebaut werden kann und Sie versuchen, den Fehler zu finden.

25.3.4.6. Master/Slave-Replikation mit ReplicationConnection

Seit Connector/J 3.1.7 haben wir eine Variante des Treibers entwickelt, die Anfragen je nach dem Zustand von Connection.getReadOnly() automatisch an einen lesenden und schreibenden Master oder eine Ausfallserver oder eine nach dem Round-Robin-Verfahren lastbalancierte Gruppe von Slaves weiterleitet.

Wenn eine Anwendung durch Aufruf von Connection.setReadOnly(true) signalisiert, dass eine Transaktion nur-lesend sein soll, verwendet diese replikationsfähige Verbindung eine der per round-robin lastbalancierten Slave-Verbindungen (eine Verbindung verbleibt bei einem Slave, bis dieser aus dem Dienst genommen wird). Wenn Sie eine schreibende Transaktion haben oder eine zeitsensible Leseoperation ausführen müssen (vergessen Sie nicht, die Replikation in MySQL ist asynchron), dann stellen Sie die Verbindung mit Connection.setReadOnly(false) so ein, dass sie nicht nur-lesend ist. Der Treiber sorgt dann dafür, dass zukünftige Aufrufe an den MySQL-Masterserver gehen. Außerdem reicht der Server den aktuellen Zustand von Autocommit, Isolationsebene und Katalog an alle Verbindungen weiter, die er für diese Lastverteilungsfunktionalität benötigt.

Um diese Funktionalität zu ermöglichen, verwenden Sie die Klasse " com.mysql.jdbc.ReplicationDriver ", wenn Sie den Verbindungspool Ihres Anwendungsservers konfigurieren, oder wenn Sie eine Instanz eines JDBC-Treibers für Ihre Standalone-Anwendung erzeugen. Da der ReplicationDriver dasselbe URL-Format wie der Standard-MySQL-JDBC-Treiber akzeptiert, funktioniert er gegenwärtig mit einem Verbindungsaufbau à la java.sql.DriverManager nur dann, wenn er der einzige MySQL-JDBC-Treiber ist, der beim DriverManager registriert wurde.

Hier sehen Sie ein einfaches, kurzes Beispiel dafür, wie man einen ReplicationDriver in einer Standalone-Anwendung einsetzen könnte.

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Properties;

import com.mysql.jdbc.ReplicationDriver;

public class ReplicationDriverDemo {

    public static void main(String[] args) throws Exception {
        ReplicationDriver driver = new ReplicationDriver();

        Properties props = new Properties();

        // Für die Ausfallsicherung mit Slaves
        props.put("autoReconnect", "true");

        // Lastverteilung zwischen den Slaves
        props.put("roundRobinLoadBalance", "true");

        props.put("user", "foo");
        props.put("password", "bar");

        //
        // Sieht aus wie ein normaler MySQL-JDBC-URL mit einer kommagetrennten Liste von Hosts,
        // wobei der erste der 'Master' und die restlichen
        // die Slaves sind, auf die der Treiber die Last verteilt
        //

        Connection conn =
            driver.connect("jdbc:mysql://master,slave1,slave2,slave3/test",
                props);

        //
        // Lese/Schreiboperationen auf dem Master ausführen, indem
        // das Readonly-Flag auf "false" gesetzt wird.
        //

        conn.setReadOnly(false);
        conn.setAutoCommit(false);
        conn.createStatement().executeUpdate("UPDATE some_table ....");
        conn.commit();

        //
        // Nun eine Anfrage auf einem Slave ausführen, wobei der Treiber automatisch
        // einen aus der Liste auswählt
        //

        conn.setReadOnly(true);

        ResultSet rs = conn.createStatement().executeQuery("SELECT a,b,c FROM some_other_table");

         .......
    }
}

25.3.5. Hinweise und Tipps zu Connector/J

25.3.5.1. Grundkonzepte von JDBC

In diesem Abschnitt wird Grundlagenwissen über JDBC vermittelt.

25.3.5.1.1. Verbindung mit MySQL über die Schnittstelle DriverManager

Wenn Sie JDBC außerhalb eines Anwendungsservers benutzen, wird die Einrichtung von Verbindungen über die Klasse DriverManager verwaltet.

Sie müssen dem DriverManager mitteilen, mit welchen JDBC-Treibern er sich verbinden soll. Die einfachste Möglichkeit besteht darin, die Methode Class.forName() auf der Klasse aufzurufen, welche die java.sql.Driver-Schnittstelle implementiert. Bei MySQL Connector/J heißt diese Klasse com.mysql.jdbc.Driver. Mit dieser Methode können Sie eine externe Konfigurationsdatei verwenden, um den Namen der Treiberklasse und die Treiberparameter zu übergeben, wenn eine Datenbankverbindung aufgebaut wird.

Der folgende Java-Code zeigt, wie Sie MySQL Connector/J in der main()-Methode Ihrer Anwendung registrieren könnten:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

// Achtung, nicht com.mysql.jdbc.* importieren,
// sonst bekommen Sie Probleme!

public class LoadDriver {
    public static void main(String[] args) {
        try {
            // Der Aufruf von newInstance() ist ein Workaround
            // für einige misslungene Java-Implementierungen

            Class.forName("com.mysql.jdbc.Driver").newInstance();
        } catch (Exception ex) {
            // Fehler behandeln
        }
}

Nachdem der Treiber beim DriverManager registriert wurde, können Sie eine Connection-Instanz zur Verbindung mit einer bestimmten Datenbank erzeugen, indem Sie DriverManager.getConnection() aufrufen:

Beispiel 25.1. Eine Verbindung vom DriverManager erhalten

Dieses Beispiel zeigt, wie Sie eine Connection-Instanz vom DriverManager bekommen können. Es gibt verschiedene Signaturen für die getConnection()-Methode. Wie man mit ihnen umgeht, entnehmen Sie bitte der API-Dokumentation, die mit Ihrem JDK mitgeliefert wurde.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

    ... try {
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");

            // Verbindung benutzen

           ....
        } catch (SQLException ex) {
            // Fehler behandeln
            System.out.println("SQLException: " + ex.getMessage());
            System.out.println("SQLState: " + ex.getSQLState());
            System.out.println("VendorError: " + ex.getErrorCode());
        }

Sobald eine Connection eingerichtet ist, kann sie genutzt werden, um Statement- und PreparedStatement-Objekte auszuführen und Metadaten über die Datenbank abzurufen. Dies wird in den folgenden Abschnitten erklärt.

25.3.5.1.2. SQL-Anweisungen mit Statement-Objekten ausführen

Mit Statement-Objekten können Sie grundlegende SQL-Anfragen ausführen und die Ergebnisse mithilfe der weiter unten beschriebenen Klasse ResultSet abrufen.

Um ein Statement-Objekt zu erzeugen, rufen Sie die Methode createStatement() auf dem Connection-Objekt auf, das Sie mit einer der zuvor beschriebenen Methoden DriverManager.getConnection() oder DataSource.getConnection() erzeugt haben.

Wenn Sie ein Statement-Objekt angelegt haben, können Sie eine SELECT-Anfrage ausführen, indem Sie executeQuery(String) mit der gewünschten SQL-Anweisung aufrufen.

Um Daten in der Datenbank zu aktualisieren, verwenden Sie die Methode executeUpdate(String SQL). Diese liefert die Anzahl der von dem Update betroffenen Zeilen zurück.

Wenn Sie im Voraus noch nicht wissen, ob Ihre SQL-Anweisung ein SELECT oder ein UPDATE/INSERT wird, können Sie die Methode execute(String SQL) verwenden. Sie gibt true zurück, wenn die SQL-Anfrage ein SELECT ist, oder false, wenn sie ein UPDATE, INSERT oder DELETE ist. Handelt es sich um ein SELECT, so können Sie die Ergebnisse mit der Methode getResultSet() abrufen. Für UPDATE-, INSERT- oder DELETE-Anweisungen können Sie die Anzahl der betroffenen Zeilen in Erfahrung bringen, indem Sie getUpdateCount() auf dem Statement-Objekt aufrufen.

Beispiel 25.2. Mit java.sql.Statement eine SELECT-Anfrage ausführen

// conn sei eine bereits vorhandene JDBC-Verbindung
Statement stmt = null;
ResultSet rs = null;

try {
    stmt = conn.createStatement();
    rs = stmt.executeQuery("SELECT foo FROM bar");

    // oder, wenn Sie im Voraus nicht wissen, ob die
    // Anfrage ein SELECT ist...

    if (stmt.execute("SELECT foo FROM bar")) {
        rs = stmt.getResultSet();
    }

    // Tue etwas mit dem ResultSet ....
} finally {
    // Ressourcen sollten immer in einem
    // finally{}-Block
    // in der umgekehrten Reihenfolge ihrer Zuweisung
    // freigegeben werden

    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException sqlEx) { // ignore }

        rs = null;
    }

    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException sqlEx) { // ignore }

        stmt = null;
    }
}
25.3.5.1.3. Gespeicherte Prozeduren mit CallableStatements ausführen

Seit der MySQL-Server-Version 5.0 in Verbindung mit Connector/J 3.1.1 oder höher ist die Schnittstelle java.sql.CallableStatement mit Ausnahme der Methode getParameterMetaData() vollständig implementiert.

Mehr über gespeicherte Prozeduren in MySQL erfahren Sie in Kapitel 19, Gespeicherte Prozeduren und Funktionen.

Connector/J stellt Funktionalität für gespeicherte Prozeduren über die JDBC-Schnittstelle CallableStatement zur Verfügung.

Hinweis.  Aktuelle Versionen von MySQL-Server geben nicht genug Informationen zurück, damit der JDBC-Treiber Ergebnismengen-Metadaten für Callable Statements liefern kann. Folglich wird ResultSetMetaData für CallableStatement unter Umständen den Wert NULL zurückgeben.

Das folgende Beispiel zeigt eine gespeicherte Prozedur, die den Wert von inOutParam um 1 inkrementiert und den im inputParam übergebenen String als ResultSet zurückgibt:

Beispiel 25.3. Gespeicherte Prozeduren

CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam INT)
BEGIN
    DECLARE z INT;
    SET z = inOutParam + 1;
    SET inOutParam = z;

    SELECT inputParam;

    SELECT CONCAT('zyxw', inputParam);
END

Um die Prozedur demoSp mit Connector/J einzusetzen, gehen Sie folgendermaßen vor:

  1. Sie bereiten das Callable Statement mit Connection.prepareCall() vor.

    Beachten Sie, dass Sie die Escape-Syntax von JDBC anwenden müssen, und dass die runden Klammern um die Parameter-Platzhalter obligatorisch sind:

    Beispiel 25.4. Using Connection.prepareCall()

    import java.sql.CallableStatement;
    
    ...
    
        //
        // Bereite Aufruf der gespeicherten Prozedur 'demoSp'
        // mit zwei Parametern vor
        //
        // Beachten Sie die JDBC-Escape-Syntax ({call ...})
        //
    
        CallableStatement cStmt = conn.prepareCall("{call demoSp(?, ?)}");
    
    
    
        cStmt.setString(1, "abcdefg");

    Note.  Connection.prepareCall() ist eine aufwändige Methode, da der Treiber Metadaten abfragen muss, um die Ausgabeparameter zu unterstützen. Aus Performance-Gründen sollten Sie unnötige Aufrufe von Connection.prepareCall() vermeiden, indem Sie CallableStatement-Objekte in Ihrem Code wiederverwenden.

  2. Registrieren Sie die Ausgabeparameter (sofern vorhanden)

    Um die Werte der Ausgabeparameter (Parameter, die Sie beim Anlegen der gespeicherten Prozedur als OUT oder INOUT gekennzeichnet haben) abrufen zu können, müssen sie in JDBC vor der Ausführung der Anweisung mit einer der diversen registerOutputParameter()-Methoden in der Klasse CallableStatement registriert worden sein:

    Beispiel 25.5. Registrierung von Ausgabeparametern

    import java.sql.Types;
    ...
    //
    // Connector/J unterstützt benannte und indizierte
    // Ausgabeparameter. Mit beiden Methoden können Sie
    // Ausgabeparameter registrieren oder, unabhängig
    // von der gewählten Registrierungsmethode,
    // auch abrufen.
    //
    // Die folgenden Beispiele zeigen, wie die verschiedenen
    // Registrierungsmethoden für Ausgabeparameter verwendet werden
    // (wobei Sie natürlich nur eine Registrierung
    // pro Parameter verwenden).
    //
     
    //
    // Registriert den zweiten Parameter als Ausgabe und
    // verwendet den Typ 'INTEGER' für Rückgabewerte von
    // getObject()
    //
     
    cStmt.registerOutParameter(2, Types.INTEGER);
     
    //
    // Registriert den benannten Parameter 'inOutParam' und
    // verwendet den Typ 'INTEGER' für Rückgabewerte von
    // getObject()
    //
    
    cStmt.registerOutParameter("inOutParam", Types.INTEGER);
    ...
    

  3. Stellt die Eingabeparameter ein (sofern vorhanden)

    Eingabe und Ein/Ausgabeparameter werden ebenso gesetzt, wie für PreparedStatement-Objekte. Allerdings können CallableStatement-Parameter auch namentlich eingestellt werden:

    Beispiel 25.6. Einstellung von CallableStatement-Eingabeparametern

    ...
    
        //
        // Parameter nach Index einstellen
        //
    
        cStmt.setString(1, "abcdefg");
    
        //
        // Oder Parameter mit
        // Namen einstellen
        //
    
        cStmt.setString("inputParameter", "abcdefg");
    
        //
        // 'in/out'-Parameter nach Index einstellen
        //
    
        cStmt.setInt(2, 1);
    
        //
        // Oder 'in/out'-Parameter
        // mit Namen einstellen
        //
    
        cStmt.setInt("inOutParam", 1);
    
    ...

  4. Führen Sie CallableStatement aus und rufen Sie Ergebnismengen oder Ausgabeparameter, sofern vorhanden, ab.

    CallableStatement unterstützt zwar alle Ausführungsmethoden von Statement (executeUpdate(), executeQuery() oder execute()), aber execute() ist am flexibelsten, da Sie mit dieser Methode nicht im Voraus wissen müssen, ob die gespeicherte Prozedur Ergebnismengen unterstützt:

    Beispiel 25.7. Abruf von Ergebnissen und Ausgabeparameterwerten

    ...
    
        boolean hadResults = cStmt.execute();
    
        //
        // Alle zurückgelieferten Ergebnismengen verarbeiten
        //
    
        while (hadResults) {
            ResultSet rs = cStmt.getResultSet();
    
        // Ergebnismenge verarbeiten
            ...
    
            hadResults = rs.getMoreResults();
        }
    
        //
        // Ausgabeparameter abrufen
        //
        // Connector/J unterstützt Abruf sowohl nach Index
        // als auch nach Namen
        //
    
        int outputValue = rs.getInt(2); // index-based
    
        outputValue = rs.getInt("inOutParam"); // name-based
    
    ...

25.3.5.1.4. Abruf von AUTO_INCREMENT-Spaltenwerten

Vor der Version 3.0 der JDBC-API gab es kein Standardmittel, um Schlüsselwerte aus Datenbanken zu holen, die „Auto Increment“- oder Identitätsspalte unterstützten. Mit älteren JDBC-Treibern für MySQL konnten Sie immer eine MySQL-spezifische Methode auf der Schnittstelle Statement verwenden, oder SELECT LAST_INSERT_ID() sagen, wenn Sie eine INSERT-Operation auf einer Tabelle mit AUTO_INCREMENT-Schlüssel ausgeführt hatten. Doch die MySQL-spezifische Methode ist nicht portierbar und der Abruf der Werte des AUTO_INCREMENT-Schlüssels mit SELECT macht einen zusätzlichen Datenbankzugriff erforderlich, ist also nicht die effizienteste Methode. Die folgenden Codestücke zeigen die drei unterschiedlichen Möglichkeiten zum Abruf von AUTO_INCREMENT-Werten. Zuerst zeigen wir, wie die neue JDBC-3.0-Methode getGeneratedKeys() benutzt wird, die jetzt die Methode der Wahl ist, wenn Sie AUTO_INCREMENT-Schlüssel abfragen müssen und Zugang zu JDBC-3.0 haben. Das zweite Beispiel zeigt, wie Sie denselben Wert mit einer standardmäßigen SELECT LAST_INSERT_ID()-Anfrage abholen können. Das letzte Beispiel zeigt, wie aktualisierbare Ergebnismengen den AUTO_INCREMENT-Wert abrufen können, wenn die Methode insertRow() verwendet wurde.

Beispiel 25.8. AUTO_INCREMENT-Spaltenwerte mit Statement.getGeneratedKeys() abrufen

   Statement stmt = null;
   ResultSet rs = null;

   try {

    //
    // Erzeugt ein Statement-Objekt, das wir für
    // 'normale' Ergebnismengen verwenden können.
    // Die 'conn'-Verbindung zu einer MySQL-Datenbank
    // sei bereits vorhanden.

    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                                java.sql.ResultSet.CONCUR_UPDATABLE);

    //
    // DDL-Anfragen für dieses Beispiel
    //

    stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");
    stmt.executeUpdate(
            "CREATE TABLE autoIncTutorial ("
            + "priKey INT NOT NULL AUTO_INCREMENT, "
            + "dataField VARCHAR(64), PRIMARY KEY (priKey))");

    //
    // Fügt eine Zeile ein, die einen AUTO INCREMENT-Schlüssel im
    // Feld 'priKey' generiert
    //

    stmt.executeUpdate(
            "INSERT INTO autoIncTutorial (dataField) "
            + "values ('Can I Get the Auto Increment Field?')",
            Statement.RETURN_GENERATED_KEYS);

    //
    // So kann man den Wert einer Auto-Increment-Spalte mit
    // Statement.getGeneratedKeys() abholen
    //

    int autoIncKeyFromApi = -1;

    rs = stmt.getGeneratedKeys();

    if (rs.next()) {
        autoIncKeyFromApi = rs.getInt(1);
    } else {

    // hier Ausnahme auslösen
    }

    rs.close();

    rs = null;

    System.out.println("Key returned from getGeneratedKeys():"
        + autoIncKeyFromApi);
} finally {

    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException ex) {
            // ignorieren
        }
    }

    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException ex) {
            // ignorieren
        }
    }
}

Beispiel 25.9. Abruf von AUTO_INCREMENT-Spaltenwerten mit SELECT LAST_INSERT_ID()

   Statement stmt = null;
   ResultSet rs = null;

   try {

    //
    // Erzeugt ein Statement-Objekt, das wir für
    // 'normale' Ergebnismengen benutzen können.

    stmt = conn.createStatement();

    //
    // DDL-Anfragen für dieses Beispiel
    //

    stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");
    stmt.executeUpdate(
            "CREATE TABLE autoIncTutorial ("
            + "priKey INT NOT NULL AUTO_INCREMENT, "
            + "dataField VARCHAR(64), PRIMARY KEY (priKey))");

    //
    // Fügt eine Zeile ein, die einen AUTO INCREMENT-Schlüssel im Feld
    // 'priKey' generiert
    //

    stmt.executeUpdate(
            "INSERT INTO autoIncTutorial (dataField) "
            + "values ('Can I Get the Auto Increment Field?')");

    //
    // Verwendet die Funktion MySQL LAST_INSERT_ID(),
    // um dasselbe wie getGeneratedKeys() zu tun
    //

    int autoIncKeyFromFunc = -1;
    rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");

    if (rs.next()) {
        autoIncKeyFromFunc = rs.getInt(1);
    } else {
        // hier Ausnahme auslösen
    }

    rs.close();

    System.out.println("Key returned from " + "'SELECT LAST_INSERT_ID()': "
        + autoIncKeyFromFunc);

} finally {

    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException ex) {
            // ignorieren
        }
    }

    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException ex) {
            // ignorieren
        }
    }
}
   

Beispiel 25.10. Retrieving AUTO_INCREMENT column values in Updatable ResultSets

   Statement stmt = null;
   ResultSet rs = null;

   try {

    //
    // Erzeugt ein Statement-Objekt, das wir für
    // 'normale' ebenso wie für 'aktualisierbare' Ergebnismengen verwenden können.
    // Die 'conn''-Verbindung zu
    // einer MySQL-Datenbank sei bereits vorhanden
    //

    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                                java.sql.ResultSet.CONCUR_UPDATABLE);

    //
    // DDL-Anfragen für dieses Beispiel
    //

    stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");
    stmt.executeUpdate(
            "CREATE TABLE autoIncTutorial ("
            + "priKey INT NOT NULL AUTO_INCREMENT, "
            + "dataField VARCHAR(64), PRIMARY KEY (priKey))");

    //
    // So wird ein AUTO INCREMENT-Schlüssel von einer
    // aktualisierbaren Ergebnismenge abgerufen
    //

    rs = stmt.executeQuery("SELECT priKey, dataField "
       + "FROM autoIncTutorial");

    rs.moveToInsertRow();

    rs.updateString("dataField", "AUTO INCREMENT here?");
    rs.insertRow();

    //
    // Der Treiber fügt die Zeilen am Ende hinzu
    //

    rs.last();

    //
    // Jetzt müsste die zuvor eingefügte Zeile erreicht sein
    //

    int autoIncKeyFromRS = rs.getInt("priKey");

    rs.close();

    rs = null;

    System.out.println("Key returned for inserted row: "
        + autoIncKeyFromRS);

} finally {

    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException ex) {
            // ignorieren
        }
    }

    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException ex) {
            // ignorieren
        }
    }
}


   

Wenn Sie den Code des obigen Beispiels ausführen, müsste folgende Ausgabe erscheinen: Key returned from getGeneratedKeys(): 1 Key returned from SELECT LAST_INSERT_ID(): 1 Key returned for inserted row: 2 Bitte denken Sie daran, dass die Verwendung der Anfrage SELECT LAST_INSERT_ID() gelegentlich knifflig sein kann, da der Wert dieser Funktion als Geltungsbereich die Verbindung hat. Wenn also eine andere Anfrage auf derselben Verbindung ausgeführt wird, wird der Wert überschrieben. Dagegen hat die Methode getGeneratedKeys() das Statement-Objekt als Geltungsbereich und kann daher zwar genutzt werden, wenn andere Anfragen auf derselben Verbindung ausgeführt werden, aber nicht, wenn die Anfragen auf dem Statement-Objekt ausgeführt werden.

25.3.5.2. Connector/J mit J2EE und anderen Java-Frameworks einsetzen

In diesem Abschnitt wird beschrieben, wie Sie Connector/J in in unterschiedlichen Zusammenhängen einsetzen können.

25.3.5.2.1. Grundkonzepte von J2EE

Dieser Abschnitt vermittelt einige Grundkonzepte von J2EE, die für die Arbeit mit Connector/J von Bedeutung sind.

25.3.5.2.1.1. Verbindungspooling

Verbindungspooling ist eine Technik, die darin besteht, einen Pool von Verbindungen aufzubauen und zu verwalten, damit diese für Threads, die sie benötigen, bereits zur Verfügung stehen.

Diese Technik beruht auf der Tatsache, dass die meisten Anwendungen nur dann Thread-Zugriff auf eine JDBC-Verbindung benötigen, wenn sie gerade aktiv eine Transaktion abwickeln, die in wenigen Millisekunden fertig ist. Wenn nicht gerade eine Transaktion verarbeitet wird, würde die Verbindung normalerweise untätig herumsitzen. In einem Verbindungspool kann sie dagegen von anderen Threads sinnvoll eingesetzt werden.

In der Praxis sieht das so aus: Wenn ein Thread auf MySQL oder eine andere Datenbank mit JDBC zugreifen muss, fordert er eine Verbindung aus dem Pool an. Hat er seine Arbeit auf der Verbindung beendet, gibt er sie an den Pool zurück, damit andere Threads sie wiederverwenden können.

Eine Verbindung, die aus dem Pool entliehen wurde, wird ausschließlich von dem Thread benutzt, der sie angefordert hatte. Aus Sicht der Programmierung ist dies dasselbe, als riefe der Thread jedesmal, wenn ein eine JDBC-Verbindung benötigt, DriverManager.getConnection() auf. Beim Verbindungspooling kann er allerdings am Ende entweder eine neue oder eine bereits vorhandene Verbindung erwerben.

Verbindungspooling kann die Performance einer Java-Anwendung deutlich verbessern, da weniger Ressourcen verbraucht werden. Die Hauptvorteile des Verbindungspoolings sind:

  • Schnellerer Verbindungsaufbau

    MySQL baut zwar im Vergleich zu anderen Datenbanken ohnehin Verbindungen sehr schnell auf, aber dennoch steigt bei der Aufnahme neuer JDBC-Verbindungen immer noch die Belastung für Netzwerk und JDBC-Treiber. Diese Belastung wird durch die Wiederverwendung von Verbindungen vermieden.

  • Einfacheres Programmiermodell

    Durch das Verbindungspooling kann sich jeder einzelne Thread verhalten, als hätte er eine eigene JDBC-Verbindung. So können Sie ganz einfache JDBC-Programmiertechniken verwenden.

  • Bessere Kontrolle über den Ressourcenverbrauch

    Wenn Sie auf Verbindungspooling verzichten und stattdessen jedesmal eine neue Verbindung öffnen, wenn ein Thread eine braucht, wird Ihre Anwendung unter Umständen viele Ressourcen unnötig belegen. Bei besonderer Belastung kann dies zu unvorhersehbarem Verhalten führen.

Bedenken Sie, dass jede Verbindung zu MySQL einen Aufwand bedeutet (für Arbeitsspeicher, CPU, Kontextumschaltungen usw.), und dies sowohl auf der Client- als auch auf der Serverseite. Mit jeder weiteren Verbindung schrumpfen die Ressourcen, die Ihrer Anwendung und dem MySQL-Server noch zur Verfügung stehen. Viele dieser Ressourcen werden ganz unabhängig davon belegt, ob die Verbindung gerade etwas Nützliches leistet oder nicht!

Verbindungspools können so getunt werden, dass die Performance möglichst gut ist, während gleichtzeitig die Ressourcenauslastung immer unter dem Niveau gehalten wird, ab dem die Anwendung nicht nur langsamer läuft, sondern sogar abstürzen kann.

Zum Glück hat Sun das Verbindungspooling in JDBC in den JDBC-2.0 Optional-Schnittstellen standardisiert, und alle wichtigen Anwendungsserver verfügen über Implementierungen dieser APIs, die mit MySQL Connector/J gut harmonieren.

Generell richten Sie den Verbindungspool in den Konfigurationsdateien Ihres Anwendungsservers ein und greifen über das Java Naming and Directory Interface (JNDI) darauf zu. Der folgende Code zeigt, wie ein Verbindungspool mit einer Anwendung auf einem J2EE-Anwendungsserver genutzt werden könnte:

Beispiel 25.11. Verwendung eines Verbindungspools mit einem J2EE-Anwendungsserver

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.InitialContext;
import javax.sql.DataSource;


public class MyServletJspOrEjb {

    public void doSomething() throws Exception {
        /*
         * JNDI Initial-Kontext erstellen, um die
         *  DataSource nachschlagen zu können
         *
         * In Produktionscode sollte dieser als Objekt oder statische Variable
         * gespeichert werden, da die Erstellung eines
         * JNDI-Kontexts sehr aufwändig sein kann.
         *
         * Hinweis: Der Code funktioniert nur, wenn Sie Servlets
         * oder EJBs in einem J2EE-Anwendungsserver verwenden. Nutzen Sie
         * Verbindungspooling in Standalone-Java-Code, so
         * müssen sie die Datenquellen mit den Mitteln erstellen/konfigurieren,
         * die Ihre jeweilige Bibliothek für Verbindungspooling
         * zur Verfügung stellt.
         */

        InitialContext ctx = new InitialContext();

         /*
          * Nachschlageoperation auf der DataSource mit einem vom Anwendungsserver
          * bereitgestellten Pool im Rücken. DataSource-Objekte sollten ebenfalls
          * als Instanzvariablen zwischengespeichert werden,
          * da auch JNDI-Lookups aufwändig sind.
          */

        DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/MySQLDB");

        /*
         * Der folgende Code würde eigentlich in die 'service'-Methode Ihres
         * Servlets, JSPs oder EJBs gehören, dorthin, wo
         * sie mit einer JDBC-Verbindung arbeiten müssen.
         */

        Connection conn = null;
        Statement stmt = null;

        try {
            conn = ds.getConnection();

            /*
             * Die weitere Arbeit mit MySQL wird mit normaler JDBC-Programmierung
             * erledigt. Schließen sie jede Ressource, wenn Sie sie nicht mehr benötigen,
             * damit die Verbindungspool-Ressourcen so rasch wie möglich
             * wiederhergestellt werden
             */

            stmt = conn.createStatement();
            stmt.execute("SOME SQL QUERY");

            stmt.close();
            stmt = null;

            conn.close();
            conn = null;
        } finally {
            /*
             * Hier werden jdbc-Objekte abgeschlossen, die im normalen
             * Code nicht explizit geschlossen worden sind. So
             * entstehen keine Ressourcen-'Lecks'...
             */

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (sqlexception sqlex) {
                    // ignorieren -- da wir hier sowieso nichts daran tun können
                }

                stmt = null;
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (sqlexception sqlex) {
                     // ignorieren -- da wir hier sowieso nichts daran tun können
                }

                conn = null;
            }
        }
    }
}

Wie das obige Beispiel zeigt, sieht der Rest des Codes, nachdem Sie den JNDI-InitialContext beschafft und die DataSource nachgeschlagen haben, für erfahrene JDBC-Programmierer schon vertrauter aus.

Das Wichtigste, was Sie sich merken müssen, wenn Sie mit Verbindungspooling arbeiten: Egal was in Ihrem Code passiert (Ausnahmen, Kontrollfluss usw.), sorgen Sie immer dafür, dass Verbindungen und alles, was mit ihnen angelegt wurde (Anweisungen, Ergebnismengen usw.) immer geschlossen werden. Sonst können sie nicht wiederverwendet werden und verlaufen im Sande. Im besten Fall bedeutet dies, dass die von ihnen belegten MySQL-Server-Ressourcen (Puffer, Sperren oder Sockets) für einige Zeit wegfallen, aber im schlimmsten Fall gehen sie für immer verloren.

Was ist die optimale Größe für meinen Verbindungspool?

Wie bei anderen Konfigurations-Faustregeln lautet auch hier die Antwort: Kommt drauf an. Zwar hängt die optimale Größe von der erwarteten Last und durchschnittlichen Datenbanktransaktionsdauer ab, aber die beste Größe für einen Verbindungspool kann kleiner sein als Sie erwarten. Wenn man die Java Petstore Blueprint-Anwendung von Sun als Beispiel nimmt, kann ein Pool von 15-20 Verbindungen für eine mäßige Last (600 Benutzer gleichzeitig) ausreichen. Mit MySQL und Tomcat wären die Reaktionszeiten in einem solchen Szenario annehmbar.

Um einen Verbindungspool für Ihre Anwendung angemessen zu dimensionieren, sollten Sie Belastungstestskripten mit Apache JMeter oder The Grinder erstellen und ausprobieren, wie sich Ihre Anwendung unter Last verhält.

Am einfachsten beginnen Sie wie folgt: Stellen Sie die Höchstzahl von Verbindungen für Ihren Pool auf unbegrenzt ein, lassen Sie einen Belastungstest laufen, und messen Sie, wie viele nebenläufige Verbindungen maximal gebraucht wurden. Von dort aus gehen sie einen Schritt zurück und schauen nach, welche Mindest- und Höchstzahlen an Pool-Verbindungen die beste Performance für Ihre Anwendung ergeben.

25.3.5.2.2. Verwendung von Connector/J mit Tomcat

Die folgenden Hinweise beruhen auf den Anleitungen für Tomcat-5.x in http://jakarta.apache.org/tomcat/tomcat-5.0-doc/jndi-datasource-examples-howto.html Dies ist zum Zeitpunkt der Erstellung dieses Dokuments die aktuelle Version.

Zuerst installieren Sie die mit Connector/J mitgelieferte .jar-Datei in $CATALINA_HOME/common/lib, sodass sie allen in dem Container installierten Anwendungen zur Verfügung steht.

Nun konfigurieren Sie die JNDI-DataSource, indem Sie $CATALINA_HOME/conf/server.xml in dem Kontext, der Ihre Webanwendung definiert, eine Ressourcendeklaration hinzufügen:

<Context ....>

  ...

  <Resource name="jdbc/MySQLDB"
               auth="Container"
               type="javax.sql.DataSource"/>

  <!-- Muss _genau_  mit dem oben verwendeten Namen übereinstimmen!

       Der Verbindungspool wird mit dem Namen
       "java:/comp/env/jdbc/MySQLDB" in JNDI eingebunden
  -->

  <ResourceParams name="jdbc/MySQLDB">
    <parameter>
      <name>factory</name>
      <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
    </parameter>

    <!-- Stellen Sie diesen Wert nicht höher als max_connections auf Ihrem
         MySQL-Server ein. Normalerweise sollte er 10 oder einige Dutzend
         Verbindungen vorsehen, nicht hunderte oder tausende -->

    <parameter>
      <name>maxActive</name>
      <value>10</value>
    </parameter>

    <!-- Sie möchten nicht zu viele untätige Verbindungen unnötig offen lassen,
         nur ein paar, um mögliche Belastungsspitzen zu
         absorbieren -->

    <parameter>
      <name>maxIdle</name>
      <value>5</value>
    </parameter>

    <!-- Bitte verwenden Sie nicht autoReconnect=true, erstens wird es irgendwann abgeschafft
         und zweitens ist es ein Kreuz für ältere Verbindungspools, die
         keine Verbindungen testen konnten. Sie müssen entscheiden, ob Ihre Verbindung
         SQLExceptions beherrschen soll (Hinweis: das sollte sie!)  und wie viel
         Leistungseinbußen Sie hinnehmen wollen, um zu gewährleisten, dass
         die Verbindung "frisch" ist -->

    <parameter>
      <name>validationQuery</name>
      <value>SELECT 1</value>
    </parameter>

   <!-- Der konservativste Ansatz ist: Testen Sie Verbindungen, bevor
        Ihre Anwendung sie bekommt. Für die meisten Anwendungen ist das gut,
        außerdem ist die obige Anfrage ganz klein und belegt kaum Serverressourcen,
        abgesehen von der Zeit, die es braucht,
        sie im Netzwerk zu übermitteln.

        Wenn Sie eine Hochlast-Anwendung haben, werden Sie
        eine andere Lösung suchen müssen. -->

    <parameter>
      <name>testOnBorrow</name>
      <value>true</value>
    </parameter>

   <!-- Ansonsten, oder zusätzlich zu testOnBorrow, können Sie testen,
        während die Verbindung untätig ist  -->

    <parameter>
      <name>testWhileIdle</name>
      <value>true</value>
    </parameter>

    <!-- Diesen Wert müssen Sie einstellen, sonst wird
          der Idle-Evicter-Thread nie ausgeführt, selbst wenn Sie
         veranlasst haben, dass untätige Verbindungen getestet werden -->

    <parameter>
      <name>timeBetweenEvictionRunsMillis</name>
      <value>10000</value>
    </parameter>

    <!-- Verbindungen sollten nie zu lange untätig herumsitzen,
         jedenfalls nicht länger als wait_timeout in der Serverkonfiguration.
         Einige Minuten oder Minutenbruchteile sind hier
         manchmal akzeptabel, es hängt von Ihrer Anwendung
         und den Belastungsspitzen ab -->

    <parameter>
      <name>minEvictableIdleTimeMillis</name>
      <value>60000</value>
    </parameter>

    <!-- Benutzername und Passwort für die MySQL-Verbindung -->

    <parameter>
     <name>username</name>
     <value>someuser</value>
    </parameter>

    <parameter>
     <name>password</name>
     <value>somepass</value>
    </parameter>

    <!-- Klassenname für den Connector/J-Treiber -->

    <parameter>
       <name>driverClassName</name>
       <value>com.mysql.jdbc.Driver</value>
    </parameter>

    <!-- Der JDBC-Verbindungs-URL für MySQL. Wenn Sie andere
         MySQL-spezifische Parameter üübergeben möchten, müssen Sie
         dies hier im URL tun. Sie in den obigen Parameter-Tags
         einzustellen, hätte keine Wirkung. Außerdem müssen Sie
         &amp; als Trennzeichen zwischen die Parameterwerte setzen, da das
         Ampersand in XML ein reserviertes Zeichen ist. -->

    <parameter>
      <name>url</name>
      <value>jdbc:mysql://localhost:3306/test</value>
    </parameter>

  </ResourceParams>
</Context>

Generell sollten Sie die Installationsanleitung zu Ihrer Tomcat-Version befolgen, da sich die Datenquellenkonfiguration in Tomcat von Zeit zu Zeit ändert. Leider wird, wenn Sie in Ihrer XML-Datei die verkehrte Syntax verwenden, eine Ausnahme wie diese angezeigt:

Error: java.sql.SQLException: Cannot load JDBC driver class 'null ' SQL
state: null 
25.3.5.2.3. Verwendung von Connector/J mit JBoss

Die folgenden Anleitungen beziehen sich auf JBoss-4.x. Um die Klassen des JDBC-Teibers dem Anwendungsserver zur Verfügung zu stellen, kopieren Sie die .jar-Datei von Connector/J in das lib-Verzeichnis für Ihre Server-Konfiguration (normalerweise heißt es default). Dann legen Sie in demselben Konfigurationsverzeichnis in einem Unterverzeichnis namens deploy eine Datenquellenkonfigurationsdatei an, die mit "-ds.xml" endet. Diese veranlasst JBoss, die betreffende Datei als JDBC-Datasource einzusetzen. Die Datei sollte folgendes enthalten:

<datasources>
    <local-tx-datasource>
        <!-- Dieser Verbindungspool wird in JNDI unter dem Namen
             "java:/MySQLDB" eingebunden -->

        <jndi-name>MySQLDB</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/dbname</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>user</user-name>
        <password>pass</password>

        <min-pool-size>5</min-pool-size>

          <!--  Stellen Sie diesen Wert nicht höher als max_connections auf Ihrem
          MySQL-Server ein. Normalerweise sollte er 10 oder einige Dutzend
          Verbindungen vorsehen, nicht hunderte oder tausende -->

        <max-pool-size>20</max-pool-size>

          <!-- Verbindungen sollten nie zu lange untätig herumsitzen,
          jedenfalls nicht länger als wait_timeout in der Serverkonfiguration.
          Einige Minuten oder Minutenbruchteile sind hier
          manchmal akzeptabel, es hängt von Ihrer Anwendung
          und den Belastungsspitzen ab -->

        <idle-timeout-minutes>5</idle-timeout-minutes>

        <!-- Wenn Sie Connector/J 3.1.8 oder höher benutzen, können Sie
             unsere Implementierung verwenden, um die Stabilität
             des Verbindungspools zu erhöhen. -->

        <exception-sorter-class-name>com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter</exception-sorter-class-name>
        <valid-connection-checker-class-name>com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker</valid-connection-checker-class-name>

    </local-tx-datasource>
</datasources> 

25.3.5.3. Häufige Probleme und Lösungen

Einige Probleme treten öfters mit MySQL Connector/J auf. Dieser Abschnitt beschreibt die Symtome und ihre Heilung.

Fragen

  • 26.3.5.3.1: Wenn ich mit MySQL Connector/J eine Datenbankverbindung aufbaue, wird folgende Ausnahme ausgelöst:

    SQLException: Server configuration denies access to data source
    SQLState: 08001
    VendorError: 0

    Was ist da los? Mit dem Kommandozeilen-Client von MySQL funktioniert die Verbindung einwandfrei.

  • 26.3.5.3.2: Meine Anwendung löst die SQLException 'No Suitable Driver' aus. Warum?

  • 26.3.5.3.3: Ich versuche, MySQL Connector/J in einem Applet oder einer Anwendung einzusetzen und bekomme einen Fehler wie diesen gemeldet:

    SQLException: Cannot connect to MySQL server on host:3306.
    Is there a MySQL server running on the machine/port you
    are trying to connect to?
    
    (java.security.AccessControlException)
    SQLState: 08S01
    VendorError: 0 
  • 26.3.5.3.4: Ich habe ein Servlet/Programm, das es einen Tag lang tut und dann über Nacht nicht mehr funktioniert

  • 26.3.5.3.5: Ich versuche, aktualisierbare Ergebnismengen von JDBC-2.0 einzusetzen, und eine Fehlermeldung behauptet, meine Ergebnismenge sei gar nicht aktualisierbar.

Fragen und Antworten

26.3.5.3.1: Wenn ich mit MySQL Connector/J eine Datenbankverbindung aufbaue, wird folgende Ausnahme ausgelöst:

SQLException: Server configuration denies access to data source
SQLState: 08001
VendorError: 0

Was ist da los? Mit dem Kommandozeilen-Client von MySQL funktioniert die Verbindung einwandfrei.

MySQL Connector/J muss für die Verbindung mit MySQL TCP/IP-Sockets einsetzen, da Java keine Unix Domain Sockets unterstützt. Der Sicherheitsmanager von MySQL schaut deshalb bei einem Verbindungsversuch mit MySQL Connector/J in seine Berechtigungstabellen, um festzustellen, ob die Verbindung zulässig ist.

Damit das funktionieren kann, müssen Sie dem MySQL-Server mithilfe der GRANT Anweisung die notwendigen Sicherheitszeugnisse vorweisen. Weitere Informationen siehe Abschnitt 13.5.1.3, „GRANT und REVOKE.

Hinweis.  Ein Verbindungstest mit dem Kommandozeilenclient mysql funktioniert nur, wenn Sie das Flag --host hinzufügen und als Host etwas anderes als localhost einsetzen. Der Kommandozeilenclient mysql wird Unix-Domain-Sockets verwenden, wen Sie den speziellen Hostnamen localhost benutzen. Um die Verbindung mit localhost zu testen, müssen Sie stattdessen 127.0.0.1 als Hostnamen einsetzen.

Warnung.  Wenn Sie bei der Änderungen von Berechtigungen in MySQL Fehler machen, kann dies dazu führen, dass Ihre Serverinstallation keine optimalen Sicherheitseigenschaften mehr hat.

26.3.5.3.2: Meine Anwendung löst die SQLException 'No Suitable Driver' aus. Warum?

Für diesen Fehler gibt es drei mögliche Gründe:

  • Der Connector/J-Treiber liegt nicht in Ihrem CLASSPATH, siehe auch Abschnitt 25.3.2, „Installation von Connector/J“.

  • Der Verbindungs URL hat ein falsches Format oder Sie referenzieren den verkehrten JDBC-Treiber.

  • Die Systemeigenschaft jdbc.drivers wurde bei Benutzung des DriverManager nicht auf das Verzeichnis des Connector/J-Treibers eingestellt.

26.3.5.3.3: Ich versuche, MySQL Connector/J in einem Applet oder einer Anwendung einzusetzen und bekomme einen Fehler wie diesen gemeldet:

SQLException: Cannot connect to MySQL server on host:3306.
Is there a MySQL server running on the machine/port you
are trying to connect to?

(java.security.AccessControlException)
SQLState: 08S01
VendorError: 0 

Entweder führen Sie ein Applet aus, oder Ihr MySQL-Server wurde mit der Option "--skip-networking" installiert, oder Ihr MySQL-Server sitzt hinter einer Firewall.

Applets können Netzwerkverbindungen nur mit dem Computer aufnehmen, auf den der Webserver läuft, der die .class-Dateien des Applets liefert. Das bedeutet, dass MySQL ebenfalls auf demselben Computer laufen muss (es sei denn, Sie verwenden irgendeine Art von Port-Umleitung). Außerdem bedeutet es, dass Sie Applets nicht in Ihrem lokalen Dateisystem testen können, sondern immer erst auf einem Webserver installieren müssen.

MySQL Connector/J kann mit MySQL nur über TCP/IP kommunizieren, da Java keine Unix-Domain-Sockets unterstützt. Die TCP/IP-Kommunikation mit MySQL kann jedoch in Mitleidenschaft gezogen werden, wenn MySQL mit der Option "--skip-networking" gestartet wurde oder hinter einer Firewall sitzt.

Wenn MySQL mit der Option "--skip-networking" gestartet wurde (dies tut beispielsweise das Debian Linux-Package von MySQL Server), müssen Sie dies in der Datei /etc/mysql/my.cnf or /etc/my.cnf auskommentieren. Natürlich kann Ihre my.cnf-Datei auch im data-Verzeichnis Ihres MySQL-Servers oder irgendwo sonst liegen (je nachdem, wie MySQL für Ihr System kompiliert wurde). Binärversionen von MySQL AB schauen immer in /etc/my.cnf and [datadir]/my.cnf. Wenn Ihr MySQL-Server durch eine Firewall geschützt ist, müssen Sie diese so konfigurieren, dass sie TCP/IP-Verbindungen von dem Host, auf dem der Java-Code läuft, zu dem MySQL-Server auf dem Port zulässt, auf den MySQL lauscht (nach Voreinstellung 3306).

26.3.5.3.4: Ich habe ein Servlet/Programm, das es einen Tag lang tut und dann über Nacht nicht mehr funktioniert

MySQL schließt Verbindungen, die 8 Stunden lang inaktiv waren. Sie müssen entweder einen Verbindungspool, der alte Verbindungen behandelt, oder den "autoReconnect"-Parameter verwenden (siehe Abschnitt 25.3.4.1, „Driver/Datasource-Klassennamen, URL-Syntax und Konfigurationseigenschaften für Connector/J“).

Außerdem sollten Sie SQLExceptions in Ihrer Anwendung abfangen und behandeln, anstatt sie immer weiter durchzureichen, bis Ihre Anwendung abbricht; schon allein weil es guter Stil ist. MySQL Connector/J stellt den SQLState (siehe java.sql.SQLException.getSQLState() in Ihren APIDOCS) auf "08S01" ein, wenn es während der Verarbeitung einer Anfrage Netzwerkprobleme bekommt. Ihr Anwendungscode sollte dann versuchen, sich erneut mit MySQL zu verbinden.

Das folgende (vereinfachte) Beispiel zeigt, mit welchem Code man solche Ausnahmen behandeln könnte:

Beispiel 25.12. Beispiel einer Transaktion mit Retry-Logik

public void doBusinessOp() throws SQLException {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        //
        // Wie oft wollen Sie die Transaktion erneut versuchen
        // (oder wenigstens eine Verbindung zu bekommen)?
        //
        int retryCount = 5;

        boolean transactionCompleted = false;

        do {
            try {
                conn = getConnection(); // wir setzen voraus, dass diese von einer
                                        // javax.sql.DataSource oder dem
                                        // java.sql.DriverManager geliefert wird

                conn.setAutoCommit(false);

                //
                // An diesem Punkt hängt die 'Retry-Fähigkeit' der
                // Transaktion von Ihrer Anwendungslogik ab und davon
                // ob Sie Autocommit verwenden (in diesem Fall nicht)
                // und ob Sie transaktionssichere Speicher-Engines
                // einsetzen
                //
                // Für dieses Beispiel gehen wir davon aus, das es _nicht_ sicher ist,
                // die gesamte Transaktion erneut zu versuchen, und setzen daher
                // die Retry-Zahl auf 0
                //
                // Wenn Sie nur transaktionssichere Tabellen verwenden oder
                // Ihre Anwendung sich davon erholen könnte, wenn eine Verbindung
                // mitten in der Operation abstürzt, dann würden Sie hier am
                // 'retryCount' nichts ändern und die Schleife einfach so lange durchlaufen,
                // bis retryCount == 0.
                //
                retryCount = 0;

                stmt = conn.createStatement();

                String query = "SELECT foo FROM bar ORDER BY baz";

                rs = stmt.executeQuery(query);

                while (rs.next()) {
                }

                rs.close();
                rs = null;

                stmt.close();
                stmt = null;

                conn.commit();
                conn.close();
                conn = null;

                transactionCompleted = true;
            } catch (SQLException sqlEx) {

                //
                // Die beiden 'Retry-fähigen' SQL-Zustände sind 08S01
                // für einen Kommunikationsfehler und 40001 für Deadlock.
                //
                // Retry nur dann, wenn der Fehler wegen einer alten Verbindung,
                // Kommunikationsproblemen oder einem Deadlock auftrat
                //

                String sqlState = sqlEx.getSQLState();

                if ("08S01".equals(sqlState) || "40001".equals(sqlState)) {
                    retryCount--;
                } else {
                    retryCount = 0;
                }
            } finally {
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException sqlEx) {
                        // Das gehört ins Log. . .
                    }
                }

                if (stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException sqlEx) {
                        // Das gehört ebenfalls ins Log. . .
                    }
                }

                if (conn != null) {
                    try {
                        //
                        // Wenn hier conn nicht Null ist, sollte die
                        // Transaktion zurückgerollt werden, da noch
                        // nicht alle Arbeit erledigt ist

                        try {
                            conn.rollback();
                        } finally {
                            conn.close();
                        }
                    } catch (SQLException sqlEx) {
                        //
                        // Wenn hier eine Ausnahme auftritt, ist es ernst.
                        // Daher reichen wir sie besser im
                        // Stapel nach oben anstatt sie nur
                        // zu protokollieren . . .

                        throw sqlEx;
                    }
                }
            }
        } while (!transactionCompleted && (retryCount > 0));
    }

Hinweis.  Die Option autoReconnect wird nicht empfohlen, da es keine sichere Methode einer Neuverbindung mit dem MySQL-Server ohne das Risiko von Schäden am Verbindungszustand oder den Datenbankzustandsinformationen gibt. Nutzen Sie stattdessen einen Verbindungspool, der Ihre Anwendung in die Lage versetzt, eine verfügbare Verbindung aus dem Pool zur Kontaktaufnahme mit dem MySQL-Server zu benutzen. Die autoReconnect-Facility ist veraltet und wird in einem zukünftigen Release wahrscheinlich abgeschafft werden.

26.3.5.3.5: Ich versuche, aktualisierbare Ergebnismengen von JDBC-2.0 einzusetzen, und eine Fehlermeldung behauptet, meine Ergebnismenge sei gar nicht aktualisierbar.

Da MySQL keine Zeilenbezeichner kennt, kann MySQL Connector/J Ergebnismengen nur dann aktualsieren, wenn sie von Anfragen auf Tabellen herrühren, die mindestens einen Primärschlüssel haben. Außerdem muss die Anfrage jeden Primärschlüssel auswählen und darf sich nur auf eine einzige Tabelle beziehen (also keine Joins). Dies ist in der JDBC-Spezifikation festgelegt.

25.3.6. Support für Connector/J

25.3.6.1. Support von der Connector/J-Community

MySQL AB bietet der Benutzercommunity Unterstützung über Mailinglisten an. Bei Problemen mit Connector/J können Sie sich in der MySQL- und Java-Mailingliste Hilfe von erfahrenen Benutzern holen. Archive und Abonnementsinformationen stehen online unter http://lists.mysql.com/java zur Verfügung.

Wie Sie MySQL-Mailinglisten abonnieren oder die Listenarchive durchsuchen können, erfahren Sie unter http://lists.mysql.com/. Siehe Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

Community-Support von erfahrenen Benutzern erhalten Sie auch im JDBC Forum. Auch in den anderen MySQL-Foren unter http://forums.mysql.com wird Ihnen geholfen. Siehe auch Abschnitt 1.7.2, „MySQL-Community-Support in den MySQL-Foren“.

25.3.6.2. Probleme und Fehler von Connector/J melden

Normalerweise melden Sie Bugs bei http://bugs.mysql.com/, unserer Fehlerdatenbank. Diese Datenbank ist öffentlich; jeder kann in ihr stöbern oder suchen. Wenn Sie sich beim System anmelden, können Sie auch neue Bugreports übermitteln.

Wenn Sie einen Sicherheitsbug in MySQL gefunden haben, schicken Sie eine E-Mail an security_at_mysql.com.

Zum Schreiben eines guten Bugreports gehört Geduld, doch wenn Sie es von Anfang an richtig machen, sparen Sie unsere und Ihre eigene Zeit. Wenn wir einen guten Bugreport mit einem vollständigen Testfall für den Bug bekommen, werden wir den Fehler höchstwahrscheinlich im nächsten Release beheben können.

Dieser Abschnitt hilft Ihnen, Ihren Bericht korrekt zu verfassen, damit Sie nicht Ihre Zeit verschwenden, um uns Dinge mitzuteilen, die uns kaum oder gar nicht weiterhelfen.

Wenn Sie einen reproduzierbaren Bug melden, schicken Sie Ihren Bericht bitte an die Fehlerdatenbank unter http://bugs.mysql.com/. Einen Fehler, den wir reproduzieren können, werden wir mit Sicherheit im nächsten MySQL-Release auch beheben können.

Um andere Probleme zu melden, nutzen Sie bitte eine der MySQL-Mailinglisten.

Mit einer zu ausführlichen Meldung können wir meist etwas anfangen, aber nicht mit einer, die zu wenig Informationen enthält. Oft lassen die Nutzer Einzelheiten weg, weil sie glauben, die Fehlerursache bereits zu kennen, und manche Details für bedeutungslos halten.

Halten Sie sich an das Prinzip: Wenn Sie im Zweifel sind, ob Sie ein Detail erwähnen sollen, tun Sie es. Ein paar Zeilen mehr in Ihrem Bericht kosten Sie wenig Zeit und Mühe. Das ist besser, als lange auf eine Antwort zu warten, weil wir Informationen, die im Bericht fehlten, nachträglich von Ihnen einholen müssen.

Die häufigsten Fehler in Bugreports sind (a) der Verfasser gibt die Versionsnummer von Connector/J oder MySQL nicht an, und (b) er beschreibt die Plattform auf der Connector/J installiert ist, nicht genau genug (einschließlich JVM-Version sowie Plattformtyp und -version, auf der MySQL selbst installiert ist).

Ohne diese ungeheuer wichtigen Informationen ist der Bugreport in 99 Prozent der Fälle nutzlos. Sehr oft werden uns Fragen gestellt wie: „Warum funktioniert das bei mir nicht?“ Dann stellen wir fest, dass das verlangte Feature in dieser MySQL-Version nicht implementiert war, oder dass ein Bug, der in einem Bericht beschrieben wird, in den neueren MySQL-Versionen bereits behoben wurde.

Manchmal ist der Fehler plattformunabhängig. In solchen Fällen ist es für uns nachgerade unmöglich, irgendetwas zu reparieren, ohne das Betriebssystem und die Versionsnummer der Plattform zu kennen.

Wenn es irgend möglich ist, erstellen Sie bitte einen reproduzierbaren, eigenständigen Testfall, der keine Klassen von Drittanbietern einbezieht.

Um dies zu vereinfachen, liefern wir eine Basisklasse namens 'com.mysql.jdbc.util.BaseBugReport' für Testfälle mit Connector/J. Um mit dieser Klasse einen Testfall für Connector/J anzulegen, erstellen Sie eine eigene Klasse, die von com.mysql.jdbc.util.BaseBugReport erbt und die Methoden setUp(), tearDown() und runTest() überschreibt.

In der Methode setUp() legen Sie Ihre Tabellen an und laden die Daten hinein, die zum Demonstrieren des Fehlers erforderlich sind.

In die Methode runTest() schreiben Sie Code, der den Bug an den Tabellen und Daten, die mit setUp erstellt wurden, aufzeigt.

Mit der Methode tearDown() löschen Sie die mit setUp() erstellten Tabellen.

In einer dieser drei Methoden sollten Sie mit einer Variante der getConnection()-Methode eine JDBC-Verbindung mit MySQL aufbauen:

  • getConnection() - Richtet eine Verbindung mit dem in getUrl() angegebenen JDBC URL ein. Wenn bereits eine Verbindung besteht, wird diese zurückgegeben, andernfalls wird eine neue Verbindung angelegt.

  • getNewConnection() - Dies verwenden Sie, wenn sie eine neue Verbindung für Ihren Bugreport benötigen (d.h. wenn mehr als eine Verbindung beteiligt sind).

  • getConnection(String url) - Gibt eine Verbindung mit dem angegebenen URL zurück.

  • getConnection(String url, Properties props) - Gibt eine Verbindung mit diesem URL und diesen Eigenschaften zurück.

Wenn Sie einen anderen JDBC-URL als 'jdbc:mysql:///test' benutzen müssen, überschreiben Sie auch die Methode getUrl().

Mit den Methoden assertTrue(boolean expression) und assertTrue(String failureMessage, boolean expression) erstellen Sie Bedingungen, die in Ihrem Testfall erfüllt sein müssen, um das erwartete Verhalten zu demonstrieren (im Gegensatz zu dem Verhalten, das Sie beobachten, und wegen dem Sie den Bugreport schreiben).

Zum Schluss schreiben Sie eine main()-Methode, die eine neue Instanz Ihres Testfalls erzeugt und die run-Methode aufruft:

public static void main(String[] args) throws Exception {
      new MyBugReport().run();
 }

Wenn Sie mit Ihrem Testfall fertig sind und sich überzeugt haben, dass er den Fehler, den Sie melden, demonstriert, übermitteln Sie ihn mit Ihrem Bugreport an http://bugs.mysql.com/.

25.3.6.3. Connector/J Change History

Die Connector/J Change History (Changelog) befindet sich im Haupt-Changelog für MySQL. Siehe Abschnitt D.3, „MySQL Connector/J Change History“.

25.4. MySQL Connector/MXJ

MySQL Connector/MXJ ist eine intelligente Lösung, um eine MySQL-Datenbank-Engine (mysqld) innerhalb eines Java-Packages zu installieren.

25.4.1. Einführung in Connector/MXJ

MySQL Connector/MXJ ist ein Java Utility-Package, mit dem Sie eine MySQL-Datenbank ganz einfach durch Angabe eines Zusatzparameters im JDBC-Verbindungs-URL einsetzen und managen können. Dieser Parameter sorgt dafür, dass die Datenbank beim ersten Verbindungsaufbau gestartet wird. Java-Entwickler können datenbankgestützte Anwendungen dadurch einfacher erstellen, da die Installationshindernisse für sie selbst und die Endanwender wegfallen.

MySQL Connector/MXJ lässt die MySQL-Datenbank wie eine Java-Komponente erscheinen, indem es ermittelt, auf welcher Plattform ein System läuft, die passende Binärversion heraussucht und die Installationsdatei startet. Optional wird sogar eine Anfangsdatenbank mit den vom Benutzer vorgegebenen Parametern eingerichtet.

In den folgenden Anleitungen wird MySQL Connector/MXJ mit einem JDBC-Treiber eingesetzt und als JMX MBean auf JBoss installiert.

Quell- und Binärdateien erhalten Sie bei: http://dev.mysql.com/downloads/connector/mxj/.

Da dies ein Beta-Release ist, freuen wir uns über Feedback von Ihrer Seite.

Bitte richten Sie Fragen oder Kommentare an die MySQL- und Java-Mailingliste.

25.4.1.1. Versionen von Connector/MXJ

Connector/MX

  • Connector/MXJ 5.x, zurzeit noch im Beta-Stadium, enthält mysqld in der Version 5.0.22 sowie Binärdateien für Linux x86, Mac OS X PPC, Windows XP/NT/2000 x86 und Solaris SPARC. Connector/MXJ 5.x erfordert das Connector/J 5.x-Package.

  • Connector/MXJ 1.x umfasst mysqld in der Version 4.1.13 und Binärdateien für Linux x86, Windows XP/NT/2000 x86 und Solaris SPARC. Connector/MXJ 1.x erfordert das Connector/J 3.x-Package.

Diese Anleitung bezieht sich auf den Connector/MXJ 5.x-Release. Informationen über ältere Releases entnehmen Sie bitte der Dokumentation zu der jeweiligen Distribution.

25.4.1.2. Überblick über Connector/MXJ

Connector/MXJ besteht aus einer Java-Klasse, einer Kopie der mysqld-Binary für eine bestimmte Liste von Plattformen sowie den zugehörigen Dateien und Support-Utilities. Die Java-Klasse steuert die Initialisierung einer Instanz der eingebetteten mysqld-Binary und die weitere Verwaltung des mysqld-Prozesses. Die gesamte Sequenz und Verwaltung kann mit den Java-Klassen von Connector/MXJ komplett in Java abgewickelt werden. Die nachfolgende Abbildung gibt einen Überblick über den Inhalt von Connector/MXJ.

Überblick über Connector/MXJ

Es ist wichtig zu wissen, dass Connector/MXJ keine eingebettete Version von MySQL ist und ebenso wenig eine MySQL-Version, die als Teil einer Java-Klasse geschrieben wurde. Connector/MXJ arbeitet mit einer eingebetteten, kompilierten Binärversion von mysqld, wie sie auch sonst bei einer normalen MySQL-Installation zum Einsatz kommen würde.

Es sind der Connector/MXJ-Wrapper sowie die unterstützenden Klassen und Tools, die Connector/MXJ wie eine MySQL-Instanz aussehen lassen.

Wenn Sie Connector/MXJ initialisieren, wird die mysqld-Binärdatei für die betreffende Plattform, zusammen mit einem vorkonfigurierten Data Directory, extrahiert. Beides ist in der JAR-Datei von Connector/MXJ enthalten. Die mysqld-Instanz wird dann mit den bei der Initialisierung angegebenen weiteren Optionen gestartet, und schon ist die MySQL-Datenbank zugänglich.

Da Connector/MXJ in Kombination mit Connector/J arbeitet, können Sie über eine JDBC-Verbindung auf die MySQL-Instanz zugreifen. Wenn Sie den Server nicht mehr benötigen, wird die Instanz abgeschlossen und die während der Session angelegten Daten werden nach Voreinstellung in dem temporären Verzeichnis bewahrt, das beim Hochfahren der Instanz angelegt worden ist.

Connector/MXJ und die eingebettete mysqld können in mehreren Umgebungen eingesetzt werden, in denen es unmöglich wäre, eine vorhandene Datenbank zu benutzen oder eine neue MySQL-Instanz zu installieren. Solche Umgebungen sind beispielsweise Embedded Datenbankanwendungen auf CD-ROM und vorübergehende Datenbankanforderungen einer Java-Anwendungsumgebung.

25.4.2. Installation von Connector/MXJ

Für Connector/MXJ gibt es keine Installationsanwendung oder -prozesse, doch die folgenden Schritte können die Installation und den Einsatz von Connector/MXJ erleichtern.

Folgende Grundvoraussetzungen müssen erfüllt sein:

  • Java Runtime Environment (v1.4.0 oder höher), wenn Sie nur das Package einsetzen möchten.

  • Java Development Kit (v1.4.0 oder höher), wenn Sie Connector/MXJ aus den Quelldateien erstellen wollen.

  • Connector/J 5.0 oder höher.

Je nach der Installations-/Einsatzumgebung benötigen Sie vielleicht auch Folgendes:

25.4.2.1. Unterstützte Plattformen

Connector/MXJ ist mit jeder Plattform kompatibel, die Java und MySQL unterstützt. Connector/MXJ enthält die mysqld-Binary für ausgewählte Plattformen bereits ab Werk:

  • Linux, i386

  • Windows NT, Windows 2000, Windows XP, x86

  • Solaris 8, SPARC 32 (kompatibel mit Solaris 8, Solaris 9 und Solaris 10 auf SPARC mit 32 Bit und 64 Bit)

  • Mac OS X, PowerPC

Mehr über die Integration Ihres eigenen Connector/MXJ in die verschiedenen Plattformen erfahren Sie unter Abschnitt 25.4.5.1, „Ein eigenes Connector/MXJ-Package anlegen“.

25.4.2.2. Basisinstallation von Connector/MXJ

Da kein formaler Installationsprozess existiert, bleiben die Installationsmethode, das Installationsverzeichnis und die Zugriffsmethoden von Connector/MXJ vollständig Ihren persönlichen Bedürfnissen überlassen.

Für eine Basisinstallation suchen Sie ein Zielverzeichnis für die Dateien von Connector/MXJ aus. Auf Unix/Linux wäre dies so etwas wie /usr/local/connector-mxj und auf Windows so etwas wie C:\Connector-MXJ oder ein Unterverzeichnis von Programmdateien.

Die Dateien werden folgendermaßen installiert:

  1. Sie laden das Connector/MXJ-Package entweder im Tar/Gzip-Format (ideal für Unix/Linux) oder im Zip-Format (Windows) herunter.

  2. Sie extrahieren die Dateien, wodurch das Verzeichnis connector-mxj angelegt wird. Dieses können Sie an den gewünschten Speicherort kopieren und nach Wunsch umbenennen.

  3. Am besten schreiben Sie das Verzeichnis von Connector/MXJ JAR (connextor-mxj.jar) auch in Ihre globale Variable CLASSPATH. Zusätzlich müssen Sie die AspectJ Runtime hinzufügen, die in lib/aspectjrt.jar liegt.

    Auf Unix/Linux können Sie dies entweder global tun, indem Sie das globale Shell-Profil entsprechend bearbeiten, oder auf Benutzerebene, indem Sie das jeweilige individuelle Shell-Profil ändern.

    Auf Windows 2000, Windows NT und Windows XP bearbeiten Sie den globalen CLASSPATH, indem Sie die Umgebungsvariablen in der Systemsteuerung für System ändern.

25.4.2.3. Schnellstart mit Connector/MXJ

Sobald Sie die Komponenten von Connector/MXJ und Connector/J extrahiert haben, können Sie eine Beispielanwendung ausführen, die eine MySQL-Instanz erstellt. Testen können Sie die Installation mit ConnectorMXJUrlTestExample:

java ConnectorMXJUrlTestExample
jdbc:mysql:mxj://localhost:3336/test?server.basedir=/var/tmp/test-mxj
[MysqldResource] launching mysqld (getOptions)
[/var/tmp/test-mxj/bin/mysqld][--no-defaults][--pid-file=/var/tmp/test-mxj/data/MysqldResource.pid][--socket=mysql.sock][--datadir=/var/tmp/test-mxj/data][--port=3336][--basedir=/var/tmp/test-mxj]
[MysqldResource] launching mysqld (driver_launched_mysqld_1)
InnoDB: The first specified data file ./ibdata1 did not exist:
InnoDB: a new database to be created!
060726 15:40:42  InnoDB: Setting file ./ibdata1 size to 10 MB
InnoDB: Database physically writes the file full: wait...
060726 15:40:43  InnoDB: Log file ./ib_logfile0 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
060726 15:40:43  InnoDB: Log file ./ib_logfile1 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
060726 15:40:44  InnoDB: Started; log sequence number 0 0
060726 15:40:44 [Note] /var/tmp/test-mxj/bin/mysqld: ready for connections.
Version: '5.0.22-max'  socket: 'mysql.sock'  port: 3336  MySQL Community Edition - Experimental (GPL)
[MysqldResource] mysqld running as process: 1210
------------------------

5.0.22-max

------------------------
[MysqldResource] stopping mysqld (process: 1210)
060726 15:40:44 [Note] /var/tmp/test-mxj/bin/mysqld: Normal shutdown

060726 15:40:45  InnoDB: Starting shutdown...
060726 15:40:48  InnoDB: Shutdown completed; log sequence number 0 43655
060726 15:40:48 [Note] /var/tmp/test-mxj/bin/mysqld: Shutdown complete

[MysqldResource] clearing options
[MysqldResource] shutdown complete

Diese Ausgabe zeigt, wie MySQL startet, die notwendigen Dateien (Logdateien, InnoDB-Datendateien) angelegt werden und die MySQL-Datenbank in den Betriebszustand geht. Dann wird die Instanz von Connector/MXJ heruntergefahren, bevor das Beispiel endet.

25.4.2.4. Connector/MXJ mit dem Treiberstart installieren

Connector/MXJ und Connector/J arbeiten zusammen, damit Sie eine Instanz des mysqld-Servers einfach durch ein Schlüsselwort im JDBC-Verbindungs-String starten können. So lässt sich die Integration von Connector/MXJ in eine Java-Anwendung automatisieren und der Einsatz von Connector/MXJ wird ganz einfach:

  1. Laden und extrahieren Sie Connector/MXJ und schreiben Sie connector-mxj.jar in den CLASSPATH.

  2. Nehmen Sie in den JDBC-Verbindungs-String das Schlüsselwort mxj auf, wie hier gezeigt: jdbc:mysql:mxj://localhost:PORT/DBNAME.

Mehr zum Thema erfahren Sie in Abschnitt 25.4.3, „Konfiguration von Connector/MXJ“.

25.4.2.5. Connector/MXJ mit JBoss

Für den Einsatz in einer JBoss-Umgebung müssen Sie diese in den JDBC-Parametern so konfigurieren, dass sie die Connector/MXJ-Komponente benutzt:

  1. Laden Sie Connector/MXJ und kopieren Sie die Datei connector-mxj.jar in das Verzeichnis $JBOSS_HOME/server/default/lib.

  2. Laden Sie Connector/J und kopieren Sie die Datei connector-mxj.jar in das Verzeichnis $JBOSS_HOME/server/default/lib.

  3. Erzeugen Sie eine MBean-Service-XML-Datei im Verzeichnis $JBOSS_HOME/server/default/deploy, wobei eventuell Attribute wie datadir und autostart eingestellt werden.

  4. Stellen Sie die JDBC-Parameter Ihrer Webanwendung wie folgt ein:

    String driver = "com.mysql.jdbc.Driver"; 
    String url = "jdbc:mysql:///test?propertiesTransform="+
                 "com.mysql.management.jmx.ConnectorMXJPropertiesTransform"; 
    String user = "root"; 
    String password = ""; 
    Class.forName(driver);
    Connection conn = DriverManager.getConnection(url, user, password); 

Am besten legen Sie für Benutzer und Datenbank separate Tablespaces an, anstatt "root und test" zu verwenden.

Außerdem sollten Sie unbedingt eine Backup-Prozedur einrichten, um die Datenbankdateien im datadir zu sichern.

25.4.2.6. Installation mit JUnit überprüfen

Das beste Mittel, um sicherzustellen, dass Ihre Plattform unterstützt wird, sind die JUnit-Tests. Diese überprüfen die Connector/MXJ-Klassen und zugehörige Komponenten.

25.4.2.6.1. JUnit-Testanforderungen

Zuerst müssen Sie sich vergewissern, dass die Komponenten auf Ihrer Plattform funktionieren. Da die Klasse MysqldResource in Wirklichkeit ein Wrapper für eine native MySQL-Version ist, werden nicht alle Plattformen unterstützt. Zu der Zeit, da dies geschrieben wird, funktioniert Linux auf der i386-Architektur ziemlich gut, ebenso wie OS X v10.3. Begrenzte Tests wurden auch bereits mit Windows und Solaris vorgenommen.

Anforderungen:

  1. JDK-1.4 oder höher (oder die JRE, wenn Sie keine Quelldateien oder JSPs kompilieren).

  2. MySQL Connector/J Version 5.0 oder höher (von http://dev.mysql.com/downloads/connector/j/) muss installiert und über den CLASSPATH zugänglich sein.

  3. Die javax.management-Klassen für die JMX-Version 1.2.1, die in folgenden Anwendungsservern vorhanden sind:

  4. JUnit 3.8.1 (von http://www.junit.org/).

Wenn Sie von der Quelle kompilieren, gelten zusätzlich zu den obigen Anforderungen folgende:

  1. Ant in der Version 1.5 oder höher (von http://ant.apache.org/).

25.4.2.6.2. Durchführung der JUnit-Tests
  1. Die Tests versuchen, MySQL auf Port 3336 zu starten. Wenn Sie MySQL bereits ausführen, kann dies Konflikte verursachen. Das ist jedoch recht unwahrscheinlich, da der Standardport für MySQL 3306 ist. Sie können allerdings die Java-Eigenschaft "c-mxj_test_port" auch auf einen anderen Port Ihrer Wahl einstellen. Alternativ können Sie auch beim Starten alle noch laufenden MySQL-Instanzen auf dem Zielrechner herunterfahren.

    Nach Voreinstellung unterdrücken die Tests die Konsolenausgabe. Wenn Sie ausführliche Meldungen haben möchten, setzen Sie die Java-Eigenschaft "c-mxj_test_silent" auf "false".

  2. Um die JUnit-Testsuite auszuführen, muss der $CLASSPATH Folgendes enthalten:

    • JUnit

    • JMX

    • Connector/J

    • MySQL Connector/MXJ

  3. Fehlt connector-mxj.jar in Ihrem Download, extrahieren Sie bitte das MySQL Connector/MXJ-Quellarchiv.

    cd mysqldjmx
    ant dist
         

    Dann fügen Sie dem CLASSPATH $TEMP/cmxj/stage/connector-mxj/connector-mxj.jar hinzu.

  4. Wenn Sie junit haben, führen Sie die JUnit-Tests durch. Geben Sie hierzu auf der Kommandozeile Folgendes ein:

    java junit.textui.TestRunner com.mysql.management.AllTestsSuite
        

    Es müsste in etwa folgende Ausgabe erscheinen:

    .........................................
    .........................................
    ..........
    Time: 259.438
    
    OK (101 tests)
      

    Die Tests laufen gegen Ende etwas langsam, fassen Sie sich also in Geduld.

25.4.3. Konfiguration von Connector/MXJ

25.4.3.1. Ausführung als Teil des JDBC-Treibers

Ein Feature des MySQL Connector/J-JDBC-Treibers ist seine Fähigkeit, eine Verbindung mit einer eingebetteten Connector/MXJ-Instanz durch das Schlüsselwort mxj im JDBC-Verbindungs-String einzurichten.

Das folgende Beispiel ist ein Programm, das eine Verbindung aufbaut, eine Anfrage ausführt und die Ergebnisse an System.out ausgibt. Die MySQL-Datenbank wird im Rahmen des Verbindungsprozesses gestartet und im finally-Block heruntergefahren.

Diese Datei liegt im Connector/MXJ-Package unter src/ConnectorMXJUrlTestExample.java.

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import com.mysql.management.driverlaunched.ServerLauncherSocketFactory;

public class ConnectorMXJUrlTestExample {
    public static String DRIVER = "com.mysql.jdbc.Driver";

    public static String JAVA_IO_TMPDIR = "java.io.tmpdir";

    public static void main(String[] args) throws Exception {
        File ourAppDir = new File(System.getProperty(JAVA_IO_TMPDIR));
        File databaseDir = new File(ourAppDir, "test-mxj");
        int port = 3336;

        String url = "jdbc:mysql:mxj://localhost:" + port + "/test" + "?"
                + "server.basedir=" + databaseDir;

        System.out.println(url);

        String userName = "root";
        String password = "";

        Class.forName(DRIVER);
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, userName, password);
            printQueryResults(conn, "SELECT VERSION()");
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            ServerLauncherSocketFactory.shutdown(databaseDir, null);
        }
    }

    public static void printQueryResults(Connection conn, String SQLquery)
            throws Exception {
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(SQLquery);
        int columns = rs.getMetaData().getColumnCount();
        System.out.println("------------------------");
        System.out.println();
        while (rs.next()) {
            for (int i = 1; i <= columns; i++) {
                System.out.println(rs.getString(i));
            }
            System.out.println();
        }
        rs.close();
        stmt.close();
        System.out.println("------------------------");
        System.out.flush();
        Thread.sleep(100); // wait for System.out to finish flush
    }
}

Um dieses Programm auszuführen, vergewissern Sie sich zuerst, dass connector-mxj.jar und Connector/J im CLASSPATH liegen, und geben dann Folgendes ein:

java ConnectorMXJTestExample
  

25.4.3.2. Ausführung in einem Java-Objekt

Wenn Sie eine Java-Anwendung haben und eine MySQL-Datenbank darin „einbetten“ möchten, benutzen Sie die Klasse com.mysql.management.MysqldResource. Diese Klasse instanziieren Sie entweder mit dem (parameterlosen) Standardkonstruktor oder, indem Sie ein java.io.File-Objekt übergeben, welches das Verzeichnis darstellt, in das Sie den Server "entpacken" möchten. Sie können sie auch mit Ausgabeströmen zu "stdout" und "stderr" für die Protokollierung instanziieren.

Sobald das Datenbankobjekt erzeugt ist, ist es in der Lage, eine java.util.Map mit den für die Plattform und verwendete MySQL-Version passenden Serveroptionen anzuzeigen.

Die MysqldResource versetzt Sie in die Lage, MySQL mit einer von Ihnen gelieferten java.util.Map von Serveroptionen zu "starten" und die Datenbank "herunterzufahren". Das folgende Beispiel zeigt in vereinfachter Form, wie MySQL mit reinen Java-Objekten in eine Anwendung eingebettet wird.

Diese Datei liegt im Connector/MXJ-Package unter dem Namen src/ConnectorMXJObjectTestExample.java vor.

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

import com.mysql.management.MysqldResource;

public class ConnectorMXJObjectTestExample {
    public static String DRIVER = "com.mysql.jdbc.Driver";

    public static String JAVA_IO_TMPDIR = "java.io.tmpdir";

    public static void main(String[] args) throws Exception {
        File ourAppDir = new File(System.getProperty(JAVA_IO_TMPDIR));
        File databaseDir = new File(ourAppDir, "mysql-mxj");
        int port = 3336;

        MysqldResource mysqldResource = startDatabase(databaseDir, port);

        String userName = "root";
        String password = "";

        Class.forName(DRIVER);
        Connection conn = null;
        try {
            String url = "jdbc:mysql://localhost:" + port + "/test";
            conn = DriverManager.getConnection(url, userName, password);
            printQueryResults(conn, "SELECT VERSION()");
        } finally {
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                mysqldResource.shutdown();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static MysqldResource startDatabase(File databaseDir, int port) {
        MysqldResource mysqldResource = new MysqldResource(databaseDir);

        Map database_options = new HashMap();
        database_options.put("port", Integer.toString(port));
        mysqldResource.start("test-mysqld-thread", database_options);

        if (!mysqldResource.isRunning()) {
            throw new RuntimeException("MySQL did not start.");
        }

        System.out.println("MySQL is running.");

        return mysqldResource;
    }

    public static void printQueryResults(Connection conn, String SQLquery)
            throws Exception {
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(SQLquery);
        int columns = rs.getMetaData().getColumnCount();
        System.out.println("------------------------");
        System.out.println();
        while (rs.next()) {
            for (int i = 1; i <= columns; i++) {
                System.out.println(rs.getString(i));
            }
            System.out.println();
        }
        rs.close();
        stmt.close();
        System.out.println("------------------------");
        System.out.flush();
        Thread.sleep(100); // wait for System.out to finish flush
    }
}
  

25.4.3.3. Einstellung von Serveroptionen

Für eine MySQL-Datenbank sind natürlich viele Optionen einzustellen. Diese können Sie im JDBC-Verbindungs-String angeben, indem Sie einfach vor jede Serveroption das Präfix ''server.'' setzen. In den folgenden Beispielen setzen wir zwei Treiber- und zwei Serverparameter:

        String url = "jdbc:mysql://" + hostColonPort + "/" 
                + "?"
                + "cacheServerConfiguration=true"
                + "&"
                + "useLocalSessionState=true"
                + "&"
                + "server.basedir=/opt/myapp/db"
                + "&"
                + "server.datadir=/mnt/bigdisk/myapp/data";
  

25.4.4. Referenz zu Connector/MXJ

25.4.4.1. MysqldResource-API

25.4.4.1.1. MysqldResource-Konstruktoren

Die Klasse MysqldResource kennt drei verschiedene Konstruktorformen:

  • public MysqldResource(File baseDir, File dataDir, String mysqlVersionString, PrintStream out, PrintStream err, Utils util)

    Dieser detaillierteste Konstruktor stellt das Basisverzeichnis und das Data Directory ein, wählt einen Server anhand seines Versions-Strings aus und stellt die Standardausgabe, das Standardfehlerlog und die MySQL-Utilities-Klasse ein.

  • public MysqldResource(File baseDir, File dataDir, String mysqlVersionString, PrintStream out, PrintStream err)

    Dieser Konstruktor stellt das Basisverzeichnis und das Data Directory ein, wählt einen Server anhand seines Versions-Strings aus und stellt die Standardausgabe und das Standardfehlerlog ein.

  • public MysqldResource(File baseDir, File dataDir, String mysqlVersionString)

    Dieser Konstruktor stellt das Basisverzeichnis und das Data Directory ein und wählt einen Server anhand seines Versions-Strings aus. Die Standardausgabe und das Standardfehlerlog werden in System.out und System.err geschrieben.

  • public MysqldResource(File baseDir, File dataDir)

    Dieser Konstruktor stellt das Basisverzeichnis und das Data Directory ein und wählt die Standard-MySQL-Version aus. Die Standardausgabe und das Standardfehlerlog werden in System.out und System.err geschrieben.

  • public MysqldResource(File baseDir);

    Dieser Konstruktor erlaubt die Einstellung eines "basedir" für die MySQL-Dateien. Die Standardausgabe und das Standardfehlerlog werden in System.out und System.err geschrieben.

  • public MysqldResource();

    Das Basisverzeichnis ist auf java.io.tempdir voreingestellt. Die Standardausgabe und das Standardfehlerlog werden in System.out und System.err geschrieben.

25.4.4.1.2. MysqldResource-Methoden

Die MysqldResource-API kennt folgende Methoden:

  • void start(String threadName, Map mysqldArgs);

    Lädt und startet MySQL. Der String "threadName" benennt den Thread, der die MySQL-Kommandozeile ausführt. Die Map enthält die an die Kommandozeile zu übergebenden Argumente und ihre Werte.

  • void shutdown();

    Fährt die vom MysqldResource-Objekt verwaltete MySQL-Instanz herunter.

  • Map getServerOptions();

    Gibt eine Map mit allen Optionen und ihren aktuellen Optionen zurück, die der MySQL-Datenbank zur Verfügung stehen (oder mit den Standardoptionen, wenn die Datenbank nicht läuft).

  • boolean isRunning();

    Gibt true zurück, wenn die MySQL-Datenbank läuft.

  • boolean isReadyForConnections();

    Gibt true zurück, wenn die Datenbank meldet, dass sie für Verbindungen zur Verfügung steht.

  • void setKillDelay(int millis);

    Das Standard-„Kill Delay“ beträgt 30 Sekunden. Dies ist die Zeit, die zwischen der Shutdown-Anforderung und einem „force kill“ vergeht, wenn die Datenbank nicht selbst herunterfährt.

  • void addCompletionListenser(Runnable listener);

    Ermöglicht es, Anwendungen zu benachrichtigen, wenn der Serverprozess fertig ist. Jeder ''Listener'' wird in seinem eigenen Thread abgeschlossen.

  • String getVersion();

    Gibt die MySQL-Version zurück.

  • void setVersion(int MajorVersion, int minorVersion, int patchLevel);

    In der Standarddistribution ist nur eine einzige MySQL-Version enthalten. Es ist jedoch auch möglich, mehrere Versionen beizufügen und anzugeben, welche davon benutzt werden soll.

25.4.5. Hinweise und Tipps zu Connector/MXJ

Dieser Abschnitt enthält Hinweise und Tipps zur Verwendung von Connector/MXJ in Ihren Anwendungen.

25.4.5.1. Ein eigenes Connector/MXJ-Package anlegen

Wenn Sie ein eigenes Connector/MXJ-Package schnüren wollen, das eine bestimmte mysqld-Version oder Plattform enthält, dann müssen Sie die Datei connector-mxj.jar extrahieren und neu erstellen.

Als Erstes legen Sie ein neues Verzeichnis an, in welches Sie die connector-mxj.jar-Datei extrahieren:

shell> mkdir custom-mxj
shell> cd custom-mxj
shell> jar -xf connector-mxj.jar
shell> ls
5-0-22/
ConnectorMXJObjectTestExample.class
ConnectorMXJUrlTestExample.class
META-INF/
TestDb.class
com/
kill.exe

Das MySQL-Versionsverzeichnis, im obigen Beispiel 5-0-22, enthält alle Dateien, die notwendig sind, um bei der Ausführung von Connector/MXJ eine MySQL-Instanz zu erzeugen. Alle Dateien in diesem Verzeichnis sind für jede Version von MySQL notwendig, die Sie einbetten möchten. Achten Sie bitte auch auf das Format der Versionsnummer, das Bindestriche statt Punkte enthält, um die Einzelbestandteile der Versionsnummer abzugrenzen.

In dem versionsspezifischen Verzeichnis liegen plattformspezifische Verzeichnisse sowie die von MySQL für die diversen Plattformen benötigten Archive des data- und share-Verzeichnisses. Hier sehen Sie zum Beispiel das Listing des standardmäßigen Connector/MXJ-Packages:

shell>> ls
Linux-i386/
META-INF/
Mac_OS_X-ppc/
SunOS-sparc/
Win-x86/
com/
data_dir.jar
share_dir.jar
win_share_dir.jar

Plattformspezifische Verzeichnisse werden nach Betriebssystem und Plattform aufgeführt. So liegt zum Beispiel die mysqld für Mac OS X PowerPC im Verzeichnis Mac_OS_X-ppc. Sie können Verzeichnisse, die Sie nicht benötigen, löschen und neue Verzeichnisse für weitere Plattformen hinzufügen.

Um eine plattformspezifische mysqld hinzuzufügen, erstellen Sie ein neues Verzeichnis mit dem für Ihr Betriebssystem/Ihre Plattform passenden Namen. Sie könnten zum Beispiel für Mac OS X/Intel das Verzeichnis Mac_OS_X-i386 einrichten.

Auf Unix-Systemen können Sie die Plattform mit uname ermitteln:

shell> uname -p
i386

Nun müssen Sie mysqld für die MySQL-Version und Plattform in das neue Verzeichnis kompilieren, die Sie in Ihr eigenes connector-mxj.jar-Package aufnehmen möchten.

Legen Sie in dem soeben erstellten BS/Plattform-Verzeichnis eine Datei namens version.txt an, die den Versions-String und Pfad der mysqld-Binary enthält, zum Beispiel:

mysql-5.0.22-osx10.3-i386/bin/mysqld

Nun können Sie die Dateiconnector-mxj.jar mit der frisch hinzugefügten mysqld-Binary neu erstellen:

shell> cd custom-mxj
shell> jar -cf ../connector-mxj.jar *

Testen können Sie dieses Ppackage wie in Abschnitt 25.4.2.3, „Schnellstart mit Connector/MXJ“, beschrieben.

25.4.5.2. Connector/MXJ mit einer vorkonfigurierten Datenbank einsetzen

Um eine vorkonfigurierte und mit Daten bevölkerte Datenbank in Ihre Connector/MXJ-JAR-Datei aufzunehmen, müssen Sie eine eigene data_dir.jar-Datei anlegen, wie sie in der Haupt-connector-mxj.jar-Datei enthalten ist:

  1. Zuerst extrahieren Sie connector-mxj.jar wie im vorigen Abschnitt beschrieben (siehe Abschnitt 25.4.5.1, „Ein eigenes Connector/MXJ-Package anlegen“).

  2. Erstellen Sie in einer vorhandenen MySQL-Instanz (einschließlich Connector/MXJ-Instanzen) Ihre Datenbank und laden Sie Daten hinein. Die Formate der Datendateien sind plattformunabhängig.

  3. Fahren Sie die MySQL-Instanz herunter.

  4. Erstellen Sie aus dem Data Directory und den Datenbanken, die Sie in Ihr Connector/MXJ-Package einbinden möchten, eine JAR-Datei. Diese sollte zusätzlich zu den spezifischen Datenbanken, die Sie aufnehmen möchten, auch die mysql-Datenbank mit den Daten zur Benutzerauthentifizierung enthalten. Folgender Befehl legt beispielsweise ein JAR mit den Datenbanken mysql und mxjtest an:

    shell> jar -cf ../data_dir.jar mysql mxjtest
  5. Kopieren Sie die data_dir.jar-Datei in das extrahierte connector-mxj.jar-Verzeichnis und erstellen Sie dann ein Archiv für connector-mxj.jar.

Wenn Sie Datenbanken mit der InnoDB-Engine anlegen, müssen Sie die Dateien ibdata.* und ib_logfile.* in das data_dir.jar-Archiv aufnehmen.

25.4.5.3. Ausführung mit (speziellem) JMX-Agent

Als JMX MBean erfordert MySQL Connector/MXJ einen JMX v1.2-konformen MBean-Container wie etwa JBoss in der Version 4. Die MBean stellt mithilfe der JMX-Management-APIs die für die gegebene Plattform geeigneten Parameter ein (und ermöglicht auch Ihnen, die Parameter zu setzen).

Wenn Sie nicht die SUN-Referenzimplementierung der JMX-Bibliotheken verwenden, sollten Sie diesen Abschnitt übergehen, und wenn Sie JBoss verwenden, überspringen Sie auch den nachfolgenden Abschnitt.

Betrachten wir nun die MysqldDynamicMBean in einem JMX-Agenten in Aktion. Im com.mysql.management.jmx.sunri-Package befindet sich ein speziell angepasster JMX-Agent mit zwei MBeans:

  1. MysqldDynamicMBean und

  2. einem com.sun.jdmk.comm.HtmlAdaptorServer, der eine Webschnittstelle zur Manipulation der Beans in einem JMX-Agent bereitstellt.

Wenn dieser sehr einfache Agent gestartet wird, kann eine MySQL-Datenbank über einen Webbrowser gestartet und angehalten werden.

  1. Beenden Sie den Plattformtest wie oben.

    • Aktuelle Versionen von JDK, JUnit, Connector/J, MySQL Connector/MXJ

    • Dieser Abschnitt erfordert die SUN-Referenzimplementierung von JMX.

    • PATH, JAVA_HOME, ANT_HOME, CLASSPATH

  2. Wenn Sie nicht von der Quelle installieren, gehen Sie zum nächsten Abschnitt weiter.

    Rebuild mit "sunri.present"

    ant -Dsunri.present=true dist 
    re-run tests:
    java junit.textui.TestRunner com.mysql.management.AllTestsSuite
    
  3. Starten Sie den Test-Agenten auf der Kommandozeile:

    java com.mysql.management.jmx.sunri.MysqldTestAgentSunHtmlAdaptor &
         
  4. ... von einem Browser:

    http://localhost:9092/
         
  5. ... unter MysqldAgent:

    select "name=mysqld"
         
  6. Beobachten Sie die MBean-View.

  7. Scrollen Sie den Bildschirm nach unten und klicken Sie auf startMysqld.

  8. Klicken Sie auf Back to MBean View.

  9. Scrollen Sie den Bildschirm nach unten und klicken Sie auf stopMysqld.

  10. Halten Sie den Java-Prozess an, der den Test-Agent ausführt (jmx server).

25.4.5.4. Einsatz in einer Standardumgebung von JMX Agent (JBoss)

Wenn Sie sich darauf verlassen können, dass MBean auf der Plattform funktioniert, können Sie die MBean in einem normalen JMX Agent einsetzen. Die folgenden Anleitungen beziehen sich auf eine Installation mit JBoss.

  1. Achten Sie auf eine aktuelle Version des Java Development Kits (v1.4.x), siehe oben.

    • Vergewissern Sie sich, dass JAVA_HOME gesetzt ist (JBoss benötigt JAVA_HOME).

    • Sorgen Sie dafür, dass JAVA_HOME/bin im PATH liegt (Sie müssen NICHT den CLASSPATH einstellen und benötigen auch keines der JARs aus den vorherigen Tests).

  2. Achten Sie auf eine aktuelle Version von JBoss (v4.0RC1 oder höher).

    http://www.jboss.org/index.html
    select "Downloads"
    select "jboss-4.0.zip"
    pick a mirror
    unzip ~/dload/jboss-4.0.zip
    create a JBOSS_HOME environment variable set to the unzipped directory
    unix only:
    cd $JBOSS_HOME/bin
    chmod +x *.sh
    
  3. Kopieren Sie connector-mxj.jar in $JBOSS_HOME/server/default/lib.

  4. Kopieren Sie mysql-connector-java-3.1.4-beta-bin.jar in $JBOSS_HOME/server/default/lib.

  5. Legen Sie ein mxjtest.war-Verzeichnis in $JBOSS_HOME/server/default/deploy an.

  6. Kopieren Sie index.jsp in $JBOSS_HOME/server/default/deploy/mxjtest.war.

  7. Legen Sie eine mysqld-service.xml-Datei in $JBOSS_HOME/server/default/deploy an.

    <?xml version="1.0" encoding="UTF-8"?>
     <server>
      <mbean code="com.mysql.management.jmx.jboss.JBossMysqldDynamicMBean"
         name="mysql:type=service,name=mysqld">
      <attribute name="datadir">/tmp/xxx_data_xxx</attribute>
      <attribute name="autostart">true</attribute>
      </mbean>
     </server>
         
  8. Starten Sie jboss:

    • auf Unix: $JBOSS_HOME/bin/run.sh

    • auf Windows: %JBOSS_HOME%\bin\run.bat

    Wappnen Sie sich: JBoss schickt jede Menge Ausgabe auf den Bildschirm.

  9. Wenn JBoss keine Ausgabe mehr an den Bildschirm sendet, öffnen Sie einen Browser auf http://localhost:8080/jmx-console.

  10. Scrollen Sie auf der Seite nach unten zum Abschnitt mysql und wählen Sie den mysqld-Link aus.

  11. Schauen Sie auf die Seite JMX MBean View. MySQL müsste bereits laufen.

  12. (Wenn "autostart=true" eingestellt ist, können Sie diesen Schritt übergehen.) Scrollen Sie auf dem Bildschirm nach unten. Sie können auf Invoke klicken, damit MySQL aufhört (oder anfängt), Operation completed successfully without a return value zu sagen. Klicken Sie auf Back to MBean View.

  13. Um sich zu vergewissern, dass MySQL läuft, öffnen Sie einen Browser auf http://localhost:8080/mxjtest/. Sie müssten jetzt sehen können, dass

    SELECT 1

    folgendes Ergebnis zurückgegeben hat:

    1
  14. Mit der Benutzerführung von $JBOSS_HOME/server/default/deploy/mxjtest.war/index.jsp können Sie MySQL in Ihrer Webanwendung einsetzen. Eine test-Datenbank und ein root-User (ohne Passwort) stehen bereits zum Herumexperimentieren bereit. Versuchen Sie, eine Tabelle anzulegen, einige Zeilen einzufügen und SELECT-Operationen darauf auszuführen.

  15. Fahren Sie MySQL herunter. MySQL wird automatisch angehalten, wenn JBoss herunterfährt. Oder scrollen Sie im Browser die MBean View nach unten und klicken Sie auf den Button Invoke, um den Dienst anzuhalten. Es wird Operation completed successfully without a return value angezeigt. ps oder der Taskmanager werden Ihnen bestätigen, dass MySQL nicht mehr ausgeführt wird.

Seit der Beta-Version 1.0.6 kann die MBean die MySQL-Datenbank beim Hochfahren starten. Mithilfe der Life-Cycle-Erweiterungsmethoden von JBoss haben wir außerdem dafür gesorgt, dass MySQL mit JBoss gemeinsam herunterfährt.

25.4.6. Support für Connector/MXJ

Es gibt viele Möglichkeiten, Support für Connector/MXJ zu bekommen. Bitte fragen Sie die Connector/MXJ-Community um Hilfe, ehe Sie einen potenziellen Bug oder ein Problem melden. Siehe Abschnitt 25.4.6.1, „Support von der Connector/MXJ-Community“.

25.4.6.1. Support von der Connector/MXJ-Community

MySQL AB unterstützt die Benutzer-Community mit mehreren Mailinglisten und Webforen.

Hilfe und Support finden Sie in der MySQL- und Java-Mailingliste.

Wie Sie MySQL-Mailinglisten abonnieren oder die Listenarchive durchsuchen können, erfahren Sie unter http://lists.mysql.com/. Siehe Abschnitt 1.7.1, „Die MySQL-Mailinglisten“.

Community-Support von erfahrenen Benutzern erhalten Sie auch im MyODBC-Forum . Auch in den anderen MySQL-Foren unter http://forums.mysql.com wird Ihnen geholfen. Siehe Abschnitt 1.7.2, „MySQL-Community-Support in den MySQL-Foren“.

25.4.6.2. Probleme und Fehler von Connector/MXJ melden

Wenn Sie Probleme mit Connector/MXJ haben, wenden Sie sich bitte zuerst an die Connector/MXJ-Community, siehe Abschnitt 25.4.6.1, „Support von der Connector/MXJ-Community“.

Wenn Sie ein Problem melden, geben Sie uns bitte per E-Mail folgende Informationen:

  • Betriebssystem und Version

  • Connector/MXJ-Version

  • MySQL Server-Version

  • Kopien von Fehlermeldungen oder anderen unerwarteten Ausgaben

  • einfaches, reproduzierbares Beispiel

Achtung: Je mehr Informationen Sie uns geben können, umso wahrscheinlicher ist es, dass wir das Problem beheben können.

Wenn Sie der Auffassung sind, dass es sich um einen Bug handelt, senden Sie uns einen Bugreport über http://bugs.mysql.com/.

Kapitel 26. MySQL erweitern

26.1. Hinzufügen neuer Funktionen zu MySQL

In diesem Kapitel wird vieles beschrieben, was Sie wissen müssen, wenn Sie am Code von MySQL arbeiten möchten. Wenn Sie selbst zu der Entwicklung von MySQL beitragen wollen, Zugriff auf den allerneuesten Entwicklungsstand des Codes zwischen zwei Versionen benötigen oder einfach nur die Entwicklung mitverfolgen möchten, befolgen Sie bitte die Anleitungen unter Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“. Wenn Sie sich für die Interna von MySQL interessieren, sollten Sie auch unsere internals-Mailingliste abonnieren. Auf dieser Liste herrscht relativ wenig Verkehr. Wie Sie sie abonnieren können, erfahren Sie unter Abschnitt 1.7.1, „Die MySQL-Mailinglisten“. Alle Entwickler bei MySQL AB sind auf der internals-List und wir helfen gerne auch anderen weiter, die am MySQL-Code arbeiten. Bitte nutzen Sie diese Liste, um Fragen über den Code zu stellen und Patches zu übermitteln, falls Sie gerne selbst zu dem MySQL-Projekt beitragen möchten!

26.1.1. MySQL-Threads

Der MySQL Server erzeugt folgende Threads:

  • Der TCP/IP-Verbindungs-Thread behandelt alle Verbindungsanfragen und erzeugt für jede Verbindung einen neuen dedizierten Thread zur Authentifizierung und Verarbeitung von SQL-Anfragen.

  • Auf Windows NT gibt es einen Handler-Thread für die Named Pipe, der für Named-Pipe-Verbindungsanfragen dieselbe Arbeit wie der TCP/IP-Verbindungs-Thread leistet.

  • Der Signal-Thread kümmert sich um Signale und normalerweise auch um Alarmsignale und process_alarm()-Aufrufe, um Verbindungen, die zu lange ungenutzt waren, per Timeout zu beenden.

  • Wenn mysqld mit -DUSE_ALARM_THREAD kompiliert wird, wird ein spezieller Thread für den Umgang mit Alarmen erzeugt. Das wird aber nur bei Systemen getan, auf denen es Probleme mit sigwait() gibt, oder wenn Sie den Code der Funktion thr_alarm() in Ihrer Anwendung ohne einen dedizierten Thread zur Signalbehandlung einsetzen möchten.

  • Wenn die Option --flush_time=val gesetzt ist, wird ein dedizierter Thread erzeugt, der in den gegebenen Abständen alle Tabellen auf die Platte zurückschreibt.

  • Jede Verbindung besitzt ihren eigenen Thread.

  • Jede Tabelle, für die INSERT DELAYED gilt, bekommt ihren eigenen Thread.

  • Wenn Sie die Option --master-host setzen, wird ein Thread für die Slave-Replikation gestartet, um Updates vom Master zu lesen und anzuwenden.

Der Befehl mysqladmin processlist zeigt nur den Verbindungs-Thread, den INSERT DELAYED-Thread und den Replikations-Thread an.

26.1.2. MySQL-Testsystem

Mit dem in den Unix-Quell- und Binärdistributionen enthaltenen Testsystem können Nutzer und Entwickler Regressionstests mit dem MySQL-Code durchführen. Diese Tests kann man auf Unix, aber zurzeit noch nicht in einer nativen Windows-Umgebung laufen lassen.

Die momentan vorhandenen Testfälle testen nicht alles in MySQL, sollten aber die offensichtlichsten Fehler im Code zur SQL-Verarbeitung sowie OS/Bibliothek-Probleme finden, und leisten ziemlich gründliche Arbeit beim Testen von Replikation. Unser Ziel ist es, letztlich 100 % des Codes mit unseren Tests abzudecken. Wir freuen uns über Beiträge zu unserer Testreihe. Insbesondere können Sie uns Tests für systemkritische Funktionalitäten schicken, um zu gewährleisten, dass alle zukünftigen MySQL-Releases auch mit Ihren Anwendungen harmonieren.

26.1.2.1. Benutzung der MySQL-Testsuite

Das Testsystem besteht aus einem Testsprachen-Interpreter (mysqltest), einem Shell-Skript, um alle Tests auszuführen (mysql-test-run), den eigentlichen Testfällen, die in einer speziellen Testsprache geschrieben sind, sowie aus den erwarteten Ergebnissen. Um die Testreihe nach einem Build auf Ihrem System auszuführen, geben Sie make test oder mysql-test/mysql-test-run im Wurzelverzeichnis des Quellcodes ein. Wenn Sie eine Binärdistribution installiert haben, wechseln Sie in das Wurzelverzeichnis der Installation (beispielsweise /usr/local/mysql) und führen scripts/mysql-test-run aus. Alle Tests sollten erfolgreich laufen. Ist das nicht der Fall, müssen Sie die Gründe herausfinden und einen Bugreport übermitteln, wenn es sich um einen Fehler in MySQL handelt. Siehe Abschnitt 26.1.2.3, „Berichten von Bugs in der MySQL-Test-Suite“.

Wenn eine Instanz von mysqld auf dem Computer läuft, auf dem Sie die Testreihe ausführen möchten, müssen Sie diese nur dann herunterfahren, wenn sie den Port 9306 oder 9307 belegt. Wenn einer dieser Ports nicht frei ist, müssen Sie in mysql-test-run die Werte des Master- oder Slave-Ports umändern und einen Port einsetzen, der frei ist.

Sie können einen einzelnen Testfall mit mysql-test/mysql-test-run test_name ausführen.

Wenn ein Test scheitert, führen Sie mysql-test-run mit der Option --force aus, um zu prüfen, ob auch andere Tests fehlschlagen.

26.1.2.2. Erweiterung der MySQL-Testsuite

Mit der Sprache mysqltest können Sie auch Ihre eigenen Testfälle schreiben. Allerdings haben wir leider die Dokumentation dieser Sprache noch nicht ganz fertig gestellt. Sie können sich jedoch unsere aktuellen Testfälle anschauen und als Beispiele heranziehen. Die folgenden Hinweise müssten Ihnen bei den ersten Schritten eine Hilfe sein:

  • Sie finden die Tests in mysql-test/t/*.test.

  • Ein Testfall besteht aus Anweisungen, die mit ; abgeschlossen werden, und ähnelt der Eingabe für den mysql-Kommandozeilen-Client. Eine Anweisung ist standardmäßig eine SQL-Anweisung, die an den MySQL Server gesandt wird, es sei denn, sie wird als interner Befehl erkannt (wie beispielsweise sleep).

  • Vor allen Anfragen, die Ergebnisse produzieren, wie beispielsweise SELECT, SHOW oder EXPLAIN, muss ein @/path/to/result/file stehen. Diese Datei muss die erwarteten Ergebnisse enthalten. Ein einfaches Mittel, um die Ergebnisdatei zu generieren, besteht darin, mysqltest -r < t/test-case-name.test im Verzeichnis mysql-test auszuführen und dann die generierten Ergebnisdateien wenn nötig zu bearbeiten, um sie an die erwartete Ausgabe anzupassen. In diesem Fall müssen Sie sehr genau darauf achten, keine unsichtbaren Zeichen zu löschen oder hinzuzufügen. Sie dürfen nur den Text ändern oder Zeilen löschen. Wenn Sie eine Zeile einfügen müssen, achten Sie darauf, dass die Felder durch einen Tabulator getrennt werden, und setzen Sie auch am Ende einen Tabulator. Mit od -c können Sie sich vergewissern, dass Ihr Editor bei der Bearbeitung keinen Unsinn gemacht hat. Wir hoffen, dass Sie niemals die Ausgabe von mysqltest -r bearbeiten müssen, da dies nur nötig wird, wenn Sie einen Fehler finden.

  • Um Ihr System wie unseres einzurichten, legen Sie die Ergebnisdateien in das Verzeichnis mysql-test/r und nennen sie test_name.result. Wenn der Test mehr als ein Ergebnis produziert, verwenden Sie die Namen test_name.a.result, test_name.b.result und so weiter.

  • Wenn eine Anweisung einen Fehler zurückgibt, sollten Sie diesen mit --error error-number auf der Zeile vor dieser Anweisung angeben. Die Fehlernummer kann auch eine kommagetrennte Liste von Fehlernummern sein.

  • Wenn Sie einen Replikationstestfall schreiben, setzen Sie in die erste Zeile der Testdatei den Text source include/master-slave.inc;. Mit connection master; und connection slave; schalten Sie zwischen Master und Slave um. Wenn Sie auf einer anderen Verbindung arbeiten müssen, können Sie für den Master connection master1; und für den Slave connection slave1; eingeben.

  • Falls Sie eine Schleifenverarbeitung ausführen müssen, können Sie Folgendes tun:

    let $1=1000;
    while ($1)
    {
     # Hier Anfragen einfügen
     dec $1;
    }
    
  • Mit sleep schläft das System zwischen zwei Anfragen. Da in diesem Befehl auch Sekundenbruchteile eingestellt werden können, bedeutet beispielsweise sleep 1.3;, dass das System 1,3 Sekunden schläft.

  • Um den Slave mit Zusatzoptionen für den Testfall auszuführen, setzen Sie die Optionen in einem Kommandozeilenformat in die Datei mysql-test/t/test_name-slave.opt bzw. für den Master in die Datei mysql-test/t/test_name-master.opt.

  • Wenn Sie Fragen zu der Testreihe haben oder selbst einen Test beisteuern möchten, schicken Sie eine E-Mail an die MySQL-Mailingliste internals (siehe Abschnitt 1.7.1, „Die MySQL-Mailinglisten“). Da diese Liste keine Anhänge akzeptiert, laden Sie alle relevanten Dateien per FTP auf folgende Adresse hoch: ftp://ftp.mysql.com/pub/mysql/upload/.

26.1.2.3. Berichten von Bugs in der MySQL-Test-Suite

Wenn Ihre MySQL-Version die Testreihe nicht besteht, tun Sie Folgendes:

  • Senden Sie uns bitte erst dann einen Bugreport, wenn Sie so viel wie möglich über das Problem herausgefunden haben! Schauen Sie bitte auch in die Anleitungen unter Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

  • Speichern Sie die Ausgabe von mysql-test-run sowie die Inhalte sämtlicher .reject-Dateien im Verzeichnis mysql-test/r.

  • Wenn ein Test in der Testreihe fehlschlägt, überprüfen Sie, ob der Test auch dann scheitert, wenn er isoliert ausgeführt wird:

    cd mysql-test
    mysql-test-run --local test-name
    

    Wenn dies scheitert, sollten Sie MySQL mit der Option --with-debug konfigurieren und mysql-test-run mit der Option --debug ausführen. Wenn auch das fehlschlägt, senden Sie die Trace-Datei var/tmp/master.trace an ftp://ftp.mysql.com/pub/mysql/upload/, damit wir sie untersuchen können. Bitte senden Sie uns außerdem eine vollständige Beschreibung Ihres Systems, die Version Ihrer mysqld-Binary sowie Informationen, wie Sie sie kompiliert haben.

  • Lassen Sie mysql-test-run mit der --force-Option laufen, um zu erfahren, ob auch ein anderer Test scheitert.

  • Wenn Sie MySQL selbst kompiliert haben, schlagen Sie in unserem Handbuch nach, wie MySQL auf Ihrer Plattform kompiliert wird, oder – noch besser – verwenden Sie eine der Binaries, die wir für Sie bereits vokompiliert haben (siehe http://dev.mysql.com/downloads/). Alle unsere Standardbinaries dürften die Testreihe überstehen!

  • Wenn Sie eine Fehlermeldung wie Result length mismatch oder Result content mismatch bekommen, so bedeutet dies, dass die Testausgabe nicht mit der erwarteten Ausgabe übereinstimmt. Dies könnte ein Bug in MySQL sein oder aber daran liegen, dass Ihre mysqld-Version unter bestimmten Umständen abweichende Ergebnisse bringt.

    Die Ergebnisse von gescheiterten Tests werden in eine Datei gespeichert, die genau wie die Ergebnisdatei heißt, aber die Erweiterung .reject hat. Wenn Ihr Testfall scheitert, lassen Sie einen Diff-Befehl auf den beiden Dateien laufen. Ist nicht zu erkennen, worin sie sich unterscheiden, so untersuchen Sie beide mit od -c und vergleichen auch ihre Längen.

  • Scheitert ein Test vollständig, suchen Sie in den Logdateien im Verzeichnis mysql-test/var/log nach Gründen.

  • Haben Sie MySQL mit Debugging kompiliert, so können Sie versuchen, mysql-test-run mit der Option --gdb und/oder --debug auszuführen. Siehe auch Abschnitt E.1.2, „Trace-Dateien erzeugen“.

    Wurde MySQL nicht mit Debugging kompiliert, so sollten Sie dies nun nachholen. Dazu müssen Sie lediglich configure mit den --with-debug-Optionen ausführen. Siehe Abschnitt 2.8, „Installation der Quelldistribution“.

26.2. Die MySQL-Plug-In-Schnittstelle

MySQL 5.1 und höher unterstützt eine Plug-In-API, mit der Serverkomponenten zur Laufzeit ge- oder entladen werden können, ohne den Server neu zu starten. Zurzeit unterstützt diese API die Erstellung von Volltext-Parser-Plug-Ins. Durch ein solches Plug-In lässt sich der eingebaute Volltext-Parser ersetzen oder verbessern. So kann beispielsweise ein Plug-In andere Regeln als der eingebaute Parser verwenden, um Text in Wörter zu parsen. Das kann nützlich sein, wenn Sie Text parsen möchten, der andere Merkmale hat, als sie der eingebaute Parser erwartet.

Die Plug-In-API soll Nachfolger der älteren Schnittstelle für benutzerdefinierte Funktionen (UDFs) sein. Im Endausbau wird sie auch eine API für die Erstellung von UDFs enthalten und die ältere, nicht als Plug-In geschriebene UDF-API ersetzen. Von da an wird es möglich sein, UDFs so zu überarbeiten, dass sie als Plug-In-UDFs benutzt werden können und somit auch von den besseren Sicherheits- und Versionierungsfähigkeiten der Plug-In-API profitieren. Im Anschluss daran wird der Support für die alte UDF-API auslaufen.

Die Plug-In-API benötigt die plugin-Tabelle in der mysql-Datenbank. Diese Tabelle wird im Installationsprozess von MySQL angelegt. Wenn Sie von einer älteren Version auf MySQL 5.1 aufrüsten, erstellen Sie diese Tabelle mit dem Befehl mysql_fix_privilege_tables. Siehe Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

26.2.1. Charakteristiken der Plug-In-Schnittstelle

In mancher Hinsicht ähnelt die Plug-In-API der älteren UDF-API, die sie ersetzen soll, aber sie bietet eine Reihe von Vorteilen gegenüber ihrer Vorläuferin:

  • Das Plug-In-Framework ist erweiterbar, sodass es verschiedene Arten von Plug-Ins aufnehmen kann.

    Manche Aspekte hat die Plug-In-API mit allen Plug-Ins gemeinsam, aber sie gestattet darüber hinaus auch typspezifische Schnittstellenelemente, sodass unterschiedliche Arten von Plug-Ins erstellt werden können. Ein Plug-In, das einem bestimmten Zweck dient, kann somit die für seine Erfordernisse geeignetste Schnittstelle haben, anstatt sich an den Bedürfnissen eines anderen Plug-In-Typs zu orientieren.

    Auch wenn zurzeit nur die Schnittstelle für Volltext-Parser-Plug-Ins implementiert ist, können noch andere hinzukommen, wie beispielsweise eine Schnittsstelle für UDF-Plug-Ins.

  • Zur Plug-In-API gehören auch Versionsinformationen.

    Durch die Versionsinformationen der Plug-In-API kann sich eine Plug-In-Bibliothek sowie jedes in ihr enthaltene Plug-In selbst identifizieren, und zwar mithilfe der API-Version, die zur Erstellung der Bibliothek benutzt wurde. Wenn sich die API mit der Zeit ändert, ändern sich auch die Versionsnummern, aber der Server kann immer anhand der Versionsinformationen einer konkreten Plug-In-Bibliothek herausfinden, ob er die Plug-Ins dieser Bibliothek unterstützt.

    Es gibt zwei Arten von Versionsnummern. Die erste ist die Version des allgemeinen Plug-In-Frameworks selbst. Jede Plug-In-Bibliothek enthält diese Art von Versionsnummer. Die zweite ist die Nummer des einzelnen Plug-Ins. Jeder spezifische Typ von Plug-In in einer Bibliothek hat für seine Schnittstelle eine Versionsnummer, sodass jedes Plug-In in einer Bibliothek eine typspezifische Versionsnummer besitzt. So hat beispielsweise eine Bibliothek, in der ein Volltext-Parser-Plug-In liegt, eine allgemeine Plug-In-API-Versionsnummer und das einzelne Plug-In hat seinerseits eine Versionsnummer, die für ebendiese Volltext-Plug-In-Schnittstelle spezifisch ist.

  • Die Sicherheit der Plug-Ins wurde gegenüber der alten UDF-Schnittstelle verbessert.

    Die ältere Schnittstelle zur Erstellung von UDFs ohne Plug-In ermöglichte es, Bibliotheken aus jedem Verzeichnis zu laden, das der dynamische Linker des Systems durchsuchte, und die Symbole zur Identifikation der UDF-Bibliothek waren relativ unspezifisch. Die neueren Regeln sind strenger. Eine Plug-In-Bibliothek muss in einem speziellen dedizierten Verzeichnis installiert sein, dessen Speicherort vom Server kontrolliert wird und zur Laufzeit nicht geändert werden kann. Außerdem muss die Bibliothek bestimmte Symbole enthalten, die sie als Plug-In-Bibliothek kennzeichnen. Der Server wird nichts als Plug-In laden, das nicht als Plug-In gebaut wurde.

    Die neuere Plug-In-Schnittstelle löst die Sicherheitsprobleme der älteren UDF-Schnittstelle. Wenn ein UDF-Plug-In-Typ implementiert wird, können Nicht-Plug-In-UDFs in das neue Framework überführt werden und die alte Schnittstelle kann auslaufen.

Die Plug-In-Implementierung besteht aus folgenden Komponenten:

Quelldateien (die angegebenen Speicherorte gelten für eine MySQL-Quelldistribution):

  • include/plugin.h stellt die öffentliche Plug-In-API zur Verfügung. Jeder, der eine Plug-In-Bibliothek schreiben möchte, sollte sich diese Datei anschauen.

  • sql/sql_plugin.h und sql/sql_plugin.cc enthalten die interne Plug-In-Implementierung. Diese Dateien müssen Verfasser von Plug-Ins sich nicht anschauen. Nur wenn Sie mehr darüber erfahren möchten, wie der Server mit Plug-Ins umgeht, sind diese Dateien für Sie interessant.

Systemtabelle:

  • Die plugin-Tabelle in der mysql-Datenbank listet alle installierten Plug-Ins auf und ist für die Nutzung von Plug-Ins erforderlich. Neuere MySQL-Versionen legen diese Tabelle bei der Installation an. Wenn Sie von einer älteren Version als MySQL 5.1 aufrüsten, sollten Sie mit mysql_fix_privilege_tables Ihre Systemtabellen aktualisieren und die plugin-Tabelle anlegen.

SQL-Anweisungen:

  • INSTALL PLUGIN registriert ein Plug-In in der plugin-Tabelle und lädt den Plug-In-Code.

  • UNINSTALL PLUGIN deregistriert ein Plug-In bei der plugin-Tabelle und und entlädt den Plug-In-Code.

  • Die WITH PARSER-Klausel für die Erstellung von Volltextindizes verbindet ein Volltext-Parser-Plug-In mit einem gegebenen FULLTEXT-Index.

  • SHOW PLUGIN zeigt Informationen über bekannte Plug-Ins an. Die PLUGINS-Tabelle in INFORMATION_SCHEMA liefert ebenfalls Informationen über Plug-Ins.

Systemvariable:

  • plugin_dir zeigt an, wo im Verzeichnis alle Plug-Ins installiert werden müssen. Den Wert dieser Variablen können Sie beim Serverstart mit der Option --plugin_dir=path angeben.

26.2.2. Volltext-Parser-Plug-Ins

MySQL verfügt über einen eingebauten Parser, der nach Voreinstellung für Volltextoperationen eingesetzt wird (Text parsen, der indiziert werden soll, oder einen Anfrage-String parsen, um die Suchbegriffe herauszufinden). In der Volltextverarbeitung bedeutet „Parsen“, dass Wörter aus einem Text oder Anfrage-String anhand von Regeln extrahiert werden, die definieren, aus welcher Zeichenfolge ein Wort besteht und wo die Wortgrenzen liegen.

Beim Parsen für Indizierungszwecke übergibt der Parser jedes Wort an den Server, und dieser fügt das Wort einem Volltextindex hinzu. Beim Parsen eines Anfrage-Strings übergibt der Parser ebenfalls jedes Wort an den Server, und dieser sammelt die Wörter, um sie für eine Suchoperation zusammenzustellen.

Die Parsing-Eigenschaften des eingebauten Volltext-Parsers werden in Abschnitt 12.7, „MySQL-Volltextsuche“, beschrieben. Hierzu gehören auch die Regeln, nach denen Wörter aus einem Text herausgezogen werden. Der Parser wird von bestimmten Systemvariablen wie ft_min_word_len und ft_max_word_len beeinflusst, die kürzere oder längere Wörter ausschließen können, und durch die Liste der Stoppwörter (diese sind häufig vorkommende Wörter, die übergangen werden).

Durch die Plug-In-API sind Sie in der Lage, einen eigenen Volltext-Parser zu verwenden und somit die Grundaufgaben eines Parsers unter Kontrolle zu haben. Ein Parser-Plug-In kann zwei Rollen spielen:

  • Es kann den eingebauten Parser ersetzen. In dieser Rolle liest das Plug-In die zu parsende Eingabe, zerlegt sie in Wörter und übergibt diese Wörter an den Server (entweder zum Indizieren oder zum Sammeln von Wörtern).

    Sie könnten einen Parser auf diese Weise einsetzen, wenn Sie die Eingabe nach anderen Regeln als der eingebaute Parser in Wörter zerlegen möchten. Für den eingebauten Parser besteht beispielsweise der Text „case-sensitive“ aus zwei Wörtern, nämlich „case“ und „sensitive“, während eine Anwendung diesen Text möglicherweise als ein einziges Wort ansehen sollte.

  • Das Plug-In kann auch mit dem eingebauten Parser zusammenarbeiten, indem es als Frontend für diesen dient. In dieser Rolle extrahiert das Plug-In Text aus der Eingabe und übergibt ihn an den Parser, der seinerseits den Text nach seinen normalen Parsing-Regeln in Wörter zerlegt. Diese Art von Parsing wird besonders von den Systemvariablen ft_xxx und der Stoppwörterliste beeinflusst.

    Auf diese Weise könnten Sie einen Parser einsetzen, wenn Sie beispielsweise PDF- oder XML-Dokumente oder .doc-Dateien indizieren müssen. Der eingebaute Parser ist nicht für diese Arten von Dokumenten gedacht, aber ein Plug-In-Parser kann Text aus diesen Quellen extrahieren und an den eingebauten Parser übergeben.

Ein Parser-Plug-In kann auch in beiden Rollen aktiv sein. Es kann Text aus einer Eingabe holen, die kein einfaches Textdokument ist (die Frontend-Rolle), und diesen Text auch in Wörter zerlegen (also den eingebauten Parser ersetzen).

Ein Volltext-Plug-In ist mit Volltextindizes indexweise verbunden: Wenn Sie ein Parser-Plug-In installieren, wird es deswegen noch nicht für Volltextoperationen benutzt, sondern steht zunächst einmal nur zur Verfügung. Ein Volltext-Parser kann dann beispielsweise in einer WITH PARSER-Klausel bei der Erstellung einzelner FULLTEXT-Indizes angegeben werden. Um einen solchen Index gleichzeitig mit der Tabelle zu erstellen, tun Sie Folgendes:

CREATE TABLE t
(
  doc CHAR(255),
  FULLTEXT INDEX (doc) WITH PARSER my_parser
);

Oder Sie fügen den Index nach der Erstellung der Tabelle hinzu:

ALTER TABLE t ADD FULLTEXT INDEX (doc) WITH PARSER my_parser;

Um den Parser mit dem Index zu verbinden, müssen Sie lediglich die WITH PARSER-Klausel in die SQL-Anfrage einfügen. Suchoperationen werden wie immer formuliert, ohne die Anfragen in irgendeiner Weise zu ändern.

Wenn Sie ein Parser-Plug-In mit einem FULLTEXT-Index verbinden, ist dieses Plug-In erforderlich, um den Index nutzen zu können. Wird es gelöscht, wird jeder mit ihm verbundene Index unbenutzbar. Jeder Versuch, ihn in einer Tabelle zu verwenden, für die kein Plug-In zur Verfügung steht, löst einen Fehler aus. Nur DROP TABLE ist nach wie vor möglich.

26.2.3. INSTALL PLUGIN

INSTALL PLUGIN plugin_name SONAME 'plugin_library'

Mit dieser Anweisung wird ein Plug-In installiert.

plugin_name ist der Name des Plug-Ins, wie er in der Plug-In-Deklarationsstruktur in der Bibliotheksdatei festgelegt ist. Ob in Plug-In-Namen die Groß- und Kleinschreibung beachtet wird, hängt von der Dateinamensemantik des Hostsystems ab.

plugin_library ist der Name der Shared Library, die den Plug-In-Code enthält. Dieser Name umfasst auch die Dateinamenserweiterung (beispielsweise libmyplugin.so oder libmyplugin.dylib).

Die Shared Library muss im Plug-In-Verzeichnis liegen (also in dem Verzeichnis, das die Systemvariable plugin_dir angibt). Die Bibliothek muss in dem Plug-In-Verzeichnis selbst und nicht in einem Unterverzeichnis liegen. Nach Voreinstellung ist plugin_dir das Verzeichnis, welches die Konfigurationsvariable pkglibdir vorgibt, aber es kann auch durch Einstellen des Werts von plugin_dir beim Serverstart geändert werden. Das folgende Beispiel zeigt, wie der Wert in einer my.cnf-Datei gesetzt wird:

[mysqld]
plugin_dir=/path/to/plugin/directory

Ist der Wert von plugin_dir ein relativer Pfadname, wird er mit Bezug auf das MySQL-Basisverzeichnis interpretiert (dieses ist in der Systemvariablen basedir festgelegt).

INSTALL PLUGIN fügt der mysql.plugin-Tabelle eine Zeile mit einer Beschreibung des plugins hinzu. Diese Tabelle enthält den Namen des Plug-Ins und der Bibliotheksdatei.

INSTALL PLUGIN lädt und initialisiert auch den Plug-In-Code, um das Plug-In nutzbar zu machen. Um ein Plug-In zu initialisieren, wird seine Initialisierungsfunktion ausgeführt, die alle Einstellungen vornimmt, welche zur Benutzung des Plug-Ins erforderlich sind.

Für INSTALL PLUGIN benötigen Sie das INSERT-Recht für die mysql.plugin-Tabelle.

Beim Serverstart lädt und initialisiert der Server alle in der mysql.plugin-Tabelle aufgelisteten Plug-Ins. Dies bedeutet, dass ein Plug-In mit INSTALL PLUGIN nur einmalig installiert wird und nicht bei jedem Serverstart. Das Laden von Plug-Ins beim Hochfahren des Servers funktioniert nicht, wenn der Server mit der Option --skip-grant-tables gestartet wird.

Wenn der Server herunterfährt, führt er die Deinitialisierungsfunktion für jedes geladene Plug-In aus, damit dieses Gelegenheit zu eventuellen Aufräumarbeiten bekommt.

Um ein Plug-In vollständig zu entfernen, führen Sie die UNINSTALL PLUGIN-Anweisung aus.

Die SHOW PLUGIN-Anweisung verrät Ihnen, welche Plug-Ins installiert sind.

Wenn Sie eine Plug-In-Bibliothek neu kompilieren und neu installieren müssen, können Sie aus folgenden Methoden wählen:

  • Sie deinstallieren alle Plug-Ins der Bibliothek mit UNINSTALL PLUGIN, installieren die neue Plug-In-Bibliotheksdatei in das Plug-In-Verzeichnis und installieren dann mit INSTALL PLUGIN alle Plug-Ins in der Bibliothek. Diese Vorgehensweise hat den Vorteil, dass man den Server nicht anhalten muss. Wenn jedoch die Plug-In-Bibliothek viele Plug-Ins enthält, müssen Sie viele INSTALL PLUGIN- und UNINSTALL PLUGIN-Anweisungen geben.

  • Alternativ können Sie den Server anhalten, die neue Plug-In-Bibliotheksdatei in das Plug-In-Verzeichnis installieren und dann den Server neu starten.

26.2.4. UNINSTALL PLUGIN

UNINSTALL PLUGIN plugin_name

Diese Anweisung entfernt ein installiertes Plug-In. Sie können ein Plug-In nicht entfernen, wenn es von einer Tabelle, die offen ist, noch gebraucht wird.

Der plugin_name muss der Name eines in der mysql.plugin-Tabelle aufgeführten Plug-Ins sein. Der Server führt die Deinitialisierungsfunktion des Plug-Ins aus und entfernt die Zeile für dieses Plug-In aus der mysql.plugin-Tabelle, damit es künftig beim Hochfahren des Servers nicht mehr geladen und initialisiert wird. UNINSTALL PLUGIN entfernt allerdings nicht die Dateien des Plug-Ins aus der Shared Library.

Um UNINSTALL PLUGIN benutzen zu können, benötigen Sie das DELETE-Recht für die mysql.plugin-Tabelle.

Die Entfernung von Plug-Ins hat Folgen für die Benutzung von Tabellen, die mit diesem Plug-In verbunden sind. Wenn beispielsweise ein Volltext-Parser-Plug-In mit einem FULLTEXT-Index auf der Tabelle verbunden ist, wird die Tabelle durch Deinstallation des Plug-Ins unbenutzbar. Jeder Versuch, auf sie zuzugreifen, löst einen Fehler aus. Sie kann noch nicht einmal mehr geöffnet werden, um den Index zu entfernen, der das Plug-In benutzt. Also sollten Sie bei der Deinstallation von Plug-Ins vorsichtig sein, wenn Ihnen Ihre Tabelleninhalte wichtig sind. Wenn Sie ein Plug-In deinstallieren, das Sie nicht wieder benutzen möchten, aber sich noch für den Inhalt der zugehörigen Tabelle interessieren, sollten Sie die Tabelle mit mysqldump kopieren und die WITH PARSER-Klausel aus der gespeicherten CREATE TABLE-Anweisung entfernen, damit Sie die Tabelle später erneut laden können. Wenn Ihnen die Tabelle egal ist, können Sie sie mit DROP TABLE auch dann noch löschen, wenn Ihre Plug-Ins nicht mehr vorhanden sind.

26.2.5. Schreiben von Plug-Ins

Dieser Abschnitt beschreibt die allgemeinen und typspezifischen Teile der Plug-In-API. Außerdem wird Schritt für Schritt erklärt, wie man eine Plug-In-Bibliothek erstellt. Ein Beispiel für Plug-In-Quellcode finden Sie im plugin/fulltext-Verzeichnis einer MySQL-Quelldistribution.

Sie können Plug-Ins in C oder C++ schreiben. Da die Plug-Ins dynamisch ge- und entladen werden, muss Ihr Betriebssystem dynamisches Laden unterstützen und auch mysqld dynamisch (nicht statisch) kompiliert worden sein.

Ein Plug-In enthält Code, der Teil des laufenden Servers wird. Daher gelten für das Schreiben von Plug-Ins dieselben Einschränkungen wie für Servercode. Sie bekommen beispielsweise Schwierigkeiten, wenn Sie versuchen, Funktionen aus der libstdc++-Bibliothek zu benutzen. Beachten Sie, dass sich diese Einschränkungen in zukünftigen Versionen des Servers noch ändern können, sodass bei einem Server-Upgrade unter Umständen auch Plug-Ins überarbeitet werden müssen, die ursprünglich für ältere Server erstellt wurden. Informationen über diese Einschränkungen finden Sie in Abschnitt 2.8.2, „Typische configure-Optionen“, und Abschnitt 2.8.4, „Probleme beim Kompilieren?“.

26.2.5.1. Allgemeine Plug-In-Strukturen und -Funktionen

Jedes Plug-In muss eine allgemeine Plug-In-Deklaration besitzen. Die Deklaration entspricht der st_mysql_plugin-Struktur in der plugin.h-Datei:

struct st_mysql_plugin
{
  int type;             /* Der Plug-In-Typ (ein MYSQL_XXX_PLUGIN-Wert)   */
  void *info;           /* Zeiger auf den typspezifischen Plug-In-Deskriptor   */
  const char *name;     /* Plug-In-Name                                  */
  const char *author;   /* Plug-In-Autor (für SHOW PLUGINS)             */
  const char *descr;    /* Allgemeine Beschreibung (für SHOW PLUGINS ) */
  int (*init)(void);    /* Die beim Laden des Plug-Ins aufgerufene Funktion */
  int (*deinit)(void);  /* Die beim Entladen des Plug-Ins aufgerufene Funktion */
};

Die st_mysql_plugin-Struktur ist allen Plug-In-Typen gemein. Ihre Bestandteile sollten folgendermaßen ausgefüllt werden:

  • type

    Der Plug-In-Typ. Dieser muss einer der Plug-In-Typwerte aus plugin.h sein. Für ein Volltext-Parser-Plug-In ist der type-Wert MYSQL_FTPARSER_PLUGIN.

  • info

    Ein Zeiger auf den Deskriptor für das Plug-In. Anders als die allgemeine Plug-In-Deklarationsstruktur hängt die Struktur dieses Deskriptors von dem konkreten Plug-In-Typ ab. Jeder Deskriptor hat eine Versionsnummer, die auf die API-Version für diesen Plug-In-Typ verweist, sowie andere erforderliche Bestandteile. Der Deskriptor für Volltext-Plug-Ins ist in Abschnitt 26.2.5.2, „Typspezifische Plug-In-Strukturen und -Funktionen“, beschrieben.

  • name

    Der Name des Plug-Ins. Dieser wird in der plugin-Tabelle aufgeführt und in SQL-Anweisungen wie INSTALL PLUGIN und UNINSTALL PLUGIN zur Benennung des Plug-Ins verwendet.

  • author

    Der Autor des Plug-Ins. Kann alles sein, was Sie wollen.

  • desc

    Eine allgemeine Beschreibung des Plug-Ins. Kann alles sein, was Sie wollen.

  • init

    Eine nur einmalig benutzte Initialisierungsfunktion. Diese wird ausgeführt, wenn das Plug-In geladen wird, was bei INSTALL PLUGIN oder für Plug-Ins aus der plugin-Tabelle beim Serverstart geschieht. Diese Funktion hat keine Argumente und gibt bei Erfolg null und bei Misserfolg einen von null verschiedenen Wert zurück.

  • deinit

    Eine nur einmalig benutzte Deinitialisierungsfunktion. Diese wird ausgeführt, wenn das Plug-In entladen wird, was bei UNINSTALL PLUGIN oder für Plug-Ins aus der plugin-Tabelle beim Server-Shutdown geschieht. Diese Funktion hat keine Argumente und gibt bei Erfolg null und bei Misserfolg einen von null verschiedenen Wert zurück

Die Funktionen init und deinit in der allgemeinen Plug-In-Deklaration werden nur beim Laden und Entladen des Plug-Ins aufgerufen. Sie haben nichts mit einer Benutzung des Plug-Ins zu tun, wie sie vorliegt, wenn eine SQL-Anweisung das Plug-In aufruft.

Wenn eine init- oder deinit-Funktion für ein Plug-In nicht notwendig ist, kann sie in der st_mysql_plugin-Struktur mit 0 angegeben werden.

26.2.5.2. Typspezifische Plug-In-Strukturen und -Funktionen

In der st_mysql_plugin-Struktur, die eine allgemeine Plug-In-Deklaration definiert, verweist der Bestandteil info auf einen typspezifischen Plug-In-Deskriptor. Bei einem Volltext-Parser-Plug-In entspricht dieser Deskriptor der st_mysql_ftparser-Struktur in der plugin.h-Datei:

struct st_mysql_ftparser
{
  int interface_version;
  int (*parse)(MYSQL_FTPARSER_PARAM *param);
  int (*init)(MYSQL_FTPARSER_PARAM *param);
  int (*deinit)(MYSQL_FTPARSER_PARAM *param);
};

Wie die Strukturdefinition zeigt, hat der Deskriptor eine Versionsnummer (MYSQL_FTPARSER_INTERFACE_VERSION für Volltext-Parser-Plug-Ins) und enthält Zeiger auf drei Funktionen. Die Bestandteile init und deinit sollten auf eine Funktion verweisen oder auf 0 gesetzt werden, wenn die Funktion nicht gebraucht wird. Der Bestandteil parse muss auf die Parse-Funktion verweisen.

Ein Volltext-Parser-Plug-In wird für zwei Dinge verwendet: Indizierung und Suchoperationen. In beiden Fällen ruft der Server die Initialisierungs- und Deinitialisierungsfunktion am Anfang und am Ende der Verarbeitung jeder SQL-Anweisung auf, in der das Plug-In benutzt wird. Während der Verarbeitung der Anweisung ruft der Server die Parsing-Hauptfunktion jedoch kontextabhängig auf:

  • Zum Indizieren ruft der Server den Parser für jeden zu indizierenden Spaltenwert auf.

  • In Suchoperationen ruft der Server den Parser auf, um den Such-String zu parsen. Ebenso kann der Parser für Zeilen aufgerufen werden, die von der Anweisung verarbeitet werden. Im Modus für natürliche Sprache braucht der Server den Parser nicht aufzurufen. Ini Phrasensuchen im booleschen Modus oder Suchen in natürlicher Sprache mit Abfrageerweiterung (Query Expansion) wird der Parser eingesetzt, um in den Spaltenwerten Informationen zu parsen, die nicht im Index vorliegen. Wenn eine Suche nach einer Spalte mit FULLTEXT-Index im booleschen Modus durchgeführt wird, wird ebenfalls der eingebaute Parser aufgerufen. (Plug-Ins sind mit konkreten Indizes verbunden. Ist kein Index vorhanden, wird auch kein Plug-In verwendet.)

Beachten Sie, dass die Plug-In-Deklaration im Plug-In-Bibliotheksdeskriptor Initialisierungs- und Deinitialisierungsfunktionen hat, ebenso wie der Plug-In-Deskriptor, auf den sie verweist. Diese Funktionspaare dienen unterschiedlichen Zwecken und werden aus unterschiedlichen Gründen aufgerufen:

  • Für die Plug-In-Deklaration im Plug-In-Bibliotheksdeskriptor werden die Initialisierungs- und Deinitialisierungsfunktionen beim Laden und Entladen des Plug-Ins aufgerufen.

  • Für den Plug-In-Deskriptor werden die Initialisierungs- und Deinitialisierungsfunktionen für jede SQL-Anweisung aufgerufen, in der das Plug-In benutzt wird.

Jede API-Funktion, die im Plug-In-Deskriptor genannt ist, sollte null bei einem Erfolg und einen von null verschiedenen Wert bei einem Misserfolg zurückgeben, und jede sollte ein Argument entgegennehmen, das auf eine MYSQL_FTPARSER_PARAM-Struktur verweist, die den Parsing-Kontext enthält. Die Struktur ist wie folgt definiert:

typedef struct st_mysql_ftparser_param
{
  int (*mysql_parse)(void *param, byte *doc, uint doc_len);
  int (*mysql_add_word)(void *param, byte *word, uint word_len,
                        MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
  void *ftparser_state;
  void *mysql_ftparam;
  CHARSET_INFO *cs;
  byte *doc;
  uint length;
  int mode;
} MYSQL_FTPARSER_PARAM;

Die Bestandteile der Struktur werden folgendermaßen benutzt:

  • mysql_parse

    Ein Zeiger auf eine Callback-Funktion, die den eingebauten Parser des Servers aufruft. Diesen Callback verwenden Sie, wenn das Plug-In als Frontend des eingebauten Parsers fungiert. Wenn also die Plug-In-Parsing-Funktion aufgerufen wird, soll sie die Eingabe verarbeiten, um den Inhalt zu extrahieren, und diesen dann an den mysql_parse-Callback übergeben.

    Der erste Parameter dieser Callback-Funktion sollte der mysql_ftparam-Teil der Struktur des Parsing-Kontextes sein. Das heißt: Wenn param auf die Struktur verweist, wird der Callback folgendermaßen aufgerufen:

    param->mysql_parse(param->mysql_ftparam, ...);
    

    Ein Frontend-Plug-In kann Text extrahieren und komplett oder häppchenweise an den eingebauten Parser übergeben. Im zweiten Fall behandelt der eingebaute Parser die Textstücke, als befänden sich implizite Wortgrenzen zwischen ihnen.

  • mysql_add_word

    Ein Zeiger auf eine Callback-Funktion, die einem Volltextindex oder der Liste der Suchbegriffe ein Wort hinzufügt. Diesen Callback verwenden Sie, wenn das Parser-Plug-In den eingebauten Parser ersetzen soll. Das bedeutet: Wenn die Parsing-Funktion des Plug-Ins aufgerufen wird, soll sie die Eingabe in Wörter parsen und für jedes Wort den mysql_add_word-Callback aufrufen.

    Der erste Parameter dieser Callback-Funktion soll der mysql_ftparam-Teil der Struktur des Parsing-Kontexts sein. Das heißt: Wenn param auf die Struktur verweist, wird der Callback wie folgt aufgerufen:

    param->mysql_add_word(param->mysql_ftparam, ...);
    
  • ftparser_state

    Dies ist ein generischer Zeiger. Das Plug-In kann ihn auf die Informationen verweisen lassen, die es intern für seine eigenen Zwecke benutzt.

  • mysql_ftparam

    Wird durch den Server eingestellt und als erstes Argument an den mysql_parse- oder mysql_add_word-Callback übergeben.

  • cs

    Verweist auf den Zeichensatz für den Text, oder auf 0, wenn diese Information nicht zur Verfügung steht.

  • doc

    Ein Zeiger auf den zu parsenden Text.

  • length

    Die Länge des zu parsenden Texts in Bytes.

  • mode

    Der Parsing-Modus. Dieser Wert ist eine der folgenden Konstanten:

    • MYSQL_FTPARSER_SIMPLE_MODE

      Parsen im schnellen, einfachen Modus. Dies wird für Indizes und für Anfragen mit natürlichen Sprachen verwendet. Der Parser sollte an den Server nur die zu indizierenden Wörter übergeben. Wenn er Längenbeschränkungen oder eine Liste mit zu ignorierenden Stoppwörtern verwendet, soll er die hierdurch ausgeschlossenen Wörter nicht an den Server übergeben.

    • MYSQL_FTPARSER_WITH_STOPWORDS

      Parsen im Stoppwortmodus. Dies wird bei booleschen Suchoperationen für den Abgleich von Begriffen verwendet. Der Parser sollte alle Wörter an den Server übergeben, auch Stoppwörter oder Wörter, die die normalen Längenbeschränkungen übersteigen.

    • MYSQL_FTPARSER_FULL_BOOLEAN_INFO

      Parsen im booleschen Modus. Wird zum Parsen von booleschen Anfrage-Strings genutzt. Der Parser soll nicht nur Wörter, sondern auch Operatoren für den booleschen Modus erkennen, und diese als Token mit dem mysql_add_word-Callback an den Server übergeben. Um dem Server zu sagen, welche Art von Token übergeben wird, muss das Plug-In eine MYSQL_FTPARSER_BOOLEAN_INFO-Struktur ausfüllen und einen Zeiger auf diese Struktur mit übergeben.

Wenn der Parser im booleschen Modus aufgerufen wird, hat param->mode den Wert MYSQL_FTPARSER_FULL_BOOLEAN_INFO. Die MYSQL_FTPARSER_BOOLEAN_INFO-Struktur, die der Parser zur Übergabe von Token-Informationen an den Server benutzt, sieht folgendermaßen aus:

typedef struct st_mysql_ftparser_boolean_info
{
  enum enum_ft_token_type type;
  int yesno;
  int weight_adjust;
  bool wasign;
  bool trunc;
  /* Diese sind im Parser-Zustand und müssen entfernt werden. */
  byte prev;
  byte *quot;
} MYSQL_FTPARSER_BOOLEAN_INFO;

Der Parser sollte die Bestandteile der Struktur folgendermaßen ausfüllen:

  • type

    Der Token-Typ. Dies sollte einer der Werte der folgenden Tabelle sein:

    TypBedeutung
    FT_TOKEN_EOFEnde der Daten
    FT_TOKEN_WORDEin normales Wort
    FT_TOKEN_LEFT_PARENBeginn einer Gruppe oder eines Teilausdrucks
    FT_TOKEN_RIGHT_PARENEnde einer Gruppe oder eines Teilausdrucks
    FT_TOKEN_STOPWORDEin Stoppwort
  • yesno

    Gibt an, ob das Wort vorhanden sein muss, damit eine Übereinstimmung festgestellt wird. 0 bedeutet, dass das Wort optional ist, sein Vorhandensein jedoch die Relevanz der Übereinstimmung erhöht. Werte größer 0 bedeuten, dass das Wort obligatorisch ist, und Werte kleiner 0, dass es nicht vorhanden sein darf.

  • weight_adjust

    Ein Gewichtsfaktor, der festlegt, wie viel eine Übereinstimmung für das Wort zählt. Indem man diesen Faktor herauf- oder heruntersetzt, beeinflusst man die Bedeutung, die dieses Wort in Relevanzberechnungen hat. Ist der Wert null, so erfolgt keine Anpassung der Gewichtung. Werte größer oder kleiner null bedeuten ein höheres oder geringeres Gewicht. Die Beispiele unter Abschnitt 12.7.1, „Boolesche Volltextsuche“, die <- und >-Operatoren verwenden, zeigen, wie Gewichtung funktioniert.

  • wasign

    Das Vorzeichen des Gewichtungsfaktors. Ein negativer Wert verhält sich wie der boolesche Suchoperator ~, der dafür sorgt, dass das Wort in negativer Weise zur Relevanz beiträgt.

  • trunc

    Zeigt an, ob der Abgleich in derselben Weise durchgeführt wird, als ob der Kappungsoperator * im booleschen Modus angegeben worden wäre.

Plug-Ins sollten nicht die Bestandteile prev und quot der MYSQL_FTPARSER_BOOLEAN_INFO-Struktur benutzen.

26.2.5.3. Erzeugen einer Plug-In-Bibliothek

Dieser Abschnitt erklärt die Erstellung einer Plug-In-Bibliothek Schritt für Schritt. Er zeigt, wie man eine Bibliothek entwickelt, die ein Volltext-Parsing-Plug-In namens simple_parser enthält. Dieses Plug-In wendet einfachere Regeln als der eingebaute Volltext-Parser von MySQL an: Wörter sind nichtleere Folgen von Whitespace-Zeichen.

Jede Plug-In-Bibliothek enthält Folgendes:

  • Ein Plug-In-Bibliotheksdeskriptor mit der Versionsnummer der allgemeinen Plug-In-API der Bibliothek und einer allgemeinen Deklaration für jedes Plug-In in der Bibliothek.

  • Jede allgemeine Plug-In-Deklaration enthält Informationen, die allen Arten von Plug-Ins gemeinsam sind: einen Wert, der den Plug-In-Typ anzeigt, den Namen, den Autor und die Beschreibung des Plug-Ins sowie Zeiger auf die Initialisierungs- und die Deinitialisierungfunktionen, die der Server beim Laden und Entladen des Plug-Ins aufrufen muss.

  • Außerdem enthält die allgemeine Plug-In-Deklaration einen Zeiger auf einen typspezifischen Plug-In-Deskriptor. Die Struktur dieser Deskriptoren kann je nach Plug-In-Typ unterschiedlich sein, da jede Art von Plug-In ihre eigene API haben kann. Ein Plug-In-Deskriptor enthält eine typspezifische API-Versionsnummer und Zeiger auf die Funktionen, die zur Implementierung dieses Plug-In-Typs erforderlich sind. So hat beispielsweise ein Volltext-Parser-Plug-In Initialisierungs- und Deinitialisierungsfunktionen und eine Parsing-Hauptfunktion. Der Server ruft diese Funktionen auf, wenn er das Plug-In zum Parsen von Text einsetzt.

  • Die Plug-In-Bibliothek enthält die Schnittstellenfunktionen, auf die der Bibliotheksdeskriptor und die Plug-In-Deskriptoren verweisen.

Eine Plug-In-Bibliothek wird folgendermaßen angelegt:

  1. Zuerst binden Sie die von der Plug-In-Bibliothek benötigten Header-Dateien ein. Die Datei plugin.h ist auf jeden Fall notwendig, allerdings kann die Bibliothek auch noch andere Dateien erfordern. Zum Beispiel:

    #include <my_global.h>
    #include <m_string.h>
    #include <m_ctype.h>
    #include <plugin.h>
    
  2. Dann richten Sie den Deskriptor für die Plug-In-Bibliotheksdatei ein.

    Jede Plug-In-Bibliothek muss einen Bibliotheksdeskriptor besitzen, der zwei Symbole definiert:

    • _mysql_plugin_interface_version_ ist die Versionsnummer des allgemeinen Plug-In-Frameworks. Sie wird durch das Symbol MYSQL_PLUGIN_INTERFACE_VERSION angegeben, das in der Datei plugin.h definiert ist.

    • _mysql_plugin_declarations_ definiert ein Array von Plug-In-Deklarationen, wobei am Ende eine Deklaration steht, in der alle Bestandteile auf 0 gesetzt sind. Jede Deklaration ist eine Instanz der Struktur st_mysql_plugin (ebenfalls in plugin.h definiert). Für jedes Plug-In in der Bibliothek muss eine solche Deklaration vorhanden sein.

    Wenn der Server diese beiden Symbole nicht in einer Bibliothek vorfindet, akzeptiert er sie nicht als gültige Plug-In-Bibliothek und weist sie mit einer Fehlermeldung zurück. So wird verhindert, dass eine Bibliothek für Plug-In-Zwecke benutzt wird, die nicht speziell als Plug-In-Bibliothek ausgelegt wurde.

    Die üblichste (und bequemste) Art, die beiden notwendigen Symbole zu definieren, bieten die beiden Makros mysql_declare_plugin und mysql_declare_plugin_end aus der Datei plugin.h:

    mysql_declare_plugin
     ... eine oder mehr Plug-In-Deklarationen ...
    mysql_declare_plugin_end;
    

    Der Bibliotheksdeskriptor für eine Bibliothek mit einem einzigen Plug-In namens simple_parser sähe beispielsweise folgendermaßen aus:

    mysql_declare_plugin
    {
      MYSQL_FTPARSER_PLUGIN,      /* Typ                      */
      &simple_parser_descriptor,  /* Deskriptor                */
      "simple_parser",            /* Name                      */
      "MySQL AB",                 /* Autor                    */
      "Simple Full-Text Parser",  /* Beschreibung               */
      simple_parser_plugin_init,  /* Initialisierungsfunktion   */
      simple_parser_plugin_deinit /* Deinitialisierungsfunktion */
    }
    mysql_declare_plugin_end;
    

    Der Typ eines Volltext-Parser-Plug-Ins müsste MYSQL_FTPARSER_PLUGIN sein. Dieser Wert kennzeichnet das Plug-In als zulässig zur Benutzung in einer WITH PARSER-Klausel, wenn ein FULLTEXT-Index angelegt werden soll. (Kein anderer Plug-In-Typ ist für diese Klausel erlaubt.)

    Die Makros mysql_declare_plugin und mysql_declare_plugin_end sind in plugin.h folgendermaßen definiert:

    #define mysql_declare_plugin                                          \
    int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \
    struct st_mysql_plugin _mysql_plugin_declarations_[]= {
    #define mysql_declare_plugin_end ,{0,0,0,0,0,0,0}}
    

    In der oben gezeigten Verwendung werden die Makros zu folgendem Code expandiert, der beide erforderlichen Symbole definiert (_mysql_plugin_interface_version_ und _mysql_plugin_declarations_):

    int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION;
    struct st_mysql_plugin _mysql_plugin_declarations_[]= {
    {
      MYSQL_FTPARSER_PLUGIN,      /* Typ                      */
      &simple_parser_descriptor,  /* Deskriptor                */
      "simple_parser",            /* Name                      */
      "MySQL AB",                 /* Autor                    */
      "Simple Full-Text Parser",  /* Beschreibung               */
      simple_parser_plugin_init,  /* Initialisierungsfunktion   */
      simple_parser_plugin_deinit /* Deinitialisierungsfunktion */
    }
      ,{0,0,0,0,0,0,0}
    };
    

    Im obigen Beispiel wird nur ein einzelnes Plug-In im Bibliotheksdeskriptor deklariert, aber es ist ebenso gut möglich, mehrere Plug-Ins zu deklarieren. Hierzu führen Sie die Deklarationen – durch Kommata getrennt – in mysql_declare_plugin und mysql_declare_plugin_end auf.

  3. Nun richten Sie den Plug-In-Deskriptor ein.

    Jede Plug-In-Deklaration im Bibliotheksdeskriptor verweist auf einen typspezifischen Deskriptor für das zugehörige Plug-In. In der Deklaration von simple_parser wird dieser Deskriptor von &simple_parser_descriptor angezeigt. Der Deskriptor gibt die Versionsnummer für die Volltext-Plug-In-Schnittstelle (wie sie in MYSQL_FTPARSER_INTERFACE_VERSION steht) sowie die Parsing-, Initialisierungs- und Deinitialisierungsfunktionen des Plug-Ins an:

    static struct st_mysql_ftparser simple_parser_descriptor=
    {
      MYSQL_FTPARSER_INTERFACE_VERSION, /* Schnittstellenversion      */
      simple_parser_parse,              /* Parsing-Funktion       */
      simple_parser_init,               /* Parser-Initialisierungsfunktion   */
      simple_parser_deinit              /* Parser-Deinitialisierungsfunktion */
    };
    
  4. Jetzt richten Sie die Plug-In-Schnittstellenfunktionen ein.

    In der allgemeinen Plug-In-Deklaration des Bibliotheksdeskriptors werden die Initialisierungs- und Deinitialisierungsfunktionen angegeben, die der Server zum Laden und Entladen des Plug-Ins aufrufen muss. Für den simple_parser geben diese Funktionen lediglich null zurück, um anzuzeigen, dass sie Erfolg hatten:

    static int simple_parser_plugin_init(void)
    {
      return(0);
    }
    
    static int simple_parser_plugin_deinit(void)
    {
      return(0);
    }
    

    Da diese Funktionen eigentlich nichts tun, könnten Sie sie ebenso gut weglassen und in der Plug-In-Deklaration jeweils durch 0 ersetzen.

    Der typspezifische Plug-In-Deskriptor für den simple_parser gibt die Initialisierungs-, Deinitialisierungs- und Parsing-Funktionen an, die der Server bei Benutzung dieses Plug-Ins aufrufen muss. Beim simple_parser tun die Initialisierungs- und Deinitialisierungsfunktionen gar nichts:

    static int simple_parser_init(MYSQL_FTPARSER_PARAM *param)
    {
      return(0);
    }
    
    static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param)
    {
      return(0);
    }
    

    Da diese Funktionen nichts tun, könnte man sie hier ebenfalls weglassen und im Plug-In-Deskriptor 0 für sie angeben.

    Da die Parsing-Hauptfunktion simple_parser_parse() den eingebauten Volltext-Parser ersetzen soll, muss sie Text in Wörter zerlegen und diese Wörter an den Server übergeben. Das erste Argument der Parsing-Funktion ist ein Zeiger auf eine Struktur, die den Parsing-Kontext enthält. Diese Struktur besitzt einen doc-Bestandteil, der auf den zu parsenden Text verweist, und einen length-Bestandteil, der die Länge dieses Texts anzeigt. Da das Plug-In ganz einfache Parsing-Regeln verwendet, wonach nichtleere Folgen von Whitespace-Zeichen als Wörter betrachtet werden, erkennt es Wörter folgendermaßen:

    static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param)
    {
      char *end, *start, *docend= param->doc + param->length;
    
      for (end= start= param->doc;; end++)
      {
        if (end == docend)
        {
          if (end > start)
            add_word(param, start, end - start);
          break;
        }
        else if (isspace(*end))
        {
          if (end > start)
            add_word(param, start, end - start);
          start= end + 1;
        }
      }
      return(0);
    }
    

    Während der Parser ein Wort nach dem anderen erkennt, ruft er die Funktion add_word() auf, um es an den Server zu übergeben. add_word() ist nur eine Hilfsfunktion, die nicht zur Plug-In-Schnittstelle gehört. Der Parser übergibt den Zeiger auf den Parsing-Kontext, den Zeiger auf das Wort und einen Längenwert an add_word().

    static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len)
    {
      MYSQL_FTPARSER_BOOLEAN_INFO bool_info=
        { FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 };
    
      if (param->mode == MYSQL_FTPARSER_FULL_BOOLEAN_INFO)
        param->mysql_add_word(param->mysql_ftparam, word, len, &bool_info);
      else
        param->mysql_add_word(param->mysql_ftparam, word, len, 0);
    }
    

    Beim Parsen im booleschen Modus füllt add_word() die Bestandteile der bool_info-Struktur aus, wie in Abschnitt 26.2.5.2, „Typspezifische Plug-In-Strukturen und -Funktionen“ beschrieben.

  5. Kompilieren Sie die Plug-In-Bibliothek als Shared Library und installieren Sie sie in das Plug-In-Verzeichnis.

    Die Prozedur zum Kompilieren von Shared-Objekten ist von System zu System unterschiedlich. Wenn Sie Ihre Bibliothek mithilfe der GNU-Autotools bauen, müsste libtool in der Lage sein, die richtigen Kompilierbefehle für Ihr System zu generieren. Wenn die Bibliothek mypluglib heißt, müssten Sie zum Schluss mit einer Shared Object-Datei dastehen, die so ähnlich wie libmypluglib.so heißt. (Der Dateiname kann auf Ihrem System eine andere Erweiterung haben.)

    Die Stelle, an der Sie die Bibliothek in Ihrem Plug-In-Verzeichnis installieren müssen, verrät Ihnen die Systemvariable plugin_dir. Zum Beispiel:

    mysql> SHOW VARIABLES LIKE 'plugin_dir';
    +---------------+----------------------------+
    | Variable_name | Value                      |
    +---------------+----------------------------+
    | plugin_dir    | /usr/local/mysql/lib/mysql |
    +---------------+----------------------------+
    

    Wenn Sie die Plug-In-Bibliothek installieren, achten Sie bitte darauf, dass Ihre Berechtigungen eine Ausführung durch den Server erlauben.

  6. Registrieren Sie das Plug-In beim Server.

    Die INSTALL PLUGIN-Anweisung lässt den Server das Plug-In in die plugin-Tabelle übernehmen und seinen Code aus der Bibliotheksdatei laden. Registrieren Sie mit dieser Anweisung den simple_parser beim Server und vergewissern Sie sich dann, dass er in die plugin-Tabelle aufgenommen wurde:

    mysql> INSTALL PLUGIN simple_parser SONAME 'libmypluglib.so';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM mysql.plugin;
    +---------------+-----------------+
    | name          | dl              |
    +---------------+-----------------+
    | simple_parser | libmypluglib.so |
    +---------------+-----------------+
    1 row in set (0.00 sec)
    
  7. Nun probieren Sie das Plug-In aus.

    Legen Sie eine Tabelle mit einer String-Spalte an und verbinden Sie das Parser-Plug-In mit einem FULLTEXT-Index auf der Spalte:

    mysql> CREATE TABLE t (c VARCHAR(255),
        ->   FULLTEXT (c) WITH PARSER simple_parser);
    Query OK, 0 rows affected (0.01 sec)
    

    Fügen Sie Text in die Tabelle ein und versuchen Sie einige Suchoperationen. Dabei sollte ausprobiert werden, ob das Parser-Plug-In wirklich alle Nicht-Whitespace-Zeichen als Wortzeichen betrachtet:

    mysql> INSERT INTO t VALUES
        ->   ('latin1_general_cs is a case-sensitive collation'),
        ->   ('I\'d like a case of oranges'),
        ->   ('this is sensitive information'),
        ->   ('another row'),
        ->   ('yet another row');
    Query OK, 5 rows affected (0.02 sec)
    Records: 5  Duplicates: 0  Warnings: 0
    
    mysql> SELECT c FROM t;
    +-------------------------------------------------+
    | c                                               |
    +-------------------------------------------------+
    | latin1_general_cs is a case-sensitive collation |
    | I'd like a case of oranges                      |
    | this is sensitive information                   |
    | another row                                     |
    | yet another row                                 |
    +-------------------------------------------------+
    5 rows in set (0.00 sec)
    
    mysql> SELECT MATCH(c) AGAINST('case') FROM t;
    +--------------------------+
    | MATCH(c) AGAINST('case') |
    +--------------------------+
    |                        0 |
    |          1.2968142032623 |
    |                        0 |
    |                        0 |
    |                        0 |
    +--------------------------+
    5 rows in set (0.00 sec)
    
    mysql> SELECT MATCH(c) AGAINST('sensitive') FROM t;
    +-------------------------------+
    | MATCH(c) AGAINST('sensitive') |
    +-------------------------------+
    |                             0 |
    |                             0 |
    |               1.3253291845322 |
    |                             0 |
    |                             0 |
    +-------------------------------+
    5 rows in set (0.01 sec)
    
    mysql> SELECT MATCH(c) AGAINST('case-sensitive') FROM t;
    +------------------------------------+
    | MATCH(c) AGAINST('case-sensitive') |
    +------------------------------------+
    |                    1.3109166622162 |
    |                                  0 |
    |                                  0 |
    |                                  0 |
    |                                  0 |
    +------------------------------------+
    5 rows in set (0.01 sec)
    
    mysql> SELECT MATCH(c) AGAINST('I\'d') FROM t;
    +--------------------------+
    | MATCH(c) AGAINST('I\'d') |
    +--------------------------+
    |                        0 |
    |          1.2968142032623 |
    |                        0 |
    |                        0 |
    |                        0 |
    +--------------------------+
    5 rows in set (0.01 sec)
    

Beachten Sie, dass weder „case“ noch „insensitive“ auf „case-insensitive“ passen, wie es bei dem eingebauten Parser der Fall wäre.

26.3. Hinzufügen neuer Funktionen zu MySQL

Es gibt zwei Möglichkeiten, neue Funktionen zu MySQL hinzuzufügen:

  • Die erste Möglichkeit ist die Schnittstelle für benutzerdefinierte Funktionen (User-Defined Functions, UDFs). Benutzerdefinierte Funktionen werden als Objektdateien kompiliert und dann dynamisch mit den Anweisungen CREATE FUNCTION und DROP FUNCTION auf den Server geladen oder von ihm entfernt. Siehe auch Abschnitt 26.3.2, „CREATE FUNCTION/DROP FUNCTION.

  • Die zweite Möglichkeit: Sie fügen die Funktionen als native (eingebaute) MySQL-Funktionen hinzu. Native Funktionen werden in den mysqld-Server kompiliert und stehen dann dauerhaft zur Verfügung.

Beide Methoden haben ihre Vor- und Nachteile:

  • Wenn Sie benutzerdefinierte Funktionen schreiben, müssen Sie zusätzlich zum Server auch noch Objektdateien installieren. Wenn Sie Ihre Funktion in den Server kompilieren, entfällt das.

  • Um native Funktionen zu erstellen, müssen Sie eine Quelldistribution ändern; für UDFs müssen Sie das nicht. UDFs können Sie auch einer Binärdistribution von MySQL hinzufügen, ohne in den Quellcode von MySQL eingreifen zu müssen.

  • Wenn Sie Ihre MySQL-Distribution aufrüsten, können Sie die zuvor installierten UDFs auch weiterhin nutzen, es sei denn, die neue Version ist eine, bei der sich die UDF-Schnittstelle geändert hat. Für native Funktionen müssen Sie Ihre Modifikationen bei jedem Upgrade wiederholen.

Ganz gleich, welchen Weg Sie einschlagen, um neue Funktionen hinzuzufügen: Aufgerufen werden sie in SQL-Anweisungen nicht anders als native Funktionen, wie zum Beispiel ABS() oder SOUNDEX().

Auch gespeicherte Funktionen bieten die Möglichkeit, Funktionen hinzuzufügen. Gespeicherte Funktionen schreiben Sie in SQL-Anweisungen, anstatt sie in den Objektcode zu kompilieren. Die Syntax für gespeicherte Funktionen wird in Kapitel 19, Gespeicherte Prozeduren und Funktionen, beschrieben.

Die folgenden Abschnitte beschreiben Features der UDF-Schnittstelle, geben Anleitungen zum Schreiben von UDFs, erläutern Sicherheitsmaßnahmen, mit denen MySQL den Missbrauch von UDFs verhindert, und erklären, wie native MySQL-Funktionen hinzugefügt werden.

Quellcode, der zeigt, wie man UDFs schreibt, finden Sie in der Datei sql/udf_example.cc, die in den MySQL-Quelldistributionen enthalten ist.

26.3.1. Features der Schnittstelle für benutzerdefinierte Funktionen (UDF)

Die MySQL-Schnittstelle für benutzerdefinierte Funktionen stellt folgende Features und Fähigkeiten zur Verfügung:

  • Funktionen können String-, Integer- oder Real-Werte zurückgeben.

  • Einfache Funktionen, die immer nur auf einer einzigen Zeile operieren, können ebenso definiert werden wie Aggregatfunktionen, die auf Zeilengruppen arbeiten.

  • Die Funktionen erhalten Informationen, die sie in die Lage versetzen, die Anzahl und den Typ der an sie übergebenen Argumente zu überprüfen.

  • Sie können MySQL anweisen, Argumenten einen bestimmten Typ aufzuzwingen, bevor sie an eine Funktion übergeben werden.

  • Sie können verlangen, dass eine Funktion NULL zurückgibt oder dass ein Fehler ausgelöst wird.

26.3.2. CREATE FUNCTION/DROP FUNCTION

CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|INTEGER|REAL|DECIMAL}
    SONAME shared_library_name

Mit benutzerdefinierten Funktionen (UDFs) können Sie MySQL um neue Funktionen erweitern, die wie native (eingebaute) MySQL-Funktionen wie etwa ABS() oder CONCAT() funktionieren.

function_name ist der Name, mit dem die Funktion in SQL-Anweisungen aufgerufen wird. Die RETURNS-Klausel zeigt den Rückgabetyp der Funktion an. DECIMAL ist zwar hinter RETURNS zulässig, aber gegenwärtig geben DECIMAL-Funktionen String-Werte zurück und sollten daher wie STRING-Funktionen geschrieben werden.

shared_library_name ist der Basisname der Shared Object-Datei, die den Code zur Implementierung der Funktion enthält. Diese Datei muss im Plug-In-Verzeichnis liegen, welches durch den Wert der Systemvariablen plugin_dir vorgegeben ist. (Hinweis: Dies ist eine Änderung in MySQL 5.1. In früheren Versionen von MySQL konnte die Shared Object-Datei in jedem beliebigen Verzeichnis liegen, das der dynamische Linker des Systems untersuchte.)

Zur Erstellung einer Funktion benötigen Sie das INSERT-Recht für die mysql-Datenbank, da CREATE FUNCTION in die Systemtabelle mysql.func eine Zeile mit dem Namen, Typ und Shared Library-Namen der Funktion einfügt. Wenn diese Tabelle bei Ihnen fehlt, müssen Sie sie mit dem Skript mysql_fix_privilege_tables anlegen. Siehe Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Eine aktive Funktion ist eine Funktion, die mit CREATE FUNCTION geladen, aber nicht mit DROP FUNCTION wieder gelöscht wurde. Alle aktiven Funktionen werden bei jedem Serverstart neu geladen, es sei denn, Sie starten mysqld mit der Option --skip-grant-tables. In diesem Fall wird die UDF-Initialisierung übersprungen und die UDFs stehen nicht zur Verfügung.

Anleitungen zum Schreiben benutzerdefinierter Funktionen finden Sie unter Abschnitt 26.3.4, „Hinzufügen einer neuen benutzerdefinierten Funktion“. Damit der UDF-Mechanismus funktioniert, müssen die Funktionen in C oder C++ geschrieben sein, Ihr Betriebssystem muss dynamisches Laden unterstützen, und Sie müssen mysqld dynamisch (nicht statisch) kompiliert haben.

Eine AGGREGATE-Funktion funktioniert genau wie eine native MySQL-Aggregatfunktion (Summenfunktion), wie beispielsweise SUM oder COUNT(). Damit AGGREGATE funktioniert, muss Ihre mysql.func-Tabelle eine type-Spalte enthalten. Wenn Ihre mysql.func-Tabelle diese Spalte nicht hat, müssen Sie sie mit dem Skript mysql_fix_privilege_tables erzeugen.

26.3.3. DROP FUNCTION

DROP FUNCTION function_name

Diese Anweisung löscht eine benutzerdefinierte Funktion (UDF) namens function_name.

Um eine Funktion löschen zu dürfen, benötigen Sie das DELETE-Recht für die mysql-Datenbank, denn DROP FUNCTION löscht aus der Systemtabelle mysql.func die Zeile, die den Namen, Typ und Shared Library-Namen der Funktion enthält.

26.3.4. Hinzufügen einer neuen benutzerdefinierten Funktion

Damit der UDF-Mechanismus funktioniert, müssen die Funktionen in C oder C++ geschrieben sein, und Ihr Betriebssystem muss dynamisches Laden unterstützen. Die MySQL-Quelldistribution enthält eine Datei namens sql/udf_example.cc, die fünf neue Funktionen definiert. In dieser Datei können Sie sehen, wie die Aufrufkonventionen für UDFs funktionieren.

Da eine UDF Code enthält, der zum Teil des laufenden Servers gehört, müssen Sie beim Schreiben von UDFs alle Einschränkungen beachten, die auch sonst für das Schreiben von Servercode gelten. Sie können beispielsweise Probleme bekommen, wenn Sie versuchen, Funktionen aus der libstdc++-Bibliothek zu benutzen. Beachten Sie, dass sich diese Einschränkungen in zukünftigen Versionen des Servers noch ändern können. Daher kann es sein, dass Sie bei einem Server-Upgrade auch Ihre für ältere Serverversionen geschriebenen UDFs überarbeiten müssen. Informationen über diese Einschränkungen erhalten Sie unter Abschnitt 2.8.2, „Typische configure-Optionen“, und Abschnitt 2.8.4, „Probleme beim Kompilieren?“.

Um UDFs nutzen zu können, müssen Sie mysqld dynamisch verlinken. Bitte konfigurieren Sie MySQL nicht mit der Option --with-mysqld-ldflags=-all-static. Wenn Sie eine UDF benutzen möchten, die auf Symbole aus mysqld zugreifen muss (beispielsweise die metaphone-Funktion in sql/udf_example.cc, die default_charset_info braucht), müssen Sie das Programm mit der Option -rdynamic verlinken (siehe man dlopen). Wenn Sie den Einsatz von UDFs planen, sollten Sie MySQL grundsätzlich mit --with-mysqld-ldflags=-rdynamic konfigurieren, wenn nichts Wichtiges dagegen spricht.

Wenn Sie eine vorkompilierte Distribution von MySQL einsetzen müssen, so verwenden Sie MySQL-Max: Diese Version enthält einen dynamisch verlinkten Server, der dynamisches Laden unterstützt.

Für jede Funktion, die Sie in SQL-Anweisungen nutzen möchten, sollten Sie zugehörige C- oder C++-Funktionen definieren. In den folgenden Ausführungen steht der Name „xxx“ für den Namen einer Beispielfunktion. Um zwischen dem Einsatz in SQL und C/C++ zu unterscheiden, wird ein Funktionsaufruf in SQL mit XXX() (Großbuchstaben) und ein Funktionsaufruf in C/C++ mit xxx() (Kleinbuchstaben) angegeben.

Sie schreiben folgende C-/C++-Funktionen, um die Schnittstelle für XXX() zu implementieren:

  • xxx() (obligatorisch)

    Die Hauptfunktion. Hier wird das Ergebnis der Funktion berechnet. Die Entsprechung zwischen dem Datentyp der SQL-Funktion und dem Rückgabetyp der C-/C++-Funktion sehen Sie hier:

    SQL-TypC-/C++-Typ
    STRINGchar *
    INTEGERlong long
    REALdouble

    Es ist auch möglich, eine DECIMAL-Funktion zu deklarieren. Da deren Wert jedoch zurzeit noch als String zurückgeliefert wird, sollten Sie eine solche UDF wie eine STRING-Funktion auslegen.

  • xxx_init() (optional)

    Die Initialisierungsfunktion für xxx(). Sie kann zu folgenden Zwecken benutzt werden:

    • Um zu prüfen, wie viele Argumente XXX() hat.

    • Um nachzuschauen, ob die Argumente den verlangten Typ haben oder, alternativ, um MySQL anzuweisen, den Argumenten die Typen aufzuzwingen, die für den Aufruf der Hauptfunktion erforderlich sind.

    • Um den von der Hauptfunktion benötigten Speicher zu reservieren.

    • Um die maximale Länge der Ergebnismenge anzugeben.

    • Um (für REAL-Funktionen) die Höchstzahl der Dezimalstellen in der Ergebnismenge anzugeben.

    • Um mitzuteilen, ob das Ergebnis auch NULL sein darf.

  • xxx_deinit() (optional)

    Die Deinitialisierungsfunktion für xxx(). Diese sollte den von der Initialisierungsfunktion reservierten Speicher wieder freigeben.

Wenn eine SQL-Anweisung XXX() aufruft, ruft MySQL die Initialisierungsfunktion xxx_init() auf, damit sie die notwendigen Vorbereitungen trifft, wie beispielsweise eine Überprüfung der Argumente oder die Speicherzuweisung. Wenn xxx_init() einen Fehler zurückliefert, bricht MySQL die SQL-Anweisung mit einer Fehlermeldung ab und ruft weder die Haupt- noch die Deinitialisierungsfunktion auf. Ansonsten ruft MySQL nun die Hauptfunktion xxx() einmal pro Zeile auf. Wenn alle Zeilen verarbeitet wurden, ruft MySQL die Deinitialisierungsfunktion xxx_deinit() auf, damit diese die notwendigen Aufräumarbeiten übernehmen kann.

Für Aggregatfunktionen, die wie SUM() arbeiten, müssen Sie außerdem folgende Funktionen bereitstellen:

  • xxx_clear() (obligatorisch für 5.1)

    Setzt den aktuellen Aggregatwert zurück, setzt aber das Argument nicht als Aggregatanfangswert für eine neue Gruppe ein.

  • xxx_add() (obligatorisch)

    Addiert das Argument zum aktuellen Aggregatwert.

MySQL geht folgendermaßen mit Aggregat-UDFs um:

  1. Es ruft xxx_init() auf, damit die Aggregatfunktion den Speicher reserviert, den sie für ihre Ergebnisse benötigt.

  2. Es sortiert die Tabelle entsprechend dem GROUP BY-Ausdruck.

  3. Es ruft für die erste Zeile jeder neuen Gruppe xxx_clear() auf.

  4. Es ruft für jede neue Zeile, die zu derselben Gruppe gehört, xxx_add() auf.

  5. Es ruft xxx() auf, um das Aggregatergebnis zu erhalten, wenn die Gruppe wechselt oder nachdem die letzte Zeile verarbeitet wurde.

  6. Es wiederholt die Schritte 3 bis 5, bis alle Zeilen verarbeitet sind.

  7. Es ruft xxx_deinit() auf, damit die UDF den von ihr reservierten Speicher wieder freigibt.

Alle Funktionen müssen Thread-sicher sein, also nicht nur die Hauptfunktion, sondern auch die Initialisierungs- und Deinitialisierungsfunktionen und alle sonstigen Funktionen, die für Aggregatfunktionen erforderlich sind. Dies hat zur Folge, dass Sie keine globalen oder statischen Variablen zuweisen dürfen, die sich ändern! Wenn Sie Arbeitsspeicher benötigen, weisen Sie ihn mit xxx_init() zu und geben ihn mit xxx_deinit() frei.

26.3.4.1. UDF-Aufrufsequenzen

Dieser Abschnitt beschreibt die verschiedenen Funktionen, die Sie definieren müssen, um eine einfache UDF anzulegen. Abschnitt 26.3.4, „Hinzufügen einer neuen benutzerdefinierten Funktion“, beschreibt die Reihenfolge, in der MySQL diese Funktionen aufruft.

Die xxx()-Hauptfunktion sollte so deklariert werden, wie es in diesem Abschnitt gezeigt wird. Beachten Sie, dass der Rückgabetyp und die Parameter unterschiedlich sind, je nachdem, ob Sie die SQL-Funktion XXX() in der CREATE FUNCTION-Anweisung mit dem Rückgabetyp STRING, INTEGER oder REAL deklarieren:

Für STRING-Funktionen gilt:

char *xxx(UDF_INIT *initid, UDF_ARGS *args,
          char *result, unsigned long *length,
          char *is_null, char *error);

Für INTEGER-Funktionen gilt:

long long xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

Für REAL-Funktionen gilt:

double xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

Die Initialisierungs- und Deinitialisierungsfunktionen werden wie folgt deklariert:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

void xxx_deinit(UDF_INIT *initid);

Der Parameter initid wird an alle drei Funktionen übergeben. Er verweist auf eine UDF_INIT-Struktur, die Informationen zwischen Funktionen übergibt. Die Bestandteile der UDF_INIT-Struktur werden im Folgenden aufgeführt. Die Initialisierungsfunktion sollte alle diejenigen Bestandteile ausfüllen, die geändert werden sollen. (Um einen Standardwert beizubehalten, ändern Sie einfach nichts.)

  • my_bool maybe_null

    xxx_init() sollte maybe_null auf 1 einstellen, wenn xxx() den Wert NULL zurückliefern kann. Der Standardwert ist 1, wenn irgendwelche Argumente als maybe_null deklariert sind.

  • unsigned int decimals

    Die Anzahl der Dezimalstellen rechts vom Dezimalpunkt (also salopp ausgedrückt: die Nachkommastellen). Der Standardwert ist die Höchtzahl der Dezimalstellen in den an die Hauptfunktion übergebenen Argumenten. (Wenn beispielsweise 1.34, 1.345 und 1.3 an die Funktion übergeben werden, wäre der Standardwert 3, da 1.345 3 Nachkommastellen hat.

  • unsigned int max_length

    Die Maximallänge des Ergebnisses. Der Standardwert max_length richtet sich nach dem Ergebnistyp der Funktion. Bei String-Funktionen ist er die Länge des längsten Arguments; bei Integer-Funktionen ist er 21 Ziffern. Bei Real-Funktionen ist der Standardwert 13 plus die Anzahl der durch initid->decimals vorgegebenen Dezimalstellen. (Bei numerischen Funktionen sind in der Länge auch Vorzeichen und Dezimalpunkt inbegriffen.)

    Wenn Sie einen Blob-Wert zurückliefern möchten, können Sie max_length auf 65 Kbyte oder 16 Mbyte einstellen. Der Speicherplatz wird zwar nicht reserviert, aber anhand der Länge entscheidet das System, welcher Datentyp für eine eventuell erforderliche temporäre Speicherung der Daten verwendet wird.

  • char *ptr

    Ein Zeiger, den die Funktion für ihre eigenen Zwecke verwenden kann. So können sich die Funktionen beispielsweise mit initid->ptr gegenseitig mitteilen, wie viel Speicher sie reservieren müssen. xxx_init() sollte den Speicher reservieren und diesem Zeiger zuweisen.

    initid->ptr = allocated_memory;
    

    In xxx() und xxx_deinit() verweisen Sie auf initid->ptr, um Speicher zu benutzen oder freizugeben.

  • my_bool const_item

    xxx_init() sollte const_item auf 1 setzen, wenn xxx() immer denselben Wert zurückgibt, und auf 0, wenn das nicht der Fall ist.

26.3.4.2. UDF-Aufrufsequenzen für Aggregatfunktionen

In diesem Abschnitt erfahren Sie, welche Funktionen Sie definieren müssen, um eine Aggregatfunktion als UDF anzulegen. Abschnitt 26.3.4, „Hinzufügen einer neuen benutzerdefinierten Funktion“, beschreibt die Reihenfolge, in der MySQL diese Funktionen aufruft.

  • xxx_reset()

    Diese Funktion wird aufgerufen, wenn MySQL die erste Zeile einer neuen Gruppe findet. Sie sollte eventuell vorhandene interne Summenvariablen zurücksetzen und dann das gegebene UDF_ARGS-Argument als ersten Wert des neuen internen Summenwerts für diese Gruppe verwenden. xxx_reset() wird folgendermaßen deklariert:

    char *xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
                    char *is_null, char *error);
    

    xxx_reset() wird in MySQL 5.1 weder benötigt noch benutzt. Die UDF-Schnittstelle verwendet stattdessen xxx_clear(). Sie können jedoch xxx_reset() zusätzlich zu xxx_clear() definieren, wenn Ihre UDF auch mit älteren Serverversionen laufen soll. (Wenn Sie beide Funktionen einbeziehen möchten, können Sie xxx_reset() intern oft implementieren, indem Sie zunächst xxx_clear() alle Variablen zurücksetzen lassen und dann xxx_add() aufrufen, um das Argument UDF_ARGS als ersten Wert der Gruppe hinzuzufügen.)

  • xxx_clear()

    Diese Funktion wird aufgerufen, wenn MySQL die Summenergebnisse zurücksetzen muss. Sie wird für jede neue Gruppe ganz am Anfang aufgerufen, kann aber auch verwendet werden, um die Werte für eine Anfrage zurückzusetzen, wenn keine übereinstimmenden Zeilen gefunden wurden. xxx_clear() wird folgendermaßen deklariert:

    char *xxx_clear(UDF_INIT *initid, char *is_null, char *error);
    

    is_null wird auf CHAR(0) eingestellt, bevor xxx_clear() aufgerufen wird.

    Wenn etwas schief gegangen ist, können Sie einen Wert in der Variablen speichern, auf die das Argument error verweist. error zeigt auf eine Singlebyte-Variable, nicht auf einen String-Puffer.

    xxx_clear() ist für MySQL 5.1 obligatorisch.

  • xxx_add()

    Diese Funktion wird für alle Zeilen außer der ersten aufgerufen, die zu derselben Gruppe gehören. Mit ihr addieren Sie den Wert des Arguments UDF_ARGS zu Ihrer internen Summenvariablen.

    char *xxx_add(UDF_INIT *initid, UDF_ARGS *args,
                  char *is_null, char *error);
    

Die xxx()-Funktion für eine Aggregat-UDF sollte genauso definiert werden wie die für eine einfache UDF. Siehe hierzu Abschnitt 26.3.4.1, „UDF-Aufrufsequenzen“.

Für eine Aggregat-UDF ruft MySQL die Funktion xxx() auf, nachdem alle Zeilen der Gruppe abgearbeitet sind. Im Normalfall greifen Sie hier niemals auf ihr UDF_ARGS-Argument zu, sondern geben einen Wert zurück, der auf Ihren internen Summenvariablen beruht.

Rückgabewerte sollten in xxx() genau wie bei einer UDF behandelt werden, die keine Aggregatfunktion ist. Siehe Abschnitt 26.3.4.4, „Rückgabewerte und Fehlerbehandlung“.

Die Funktionen xxx_reset() und xxx_add() gehen mit ihrem UDF_ARGS-Argument genauso um wie Funktionen für Nicht-Aggregat-UDFs. Siehe Abschnitt 26.3.4.3, „Verarbeitung von Argumenten“.

Die Zeigerargumente für is_null und error sind dieselben wie bei allen Aufrufen von xxx_reset(), xxx_clear(), xxx_add() und xxx(). Das können Sie nutzen, um sich zu merken, dass ein Fehler ausgelöst wurde oder ob die xxx()-Funktion NULL zurückgeben sollte. Bitte speichern Sie keinen String in *error! error verweist auf eine Single-Byte-Variable, nicht auf einen String-Puffer.

*is_null wird für jede Gruppe (vor dem Aufruf von xxx_clear()) zurückgesetzt, *error nie.

Sind *is_null oder *error gesetzt, wenn xxx() zurückkehrt, liefert MySQL NULL als Ergebnis der Gruppenfunktion zurück.

26.3.4.3. Verarbeitung von Argumenten

Der Parameter args verweist auf eine UDF_ARGS-Struktur mit folgenden Bestandteilen:

  • unsigned int arg_count

    Die Anzahl der Argumente. Diesen Wert muss die Initialisierungsfunktion prüfen, wenn Ihre Funktion mit einer bestimmten Anzahl von Argumenten aufgerufen werden muss. Zum Beispiel:

    if (args->arg_count != 2)
    {
        strcpy(message,"XXX() requires two arguments");
        return 1;
    }
    
  • enum Item_result *arg_type

    Ein Zeiger auf ein Array, das die Argumenttypen enthält. Mögliche Typwerte sind STRING_RESULT, INT_RESULT und REAL_RESULT.

    Um sicherzustellen, dass die Argumente einen bestimmten Typ haben, und um einen Fehler auszulösen, wenn der Typ nicht stimmt, muss die Initialisierungsfunktion das Array arg_type betrachten. Zum Beispiel:

    if (args->arg_type[0] != STRING_RESULT ||
        args->arg_type[1] != INT_RESULT)
    {
        strcpy(message,"XXX() requires a string and an integer");
        return 1;
    }
    

    Anstatt zu verlangen, dass die Funktionsargumente bestimmte Typen haben, können Sie auch mit der Initialisierungsfunktion die arg_type-Elemente auf die gewünschten Typen einstellen. Dies veranlasst MySQL, den Argumenten bei jedem Aufruf von xxx() die richtigen Typen aufzuzwingen. Um beispielsweise aus dem ersten Argument einen String und aus dem zweiten einen Integer zu machen, muss Ihre xxx_init()-Funktion Folgendes tun:

    args->arg_type[0] = STRING_RESULT;
    args->arg_type[1] = INT_RESULT;
    
  • char **args

    args->args informiert die Initialisierungsfunktion über das Wesen der an Ihre Funktion übergebenen Argumente. Bei einem Konstantenargument i verweist args->args[i] auf den Argumentwert. (Wie Sie richtig auf diesen Wert zugreifen, erfahren Sie weiter unten.) Bei einem Nichtkonstantenargument ist args->args[i] gleich 0. Ein Konstantenargument ist ein Ausdruck, der nur Konstanten verwendet, wie beispielsweise 3 oder 4*7-2 oder SIN(3.14). Ein Nichtkonstantenargument ist ein Ausdruck, der auf Werte verweist, die sich von Zeile zu Zeile ändern können, wie etwa Spaltennamen oder Funktionen, die mit Nichtkonstantenargumenten aufgerufen werden.

    Für jeden Aufruf der Hauptfunktion enthält args->args die Argumente, die tatsächlich an die in Bearbeitung befindliche Zeile übergeben werden.

    Funktionen können folgendermaßen auf ein Argument i verweisen:

    • Ein Argument vom Typ STRING_RESULT wird als String-Zeiger mit einer Längenangabe übergeben, damit auch Binärdaten oder Daten von beliebiger Länge verarbeitet werden können. Der String-Inhalt ist als args->args[i] und die Länge des Strings als args->lengths[i] angegeben. Bitte setzen Sie nicht voraus, dass Strings mit null beendet werden.

    • Bei Argumenten vom Typ INT_RESULT müssen Sie args->args[i] in einen long long-Wert umwandeln:

      long long int_val;
      int_val = *((long long*) args->args[i]);
      
    • Bei Argumenten vom Typ REAL_RESULT müssen Sie args->args[i] in einen double-Wert umwandeln:

      double    real_val;
      real_val = *((double*) args->args[i]);
      
  • unsigned long *lengths

    Für die Initialisierungsfunktion zeigt das Array lengths die maximale String-Länge für jedes Argument an. Diese sollten Sie nicht ändern. Für jeden Aufruf der Hauptfunktion enthält lengths die tatsächlichen Längen der String-Argumente, die an die in Bearbeitung befindliche Zeile übergeben werden. Für Argumente der Typen INT_RESULT oder REAL_RESULT enthält lengths immer noch die maximale Länge des Arguments (wie für die Initialisierungsfunktion).

26.3.4.4. Rückgabewerte und Fehlerbehandlung

Die Initialisierungsfunktion sollte 0 zurückgeben, wenn kein Fehler auftritt, und ansonsten 1. Kommt es zu einem Fehler, so sollte xxx_init() eine auf null endende Fehlermeldung im Parameter message speichern. Die Meldung wird an den Client zurückgegeben. Der Puffer für Fehlermeldungen ist zwar MYSQL_ERRMSG_SIZE Zeichen lang, aber Sie sollten dennoch versuchen, die Meldungen auf maximal 80 Zeichen zu begrenzen, damit sie auf die Breite eines normalen Bildschirms passen.

Der Rückgabewert der Hauptfunktion xxx() ist für long long- und double-Funktionen der Funktionswert. Eine String-Funktion sollte einen Zeiger auf das Ergebnis zurückliefern und *result und *length auf den Inhalt und die Länge des Ergebniswerts einstellen. Zum Beispiel:

memcpy(result, "result string", 13);
*length = 13;

Der result-Puffer, der an die xxx()-Funktion übergeben wird, ist 255 Byte lang. Wenn Ihr Ergebnis hineinpasst, müssen Sie sich um die Speicherzuweisung für Ergebnisse keine Gedanken machen.

Muss Ihre String-Funktion jedoch einen String zurückliefern, der länger als 255 Byte ist, so müssen Sie den Speicher dafür reservieren, indem Sie malloc() in Ihrer xxx_init()- oder xxx()-Funktion aufrufen und den Speicher dann in der xxx_deinit()-Funktion wieder freigeben. Sie können den reservierten Speicher auch in dem ptr-Slot in der UDF_INIT-Struktur speichern, um ihn für zukünftige xxx()-Aufrufe wiederverwenden zu können. Siehe Abschnitt 26.3.4.1, „UDF-Aufrufsequenzen“.

Um den Rückgabewert NULL in der Hauptfunktion anzuzeigen, setzen Sie *is_null auf 1:

*is_null = 1;

Um anzuzeigen, dass die Hauptfunktion einen Fehler zurückgibt, setzen Sie *error auf 1:

*error = 1;

Wenn xxx() den Wert von *error für irgendeine Zeile auf 1 setzt, ist der Funktionswert für die aktuelle Zeile und alle folgenden Zeilen, die in der Anweisung verarbeitet werden, in welcher XXX() aufgerufen wird, gleich NULL. (xxx() wird für die nachfolgenden Zeilen noch nicht einmal aufgerufen.)

26.3.4.5. Kompilieren und Installieren benutzerdefinierter Funktionen

Dateien, die UDFs implementieren, müssen auf dem Serverhost kompiliert und installert werden. Dies wird weiter unten für die Beispiel-UDF-Datei sql/udf_example.cc aus der MySQL-Quelldistribution beschrieben.

Die nachfolgenden Instruktionen gelten für Unix. Anleitungen für Windows finden Sie weiter unten in diesem Abschnitt.

Die Datei udf_example.cc enthält die folgenden Funktionen:

  • Die Funktion metaphon() gibt einen Metaphon-String aus dem String-Argument zurück. Dieser ist so etwas wie ein Soundex-String, allerdings besser auf die englische Sprache zugeschnitten.

  • Die Funktion myfunc_double() gibt die Summe der ASCII-Werte der in ihren Argumenten enthaltenen Zeichen geteilt durch die Summe der Längen dieser Argumente zurück.

  • Die Funktion myfunc_int() gibt die Summe der Längen ihrer Argumente zurück.

  • Die Funktion sequence([const int]) gibt eine Sequenz zurück, die ab der gegebenen Zahl oder, wenn keine gegeben wurde, ab 1 beginnt.

  • Die Funktion lookup() gibt die IP-Nummer eines Hostnamens zurück.

  • Die Funktion reverse_lookup() gibt den Hostnamen zu einer IP-Nummer zurück. Diese Funktion kann entweder mit einem einzigen String-Argument der Form 'xxx.xxx.xxx.xxx' oder mit vier Zahlen aufgerufen werden.

Eine Datei, die dynamisch zu laden sein soll, sollte als Sharable Object-Datei mit einem Befehl wie diesem kompiliert werden:

shell> gcc -shared -o udf_example.so udf_example.cc

Wenn Sie gcc benutzen, müsste sich udf_example.so auch mit einem einfacheren Befehl anlegen lassen:

shell> make udf_example.so

Die richtigen Compiler-Optionen für Ihr System finden Sie einfach heraus, indem Sie folgenden Befehl im sql-Verzeichnis Ihres MySQL-Quellbaums laufen lassen:

shell> make udf_example.o

Sie sollten einen ähnlichen Compile-Befehl geben, wie ihn make anzeigt, allerdings ohne die Option -c am Zeilenende. Stattdessen fügen Sie die Option -o udf_example.so hinzu. (Auf manchen Systemen müssen Sie eventuell die Option -c im Befehl beibehalten.)

Nachdem Sie ein Shared Object für UDFs kompiliert haben, müssen Sie es installieren und MySQL mitteilen, dass es da ist. Wenn Sie ein Shared Object aus udf_example.cc kompilieren, entsteht eine Datei, die ungefähr udf_example.so heißt (der genaue Name ist plattformabhängig). Diese Datei kopieren Sie in das Plug-In-Verzeichnis des Servers, das Sie anhand der Systemvariablen plugin_dir herausfinden können. (Hinweis: Dies ist eine Änderung in MySQL 5.1. In früheren Versionen von MySQL konnte das Shared Object in jedem Verzeichnis liegen, das der dynamische Linker Ihres Systems untersuchte.)

Auf manchen Systemen erkennt das Programm ldconfig, das den dynamischen Linker konfiguriert, ein Shared Object nur dann, wenn sein Name mit lib anfängt. In solchen Fällen sollten Sie eine Datei wie udf_example.so in libudf_example.so umbenennen.

Auf Windows können Sie benutzerdefinierte Funktionen wie folgt kompilieren:

  1. Zuerst benötigen Sie das BitKeeper-Quellarchiv für MySQL 5.1. Siehe Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“.

  2. In diesem Quellarchiv suchen Sie im Verzeichnis VC++Files/examples/udf_example nach den Dateien udf_example.def, udf_example.dsp und udf_example.dsw.

  3. Außerdem schauen Sie im Quellarchiv in das Verzeichnis sql und kopieren daraus die Datei udf_example.cc in das VC++Files/examples/udf_example-Verzeichnis. Dann benennen Sie die Datei in udf_example.cpp um.

  4. Öffnen Sie die Datei udf_example.dsw mit Visual Studio VC++ und kompilieren Sie damit die UDFs als ganz normales Projekt.

Sobald die Shared Object-Datei installiert ist, teilen Sie mysqld die neuen Funktionen mit folgenden Anweisungen mit:

mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME 'udf_example.so';
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME 'udf_example.so';
mysql> CREATE FUNCTION lookup RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE FUNCTION reverse_lookup
    ->        RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE AGGREGATE FUNCTION avgcost
    ->        RETURNS REAL SONAME 'udf_example.so';

Zum Löschen von Funktionen verwenden Sie DROP FUNCTION:

mysql> DROP FUNCTION metaphon;
mysql> DROP FUNCTION myfunc_double;
mysql> DROP FUNCTION myfunc_int;
mysql> DROP FUNCTION lookup;
mysql> DROP FUNCTION reverse_lookup;
mysql> DROP FUNCTION avgcost;

Die Anweisungen CREATE FUNCTION und DROP FUNCTION nehmen Änderungen in der Systemtabelle func in der mysql-Datenbank vor. Der Name, Typ und Shared Library-Name werden in dieser Tabelle gespeichert. Daher benötigen Sie INSERT- und DELETE-Rechte für die mysql-Datenbank, um dort Funktionen anzulegen und zu löschen.

Bitte verwenden Sie CREATE FUNCTION nicht, um eine Funktion hinzuzufügen, die bereits angelegt ist. Wenn Sie eine Funktion neu installieren müssen, entfernen Sie sie mit DROP FUNCTION und installieren sie dann mit CREATE FUNCTION neu. Das müssen Sie beispielsweise tun, wenn Sie eine neue Version Ihrer Funktion installieren, damit auch mysqld von der neuen Version weiß. Ansonsten würde der Server weiterhin die alte Version verwenden.

Eine aktive Funktion ist eine Funktion, die mit CREATE FUNCTION geladen, aber nicht mit DROP FUNCTION entfernt wurde. Alle aktiven Funktionen werden bei jedem Serverstart neu geladen, es sei denn, Sie fahren mysqld mit der Option --skip-grant-tables hoch. In diesem Fall wird die UDF-Initialisierung übersprungen und die UDFs stehen nicht zur Verfügung.

26.3.4.6. Vorsichtsmaßnahmen bei benutzerdefinierten Funktionen (UDF)

MySQL verhindert durch folgende Maßnahmen den Missbrauch benutzerdefinierter Funktionen:

Sie benötigen das INSERT-Recht, um CREATE FUNCTION, und das DELETE-Recht, um DROP FUNCTION sagen zu dürfen. Die Berechtigungen sind erforderlich, weil diese Anweisungen Zeilen der mysql.func-Tabelle anlegen und löschen.

Für UDFs sollte zusätzlich zu dem xxx-Symbol für die Hauptfunktion xxx() mindestens ein weiteres Symbol definiert sein. Diese Hilfssymbole stehen für die Funktionen xxx_init(), xxx_deinit(), xxx_reset(), xxx_clear() und xxx_add(). mysqld unterstützt überdies eine --allow-suspicious-udfs-Option, die steuert, ob UDFs, die nur das eine xxx-Symbol haben, überhaupt geladen werden dürfen. Nach Voreinstellung ist die Option ausgeschaltet, um zu verhindern, dass aus Shared Object-Dateien Funktionen geladen werden, die keine gültigen UDFs sind. Wenn Sie noch mit älteren UDFs arbeiten, die lediglich das xxx-Symbol haben und nicht mit einem Hilfssymbol rekompiliert werden können, kann es notwendig werden, die Option --allow-suspicious-udfs anzugeben. Ansonsten sollten Sie diese Option möglichst nicht einschalten.

Objektdateien für UDFs dürfen nicht in jedes beliebige Verzeichnis gelegt werden, sondern nur in das Plug-In-Verzeichnis des Servers, das Sie am Wert der Systemvariablen plugin_dir erkennen können. (Hinweis: Dies ist neu in MySQL 5.1. In früheren Versionen von MySQL konnte das Shared Object in jedem Verzeichnis platziert werden, das der dynamische Linker des Systems untersuchte.)

26.3.5. Hinzufügen einer neuen nativen Funktion

Hier wird erklärt, wie Sie vorgehen müssen, um eine neue native Funktion hinzuzufügen. Beachten Sie, dass Sie native Funktionen nicht in eine Binärdistribution einfügen können, da ein Eingriff in den Quellcode von MySQL notwendig ist. Sie müssen MySQL also selbst aus einer Quelldistribution kompilieren. Außerdem müssen Sie bei einer Umstellung auf eine andere MySQL-Version (beispielsweise wenn eine neue Version herauskommt) daran denken, die gesamte Prozedur mit der neuen Version zu wiederholen.

Um eine neue native MySQL-Funktion hinzuzufügen, verfahren Sie folgendermaßen:

  1. Sie binden in lex.h eine neue Zeile ein, die den Namen der Funktion im Array sql_functions[] definiert.

  2. Wenn der Funktionsprototyp einfach ist (nur null, ein, zwei oder drei Argumente hat), geben Sie in lex.h als zweites Argument im Array sql_functions[] den Wert SYM(FUNC_ARGN) an (wobei N die Anzahl der Argumente ist) und fügen eine Funktion hinzu, die ein Funktionsobjekt in item_create.cc erzeugt. Als Beispiele dafür können Sie sich "ABS" und create_funcs_abs() anschauen.

    Ist der Funktionsprototyp komplizierter (wenn beispielsweise die Funktion eine variable Anzahl Argumente entgegennimmt), müssen Sie zwei neue Zeilen in sql_yacc.yy einfügen: Die eine gibt ein Präprozessorsymbol an, das yacc definieren sollte (diese sollte an den Anfang der Datei eingefügt werden). Dann definieren Sie die Funktionsparameter und fügen ein „item“ mit diesen Parametern zu der Parsing-Regel für simple_expr Parametern hinzu. Als Beispiel dafür, wie dies getan wird, können Sie die diversen Exemplare von ATAN in sql_yacc.yy anschauen.

  3. Deklarieren Sie in item_func.h eine Klasse, die aus Item_num_func oder Item_str_func erbt, je nachdem, ob Ihre Funktion eine Zahl oder einen String zurückgibt.

  4. In item_func.cc fügen Sie eine der folgenden Deklarationen ein, je nachdem, ob Sie eine numerische oder eine String-Funktion definieren:

    double   Item_func_newname::val()
    longlong Item_func_newname::val_int()
    String  *Item_func_newname::Str(String *str)
    

    Wenn Sie Ihr Objekt aus einem der Standardelemente erben (wie etwa Item_num_func), müssen Sie wahrscheinlich nur eine dieser Funktionen definieren und es dann dem Parent-Objekt überlassen, sich um die übrigen Funktionen zu kümmern. So definiert zum Beispiel die Klasse Item_str_func eine val()-Funktion, die atof() auf dem Rückgabewert von ::str() ausführt.

  5. Außerdem müssen Sie wahrscheinlich folgende Objektfunktion definieren:

    void Item_func_newname::fix_length_and_dec()
    

    Diese Funktion sollte zumindest max_length anhand der gegebenen Argumente berechnen. max_length gibt an, wie viele Zeichen die Funktion höchstens zurückgeben kann. Diese Funktion sollte überdies maybe_null = 0 einstellen, wenn die Hauptfunktion keinen NULL-Wert zurückgeben kann. Ob irgendwelche Funktionsargumente NULL zurückgeben könnten, prüft die Funktion anhand der maybe_null-Variablen dieser Argumente. Ein typisches Beispiel dafür finden Sie in Item_func_mod::fix_length_and_dec.

Alle Funktionen müssen Thread-sicher sein. Mit anderen Worten: Sie dürfen keine globalen oder statischen Variablen in diesen Funktionen benutzen, ohne sie durch Mutex-Objekte zu schützen.

Wenn Sie NULL aus einer ::val()-, ::val_int()- oder ::str()-Funktion zurückgeben möchten, müssen Sie null_value auf 1 setzen und 0 zurückliefern.

Für ::str()-Objektfunktionen müssen Sie sich darüber hinaus Folgendes merken:

  • Das String *str-Argument liefert einen String-Puffer, der genutzt werden kann, um das Ergebnis zu speichern. (Um mehr über den Typ String zu erfahren, werfen Sie einen Blick in die Datei sql_string.h.)

  • Die ::str()-Funktion sollte den String zurückgeben, der das Resultat speichert, oder (char*) 0, wenn das Resultat NULL ist.

  • Alle gegenwärtigen String-Funktionen versuchen, nur dann Speicher zu reservieren, wenn es absolut unumgänglich ist!

26.4. Hinzufügen neuer Prozeduren zu MySQL

In MySQL können Sie mit der Sprache C++ eine Prozedur definieren, die Daten in einer Anfrage betrachten und ändern kann, ehe sie sie an den Client sendet. Diese Änderung kann zeilenweise oder auf der Ebene von GROUP BY erfolgen.

Wir haben eine Beispielprozedur geschrieben, um zu zeigen, was alles möglich ist.

Außerdem empfehlen wir Ihnen, einen Blick auf mylua zu werfen. Damit können Sie nämlich die Sprache LUA einsetzen, um eine Prozedur zur Laufzeit in mysqld zu laden.

26.4.1. PROCEDURE ANALYSE

analyse([max_elements,[max_memory]])

Diese Prozedur ist in der Datei sql/sql_analyse.cc definiert. Sie untersucht ein Anfrageergebnis und gibt eine Analyse der Resultate zurück:

  • max_elements (Standardwert 256) ist die Höchstzahl unterschiedlicher Werte, die analyse pro Spalte erkennen kann. Diesen Wert verwendet analyse, um zu prüfen, ob ENUM der optimale Datentyp wäre.

  • max_memory (Standardwert 8192) ist der größtmögliche Speicher, den analyse pro Spalte zuweisen kann, während die Prozedur versucht, alle unterschiedlichen Werte zu finden.

SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]])

26.4.2. Schreiben einer Prozedur

Die einzige Dokumentation hierzu ist zurzeit der Quellcode.

Alle Informationen über Prozeduren finden Sie in den folgenden Dateien:

  • sql/sql_analyse.cc

  • sql/procedure.h

  • sql/procedure.cc

  • sql/sql_select.cc

Anhang A. Probleme und häufig auftretende Fehler

Inhaltsverzeichnis

A.1. Wie man feststellt, was Probleme verursacht
A.2. Einige häufige Fehler bei der Benutzung von MySQL
A.2.1. Access denied-Fehler
A.2.2. Can't connect to [local] MySQL server-Fehler
A.2.3. Client does not support authentication protocol
A.2.4. Interaktive Kennworteingabe schlägt fehl
A.2.5. Host '...' is blocked-Fehler
A.2.6. Too many connections-Fehler
A.2.7. No free memory-Fehler
A.2.8. MySQL server has gone away-Fehler
A.2.9. Packet too large-Fehler
A.2.10. Kommunikationsfehler/abgebrochene Verbindung
A.2.11. The table is full-Fehler
A.2.12. Can't create/write to file-Fehler
A.2.13. Command out of sync-Fehler in Client
A.2.14. User ignored-Fehler
A.2.15. Table 'xxx' doesn't exist-Fehler
A.2.16. Can't initialize charset xxx-Fehler
A.2.17. Datei nicht gefunden
A.3. Installationsbezogene Themen
A.3.1. Probleme beim Linken mit der MySQL-Clientbibliothek
A.3.2. Probleme mit Dateirechten
A.4. Administrationsbezogene Themen
A.4.1. Wie ein vergessenes Kennwort zurückgesetzt wird
A.4.2. Was zu tun ist, wenn MySQL andauernd abstürzt
A.4.3. Wie MySQL mit vollen Festplatten umgeht
A.4.4. Wohin MySQL temporäre Dateien speichert
A.4.5. Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern
A.4.6. Probleme mit Zeitzonen
A.5. Anfragenbezogene Themen
A.5.1. Groß-/Kleinschreibung beim Suchen
A.5.2. Probleme bei der Benutzung von DATE-Spalten
A.5.3. Probleme mit NULL-Werten
A.5.4. Probleme mit alias
A.5.5. Rollback schlägt bei nichttransaktionssicheren Tabellen fehl
A.5.6. Zeilen aus verwandten Tabellen löschen
A.5.7. Lösung von Problemen mit nicht übereinstimmenden Zeilen
A.5.8. Probleme mit Fließkommavergleichen
A.6. Probleme im Zusammenhang mit dem Optimierer
A.7. Tabellendefinitionsbezogene Themen
A.7.1. Probleme mit ALTER TABLE
A.7.2. Wie man die Reihenfolge der Spalten in einer Tabelle ändert
A.7.3. Probleme mit TEMPORARY TABLE
A.8. Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL
A.8.1. Offene Probleme in MySQL

In diesem Anhang sind einige häufige Probleme und Fehlermeldungen aufgeführt, auf die Sie vielleicht stoßen werden. Außerdem wird beschrieben, wie man die Fehlerursachen findet und die Probleme behebt.

A.1. Wie man feststellt, was Probleme verursacht

Wenn Sie auf ein Problem stoßen, müssen Sie als Erstes herausfinden, von welchem Programm oder Hardwareteil es verursacht wird.

  • Die folgenden Symptome sprechen für Probleme mit der Hardware (Arbeitsspeicher, Motherboard, CPU oder Festplatte) oder mit dem Kernel:

    • Die Tastatur funktioniert nicht. Dies lässt sich normalerweise durch Drücken der Feststelltaste herausfinden. Wenn sich das Feststell-Licht dabei nicht ändert, müssen Sie Ihre Tastatur austauschen. (Bevor Sie das tun, sollten Sie allerdings den Computer neu starten und alle Kabelverbindungen der Tastatur überprüfen.)

    • Der Mauszeiger bewegt sich nicht.

    • Der Computer antwortet nicht auf die Ping-Versuche eines Remote-Computers.

    • Andere Programme, die nichts mit MySQL zu tun haben, funktionieren ebenfalls nicht.

    • Ihr System führt überraschend einen Neustart durch. (Ein fehlerhaftes Benutzerprogramm darf nie in der Lage sein, Ihr System herunterzufahren.)

    In diesem Fall überprüfen Sie als Erstes alle Ihre Kabel und lassen ein Diagnosetool laufen, um Ihre Hardware zu überprüfen. Außerdem schauen Sie nach, ob es irgendwelche Patches, Updates oder Service Packs für Ihr Betriebssystem gibt, die Ihr Problem lösen könnten. Auch die Aktualität Ihrer Bibliotheken (zum Beispiel glibc) muss überprüft werden.

    Es ist immer gut, einen Computer mit ECC-Memory zu überprüfen, um eventuelle Arbeitsspeicherprobleme frühzeitig zu finden.

  • Wenn Ihre Tastatur gesperrt ist, können Sie dies vielleicht beheben, indem Sie sich von einem anderen Computer aus auf Ihrem Rechner anmelden und kbd_mode -a ausführen.

  • Bitte fahnden Sie in Ihrem Systemlog (/var/log/messages oder ähnlich) nach Ursachen für Ihr Problem. Wenn Sie denken, dass es an MySQL liegt, sollten Sie auch die Logdateien von MySQL untersuchen. Siehe Abschnitt 5.12, „Die MySQL-Logdateien“.

  • Wenn Sie nicht der Ansicht sind, dass es sich um ein Hardwareproblem handelt, müssen Sie herausfinden, welches Programm die Probleme macht. Mit top, ps, Task-Manager oder einem ähnlichen Tool können Sie nachschauen, welches Programm die gesamte CPU mit Beschlag belegt oder den Computer sperrt.

  • Mit top, df oder einem ähnlichen Programm können Sie prüfen, ob Arbeitsspeicher, Festplattenplatz, Dateideskriptoren oder eine andere wichtige Ressource ausgeht.

  • Ist das Problem ein außer Kontrolle geratener Prozess, können Sie versuchen, diesen anzuhalten. Wenn er sich weigert, liegt wahrscheinlich ein Fehler im Betriebssystem vor.

Wenn Sie nach gründlicher Prüfung aller anderen Möglichkeiten zu dem Schluss kommen, dass der MySQL Server oder ein MySQL-Client das Problem verursacht hat, ist es an der Zeit, einen Bugreport für unsere Mailingliste oder unser Support-Team zu verfassen. Bitte beschreiben Sie darin sehr genau, wie sich das System verhält und was Ihrer Meinung nach vorgeht. Außerdem schreiben Sie bitte Ihre Einschätzung, was die Wurzel des Problems sein könnte. Bitte berücksichtigen Sie alle im vorliegenden Kapitel beschriebenen Situationen und sagen Sie genau, wie die Probleme auftreten, wenn Sie Ihr System überprüfen. Ausgabe und Fehlermeldungen von Programmen und Logdateien können Sie mit „Kopieren und Einfügen“ in Ihren Fehlerbericht übernehmen.

Versuchen Sie, detailliert zu beschreiben, welches Programm nicht funktioniert und welche Symptome vorhanden sind. Wir haben schon viele Bugreports gesehen, in denen es lediglich hieß: „Das System funktioniert nicht“. So bekommen wir keine Informationen, die uns helfen, das Problem zu beheben.

Wenn ein Programm abstürzt, sind folgende Informationen nützlich:

  • Hat das Programm einen Segmentierungsfehler gemacht (hat es einen Core Dump erstellt)?

  • Belegt das Programm sämtliche Prozessorzeit? Dies können Sie mit top überprüfen. Lassen Sie das Programm für eine Weile laufen, vielleicht führt es ja nur gerade eine rechenintensive Operation durch.

  • Wenn der mysqld-Server Probleme macht: Können Sie mit mysqladmin -u root ping oder mysqladmin -u root processlist irgendeine Antwort von ihm bekommen?

  • Was sagt Ihr Clientprogramm, wenn Sie versuchen, sich mit dem MySQL Server zu verbinden? (Versuchen Sie es zum Beispiel mit mysql.) Blockiert der Client? Gibt das Programm irgendetwas aus?

Wenn Sie uns einen Bugreport schicken, halten Sie sich bitte an die in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschriebene Vorgehensweise.

A.2. Einige häufige Fehler bei der Benutzung von MySQL

In diesem Abschnitt werden einige Fehler beschrieben, auf die Benutzer häufig bei der Ausführung von MySQL-Programmen stoßen. Die Probleme zeigen sich zwar bei der Ausführung von Clientprogrammen, aber die Lösung ist in vielen Fällen eine Konfigurationsänderung des MySQL Servers.

A.2.1. Access denied-Fehler

Ein Access denied-Fehler kann viele Ursachen haben. Oft hängt er damit zusammen, welchen MySQL-Konten der Server die Benutzung von Clientprogrammen gestattet. Siehe Abschnitt 5.8.8, „Gründe für Access denied-Fehler“, und Abschnitt 5.8.2, „Wie das Berechtigungssystem funktioniert“.

A.2.2. Can't connect to [local] MySQL server-Fehler

Auf Unix hat ein MySQL-Client zwei Möglichkeiten, sich mit dem mysqld-Server zu verbinden: Entweder verwendet er eine Unix-Socketdatei (nach Voreinstellung /tmp/mysql.sock), um sich über eine Datei im Dateisystem zu verbinden, oder er verwendet TCP/IP, um sich über eine Portnummer zu verbinden. Eine Verbindung über eine Unix-Socketdatei ist schneller als TCP/IP, kann aber nur genutzt werden, wenn sich der Client mit einem Server auf demselben Computer verbindet. Der Weg über die Unix-Socketdatei wird gewählt, wenn Sie keinen Hostnamen oder localhost angeben.

Wenn der MySQL Server auf Windows 9x oder Me läuft, können Sie sich nur per TCP/IP verbinden. Wenn er auf Windows NT, 2000, XP oder 2003 läuft und mit der Option --enable-named-pipe gestartet wird, können Sie sich auch mit Named Pipes verbinden, wenn der Client auf demselben Host wie der Server läuft. Der Name der Named Pipe ist nach Voreinstellung MySQL. Wenn Sie für die Verbindung mit mysqld keinen Hostnamen angeben, versucht ein MySQL-Client als Erstes eine Verbindung mit der Named Pipe. Wenn das nicht klappt, verbindet er sich mit dem TCP/IP-Port. Indem Sie . als Hostnamen angeben, zwingen Sie Windows zur Verwendung von Named Pipes.

Der Fehler (2002) Can't connect to ... bedeutet normalerweise, dass auf dem System kein MySQL Server läuft oder dass Sie bei Ihrem Verbindungsversuch einen verkehrten Unix-Socketdateinamen oder TCP/IP-Port angegeben haben.

Prüfen Sie als Erstes, ob auf Ihrem Serverhost ein Prozess namens mysqld läuft. (Hierzu verwenden Sie auf Unix ps xa | grep mysqld und auf Windows den Task- Manager.) Wenn kein solcher Prozess läuft, starten Sie den Server. Siehe hierzu Abschnitt 2.9.2.3, „Probleme mit dem Start des MySQL Servers“.

Läuft ein mysqld-Server, so überprüfen Sie ihn mit den folgenden Befehlen. Die Portnummer oder der Name der Unix-Socketdatei können in Ihrem Fall abweichen. host_ip ist die IP-Nummer des Computers, auf welchem der Server ausgeführt wird.

shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h host_ip version
shell> mysqladmin --protocol=socket --socket=/tmp/mysql.sock version

Beachten Sie, dass Backticks anstelle von Anführungszeichen für den hostname-Befehl verwendet werden. Diese sorgen dafür, dass die Ausgabe von hostname (also des aktuellen Hostnamens) in den Befehl mysqladmin eingesetzt wird. Wenn Sie keinen hostname-Befehl zur Verfügung haben oder mit Windows arbeiten, können Sie den Hostnamen Ihres Computers hinter der Option -h manuell eingeben (ohne Backticks). Oder Sie versuchen, sich mit -h 127.0.0.1 über TCP/IP mit dem lokalen Host zu verbinden.

Der Fehler Can't connect to local MySQL server könnte aus folgenden Gründen auftreten:

  • mysqld läuft nicht. Vergewissern Sie sich, ob der Prozess mysqld in der Prozessliste Ihres Betriebssystems auftaucht.

  • Sie führen einen MySQL Server auf Windows mit vielen TCP/IP-Verbindungen aus. Wenn es häufiger vorkommt, dass Ihre Clients diesen Fehler melden, finden Sie an folgender Stelle einen Workaround: Abschnitt A.2.2.1, „Connection to MySQL server failing on Windows-Fehler“.

  • Ihr System verwendet MIT-pthreads. Wenn Sie auf einem System arbeiten, das keine nativen Threads kennt, verwendet mysqld das Package MIT-pthreads (siehe Abschnitt 2.1.1, „Betriebssysteme, die von MySQL unterstützt werden“). Allerdings unterstützen nicht alle MIT-pthreads Unix-Socketdateien. Auf einem System ohne Socketdateiunterstützung müssen Sie bei einer Serververbindung den Hostnamen immer explizit angeben. Versuchen Sie, mit folgendem Befehl die Serververbindung zu überprüfen:

    shell> mysqladmin -h `hostname` version
    
  • Jemand hat die von mysqld verwendete Unix-Socketdatei entfernt (standardmäßig /tmp/mysql.sock). Vielleicht haben Sie ja einen cron-Job, der alte Dateien aus dem Verzeichnis /tmp löscht. Mit mysqladmin version können Sie sich vergewissern, dass die Unix-Socketdatei, die mysqladmin benötigt, auch tatsächlich existiert. Wenn dies das Problem ist, müssen Sie den cron-Job so abändern, dass er mysql.sock nicht mehr entfernt, oder die Socketdatei an einen anderen Ort verlagern. Siehe Abschnitt A.4.5, „Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern“.

  • Sie haben den mysqld-Server zwar mit der Option --socket=/path/to/socket gestartet, aber vergessen, den Clientprogrammen den neuen Namen der Socketdatei mitzuteilen. Wenn Sie den Socketpfadnamen für den Server ändern, müssen Sie auch die MySQL-Clients entsprechend benachrichtigen. Dies erledigen Sie, indem Sie dieselbe --socket-Option einsetzen, wenn Sie die Clientprogramme ausführen. Außerdem müssen Sie gewährleisten, dass die Clients ein Zugriffsrecht auf die mysql.sock-Datei haben. Um herauszufinden, wo die Socketdatei liegt, tun Sie Folgendes:

    shell> netstat -ln | grep mysql
    

    Siehe Abschnitt A.4.5, „Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern“.

  • Sie arbeiten auf Linux und ein Server-Thread ist ausgefallen (mit Core Dump). In diesem Fall müssen Sie auch die anderen mysqld-Threads anhalten (zum Beispiel mit kill oder mit dem mysql_zap-Skript), bevor Sie den MySQL Server neu starten können. Siehe Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

  • Der Server oder das Clientprogramm hat nicht die richtigen Zugriffsberechtigungen für das Verzeichnis mit der Unix-Socketdatei oder der Socketdatei selbst. In diesem Fall müssen Sie die Berechtigungen so ändern, dass der Server und die Clients an diese Dateien herankommen, oder mysqld mit einer --socket-Option neu starten, die eine Socketdatei in einem Verzeichnis angibt, wo der Server sie anlegen kann und die Clients auf sie zugreifen können.

Wenn Sie die Fehlermeldung Can't connect to MySQL server on some_host bekommen, können Sie mit folgenden Mitteln herausfinden, wo das Problem liegt:

  • Prüfen Sie, ob der Server auf diesem Host läuft, indem Sie telnet some_host 3306 ausführen und dann die Eingabetaste einige Male drücken. (3306 ist die Standardnummer für den MySQL-Port. Ändern Sie den Wert, wenn Ihr Server einen anderen Port verwendet.) Wenn ein MySQL Server auf diesem Port läuft und lauscht, müssten Sie eine Antwort bekommen, die auch die Versionsnummer des Servers angibt. Erhalten Sie stattdessen einen Fehler wie beispielsweise telnet: Unable to connect to remote host: Connection refused, dann ist auf dem angegebenen Port kein Server zu erreichen.

  • Wenn der Server auf dem lokalen Host läuft, können Sie versuchen, sich per mysqladmin -h localhost variables über die Unix-Socketdatei zu verbinden. Überprüfen Sie, auf welcher TCP/IP-Portnummer der Server lauscht (also den Wert der Variablen port).

  • Vergewissern Sie sich, dass der mysqld-Server nicht mit der Option --skip-networking gestartet wurde. Ansonsten können Sie sich nicht per TCP/IP verbinden.

  • Vergewissern Sie sich, dass keine Firewall den Zugriff auf MySQL verhindert. Anwendungen wie ZoneAlarm und die Windows XP-Firewall müssen unter Umständen speziell konfiguriert werden, damit sie den externen Zugriff auf einen MySQL Server erlauben.

A.2.2.1. Connection to MySQL server failing on Windows-Fehler

Wenn Sie einen MySQL Server auf Windows mit vielen TCP/IP-Verbindungen ausführen und Ihre Clients häufig einen Can't connect to MySQL server-Fehler melden, könnte es sein, dass Windows nicht genügend vorübergehende (kurzlebige) Ports erlaubt, um diese Verbindungen zu ermöglichen.

Nach Voreinstellung gestattet Windows 5000 vorübergehende (kurzlebige) TCP-Ports. Wenn ein Port geschlossen wird, verbleibt er 120 Sekunden lang in einem TIME_WAIT-Status. Wird die Verbindung in diesem Status wiederverwendet, so entstehen viel weniger Kosten als bei der Einrichtung einer neuen Verbindung. Allerdings steht der Port vor Ablauf dieser Zeit nicht zur Verfügung.

Wenn Sie nur einen kleinen Vorrat verfügbarer TCP-Ports (5000) haben und viele dieser Ports in kurzer Zeit geöffnet und mit dem TIME_WAIT-Status wieder geschlossen werden, kann es leicht passieren, dass Ihnen die Ports ausgehen. Es gibt zwei Möglichkeiten, dieses Problem in den Griff zu bekommen:

  • Sie sorgen dafür, dass die TCP-Ports nicht so schnell aufgebraucht werden, indem Sie, wo immer es möglich ist, Verbindungspooling oder persistente Verbindungen in Betracht ziehen.

  • Sie ändern einige Einstellungen in der Windows-Registrierung (siehe weiter unten).

Wichtig: Im folgenden Verfahren wird die Windows-Registrierung geändert. Bevor Sie dies tun, müssen Sie Ihre Registrierung unbedingt sichern und genau wissen, wie Sie sie wiederherstellen können, falls etwas geschieht. Wie man die Registrierung sichert, wiederherstellt und bearbeitet, verrät Ihnen folgender Artikel aus der Microsoft Knowledge Base: http://support.microsoft.com/kb/256986/EN-US/.

  1. Starten Sie den Registrierungs-Editor (Regedt32.exe).

  2. Suchen Sie folgenden Registrierungsschlüssel:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
    
  3. Klicken Sie im Menü Bearbeiten auf Wert hinzufügen und fügen Sie dann folgenden Registrierungswert ein:

    Value Name: MaxUserPort
    Data Type: REG_DWORD
    Value: 65534
    

    Dieser Wert stellt ein, wie viele vorübergehende Ports einem Benutzer zur Verfügung stehen. Der zulässige Wertebereich liegt zwischen 5000 und 65534 (Dezimalsystem). Der Standardwert ist 0x1388 (5000 dezimal).

  4. Klicken Sie im Menü Bearbeiten auf Wert hinzufügen und fügen Sie dann folgenden Registrierungswert hinzu:

    Value Name: TcpTimedWaitDelay
    Data Type: REG_DWORD
    Value: 30
    

    Hiermit stellen Sie ein, wie viele Sekunden eine Verbindung mit einem TCP-Port im TIME_WAIT-Status verbleibt, ehe sie geschlossen wird. Der zulässige Wertebereich liegt zwischen 0 (null) und 300 (dezimal). Der Standardwert ist 0x78 (120 dezimal).

  5. Schließen Sie den Registrierungs-Editor.

  6. Starten Sie den Computer neu.

Hinweis: Um die obigen Änderungen rückgängig zu machen, löschen Sie einfach die Registrierungseinträge, die Sie erstellt haben.

A.2.3. Client does not support authentication protocol

MySQL 5.1 verwendet ein Authentifizierungsprotokoll, das auf einem Passwort-Hash-Algorithmus basiert, der mit älteren Clients (vor Version 4.1) inkompatibel ist. Wenn Sie den Server von 4.1 auf die neue Version aufrüsten, können Verbindungsversuche mit einem älteren Client folgenden Fehler verursachen:

shell> mysql
Client does not support authentication protocol requested
by Server; consider upgrading MySQL client

Für dieses Problem gibt es folgende Lösungsansätze:

  • Sie aktualisieren alle Clientprogramme, sodass sie die Clientbibliothek von 4.1.1 oder eine neuere Version benutzen.

  • Wenn Sie mit einem Clientprogramm einer Version vor 4.1 auf den Server zugreifen, verwenden Sie ein Konto, das noch ein Passwort aus der Zeit von vor 4.1 hat.

  • Stellen Sie das Passwort für Benutzer, die ein älteres Clientprogramm als 4.1 verwenden, im Stil der Version von vor 4.1 ein. Dies können Sie mit der SET PASSWORD-Anweisung oder der OLD_PASSWORD()-Funktion tun:

    mysql> SET PASSWORD FOR
        -> 'some_user'@'some_host' = OLD_PASSWORD('newpwd');
    

    Alternativ können Sie auch UPDATE und FLUSH PRIVILEGES einsetzen:

    mysql> UPDATE mysql.user SET Password = OLD_PASSWORD('newpwd')
        -> WHERE Host = 'some_host' AND User = 'some_user';
    mysql> FLUSH PRIVILEGES;
    

    In diesen Beispielen müssen Sie „newpwd“ durch das neue, von Ihnen gewählte Passwort ersetzen. Da MySQL Ihnen das Originalpasswort nicht verraten kann, müssen Sie ein neues aussuchen.

  • Veranlassen Sie den Server, den älteren Passwort-Hashing-Algorithmus zu verwenden:

    1. Starten Sie mysqld mit der Option --old-passwords.

    2. Weisen Sie jedem Konto, dessen Passwort auf das längere 4.1-Fomat umgestellt wurde, ein Passwort im alten Format zu. Welche Konten das sind, verrät Ihnen folgende Anfrage:

      mysql> SELECT Host, User, Password FROM mysql.user
          -> WHERE LENGTH(Password) > 16;
      

      Für jeden Konteneintrag, den der Server zeigt, nehmen Sie die Werte Host und User und weisen mit der Funktion OLD_PASSWORD() und SET PASSWORD oder UPDATE ein neues Passwort zu, wie oben beschrieben.

Hinweis: In älteren PHP-Versionen unterstützt die mysql-Erweiterung nicht das Authentifizierungsprotokoll von MySQL 4.1.1 und höher. Das gilt unabhängig von der verwendeten PHP-Version. Wenn Sie die mysql-Erweiterung mit MySQL 4.1 oder höher nutzen möchten, müssen Sie unter Umständen einen der oben beschriebenen Wege einschlagen, um MySQL für ältere Clients zu konfigurieren. Die mysqli-Erweiterung (die in PHP 5 für "MySQL, Improved" steht) ist kompatibel mit dem verbesserten Passwort-Hashing von MySQL 4.1 und höher. Hier ist keine spezielle Konfiguration für MySQL erforderlich, um diese MySQL-Clientbibliothek nutzen zu können. Weitere Informationen über die mysqli-Erweiterung finden Sie unter http://php.net/mysqli.

Unter Umständen kann auch die ältere mysql-Erweiterung mit der neuen MySQL-Clientbibliothek kompiliert werden. Dieser Vorgang ist jedoch nicht Thema unseres Referenzhandbuchs. Weitere Informationen finden Sie in der PHP-Dokumentation. Eventuell können Sie in solchen Fragen auch im MySQL with PHP forum Hilfe finden.

Hintergrundinformationen über Passwort-Hashing und Authentifizierung gibt es unter Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“.

A.2.4. Interaktive Kennworteingabe schlägt fehl

MySQL-Clientprogramme fordern zur Eingabe eines Passworts auf, wenn sie mit der Option --password oder -p ohne einen Passwortwert dahinter aufgerufen werden:

shell> mysql -u user_name -p
Enter password:

Auf manchen Systemen kann es vorkommen, dass das Passwort funktioniert, wenn man es in einer Optionsdatei oder auf der Kommandozeile angibt, aber nicht, wenn man es interaktiv am Enter password:-Prompt eintippt. Dies geschieht, wenn die Bibliothek, die das System zum Lesen von Passwörtern zur Verfügung stellt, die Passwortwerte auf eine geringe Zeichenzahl einschränkt (in der Regel 8 Zeichen). Dieses Problem betrifft nicht MySQL, sondern die Systembibliothek. Um es zu lösen, müssen Sie entweder Ihr MySQL-Passwort auf einen Wert kürzen, der nur 8 Zeichen lang ist, oder es in eine Optionsdatei setzen.

A.2.5. Host '...' is blocked-Fehler

Wenn folgender Fehler gemeldet wird, bedeutet dies, dass mysqld vom Host 'host_name' viele Verbindungsanforderungen empfangen hat, die in der Mitte unterbrochen wurden:

Host 'host_name' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'

Wie viele unterbrochene Anforderungen maximal zulässig sind, ist in der Systemvariablen max_connect_errors festgelegt. Nach max_connect_errors gescheiterten Anforderungen nimmt mysqld an, dass etwas nicht in Ordnung ist (beispielsweise ein Einbruchsversuch), und blockiert weitere Verbindungen dieses Hosts, bis Sie einen mysqladmin flush-hosts-Befehl oder eine FLUSH HOSTS-Anweisung geben. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“.

Nach Voreinstellung blockiert mysqld einen Host nach 10 Verbindungsfehlern. Diesen Wert können Sie ändern, indem Sie den Server folgendermaßen starten:

shell> mysqld_safe --max_connect_errors=10000 &

Wenn Sie diese Fehlermeldung für einen Host bekommen, prüfen Sie als Erstes, ob mit den TCP/IP-Verbindungen von diesem Host alles in Ordnung ist. Bei Netzwerkproblemen nützt es nichts, den Wert der Variablen max_connect_errors heraufzusetzen.

A.2.6. Too many connections-Fehler

Wenn Sie beim Versuch einer Verbindung mit dem mysqld-Server einen Too many connections-Fehler bekommen, so bedeutet dies, dass alle verfügbaren Verbindungen von anderen Clients belegt sind.

Die Systemvariable max_connections legt fest, wie viele Verbindungen zulässig sind. Ihr Standardwert ist 100. Wenn Sie mehr Verbindungen benötigen, müssen Sie mysqld mit einem größeren Wert für diese Variable neu starten.

mysqld erlaubt in Wirklichkeit max_connections+1 Clients eine Verbindung. Die eine zusätzliche Verbindung ist für Konten reserviert, die das SUPER-Recht haben. Indem Sie dieses Recht nur an Administratoren und nicht an normale Benutzer vergeben (diese benötigen es ohnehin nicht), kann sich ein Administrator selbst dann noch mit dem Server verbinden und mit der Anweisung SHOW PROCESSLIST eine Problemdiagnose vornehmen, wenn die Höchstzahl der unprivilegierten Clientverbindungen erreicht ist. Siehe Abschnitt 13.5.4.19, „SHOW PROCESSLIST.

Wie viele Verbindungen MySQL maximal unterstützen kann, hängt von der Qualität der Thread-Bibliothek auf einer gegebenen Plattform ab. Linux oder Solaris müssten 500 bis 1.000 gleichzeitige Verbindungen dulden können, je nachdem, wie viel Arbeitsspeicher Sie haben und was Ihre Clients tun. Statische Linux-Binaries von MySQL AB können bis zu 4.000 Verbindungen unterstützen.

A.2.7. No free memory-Fehler

Wenn Sie mit dem Clientprogramm mysql eine Anfrage absetzen und einen Fehler wie den folgenden ernten, so bedeutet dies, dass mysql zu wenig Arbeitsspeicher hat, um das vollständige Abfrageergebnis zu speichern:

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory

Dieses Problem beheben Sie, indem Sie zuerst prüfen, ob Ihre Anfrage korrekt ist. Ist es normal, dass sie so viele Zeilen zurückgibt? Wenn nicht, korrigieren Sie die Anfrage und versuchen es erneut. Andernfalls können Sie mysql mit der Option --quick aufrufen. Dann verwendet sie zum Abruf der Ergebnismenge die C-API-Funktion mysql_use_result(), die wesentlich weniger Last für den Client (aber mehr Last für den Server) bedeutet.

A.2.8. MySQL server has gone away-Fehler

In diesem Abschnitt wird auch der hiermit verwandte Lost connection to server during query-Fehler behandelt.

Die häufigste Ursache eines MySQL server has gone away-Fehlers ist, dass der Server die Verbindung wegen eines Timeouts geschlossen hat. In diesem Fall wird normalerweise einer der folgenden Fehlercodes (je nach Betriebssystem) gemeldet:

FehlercodeBeschreibung
CR_SERVER_GONE_ERRORDer Client konnte keine Frage an den Server senden.
CR_SERVER_LOSTDer Client konnte zwar ohne Fehler auf den Server schreiben, erhielt aber keine (oder keine vollständige) Antwort auf die Frage.

Nach Voreinstellung schließt der Server die Verbindung, wenn nichts geschieht, nach acht Stunden. Dieses Zeitlimit können Sie in der Variablen wait_timeout ändern, wenn Sie mysqld starten. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“.

Wenn Sie ein Skript verwenden, müssen Sie die Anfrage nur erneut absetzen, damit der Client sich automatisch erneut verbindet. Das setzt voraus, dass die automatische Neuverbindung im Client eingeschaltet ist (was beim mysql-Kommandozeilen-Client standardmäßig der Fall ist).

Oft kommen MySQL server has gone away-Fehler auch aus folgenden Gründen zustande:

  • Sie (oder der Datenbankadministrator) haben den laufenden Thread mit einer KILL-Anweisung oder einem mysqladmin kill-Befehl angehalten.

  • Sie haben versucht, eine Anfrage nach dem Schließen der Serververbindung abzusetzen. Dies weist auf einen Fehler in der Anwendungslogik hin, der korrigiert werden muss.

  • Sie haben einen Timeout von der TCP/IP-Verbindung auf der Clientseite erhalten. Dazu kann es bei folgenden Befehlen kommen: mysql_options(..., MYSQL_OPT_READ_TIMEOUT, ...) oder mysql_options(..., MYSQL_OPT_WRITE_TIMEOUT, ...). In diesem Fall können Sie Ihr Problem lösen, indem Sie den Timeout heraufsetzen.

  • Sie haben einen Timeout auf der Serverseite und die automatische Neuverbindung ist im Client deaktiviert worden (das Flag reconnect in der MYSQL-Struktur ist gleich 0).

  • Sie verwenden einen Windows-Client und der Server hat die Verbindung beendet (wahrscheinlich, weil wait_timeout abgelaufen ist), bevor der Befehl gegeben wurde.

    Das Problem mit Windows besteht darin, dass MySQL manchmal keinen Fehler vom Betriebssystem gemeldet bekommt, wenn es Daten in die TCP/IP-Verbindung mit dem Server schreibt. Stattdessen wird der Fehler erst bei dem Versuch gemeldet, Daten aus dieser Verbindung zu lesen.

    Selbst wenn das Flag reconnect in der MYSQL-Struktur gleich 1 ist, wird sich MySQL in diesem Fall nicht automatisch neu verbinden und die Anfrage neu absetzen, da es nicht wissen kann, ob der Server die ursprüngliche Anfrage bekommen hat oder nicht.

    Die Lösung ist entweder ein mysql_ping auf der Verbindung, falls seit der letzten Abfrage viel Zeit vergangen ist (so handelt auch MyODBC), oder eine Änderung von wait_timeout auf dem mysqld-Server auf einen Wert, der so hoch ist, dass es praktisch nie zu einem Timeout kommt.

  • Solche Fehlermeldungen können Sie auch erhalten, wenn Sie an den Server eine zu große oder eine falsche Anfrage senden. Wenn mysqld ein Paket empfängt, das zu groß oder nicht ordnungsgemäß ist, nimmt das Programm an, dass mit dem Client etwas nicht stimmt, und schließt die Verbindung. Wenn Sie große Anfragen benötigen (zum Beispiel weil Sie mit umfangreichen BLOB-Spalten arbeiten), können Sie das Limit pro Anfrage heraufsetzen, indem Sie die Servervariable max_allowed_packet von ihrem Standardwert 1 Mbyte auf etwas Höheres heraufsetzen. Vielleicht müssen Sie auch die Paketgröße auf der Clientseite erhöhen. Über die Einstellung der Paketgröße können Sie unter Abschnitt A.2.9, „Packet too large-Fehler“, mehr erfahren.

  • Ihre Verbindung wird auch abbrechen, wenn Sie ein Paket der Größe 16 Mbyte oder mehr verschicken und Ihr Client älter als Version 4.0.8 ist, während Ihr Server die Version 4.0.8 oder höher verwendet (oder umgekehrt).

  • Eventuell kommt es auch zu dem Fehler MySQL server has gone away, wenn MySQL mit der Option --skip-networking gestartet wird.

  • Während der Ausführung der Anfrage trat ein Fehler auf, der den Server angehalten hat.

Ob der MySQL Server abgestürzt und wieder hochgefahren ist, erfahren Sie, indem Sie mysqladmin version ausführen und auf die Uptime des Servers achten. Wenn die Clientverbindung unterbrochen war, weil mysqld abgestürzt und wieder hochgefahren ist, sollten Sie sich auf die Erforschung der Absturzursachen konzentrieren. Zuerst prüfen Sie, ob der Server bei derselben Anfrage erneut abstürzen wird. Siehe Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

Mehr Informationen über unterbrochene Verbindungen bekommen Sie, wenn Sie mysqld mit der Option --log-warnings=2 starten. Damit werden einige Verbindungsabbruchfehler in der Datei hostname.err protokolliert. Siehe Abschnitt 5.12.1, „Die Fehler-Logdatei“.

Wenn Sie einen Bugreport über dieses Problem schicken möchten, senden Sie uns bitte auch folgende Informationen:

Siehe auch Abschnitt A.2.10, „Kommunikationsfehler/abgebrochene Verbindung“, und Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

A.2.9. Packet too large-Fehler

Ein Kommunikationspaket ist eine einzelne an den MySQL Server geschickte SQL-Anweisung oder eine einzelne an den Client geschickte Zeile.

Das größtmögliche Paket, das von einem oder an einen MySQL 5.1 Server oder -Client übermittelt werden kann, ist 1 Gbyte groß.

Wenn ein MySQL-Client oder der mysqld-Server ein Paket empfängt, dessen Größe max_allowed_packet Bytes übersteigt, löst er einen Packet too large-Fehler aus und schließt die Verbindung. Manche Clients melden auch einen Lost connection to MySQL Server during query-Fehler, wenn das Kommunikationspaket zu groß ist.

Da Client und Server jeweils ihre eigene max_allowed_packet-Variable haben, müssen Sie diese auf beiden Seiten erhöhen, wenn Sie größere Pakete verschicken möchten.

Der Standardwert der max_allowed_packet-Variable des Clientprogramms mysql ist 16 Mbyte. Um ihn zu erhöhen, starten Sie mysql wie folgt:

mysql> mysql --max_allowed_packet=32M

So wächst die Paketgröße auf 32 MB.

Die maximale max_allowed_packet-Größe des Servers ist 1 MB. Sie können sie heraufsetzen, wenn der Server umfangreiche Anfragen verarbeiten muss (beispielsweise mit großen BLOB-Spalten). Um diese Variable auf 16 Mbytezu setzen, starten Sie den Server wie folgt:

mysql> mysqld --max_allowed_packet=16M

Sie können max_allowed_packet auch mit einer Optiondatei einstellen. Um beispielsweise die Paketgröße für den Server auf 16 Mbytezu setzen, fügen Sie einer Optionsdatei folgende Zeilen hinzu:

[mysqld]
max_allowed_packet=16M

Der Wert dieser Variablen lässt sich ohne Sicherheitsrisiko erhöhen, da der zusätzliche Speicher nur bei Bedarf zugewiesen wird. So weist beispielsweise mysqld nur dann mehr Speicher zu, wenn Sie eine lange Anfrage haben oder wenn mysqld eine große Ergebniszeile zurückgeben muss. Der kleine Standardwert dieser Variablen ist eine Vorsichtsmaßnahme, um unkorrekte Pakete zwischen Client und Server abzufangen und zu gewährleisten, dass Sie keine Speicherplatzprobleme bekommen, weil Sie versehentlich zu große Pakete verwenden.

Es können auch seltsame Dinge mit großen Paketen passieren, wenn Sie umfangreiche BLOB-Werte benutzen, aber mysqld zu wenig Speicher gegeben haben, um mit der Anfrage umzugehen. Wenn Sie den Verdacht haben, dass dies der Fall ist, müssen Sie ulimit -d 256000 am Anfang des mysqld_safe-Skripts hinzufügen und mysqld neu starten.

A.2.10. Kommunikationsfehler/abgebrochene Verbindung

Das Fehlerlog des Servers kann wichtige Informationen über Verbindungsprobleme geben (siehe Abschnitt 5.12.1, „Die Fehler-Logdatei“). Wenn Sie den Server mit der Option --log-warnings starten, finden Sie im Fehlerlog vielleicht Meldungen wie diese:

010301 14:38:23  Aborted connection 854 to db: 'users' user: 'josh'

Wenn Aborted connections-Meldungen im Fehlerlog stehen, kann das folgende Ursachen haben:

  • Das Clientprogramm hat nicht mysql_close() aufgerufen, bevor es endete.

  • Der Client hat länger als wait_timeout oder interactive_timeout Sekunden geschlafen, ohne Requests an den Server zu senden. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“.

  • Das Clientprogramm brach plötzlich mitten in einer Datenübertragung ab.

Wenn so etwas geschieht, setzt der Server die Statusvariable Aborted_clients herauf.

Bei folgenden Vorfällen inkrementiert der Server die Statusvariable Aborted_connects:

  • Ein Client hat kein Zugriffsrecht auf die Datenbank.

  • Ein Client benutzt ein falsches Passwort.

  • Ein Verbindungspaket enthält nicht die richtigen Informationen.

  • Es dauert mehr als connect_timeout Sekunden, ein Verbindungspaket zu erhalten. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“.

Wenn diese Dinge passieren, kann das bedeuten, dass jemand versucht, in den Server einzudringen!

Andere Gründe für einen Abbruch von Clients oder Verbindungen können sein:

  • Verwendung eines Ethernet-Protokolls mit Linux, sowohl Halb- als auch Voll-Duplex. Viele Linux Ethernet-Treiber haben diesen Fehler. Ob der Fehler auch bei Ihnen vorhanden ist, können Sie testen, indem Sie eine große Datei per FTP zwischen dem Client- und dem Servercomputer übertragen. Wenn der Transfer in einer Art Stop-and-Go-Verkehr abläuft, haben Sie ein Linux-Duplex-Syndrom. Die einzige Lösung besteht darin, den Duplex-Modus für Ihre Netzwerkkarte und ihren Hub/Switch immer entweder auf Voll-Duplex oder auf Halb-Duplex einzustellen und anhand der Ergebnisse die geeignetste Einstellung zu ermitteln.

  • Ein Problem mit der Thread-Bibliothek, das Unterbrechungen der Lesevorgänge verursacht.

  • Ein schlecht konfiguriertes TCP/IP.

  • Fehler in Ethernets, Hubs, Switches, Kabeln usw. Diese lassen sich nur durch Ersetzung von Hardware zweifelsfrei diagnostizieren.

  • Die Variable max_allowed_packet ist zu klein oder Anfragen erfordern mehr Arbeitsspeicher, als Sie für mysqld zugewiesen haben. Siehe Abschnitt A.2.9, „Packet too large-Fehler“.

Siehe auch Abschnitt A.2.8, „MySQL server has gone away-Fehler“.

A.2.11. The table is full-Fehler

Ein Fehler wegen voller Tabelle kann aus mehreren Gründen auftreten:

  • Sie verwenden einen älteren MySQL Server als 3.23 und eine arbeitsspeicherresidente temporäre Tabelle wird größer als tmp_table_size Bytes. Um dies zu verhindern, lassen Sie mysqld mithilfe der Option --tmp_table_size=val die Größe der temporären Tabellen heraufsetzen oder setzen die SQL-Option SQL_BIG_TABLES, bevor Sie die problematische Anfrage absetzen. Siehe Abschnitt 13.5.3, „SET.

    Sie können auch mysqld mit der Option --big-tables starten. Das ist genau dasselbe, als würden Sie SQL_BIG_TABLES für sämtliche Anfragen verwenden.

    Seit MySQL 3.23 sollte dieses Problem erledigt sein. Wenn eine speicherresidente temporäre Tabelle größer als tmp_table_size wird, macht sie der Server automatisch zu einer MyISAM-Tabelle auf der Festplatte.

  • Sie verwenden InnoDB-Tabellen und haben keinen Platz mehr im InnoDB-Tablespace. In diesem Fall müssen Sie den InnoDB-Tablespace vergrößern. Siehe Abschnitt 14.2.7, „Hinzufügen und Entfernen von InnoDB-Daten- und -Logdateien“.

  • Sie verwenden ISAM- oder MyISAM-Tabellen auf einem Betriebssystem, das nur maximal 2 Gbyte große Dateien zulässt, und Ihre Daten- oder Indexdatei übersteigt dieses Limit.

  • Sie benutzen eine MyISAM-Tabelle, die mehr Platz braucht, als die interne Zeigergröße gestattet. Wenn Sie nicht beim Anlegen der Tabelle die Tabellenoption MAX_ROWS gesetzt haben, verwendet MySQL die Systemvariable myisam_data_pointer_size. Deren Standardwert beträgt 6 Byte, genug, um 256-Tbyte- Daten zuzulassen. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“.

    Die Größenlimits für Daten- und Indexdatei prüfen Sie mit folgender Anweisung:

    SHOW TABLE STATUS FROM database LIKE 'tbl_name';
    

    Sie können auch myisamchk -dv /path/to/table-index-file benutzen.

    Ist die Zeigergröße zu klein, können Sie dies mit ALTER TABLE ändern:

    ALTER TABLE tbl_name MAX_ROWS=1000000000 AVG_ROW_LENGTH=nnn;
    

    Den Wert AVG_ROW_LENGTH müssen Sie nur für Tabellen mit BLOB- oder TEXT-Spalten angeben; in diesem Fall kann MySQL den Platzbedarf nicht anhand der Zeilenzahl optimieren.

A.2.12. Can't create/write to file-Fehler

Wenn Sie bei manchen Anfragen den folgenden Fehlertyp ernten, so bedeutet dies, dass MySQL keine temporäre Datei für die Ergebnismenge im temporären Verzeichnis anlegen kann:

Can't create/write to file '\\sqla3fe_0.ism'.

Dieser Fehler ist typisch für Windows; bei Unix sieht die Meldung ähnlich aus.

Eine Möglichkeit ist die, mysqld mit der Option --tmpdir zu starten oder sie in den Abschnitt [mysqld] Ihrer Optionsdatei zu schreiben. Um beispielsweise das Verzeichnis C:\temp vorzugeben, schreiben Sie:

[mysqld]
tmpdir=C:/temp

Das Verzeichnic C:\temp muss existieren und genügend Platz bieten, damit der MySQL Server hineinschreiben kann. Siehe Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

Auch Berechtigungsprobleme können den Fehler verursachen. Achten Sie darauf, dass der MySQL Server in das tmpdir-Verzeichnis schreiben darf.

Schauen Sie auch auf den Fehlercode, den Ihnen perror liefert. Manchmal kann der Server nicht in eine Tabelle schreiben, weil das Dateisystem voll ist:

shell> perror 28
Error code  28:  No space left on device

A.2.13. Command out of sync-Fehler in Client

Wenn Commands out of sync; you can't run this command now in Ihrem Clientcode gemeldet wird, rufen Sie Clientfunktionen in der verkehrten Reihenfolge auf.

Dies kann zum Beispiel geschehen, wenn Sie mysql_use_result() benutzen und versuchen, eine neue Anfrage auszuführen, ehe Sie mysql_free_result() aufgerufen haben. Oder wenn Sie versuchen, zwei Anfragen, die Daten liefern, auszuführen, ohne dazwischen mysql_use_result() oder mysql_store_result() aufzurufen.

A.2.14. User ignored-Fehler

Wenn Sie folgende Fehlermeldung sehen, so bedeutet dies, dass beim Starten von mysqld oder beim Neuladen der Berechtigungstabellen in der user-Tabelle ein Konto mit einem verkehrten Passwort gefunden wurde.

Found wrong password for user 'some_user'@'some_host'; ignoring user

Infolgedessen wird das Konto vom Berechtigungssystem einfach ignoriert.

Die folgende Liste zeigt mögliche Ursachen und Lösungen für dieses Problem auf:

  • Vielleicht führen Sie eine aktuelle mysqld-Version mit einer alten user-Tabelle aus. Führen sie mysqlshow mysql user aus, um zu überprüfen, ob die Password-Spalte kürzer als 16 Zeichen ist. Wenn ja, so können Sie dies mit dem Skript scripts/add_long_password korrigieren.

  • Das Konto hat ein altes Passwort (8 Zeichen lang) und Sie haben mysqld nicht mit der Option --old-protocol gestartet. Dann können Sie entweder das Konto in der user-Tabelle auf ein neues Passwort umstellen oder mysqld mit der Option --old-protocol neu starten.

  • Sie haben in der user-Tabelle ein Passwort angegeben, ohne die PASSWORD()-Funktion zu benutzen. Stellen Sie mit mysql das Konto in der user-Tabelle auf ein neues Passwort um und achten Sie darauf, die Funktion PASSWORD() zu verwenden:

    mysql> UPDATE user SET Password=PASSWORD('newpwd')
        -> WHERE User='some_user' AND Host='some_host';
    

A.2.15. Table 'xxx' doesn't exist-Fehler

Wenn Sie eine der folgenden Fehlermeldungen sehen, so bedeutet dies, dass in der voreingestellten Datenbank keine Tabelle mit dem gegebenen Namen existiert:

Table 'tbl_name' doesn't exist
Can't find file: 'tbl_name' (errno: 2)

In manchen Fällen ist die Tabelle zwar vorhanden, aber Sie sprechen sie nicht richtig an:

  • Da MySQL Datenbanken und Tabellen in Verzeichnissen und Dateien speichert, unterscheiden die Namen der Datenbanken und Tabellen zwischen Groß- und Kleinschreibung, wenn sie in einem Dateisystem vorliegen, das selbst zwischen Groß- und Kleinschreibung unterscheidet.

  • Selbst in Dateisystemen, die nicht zwischen Groß- und Kleinschreibung unterscheiden, wie etwa Windows, muss eine Tabelle in einer Anfrage immer gleich geschrieben werden (entweder groß oder klein).

Der Befehl SHOW TABLES verrät Ihnen, welche Tabellen in Ihrer Datenbank vorliegen. Siehe Abschnitt 13.5.4, „SHOW.

A.2.16. Can't initialize charset xxx-Fehler

Bei Zeichensatzproblemen kann ein Fehler wie dieser auftreten:

MySQL Connection Failed: Can't initialize character set charset_name

Dieser Fehler kann folgende Gründe haben:

  • Der Zeichensatz ist ein Multibytezeichensatz und in Ihrem Client ist keine Unterstützung dafür vorhanden. In diesem Fall müssen Sie den Client neu kompilieren, indem Sie configure mit der Option --with-charset=charset_name oder --with-extra-charsets=charset_name ausführen. Siehe Abschnitt 2.8.2, „Typische configure-Optionen“.

    Alle MySQL-Standardbinaries werden mit der Option --with-extra-character-sets=complex kompiliert, die alle Multibytezeichensätze unterstützt. Siehe Abschnitt 5.11.1, „Der für Daten und zum Sortieren benutzte Zeichensatz“.

  • Der Zeichensatz ist ein einfacher Zeichensatz, der nicht in mysqld kompiliert ist, und seine Definitionsdateien sind nicht dort, wo der Client sie sucht.

    In diesem Fall können Sie Ihr Problem mit einer der folgenden Methoden lösen:

    • Sie rekompilieren den Client mit Unterstützung für den betreffenden Zeichensatz. Siehe Abschnitt 2.8.2, „Typische configure-Optionen“.

    • Sie geben dem Client das Verzeichnis an, in dem er die Definitionsdateien des Zeichensatzes finden kann. Für viele Clients können Sie dies mit der Option --character-sets-dir tun.

    • Sie kopieren die Definitionsdateien des Zeichensatzes in den Pfad, wo der Client sie sucht.

A.2.17. Datei nicht gefunden

Wenn Sie den Fehler ERROR '...' not found (errno: 23), Can't open file: ... (errno: 24) oder einen anderen Fehler mit der errno 23 oder errno 24 von MySQL gemeldet bekommen, haben Sie nicht genügend Dateideskriptoren für den MySQL Server zugewiesen. Das Dienstprogramm perror verrät Ihnen, was welche Fehlernummer bedeutet:

shell> perror 23
Error code  23:  File table overflow
shell> perror 24
Error code  24:  Too many open files
shell> perror 11
Error code  11:  Resource temporarily unavailable

Das Problem hierbei ist, dass mysqld versucht, zu viele Dateien gleichzeitig geöffnet zu halten. Sie können entweder mysqld veranlassen, nicht so viele Dateien zugleich zu öffnen, oder die Anzahl der für mysqld verfügbaren Dateideskriptoren erhöhen.

Damit mysqld weniger Dateien zugleich offen behält, können Sie den Tabellen-Cache verkleinern, indem Sie den Wert der Systemvariablen table_open_cache heruntersetzen (ihr Standardwert ist 64). Wenn Sie die max_connections vermindern, vermindern Sie in einem auch die Anzahl der offenen Dateien (der Standardwert beträgt 100).

Die Anzahl der für mysqld verfügbaren Dateideskriptoren ändern Sie mit der Option --open-files-limit für mysqld_safe, oder Sie setzen (seit MySQL 3.23.30) die Systemvariable open_files_limit. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“. Am einfachsten können Sie diese Werte ändern, indem Sie eine Option in Ihrer Optionsdatei einstellen. Siehe Abschnitt 4.3.2, „my.cnf-Optionsdateien“. Wenn Sie eine ältere Version von mysqld verwenden, in der sich die Höchstzahl der offenen Dateien nicht einstellen lässt, können Sie das Skript mysqld_safe bearbeiten. Dort gibt es eine auskommentierte Zeile mit dem Inhalt ulimit -n 256. Daraus entfernen Sie das Kommentarzeichen ‘#’ und stellen die Zahl 256 auf die Anzahl der gewünschten Dateideskriptoren um, die mysqld zur Verfügung stehen sollen.

--open-files-limit und ulimit können zwar die Anzahl der Dateideskriptoren erhöhen, aber nur bis zu dem Limit, das für Ihr Betriebssystem zulässig ist. Außerdem gibt es ein „hartes“ Limit, das nur überschrieben werden kann, wenn Sie mysqld_safe oder mysqld als root starten (denken Sie aber daran, in diesem Fall den Server mit der --user-Option zu starten, damit er nicht nach dem Hochfahren als root weiterläuft). Wenn Sie das Betriebssystemlimit für die Anzahl der Dateideskriptoren, die für jeden Prozess verfügbar sind, ändern möchten, müssen Sie in Ihre Systemdokumentation schauen.

Hinweis: Wenn Sie die tcsh-Shell ausführen, funktioniert ulimit nicht! Außerdem meldet tcsh verkehrte Werte, wenn Sie nach den aktuellen Limits fragen. In diesem Fall sollten Sie mysqld_safe mit sh starten.

A.3. Installationsbezogene Themen

A.3.1. Probleme beim Linken mit der MySQL-Clientbibliothek

Wenn Sie ein Anwendungsprogramm so verlinken, dass es die MySQL-Clientbibliothek benutzt, werden für Symbole, die mit mysql_ anfangen, undefined reference-Fehler gemeldet werden:

/tmp/ccFKsdPa.o: In function `main':
/tmp/ccFKsdPa.o(.text+0xb): undefined reference to `mysql_init'
/tmp/ccFKsdPa.o(.text+0x31): undefined reference to `mysql_real_connect'
/tmp/ccFKsdPa.o(.text+0x57): undefined reference to `mysql_real_connect'
/tmp/ccFKsdPa.o(.text+0x69): undefined reference to `mysql_error'
/tmp/ccFKsdPa.o(.text+0x9a): undefined reference to `mysql_close'

Um dieses Problem zu lösen, fügen Sie am Ende Ihres Link-Befehls -Ldir_path -lmysqlclient an, wobei dir_path den Pfadnamen des Verzeichnisses darstellt, in dem die Clientbibliothek liegt. Mit folgendem Befehl können Sie das richtige Verzeichnis herausfinden:

shell> mysql_config --libs

Die Ausgabe von mysql_config kann auch auf andere Bibliotheken hinweisen, die ebenfalls im Link-Befehl angegeben werden sollten.

Wenn undefined reference-Fehler für die Funktion uncompress oder compress gemeldet werden, fügen Sie am Ende des Link-Befehls -lz an und versuchen es erneut.

Treten undefined reference-Fehler im Zusammenhang mit einer Funktion auf, die auf Ihrem System existieren müsste, wie beispielsweise connect, sehen Sie auf der Handbuchseite zu dieser Funktion nach, um festzustellen, welche Bibliotheken Sie im Link-Befehl angeben müssen.

Wenn Funktionen auf Ihrem System nicht existieren, werden undefined reference-Fehler wie diese gemeldet:

mf_format.o(.text+0x201): undefined reference to `__lxstat'

Das bedeutet normalerweise, dass Ihre MySQL-Clientbibliothek auf einem System kompiliert wurde, das mit Ihrem nicht zu 100 % kompatibel ist. In diesem Fall sollten Sie die neueste MySQL-Quelldistribution herunterladen und MySQL selbst kompilieren. Siehe Abschnitt 2.8, „Installation der Quelldistribution“.

Zur Laufzeit können undefined reference-Fehler auftreten, wenn Sie versuchen, ein MySQL-Programm auszuführen. Wenn diese Fehler Symbole betreffen, die mit mysql_ anfangen oder anzeigen, dass die mysqlclient-Bibliothek nicht zu finden ist, so bedeutet dies, dass Ihr System die Shared Library libmysqlclient.so nicht finden kann. Dies beheben Sie, indem Sie Ihr System dort, wo sich die Bibliothek befindet, nach Shared Libraries suchen lassen. Aus den folgenden Verfahren können Sie das für Ihr System geeignete auswählen:

  • Sie fügen den Pfad zu dem Verzeichnis, in dem libmysqlclient.so liegt, der Umgebungsvariablen LD_LIBRARY_PATH hinzu.

  • Sie fügen den Pfad zu dem Verzeichnis, in dem libmysqlclient.so liegt, der Umgebungsvariablen LD_LIBRARY hinzu.

  • Sie kopieren libmysqlclient.so in ein Verzeichnis, in dem Ihr System nachschaut, wie beispielsweise /lib, und aktualisieren die Shared Library-Informationen, indem Sie ldconfig ausführen.

Sie können dieses Problem auch angehen, indem Sie Ihr Programm statisch mit der Option -static verlinken oder indem Sie die dynamischen MySQL-Bibliotheken entfernen, bevor Sie Ihren Code verlinken. Ehe Sie die zweite Methode wählen, müssen Sie sich vergewissern, dass keine anderen Programme die dynamischen Bibliotheken benutzen.

A.3.2. Probleme mit Dateirechten

Wenn Sie Probleme mit Dateiberechtigungen haben, ist vielleicht die Umgebungsvariable UMASK beim Starten von mysqld falsch gesetzt. So könnte MySQL beispielsweise folgende Fehlermeldung ausgeben, wenn Sie eine Tabelle anlegen:

ERROR: Can't find file: 'path/with/filename.frm' (Errcode: 13)

Der Standardwert von UMASK ist 0660. Dies können Sie ändern, indem Sie mysqld_safe folgendermaßen starten:

shell> UMASK=384  # = 600 in octal
shell> export UMASK
shell> mysqld_safe &

Nach Voreinstellung legt MySQL Datenbanken und RAID-Verzeichnisse mit dem Zugriffsberechtigungswert 0700 an. Dies können Sie ändern, indem Sie die Variable UMASK_DIR einstellen. Wenn Sie ihren Standardwert ändern, werden neue Verzeichnisse mit einer Kombination der Werte UMASK und UMASK_DIR angelegt. Wenn Sie beispielsweise Gruppenzugriff für alle neuen Verzeichnisse festlegen möchten, gehen Sie folgendermaßen vor:

shell> UMASK_DIR=504  # = 770 in octal
shell> export UMASK_DIR
shell> mysqld_safe &

In der Version 3.23.25 und höher geht MySQL von einem Oktalwert für UMASK und UMASK_DIR aus, wenn der Wert mit einer Null beginnt.

Siehe Anhang F, Umgebungsvariablen.

A.4. Administrationsbezogene Themen

A.4.1. Wie ein vergessenes Kennwort zurückgesetzt wird

Wenn Sie niemals ein root-Passwort für MySQL gesetzt haben, verlangt der Server überhaupt kein Passwort für eine root-Verbindung. Allerdings empfehlen wir Ihnen dringend, für jedes Konto ein Passwort einzurichten. Siehe Abschnitt 5.7.1, „Allgemeine Sicherheitsrichtlinien“.

Wenn Sie ein root-Passwort eingerichtet hatten, aber sich nicht mehr daran erinnern können, müssen Sie es neu einstellen. Die nachfolgende Anleitung ist auf Windows zugeschnitten; eine entsprechende Anleitung für Unix-Systeme finden Sie weiter unten in diesem Abschnitt.

Vorgehen unter Windows:

  1. Sie melden sich als Administrator an.

  2. Sie halten den MySQL Server an, falls er läuft. Läuft er als Windows-Dienst, müssen Sie dazu den Dienstmanager verwenden:

    Start -> Systemsteuerung -> Verwaltung -> Dienste
    

    Suchen Sie in der Dienstliste den MySQL-Dienst und halten Sie ihn an.

    Wenn Ihr Server nicht als Dienst läuft, müssen Sie eventuell den Task-Manager einschalten, um ihn mit Gewalt zu stoppen.

  3. Legen Sie eine Textdatei an und schreiben Sie folgenden Befehl auf einer einzigen Zeile hinein:

    SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPassword');
    

    Speichern Sie die Datei unter einem beliebigen Namen. In diesem Beispiel nennen wir sie C:\mysql-init.txt.

  4. Öffnen Sie ein Konsolenfenster mit der DOS-Eingabeaufforderung:

    Start -> Ausführen -> cmd
    
  5. Wir gehen davon aus, dass Sie MySQL in C:\mysql installiert haben. Wenn nicht, müssen Sie die folgenden Befehle entsprechend abändern.

    Führen Sie an der Eingabeaufforderung folgenden Befehl aus:

    C:\> C:\mysql\bin\mysqld-nt --init-file=C:\mysql-init.txt
    

    Der Inhalt der in der Option --init-file angegebenen Datei wird beim Serverstart ausgeführt, sodass das root-Wort geändert wird. Nachdem der Server hochgefahren ist, sollten Sie C:\mysql-init.txt löschen.

    Wenn Sie MySQL mit dem MySQL Installation Wizard installieren, müssen Sie unter Umständen die Option --defaults-file angeben:

    C:\> "C:\Programme\MySQL\MySQL Server 5.1\bin\mysqld-nt.exe"
             --defaults-file="C:\Program Files\MySQL\MySQL Server 5.1\my.ini"
             --init-file=C:\mysql-init.txt
    

    Die passende Einstellung für --defaults-file finden Sie mithilfe des Dienstmanagers:

    Start -> Systemsteuerung -> Verwaltung -> Dienste
    

    Suchen Sie den MySQL-Dienst, klicken Sie ihn mit rechts an und wählen Sie Eigenschaften. Das Feld Pfad zur EXE-Datei enthält die Einstellung für --defaults-file.

  6. Halten Sie den MySQL Server an und starten Sie ihn dann im Normalmodus neu. Wenn Sie den Server als Dienst betreiben, starten Sie ihn im Dienste-Fenster von Windows; wenn Sie ihn manuell betreiben, starten Sie ihn mit dem Befehl, den Sie auch sonst immer benutzen.

  7. Nun müssten Sie mit dem neuen Passwort eine Verbindung bekommen können.

In einer Unix-Umgebung stellen Sie das root-Passwort folgendermaßen um:

  1. Sie melden sich als Unix- root-User oder als der Benutzer, unter dem der mysqld-Server läuft, an.

  2. Sie suchen die .pid-Datei, welche die Prozess-ID des Servers enthält. Wo sie liegt und wie sie heißt, hängt von Ihrer Distribution, Ihrem Hostnamen und Ihrer Konfiguration ab. Gebräuchliche Speicherorte sind zum Beispiel /var/lib/mysql/, /var/run/mysqld/ und /usr/local/mysql/data/. Im Allgemeinen hat der Dateiname die Erweiterung .pid und fängt entweder mit mysqld oder dem Hostnamen Ihres Systems an.

    Sie können den MySQL Server anhalten, indem Sie einen normalen kill-Befehl (nicht kill -9) an den mysqld-Prozess übermitteln und dabei den Pfadnamen der .pid-Datei angeben:

    shell> kill `cat /mysql-data-directory/host_name.pid`
    

    Beachten Sie, dass wir Backticks anstelle von Anführungszeichen für den cat-Befehl benutzen. Sie sorgen dafür, dass die Ausgabe von cat in den kill-Befehl eingesetzt wird.

  3. Legen Sie eine Textdatei an und schreiben Sie folgenden Befehl auf einer einzigen Zeile hinein:

    SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPassword');
    

    Speichern Sie die Datei unter einem beliebigen Namen. In diesem Beispiel heißt sie ~/mysql-init.

  4. Starten Sie den MySQL Server mit der Spezialoption --init-file=~/mysql-init:

    shell> mysqld_safe --init-file=~/mysql-init &
    

    Der Inhalt der init-Datei wird beim Serverstart ausgeführt und ändert das Root-Passwort. Nachdem der Server hochgefahren ist, sollten Sie ~/mysql-init löschen.

  5. Nun müsste das neue Passwort funktionieren.

Alternativ können Sie das neue Passwort auf jeder Plattform auch mit dem Client mysql einstellen (aber diese Methode ist nicht so sicher):

  1. Halten Sie mysqld an und starten Sie ihn erneut mit den Optionen --skip-grant-tables --user=root (Windows-Nutzer lassen --user=root weg).

  2. Verbinden Sie sich mit folgendem Befehl mit dem mysqld-Server:

    shell> mysql -u root
    
  3. Geben Sie im mysql-Client folgende Anweisungen:

    mysql> UPDATE mysql.user SET Password=PASSWORD('newpwd')
        ->                   WHERE User='root';
    mysql> FLUSH PRIVILEGES;
    

    Ersetzen Sie „newpwd“ durch das root-Passwort, das Sie in Wirklichkeit benutzen möchten.

  4. Das neue Passwort sollte nun funktionieren.

A.4.2. Was zu tun ist, wenn MySQL andauernd abstürzt

Jede MySQL-Version wird vor dem Release auf vielen Plattformen getestet. Dennoch kann es immer noch Bugs in MySQL geben, allerdings ziemlich wenige, die darüber hinaus schwer zu finden sind. Wenn Sie ein Problem haben, ist es immer gut, ganz genau festzustellen, was Ihr System zum Absturz brachte. Dann sind Ihre Chancen auf schnelle Abhilfe viel besser.

Als Erstes müssen Sie herausfinden, ob Ihr mysqld-Server oder Ihr Client an dem Absturz schuld ist. Der Befehl mysqladmin version verrät Ihnen, wie lange Ihr mysqld-Server bereits läuft. Wenn mysqld herunter- und wieder hochgefahren ist, finden Sie die Wurzel des Problems vielleicht im Fehlerlog des Servers. Siehe Abschnitt 5.12.1, „Die Fehler-Logdatei“.

Auf manchen Systemen enthält das Fehlerlog einen Stack-Trace mit der Information, wo mysqld abgestürzt ist. Diesen Trace können Sie mit dem Programm resolve_stack_dump auswerten. Siehe Abschnitt E.1.4, „Einen Stack-Trace benutzen“. Beachten Sie, dass die Variablenwerte im Fehlerlog nicht immer hundertprozentig korrekt sind.

Viele Serverabstürze werden durch beschädigte Daten- oder Indexdateien verursacht. MySQL aktualisiert nach jeder SQL-Anweisung und vor der Benachrichtigung des Clients über das Ergebnis die Dateien auf der Festplatte mit dem Systemaufruf write(). (Das gilt allerdings nicht, wenn Sie mit der Option --delay-key-write arbeiten: Hier werden zwar die Datendateien zeitnah geschrieben, aber nicht die Indexdateien.) Das bedeutet, dass der Inhalt der Datendateien selbst bei einem mysqld-Absturz sicher ist, weil das Betriebssystem dafür sorgt, dass die Arbeitsspeicherdaten auf die Platte zurückgeschrieben werden. Sie können MySQL zwingen, nach jeder SQL-Anweisung gleich alles auf die Platte zurückzuschreiben, indem Sie mysqld mit der Option --flush starten.

Das bedeutet, dass Sie normalerweise nur in folgenden Fällen mit beschädigten Tabellen zu tun haben:

  • Wenn der MySQL Server oder der Serverhost mitten in einem Update abgestürzt ist.

  • Wenn Sie einen Bug in mysqld gefunden haben, der den Prozess mitten in einem Update anhielt.

  • Wenn ein externes Programm Daten- oder Indexdateien zur gleichen Zeit wie mysqld ändert, ohne die Tabelle ordentlich zu sperren.

  • Wenn Sie viele mysqld-Server zugleich mit demselben Data Directory auf einem System betreiben, das keine vernünftigen Dateisystemsperren kennt (diese werden normalerweise von dem Sperrenmanager lockd verwaltet), oder wenn Sie mehrere Server bei ausgeschaltetem externem Locking laufen lassen.

  • Wenn Sie eine abgestürzte Daten- oder Indexdatei mit völlig kaputten Daten haben, die mysqld in Verwirrung stürzt.

  • Wenn Sie einen Fehler im Code der Datenspeicherung gefunden haben. Das ist zwar unwahrscheinlich, aber nicht unmöglich. In diesem Fall können Sie versuchen, die Speicher-Engine auf eine andere Engine umzustellen, indem Sie ALTER TABLE auf einer reparierten Kopie der Tabelle ausführen.

Da der Grund für einen Absturz so schwer festzustellen ist, sollten Sie zuerst versuchen, herauszufinden, ob Dinge, die bei anderen funktionieren, bei Ihnen abstürzen. Hierzu sollten Sie Folgendes ausprobieren:

  • Halten Sie den mysqld-Server mit mysqladmin shutdown an, führen Sie im Data Directory myisamchk --silent --force */*.MYI aus, um alle MyISAM-Tabellen zu prüfen, und starten Sie mysqld erneut. Dann ist gewährleistet, dass der Server in einem sauberen Zustand läuft. Siehe Kapitel 5, Datenbankverwaltung.

  • Starten Sie mysqld mit der Option --log und versuchen Sie, an den Logdaten zu erkennen, ob eine spezifische Anfrage den Server abstürzen lässt. Rund 95 % aller Fehler hängen mit einer konkreten Anfrage zusammen. Normalerweise ist dies eine der letzten Anfragen, die in der Logdatei kurz vor dem Neustart des Servers protokolliert sind. Siehe auch Abschnitt 5.12.2, „Die allgemeine Anfragen-Logdatei“. Wenn Sie MySQL mit einer bestimmten Anfrage wiederholt zum Absturz bringen können, obwohl Sie alle Tabellen kurz vorher überprüft haben, dann haben Sie den Fehler gefunden und sollten einen Bugreport übermitteln. Siehe hierzu Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

  • Versuchen Sie, einen Testfall einzurichten, den wir verwenden können, um den Fehler zu reproduzieren. Siehe Abschnitt E.1.6, „Erzeugen eines Testfalls, wenn Sie Tabellenbeschädigung feststellen“.

  • Versuchen Sie, die Tests im Verzeichnis mysql-test und die MySQL-Benchmarks auszuführen. Siehe Abschnitt 26.1.2, „MySQL-Testsystem“. Damit sollte MySQL ziemlich gut getestet sein. Sie können den Benchmarks auch Code hinzufügen, der Ihre Anwendung simuliert. Die Benchmarks finden Sie im Verzeichnis sql-bench einer Quelldistribution oder im Verzeichnis sql-bench unterhalb des MySQL-Installationsverzeichnisses in einer Binärdistribution.

  • Probieren Sie es mit dem Skript fork_big.pl. (Dieses finden Sie im Verzeichnis tests der Quelldistributionen.)

  • Wenn Sie MySQL für das Debugging konfigurieren, lassen sich Informationen über mögliche Fehler viel leichter beschaffen. In der Debuggingkonfiguration ist eine Arbeitsspeicherzuweisung enthalten, die so manchem Fehler auf die Spur kommt. Außerdem liefert diese Konfiguration viele Ausgabedaten über alles, was vor sich geht. Rekonfigurieren Sie also MySQL mit der Option --with-debug oder --with-debug=full für configure und kompilieren Sie dann neu. Siehe auch Abschnitt E.1, „Einen MySQL-Server debuggen“.

  • Installieren Sie immer die neuesten Patches für Ihr Betriebssystem.

  • Stellen Sie die Option --skip-external-locking für mysqld ein. Auf manchen Systemen funktioniert der Sperrenmanager lockd nicht richtig. Die Option --skip-external-locking hält mysqld davon ab, externes Locking zu benutzen. (Das bedeutet, dass Sie nicht zwei mysqld-Server mit demselben Data Directory betreiben können und dass Sie mit myisamchk aufpassen müssen. Aber immerhin kann es sehr aufschlussreich sein, die Option einmal auszuprobieren.)

  • Haben Sie es schon mit mysqladmin -u root processlist versucht, wenn mysqld scheinbar läuft, aber nicht antwortet? Manchmal ist mysqld gar nicht ins Koma gefallen, auch wenn es den Anschein hat. Vielleicht sind alle Verbindungen belegt oder es gibt ein Problem mit internen Sperren. Normalerweise kann mysqladmin -u root processlist selbst in solchen Fällen eine Verbindung einrichten und Aufschluss über die Anzahl und den Status der laufenden Verbindungen geben.

  • Führen Sie in einem separaten Fenster den Befehl mysqladmin -i 5 status oder mysqladmin -i 5 -r status aus, um Statistiken zu erstellen, während sie andere Anfragen ausführen.

  • Versuchen Sie Folgendes:

    1. Starten Sie mysqld von gdb (oder einem anderen Debugger) aus. Siehe auch Abschnitt E.1.3, „mysqld unter gdb debuggen“.

    2. Lassen Sie Ihre Testskripten laufen.

    3. Geben Sie den Backtrace und die lokalen Variablen auf den drei untersten Ebenen aus. In gdb tun Sie dies mit den folgenden Befehlen, wenn mysqld innerhalb von gdb abgestürzt ist:

      backtrace
      info local
      up
      info local
      up
      info local
      

      In gdb können Sie auch mit info threads herausfinden, welche Threads vorhanden sind, und mit thread N auf einen bestimmten Thread umschalten, wobei N die Thread-ID ist.

  • Versuchen Sie, Ihre Anwendung mit einem Perl-Skript zu simulieren, um MySQL zu einem Absturz oder Fehlverhalten zu veranlassen.

  • Senden Sie einen normalen Bugreport. Siehe Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“. Machen Sie noch detailliertere Angaben als üblich. Da MySQL bei den meisten Nutzern funktioniert, kann es sein, dass der Crash durch Umstände verursacht wird, die nur auf Ihrem Compter existieren (zum Beispiel im Zusammenhang mit Ihren Systembibliotheken).

  • Wenn Sie Schwierigkeiten mit Tabellen haben, die Datenzeilen mit variabler Länge speichern und nur VARCHAR-, aber keine BLOB- oder TEXT-Spalten benutzen, können Sie mit ALTER TABLE ausprobieren, alle VARCHAR- in CHAR-Spalten zu ändern. Damit zwingen Sie MySQL, Zeilen mit fester Länge zu verwenden, die zwar ein bisschen mehr Platz belegen, aber weniger anfällig für Beschädigungen sind.

    Der jetzige Code für dynamische Zeilen, den MySQL AB schon seit Jahren verwendet, macht nur minimale Probleme, aber Zeilen dynamischer Länge sind von Natur aus fehleranfälliger. Daher sollten Sie bei Problemen folgende Strategie versuchen:

  • Beziehen Sie auch Ihre Serverhardware als mögliche Fehlerursache ein. Auch Hardwaredefekte können Datenkorruption verursachen. Achten Sie bei der Hardware besonders auf RAMs und Festplattenlaufwerke.

A.4.3. Wie MySQL mit vollen Festplatten umgeht

Dieser Abschnitt beschreibt, wie MySQL mit Fehlern umgeht, die aufgrund einer vollen Festplatte auftreten (wie beispielsweise „no space left on device“), und wie Fehler aufgrund von Kontingentüberschreitung behandelt werden (wie zum Beispiel „write failed“ oder „user block limit reached“).

Dieser Abschnitt ist für Schreiboperationen auf MyISAM-Tabellen relevant. Er gilt jedoch auch für Schreiboperationen in Binärlogdateien und die Binärlog-Indexdatei, nur dass die Begriffe „row“ und „record“ im Zusammenhang mit Logs „Ereignisse“ bedeuten.

Wenn ein Fehler wegen voller Festplatte auftritt, geht MySQL wie folgt vor:

  • Es prüft einmal pro Minute, ob genug Platz vorhanden ist, um die aktuelle Zeile zu schreiben. Wenn dies der Fall ist, macht es weiter, als sei nichts geschehen.

  • Alle 10 Minuten schreibt es in die Logdatei eine Warnung, dass die Festplatte voll ist.

Dieses Problem können Sie folgendermaßen beheben:

  • Um weiterarbeiten zu können, müssen Sie lediglich genug Platz auf der Platte schaffen, um alle Datensätze zu schreiben.

  • Um den Thread anzuhalten, sagen Sie mysqladmin kill. Dann wird der Thread das nächste Mal, wenn er die Platte überprüft (also in einer Minute), gestoppt.

  • Eventuell warten andere Threads auf die Tabelle, welche die Fehlerbedingung disk-full verursacht hat. Wenn Sie mehrere „gesperrte“ Threads haben, können nach Abbruch des einen Threads, der wegen der disk-full-Bedingung wartet, die anderen Threads weiterlaufen.

Das oben geschilderte Verhalten tritt nicht ein, wenn Sie REPAIR TABLE oder OPTIMIZE TABLE gesagt haben oder wenn die Indizes nach LOAD DATA INFILE oder nach einer ALTER TABLE-Anweisung in Stapelverarbeitung erstellt werden. Alle diese Anweisungen können große temporäre Dateien erzeugen, die den Rest des Systems in Schwierigkeiten bringen, wenn sie sich selbst überlassen bleiben. Wenn die Platte voll läuft, während MySQL eine dieser Operationen ausführt, löscht MySQL eine der großen temporären Dateien und kennzeichnet die Tabelle als abgestürzt. Ausnahme: Bei ALTER TABLE bleibt die alte Tabelle unverändert.

A.4.4. Wohin MySQL temporäre Dateien speichert

MySQL verwendet den Wert der Umgebungsvariablen TMPDIR als Pfad zu dem Verzeichnis, in dem die temporären Dateien gespeichert werden. Wenn Sie TMPDIR nicht eingestellt haben, benutzt MySQL den systemeigenen Standardwert, also normalerweise /tmp, /var/tmp oder /usr/tmp. Wenn das Dateisystem, in dem Ihr Verzeichnis für temporäre Dateien liegt, zu klein ist, können Sie mit der Option --tmpdir von mysqld ein anderes Verzeichnis in einem ausreichend großen Dateisystem einstellen.

In MySQL 5.1 kann die Option --tmpdir auf eine Liste mit mehreren Pfaden eingestellt werden, die dann im Ringverfahren (jeder kommt einmal dran) benutzt werden. Die Pfade sollten auf Unix durch Doppelpunkte (‘:’) getrennt werden, und auf Windows, NetWare und OS/2 durch Semikola (‘;’). Hinweis: Um die Last wirkungsvoll zu verteilen, sollten diese Pfade zu verschiedenen physikalischen Platten und nicht nur zu verschiedenen Partitionen derselben Festplatte führen.

Wenn der MySQL Server ein Replikationsslave ist, sollten Sie die Option --tmpdir nicht auf ein Verzeichnis in einem arbeitsspeicherbasierten Dateisystem oder auf ein anderes Verzeichnis einstellen, das beim Neustart des Serverhosts gelöscht wird. Ein Replikationsslave benötigt einige seiner temporären Dateien, um einen Neustart des Computers so zu überleben, dass er temporäre Tabellen oder LOAD DATA INFILE-Operationen replizieren kann. Wenn Dateien aus dem temporären Verzeichnis beim Neustart des Servers verloren gehen, scheitert die Replikation.

MySQL legt alle temporären Dateien als verborgene Dateien an. Das soll gewährleisten, dass die temporären Dateien beim Herunterfahren von mysqld entfernt werden. Allerdings haben verborgene Dateien den Nachteil, dass eine große temporäre Datei, die das Dateisystem überlastet, in welchem das temporäre Verzeichnis liegt, nicht zu sehen ist.

Bei Sortieroperationen (ORDER BY oder GROUP BY) verwendet MySQL normalerweise ein oder zwei temporäre Dateien. Wie viel Platz auf der Festplatte dafür maximal notwendig ist, verrät Ihnen der folgende Ausdruck:

(Länge der Daten + sizeof(Zeilenzeiger))
* Anzahl der gefundenen Zeilen
* 2

Der Zeilenzeiger ist normalerweise 4 Byte groß, kann aber bei sehr großen Tabellen in Zukunft noch wachsen.

Für manche SELECT-Anfragen legt MySQL ebenfalls temporäre SQL-Tabellen an. Diese sind nicht verborgen und haben Namen der Form SQL_*.

ALTER TABLE legt eine temporäre Tabelle in dem Verzeichnis der Originaltabelle an.

A.4.5. Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern

Die Unix-Socketdatei, die der Server für die Kommunikation mit lokalen Clients benötigt, liegt nach Voreinstellung unter /tmp/mysql.sock. (In manchen Distributionsformaten kann es auch ein anderes Verzeichnis sein, wie beispielsweise /var/lib/mysql für RPMs.)

Auf manchen Unix-Versionen kann jeder Dateien aus dem Verzeichnis /tmp oder anderen ähnlichen Verzeichnissen für temporäre Dateien löschen. Wenn die Socketdatei auf Ihrem Dateisystem in einem solchen Verzeichnis liegt, kann das zu Problemen führen.

Auf den meisten Unix-Versionen können Sie Ihr /tmp-Verzeichnis schützen, sodass die Dateien nur von ihren Eigentümern oder dem Superuser (root) gelöscht werden können. Hierzu setzen Sie das sticky-Bit auf dem /tmp-Verzeichnis, indem Sie sich als root anmelden und folgenden Befehl geben:

shell> chmod +t /tmp

Ob das sticky-Bit gesetzt wurde, prüfen Sie mit ls -ld /tmp. Wenn das letzte Zeichen der Berechtigung ein t ist, wurde das Bit gesetzt.

Sie können auch veranlassen, dass der Server die Unix-Socketdatei in einem anderen Verzeichnis erstellt. Wenn Sie dies tun, müssen Sie den Clientprogrammen auch verraten, wo diese Datei jetzt liegt. Den Speicherort können Sie auf mehrere Weisen angeben:

  • Sie geben den Pfad in einer globalen oder lokalen Optionsdatei an, zum Beispiel indem Sie folgende Zeilen in /etc/my.cnf speichern:

    [mysqld]
    socket=/path/to/socket
    
    [client]
    socket=/path/to/socket
    

    Siehe Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

  • Sie geben auf der Kommandozeile für mysqld_safe und beim Ausführen von Clientprogrammen eine --socket-Option an.

  • Sie stellen die Umgebungsvariable MYSQL_UNIX_PORT auf den Pfad zur Unix-Socketdatei ein.

  • Sie rekompilieren MySQL aus den Quelldateien so, dass ein anderer Standardspeicherort für die Unix-Socketdatei festgelegt wird. Den Dateipfad definieren Sie mit der Option --with-unix-socket-path, wenn Sie configure ausführen. Siehe auch Abschnitt 2.8.2, „Typische configure-Optionen“.

Ob der neue Socketspeicherort funktioniert, können Sie überprüfen, indem Sie mit folgendem Befehl eine Serververbindung herstellen:

shell> mysqladmin --socket=/path/to/socket version

A.4.6. Probleme mit Zeitzonen

Wenn Sie das Problem haben, dass SELECT NOW() Werte in UTC anstelle Ihrer Ortszeit liefert, müssen Sie Ihren Server auf Ihre Zeitzone einstellen. Dasselbe gilt, wenn UNIX_TIMESTAMP() den verkehrten Wert zurückgibt. Dies sollte für die Umgebung veranlasst werden, in welcher der Server läuft, also zum Beispiel in mysqld_safe oder mysql.server. Siehe Anhang F, Umgebungsvariablen.

Die Zeitzone für den Server stellen Sie mit der Option --timezone=timezone_name von mysqld_safe ein. Alternativ können Sie die Umgebungsvariable TZ einstellen, bevor Sie mysqld starten.

Die zulässigen Werte für --timezone oder TZ hängen vom System ab. Bitte schlagen Sie in der Dokumentation Ihres Betriebssystems die jeweils passenden Werte nach.

A.5. Anfragenbezogene Themen

A.5.1. Groß-/Kleinschreibung beim Suchen

Nach Voreinstellung unterscheiden Suchoperationen in MySQL nicht zwischen Groß- und Kleinschreibung (wobei allerdings manche Zeichensätze grundsätzlich immer zwischen Groß- und Kleinschreibung unterscheiden, wie beispielsweise czech). Das bedeutet, dass Sie bei einer Suche mit col_name LIKE 'a%' alle Spaltenwerte geliefert bekommen, die mit A oder a anfangen. Wenn Sie diese Suche auf Groß- oder Kleinbuchstaben einschränken möchten, müssen Sie dafür sorgen, dass die Kollation eines der beiden Operanden Groß- und Kleinschreibung unterscheidet oder eine Binärkollation ist. Wenn Sie beispielsweise eine Spalte und einen String vergleichen, die beide den Zeichensatz latin1 verwenden, können Sie den COLLATE-Operator einschalten, um einem der beiden Operanden die Kollation latin1_general_cs oder latin1_bin zuzuweisen. Zum Beispiel:

col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin

Wenn Sie in einer Spalte immer die Groß- und Kleinschreibung berücksichtigen möchten, deklarieren Sie sie mit einer Binärkollation oder CS-Kollation (CS steht für die Unterscheidung von Groß- und Kleinschreibung). Siehe Abschnitt 13.1.5, „CREATE TABLE.

Einfache Vergleichsoperationen (>=, >, =, <, <=, Sortieren und Gruppieren) beruhen auf dem „Sortierwert“ der Zeichen. Zeichen mit demselben Sortierwert (wie etwa ‘E’, ‘e’ und ‘é’) werden als gleich betrachtet.

A.5.2. Probleme bei der Benutzung von DATE-Spalten

Das Format eines DATE-Werts ist 'YYYY-MM-DD'. Im Standard-SQL ist kein anderes Format erlaubt. Dieses Format muss in UPDATE-Ausdrücken und in der WHERE-Klausel von SELECT-Anweisungen immer verwendet werden. Zum Beispiel:

mysql> SELECT * FROM tbl_name WHERE date >= '2003-05-05';

Der Bequemlichkeit halber konvertiert MySQL ein Datum, das in einem numerischen Kontext benutzt wird, automatisch in eine Zahl (und umgekehrt). MySQL ist auch clever genug, um bei Updates und in einer WHERE-Klausel, die ein Datum mit einer TIMESTAMP-, DATE- oder DATETIME-Spalte vergleicht, eine „lockere“-String-Form zuzulassen. („Lockere Form“ bedeutet, dass zwischen den einzelnen Teilen jedes Interpunktionszeichen als Trennzeichen zulässig ist. So sind zum Beispiel '2004-08-15' und '2004#08#15' äquivalent.) MySQL kann auch einen String, der keine Trennzeichen enthält (wie etwa '20040815') konvertieren, vorausgesetzt, er ergibt einen vernünftigen Datumswert.

Wenn Sie Werte vom Typ DATE, TIME, DATETIME oder TIMESTAMP mit einem konstanten String vergleichen, der die Operatoren <, <=, =, >=, > oder BETWEEN enthält, konvertiert MySQL den String normalerweise intern in einen langen Integer, um Vergleiche schneller ausführen zu können (und ein wenig „locker“ bei der String-Prüfung sein zu können). Von dieser Konvertierung gibt es allerdings folgende Ausnahmen:

  • wenn Sie zwei Spalten vergleichen

  • wenn Sie eine DATE-, TIME-, DATETIME- oder TIMESTAMP-Spalte mit einem Ausdruck vergleichen

  • wenn Sie eine andere Vergleichsmethode als die oben aufgeführten verwenden, wie etwa IN oder STRCMP()

In diesen Ausnahmefällen führt MySQL den Vergleich durch, indem es die Objekte in Strings konvertiert und dann die Strings vergleicht.

Um sicherzugehen, sollten Sie davon ausgehen, dass Strings als Strings verglichen werden, und die passenden Funktionen einsetzen, wenn Sie einen Temporalwert mit einem String vergleichen möchten.

Das spezielle Datum '0000-00-00' kann als '0000-00-00' gespeichert und abgerufen werden. Wenn Sie ein '0000-00-00'-Datum in MyODBC benutzen, so wird es in MyODBC 2.50.12 und höher automatisch in NULL konvertiert, da ODBC mit Datumswerten dieser Art nicht umgehen kann.

Da MySQL die oben beschriebenen Konvertierungen vornimmt, funktionieren folgende Anweisungen:

mysql> INSERT INTO tbl_name (idate) VALUES (19970505);
mysql> INSERT INTO tbl_name (idate) VALUES ('19970505');
mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00');

mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT MOD(idate,100) FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';

Doch die folgende Anweisung funktioniert nicht:

mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'20030505')=0;

Da STRCMP() eine String-Funktion ist, konvertiert sie idate in einen String im Format 'YYYY-MM-DD' und führt einen String-Vergleich durch. '20030505' wird nicht in das Datum '2003-05-05' konvertiert, um einen Datumsvergleich durchzuführen.

Wenn Sie den SQL-Modus ALLOW_INVALID_DATES eingestellt haben, gestattet MySQL Ihnen die Speicherung von Datumswerten bei nur rudimentärer Überprüfung: MySQL verlangt lediglich, dass der Tag im Bereich von 1 bis 31 und der Monat im Bereich von 1 bis 12 liegt.

Dadurch eignet sich MySQL gut für Webanwendungen, bei denen Jahr, Monat und Tag in drei verschiedenen Feldern abgerufen werden und in denen Sie genau das, was der Benutzer eingibt, speichern möchten (ohne das Datum zu validieren).

Wenn Sie nicht den SQL-Modus NO_ZERO_IN_DATE SQL verwenden, kann der Tag oder der Monat null sein. Das ist praktisch, wenn Sie in einer DATE-Spalte einen Geburtstag speichern möchten, dessen Datum Sie nur teilweise kennen.

Wenn Sie nicht den SQL-Modus NO_ZERO_DATE verwenden, gestattet Ihnen MySQL auch, '0000-00-00' als „Dummy-Datum“ zu speichern. Das ist manchmal praktischer als NULL-Werte.

Wenn sich das Datum nicht in einen vernünftigen Wert konvertieren lässt, wird eine 0 in der DATE-Spalte gespeichert und als '0000-00-00' abgerufen. Dies ist eine Frage von Schnelligkeit und Bequemlichkeit. Wir sind der Ansicht, dass der Datenbankserver dieselben Daten liefern sollte, die gespeichert wurden (selbst wenn diese Daten im Einzelfall nicht immer logisch richtig sind). Wir denken, dass es Sache der Anwendung ist, die Datumswerte zu überprüfen.

Wenn Sie wollen, dass MySQL die Daten überprüft und nur gültige zulässt (es sei denn, dies wird durch IGNORE außer Kraft gesetzt), müssen Sie den sql_mode auf "NO_ZERO_IN_DATE,NO_ZERO_DATE" einstellen.

A.5.3. Probleme mit NULL-Werten

NULL-Werte stiften bei SQL-Neulingen immer wieder Verwirrung, da diese oft denken, NULL sei dasselbe wie der leere String ''. Doch das ist nicht der Fall. Die folgenden Anweisungen sind beispielsweise völlig verschieden:

mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ('');

Beide Anweisungen fügen einen Wert in die phone-Spalte ein, die erste allerdings einen NULL-Wert und die zweite einen leeren String. Die erste Eingabe bedeutet so viel wie „Telefonnummer unbekannt“ und die zweite bedeutet „Die Person hat kein Telefon und somit keine Telefonnummer“.

Als Hilfe für den Umgang mit NULL-Werten sind die Operatoren IS NULL und IS NOT NULL sowie die Funktion IFNULL() da.

In SQL ergibt ein Vergleich zwischen NULL und irgendeinem anderen Wert nie einen Treffer, selbst wenn auch der andere Wert NULL ist. Ein Ausdruck, der NULL enthält, ergibt immer den Wert NULL, es sei denn, die Dokumentation der Operatoren und Funktionen, die an dem Ausdruck beteiligt sind, sagt ausdrücklich etwas anderes. Alle Spalten im folgenden Beispiel geben NULL zurück:

mysql> SELECT NULL, 1+NULL, CONCAT('Invisible',NULL);

Wenn Sie Spaltenwerte suchen, die NULL sind, verwenden Sie bitte nicht den Test expr = NULL. Die folgende Anweisung gibt gar keine Zeilen zurück, da expr = NULL niemals wahr sein kann:

mysql> SELECT * FROM my_table WHERE phone = NULL;

Wenn Sie NULL-Werte suchen, dann mit IS NULL. Die folgenden Anweisungen zeigen, wie man die Telefonnummer NULL und die leere Telefonnummer finden kann:

mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = '';

Weitere Informationen und Beispiele finden Sie unter Abschnitt 3.3.4.6, „Mit NULL-Werten arbeiten“.

Sie können einer Spalte, die NULL-Werte enthält, einen Index hinzufügen, wenn Sie MyISAM, InnoDB, BDB oder MEMORY als Speicher-Engine einsetzen. Andernfalls müssen Sie die indizierte Spalte als NOT NULL deklarieren und können keine NULL-Werte in sie einfügen.

Wenn Sie Daten mit LOAD DATA INFILE lesen, werden leere oder fehlende Spalten mit '' aktualisiert. Möchten Sie in eine Spalte einen NULL-Wert einfügen, so müssen Sie \N in die Datendatei schreiben. Das Literal „NULL“ kann unter bestimmten Umständen ebenfalls verwendet werden. Siehe Abschnitt 13.2.5, „LOAD DATA INFILE.

DISTINCT, GROUP BY oder ORDER BY betrachten alle NULL-Werte als gleich.

ORDER BY stellt die NULL-Werte immer an den Anfang oder, wenn DESC für eine absteigende Sortierreihenfolge angegeben wurde, an das Ende.

Aggregatfunktionen (Summenfunktionen) wie COUNT(), MIN() und SUM() ignorieren NULL-Werte. Eine Ausnahme bildet die Funktion COUNT(*), die Zeilen und nicht einzelne Spaltenwerte zählt. Die folgende Anweisung erstellt beispielsweise zwei Zählungen: eine Zählung der Zeilen in der Tabelle und eine Zählung der von NULL verschiedenen Werte in der Spalte age:

mysql> SELECT COUNT(*), COUNT(age) FROM person;

Für manche Datentypen behandelt MySQL NULL-Werte ganz speziell. Wenn Sie NULL in eine TIMESTAMP-Spalte einfügen, werden Datum und Uhrzeit von jetzt eingefügt. Wenn Sie NULL in eine Integer-Spalte einfügen, die das AUTO_INCREMENT-Attribut hat, wird stattdessen die nächste Folgenummer eingesetzt.

A.5.4. Probleme mit alias

Einen Alias können Sie verwenden, um eine Spalte in GROUP BY-, ORDER BY- oder HAVING-Klauseln zu benennen. Außerdem sind Aliasnamen nützlich, um Spalten bessere Namen zu verpassen:

SELECT SQRT(a*b) AS root FROM tbl_name GROUP BY root HAVING root > 0;
SELECT id, COUNT(*) AS cnt FROM tbl_name GROUP BY id HAVING cnt > 0;
SELECT id AS 'Customer identity' FROM tbl_name;

Im Standard-SQL dürfen Sie in WHERE-Klauseln keine Spaltenaliase benutzen, da der Spaltenwert unter Umständen noch gar nicht festliegt, wenn der WHERE-Code ausgeführt wird. Die folgende Anfrage ist beispielsweise unzulässig:

SELECT id, COUNT(*) AS cnt FROM tbl_name WHERE cnt > 0 GROUP BY id;

Die WHERE-Anweisung soll festlegen, welche Zeilen in den GROUP BY-Teil einfließen, während die HAVING-Klausel entscheiden soll, welche Zeilen der Ergebnismenge benutzt werden sollen.

A.5.5. Rollback schlägt bei nichttransaktionssicheren Tabellen fehl

Wenn Sie die folgende Meldung beim Versuch eines ROLLBACK erhalten, so bedeutet dies, dass mindestens eine in der Transaktion verwendete Tabelle gar keine Transaktionen unterstützt:

Änderungen an einigen nicht transaktionalen Tabellen konnten nicht zurückgerollt werden

Diese nichttransaktionssicheren Tabellen werden von der ROLLBACK-Anweisung gar nicht betroffen.

Wenn Sie nicht absichtlich transaktionssichere und nichttransaktionssichere Tabellen in der Transaktion mischen, tritt diese Fehlermeldung wahrscheinlich auf, weil eine Tabelle, die Sie für transaktionssicher gehalten haben, dies in Wirklichkeit nicht ist. Das kann passieren, wenn Sie eine Tabelle mit einer transaktionssicheren Speicher-Engine anlegen, die nicht von Ihrem mysqld-Server unterstützt wird (oder mit einer Startoption ausgeschaltet wurde). Wenn mysqld eine Speicher-Engine nicht unterstützt, wird eine MyISAM-Tabelle angelegt, und diese ist nicht transaktionssicher.

Welche Speicher Engine eine Tabelle verwendet, erfahren Sie mit folgenden Anweisungen:

SHOW TABLE STATUS LIKE 'tbl_name';
SHOW CREATE TABLE tbl_name;

Siehe Abschnitt 13.5.4.21, „SHOW TABLE STATUS, und Abschnitt 13.5.4.6, „SHOW CREATE TABLE.

Welche Speicher-Engines Ihr mysqld-Server verwendet, finden Sie mit dieser Anweisung heraus:

SHOW ENGINES;

Sie können jedoch auch nachfolgende Anweisung ausführen und den Wert der Variablen betrachten, die für die von Ihnen gewünschte Speicher-Engine steht:

SHOW VARIABLES LIKE 'have_%';

Um beispielsweise festzustellen, ob die Speicher-Engine InnoDB zur Verfügung steht, schauen Sie auf den Wert der Variablen have_innodb.

Siehe Abschnitt 13.5.4.9, „SHOW ENGINES, und Abschnitt 13.5.4.24, „SHOW VARIABLES.

A.5.6. Zeilen aus verwandten Tabellen löschen

Wenn die DELETE-Anweisung für related_table insgesamt mehr als 1 Mbyte beträgt (der Standardwert der Systemvariablen max_allowed_packet), dann müssen Sie sie aufteilen und als mehrere kleinere DELETE-Anweisungen ausführen. Am schnellsten läuft ein DELETE, wenn Sie nur 100 bis 1.000 related_column-Werte pro (indizierter) Anweisung angeben. Wenn related_column keinen Index hat, ist die Geschwindigkeit von der Anzahl der Argumente der IN-Klausel unabhängig.

A.5.7. Lösung von Problemen mit nicht übereinstimmenden Zeilen

Wenn Sie eine komplizierte Anfrage ausführen, die viele Tabellen benutzt, aber nichts zurückgibt, können Sie mit folgendem Verfahren herausfinden, was schief gegangen ist:

  1. Testen Sie die Anfrage mit EXPLAIN, um offensichtliche Fehler zu finden. Siehe Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“.

  2. Wählen Sie nur diejenigen Spalten aus, die in der WHERE-Klausel aufgeführt sind.

  3. Entfernen Sie immer nur eine einzige Tabelle aus der Anfrage so lange, bis sie irgendwelche Zeilen zurückgibt. Wenn die Tabellen groß sind, sollten Sie in Ihrer Anfrage LIMIT 10 verwenden.

  4. Geben Sie eine SELECT-Anweisung für die Spalte der zuletzt aus der Anfrage entfernten Tabelle, die eigentlich eine passende Zeile hätte enthalten müssen.

  5. Wenn Sie FLOAT- oder DOUBLE-Spalten mit Dezimalzahlen vergleichen, können Sie keine Gleichheitsvergleiche (=) durchführen. Dieses Problem tritt in allen Programmiersprachen auf, da nicht alle Fließkommawerte mit einer exakten Genauigkeit gespeichert werden können. In manchen Fällen können Sie dies beheben, indem Sie aus einem FLOAT- einen DOUBLE-Wert machen. Siehe Abschnitt A.5.8, „Probleme mit Fließkommavergleichen“.

  6. Wenn Sie den Fehler immer noch nicht finden können, legen Sie einen minimalen Testfall an, der mit mysql test < query.sql ausgeführt werden kann und Ihre Probleme verdeutlicht. Eine Testdatei legen Sie an, indem Sie die Tabellen mit mysqldump --quick db_name tbl_name_1 ... tbl_name_n > query.sql kopieren. Öffnen Sie die Datei in einem Editor, entfernen Sie einige eingefügte Zeilen (wenn mehr da sind, als zur Verdeutlichung des Problems notwendig ist) und fügen Sie am Ende der Datei Ihre SELECT-Anweisung an.

    Mit folgenden Befehlen können Sie sich vergewissern, dass Ihre Testdatei das Problem zeigt:

    shell> mysqladmin create test2
    shell> mysql test2 < query.sql
    

    Hängen Sie die Testdatei an einen Bugreport an. Diesen können Sie uns senden, wie in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“, beschrieben.

A.5.8. Probleme mit Fließkommavergleichen

Der folgende Abschnitt ist vor allem für DOUBLE- und FLOAT-Spalten interessant, da Fließkommazahlen von Natur aus ungenau sind. MySQL führt DECIMAL-Operationen mit einer Genauigkeit von 64 Dezimalstellen aus. Das müsste die meisten Probleme im Hinblick auf die Genauigkeit von DECIMAL-Spalten lösen.

Fließkommazahlen stiften gelegentlich Verwirrung, da sie in einer Computerarchitektur nicht als exakte Werte gespeichert werden. Das, was der Bildschirm zeigt, ist in der Regel nicht der genaue Wert der Zahl. Die Datentypen FLOAT und DOUBLE sind Fließkommatypen. DECIMAL-Spalten speichern Werte mit einer exakten Anzahl Stellen, weil sie als Strings dargestellt werden.

Das folgende Beispiel verdeutlicht das Problem an einem DOUBLE:

mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
    -> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
    -> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
    -> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
    -> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
    -> (6, 0.00, 0.00), (6, -51.40, 0.00);

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
    -> FROM t1 GROUP BY i HAVING a <> b;

+------+-------+------+
| i    | a     | b    |
+------+-------+------+
|    1 |  21.4 | 21.4 |
|    2 |  76.8 | 76.8 |
|    3 |   7.4 |  7.4 |
|    4 |  15.4 | 15.4 |
|    5 |   7.2 |  7.2 |
|    6 | -51.4 |    0 |
+------+-------+------+

Das Ergebnis ist richtig. Auch wenn die ersten fünf Datensätze nicht so aussehen, als würden sie den Test bestehen (die Werte von a und b sehen nicht verschieden aus), können sie dennoch unterschiedlich sein, da sie womöglich in der zehnten Nachkommastelle oder so (je nach Computerarchitektur) eine Abweichung aufweisen.

Wären die Spalten d1 und d2 als DECIMAL statt als DOUBLE definiert, so hätte die SELECT-Anfrage nur eine einzige Zeile geliefert, nämlich die letzte der obigen Tabelle.

A.6. Probleme im Zusammenhang mit dem Optimierer

MySQL ermittelt den besten Ausführungsweg für eine Anfrage mit einem kostenorientierten Optimierer. In vielen Fällen kann MySQL den bestmöglichen Ausführungsplan berechnen, aber manchmal hat es nicht genügend Informationen über die Daten und muss „fundierte“ Annahmen über die Daten treffen.

Wenn MySQL einmal nicht das Richtige tun sollte, stehen folgende Tools als Hilfestellung zur Verfügung:

  • Die EXPLAIN-Anweisung lässt erkennen, wie MySQL eine Anfrage verarbeitet. Um sie zu benutzen, setzen Sie einfach das Schlüsselwort EXPLAIN vor Ihre SELECT-Anweisung:

    mysql> EXPLAIN SELECT * FROM t1, t2 WHERE t1.i = t2.i;
    

    EXPLAIN wird in Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“, genauer beschrieben.

  • Mit ANALYZE TABLE tbl_name können Sie die Schlüsselverteilungen für die gescannte Tabelle aktualisieren. Siehe auch Abschnitt 13.5.2.1, „ANALYZE TABLE.

  • Wenn Sie für die gescannte Tabelle die FORCE INDEX-Anweisung geben, teilen Sie MySQL dadurch mit, dass Tabellenscans im Vergleich zur Verwendung des vorgegebenen Indexes sehr aufwändig sind. Siehe Abschnitt 13.2.7, „SELECT.

    SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
    WHERE t1.col_name=t2.col_name;
    

    USE INDEX und IGNORE INDEX können ebenfalls nützlich sein.

  • Globale und tabellenspezifische STRAIGHT_JOINs. Siehe Abschnitt 13.2.7, „SELECT.

  • Sie können auch globale oder Thread-spezifische Systemvariablen einstellen, zum Beispiel indem Sie mysqld mit der Option --max-seeks-for-key=1000 starten oder dem Optimierer mit SET max_seeks_for_key=1000 sagen, dass er davon ausgehen soll, dass kein Schlüsselscan mehr als 1.000 Schlüsselsuchoperationen bedeutet. Siehe Abschnitt 5.2.2, „Server-Systemvariablen“.

A.7. Tabellendefinitionsbezogene Themen

A.7.1. Probleme mit ALTER TABLE

ALTER TABLE stellt die Tabelle auf den aktuellen Zeichensatz um. Wenn Sie während der Ausführung von ALTER TABLE einen Fehler wegen doppelt vorhandener Schlüssel bekommen, liegt dies entweder daran, dass der neue Zeichensatz zwei Schlüssel demselben Wert zuordnet, oder daran, dass die Tabelle beschädigt ist. Im zweiten Fall müssen Sie eine REPAIR TABLE-Anweisung auf der Tabelle ausführen.

Wenn ALTER TABLE mit der folgenden Fehlermeldung abbricht, kann dies daran liegen, dass MySQL bei einer vorherigen ALTER TABLE-Operation abgestürzt ist und noch eine alte Tabelle namens A-xxx oder B-xxx in der Gegend herumfliegt:

Error on rename of './database/name.frm'
to './database/B-xxx.frm' (Errcode: 17)

In diesem Fall gehen Sie in das Data Directory von MySQL und löschen alle Dateien, deren Namen mit A- oder B- anfangen. (Oder Sie verschieben sie an einen anderen Ort, anstatt sie zu löschen).

ALTER TABLE funktioniert folgendermaßen:

  • Erzeuge eine neue Tabelle namens A-xxx mit den gewünschten Strukturänderungen.

  • Kopiere alle Zeilen der Originaltabelle in A-xxx.

  • Benenne die Originaltabelle in B-xxx um.

  • Gib A-xxx den ursprünglichen Namen der Tabelle.

  • Lösche B-xxx.

Wenn bei der Umbenennungsoperation etwas schief geht, versucht MySQL, die Änderungen rückgängig zu machen. Bei ernsthaften Problemen (die eigentlich nicht vorkommen sollten) könnte MySQL die alte Tabelle als B-xxx zurücklassen. Mit einer einfachen Umbenennung der Tabellendateien auf Systemebene müssten Sie Ihre Daten zurückbekommen.

Wenn Sie ALTER TABLE auf einer transaktionssicheren Tabelle ausführen oder Windows oder OS/2 benutzen, wird ALTER TABLE eine Sperre der Tabelle aufheben, falls Sie zuvor eine LOCK TABLE-Anweisung auf ihr ausgeführt haben, da InnoDB und diese Betriebssysteme keine Tabelle löschen können, die gerade in Gebrauch ist.

A.7.2. Wie man die Reihenfolge der Spalten in einer Tabelle ändert

Zuerst müssen Sie überlegen, ob es wirklich notwendig ist, die Spaltenreihenfolge in der Tabelle zu ändern. Das Hauptanliegen von SQL ist ja schließlich, die Anwendung vom Format der Datenspeicherung abzukoppeln. Sie sollten immer die Reihenfolge angeben, in der Sie Ihre Daten abholen möchten. Die erste der folgenden Anweisungen gibt die Spalten in der Reihenfolge col_name1, col_name2, col_name3 zurück, und die zweite in der Reihenfolge col_name1, col_name3, col_name2:

mysql> SELECT col_name1, col_name2, col_name3 FROM tbl_name;
mysql> SELECT col_name1, col_name3, col_name2 FROM tbl_name;

Wenn Sie dennoch die Reihenfolge der Spalten ändern möchten, tun Sie das folgendermaßen:

  1. Sie erzeugen eine neue Tabelle, in der die Spalten die neue Reihenfolge haben.

  2. Sie führen folgende Anweisung aus:

    mysql> INSERT INTO new_table
        -> SELECT columns-in-new-order FROM old_table;
    
  3. Sie löschen die old_table oder benennen sie um.

  4. Sie geben der neuen Tabelle den Namen des Originals:

    mysql> ALTER TABLE new_table RENAME old_table;
    

SELECT * eignet sich gut für Testanfragen. In einer Anwendung sollten Sie sich jedoch nie darauf verlassen, mit SELECT * die Spalten nach ihrer Position abzufragen. Die Reihenfolge und Position, in der die Spalten zurückgegeben werden, kann sich ändern, wenn Sie Spalten neu einfügen, verschieben oder löschen. Eine einfache Änderung an der Tabellenstruktur kann so Ihre Anwendung bereits zum Absturz bringen.

A.7.3. Probleme mit TEMPORARY TABLE

Für die Nutzung von TEMPORARY-Tabellen gibt es folgende Beschränkungen:

  • Eine TEMPORARY-Tabelle kann nur den Typ HEAP, ISAM, MyISAM, MERGE oder InnoDB haben.

  • Eine TEMPORARY-Tabelle kann nicht mehrmals in derselben Anfrage benutzt werden. Das Folgende funktioniert beispielsweise nicht:

    mysql> SELECT * FROM temp_table, temp_table AS t2;
    ERROR 1137: Can't reopen table: 'temp_table'
    
  • Die SHOW TABLES-Anweisung führt keine TEMPORARY-Tabellen auf.

  • Sie können eine TEMPORARY-Tabelle nicht mit RENAME, sondern nur mit ALTER TABLE umbenennen:

    mysql> ALTER TABLE orig_name RENAME new_name;
    
  • Im Zusammenhang mit Replikation können temporäre Tabellen Probleme machen. Weiteres erfahren Sie unter Abschnitt 6.8, „Replikation: Features und bekannte Probleme“.

A.8. Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL

Die folgenden Fehler sind in den neueren Versionen von MySQL bekannt geworden.

Informationen über plattformspezifische Probleme finden Sie in den Anleitungen zur Installation und Portierung von MySQL unter Abschnitt 2.12, „Betriebssystemspezifische Anmerkungen“, und Anhang E, Anmerkungen zur Portierung auf andere Systeme.

A.8.1. Offene Probleme in MySQL

Die folgenden Probleme sind bekannt und werden vorrangig gelöst:

  • Wenn Sie einen NULL-Wert mit einer Unterabfrage kombinieren, die eine ALL/ANY/SOME-Klausel hat, und die Unterabfrage ein leeres Ergebnis zurückliefert, kann der Vergleich das nicht standardmäßige Resultat NULL ergeben anstatt TRUE oder FALSE. Dies wird in MySQL 5.1 behoben.

  • Die Optimierung von Unterabfragen ist bei IN weniger effizient als bei =.

  • Selbst wenn Sie lower_case_table_names=2 verwenden (damit sich MySQL an die Groß-/Kleinschreibung von Datenbank- und Tabellennamen erinnert) kann MySQL sich diese nicht für Datenbanknamen im Zusammenhang mit der Funktion DATABASE() oder den diversen Logs merken (dies gilt für Systeme, die nicht zwischen Groß- und Kleinschreibung unterscheiden).

  • Das Löschen eines FOREIGN KEY-Constraints funktioniert nicht in einer Replikation, da der Constraint auf dem Slave unter Umständen einen anderen Namen hat.

  • REPLACE (und LOAD DATA mit der REPLACE-Option) löst kein ON DELETE CASCADE aus.

  • DISTINCT mit ORDER BY funktioniert nicht in GROUP_CONCAT(), wenn Sie nicht nur die Spalten verwenden, die in der DISTINCT-Liste aufgeführt sind.

  • Wenn ein Benutzer eine langwierige Transaktion laufen lässt und ein anderer Benutzer eine Tabelle löscht, die von der Transaktion geändert wird, besteht ein gewisses Risiko, dass der DROP TABLE im Binärlog festgehalten wird, bevor die Tabelle in der Transaktion benutzt wird. Dies wollen wir beheben, indem wir den DROP TABLE-Befehl so lange aussetzen lassen, bis die Tabelle in keiner Transaktion mehr benutzt wird.

  • Wenn Sie einen großen Integer-Wert (zwischen 263 und 264–1) in eine Decimal- oder String-Spalte einfügen, wird er als negativer Wert geschrieben, da die Zahl als vorzeichenbehafteter Integer ausgewertet wird.

  • FLUSH TABLES WITH READ LOCK kann COMMIT nicht blockieren, wenn der Server ohne Binärlogging läuft. Das kann zu Konsistenzproblemen mit Tabellen führen, wenn Sie eine vollständige Datensicherung ausführen.

  • ANALYZE TABLE kann BDB-Tabellen unter Umständen bis zum nächsten Neustart von mysqld unbenutzbar machen. Wenn dies geschieht, suchen Sie in der Fehlerdatei von MySQL nach Fehlern der folgenden Art:

    001207 22:07:56  bdb:  log_flush: LSN past current end-of-log
    
  • Führen Sie kein ALTER TABLE auf einer BDB-Tabelle aus, auf der Transaktionen mit mehreren Anweisungen laufen. Dies können Sie erst nach Abschluss aller dieser Transaktionen tun, da die Transaktion ansonsten eventuell ignoriert wird.

  • ANALYZE TABLE, OPTIMIZE TABLE und REPAIR TABLE können Probleme mit Tabellen verursachen, die mit INSERT DELAYED laufen.

  • Auch mit LOCK TABLE ... und FLUSH TABLES ... ist nicht gewährleistet, dass nicht noch eine halbfertige Transaktion auf der Tabelle abläuft.

  • BDB-Tabellen öffnen sich relativ langsam. Wenn Sie viele BDB-Tabellen in einer Datenbank haben, braucht der mysql-Client viel Zeit, es sei denn, Sie verwenden die Option -A oder rehash. Das macht sich besonders bei großen Tabellen-Caches bemerkbar.

  • Replikation verwendet Logging auf Anweisungsebene: Der Master schreibt die ausgeführten Anweisungen in das Binärlog. Dies ist eine sehr schnelle, kompakte und wirkungsvolle Loggingmethode, die in den meisten Fällen auch perfekt funktioniert.

    Es ist jedoch möglich, dass Unterschiede zwischen den Daten von Master und Slave auftreten, wenn eine Anfrage so entworfen wurde, dass sie Daten in nichtdeterministischer Weise ändert (was allerdings generell, auch außerhalb einer Replikation, nicht zu empfehlen ist).

    Beispielsweise:

    • CREATE ... SELECT- oder INSERT ... SELECT-Anweisungen, die null oder NULL-Werte in eine AUTO_INCREMENT-Spalte einfügen.

    • DELETE, wenn Sie Zeilen aus einer Tabelle löschen, die Fremdschlüssel mit ON DELETE CASCADE-Eigenschaften hat.

    • REPLACE ... SELECT, INSERT IGNORE ... SELECT, wenn Sie in den eingefügten Daten Schlüsselduplikate haben.

    Genau dann, wenn die vorangegangenen Anfragen keine ORDER BY-Klausel haben, die eine deterministische Sortierreihenfolge garantiert.

    So kann beispielsweise ein SELECT für INSERT ... SELECT ohne ORDER BY-Klausel Zeilen in einer anderen Reihenfolge zurückliefern (was dazu führt, dass eine Zeile einen unterschiedlichen Rang und somit auch unterschiedliche Nummern in der AUTO_INCREMENT-Spalte haben kann), je nachdem, wie sich die Optimierer von Master und Slave entscheiden.

    Eine Anfrage wird auf Master und Slave nur in folgenden Fällen unterschiedlich optimiert:

    • Wenn die Tabelle auf dem Master mit einer anderen Speicher-Engine als auf dem Slave gespeichert wird. (Es ist nämlich möglich, auf Master und Slave verschiedene Speicher-Engines zu verwenden. So können Sie beispielsweise InnoDB auf dem Master und MyISAM auf dem Slave einsetzen, wenn der Slave weniger Festplattenspeicher zur Verfügung hat.)

    • Wenn die Größen der MySQL-Puffer (key_buffer_size und so weiter) auf Master und Slave unterschiedlich sind.

    • Wenn Master und Slave mit unterschiedlichen MySQL-Versionen laufen und der Optimierungscode einen Unterschied zwischen diesen beiden Versionen macht.

    Dieses Problem kann auch die Datenbankwiederherstellung mit mysqlbinlog|mysql beeinträchtigen.

    Am einfachsten lässt sich dieses Problem verhindern, wenn Sie den oben erwähnten nichtdeterministischen Anfragen eine ORDER BY-Klausel hinzufügen, um zu gewährleisten, dass die Zeilen immer in derselben Reihenfolge gespeichert oder modifiziert werden.

    In künftigen MySQL-Versionen werden wir automatisch eine ORDER BY-Klausel hinzufügen, wo sie nötig ist.

Die folgenden Probleme sind bekannt und werden bald behoben:

  • Die Logdateinamen basieren auf dem Namen des Serverhosts (sofern Sie nicht mit der Startoption einen Dateinamen vorgeben). Wenn Sie Ihren Hostnamen ändern möchten, müssen Sie Optionen wie beispielsweise --log-bin=old_host_name-bin verwenden. Oder Sie benennen die alten Dateien mit dem neuen Hostnamen um (wenn es Binärlogs sind, müssen Sie dazu auch die Indexdatei des Binärlogs bearbeiten und die Binlognamen ebenfalls ändern). Siehe Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

  • mysqlbinlog löscht keine temporären Dateien, die nach einem LOAD DATA INFILE-Befehl übrig bleiben. Siehe Abschnitt 8.8, „mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien“.

  • RENAME funktioniert nicht mit TEMPORARY-Tabellen oder Tabellen, die in einer MERGE-Tabelle benutzt werden.

  • Aufgrund der Art und Weise, wie Tabellenformatdateien (.frm-Dateien) gespeichert werden, können Sie Zeichen 255 (CHAR(255)) nicht in Tabellennamen, Spaltennamen und Enumerationen verwenden. Dies soll in Version 5.1 behoben werden, wenn wir neue Formatdateien für die Tabellendefinitionen implementieren.

  • Wenn Sie SET CHARACTER SET benutzen, können Sie keine übersetzten Zeichen in den Namen von Datenbanken, Tabellen und Spalten verwenden.

  • Sie dürfen kein ‘_’ oder ‘%’ mit ESCAPE in LIKE ... ESCAPE verwenden.

  • Wenn Sie in einer DECIMAL-Spalte dieselbe Zahl in verschiedenen Formaten gespeichert haben (beispielsweise +01.00, 1.00, 01.00), kann es passieren, dass GROUP BY diese Werte als unterschiedlich betrachtet.

  • Sie können den Server nicht in einem anderen Verzeichnis bauen, wenn Sie MIT-pthreads verwenden. Da sich dies nur durch eine Änderung von MIT-pthreads beheben ließe, werden wir es wahrscheinlich nicht reparieren können. Siehe auch Abschnitt 2.8.5, „Anmerkungen zu MIT-pthreads“.

  • BLOB- und TEXT-Werte können in GROUP BY, ORDER BY oder DISTINCT nicht zuverlässig benutzt werden, da in diesen Fällen zum Vergleich von BLOB-Werten nur die ersten max_sort_length Bytes herangezogen werden. Der Standardwert von max_sort_length beträgt 1.024 und kann beim Serverstart oder zur Laufzeit geändert werden.

  • Numerische Berechnungen werden mit BIGINT oder DOUBLE ausgeführt (beide sind normalerweise 64 Bits lang). Welche Genauigkeit sie haben, hängt von der Funktion ab. Im Allgemeinen werden Bitfunktionen mit einer BIGINT-Genauigkeit, IF und ELT() mit einer BIGINT- oder DOUBLE-Genauigkeit und alles Übrige mit einer DOUBLE-Genauigkeit ausgeführt. Sie sollten möglichst (außer für Bitfelder) keine sehr langen Werte verwenden, wenn diese länger als 63 Bits (9223372036854775807) werden können.

  • In einer Tabelle dürfen bis zu 255 ENUM- und SET-Spalten vorhanden sein.

  • In MIN(), MAX() und anderen Aggregatfunktionen vergleicht MySQL ENUM- und SET-Spalten gegenwärtig nach ihrem Stringwert anstatt nach der relativen Position des Strings in der Menge.

  • mysqld_safe leitet alle Meldungen von mysqld in das mysqld-Log. Wenn Sie das Log mit mysqladmin refresh schließen und neu öffnen, besteht jedoch das Problem, dass stdout und stderr weiterhin in das alte Log umgeleitet werden. Wenn Sie viel mit --log arbeiten, sollten Sie mysqld_safe so bearbeiten, dass es Logeinträge in host_name.err statt in host_name.log schreibt, damit Sie den Speicherplatz des alten Logs leichter zurückholen können, indem Sie es einfach löschen und mysqladmin refresh ausführen.

  • In einer UPDATE-Anweisung werden die Spalten von links nach rechts aktualisiert. Wenn Sie eine aktualisierte Spalte benutzen, bekommen Sie den aktualisierten statt des ursprünglichen Werts. Die folgende Anweisung inkrementiert beispielsweise KEY um 2 und nicht um 1:

    mysql> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1;
    
  • Sie können zwar in derselben Anfrage mehrere temporäre Tabellen benutzen, aber nicht dieselbe zweimal. Das Folgende funktioniert beispielsweise nicht:

    mysql> SELECT * FROM temp_table, temp_table AS t2;
    ERROR 1137: Can't reopen table: 'temp_table'
    
  • Der Optimierer behandelt DISTINCT unterschiedlich, je nachdem, ob Sie in einem Join „verborgene“ Spalten benutzen oder nicht. Verborgene Spalten werden in einem Join als Teil des Ergebnisses betrachtet (obwohl sie nicht angezeigt werden), während sie in normalen Anfragen nicht an einem DISTINCT-Vergleich teilnehmen. Dies werden wir wahrscheinlich in Zukunft dahingehend ändern, dass die verborgenen Spalten bei DISTINCT nicht mehr am Vergleich beteiligt werden.

    Ein Beispiel dafür ist:

    SELECT DISTINCT mp3id FROM band_downloads
           WHERE userid = 9 ORDER BY id DESC;
    

    und

    SELECT DISTINCT band_downloads.mp3id
           FROM band_downloads,band_mp3
           WHERE band_downloads.userid = 9
           AND band_mp3.id = band_downloads.mp3id
           ORDER BY band_downloads.id DESC;
    

    Im zweiten Fall bekommen Sie mit MySQL Server 3.23.x vielleicht zwei identische Zeilen in der Ergebnismenge (da die Werte in der verborgenen id-Spalte unterschiedlich sein können).

    Beachten Sie, dass dies nur in Anfragen ohne ORDER BY-Spalten im Ergebnis passieren kann.

  • Wenn Sie eine PROCEDURE auf einer Anfrage ausführen, die eine leere Menge zurückgibt, wird die PROCEDURE in manchen Fällen die Spalten nicht transformieren.

  • Beim Anlegen einer Tabelle vom Typ MERGE wird nicht geprüft, ob die Typen der zugrunde liegenden Tabellen kompatibel sind.

  • Wenn Sie einer Tabelle, die in einer MERGE-Tabelle benutzt wird, mit ALTER TABLE einen UNIQUE-Index hinzufügen und dann einen normalen Index auf die MERGE-Tabelle legen, ist die Reihenfolge der Schlüssel bei Tabellen anders, wenn zuvor ein Nicht-UNIQUE-Schlüssel in der Tabelle bestand. Der Grund: ALTER TABLE setzt UNIQUE-Indizes vor normale Indizes, um so früh wie möglich Schlüsselduplikate erkennen zu können.

Anhang B. Fehlercodes und -meldungen

Dieses Kapitel enthält die Fehler, die auftreten können, wenn MySQL aus einer beliebigen Host-Sprache aus aufgerufen wird. Die erste Liste enhält die Fehlermeldungen des Servers, die zweite Liste die Fehlermeldungen der Clientprogramme.

Die Fehlermeldungen werden laufend überarbeitet. Daher kann es sein, dass einige Meldungen nicht, noch nicht, oder nicht mehr auf deutsch verfügbar sind. In diesem Fall werden englische Fehlermeldungen verwendet.

B.1. Fehlercodes und -meldungen des Servers

Die Fehlermeldungen des Servers stammen aus folgenden Quelldateien:

  • Die Texte der Fehlermeldungen befinden sich in der Datei share/errmsg.txt. %d und %s stellen Zahlen beziehungsweise Strings dar, die bei der Ausgabe der Meldungen entsprechend ersetzt werden.

  • Die Inhalte der Datei share/errmsg.txt werden verwendet, um die Definitionen in den MySQL-Quelldateien include/mysqld_error.h und include/mysqld_ername.h zu erzeugen.

  • Die SQLSTATE-Werte in share/errmsg.txt werden zur Erzeugung der Definitionen in der MySQL-Quelldatei include/sql_state.h verwendet.

Weil die Fehlermeldungen häufig aktualisiert werden, kann es sein, dass die genannten Dateien zusätzliche Fehlermeldungen enthalten, die hier noch nicht aufgeführt sind.

  • Fehler: 1000 SQLSTATE: HY000 (ER_HASHCHK)

    Meldung: hashchk

  • Fehler: 1001 SQLSTATE: HY000 (ER_NISAMCHK)

    Meldung: isamchk

  • Fehler: 1002 SQLSTATE: HY000 (ER_NO)

    Meldung: Nein

  • Fehler: 1003 SQLSTATE: HY000 (ER_YES)

    Meldung: Ja

  • Fehler: 1004 SQLSTATE: HY000 (ER_CANT_CREATE_FILE)

    Meldung: Kann Datei '%s' nicht erzeugen (Fehler: %d)

  • Fehler: 1005 SQLSTATE: HY000 (ER_CANT_CREATE_TABLE)

    Meldung: Kann Tabelle '%s' nicht erzeugen (Fehler: %d)

  • Fehler: 1006 SQLSTATE: HY000 (ER_CANT_CREATE_DB)

    Meldung: Kann Datenbank '%s' nicht erzeugen (Fehler: %d)

  • Fehler: 1007 SQLSTATE: HY000 (ER_DB_CREATE_EXISTS)

    Meldung: Kann Datenbank '%s' nicht erzeugen. Datenbank existiert bereits

  • Fehler: 1008 SQLSTATE: HY000 (ER_DB_DROP_EXISTS)

    Meldung: Kann Datenbank '%s' nicht löschen; Datenbank nicht vorhanden

  • Fehler: 1009 SQLSTATE: HY000 (ER_DB_DROP_DELETE)

    Meldung: Fehler beim Löschen der Datenbank ('%s' kann nicht gelöscht werden, Fehler: %d)

  • Fehler: 1010 SQLSTATE: HY000 (ER_DB_DROP_RMDIR)

    Meldung: Fehler beim Löschen der Datenbank (Verzeichnis '%s' kann nicht gelöscht werden, Fehler: %d)

  • Fehler: 1011 SQLSTATE: HY000 (ER_CANT_DELETE_FILE)

    Meldung: Fehler beim Löschen von '%s' (Fehler: %d)

  • Fehler: 1012 SQLSTATE: HY000 (ER_CANT_FIND_SYSTEM_REC)

    Meldung: Datensatz in der Systemtabelle nicht lesbar

  • Fehler: 1013 SQLSTATE: HY000 (ER_CANT_GET_STAT)

    Meldung: Kann Status von '%s' nicht ermitteln (Fehler: %d)

  • Fehler: 1014 SQLSTATE: HY000 (ER_CANT_GET_WD)

    Meldung: Kann Arbeitsverzeichnis nicht ermitteln (Fehler: %d)

  • Fehler: 1015 SQLSTATE: HY000 (ER_CANT_LOCK)

    Meldung: Datei kann nicht gesperrt werden (Fehler: %d)

  • Fehler: 1016 SQLSTATE: HY000 (ER_CANT_OPEN_FILE)

    Meldung: Kann Datei '%s' nicht öffnen (Fehler: %d)

  • Fehler: 1017 SQLSTATE: HY000 (ER_FILE_NOT_FOUND)

    Meldung: Kann Datei '%s' nicht finden (Fehler: %d)

  • Fehler: 1018 SQLSTATE: HY000 (ER_CANT_READ_DIR)

    Meldung: Verzeichnis von '%s' nicht lesbar (Fehler: %d)

  • Fehler: 1019 SQLSTATE: HY000 (ER_CANT_SET_WD)

    Meldung: Kann nicht in das Verzeichnis '%s' wechseln (Fehler: %d)

  • Fehler: 1020 SQLSTATE: HY000 (ER_CHECKREAD)

    Meldung: Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%s' geändert

  • Fehler: 1021 SQLSTATE: HY000 (ER_DISK_FULL)

    Meldung: Festplatte voll (%s). Warte, bis jemand Platz schafft ...

  • Fehler: 1022 SQLSTATE: 23000 (ER_DUP_KEY)

    Meldung: Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%s'

  • Fehler: 1023 SQLSTATE: HY000 (ER_ERROR_ON_CLOSE)

    Meldung: Fehler beim Schließen von '%s' (Fehler: %d)

  • Fehler: 1024 SQLSTATE: HY000 (ER_ERROR_ON_READ)

    Meldung: Fehler beim Lesen der Datei '%s' (Fehler: %d)

  • Fehler: 1025 SQLSTATE: HY000 (ER_ERROR_ON_RENAME)

    Meldung: Fehler beim Umbenennen von '%s' in '%s' (Fehler: %d)

  • Fehler: 1026 SQLSTATE: HY000 (ER_ERROR_ON_WRITE)

    Meldung: Fehler beim Speichern der Datei '%s' (Fehler: %d)

  • Fehler: 1027 SQLSTATE: HY000 (ER_FILE_USED)

    Meldung: '%s' ist für Änderungen gesperrt

  • Fehler: 1028 SQLSTATE: HY000 (ER_FILSORT_ABORT)

    Meldung: Sortiervorgang abgebrochen

  • Fehler: 1029 SQLSTATE: HY000 (ER_FORM_NOT_FOUND)

    Meldung: View '%s' existiert für '%s' nicht

  • Fehler: 1030 SQLSTATE: HY000 (ER_GET_ERRNO)

    Meldung: Fehler %d (Speicher-Engine)

  • Fehler: 1031 SQLSTATE: HY000 (ER_ILLEGAL_HA)

    Meldung: Diese Option gibt es nicht (Speicher-Engine für '%s')

  • Fehler: 1032 SQLSTATE: HY000 (ER_KEY_NOT_FOUND)

    Meldung: Kann Datensatz in '%s' nicht finden

  • Fehler: 1033 SQLSTATE: HY000 (ER_NOT_FORM_FILE)

    Meldung: Falsche Information in Datei '%s'

  • Fehler: 1034 SQLSTATE: HY000 (ER_NOT_KEYFILE)

    Meldung: Fehlerhafte Index-Datei für Tabelle '%s'; versuche zu reparieren

  • Fehler: 1035 SQLSTATE: HY000 (ER_OLD_KEYFILE)

    Meldung: Alte Index-Datei für Tabelle '%s'. Bitte reparieren

  • Fehler: 1036 SQLSTATE: HY000 (ER_OPEN_AS_READONLY)

    Meldung: Tabelle '%s' ist nur lesbar

  • Fehler: 1037 SQLSTATE: HY001 (ER_OUTOFMEMORY)

    Meldung: Kein Speicher vorhanden (%d Bytes benötigt). Bitte Server neu starten

  • Fehler: 1038 SQLSTATE: HY001 (ER_OUT_OF_SORTMEMORY)

    Meldung: Kein Speicher zum Sortieren vorhanden. sort_buffer_size sollte im Server erhöht werden

  • Fehler: 1039 SQLSTATE: HY000 (ER_UNEXPECTED_EOF)

    Meldung: Unerwartetes Ende beim Lesen der Datei '%s' (Fehler: %d)

  • Fehler: 1040 SQLSTATE: 08004 (ER_CON_COUNT_ERROR)

    Meldung: Zu viele Verbindungen

  • Fehler: 1041 SQLSTATE: HY000 (ER_OUT_OF_RESOURCES)

    Meldung: Kein Speicher mehr vorhanden. Prüfen Sie, ob mysqld oder ein anderer Prozess den gesamten Speicher verbraucht. Wenn nicht, sollten Sie mit 'ulimit' dafür sorgen, dass mysqld mehr Speicher benutzen darf, oder mehr Swap-Speicher einrichten

  • Fehler: 1042 SQLSTATE: 08S01 (ER_BAD_HOST_ERROR)

    Meldung: Kann Hostnamen für diese Adresse nicht erhalten

  • Fehler: 1043 SQLSTATE: 08S01 (ER_HANDSHAKE_ERROR)

    Meldung: Ungültiger Handshake

  • Fehler: 1044 SQLSTATE: 42000 (ER_DBACCESS_DENIED_ERROR)

    Meldung: Benutzer '%s'@'%s' hat keine Zugriffsberechtigung für Datenbank '%s'

  • Fehler: 1045 SQLSTATE: 28000 (ER_ACCESS_DENIED_ERROR)

    Meldung: Benutzer '%s'@'%s' hat keine Zugriffsberechtigung (verwendetes Passwort: %s)

  • Fehler: 1046 SQLSTATE: 3D000 (ER_NO_DB_ERROR)

    Meldung: Keine Datenbank ausgewählt

  • Fehler: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)

    Meldung: Unbekannter Befehl

  • Fehler: 1048 SQLSTATE: 23000 (ER_BAD_NULL_ERROR)

    Meldung: Feld '%s' darf nicht NULL sein

  • Fehler: 1049 SQLSTATE: 42000 (ER_BAD_DB_ERROR)

    Meldung: Unbekannte Datenbank '%s'

  • Fehler: 1050 SQLSTATE: 42S01 (ER_TABLE_EXISTS_ERROR)

    Meldung: Tabelle '%s' bereits vorhanden

  • Fehler: 1051 SQLSTATE: 42S02 (ER_BAD_TABLE_ERROR)

    Meldung: Unbekannte Tabelle '%s'

  • Fehler: 1052 SQLSTATE: 23000 (ER_NON_UNIQ_ERROR)

    Meldung: Feld '%s' in %s ist nicht eindeutig

  • Fehler: 1053 SQLSTATE: 08S01 (ER_SERVER_SHUTDOWN)

    Meldung: Der Server wird heruntergefahren

  • Fehler: 1054 SQLSTATE: 42S22 (ER_BAD_FIELD_ERROR)

    Meldung: Unbekanntes Tabellenfeld '%s' in %s

  • Fehler: 1055 SQLSTATE: 42000 (ER_WRONG_FIELD_WITH_GROUP)

    Meldung: '%s' ist nicht in GROUP BY vorhanden

  • Fehler: 1056 SQLSTATE: 42000 (ER_WRONG_GROUP_FIELD)

    Meldung: Gruppierung über '%s' nicht möglich

  • Fehler: 1057 SQLSTATE: 42000 (ER_WRONG_SUM_SELECT)

    Meldung: Die Verwendung von Summierungsfunktionen und Spalten im selben Befehl ist nicht erlaubt

  • Fehler: 1058 SQLSTATE: 21S01 (ER_WRONG_VALUE_COUNT)

    Meldung: Die Anzahl der Spalten entspricht nicht der Anzahl der Werte

  • Fehler: 1059 SQLSTATE: 42000 (ER_TOO_LONG_IDENT)

    Meldung: Name des Bezeichners '%s' ist zu lang

  • Fehler: 1060 SQLSTATE: 42S21 (ER_DUP_FIELDNAME)

    Meldung: Doppelter Spaltenname: '%s'

  • Fehler: 1061 SQLSTATE: 42000 (ER_DUP_KEYNAME)

    Meldung: Doppelter Name für Schlüssel vorhanden: '%s'

  • Fehler: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)

    Meldung: Doppelter Eintrag '%s' für Schlüssel '%s'

  • Fehler: 1063 SQLSTATE: 42000 (ER_WRONG_FIELD_SPEC)

    Meldung: Falsche Spezifikation für Feld '%s'

  • Fehler: 1064 SQLSTATE: 42000 (ER_PARSE_ERROR)

    Meldung: %s bei '%s' in Zeile %d

  • Fehler: 1065 SQLSTATE: 42000 (ER_EMPTY_QUERY)

    Meldung: Leere Abfrage

  • Fehler: 1066 SQLSTATE: 42000 (ER_NONUNIQ_TABLE)

    Meldung: Tabellenname/Alias '%s' nicht eindeutig

  • Fehler: 1067 SQLSTATE: 42000 (ER_INVALID_DEFAULT)

    Meldung: Fehlerhafter Vorgabewert (DEFAULT) für '%s'

  • Fehler: 1068 SQLSTATE: 42000 (ER_MULTIPLE_PRI_KEY)

    Meldung: Mehrere Primärschlüssel (PRIMARY KEY) definiert

  • Fehler: 1069 SQLSTATE: 42000 (ER_TOO_MANY_KEYS)

    Meldung: Zu viele Schlüssel definiert. Maximal %d Schlüssel erlaubt

  • Fehler: 1070 SQLSTATE: 42000 (ER_TOO_MANY_KEY_PARTS)

    Meldung: Zu viele Teilschlüssel definiert. Maximal %d Teilschlüssel erlaubt

  • Fehler: 1071 SQLSTATE: 42000 (ER_TOO_LONG_KEY)

    Meldung: Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d

  • Fehler: 1072 SQLSTATE: 42000 (ER_KEY_COLUMN_DOES_NOT_EXITS)

    Meldung: In der Tabelle gibt es kein Schlüsselfeld '%s'

  • Fehler: 1073 SQLSTATE: 42000 (ER_BLOB_USED_AS_KEY)

    Meldung: BLOB-Feld '%s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden

  • Fehler: 1074 SQLSTATE: 42000 (ER_TOO_BIG_FIELDLENGTH)

    Meldung: Feldlänge für Feld '%s' zu groß (maximal %d). BLOB- oder TEXT-Spaltentyp verwenden!

  • Fehler: 1075 SQLSTATE: 42000 (ER_WRONG_AUTO_KEY)

    Meldung: Falsche Tabellendefinition. Es darf nur eine AUTO_INCREMENT-Spalte geben, und diese muss als Schlüssel definiert werden

  • Fehler: 1076 SQLSTATE: HY000 (ER_READY)

    Meldung: %s: Bereit für Verbindungen. Version: '%2' Socket: '%s' Port: %d

  • Fehler: 1077 SQLSTATE: HY000 (ER_NORMAL_SHUTDOWN)

    Meldung: %s: Normal heruntergefahren

  • Fehler: 1078 SQLSTATE: HY000 (ER_GOT_SIGNAL)

    Meldung: %s: Signal %d erhalten. Abbruch!

  • Fehler: 1079 SQLSTATE: HY000 (ER_SHUTDOWN_COMPLETE)

    Meldung: %s: Herunterfahren beendet

  • Fehler: 1080 SQLSTATE: 08S01 (ER_FORCING_CLOSE)

    Meldung: %s: Thread %ld zwangsweise beendet. Benutzer: '%s'

  • Fehler: 1081 SQLSTATE: 08S01 (ER_IPSOCK_ERROR)

    Meldung: Kann IP-Socket nicht erzeugen

  • Fehler: 1082 SQLSTATE: 42S12 (ER_NO_SUCH_INDEX)

    Meldung: Tabelle '%s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Tabelle neu anlegen

  • Fehler: 1083 SQLSTATE: 42000 (ER_WRONG_FIELD_TERMINATORS)

    Meldung: Feldbegrenzer-Argument ist nicht in der erwarteten Form. Bitte im Handbuch nachlesen

  • Fehler: 1084 SQLSTATE: 42000 (ER_BLOBS_AND_NO_TERMINATED)

    Meldung: Eine feste Zeilenlänge kann für BLOB-Felder nicht verwendet werden. Bitte 'fields terminated by' verwenden

  • Fehler: 1085 SQLSTATE: HY000 (ER_TEXTFILE_NOT_READABLE)

    Meldung: Datei '%s' muss im Datenbank-Verzeichnis vorhanden oder lesbar für alle sein

  • Fehler: 1086 SQLSTATE: HY000 (ER_FILE_EXISTS_ERROR)

    Meldung: Datei '%s' bereits vorhanden

  • Fehler: 1087 SQLSTATE: HY000 (ER_LOAD_INFO)

    Meldung: Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld

  • Fehler: 1088 SQLSTATE: HY000 (ER_ALTER_INFO)

    Meldung: Datensätze: %ld Duplikate: %ld

  • Fehler: 1089 SQLSTATE: HY000 (ER_WRONG_SUB_KEY)

    Meldung: Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder die Speicher-Engine unterstützt keine Unterteilschlüssel

  • Fehler: 1090 SQLSTATE: 42000 (ER_CANT_REMOVE_ALL_FIELDS)

    Meldung: Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Dafür DROP TABLE verwenden

  • Fehler: 1091 SQLSTATE: 42000 (ER_CANT_DROP_FIELD_OR_KEY)

    Meldung: Kann '%s' nicht löschen. Existiert die Spalte oder der Schlüssel?

  • Fehler: 1092 SQLSTATE: HY000 (ER_INSERT_INFO)

    Meldung: Datensätze: %ld Duplikate: %ld Warnungen: %ld

  • Fehler: 1093 SQLSTATE: HY000 (ER_UPDATE_TABLE_USED)

    Meldung: Die Verwendung der zu aktualisierenden Zieltabelle '%s' ist in der FROM-Klausel nicht zulässig.

  • Fehler: 1094 SQLSTATE: HY000 (ER_NO_SUCH_THREAD)

    Meldung: Unbekannte Thread-ID: %lu

  • Fehler: 1095 SQLSTATE: HY000 (ER_KILL_DENIED_ERROR)

    Meldung: Sie sind nicht Eigentümer von Thread %lu

  • Fehler: 1096 SQLSTATE: HY000 (ER_NO_TABLES_USED)

    Meldung: Keine Tabellen verwendet

  • Fehler: 1097 SQLSTATE: HY000 (ER_TOO_BIG_SET)

    Meldung: Zu viele Strings für Feld %s und SET angegeben

  • Fehler: 1098 SQLSTATE: HY000 (ER_NO_UNIQUE_LOGFILE)

    Meldung: Kann keinen eindeutigen Dateinamen für die Logdatei %s(1-999) erzeugen

  • Fehler: 1099 SQLSTATE: HY000 (ER_TABLE_NOT_LOCKED_FOR_WRITE)

    Meldung: Tabelle '%s' ist mit Lesesperre versehen und kann nicht aktualisiert werden

  • Fehler: 1100 SQLSTATE: HY000 (ER_TABLE_NOT_LOCKED)

    Meldung: Tabelle '%s' wurde nicht mit LOCK TABLES gesperrt

  • Fehler: 1101 SQLSTATE: 42000 (ER_BLOB_CANT_HAVE_DEFAULT)

    Meldung: BLOB/TEXT-Feld '%s' darf keinen Vorgabewert (DEFAULT) haben

  • Fehler: 1102 SQLSTATE: 42000 (ER_WRONG_DB_NAME)

    Meldung: Unerlaubter Datenbankname '%s'

  • Fehler: 1103 SQLSTATE: 42000 (ER_WRONG_TABLE_NAME)

    Meldung: Unerlaubter Tabellenname '%s'

  • Fehler: 1104 SQLSTATE: 42000 (ER_TOO_BIG_SELECT)

    Meldung: Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden

  • Fehler: 1105 SQLSTATE: HY000 (ER_UNKNOWN_ERROR)

    Meldung: Unbekannter Fehler

  • Fehler: 1106 SQLSTATE: 42000 (ER_UNKNOWN_PROCEDURE)

    Meldung: Unbekannte Prozedur '%s'

  • Fehler: 1107 SQLSTATE: 42000 (ER_WRONG_PARAMCOUNT_TO_PROCEDURE)

    Meldung: Falsche Parameterzahl für Prozedur '%s'

  • Fehler: 1108 SQLSTATE: HY000 (ER_WRONG_PARAMETERS_TO_PROCEDURE)

    Meldung: Falsche Parameter für Prozedur '%s'

  • Fehler: 1109 SQLSTATE: 42S02 (ER_UNKNOWN_TABLE)

    Meldung: Unbekannte Tabelle '%s' in '%s'

  • Fehler: 1110 SQLSTATE: 42000 (ER_FIELD_SPECIFIED_TWICE)

    Meldung: Feld '%s' wurde zweimal angegeben

  • Fehler: 1111 SQLSTATE: HY000 (ER_INVALID_GROUP_FUNC_USE)

    Meldung: Falsche Verwendung einer Gruppierungsfunktion

  • Fehler: 1112 SQLSTATE: 42000 (ER_UNSUPPORTED_EXTENSION)

    Meldung: Tabelle '%s' verwendet eine Erweiterung, die in dieser MySQL-Version nicht verfügbar ist

  • Fehler: 1113 SQLSTATE: 42000 (ER_TABLE_MUST_HAVE_COLUMNS)

    Meldung: Eine Tabelle muss mindestens eine Spalte besitzen

  • Fehler: 1114 SQLSTATE: HY000 (ER_RECORD_FILE_FULL)

    Meldung: Tabelle '%s' ist voll

  • Fehler: 1115 SQLSTATE: 42000 (ER_UNKNOWN_CHARACTER_SET)

    Meldung: Unbekannter Zeichensatz: '%s'

  • Fehler: 1116 SQLSTATE: HY000 (ER_TOO_MANY_TABLES)

    Meldung: Zu viele Tabellen. MySQL kann in einem Join maximal %d Tabellen verwenden

  • Fehler: 1117 SQLSTATE: HY000 (ER_TOO_MANY_FIELDS)

    Meldung: Zu viele Felder

  • Fehler: 1118 SQLSTATE: 42000 (ER_TOO_BIG_ROWSIZE)

    Meldung: Zeilenlänge zu groß. Die maximale Zeilenlänge für den verwendeten Tabellentyp (ohne BLOB-Felder) beträgt %ld. Einige Felder müssen in BLOB oder TEXT umgewandelt werden

  • Fehler: 1119 SQLSTATE: HY000 (ER_STACK_OVERRUN)

    Meldung: Thread-Stack-Überlauf. Benutzt: %ld von %ld Stack. 'mysqld -O thread_stack=#' verwenden, um bei Bedarf einen größeren Stack anzulegen

  • Fehler: 1120 SQLSTATE: 42000 (ER_WRONG_OUTER_JOIN)

    Meldung: OUTER JOIN enthält fehlerhafte Abhängigkeiten. In ON verwendete Bedingungen überprüfen

  • Fehler: 1121 SQLSTATE: 42000 (ER_NULL_COLUMN_IN_INDEX)

    Meldung: Table handler doesn't support NULL in given index. Please change column '%s' to be NOT NULL or use another handler

  • Fehler: 1122 SQLSTATE: HY000 (ER_CANT_FIND_UDF)

    Meldung: Kann Funktion '%s' nicht laden

  • Fehler: 1123 SQLSTATE: HY000 (ER_CANT_INITIALIZE_UDF)

    Meldung: Kann Funktion '%s' nicht initialisieren: %s

  • Fehler: 1124 SQLSTATE: HY000 (ER_UDF_NO_PATHS)

    Meldung: Keine Pfade gestattet für Shared Library

  • Fehler: 1125 SQLSTATE: HY000 (ER_UDF_EXISTS)

    Meldung: Funktion '%s' existiert schon

  • Fehler: 1126 SQLSTATE: HY000 (ER_CANT_OPEN_LIBRARY)

    Meldung: Kann Shared Library '%s' nicht öffnen (Fehler: %d %s)

  • Fehler: 1127 SQLSTATE: HY000 (ER_CANT_FIND_DL_ENTRY)

    Meldung: Kann Funktion '%s' in der Library nicht finden

  • Fehler: 1128 SQLSTATE: HY000 (ER_FUNCTION_NOT_DEFINED)

    Meldung: Funktion '%s' ist nicht definiert

  • Fehler: 1129 SQLSTATE: HY000 (ER_HOST_IS_BLOCKED)

    Meldung: Host '%s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'

  • Fehler: 1130 SQLSTATE: HY000 (ER_HOST_NOT_PRIVILEGED)

    Meldung: Host '%s' hat keine Berechtigung, sich mit diesem MySQL-Server zu verbinden

  • Fehler: 1131 SQLSTATE: 42000 (ER_PASSWORD_ANONYMOUS_USER)

    Meldung: Sie benutzen MySQL als anonymer Benutzer und dürfen daher keine Passwörter ändern

  • Fehler: 1132 SQLSTATE: 42000 (ER_PASSWORD_NOT_ALLOWED)

    Meldung: Sie benötigen die Berechtigung zum Aktualisieren von Tabellen in der Datenbank 'mysql', um die Passwörter anderer Benutzer ändern zu können

  • Fehler: 1133 SQLSTATE: 42000 (ER_PASSWORD_NO_MATCH)

    Meldung: Kann keinen passenden Datensatz in Tabelle 'user' finden

  • Fehler: 1134 SQLSTATE: HY000 (ER_UPDATE_INFO)

    Meldung: Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld

  • Fehler: 1135 SQLSTATE: HY000 (ER_CANT_CREATE_THREAD)

    Meldung: Kann keinen neuen Thread erzeugen (Fehler: %d). Sollte noch Speicher verfügbar sein, bitte im Handbuch wegen möglicher Fehler im Betriebssystem nachschlagen

  • Fehler: 1136 SQLSTATE: 21S01 (ER_WRONG_VALUE_COUNT_ON_ROW)

    Meldung: Anzahl der Felder stimmt nicht mit der Anzahl der Werte in Zeile %ld überein

  • Fehler: 1137 SQLSTATE: HY000 (ER_CANT_REOPEN_TABLE)

    Meldung: Kann Tabelle'%s' nicht erneut öffnen

  • Fehler: 1138 SQLSTATE: 22004 (ER_INVALID_USE_OF_NULL)

    Meldung: Unerlaubte Verwendung eines NULL-Werts

  • Fehler: 1139 SQLSTATE: 42000 (ER_REGEXP_ERROR)

    Meldung: regexp lieferte Fehler '%s'

  • Fehler: 1140 SQLSTATE: 42000 (ER_MIX_OF_GROUP_FUNC_AND_FIELDS)

    Meldung: Das Vermischen von GROUP-Feldern (MIN(),MAX(),COUNT()...) mit Nicht-GROUP-Feldern ist nicht zulässig, wenn keine GROUP-BY-Klausel vorhanden ist

  • Fehler: 1141 SQLSTATE: 42000 (ER_NONEXISTING_GRANT)

    Meldung: Für Benutzer '%s' auf Host '%s' gibt es keine solche Berechtigung

  • Fehler: 1142 SQLSTATE: 42000 (ER_TABLEACCESS_DENIED_ERROR)

    Meldung: %s Befehl nicht erlaubt für Benutzer '%s'@'%s' auf Tabelle '%s'

  • Fehler: 1143 SQLSTATE: 42000 (ER_COLUMNACCESS_DENIED_ERROR)

    Meldung: %s Befehl nicht erlaubt für Benutzer '%s'@'%s' und Feld '%s' in Tabelle '%s'

  • Fehler: 1144 SQLSTATE: 42000 (ER_ILLEGAL_GRANT_FOR_TABLE)

    Meldung: Unzulässiger GRANT- oder REVOKE-Befehl. Verfügbare Berechtigungen sind im Handbuch aufgeführt

  • Fehler: 1145 SQLSTATE: 42000 (ER_GRANT_WRONG_HOST_OR_USER)

    Meldung: Das Host- oder User-Argument für GRANT ist zu lang

  • Fehler: 1146 SQLSTATE: 42S02 (ER_NO_SUCH_TABLE)

    Meldung: Tabelle '%s.%s' existiert nicht

  • Fehler: 1147 SQLSTATE: 42000 (ER_NONEXISTING_TABLE_GRANT)

    Meldung: Eine solche Berechtigung ist für User '%s' auf Host '%s' an Tabelle '%s' nicht definiert

  • Fehler: 1148 SQLSTATE: 42000 (ER_NOT_ALLOWED_COMMAND)

    Meldung: Der verwendete Befehl ist in dieser MySQL-Version nicht zulässig

  • Fehler: 1149 SQLSTATE: 42000 (ER_SYNTAX_ERROR)

    Meldung: Fehler in der SQL-Syntax. Bitte die korrekte Syntax im Handbuch nachschlagen

  • Fehler: 1150 SQLSTATE: HY000 (ER_DELAYED_CANT_CHANGE_LOCK)

    Meldung: Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%s' nicht erhalten

  • Fehler: 1151 SQLSTATE: HY000 (ER_TOO_MANY_DELAYED_THREADS)

    Meldung: Zu viele verzögerte (DELAYED) Threads in Verwendung

  • Fehler: 1152 SQLSTATE: 08S01 (ER_ABORTING_CONNECTION)

    Meldung: Abbruch der Verbindung %ld zur Datenbank '%s'. Benutzer: '%s' (%s)

  • Fehler: 1153 SQLSTATE: 08S01 (ER_NET_PACKET_TOO_LARGE)

    Meldung: Empfangenes Paket ist größer als 'max_allowed_packet' Bytes

  • Fehler: 1154 SQLSTATE: 08S01 (ER_NET_READ_ERROR_FROM_PIPE)

    Meldung: Lese-Fehler bei einer Verbindungs-Pipe

  • Fehler: 1155 SQLSTATE: 08S01 (ER_NET_FCNTL_ERROR)

    Meldung: fcntl() lieferte einen Fehler

  • Fehler: 1156 SQLSTATE: 08S01 (ER_NET_PACKETS_OUT_OF_ORDER)

    Meldung: Pakete nicht in der richtigen Reihenfolge empfangen

  • Fehler: 1157 SQLSTATE: 08S01 (ER_NET_UNCOMPRESS_ERROR)

    Meldung: Kommunikationspaket lässt sich nicht entpacken

  • Fehler: 1158 SQLSTATE: 08S01 (ER_NET_READ_ERROR)

    Meldung: Fehler beim Lesen eines Kommunikationspakets

  • Fehler: 1159 SQLSTATE: 08S01 (ER_NET_READ_INTERRUPTED)

    Meldung: Zeitüberschreitung beim Lesen eines Kommunikationspakets

  • Fehler: 1160 SQLSTATE: 08S01 (ER_NET_ERROR_ON_WRITE)

    Meldung: Fehler beim Schreiben eines Kommunikationspakets

  • Fehler: 1161 SQLSTATE: 08S01 (ER_NET_WRITE_INTERRUPTED)

    Meldung: Zeitüberschreitung beim Schreiben eines Kommunikationspakets

  • Fehler: 1162 SQLSTATE: 42000 (ER_TOO_LONG_STRING)

    Meldung: Ergebnis-String ist länger als 'max_allowed_packet' Bytes

  • Fehler: 1163 SQLSTATE: 42000 (ER_TABLE_CANT_HANDLE_BLOB)

    Meldung: Der verwendete Tabellentyp unterstützt keine BLOB- und TEXT-Felder

  • Fehler: 1164 SQLSTATE: 42000 (ER_TABLE_CANT_HANDLE_AUTO_INCREMENT)

    Meldung: Der verwendete Tabellentyp unterstützt keine AUTO_INCREMENT-Felder

  • Fehler: 1165 SQLSTATE: HY000 (ER_DELAYED_INSERT_TABLE_LOCKED)

    Meldung: INSERT DELAYED kann für Tabelle '%s' nicht verwendet werden, da sie mit LOCK TABLES gesperrt ist

  • Fehler: 1166 SQLSTATE: 42000 (ER_WRONG_COLUMN_NAME)

    Meldung: Falscher Spaltenname '%s'

  • Fehler: 1167 SQLSTATE: 42000 (ER_WRONG_KEY_COLUMN)

    Meldung: Die verwendete Speicher-Engine kann die Spalte '%s' nicht indizieren

  • Fehler: 1168 SQLSTATE: HY000 (ER_WRONG_MRG_TABLE)

    Meldung: Nicht alle Tabellen in der MERGE-Tabelle sind gleich definiert

  • Fehler: 1169 SQLSTATE: 23000 (ER_DUP_UNIQUE)

    Meldung: Schreiben in Tabelle '%s' nicht möglich wegen einer Eindeutigkeitsbeschränkung (unique constraint)

  • Fehler: 1170 SQLSTATE: 42000 (ER_BLOB_KEY_WITHOUT_LENGTH)

    Meldung: BLOB- oder TEXT-Spalte '%s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet

  • Fehler: 1171 SQLSTATE: 42000 (ER_PRIMARY_CANT_HAVE_NULL)

    Meldung: Alle Teile eines PRIMARY KEY müssen als NOT NULL definiert sein. Wenn NULL in einem Schlüssel benötigt wird, muss ein UNIQUE-Schlüssel verwendet werden

  • Fehler: 1172 SQLSTATE: 42000 (ER_TOO_MANY_ROWS)

    Meldung: Ergebnis besteht aus mehr als einer Zeile

  • Fehler: 1173 SQLSTATE: 42000 (ER_REQUIRES_PRIMARY_KEY)

    Meldung: Dieser Tabellentyp benötigt einen Primärschlüssel (PRIMARY KEY)

  • Fehler: 1174 SQLSTATE: HY000 (ER_NO_RAID_COMPILED)

    Meldung: Diese MySQL-Version ist nicht mit RAID-Unterstützung kompiliert

  • Fehler: 1175 SQLSTATE: HY000 (ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE)

    Meldung: MySQL läuft im sicheren Aktualisierungsmodus (safe update mode). Sie haben versucht, eine Tabelle zu aktualisieren, ohne in der WHERE-Klausel ein KEY-Feld anzugeben

  • Fehler: 1176 SQLSTATE: 42000 (ER_KEY_DOES_NOT_EXITS)

    Meldung: Schlüssel '%s' existiert in der Tabelle '%s' nicht

  • Fehler: 1177 SQLSTATE: 42000 (ER_CHECK_NO_SUCH_TABLE)

    Meldung: Kann Tabelle nicht öffnen

  • Fehler: 1178 SQLSTATE: 42000 (ER_CHECK_NOT_IMPLEMENTED)

    Meldung: Die Speicher-Engine für diese Tabelle unterstützt kein %s

  • Fehler: 1179 SQLSTATE: 25000 (ER_CANT_DO_THIS_DURING_AN_TRANSACTION)

    Meldung: Sie dürfen diesen Befehl nicht in einer Transaktion ausführen

  • Fehler: 1180 SQLSTATE: HY000 (ER_ERROR_DURING_COMMIT)

    Meldung: Fehler %d beim COMMIT

  • Fehler: 1181 SQLSTATE: HY000 (ER_ERROR_DURING_ROLLBACK)

    Meldung: Fehler %d beim ROLLBACK

  • Fehler: 1182 SQLSTATE: HY000 (ER_ERROR_DURING_FLUSH_LOGS)

    Meldung: Fehler %d bei FLUSH_LOGS

  • Fehler: 1183 SQLSTATE: HY000 (ER_ERROR_DURING_CHECKPOINT)

    Meldung: Fehler %d bei CHECKPOINT

  • Fehler: 1184 SQLSTATE: 08S01 (ER_NEW_ABORTING_CONNECTION)

    Meldung: Abbruch der Verbindung %ld zur Datenbank '%s'. Benutzer: '%s', Host: '%s' (%s)

  • Fehler: 1185 SQLSTATE: HY000 (ER_DUMP_NOT_IMPLEMENTED)

    Meldung: Die Speicher-Engine für die Tabelle unterstützt keinen binären Tabellen-Dump

  • Fehler: 1186 SQLSTATE: HY000 (ER_FLUSH_MASTER_BINLOG_CLOSED)

    Meldung: Binlog geschlossen. Kann RESET MASTER nicht ausführen

  • Fehler: 1187 SQLSTATE: HY000 (ER_INDEX_REBUILD)

    Meldung: Neuerstellung des Index der Dump-Tabelle '%s' fehlgeschlagen

  • Fehler: 1188 SQLSTATE: HY000 (ER_MASTER)

    Meldung: Fehler vom Master: '%s'

  • Fehler: 1189 SQLSTATE: 08S01 (ER_MASTER_NET_READ)

    Meldung: Netzfehler beim Lesen vom Master

  • Fehler: 1190 SQLSTATE: 08S01 (ER_MASTER_NET_WRITE)

    Meldung: Netzfehler beim Schreiben zum Master

  • Fehler: 1191 SQLSTATE: HY000 (ER_FT_MATCHING_KEY_NOT_FOUND)

    Meldung: Kann keinen FULLTEXT-Index finden, der der Feldliste entspricht

  • Fehler: 1192 SQLSTATE: HY000 (ER_LOCK_OR_ACTIVE_TRANSACTION)

    Meldung: Kann den angegebenen Befehl wegen einer aktiven Tabellensperre oder einer aktiven Transaktion nicht ausführen

  • Fehler: 1193 SQLSTATE: HY000 (ER_UNKNOWN_SYSTEM_VARIABLE)

    Meldung: Unbekannte Systemvariable '%s'

  • Fehler: 1194 SQLSTATE: HY000 (ER_CRASHED_ON_USAGE)

    Meldung: Tabelle '%s' ist als defekt markiert und sollte repariert werden

  • Fehler: 1195 SQLSTATE: HY000 (ER_CRASHED_ON_REPAIR)

    Meldung: Tabelle '%s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl

  • Fehler: 1196 SQLSTATE: HY000 (ER_WARNING_NOT_COMPLETE_ROLLBACK)

    Meldung: Änderungen an einigen nicht transaktionalen Tabellen konnten nicht zurückgerollt werden

  • Fehler: 1197 SQLSTATE: HY000 (ER_TRANS_CACHE_FULL)

    Meldung: Transaktionen, die aus mehreren Befehlen bestehen, benötigten mehr als 'max_binlog_cache_size' Bytes an Speicher. Btte vergrössern Sie diese Server-Variable versuchen Sie es noch einmal

  • Fehler: 1198 SQLSTATE: HY000 (ER_SLAVE_MUST_STOP)

    Meldung: Diese Operation kann bei einem aktiven Slave nicht durchgeführt werden. Bitte zuerst STOP SLAVE ausführen

  • Fehler: 1199 SQLSTATE: HY000 (ER_SLAVE_NOT_RUNNING)

    Meldung: Diese Operation benötigt einen aktiven Slave. Bitte Slave konfigurieren und mittels START SLAVE aktivieren

  • Fehler: 1200 SQLSTATE: HY000 (ER_BAD_SLAVE)

    Meldung: Der Server ist nicht als Slave konfiguriert. Bitte in der Konfigurationsdatei oder mittels CHANGE MASTER TO beheben

  • Fehler: 1201 SQLSTATE: HY000 (ER_MASTER_INFO)

    Meldung: Konnte Master-Info-Struktur nicht initialisieren. Weitere Fehlermeldungen können im MySQL-Error-Log eingesehen werden

  • Fehler: 1202 SQLSTATE: HY000 (ER_SLAVE_THREAD)

    Meldung: Konnte Slave-Thread nicht starten. Bitte System-Ressourcen überprüfen

  • Fehler: 1203 SQLSTATE: 42000 (ER_TOO_MANY_USER_CONNECTIONS)

    Meldung: Benutzer '%s' hat mehr als 'max_user_connections' aktive Verbindungen

  • Fehler: 1204 SQLSTATE: HY000 (ER_SET_CONSTANTS_ONLY)

    Meldung: Bei SET dürfen nur konstante Ausdrücke verwendet werden

  • Fehler: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)

    Meldung: Beim Warten auf eine Sperre wurde die zulässige Wartezeit überschritten. Bitte versuchen Sie, die Transaktion neu zu starten

  • Fehler: 1206 SQLSTATE: HY000 (ER_LOCK_TABLE_FULL)

    Meldung: Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle

  • Fehler: 1207 SQLSTATE: 25000 (ER_READ_ONLY_TRANSACTION)

    Meldung: Während einer READ-UNCOMMITTED-Transaktion können keine UPDATE-Sperren angefordert werden

  • Fehler: 1208 SQLSTATE: HY000 (ER_DROP_DB_WITH_READ_LOCK)

    Meldung: DROP DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält

  • Fehler: 1209 SQLSTATE: HY000 (ER_CREATE_DB_WITH_READ_LOCK)

    Meldung: CREATE DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält

  • Fehler: 1210 SQLSTATE: HY000 (ER_WRONG_ARGUMENTS)

    Meldung: Falsche Argumente für %s

  • Fehler: 1211 SQLSTATE: 42000 (ER_NO_PERMISSION_TO_CREATE_USER)

    Meldung: '%s'@'%s' ist nicht berechtigt, neue Benutzer hinzuzufügen

  • Fehler: 1212 SQLSTATE: HY000 (ER_UNION_TABLES_IN_DIFFERENT_DIR)

    Meldung: Falsche Tabellendefinition. Alle MERGE-Tabellen müssen sich in derselben Datenbank befinden

  • Fehler: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)

    Meldung: Beim Versuch, eine Sperre anzufordern, ist ein Deadlock aufgetreten. Versuchen Sie, die Transaktion neu zu starten

  • Fehler: 1214 SQLSTATE: HY000 (ER_TABLE_CANT_HANDLE_FT)

    Meldung: Der verwendete Tabellentyp unterstützt keine FULLTEXT-Indizes

  • Fehler: 1215 SQLSTATE: HY000 (ER_CANNOT_ADD_FOREIGN)

    Meldung: Fremdschlüssel-Beschränkung kann nicht hinzugefügt werden

  • Fehler: 1216 SQLSTATE: 23000 (ER_NO_REFERENCED_ROW)

    Meldung: Hinzufügen oder Aktualisieren eines Kind-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl

  • Fehler: 1217 SQLSTATE: 23000 (ER_ROW_IS_REFERENCED)

    Meldung: Löschen oder Aktualisieren eines Eltern-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl

  • Fehler: 1218 SQLSTATE: 08S01 (ER_CONNECT_TO_MASTER)

    Meldung: Fehler bei der Verbindung zum Master: %s

  • Fehler: 1219 SQLSTATE: HY000 (ER_QUERY_ON_MASTER)

    Meldung: Beim Ausführen einer Abfrage auf dem Master trat ein Fehler auf: %s

  • Fehler: 1220 SQLSTATE: HY000 (ER_ERROR_WHEN_EXECUTING_COMMAND)

    Meldung: Fehler beim Ausführen des Befehls %s: %s

  • Fehler: 1221 SQLSTATE: HY000 (ER_WRONG_USAGE)

    Meldung: Falsche Verwendung von %s und %s

  • Fehler: 1222 SQLSTATE: 21000 (ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT)

    Meldung: Die verwendeten SELECT-Befehle liefern unterschiedliche Anzahlen von Feldern zurück

  • Fehler: 1223 SQLSTATE: HY000 (ER_CANT_UPDATE_WITH_READLOCK)

    Meldung: Augrund eines READ-LOCK-Konflikts kann die Abfrage nicht ausgeführt werden

  • Fehler: 1224 SQLSTATE: HY000 (ER_MIXING_NOT_ALLOWED)

    Meldung: Die gleichzeitige Verwendung von Tabellen mit und ohne Transaktionsunterstützung ist deaktiviert

  • Fehler: 1225 SQLSTATE: HY000 (ER_DUP_ARGUMENT)

    Meldung: Option '%s' wird im Befehl zweimal verwendet

  • Fehler: 1226 SQLSTATE: 42000 (ER_USER_LIMIT_REACHED)

    Meldung: Benutzer '%s' hat die Ressourcenbeschränkung '%s' überschritten (aktueller Wert: %ld)

  • Fehler: 1227 SQLSTATE: 42000 (ER_SPECIFIC_ACCESS_DENIED_ERROR)

    Meldung: Kein Zugriff. Hierfür wird die Berechtigung %s benötigt

  • Fehler: 1228 SQLSTATE: HY000 (ER_LOCAL_VARIABLE)

    Meldung: Variable '%s' ist eine lokale Variable und kann nicht mit SET GLOBAL verändert werden

  • Fehler: 1229 SQLSTATE: HY000 (ER_GLOBAL_VARIABLE)

    Meldung: Variable '%s' ist eine globale Variable und muss mit SET GLOBAL verändert werden

  • Fehler: 1230 SQLSTATE: 42000 (ER_NO_DEFAULT)

    Meldung: Variable '%s' hat keinen Vorgabewert

  • Fehler: 1231 SQLSTATE: 42000 (ER_WRONG_VALUE_FOR_VAR)

    Meldung: Variable '%s' kann nicht auf '%s' gesetzt werden

  • Fehler: 1232 SQLSTATE: 42000 (ER_WRONG_TYPE_FOR_VAR)

    Meldung: Falscher Argumenttyp für Variable '%s'

  • Fehler: 1233 SQLSTATE: HY000 (ER_VAR_CANT_BE_READ)

    Meldung: Variable '%s' kann nur verändert, nicht gelesen werden

  • Fehler: 1234 SQLSTATE: 42000 (ER_CANT_USE_OPTION_HERE)

    Meldung: Falsche Verwendung oder Platzierung von '%s'

  • Fehler: 1235 SQLSTATE: 42000 (ER_NOT_SUPPORTED_YET)

    Meldung: Diese MySQL-Version unterstützt '%s' nicht

  • Fehler: 1236 SQLSTATE: HY000 (ER_MASTER_FATAL_ERROR_READING_BINLOG)

    Meldung: Schwerer Fehler %d: '%s vom Master beim Lesen des binären Logs

  • Fehler: 1237 SQLSTATE: HY000 (ER_SLAVE_IGNORED_TABLE)

    Meldung: Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert

  • Fehler: 1238 SQLSTATE: HY000 (ER_INCORRECT_GLOBAL_LOCAL_VAR)

    Meldung: Variable '%s' ist eine %s-Variable

  • Fehler: 1239 SQLSTATE: 42000 (ER_WRONG_FK_DEF)

    Meldung: Falsche Fremdschlüssel-Definition für '%s': %s

  • Fehler: 1240 SQLSTATE: HY000 (ER_KEY_REF_DO_NOT_MATCH_TABLE_REF)

    Meldung: Schlüssel- und Tabellenverweis passen nicht zusammen

  • Fehler: 1241 SQLSTATE: 21000 (ER_OPERAND_COLUMNS)

    Meldung: Operand sollte %d Spalte(n) enthalten

  • Fehler: 1242 SQLSTATE: 21000 (ER_SUBQUERY_NO_1_ROW)

    Meldung: Unterabfrage lieferte mehr als einen Datensatz zurück

  • Fehler: 1243 SQLSTATE: HY000 (ER_UNKNOWN_STMT_HANDLER)

    Meldung: Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben

  • Fehler: 1244 SQLSTATE: HY000 (ER_CORRUPT_HELP_DB)

    Meldung: Die Hilfe-Datenbank ist beschädigt oder existiert nicht

  • Fehler: 1245 SQLSTATE: HY000 (ER_CYCLIC_REFERENCE)

    Meldung: Zyklischer Verweis in Unterabfragen

  • Fehler: 1246 SQLSTATE: HY000 (ER_AUTO_CONVERT)

    Meldung: Feld '%s' wird von %s nach %s umgewandelt

  • Fehler: 1247 SQLSTATE: 42S22 (ER_ILLEGAL_REFERENCE)

    Meldung: Verweis '%s' wird nicht unterstützt (%s)

  • Fehler: 1248 SQLSTATE: 42000 (ER_DERIVED_MUST_HAVE_ALIAS)

    Meldung: Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden

  • Fehler: 1249 SQLSTATE: 01000 (ER_SELECT_REDUCED)

    Meldung: Select %u wurde während der Optimierung reduziert

  • Fehler: 1250 SQLSTATE: 42000 (ER_TABLENAME_NOT_ALLOWED_HERE)

    Meldung: Tabelle '%s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %s verwendet werden

  • Fehler: 1251 SQLSTATE: 08004 (ER_NOT_SUPPORTED_AUTH_MODE)

    Meldung: Client unterstützt das vom Server erwartete Authentifizierungsprotokoll nicht. Bitte aktualisieren Sie Ihren MySQL-Client

  • Fehler: 1252 SQLSTATE: 42000 (ER_SPATIAL_CANT_HAVE_NULL)

    Meldung: Alle Teile eines SPATIAL-Index müssen als NOT NULL deklariert sein

  • Fehler: 1253 SQLSTATE: 42000 (ER_COLLATION_CHARSET_MISMATCH)

    Meldung: COLLATION '%s' ist für CHARACTER SET '%s' ungültig

  • Fehler: 1254 SQLSTATE: HY000 (ER_SLAVE_WAS_RUNNING)

    Meldung: Slave läuft bereits

  • Fehler: 1255 SQLSTATE: HY000 (ER_SLAVE_WAS_NOT_RUNNING)

    Meldung: Slave wurde bereits angehalten

  • Fehler: 1256 SQLSTATE: HY000 (ER_TOO_BIG_FOR_UNCOMPRESS)

    Meldung: Unkomprimierte Daten sind zu groß. Die maximale Größe beträgt %d (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)

  • Fehler: 1257 SQLSTATE: HY000 (ER_ZLIB_Z_MEM_ERROR)

    Meldung: ZLIB: Nicht genug Speicher

  • Fehler: 1258 SQLSTATE: HY000 (ER_ZLIB_Z_BUF_ERROR)

    Meldung: ZLIB: Im Ausgabepuffer ist nicht genug Platz vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)

  • Fehler: 1259 SQLSTATE: HY000 (ER_ZLIB_Z_DATA_ERROR)

    Meldung: ZLIB: Eingabedaten beschädigt

  • Fehler: 1260 SQLSTATE: HY000 (ER_CUT_VALUE_GROUP_CONCAT)

    Meldung: %d Zeile(n) durch GROUP_CONCAT() abgeschnitten

  • Fehler: 1261 SQLSTATE: 01000 (ER_WARN_TOO_FEW_RECORDS)

    Meldung: Zeile %ld enthält nicht für alle Felder Daten

  • Fehler: 1262 SQLSTATE: 01000 (ER_WARN_TOO_MANY_RECORDS)

    Meldung: Zeile %ld gekürzt, die Zeile enthielt mehr Daten, als es Eingabefelder gibt

  • Fehler: 1263 SQLSTATE: 22004 (ER_WARN_NULL_TO_NOTNULL)

    Meldung: Feld auf Vorgabewert gesetzt, da NULL für NOT-NULL-Feld '%s' in Zeile %ld angegeben

  • Fehler: 1264 SQLSTATE: 22003 (ER_WARN_DATA_OUT_OF_RANGE)

    Meldung: Out of range value for column '%s' at row %ld

  • Fehler: 1265 SQLSTATE: 01000 (WARN_DATA_TRUNCATED)

    Meldung: Daten abgeschnitten für Feld '%s' in Zeile %ld

  • Fehler: 1266 SQLSTATE: HY000 (ER_WARN_USING_OTHER_HANDLER)

    Meldung: Für Tabelle '%s' wird Speicher-Engine %s benutzt

  • Fehler: 1267 SQLSTATE: HY000 (ER_CANT_AGGREGATE_2COLLATIONS)

    Meldung: Unerlaubte Mischung von Sortierreihenfolgen (%s, %s) und (%s, %s) für Operation '%s'

  • Fehler: 1268 SQLSTATE: HY000 (ER_DROP_USER)

    Meldung: Kann einen oder mehrere der angegebenen Benutzer nicht löschen

  • Fehler: 1269 SQLSTATE: HY000 (ER_REVOKE_GRANTS)

    Meldung: Kann nicht alle Berechtigungen widerrufen, die für einen oder mehrere Benutzer gewährt wurden

  • Fehler: 1270 SQLSTATE: HY000 (ER_CANT_AGGREGATE_3COLLATIONS)

    Meldung: Unerlaubte Mischung von Sortierreihenfolgen (%s, %s), (%s, %s), (%s, %s) für Operation '%s'

  • Fehler: 1271 SQLSTATE: HY000 (ER_CANT_AGGREGATE_NCOLLATIONS)

    Meldung: Unerlaubte Mischung von Sortierreihenfolgen für Operation '%s'

  • Fehler: 1272 SQLSTATE: HY000 (ER_VARIABLE_IS_NOT_STRUCT)

    Meldung: Variable '%s' ist keine Variablen-Komponente (kann nicht als XXXX.variablen_name verwendet werden)

  • Fehler: 1273 SQLSTATE: HY000 (ER_UNKNOWN_COLLATION)

    Meldung: Unbekannte Sortierreihenfolge: '%s'

  • Fehler: 1274 SQLSTATE: HY000 (ER_SLAVE_IGNORED_SSL_PARAMS)

    Meldung: SSL-Parameter in CHANGE MASTER werden ignoriert, weil dieser MySQL-Slave ohne SSL-Unterstützung kompiliert wurde. Sie können aber später verwendet werden, wenn ein MySQL-Slave mit SSL gestartet wird

  • Fehler: 1275 SQLSTATE: HY000 (ER_SERVER_IS_IN_SECURE_AUTH_MODE)

    Meldung: Server läuft im Modus --secure-auth, aber '%s'@'%s' hat ein Passwort im alten Format. Bitte Passwort ins neue Format ändern

  • Fehler: 1276 SQLSTATE: HY000 (ER_WARN_FIELD_RESOLVED)

    Meldung: Feld oder Verweis '%s%s%s%s%s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst

  • Fehler: 1277 SQLSTATE: HY000 (ER_BAD_SLAVE_UNTIL_COND)

    Meldung: Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL

  • Fehler: 1278 SQLSTATE: HY000 (ER_MISSING_SKIP_SLAVE)

    Meldung: Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn ein Slave-Server unerwartet neu startet

  • Fehler: 1279 SQLSTATE: HY000 (ER_UNTIL_COND_IGNORED)

    Meldung: SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert

  • Fehler: 1280 SQLSTATE: 42000 (ER_WRONG_NAME_FOR_INDEX)

    Meldung: Falscher Indexname '%s'

  • Fehler: 1281 SQLSTATE: 42000 (ER_WRONG_NAME_FOR_CATALOG)

    Meldung: Falscher Katalogname '%s'

  • Fehler: 1282 SQLSTATE: HY000 (ER_WARN_QC_RESIZE)

    Meldung: Änderung der Query-Cache-Größe auf %lu fehlgeschlagen; neue Query-Cache-Größe ist %lu

  • Fehler: 1283 SQLSTATE: HY000 (ER_BAD_FT_COLUMN)

    Meldung: Feld '%s' kann nicht Teil eines FULLTEXT-Index sein

  • Fehler: 1284 SQLSTATE: HY000 (ER_UNKNOWN_KEY_CACHE)

    Meldung: Unbekannter Schlüssel-Cache '%s'

  • Fehler: 1285 SQLSTATE: HY000 (ER_WARN_HOSTNAME_WONT_WORK)

    Meldung: MySQL wurde mit --skip-name-resolve gestartet. Diese Option darf nicht verwendet werden, damit diese Rechtevergabe möglich ist

  • Fehler: 1286 SQLSTATE: 42000 (ER_UNKNOWN_STORAGE_ENGINE)

    Meldung: Unbekannte Speicher-Engine '%s'

  • Fehler: 1287 SQLSTATE: HY000 (ER_UNUSED_1)

    Meldung: '%s' ist veraltet. Bitte benutzen Sie '%s'

  • Fehler: 1288 SQLSTATE: HY000 (ER_NON_UPDATABLE_TABLE)

    Meldung: Die Zieltabelle %s von %s ist nicht aktualisierbar

  • Fehler: 1289 SQLSTATE: HY000 (ER_FEATURE_DISABLED)

    Meldung: Das Feature '%s' ist ausgeschaltet, Sie müssen MySQL mit '%s' übersetzen, damit es verfügbar ist

  • Fehler: 1290 SQLSTATE: HY000 (ER_OPTION_PREVENTS_STATEMENT)

    Meldung: Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen

  • Fehler: 1291 SQLSTATE: HY000 (ER_DUPLICATED_VALUE_IN_TYPE)

    Meldung: Feld '%s' hat doppelten Wert '%s' in %s

  • Fehler: 1292 SQLSTATE: 22007 (ER_TRUNCATED_WRONG_VALUE)

    Meldung: Falscher %s-Wert gekürzt: '%s'

  • Fehler: 1293 SQLSTATE: HY000 (ER_TOO_MUCH_AUTO_TIMESTAMP_COLS)

    Meldung: Fehlerhafte Tabellendefinition. Es kann nur eine einzige TIMESTAMP-Spalte mit CURRENT_TIMESTAMP als DEFAULT oder in einer ON-UPDATE-Klausel geben

  • Fehler: 1294 SQLSTATE: HY000 (ER_INVALID_ON_UPDATE)

    Meldung: Ungültige ON-UPDATE-Klausel für Spalte '%s'

  • Fehler: 1295 SQLSTATE: HY000 (ER_UNSUPPORTED_PS)

    Meldung: Dieser Befehl wird im Protokoll für vorbereitete Anweisungen noch nicht unterstützt

  • Fehler: 1296 SQLSTATE: HY000 (ER_GET_ERRMSG)

    Meldung: Fehler %d '%s' von %s

  • Fehler: 1297 SQLSTATE: HY000 (ER_GET_TEMPORARY_ERRMSG)

    Meldung: Temporärer Fehler %d '%s' von %s

  • Fehler: 1298 SQLSTATE: HY000 (ER_UNKNOWN_TIME_ZONE)

    Meldung: Unbekannte oder falsche Zeitzone: '%s'

  • Fehler: 1299 SQLSTATE: HY000 (ER_WARN_INVALID_TIMESTAMP)

    Meldung: Ungültiger TIMESTAMP-Wert in Feld '%s', Zeile %ld

  • Fehler: 1300 SQLSTATE: HY000 (ER_INVALID_CHARACTER_STRING)

    Meldung: Ungültiger %s-Zeichen-String: '%s'

  • Fehler: 1301 SQLSTATE: HY000 (ER_WARN_ALLOWED_PACKET_OVERFLOWED)

    Meldung: Ergebnis von %s() war größer als max_allowed_packet (%ld) Bytes und wurde deshalb gekürzt

  • Fehler: 1302 SQLSTATE: HY000 (ER_CONFLICTING_DECLARATIONS)

    Meldung: Widersprüchliche Deklarationen: '%s%s' und '%s%s'

  • Fehler: 1303 SQLSTATE: 2F003 (ER_SP_NO_RECURSIVE_CREATE)

    Meldung: Kann kein %s innerhalb einer anderen gespeicherten Routine erzeugen

  • Fehler: 1304 SQLSTATE: 42000 (ER_SP_ALREADY_EXISTS)

    Meldung: %s %s existiert bereits

  • Fehler: 1305 SQLSTATE: 42000 (ER_SP_DOES_NOT_EXIST)

    Meldung: %s %s existiert nicht

  • Fehler: 1306 SQLSTATE: HY000 (ER_SP_DROP_FAILED)

    Meldung: DROP %s %s ist fehlgeschlagen

  • Fehler: 1307 SQLSTATE: HY000 (ER_SP_STORE_FAILED)

    Meldung: CREATE %s %s ist fehlgeschlagen

  • Fehler: 1308 SQLSTATE: 42000 (ER_SP_LILABEL_MISMATCH)

    Meldung: %s ohne passende Marke: %s

  • Fehler: 1309 SQLSTATE: 42000 (ER_SP_LABEL_REDEFINE)

    Meldung: Neudefinition der Marke %s

  • Fehler: 1310 SQLSTATE: 42000 (ER_SP_LABEL_MISMATCH)

    Meldung: Ende-Marke %s ohne zugehörigen Anfang

  • Fehler: 1311 SQLSTATE: 01000 (ER_SP_UNINIT_VAR)

    Meldung: Zugriff auf nichtinitialisierte Variable %s

  • Fehler: 1312 SQLSTATE: 0A000 (ER_SP_BADSELECT)

    Meldung: PROCEDURE %s kann im gegebenen Kontext keine Ergebnismenge zurückgeben

  • Fehler: 1313 SQLSTATE: 42000 (ER_SP_BADRETURN)

    Meldung: RETURN ist nur innerhalb einer FUNCTION erlaubt

  • Fehler: 1314 SQLSTATE: 0A000 (ER_SP_BADSTATEMENT)

    Meldung: %s ist in gespeicherten Prozeduren nicht erlaubt

  • Fehler: 1315 SQLSTATE: 42000 (ER_UPDATE_LOG_DEPRECATED_IGNORED)

    Meldung: Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert

  • Fehler: 1316 SQLSTATE: 42000 (ER_UPDATE_LOG_DEPRECATED_TRANSLATED)

    Meldung: Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN übersetzt

  • Fehler: 1317 SQLSTATE: 70100 (ER_QUERY_INTERRUPTED)

    Meldung: Ausführung der Abfrage wurde unterbrochen

  • Fehler: 1318 SQLSTATE: 42000 (ER_SP_WRONG_NO_OF_ARGS)

    Meldung: Falsche Anzahl von Argumenten für %s %s; erwarte %u, erhalte %u

  • Fehler: 1319 SQLSTATE: 42000 (ER_SP_COND_MISMATCH)

    Meldung: Undefinierte CONDITION: %s

  • Fehler: 1320 SQLSTATE: 42000 (ER_SP_NORETURN)

    Meldung: Kein RETURN in FUNCTION %s gefunden

  • Fehler: 1321 SQLSTATE: 2F005 (ER_SP_NORETURNEND)

    Meldung: FUNCTION %s endete ohne RETURN

  • Fehler: 1322 SQLSTATE: 42000 (ER_SP_BAD_CURSOR_QUERY)

    Meldung: Cursor-Anweisung muss ein SELECT sein

  • Fehler: 1323 SQLSTATE: 42000 (ER_SP_BAD_CURSOR_SELECT)

    Meldung: Cursor-SELECT darf kein INTO haben

  • Fehler: 1324 SQLSTATE: 42000 (ER_SP_CURSOR_MISMATCH)

    Meldung: Undefinierter CURSOR: %s

  • Fehler: 1325 SQLSTATE: 24000 (ER_SP_CURSOR_ALREADY_OPEN)

    Meldung: Cursor ist schon geöffnet

  • Fehler: 1326 SQLSTATE: 24000 (ER_SP_CURSOR_NOT_OPEN)

    Meldung: Cursor ist nicht geöffnet

  • Fehler: 1327 SQLSTATE: 42000 (ER_SP_UNDECLARED_VAR)

    Meldung: Nicht deklarierte Variable: %s

  • Fehler: 1328 SQLSTATE: HY000 (ER_SP_WRONG_NO_OF_FETCH_ARGS)

    Meldung: Falsche Anzahl von FETCH-Variablen

  • Fehler: 1329 SQLSTATE: 02000 (ER_SP_FETCH_NO_DATA)

    Meldung: Keine Daten - null Zeilen geholt (fetch), ausgewählt oder verarbeitet

  • Fehler: 1330 SQLSTATE: 42000 (ER_SP_DUP_PARAM)

    Meldung: Doppelter Parameter: %s

  • Fehler: 1331 SQLSTATE: 42000 (ER_SP_DUP_VAR)

    Meldung: Doppelte Variable: %s

  • Fehler: 1332 SQLSTATE: 42000 (ER_SP_DUP_COND)

    Meldung: Doppelte Bedingung: %s

  • Fehler: 1333 SQLSTATE: 42000 (ER_SP_DUP_CURS)

    Meldung: Doppelter Cursor: %s

  • Fehler: 1334 SQLSTATE: HY000 (ER_SP_CANT_ALTER)

    Meldung: ALTER %s %s fehlgeschlagen

  • Fehler: 1335 SQLSTATE: 0A000 (ER_SP_SUBSELECT_NYI)

    Meldung: Subquery-Wert wird nicht unterstützt

  • Fehler: 1336 SQLSTATE: 0A000 (ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG)

    Meldung: %s ist in gespeicherten Funktionen und in Triggern nicht erlaubt

  • Fehler: 1337 SQLSTATE: 42000 (ER_SP_VARCOND_AFTER_CURSHNDLR)

    Meldung: Deklaration einer Variablen oder einer Bedingung nach der Deklaration eines Cursors oder eines Handlers

  • Fehler: 1338 SQLSTATE: 42000 (ER_SP_CURSOR_AFTER_HANDLER)

    Meldung: Deklaration eines Cursors nach der Deklaration eines Handlers

  • Fehler: 1339 SQLSTATE: 20000 (ER_SP_CASE_NOT_FOUND)

    Meldung: Fall für CASE-Anweisung nicht gefunden

  • Fehler: 1340 SQLSTATE: HY000 (ER_FPARSER_TOO_BIG_FILE)

    Meldung: Konfigurationsdatei '%s' ist zu groß

  • Fehler: 1341 SQLSTATE: HY000 (ER_FPARSER_BAD_HEADER)

    Meldung: Nicht wohlgeformter Dateityp-Header in Datei '%s'

  • Fehler: 1342 SQLSTATE: HY000 (ER_FPARSER_EOF_IN_COMMENT)

    Meldung: Unerwartetes Dateiende beim Parsen des Kommentars '%s'

  • Fehler: 1343 SQLSTATE: HY000 (ER_FPARSER_ERROR_IN_PARAMETER)

    Meldung: Fehler beim Parsen des Parameters '%s' (Zeile: '%s')

  • Fehler: 1344 SQLSTATE: HY000 (ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER)

    Meldung: Unerwartetes Dateiende beim Überspringen des unbekannten Parameters '%s'

  • Fehler: 1345 SQLSTATE: HY000 (ER_VIEW_NO_EXPLAIN)

    Meldung: EXPLAIN/SHOW kann nicht verlangt werden. Rechte für zugrunde liegende Tabelle fehlen

  • Fehler: 1346 SQLSTATE: HY000 (ER_FRM_UNKNOWN_TYPE)

    Meldung: Datei '%s' hat unbekannten Typ '%s' im Header

  • Fehler: 1347 SQLSTATE: HY000 (ER_WRONG_OBJECT)

    Meldung: '%s.%s' ist nicht %s

  • Fehler: 1348 SQLSTATE: HY000 (ER_NONUPDATEABLE_COLUMN)

    Meldung: Feld '%s' ist nicht aktualisierbar

  • Fehler: 1349 SQLSTATE: HY000 (ER_VIEW_SELECT_DERIVED)

    Meldung: SELECT der View enthält eine Subquery in der FROM-Klausel

  • Fehler: 1350 SQLSTATE: HY000 (ER_VIEW_SELECT_CLAUSE)

    Meldung: SELECT der View enthält eine '%s'-Klausel

  • Fehler: 1351 SQLSTATE: HY000 (ER_VIEW_SELECT_VARIABLE)

    Meldung: SELECT der View enthält eine Variable oder einen Parameter

  • Fehler: 1352 SQLSTATE: HY000 (ER_VIEW_SELECT_TMPTABLE)

    Meldung: SELECT der View verweist auf eine temporäre Tabelle '%s'

  • Fehler: 1353 SQLSTATE: HY000 (ER_VIEW_WRONG_LIST)

    Meldung: SELECT- und Feldliste der Views haben unterschiedliche Anzahlen von Spalten

  • Fehler: 1354 SQLSTATE: HY000 (ER_WARN_VIEW_MERGE)

    Meldung: View-Merge-Algorithmus kann hier momentan nicht verwendet werden (undefinierter Algorithmus wird angenommen)

  • Fehler: 1355 SQLSTATE: HY000 (ER_WARN_VIEW_WITHOUT_KEY)

    Meldung: Die aktualisierte View enthält nicht den vollständigen Schlüssel der zugrunde liegenden Tabelle

  • Fehler: 1356 SQLSTATE: HY000 (ER_VIEW_INVALID)

    Meldung: View '%s.%s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them

  • Fehler: 1357 SQLSTATE: HY000 (ER_SP_NO_DROP_SP)

    Meldung: Kann eine %s nicht von innerhalb einer anderen gespeicherten Routine löschen oder ändern

  • Fehler: 1358 SQLSTATE: HY000 (ER_SP_GOTO_IN_HNDLR)

    Meldung: GOTO ist im Handler einer gespeicherten Prozedur nicht erlaubt

  • Fehler: 1359 SQLSTATE: HY000 (ER_TRG_ALREADY_EXISTS)

    Meldung: Trigger existiert bereits

  • Fehler: 1360 SQLSTATE: HY000 (ER_TRG_DOES_NOT_EXIST)

    Meldung: Trigger existiert nicht

  • Fehler: 1361 SQLSTATE: HY000 (ER_TRG_ON_VIEW_OR_TEMP_TABLE)

    Meldung: '%s' des Triggers ist View oder temporäre Tabelle

  • Fehler: 1362 SQLSTATE: HY000 (ER_TRG_CANT_CHANGE_ROW)

    Meldung: Aktualisieren einer %s-Zeile ist in einem %-Trigger nicht erlaubt

  • Fehler: 1363 SQLSTATE: HY000 (ER_TRG_NO_SUCH_ROW_IN_TRG)

    Meldung: Es gibt keine %s-Zeile im %s-Trigger

  • Fehler: 1364 SQLSTATE: HY000 (ER_NO_DEFAULT_FOR_FIELD)

    Meldung: Feld '%s' hat keinen Vorgabewert

  • Fehler: 1365 SQLSTATE: 22012 (ER_DIVISION_BY_ZERO)

    Meldung: Division durch 0

  • Fehler: 1366 SQLSTATE: HY000 (ER_TRUNCATED_WRONG_VALUE_FOR_FIELD)

    Meldung: Falscher %s-Wert: '%s' für Feld '%s' in Zeile %ld

  • Fehler: 1367 SQLSTATE: 22007 (ER_ILLEGAL_VALUE_FOR_TYPE)

    Meldung: Nicht zulässiger %s-Wert '%s' beim Parsen gefunden

  • Fehler: 1368 SQLSTATE: HY000 (ER_VIEW_NONUPD_CHECK)

    Meldung: CHECK OPTION auf nicht-aktualisierbarem View '%s.%s'

  • Fehler: 1369 SQLSTATE: HY000 (ER_VIEW_CHECK_FAILED)

    Meldung: CHECK OPTION fehlgeschlagen: '%s.%s'

  • Fehler: 1370 SQLSTATE: 42000 (ER_PROCACCESS_DENIED_ERROR)

    Meldung: Befehl %s nicht zulässig für Benutzer '%s'@'%s' in Routine '%s'

  • Fehler: 1371 SQLSTATE: HY000 (ER_RELAY_LOG_FAIL)

    Meldung: Bereinigen alter Relais-Logs fehlgeschlagen: %s

  • Fehler: 1372 SQLSTATE: HY000 (ER_PASSWD_LENGTH)

    Meldung: Passwort-Hash sollte eine Hexdaezimalzahl mit %d Stellen sein

  • Fehler: 1373 SQLSTATE: HY000 (ER_UNKNOWN_TARGET_BINLOG)

    Meldung: Ziel-Log im Binlog-Index nicht gefunden

  • Fehler: 1374 SQLSTATE: HY000 (ER_IO_ERR_LOG_INDEX_READ)

    Meldung: Fehler beim Lesen der Log-Index-Datei

  • Fehler: 1375 SQLSTATE: HY000 (ER_BINLOG_PURGE_PROHIBITED)

    Meldung: Server-Konfiguration erlaubt keine Binlog-Bereinigung

  • Fehler: 1376 SQLSTATE: HY000 (ER_FSEEK_FAIL)

    Meldung: fseek() fehlgeschlagen

  • Fehler: 1377 SQLSTATE: HY000 (ER_BINLOG_PURGE_FATAL_ERR)

    Meldung: Schwerwiegender Fehler bei der Log-Bereinigung

  • Fehler: 1378 SQLSTATE: HY000 (ER_LOG_IN_USE)

    Meldung: Ein zu bereinigendes Log wird gerade benutzt, daher keine Bereinigung

  • Fehler: 1379 SQLSTATE: HY000 (ER_LOG_PURGE_UNKNOWN_ERR)

    Meldung: Unbekannter Fehler bei Log-Bereinigung

  • Fehler: 1380 SQLSTATE: HY000 (ER_RELAY_LOG_INIT)

    Meldung: Initialisierung der Relais-Log-Position fehlgeschlagen: %s

  • Fehler: 1381 SQLSTATE: HY000 (ER_NO_BINARY_LOGGING)

    Meldung: Sie verwenden keine Binärlogs

  • Fehler: 1382 SQLSTATE: HY000 (ER_RESERVED_SYNTAX)

    Meldung: Die Schreibweise '%s' ist für interne Zwecke des MySQL-Servers reserviert

  • Fehler: 1383 SQLSTATE: HY000 (ER_WSAS_FAILED)

    Meldung: WSAStartup fehlgeschlagen

  • Fehler: 1384 SQLSTATE: HY000 (ER_DIFF_GROUPS_PROC)

    Meldung: Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten

  • Fehler: 1385 SQLSTATE: HY000 (ER_NO_GROUP_FOR_PROC)

    Meldung: SELECT muss bei dieser Prozedur ein GROUP BY haben

  • Fehler: 1386 SQLSTATE: HY000 (ER_ORDER_WITH_PROC)

    Meldung: Kann bei dieser Prozedur keine ORDER-BY-Klausel verwenden

  • Fehler: 1387 SQLSTATE: HY000 (ER_LOGGING_PROHIBIT_CHANGING_OF)

    Meldung: Binärlogs und Replikation verhindern Wechsel des globalen Servers %s

  • Fehler: 1388 SQLSTATE: HY000 (ER_NO_FILE_MAPPING)

    Meldung: Kann Datei nicht abbilden: %s, Fehler: %d

  • Fehler: 1389 SQLSTATE: HY000 (ER_WRONG_MAGIC)

    Meldung: Falsche magische Zahlen in %s

  • Fehler: 1390 SQLSTATE: HY000 (ER_PS_MANY_PARAM)

    Meldung: Vorbereitete Anweisung enthält zu viele Platzhalter

  • Fehler: 1391 SQLSTATE: HY000 (ER_KEY_PART_0)

    Meldung: Länge des Schlüsselteils '%s' kann nicht 0 sein

  • Fehler: 1392 SQLSTATE: HY000 (ER_VIEW_CHECKSUM)

    Meldung: View-Text-Prüfsumme fehlgeschlagen

  • Fehler: 1393 SQLSTATE: HY000 (ER_VIEW_MULTIUPDATE)

    Meldung: Kann nicht mehr als eine Basistabelle über Join-View '%s.%s' ändern

  • Fehler: 1394 SQLSTATE: HY000 (ER_VIEW_NO_INSERT_FIELD_LIST)

    Meldung: Kann nicht ohne Feldliste in Join-View '%s.%s' einfügen

  • Fehler: 1395 SQLSTATE: HY000 (ER_VIEW_DELETE_MERGE_VIEW)

    Meldung: Kann nicht aus Join-View '%s.%s' löschen

  • Fehler: 1396 SQLSTATE: HY000 (ER_CANNOT_USER)

    Meldung: Operation %s schlug fehl für %s

  • Fehler: 1397 SQLSTATE: XAE04 (ER_XAER_NOTA)

    Meldung: XAER_NOTA: Unbekannte XID

  • Fehler: 1398 SQLSTATE: XAE05 (ER_XAER_INVAL)

    Meldung: XAER_INVAL: Ungültige Argumente (oder nicht unterstützter Befehl)

  • Fehler: 1399 SQLSTATE: XAE07 (ER_XAER_RMFAIL)

    Meldung: XAER_RMFAIL: DEr Befehl kann nicht ausgeführt werden, wenn die globale Transaktion im Zustand %s ist

  • Fehler: 1400 SQLSTATE: XAE09 (ER_XAER_OUTSIDE)

    Meldung: XAER_OUTSIDE: Einige Arbeiten werden außerhalb der globalen Transaktion verrichtet

  • Fehler: 1401 SQLSTATE: XAE03 (ER_XAER_RMERR)

    Meldung: XAER_RMERR: Schwerwiegender Fehler im Transaktionszweig - prüfen Sie Ihre Daten auf Konsistenz

  • Fehler: 1402 SQLSTATE: XA100 (ER_XA_RBROLLBACK)

    Meldung: XA_RBROLLBACK: Transaktionszweig wurde zurückgerollt

  • Fehler: 1403 SQLSTATE: 42000 (ER_NONEXISTING_PROC_GRANT)

    Meldung: Es gibt diese Berechtigung für Benutzer '%s' auf Host '%s' für Routine '%s' nicht

  • Fehler: 1404 SQLSTATE: HY000 (ER_PROC_AUTO_GRANT_FAIL)

    Meldung: Gewährung von EXECUTE- und ALTER-ROUTINE-Rechten fehlgeschlagen

  • Fehler: 1405 SQLSTATE: HY000 (ER_PROC_AUTO_REVOKE_FAIL)

    Meldung: Rücknahme aller Rechte für die gelöschte Routine fehlgeschlagen

  • Fehler: 1406 SQLSTATE: 22001 (ER_DATA_TOO_LONG)

    Meldung: Daten zu lang für Feld '%s' in Zeile %ld

  • Fehler: 1407 SQLSTATE: 42000 (ER_SP_BAD_SQLSTATE)

    Meldung: Ungültiger SQLSTATE: '%s'

  • Fehler: 1408 SQLSTATE: HY000 (ER_STARTUP)

    Meldung: %s: bereit für Verbindungen. Version: '%s' Socket: '%s' Port: %d %s

  • Fehler: 1409 SQLSTATE: HY000 (ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR)

    Meldung: Kann Wert aus Datei mit Zeilen fester Größe nicht in Variable laden

  • Fehler: 1410 SQLSTATE: 42000 (ER_CANT_CREATE_USER_WITH_GRANT)

    Meldung: Sie dürfen keinen Benutzer mit GRANT anlegen

  • Fehler: 1411 SQLSTATE: HY000 (ER_WRONG_VALUE_FOR_TYPE)

    Meldung: Falscher %s-Wert: '%s' für Funktion %s

  • Fehler: 1412 SQLSTATE: HY000 (ER_TABLE_DEF_CHANGED)

    Meldung: Tabellendefinition wurde geändert, bitte starten Sie die Transaktion neu

  • Fehler: 1413 SQLSTATE: 42000 (ER_SP_DUP_HANDLER)

    Meldung: Doppelter Handler im selben Block deklariert

  • Fehler: 1414 SQLSTATE: 42000 (ER_SP_NOT_VAR_ARG)

    Meldung: OUT- oder INOUT-Argument %d für Routine %s ist keine Variable

  • Fehler: 1415 SQLSTATE: 0A000 (ER_SP_NO_RETSET)

    Meldung: Rückgabe einer Ergebnismenge aus einer %s ist nicht erlaubt

  • Fehler: 1416 SQLSTATE: 22003 (ER_CANT_CREATE_GEOMETRY_OBJECT)

    Meldung: Kann kein Geometrieobjekt aus den Daten machen, die Sie dem GEOMETRY-Feld übergeben haben

  • Fehler: 1417 SQLSTATE: HY000 (ER_FAILED_ROUTINE_BREAK_BINLOG)

    Meldung: Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen aktualisiert wurden, enthält das Binärlog ihre Änderungen nicht

  • Fehler: 1418 SQLSTATE: HY000 (ER_BINLOG_UNSAFE_ROUTINE)

    Meldung: Diese Routine hat weder DETERMINISTIC, NO SQL noch READS SQL DATA in der Deklaration und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_routine_creators verwenden)

  • Fehler: 1419 SQLSTATE: HY000 (ER_BINLOG_CREATE_ROUTINE_NEED_SUPER)

    Meldung: Sie haben keine SUPER-Berechtigung und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_routine_creators verwenden)

  • Fehler: 1420 SQLSTATE: HY000 (ER_EXEC_STMT_WITH_OPEN_CURSOR)

    Meldung: Sie können keine vorbereitete Anweisung ausführen, die mit einem geöffneten Cursor verknüpft ist. Setzen Sie die Anweisung zurück, um sie neu auszuführen

  • Fehler: 1421 SQLSTATE: HY000 (ER_STMT_HAS_NO_OPEN_CURSOR)

    Meldung: Die Anweisung (%lu) hat keinen geöffneten Cursor

  • Fehler: 1422 SQLSTATE: HY000 (ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG)

    Meldung: Explizites oder implizites Commit ist in gespeicherten Funktionen und in Triggern nicht erlaubt

  • Fehler: 1423 SQLSTATE: HY000 (ER_NO_DEFAULT_FOR_VIEW_FIELD)

    Meldung: Ein Feld der dem View '%s.%s' zugrundeliegenden Tabelle hat keinen Vorgabewert

  • Fehler: 1424 SQLSTATE: HY000 (ER_SP_NO_RECURSION)

    Meldung: Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt

  • Fehler: 1425 SQLSTATE: 42000 (ER_TOO_BIG_SCALE)

    Meldung: Zu großer Skalierungsfaktor %d für Feld '%s' angegeben. Maximum ist %d

  • Fehler: 1426 SQLSTATE: 42000 (ER_TOO_BIG_PRECISION)

    Meldung: Zu große Genauigkeit %d für Feld '%s' angegeben. Maximum ist %d

  • Fehler: 1427 SQLSTATE: 42000 (ER_M_BIGGER_THAN_D)

    Meldung: Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%s')

  • Fehler: 1428 SQLSTATE: HY000 (ER_WRONG_LOCK_OF_SYSTEM_TABLE)

    Meldung: Sie können Schreibsperren auf der Systemtabelle '%s.%s' nicht mit anderen Tabellen kombinieren

  • Fehler: 1429 SQLSTATE: HY000 (ER_CONNECT_TO_FOREIGN_DATA_SOURCE)

    Meldung: Kann nicht mit Fremddatenquelle verbinden: %s

  • Fehler: 1430 SQLSTATE: HY000 (ER_QUERY_ON_FOREIGN_DATA_SOURCE)

    Meldung: Bei der Verarbeitung der Abfrage ist in der Fremddatenquelle ein Problem aufgetreten. Datenquellenfehlermeldung: %s

  • Fehler: 1431 SQLSTATE: HY000 (ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST)

    Meldung: Die Fremddatenquelle, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %s

  • Fehler: 1432 SQLSTATE: HY000 (ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE)

    Meldung: Kann föderierte Tabelle nicht erzeugen. Der Datenquellen-Verbindungsstring '%s' hat kein korrektes Format

  • Fehler: 1433 SQLSTATE: HY000 (ER_FOREIGN_DATA_STRING_INVALID)

    Meldung: Der Datenquellen-Verbindungsstring '%s' hat kein korrektes Format

  • Fehler: 1434 SQLSTATE: HY000 (ER_CANT_CREATE_FEDERATED_TABLE)

    Meldung: Kann föderierte Tabelle nicht erzeugen. Fremddatenquellenfehlermeldung: %s

  • Fehler: 1435 SQLSTATE: HY000 (ER_TRG_IN_WRONG_SCHEMA)

    Meldung: Trigger im falschen Schema

  • Fehler: 1436 SQLSTATE: HY000 (ER_STACK_OVERRUN_NEED_MORE)

    Meldung: Thread-Stack-Überlauf: %ld Bytes eines %ld-Byte-Stacks in Verwendung, und %ld Bytes benötigt. Verwenden Sie 'mysqld -O thread_stack=#', um einen größeren Stack anzugeben

  • Fehler: 1437 SQLSTATE: 42000 (ER_TOO_LONG_BODY)

    Meldung: Routinen-Body für '%s' ist zu lang

  • Fehler: 1438 SQLSTATE: HY000 (ER_WARN_CANT_DROP_DEFAULT_KEYCACHE)

    Meldung: Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden

  • Fehler: 1439 SQLSTATE: 42000 (ER_TOO_BIG_DISPLAYWIDTH)

    Meldung: Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%s' (Maximum: %d)

  • Fehler: 1440 SQLSTATE: XAE08 (ER_XAER_DUPID)

    Meldung: XAER_DUPID: Die XID existiert bereits

  • Fehler: 1441 SQLSTATE: 22008 (ER_DATETIME_FUNCTION_OVERFLOW)

    Meldung: Datetime-Funktion: %s Feldüberlauf

  • Fehler: 1442 SQLSTATE: HY000 (ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG)

    Meldung: Kann Tabelle '%s' in gespeicherter Funktion oder Trigger nicht aktualisieren, weil sie bereits von der Anweisung verwendet wird, die diese gespeicherte Funktion oder den Trigger aufrief

  • Fehler: 1443 SQLSTATE: HY000 (ER_VIEW_PREVENT_UPDATE)

    Meldung: Die Definition der Tabelle '%s' verhindert die Operation %s auf Tabelle '%s'

  • Fehler: 1444 SQLSTATE: HY000 (ER_PS_NO_RECURSION)

    Meldung: Die vorbereitete Anweisung enthält einen Aufruf einer gespeicherten Routine, die auf eben dieselbe Anweisung verweist. Es ist nicht erlaubt, eine vorbereitete Anweisung in solch rekursiver Weise auszuführen

  • Fehler: 1445 SQLSTATE: HY000 (ER_SP_CANT_SET_AUTOCOMMIT)

    Meldung: Es ist nicht erlaubt, innerhalb einer gespeicherten Funktion oder eines Triggers AUTOCOMMIT zu setzen

  • Fehler: 1446 SQLSTATE: HY000 (ER_MALFORMED_DEFINER)

    Meldung: Definierer des View ist nicht vollständig spezifiziert

  • Fehler: 1447 SQLSTATE: HY000 (ER_VIEW_FRM_NO_USER)

    Meldung: View '%s'.'%s' hat keine Definierer-Information (altes Tabellenformat). Der aktuelle Benutzer wird als Definierer verwendet. Bitte erstellen Sie den View neu

  • Fehler: 1448 SQLSTATE: HY000 (ER_VIEW_OTHER_USER)

    Meldung: Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%s'@'%s' zu erzeugen

  • Fehler: 1449 SQLSTATE: HY000 (ER_NO_SUCH_USER)

    Meldung: '%s'@'%s' ist nicht registriert

  • Fehler: 1450 SQLSTATE: HY000 (ER_FORBID_SCHEMA_CHANGE)

    Meldung: Wechsel des Schemas von '%s' auf '%s' ist nicht erlaubt

  • Fehler: 1451 SQLSTATE: 23000 (ER_ROW_IS_REFERENCED_2)

    Meldung: Kann Eltern-Zeile nicht löschen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%s)

  • Fehler: 1452 SQLSTATE: 23000 (ER_NO_REFERENCED_ROW_2)

    Meldung: Kann Kind-Zeile nicht hinzufügen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%s)

  • Fehler: 1453 SQLSTATE: 42000 (ER_SP_BAD_VAR_SHADOW)

    Meldung: Variable '%s' muss mit `...` geschützt oder aber umbenannt werden

  • Fehler: 1454 SQLSTATE: HY000 (ER_TRG_NO_DEFINER)

    Meldung: Kein Definierer-Attribut für Trigger '%s'.'%s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an.

  • Fehler: 1455 SQLSTATE: HY000 (ER_OLD_FILE_FORMAT)

    Meldung: '%s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen

  • Fehler: 1456 SQLSTATE: HY000 (ER_SP_RECURSION_LIMIT)

    Meldung: Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %s überschritten

  • Fehler: 1457 SQLSTATE: HY000 (ER_SP_PROC_TABLE_CORRUPT)

    Meldung: Routine %s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)

  • Fehler: 1458 SQLSTATE: 42000 (ER_SP_WRONG_NAME)

    Meldung: Ungültiger Routinenname '%s'

  • Fehler: 1459 SQLSTATE: HY000 (ER_TABLE_NEEDS_UPGRADE)

    Meldung: Tabellenaktualisierung erforderlich. Bitte zum Reparieren "REPAIR TABLE `%s`" eingeben!

  • Fehler: 1460 SQLSTATE: 42000 (ER_SP_NO_AGGREGATE)

    Meldung: AGGREGATE wird bei gespeicherten Funktionen nicht unterstützt

  • Fehler: 1461 SQLSTATE: 42000 (ER_MAX_PREPARED_STMT_COUNT_REACHED)

    Meldung: Kann nicht mehr Anweisungen als max_prepared_stmt_count erzeugen (aktueller Wert: %lu)

  • Fehler: 1462 SQLSTATE: HY000 (ER_VIEW_RECURSIVE)

    Meldung: `%s`.`%s` enthält View-Rekursion

  • Fehler: 1463 SQLSTATE: 42000 (ER_NON_GROUPING_FIELD_USED)

    Meldung: In der %s-Klausel wird das die Nicht-Gruppierungsspalte '%s' verwendet

  • Fehler: 1464 SQLSTATE: HY000 (ER_TABLE_CANT_HANDLE_SPKEYS)

    Meldung: Der verwendete Tabellentyp unterstützt keine SPATIAL-Indizes

  • Fehler: 1465 SQLSTATE: HY000 (ER_ILLEGAL_HA_CREATE_OPTION)

    Meldung: Speicher-Engine '%s' der Tabelle unterstützt die Option '%s' nicht

  • Fehler: 1466 SQLSTATE: HY000 (ER_PARTITION_REQUIRES_VALUES_ERROR)

    Meldung: %s-PARTITIONierung erfordert Definition von VALUES %s für jede Partition

  • Fehler: 1467 SQLSTATE: HY000 (ER_PARTITION_WRONG_VALUES_ERROR)

    Meldung: Nur %s-PARTITIONierung kann VALUES %s in der Partitionsdefinition verwenden

  • Fehler: 1468 SQLSTATE: HY000 (ER_PARTITION_MAXVALUE_ERROR)

    Meldung: MAXVALUE kann nur für die Definition der letzten Partition verwendet werden

  • Fehler: 1469 SQLSTATE: HY000 (ER_PARTITION_SUBPARTITION_ERROR)

    Meldung: Unterpartitionen dürfen nur HASH- oder KEY-Partitionen sein

  • Fehler: 1470 SQLSTATE: HY000 (ER_PARTITION_SUBPART_MIX_ERROR)

    Meldung: Unterpartitionen können nur Hash- oder Key-Partitionen sein

  • Fehler: 1471 SQLSTATE: HY000 (ER_PARTITION_WRONG_NO_PART_ERROR)

    Meldung: Falsche Anzahl von Partitionen definiert, stimmt nicht mit vorherigen Einstellungen überein

  • Fehler: 1472 SQLSTATE: HY000 (ER_PARTITION_WRONG_NO_SUBPART_ERROR)

    Meldung: Falsche Anzahl von Unterpartitionen definiert, stimmt nicht mit vorherigen Einstellungen überein

  • Fehler: 1473 SQLSTATE: HY000 (ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR)

    Meldung: Konstante oder Random-Ausdrücke in (Unter-)Partitionsfunktionen sind nicht erlaubt

  • Fehler: 1474 SQLSTATE: HY000 (ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR)

    Meldung: Ausdrücke in RANGE/LIST VALUES müssen konstant sein

  • Fehler: 1475 SQLSTATE: HY000 (ER_FIELD_NOT_FOUND_PART_ERROR)

    Meldung: Felder in der Feldliste der Partitionierungsfunktion wurden in der Tabelle nicht gefunden

  • Fehler: 1476 SQLSTATE: HY000 (ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR)

    Meldung: Eine Feldliste ist nur in KEY-Partitionen erlaubt

  • Fehler: 1477 SQLSTATE: HY000 (ER_INCONSISTENT_PARTITION_INFO_ERROR)

    Meldung: Die Partitionierungsinformationen in der frm-Datei stimmen nicht mit dem überein, was in die frm-Datei geschrieben werden kann

  • Fehler: 1478 SQLSTATE: HY000 (ER_PARTITION_FUNC_NOT_ALLOWED_ERROR)

    Meldung: Die %s-Funktion gibt einen falschen Typ zurück

  • Fehler: 1479 SQLSTATE: HY000 (ER_PARTITIONS_MUST_BE_DEFINED_ERROR)

    Meldung: Für %s-Partitionen muss jede Partition definiert sein

  • Fehler: 1480 SQLSTATE: HY000 (ER_RANGE_NOT_INCREASING_ERROR)

    Meldung: Werte in VALUES LESS THAN müssen für jede Partition strikt aufsteigend sein

  • Fehler: 1481 SQLSTATE: HY000 (ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR)

    Meldung: VALUES-Werte müssen vom selben Typ wie die Partitionierungsfunktion sein

  • Fehler: 1482 SQLSTATE: HY000 (ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR)

    Meldung: Mehrfachdefinition derselben Konstante bei Listen-Partitionierung

  • Fehler: 1483 SQLSTATE: HY000 (ER_PARTITION_ENTRY_ERROR)

    Meldung: Partitionierung kann in einer Abfrage nicht alleinstehend benutzt werden

  • Fehler: 1484 SQLSTATE: HY000 (ER_MIX_HANDLER_ERROR)

    Meldung: Das Vermischen von Handlern in Partitionen ist in dieser Version von MySQL nicht erlaubt

  • Fehler: 1485 SQLSTATE: HY000 (ER_PARTITION_NOT_DEFINED_ERROR)

    Meldung: Für die partitionierte Engine müssen alle %s definiert sein

  • Fehler: 1486 SQLSTATE: HY000 (ER_TOO_MANY_PARTITIONS_ERROR)

    Meldung: Es wurden zu vielen Partitionen (einschließlich Unterpartitionen) definiert

  • Fehler: 1487 SQLSTATE: HY000 (ER_SUBPARTITION_ERROR)

    Meldung: RANGE/LIST-Partitionierung kann bei Unterpartitionen nur zusammen mit HASH/KEY-Partitionierung verwendet werden

  • Fehler: 1488 SQLSTATE: HY000 (ER_CANT_CREATE_HANDLER_FILE)

    Meldung: Erzeugen einer spezifischen Handler-Datei fehlgeschlagen

  • Fehler: 1489 SQLSTATE: HY000 (ER_BLOB_FIELD_IN_PART_FUNC_ERROR)

    Meldung: In der Partitionierungsfunktion sind BLOB-Spalten nicht erlaubt

  • Fehler: 1490 SQLSTATE: HY000 (ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF)

    Meldung: A %s must include all columns in the table's partitioning function

  • Fehler: 1491 SQLSTATE: HY000 (ER_NO_PARTS_ERROR)

    Meldung: Eine Anzahl von %s = 0 ist kein erlaubter Wert

  • Fehler: 1492 SQLSTATE: HY000 (ER_PARTITION_MGMT_ON_NONPARTITIONED)

    Meldung: Partitionsverwaltung einer nicht partitionierten Tabelle ist nicht möglich

  • Fehler: 1493 SQLSTATE: HY000 (ER_FOREIGN_KEY_ON_PARTITIONED)

    Meldung: Fremdschlüssel-Beschränkungen sind im Zusammenhang mit Partitionierung nicht zulässig

  • Fehler: 1494 SQLSTATE: HY000 (ER_DROP_PARTITION_NON_EXISTENT)

    Meldung: Fehler in der Partitionsliste bei %s

  • Fehler: 1495 SQLSTATE: HY000 (ER_DROP_LAST_PARTITION)

    Meldung: Es lassen sich nicht sämtliche Partitionen löschen, benutzen Sie statt dessen DROP TABLE

  • Fehler: 1496 SQLSTATE: HY000 (ER_COALESCE_ONLY_ON_HASH_PARTITION)

    Meldung: COALESCE PARTITION kann nur auf HASH- oder KEY-Partitionen benutzt werden

  • Fehler: 1497 SQLSTATE: HY000 (ER_REORG_HASH_ONLY_ON_SAME_NO)

    Meldung: REORGANIZE PARTITION kann nur zur Reorganisation von Partitionen verwendet werden, nicht, um ihre Nummern zu ändern

  • Fehler: 1498 SQLSTATE: HY000 (ER_REORG_NO_PARAM_ERROR)

    Meldung: REORGANIZE PARTITION ohne Parameter kann nur für auto-partitionierte Tabellen verwendet werden, die HASH-Partitionierung benutzen

  • Fehler: 1499 SQLSTATE: HY000 (ER_ONLY_ON_RANGE_LIST_PARTITION)

    Meldung: %s PARTITION kann nur für RANGE- oder LIST-Partitionen verwendet werden

  • Fehler: 1500 SQLSTATE: HY000 (ER_ADD_PARTITION_SUBPART_ERROR)

    Meldung: Es wurde versucht, eine oder mehrere Partitionen mit der falschen Anzahl von Unterpartitionen hinzuzufügen

  • Fehler: 1501 SQLSTATE: HY000 (ER_ADD_PARTITION_NO_NEW_PARTITION)

    Meldung: Es muss zumindest eine Partition hinzugefügt werden

  • Fehler: 1502 SQLSTATE: HY000 (ER_COALESCE_PARTITION_NO_PARTITION)

    Meldung: Zumindest eine Partition muss mit COALESCE PARTITION zusammengefügt werden

  • Fehler: 1503 SQLSTATE: HY000 (ER_REORG_PARTITION_NOT_EXIST)

    Meldung: Es wurde versucht, mehr Partitionen als vorhanden zu reorganisieren

  • Fehler: 1504 SQLSTATE: HY000 (ER_SAME_NAME_PARTITION)

    Meldung: Doppelter Partitionsname: %s

  • Fehler: 1505 SQLSTATE: HY000 (ER_NO_BINLOG_ERROR)

    Meldung: Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten

  • Fehler: 1506 SQLSTATE: HY000 (ER_CONSECUTIVE_REORG_PARTITIONS)

    Meldung: Bei der Reorganisation eines Satzes von Partitionen müssen diese in geordneter Reihenfolge vorliegen

  • Fehler: 1507 SQLSTATE: HY000 (ER_REORG_OUTSIDE_RANGE)

    Meldung: Die Reorganisation von RANGE-Partitionen kann Gesamtbereiche nicht verändern, mit Ausnahme der letzten Partition, die den Bereich erweitern kann

  • Fehler: 1508 SQLSTATE: HY000 (ER_PARTITION_FUNCTION_FAILURE)

    Meldung: Partitionsfunktion in dieser Version dieses Handlers nicht unterstützt

  • Fehler: 1509 SQLSTATE: HY000 (ER_PART_STATE_ERROR)

    Meldung: Partitionszustand kann nicht von CREATE oder ALTER TABLE aus definiert werden

  • Fehler: 1510 SQLSTATE: HY000 (ER_LIMITED_PART_RANGE)

    Meldung: Der Handler %s unterstützt in VALUES nur 32-Bit-Integers

  • Fehler: 1511 SQLSTATE: HY000 (ER_PLUGIN_IS_NOT_LOADED)

    Meldung: Plugin '%s' ist nicht geladen

  • Fehler: 1512 SQLSTATE: HY000 (ER_WRONG_VALUE)

    Meldung: Falscher %s-Wert: '%s'

  • Fehler: 1513 SQLSTATE: HY000 (ER_NO_PARTITION_FOR_GIVEN_VALUE)

    Meldung: Tabelle hat für den Wert %s keine Partition

  • Fehler: 1514 SQLSTATE: HY000 (ER_FILEGROUP_OPTION_ONLY_ONCE)

    Meldung: %s darf nicht mehr als einmal angegegeben werden

  • Fehler: 1515 SQLSTATE: HY000 (ER_CREATE_FILEGROUP_FAILED)

    Meldung: Anlegen von %s fehlgeschlagen

  • Fehler: 1516 SQLSTATE: HY000 (ER_DROP_FILEGROUP_FAILED)

    Meldung: Löschen (drop) von %s fehlgeschlagen

  • Fehler: 1517 SQLSTATE: HY000 (ER_TABLESPACE_AUTO_EXTEND_ERROR)

    Meldung: Der Handler unterstützt keine automatische Erweiterung (Autoextend) von Tablespaces

  • Fehler: 1518 SQLSTATE: HY000 (ER_WRONG_SIZE_NUMBER)

    Meldung: Ein Größen-Parameter wurde unkorrekt angegeben, muss entweder Zahl sein oder im Format 10M

  • Fehler: 1519 SQLSTATE: HY000 (ER_SIZE_OVERFLOW_ERROR)

    Meldung: Die Zahl für die Größe war korrekt, aber der Zahlanteil darf nicht größer als 2 Milliarden sein

  • Fehler: 1520 SQLSTATE: HY000 (ER_ALTER_FILEGROUP_FAILED)

    Meldung: Änderung von %s fehlgeschlagen

  • Fehler: 1521 SQLSTATE: HY000 (ER_BINLOG_ROW_LOGGING_FAILED)

    Meldung: Schreiben einer Zeilen ins zeilenbasierte Binärlog fehlgeschlagen

  • Fehler: 1522 SQLSTATE: HY000 (ER_BINLOG_ROW_WRONG_TABLE_DEF)

    Meldung: Tabellendefinition auf Master und Slave stimmt nicht überein

  • Fehler: 1523 SQLSTATE: HY000 (ER_BINLOG_ROW_RBR_TO_SBR)

    Meldung: Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können

  • Fehler: 1524 SQLSTATE: HY000 (ER_EVENT_ALREADY_EXISTS)

    Meldung: Event '%s' existiert bereits

  • Fehler: 1525 SQLSTATE: HY000 (ER_EVENT_STORE_FAILED)

    Meldung: Speichern von Event %s fehlgeschlagen. Fehlercode der Speicher-Engine: %d

  • Fehler: 1526 SQLSTATE: HY000 (ER_EVENT_DOES_NOT_EXIST)

    Meldung: Unbekanntes Event '%s'

  • Fehler: 1527 SQLSTATE: HY000 (ER_EVENT_CANT_ALTER)

    Meldung: Ändern des Events '%s' fehlgeschlagen

  • Fehler: 1528 SQLSTATE: HY000 (ER_EVENT_DROP_FAILED)

    Meldung: Löschen von %s fehlgeschlagen

  • Fehler: 1529 SQLSTATE: HY000 (ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG)

    Meldung: INTERVAL ist entweder nicht positiv oder zu groß

  • Fehler: 1530 SQLSTATE: HY000 (ER_EVENT_ENDS_BEFORE_STARTS)

    Meldung: ENDS ist entweder ungültig oder liegt vor STARTS

  • Fehler: 1531 SQLSTATE: HY000 (ER_EVENT_EXEC_TIME_IN_THE_PAST)

    Meldung: Aktivierungszeit (AT) liegt in der Vergangenheit

  • Fehler: 1532 SQLSTATE: HY000 (ER_EVENT_OPEN_TABLE_FAILED)

    Meldung: Öffnen von mysql.event fehlgeschlagen

  • Fehler: 1533 SQLSTATE: HY000 (ER_EVENT_NEITHER_M_EXPR_NOR_M_AT)

    Meldung: Kein DATETIME-Ausdruck angegeben

  • Fehler: 1534 SQLSTATE: HY000 (ER_COL_COUNT_DOESNT_MATCH_CORRUPTED)

    Meldung: Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt

  • Fehler: 1535 SQLSTATE: HY000 (ER_CANNOT_LOAD_FROM_TABLE)

    Meldung: Kann mysql.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt, siehe Fehlerlog

  • Fehler: 1536 SQLSTATE: HY000 (ER_EVENT_CANNOT_DELETE)

    Meldung: Löschen des Events aus mysql.event fehlgeschlagen

  • Fehler: 1537 SQLSTATE: HY000 (ER_EVENT_COMPILE_ERROR)

    Meldung: Fehler beim Kompilieren des Event-Bodys

  • Fehler: 1538 SQLSTATE: HY000 (ER_EVENT_SAME_NAME)

    Meldung: Alter und neuer Event-Name sind gleich

  • Fehler: 1539 SQLSTATE: HY000 (ER_EVENT_DATA_TOO_LONG)

    Meldung: Daten der Spalte '%s' zu lang

  • Fehler: 1540 SQLSTATE: HY000 (ER_DROP_INDEX_FK)

    Meldung: Kann Index '%s' nicht löschen: wird für einen Fremdschlüssel benötigt

  • Fehler: 1541 SQLSTATE: HY000 (ER_WARN_DEPRECATED_SYNTAX)

    Meldung: Die Syntax '%s' ist veraltet und wird in MySQL %s entfernt. Bitte benutzen Sie statt dessen %s

  • Fehler: 1542 SQLSTATE: HY000 (ER_CANT_WRITE_LOCK_LOG_TABLE)

    Meldung: Eine Log-Tabelle kann nicht schreibgesperrt werden. Es ist ohnehin nur Lesezugriff möglich

  • Fehler: 1543 SQLSTATE: HY000 (ER_CANT_READ_LOCK_LOG_TABLE)

    Meldung: Log-Tabellen können nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL

  • Fehler: 1544 SQLSTATE: 23000 (ER_FOREIGN_DUPLICATE_KEY)

    Meldung: Aufrechterhalten der Fremdschlüssel-Constraints für Tabelle '%s', Eintrag '%s', Schlüssel %d würde zu einem doppelten Eintrag führen

  • Fehler: 1545 SQLSTATE: HY000 (ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE)

    Meldung: Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie scripts/mysql_fix_privilege_tables, um den Fehler zu beheben

  • Fehler: 1546 SQLSTATE: HY000 (ER_REMOVED_SPACES)

    Meldung: Führende Leerzeichen werden aus dem Namen '%s' entfernt

  • Fehler: 1547 SQLSTATE: HY000 (ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR)

    Meldung: Kann nicht aus dem zeilenbasierten Binärlog-Format herauswechseln, wenn die Sitzung offene temporäre Tabellen hat

  • Fehler: 1548 SQLSTATE: HY000 (ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT)

    Meldung: Das Binärlog-Format kann innerhalb einer gespeicherten Funktion oder eines Triggers nicht geändert werden

  • Fehler: 1549 SQLSTATE: HY000 (ER_NDB_CANT_SWITCH_BINLOG_FORMAT)

    Meldung: Die Speicher-Engine NDB Cluster unterstützt das Ändern des Binärlog-Formats zur Laufzeit noch nicht

  • Fehler: 1550 SQLSTATE: HY000 (ER_PARTITION_NO_TEMPORARY)

    Meldung: Anlegen temporärer Tabellen mit Partitionen nicht möglich

  • Fehler: 1551 SQLSTATE: HY000 (ER_PARTITION_CONST_DOMAIN_ERROR)

    Meldung: Partitionskonstante liegt außerhalb der Partitionsfunktionsdomäne

  • Fehler: 1552 SQLSTATE: HY000 (ER_PARTITION_FUNCTION_IS_NOT_ALLOWED)

    Meldung: Diese Partitionierungsfunktion ist nicht erlaubt

  • Fehler: 1553 SQLSTATE: HY000 (ER_DDL_LOG_ERROR)

    Meldung: Fehler im DDL-Log

  • Fehler: 1554 SQLSTATE: HY000 (ER_NULL_IN_VALUES_LESS_THAN)

    Meldung: In VALUES LESS THAN dürfen keine NULL-Werte verwendet werden

  • Fehler: 1555 SQLSTATE: HY000 (ER_WRONG_PARTITION_NAME)

    Meldung: Falscher Partitionsname

  • Fehler: 1556 SQLSTATE: 25001 (ER_CANT_CHANGE_TX_ISOLATION)

    Meldung: Transaktionsisolationsebene kann während einer laufenden Transaktion nicht geändert werden

  • Fehler: 1557 SQLSTATE: HY000 (ER_DUP_ENTRY_AUTOINCREMENT_CASE)

    Meldung: ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%s' für Schlüssel '%s' auftritt

  • Fehler: 1558 SQLSTATE: HY000 (ER_EVENT_MODIFY_QUEUE_ERROR)

    Meldung: Interner Scheduler-Fehler %d

  • Fehler: 1559 SQLSTATE: HY000 (ER_EVENT_SET_VAR_ERROR)

    Meldung: Fehler während des Startens oder Anhalten des Schedulers. Fehlercode %u

  • Fehler: 1560 SQLSTATE: HY000 (ER_PARTITION_MERGE_ERROR)

    Meldung: Engine kann in partitionierten Tabellen nicht verwendet werden

  • Fehler: 1561 SQLSTATE: HY000 (ER_CANT_ACTIVATE_LOG)

    Meldung: Kann Logdatei '%s' nicht aktivieren

  • Fehler: 1562 SQLSTATE: HY000 (ER_RBR_NOT_AVAILABLE)

    Meldung: The server was not built with row-based replication

  • Fehler: 1563 SQLSTATE: HY000 (ER_BASE64_DECODE_ERROR)

    Meldung: Der Server hat keine zeilenbasierte Replikation

  • Fehler: 1564 SQLSTATE: HY000 (ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA)

    Meldung: Trigger können nicht auf Systemtabellen erzeugt werden

  • Fehler: 1565 SQLSTATE: HY000 (ER_EVENT_RECURSIVITY_FORBIDDEN)

    Meldung: Rekursivität von EVENT-DDL-Anweisungen ist unzulässig wenn ein Hauptteil (Body) existiert

  • Fehler: 1566 SQLSTATE: HY000 (ER_EVENTS_DB_ERROR)

    Meldung: Kann nicht weitermachen, weil die Tabellen, die von Events verwendet werden, beim Serverstart als beschädigt markiert wurden

  • Fehler: 1567 SQLSTATE: HY000 (ER_ONLY_INTEGERS_ALLOWED)

    Meldung: An dieser Stelle sind nur Ganzzahlen zulässig

  • Fehler: 1568 SQLSTATE: HY000 (ER_AUTOINC_READ_FAILED)

    Meldung: Lesen des Autoincrement-Werts von der Speicher-Engine fehlgeschlagen

  • Fehler: 1569 SQLSTATE: HY000 (ER_USERNAME)

    Meldung: Benutzername

  • Fehler: 1570 SQLSTATE: HY000 (ER_HOSTNAME)

    Meldung: Hostname

  • Fehler: 1571 SQLSTATE: HY000 (ER_WRONG_STRING_LENGTH)

    Meldung: String '%s' ist zu lang für %s (sollte nicht länger sein als %d)

  • Fehler: 1572 SQLSTATE: HY000 (ER_UNSUPORTED_LOG_ENGINE)

    Meldung: Diese Speicher-Engine kann für Logtabellen nicht verwendet werden

  • Fehler: 1573 SQLSTATE: HY000 (ER_BAD_LOG_STATEMENT)

    Meldung: Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist

  • Fehler: 1574 SQLSTATE: HY000 (ER_NON_INSERTABLE_TABLE)

    Meldung: The target table %s of the %s is not insertable-into

B.2. Fehlercodes und -meldungen der Clients

Die Fehlermeldungen der Clients stammen aus folgenden Quelldateien:

  • Die Fehlermeldungen und die Symbole in Klammern entsprechen den Definitionen in der MySQL-Quelldatei include/errmsg.h.

  • Die Texte der Fehlermeldungen befinden sich in der Datei libmysql/errmsg.c. %d und %s stellen Zahlen beziehungsweise Strings dar, die bei der Ausgabe der Meldungen entsprechend ersetzt werden.

Weil die Fehlermeldungen häufig aktualisiert werden, kann es sein, dass die genannten Dateien zusätzliche Fehlermeldungen enthalten, die hier noch nicht aufgeführt sind.

  • Fehler: 2000 (CR_UNKNOWN_ERROR)

    Meldung: Unknown MySQL error

  • Fehler: 2001 (CR_SOCKET_CREATE_ERROR)

    Meldung: Can't create UNIX socket (%d)

  • Fehler: 2002 (CR_CONNECTION_ERROR)

    Meldung: Can't connect to local MySQL server through socket '%s' (%d)

  • Fehler: 2003 (CR_CONN_HOST_ERROR)

    Meldung: Can't connect to MySQL server on '%s' (%d)

  • Fehler: 2004 (CR_IPSOCK_ERROR)

    Meldung: Can't create TCP/IP socket (%d)

  • Fehler: 2005 (CR_UNKNOWN_HOST)

    Meldung: Unknown MySQL server host '%s' (%d)

  • Fehler: 2006 (CR_SERVER_GONE_ERROR)

    Meldung: MySQL server has gone away

  • Fehler: 2007 (CR_VERSION_ERROR)

    Meldung: Protocol mismatch; server version = %d, client version = %d

  • Fehler: 2008 (CR_OUT_OF_MEMORY)

    Meldung: MySQL client ran out of memory

  • Fehler: 2009 (CR_WRONG_HOST_INFO)

    Meldung: Wrong host info

  • Fehler: 2010 (CR_LOCALHOST_CONNECTION)

    Meldung: Localhost via UNIX socket

  • Fehler: 2011 (CR_TCP_CONNECTION)

    Meldung: %s via TCP/IP

  • Fehler: 2012 (CR_SERVER_HANDSHAKE_ERR)

    Meldung: Error in server handshake

  • Fehler: 2013 (CR_SERVER_LOST)

    Meldung: Lost connection to MySQL server during query

  • Fehler: 2014 (CR_COMMANDS_OUT_OF_SYNC)

    Meldung: Commands out of sync; you can't run this command now

  • Fehler: 2015 (CR_NAMEDPIPE_CONNECTION)

    Meldung: Named pipe: %s

  • Fehler: 2016 (CR_NAMEDPIPEWAIT_ERROR)

    Meldung: Can't wait for named pipe to host: %s pipe: %s (%lu)

  • Fehler: 2017 (CR_NAMEDPIPEOPEN_ERROR)

    Meldung: Can't open named pipe to host: %s pipe: %s (%lu)

  • Fehler: 2018 (CR_NAMEDPIPESETSTATE_ERROR)

    Meldung: Can't set state of named pipe to host: %s pipe: %s (%lu)

  • Fehler: 2019 (CR_CANT_READ_CHARSET)

    Meldung: Can't initialize character set %s (path: %s)

  • Fehler: 2020 (CR_NET_PACKET_TOO_LARGE)

    Meldung: Got packet bigger than 'max_allowed_packet' bytes

  • Fehler: 2021 (CR_EMBEDDED_CONNECTION)

    Meldung: Embedded server

  • Fehler: 2022 (CR_PROBE_SLAVE_STATUS)

    Meldung: Error on SHOW SLAVE STATUS:

  • Fehler: 2023 (CR_PROBE_SLAVE_HOSTS)

    Meldung: Error on SHOW SLAVE HOSTS:

  • Fehler: 2024 (CR_PROBE_SLAVE_CONNECT)

    Meldung: Error connecting to slave:

  • Fehler: 2025 (CR_PROBE_MASTER_CONNECT)

    Meldung: Error connecting to master:

  • Fehler: 2026 (CR_SSL_CONNECTION_ERROR)

    Meldung: SSL connection error

  • Fehler: 2027 (CR_MALFORMED_PACKET)

    Meldung: Malformed packet

  • Fehler: 2028 (CR_WRONG_LICENSE)

    Meldung: This client library is licensed only for use with MySQL servers having '%s' license

  • Fehler: 2029 (CR_NULL_POINTER)

    Meldung: Invalid use of null pointer

  • Fehler: 2030 (CR_NO_PREPARE_STMT)

    Meldung: Statement not prepared

  • Fehler: 2031 (CR_PARAMS_NOT_BOUND)

    Meldung: No data supplied for parameters in prepared statement

  • Fehler: 2032 (CR_DATA_TRUNCATED)

    Meldung: Data truncated

  • Fehler: 2033 (CR_NO_PARAMETERS_EXISTS)

    Meldung: No parameters exist in the statement

  • Fehler: 2034 (CR_INVALID_PARAMETER_NO)

    Meldung: Invalid parameter number

  • Fehler: 2035 (CR_INVALID_BUFFER_USE)

    Meldung: Can't send long data for non-string/non-binary data types (parameter: %d)

  • Fehler: 2036 (CR_UNSUPPORTED_PARAM_TYPE)

    Meldung: Using unsupported buffer type: %d (parameter: %d)

  • Fehler: 2037 (CR_SHARED_MEMORY_CONNECTION)

    Meldung: Shared memory: %s

  • Fehler: 2038 (CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR)

    Meldung: Can't open shared memory; client could not create request event (%lu)

  • Fehler: 2039 (CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR)

    Meldung: Can't open shared memory; no answer event received from server (%lu)

  • Fehler: 2040 (CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR)

    Meldung: Can't open shared memory; server could not allocate file mapping (%lu)

  • Fehler: 2041 (CR_SHARED_MEMORY_CONNECT_MAP_ERROR)

    Meldung: Can't open shared memory; server could not get pointer to file mapping (%lu)

  • Fehler: 2042 (CR_SHARED_MEMORY_FILE_MAP_ERROR)

    Meldung: Can't open shared memory; client could not allocate file mapping (%lu)

  • Fehler: 2043 (CR_SHARED_MEMORY_MAP_ERROR)

    Meldung: Can't open shared memory; client could not get pointer to file mapping (%lu)

  • Fehler: 2044 (CR_SHARED_MEMORY_EVENT_ERROR)

    Meldung: Can't open shared memory; client could not create %s event (%lu)

  • Fehler: 2045 (CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR)

    Meldung: Can't open shared memory; no answer from server (%lu)

  • Fehler: 2046 (CR_SHARED_MEMORY_CONNECT_SET_ERROR)

    Meldung: Can't open shared memory; cannot send request event to server (%lu)

  • Fehler: 2047 (CR_CONN_UNKNOW_PROTOCOL)

    Meldung: Wrong or unknown protocol

  • Fehler: 2048 (CR_INVALID_CONN_HANDLE)

    Meldung: Invalid connection handle

  • Fehler: 2049 (CR_SECURE_AUTH)

    Meldung: Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)

  • Fehler: 2050 (CR_FETCH_CANCELED)

    Meldung: Row retrieval was canceled by mysql_stmt_close() call

  • Fehler: 2051 (CR_NO_DATA)

    Meldung: Attempt to read column without prior row fetch

  • Fehler: 2052 (CR_NO_STMT_METADATA)

    Meldung: Prepared statement contains no metadata

  • Fehler: 2053 (CR_NO_RESULT_SET)

    Meldung: Attempt to read a row while there is no result set associated with the statement

  • Fehler: 2054 (CR_NOT_IMPLEMENTED)

    Meldung: This feature is not implemented yet

Anhang C. Danksagungen

This appendix lists the developers, contributors, and supporters that have helped to make MySQL what it is today.

C.1. Entwickler bei MySQL AB

These are the developers that are or have been employed by MySQL AB to work on the MySQL database software, roughly in the order they started to work with us. Following each developer is a small list of the tasks that the developer is responsible for, or the accomplishments they have made. All developers are involved in support.

  • Michael (Monty) Widenius

    • Lead developer and main author of the MySQL server (mysqld).

    • New functions for the string library.

    • Most of the mysys library.

    • The ISAM and MyISAM libraries (B-tree index file handlers with index compression and different record formats).

    • The HEAP library. A memory table system with our superior full dynamic hashing. In use since 1981 and published around 1984.

    • The replace program (take a look at it, it's COOL!).

    • Connector/ODBC (MyODBC), the ODBC driver for Windows.

    • Fixing bugs in MIT-pthreads to get it to work for MySQL Server. And also Unireg, a curses-based application tool with many utilities.

    • Porting of mSQL tools like msqlperl, DBD/DBI, and DB2mysql.

    • Most of crash-me and the foundation for the MySQL benchmarks.

  • David Axmark

    • Initial main writer of the Reference Manual, including enhancements to texi2html.

    • Automatic Web site updating from the manual.

    • Initial Autoconf, Automake, and Libtool support.

    • Licensing.

    • Parts of all the text files. (Nowadays only the README is left. The rest ended up in the manual.)

    • Lots of testing of new features.

    • Our in-house Free Software legal expert.

    • Mailing list maintainer (who never has the time to do it right...).

    • Our original portability code (now more than 10 years old). Nowadays only some parts of mysys are left.

    • Someone for Monty to call in the middle of the night when he just got that new feature to work.

    • Chief "Open Sourcerer" (MySQL community relations).

  • Jani Tolonen

    • mysqlimport

    • A lot of extensions to the command-line clients.

    • PROCEDURE ANALYSE()

  • Sinisa Milivojevic (now in support)

    • Compression (with zlib) in the client/server protocol.

    • Perfect hashing for the lexical analyzer phase.

    • Multi-row INSERT

    • mysqldump -e option

    • LOAD DATA LOCAL INFILE

    • SQL_CALC_FOUND_ROWS SELECT option

    • --max-user-connections=... option

    • net_read and net_write_timeout

    • GRANT/REVOKE and SHOW GRANTS FOR

    • New client/server protocol for 4.0

    • UNION in 4.0

    • Multiple-table DELETE/UPDATE

    • Subqueries in the FROM clause (4.1).

    • User resources management

    • Initial developer of the MySQL++ C++ API and the MySQLGUI client.

  • Tonu Samuel (past developer)

    • VIO interface (the foundation for the encrypted client/server protocol).

    • MySQL Filesystem (a way to use MySQL databases as files and directories).

    • The CASE expression.

    • The MD5() and COALESCE() functions.

    • RAID support for MyISAM tables.

  • Sasha Pachev (past developer)

    • Initial implementation of replication (up to version 4.0).

    • SHOW CREATE TABLE.

    • mysql-bench

  • Matt Wagner

    • MySQL test suite.

    • Webmaster (until 2002).

  • Miguel Solorzano (now in support)

    • Win32 development and release builds.

    • Windows NT server code.

    • WinMySQLAdmin

  • Timothy Smith (now in support)

    • Dynamic character sets support.

    • configure, RPMs and other parts of the build system.

    • Initial developer of libmysqld, the embedded server.

  • Sergei Golubchik

    • Full-text search.

    • Added keys to the MERGE library.

    • Precision math.

  • Jeremy Cole (past developer)

    • Proofreading and editing this fine manual.

    • ALTER TABLE ... ORDER BY ....

    • UPDATE ... ORDER BY ....

    • DELETE ... ORDER BY ....

  • Indrek Siitan

    • Designing/programming of our Web interface.

    • Author of our newsletter management system.

  • Jorge del Conde (now in support)

    • MySQLCC (MySQL Control Center)

    • Win32 development

    • Initial implementation of the Web site portals.

  • Venu Anuganti (past developer)

    • MyODBC 3.51

    • New client/server protocol for 4.1 (for prepared statements).

  • Arjen Lentz (now handling community)

    • Maintainer of the MySQL Reference Manual.

    • Preparing the O'Reilly printed edition of the manual.

  • Alexander (Bar) Barkov, Alexey (Holyfoot) Botchkov, and Ramil Kalimullin

    • Spatial data (GIS) and R-Trees implementation for 4.1

    • Unicode and character sets for 4.1; documentation for same

  • Oleksandr (Sanja) Byelkin

    • Query cache in 4.0

    • Implementation of subqueries (4.1).

    • Implementation of views (5.0).

  • Aleksey (Walrus) Kishkin and Alexey (Ranger) Stroganov

    • Benchmarks design and analysis.

    • Maintenance of the MySQL test suite.

  • Zak Greant (past employee)

    • Open Source advocate, MySQL community relations.

  • Carsten Pedersen

    • The MySQL Certification program.

  • Lenz Grimmer

    • Production (build and release) engineering.

  • Peter Zaitsev

    • SHA1(), AES_ENCRYPT() and AES_DECRYPT() functions.

    • Debugging, cleaning up various features.

  • Alexander (Salle) Keremidarski

    • Support.

    • Debugging.

  • Per-Erik Martin

    • Lead developer for stored procedures (5.0).

  • Jim Winstead

    • Former lead Web developer.

    • Improving server, fixing bugs.

  • Mark Matthews

    • Connector/J driver (Java).

  • Peter Gulutzan

    • SQL standards compliance.

    • Documentation of existing MySQL code/algorithms.

    • Character set documentation.

  • Guilhem Bichot

    • Replication, from MySQL version 4.0.

    • Fixed handling of exponents for DECIMAL.

    • Author of mysql_tableinfo.

    • Backup (in 5.1).

  • Antony T. Curtis

    • Porting of the MySQL Database software to OS/2.

  • Mikael Ronstrom

    • Much of the initial work on NDB Cluster until 2000. Roughly half the code base at that time. Transaction protocol, node recovery, system restart and restart code and parts of the API functionality.

    • Lead Architect, developer, debugger of NDB Cluster 1994-2004

    • Lots of optimizations

  • Jonas Oreland

    • On-line Backup

    • The automatic test environment of MySQL Cluster

    • Portability Library for NDB Cluster

    • Lots of other things

  • Pekka Nouisiainen

    • Ordered index implementation of MySQL Cluster

    • BLOB support in MySQL Cluster

    • Charset support in MySQL Cluster

  • Martin Skold

    • Unique index implementation of MySQL Cluster

    • Integration of NDB Cluster into MySQL

  • Magnus Svensson

    • The test framework for MySQL Cluster

    • Integration of NDB Cluster into MySQL

  • Tomas Ulin

    • Lots of work on configuration changes for simple installation and use of MySQL Cluster

  • Konstantin Osipov

    • Prepared statements.

    • Cursors.

  • Dmitri Lenev

    • Time zone support.

    • Triggers (in 5.0).

C.2. Kontributoren zu MySQL

Although MySQL AB owns all copyrights in the MySQL server and the MySQL manual, we wish to recognize those who have made contributions of one kind or another to the MySQL distribution. Contributors are listed here, in somewhat random order:

  • Gianmassimo Vigazzola or

    The initial port to Win32/NT.

  • Per Eric Olsson

    For more or less constructive criticism and real testing of the dynamic record format.

  • Irena Pancirov

    Win32 port with Borland compiler. mysqlshutdown.exe and mysqlwatch.exe

  • David J. Hughes

    For the effort to make a shareware SQL database. At TcX, the predecessor of MySQL AB, we started with mSQL, but found that it couldn't satisfy our purposes so instead we wrote an SQL interface to our application builder Unireg. mysqladmin and mysql client are programs that were largely influenced by their mSQL counterparts. We have put a lot of effort into making the MySQL syntax a superset of mSQL. Many of the API's ideas are borrowed from mSQL to make it easy to port free mSQL programs to the MySQL API. The MySQL software doesn't contain any code from mSQL. Two files in the distribution (client/insert_test.c and client/select_test.c) are based on the corresponding (non-copyrighted) files in the mSQL distribution, but are modified as examples showing the changes necessary to convert code from mSQL to MySQL Server. (mSQL is copyrighted David J. Hughes.)

  • Patrick Lynch

    For helping us acquire http://www.mysql.com/.

  • Fred Lindberg

    For setting up qmail to handle the MySQL mailing list and for the incredible help we got in managing the MySQL mailing lists.

  • Igor Romanenko

    mysqldump (previously msqldump, but ported and enhanced by Monty).

  • Yuri Dario

    For keeping up and extending the MySQL OS/2 port.

  • Tim Bunce

    Author of mysqlhotcopy.

  • Zarko Mocnik

    Sorting for Slovenian language.

  • "TAMITO"

    The _MB character set macros and the ujis and sjis character sets.

  • Joshua Chamas

    Base for concurrent insert, extended date syntax, debugging on NT, and answering on the MySQL mailing list.

  • Yves Carlier

    mysqlaccess, a program to show the access rights for a user.

  • Rhys Jones (And GWE Technologies Limited)

    For one of the early JDBC drivers.

  • Dr Xiaokun Kelvin ZHU

    Further development of one of the early JDBC drivers and other MySQL-related Java tools.

  • James Cooper

    For setting up a searchable mailing list archive at his site.

  • Rick Mehalick

    For xmysql, a graphical X client for MySQL Server.

  • Doug Sisk

    For providing RPM packages of MySQL for Red Hat Linux.

  • Diemand Alexander V.

    For providing RPM packages of MySQL for Red Hat Linux-Alpha.

  • Antoni Pamies Olive

    For providing RPM versions of a lot of MySQL clients for Intel and SPARC.

  • Jay Bloodworth

    For providing RPM versions for MySQL 3.21.

  • David Sacerdote

    Ideas for secure checking of DNS hostnames.

  • Wei-Jou Chen

    Some support for Chinese(BIG5) characters.

  • Wei He

    A lot of functionality for the Chinese(GBK) character set.

  • Jan Pazdziora

    Czech sorting order.

  • Zeev Suraski

    FROM_UNIXTIME() time formatting, ENCRYPT() functions, and bison advisor. Active mailing list member.

  • Luuk de Boer

    Ported (and extended) the benchmark suite to DBI/DBD. Have been of great help with crash-me and running benchmarks. Some new date functions. The mysql_setpermission script.

  • Alexis Mikhailov

    User-defined functions (UDFs); CREATE FUNCTION and DROP FUNCTION.

  • Andreas F. Bobak

    The AGGREGATE extension to user-defined functions.

  • Ross Wakelin

    Help to set up InstallShield for MySQL-Win32.

  • Jethro Wright III

    The libmysql.dll library.

  • James Pereria

    Mysqlmanager, a Win32 GUI tool for administering MySQL Servers.

  • Curt Sampson

    Porting of MIT-pthreads to NetBSD/Alpha and NetBSD 1.3/i386.

  • Martin Ramsch

    Examples in the MySQL Tutorial.

  • Steve Harvey

    For making mysqlaccess more secure.

  • Konark IA-64 Centre of Persistent Systems Private Limited

    http://www.pspl.co.in/konark/. Help with the Win64 port of the MySQL server.

  • Albert Chin-A-Young.

    Configure updates for Tru64, large file support and better TCP wrappers support.

  • John Birrell

    Emulation of pthread_mutex() for OS/2.

  • Benjamin Pflugmann

    Extended MERGE tables to handle INSERTS. Active member on the MySQL mailing lists.

  • Jocelyn Fournier

    Excellent spotting and reporting innumerable bugs (especially in the MySQL 4.1 subquery code).

  • Marc Liyanage

    Maintaining the Mac OS X packages and providing invaluable feedback on how to create Mac OS X PKGs.

  • Robert Rutherford

    Providing invaluable information and feedback about the QNX port.

  • Previous developers of NDB Cluster

    Lots of people were involved in various ways summer students, master thesis students, employees. In total more than 100 people so too many to mention here. Notable name is Ataullah Dabaghi who up until 1999 contributed around a third of the code base. A special thanks also to developers of the AXE system which provided much of the architectural foundations for NDB Cluster with blocks, signals and crash tracing functionality. Also credit should be given to those who believed in the ideas enough to allocate of their budgets for its development from 1992 to present time.

Other contributors, bugfinders, and testers: James H. Thompson, Maurizio Menghini, Wojciech Tryc, Luca Berra, Zarko Mocnik, Wim Bonis, Elmar Haneke, , , , Ted Deppner , Mike Simons, Jaakko Hyvatti.

And lots of bug report/patches from the folks on the mailing list.

A big tribute goes to those that help us answer questions on the MySQL mailing lists:

C.3. Redakteure und Übersetzer

The following people have helped us with writing the MySQL documentation and translating the documentation or error messages in MySQL.

  • Paul DuBois

    Ongoing help with making this manual correct and understandable. That includes rewriting Monty's and David's attempts at English into English as other people know it.

  • Kim Aldale

    Helped to rewrite Monty's and David's early attempts at English into English.

  • Michael J. Miller Jr.

    For the first MySQL manual. And a lot of spelling/language fixes for the FAQ (that turned into the MySQL manual a long time ago).

  • Yan Cailin

    First translator of the MySQL Reference Manual into simplified Chinese in early 2000 on which the Big5 and HK coded (http://mysql.hitstar.com/) versions were based. Personal home page at linuxdb.yeah.net.

  • Jay Flaherty

    Big parts of the Perl DBI/DBD section in the manual.

  • Paul Southworth , Ray Loyzaga

    Proof-reading of the Reference Manual.

  • Therrien Gilbert , Jean-Marc Pouyot

    French error messages.

  • Petr Snajdr,

    Czech error messages.

  • Jaroslaw Lewandowski

    Polish error messages.

  • Miguel Angel Fernandez Roiz

    Spanish error messages.

  • Roy-Magne Mo

    Norwegian error messages and testing of MySQL 3.21.xx.

  • Timur I. Bakeyev

    Russian error messages.

  • & Filippo Grassilli

    Italian error messages.

  • Dirk Munzinger

    German error messages.

  • Billik Stefan

    Slovak error messages.

  • Stefan Saroiu

    Romanian error messages.

  • Peter Feher

    Hungarian error messages.

  • Roberto M. Serqueira

    Portuguese error messages.

  • Carsten H. Pedersen

    Danish error messages.

  • Arjen G. Lentz

    Dutch error messages, completing earlier partial translation (also work on consistency and spelling).

C.4. Von MySQL benutzte und mit MySQL ausgelieferte Bibliotheken

The following is a list of the creators of the libraries we have included with the MySQL server source to make it easy to compile and install MySQL. We are very thankfully to all individuals that have created these and it has made our life much easier.

  • Fred Fish

    For his excellent C debugging and trace library. Monty has made a number of smaller improvements to the library (speed and additional options).

  • Richard A. O'Keefe

    For his public domain string library.

  • Henry Spencer

    For his regex library, used in WHERE column REGEXP regexp.

  • Chris Provenzano

    Portable user level pthreads. From the copyright: This product includes software developed by Chris Provenzano, the University of California, Berkeley, and contributors. We are currently using version 1_60_beta6 patched by Monty (see mit-pthreads/Changes-mysql).

  • Jean-loup Gailly and Mark Adler

    For the zlib library (used on MySQL on Windows).

  • Bjorn Benson

    For his safe_malloc (memory checker) package which is used in when you configure MySQL with --debug.

  • Free Software Foundation

    The readline library (used by the mysql command-line client).

  • The NetBSD foundation

    The libedit package (optionally used by the mysql command-line client).

C.5. Pakete, die MySQL unterstützen

The following is a list of creators/maintainers of some of the most important API/packages/applications that a lot of people use with MySQL.

We can't list every possible package here because the list would then be way to hard to maintain. For other packages, please refer to the software portal at http://solutions.mysql.com/software/.

  • Tim Bunce, Alligator Descartes

    For the DBD (Perl) interface.

  • Andreas Koenig

    For the Perl interface for MySQL Server.

  • Jochen Wiedmann

    For maintaining the Perl DBD::mysql module.

  • Eugene Chan

    For porting PHP for MySQL Server.

  • Georg Richter

    MySQL 4.1 testing and bug hunting. New PHP 5.0 mysqli extension (API) for use with MySQL 4.1 and up.

  • Giovanni Maruzzelli

    For porting iODBC (Unix ODBC).

  • Xavier Leroy

    The author of LinuxThreads (used by the MySQL Server on Linux).

C.6. Werkzeuge, die zum Herstellen von MySQL benutzt werden

The following is a list of some of the tools we have used to create MySQL. We use this to express our thanks to those that has created them as without these we could not have made MySQL what it is today.

  • Free Software Foundation

    From whom we got an excellent compiler (gcc), an excellent debugger (gdb and the libc library (from which we have borrowed strto.c to get some code working in Linux).

  • Free Software Foundation & The XEmacs development team

    For a really great editor/environment used by almost everybody at MySQL AB.

  • Julian Seward

    Author of valgrind, an excellent memory checker tool that has helped us find a lot of otherwise hard to find bugs in MySQL.

  • Dorothea Lütkehaus and Andreas Zeller

    For DDD (The Data Display Debugger) which is an excellent graphical front end to gdb).

C.7. Unterstützer von MySQL

Although MySQL AB owns all copyrights in the MySQL server and the MySQL manual, we wish to recognize the following companies, which helped us finance the development of the MySQL server, such as by paying us for developing a new feature or giving us hardware for development of the MySQL server.

  • VA Linux / Andover.net

    Funded replication.

  • NuSphere

    Editing of the MySQL manual.

  • Stork Design studio

    The MySQL Web site in use between 1998-2000.

  • Intel

    Contributed to development on Windows and Linux platforms.

  • Compaq

    Contributed to Development on Linux/Alpha.

  • SWSoft

    Development on the embedded mysqld version.

  • FutureQuest

    --skip-show-database

Anhang D. MySQL-Änderungsverlauf (Change History)

Inhaltsverzeichnis

D.1. Änderungen in Release 5.1.x (Entwicklung)
D.1.1. Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)
D.1.2. Änderungen in Release 5.1.5 (10. Januar 2006)
D.1.3. Änderungen in Release 5.1.4 (21. Dezember 2005)
D.1.4. Änderungen in Release 5.1.3 (29. November 2005)
D.1.5. Änderungen in Release 5.1.2 (Nicht veröffentlicht)
D.1.6. Änderungen in Release 5.1.1 (Nicht veröffentlicht)
D.2. Änderungen in MyODBC
D.2.1. Änderungen in MyODBC 3.51.13
D.2.2. Änderungen in MyODBC 3.51.12
D.2.3. Änderungen in MyODBC 3.51.11
D.3. MySQL Connector/J Change History
D.3.1. Changes in MySQL Connector/J 5.0.3 (26 July 2006)
D.3.2. Changes in MySQL Connector/J 5.0.2-beta (11 July 2006)
D.3.3. Changes in MySQL Connector/J 5.0.1-beta (Not Released)
D.3.4. Changes in MySQL Connector/J 5.0.0-beta (22 December 2005)
D.3.5. Changes in MySQL Connector/J 3.1.14 (not yet released)
D.3.6. Changes in MySQL Connector/J 3.1.13 (26 May 2006)
D.3.7. Changes in MySQL Connector/J 3.1.12 (30 November 2005)
D.3.8. Changes in MySQL Connector/J 3.1.11-stable (07 October 2005)
D.3.9. Changes in MySQL Connector/J 3.1.10-stable (23 June 2005)
D.3.10. Changes in MySQL Connector/J 3.1.9-stable (22 June 2005)
D.3.11. Changes in MySQL Connector/J 3.1.8-stable (14 April 2005)
D.3.12. Changes in MySQL Connector/J 3.1.7-stable (18 February 2005)
D.3.13. Changes in MySQL Connector/J 3.1.6-stable (23 December 2004)
D.3.14. Changes in MySQL Connector/J 3.1.5-gamma (02 December 2004)
D.3.15. Changes in MySQL Connector/J 3.1.4-beta (04 September 2004)
D.3.16. Changes in MySQL Connector/J 3.1.3-beta (07 July 2004)
D.3.17. Changes in MySQL Connector/J 3.1.2-alpha (09 June 2004)
D.3.18. Changes in MySQL Connector/J 3.1.1-alpha (14 February 2004)
D.3.19. Changes in MySQL Connector/J 3.1.0-alpha (18 February 2003)
D.3.20. Changes in MySQL Connector/J 3.0.17-ga (23 June 2005)
D.3.21. Changes in MySQL Connector/J 3.0.16-ga (15 November 2004)
D.3.22. Changes in MySQL Connector/J 3.0.15-production (04 September 2004)
D.3.23. Changes in MySQL Connector/J 3.0.14-production (28 May 2004)
D.3.24. Changes in MySQL Connector/J 3.0.13-production (27 May 2004)
D.3.25. Changes in MySQL Connector/J 3.0.12-production (18 May 2004)
D.3.26. Changes in MySQL Connector/J 3.0.11-stable (19 February 2004)
D.3.27. Changes in MySQL Connector/J 3.0.10-stable (13 January 2004)
D.3.28. Changes in MySQL Connector/J 3.0.9-stable (07 October 2003)
D.3.29. Changes in MySQL Connector/J 3.0.8-stable (23 May 2003)
D.3.30. Changes in MySQL Connector/J 3.0.7-stable (08 April 2003)
D.3.31. Changes in MySQL Connector/J 3.0.6-stable (18 February 2003)
D.3.32. Changes in MySQL Connector/J 3.0.5-gamma (22 January 2003)
D.3.33. Changes in MySQL Connector/J 3.0.4-gamma (06 January 2003)
D.3.34. Changes in MySQL Connector/J 3.0.3-dev (17 December 2002)
D.3.35. Changes in MySQL Connector/J 3.0.2-dev (08 November 2002)
D.3.36. Changes in MySQL Connector/J 3.0.1-dev (21 September 2002)
D.3.37. Changes in MySQL Connector/J 3.0.0-dev (31 July 2002)
D.3.38. Changes in MySQL Connector/J 2.0.14 (16 May 2002)
D.3.39. Changes in MySQL Connector/J 2.0.13 (24 April 2002)
D.3.40. Changes in MySQL Connector/J 2.0.12 (07 April 2002)
D.3.41. Changes in MySQL Connector/J 2.0.11 (27 January 2002)
D.3.42. Changes in MySQL Connector/J 2.0.10 (24 January 2002)
D.3.43. Changes in MySQL Connector/J 2.0.9 (13 January 2002)
D.3.44. Changes in MySQL Connector/J 2.0.8 (25 November 2001)
D.3.45. Changes in MySQL Connector/J 2.0.7 (24 October 2001)
D.3.46. Changes in MySQL Connector/J 2.0.6 (16 June 2001)
D.3.47. Changes in MySQL Connector/J 2.0.5 (13 June 2001)
D.3.48. Changes in MySQL Connector/J 2.0.3 (03 December 2000)
D.3.49. Changes in MySQL Connector/J 2.0.1 (06 April 2000)
D.3.50. Changes in MySQL Connector/J 2.0.0pre5 (21 February 2000)
D.3.51. Changes in MySQL Connector/J 2.0.0pre4 (10 January 2000)
D.3.52. Changes in MySQL Connector/J 2.0.0pre (17 August 1999)
D.3.53. Changes in MySQL Connector/J 1.2b (04 July 1999)
D.3.54. Changes in MySQL Connector/J 1.2a (14 April 1999)
D.3.55. Changes in MySQL Connector/J 1.1i (24 March 1999)
D.3.56. Changes in MySQL Connector/J 1.1h (08 March 1999)
D.3.57. Changes in MySQL Connector/J 1.1g (19 February 1999)
D.3.58. Changes in MySQL Connector/J 1.1f (31 December 1998)
D.3.59. Changes in MySQL Connector/J 1.1b (03 November 1998)
D.3.60. Changes in MySQL Connector/J 1.1 (02 September 1998)
D.3.61. Changes in MySQL Connector/J 1.0 (24 August 1998)
D.3.62. Changes in MySQL Connector/J 0.9d (04 August 1998)
D.3.63. Changes in MySQL Connector/J 0.9 (28 July 1998)
D.3.64. Changes in MySQL Connector/J 0.8 (06 July 1998)
D.3.65. Changes in MySQL Connector/J 0.7 (01 July 1998)
D.3.66. Changes in MySQL Connector/J 0.6 (21 May 1998)

This appendix lists the changes from version to version in the MySQL source code through the latest version of MySQL 5.1, which is currently MySQL 5.1.5-alpha. Starting with MySQL 5.0, we began offering a new version of the Manual for each new series of MySQL releases (5.0, 5.1, and so on). For information about changes in previous release series of the MySQL database software, see the corresponding version of this Manual. For information about legacy versions of the MySQL software through the 4.1 series, see MySQL-Referenzhandbuch für die Versionen 3.23, 4.0 und 4.1.

We update this section as we add new features in the 5.1 series, so that everybody can follow the development process.

Note that we tend to update the manual at the same time we make changes to MySQL. If you find a recent version of MySQL listed here that you can't find on our download page (http://dev.mysql.com/downloads/), it means that the version has not yet been released.

The date mentioned with a release version is the date of the last BitKeeper ChangeSet on which the release was based, not the date when the packages were made available. The binaries are usually made available a few days after the date of the tagged ChangeSet, because building and testing all packages takes some time.

The manual included in the source and binary distributions may not be fully accurate when it comes to the release changelog entries, because the integration of the manual happens at build time. For the most up-to-date release changelog, please refer to the online version instead.

D.1. Änderungen in Release 5.1.x (Entwicklung)

The following changelog shows what has been done in the 5.1 tree:

  • MySQL 5.1 enables table partitioning with a selection of partitioning algorithms and options available, independently of the storage engine used by the table. Syntactically, this implements a number of new extensions to the CREATE TABLE, ALTER TABLE, and EXPLAIN ... SELECT statements. See Kapitel 17, Partitionierung.

  • MySQL 5.1 implements support for a plugin API that allows the loading and unloading of components at runtime, without restarting the server. See Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“.

For a full list of changes, please refer to the changelog sections for each individual 5.1.x release.

D.1.1. Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)

Functionality added or changed:

  • Incompatible change: This release introduced the TRIGGER privilege. Previously, the SUPER privilege was needed to create or drop triggers. Now those operations require the TRIGGER privilege. This is a security improvement because you no longer need to grant users the SUPER privilege to enable them to create triggers. However, the requirement that the account named in a trigger's DEFINER clause must have the SUPER privilege has changed to a requirement for the TRIGGER privilege. You should check which accounts are named in the DEFINER clause of existing triggers and make sure that those accounts have the TRIGGER privilege. Otherwise, they will fail when activated. (Bug#9142)

  • Incompatible change: Due to a change in the naming scheme for partitioning and subpartitioning files, it is not possible for the server to read partitioned tables created in previous MySQL versions. A suggested workaround is (1) to create a non-partitioned table with the same table schema using a standard CREATE TABLE statement (that is, with no partitioning clauses) and then (2) to issue aSELECT INTO to copy the data into the non-partitioned table before the upgrade; following the upgrade, you can partition the new table using ALTER TABLE ... PARTITION BY .... Alternatively, you can dump the table using mysqldump prior to upgrading and reload it afterwards with LOAD DATA. In either case, you should drop the pre-5.1.6 partitioned tables before upgrading to 5.1.6 or later. (Bug#13437)

    Important: If any partitioned tables that were created prior to MySQL 5.1.6 are present following an upgrade to MySQL 5.1.6 or later, it is also not possible to read from the INFORMATION_SCHEMA.PARTITIONS table, nor will you be able to drop those tables or the database or databases in which they are located. In this event, you must: (1) shut down mysqld; (2) manually delete the table, partition, and (if any) subpartition files; and then (3) restart the MySQL Server. (Bug#16695)

  • Incompatible change: Words with apostrophes are now matched in a FULLTEXT search against non-apostrophe words (for example, a search for Jerry will match against the term Jerry's). Users upgrading to this version must issue REPAIR TABLE statements for tables containing FULLTEXT indexes. (Bug#14194)

  • The mysqldump utility now supports an option for dumping tablespaces. Use -Y or --all-tablespaces to enable this functionality. (Bug#16753)

  • Partition support is not an „engine“, but it was included in the output of SHOW ENGINES. Now it is not. (Bug#14355) The have_partition_engine was renamed to have_partitioning. (Bug#16718)

  • ANALYZE TABLE is now supported for partitioned tables. (Bug#13441)

  • Added the --both-log-formats and --old-log-format options for controlling whether log files or log tables are used. variable.

  • Added the character_set_filesystem system variable.

  • Added the event_scheduler system variable.

  • Added the ndb_extra_logging system variable.

  • Added the EVENTS table to INFORMATION_SCHEMA.

  • Added the PARTITIONS table to INFORMATION_SCHEMA.

  • The ARCHIVE storage engine supports the AUTO_INCREMENT column attribute and the AUTO_INCREMENT table option. Abschnitt 14.8, „Die ARCHIVE-Speicher-Engine“.

  • Fixed a crash when fulltext search parser plugin returned more words than half of the length (in bytes) of the query string. (Bug#16722)

Bugs fixed:

  • MYSQL_OPT_RECONNECT option was modified by calls to the mysql_real_connect() function. (Bug#15719)

  • Specifying a value for --tmptable without a trailing slash had unpredictable results. (Bug#15904)

  • Attempting to insert data into a partitioned table that used the BLACKHOLE storage engine caused mysqld to crash. (Bug#14524)

  • Using RANGE partitioning with a CASE statement as the partitioning function would cause records to be placed in the wrong partition. (Bug#15393)

  • ALTER TABLE ... ADD PARTITIONS on a table with one partition crashed the server. (Bug#15820)

  • NDB Cluster returned incorrect Can't find file error for OS error 24, changed to Too many open files. (Bug#15020)

  • Multi-byte path names for LOAD DATA and SELECT ... INTO OUTFILE caused errors. (Bug#12448)

  • Certain subqueries where the inner query is the result of a aggregate function would return different results on MySQL 5.0 than on MySQL 4.1. (Bug#15347)

  • Error message for specifying value for which no partition exists returned wrong values on certain platforms. (Bug#15910)

  • Certain Japanese table names were not properly saved during a CREATE TABLE statement. (Bug#3906)

  • NDB Cluster leaked disk space when performing INSERTS/DELETES in a loop. (Bug#16771)

  • NDB Cluster returned wrong error when tablespace on disk was full. (Bug#16738)

  • The DATA DIRECTORY and INDEX DIRECTORY clauses of a CREATE TABLE statement involving partitions did not work. (Bug#14354)

  • Subselect could return wrong results when records cache and grouping was involved. (Bug#15347)

  • In some cases the query optimizer did not properly perform multiple joins where inner joins followed left joins, resulting in corrupted result sets. (Bug#15633)

  • The absence of a table in the left part of a left or right join was not checked prior to name resolution, which resulted in a server crash. (Bug#15538)

  • NDB Cluster: Trying to import too many dumped tables requiring resources beyond those allocated in the cluster configuration would cause the server to crash instead of reporting an insufficient resources error. (Bug#16455)

  • NDB Cluster (Disk Data): Tablespaces created using parameters with relatively low values (< 10 MB) produced filesizes much smaller than expected. (Bug#16742)

  • NDB Cluster: CREATE TABLESPACE statements were incorrectly parsed on 64-bit platforms. (INITIAL SIZE size worked, but INITIAL SIZE = size failed.) (Bug#13556)

  • Trying to add more than one partition in a single ALTER TABLE ... ADD PARTITION statement caused the server to crash. (Bug#16534)

  • Creating a partitioned table using a storage engine other than the session default storage engine caused the server to crash. (Bug#15966)

  • An ALTER TABLE ... PARTITION BY ... statement did not have any effect. (Bug#15523)

  • NDBCluster (Disk Data): The error message generated by a failed ADD UNDOFILE did not provide any reasons for the failure. (Bug#16267)

  • NDBCluster (Disk Data): DROP LOGFILE GROUP corrupted the cluster file system and caused ndbd to fail when running more than one node on the same system. (Bug#16193)

  • NDBCluster: A bitfield whose offset and length totaled 32 would crash the cluster. (Bug#16125)

  • NDBCluster: Upon the completion of a scan where a key request remained outstanding on the primary replica and a starting node died, the scan did not terminate. This caused incompleted error handling of the failed node. (Bug#15908)

  • NDBCluster: The ndb_autodiscover test failed sporadically due to a node not being permitted to connect to the cluster. (Bug#15619)

  • Using mysqldump to obtain a dump of a partitioned table employing the NDB storage engine produced a non-functional table creation statement. (Bug#13155)

  • SHOW CREATE TABLE did not display the PARTITIONS clause for tables partitioned by HASH or KEY. (Bug#14327)

  • Inserting a negative value into an integer column used as the partitioning key for a table partitioned by HASH could cause the server to crash. (Bug#15968)

  • With a table partitioned by LIST, inserting a value which was smaller than any value shown in the partitioning value-lists could cause the server to crash. (Bug#14365)

  • ALTER TABLE ... DROP PARTITION would truncate all DATE column values in the table's remaining partitions to NULL. (Bug#13644)

  • ALTER TABLE ... ADD PARTITION could crash the server or cause an Out of memory error in some circumstances. (Bug#13447)

  • The server would allow foreign keys to be declared in the definition of a partitioned table despite the fact that partitioned tables do not support foreign keys (see Abschnitt 17.4, „Beschränkungen und Grenzen der Partitionierung“). (Bug#13446)

  • A SELECT from a key-partitioned table with a multi-column key could cause the server to crash. (Bug#13445)

  • Issuing a TRUNCATE statement twice in succession on the same partitioned table would cause the server to crash. (Bug#13442)

  • Using a REPLACE statement on a partitioned table caused the server to crash. (Bug#13440)

  • Using an identifier rather than a literal integer value in the LESS THAN clause of a range-partitioned table could cause the server to crash and corruption of tables. (Bug#13439)

  • Using ENGINE=... within a PARTITION clause could cause the server to crash. (Bug#13438)

  • CREATE TABLE ... LIKE did not work if the table whose schema was to be copied was a partitoned table. (Bug#13435)

  • SHOW CREATE TABLE did not display the PARTITIONS clause for tables partitioned by HASH or KEY. (Bug#14327)

  • Certain permission management statements could create a NULL hostname for a user, resulting in a server crash. (Bug#15598)

  • Temporary table aliasing did not work inside stored functions. (Bug#12198)

  • Parallel builds occasionally failed on Solaris. (Bug#16282)

D.1.2. Änderungen in Release 5.1.5 (10. Januar 2006)

Functionality added or changed:

  • Added the INFORMATION_SCHEMA ENGINES table.

  • Added the INFORMATION_SCHEMA PLUGINS table and the SHOW PLUGIN statement.

  • Added the binlog_format system variable that controls whether to use row-based or statement-based binary logging. Added the --binlog-format and --binlog-row-event-max-size server options for binary logging control. See Abschnitt 6.3, „Zeilenbasierte Replikation“.

  • Plugins now can have status variables that are displayed in the output from SHOW STATUS.

  • Added the XML functions ExtractValue() and UpdateXML(). ExtractValue() returns the content of a fragment of XML matching a given XPath expression. UpdateXML() replaces the element selected from a fragment of XML by an XPath expression supplied by the user with a second XML fragment (also user-supplied), and returns the modified XML. See Abschnitt 12.9, „XML-Funktionen“.

  • Added the --base64-output option to mysqlbinlog to print all binary log entries using base64 encoding. This is for debugging only. Logs produced using this option should not be applied on production systems.

  • Added the --port-open-timeout option to mysqld to control how many seconds the server should wait for the TCP/IP port to become free if it cannot be opened. (Bug#15591)

  • Two new Hungarian collations are included: utf8_hungarian_ci and ucs2_hungarian_ci. These support the correct sort order for Hungarian vowels. However, they do not support the correct order for sorting Hungarian consonant contractions; this issue will be fixed in a future release.

Bugs fixed:

  • InnoDB: An UPDATE statement with no index column in the WHERE condition locked all the rows in the table. (Bug#3300)

  • INSERT DELAYED caused mysqld to crash. (Bug#16095)

  • The output of mysqldump --triggers did not contain the DEFINER clause in dumped trigger definitions. (Bug#15110)

  • The output of SHOW TRIGGERS contained extraneous whitespace. (Bug#15103)

  • An INSERT ... SELECT statement between tables in a MERGE set can return errors when statement involves insert into child table from merge table or vice-versa. (Bug#5390)

  • A COMMIT statement followed by a ALTER TABLE statement on a BDB table caused server crash. (Bug#14212)

  • InnoDB: Comparison of indexed VARCHAR CHARACTER SET ucs2 COLLATE ucs2_bin columns using LIKE could fail. (Bug#14583)

  • Creating a trigger caused a server crash if the table or trigger database was not known because no default database had been selected. (Bug#14863)

  • Issuing a DROP USER command could cause some users to encounter a hostname is not allowed to connect to this MySQL server error. (Bug#15775)

  • The --plugin_dir option was not working. Also fix error with specifying parser name for fulltext. (Bug#16068)

  • Attempting to insert into a table partitioned by LIST a value less than any specified in one of the table's partition definitions resulted in a server crash. In such cases, mysqld now returns ERROR 1500 (HY000): Table has no partition for value v , where v is the out-of-range value. (Bug#15819)

D.1.3. Änderungen in Release 5.1.4 (21. Dezember 2005)

Functionality added or changed:

  • Added the mysqlslap program, which is designed to emulate client load for a MySQL server and report the timing of each stage. It works as if multiple clients are accessing the server.

  • Added the --server-id option to mysqlbinlog to enable only those events created by the server having the given server ID to be extracted. (Bug#15485)

  • It is now possible to build the server such that MyISAM tables can support up to 128 keys rather than the standard 64. This can be done by configuring the build using the option --with-max-indexes=N, where N≤128 is the maximum number of indexes to permit per table. (Bug#10932)

  • The bundled BDB library was upgraded to version 4.4.16.

  • Added the cp1250_polish_ci collation for the cp1250 character set.

  • Added the myisam_use_mmap system variable.

  • Added the --bdb-data-direct and --bdb-log-direct server options.

Bugs fixed:

  • Server could not be built on default Debian systems with BDB enabled. (Bug#15734)

  • BDB: A DELETE, INSERT, or UPDATE of a BDB table could cause the server to crash where the query contained a subquery using an index read. (Bug#15536)

  • A left join on a column that having a NULL value could cause the server to crash. (Bug#15268)

  • It was not possible to reorganize a partition reusing a discarded partition name.

    Now, for example, you can create a table such as this one:

    CREATE TABLE t1 (a INT) 
        PARTITION BY RANGE (a) (
          PARTITION p0 VALUES LESS THAN (10),
          PARTITION p1 VALUES LESS THAN (20),
          PARTITION p2 VALUES LESS THAN MAXVALUE
        );
    

    and then repartition it as shown here:

    ALTER TABLE t1 REORGANIZE PARTITION p2 INTO (
        PARTITION p2 VALUES LESS THAN (30)
    );
    

    Previously, attempting to do so would produce the error All partitions must have unique names in the table . (Bug#15521)

  • NDB Cluster: The --ndb option for perror did not function. (Bug#15486)

  • The BLACKHOLE storage engine did not handle transactions properly: Rolled-back transactions were written to the binary log. Now they ae not. (Bug#15406)

  • NDB Cluster: Using ORDER BY primary_key_column when selecting from a table having the primary key on a VARCHAR column caused a forced shutdown of the cluster. (Bug#14828, Bug#15240, Bug#15682, Bug#15517)

  • ANALYZE TABLE did not properly update table statistics for a MyISAM table with a FULLTEXT index containing stopwords, so a subsequent ANALYZE TABLE would not recognize the table as having already been analyzed. (Bug#14902)

  • The maximum value of MAX_ROWS was handled incorrectly on 64-bit systems. (Bug#14155)

  • Multiple-table update operations were counting updates and not updated rows. As a result, if a row had several updates it was counted several times for the „rows matched“ value but updated only once. (Bug#15028)

  • SELECT queries that began with an opening parenthesis were not being placed in the query cache. (Bug#14652)

  • Space truncation was being ignored when inserting into BINARY or VARBINARY columns. Now space truncation results in a warning, or an error in strict mode. (Bug#14299)

  • Selecting from a view processed with the temptable algorithm caused a server crash if the query cache was enabled. (Bug#15119)

  • Creating a view that referenced a stored function that selected from a view caused a crash upon selection from the view. (Bug#15096)

  • Creating a view within a stored procedure could result in an out of memory error or a server crash. (Bug#14885)

  • SHOW CREATE DATABASE was sometimes refused when the client had privileges for the database. (Bug#9785)

  • mysql ignored the MYSQL_TCP_PORT environment variable. (Bug#5792)

  • ROW_COUNT() returned an incorrect result after EXECUTE of a prepared statement. (Bug#14956)

  • Invalid casts to DATE values now result in a message of Incorrect datetime value, rather than Truncated incorrect datetime value. (Bug#8294)

  • Attempts to assign NULL to a NOT NULL column in strict mode now result in a message of Column 'col_name' cannot be null, rather than Column set to default value; NULL supplied to NOT NULL column 'col_name' at row n. (Bug#11491)

  • For binary string data types, mysqldump --hex-blob produced an illegal output value of 0x rather than ''. (Bug#13318)

  • Some comparisons for the IN() operator were inconsistent with equivalent comparisons for the = operator. (Bug#12612)

D.1.4. Änderungen in Release 5.1.3 (29. November 2005)

Functionality added or changed:

This is the first public alpha release of the current MySQL 5.1 development branch, providing an insight to upcoming features. Although some of these are still under heavy development, this release includes the following new features and changes (in comparison to the current MySQL 5.0 production release):

  • Partitioning: allows distributing portions of individual tables across a filesystem, according to rules which can be set when the table is created. In effect, different portions of a table are stored as separate tables in different locations, but from the user point of view, the partitioned table is still a single table. See Kapitel 17, Partitionierung, for further information on this functionality. (Author: Mikael Ronström)

  • Plugin API: MySQL 5.1 adds support for a very flexible plugin API that enables loading and unloading of various components at runtime, without restarting the server. Although the work on this is not finished yet, plugin full-text parsers are a first step in this direction. This allows users to implement their own input filter on the indexed text, enabling full-text search capability on arbitrary data such as PDF files or other document formats. A pre-parser full-text plugin performs the actual parsing and extraction of the text and hands it over to the built-in MySQL full-text search. (Author: Sergey Vojtovich)

    The plugin API requires the mysql.plugin table. When upgrading from an older version of MySQL, you should run the mysql_fix_privilege_tables command to create this table. See Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

    Incompatible change: Plugins are installed in the directory named by the plugin_dir system variable. This variable also controls the location from which the server loads user-defined functions (UDFs), which is a change from earlier versions of MySQL. That is, all UDF library files now must be installed in the plugin directory. When upgrading from an older version of MySQL, you must migrate your UDF files to the plugin directory.

  • The Instance Manager (IM) now has some additional functionality:

    • SHOW instance_name LOG FILES provides a listing of all log files used by the instance. (Author: Petr Chardin)

    • SHOW instance_name LOG {ERROR | SLOW | GENERAL} size retrieves a part of the specified log file. (Author: Petr Chardin)

    • SET instance_name. option_name=option_value sets an option to the specified value and writes it to the config file See Abschnitt 5.5, „mysqlmanager — Der MySQL Instance Manager“, for more details on these new commands. (Author: Petr Chardin)

  • The performance of boolean full-text searches (using the „+“ Operator) has been improved. See Abschnitt 12.7, „MySQL-Volltextsuche“, for more details about full-text searching. (Author: Sergey Vojtovich)

  • VARCHAR fields used in MySQL Cluster tables are now variable-sized; that is, they now only allocate as much space as required to store the data. Previously, a VARCHAR(n) column allocated n+2 bytes (aligned to 4 bytes), regardless if the actual inserted value required that much space. (In other words, a VARCHAR column always required the same, fixed, amount of storage as a CHAR column of the same size.)

  • Renamed the table_cache system variable to table_open_cache. Any scripts that refer to table_cache should be updated to use the new name.

  • Added the table_definition_cache system variable. If you use a large number of tables, you can create a large table definition cache to speed up opening of tables. The table definition cache takes less space and does not use file descriptors, unlike the normal table cache.

Bugs fixed:

  • Set functions could not be aggregated in outer subqueries. (Bug#12762)

D.1.5. Änderungen in Release 5.1.2 (Nicht veröffentlicht)

Functionality added or changed:

  • Added MAXLOCKS, MINLOCKS, MAXWRITE, and MINWRITE as allowable values of the --bdb-lock-detect option. (Bug#14876)

  • Added the bdb_cache_parts and bdb_region_size system variables, and allowed bdb_cache_size to be larger than 4GB on systems that support it. (Bug#14895)

  • Added Transactions, XA, and Savepoints columns to SHOW ENGINES output.

  • Added --replace to mysqldump. This option uses REPLACE INTO, rather than INSERT INTO, when writing the dumpfile.

Bugs fixed:

  • Foreign keys were not properly enforced in TEMPORARY tables. Foreign keys now are disallowed in TEMPORARY tables. (Bug#12084)

D.1.6. Änderungen in Release 5.1.1 (Nicht veröffentlicht)

Functionality added or changed:

Bugs fixed:

  • Performing a CREATE TABLE statement with a PARTITION BY clause in a prepared statement could crash a server running in debug mode. (Bug#12097)

  • NDB: Specifying the wrong nodegroup in a CREATE TABLE using partitioning would lead to the table name being locked after the CREATE TABLE statement failed (that is, the table name could not be re-used). (Bug#12114)

  • Using ORDER BY in a query with a partitioned table on a 64-bit operating system could crash the server. (Bug#12116)

  • When two threads compete for the same table, a deadlock could occur if one thread has also a lock on another table through LOCK TABLES and the thread is attempting to remove the table in some manner and the other thread want locks on both tables. (Bug#10600)

D.2. Änderungen in MyODBC

D.2.1. Änderungen in MyODBC 3.51.13

Functionality added or changed:

  • N/A

Bugs fixed:

  • The SQLDriverConnect() ODBC method did not work with recent MyODBC releases. (Bug#12393)

D.2.2. Änderungen in MyODBC 3.51.12

Functionality added or changed:

  • N/A

Bugs fixed:

  • SQLColumns() returned no information for tables that had a column named using a reserved word. (Bug#9539)

D.2.3. Änderungen in MyODBC 3.51.11

Functionality added or changed: No changes.

Bugs fixed:

  • mysql_list_dbcolumns() and insert_fields() were retrieving all rows from a table. Fixed the queries generated by these functions to return no rows. (Bug#8198)

  • SQLGetTypoInfo() returned tinyblob for SQL_VARBINARY and nothing for SQL_BINARY. Fixed to return varbinary for SQL_VARBINARY, binary for SQL_BINARY, and longblob for SQL_LONGVARBINARY. (Bug#8138)

D.3. MySQL Connector/J Change History

D.3.1. Changes in MySQL Connector/J 5.0.3 (26 July 2006)
D.3.2. Changes in MySQL Connector/J 5.0.2-beta (11 July 2006)
D.3.3. Changes in MySQL Connector/J 5.0.1-beta (Not Released)
D.3.4. Changes in MySQL Connector/J 5.0.0-beta (22 December 2005)
D.3.5. Changes in MySQL Connector/J 3.1.14 (not yet released)
D.3.6. Changes in MySQL Connector/J 3.1.13 (26 May 2006)
D.3.7. Changes in MySQL Connector/J 3.1.12 (30 November 2005)
D.3.8. Changes in MySQL Connector/J 3.1.11-stable (07 October 2005)
D.3.9. Changes in MySQL Connector/J 3.1.10-stable (23 June 2005)
D.3.10. Changes in MySQL Connector/J 3.1.9-stable (22 June 2005)
D.3.11. Changes in MySQL Connector/J 3.1.8-stable (14 April 2005)
D.3.12. Changes in MySQL Connector/J 3.1.7-stable (18 February 2005)
D.3.13. Changes in MySQL Connector/J 3.1.6-stable (23 December 2004)
D.3.14. Changes in MySQL Connector/J 3.1.5-gamma (02 December 2004)
D.3.15. Changes in MySQL Connector/J 3.1.4-beta (04 September 2004)
D.3.16. Changes in MySQL Connector/J 3.1.3-beta (07 July 2004)
D.3.17. Changes in MySQL Connector/J 3.1.2-alpha (09 June 2004)
D.3.18. Changes in MySQL Connector/J 3.1.1-alpha (14 February 2004)
D.3.19. Changes in MySQL Connector/J 3.1.0-alpha (18 February 2003)
D.3.20. Changes in MySQL Connector/J 3.0.17-ga (23 June 2005)
D.3.21. Changes in MySQL Connector/J 3.0.16-ga (15 November 2004)
D.3.22. Changes in MySQL Connector/J 3.0.15-production (04 September 2004)
D.3.23. Changes in MySQL Connector/J 3.0.14-production (28 May 2004)
D.3.24. Changes in MySQL Connector/J 3.0.13-production (27 May 2004)
D.3.25. Changes in MySQL Connector/J 3.0.12-production (18 May 2004)
D.3.26. Changes in MySQL Connector/J 3.0.11-stable (19 February 2004)
D.3.27. Changes in MySQL Connector/J 3.0.10-stable (13 January 2004)
D.3.28. Changes in MySQL Connector/J 3.0.9-stable (07 October 2003)
D.3.29. Changes in MySQL Connector/J 3.0.8-stable (23 May 2003)
D.3.30. Changes in MySQL Connector/J 3.0.7-stable (08 April 2003)
D.3.31. Changes in MySQL Connector/J 3.0.6-stable (18 February 2003)
D.3.32. Changes in MySQL Connector/J 3.0.5-gamma (22 January 2003)
D.3.33. Changes in MySQL Connector/J 3.0.4-gamma (06 January 2003)
D.3.34. Changes in MySQL Connector/J 3.0.3-dev (17 December 2002)
D.3.35. Changes in MySQL Connector/J 3.0.2-dev (08 November 2002)
D.3.36. Changes in MySQL Connector/J 3.0.1-dev (21 September 2002)
D.3.37. Changes in MySQL Connector/J 3.0.0-dev (31 July 2002)
D.3.38. Changes in MySQL Connector/J 2.0.14 (16 May 2002)
D.3.39. Changes in MySQL Connector/J 2.0.13 (24 April 2002)
D.3.40. Changes in MySQL Connector/J 2.0.12 (07 April 2002)
D.3.41. Changes in MySQL Connector/J 2.0.11 (27 January 2002)
D.3.42. Changes in MySQL Connector/J 2.0.10 (24 January 2002)
D.3.43. Changes in MySQL Connector/J 2.0.9 (13 January 2002)
D.3.44. Changes in MySQL Connector/J 2.0.8 (25 November 2001)
D.3.45. Changes in MySQL Connector/J 2.0.7 (24 October 2001)
D.3.46. Changes in MySQL Connector/J 2.0.6 (16 June 2001)
D.3.47. Changes in MySQL Connector/J 2.0.5 (13 June 2001)
D.3.48. Changes in MySQL Connector/J 2.0.3 (03 December 2000)
D.3.49. Changes in MySQL Connector/J 2.0.1 (06 April 2000)
D.3.50. Changes in MySQL Connector/J 2.0.0pre5 (21 February 2000)
D.3.51. Changes in MySQL Connector/J 2.0.0pre4 (10 January 2000)
D.3.52. Changes in MySQL Connector/J 2.0.0pre (17 August 1999)
D.3.53. Changes in MySQL Connector/J 1.2b (04 July 1999)
D.3.54. Changes in MySQL Connector/J 1.2a (14 April 1999)
D.3.55. Changes in MySQL Connector/J 1.1i (24 March 1999)
D.3.56. Changes in MySQL Connector/J 1.1h (08 March 1999)
D.3.57. Changes in MySQL Connector/J 1.1g (19 February 1999)
D.3.58. Changes in MySQL Connector/J 1.1f (31 December 1998)
D.3.59. Changes in MySQL Connector/J 1.1b (03 November 1998)
D.3.60. Changes in MySQL Connector/J 1.1 (02 September 1998)
D.3.61. Changes in MySQL Connector/J 1.0 (24 August 1998)
D.3.62. Changes in MySQL Connector/J 0.9d (04 August 1998)
D.3.63. Changes in MySQL Connector/J 0.9 (28 July 1998)
D.3.64. Changes in MySQL Connector/J 0.8 (06 July 1998)
D.3.65. Changes in MySQL Connector/J 0.7 (01 July 1998)
D.3.66. Changes in MySQL Connector/J 0.6 (21 May 1998)

D.3.1. Changes in MySQL Connector/J 5.0.3 (26 July 2006)

  • Fixed Statement.cancel() causes NullPointerException if underlying connection has been closed due to server failure. (Bug#20650)

  • Added configuration option "noAccessToProcedureBodies" which will cause the driver to create basic parameter metadata for CallableStatements when the user does not have access to procedure bodies via "SHOW CREATE PROCEDURE" or selecting from mysql.proc instead of throwing an exception. The default value for this option is "false"

D.3.2. Changes in MySQL Connector/J 5.0.2-beta (11 July 2006)

  • Fixed can't use XAConnection for local transactions when no global transaction is in progress. (Bug#17401)

  • Fixed driver fails on non-ASCII platforms. The driver was assuming that the platform character set would be a superset of MySQL's latin1 when doing the handshake for authentication, and when reading error messages. We now use Cp1252 for all strings sent to the server during the handshake phase, and a hard-coded mapping of the language systtem variable to the character set that is used for error messages. (Bug#18086)

  • Fixed ConnectionProperties (and thus some subclasses) are not serializable, even though some J2EE containers expect them to be. (Bug#19169)

  • Fixed MysqlValidConnectionChecker for JBoss doesn't work with MySQLXADataSources. (Bug#20242)

  • Better caching of character set converters (per-connection) to remove a bottleneck for multibyte character sets.

  • Added connection/datasource property pinGlobalTxToPhysicalConnection (defaults to false). When set to true, when using XAConnections, the driver ensures that operations on a given XID are always routed to the same physical connection. This allows the XAConnection to support XA START ... JOIN after XA END has been called, and is also a workaround for transaction managers that don't maintain thread affinity for a global transaction (most either always maintain thread affinity, or have it as a configuration option).

  • MysqlXaConnection.recover(int flags) now allows combinations of XAResource.TMSTARTRSCAN and TMENDRSCAN. To simulate the „scanning“ nature of the interface, we return all prepared XIDs for TMSTARTRSCAN, and no new XIDs for calls with TMNOFLAGS, or TMENDRSCAN when not in combination with TMSTARTRSCAN. This change was made for API compliance, as well as integration with IBM WebSphere's transaction manager.

D.3.3. Changes in MySQL Connector/J 5.0.1-beta (Not Released)

Not released due to a packaging error

D.3.4. Changes in MySQL Connector/J 5.0.0-beta (22 December 2005)

  • XADataSource implemented (ported from 3.2 branch which won't be released as a product). Use com.mysql.jdbc.jdbc2.optional.MysqlXADataSource as your datasource class name in your application server to utilize XA transactions in MySQL-5.0.10 and newer.

  • PreparedStatement.setString() didn't work correctly when sql_mode on server contained NO_BACKSLASH_ESCAPES and no characters that needed escaping were present in the string.

  • Attempt detection of the MySQL type BINARY (it's an alias, so this isn't always reliable), and use the java.sql.Types.BINARY type mapping for it.

  • Moved -bin-g.jar file into separate debug subdirectory to avoid confusion.

  • Don't allow .setAutoCommit(true), or .commit() or .rollback() on an XA-managed connection as per the JDBC specification.

  • If the connection useTimezone is set to true, then also respect time zone conversions in escape-processed string literals (for example, "{ts ...}" and "{t ...}").

  • Return original column name for RSMD.getColumnName() if the column was aliased, alias name for .getColumnLabel() (if aliased), and original table name for .getTableName(). Note this only works for MySQL-4.1 and newer, as older servers don't make this information available to clients.

  • Setting useJDBCCompliantTimezoneShift=true (it's not the default) causes the driver to use GMT for all TIMESTAMP/DATETIME time zones, and the current VM time zone for any other type that refers to time zones. This feature can not be used when useTimezone=true to convert between server and client time zones.

  • Add one level of indirection of internal representation of CallableStatement parameter metadata to avoid class not found issues on JDK-1.3 for ParameterMetadata interface (which doesn't exist prior to JDBC-3.0).

  • Added unit tests for XADatasource, as well as friendlier exceptions for XA failures compared to the "stock" XAException (which has no messages).

  • Idle timeouts cause XAConnections to whine about rolling themselves back. (Bug#14729)

  • Added support for Connector/MXJ integration via url subprotocol jdbc:mysql:mxj://....

  • Moved all SQLException constructor usage to a factory in SQLError (ground-work for JDBC-4.0 SQLState-based exception classes).

  • Removed Java5-specific calls to BigDecimal constructor (when result set value is '', (int)0 was being used as an argument indirectly via method return value. This signature doesn't exist prior to Java5.)

  • Added service-provider entry to META-INF/services/java.sql.Driver for JDBC-4.0 support.

  • Return "[VAR]BINARY" for RSMD.getColumnTypeName() when that is actually the type, and it can be distinguished (MySQL-4.1 and newer).

  • When fix for Bug#14562 was merged from 3.1.12, added functionality for CallableStatement's parameter metadata to return correct information for .getParameterClassName().

  • Fuller synchronization of Connection to avoid deadlocks when using multithreaded frameworks that multithread a single connection (usually not recommended, but the JDBC spec allows it anyways), part of fix to Bug#14972).

  • Implementation of Statement.cancel() and Statement.setQueryTimeout(). Both require MySQL-5.0.0 or newer server, require a separate connection to issue the KILL QUERY statement, and in the case of setQueryTimeout() creates an additional thread to handle the timeout functionality.

    Note: Failures to cancel the statement for setQueryTimeout() may manifest themselves as RuntimeExceptions rather than failing silently, as there is currently no way to unblock the thread that is executing the query being cancelled due to timeout expiration and have it throw the exception instead.

D.3.5. Changes in MySQL Connector/J 3.1.14 (not yet released)

  • Fixed updatable result set throws ClassCastException when there is row data and moveToInsertRow() is called. (Fixes Bug#20479)

  • Fixed Updatable result set that contains a BIT column fails when server-side prepared statements are used. (Fixes Bug#20485)

  • Fixed memory leak with profileSQL=true. (Fixes Bug#16987)

  • Connection fails to localhost when using timeout and IPv6 is configured. (Fixes Bug#19726)

  • Fixed NullPointerException in MysqlDataSourceFactory due to Reference containing RefAddrs with null content. (Fixes Bug#16791)

  • Fixed ResultSet.getShort() for UNSIGNED TINYINT returns incorrect values when using server-side prepared statements. (Fixes Bug#20306)

  • Fixed can't pool server-side prepared statements, exception raised when re-using them. (Fixes Bug#20687)

  • Fixed Bug#21062 - ResultSet.getSomeInteger() doesn't work for BIT(>1).

  • Fixed Bug#18880 - ResultSet.getFloatFromString() can't retrieve values near Float.MIN/MAX_VALUE.

  • Fixed Bug#20888 - escape of quotes in client-side prepared statements parsing not respected. Patch covers more than bug report, including NO_BACKSLASH_ESCAPES being set, and stacked quote characters forms of escaping (i.e. '' or "").

  • Fixed Bug#19993 - ReplicationDriver does not always round-robin load balance depending on URL used for slaves list.

D.3.6. Changes in MySQL Connector/J 3.1.13 (26 May 2006)

  • INOUT parameter does not store IN value. (Bug#15464)

  • Exception thrown for new decimal type when using updatable result sets. (Bug#14609)

  • No "dos" character set in MySQL > 4.1.0. (Bug#15544)

  • PreparedStatement.setObject() serializes BigInteger as object, rather than sending as numeric value (and is thus not complementary to .getObject() on an UNSIGNED LONG type). (Bug#15383)

  • ResultSet.getShort() for UNSIGNED TINYINT returned wrong values. (Bug#11874)

  • lib-nodist directory missing from package breaks out-of-box build. (Bug#15676)

  • DBMD.getColumns() returns wrong type for BIT. (Bug#15854)

  • Fixed issue where driver was unable to initialize character set mapping tables. Removed reliance on .properties files to hold this information, as it turns out to be too problematic to code around class loader hierarchies that change depending on how an application is deployed. Moved information back into the CharsetMapping class. (Bug#14938)

  • Fixed updatable result set doesn't return AUTO_INCREMENT values for insertRow() when multiple column primary keys are used. (the driver was checking for the existence of single-column primary keys and an autoincrement value > 0 instead of a straightforward isAutoIncrement() check). (Bug#16841)

  • Fixed Statement.getGeneratedKeys() throws NullPointerException when no query has been processed. (Bug#17099)

  • Fixed driver trying to call methods that don't exist on older and newer versions of Log4j. The fix is not trying to auto-detect presense of log4j, too many different incompatible versions out there in the wild to do this reliably. (Bug#13469)

    If you relied on autodetection before, you will need to add "logger=com.mysql.jdbc.log.Log4JLogger" to your JDBC URL to enable Log4J usage, or alternatively use the new "CommonsLogger" class to take care of this.

  • Added support for Apache Commons logging, use "com.mysql.jdbc.log.CommonsLogger" as the value for the "logger" configuration property.

  • LogFactory now prepends "com.mysql.jdbc.log" to log class name if it can't be found as-specified. This allows you to use "short names" for the built-in log factories, for example "logger=CommonsLogger" instead of "logger=com.mysql.jdbc.log.CommonsLogger".

  • Fixed issue with ReplicationConnection incorrectly copying state, doesn't transfer connection context correctly when transitioning between the same read-only states. (Bug#15570)

  • Fixed issue where server-side prepared statements don't cause truncation exceptions to be thrown when truncation happens. (Bug#18041)

  • Added performance feature, re-writing of batched executes for Statement.executeBatch() (for all DML statements) and PreparedStatement.executeBatch() (for INSERTs with VALUE clauses only). Enable by using "rewriteBatchedStatements=true" in your JDBC URL.

  • Fixed CallableStatement.registerOutParameter() not working when some parameters pre-populated. Still waiting for feedback from JDBC experts group to determine what correct parameter count from getMetaData() should be, however. (Bug#17898)

  • Fixed calling clearParameters() on a closed prepared statement causes NPE. (Bug#17587)

  • Map "latin1" on MySQL server to CP1252 for MySQL > 4.1.0.

  • Added additional accessor and mutator methods on ConnectionProperties so that DataSource users can use same naming as regular URL properties.

  • Fixed data truncation and getWarnings() only returns last warning in set. (Bug#18740)

  • Improved performance of retrieving BigDecimal, Time, Timestamp and Date values from server-side prepared statements by creating fewer short-lived instances of Strings when the native type is not an exact match for the requested type. Fixes Bug#18496 for BigDecimals.

  • Fixed aliased column names where length of name > 251 are corrupted. (Bug#18554)

  • Fixed ResultSet.wasNull() not always reset correctly for booleans when done via conversion for server-side prepared statements. (Bug#17450)

  • Fixed invalid classname returned for ResultSetMetaData.getColumnClassName() for BIGINT type. (Bug#19282)

  • Fixed case where driver wasn't reading server status correctly when fetching server-side prepared statement rows, which in some cases could cause warning counts to be off, or multiple result sets to not be read off the wire.

  • Driver now aware of fix for BIT type metadata that went into MySQL-5.0.21 for server not reporting length consistently (Bug#13601).

  • Fixed PreparedStatement.setObject(int, Object, int) doesn't respect scale of BigDecimals. (Bug#19615)

  • Fixed ResultSet.wasNull() returns incorrect value when extracting native string from server-side prepared statement generated result set. (Bug#19282)

D.3.7. Changes in MySQL Connector/J 3.1.12 (30 November 2005)

  • Fixed client-side prepared statement bug with embedded ? characters inside quoted identifiers (it was recognized as a placeholder, when it was not).

  • Don't allow executeBatch() for CallableStatements with registered OUT/INOUT parameters (JDBC compliance).

  • Fall back to platform-encoding for URLDecoder.decode() when parsing driver URL properties if the platform doesn't have a two-argument version of this method.

  • Java type conversion may be incorrect for MEDIUMINT. (Bug#14562)

  • Added configuration property useGmtMillisForDatetimes which when set to true causes ResultSet.getDate(), .getTimestamp() to return correct millis-since GMT when .getTime() is called on the return value (currently default is false for legacy behavior).

  • Fixed DatabaseMetaData.stores*Identifiers():

    • If lower_case_table_names=0 (on server):

      • storesLowerCaseIdentifiers() returns false

      • storesLowerCaseQuotedIdentifiers() returns false

      • storesMixedCaseIdentifiers() returns true

      • storesMixedCaseQuotedIdentifiers() returns true

      • storesUpperCaseIdentifiers() returns false

      • storesUpperCaseQuotedIdentifiers() returns true

    • If lower_case_table_names=1 (on server):

      • storesLowerCaseIdentifiers() returns true

      • storesLowerCaseQuotedIdentifiers() returns true

      • storesMixedCaseIdentifiers() returns false

      • storesMixedCaseQuotedIdentifiers() returns false

      • storesUpperCaseIdentifiers() returns false

      • storesUpperCaseQuotedIdentifiers() returns true

  • DatabaseMetaData.getColumns() doesn't return TABLE_NAME correctly. (Bug#14815)

  • Escape processor replaces quote character in quoted string with string delimiter. (Bug#14909)

  • OpenOffice expects DBMD.supportsIntegrityEnhancementFacility() to return true if foreign keys are supported by the datasource, even though this method also covers support for check constraints, which MySQL doesn't have. Setting the configuration property overrideSupportsIntegrityEnhancementFacility to true causes the driver to return true for this method. (Bug#12975)

  • Added com.mysql.jdbc.testsuite.url.default system property to set default JDBC url for testsuite (to speed up bug resolution when I'm working in Eclipse).

  • Unable to initialize character set mapping tables (due to J2EE classloader differences). (Bug#14938)

  • Deadlock while closing server-side prepared statements from multiple threads sharing one connection. (Bug#14972)

  • logSlowQueries should give better info. (Bug#12230)

  • Extraneous sleep on autoReconnect. (Bug#13775)

  • Driver incorrectly closes streams passed as arguments to PreparedStatements. Reverts to legacy behavior by setting the JDBC configuration property autoClosePStmtStreams to true (also included in the 3-0-Compat configuration „bundle“). (Bug#15024)

  • maxQuerySizeToLog is not respected. Added logging of bound values for execute() phase of server-side prepared statements when profileSQL=true as well. (Bug#13048)

  • Usage advisor complains about unreferenced columns, even though they've been referenced. (Bug#15065)

  • Don't increase timeout for failover/reconnect. (Bug#6577)

  • Process escape tokens in Connection.prepareStatement(...). (Bug#15141) You can disable this behavior by setting the JDBC URL configuration property processEscapeCodesForPrepStmts to false.

  • Reconnect during middle of executeBatch() should not occur if autoReconnect is enabled. (Bug#13255)

D.3.8. Changes in MySQL Connector/J 3.1.11-stable (07 October 2005)

  • Spurious ! on console when character encoding is utf8. (Bug#11629)

  • Fixed statements generated for testcases missing ; for „plain“ statements.

  • Incorrect generation of testcase scripts for server-side prepared statements. (Bug#11663)

  • Fixed regression caused by fix for Bug#11552 that caused driver to return incorrect values for unsigned integers when those integers where within the range of the positive signed type.

  • Moved source code to Subversion repository.

  • Escape tokenizer doesn't respect stacked single quotes for escapes. (Bug#11797)

  • GEOMETRY type not recognized when using server-side prepared statements.

  • ReplicationConnection won't switch to slave, throws „Catalog can't be null“ exception. (Bug#11879)

  • Properties shared between master and slave with replication connection. (Bug#12218)

  • Statement.getWarnings() fails with NPE if statement has been closed. (Bug#10630)

  • Only get char[] from SQL in PreparedStatement.ParseInfo() when needed.

  • Geometry types not handled with server-side prepared statements. (Bug#12104)

  • StringUtils.getBytes() doesn't work when using multi-byte character encodings and a length in characters is specified. (Bug#11614)

  • Pstmt.setObject(...., Types.BOOLEAN) throws exception. (Bug#11798)

  • maxPerformance.properties mis-spells „elideSetAutoCommits“. (Bug#11976)

  • DBMD.storesLower/Mixed/UpperIdentifiers() reports incorrect values for servers deployed on Windows. (Bug#11575)

  • ResultSet.moveToCurrentRow() fails to work when preceded by a call to ResultSet.moveToInsertRow(). (Bug#11190)

  • VARBINARY data corrupted when using server-side prepared statements and .setBytes(). (Bug#11115)

  • explainSlowQueries hangs with server-side prepared statements. (Bug#12229)

  • Escape processor didn't honor strings demarcated with double quotes. (Bug#11498)

  • Lifted restriction of changing streaming parameters with server-side prepared statements. As long as all streaming parameters were set before execution, .clearParameters() does not have to be called. (due to limitation of client/server protocol, prepared statements can not reset individual stream data on the server side).

  • Reworked Field class, *Buffer, and MysqlIO to be aware of field lengths > Integer.MAX_VALUE.

  • Updated DBMD.supportsCorrelatedQueries() to return true for versions > 4.1, supportsGroupByUnrelated() to return true and getResultSetHoldability() to return HOLD_CURSORS_OVER_COMMIT.

  • Handling of catalog argument in DatabaseMetaData.getIndexInfo(), which also means changes to the following methods in DatabaseMetaData: (Bug#12541)

    • getBestRowIdentifier()

    • getColumns()

    • getCrossReference()

    • getExportedKeys()

    • getImportedKeys()

    • getIndexInfo()

    • getPrimaryKeys()

    • getProcedures() (and thus indirectly getProcedureColumns())

    • getTables()

    The catalog argument in all of these methods now behaves in the following way:

    • Specifying NULL means that catalog will not be used to filter the results (thus all databases will be searched), unless you've set nullCatalogMeansCurrent=true in your JDBC URL properties.

    • Specifying "" means „current“ catalog, even though this isn't quite JDBC spec compliant, it's there for legacy users.

    • Specifying a catalog works as stated in the API docs.

    • Made Connection.clientPrepare() available from „wrapped“ connections in the jdbc2.optional package (connections built by ConnectionPoolDataSource instances).

  • Added Connection.isMasterConnection() for clients to be able to determine if a multi-host master/slave connection is connected to the first host in the list.

  • Tokenizer for = in URL properties was causing sessionVariables=.... to be parameterized incorrectly. (Bug#12753)

  • Foreign key information that is quoted is parsed incorrectly when DatabaseMetaData methods use that information. (Bug#11781)

  • The sendBlobChunkSize property is now clamped to max_allowed_packet with consideration of stream buffer size and packet headers to avoid PacketTooBigExceptions when max_allowed_packet is similar in size to the default sendBlobChunkSize which is 1M.

  • CallableStatement.clearParameters() now clears resources associated with INOUT/OUTPUT parameters as well as INPUT parameters.

  • Connection.prepareCall() is database name case-sensitive (on Windows systems). (Bug#12417)

  • cp1251 incorrectly mapped to win1251 for servers newer than 4.0.x. (Bug#12752)

  • java.sql.Types.OTHER returned for BINARY and VARBINARY columns when using DatabaseMetaData.getColumns(). (Bug#12970)

  • ServerPreparedStatement.getBinding() now checks if the statement is closed before attempting to reference the list of parameter bindings, to avoid throwing a NullPointerException.

  • ResultSetMetaData from Statement.getGeneratedKeys() caused a NullPointerException to be thrown whenever a method that required a connection reference was called. (Bug#13277)

  • Backport of Field class, ResultSetMetaData.getColumnClassName(), and ResultSet.getObject(int) changes from 5.0 branch to fix behavior surrounding VARCHAR BINARY/VARBINARY and related types.

  • Fixed NullPointerException when converting catalog parameter in many DatabaseMetaDataMethods to byte[]s (for the result set) when the parameter is null. (null isn't technically allowed by the JDBC specification, but we've historically allowed it).

  • Backport of VAR[BINARY|CHAR] [BINARY] types detection from 5.0 branch.

  • Read response in MysqlIO.sendFileToServer(), even if the local file can't be opened, otherwise next query issued will fail, because it's reading the response to the empty LOAD DATA INFILE packet sent to the server.

  • Workaround for Bug#13374: ResultSet.getStatement() on closed result set returns NULL (as per JDBC 4.0 spec, but not backward-compatible). Set the connection property retainStatementAfterResultSetClose to true to be able to retrieve a ResultSet's statement after the ResultSet has been closed via .getStatement() (the default is false, to be JDBC-compliant and to reduce the chance that code using JDBC leaks Statement instances).

  • URL configuration parameters don't allow ‘&’ or ‘=’ in their values. The JDBC driver now parses configuration parameters as if they are encoded using the application/x-www-form-urlencoded format as specified by java.net.URLDecoder (http://java.sun.com/j2se/1.5.0/docs/api/java/net/URLDecoder.html). (Bug#13453)

    If the ‘%’ character is present in a configuration property, it must now be represented as %25, which is the encoded form of ‘%’ when using application/x-www-form-urlencoded encoding.

  • The configuration property sessionVariables now allows you to specify variables that start with the ‘@’ sign.

  • When gatherPerfMetrics is enabled for servers older than 4.1.0, a NullPointerException is thrown from the constructor of ResultSet if the query doesn't use any tables. (Bug#13043)

D.3.9. Changes in MySQL Connector/J 3.1.10-stable (23 June 2005)

  • Fixed connecting without a database specified raised an exception in MysqlIO.changeDatabaseTo().

  • Initial implemention of ParameterMetadata for PreparedStatement.getParameterMetadata(). Only works fully for CallableStatements, as current server-side prepared statements return every parameter as a VARCHAR type.

D.3.10. Changes in MySQL Connector/J 3.1.9-stable (22 June 2005)

  • Overhaul of character set configuration, everything now lives in a properties file.

  • Driver now correctly uses CP932 if available on the server for Windows-31J, CP932 and MS932 java encoding names, otherwise it resorts to SJIS, which is only a close approximation. Currently only MySQL-5.0.3 and newer (and MySQL-4.1.12 or .13, depending on when the character set gets backported) can reliably support any variant of CP932.

  • com.mysql.jdbc.PreparedStatement.ParseInfo does unnecessary call to toCharArray(). (Bug#9064)

  • Memory leak in ServerPreparedStatement if serverPrepare() fails. (Bug#10144)

  • Actually write manifest file to correct place so it ends up in the binary jar file.

  • Added createDatabaseIfNotExist property (default is false), which will cause the driver to ask the server to create the database specified in the URL if it doesn't exist. You must have the appropriate privileges for database creation for this to work.

  • Unsigned SMALLINT treated as signed for ResultSet.getInt(), fixed all cases for UNSIGNED integer values and server-side prepared statements, as well as ResultSet.getObject() for UNSIGNED TINYINT. (Bug#10156)

  • Double quotes not recognized when parsing client-side prepared statements. (Bug#10155)

  • Made enableStreamingResults() visible on com.mysql.jdbc.jdbc2.optional.StatementWrapper.

  • Made ServerPreparedStatement.asSql() work correctly so auto-explain functionality would work with server-side prepared statements.

  • Made JDBC2-compliant wrappers public in order to allow access to vendor extensions.

  • Cleaned up logging of profiler events, moved code to dump a profiler event as a string to com.mysql.jdbc.log.LogUtils so that third parties can use it.

  • DatabaseMetaData.supportsMultipleOpenResults() now returns true. The driver has supported this for some time, DBMD just missed that fact.

  • Driver doesn't support {?=CALL(...)} for calling stored functions. This involved adding support for function retrieval to DatabaseMetaData.getProcedures() and getProcedureColumns() as well. (Bug#10310)

  • SQLException thrown when retrieving YEAR(2) with ResultSet.getString(). The driver will now always treat YEAR types as java.sql.Dates and return the correct values for getString(). Alternatively, the yearIsDateType connection property can be set to false and the values will be treated as SHORTs. (Bug#10485)

  • The datatype returned for TINYINT(1) columns when tinyInt1isBit=true (the default) can be switched between Types.BOOLEAN and Types.BIT using the new configuration property transformedBitIsBoolean, which defaults to false. If set to false (the default), DatabaseMetaData.getColumns() and ResultSetMetaData.getColumnType() will return Types.BOOLEAN for TINYINT(1) columns. If true, Types.BOOLEAN will be returned instead. Regardless of this configuration property, if tinyInt1isBit is enabled, columns with the type TINYINT(1) will be returned as java.lang.Boolean instances from ResultSet.getObject(...), and ResultSetMetaData.getColumnClassName() will return java.lang.Boolean.

  • SQLException is thrown when using property characterSetResults with cp932 or eucjpms. (Bug#10496)

  • Reorganized directory layout. Sources now are in src folder. Don't pollute parent directory when building, now output goes to ./build, distribution goes to ./dist.

  • Added support/bug hunting feature that generates .sql test scripts to STDERR when autoGenerateTestcaseScript is set to true.

  • 0-length streams not sent to server when using server-side prepared statements. (Bug#10850)

  • Setting cachePrepStmts=true now causes the Connection to also cache the check the driver performs to determine if a prepared statement can be server-side or not, as well as caches server-side prepared statements for the lifetime of a connection. As before, the prepStmtCacheSize parameter controls the size of these caches.

  • Try to handle OutOfMemoryErrors more gracefully. Although not much can be done, they will in most cases close the connection they happened on so that further operations don't run into a connection in some unknown state. When an OOM has happened, any further operations on the connection will fail with a „Connection closed“ exception that will also list the OOM exception as the reason for the implicit connection close event.

  • Don't send COM_RESET_STMT for each execution of a server-side prepared statement if it isn't required.

  • Driver detects if you're running MySQL-5.0.7 or later, and does not scan for LIMIT ?[,?] in statements being prepared, as the server supports those types of queries now.

  • VARBINARY data corrupted when using server-side prepared statements and ResultSet.getBytes(). (Bug#11115)

  • Connection.setCatalog() is now aware of the useLocalSessionState configuration property, which when set to true will prevent the driver from sending USE ... to the server if the requested catalog is the same as the current catalog.

  • Added the following configuration bundles, use one or many via the useConfigs configuration property:

    • maxPerformance — maximum performance without being reckless

    • solarisMaxPerformance — maximum performance for Solaris, avoids syscalls where it can

    • 3-0-Compat — Compatibility with Connector/J 3.0.x functionality

  • Added maintainTimeStats configuration property (defaults to true), which tells the driver whether or not to keep track of the last query time and the last successful packet sent to the server's time. If set to false, removes two syscalls per query.

  • autoReconnect ping causes exception on connection startup. (Bug#11259)

  • Connector/J dumping query into SQLException twice. (Bug#11360)

  • Fixed PreparedStatement.setClob() not accepting null as a parameter.

  • Production package doesn't include JBoss integration classes. (Bug#11411)

  • Removed nonsensical „costly type conversion“ warnings when using usage advisor.

D.3.11. Changes in MySQL Connector/J 3.1.8-stable (14 April 2005)

  • Fixed DatabaseMetaData.getTables() returning views when they were not asked for as one of the requested table types.

  • Added support for new precision-math DECIMAL type in MySQL 5.0.3 and up.

  • Fixed ResultSet.getTime() on a NULL value for server-side prepared statements throws NPE.

  • Made Connection.ping() a public method.

  • DATE_FORMAT() queries returned as BLOBs from getObject(). (Bug#8868)

  • ServerPreparedStatements now correctly „streamBLOB/CLOB data to the server. You can configure the threshold chunk size using the JDBC URL property blobSendChunkSize (the default is 1MB).

  • BlobFromLocator now uses correct identifier quoting when generating prepared statements.

  • Server-side session variables can be preset at connection time by passing them as a comma-delimited list for the connection property sessionVariables.

  • Fixed regression in ping() for users using autoReconnect=true.

  • PreparedStatement.addBatch() doesn't work with server-side prepared statements and streaming BINARY data. (Bug#9040)

  • DBMD.supportsMixedCase*Identifiers() returns wrong value on servers running on case-sensitive filesystems. (Bug#8800)

  • Cannot use UTF-8 for characterSetResults configuration property. (Bug#9206)

  • A continuation of Bug#8868, where functions used in queries that should return non-string types when resolved by temporary tables suddenly become opaque binary strings (work-around for server limitation). Also fixed fields with type of CHAR(n) CHARACTER SET BINARY to return correct/matching classes for RSMD.getColumnClassName() and ResultSet.getObject(). (Bug#9236)

  • DBMD.supportsResultSetConcurrency() not returning true for forward-only/read-only result sets (we obviously support this). (Bug#8792)

  • DATA_TYPE column from DBMD.getBestRowIdentifier() causes ArrayIndexOutOfBoundsException when accessed (and in fact, didn't return any value). (Bug#8803)

  • Check for empty strings ('') when converting CHAR/VARCHAR column data to numbers, throw exception if emptyStringsConvertToZero configuration property is set to false (for backward-compatibility with 3.0, it is now set to true by default, but will most likely default to false in 3.2).

  • PreparedStatement.getMetaData() inserts blank row in database under certain conditions when not using server-side prepared statements. (Bug#9320)

  • Connection.canHandleAsPreparedStatement() now makes „best effort“ to distinguish LIMIT clauses with placeholders in them from ones without in order to have fewer false positives when generating work-arounds for statements the server cannot currently handle as server-side prepared statements.

  • Fixed build.xml to not compile log4j logging if log4j not available.

  • Added support for the c3p0 connection pool's (http://c3p0.sf.net/) validation/connection checker interface which uses the lightweight COM_PING call to the server if available. To use it, configure your c3p0 connection pool's connectionTesterClassName property to use com.mysql.jdbc.integration.c3p0.MysqlConnectionTester.

  • Better detection of LIMIT inside/outside of quoted strings so that the driver can more correctly determine whether a prepared statement can be prepared on the server or not.

  • Stored procedures with same name in different databases confuse the driver when it tries to determine parameter counts/types. (Bug#9319)

  • Added finalizers to ResultSet and Statement implementations to be JDBC spec-compliant, which requires that if not explicitly closed, these resources should be closed upon garbage collection.

  • Stored procedures with DECIMAL parameters with storage specifications that contained ‘,’ in them would fail. (Bug#9682)

  • PreparedStatement.setObject(int, Object, int type, int scale) now uses scale value for BigDecimal instances.

  • Statement.getMoreResults() could throw NPE when existing result set was .close()d. (Bug#9704)

  • The performance metrics feature now gathers information about number of tables referenced in a SELECT.

  • The logging system is now automatically configured. If the value has been set by the user, via the URL property logger or the system property com.mysql.jdbc.logger, then use that, otherwise, autodetect it using the following steps:

    1. Log4j, if it's available,

    2. Then JDK1.4 logging,

    3. Then fallback to our STDERR logging.

  • DBMD.getTables() shouldn't return tables if views are asked for, even if the database version doesn't support views. (Bug#9778)

  • Fixed driver not returning true for -1 when ResultSet.getBoolean() was called on result sets returned from server-side prepared statements.

  • Added a Manifest.MF file with implementation information to the .jar file.

  • More tests in Field.isOpaqueBinary() to distinguish opaque binary (that is, fields with type CHAR(n) and CHARACTER SET BINARY) from output of various scalar and aggregate functions that return strings.

  • Should accept null for catalog (meaning use current) in DBMD methods, even though it's not JDBC-compliant for legacy's sake. Disable by setting connection property nullCatalogMeansCurrent to false (which will be the default value in C/J 3.2.x). (Bug#9917)

  • Should accept null for name patterns in DBMD (meaning ‘%’), even though it isn't JDBC compliant, for legacy's sake. Disable by setting connection property nullNamePatternMatchesAll to false (which will be the default value in C/J 3.2.x). (Bug#9769)

D.3.12. Changes in MySQL Connector/J 3.1.7-stable (18 February 2005)

  • Timestamp key column data needed _binary stripped for UpdatableResultSet.refreshRow(). (Bug#7686)

  • Timestamps converted incorrectly to strings with server-side prepared statements and updatable result sets. (Bug#7715)

  • Detect new sql_mode variable in string form (it used to be integer) and adjust quoting method for strings appropriately.

  • Added holdResultsOpenOverStatementClose property (default is false), that keeps result sets open over statement.close() or new execution on same statement (suggested by Kevin Burton).

  • Infinite recursion when „falling back“ to master in failover configuration. (Bug#7952)

  • Disable multi-statements (if enabled) for MySQL-4.1 versions prior to version 4.1.10 if the query cache is enabled, as the server returns wrong results in this configuration.

  • Fixed duplicated code in configureClientCharset() that prevented useOldUTF8Behavior=true from working properly.

  • Removed dontUnpackBinaryResults functionality, the driver now always stores results from server-side prepared statements as is from the server and unpacks them on demand.

  • Emulated locators corrupt binary data when using server-side prepared statements. (Bug#8096)

  • Fixed synchronization issue with ServerPreparedStatement.serverPrepare() that could cause deadlocks/crashes if connection was shared between threads.

  • By default, the driver now scans SQL you are preparing via all variants of Connection.prepareStatement() to determine if it is a supported type of statement to prepare on the server side, and if it is not supported by the server, it instead prepares it as a client-side emulated prepared statement. You can disable this by passing emulateUnsupportedPstmts=false in your JDBC URL. (Bug#4718)

  • Remove _binary introducer from parameters used as in/out parameters in CallableStatement.

  • Always return byte[]s for output parameters registered as *BINARY.

  • Send correct value for „booleantrue to server for PreparedStatement.setObject(n, "true", Types.BIT).

  • Fixed bug with Connection not caching statements from prepareStatement() when the statement wasn't a server-side prepared statement.

  • Choose correct „direction“ to apply time adjustments when both client and server are in GMT time zone when using ResultSet.get(..., cal) and PreparedStatement.set(...., cal).

  • Added dontTrackOpenResources option (default is false, to be JDBC compliant), which helps with memory use for non-well-behaved apps (that is, applications that don't close Statement objects when they should).

  • ResultSet.getString() doesn't maintain format stored on server, bug fix only enabled when noDatetimeStringSync property is set to true (the default is false). (Bug#8428)

  • Fixed NPE in ResultSet.realClose() when using usage advisor and result set was already closed.

  • PreparedStatements not creating streaming result sets. (Bug#8487)

  • Don't pass NULL to String.valueOf() in ResultSet.getNativeConvertToString(), as it stringifies it (that is, returns null), which is not correct for the method in question.

  • ResultSet.getBigDecimal() throws exception when rounding would need to occur to set scale. The driver now chooses a rounding mode of „half up“ if non-rounding BigDecimal.setScale() fails. (Bug#8424)

  • Added useLocalSessionState configuration property, when set to true the JDBC driver trusts that the application is well-behaved and only sets autocommit and transaction isolation levels using the methods provided on java.sql.Connection, and therefore can manipulate these values in many cases without incurring round-trips to the database server.

  • Added enableStreamingResults() to Statement for connection pool implementations that check Statement.setFetchSize() for specification-compliant values. Call Statement.setFetchSize(>=0) to disable the streaming results for that statement.

  • Added support for BIT type in MySQL-5.0.3. The driver will treat BIT(1-8) as the JDBC standard BIT type (which maps to java.lang.Boolean), as the server does not currently send enough information to determine the size of a bitfield when < 9 bits are declared. BIT(>9) will be treated as VARBINARY, and will return byte[] when getObject() is called.

D.3.13. Changes in MySQL Connector/J 3.1.6-stable (23 December 2004)

  • Fixed hang on SocketInputStream.read() with Statement.setMaxRows() and multiple result sets when driver has to truncate result set directly, rather than tacking a LIMIT n on the end of it.

  • DBMD.getProcedures() doesn't respect catalog parameter. (Bug#7026)

D.3.14. Changes in MySQL Connector/J 3.1.5-gamma (02 December 2004)

  • Fix comparisons made between string constants and dynamic strings that are converted with either toUpperCase() or toLowerCase() to use Locale.ENGLISH, as some locales „override“ case rules for English. Also use StringUtils.indexOfIgnoreCase() instead of .toUpperCase().indexOf(), avoids creating a very short-lived transient String instance.

  • Server-side prepared statements did not honor zeroDateTimeBehavior property, and would cause class-cast exceptions when using ResultSet.getObject(), as the all-zero string was always returned. (Bug#5235)

  • Fixed batched updates with server prepared statements weren't looking if the types had changed for a given batched set of parameters compared to the previous set, causing the server to return the error „Wrong arguments to mysql_stmt_execute()“.

  • Handle case when string representation of timestamp contains trailing ‘.’ with no numbers following it.

  • Inefficient detection of pre-existing string instances in ResultSet.getNativeString(). (Bug#5706)

  • Don't throw exceptions for Connection.releaseSavepoint().

  • Use a per-session Calendar instance by default when decoding dates from ServerPreparedStatements (set to old, less performant behavior by setting property dynamicCalendars=true).

  • Added experimental configuration property dontUnpackBinaryResults, which delays unpacking binary result set values until they're asked for, and only creates object instances for non-numerical values (it is set to false by default). For some usecase/jvm combinations, this is friendlier on the garbage collector.

  • UNSIGNED BIGINT unpacked incorrectly from server-side prepared statement result sets. (Bug#5729)

  • ServerSidePreparedStatement allocating short-lived objects unnecessarily. (Bug#6225)

  • Removed unwanted new Throwable() in ResultSet constructor due to bad merge (caused a new object instance that was never used for every result set created). Found while profiling for Bug#6359.

  • Fixed too-early creation of StringBuffer in EscapeProcessor.escapeSQL(), also return String when escaping not needed (to avoid unnecessary object allocations). Found while profiling for Bug#6359.

  • Use null-safe-equals for key comparisons in updatable result sets.

  • SUM() on DECIMAL with server-side prepared statement ignores scale if zero-padding is needed (this ends up being due to conversion to DOUBLE by server, which when converted to a string to parse into BigDecimal, loses all „padding“ zeros). (Bug#6537)

  • Use DatabaseMetaData.getIdentifierQuoteString() when building DBMD queries.

  • Use 1MB packet for sending file for LOAD DATA LOCAL INFILE if that is < max_allowed_packet on server.

  • ResultSetMetaData.getColumnDisplaySize() returns incorrect values for multi-byte charsets. (Bug#6399)

  • Make auto-deserialization of java.lang.Objects stored in BLOB columns configurable via autoDeserialize property (defaults to false).

  • Re-work Field.isOpaqueBinary() to detect CHAR(n) CHARACTER SET BINARY to support fixed-length binary fields for ResultSet.getObject().

  • Use our own implementation of buffered input streams to get around blocking behavior of java.io.BufferedInputStream. Disable this with useReadAheadInput=false.

  • Failing to connect to the server when one of the addresses for the given host name is IPV6 (which the server does not yet bind on). The driver now loops through all IP addresses for a given host, and stops on the first one that accepts() a socket.connect(). (Bug#6348)

D.3.15. Changes in MySQL Connector/J 3.1.4-beta (04 September 2004)

  • Connector/J 3.1.3 beta does not handle integers correctly (caused by changes to support unsigned reads in Buffer.readInt() -> Buffer.readShort()). (Bug#4510)

  • Added support in DatabaseMetaData.getTables() and getTableTypes() for views, which are now available in MySQL server 5.0.x.

  • ServerPreparedStatement.execute*() sometimes threw ArrayIndexOutOfBoundsException when unpacking field metadata. (Bug#4642)

  • Optimized integer number parsing, enable „old“ slower integer parsing using JDK classes via useFastIntParsing=false property.

  • Added useOnlyServerErrorMessages property, which causes message text in exceptions generated by the server to only contain the text sent by the server (as opposed to the SQLState's „standard“ description, followed by the server's error message). This property is set to true by default.

  • ResultSet.wasNull() does not work for primatives if a previous null was returned. (Bug#4689)

  • Track packet sequence numbers if enablePacketDebug=true, and throw an exception if packets received out-of-order.

  • ResultSet.getObject() returns wrong type for strings when using prepared statements. (Bug#4482)

  • Calling MysqlPooledConnection.close() twice (even though an application error), caused NPE. Fixed.

  • ServerPreparedStatements dealing with return of DECIMAL type don't work. (Bug#5012)

  • ResultSet.getObject() doesn't return type Boolean for pseudo-bit types from prepared statements on 4.1.x (shortcut for avoiding extra type conversion when using binary-encoded result sets obscured test in getObject() for „pseudo“ bit type). (Bug#5032)

  • You can now use URLs in LOAD DATA LOCAL INFILE statements, and the driver will use Java's built-in handlers for retreiving the data and sending it to the server. This feature is not enabled by default, you must set the allowUrlInLocalInfile connection property to true.

  • The driver is more strict about truncation of numerics on ResultSet.get*(), and will throw an SQLException when truncation is detected. You can disable this by setting jdbcCompliantTruncation to false (it is enabled by default, as this functionality is required for JDBC compliance).

  • Added three ways to deal with all-zero datetimes when reading them from a ResultSet: exception (the default), which throws an SQLException with an SQLState of S1009; convertToNull, which returns NULL instead of the date; and round, which rounds the date to the nearest closest value which is '0001-01-01'.

  • Fixed ServerPreparedStatement to read prepared statement metadata off the wire, even though it's currently a placeholder instead of using MysqlIO.clearInputStream() which didn't work at various times because data wasn't available to read from the server yet. This fixes sporadic errors users were having with ServerPreparedStatements throwing ArrayIndexOutOfBoundExceptions.

  • Use com.mysql.jdbc.Message's classloader when loading resource bundle, should fix sporadic issues when the caller's classloader can't locate the resource bundle.

D.3.16. Changes in MySQL Connector/J 3.1.3-beta (07 July 2004)

  • Mangle output parameter names for CallableStatements so they will not clash with user variable names.

  • Added support for INOUT parameters in CallableStatements.

  • Null bitmask sent for server-side prepared statements was incorrect. (Bug#4119)

  • Use SQL Standard SQL states by default, unless useSqlStateCodes property is set to false.

  • Added packet debuging code (see the enablePacketDebug property documentation).

  • Added constants for MySQL error numbers (publicly accessible, see com.mysql.jdbc.MysqlErrorNumbers), and the ability to generate the mappings of vendor error codes to SQLStates that the driver uses (for documentation purposes).

  • Externalized more messages (on-going effort).

  • Error in retrieval of mediumint column with prepared statements and binary protocol. (Bug#4311)

  • Support new time zone variables in MySQL-4.1.3 when useTimezone=true.

  • Support for unsigned numerics as return types from prepared statements. This also causes a change in ResultSet.getObject() for the bigint unsigned type, which used to return BigDecimal instances, it now returns instances of java.lang.BigInteger.

D.3.17. Changes in MySQL Connector/J 3.1.2-alpha (09 June 2004)

  • Fixed stored procedure parameter parsing info when size was specified for a parameter (for example, char(), varchar()).

  • Enabled callable statement caching via cacheCallableStmts property.

  • Fixed case when no output parameters specified for a stored procedure caused a bogus query to be issued to retrieve out parameters, leading to a syntax error from the server.

  • Fixed case when no parameters could cause a NullPointerException in CallableStatement.setOutputParameters().

  • Removed wrapping of exceptions in MysqlIO.changeUser().

  • Fixed sending of split packets for large queries, enabled nio ability to send large packets as well.

  • Added .toString() functionality to ServerPreparedStatement, which should help if you're trying to debug a query that is a prepared statement (it shows SQL as the server would process).

  • Added gatherPerformanceMetrics property, along with properties to control when/where this info gets logged (see docs for more info).

  • ServerPreparedStatements weren't actually de-allocating server-side resources when .close() was called.

  • Added logSlowQueries property, along with slowQueriesThresholdMillis property to control when a query should be considered „slow.

  • Correctly map output parameters to position given in prepareCall() versus. order implied during registerOutParameter(). (Bug#3146)

  • Correctly detect initial character set for servers >= 4.1.0.

  • Cleaned up detection of server properties.

  • Support placeholder for parameter metadata for server >= 4.1.2.

  • getProcedures() does not return any procedures in result set. (Bug#3539)

  • getProcedureColumns() doesn't work with wildcards for procedure name. (Bug#3540)

  • DBMD.getSQLStateType() returns incorrect value. (Bug#3520)

  • Added connectionCollation property to cause driver to issue set collation_connection=... query on connection init if default collation for given charset is not appropriate.

  • Fixed DatabaseMetaData.getProcedures() when run on MySQL-5.0.0 (output of SHOW PROCEDURE STATUS changed between 5.0.0 and 5.0.1.

  • getWarnings() returns SQLWarning instead of DataTruncation. (Bug#3804)

  • Don't enable server-side prepared statements for server version 5.0.0 or 5.0.1, as they aren't compatible with the '4.1.2+' style that the driver uses (the driver expects information to come back that isn't there, so it hangs).

D.3.18. Changes in MySQL Connector/J 3.1.1-alpha (14 February 2004)

  • Fixed bug with UpdatableResultSets not using client-side prepared statements.

  • Fixed character encoding issues when converting bytes to ASCII when MySQL doesn't provide the character set, and the JVM is set to a multi-byte encoding (usually affecting retrieval of numeric values).

  • Unpack „unknown“ data types from server prepared statements as Strings.

  • Implemented long data (Blobs, Clobs, InputStreams, Readers) for server prepared statements.

  • Implemented Statement.getWarnings() for MySQL-4.1 and newer (using SHOW WARNINGS).

  • Default result set type changed to TYPE_FORWARD_ONLY (JDBC compliance).

  • Centralized setting of result set type and concurrency.

  • Refactored how connection properties are set and exposed as DriverPropertyInfo as well as Connection and DataSource properties.

  • Support for NIO. Use useNIO=true on platforms that support NIO.

  • Support for transaction savepoints (MySQL >= 4.0.14 or 4.1.1).

  • Support for mysql_change_user(). See the changeUser() method in com.mysql.jdbc.Connection.

  • Reduced number of methods called in average query to be more efficient.

  • Prepared Statements will be re-prepared on auto-reconnect. Any errors encountered are postponed until first attempt to re-execute the re-prepared statement.

  • Ensure that warnings are cleared before executing queries on prepared statements, as-per JDBC spec (now that we support warnings).

  • Support „oldprofileSql capitalization in ConnectionProperties. This property is deprecated, you should use profileSQL if possible.

  • Optimized Buffer.readLenByteArray() to return shared empty byte array when length is 0.

  • Allow contents of PreparedStatement.setBlob() to be retained between calls to .execute*().

  • Deal with 0-length tokens in EscapeProcessor (caused by callable statement escape syntax).

  • Check for closed connection on delete/update/insert row operations in UpdatableResultSet.

  • Fix support for table aliases when checking for all primary keys in UpdatableResultSet.

  • Removed useFastDates connection property.

  • Correctly initialize datasource properties from JNDI Refs, including explicitly specified URLs.

  • DatabaseMetaData now reports supportsStoredProcedures() for MySQL versions >= 5.0.0

  • Fixed stack overflow in Connection.prepareCall() (bad merge).

  • Fixed IllegalAccessError to Calendar.getTimeInMillis() in DateTimeValue (for JDK < 1.4).

  • DatabaseMetaData.getColumns() is not returning correct column ordinal info for non-'%' column name patterns. (Bug#1673)

  • Merged fix of datatype mapping from MySQL type FLOAT to java.sql.Types.REAL from 3.0 branch.

  • Detect collation of column for RSMD.isCaseSensitive().

  • Fixed sending of queries larger than 16M.

  • Added named and indexed input/output parameter support to CallableStatement. MySQL-5.0.x or newer.

  • Fixed NullPointerException in ServerPreparedStatement.setTimestamp(), as well as year and month descrepencies in ServerPreparedStatement.setTimestamp(), setDate().

  • Added ability to have multiple database/JVM targets for compliance and regression/unit tests in build.xml.

  • Fixed NPE and year/month bad conversions when accessing some datetime functionality in ServerPreparedStatements and their resultant result sets.

  • Display where/why a connection was implicitly closed (to aid debugging).

  • CommunicationsException implemented, that tries to determine why communications was lost with a server, and displays possible reasons when .getMessage() is called.

  • NULL values for numeric types in binary encoded result sets causing NullPointerExceptions. (Bug#2359)

  • Implemented Connection.prepareCall(), and DatabaseMetaData. getProcedures() and getProcedureColumns().

  • Reset long binary parameters in ServerPreparedStatement when clearParameters() is called, by sending COM_RESET_STMT to the server.

  • Merged prepared statement caching, and .getMetaData() support from 3.0 branch.

  • Fixed off-by-1900 error in some cases for years in TimeUtil.fastDate/TimeCreate() when unpacking results from server-side prepared statements.

  • Fixed charset conversion issue in getTables(). (Bug#2502)

  • Implemented multiple result sets returned from a statement or stored procedure.

  • Server-side prepared statements were not returning datatype YEAR correctly. (Bug#2606)

  • Enabled streaming of result sets from server-side prepared statements.

  • Class-cast exception when using scrolling result sets and server-side prepared statements. (Bug#2623)

  • Merged unbuffered input code from 3.0.

  • Fixed ConnectionProperties that weren't properly exposed via accessors, cleaned up ConnectionProperties code.

  • NULL fields were not being encoded correctly in all cases in server-side prepared statements. (Bug#2671)

  • Fixed rare buffer underflow when writing numbers into buffers for sending prepared statement execution requests.

  • Use DocBook version of docs for shipped versions of drivers.

D.3.19. Changes in MySQL Connector/J 3.1.0-alpha (18 February 2003)

  • Added requireSSL property.

  • Added useServerPrepStmts property (default false). The driver will use server-side prepared statements when the server version supports them (4.1 and newer) when this property is set to true. It is currently set to false by default until all bind/fetch functionality has been implemented. Currently only DML prepared statements are implemented for 4.1 server-side prepared statements.

  • Track open Statements, close all when Connection.close() is called (JDBC compliance).

D.3.20. Changes in MySQL Connector/J 3.0.17-ga (23 June 2005)

  • Timestamp/Time conversion goes in the wrong „direction“ when useTimeZone=true and server time zone differs from client time zone. (Bug#5874)

  • DatabaseMetaData.getIndexInfo() ignored unique parameter. (Bug#7081)

  • Support new protocol type MYSQL_TYPE_VARCHAR.

  • Added useOldUTF8Behavior' configuration property, which causes JDBC driver to act like it did with MySQL-4.0.x and earlier when the character encoding is utf-8 when connected to MySQL-4.1 or newer.

  • Statements created from a pooled connection were returning physical connection instead of logical connection when getConnection() was called. (Bug#7316)

  • PreparedStatements don't encode Big5 (and other multi-byte) character sets correctly in static SQL strings. (Bug#7033)

  • Connections starting up failed-over (due to down master) never retry master. (Bug#6966)

  • PreparedStatement.fixDecimalExponent() adding extra +, making number unparseable by MySQL server. (Bug#7061)

  • Timestamp key column data needed _binary stripped for UpdatableResultSet.refreshRow(). (Bug#7686)

  • Backported SQLState codes mapping from Connector/J 3.1, enable with useSqlStateCodes=true as a connection property, it defaults to false in this release, so that we don't break legacy applications (it defaults to true starting with Connector/J 3.1).

  • PreparedStatement.fixDecimalExponent() adding extra +, making number unparseable by MySQL server. (Bug#7601)

  • Escape sequence {fn convert(..., type)} now supports ODBC-style types that are prepended by SQL_.

  • Fixed duplicated code in configureClientCharset() that prevented useOldUTF8Behavior=true from working properly.

  • Handle streaming result sets with more than 2 billion rows properly by fixing wraparound of row number counter.

  • MS932, SHIFT_JIS, and Windows_31J not recognized as aliases for sjis. (Bug#7607)

  • Adding CP943 to aliases for sjis. (Bug#6549, fixed while fixing Bug#7607)

  • Which requires hex escaping of binary data when using multi-byte charsets with prepared statements. (Bug#8064)

  • NON_UNIQUE column from DBMD.getIndexInfo() returned inverted value. (Bug#8812)

  • Workaround for server Bug#9098: Default values of CURRENT_* for DATE, TIME, DATETIME, and TIMESTAMP columns can't be distinguished from string values, so UpdatableResultSet.moveToInsertRow() generates bad SQL for inserting default values.

  • EUCKR charset is sent as SET NAMES euc_kr which MySQL-4.1 and newer doesn't understand. (Bug#8629)

  • DatabaseMetaData.supportsSelectForUpdate() returns correct value based on server version.

  • Use hex escapes for PreparedStatement.setBytes() for double-byte charsets including „aliasesWindows-31J, CP934, MS932.

  • Added support for the EUC_JP_Solaris character encoding, which maps to a MySQL encoding of eucjpms (backported from 3.1 branch). This only works on servers that support eucjpms, namely 5.0.3 or later.

D.3.21. Changes in MySQL Connector/J 3.0.16-ga (15 November 2004)

  • Re-issue character set configuration commands when re-using pooled connections and/or Connection.changeUser() when connected to MySQL-4.1 or newer.

  • Fixed ResultSetMetaData.isReadOnly() to detect non-writable columns when connected to MySQL-4.1 or newer, based on existence of „original“ table and column names.

  • ResultSet.updateByte() when on insert row throws ArrayOutOfBoundsException. (Bug#5664)

  • Fixed DatabaseMetaData.getTypes() returning incorrect (this is, non-negative) scale for the NUMERIC type.

  • Off-by-one bug in Buffer.readString(string). (Bug#5664)

  • Made TINYINT(1) -> BIT/Boolean conversion configurable via tinyInt1isBit property (default true to be JDBC compliant out of the box).

  • Only set character_set_results during connection establishment if server version >= 4.1.1.

  • Fixed regression where useUnbufferedInput was defaulting to false.

  • ResultSet.getTimestamp() on a column with TIME in it fails. (Bug#5664)

D.3.22. Changes in MySQL Connector/J 3.0.15-production (04 September 2004)

  • StringUtils.escapeEasternUnicodeByteStream was still broken for GBK. (Bug#4010)

  • Failover for autoReconnect not using port numbers for any hosts, and not retrying all hosts. (Warning: This required a change to the SocketFactory connect() method signature, which is now public Socket connect(String host, int portNumber, Properties props); therefore, any third-party socket factories will have to be changed to support this signature. (Bug#4334)

  • Logical connections created by MysqlConnectionPoolDataSource will now issue a rollback() when they are closed and sent back to the pool. If your application server/connection pool already does this for you, you can set the rollbackOnPooledClose property to false to avoid the overhead of an extra rollback().

  • Removed redundant calls to checkRowPos() in ResultSet.

  • DOUBLE mapped twice in DBMD.getTypeInfo(). (Bug#4742)

  • Added FLOSS license exemption.

  • Calling .close() twice on a PooledConnection causes NPE. (Bug#4808)

  • DBMD.getColumns() returns incorrect JDBC type for unsigned columns. This affects type mappings for all numeric types in the RSMD.getColumnType() and RSMD.getColumnTypeNames() methods as well, to ensure that „like“ types from DBMD.getColumns() match up with what RSMD.getColumnType() and getColumnTypeNames() return. (Bug#4138, Bug#4860)

  • Production“ is now „GA“ (General Availability) in naming scheme of distributions.

  • RSMD.getPrecision() returning 0 for non-numeric types (should return max length in chars for non-binary types, max length in bytes for binary types). This fix also fixes mapping of RSMD.getColumnType() and RSMD.getColumnTypeName() for the BLOB types based on the length sent from the server (the server doesn't distinguish between TINYBLOB, BLOB, MEDIUMBLOB or LONGBLOB at the network protocol level). (Bug#4880)

  • ResultSet should release Field[] instance in .close(). (Bug#5022)

  • ResultSet.getMetaData() should not return incorrectly initialized metadata if the result set has been closed, but should instead throw an SQLException. Also fixed for getRow() and getWarnings() and traversal methods by calling checkClosed() before operating on instance-level fields that are nullified during .close(). (Bug#5069)

  • Parse new time zone variables from 4.1.x servers.

  • Use _binary introducer for PreparedStatement.setBytes() and set*Stream() when connected to MySQL-4.1.x or newer to avoid misinterpretation during character conversion.

D.3.23. Changes in MySQL Connector/J 3.0.14-production (28 May 2004)

  • Fixed URL parsing error.

D.3.24. Changes in MySQL Connector/J 3.0.13-production (27 May 2004)

  • Using a MySQLDatasource without server name fails. (Bug#3848)

  • No Database Selected when using MysqlConnectionPoolDataSource. (Bug#3920)

  • PreparedStatement.getGeneratedKeys() method returns only 1 result for batched insertions. (Bug#3873)

D.3.25. Changes in MySQL Connector/J 3.0.12-production (18 May 2004)

  • Add unsigned attribute to DatabaseMetaData.getColumns() output in the TYPE_NAME column.

  • Added failOverReadOnly property, to allow end-user to configure state of connection (read-only/writable) when failed over.

  • Backported „change user“ and „reset server state“ functionality from 3.1 branch, to allow clients of MysqlConnectionPoolDataSource to reset server state on getConnection() on a pooled connection.

  • Don't escape SJIS/GBK/BIG5 when using MySQL-4.1 or newer.

  • Allow url parameter for MysqlDataSource and MysqlConnectionPool DataSource so that passing of other properties is possible from inside appservers.

  • Map duplicate key and foreign key errors to SQLState of 23000.

  • Backport documentation tooling from 3.1 branch.

  • Return creating statement for ResultSets created by getGeneratedKeys(). (Bug#2957)

  • Allow java.util.Date to be sent in as parameter to PreparedStatement.setObject(), converting it to a Timestamp to maintain full precision. (Bug#103).

  • Don't truncate BLOB or CLOB values when using setBytes() and/or setBinary/CharacterStream(). (Bug#2670).

  • Dynamically configure character set mappings for field-level character sets on MySQL-4.1.0 and newer using SHOW COLLATION when connecting.

  • Map binary character set to US-ASCII to support DATETIME charset recognition for servers >= 4.1.2.

  • Use SET character_set_results during initialization to allow any charset to be returned to the driver for result sets.

  • Use charsetnr returned during connect to encode queries before issuing SET NAMES on MySQL >= 4.1.0.

  • Add helper methods to ResultSetMetaData (getColumnCharacterEncoding() and getColumnCharacterSet()) to allow end-users to see what charset the driver thinks it should be using for the column.

  • Only set character_set_results for MySQL >= 4.1.0.

  • StringUtils.escapeSJISByteStream() not covering all eastern double-byte charsets correctly. (Bug#3511)

  • Renamed StringUtils.escapeSJISByteStream() to more appropriate escapeEasternUnicodeByteStream().

  • Not specifying database in URL caused MalformedURL exception. (Bug#3554)

  • Auto-convert MySQL encoding names to Java encoding names if used for characterEncoding property.

  • Added encoding names that are recognized on some JVMs to fix case where they were reverse-mapped to MySQL encoding names incorrectly.

  • Use junit.textui.TestRunner for all unit tests (to allow them to be run from the command line outside of Ant or Eclipse).

  • UpdatableResultSet not picking up default values for moveToInsertRow(). (Bug#3557)

  • Inconsistent reporting of data type. The server still doesn't return all types for *BLOBs *TEXT correctly, so the driver won't return those correctly. (Bug#3570)

  • DBMD.getSQLStateType() returns incorrect value. (Bug#3520)

  • Fixed regression in PreparedStatement.setString() and eastern character encodings.

  • Made StringRegressionTest 4.1-unicode aware.

D.3.26. Changes in MySQL Connector/J 3.0.11-stable (19 February 2004)

  • Trigger a SET NAMES utf8 when encoding is forced to utf8 or utf-8 via the characterEncoding property. Previously, only the Java-style encoding name of utf-8 would trigger this.

  • AutoReconnect time was growing faster than exponentially. (Bug#2447)

  • Fixed failover always going to last host in list. (Bug#2578)

  • Added useUnbufferedInput parameter, and now use it by default (due to JVM issue http://developer.java.sun.com/developer/bugParade/bugs/4401235.html)

  • Detect on/off or 1, 2, 3 form of lower_case_table_names value on server.

  • Return java.lang.Integer for TINYINT and SMALLINT types from ResultSetMetaData.getColumnClassName(). (Bug#2852)

  • Return java.lang.Double for FLOAT type from ResultSetMetaData.getColumnClassName(). (Bug#2855)

  • Return [B instead of java.lang.Object for BINARY, VARBINARY and LONGVARBINARY types from ResultSetMetaData.getColumnClassName() (JDBC compliance).

  • Issue connection events on all instances created from a ConnectionPoolDataSource.

D.3.27. Changes in MySQL Connector/J 3.0.10-stable (13 January 2004)

  • Don't count quoted IDs when inside a 'string' in PreparedStatement parsing. (Bug#1511)

  • Friendlier“ exception message for PacketTooLargeException. (Bug#1534)

  • Backported fix for aliased tables and UpdatableResultSets in checkUpdatability() method from 3.1 branch.

  • Fix for ArrayIndexOutOfBounds exception when using Statement.setMaxRows(). (Bug#1695)

  • Barge blobs and split packets not being read correctly. (Bug#1576)

  • Fixed regression of Statement.getGeneratedKeys() and REPLACE statements.

  • Subsequent call to ResultSet.updateFoo() causes NPE if result set is not updatable. (Bug#1630)

  • Fix for 4.1.1-style authentication with no password.

  • Foreign Keys column sequence is not consistent in DatabaseMetaData.getImported/Exported/CrossReference(). (Bug#1731)

  • DatabaseMetaData.getSystemFunction() returning bad function VResultsSion. (Bug#1775)

  • Cross-database updatable result sets are not checked for updatability correctly. (Bug#1592)

  • DatabaseMetaData.getColumns() should return Types.LONGVARCHAR for MySQL LONGTEXT type.

  • ResultSet.getObject() on TINYINT and SMALLINT columns should return Java type Integer. (Bug#1913)

  • Added alwaysClearStream connection property, which causes the driver to always empty any remaining data on the input stream before each query.

  • Added more descriptive error message Server Configuration Denies Access to DataSource, as well as retrieval of message from server.

  • Autoreconnect code didn't set catalog upon reconnect if it had been changed.

  • Implement ResultSet.updateClob().

  • ResultSetMetaData.isCaseSensitive() returned wrong value for CHAR/VARCHAR columns.

  • Connection property maxRows not honored. (Bug#1933)

  • Statements being created too many times in DBMD.extractForeignKeyFromCreateTable(). (Bug#1925)

  • Support escape sequence {fn convert ... }. (Bug#1914)

  • ArrayIndexOutOfBounds when parameter number == number of parameters + 1. (Bug#1958)

  • ResultSet.findColumn() should use first matching column name when there are duplicate column names in SELECT query (JDBC-compliance). (Bug#2006)

  • Removed static synchronization bottleneck from PreparedStatement.setTimestamp().

  • Removed static synchronization bottleneck from instance factory method of SingleByteCharsetConverter.

  • Enable caching of the parsing stage of prepared statements via the cachePrepStmts, prepStmtCacheSize, and prepStmtCacheSqlLimit properties (disabled by default).

  • Speed up parsing of PreparedStatements, try to use one-pass whenever possible.

  • Fixed security exception when used in Applets (applets can't read the system property file.encoding which is needed for LOAD DATA LOCAL INFILE).

  • Use constants for SQLStates.

  • Map charset ko18_ru to ko18r when connected to MySQL-4.1.0 or newer.

  • Ensure that Buffer.writeString() saves room for the \0.

  • Fixed exception Unknown character set 'danish' on connect with JDK-1.4.0

  • Fixed mappings in SQLError to report deadlocks with SQLStates of 41000.

  • maxRows property would affect internal statements, so check it for all statement creation internal to the driver, and set to 0 when it is not.

D.3.28. Changes in MySQL Connector/J 3.0.9-stable (07 October 2003)

  • Faster date handling code in ResultSet and PreparedStatement (no longer uses Date methods that synchronize on static calendars).

  • Fixed test for end of buffer in Buffer.readString().

  • Fixed ResultSet.previous() behavior to move current position to before result set when on first row of result set. (Bug#496)

  • Fixed Statement and PreparedStatement issuing bogus queries when setMaxRows() had been used and a LIMIT clause was present in the query.

  • refreshRow didn't work when primary key values contained values that needed to be escaped (they ended up being doubly escaped). (Bug#661)

  • Support InnoDB contraint names when extracting foreign key information in DatabaseMetaData (implementing ideas from Parwinder Sekhon). (Bug#517, Bug#664)

  • Backported 4.1 protocol changes from 3.1 branch (server-side SQL states, new field information, larger client capability flags, connect-with-database, and so forth).

  • Fix UpdatableResultSet to return values for getXXX() when on insert row. (Bug#675)

  • The insertRow in an UpdatableResultSet is now loaded with the default column values when moveToInsertRow() is called. (Bug#688)

  • DatabaseMetaData.getColumns() wasn't returning NULL for default values that are specified as NULL.

  • Change default statement type/concurrency to TYPE_FORWARD_ONLY and CONCUR_READ_ONLY (spec compliance).

  • Don't try and reset isolation level on reconnect if MySQL doesn't support them.

  • Don't wrap SQLExceptions in RowDataDynamic.

  • Don't change timestamp TZ twice if useTimezone==true. (Bug#774)

  • Fixed regression in large split-packet handling. (Bug#848)

  • Better diagnostic error messages in exceptions for „streaming“ result sets.

  • Issue exception on ResultSet.getXXX() on empty result set (wasn't caught in some cases).

  • Don't hide messages from exceptions thrown in I/O layers.

  • Don't fire connection closed events when closing pooled connections, or on PooledConnection.getConnection() with already open connections. (Bug#884)

  • Clip +/- INF (to smallest and largest representative values for the type in MySQL) and NaN (to 0) for setDouble/setFloat(), and issue a warning on the statement when the server does not support +/- INF or NaN.

  • Double-escaping of '\' when charset is SJIS or GBK and '\' appears in non-escaped input. (Bug#879)

  • When emptying input stream of unused rows for „streaming“ result sets, have the current thread yield() every 100 rows in order to not monopolize CPU time.

  • DatabaseMetaData.getColumns() getting confused about the keyword „set“ in character columns. (Bug#1099)

  • Fixed deadlock issue with Statement.setMaxRows().

  • Fixed CLOB.truncate(). (Bug#1130)

  • Optimized CLOB.setChracterStream(). (Bug#1131)

  • Made databaseName, portNumber, and serverName optional parameters for MysqlDataSourceFactory. (Bug#1246)

  • ResultSet.get/setString mashing char 127. (Bug#1247)

  • Backported authentication changes for 4.1.1 and newer from 3.1 branch.

  • Added com.mysql.jdbc.util.BaseBugReport to help creation of testcases for bug reports.

  • Added property to „clobber“ streaming results, by setting the clobberStreamingResults property to true (the default is false). This will cause a „streamingResultSet to be automatically closed, and any oustanding data still streaming from the server to be discarded if another query is executed before all the data has been read from the server.

D.3.29. Changes in MySQL Connector/J 3.0.8-stable (23 May 2003)

  • Allow bogus URLs in Driver.getPropertyInfo().

  • Return list of generated keys when using multi-value INSERTS with Statement.getGeneratedKeys().

  • Use JVM charset with filenames and LOAD DATA [LOCAL] INFILE.

  • Fix infinite loop with Connection.cleanup().

  • Changed Ant target compile-core to compile-driver, and made testsuite compilation a separate target.

  • Fixed result set not getting set for Statement.executeUpdate(), which affected getGeneratedKeys() and getUpdateCount() in some cases.

  • Unicode character 0xFFFF in a string would cause the driver to throw an ArrayOutOfBoundsException. (Bug#378).

  • Return correct number of generated keys when using REPLACE statements.

  • Fix problem detecting server character set in some cases.

  • Fix row data decoding error when using very large packets.

  • Optimized row data decoding.

  • Issue exception when operating on an already closed prepared statement.

  • Fixed SJIS encoding bug, thanks to Naoto Sato.

  • Optimized usage of EscapeProcessor.

  • Allow multiple calls to Statement.close().

D.3.30. Changes in MySQL Connector/J 3.0.7-stable (08 April 2003)

  • Fixed MysqlPooledConnection.close() calling wrong event type.

  • Fixed StringIndexOutOfBoundsException in PreparedStatement.setClob().

  • 4.1 Column Metadata fixes.

  • Remove synchronization from Driver.connect() and Driver.acceptsUrl().

  • IOExceptions during a transaction now cause the Connection to be closed.

  • Fixed missing conversion for YEAR type in ResultSetMetaData.getColumnTypeName().

  • Don't pick up indexes that start with pri as primary keys for DBMD.getPrimaryKeys().

  • Throw SQLExceptions when trying to do operations on a forcefully closed Connection (that is, when a communication link failure occurs).

  • You can now toggle profiling on/off using Connection.setProfileSql(boolean).

  • Fixed charset issues with database metadata (charset was not getting set correctly).

  • Updatable ResultSets can now be created for aliased tables/columns when connected to MySQL-4.1 or newer.

  • Fixed LOAD DATA LOCAL INFILE bug when file > max_allowed_packet.

  • Fixed escaping of 0x5c ('\') character for GBK and Big5 charsets.

  • Fixed ResultSet.getTimestamp() when underlying field is of type DATE.

  • Ensure that packet size from alignPacketSize() does not exceed max_allowed_packet (JVM bug)

  • Don't reset Connection.isReadOnly() when autoReconnecting.

D.3.31. Changes in MySQL Connector/J 3.0.6-stable (18 February 2003)

  • Fixed ResultSetMetaData to return "" when catalog not known. Fixes NullPointerExceptions with Sun's CachedRowSet.

  • Fixed DBMD.getTypeInfo() and DBMD.getColumns() returning different value for precision in TEXT and BLOB types.

  • Allow ignoring of warning for „non transactional tables“ during rollback (compliance/usability) by setting ignoreNonTxTables property to true.

  • Fixed SQLExceptions getting swallowed on initial connect.

  • Fixed Statement.setMaxRows() to stop sending LIMIT type queries when not needed (performance).

  • Clean up Statement query/method mismatch tests (that is, INSERT not allowed with .executeQuery()).

  • More checks added in ResultSet traversal method to catch when in closed state.

  • Fixed ResultSetMetaData.isWritable() to return correct value.

  • Add „window“ of different NULL sorting behavior to DBMD.nullsAreSortedAtStart (4.0.2 to 4.0.10, true; otherwise, no).

  • Implemented Blob.setBytes(). You still need to pass the resultant Blob back into an updatable ResultSet or PreparedStatement to persist the changes, because MySQL does not support „locators“.

  • Backported 4.1 charset field info changes from Connector/J 3.1.

D.3.32. Changes in MySQL Connector/J 3.0.5-gamma (22 January 2003)

  • Fixed Buffer.fastSkipLenString() causing ArrayIndexOutOfBounds exceptions with some queries when unpacking fields.

  • Implemented an empty TypeMap for Connection.getTypeMap() so that some third-party apps work with MySQL (IBM WebSphere 5.0 Connection pool).

  • Added missing LONGTEXT type to DBMD.getColumns().

  • Retrieve TX_ISOLATION from database for Connection.getTransactionIsolation() when the MySQL version supports it, instead of an instance variable.

  • Quote table names in DatabaseMetaData.getColumns(), getPrimaryKeys(), getIndexInfo(), getBestRowIdentifier().

  • Greatly reduce memory required for setBinaryStream() in PreparedStatements.

  • Fixed ResultSet.isBeforeFirst() for empty result sets.

  • Added update options for foreign key metadata.

D.3.33. Changes in MySQL Connector/J 3.0.4-gamma (06 January 2003)

  • Added quoted identifiers to database names for Connection.setCatalog.

  • Added support for quoted identifiers in PreparedStatement parser.

  • Streamlined character conversion and byte[] handling in PreparedStatements for setByte().

  • Reduce memory footprint of PreparedStatements by sharing outbound packet with MysqlIO.

  • Added strictUpdates property to allow control of amount of checking for „correctness“ of updatable result sets. Set this to false if you want faster updatable result sets and you know that you create them from SELECT statements on tables with primary keys and that you have selected all primary keys in your query.

  • Added support for 4.0.8-style large packets.

  • Fixed PreparedStatement.executeBatch() parameter overwriting.

D.3.34. Changes in MySQL Connector/J 3.0.3-dev (17 December 2002)

  • Changed charsToByte in SingleByteCharConverter to be non-static.

  • Changed SingleByteCharConverter to use lazy initialization of each converter.

  • Fixed charset handling in Fields.java.

  • Implemented Connection.nativeSQL().

  • More robust escape tokenizer: Recognize -- comments, and allow nested escape sequences (see testsuite.EscapeProcessingTest).

  • DBMD.getImported/ExportedKeys() now handles multiple foreign keys per table.

  • Fixed ResultSetMetaData.getPrecision() returning incorrect values for some floating-point types.

  • Fixed ResultSetMetaData.getColumnTypeName() returning BLOB for TEXT and TEXT for BLOB types.

  • Fixed Buffer.isLastDataPacket() for 4.1 and newer servers.

  • Added CLIENT_LONG_FLAG to be able to get more column flags (isAutoIncrement() being the most important).

  • Because of above, implemented ResultSetMetaData.isAutoIncrement() to use Field.isAutoIncrement().

  • Honor lower_case_table_names when enabled in the server when doing table name comparisons in DatabaseMetaData methods.

  • Some MySQL-4.1 protocol support (extended field info from selects).

  • Use non-aliased table/column names and database names to fullly qualify tables and columns in UpdatableResultSet (requires MySQL-4.1 or newer).

  • Allow user to alter behavior of Statement/ PreparedStatement.executeBatch() via continueBatchOnError property (defaults to true).

  • Check for connection closed in more Connection methods (createStatement, prepareStatement, setTransactionIsolation, setAutoCommit).

  • More robust implementation of updatable result sets. Checks that all primary keys of the table have been selected.

  • LOAD DATA LOCAL INFILE ... now works, if your server is configured to allow it. Can be turned off with the allowLoadLocalInfile property (see the README).

  • Substitute '?' for unknown character conversions in single-byte character sets instead of '\0'.

  • NamedPipeSocketFactory now works (only intended for Windows), see README for instructions.

D.3.35. Changes in MySQL Connector/J 3.0.2-dev (08 November 2002)

  • Fixed issue with updatable result sets and PreparedStatements not working.

  • Fixed ResultSet.setFetchDirection(FETCH_UNKNOWN).

  • Fixed issue when calling Statement.setFetchSize() when using arbitrary values.

  • Fixed incorrect conversion in ResultSet.getLong().

  • Implemented ResultSet.updateBlob().

  • Removed duplicate code from UpdatableResultSet (it can be inherited from ResultSet, the extra code for each method to handle updatability I thought might someday be necessary has not been needed).

  • Fixed UnsupportedEncodingException thrown when „forcing“ a character encoding via properties.

  • Fixed various non-ASCII character encoding issues.

  • Added driver property useHostsInPrivileges. Defaults to true. Affects whether or not @hostname will be used in DBMD.getColumn/TablePrivileges.

  • All DBMD result set columns describing schemas now return NULL to be more compliant with the behavior of other JDBC drivers for other database systems (MySQL does not support schemas).

  • Added SSL support. See README for information on how to use it.

  • Properly restore connection properties when autoReconnecting or failing-over, including autoCommit state, and isolation level.

  • Use SHOW CREATE TABLE when possible for determining foreign key information for DatabaseMetaData. Also allows cascade options for DELETE information to be returned.

  • Escape 0x5c character in strings for the SJIS charset.

  • Fixed start position off-by-1 error in Clob.getSubString().

  • Implemented Clob.truncate().

  • Implemented Clob.setString().

  • Implemented Clob.setAsciiStream().

  • Implemented Clob.setCharacterStream().

  • Added com.mysql.jdbc.MiniAdmin class, which allows you to send shutdown command to MySQL server. This is intended to be used when „embedding“ Java and MySQL server together in an end-user application.

  • Added connectTimeout parameter that allows users of JDK-1.4 and newer to specify a maxium time to wait to establish a connection.

  • Failover and autoReconnect work only when the connection is in an autoCommit(false) state, in order to stay transaction-safe.

  • Added queriesBeforeRetryMaster property that specifies how many queries to issue when failed over before attempting to reconnect to the master (defaults to 50).

  • Fixed DBMD.supportsResultSetConcurrency() so that it returns true for ResultSet.TYPE_SCROLL_INSENSITIVE and ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE.

  • Fixed ResultSet.isLast() for empty result sets (should return false).

  • PreparedStatement now honors stream lengths in setBinary/Ascii/Character Stream() unless you set the connection property useStreamLengthsInPrepStmts to false.

  • Removed some not-needed temporary object creation by smarter use of Strings in EscapeProcessor, Connection and DatabaseMetaData classes.

D.3.36. Changes in MySQL Connector/J 3.0.1-dev (21 September 2002)

  • Fixed ResultSet.getRow() off-by-one bug.

  • Fixed RowDataStatic.getAt() off-by-one bug.

  • Added limited Clob functionality (ResultSet.getClob(), PreparedStatemtent.setClob(), PreparedStatement.setObject(Clob).

  • Added socketTimeout parameter to URL.

  • Connection.isClosed() no longer „pings“ the server.

  • Connection.close() issues rollback() when getAutoCommit() is false.

  • Added paranoid parameter, which sanitizes error messages by removing „sensitive“ information from them (such as hostnames, ports, or usernames), as well as clearing „sensitive“ data structures when possible.

  • Fixed ResultSetMetaData.isSigned() for TINYINT and BIGINT.

  • Charsets now automatically detected. Optimized code for single-byte character set conversion.

  • Implemented ResultSet.getCharacterStream().

  • Added LOCAL TEMPORARY to table types in DatabaseMetaData.getTableTypes().

  • Massive code clean-up to follow Java coding conventions (the time had come).

D.3.37. Changes in MySQL Connector/J 3.0.0-dev (31 July 2002)

  • !!! LICENSE CHANGE !!! The driver is now GPL. If you need non-GPL licenses, please contact me <mark@mysql.com>.

  • JDBC-3.0 functionality including Statement/PreparedStatement.getGeneratedKeys() and ResultSet.getURL().

  • Performance enchancements: Driver is now 50–100% faster in most situations, and creates fewer temporary objects.

  • Repackaging: New driver name is com.mysql.jdbc.Driver, old name still works, though (the driver is now provided by MySQL-AB).

  • Better checking for closed connections in Statement and PreparedStatement.

  • Support for streaming (row-by-row) result sets (see README) Thanks to Doron.

  • Support for large packets (new addition to MySQL-4.0 protocol), see README for more information.

  • JDBC Compliance: Passes all tests besides stored procedure tests.

  • Fix and sort primary key names in DBMetaData (SF bugs 582086 and 582086).

  • Float types now reported as java.sql.Types.FLOAT (SF bug 579573).

  • ResultSet.getTimestamp() now works for DATE types (SF bug 559134).

  • ResultSet.getDate/Time/Timestamp now recognizes all forms of invalid values that have been set to all zeros by MySQL (SF bug 586058).

  • Testsuite now uses Junit (which you can get from http://www.junit.org.

  • The driver now only works with JDK-1.2 or newer.

  • Added multi-host failover support (see README).

  • General source-code cleanup.

  • Overall speed improvements via controlling transient object creation in MysqlIO class when reading packets.

  • Performance improvements in string handling and field metadata creation (lazily instantiated) contributed by Alex Twisleton-Wykeham-Fiennes.

D.3.38. Changes in MySQL Connector/J 2.0.14 (16 May 2002)

  • More code cleanup.

  • PreparedStatement now releases resources on .close(). (SF bug 553268)

  • Quoted identifiers not used if server version does not support them. Also, if server started with --ansi or --sql-mode=ANSI_QUOTES, ‘"’ will be used as an identifier quote character, otherwise ‘'’ will be used.

  • ResultSet.getDouble() now uses code built into JDK to be more precise (but slower).

  • LogicalHandle.isClosed() calls through to physical connection.

  • Added SQL profiling (to STDERR). Set profileSql=true in your JDBC URL. See README for more information.

  • Fixed typo for relaxAutoCommit parameter.

D.3.39. Changes in MySQL Connector/J 2.0.13 (24 April 2002)

  • More code cleanup.

  • Fixed unicode chars being read incorrectly. (SF bug 541088)

  • Faster blob escaping for PrepStmt.

  • Added set/getPortNumber() to DataSource(s). (SF bug 548167)

  • Added setURL() to MySQLXADataSource. (SF bug 546019)

  • PreparedStatement.toString() fixed. (SF bug 534026)

  • ResultSetMetaData.getColumnClassName() now implemented.

  • Rudimentary version of Statement.getGeneratedKeys() from JDBC-3.0 now implemented (you need to be using JDK-1.4 for this to work, I believe).

  • DBMetaData.getIndexInfo() - bad PAGES fixed. (SF BUG 542201)

D.3.40. Changes in MySQL Connector/J 2.0.12 (07 April 2002)

  • General code cleanup.

  • Added getIdleFor() method to Connection and MysqlLogicalHandle.

  • Relaxed synchronization in all classes, should fix 520615 and 520393.

  • Added getTable/ColumnPrivileges() to DBMD (fixes 484502).

  • Added new types to getTypeInfo(), fixed existing types thanks to Al Davis and Kid Kalanon.

  • Added support for BIT types (51870) to PreparedStatement.

  • Fixed getRow() bug (527165) in ResultSet.

  • Fixes for ResultSet updatability in PreparedStatement.

  • Fixed time zone off-by-1-hour bug in PreparedStatement (538286, 528785).

  • ResultSet: Fixed updatability (values being set to null if not updated).

  • DataSources - fixed setUrl bug (511614, 525565), wrong datasource class name (532816, 528767).

  • Added identifier quoting to all DatabaseMetaData methods that need them (should fix 518108).

  • Added support for YEAR type (533556).

  • ResultSet.insertRow() should now detect auto_increment fields in most cases and use that value in the new row. This detection will not work in multi-valued keys, however, due to the fact that the MySQL protocol does not return this information.

  • ResultSet.refreshRow() implemented.

  • Fixed testsuite.Traversal afterLast() bug, thanks to Igor Lastric.

D.3.41. Changes in MySQL Connector/J 2.0.11 (27 January 2002)

  • Fixed missing DELETE_RULE value in DBMD.getImported/ExportedKeys() and getCrossReference().

  • Full synchronization of Statement.java.

  • More changes to fix Unexpected end of input stream errors when reading BLOB values. This should be the last fix.

D.3.42. Changes in MySQL Connector/J 2.0.10 (24 January 2002)

  • Fixed spurious Unexpected end of input stream errors in MysqlIO (bug 507456).

  • Fixed null-pointer-exceptions when using MysqlConnectionPoolDataSource with Websphere 4 (bug 505839).

D.3.43. Changes in MySQL Connector/J 2.0.9 (13 January 2002)

  • Ant build was corrupting included jar files, fixed (bug 487669).

  • Fixed extra memory allocation in MysqlIO.readPacket() (bug 488663).

  • Implementation of DatabaseMetaData.getExported/ImportedKeys() and getCrossReference().

  • Full synchronization on methods modifying instance and class-shared references, driver should be entirely thread-safe now (please let me know if you have problems).

  • DataSource implementations moved to org.gjt.mm.mysql.jdbc2.optional package, and (initial) implementations of PooledConnectionDataSource and XADataSource are in place (thanks to Todd Wolff for the implementation and testing of PooledConnectionDataSource with IBM WebSphere 4).

  • Added detection of network connection being closed when reading packets (thanks to Todd Lizambri).

  • Fixed quoting error with escape processor (bug 486265).

  • Report batch update support through DatabaseMetaData (bug 495101).

  • Fixed off-by-one-hour error in PreparedStatement.setTimestamp() (bug 491577).

  • Removed concatenation support from driver (the || operator), as older versions of VisualAge seem to be the only thing that use it, and it conflicts with the logical || operator. You will need to start mysqld with the --ansi flag to use the || operator as concatenation (bug 491680).

  • Fixed casting bug in PreparedStatement (bug 488663).

D.3.44. Changes in MySQL Connector/J 2.0.8 (25 November 2001)

  • Batch updates now supported (thanks to some inspiration from Daniel Rall).

  • XADataSource/ConnectionPoolDataSource code (experimental)

  • PreparedStatement.setAnyNumericType() now handles positive exponents correctly (adds + so MySQL can understand it).

  • DatabaseMetaData.getPrimaryKeys() and getBestRowIdentifier() are now more robust in identifying primary keys (matches regardless of case or abbreviation/full spelling of Primary Key in Key_type column).

D.3.45. Changes in MySQL Connector/J 2.0.7 (24 October 2001)

  • PreparedStatement.setCharacterStream() now implemented

  • Fixed dangling socket problem when in high availability (autoReconnect=true) mode, and finalizer for Connection will close any dangling sockets on GC.

  • Fixed ResultSetMetaData.getPrecision() returning one less than actual on newer versions of MySQL.

  • ResultSet.getBlob() now returns null if column value was null.

  • Character sets read from database if useUnicode=true and characterEncoding is not set. (thanks to Dmitry Vereshchagin)

  • Initial transaction isolation level read from database (if avaialable). (thanks to Dmitry Vereshchagin)

  • Fixed DatabaseMetaData.supportsTransactions(), and supportsTransactionIsolationLevel() and getTypeInfo() SQL_DATETIME_SUB and SQL_DATA_TYPE fields not being readable.

  • Fixed PreparedStatement generating SQL that would end up with syntax errors for some queries.

  • Fixed ResultSet.isAfterLast() always returning false.

  • Fixed time zone issue in PreparedStatement.setTimestamp(). (thanks to Erik Olofsson)

  • Captialize type names when captializeTypeNames=true is passed in URL or properties (for WebObjects. (thanks to Anjo Krank)

  • Updatable result sets now correctly handle NULL values in fields.

  • PreparedStatement.setDouble() now uses full-precision doubles (reverting a fix made earlier to truncate them).

  • PreparedStatement.setBoolean() will use 1/0 for values if your MySQL version is 3.21.23 or higher.

D.3.46. Changes in MySQL Connector/J 2.0.6 (16 June 2001)

  • Fixed PreparedStatement parameter checking.

  • Fixed case-sensitive column names in ResultSet.java.

D.3.47. Changes in MySQL Connector/J 2.0.5 (13 June 2001)

  • Fixed ResultSet.getBlob() ArrayIndex out-of-bounds.

  • Fixed ResultSetMetaData.getColumnTypeName for TEXT/BLOB.

  • Fixed ArrayIndexOutOfBounds when sending large BLOB queries. (Max size packet was not being set)

  • Added ISOLATION level support to Connection.setIsolationLevel()

  • Fixed NPE on PreparedStatement.executeUpdate() when all columns have not been set.

  • Fixed data parsing of TIMESTAMP values with 2-digit years.

  • Added Byte to PreparedStatement.setObject().

  • ResultSet.getBoolean() now recognizes -1 as true.

  • ResultSet has +/-Inf/inf support.

  • ResultSet.insertRow() works now, even if not all columns are set (they will be set to NULL).

  • DataBaseMetaData.getCrossReference() no longer ArrayIndexOOB.

  • getObject() on ResultSet correctly does TINYINT->Byte and SMALLINT->Short.

D.3.48. Changes in MySQL Connector/J 2.0.3 (03 December 2000)

  • Implemented getBigDecimal() without scale component for JDBC2.

  • Fixed composite key problem with updatable result sets.

  • Added detection of -/+INF for doubles.

  • Faster ASCII string operations.

  • Fixed incorrect detection of MAX_ALLOWED_PACKET, so sending large blobs should work now.

  • Fixed off-by-one error in java.sql.Blob implementation code.

  • Added ultraDevHack URL parameter, set to true to allow (broken) Macromedia UltraDev to use the driver.

D.3.49. Changes in MySQL Connector/J 2.0.1 (06 April 2000)

  • Fixed RSMD.isWritable() returning wrong value. Thanks to Moritz Maass.

  • Cleaned up exception handling when driver connects.

  • Columns that are of type TEXT now return as Strings when you use getObject().

  • DatabaseMetaData.getPrimaryKeys() now works correctly with respect to key_seq. Thanks to Brian Slesinsky.

  • No escape processing is done on PreparedStatements anymore per JDBC spec.

  • Fixed many JDBC-2.0 traversal, positioning bugs, especially with respect to empty result sets. Thanks to Ron Smits, Nick Brook, Cessar Garcia and Carlos Martinez.

  • Fixed some issues with updatability support in ResultSet when using multiple primary keys.

D.3.50. Changes in MySQL Connector/J 2.0.0pre5 (21 February 2000)

  • Fixed Bad Handshake problem.

D.3.51. Changes in MySQL Connector/J 2.0.0pre4 (10 January 2000)

  • Fixes to ResultSet for insertRow() - Thanks to Cesar Garcia

  • Fix to Driver to recognize JDBC-2.0 by loading a JDBC-2.0 class, instead of relying on JDK version numbers. Thanks to John Baker.

  • Fixed ResultSet to return correct row numbers

  • Statement.getUpdateCount() now returns rows matched, instead of rows actually updated, which is more SQL-92 like.

10-29-99

  • Statement/PreparedStatement.getMoreResults() bug fixed. Thanks to Noel J. Bergman.

  • Added Short as a type to PreparedStatement.setObject(). Thanks to Jeff Crowder

  • Driver now automagically configures maximum/preferred packet sizes by querying server.

  • Autoreconnect code uses fast ping command if server supports it.

  • Fixed various bugs with respect to packet sizing when reading from the server and when alloc'ing to write to the server.

D.3.52. Changes in MySQL Connector/J 2.0.0pre (17 August 1999)

  • Now compiles under JDK-1.2. The driver supports both JDK-1.1 and JDK-1.2 at the same time through a core set of classes. The driver will load the appropriate interface classes at runtime by figuring out which JVM version you are using.

  • Fixes for result sets with all nulls in the first row. (Pointed out by Tim Endres)

  • Fixes to column numbers in SQLExceptions in ResultSet (Thanks to Blas Rodriguez Somoza)

  • The database no longer needs to specified to connect. (Thanks to Christian Motschke)

D.3.53. Changes in MySQL Connector/J 1.2b (04 July 1999)

  • Better Documentation (in progress), in doc/mm.doc/book1.html

  • DBMD now allows null for a column name pattern (not in spec), which it changes to '%'.

  • DBMD now has correct types/lengths for getXXX().

  • ResultSet.getDate(), getTime(), and getTimestamp() fixes. (contributed by Alan Wilken)

  • EscapeProcessor now handles \{ \} and { or } inside quotes correctly. (thanks to Alik for some ideas on how to fix it)

  • Fixes to properties handling in Connection. (contributed by Juho Tikkala)

  • ResultSet.getObject() now returns null for NULL columns in the table, rather than bombing out. (thanks to Ben Grosman)

  • ResultSet.getObject() now returns Strings for types from MySQL that it doesn't know about. (Suggested by Chris Perdue)

  • Removed DataInput/Output streams, not needed, 1/2 number of method calls per IO operation.

  • Use default character encoding if one is not specified. This is a work-around for broken JVMs, because according to spec, EVERY JVM must support "ISO8859_1", but they don't.

  • Fixed Connection to use the platform character encoding instead of "ISO8859_1" if one isn't explicitly set. This fixes problems people were having loading the character- converter classes that didn't always exist (JVM bug). (thanks to Fritz Elfert for pointing out this problem)

  • Changed MysqlIO to re-use packets where possible to reduce memory usage.

  • Fixed escape-processor bugs pertaining to {} inside quotes.

D.3.54. Changes in MySQL Connector/J 1.2a (14 April 1999)

  • Fixed character-set support for non-Javasoft JVMs (thanks to many people for pointing it out)

  • Fixed ResultSet.getBoolean() to recognize 'y' & 'n' as well as '1' & '0' as boolean flags. (thanks to Tim Pizey)

  • Fixed ResultSet.getTimestamp() to give better performance. (thanks to Richard Swift)

  • Fixed getByte() for numeric types. (thanks to Ray Bellis)

  • Fixed DatabaseMetaData.getTypeInfo() for DATE type. (thanks to Paul Johnston)

  • Fixed EscapeProcessor for "fn" calls. (thanks to Piyush Shah at locomotive.org)

  • Fixed EscapeProcessor to not do extraneous work if there are no escape codes. (thanks to Ryan Gustafson)

  • Fixed Driver to parse URLs of the form "jdbc:mysql://host:port" (thanks to Richard Lobb)

D.3.55. Changes in MySQL Connector/J 1.1i (24 March 1999)

  • Fixed Timestamps for PreparedStatements

  • Fixed null pointer exceptions in RSMD and RS

  • Re-compiled with jikes for valid class files (thanks ms!)

D.3.56. Changes in MySQL Connector/J 1.1h (08 March 1999)

  • Fixed escape processor to deal with unmatched { and } (thanks to Craig Coles)

  • Fixed escape processor to create more portable (between DATETIME and TIMESTAMP types) representations so that it will work with BETWEEN clauses. (thanks to Craig Longman)

  • MysqlIO.quit() now closes the socket connection. Before, after many failed connections some OS's would run out of file descriptors. (thanks to Michael Brinkman)

  • Fixed NullPointerException in Driver.getPropertyInfo. (thanks to Dave Potts)

  • Fixes to MysqlDefs to allow all *text fields to be retrieved as Strings. (thanks to Chris at Leverage)

  • Fixed setDouble in PreparedStatement for large numbers to avoid sending scientific notation to the database. (thanks to J.S. Ferguson)

  • Fixed getScale() and getPrecision() in RSMD. (contrib'd by James Klicman)

  • Fixed getObject() when field was DECIMAL or NUMERIC (thanks to Bert Hobbs)

  • DBMD.getTables() bombed when passed a null table-name pattern. Fixed. (thanks to Richard Lobb)

  • Added check for "client not authorized" errors during connect. (thanks to Hannes Wallnoefer)

D.3.57. Changes in MySQL Connector/J 1.1g (19 February 1999)

  • Result set rows are now byte arrays. Blobs and Unicode work bidriectonally now. The useUnicode and encoding options are implemented now.

  • Fixes to PreparedStatement to send binary set by setXXXStream to be sent untouched to the MySQL server.

  • Fixes to getDriverPropertyInfo().

D.3.58. Changes in MySQL Connector/J 1.1f (31 December 1998)

  • Changed all ResultSet fields to Strings, this should allow Unicode to work, but your JVM must be able to convert between the character sets. This should also make reading data from the server be a bit quicker, because there is now no conversion from StringBuffer to String.

  • Changed PreparedStatement.streamToString() to be more efficient (code from Uwe Schaefer).

  • URL parsing is more robust (throws SQL exceptions on errors rather than NullPointerExceptions)

  • PreparedStatement now can convert Strings to Time/Date values via setObject() (code from Robert Currey).

  • IO no longer hangs in Buffer.readInt(), that bug was introduced in 1.1d when changing to all byte-arrays for result sets. (Pointed out by Samo Login)

D.3.59. Changes in MySQL Connector/J 1.1b (03 November 1998)

  • Fixes to DatabaseMetaData to allow both IBM VA and J-Builder to work. Let me know how it goes. (thanks to Jac Kersing)

  • Fix to ResultSet.getBoolean() for NULL strings (thanks to Barry Lagerweij)

  • Beginning of code cleanup, and formatting. Getting ready to branch this off to a parallel JDBC-2.0 source tree.

  • Added "final" modifier to critical sections in MysqlIO and Buffer to allow compiler to inline methods for speed.

9-29-98

  • If object references passed to setXXX() in PreparedStatement are null, setNull() is automatically called for you. (Thanks for the suggestion goes to Erik Ostrom)

  • setObject() in PreparedStatement will now attempt to write a serialized representation of the object to the database for objects of Types.OTHER and objects of unknown type.

  • Util now has a static method readObject() which given a ResultSet and a column index will re-instantiate an object serialized in the above manner.

D.3.60. Changes in MySQL Connector/J 1.1 (02 September 1998)

  • Got rid of "ugly hack" in MysqlIO.nextRow(). Rather than catch an exception, Buffer.isLastDataPacket() was fixed.

  • Connection.getCatalog() and Connection.setCatalog() should work now.

  • Statement.setMaxRows() works, as well as setting by property maxRows. Statement.setMaxRows() overrides maxRows set via properties or url parameters.

  • Automatic re-connection is available. Because it has to "ping" the database before each query, it is turned off by default. To use it, pass in "autoReconnect=true" in the connection URL. You may also change the number of reconnect tries, and the initial timeout value via "maxReconnects=n" (default 3) and "initialTimeout=n" (seconds, default 2) parameters. The timeout is an exponential backoff type of timeout; for example, if you have initial timeout of 2 seconds, and maxReconnects of 3, then the driver will timeout 2 seconds, 4 seconds, then 16 seconds between each re-connection attempt.

D.3.61. Changes in MySQL Connector/J 1.0 (24 August 1998)

  • Fixed handling of blob data in Buffer.java

  • Fixed bug with authentication packet being sized too small.

  • The JDBC Driver is now under the LPGL

8-14-98

  • Fixed Buffer.readLenString() to correctly read data for BLOBS.

  • Fixed PreparedStatement.stringToStream to correctly read data for BLOBS.

  • Fixed PreparedStatement.setDate() to not add a day. (above fixes thanks to Vincent Partington)

  • Added URL parameter parsing (?user=... and so forth).

D.3.62. Changes in MySQL Connector/J 0.9d (04 August 1998)

  • Big news! New package name. Tim Endres from ICE Engineering is starting a new source tree for GNU GPL'd Java software. He's graciously given me the org.gjt.mm package directory to use, so now the driver is in the org.gjt.mm.mysql package scheme. I'm "legal" now. Look for more information on Tim's project soon.

  • Now using dynamically sized packets to reduce memory usage when sending commands to the DB.

  • Small fixes to getTypeInfo() for parameters, and so forth.

  • DatabaseMetaData is now fully implemented. Let me know if these drivers work with the various IDEs out there. I've heard that they're working with JBuilder right now.

  • Added JavaDoc documentation to the package.

  • Package now available in .zip or .tar.gz.

D.3.63. Changes in MySQL Connector/J 0.9 (28 July 1998)

  • Implemented getTypeInfo(). Connection.rollback() now throws an SQLException per the JDBC spec.

  • Added PreparedStatement that supports all JDBC API methods for PreparedStatement including InputStreams. Please check this out and let me know if anything is broken.

  • Fixed a bug in ResultSet that would break some queries that only returned 1 row.

  • Fixed bugs in DatabaseMetaData.getTables(), DatabaseMetaData.getColumns() and DatabaseMetaData.getCatalogs().

  • Added functionality to Statement that allows executeUpdate() to store values for IDs that are automatically generated for AUTO_INCREMENT fields. Basically, after an executeUpdate(), look at the SQLWarnings for warnings like "LAST_INSERTED_ID = 'some number', COMMAND = 'your SQL query'". If you are using AUTO_INCREMENT fields in your tables and are executing a lot of executeUpdate()s on one Statement, be sure to clearWarnings() every so often to save memory.

D.3.64. Changes in MySQL Connector/J 0.8 (06 July 1998)

  • Split MysqlIO and Buffer to separate classes. Some ClassLoaders gave an IllegalAccess error for some fields in those two classes. Now mm.mysql works in applets and all classloaders. Thanks to Joe Ennis <jce@mail.boone.com> for pointing out the problem and working on a fix with me.

D.3.65. Changes in MySQL Connector/J 0.7 (01 July 1998)

  • Fixed DatabaseMetadata problems in getColumns() and bug in switch statement in the Field constructor. Thanks to Costin Manolache <costin@tdiinc.com> for pointing these out.

D.3.66. Changes in MySQL Connector/J 0.6 (21 May 1998)

  • Incorporated efficiency changes from Richard Swift <Richard.Swift@kanatek.ca> in MysqlIO.java and ResultSet.java:

  • We're now 15% faster than gwe's driver.

  • Started working on DatabaseMetaData.

  • The following methods are implemented:

    • getTables()

    • getTableTypes()

    • getColumns

    • getCatalogs()

Anhang E. Anmerkungen zur Portierung auf andere Systeme

This appendix helps you port MySQL to other operating systems. Do check the list of currently supported operating systems first. See Abschnitt 2.1.1, „Betriebssysteme, die von MySQL unterstützt werden“. If you have created a new port of MySQL, please let us know so that we can list it here and on our Web site (http://www.mysql.com/), recommending it to other users.

Note: If you create a new port of MySQL, you are free to copy and distribute it under the GPL license, but it does not make you a copyright holder of MySQL.

A working POSIX thread library is needed for the server. On Solaris 2.5 we use Sun PThreads (the native thread support in 2.4 and earlier versions is not good enough), on Linux we use LinuxThreads by Xavier Leroy, .

The hard part of porting to a new Unix variant without good native thread support is probably to port MIT-pthreads. See mit-pthreads/README and Programming POSIX Threads (http://www.humanfactor.com/pthreads/).

Up to MySQL 4.0.2, the MySQL distribution included a patched version of Chris Provenzano's Pthreads from MIT (see the MIT Pthreads Web page at http://www.mit.edu/afs/sipb/project/pthreads/ and a programming introduction at http://www.mit.edu:8001/people/proven/IAP_2000/). These can be used for some operating systems that do not have POSIX threads. See Abschnitt 2.8.5, „Anmerkungen zu MIT-pthreads“.

It is also possible to use another user level thread package named FSU Pthreads (see http://moss.csc.ncsu.edu/~mueller/pthreads/). This implementation is being used for the SCO port.

See the thr_lock.c and thr_alarm.c programs in the mysys directory for some tests/examples of these problems.

Both the server and the client need a working C++ compiler. We use gcc on many platforms. Other compilers that are known to work are SPARCworks, Sun Forte, Irix cc, HP-UX aCC, IBM AIX xlC_r), Intel ecc/icc and Compaq cxx).

To compile only the client use ./configure --without-server.

There is currently no support for only compiling the server, nor is it likely to be added unless someone has a good reason for it.

If you want/need to change any Makefile or the configure script you also need GNU Automake and Autoconf. See Abschnitt 2.8.3, „Installation vom Entwicklungs-Source-Tree“.

All steps needed to remake everything from the most basic files.

/bin/rm */.deps/*.P
/bin/rm -f config.cache
aclocal
autoheader
aclocal
automake
autoconf
./configure --with-debug=full --prefix='your installation directory'

# The makefiles generated above need GNU make 3.75 or newer.
# (called gmake below)
gmake clean all install init-db

If you run into problems with a new port, you may have to do some debugging of MySQL! See Abschnitt E.1, „Einen MySQL-Server debuggen“.

Note: Before you start debugging mysqld, first get the test programs mysys/thr_alarm and mysys/thr_lock to work. This ensures that your thread installation has even a remote chance to work!

E.1. Einen MySQL-Server debuggen

If you are using some functionality that is very new in MySQL, you can try to run mysqld with the --skip-new (which disables all new, potentially unsafe functionality) or with --safe-mode which disables a lot of optimization that may cause problems. See Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

If mysqld doesn't want to start, you should verify that you don't have any my.cnf files that interfere with your setup! You can check your my.cnf arguments with mysqld --print-defaults and avoid using them by starting with mysqld --no-defaults ....

If mysqld starts to eat up CPU or memory or if it „hangs,“ you can use mysqladmin processlist status to find out if someone is executing a query that takes a long time. It may be a good idea to run mysqladmin -i10 processlist status in some window if you are experiencing performance problems or problems when new clients can't connect.

The command mysqladmin debug dumps some information about locks in use, used memory and query usage to the MySQL log file. This may help solve some problems. This command also provides some useful information even if you haven't compiled MySQL for debugging!

If the problem is that some tables are getting slower and slower you should try to optimize the table with OPTIMIZE TABLE or myisamchk. See Kapitel 5, Datenbankverwaltung. You should also check the slow queries with EXPLAIN.

You should also read the OS-specific section in this manual for problems that may be unique to your environment. See Abschnitt 2.12, „Betriebssystemspezifische Anmerkungen“.

E.1.1. MySQL zum Debuggen kompilieren

If you have some very specific problem, you can always try to debug MySQL. To do this you must configure MySQL with the --with-debug or the --with-debug=full option. You can check whether MySQL was compiled with debugging by doing: mysqld --help. If the --debug flag is listed with the options then you have debugging enabled. mysqladmin ver also lists the mysqld version as mysql ... --debug in this case.

If you are using gcc or egcs, the recommended configure line is:

CC=gcc CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors \
   -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql \
   --with-debug --with-extra-charsets=complex

This avoids problems with the libstdc++ library and with C++ exceptions (many compilers have problems with C++ exceptions in threaded code) and compile a MySQL version with support for all character sets.

If you suspect a memory overrun error, you can configure MySQL with --with-debug=full, which installs a memory allocation (SAFEMALLOC) checker. However, running with SAFEMALLOC is quite slow, so if you get performance problems you should start mysqld with the --skip-safemalloc option. This disables the memory overrun checks for each call to malloc() and free().

If mysqld stops crashing when you compile it with --with-debug, you probably have found a compiler bug or a timing bug within MySQL. In this case, you can try to add -g to the CFLAGS and CXXFLAGS variables above and not use --with-debug. If mysqld dies, you can at least attach to it with gdb or use gdb on the core file to find out what happened.

When you configure MySQL for debugging you automatically enable a lot of extra safety check functions that monitor the health of mysqld. If they find something „unexpected,“ an entry is written to stderr, which safe_mysqld directs to the error log! This also means that if you are having some unexpected problems with MySQL and are using a source distribution, the first thing you should do is to configure MySQL for debugging! (The second thing is to send mail to a MySQL mailing list and ask for help. See Abschnitt 1.7.1, „Die MySQL-Mailinglisten“. If you believe that you have found a bug, please use the instructions at Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

In the Windows MySQL distribution, mysqld.exe is by default compiled with support for trace files.

E.1.2. Trace-Dateien erzeugen

If the mysqld server doesn't start or if you can cause it to crash quickly, you can try to create a trace file to find the problem.

To do this, you must have a mysqld that has been compiled with debugging support. You can check this by executing mysqld -V. If the version number ends with -debug, it's compiled with support for trace files. (On Windows, the debugging server is named mysqld-debug rather than mysqld as of MySQL 4.1.)

Start the mysqld server with a trace log in /tmp/mysqld.trace on Unix or C:\mysqld.trace on Windows:

shell> mysqld --debug

On Windows, you should also use the --standalone flag to not start mysqld as a service. In a console window, use this command:

C:\> mysqld-debug --debug --standalone

After this, you can use the mysql.exe command-line tool in a second console window to reproduce the problem. You can stop the mysqld server with mysqladmin shutdown.

Note that the trace file become very big! If you want to generate a smaller trace file, you can use debugging options something like this:

mysqld --debug=d,info,error,query,general,where:O,/tmp/mysqld.trace

This only prints information with the most interesting tags to the trace file.

If you make a bug report about this, please only send the lines from the trace file to the appropriate mailing list where something seems to go wrong! If you can't locate the wrong place, you can ftp the trace file, together with a full bug report, to ftp://ftp.mysql.com/pub/mysql/upload/ so that a MySQL developer can take a look a this.

The trace file is made with the DBUG package by Fred Fish. See Abschnitt E.3, „Das DBUG-Paket“.

E.1.3. mysqld unter gdb debuggen

On most systems you can also start mysqld from gdb to get more information if mysqld crashes.

With some older gdb versions on Linux you must use run --one-thread if you want to be able to debug mysqld threads. In this case, you can only have one thread active at a time. We recommend you to upgrade to gdb 5.1 ASAP as thread debugging works much better with this version!

NTPL threads (the new thread library on Linux) may cause problems while running mysqld under gdb. Some symptoms are:

  • mysqld hangs during startup (before it writes ready for connections).

  • mysqld crashes during a pthread_mutex_lock() or pthread_mutex_unlock() call.

In this case, you should set the following environment variable in the shell before starting gdb:

LD_ASSUME_KERNEL=2.4.1
export LD_ASSUME_KERNEL

When running mysqld under gdb, you should disable the stack trace with --skip-stack-trace to be able to catch segfaults within gdb.

In MySQL 4.0.14 and above you should use the --gdb option to mysqld. This installs an interrupt handler for SIGINT (needed to stop mysqld with ^C to set breakpoints) and disable stack tracing and core file handling.

It's very hard to debug MySQL under gdb if you do a lot of new connections the whole time as gdb doesn't free the memory for old threads. You can avoid this problem by starting mysqld with --thread_cache_size='max_connections+1'. In most cases just using --thread_cache_size=5' helps a lot!

If you want to get a core dump on Linux if mysqld dies with a SIGSEGV signal, you can start mysqld with the --core-file option. This core file can be used to make a backtrace that may help you find out why mysqld died:

shell> gdb mysqld core
gdb>   backtrace full
gdb>   exit

See Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

If you are using gdb 4.17.x or above on Linux, you should install a .gdb file, with the following information, in your current directory:

set print sevenbit off
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
handle SIGWAITING nostop noprint
handle SIGLWP nostop noprint
handle SIGPIPE nostop
handle SIGALRM nostop
handle SIGHUP nostop
handle SIGTERM nostop noprint

If you have problems debugging threads with gdb, you should download gdb 5.x and try this instead. The new gdb version has very improved thread handling!

Here is an example how to debug mysqld:

shell> gdb /usr/local/libexec/mysqld
gdb> run
...
backtrace full # Do this when mysqld crashes

Include the above output in a bug report, which you can file using the instructions in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

If mysqld hangs you can try to use some system tools like strace or /usr/proc/bin/pstack to examine where mysqld has hung.

strace /tmp/log libexec/mysqld

If you are using the Perl DBI interface, you can turn on debugging information by using the trace method or by setting the DBI_TRACE environment variable.

E.1.4. Einen Stack-Trace benutzen

On some operating systems, the error log contains a stack trace if mysqld dies unexpectedly. You can use this to find out where (and maybe why) mysqld died. See Abschnitt 5.12.1, „Die Fehler-Logdatei“. To get a stack trace, you must not compile mysqld with the -fomit-frame-pointer option to gcc. See Abschnitt E.1.1, „MySQL zum Debuggen kompilieren“.

If the error file contains something like the following:

mysqld got signal 11;
The manual section 'Debugging a MySQL server' tells you how to use a
stack trace and/or the core file to produce a readable backtrace that may
help in finding out why mysqld died
Attempting backtrace. You can use the following information to find out
where mysqld died.  If you see no messages after this, something went
terribly wrong...
stack range sanity check, ok, backtrace follows
0x40077552
0x81281a0
0x8128f47
0x8127be0
0x8127995
0x8104947
0x80ff28f
0x810131b
0x80ee4bc
0x80c3c91
0x80c6b43
0x80c1fd9
0x80c1686

you can find where mysqld died by doing the following:

  1. Copy the preceding numbers to a file, for example mysqld.stack.

  2. Make a symbol file for the mysqld server:

    nm -n libexec/mysqld > /tmp/mysqld.sym
    

    Note that most MySQL binary distributions (except for the "debug" packages, where this information is included inside of the binaries themselves) ship with the above file, named mysqld.sym.gz. In this case, you can simply unpack it by doing:

    gunzip < bin/mysqld.sym.gz > /tmp/mysqld.sym
    
  3. Execute resolve_stack_dump -s /tmp/mysqld.sym -n mysqld.stack.

    This prints out where mysqld died. If this doesn't help you find out why mysqld died, you should make a bug report and include the output from the above command with the bug report.

    Note however that in most cases it does not help us to just have a stack trace to find the reason for the problem. To be able to locate the bug or provide a workaround, we would in most cases need to know the query that killed mysqld and preferable a test case so that we can repeat the problem! See Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

E.1.5. Logdateien benutzen, um Ursachen für Fehler in mysqld zu finden

Note that before starting mysqld with --log you should check all your tables with myisamchk. See Kapitel 5, Datenbankverwaltung.

If mysqld dies or hangs, you should start mysqld with --log. When mysqld dies again, you can examine the end of the log file for the query that killed mysqld.

If you are using --log without a file name, the log is stored in the database directory as host_name.log In most cases it is the last query in the log file that killed mysqld, but if possible you should verify this by restarting mysqld and executing the found query from the mysql command-line tools. If this works, you should also test all complicated queries that didn't complete.

You can also try the command EXPLAIN on all SELECT statements that takes a long time to ensure that mysqld is using indexes properly. See Abschnitt 7.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“.

You can find the queries that take a long time to execute by starting mysqld with --log-slow-queries. See Abschnitt 5.12.4, „Die Logdatei für langsame Anfragen“.

If you find the text mysqld restarted in the error log file (normally named hostname.err) you probably have found a query that causes mysqld to fail. If this happens, you should check all your tables with myisamchk (see Kapitel 5, Datenbankverwaltung), and test the queries in the MySQL log files to see whether one fails. If you find such a query, try first upgrading to the newest MySQL version. If this doesn't help and you can't find anything in the mysql mail archive, you should report the bug to a MySQL mailing list. The mailing lists are described at http://lists.mysql.com/, which also has links to online list archives.

If you have started mysqld with myisam-recover, MySQL automatically checks and tries to repair MyISAM tables if they are marked as 'not closed properly' or 'crashed'. If this happens, MySQL writes an entry in the hostname.err file 'Warning: Checking table ...' which is followed by Warning: Repairing table if the table needs to be repaired. If you get a lot of these errors, without mysqld having died unexpectedly just before, then something is wrong and needs to be investigated further. See Abschnitt 5.2.1, „Befehlsoptionen für mysqld.

It is not a good sign if mysqld did die unexpectedly, but in this case, you should not investigate the Checking table... messages, but instead try to find out why mysqld died.

E.1.6. Erzeugen eines Testfalls, wenn Sie Tabellenbeschädigung feststellen

If you get corrupted tables or if mysqld always fails after some update commands, you can test whether this bug is reproducible by doing the following:

  • Take down the MySQL daemon (with mysqladmin shutdown).

  • Make a backup of the tables (to guard against the very unlikely case that the repair does something bad).

  • Check all tables with myisamchk -s database/*.MYI. Repair any wrong tables with myisamchk -r database/table.MYI.

  • Make a second backup of the tables.

  • Remove (or move away) any old log files from the MySQL data directory if you need more space.

  • Start mysqld with --log-bin. See Abschnitt 5.12.3, „Die binäre Update-Logdatei“. If you want to find a query that crashes mysqld, you should use --log --log-bin.

  • When you have gotten a crashed table, stop the mysqld server.

  • Restore the backup.

  • Restart the mysqld server without --log-bin

  • Re-execute the commands with mysqlbinlog update-log-file | mysql. The update log is saved in the MySQL database directory with the name hostname-bin.#.

  • If the tables are corrupted again or you can get mysqld to die with the above command, you have found reproducible bug that should be easy to fix! FTP the tables and the binary log to ftp://ftp.mysql.com/pub/mysql/upload/ and report it in our bugs database using the instructions given in Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“. (Please note that the /pub/mysql/upload/ FTP directory is not listable, so you'll not see what you've uploaded in your FTP client.) If you are a support customer, you can use the MySQL Customer Support Center https://support.mysql.com/ to alert the MySQL team about the problem and have it fixed as soon as possible.

You can also use the script mysql_find_rows to just execute some of the update statements if you want to narrow down the problem.

E.2. Einen MySQL-Client debuggen

To be able to debug a MySQL client with the integrated debug package, you should configure MySQL with --with-debug or --with-debug=full. See Abschnitt 2.8.2, „Typische configure-Optionen“.

Before running a client, you should set the MYSQL_DEBUG environment variable:

shell> MYSQL_DEBUG=d:t:O,/tmp/client.trace
shell> export MYSQL_DEBUG

This causes clients to generate a trace file in /tmp/client.trace.

If you have problems with your own client code, you should attempt to connect to the server and run your query using a client that is known to work. Do this by running mysql in debugging mode (assuming that you have compiled MySQL with debugging on):

shell> mysql --debug=d:t:O,/tmp/client.trace

This provides useful information in case you mail a bug report. See Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

If your client crashes at some 'legal' looking code, you should check that your mysql.h include file matches your MySQL library file. A very common mistake is to use an old mysql.h file from an old MySQL installation with new MySQL library.

E.3. Das DBUG-Paket

The MySQL server and most MySQL clients are compiled with the DBUG package originally created by Fred Fish. When you have configured MySQL for debugging, this package makes it possible to get a trace file of what the program is debugging. See Abschnitt E.1.2, „Trace-Dateien erzeugen“.

This section summaries the argument values that you can specify in debug options on the command line for MySQL programs that have been built with debugging support. For more information about programming with the DBUG package, see the DBUG manual in the dbug directory of MySQL source distributions. It's best to use a recent distribution for MySQL 5.1 to get the most updated DBUG manual.

You use the debug package by invoking a program with the --debug="..." or the -#... option.

Most MySQL programs have a default debug string that is used if you don't specify an option to --debug. The default trace file is usually /tmp/program_name.trace on Unix and \program_name.trace on Windows.

The debug control string is a sequence of colon-separated fields as follows:

<field_1>:<field_2>:...:<field_N>

Each field consists of a mandatory flag character followed by an optional ‘,’ and comma-separated list of modifiers:

flag[,modifier,modifier,...,modifier]

The currently recognized flag characters are:

FlagDescription
dEnable output from DBUG_<N> macros for the current state. May be followed by a list of keywords which selects output only for the DBUG macros with that keyword. An empty list of keywords implies output for all macros.
DDelay after each debugger output line. The argument is the number of tenths of seconds to delay, subject to machine capabilities. For example, -#D,20 specifies a delay of two seconds.
fLimit debugging, tracing, and profiling to the list of named functions. Note that a null list disables all functions. The appropriate d or t flags must still be given; this flag only limits their actions if they are enabled.
FIdentify the source file name for each line of debug or trace output.
iIdentify the process with the PID or thread ID for each line of debug or trace output.
gEnable profiling. Create a file called dbugmon.out containing information that can be used to profile the program. May be followed by a list of keywords that select profiling only for the functions in that list. A null list implies that all functions are considered.
LIdentify the source file line number for each line of debug or trace output.
nPrint the current function nesting depth for each line of debug or trace output.
NNumber each line of debug output.
oRedirect the debugger output stream to the specified file. The default output is stderr.
OLike o, but the file is really flushed between each write. When needed, the file is closed and reopened between each write.
pLimit debugger actions to specified processes. A process must be identified with the DBUG_PROCESS macro and match one in the list for debugger actions to occur.
PPrint the current process name for each line of debug or trace output.
rWhen pushing a new state, do not inherit the previous state's function nesting level. Useful when the output is to start at the left margin.
SDo function _sanity(_file_,_line_) at each debugged function until _sanity() returns something that differs from 0. (Mostly used with safemalloc to find memory leaks)
tEnable function call/exit trace lines. May be followed by a list (containing only one modifier) giving a numeric maximum trace level, beyond which no output occurs for either debugging or tracing macros. The default is a compile time option.

Some examples of debug control strings that might appear on a shell command line (the -# is typically used to introduce a control string to an application program) are:

-#d:t
-#d:f,main,subr1:F:L:t,20
-#d,input,output,files:n
-#d:t:i:O,\\mysqld.trace

In MySQL, common tags to print (with the d option) are enter, exit, error, warning, info, and loop.

E.4. Anmerkungen zu RTS-Thread

I have tried to use the RTS thread packages with MySQL but stumbled on the following problems:

They use old versions of many POSIX calls and it is very tedious to make wrappers for all functions. I am inclined to think that it would be easier to change the thread libraries to the newest POSIX specification.

Some wrappers are currently written. See mysys/my_pthread.c for more info.

At least the following should be changed:

pthread_get_specific should use one argument. sigwait should take two arguments. A lot of functions (at least pthread_cond_wait, pthread_cond_timedwait()) should return the error code on error. Now they return -1 and set errno.

Another problem is that user-level threads use the ALRM signal and this aborts a lot of functions (read, write, open...). MySQL should do a retry on interrupt on all of these but it is not that easy to verify it.

The biggest unsolved problem is the following:

To get thread-level alarms I changed mysys/thr_alarm.c to wait between alarms with pthread_cond_timedwait(), but this aborts with error EINTR. I tried to debug the thread library as to why this happens, but couldn't find any easy solution.

If someone wants to try MySQL with RTS threads I suggest the following:

  • Change functions MySQL uses from the thread library to POSIX. This shouldn't take that long.

  • Compile all libraries with the -DHAVE_rts_threads.

  • Compile thr_alarm.

  • If there are some small differences in the implementation, they may be fixed by changing my_pthread.h and my_pthread.c.

  • Run thr_alarm. If it runs without any „warning,“ „error,“ or aborted messages, you are on the right track. Here is a successful run on Solaris:

    Main thread: 1
    Thread 0 (5) started
    Thread: 5  Waiting
    process_alarm
    Thread 1 (6) started
    Thread: 6  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 1 (1) sec
    Thread: 6  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 2 (2) sec
    Thread: 6  Simulation of no alarm needed
    Thread: 6  Slept for 0 (3) sec
    Thread: 6  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 4 (4) sec
    Thread: 6  Waiting
    process_alarm
    thread_alarm
    Thread: 5  Slept for 10 (10) sec
    Thread: 5  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 5 (5) sec
    Thread: 6  Waiting
    process_alarm
    process_alarm
    
    ...
    thread_alarm
    Thread: 5  Slept for 0 (1) sec
    end
    

E.5. Unterschiede zwischen verschiedenen Thread-Paketen

MySQL is very dependent on the thread package used. So when choosing a good platform for MySQL, the thread package is very important.

There are at least three types of thread packages:

  • User threads in a single process. Thread switching is managed with alarms and the threads library manages all non-thread-safe functions with locks. Read, write and select operations are usually managed with a thread-specific select that switches to another thread if the running threads have to wait for data. If the user thread packages are integrated in the standard libs (FreeBSD and BSDI threads) the thread package requires less overhead than thread packages that have to map all unsafe calls (MIT-pthreads, FSU Pthreads and RTS threads). In some environments (for example, SCO), all system calls are thread-safe so the mapping can be done very easily (FSU Pthreads on SCO). Downside: All mapped calls take a little time and it's quite tricky to be able to handle all situations. There are usually also some system calls that are not handled by the thread package (like MIT-pthreads and sockets). Thread scheduling isn't always optimal.

  • User threads in separate processes. Thread switching is done by the kernel and all data are shared between threads. The thread package manages the standard thread calls to allow sharing data between threads. LinuxThreads is using this method. Downside: Lots of processes. Thread creating is slow. If one thread dies the rest are usually left hanging and you must kill them all before restarting. Thread switching is somewhat expensive.

  • Kernel threads. Thread switching is handled by the thread library or the kernel and is very fast. Everything is done in one process, but on some systems, ps may show the different threads. If one thread aborts, the whole process aborts. Most system calls are thread-safe and should require very little overhead. Solaris, HP-UX, AIX and OSF/1 have kernel threads.

In some systems kernel threads are managed by integrating user level threads in the system libraries. In such cases, the thread switching can only be done by the thread library and the kernel isn't really „thread aware.

Anhang F. Umgebungsvariablen

This appendix lists all the environment variables that are used directly or indirectly by MySQL. Most of these can also be found in other places in this manual.

Note that any options on the command line take precedence over values specified in option files and environment variables, and values in option files take precedence over values in environment variables.

In many cases, it is preferable to use an option file instead of environment variables to modify the behavior of MySQL. See Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

VariableDescription
CXXThe name of your C++ compiler (for running configure).
CCThe name of your C compiler (for running configure).
CFLAGSFlags for your C compiler (for running configure).
CXXFLAGSFlags for your C++ compiler (for running configure).
DBI_USERThe default username for Perl DBI.
DBI_TRACETrace options for Perl DBI.
HOMEThe default path for the mysql history file is $HOME/.mysql_history.
LD_RUN_PATHUsed to specify the location of libmysqlclient.so.
MYSQL_DEBUGDebug trace options when debugging.
MYSQL_HISTFILEThe path to the mysql history file. If this variable is set, its value overrides the default for $HOME/.mysql_history.
MYSQL_HOSTThe default hostname used by the mysql command-line client.
MYSQL_PS1The command prompt to use in the mysql command-line client.
MYSQL_PWDThe default password when connecting to mysqld. Note that using this is insecure. See Abschnitt 5.9.6, „Wie Sie Ihre Kennwörter sicher halten“.
MYSQL_TCP_PORTThe default TCP/IP port number.
MYSQL_UNIX_PORTThe default Unix socket filename; used for connections to localhost.
PATHUsed by the shell to find MySQL programs.
TMPDIRThe directory where temporary files are created.
TZThis should be set to your local time zone. See Abschnitt A.4.6, „Probleme mit Zeitzonen“.
UMASK_DIRThe user-directory creation mask when creating directories. Note that this is ANDed with UMASK.
UMASKThe user-file creation mask when creating files.
USERThe default username on Windows and NetWare used when connecting to mysqld.

Anhang G. Beschreibung der MySQL-Syntax für reguläre Ausdrücke

Ein regulärer Ausdruck ist ein mächtiges Werkzeug, um ein Muster für eine komplexe Suchoperation zu spezifizieren.

MySQL verwendet Henry Spencers Implementierung für reguläre Ausdrücke, die auf POSIX 1003.2 zugeschnitten ist. Siehe auch Anhang C, Danksagungen. MySQL benutzt die erweiterte Version, um Mustererkennung mit dem REGEXP-Operator in SQL-Anweisungen zu ermöglichen. Siehe hierzu Abschnitt 3.3.4.7, „Übereinstimmende Suchmuster“, und Abschnitt 12.3.1, „String-Vergleichsfunktionen“.

Dieser Anhang fasst mit Beispielen die Sonderzeichen und Konstrukte zusammen, die in MySQL für REGEXP-Operationen eingesetzt werden können. Wir wiederholen hier nicht jedes Detail von Henry Spencers regex(7)-Handbuchseite. Diese Seite ist in den Quelldistributionen von MySQL inbegriffen, nämlich in der Datei regex.7 unter dem Verzeichnis regex.

Ein regulärer Ausdruck beschreibt eine Menge von Strings. Der einfachste reguläre Ausdruck ist einer ohne Sonderzeichen. So erkennt beispielsweise der reguläre Ausdruck hello nichts anderes als den String hello.

Nichttriviale reguläre Ausdrücke verwenden spezielle Konstrukte, um mehr als nur einen einzigen String erkennen zu können. So passt beispielsweise der reguläre Ausdruck hello|word entweder auf den String hello oder auf den String word.

Als komplexeres Beispiel erkennt der reguläre Ausdruck B[an]*s die Strings Bananas, Baaaaas, Bs und und alle anderen Strings, die mit B anfangen, mit s enden und beliebig viele a- oder n-Zeichen dazwischen aufweisen.

Ein regulärer Ausdruck für den REGEXP-Operator kann alle folgenden Sonderzeichen und Konstrukte benutzen:

  • ^

    Den Anfang eines Strings erkennen.

    mysql> SELECT 'fo\nfo' REGEXP '^fo$';                   -> 0
    mysql> SELECT 'fofo' REGEXP '^fo';                      -> 1
    
  • $

    Das Ende eines Strings erkennen.

    mysql> SELECT 'fo\no' REGEXP '^fo\no$';                 -> 1
    mysql> SELECT 'fo\no' REGEXP '^fo$';                    -> 0
    
  • .

    Irgendwelche Zeichen erkennen (einschließlich Carriage Return und Newline).

    mysql> SELECT 'fofo' REGEXP '^f.*$';                    -> 1
    mysql> SELECT 'fo\r\nfo' REGEXP '^f.*$';                -> 1
    
  • a*

    Irgendeine Folge von null oder mehr a-Zeichen erkennen.

    mysql> SELECT 'Ban' REGEXP '^Ba*n';                     -> 1
    mysql> SELECT 'Baaan' REGEXP '^Ba*n';                   -> 1
    mysql> SELECT 'Bn' REGEXP '^Ba*n';                      -> 1
    
  • a+

    Irgendeine Folge von einem oder mehr a-Zeichen erkennen.

    mysql> SELECT 'Ban' REGEXP '^Ba+n';                     -> 1
    mysql> SELECT 'Bn' REGEXP '^Ba+n';                      -> 0
    
  • a?

    Null oder ein a-Zeichen erkennen.

    mysql> SELECT 'Bn' REGEXP '^Ba?n';                      -> 1
    mysql> SELECT 'Ban' REGEXP '^Ba?n';                     -> 1
    mysql> SELECT 'Baan' REGEXP '^Ba?n';                    -> 0
    
  • de|abc

    Eine der Zeichenfolgen de oder abc erkennen.

    mysql> SELECT 'pi' REGEXP 'pi|apa';                     -> 1
    mysql> SELECT 'axe' REGEXP 'pi|apa';                    -> 0
    mysql> SELECT 'apa' REGEXP 'pi|apa';                    -> 1
    mysql> SELECT 'apa' REGEXP '^(pi|apa)$';                -> 1
    mysql> SELECT 'pi' REGEXP '^(pi|apa)$';                 -> 1
    mysql> SELECT 'pix' REGEXP '^(pi|apa)$';                -> 0
    
  • (abc)*

    Null oder mehr Instanzen der Zeichenfolge abc erkennen.

    mysql> SELECT 'pi' REGEXP '^(pi)*$';                    -> 1
    mysql> SELECT 'pip' REGEXP '^(pi)*$';                   -> 0
    mysql> SELECT 'pipi' REGEXP '^(pi)*$';                  -> 1
    
  • {1}, {2,3}

    Die {n}- oder {m,n}-Notation bietet eine allgemeingültigere Möglichkeit, reguläre Ausdrücke zu schreiben, die viele Exemplare des vorangehenden atomaren Bestandteils (oder „Teils“) des Musters erkennen. m und n sind Integer.

    • a*

      Kann als a{0,} geschrieben werden.

    • a+

      Kann als a{1,} geschrieben werden.

    • a?

      Kann als a{0,1} geschrieben werden.

    Genauer gesagt: a{n} erkennt genau n Instanzen von a. a{n,} erkennt n oder mehr Instanzen von a. a{m,n} erkennt m bis einschließlich n Instanzen von a.

    m und n müssen zwischen 0 und RE_DUP_MAX (Standardwert 255) einschließlich liegen. Sind sowohl m als auch n angegeben, muss m kleiner oder gleich n sein.

    mysql> SELECT 'abcde' REGEXP 'a[bcd]{2}e';              -> 0
    mysql> SELECT 'abcde' REGEXP 'a[bcd]{3}e';              -> 1
    mysql> SELECT 'abcde' REGEXP 'a[bcd]{1,10}e';           -> 1
    
  • [a-dX], [^a-dX]

    Erkennt jedes Zeichen, das gleich (oder, wenn ^ verwendet wird, ungleich) a, b, c, d oder X ist. Ein --Zeichen zwischen zwei anderen Zeichen bildet einen Bereich, der alle Zeichen vom ersten bis zum zweiten erkennt. So erkennt beispielsweise [0-9] jede Ziffer des Dezimalsystems. Um das Literalzeichen ] einzubinden, muss dieses unmittelbar hinter der öffnenden eckigen Klammer [ stehen. Um ein Literalzeichen - einzubinden, muss es als erstes oder letztes Zeichen geschrieben werden. Jedes Zeichen innerhalb eines Klammerpaars [], das keine definierte Sonderbedeutung hat, erkennt nur sich selbst.

    mysql> SELECT 'aXbc' REGEXP '[a-dXYZ]';                 -> 1
    mysql> SELECT 'aXbc' REGEXP '^[a-dXYZ]$';               -> 0
    mysql> SELECT 'aXbc' REGEXP '^[a-dXYZ]+$';              -> 1
    mysql> SELECT 'aXbc' REGEXP '^[^a-dXYZ]+$';             -> 0
    mysql> SELECT 'gheis' REGEXP '^[^a-dXYZ]+$';            -> 1
    mysql> SELECT 'gheisa' REGEXP '^[^a-dXYZ]+$';           -> 0
    
  • [.characters.]

    In einem Ausdruck in eckigen Klammern ([ und ]) wird hiermit die Zeichenfolge dieses Kollationselements erkannt. characters ist entweder ein einzelnes Zeichen oder ein Zeichenname wie newline. Die vollständige Liste der Zeichennamen finden Sie in der Datei regexp/cname.h.

    mysql> SELECT '~' REGEXP '[[.~.]]';                     -> 1
    mysql> SELECT '~' REGEXP '[[.tilde.]]';                 -> 1
    
  • [=character_class=]

    In einem Ausdruck in eckigen Klammern ([ und ]) stellt [=character_class=] eine Äquivalenzklasse dar. Sie erkennt alle Zeichen mit demselben Kollationswert einschließlich sich selbst. Wenn beispielsweise o und (+) die Elemente der Äquivalenzklasse sind, dann sind [[=o=]], [[=(+)=]] und [o(+)] alle synonym. Eine Äquivalenzklasse darf nicht als Endpunkt eines Bereichs verwendet werden.

  • [:character_class:]

    In einem Ausdruck in eckigen Klammern ([ und ]) stellt [:character_class:] eine Zeichenklasse dar, die alle zu dieser Klasse gehörigen Zeichen erkennt. Die folgende Tabelle listet die Standardklassennamen auf. Es sind die Namen der Zeichenklassen, die auf der Handbuchseite ctype(3) definiert sind. Die Klassennamen können in manchen Spracheinstellungen andere sein. Eine Zeichenklasse darf nicht als Endpunkt eines Bereichs verwendet werden.

    alnumAlphanumerische Zeichen
    alphaAlphabetische Zeichen
    blankWhitespace-Zeichen
    cntrlSteuerzeichen
    digitZiffernzeichen
    graphGraphische Zeichen
    lowerKleinbuchstaben
    printGraphische oder Leerzeichen
    punctInterpunktionszeichen
    spaceLeerzeichen, Tabulator, Newline und Carriage Return
    upperGroßbuchstaben
    xdigitHexadezimalziffern
    mysql> SELECT 'justalnums' REGEXP '[[:alnum:]]+';       -> 1
    mysql> SELECT '!!' REGEXP '[[:alnum:]]+';               -> 0
    
  • [[:<:]], [[:>:]]

    Diese Markierungen bedeuten Wortgrenzen. Sie erkennen den Anfang und das Ende eines Worts. Ein Wort ist eine Folge von Wortzeichen, denen kein weiteres Wortzeichen voransteht oder folgt. Ein Wortzeichen ist ein alphanumerisches Zeichen aus der Klasse alnum oder ein Unterstrich (_).

    mysql> SELECT 'a word a' REGEXP '[[:<:]]word[[:>:]]';   -> 1
    mysql> SELECT 'a xword a' REGEXP '[[:<:]]word[[:>:]]';  -> 0
    

Um ein Sonderzeichen in einem regulären Ausdruck als Literal zu benutzen, setzen Sie zwei Backslash-Zeichen davor (\). Der Parser von MySQL interpretiert einen der Backslashes und die Bibliothek für reguläre Ausdrücke den anderen. Um beispielsweise den String 1+2 zu erkennen, der das Sonderzeichen + enthält, ist nur der letzte der folgenden regulären Ausdrücke der richtige:

mysql> SELECT '1+2' REGEXP '1+2';                       -> 0
mysql> SELECT '1+2' REGEXP '1\+2';                      -> 0
mysql> SELECT '1+2' REGEXP '1\\+2';                     -> 1

Anhang H. Beschränkungen in MySQL

This Appendix lists current limits in MySQL 5.1.

H.1. Beschränkungen von Joins

The maximum number of tables that can be referenced in a single join is 61. This also applies to the number of tables that can be referenced in the definition of a view.

Anhang I. Feature-Beschränkungen

Im vorliegenden Kapitel werden Beschränkungen beschrieben, die für MySQL-Features wie beispielsweise Unterabfragen oder Views gelten.

I.1. Beschränkungen bei gespeicherten Routinen und Triggern

Einige hier aufgeführten Beschränkungen gelten für alle gespeicherten Routinen, also sowohl für gespeicherte Prozeduren als auch für gespeicherte Funktionen. Manche Beschränkungen gelten nur für gespeicherte Funktionen, aber nicht für gespeicherte Prozeduren.

Alle Beschränkungen für gespeicherte Funktionen gelten auch für Trigger. Außerdem sind Trigger zurzeit noch nicht für Fremdschlüsselaktionen aktiviert.

Gespeicherte Routinen dürfen keine beliebigen SQL-Anweisungen enthalten. Die folgenden Anweisungen sind unzulässig:

  • die Sperranweisungen LOCK TABLES und UNLOCK TABLES

  • LOAD DATA und LOAD TABLE

  • Vorbereitete SQL-Anweisungen (PREPARE, EXECUTE, DEALLOCATE PREPARE). Folge: Sie können in gespeicherten Routinen kein dynamisches SQL benutzen (indem Sie Anweisungen dynamisch als Strings generieren und dann ausführen). Diese Einschränkung wird in MySQL 5.0.13 für gespeicherte Prozeduren aufgehoben, gilt aber weiterhin für gespeicherte Funktionen und Trigger.

Für gespeicherte Funktionen (nicht aber gespeicherte Prozeduren) sind zusätzlich folgende Anweisungen unzulässig:

  • Anweisungen, die ein explizites oder implizites Commit oder Rollback ausführen

  • Anweisungen, die eine Ergebnismenge zurückgeben. Dazu gehören auch SELECT-Anweisungen, die keine INTO var_list-Klausel besitzen, sowie SHOW-Anweisungen. Eine Funktion kann eine Ergebnismenge entweder mit SELECT ... INTO var_list oder mit einem Cursor und FETCH-Anweisungen verarbeiten. Siehe Abschnitt 19.2.7.3, „SELECT ... INTO-Anweisung“.

  • FLUSH-Anweisungen

  • Rekursive Anweisungen. Das bedeutet, dass gespeicherte Funktionen nicht rekursiv benutzt werden können.

Achtung: Obwohl einige Beschränkungen normalerweise zwar für gespeicherte Funktionen und Trigger, aber nicht für gespeicherte Prozeduren gelten sollten, gelten sie dennoch für gespeicherte Prozeduren, wenn diese aus einer gespeicherten Funktion oder einem Trigger heraus aufgerufen werden. So können Sie zwar FLUSH in einer gespeicherten Prozedur verwenden, aber keine derartige gespeicherte Prozedur aus einer gespeicherten Funktion oder einem Trigger heraus aufrufen.

Es ist möglich, denselben Bezeichner für eine Routine, einen Parameter, eine lokale Variable und eine Tabellenspalte zu benutzen. Zudem kann derselbe lokale Variablenname in geschachtelten Blöcken eingesetzt werden. Zum Beispiel:

CREATE PROCEDURE p (i INT)
BEGIN
  DECLARE i INT DEFAULT 0;
  SELECT i FROM t;
  BEGIN
    DECLARE i INT DEFAULT 1;
    SELECT i FROM t;
  END;
END;

In solchen Fällen ist der Bezeichner nicht mehr eindeutig, sodass folgende Präzedenzregeln gelten:

  • Eine lokale Variable hat Vorrang vor einem Routinenparameter oder einer Tabellenspalte.

  • Ein Routinenparameter hat Vorrang vor einer Tabellenspalte.

  • Eine lokale Variable in einem inneren Block hat Vorrang vor einer lokalen Variablen in einem äußeren Block.

Dass Tabellenspalten nicht Vorrang vor Variablen haben, ist ein nichtstandardmäßiges Verhalten.

Die Verwendung von gespeicherten Routinen kann Replikationsprobleme verursachen. Dieses Thema wird in Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“, eingehender behandelt.

Da INFORMATION_SCHEMA noch keine PARAMETERS-Tabelle hat, müssen Anwendungen, die Daten von Routinenparametern zur Laufzeit benötigen, Workarounds einsetzen, also beispielsweise die Ausgabe der SHOW CREATE-Anweisungen parsen.

Es gibt keine Debuggingfähigkeiten für gespeicherte Routinen.

CALL-Anweisungen dürfen keine vorbereiteten Anweisungen sein. Das gilt sowohl für serverseitige vorbereitete Anweisungen als auch für vorbereitete SQL-Anweisungen.

UNDO-Handler werden nicht unterstützt.

FOR-Schleifen werden nicht unterstützt.

Um Probleme mit der Interaktion zwischen Server-Threads zu verhindern, verwendet der Server, wenn ein Client eine Anweisung gibt, einen Schnappschuss der Routinen und Trigger, die zur Ausführung dieser Anweisung verfügbar sind. Das bedeutet, dass der Server eine Liste von Prozeduren, Funktionen und Triggern berechnet, die bei der Ausführung der Anweisung eingesetzt werden dürfen, diese lädt und dann zur Ausführung der Anweisung schreitet. Die Folge: Während der Ausführung erkennt der Server keine Änderungen an Routinen, die von anderen Threads vorgenommen werden.

I.2. Beschränkungen von serverseitigen Cursorn

Cursors auf der Serverseite werden in der C-API mit der Funktion mysql_stmt_attr_set() implementiert. Dieselbe Implementierung wird auch für Cursors in gespeicherten Routinen verwendet. Mit einem Cursor auf der Serverseite kann dort eine Ergebnismenge generiert werden, wobei an den Client allerdings nur diejenigen Zeilen übermittelt werden, die dieser verlangt. Wenn ein Client beispielsweise eine Anfrage ausführt, sich aber nur für die erste Zeile interessiert, werden die restlichen Zeilen nicht übertragen.

In MySQL wird ein serverseitiger Cursor von einer temporären Tabelle verkörpert (materialisiert). Diese ist zu Beginn eine MEMORY-Tabelle, wird aber dann in eine MyISAM-Tabelle umgewandelt, wenn ihre Größe den Wert der Systemvariablen max_heap_table_size erreicht. Diese Implementierung führt unter anderem dazu, dass der Abruf von Zeilen mit einem Cursor bei großen Ergebnismengen langsam ist.

Cursors sind nur-lesend; mit einem Cursor können Sie also keine Zeilen aktualisieren.

UPDATE WHERE CURRENT OF und DELETE WHERE CURRENT OF sind nicht implementiert, da änderbare Cursors nicht unterstützt werden.

Cursors lassen sich nicht nach einem Commit offen halten.

Cursors unterscheiden nicht zwischen Groß- und Kleinschreibung.

Cursors sind nicht scrollbar.

Cursors haben keinen Namen. Der Anweisungs-Handler fungiert als Cursor-ID.

Sie können immer nur einen einzigen Cursor pro vorbereiteter Anweisung offen haben. Wenn Sie mehrere Cursors benötigen, müssen Sie mehrere Anweisungen vorbereiten.

Sie dürfen keinen Cursor für eine Anweisung benutzen, die eine Ergebnismenge generiert, wenn die Anweisung nicht im Prepared-Modus unterstützt wird. Dazu gehören Anweisungen wie beispielsweise CHECK TABLES, HANDLER READ und SHOW BINLOG EVENTS.

I.3. Beschränkungen von Unterabfragen

Ein bekannter Bug, der noch behoben wird: Wenn Sie einen NULL-Wert mithilfe von ALL, ANY oder SOME mit einer Unterabfrage vergleichen und die Unterabfrage eine Ergebnismenge zurückgibt, kann der Vergleich das nichtstandardmäßige Ergebnis NULL anstatt TRUE oder FALSE zurückliefern.

Die äußere Anweisung einer Unterabfrage kann ein SELECT, INSERT, UPDATE, DELETE, SET oder DO sein.

Im Allgemeinen können Sie eine Tabelle nicht in einer Unterabfrage modifizieren und zugleich mit einem Select abfragen. Diese Beschränkung gilt beispielsweise für Anweisungen der folgenden Form:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Ausnahme: Das obige Verbot gilt nicht, wenn Sie eine Unterabfrage für die modifizierte Tabelle in der FROM-Klausel verwenden. Beispiel:

UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);

Das Verbot ist hier deshalb außer Kraft gesetzt, weil die Unterabfrage in der FROM-Klausel von einer temporären Tabelle verkörpert wird, sodass die relevanten Zeilen in t zu dem Zeitpunkt, da das Update in t stattfindet, von dem Select bereits abgerufen worden sind.

Zeilenvergleichsoperationen werden nur teilweise unterstützt:

  • Für expr IN (subquery) kann expr ein n-Tupel sein (das mit Zeilenkonstruktorsyntax angegeben ist) und die Unterabfrage kann Zeilen von n-Tupeln zurückgeben.

  • Für expr op {ALL|ANY|SOME} (subquery) muss expr ein Skalarwert und die Unterabfrage eine Spaltenunterabfrage sein. Sie darf keine Zeilen mit mehreren Spalten zurückgeben.

Mit anderen Worten, für eine Unterabfrage, die Zeilen von n--Tupeln zurückgibt, wird Folgendes unterstützt:

(val_1, ..., val_n) IN (subquery)

Doch dieses wird nicht unterstützt:

(val_1, ..., val_n) op {ALL|ANY|SOME} (subquery)

Der Grund, weshalb Zeilenvergleiche für IN unterstützt werden, aber für die anderen Klauseln nicht, besteht darin, dass IN aufgrund seiner Implementierung den Vergleich als eine Serie von =-Vergleichen und AND-Operationen neu schreibt. Dieser Ansatz kann für ALL, ANY oder SOME nicht verwendet werden.

Zeilenkonstruktoren sind nicht gut optimiert. Die folgenden beiden Ausdrücke sind äquivalent, aber nur der zweite kann optimiert werden:

(col1, col2, ...) = (val1, val2, ...)
col1 = val1 AND col2 = val2 AND ...

Die Unterabfragenoptimierung ist für IN weniger effizient als für den =-Operator.

Ein typisches Beispiel für die schlechte Performance von IN tritt ein, wenn die Unterabfrage nur wenige, die übergeordnete Abfrage hingegen viele Zeilen zurückgibt, die mit den Ergebnissen der Unterabfrage verglichen werden müssen.

Unterabfragen in der FROM-Klausel dürfen keine korrelierten Unterabfragen sein. Sie werden materialisiert (ausgeführt, um eine Ergebnismenge zu erstellen), bevor die äußere Abfrage ausgeführt wird. Daher können sie nicht pro Zeile der äußeren Abfrage ausgewertet werden.

Da der Optimierer für Joins besser als für Unterabfragen gerüstet ist, lassen sich oft Anweisungen mit Unterabfragen effizienter ausführen, wenn man sie als Joins umformuliert.

Eine Ausnahme bildet der Fall, in dem eine IN-Unterabfrage als SELECT DISTINCT-Join umformuliert werden kann. Beispiel:

SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE condition);

Diese Anweisung kann man folgendermaßen umformulieren:

SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND condition;

Doch hier erfordert der Join eine zusätzliche DISTINCT-Operation und ist deswegen nicht effizienter als die Unterabfrage.

Eine mögliche zukünftige Optimierung könnte darin bestehen, dass MySQL die Join-Reihenfolge nicht für die Auswertung der Unterabfrage neu schreibt. In manchen Fällen ließe sich eine Unterabfrage effizienter ausführen, wenn MySQL sie als Join umformulierte. Dies gäbe dem Optimierer die Gelegenheit, zwischen mehreren Ausführungsplänen auszuwählen. Er könnte beispielsweise entscheiden, welche von zwei Tabellen er als Erste liest.

Beispiel:

SELECT a FROM outer_table AS ot
WHERE a IN (SELECT a FROM inner_table AS it WHERE ot.b = it.b);

Für diese Anfrage würde MySQL immer zuerst die outer_table scannen und dann die Unterabfrage für jede Zeile auf der inner_table ausführen. Wenn outer_table viele und inner_table wenige Zeilen hat, liefe die Anfrage nicht so schnell, wie sie könnte.

Die obige Anfrage könnte man folgendermaßen umformulieren:

SELECT a FROM outer_table AS ot, inner_table AS it
WHERE ot.a = it.a AND ot.b = it.b;

In diesem Fall scannen wir zuerst die kleine Tabelle (inner_table) und schauen danach die Zeilen in der großen outer_table nach. Das geht ganz schnell, wenn wir einen Index auf (ot.a,ot.b) haben.

Mögliche zukünftige Optimierung: Eine korrelierte Unterabfrage wird für jede Zeile der äußeren Abfrage ausgewertet. Es wäre besser, die Unterabfrage nicht erneut auszuwerten, wenn die Werte der äußeren Zeile immer noch dieselben sind wie in der vorherigen Zeile. Stattdessen könnte man das vorherige Ergebnis wiederverwenden.

Mögliche zukünftige Optimierung: Eine Unterabfrage in der FROM-Klausel wird ausgewertet, indem ihr Ergebnis in einer temporären Tabelle festgehalten wird, die keine Indizes verwendet. So können auch bei Vergleichen mit anderen Tabellen in der Abfrage keine Indizes eingesetzt werden, auch dann nicht, wenn es sinnvoll wäre.

Mögliche zukünftige Optimierung: Wenn eine Unterabfrage in der FROM-Klausel einer View ähnelt, auf die der Merge-Algorithmus angewendet werden kann, formulieren Sie die Anfrage um und wenden den Merge-Algorithmus an, damit Indizes genutzt werden können. Die folgende Anweisung enthält eine solche Unterabfrage:

SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;

Die Anweisung kann folgendermaßen als Join geschrieben werden:

SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;

Diese Umformulierung hat zwei Vorteile:

  • Sie verhindert den Einsatz einer temporären Tabelle, für die keine Indizes genutzt werden können. In der umformulierten Version kann der Optimierer Indizes auf t1 verwenden.

  • Sie gibt dem Optimierer mehr Freiheiten, zwischen verschiedenen Ausführungsplänen zu wählen. Indem er sie als Join umformuliert, kann der Optimierer beispielsweise entscheiden, ob er t1 oder t2 zuerst benutzt.

Mögliche zukünftige Optimierung: Für IN, = ANY, <> ANY, = ALL und <> ALL mit nichtkorrelierten Unterabfragen könnte man für das Ergebnis einen speicherresidenten Hash oder, bei größeren Ergebnismengen, eine temporäre Tabelle mit Index verwenden. Beispiel:

SELECT a FROM big_table AS bt
WHERE non_key_field IN (SELECT non_key_field FROM table WHERE condition)

In diesem Fall würden wir eine temporäre Tabelle anlegen:

CREATE TABLE t (key (non_key_field))
(SELECT non_key_field FROM table WHERE condition)

Dann könnten wir für jede Zeile in big_table einen Schlüssel-Lookup in t anhand von bt.non_key_field machen.

I.4. Beschränkungen bei Views

Die View-Verarbeitung ist nicht optimiert:

  • Es ist nicht möglich, auf einer View einen Index anzulegen.

  • Indizes können für Views eingesetzt werden, die mit dem Merge-Algorithmus verarbeitet werden. Wird jedoch eine View mit dem Temptable-Algorithmus verarbeitet, kann sie nicht von den Indizes ihrer zugrunde liegenden Tabellen profitieren (obwohl Indizes bei der Erzeugung der temporären Tabellen eingesetzt werden können).

Unterabfragen dürfen nicht in der FROM-Klausel einer View verwendet werden. Diese Beschränkung wird jedoch in Zukunft aufgehoben.

Generell können Sie nicht in derselben Unterabfrage eine Tabelle modifizieren und gleichzeitig mit Select abfragen. Siehe Abschnitt I.3, „Beschränkungen von Unterabfragen“.

Dasselbe Prinzip gilt auch, wenn Sie eine View abfragen, die ihrerseits eine Tabelle abfragt, wenn die View die Tabelle in einer Unterabfrage abfragt und mit dem Merge-Algorithmus ausgewertet wird. Beispiel:

CREATE VIEW v1 AS
SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE t1.a = t2.a);

UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;

Wird die View mit einer temporären Tabelle ausgewertet, können Sie diese Tabelle in der View-Unterabfrage abfragen und in der äußeren Abfrage dennoch die Tabelle modifizieren. In diesem Fall wird die View nämlich materialisiert, sodass Sie die Tabelle in Wirklichkeit gar nicht „zur selben Zeit“ in einer Unterabfrage abfragen und modifizieren. (Dies ist ein weiterer Grund, MySQL zur Verwendung des Temptable-Algorithmus zu zwingen, indem Sie ALGORITHM = TEMPTABLE in der View-Definition angeben.)

Mit DROP TABLE oder ALTER TABLE können Sie eine Tabelle löschen oder ändern, die in einer View-Definition benutzt wird (wodurch die View ungültig wird). Die Löschungs- oder Änderungsoperation löst keine Warnung aus. Erst später, wenn die View benutzt wird, wird ein Fehler gemeldet.

Eine View-Definition wird von bestimmten Anweisungen „eingefroren“:

  • Wenn eine von PREPARE vorbereitete Anweisung auf eine View verweist, spiegeln die Inhalte der View jedes Mal, wenn die Anweisung im weiteren Verlauf ausgeführt wird, den Zustand zu dem Zeitpunkt wider, da sie vorbereitet wurde. Das gilt auch dann, wenn die View-Definition zwischen der Vorbereitung und der Ausführung der Anweisung geändert wurde. Beispiel:

    CREATE VIEW v AS SELECT 1;
    PREPARE s FROM 'SELECT * FROM v';
    ALTER VIEW v AS SELECT 2;
    EXECUTE s;
    

    Die EXECUTE-Anweisung gibt 1 und nicht 2 zurück.

  • Wenn eine Anweisung in einer gespeicherten Routine eine View benutzt, dann mit dem Inhalt, den die View bei der ersten Ausführung der Anweisung hatte. Das bedeutet beispielsweise: Wenn die Anweisung in einer Schleife ausgeführt wird, bekommt sie in allen weiteren Durchläufen immer denselben View-Inhalt zu sehen, selbst wenn die View-Definition später in der Schleife geändert wird. Beispiel:

    CREATE VIEW v AS SELECT 1;
    delimiter //
    CREATE PROCEDURE p ()
    BEGIN
      DECLARE i INT DEFAULT 0;
      WHILE i < 5 DO
        SELECT * FROM v;
        SET i = i + 1;
        ALTER VIEW v AS SELECT 2;
      END WHILE;
    END;
    //
    delimiter ;
    CALL p();
    

    Wenn die Prozedur p() aufgerufen wird, gibt SELECT bei jedem Schleifendurchlauf 1 zurück, obwohl die View-Definition in der Schleife geändert wurde.

Im Hinblick auf die Aktualisierungsmöglichkeit besteht für Views das übergeordnete Ziel, dass jede View, die theoretisch aktualisiert werden kann, auch in der Praxis aktualisierbar sein sollte. Dazu gehören auch Views, die in ihrer Definition eine UNION haben. Zurzeit sind nicht alle theoretisch aktualisierbaren Views auch in der Praxis aktualisierbar. Die ursprüngliche Implementierung von Views war absichtlich so geschrieben worden, um möglichst schnell benutzbare und aktualisierbare Views in MySQL hinzuzubekommen. Viele theoretisch aktualisierbare Views sind dies auch in der Praxis, aber es gibt immer noch einige Einschränkungen:

  • Aktualisierbare Views, die irgendwo anders als in der WHERE-Klausel Unterabfragen haben. Manche Views mit Unterabfragen in der SELECT-Liste sind möglicherweise aktualisierbar.

  • Sie können mit UPDATE nicht mehr als eine unterliegende Tabelle einer als Join definierten View aktualisieren.

  • Sie können eine als Join definierte View nicht mit DELETE aktualisieren.

I.5. Beschränkungen bei XA-Transaktionen

Die XA-Transaktionsunterstützung beschränkt sich auf die Speicher-Engine InnoDB.

Die XA-Implementierung von MySQL ist für „externes XA“ ausgelegt, bei dem ein MySQL Server als Ressourcenmanager (RMs) und Clientprogramme als Transaktionsmanager (TMs) fungieren. „Internes XA“ ist nicht implementiert. Dies würde einzelnen Speicher-Engines in einem MySQL Server erlauben, als RMs zu agieren, und dem Server selbst, als TM zu fungieren. Internes XA ist für den Umgang mit XA-Transaktionen erforderlich, an denen mehr als eine Speicher-Engine beteiligt ist. Die Implementierung von internem XA ist unvollständig, da sie erfordert, dass eine Speicher-Engine zweiphasiges Commit auf der Tabellenhandler-Ebene unterstützt, was zurzeit nur InnoDB kann.

Für XA START werden keine JOIN- und RESUME-Klauseln unterstützt.

Für XA END wird die SUSPEND [FOR MIGRATE]-Klausel nicht unterstützt.

Die Anforderung, dass der bqual-Teil des xid-Werts für jede XA-Transaktion innerhalb einer globalen Transaktion anders sein muss, ist eine Beschränkung der derzeitigen XA-Implementierung von MySQL. Sie ist nicht Teil der XA-Spezifikation.

Wenn eine XA-Transaktion den PREPARED-Zustand erreicht hat und der MySQL Server abstürzt, kann die Transaktion nach dem erneuten Hochfahren des Servers weiterlaufen. Das soll auch so sein. Wenn allerdings die Clientverbindung abbricht und der Server weiterläuft, rollt der Server alle anhängigen XA-Transaktionen zurück, selbst solche, die den PREPARED-Zustand erreicht haben. Es sollte möglich sein, eine PREPARED-XA-Transaktion zu committen oder zurückzurollen, doch dies lässt sich nur durch Änderungen am Mechanismus des Binärlogs erreichen.

Anhang J. GNU General Public License

Version 2, June 1991


  Copyright © 1989, 1991 Free Software Foundation, Inc.
  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
  

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software---to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  1. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The ``Program'', below, refers to any such program or work, and a ``work based on the Program'' means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term ``modification''.) Each licensee is addressed as ``you''.

    Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

  2. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

    You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

  3. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

    1. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

    2. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

    3. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

    These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

    Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

    In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

  4. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

    1. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

    2. Accompany it with a written offer, valid for at least three years, to give any third-party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

    3. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

    The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

    If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

  5. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

  6. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

  7. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

  8. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

    If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

    It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

    This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

  9. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

  10. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

    Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and ``any later version'', you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

  11. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

    NO WARRANTY

  12. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  13. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found.

one line to give the program's name and a brief idea of what it does.
Copyright (C) yyyy  name of author

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than 'show w' and 'show c'; they could even be mouse-clicks or menu items---whatever suits your program.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.

signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice

This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.

Anhang K. MySQL FLOSS License Exception

The MySQL AB Exception for Free/Libre and Open Source Software-only Applications Using MySQL Client Libraries (the „FLOSS Exception“).

Version 0.4, 08 September 2005

Exception Intent

We want specified Free/Libre and Open Source Software (``FLOSS'') applications to be able to use specified GPL-licensed MySQL client libraries (the ``Program'') despite the fact that not all FLOSS licenses are compatible with version 2 of the GNU General Public License (the ``GPL'').

Legal Terms and Conditions

As a special exception to the terms and conditions of version 2.0 of the GPL:

  1. You are free to distribute a Derivative Work that is formed entirely from the Program and one or more works (each, a „FLOSS Work“) licensed under one or more of the licenses listed below in section 1, as long as:

    1. You obey the GPL in all respects for the Program and the Derivative Work, except for identifiable sections of the Derivative Work which are not derived from the Program, and which can reasonably be considered independent and separate works in themselves,

    2. all identifiable sections of the Derivative Work which are not derived from the Program, and which can reasonably be considered independent and separate works in themselves,

      1. are distributed subject to one of the FLOSS licenses listed below, and

      2. the object code or executable form of those sections are accompanied by the complete corresponding machine-readable source code for those sections on the same medium and under the same FLOSS license as the corresponding object code or executable forms of those sections, and

    3. any works which are aggregated with the Program or with a Derivative Work on a volume of a storage or distribution medium in accordance with the GPL, can reasonably be considered independent and separate works in themselves which are not derivatives of either the Program, a Derivative Work or a FLOSS Work.

    If the above conditions are not met, then the Program may only be copied, modified, distributed or used under the terms and conditions of the GPL or another valid licensing option from MySQL AB.

  2. FLOSS License List

    License nameVersion(s)/Copyright Date
    Academic Free License2.0
    Apache Software License1.0/1.1/2.0
    Apple Public Source License2.0
    Artistic licenseFrom Perl 5.8.0
    BSD license"July 22 1999"
    Common Public License1.0
    GNU Library or "Lesser" General Public License (LGPL)2.0/2.1
    Jabber Open Source License1.0
    MIT license-
    Mozilla Public License (MPL)1.0/1.1
    Open Software License2.0
    OpenSSL license (with original SSLeay license)"2003" ("1998")
    PHP License3.0
    Python license (CNRI Python License)
    Python Software Foundation License2.1.1
    Sleepycat License"1999"
    W3C License"2001"
    X11 License"2001"
    Zlib/libpng License
    Zope Public License2.0

    Due to the many variants of some of the above licenses, we require that any version follow the 2003 version of the Free Software Foundation's Free Software Definition (http://www.gnu.org/philosophy/free-sw.html) or version 1.9 of the Open Source Definition by the Open Source Initiative (http://www.opensource.org/docs/definition.php).

  3. Definitions

    1. Terms used, but not defined, herein shall have the meaning provided in the GPL.

    2. Derivative Work means a derivative work under copyright law.

  4. Applicability: This FLOSS Exception applies to all Programs that contain a notice placed by MySQL AB saying that the Program may be distributed under the terms of this FLOSS Exception. If you create or distribute a work which is a Derivative Work of both the Program and any other work licensed under the GPL, then this FLOSS Exception is not available for that work; thus, you must remove the FLOSS Exception notice from that work and comply with the GPL in all respects, including by retaining all GPL notices. You may choose to redistribute a copy of the Program exclusively under the terms of the GPL by removing the FLOSS Exception notice from that copy of the Program, provided that the copy has never been modified by you or any third party.

Appendix A. Qualified Libraries and Packages

The following is a non-exhaustive list of libraries and packages which are covered by the FLOSS License Exception. Please note that this appendix is provided merely as an additional service to specific FLOSS projects wishing to simplify licensing information for their users. Compliance with one of the licenses noted under the „FLOSS license list“ section remains a prerequisite.

Package NameQualifying License and Version
Apache Portable Runtime (APR)Apache Software License 2.0

Stichwortverzeichnis

Symbole

! (logisches NOT), Logische Operatoren
!= (ungleich), Vergleichsoperatoren
", Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
% (Jokerzeichen), Strings
% (Modulo), Mathematische Funktionen
& (Bit-AND), Bitfunktionen
&& (logisches AND), Logische Operatoren
() (Klammern), Rangfolge von Operatoren
(Strg+Z) \Z, Strings
* (Multiplikation), Arithmetische Operationen
+ (Addition), Arithmetische Operationen
- (monadisches Minus), Arithmetische Operationen
- (Subtraktion), Arithmetische Operationen
-p (Option), Wie Sie Ihre Kennwörter sicher halten
.my.cnf (Datei), my.cnf-Optionsdateien, Verbinden mit dem MySQL-Server, Gründe für Access denied-Fehler, Wie Sie Ihre Kennwörter sicher halten, Verwendung von Client-Programmen in einer Mehrserverumgebung, Replikation: Features und bekannte Probleme
.mysql_history (Datei), mysql Optionen
.pid-Datei (Prozesskennungsdatei), Erstellen eines Wartungsplans für Tabellen
/ (Division), Arithmetische Operationen
/etc/passwd, Absichern von MySQL gegen Angreifer, SELECT
< (kleiner als), Vergleichsoperatoren
<<, Besuche pro Tag berechnen
<< (Linksverschiebung), Bitfunktionen
<= (kleiner oder gleich), Vergleichsoperatoren
<=> (nullsicheres Gleich), Vergleichsoperatoren
<> (ungleich), Vergleichsoperatoren
= (Gleich), Vergleichsoperatoren
> (größer als), Vergleichsoperatoren
>= (größer oder gleich), Vergleichsoperatoren
>> (Rechtsverschiebung), Bitfunktionen
\" (doppeltes Anführungszeichen), Strings
\' (einfaches Anführungszeichen), Strings
\0 (ASCII 0), Strings
\b (Rückschritt), Strings
\n (Zeilenumbruch), Strings
\n (Zeilenvorschub), Strings
\r (Absatzschaltung), Strings
\t (Tabulator), Strings
\Z (Strg+Z) ASCII 26, Strings
\\ (Escape-Zeichen), Strings
^ (Bit-XOR), Bitfunktionen
_ (Jokerzeichen), Strings
_rowid, CREATE TABLE
`, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
| (Bit-OR), Bitfunktionen
|| (logisches OR), Logische Operatoren
~, Bitfunktionen
Ändern
Datenbank, ALTER DATABASE
Feld, ALTER TABLE
Schema, ALTER DATABASE
Spalte, ALTER TABLE
Spaltenreihenfolge, Wie man die Reihenfolge der Spalten in einer Tabelle ändert
Tabelle, ALTER TABLE, Probleme mit ALTER TABLE
Ändern der Socketposition, Typische configure-Optionen, MySQL automatisch starten und anhalten
Änderungen an Berechtigungen, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
Öffnen
Tabellen, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
Überprüfen
Tabellen auf Fehler, Wie Tabellen auf Fehler überprüft werden
Übersicht, Allgemeine Informationen über MySQL

A

Abbruch bei Clients, Kommunikationsfehler/abgebrochene Verbindung
Abfrage-Cache, MySQL-Anfragen-Cache
Abfragelog, Die allgemeine Anfragen-Logdatei
Abfragen
Beispiele, Beispiele gebräuchlicher Abfragen
eingeben, Anfragen eingeben
Geschwindigkeit, SELECT-Anweisungen und andere Anfragen optimieren
Leistungsfähigkeit einschätzen, Anfragenperformance abschätzen
Zwillingsprojekt, Anfragen aus dem Zwillingsprojekt
Abgeleitete Tabellen, Unterabfragen in der FROM-Klausel
Ablaufsteuerungsfunktionen, Ablaufsteuerungsfunktionen
Aborted connections, Kommunikationsfehler/abgebrochene Verbindung
Abrufen
Daten aus Tabellen, Informationen aus einer Tabelle abfragen
ABS(), Mathematische Funktionen
Absatzschaltung (\r), Strings
Absturz
Wiederherstellung, Benutzung von myisamchk für die Fehlerbeseitigung nach Abstürzen
wiederholter, Was zu tun ist, wenn MySQL andauernd abstürzt
Access denied, Access denied-Fehler
ACID, Transaktionen, Überblick über InnoDB-Tabellen
ACLs, Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem
ACOS(), Mathematische Funktionen
Active Server Pages (ASP), MyODBC mit Active Server Pages (ASP) verwenden
ActiveState Perl, Installation von ActiveState-Perl unter Windows
ADDDATE(), Datums- und Zeitfunktionen
Addition (+), Arithmetische Operationen
ADDTIME(), Datums- und Zeitfunktionen
Adresse der Mailingliste, Allgemeine Informationen über MySQL
AES_DECRYPT(), Verschlüsselungs- und Kompressionsfunktionen
AES_ENCRYPT(), Verschlüsselungs- und Kompressionsfunktionen
Aktualisieren
MySQL-Releases, Wann und wie Updates veröffentlicht werden
Tabellen, Transaktionen
Alias, Probleme mit alias
Aliase
für Ausdrücke, GROUP BY mit versteckten Feldern
für Ausdrücken, SELECT
für Tabellen, SELECT
in GROUP BY-Klauseln, GROUP BY mit versteckten Feldern
Namen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
Aliasnamen
Unterscheidung der Groß-/Kleinschreibung, Groß-/Kleinschreibung in Namen
ALL, SELECT
Allgemeine Informationen, Allgemeine Informationen über MySQL
ALLOW_INVALID_DATES (SQL-Modus), Der SQL-Modus des Servers
Alter
berechnen, Datumsberechnungen
ALTER COLUMN, ALTER TABLE
ALTER DATABASE, ALTER DATABASE
ALTER FUNCTION, ALTER PROCEDURE und ALTER FUNCTION
ALTER PROCEDURE, ALTER PROCEDURE und ALTER FUNCTION
ALTER SCHEMA, ALTER DATABASE
ALTER TABLE, ALTER TABLE, Probleme mit ALTER TABLE
ALTER VIEW, ALTER VIEW
ANALYZE TABLE, ANALYZE TABLE
AND
Bit-AND, Bitfunktionen
logisches, Logische Operatoren
Anderes Verzeichnis für Socket, Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern
Anführungszeichen, Strings
Strings, Strings
Anführungszeichen bei Bezeichnern, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
Anführungszeichen bei Binärdaten, Strings
Angreifer
Maßnahmen gegen, Absichern von MySQL gegen Angreifer
Anonymer Benutzer, Einrichtung der anfänglichen MySQL-Berechtigungen, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
ANSI (SQL-Modus), Der SQL-Modus des Servers
ANSI-Modus
ausführen, MySQL im ANSI-Modus laufen lassen
ANSI_QUOTES (SQL-Modus), Der SQL-Modus des Servers
Anweisungen
GRANT, Hinzufügen neuer MySQL-Benutzer
INSERT, Hinzufügen neuer MySQL-Benutzer
Replikationsmaster, SQL-Anweisungen für die Steuerung von Master-Servern
Replikationsslaves, SQL-Anweisungen für die Steuerung von Slave-Servern
Anzeigebreite, Datentypen
Anzeigegröße, Datentypen
Anzeigen
Informationen
Kardinalität, SHOW INDEX
SHOW, SHOW, SHOW COLUMNS, SHOW INDEX, SHOW OPEN TABLES, SHOW TABLES
Sortierfolge, SHOW INDEX
Tabellenstatus, SHOW TABLE STATUS
Anzeigen von Triggern, SHOW TRIGGERS
Apache, MySQL mit Apache verwenden
API's
list of, Pakete, die MySQL unterstützen
APIs, APIs und Bibliotheken
Perl, MySQLs Perl-API
ARCHIVE-Speicher-Engine, Speicher-Engines und Tabellentypen, Die ARCHIVE-Speicher-Engine
ARCHIVE-Tabellentyp, Speicher-Engines und Tabellentypen, Die ARCHIVE-Speicher-Engine
Area(), Polygon-Funktionen, MultiPolygon-Funktionen
Argumentverarbeitung, Verarbeitung von Argumenten
Arithmetische Ausdrücke, Arithmetische Operationen
Arithmetische Funktionen, Bitfunktionen
AS, SELECT, JOIN
AsBinary(), Umwandlungsfunktionen für das Geometrieformat
ASCII(), String-Funktionen
ASIN(), Mathematische Funktionen
AsText(), Umwandlungsfunktionen für das Geometrieformat
ATAN(), Mathematische Funktionen
ATAN2(), Mathematische Funktionen
Aufrufsequenzen für Aggregatfunktionen
UDF, UDF-Aufrufsequenzen für Aggregatfunktionen
Aufrufsequenzen für einfache Funktionen
UDF, UDF-Aufrufsequenzen
Ausdrucksaliase, GROUP BY mit versteckten Feldern, SELECT
Ausdrücke
erweiterte, Übereinstimmende Suchmuster
Ausführen
Abfragen, Anfragen eingeben
ANSI-Modus, MySQL im ANSI-Modus laufen lassen
mehrere Server, Mehrere MySQL-Server auf derselben Maschine laufen lassen
Stapelbetriebsmodus, mysql im Stapelbetrieb
Ausführen von configure nach vorherigem Aufruf, Probleme beim Kompilieren?
Aussprache
MySQL, Was ist MySQL?
Auswahl von Datentypen, Auswahl des richtigen Datentyps für eine Spalte
Auswählen
Datenbanken, Eine Datenbank erzeugen und auswählen
MySQL-Version, Welche MySQL-Version Sie benutzen sollten
AUTO-INCREMENT
ODBC, Abruf von Auto-Increment-Werten
AUTO_INCREMENT, Verwendung von AUTO_INCREMENT
und NULL-Werte, Probleme mit NULL-Werten
AVG(), Funktionen zur Benutzung in GROUP BY-Klauseln
AVG(DISTINCT), Funktionen zur Benutzung in GROUP BY-Klauseln

B

Backslash
Escape-Zeichen, Literale: wie Strings und Zahlen geschrieben werden
BACKUP TABLE, BACKUP TABLE
Backups, Datenbank-Datensicherungen
Datenbanken, BACKUP TABLE
batch
Optionen für mysql, mysql Optionen
Bauen
Clientprogramme, Clientprogramme bauen
BDB-Speicher-Engine, Speicher-Engines und Tabellentypen, Die BDB-Speicher-Engine
BDB-Tabellen, Transaktionen
BDB-Tabellentyp, Speicher-Engines und Tabellentypen, Die BDB-Speicher-Engine
BdMPolyFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
BdMPolyFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
BdPolyFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
BdPolyFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
Beantworten von Fragen
Verhaltensregeln, Richtlinien für die Benutzung der MySQL-Mailinglisten
Bedingungen, DECLARE-Bedingungen
Beenden
Server, MySQL automatisch starten und anhalten
Befehle
für Binärdistributionen, Installation von MySQL auf anderen Unix-ähnlichen Systemen
Befehlsoptionen
myisamchk, Allgemeine Optionen für myisamchk
mysqld, Befehlsoptionen für mysqld
Befehlssyntax, Konventionen in diesem Handbuch
Befehlszeilenoptionen
mysql, mysql Optionen
mysqladmin, mysqladmin — Client für die Verwaltung eines MySQL Servers
Befehlszeilenverlauf
mysql, mysql Optionen
BEGIN, BEGIN/COMMIT/ROLLBACK, BEGIN ... END-Syntax für komplexe Anweisungen
XA-Transaktionen, SQL-Syntax von XA-Transaktionen
Behandlung
Fehler, Rückgabewerte und Fehlerbehandlung
Beispiele
Abfragen, Beispiele gebräuchlicher Abfragen
komprimierte Tabellen, myisampack — Erzeugung komprimierter, schreibgeschützter MyISAM Tabellen
myisamchk, Ausgabe, Informationen über eine Tabelle erhalten
Bekannte Fehler, Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL
BENCHMARK(), Informationsfunktionen
Benchmarks, Die MySQL-Benchmark-Reihe, Wie Sie Ihre eigenen Benchmarks benutzen
Benennen
MySQL-Releases, Auswahl der bestgeeigneten Version von MySQL
Benutzer
hinzufügen, Installation von MySQL auf anderen Unix-ähnlichen Systemen, Schnellinstallation, Überblick
löschen, Entfernen von Benutzerkonten in MySQL, DROP USER
root, Einrichtung der anfänglichen MySQL-Berechtigungen
Benutzerberechtigungen
aufheben, Entfernen von Benutzerkonten in MySQL, DROP USER
hinzufügen, Hinzufügen neuer MySQL-Benutzer
löschen, Entfernen von Benutzerkonten in MySQL, DROP USER
Benutzerdefinierte Funktionen, DROP FUNCTION
hinzufügen, Hinzufügen neuer Funktionen zu MySQL, Hinzufügen einer neuen benutzerdefinierten Funktion
benutzerdefinierte Funktionen, CREATE FUNCTION/DROP FUNCTION
Benutzerkonten
erstellen, CREATE USER
umbenennen, RENAME USER
Benutzernamen
und Passwörter, MySQL-Benutzernamen und -Kennwörter
Benutzervariablen, Benutzerdefinierte Variablen
Berechnen
Datumsangaben, Datumsberechnungen
Berechtigung
Änderungen, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
Berechtigungen
Anzeigeberechtigungen, SHOW GRANTS
aufheben, Entfernen von Benutzerkonten in MySQL, DROP USER
gewähren, GRANT und REVOKE
hinzufügen, Hinzufügen neuer MySQL-Benutzer
löschen, Entfernen von Benutzerkonten in MySQL, DROP USER
vorgabeseitige, Einrichtung der anfänglichen MySQL-Berechtigungen
widerrufen, REVOKE
Zugriffsberechtigungen, Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem
Berechtigungsdaten
Position, Von MySQL zur Verfügung gestellte Berechtigungen
Berechtigungssystem, Was das Berechtigungssystem macht
Beschreibung, Wie das Berechtigungssystem funktioniert
Berechtigungsüberprüfung
Auswirkungen auf die Geschwindigkeit, SELECT-Anweisungen und andere Anfragen optimieren
Bereichspartitionen, hinzufügen und löschen, Verwaltung von RANGE- und LIST-Partitionen
Bereichspartitionen, verwalten, Verwaltung von RANGE- und LIST-Partitionen
Bereichspartitionierung, RANGE-Partitionierung
BerkeleyDB-Speicher-Engine, Speicher-Engines und Tabellentypen, Die BDB-Speicher-Engine
BerkeleyDB-Tabellentyp, Speicher-Engines und Tabellentypen, Die BDB-Speicher-Engine
Beschränkungen
Cursors auf der Serverseite, Beschränkungen von serverseitigen Cursorn
Dateigröße, Wie groß können MySQL-Tabellen sein?
gespeicherte Routinen, Beschränkungen bei gespeicherten Routinen und Triggern
Trigger, Beschränkungen bei gespeicherten Routinen und Triggern
Unterabfragen, Beschränkungen von Unterabfragen
Views, Beschränkungen bei Views
Beschränkungen für Cursors auf der Serverseite, Beschränkungen von serverseitigen Cursorn
Beschränkungen für gespeicherte Routine, Beschränkungen bei gespeicherten Routinen und Triggern
Beschränkungen für Trigger, Beschränkungen bei gespeicherten Routinen und Triggern
Beschränkungen für Unterabfragen, Beschränkungen von Unterabfragen
Beschränkungen von Views, Beschränkungen bei Views
Betriebssysteme
Dateigrößen-Beschränkungen, Wie groß können MySQL-Tabellen sein?
unterstützte, Betriebssysteme, die von MySQL unterstützt werden
Windows und Unix, MySQL unter Windows im Vergleich zu MySQL unter Unix
BETWEEN ... AND, Vergleichsoperatoren
Bezeichner, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
Anführungszeichen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
Unterscheidung der Groß-/Kleinschreibung, Groß-/Kleinschreibung in Namen
Bibliothek
mysqlclient, APIs und Bibliotheken
mysqld, APIs und Bibliotheken
Big5 Chinese-Zeichencodierung, Groß-/Kleinschreibung beim Suchen
BIGINT (Datentyp), Überblick über numerische Datentypen
BIN(), String-Funktionen
BINARY, Cast-Funktionen und Operatoren
BINARY (Datentyp), Überblick über String-Typen, Die BINARY- und VARBINARY-Typen
Binärdistributionen
installieren, Installation von MySQL auf anderen Unix-ähnlichen Systemen
Linux, Anmerkungen zur Binärdistribution (Linux)
Binärlog, Die binäre Update-Logdatei
BIT (Datentyp), Überblick über numerische Datentypen
Bit-Funktionen
Beispiel, Besuche pro Tag berechnen
BitKeeper-Tree, Installation vom Entwicklungs-Source-Tree
BIT_AND(), Funktionen zur Benutzung in GROUP BY-Klauseln
BIT_COUNT, Besuche pro Tag berechnen
BIT_COUNT(), Bitfunktionen
BIT_LENGTH(), String-Funktionen
BIT_OR, Besuche pro Tag berechnen
BIT_OR(), Funktionen zur Benutzung in GROUP BY-Klauseln
BIT_XOR(), Funktionen zur Benutzung in GROUP BY-Klauseln
BLACKHOLE-Speicher-Engine, Speicher-Engines und Tabellentypen, Die BLACKHOLE-Speicher-Engine
BLACKHOLE-Tabellentyp, Speicher-Engines und Tabellentypen, Die BLACKHOLE-Speicher-Engine
BLOB
Einfügen von Binärdaten, Strings
Größe, Speicherbedarf von Spaltentypen
BLOB (Datentyp), Überblick über String-Typen, Die Spaltentypen BLOB und TEXT
BLOB-Spalten
indizieren, Spaltenindizes, CREATE TABLE
Vorgabewerte, Die Spaltentypen BLOB und TEXT
BOOL (Datentyp), Überblick über numerische Datentypen
BOOLEAN (Datentyp), Überblick über numerische Datentypen
Borland Builder 4, MyODBC mit Borland Builder 4 verwenden
Borland C++-Compiler, Borland C++
Boundary(), Allgemeine Geometriefunktionen
Breite
Anzeige, Datentypen
Buffer(), Raumbezogene Operatoren
Bugdatenbank, Wie man Bugs oder Probleme meldet
Bugreports
Kriterien für, Wie man Bugs oder Probleme meldet
Bugs
bekannte, Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL
melden, Wie man Bugs oder Probleme meldet
bugs.mysql.com, Wie man Bugs oder Probleme meldet

C

C++ Builder, MyODBC mit C++ Builder verwenden
C++-APIs, MySQL-C++-APIs
C++-Compiler
gcc, Typische configure-Optionen
C++-Compiler kann keine ausführbaren Dateien erstellen, Probleme beim Kompilieren?
C-API
Datentypen, MySQL-C-API
Funktionen, C-API: Funktionsüberblick
Linking-Probleme, Probleme beim Linken mit der C-API
C-API für vorbereitete Anweisungen
Funktionen, C-API Prepared Statements: Funktionsüberblick
C:\my.cnf (Datei), Verwendung von Client-Programmen in einer Mehrserverumgebung
CACHE INDEX, CACHE INDEX
Caches
leeren, FLUSH
CALL, Syntax der CALL-Anweisung
can't create/write to file, Can't create/write to file-Fehler
CASE, Ablaufsteuerungsfunktionen, CASE-Anweisung
CAST, Cast-Funktionen und Operatoren
CC (Umgebungsvariable), Typische configure-Optionen, Probleme beim Kompilieren?
CC environment variable, Umgebungsvariablen
cc1plus Probleme, Probleme beim Kompilieren?
CEILING(), Mathematische Funktionen
Centroid(), MultiPolygon-Funktionen
CFLAGS (Umgebungsvariable), Typische configure-Optionen, Probleme beim Kompilieren?
CFLAGS environment variable, Umgebungsvariablen
CHANGE MASTER TO, CHANGE MASTER TO
ChangeLog, MySQL-Änderungsverlauf (Change History)
changes
log, MySQL-Änderungsverlauf (Change History)
MySQL 5.1, Änderungen in Release 5.1.x (Entwicklung)
CHAR (Datentyp), Überblick über String-Typen, String-Typen
CHAR VARYING (Datentyp), Überblick über String-Typen
CHAR(), String-Funktionen
CHARACTER (Datentyp), Überblick über String-Typen
CHARACTER VARYING (Datentyp), Überblick über String-Typen
character-sets-dir
Optionen für mysql, mysql Optionen
CHARACTER_LENGTH(), String-Funktionen
CHARACTER_SETS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA CHARACTER_SETS
CHARSET(), Informationsfunktionen
CHAR_LENGTH(), String-Funktionen
CHECK TABLE, CHECK TABLE
CHECKSUM TABLE, CHECKSUM TABLE
Chinesisch, Groß-/Kleinschreibung beim Suchen
Client-Tools, APIs und Bibliotheken
Clientprogramme, Überblick über Client- und Hilfsprogramme
Bauen, Clientprogramme bauen
Clients
Threaded, Wie man einen Thread-Client herstellt
clients
debugging, Einen MySQL-Client debuggen
CLOSE, Cursor-Statement CLOSE
COALESCE(), Vergleichsoperatoren
COERCIBILITY(), Informationsfunktionen
ColdFusion, MyODBC mit ColdFusion verwenden
COLLATION(), Informationsfunktionen
COLLATIONS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA COLLATIONS
COLLATION_CHARACTER_SET_APPLICABILITY
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY
COLUMNS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA COLUMNS
COLUMN_PRIVILEGES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA COLUMN_PRIVILEGES
commands out of sync, Command out of sync-Fehler in Client
COMMIT, Transaktionen, BEGIN/COMMIT/ROLLBACK
XA-Transaktionen, SQL-Syntax von XA-Transaktionen
Compiler
C++ gcc, Typische configure-Optionen
compress
Optionen für mysql, mysql Optionen
COMPRESS(), Verschlüsselungs- und Kompressionsfunktionen
CONCAT(), String-Funktionen
CONCAT_WS(), String-Funktionen
config-file
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
config.cache (Datei), Probleme beim Kompilieren?
configure
ausführen nach vorherigem Aufruf, Probleme beim Kompilieren?
configure (Skript), Typische configure-Optionen
CONNECTION_ID(), Informationsfunktionen
Connector/JDBC, Connectors
Connector/NET, Connector/NET
Probleme melden, Support für Connector/NET
Connector/ODBC, Connectors, MySQL Connector/ODBC
Probleme melden, MyODBC-Support
Connectors
MySQL, Connectors
connect_timeout (Variable), mysql Optionen, mysqladmin — Client für die Verwaltung eines MySQL Servers
Constraints, Wie MySQL mit Constraints umgeht
CONSTRAINTS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA TABLE_CONSTRAINTS
Contains(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
contributing companies
list of, Unterstützer von MySQL
contributors
list of, Kontributoren zu MySQL
CONV(), String-Funktionen
CONVERT, Cast-Funktionen und Operatoren
CONVERT TO, ALTER TABLE
CONVERT_TZ(), Datums- und Zeitfunktionen
ConvexHull(), Raumbezogene Operatoren
COS(), Mathematische Funktionen
COT(), Mathematische Funktionen
COUNT(), Funktionen zur Benutzung in GROUP BY-Klauseln
COUNT(DISTINCT), Funktionen zur Benutzung in GROUP BY-Klauseln
crash, Einen MySQL-Server debuggen
crash-me (Programm), Applikationskonzepte unter Beachtung von Portabilitätsaspekten, Die MySQL-Benchmark-Reihe
CRC32(), Mathematische Funktionen
CREATE DATABASE, CREATE DATABASE
CREATE FUNCTION, CREATE PROCEDURE und CREATE FUNCTION, CREATE FUNCTION/DROP FUNCTION
CREATE INDEX, CREATE INDEX
CREATE PROCEDURE, CREATE PROCEDURE und CREATE FUNCTION
CREATE SCHEMA, CREATE DATABASE
CREATE TABLE, CREATE TABLE
CREATE TRIGGER, CREATE TRIGGER
CREATE USER, CREATE USER
CREATE VIEW, CREATE VIEW
CROSS JOIN, JOIN
Crosses(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
CR_SERVER_GONE_ERROR, MySQL server has gone away-Fehler
CR_SERVER_LOST_ERROR, MySQL server has gone away-Fehler
CSV-Daten, lesen, LOAD DATA INFILE, SELECT
CSV-Speicher-Engine, Speicher-Engines und Tabellentypen, Die CSV-Speicher-Engine
CSV-Tabellentyp, Speicher-Engines und Tabellentypen, Die CSV-Speicher-Engine
CURDATE(), Datums- und Zeitfunktionen
CURRENT_DATE, Datums- und Zeitfunktionen
CURRENT_TIME, Datums- und Zeitfunktionen
CURRENT_TIMESTAMP, Datums- und Zeitfunktionen
CURRENT_USER(), Informationsfunktionen
Cursors, Cursor
CURTIME(), Datums- und Zeitfunktionen
CXX (Umgebungsvariable), Typische configure-Optionen, Probleme beim Kompilieren?
CXX environment variable, Umgebungsvariablen
CXXFLAGS (Umgebungsvariable), Typische configure-Optionen, Probleme beim Kompilieren?
CXXFLAGS environment variable, Umgebungsvariablen

D

database
Optionen für mysql, mysql Optionen
DATABASE(), Informationsfunktionen
DataJunction, MyODBC mit Pervasive Software DataJunction verwenden
DATE, Probleme bei der Benutzung von DATE-Spalten
DATE (Datentyp), Überblick über Datums- und Zeittypen, Die DATETIME-, DATE- und TIMESTAMP-Typen
DATE(), Datums- und Zeitfunktionen
DATE-Spalten
Probleme, Probleme bei der Benutzung von DATE-Spalten
DATEDIFF(), Datums- und Zeitfunktionen
Dateien
Abfragelog, Die allgemeine Anfragen-Logdatei
Berechtigungen, Probleme mit Dateirechten
Binärlog, Die binäre Update-Logdatei
config.cache, Probleme beim Kompilieren?
Fehlermeldungen, Nicht englische Fehlermeldungen
Größenbeschränkungen, Wie groß können MySQL-Tabellen sein?
Log für langsame Abfragen, Die Logdatei für langsame Anfragen
Logdateien, Typische configure-Optionen, Wartung und Pflege der Logdateien
my.cnf, Replikation: Features und bekannte Probleme
not found-Meldung, Probleme mit Dateirechten
reparieren, Reparaturoptionen für myisamchk
Skriptdateien, mysql im Stapelbetrieb
tmp, Probleme mit mysql_install_db
Update-Log (ausgelaufen), Die binäre Update-Logdatei
Daten
abrufen, Informationen aus einer Tabelle abfragen
in Tabellen einladen, Daten in Tabellen einladen
Umfang, Wie Sie Ihre Daten so klein wie möglich bekommen
Zeichensätze, Der für Daten und zum Sortieren benutzte Zeichensatz
Datenbank
löschen, DROP DATABASE
ändern, ALTER DATABASE
Datenbank-Metadaten, Die Datenbank INFORMATION_SCHEMA
Datenbankdesign, Überlegungen zum Datenbankdesign
Datenbanken
auswählen, Eine Datenbank erzeugen und auswählen
Backups, Datenbank-Datensicherungen
Definition, Was ist MySQL?
erstellen, Eine Datenbank erzeugen und benutzen, CREATE DATABASE
Informationen zu, Informationen über Datenbanken und Tabellen
kopieren, Upgrade auf eine andere Architektur
Namen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
replizieren, Replikation bei MySQL
symbolische Verknüpfungen, Benutzung symbolischer Links für Datenbanken
verwenden, Eine Datenbank erzeugen und benutzen
Datenbankinformationen
ermitteln, SHOW
Datenbanknamen
Unterscheidung der Groß-/Kleinschreibung, MySQL-Erweiterungen zu ANSI SQL92, Groß-/Kleinschreibung in Namen
Datensätze
auswählen, Bestimmte Zeilen auswählen
sortieren, Zeilen sortieren
sperren, Transaktionen
zählen, Zeilen zählen
Datentyp
BIGINT, Überblick über numerische Datentypen
BINARY, Überblick über String-Typen, Die BINARY- und VARBINARY-Typen
BIT, Überblick über numerische Datentypen
BLOB, Überblick über String-Typen, Die Spaltentypen BLOB und TEXT
BOOL, Überblick über numerische Datentypen, Verwendung von Datentypen anderer Datenbanken
BOOLEAN, Überblick über numerische Datentypen, Verwendung von Datentypen anderer Datenbanken
CHAR, Überblick über String-Typen, String-Typen
CHAR VARYING, Überblick über String-Typen
CHARACTER, Überblick über String-Typen
CHARACTER VARYING, Überblick über String-Typen
DATE, Überblick über Datums- und Zeittypen, Die DATETIME-, DATE- und TIMESTAMP-Typen
DATETIME, Überblick über Datums- und Zeittypen, Die DATETIME-, DATE- und TIMESTAMP-Typen
DEC, Überblick über numerische Datentypen
DECIMAL, Überblick über numerische Datentypen, Präzisionsberechnungen
DOUBLE, Überblick über numerische Datentypen
DOUBLE PRECISION, Überblick über numerische Datentypen
ENUM, Überblick über String-Typen, Der Spaltentyp ENUM
FIXED, Überblick über numerische Datentypen
FLOAT, Überblick über numerische Datentypen
GEOMETRY, Raumbezogene Datentypen in MySQL
GEOMETRYCOLLECTION, Raumbezogene Datentypen in MySQL
INT, Überblick über numerische Datentypen
INTEGER, Überblick über numerische Datentypen
LINESTRING, Raumbezogene Datentypen in MySQL
LONG, Die Spaltentypen BLOB und TEXT
LONGBLOB, Überblick über String-Typen
LONGTEXT, Überblick über String-Typen
MEDIUMBLOB, Überblick über String-Typen
MEDIUMINT, Überblick über numerische Datentypen
MEDIUMTEXT, Überblick über String-Typen
MULTILINESTRING, Raumbezogene Datentypen in MySQL
MULTIPOINT, Raumbezogene Datentypen in MySQL
MULTIPOLYGON, Raumbezogene Datentypen in MySQL
NATIONAL CHAR, Überblick über String-Typen
NCHAR, Überblick über String-Typen
NUMERIC, Überblick über numerische Datentypen
POINT, Raumbezogene Datentypen in MySQL
POLYGON, Raumbezogene Datentypen in MySQL
REAL, Überblick über numerische Datentypen
SET, Überblick über String-Typen, Der Spaltentyp SET
SMALLINT, Überblick über numerische Datentypen
TEXT, Überblick über String-Typen, Die Spaltentypen BLOB und TEXT
TIME, Überblick über Datums- und Zeittypen, Der TIME-Typ
TIMESTAMP, Überblick über Datums- und Zeittypen, Die DATETIME-, DATE- und TIMESTAMP-Typen
TINYBLOB, Überblick über String-Typen
TINYINT, Überblick über numerische Datentypen
TINYTEXT, Überblick über String-Typen
VARBINARY, Überblick über String-Typen, Die BINARY- und VARBINARY-Typen
VARCHAR, Überblick über String-Typen, String-Typen
VARCHARACTER, Überblick über String-Typen
YEAR, Überblick über Datums- und Zeittypen, Der YEAR-Typ
Datentypen, Datentypen
C-API, MySQL-C-API
Jahr-2000-Probleme, Jahr-2000-Probleme und Datumstypen
Übersicht, Überblick über Datentypen
DATETIME (Datentyp), Überblick über Datums- und Zeittypen, Die DATETIME-, DATE- und TIMESTAMP-Typen
DATE_ADD(), Datums- und Zeitfunktionen
DATE_FORMAT(), Datums- und Zeitfunktionen
DATE_SUB(), Datums- und Zeitfunktionen
Datum und Uhrzeit, Datentypen für, Datums- und Zeittypen
Datum und Uhrzeit, Funktionen für, Datums- und Zeitfunktionen
Datumsberechnungen, Datumsberechnungen
Datumsfunktionen
Jahr-2000-Konformität, Jahr-2000-Konformität
Datumstypen, Speicherbedarf von Spaltentypen
Datumswerte
Probleme, Die DATETIME-, DATE- und TIMESTAMP-Typen
DAY(), Datums- und Zeitfunktionen
DAYNAME(), Datums- und Zeitfunktionen
DAYOFMONTH(), Datums- und Zeitfunktionen
DAYOFWEEK(), Datums- und Zeitfunktionen
DAYOFYEAR(), Datums- und Zeitfunktionen
db (Tabelle)
sortieren, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
DB2 (SQL-Modus), Der SQL-Modus des Servers
DBI->Anführungszeichen, Strings
DBI->trace, mysqld unter gdb debuggen
DBI-Schnittstelle, MySQLs Perl-API
DBI/DBD-Schnittstelle, MySQLs Perl-API
DBI_TRACE environment variable, mysqld unter gdb debuggen, Umgebungsvariablen
DBI_USER environment variable, Umgebungsvariablen
DBUG package, Das DBUG-Paket
DEALLOCATE PREPARE, SQL-Syntax für vorbereitete Anweisungen
debug
Optionen für mysql, mysql Optionen
debug-info
Optionen für mysql, mysql Optionen
debugging
client, Einen MySQL-Client debuggen
server, Einen MySQL-Server debuggen
Debugging-Unterstützung, Typische configure-Optionen
DEC (Datentyp), Überblick über numerische Datentypen
DECIMAL (Datentyp), Überblick über numerische Datentypen
DECIMAL-Datentyp, Präzisionsberechnungen
DECLARE, Syntax der DECLARE-Anweisung
DECODE(), Verschlüsselungs- und Kompressionsfunktionen
decode_bits (myisamchk-Variable), Allgemeine Optionen für myisamchk
DEFAULT
Constraint, Constraints auf ungültigen Daten
DEFAULT (Wertklausel), Vorgabewerte von Datentypen, CREATE TABLE
DEFAULT(), Verschiedene Funktionen
default-character-set
Optionen für mysql, mysql Optionen
DEGREES(), Mathematische Funktionen
Deinstallation von Plug-Ins, UNINSTALL PLUGIN
DELAYED, INSERT DELAYED
delayed_insert_limit, INSERT DELAYED
DELETE, DELETE
Delphi, MyODBC mit Delphi verwenden
DESC, DESCRIBE (Informationen über Spalten abrufen)
DESCRIBE, Informationen über Datenbanken und Tabellen, DESCRIBE (Informationen über Spalten abrufen)
Design
Auswahlmöglichkeiten, Überlegungen zum Datenbankdesign
Einschränkungen, MySQL: konzeptionelle Einschränkungen
DES_DECRYPT(), Verschlüsselungs- und Kompressionsfunktionen
DES_ENCRYPT(), Verschlüsselungs- und Kompressionsfunktionen
developers
list of, Danksagungen
Dezimal-Arithmetik, Präzisionsberechnungen
Dezimalpunkt, Datentypen
Dezimalstellen
Arithmetik, Präzisionsberechnungen
Difference(), Raumbezogene Operatoren
Dimension(), Allgemeine Geometriefunktionen
DISCARD TABLESPACE, ALTER TABLE, Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)
Disjoint(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
Distance(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
DISTINCT, Bestimmte Spalten auswählen, Optimierung von DISTINCT, Funktionen zur Benutzung in GROUP BY-Klauseln, SELECT
DISTINCTROW, SELECT
DIV, Arithmetische Operationen
Division (/), Arithmetische Operationen
DNS, Wie MySQL DNS benutzt
DO, DO
DocBook XML
Quellformat für Dokumentationen, Über dieses Handbuch
Documenters
list of, Redakteure und Übersetzer
Doppeltes Anführungszeichen (\"), Strings
DOUBLE (Datentyp), Überblick über numerische Datentypen
DOUBLE PRECISION (Datentyp), Überblick über numerische Datentypen
Downgrade, Downgrade von MySQL
DROP DATABASE, DROP DATABASE
DROP FOREIGN KEY, ALTER TABLE, Fremdschlüssel-Beschränkungen
DROP FUNCTION, DROP PROCEDURE und DROP FUNCTION, DROP FUNCTION
DROP INDEX, ALTER TABLE, DROP INDEX
DROP PREPARE, SQL-Syntax für vorbereitete Anweisungen
DROP PRIMARY KEY, ALTER TABLE
DROP PROCEDURE, DROP PROCEDURE und DROP FUNCTION
DROP SCHEMA, DROP DATABASE
DROP TABLE, DROP TABLE
DROP TRIGGER, DROP TRIGGER
DROP USER, DROP USER
DROP VIEW, DROP VIEW
DUAL, SELECT
DUMPFILE, SELECT
dynamische Tabellen, Merkmale, Kennzeichen dynamischer Tabellen

E

E-Mail-Listen, Die MySQL-Mailinglisten
Eckige Klammern, Datentypen
Eiffel-Wrapper, MySQL-Eiffel-Wrapper
Eindeutige ID, Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?
Einfaches Anführungszeichen (\'), Strings
Einfügen
Geschwindigkeit, Geschwindigkeit von INSERT-Anweisungen
Einfügeoperation
nebenläufige, Wie MySQL Tabellen sperrt, Gleichzeitige Einfügevorgänge
Eingabeaufforderungen
Bedeutungen, Anfragen eingeben
Eingeben
Abfragen, Anfragen eingeben
Einsatzzwecke
MySQL, Wofür benutzen wir MySQL?
Einschränkungen
Design, MySQL: konzeptionelle Einschränkungen
Replikation, Replikation: Features und bekannte Probleme
Einschätzen
Leistungsfähigkeit von Abfragen, Anfragenperformance abschätzen
Einstellen
Passwörter, Kennwörter einrichten
Einstellen von Passwörtern, SET PASSWORD
Einstellen von Programmvariablen, Verwendung von Optionen zum Setzen von Programmvariablen
ELT(), String-Funktionen
ENCODE(), Verschlüsselungs- und Kompressionsfunktionen
ENCRYPT(), Verschlüsselungs- und Kompressionsfunktionen
END, BEGIN ... END-Syntax für komplexe Anweisungen
EndPoint(), LineString-Funktionen
ENGINES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA ENGINES
Entladen
Tabellen, Informationen aus einer Tabelle abfragen
Entwicklungs-Source-Tree, Installation vom Entwicklungs-Source-Tree
Entwurf
Probleme, Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL
ENUM
Größe, Speicherbedarf von Spaltentypen
ENUM (Datentyp), Überblick über String-Typen, Der Spaltentyp ENUM
Envelope(), Allgemeine Geometriefunktionen
Environment variable
CC, Umgebungsvariablen
CFLAGS, Umgebungsvariablen
CXX, Umgebungsvariablen
CXXFLAGS, Umgebungsvariablen
DBI_TRACE, mysqld unter gdb debuggen, Umgebungsvariablen
DBI_USER, Umgebungsvariablen
HOME, Umgebungsvariablen
LD_RUN_PATH, Umgebungsvariablen
MYSQL_DEBUG, Einen MySQL-Client debuggen, Umgebungsvariablen
MYSQL_HISTFILE, Umgebungsvariablen
MYSQL_HOST, Umgebungsvariablen
MYSQL_PS1, Umgebungsvariablen
MYSQL_PWD, Umgebungsvariablen
MYSQL_TCP_PORT, Umgebungsvariablen
MYSQL_UNIX_PORT, Umgebungsvariablen
PATH, Umgebungsvariablen
TMPDIR, Umgebungsvariablen
TZ, Umgebungsvariablen
UMASK, Umgebungsvariablen
UMASK_DIR, Umgebungsvariablen
USER, Umgebungsvariablen
environment variables
list of, Umgebungsvariablen
Equals(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
ERROR_FOR_DIVISION_BY_ZERO (SQL-Modus), Der SQL-Modus des Servers
Erstellen
Bugreports, Wie man Bugs oder Probleme meldet
Datenbanken, Eine Datenbank erzeugen und benutzen, CREATE DATABASE
Funktion, CREATE FUNCTION/DROP FUNCTION
Schema, CREATE DATABASE
Standardstartoptionen, my.cnf-Optionsdateien
Tabellen, Eine Tabelle erzeugen
Erstellen von Benutzerkonten, CREATE USER
Erweiterungen
gegenüber Standard-SQL, Wie kompatibel zum SQL-Standard ist MySQL?
Escape-Zeichen, Literale: wie Strings und Zahlen geschrieben werden
Escape-Zeichen (\\), Strings
EVENTS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA EVENTS
example
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
EXAMPLE-Speicher-Engine, Speicher-Engines und Tabellentypen, Die EXAMPLE-Speicher-Engine
EXAMPLE-Tabellentyp, Speicher-Engines und Tabellentypen, Die EXAMPLE-Speicher-Engine
execute
Optionen für mysql, mysql Optionen
EXECUTE, SQL-Syntax für vorbereitete Anweisungen
EXECUTE (Anweisung), SQL-Syntax für vorbereitete Anweisungen
EXP(), Mathematische Funktionen
EXPLAIN, EXPLAIN-Syntax (Informationen über ein SELECT erhalten)
EXPLAIN für partitionierte Tabellen, Abruf von Informationen über Partitionen
EXPLAIN PARTITIONS, Abruf von Informationen über Partitionen
Explizite Vorgabewerte, Vorgabewerte von Datentypen
EXPORT_SET(), String-Funktionen
ExteriorRing(), Polygon-Funktionen
Externe Sperrung, Befehlsoptionen für mysqld, Server-Systemvariablen, Benutzung von myisamchk für die Fehlerbeseitigung nach Abstürzen, SHOW PROCESSLIST
EXTRACT(), Datums- und Zeitfunktionen
ExtractValue(), XML-Funktionen
Extrahieren
Datumsangaben, Datumsberechnungen

F

FALSE, Zahlen, Boolesche Werte
testen auf, Vergleichsoperatoren
Fatal Signal 11, Probleme beim Kompilieren?
Features von MySQL, Die wichtigsten Features von MySQL
FEDERATED-Speicher-Engine, Speicher-Engines und Tabellentypen, Die FEDERATED-Speicher-Engine
FEDERATED-Tabellentyp, Speicher-Engines und Tabellentypen, Die FEDERATED-Speicher-Engine
Fehler
Access denied, Access denied-Fehler
bekannte, Bekannte Fehler und konzeptionelle Unzulänglichkeiten in MySQL
handling for UDFs, Rückgabewerte und Fehlerbehandlung
häufige, Probleme und häufig auftretende Fehler
Liste von Fehlern, Einige häufige Fehler bei der Benutzung von MySQL
melden, Allgemeine Informationen über MySQL, Wie man Bugs oder Probleme meldet
Tabellen prüfen auf, Wie Tabellen auf Fehler überprüft werden
Verlinken, Probleme beim Linken mit der MySQL-Clientbibliothek
Verzeichnisprüfsumme, Anmerkungen zu Solaris
Fehlermeldungen
can't find file, Probleme mit Dateirechten
Sprachen, Nicht englische Fehlermeldungen
Fehlersuche
FreeBSD, Probleme beim Kompilieren?
Solaris, Probleme beim Kompilieren?
Feld
ändern, ALTER TABLE
Festkommaarithmetik, Präzisionsberechnungen
Festplatte voll, Wie MySQL mit vollen Festplatten umgeht
Festplatten
Verteilen von Daten auf mehrere, Daten unter Windows auf verschiedene Platten aufteilen
Festplattenprobleme, Festplatte, Anmerkungen
FETCH, Das Cursor-Statement FETCH
FIELD(), String-Funktionen
FILE, String-Funktionen
filesort optimieren, ORDER BY-Optimierung
FIND_IN_SET(), String-Funktionen
FIXED (Datentyp), Überblick über numerische Datentypen
Fließkommazahl, Überblick über numerische Datentypen
Fließkommazahlen, Zahlen
FLOAT (Datentyp), Überblick über numerische Datentypen
FLOOR(), Mathematische Funktionen
FLUSH, FLUSH
flush tables, mysqladmin — Client für die Verwaltung eines MySQL Servers
Folgen, Verwendung von AUTO_INCREMENT
FOR UPDATE, SELECT
force
Optionen für mysql, mysql Optionen
FORCE INDEX, SELECT, JOIN, Probleme im Zusammenhang mit dem Optimierer
FORCE KEY, SELECT, JOIN
FORMAT(), String-Funktionen
Forums, MySQL-Community-Support in den MySQL-Foren
FOUND_ROWS(), Informationsfunktionen
Fragen
beantworten, Richtlinien für die Benutzung der MySQL-Mailinglisten
FreeBSD – Fehlersuche, Probleme beim Kompilieren?
Fremdschlüssel, Fremdschlüssel, ALTER TABLE
Constraint, PRIMARY KEY- und UNIQUE-Index-Constraints
löschen, ALTER TABLE, Fremdschlüssel-Beschränkungen
FremdSchlüssel, Wie Fremdschlüssel verwendet werden
FROM, SELECT
FROM_DAYS(), Datums- und Zeitfunktionen
FROM_UNIXTIME(), Datums- und Zeitfunktionen
ft_max_word_len (myisamchk-Variable), Allgemeine Optionen für myisamchk
ft_min_word_len (myisamchk-Variable), Allgemeine Optionen für myisamchk
ft_stopword_file (myisamchk-Variable), Allgemeine Optionen für myisamchk
FULLTEXT, MySQL-Volltextsuche
Funktion
erstellen, CREATE FUNCTION/DROP FUNCTION
löschen, DROP FUNCTION
Funktionen, Funktionen für die Benutzung in SELECT- und WHERE-Klauseln
Ablaufsteuerung, Ablaufsteuerungsfunktionen
arithmetische, Bitfunktionen
benutzerdefinierte, Hinzufügen neuer Funktionen zu MySQL, CREATE FUNCTION/DROP FUNCTION, DROP FUNCTION
hinzufügen, Hinzufügen einer neuen benutzerdefinierten Funktion
Bitfunktionen, Bitfunktionen
C-API, C-API: Funktionsüberblick
C-API für vorbereitete Anweisungen, C-API Prepared Statements: Funktionsüberblick
Datum und Uhrzeit, Datums- und Zeitfunktionen
GROUP BY, Funktionen zur Benutzung in GROUP BY-Klauseln
gruppieren, Rangfolge von Operatoren
Informationsfunktionen, Informationsfunktionen
mathematische, Mathematische Funktionen
native
hinzufügen, Hinzufügen einer neuen nativen Funktion
neue, Hinzufügen neuer Funktionen zu MySQL
sonstige, Verschiedene Funktionen
String-Funktionen, String-Funktionen
String-Vergleichsfunktionen, String-Vergleichsfunktionen
Umwandlung, Cast-Funktionen und Operatoren
Verschlüsselungsfunktionen, Verschlüsselungs- und Kompressionsfunktionen
Funktionen für SELECT- und WHERE-Klauseln, Funktionen für die Benutzung in SELECT- und WHERE-Klauseln

G

gcc, Typische configure-Optionen
gdb
using, mysqld unter gdb debuggen
Genaue Literale, Präzisionsberechnungen
Genauigkeit
Arithmetik, Präzisionsberechnungen
General Public License, Was ist MySQL?
Geographisches Feature, Einführung in die raumbezogenen Funktionen von MySQL
GeomCollFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
GeomCollFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
Geometrie, Einführung in die raumbezogenen Funktionen von MySQL
GEOMETRY-Datentyp, Raumbezogene Datentypen in MySQL
GeometryCollection(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
GEOMETRYCOLLECTION-Datentyp, Raumbezogene Datentypen in MySQL
GeometryCollectionFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
GeometryCollectionFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
GeometryFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
GeometryFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
GeometryN(), GeometryCollection-Funktionen
GeometryType(), Allgemeine Geometriefunktionen
GeomFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen, Umwandlungsfunktionen für das Geometrieformat
GeomFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen, Umwandlungsfunktionen für das Geometrieformat
Geospatiales Feature, Einführung in die raumbezogenen Funktionen von MySQL
Geschichte von MySQL, Geschichte von MySQL
Geschwindigkeit
Einfügen, Geschwindigkeit von INSERT-Anweisungen
erhöhen durch Replikation, Replikation bei MySQL
Kompilieren, Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
Verknüpfen, Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
von Abfragen, SELECT-Anweisungen und andere Anfragen optimieren, Geschwindigkeit von SELECT-Anweisungen
Gespeicherte Prozeduren, Gespeicherte Prozeduren und Funktionen
Gespeicherte Prozeduren und Trigger
Definition, Gespeicherte Prozeduren und Trigger
GET_FORMAT(), Datums- und Zeitfunktionen
GET_LOCK(), Verschiedene Funktionen
Gewähren
Berechtigungen, GRANT und REVOKE
GIS, Raumbezogene Erweiterungen in MySQL, Einführung in die raumbezogenen Funktionen von MySQL
Gleich (=), Vergleichsoperatoren
GLength(), LineString-Funktionen, MultiLineString-Funktionen
Globale Berechtigungen, GRANT und REVOKE, REVOKE
GPL
General Public License, GNU General Public License
GNU General Public License, GNU General Public License
MySQL FLOSS License Exception, MySQL FLOSS License Exception
GRANT, GRANT und REVOKE
GRANT (Anweisung), Hinzufügen neuer MySQL-Benutzer
Grant-Tabellen, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
neu erstellen, Probleme mit mysql_install_db
sortieren, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
GRANTS, SHOW GRANTS
GREATEST(), Vergleichsoperatoren
GROUP BY, GROUP BY-Optimierung
Aliase in, GROUP BY mit versteckten Feldern
Erweiterungen gegenüber Standard-SQL, GROUP BY mit versteckten Feldern, SELECT
GROUP BY-Funktionen, Funktionen zur Benutzung in GROUP BY-Klauseln
GROUP_CONCAT(), Funktionen zur Benutzung in GROUP BY-Klauseln
Groß- und Kleinschreibung
Suchoperationen, Groß-/Kleinschreibung beim Suchen
Groß-/Kleinschreibung
bei der Zugriffssteuerung, Wie das Berechtigungssystem funktioniert
Datenbanknamen, MySQL-Erweiterungen zu ANSI SQL92
Tabellennamen, MySQL-Erweiterungen zu ANSI SQL92
Gruppierung
Ausdrücke, Rangfolge von Operatoren
Größe
Anzeige, Datentypen
Größer als (>), Vergleichsoperatoren
Größer oder gleich (>=), Vergleichsoperatoren
Gültige Zahlen
Beispiele, Zahlen

H

Handbuch
Onlineposition, Über dieses Handbuch
typografische Konventionen, Konventionen in diesem Handbuch
verfügbare Formate, Über dieses Handbuch
HANDLER, HANDLER
Handler, DECLARE-Handler
Hash-Partitionen, aufspalten und zusammenführen, Verwaltung von HASH- und KEY-Partitionen
Hash-Partitionen, verwalten, Verwaltung von HASH- und KEY-Partitionen
Hash-Partitionierung, HASH-Partitionierung
Haupt-Features von MySQL, Die wichtigsten Features von MySQL
HAVING, SELECT
HEAP-Speicher-Engine, Speicher-Engines und Tabellentypen, Die MEMORY-Speicher-Engine
HEAP-Tabellentyp, Speicher-Engines und Tabellentypen, Die MEMORY-Speicher-Engine
help
Optionen für mysql, mysql Optionen
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
Optionen für perror, perror — Erklärung der Fehlercodes
Herunterfahren
Server, Schritte nach der Installation unter Unix
Herunterladen, Woher man MySQL bekommt
HEX(), String-Funktionen
Hexadezimalwerte, Hexadezimale Werte
HIGH_NOT_PRECEDENCE (SQL-Modus), Der SQL-Modus des Servers
HIGH_PRIORITY, SELECT
Hilfsprogramme, Überblick über Client- und Hilfsprogramme
Hinweise, MySQL-Erweiterungen zu ANSI SQL92, SELECT, JOIN
Indexhinweise, SELECT, JOIN
Hinzufügen
benutzerdefinierte Funktionen, Hinzufügen einer neuen benutzerdefinierten Funktion
native Funktionen, Hinzufügen einer neuen nativen Funktion
neue Benutzer, Installation von MySQL auf anderen Unix-ähnlichen Systemen, Schnellinstallation, Überblick
neue Benutzerberechtigungen, Hinzufügen neuer MySQL-Benutzer
neue Funktionen, Hinzufügen neuer Funktionen zu MySQL
neue Kontenberechtigungen, Hinzufügen neuer MySQL-Benutzer
Prozeduren, Hinzufügen neuer Prozeduren zu MySQL
Zeichensätze, Einen neuen Zeichensatz hinzufügen
HOME (Umgebungsvariable), mysql Optionen
HOME environment variable, Umgebungsvariablen
host
Optionen für mysql, mysql Optionen
host (Tabelle), Zugriffskontrolle, Phase 2: Anfrageüberprüfung
sortieren, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
host.frm
Probleme beim Finden von, Schritte nach der Installation unter Unix
Hostname
vorgabeseitiger, Verbinden mit dem MySQL-Server
Hostnamen-Caching, Wie MySQL DNS benutzt
HOUR(), Datums- und Zeitfunktionen
html
Optionen für mysql, mysql Optionen

I

ID
Eindeutige, Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?
IF, IF-Anweisung
IF(), Ablaufsteuerungsfunktionen
IFNULL(), Ablaufsteuerungsfunktionen
IGNORE INDEX, SELECT, JOIN
IGNORE KEY, SELECT, JOIN
ignore-space
Optionen für mysql, mysql Optionen
IGNORE_SPACE (SQL-Modus), Der SQL-Modus des Servers
Implizite Vorgabewerte, Vorgabewerte von Datentypen
IMPORT TABLESPACE, ALTER TABLE, Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)
IN, Vergleichsoperatoren
Index
löschen, ALTER TABLE, DROP INDEX
Indexhinweise, SELECT, JOIN
Indizes, CREATE INDEX
Blockgröße, Server-Systemvariablen
linkes Präfix, Wie MySQL Indizes benutzt
mehrspaltige, Mehrspaltige Indizes
mehrteilige, CREATE INDEX
Namen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
Spalten, Spaltenindizes
und BLOB-Spalten, Spaltenindizes, CREATE TABLE
und IS NULL, Wie MySQL Indizes benutzt
und LIKE, Wie MySQL Indizes benutzt
und NULL-Werte, CREATE TABLE
und TEXT-Spalten, Spaltenindizes, CREATE TABLE
verwenden, Wie MySQL Indizes benutzt
Zuweisen an Schlüssel-Cache, CACHE INDEX
INET_ATON(), Verschiedene Funktionen
INET_NTOA(), Verschiedene Funktionen
Informationen über Partitionen, erlangen, Abruf von Informationen über Partitionen
Informationsfunktionen, Informationsfunktionen
INFORMATION_SCHEMA, Die Datenbank INFORMATION_SCHEMA
INNER JOIN, JOIN
InnoDB, Überblick über InnoDB-Tabellen
Solaris 10 x86_64, Probleme, Anmerkungen zu Solaris
InnoDB-Speicher-Engine, Speicher-Engines und Tabellentypen, InnoDB-Tabellen
InnoDB-Tabellen, Transaktionen
InnoDB-Tabellentyp, Speicher-Engines und Tabellentypen, InnoDB-Tabellen
INSERT, Geschwindigkeit von INSERT-Anweisungen, INSERT
INSERT (Anweisung)
Berechtigungen, Hinzufügen neuer MySQL-Benutzer
INSERT ... SELECT, INSERT ... SELECT
INSERT DELAYED, INSERT DELAYED
INSERT(), String-Funktionen
INSTALL PLUGIN, INSTALL PLUGIN
Installation
Binärdistribution, Installation von MySQL auf anderen Unix-ähnlichen Systemen
Mac OS X PKG-Pakete, Installation von MySQL unter Mac OS X
Quelldistribution, Installation der Quelldistribution
Installation von Plug-Ins, INSTALL PLUGIN
Installationsabschluss
Konfiguration und Tests, Einstellungen und Tests nach der Installation
mehrere Server, Mehrere MySQL-Server auf derselben Maschine laufen lassen
Installationsstrukturen, Installationslayouts
Installationsübersicht, Installation der Quelldistribution
Installieren
benutzerdefinierte Funktionen, Kompilieren und Installieren benutzerdefinierter Funktionen
Linux-RPM-Pakete, MySQL unter Linux installieren
Perl, Anmerkungen zur Perl-Installation
Perl unter Windows, Installation von ActiveState-Perl unter Windows
Übersicht, Installation von MySQL
INSTR(), String-Funktionen
INT (Datentyp), Überblick über numerische Datentypen
INTEGER (Datentyp), Überblick über numerische Datentypen
Integer-Arithmetik, Präzisionsberechnungen
Integer-Zahlen, Zahlen
InteriorRingN(), Polygon-Funktionen
Interna, Hinzufügen neuer Funktionen zu MySQL
Interne Compiler-Fehler, Probleme beim Kompilieren?
Interne Sperrung, Wie MySQL Tabellen sperrt
Internet Relay Chat, Unterstützung für die MySQL-Community auf Internet Relay Chat (IRC)
Intersection(), Raumbezogene Operatoren
Intersects(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
INTERVAL(), Vergleichsoperatoren
IRC, Unterstützung für die MySQL-Community auf Internet Relay Chat (IRC)
IS boolean_value, Vergleichsoperatoren
IS NOT boolean_value, Vergleichsoperatoren
IS NOT NULL, Vergleichsoperatoren
IS NULL, IS NULL-Optimierung, Vergleichsoperatoren
Indizes, Wie MySQL Indizes benutzt
ISAM-Speicher-Engine, Speicher-Engines und Tabellentypen
ISAM-Tabellentyp, Speicher-Engines und Tabellentypen
IsClosed(), MultiLineString-Funktionen
IsEmpty(), Allgemeine Geometriefunktionen
ISNULL(), Vergleichsoperatoren
ISOLATION LEVEL, SET TRANSACTION
IsRing(), LineString-Funktionen
IsSimple(), Allgemeine Geometriefunktionen
IS_FREE_LOCK(), Verschiedene Funktionen
IS_USED_LOCK(), Verschiedene Funktionen
ITERATE, ITERATE-Anweisung

J

Jahr-2000-Konformität, Jahr-2000-Konformität
Jahr-2000-Probleme, Jahr-2000-Probleme und Datumstypen
JOIN, JOIN
Jokerzeichen
in der Tabelle mysql.columns_priv, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
in der Tabelle mysql.db, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
in der Tabelle mysql.host, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
in der Tabelle mysql.procs_priv, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
in der Tabelle mysql.tables_priv, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
in der Tabelle mysql.user, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
und LIKE, Wie MySQL Indizes benutzt
Jokerzeichen (%), Strings
Jokerzeichen (_), Strings

K

Kalender, Welchen Kalender benutzt MySQL?
Keine übereinstimmenden Zeilen, Lösung von Problemen mit nicht übereinstimmenden Zeilen
key_buffer_size (myisamchk-Variable), Allgemeine Optionen für myisamchk
KEY_COLUMN_USAGE
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA KEY_COLUMN_USAGE
KILL, KILL
Klammern
eckige, Datentypen
Klammern ( und ), Rangfolge von Operatoren
Kleiner als (<), Vergleichsoperatoren
Kleiner oder gleich (<=), Vergleichsoperatoren
Kommaseparierte Wertedaten, lesen, LOAD DATA INFILE, SELECT
Kommentare
hinzufügen, Kommentar
Startkommentare, '--' als Beginn eines Kommentars
Kommentarsyntax, Kommentar
Kompatibilität
mit mSQL, String-Vergleichsfunktionen
mit ODBC, Qualifikatoren für Bezeichner, Überblick über numerische Datentypen, Typumwandlung bei der Auswertung von Ausdrücken, Vergleichsoperatoren, CREATE TABLE, JOIN
mit Oracle, MySQL-Erweiterungen zu ANSI SQL92, Funktionen zur Benutzung in GROUP BY-Klauseln, DESCRIBE (Informationen über Spalten abrufen)
mit PostgreSQL, MySQL-Erweiterungen zu ANSI SQL92
mit Standard-SQL, Wie kompatibel zum SQL-Standard ist MySQL?
Sybase, USE
zwischen MySQL-Versionen, Upgrade von MySQL 5.0
Kompilieren
benutzerdefinierte Funktionen, Kompilieren und Installieren benutzerdefinierter Funktionen
Geschwindigkeit, Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
optimieren, System/Kompilierzeitpunkt und Tuning der Startparameter
Probleme, Probleme beim Kompilieren?
statisch, Typische configure-Optionen
unter Windows, MySQL-Clients auf Windows kompilieren
komprimierte Tabellen, Kennzeichen komprimierter Tabellen
Konfiguration
nach Installationsabschluss, Einstellungen und Tests nach der Installation
Konfigurationsdateien, Gründe für Access denied-Fehler
Konfigurationsoptionen, Typische configure-Optionen
--with-charset, Typische configure-Optionen
--with-collation, Typische configure-Optionen
--with-extra-charsets, Typische configure-Optionen
--with-low-memory, Probleme beim Kompilieren?
Konformität
Jahr 2000, Jahr-2000-Konformität
Konstantentabelle, EXPLAIN-Syntax (Informationen über ein SELECT erhalten), Optimierungen der WHERE-Klausel
Konten
anonymer Benutzer, Einrichtung der anfänglichen MySQL-Berechtigungen
root, Einrichtung der anfänglichen MySQL-Berechtigungen
Kontenberechtigungen
hinzufügen, Hinzufügen neuer MySQL-Benutzer
Konventionen
typografische, Konventionen in diesem Handbuch
Kopieren von Datenbanken, Upgrade auf eine andere Architektur
Kopieren von Tabellen, CREATE TABLE
Kunden
MySQL, Wofür benutzen wir MySQL?

L

Laden
Tabellen, Daten in Tabellen einladen
LAST_DAY(), Datums- und Zeitfunktionen
LAST_INSERT_ID(), Transaktionen, INSERT
LAST_INSERT_ID([expr]), Informationsfunktionen
LCASE(), String-Funktionen
LD_LIBRARY_PATH (Umgebungsvariable), Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
LD_RUN_PATH (Umgebungsvariable), Anmerkungen zur Linux-Quelldistribution, Anmerkungen zu Solaris, Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
LD_RUN_PATH environment variable, Umgebungsvariablen
LEAST(), Vergleichsoperatoren
LEAVE, LEAVE-Anweisung
Leeren
Caches, FLUSH
LEFT JOIN, Optimierung von LEFT JOIN und RIGHT JOIN, JOIN
LEFT OUTER JOIN, JOIN
LEFT(), String-Funktionen
Leistung
Benchmarks, Wie Sie Ihre eigenen Benchmarks benutzen
einschätzen, Anfragenperformance abschätzen
Festplattenprobleme, Festplatte, Anmerkungen
verbessern, Replikation: häufig gestellte Fragen, Wie Sie Ihre Daten so klein wie möglich bekommen
LENGTH(), String-Funktionen
Letzte Zeile
Eindeutige ID, Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?
libmysqld, libmysqld, die eingebettete MySQL Server-Bibliothek
Optionen, Optionen des eingebetteten Servers
libraries
list of, Von MySQL benutzte und mit MySQL ausgelieferte Bibliotheken
License, MySQL FLOSS License Exception
LIKE, String-Vergleichsfunktionen
und Indizes, Wie MySQL Indizes benutzt
und Jokerzeichen, Wie MySQL Indizes benutzt
LIMIT, LIMIT-Optimierung, Informationsfunktionen, SELECT
limitations
MySQL Limitations, Beschränkungen in MySQL
limits
MySQL Limits, limits in MySQL, Beschränkungen in MySQL
lineare Hash-Partitionierung, LINEAR HASH-Partitionierung
lineare Schlüsselpartitionierung, KEY-Partitionierung
LineFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
LineFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
LineString(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
LINESTRING-Datentyp, Raumbezogene Datentypen in MySQL
LineStringFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
LineStringFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
Linkes Präfix bei Indizes, Wie MySQL Indizes benutzt
Linking
Probleme, Probleme beim Linken mit der C-API
Linux
Binärdistribution, Anmerkungen zur Binärdistribution (Linux)
Quelldistribution, Anmerkungen zur Linux-Quelldistribution
Listenpartitionen, hinzufügen und löschen, Verwaltung von RANGE- und LIST-Partitionen
Listenpartitionen, verwalten, Verwaltung von RANGE- und LIST-Partitionen
Listenpartitionierung, LIST-Partitionierung
Literale, Literale: wie Strings und Zahlen geschrieben werden
LN(), Mathematische Funktionen
LOAD DATA FROM MASTER, LOAD DATA FROM MASTER
LOAD DATA INFILE, LOAD DATA INFILE, Probleme mit NULL-Werten
LOAD TABLE FROM MASTER, LOAD TABLE tbl_name FROM MASTER
LOAD_FILE(), String-Funktionen
local-infile
Optionen für mysql, mysql Optionen
LOCALTIME, Datums- und Zeitfunktionen
LOCALTIMESTAMP, Datums- und Zeitfunktionen
LOCATE(), String-Funktionen
LOCK IN SHARE MODE, SELECT
LOCK TABLES, LOCK TABLES und UNLOCK TABLES
log
changes, MySQL-Änderungsverlauf (Change History)
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
Log für langsame Abfragen, Die Logdatei für langsame Anfragen
LOG(), Mathematische Funktionen
LOG10(), Mathematische Funktionen
LOG2(), Mathematische Funktionen
Logdateien, Typische configure-Optionen, Die MySQL-Logdateien
Namen, Datenbank-Datensicherungen
warten, Wartung und Pflege der Logdateien
Logische Operatoren, Logische Operatoren
LONG (Datentyp), Die Spaltentypen BLOB und TEXT
LONGBLOB (Datentyp), Überblick über String-Typen
LONGTEXT (Datentyp), Überblick über String-Typen
LOOP, LOOP-Anweisung
LOWER(), String-Funktionen
LPAD(), String-Funktionen
LTRIM(), String-Funktionen
Löschen
Benutzer, Entfernen von Benutzerkonten in MySQL, DROP USER
Datenbank, DROP DATABASE
Fremdschlüssel, ALTER TABLE
Funktion, DROP FUNCTION
Index, ALTER TABLE, DROP INDEX
mysql.sock, Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern
Primärschlüssel, ALTER TABLE
Schema, DROP DATABASE
Tabelle, DROP TABLE
Zeilen, Zeilen aus verwandten Tabellen löschen
löschen
Fremdschlüssel, Fremdschlüssel-Beschränkungen

M

Mac OS X, MySQL Connector/ODBC
Installation, Installation von MySQL unter Mac OS X
Mailinglisten, Die MySQL-Mailinglisten
Archivposition, Die MySQL-Mailinglisten
Richtlinien, Richtlinien für die Benutzung der MySQL-Mailinglisten
MAKEDATE(), Datums- und Zeitfunktionen
MAKETIME(), Datums- und Zeitfunktionen
make_binary_distribution, Überblick über serverseitige Programme und Dienstprogramme
MAKE_SET(), String-Funktionen
Master/Slave-Konfiguration, Replikation: Implementation
MASTER_POS_WAIT(), Verschiedene Funktionen, MASTER_POS_WAIT()
MATCH ... AGAINST(), MySQL-Volltextsuche
Mathematik, Präzisionsberechnungen
Mathematische Funktionen, Mathematische Funktionen
MAX(), Funktionen zur Benutzung in GROUP BY-Klauseln
MAX(DISTINCT), Funktionen zur Benutzung in GROUP BY-Klauseln
MAXDB (SQL-Modus), Der SQL-Modus des Servers
maximum memory used, mysqladmin — Client für die Verwaltung eines MySQL Servers
maximums
maximum tables per join, Beschränkungen von Joins
max_allowed_packet (Variable), mysql Optionen
MAX_CONNECTIONS_PER_HOUR, Begrenzen von Benutzer-Ressourcen
max_join_size (Variable), mysql Optionen
MAX_QUERIES_PER_HOUR, Begrenzen von Benutzer-Ressourcen
MAX_UPDATES_PER_HOUR, Begrenzen von Benutzer-Ressourcen
MAX_USER_CONNECTIONS, Begrenzen von Benutzer-Ressourcen
MBR, Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBRContains(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBRDisjoint(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBREqual(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBRIntersects(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBROverlaps(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBRTouches(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MBRWithin(), Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
MD5(), Verschlüsselungs- und Kompressionsfunktionen
MEDIUMBLOB (Datentyp), Überblick über String-Typen
MEDIUMINT (Datentyp), Überblick über numerische Datentypen
MEDIUMTEXT (Datentyp), Überblick über String-Typen
Mehrere Server, Mehrere MySQL-Server auf derselben Maschine laufen lassen
Mehrspaltenindizes, Mehrspaltige Indizes
Mehrteiliger Index, CREATE INDEX
Melden
Bugs, Wie man Bugs oder Probleme meldet
Fehler, Allgemeine Informationen über MySQL, Wie man Bugs oder Probleme meldet
melden
Connector/ODBC-Probleme, MyODBC-Support
MyODBC-Probleme, MyODBC-Support
Meldungen
Sprachen, Nicht englische Fehlermeldungen
memory in use, mysqladmin — Client für die Verwaltung eines MySQL Servers
MEMORY-Speicher-Engine, Speicher-Engines und Tabellentypen, Die MEMORY-Speicher-Engine
MEMORY-Tabellentyp, Speicher-Engines und Tabellentypen, Die MEMORY-Speicher-Engine
MERGE-Speicher-Engine, Speicher-Engines und Tabellentypen, Die MERGE-Speicher-Engine
MERGE-Tabellen
Definition, Die MERGE-Speicher-Engine
MERGE-Tabellentyp, Speicher-Engines und Tabellentypen, Die MERGE-Speicher-Engine
Metadaten
Datenbank, Die Datenbank INFORMATION_SCHEMA
Methoden
Sperrmethoden, Wie MySQL Tabellen sperrt
MICROSECOND(), Datums- und Zeitfunktionen
Microsoft Access, Microsoft Access
Microsoft ADO, Microsoft ADO
Microsoft Excel, Microsoft Excel und Spaltentypen
Microsoft Visual Basic, Microsoft Visual Basic
Microsoft Visual InterDev, Microsoft Visual InterDev
MID(), String-Funktionen
MIN(), Funktionen zur Benutzung in GROUP BY-Klauseln
MIN(DISTINCT), Funktionen zur Benutzung in GROUP BY-Klauseln
Minimum Bounding Rectangle, Relationen auf geometrischen Minimal Bounding Rectangles (MBRs)
Minus
monadisches (-), Arithmetische Operationen
MINUTE(), Datums- und Zeitfunktionen
MIT-pthreads, Anmerkungen zu MIT-pthreads
MLineFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
MLineFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
MOD (Modulo), Mathematische Funktionen
MOD(), Mathematische Funktionen
Modi
Stapelbetrieb, mysql im Stapelbetrieb
Module
Liste der, Wie stabil ist MySQL?
Modulo (%), Mathematische Funktionen
Modulo (MOD), Mathematische Funktionen
Monadisches Minus (-), Arithmetische Operationen
Monitor
Terminalmonitor, Einführung in MySQL: ein MySQL-Tutorial
Mono, Connector/NET
MONTH(), Datums- und Zeitfunktionen
MONTHNAME(), Datums- und Zeitfunktionen
MPointFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
MPointFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
MPolyFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
MPolyFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
mSQL-Kompatibilität, String-Vergleichsfunktionen
MSSQL (SQL-Modus), Der SQL-Modus des Servers
Multibytezeichen, Unterstützung für Multi-Byte-Zeichen
Multibytezeichensätze, Can't initialize charset xxx-Fehler
MultiLineString(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
MULTILINESTRING-Datentyp, Raumbezogene Datentypen in MySQL
MultiLineStringFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
MultiLineStringFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
Multiplikation (*), Arithmetische Operationen
MultiPoint(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
MULTIPOINT-Datentyp, Raumbezogene Datentypen in MySQL
MultiPointFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
MultiPointFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
MultiPolygon(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
MULTIPOLYGON-Datentyp, Raumbezogene Datentypen in MySQL
MultiPolygonFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
MultiPolygonFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
Mustervergleich, Übereinstimmende Suchmuster
My
Ableitung, Geschichte von MySQL
MyISAM
Größe, Speicherbedarf von Spaltentypen
komprimierte Tabellen, Kennzeichen komprimierter Tabellen
MyISAM-Schlüssel-Cache, Der MyISAM-Schlüssel-Cache
MyISAM-Speicher-Engine, Speicher-Engines und Tabellentypen, Die MyISAM-Speicher-Engine
MyISAM-Tabellentyp, Speicher-Engines und Tabellentypen, Die MyISAM-Speicher-Engine
myisamchk, Typische configure-Optionen, Überblick über Client- und Hilfsprogramme
Beispielausgabe, Informationen über eine Tabelle erhalten
Optionen, Allgemeine Optionen für myisamchk
myisamlog, Überblick über Client- und Hilfsprogramme
myisampack, Überblick über Client- und Hilfsprogramme, Kennzeichen komprimierter Tabellen
myisam_block_size (myisamchk-Variable), Allgemeine Optionen für myisamchk
MyODBC, MySQL Connector/ODBC
Borland, MyODBC mit Borland-Anwendungen verwenden
Borland Database Engine, MyODBC mit Borland-Anwendungen verwenden
Probleme melden, MyODBC-Support
MySQL
Aussprache, Was ist MySQL?
defined, Was ist MySQL?
introduction, Was ist MySQL?
mysql, Überblick über Client- und Hilfsprogramme
MySQL AB
Definition, Was ist MySQL AB?
MySQL Cluster in MySQL 5.0 und 5.1, MySQL Cluster: Roadmap für die Entwicklung
MySQL Embedded Server-Bibliothek, libmysqld, die eingebettete MySQL Server-Bibliothek
MySQL erhalten, Woher man MySQL bekommt
MySQL Tabellentypen, Speicher-Engines und Tabellentypen
MySQL++, MySQL-C++-APIs
MySQL, Name, Geschichte von MySQL
MySQL, Name des Delphins, Geschichte von MySQL
mysql-Befehle
Auflistung, mysql-Befehle
mysql-Befehlszeilenoptionen, mysql Optionen
MySQL-Binärdistribution, Welche MySQL-Version Sie benutzen sollten, MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden
MYSQL-C-Typ, C-API: Datentypen
MySQL-C-Typ, C-API: Prepared Statement-Datentypen
mysql-Eingabeaufforderung, mysql-Befehle
MySQL-Geschichte, Geschichte von MySQL
MySQL-Mailinglisten, Die MySQL-Mailinglisten
MySQL-Quelldistribution, Welche MySQL-Version Sie benutzen sollten
MySQL-Speicher-Engines, Speicher-Engines und Tabellentypen
mysql-Statusbefehl, mysql-Befehle
mysql-Verlaufsdatei, mysql Optionen
MySQL-Version, Woher man MySQL bekommt
mysql.server, Überblick über serverseitige Programme und Dienstprogramme
mysql.sock
Position ändern, Typische configure-Optionen
Schutz, Wie Sie die MySQL-Socketdatei /tmp/mysql.sock schützen oder ändern
MYSQL323 (SQL-Modus), Der SQL-Modus des Servers
MYSQL40 (SQL-Modus), Der SQL-Modus des Servers
mysqlaccess, Überblick über Client- und Hilfsprogramme
mysqladmin, Überblick über Client- und Hilfsprogramme, CREATE DATABASE, DROP DATABASE, SHOW STATUS, SHOW VARIABLES, FLUSH, KILL
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
mysqladmin-Befehlszeilenoptionen, mysqladmin — Client für die Verwaltung eines MySQL Servers
mysqlbinlog, Überblick über Client- und Hilfsprogramme
mysqlbug (Skript), Wie man Bugs oder Probleme meldet
mysqlcheck, Überblick über Client- und Hilfsprogramme
mysqlclient-Bibliothek, APIs und Bibliotheken
mysqld, Überblick über serverseitige Programme und Dienstprogramme
Befehlsoptionen, Befehlsoptionen für mysqld
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
starten, Wie man MySQL als normaler Benutzer laufen läßt
mysqld (Optionen), Serverparameter feineinstellen
mysqld-Bibliothek, APIs und Bibliotheken
mysqld-max, Überblick über serverseitige Programme und Dienstprogramme, mysqld-max, ein erweiterter mysqld-Server
mysqld-Server
Puffergrößen, Serverparameter feineinstellen
mysqldump, Upgrade auf eine andere Architektur, Überblick über Client- und Hilfsprogramme
mysqld_multi, Überblick über serverseitige Programme und Dienstprogramme
mysqld_safe, Überblick über serverseitige Programme und Dienstprogramme
mysqlhotcopy, Überblick über Client- und Hilfsprogramme
mysqlimport, Upgrade auf eine andere Architektur, Überblick über Client- und Hilfsprogramme, LOAD DATA INFILE
mysqlmanager, Überblick über serverseitige Programme und Dienstprogramme
mysqlshow, Überblick über Client- und Hilfsprogramme
mysqlslap, Überblick über Client- und Hilfsprogramme
mysqltest
MySQL-Testreihe, MySQL-Testsystem
mysql_affected_rows(), mysql_affected_rows()
mysql_autocommit()., mysql_autocommit()
MYSQL_BIND-C-Typ, C-API: Prepared Statement-Datentypen
mysql_change_user(), mysql_change_user()
mysql_character_set_name(), mysql_character_set_name()
mysql_close(), mysql_close()
mysql_commit()., mysql_commit()
mysql_connect(), mysql_connect()
mysql_create_db(), mysql_create_db()
mysql_data_seek(), mysql_data_seek()
MYSQL_DEBUG (Umgebungsvariable), Überblick über Client- und Hilfsprogramme
MYSQL_DEBUG environment variable, Einen MySQL-Client debuggen, Umgebungsvariablen
mysql_debug(), mysql_debug()
mysql_drop_db(), mysql_drop_db()
mysql_dump_debug_info(), mysql_dump_debug_info()
mysql_eof(), mysql_eof()
mysql_errno(), mysql_errno()
mysql_error(), mysql_error()
mysql_escape_string(), mysql_escape_string()
mysql_fetch_field(), mysql_fetch_field()
mysql_fetch_fields(), mysql_fetch_fields()
mysql_fetch_field_direct(), mysql_fetch_field_direct()
mysql_fetch_lengths(), mysql_fetch_lengths()
mysql_fetch_row(), mysql_fetch_row()
MYSQL_FIELD-C-Typ, C-API: Datentypen
mysql_field_count(), mysql_field_count(), mysql_num_fields()
MYSQL_FIELD_OFFSET-C-Typ, C-API: Datentypen
mysql_field_seek(), mysql_field_seek()
mysql_field_tell(), mysql_field_tell()
mysql_fix_privilege_tables, Überblick über serverseitige Programme und Dienstprogramme, Gründe für Access denied-Fehler
mysql_free_result(), mysql_free_result()
mysql_get_character_set_info(), mysql_get_character_set_info()
mysql_get_client_info(), mysql_get_client_info()
mysql_get_client_version(), mysql_get_client_version()
mysql_get_host_info(), mysql_get_host_info()
mysql_get_proto_info(), mysql_get_proto_info()
mysql_get_server_info(), mysql_get_server_info()
mysql_get_server_version(), mysql_get_server_version()
mysql_hex_string(), mysql_hex_string()
MYSQL_HISTFILE (Umgebungsvariable), mysql Optionen
MYSQL_HISTFILE environment variable, Umgebungsvariablen
MYSQL_HOST (Umgebungsvariable), Verbinden mit dem MySQL-Server
MYSQL_HOST environment variable, Umgebungsvariablen
mysql_info(), ALTER TABLE, INSERT, LOAD DATA INFILE, UPDATE, mysql_info()
mysql_init(), mysql_init()
mysql_insert_id(), Transaktionen, INSERT, mysql_insert_id()
mysql_install_db, Überblick über serverseitige Programme und Dienstprogramme
mysql_install_db (Skript), Probleme mit mysql_install_db
mysql_kill(), mysql_kill()
mysql_library_end(), mysql_library_end()
mysql_library_init(), mysql_library_init()
mysql_list_dbs(), mysql_list_dbs()
mysql_list_fields(), mysql_list_fields()
mysql_list_processes(), mysql_list_processes()
mysql_list_tables(), mysql_list_tables()
mysql_more_results()., mysql_more_results()
mysql_next_result()., mysql_next_result()
mysql_num_fields(), mysql_num_fields()
mysql_num_rows(), mysql_num_rows()
mysql_options(), mysql_options()
mysql_ping(), mysql_ping()
MYSQL_PS1 environment variable, Umgebungsvariablen
MYSQL_PWD (Umgebungsvariable), Verbinden mit dem MySQL-Server, Überblick über Client- und Hilfsprogramme
MYSQL_PWD environment variable, Umgebungsvariablen
mysql_query(), mysql_query(), Häufige Fragen und Probleme bei der Benutzung der C-API
mysql_real_connect(), mysql_real_connect()
mysql_real_escape_string(), Strings, mysql_real_escape_string()
mysql_real_query(), mysql_real_query()
mysql_refresh(), mysql_refresh()
mysql_reload(), mysql_reload()
MYSQL_RES-C-Typ, C-API: Datentypen
mysql_rollback()., mysql_rollback()
MYSQL_ROW-C-Typ, C-API: Datentypen
mysql_row_seek(), mysql_row_seek()
mysql_row_tell(), mysql_row_tell()
mysql_select_db(), mysql_select_db()
mysql_server_end(), mysql_server_end()
mysql_server_init(), mysql_server_init()
mysql_set_character_set(), mysql_set_character_set()
mysql_set_server_option(), mysql_set_server_option()
mysql_shutdown(), mysql_shutdown()
mysql_sqlstate(), mysql_sqlstate()
mysql_ssl_set(), mysql_ssl_set()
mysql_stat(), mysql_stat()
MYSQL_STMT-C-Typ, C-API: Prepared Statement-Datentypen
mysql_stmt_affected_rows(), mysql_stmt_affected_rows()
mysql_stmt_attr_get(), mysql_stmt_attr_get()
mysql_stmt_attr_set(), mysql_stmt_attr_set()
mysql_stmt_bind_param(), mysql_stmt_bind_param()
mysql_stmt_bind_result(), mysql_stmt_bind_result()
mysql_stmt_close(), mysql_stmt_close()
mysql_stmt_data_seek(), mysql_stmt_data_seek()
mysql_stmt_errno(), mysql_stmt_errno()
mysql_stmt_error()., mysql_stmt_error()
mysql_stmt_execute(), mysql_stmt_execute()
mysql_stmt_fetch(), mysql_stmt_fetch()
mysql_stmt_fetch_column(), mysql_stmt_fetch_column()
mysql_stmt_field_count(), mysql_stmt_field_count()
mysql_stmt_free_result(), mysql_stmt_free_result()
mysql_stmt_init(), mysql_stmt_init()
mysql_stmt_insert_id(), mysql_stmt_insert_id()
mysql_stmt_num_rows(), mysql_stmt_num_rows()
mysql_stmt_param_count(), mysql_stmt_param_count()
mysql_stmt_param_metadata(), mysql_stmt_param_metadata()
mysql_stmt_prepare(), mysql_stmt_prepare()
mysql_stmt_reset(), mysql_stmt_reset()
mysql_stmt_result_metadata., mysql_stmt_result_metadata()
mysql_stmt_row_seek(), mysql_stmt_row_seek()
mysql_stmt_row_tell(), mysql_stmt_row_tell()
mysql_stmt_send_long_data()., mysql_stmt_send_long_data()
mysql_stmt_sqlstate(), mysql_stmt_sqlstate()
mysql_stmt_store_result(), mysql_stmt_store_result()
mysql_store_result(), mysql_store_result(), Häufige Fragen und Probleme bei der Benutzung der C-API
MYSQL_TCP_PORT (Umgebungsvariable), Mehrere MySQL-Server unter Unix laufen lassen, Verwendung von Client-Programmen in einer Mehrserverumgebung, Überblick über Client- und Hilfsprogramme
MYSQL_TCP_PORT environment variable, Umgebungsvariablen
mysql_thread_end(), mysql_thread_end()
mysql_thread_id(), mysql_thread_id()
mysql_thread_init(), mysql_thread_init()
mysql_thread_safe(), mysql_thread_safe()
MYSQL_UNIX_PORT (Umgebungsvariable), Probleme mit mysql_install_db, Mehrere MySQL-Server unter Unix laufen lassen, Verwendung von Client-Programmen in einer Mehrserverumgebung, Überblick über Client- und Hilfsprogramme
MYSQL_UNIX_PORT environment variable, Umgebungsvariablen
mysql_use_result(), mysql_use_result()
mysql_warning_count()., mysql_warning_count()
mysql_zap, Überblick über Client- und Hilfsprogramme
my_init(), my_init()
my_ulonglong-C-Typ, C-API: Datentypen
my_ulonglong-Werte
printing, C-API: Datentypen

N

Named Pipes, Auswahl des MySQL Server-Typs, Test der MySQL-Installation
named-commands
Optionen für mysql, mysql Optionen
Namen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
Unterscheidung der Groß-/Kleinschreibung, Groß-/Kleinschreibung in Namen
Variablen, Benutzerdefinierte Variablen
NAME_CONST(), Verschiedene Funktionen
NATIONAL CHAR (Datentyp), Überblick über String-Typen
native Funktionen
hinzufügen, Hinzufügen einer neuen nativen Funktion
Native Thread-Unterstützung, Betriebssysteme, die von MySQL unterstützt werden
NATURAL LEFT JOIN, JOIN
NATURAL LEFT OUTER JOIN, JOIN
NATURAL RIGHT JOIN, JOIN
NATURAL RIGHT OUTER JOIN, JOIN
NCHAR (Datentyp), Überblick über String-Typen
ndb
Optionen für perror, perror — Erklärung der Fehlercodes
Nebenläufige Einfügeoperationen, Wie MySQL Tabellen sperrt, Gleichzeitige Einfügevorgänge
Negative Werte, Zahlen
Netiquette, Richtlinien für die Benutzung der MySQL-Mailinglisten
NetWare, Installation von MySQL unter NetWare
Netzmaskennotation
in der Tabelle mysql.user, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
net_buffer_length (Variable), mysql Optionen
Neue Benutzer
hinzufügen, Installation von MySQL auf anderen Unix-ähnlichen Systemen, Schnellinstallation, Überblick
Neue Features in MySQL Cluster, MySQL Cluster: Roadmap für die Entwicklung
Neue Prozeduren
hinzufügen, Hinzufügen neuer Prozeduren zu MySQL
Neuerstellung
Grant-Tabellen, Probleme mit mysql_install_db
Neuordnen
Spalten, Wie man die Reihenfolge der Spalten in einer Tabelle ändert
Neustart
Server, Schritte nach der Installation unter Unix
Nichttransaktionssichere Tabellen, Rollback schlägt bei nichttransaktionssicheren Tabellen fehl
no-auto-rehash
Optionen für mysql, mysql Optionen
no-beep
Optionen für mysql, mysql Optionen
no-log
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
no-named-commands
Optionen für mysql, mysql Optionen
no-pager
Optionen für mysql, mysql Optionen
no-tee
Optionen für mysql, mysql Optionen
NOT
logisches, Logische Operatoren
NOT BETWEEN, Vergleichsoperatoren
NOT IN, Vergleichsoperatoren
NOT LIKE, String-Vergleichsfunktionen
NOT NULL
Constraint, Constraints auf ungültigen Daten
NOT REGEXP, String-Vergleichsfunktionen
Novell NetWare, Installation von MySQL unter NetWare
NOW(), Datums- und Zeitfunktionen
NO_AUTO_CREATE_USER (SQL-Modus), Der SQL-Modus des Servers
NO_AUTO_VALUE_ON_ZERO (SQL-Modus), Der SQL-Modus des Servers
NO_BACKSLASH_ESCAPES (SQL-Modus), Der SQL-Modus des Servers
NO_DIR_IN_CREATE (SQL-Modus), Der SQL-Modus des Servers
NO_FIELD_OPTIONS (SQL-Modus), Der SQL-Modus des Servers
NO_KEY_OPTIONS (SQL-Modus), Der SQL-Modus des Servers
NO_TABLE_OPTIONS (SQL-Modus), Der SQL-Modus des Servers
NO_UNSIGNED_SUBTRACTION (SQL-Modus), Der SQL-Modus des Servers
NO_ZERO_DATE (SQL-Modus), Der SQL-Modus des Servers
NO_ZERO_IN_DATE (SQL-Modus), Der SQL-Modus des Servers
NUL, Strings
NULL, Mit NULL-Werten arbeiten, Probleme mit NULL-Werten
ORDER BY, ORDER BY-Optimierung, SELECT
testen auf Null, Vergleichsoperatoren, Ablaufsteuerungsfunktionen
NULL-Wert, Mit NULL-Werten arbeiten, NULL-Werte
NULL-Werte
und AUTO_INCREMENT-Spalten, Probleme mit NULL-Werten
und Indizes, CREATE TABLE
und TIMESTAMP-Spalten, Probleme mit NULL-Werten
vs. leere Werte, Probleme mit NULL-Werten
NULLIF(), Ablaufsteuerungsfunktionen
NUMERIC (Datentyp), Überblick über numerische Datentypen
Numerische Typen, Speicherbedarf von Spaltentypen
NumGeometries(), GeometryCollection-Funktionen
NumInteriorRings(), Polygon-Funktionen
NumPoints(), LineString-Funktionen
Näherungsweise Literale, Präzisionsberechnungen

O

OCT(), String-Funktionen
OCTET_LENGTH(), String-Funktionen
ODBC, MySQL Connector/ODBC
ODBC-Kompatibilität, Qualifikatoren für Bezeichner, Überblick über numerische Datentypen, Typumwandlung bei der Auswertung von Ausdrücken, Vergleichsoperatoren, CREATE TABLE, JOIN
Offene Tabellen, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
OLAP, GROUP BY-Modifizierer
OLD_PASSWORD(), Verschlüsselungs- und Kompressionsfunktionen
ON DUPLICATE KEY, INSERT
one-database
Optionen für mysql, mysql Optionen
Onlineposition des Handbuchs, Über dieses Handbuch
ONLY_FULL_GROUP_BY
SQL-Modus, GROUP BY mit versteckten Feldern
ONLY_FULL_GROUP_BY (SQL-Modus), Der SQL-Modus des Servers
OPEN, Cursor-OPEN-Anweisung
Open Source
Definition, Was ist MySQL?
open tables, mysqladmin — Client für die Verwaltung eines MySQL Servers
OpenGIS, Einführung in die raumbezogenen Funktionen von MySQL
opens, mysqladmin — Client für die Verwaltung eines MySQL Servers
OpenSSL, Verwendung sicherer Verbindungen
open_files_limit (Variable), mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien
Operationen
arithmetische, Arithmetische Operationen
Operatoren, Funktionen für die Benutzung in SELECT- und WHERE-Klauseln
logische, Logische Operatoren
Rangordnung, Rangfolge von Operatoren
Umwandlung, Arithmetische Operationen, Cast-Funktionen und Operatoren
Optimieren
DISTINCT, Optimierung von DISTINCT
filesort, ORDER BY-Optimierung
GROUP BY, GROUP BY-Optimierung
LEFT JOIN, Optimierung von LEFT JOIN und RIGHT JOIN
LIMIT, LIMIT-Optimierung
Tabellen, Tabellenoptimierung
Optimierer
steuern, Leistung des Abfragenoptimierers steuern
Optimierung
Tipps, Weitere Optimierungstipps
Optimierungen, Optimierungen der WHERE-Klausel, Optimierung durch Indexverschmelzung
OPTIMIZE TABLE, OPTIMIZE TABLE
Optionen
Befehlszeilenoptionen
mysql, mysql Optionen
mysqladmin, mysqladmin — Client für die Verwaltung eines MySQL Servers
configure, Typische configure-Optionen
Embedded Server, Optionen des eingebetteten Servers
in MySQL, Einführung in MySQL: ein MySQL-Tutorial
libmysqld, Optionen des eingebetteten Servers
Replikation, Replikation: Features und bekannte Probleme
Optionsdateien, my.cnf-Optionsdateien, Gründe für Access denied-Fehler
OR, Über zwei Schlüssel suchen, Optimierung durch Indexverschmelzung
Bit-OR, Bitfunktionen
logisches, Logische Operatoren
OR-Indexverschmelzungsoptimierung, Optimierung durch Indexverschmelzung
ORACLE (SQL-Modus), Der SQL-Modus des Servers
Oracle-Kompatibilität, MySQL-Erweiterungen zu ANSI SQL92, Funktionen zur Benutzung in GROUP BY-Klauseln, DESCRIBE (Informationen über Spalten abrufen)
ORD(), String-Funktionen
ORDER BY, Zeilen sortieren, ALTER TABLE, SELECT
NULL, ORDER BY-Optimierung, SELECT
OUTFILE, SELECT
Overlaps(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen

P

packages
list of, Pakete, die MySQL unterstützen
pager
Optionen für mysql, mysql Optionen
Parameter
Server, Serverparameter feineinstellen
PARTITION, Partitionierung
Partitionen, analysieren, Wartung von Partitionen
Partitionen, aufspalten und zusammenführen, Partitionsverwaltung
Partitionen, hinzufügen und löschen, Partitionsverwaltung
Partitionen, optimieren, Wartung von Partitionen
Partitionen, prüfen, Wartung von Partitionen
Partitionen, reparieren, Wartung von Partitionen
Partitionen, verwalten, Partitionsverwaltung
Partitionen, ändern, Partitionsverwaltung
Partitionierung, Partitionierung
Partitionierung durch linearen Hash, LINEAR HASH-Partitionierung
Partitionierung durch linearen Schlüssel, KEY-Partitionierung
Partitionierung durch Schlüssel, KEY-Partitionierung
Partitionierung nach Bereichen, RANGE-Partitionierung
Partitionierung nach Hash, HASH-Partitionierung
Partitionierung nach Listen, LIST-Partitionierung
Partitionierung, einschalten, Überblick über die Partitionierung in MySQL
Partitionierung, Vorteile, Überblick über die Partitionierung in MySQL
Partitionierungsinformationen, Befehle, Abruf von Informationen über Partitionen
Partitionierungskonzepte, Überblick über die Partitionierung in MySQL
Partitionierungstypen, Partitionstypen
Partitionierungsunterstützung, Überblick über die Partitionierung in MySQL
PARTITIONS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA PARTITIONS
Partitionsverwaltung, Partitionsverwaltung
password
Optionen für mysql, mysql Optionen
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
password (Option), Wie Sie Ihre Kennwörter sicher halten
PASSWORD(), Zugriffskontrolle, Phase 1: Verbindungsüberprüfung, Kennwörter einrichten, Verschlüsselungs- und Kompressionsfunktionen, User ignored-Fehler
Passwort
für Benutzer, MySQL-Benutzernamen und -Kennwörter
root, Einrichtung der anfänglichen MySQL-Berechtigungen
Passwortverschlüsselung
Umkehrbarkeit, Verschlüsselungs- und Kompressionsfunktionen
Passwörter
einstellen, Kennwörter einrichten, GRANT und REVOKE, SET PASSWORD
neu einstellen, Wie ein vergessenes Kennwort zurückgesetzt wird
Sicherheit, Was das Berechtigungssystem macht
vergessene, Wie ein vergessenes Kennwort zurückgesetzt wird
verlorene, Wie ein vergessenes Kennwort zurückgesetzt wird
PATH (Umgebungsvariable), Installation von MySQL auf anderen Unix-ähnlichen Systemen, Aufruf von MySQL-Programmen
PATH environment variable, Umgebungsvariablen
PERIOD_ADD(), Datums- und Zeitfunktionen
PERIOD_DIFF(), Datums- und Zeitfunktionen
Perl
Installation, Anmerkungen zur Perl-Installation
Installation unter Windows, Installation von ActiveState-Perl unter Windows
Perl DBI/DBD
Installationsprobleme, Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
Perl-API, MySQLs Perl-API
perror, Überblick über Client- und Hilfsprogramme
PHP-API, MySQLs PHP-API
PI(), Mathematische Funktionen
PIPES_AS_CONCAT (SQL-Modus), Der SQL-Modus des Servers
Plug-In-API, Die MySQL-Plug-In-Schnittstelle
Plug-Ins
deinstallieren, UNINSTALL PLUGIN
hinzufügen, Die MySQL-Plug-In-Schnittstelle
installieren, INSTALL PLUGIN
PLUGINS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA PLUGINS
Point(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
POINT-Datentyp, Raumbezogene Datentypen in MySQL
Point-in-Time-Wiederherstellung, Zeitpunktbezogene Wiederherstellung
PointFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
PointFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
PointN(), LineString-Funktionen
PointOnSurface(), MultiPolygon-Funktionen
PolyFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
PolyFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
Polygon(), Erzeugung von Geometriewerten mit MySQL-spezifischen Funktionen
POLYGON-Datentyp, Raumbezogene Datentypen in MySQL
PolygonFromText(), Erzeugung von Geometriewerten mit WKT-Funktionen
PolygonFromWKB(), Erzeugung von Geometriewerten mit WKB-Funktionen
port
Optionen für mysql, mysql Optionen
Portabilität, Applikationskonzepte unter Beachtung von Portabilitätsaspekten
Typen, Verwendung von Datentypen anderer Datenbanken
porting
to other systems, Anmerkungen zur Portierung auf andere Systeme
POSITION(), String-Funktionen
POSTGRESQL (SQL-Modus), Der SQL-Modus des Servers
PostgreSQL-Kompatibilität, MySQL-Erweiterungen zu ANSI SQL92
POW(), Mathematische Funktionen
POWER(), Mathematische Funktionen
PREPARE, SQL-Syntax für vorbereitete Anweisungen
XA-Transaktionen, SQL-Syntax von XA-Transaktionen
PRIMARY KEY, ALTER TABLE, CREATE TABLE
Constraint, PRIMARY KEY- und UNIQUE-Index-Constraints
Primärschlüssel
löschen, ALTER TABLE
Probleme
Access denied, Access denied-Fehler
DATE-Spalten, Probleme bei der Benutzung von DATE-Spalten
Datumswerte, Die DATETIME-, DATE- und TIMESTAMP-Typen
Häufige Fehler, Probleme und häufig auftretende Fehler
Installation unter IBM-AIX, Anmerkungen zu IBM-AIX
Installation unter Perl, Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
Installation unter Solaris, Anmerkungen zu Solaris
Kompilierung, Probleme beim Kompilieren?
melden, Wie man Bugs oder Probleme meldet
ODBC, MyODBC-Support
Serverstart, Probleme mit dem Start des MySQL Servers
Tabellensperrung, Themen, die Tabellensperren betreffen
Verlinken, Probleme beim Linken mit der MySQL-Clientbibliothek
Zeitzonen, Probleme mit Zeitzonen
PROCEDURE, SELECT
PROCESSLIST, SHOW PROCESSLIST
Programme
Client, Clientprogramme bauen
Clientprogramme, Überblick über Client- und Hilfsprogramme
crash-me, Applikationskonzepte unter Beachtung von Portabilitätsaspekten
Hilfsprogramme, Überblick über Client- und Hilfsprogramme
serverseitige, Überblick über serverseitige Programme und Dienstprogramme
Programmvariablen
einstellen, Verwendung von Optionen zum Setzen von Programmvariablen
prompt
Optionen für mysql, mysql Optionen
protocol
Optionen für mysql, mysql Optionen
Prozeduren
gespeicherte, Gespeicherte Prozeduren und Trigger, Gespeicherte Prozeduren und Funktionen
hinzufügen, Hinzufügen neuer Prozeduren zu MySQL
Prozessunterstützung, Betriebssysteme, die von MySQL unterstützt werden
Präzisionsberechnungen, Präzisionsberechnungen
Prüfoptionen
myisamchk, Prüfoptionen für myisamchk
Prüfsummenfehler, Anmerkungen zu Solaris
Puffergrößen
Client, APIs und Bibliotheken
mysqld-Server, Serverparameter feineinstellen
PURGE MASTER LOGS, PURGE MASTER LOGS
Python-API, MySQL-Python-APIs

R

RADIANS(), Mathematische Funktionen
RAND(), Mathematische Funktionen
Rangordnung
Operatoren, Rangfolge von Operatoren
Raumbezogene Erweiterungen in MySQL, Einführung in die raumbezogenen Funktionen von MySQL
raw
Optionen für mysql, mysql Optionen
read_buffer_size (myisamchk-Variable), Allgemeine Optionen für myisamchk
REAL (Datentyp), Überblick über numerische Datentypen
REAL_AS_FLOAT (SQL-Modus), Der SQL-Modus des Servers
reconnect
Optionen für mysql, mysql Optionen
RECOVER
XA-Transaktionen, SQL-Syntax von XA-Transaktionen
Referenzen, ALTER TABLE
ref_or_null, IS NULL-Optimierung
regex, Beschreibung der MySQL-Syntax für reguläre Ausdrücke
REGEXP, String-Vergleichsfunktionen
Related(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
relationale Datenbanken
Definition, Was ist MySQL?
RELEASE SAVEPOINT, SAVEPOINT und ROLLBACK TO SAVEPOINT
Release-Nummern, Welche MySQL-Version Sie benutzen sollten
Releases
aktualisieren, Wann und wie Updates veröffentlicht werden
Benennungsschema, Auswahl der bestgeeigneten Version von MySQL
testen, Auswahl der bestgeeigneten Version von MySQL
RELEASE_LOCK(), Verschiedene Funktionen
RENAME TABLE, RENAME TABLE
RENAME USER, RENAME USER
REPAIR TABLE, REPAIR TABLE
Reparaturoptionen
myisamchk, Reparaturoptionen für myisamchk
Reparieren
Tabellen, Wie Tabellen repariert werden
REPEAT, REPEAT-Anweisung
REPEAT(), String-Funktionen
replace, Überblick über Client- und Hilfsprogramme
REPLACE, REPLACE
REPLACE(), String-Funktionen
Replikation, Replikation bei MySQL
Geschwindigkeitserhöhung, Replikation bei MySQL
Replikationseinschränkungen, Replikation: Features und bekannte Probleme
Replikationsmaster
Anweisungen, SQL-Anweisungen für die Steuerung von Master-Servern
Replikationsoptionen, Replikation: Features und bekannte Probleme
Replikationsslaves
Anweisungen, SQL-Anweisungen für die Steuerung von Slave-Servern
Reporting
Connector/NET-Probleme, Support für Connector/NET
REQUIRE GRANT (Option), GRANT und REVOKE
Reservierte Wörter
Ausnahmen, Ist MySQL pingelig hinsichtlich reservierter Wörter?
RESET MASTER, RESET MASTER
RESET SLAVE, RESET SLAVE
RESTORE TABLE, RESTORE TABLE
REVERSE(), String-Funktionen
REVOKE, REVOKE
RIGHT JOIN, JOIN
RIGHT OUTER JOIN, JOIN
RIGHT(), String-Funktionen
RLIKE, String-Vergleichsfunktionen
ROLLBACK, Transaktionen, BEGIN/COMMIT/ROLLBACK
XA-Transaktionen, SQL-Syntax von XA-Transaktionen
ROLLBACK TO SAVEPOINT, SAVEPOINT und ROLLBACK TO SAVEPOINT
ROLLUP, GROUP BY-Modifizierer
root-Benutzer
Passwort neu einstellen, Wie ein vergessenes Kennwort zurückgesetzt wird
root-Passwort, Einrichtung der anfänglichen MySQL-Berechtigungen
ROUND(), Mathematische Funktionen
ROUTINES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA ROUTINES
ROW_COUNT(), Informationsfunktionen
RPAD(), String-Funktionen
RPM Package Manager, MySQL unter Linux installieren
RPM-Datei, MySQL unter Linux installieren
RTRIM(), String-Funktionen
RTS-threads, Anmerkungen zu RTS-Thread
Runden, Präzisionsberechnungen
Rundungsfehler, Überblick über numerische Datentypen
Rückgabewerte
UDFs, Rückgabewerte und Fehlerbehandlung
Rückschritt (\b), Strings

S

safe-updates
Optionen für mysql, mysql Optionen
safe-updates (Option), Verwendung der Option --safe-updates
Sakila, Geschichte von MySQL
SAVEPOINT, SAVEPOINT und ROLLBACK TO SAVEPOINT
Schema
erstellen, CREATE DATABASE
löschen, DROP DATABASE
ändern, ALTER DATABASE
SCHEMA(), Informationsfunktionen
SCHEMATA
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA SCHEMATA
SCHEMA_PRIVILEGES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA SCHEMA_PRIVILEGES
Schließen
Tabellen, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
Schlüssel, Spaltenindizes
Fremdschlüssel, Fremdschlüssel
FremdSchlüssel, Wie Fremdschlüssel verwendet werden
mehrspaltige, Mehrspaltige Indizes
Suchen über zwei Schlüssel, Über zwei Schlüssel suchen
Schlüssel-Cache
MyISAM, Der MyISAM-Schlüssel-Cache
Zuweisen von Indizes an, CACHE INDEX
Schlüssel-Platzbedarf
MyISAM, Für Indizes benötigter Speicherplatz
Schlüsselpartitionen, aufspalten und zusammenführen, Verwaltung von HASH- und KEY-Partitionen
Schlüsselpartitionen, verwalten, Verwaltung von HASH- und KEY-Partitionen
Schlüsselpartitionierung, KEY-Partitionierung
Schlüsselwörter, Ist MySQL pingelig hinsichtlich reservierter Wörter?
Schreibzugriff
tmp, Probleme mit mysql_install_db
SECOND(), Datums- und Zeitfunktionen
secure-auth
Optionen für mysql, mysql Optionen
SEC_TO_TIME(), Datums- und Zeitfunktionen
SELECT
Abfrage-Cache, MySQL-Anfragen-Cache
LIMIT, SELECT
optimieren, EXPLAIN-Syntax (Informationen über ein SELECT erhalten)
SELECT INTO, SELECT ... INTO-Anweisung
SELECT INTO TABLE, SELECT INTO TABLE
SELECT-Geschwindigkeit, Geschwindigkeit von SELECT-Anweisungen
select_limit (Variable), mysql Optionen
SEQUENCE, Verwendung von AUTO_INCREMENT
Sequenzemulation, Informationsfunktionen
Server
herunterfahren, Schritte nach der Installation unter Unix
mehrere, Mehrere MySQL-Server auf derselben Maschine laufen lassen
neu starten, Schritte nach der Installation unter Unix
Probleme beim Starten, Probleme mit dem Start des MySQL Servers
starten, Schritte nach der Installation unter Unix
starten und beenden, MySQL automatisch starten und anhalten
trennen vom, Verbindung zum Server herstellen und trennen
verbinden mit, Verbindung zum Server herstellen und trennen, Verbinden mit dem MySQL-Server
server
debugging, Einen MySQL-Server debuggen
Serverseitige Programme, Überblick über serverseitige Programme und Dienstprogramme
Servervariablen, Server-Systemvariablen, SHOW VARIABLES
SESSION_USER(), Informationsfunktionen
SET, SET, Variable SET-Anweisung
AUTOCOMMIT, SET
BIG_TABLES, SET
CHARACTER SET, Verbindungszeichensatz und -sortierfolge, SET
FOREIGN_KEY_CHECKS, SET
Größe, Speicherbedarf von Spaltentypen
IDENTITY, SET
INSERT_ID, SET
LAST_INSERT_ID, SET
NAMES, Verbindungszeichensatz und -sortierfolge, SET
ONE_SHOT, SET
SQL_AUTO_IS_NULL, SET
SQL_BIG_SELECTS, SET
SQL_BUFFER_SELECT, SET
SQL_LOG_BIN, SET
SQL_LOG_OFF, SET
SQL_LOG_UPDATE, SET
SQL_NOTES, SET
SQL_QUOTE_SHOW_CREATE, SET
SQL_SAFE_UPDATES, SET
SQL_SELECT_LIMIT, SET
SQL_WARNINGS, SET
TIMESTAMP, SET
UNIQUE_CHECKS, SET
SET (Datentyp), Überblick über String-Typen, Der Spaltentyp SET
SET GLOBAL SQL_SLAVE_SKIP_COUNTER, SET GLOBAL SQL_SLAVE_SKIP_COUNTER
SET OPTION, SET
SET PASSWORD, SET PASSWORD
SET PASSWORD (Anweisung), Kennwörter einrichten
SET SQL_LOG_BIN, SET SQL_LOG_BIN
SET TRANSACTION, SET TRANSACTION
SHA(), Verschlüsselungs- und Kompressionsfunktionen
SHA1(), Verschlüsselungs- und Kompressionsfunktionen
Shell-Syntax, Konventionen in diesem Handbuch
SHOW BINARY LOGS, SHOW MASTER LOGS
SHOW BINLOG EVENTS, SHOW, SHOW BINLOG EVENTS
SHOW CHARACTER SET, SHOW CHARACTER SET
SHOW COLLATION, SHOW COLLATION
SHOW COLUMNS, SHOW, SHOW COLUMNS
SHOW CREATE DATABASE, SHOW, SHOW CREATE DATABASE
SHOW CREATE FUNCTION, SHOW, SHOW CREATE PROCEDURE und SHOW CREATE FUNCTION
SHOW CREATE PROCEDURE, SHOW, SHOW CREATE PROCEDURE und SHOW CREATE FUNCTION
SHOW CREATE SCHEMA, SHOW, SHOW CREATE DATABASE
SHOW CREATE TABLE, SHOW, SHOW CREATE TABLE
SHOW CREATE VIEW, SHOW CREATE VIEW
SHOW DATABASES, SHOW, SHOW DATABASES
SHOW ENGINE, SHOW, SHOW ENGINE
SHOW ENGINES, SHOW, SHOW ENGINES
SHOW ERRORS, SHOW, SHOW ERRORS
SHOW FIELDS, SHOW
SHOW FUNCTION STATUS, SHOW, SHOW PROCEDURE STATUS und SHOW FUNCTION STATUS
SHOW GRANTS, SHOW, SHOW GRANTS
SHOW INDEX, SHOW, SHOW INDEX
SHOW INNODB STATUS, SHOW
SHOW KEYS, SHOW, SHOW INDEX
SHOW MASTER LOGS, SHOW, SHOW MASTER LOGS
SHOW MASTER STATUS, SHOW, SHOW MASTER STATUS
SHOW mit WHERE, Die Datenbank INFORMATION_SCHEMA, Erweiterungen der SHOW-Anweisungen
SHOW OPEN TABLES, SHOW, SHOW OPEN TABLES
SHOW PLUGIN, SHOW, SHOW PLUGIN
SHOW PRIVILEGES, SHOW, SHOW PRIVILEGES
SHOW PROCEDURE STATUS, SHOW, SHOW PROCEDURE STATUS und SHOW FUNCTION STATUS
SHOW PROCESSLIST, SHOW, SHOW PROCESSLIST
SHOW SCHEMAS, SHOW, SHOW DATABASES
SHOW SLAVE HOSTS, SHOW, SHOW SLAVE HOSTS
SHOW SLAVE STATUS, SHOW, SHOW SLAVE STATUS
SHOW STATUS, SHOW
SHOW STORAGE ENGINES, SHOW ENGINES
SHOW TABLE STATUS, SHOW
SHOW TABLE TYPES, SHOW, SHOW ENGINES
SHOW TABLES, SHOW, SHOW TABLES
SHOW TRIGGERS, SHOW, SHOW TRIGGERS
SHOW VARIABLES, SHOW
SHOW WARNINGS, SHOW, SHOW WARNINGS
SHOW-Erweiterungen, Erweiterungen der SHOW-Anweisungen
show-warnings
Optionen für mysql, mysql Optionen
shutdown_timeout (Variable), mysqladmin — Client für die Verwaltung eines MySQL Servers
Sicherheit
Maßnahmen gegen Angreifer, Absichern von MySQL gegen Angreifer
Sicherheitssystem, Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem
Sichten, Sichten (Views)
sigint-ignore
Optionen für mysql, mysql Optionen
SIGN(), Mathematische Funktionen
silent
Optionen für mysql, mysql Optionen
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
Optionen für perror, perror — Erklärung der Fehlercodes
SIN(), Mathematische Funktionen
skip-column-names
Optionen für mysql, mysql Optionen
skip-line-numbers
Optionen für mysql, mysql Optionen
Skriptdateien, mysql im Stapelbetrieb
Skripten
mysqlbug, Wie man Bugs oder Probleme meldet
mysql_install_db, Probleme mit mysql_install_db
SLEEP(), Verschiedene Funktionen
slow queries, mysqladmin — Client für die Verwaltung eines MySQL Servers
SMALLINT (Datentyp), Überblick über numerische Datentypen
socket
Optionen für mysql, mysql Optionen
Socketposition
ändern, Typische configure-Optionen
Solaris x86_64, Tipps zur Leistungssteigerung
Solaris – Fehlersuche, Probleme beim Kompilieren?
Solaris – Installationsprobleme, Anmerkungen zu Solaris
Sonstige Funktionen, Verschiedene Funktionen
Sortieren
Daten, Zeilen sortieren
Grant-Tabellen , Zugriffskontrolle, Phase 1: Verbindungsüberprüfung, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
Strings, Unterstützung für String-Vergleiche
Tabellendatensätze, Zeilen sortieren
Zeichensätze, Der für Daten und zum Sortieren benutzte Zeichensatz
sort_buffer_size (myisamchk-Variable), Allgemeine Optionen für myisamchk
sort_key_blocks (myisamchk-Variable), Allgemeine Optionen für myisamchk
SOUNDEX(), String-Funktionen
SOUNDS LIKE, String-Funktionen
SPACE(), String-Funktionen
Spalte
ändern, ALTER TABLE
Spalten
auswählen, Bestimmte Spalten auswählen
indizieren, Spaltenindizes
Namen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
sonstige Typen, Verwendung von Datentypen anderer Datenbanken
Speicheranforderungen, Speicherbedarf von Spaltentypen
Typen, Datentypen
ändern, Wie man die Reihenfolge der Spalten in einer Tabelle ändert
Spaltenkommentare, CREATE TABLE
Spaltennamen
Unterscheidung der Groß-/Kleinschreibung, Groß-/Kleinschreibung in Namen
Speicher-Engine
ARCHIVE, Die ARCHIVE-Speicher-Engine
Speicher-Engines
auswählen, Speicher-Engines und Tabellentypen
Speicheranforderungen
datentypspezifische, Speicherbedarf von Spaltentypen
Speicherkapazität
minimizing, Wie Sie Ihre Daten so klein wie möglich bekommen
Speichernutzung, Wie MySQL Speicher benutzt
myisamchk, Speicherbenutzung von myisamchk
Speicherung von Daten, Überlegungen zum Datenbankdesign
Sperren
Datensätze, Transaktionen, Wie MySQL Tabellen sperrt
extern, Befehlsoptionen für mysqld, Server-Systemvariablen, Benutzung von myisamchk für die Fehlerbeseitigung nach Abstürzen, SHOW PROCESSLIST
Seitenebene, Wie MySQL Tabellen sperrt
Tabellenebene, Wie MySQL Tabellen sperrt
Sperrmethoden, Wie MySQL Tabellen sperrt
Sperrung, System/Kompilierzeitpunkt und Tuning der Startparameter
Sperrung auf Datensatzebene, Wie MySQL Tabellen sperrt
Sperrung auf Seitenebene, Wie MySQL Tabellen sperrt
Sperrung auf Tabellenebene, Wie MySQL Tabellen sperrt
Spiegelserver, Woher man MySQL bekommt
Sprachunterstützung, Nicht englische Fehlermeldungen
SQL
Definition, Was ist MySQL?
SQL-92
Erweiterungen gegenüber, Wie kompatibel zum SQL-Standard ist MySQL?
SQL-Anweisungen
Replikationsmaster, SQL-Anweisungen für die Steuerung von Master-Servern
Replikationsslaves, SQL-Anweisungen für die Steuerung von Slave-Servern
SQL-Modus
ONLY_FULL_GROUP_BY, GROUP BY mit versteckten Feldern
SQL_BIG_RESULT, SELECT
SQL_BUFFER_RESULT, SELECT
SQL_CACHE, Anfragen-Cache-Optionen in SELECT, SELECT
SQL_CALC_FOUND_ROWS, SELECT
SQL_NO_CACHE, Anfragen-Cache-Optionen in SELECT, SELECT
SQL_SMALL_RESULT, SELECT
sql_yacc.cc Probleme, Probleme beim Kompilieren?
SQRT(), Mathematische Funktionen
SRID(), Allgemeine Geometriefunktionen
SSH, Verbinden mit einem entfernten MySQL-Server von Windows mit SSH aus
SSL, Verwendung von SSL-Verbindungen mit yaSSL
SSL und X509 (Grundlagen), Verwendung sicherer Verbindungen
SSL-Befehlsoptionen, SSL-Befehlsoptionen, GRANT und REVOKE
Stabilität, Wie stabil ist MySQL?
Standard SQL
Unterschiede gegenüber, MySQL: Unterschiede im Vergleich zu ANSI SQL92, GRANT und REVOKE
Standard-SQL
Erweiterungen gegenüber, Wie kompatibel zum SQL-Standard ist MySQL?, MySQL-Erweiterungen zu ANSI SQL92
Standardeinstellungen
Berechtigungen, Einrichtung der anfänglichen MySQL-Berechtigungen
Standardhostname, Verbinden mit dem MySQL-Server
Standardinstallationsposition, Installationslayouts
Standardkonformität, Wie kompatibel zum SQL-Standard ist MySQL?
Standardoptionen, my.cnf-Optionsdateien
Standardwerte
Embedded, Optionen des eingebetteten Servers
Stapelbetrieb, mysql im Stapelbetrieb
Start
Kommentare, '--' als Beginn eines Kommentars
Server, Schritte nach der Installation unter Unix
Server, automatisch, MySQL automatisch starten und anhalten
START
XA-Transaktionen, SQL-Syntax von XA-Transaktionen
START SLAVE, START SLAVE
START TRANSACTION, BEGIN/COMMIT/ROLLBACK
Starten
mysqld, Wie man MySQL als normaler Benutzer laufen läßt
Starten mehrerer Server, Mehrere MySQL-Server auf derselben Maschine laufen lassen
Startoptionen
Standardwerte, my.cnf-Optionsdateien
Startparameter, Serverparameter feineinstellen
mysql, mysql Optionen
mysqladmin, mysqladmin — Client für die Verwaltung eines MySQL Servers
optimieren, System/Kompilierzeitpunkt und Tuning der Startparameter
StartPoint(), LineString-Funktionen
Statisch
kompilieren, Typische configure-Optionen
STATISTICS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA STATISTICS
stats_method (myisamchk-Variable), Allgemeine Optionen für myisamchk
Status
Tabellenstatus, SHOW TABLE STATUS
Statusbefehl
Ergebnisse, mysqladmin — Client für die Verwaltung eines MySQL Servers
Statusvariablen, Server-Statusvariablen, SHOW STATUS
STD(), Funktionen zur Benutzung in GROUP BY-Klauseln
STDDEV(), Funktionen zur Benutzung in GROUP BY-Klauseln
STDDEV_POP(), Funktionen zur Benutzung in GROUP BY-Klauseln
STDDEV_SAMP(), Funktionen zur Benutzung in GROUP BY-Klauseln
Stellen, Datentypen
Steuerung des Zugriffs, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
STOP SLAVE, STOP SLAVE
Stoppwortliste
benutzerdefinierte, MySQL-Volltextsuche feineinstellen
STRAIGHT_JOIN, SELECT, JOIN
STRCMP(), String-Vergleichsfunktionen
STRICT (SQL-Modus), Der SQL-Modus des Servers
STRICT_ALL_TABLES (SQL-Modus), Der SQL-Modus des Servers
STRICT_TRANS_TABLES (SQL-Modus), Der SQL-Modus des Servers
String-Funktionen, String-Funktionen
String-Literal, Zeichensatzeinführung, Strings, Zeichensatz und Sortierfolge literaler Strings
String-Sortierung, Unterstützung für String-Vergleiche
String-Typen, String-Typen
String-Vergleiche
Unterscheidung der Groß-/Kleinschreibung, String-Vergleichsfunktionen
String-Vergleichsfunktionen, String-Vergleichsfunktionen
Strings
definierte, Literale: wie Strings und Zahlen geschrieben werden
Escape-Zeichen, Literale: wie Strings und Zahlen geschrieben werden
ohne Trennzeichen, Die DATETIME-, DATE- und TIMESTAMP-Typen
Striping
Definition, Festplatte, Anmerkungen
Struktur der Installation, Installationslayouts
STR_TO_DATE(), Datums- und Zeitfunktionen
SUBDATE(), Datums- und Zeitfunktionen
SUBSTR(), String-Funktionen
SUBSTRING(), String-Funktionen
SUBSTRING_INDEX(), String-Funktionen
SUBTIME(), Datums- und Zeitfunktionen
Subtraktion (-), Arithmetische Operationen
Suchen
MySQL-Webseiten, Wie man Bugs oder Probleme meldet
Volltextsuche, MySQL-Volltextsuche
über zwei Schlüssel, Über zwei Schlüssel suchen
Suchoperationen
Groß- und Kleinschreibung, Groß-/Kleinschreibung beim Suchen
SUM(), Funktionen zur Benutzung in GROUP BY-Klauseln
SUM(DISTINCT), Funktionen zur Benutzung in GROUP BY-Klauseln
superuser, Einrichtung der anfänglichen MySQL-Berechtigungen
Sybase-Kompatibilität, USE
Symbolische Verknüpfungen, Symbolische Verknüpfungen, Daten unter Windows auf verschiedene Platten aufteilen
SymDifference(), Raumbezogene Operatoren
Syntax
reguläre Ausdrücke, Beschreibung der MySQL-Syntax für reguläre Ausdrücke
Syntax für reguläre Ausdrücke
Beschreibung, Beschreibung der MySQL-Syntax für reguläre Ausdrücke
SYSDATE(), Datums- und Zeitfunktionen
System
Berechtigungssystem, Was das Berechtigungssystem macht
Sicherheit, Absichern von MySQL gegen Angreifer
Systemoptimierung, System/Kompilierzeitpunkt und Tuning der Startparameter
Systemtabelle, EXPLAIN-Syntax (Informationen über ein SELECT erhalten)
Systemvariablen, Server-Systemvariablen, Verwendung von Server-Systemvariablen, SHOW VARIABLES
SYSTEM_USER(), Informationsfunktionen

T

Tabelle
löschen, DROP TABLE
ändern, ALTER TABLE, Probleme mit ALTER TABLE
Tabelle ist voll, The table is full-Fehler
Tabellen
Abrufen von Daten, Informationen aus einer Tabelle abfragen
aktualisieren, Transaktionen
ARCHIVE, Die ARCHIVE-Speicher-Engine
Auswählen von Datensätzen, Bestimmte Zeilen auswählen
Auswählen von Spalten, Bestimmte Spalten auswählen
BDB, Die BDB-Speicher-Engine
Berkeley DB, Die BDB-Speicher-Engine
BLACKHOLE, Die BLACKHOLE-Speicher-Engine
CSV, Die CSV-Speicher-Engine
defragmentieren, Erstellen eines Wartungsplans für Tabellen, OPTIMIZE TABLE, Kennzeichen dynamischer Tabellen
dynamische, Kennzeichen dynamischer Tabellen
Eindeutige ID für letzte Zeile, Wie erhalte ich die eindeutige Kennung für die letzte eingefügte Zeile?
Einladen von Daten, Daten in Tabellen einladen
erstellen, Eine Tabelle erzeugen
EXAMPLE, Die EXAMPLE-Speicher-Engine
FEDERATED, Die FEDERATED-Speicher-Engine
Fehlerprüfung, Wie Tabellen auf Fehler überprüft werden
Fragmentierung, OPTIMIZE TABLE
geregelte Wartung, Erstellen eines Wartungsplans für Tabellen
Grant-Tabellen, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
HEAP, Die MEMORY-Speicher-Engine
host, Zugriffskontrolle, Phase 2: Anfrageüberprüfung
Informationen zu, Informationen über Datenbanken und Tabellen, Informationen über eine Tabelle erhalten
InnoDB, InnoDB-Tabellen
komprimiertes Format, Kennzeichen komprimierter Tabellen
Konstantentabelle, EXPLAIN-Syntax (Informationen über ein SELECT erhalten), Optimierungen der WHERE-Klausel
kopieren, CREATE TABLE
Leistung verbessern, Wie Sie Ihre Daten so klein wie möglich bekommen
maximale Größe, Wie groß können MySQL-Tabellen sein?
mehrere, Mehr als eine Tabelle benutzen
MEMORY, Die MEMORY-Speicher-Engine
MERGE, Die MERGE-Speicher-Engine
MyISAM, Die MyISAM-Speicher-Engine
Namen, Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen
offene, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
optimieren, Tabellenoptimierung
partitionieren, Die MERGE-Speicher-Engine
reparieren, Wie Tabellen repariert werden
schließen, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
Sortieren von Datensätzen, Zeilen sortieren
Status anzeigen, SHOW TABLE STATUS
symbolische Verknüpfungen, Benutzung symbolischer Links für Tabellen
synchronisieren, mysqladmin — Client für die Verwaltung eines MySQL Servers
Systemtabelle, EXPLAIN-Syntax (Informationen über ein SELECT erhalten)
Zeilen löschen, Zeilen aus verwandten Tabellen löschen
zu viele, Warum gibt es so viele offene Tabellen?
zusammenführen, Die MERGE-Speicher-Engine
Zählen von Datensätzen, Zeilen zählen
Ändern der Spaltenreihenfolge, Wie man die Reihenfolge der Spalten in einer Tabelle ändert
öffnen, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
überprüfen, Prüfoptionen für myisamchk
Tabellen-Cache, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
Tabellenaliase, SELECT
Tabellengröße, Wie groß können MySQL-Tabellen sein?
Tabellennamen
Unterscheidung der Groß-/Kleinschreibung, MySQL-Erweiterungen zu ANSI SQL92, Groß-/Kleinschreibung in Namen
Tabellenscans
vermeiden, Vermeidung von Tabellenscans
Tabellentypen
auswählen, Speicher-Engines und Tabellentypen
table
Optionen für mysql, mysql Optionen
Table is Full, SET
TABLES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA TABLES
table_open_cache, Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank
TABLE_PRIVILEGES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA TABLE_PRIVILEGES
Tabulator (\t), Strings
TAN(), Mathematische Funktionen
tar
Probleme unter Solaris, Anmerkungen zu Solaris
Tcl-API, MySQL-Tcl-APIs
tcp-ip
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
TCP/IP, Auswahl des MySQL Server-Typs, Test der MySQL-Installation
tee
Optionen für mysql, mysql Optionen
Teilpartitionen, Unterpartitionen
Teilpartitionierung, Unterpartitionen
Temporärdatei
Schreibzugriff, Probleme mit mysql_install_db
Temporäre Tabellen
Probleme, Probleme mit TEMPORARY TABLE
Terminalmonitor
Definition, Einführung in MySQL: ein MySQL-Tutorial
Testen
MySQL-Releases, Auswahl der bestgeeigneten Version von MySQL
Verbindung mit dem Server, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
Testen von mysqld
mysqltest, MySQL-Testsystem
Tests
Installation, Schritte nach der Installation unter Unix
nach Installationsabschluss, Einstellungen und Tests nach der Installation
TEXT
Größe, Speicherbedarf von Spaltentypen
TEXT (Datentyp), Überblick über String-Typen, Die Spaltentypen BLOB und TEXT
TEXT-Spalten
indizieren, Spaltenindizes, CREATE TABLE
Vorgabewerte, Die Spaltentypen BLOB und TEXT
thread packages
differences between, Unterschiede zwischen verschiedenen Thread-Paketen
Thread-Unterstützung, Betriebssysteme, die von MySQL unterstützt werden
nichtnativ, Anmerkungen zu MIT-pthreads
Threaded Clients, Wie man einen Thread-Client herstellt
threads, mysqladmin — Client für die Verwaltung eines MySQL Servers
RTS, Anmerkungen zu RTS-Thread
Threads, SHOW PROCESSLIST, Hinzufügen neuer Funktionen zu MySQL
Anzeige, SHOW PROCESSLIST
TIME (Datentyp), Überblick über Datums- und Zeittypen, Der TIME-Typ
TIME(), Datums- und Zeitfunktionen
TIMEDIFF(), Datums- und Zeitfunktionen
TIMESTAMP
und NULL-Werte, Probleme mit NULL-Werten
TIMESTAMP (Datentyp), Überblick über Datums- und Zeittypen, Die DATETIME-, DATE- und TIMESTAMP-Typen
TIMESTAMP(), Datums- und Zeitfunktionen
TIMESTAMPADD(), Datums- und Zeitfunktionen
TIMESTAMPDIFF(), Datums- und Zeitfunktionen
TIME_FORMAT(), Datums- und Zeitfunktionen
TIME_TO_SEC(), Datums- und Zeitfunktionen
TINYBLOB (Datentyp), Überblick über String-Typen
TINYINT (Datentyp), Überblick über numerische Datentypen
TINYTEXT (Datentyp), Überblick über String-Typen
Tipps
Optimierung, Weitere Optimierungstipps
TMPDIR (Umgebungsvariable), Probleme mit mysql_install_db
TMPDIR environment variable, Umgebungsvariablen
TODO
Symbolische Verknüpfungen, Benutzung symbolischer Links für Tabellen
tools
list of, Werkzeuge, die zum Herstellen von MySQL benutzt werden
Touches(), Funktionen, die raumbezogene Beziehungen zwischen Geometrien überprüfen
TO_DAYS(), Datums- und Zeitfunktionen
trace DBI method, mysqld unter gdb debuggen
TRADITIONAL (SQL-Modus), Der SQL-Modus des Servers
Transaktionen
Unterstützung, Transaktionen, Überblick über InnoDB-Tabellen
Transaktionssichere Tabellen, Transaktionen
transaktionssichere Tabellen, Überblick über InnoDB-Tabellen
Translators
list of, Redakteure und Übersetzer
Trennzeichen, Strings ohne, Die DATETIME-, DATE- und TIMESTAMP-Typen
Trigger, Gespeicherte Prozeduren und Trigger, SHOW TRIGGERS, Trigger
Trigger, anlegen, CREATE TRIGGER
Trigger, löschen, DROP TRIGGER
TRIGGERS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA TRIGGERS
TRIM(), String-Funktionen
TRUE, Zahlen, Boolesche Werte
testen auf, Vergleichsoperatoren
TRUNCATE, TRUNCATE
TRUNCATE(), Mathematische Funktionen
Tutorial, Einführung in MySQL: ein MySQL-Tutorial
Typen
Datentypen, Datentypen
Datum, Speicherbedarf von Spaltentypen
Datum und Uhrzeit, Datums- und Zeittypen
numerische, Speicherbedarf von Spaltentypen
Portabilität, Verwendung von Datentypen anderer Datenbanken
Spalten, Auswahl des richtigen Datentyps für eine Spalte
Spaltentypen, Datentypen
Strings, String-Typen
Tabellentypen, Speicher-Engines und Tabellentypen
Uhrzeit, Speicherbedarf von Spaltentypen
Typenkonvertierungen, Typumwandlung bei der Auswertung von Ausdrücken, Vergleichsoperatoren
typografische Konventionen, Konventionen in diesem Handbuch
TZ environment variable, Umgebungsvariablen
TZ-Umgebungsvariable, Probleme mit Zeitzonen

U

UCA (Unicode Collation Algorithm), Unicode-Zeichensätze
UCASE(), String-Funktionen
UCS-2, Zeichensatz-Unterstützung
UDFs, CREATE FUNCTION/DROP FUNCTION, DROP FUNCTION
definierte, Hinzufügen neuer Funktionen zu MySQL
kompilieren, Kompilieren und Installieren benutzerdefinierter Funktionen
Rückgabewerte, Rückgabewerte und Fehlerbehandlung
Uhrzeittypen, Speicherbedarf von Spaltentypen
ulimit, Datei nicht gefunden
UMASK environment variable, Umgebungsvariablen
UMASK-Umgebungsvariable, Probleme mit Dateirechten
UMASK_DIR environment variable, Umgebungsvariablen
UMASK_DIR-Umgebungsvariable, Probleme mit Dateirechten
Umbenennen von Benutzerkonten, RENAME USER
Umgebungsvariable
TZ, Probleme mit Zeitzonen
UMASK, Probleme mit Dateirechten
UMASK_DIR, Probleme mit Dateirechten
Umgebungsvariablen, Verwendung von Umgebungsvariablen für die Angabe von Optionen, Gründe für Access denied-Fehler, Überblick über Client- und Hilfsprogramme
CC, Typische configure-Optionen, Probleme beim Kompilieren?
CCX, Typische configure-Optionen, Probleme beim Kompilieren?
CFLAGS, Typische configure-Optionen, Probleme beim Kompilieren?
CXXFLAGS, Typische configure-Optionen, Probleme beim Kompilieren?
HOME, mysql Optionen
LD_LIBRARY_PATH, Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
LD_RUN_PATH, Anmerkungen zur Linux-Quelldistribution, Anmerkungen zu Solaris, Probleme bei der Benutzung der DBI/DBD-Schnittstelle von Perl
MYSQL_DEBUG, Überblick über Client- und Hilfsprogramme
MYSQL_HISTFILE, mysql Optionen
MYSQL_HOST, Verbinden mit dem MySQL-Server
MYSQL_PWD, Verbinden mit dem MySQL-Server, Überblick über Client- und Hilfsprogramme
MYSQL_TCP_PORT, Mehrere MySQL-Server unter Unix laufen lassen, Verwendung von Client-Programmen in einer Mehrserverumgebung, Überblick über Client- und Hilfsprogramme
MYSQL_UNIX_PORT, Probleme mit mysql_install_db, Mehrere MySQL-Server unter Unix laufen lassen, Verwendung von Client-Programmen in einer Mehrserverumgebung, Überblick über Client- und Hilfsprogramme
PATH, Installation von MySQL auf anderen Unix-ähnlichen Systemen, Aufruf von MySQL-Programmen
TMPDIR, Probleme mit mysql_install_db
USER, Verbinden mit dem MySQL-Server
Umkonfigurieren, Probleme beim Kompilieren?
Umwandlungen, Typumwandlung bei der Auswertung von Ausdrücken, Vergleichsoperatoren, Cast-Funktionen und Operatoren
Umwandlungsfunktionen, Cast-Funktionen und Operatoren
Umwandlungsoperatoren, Cast-Funktionen und Operatoren
Unbenannte Views, Unterabfragen in der FROM-Klausel
unbuffered
Optionen für mysql, mysql Optionen
UNCOMPRESS(), Verschlüsselungs- und Kompressionsfunktionen
UNCOMPRESSED_LENGTH(), Verschlüsselungs- und Kompressionsfunktionen
ungleich (!=), Vergleichsoperatoren
ungleich (<>), Vergleichsoperatoren
Ungültige Daten
Constraint, Constraints auf ungültigen Daten
UNHEX(), String-Funktionen
Unicode, Zeichensatz-Unterstützung
UNINSTALL PLUGIN, UNINSTALL PLUGIN
UNION, Über zwei Schlüssel suchen, UNION
Union(), Raumbezogene Operatoren
UNIQUE, ALTER TABLE
Constraint, PRIMARY KEY- und UNIQUE-Index-Constraints
Unix, MySQL Connector/ODBC, Connector/NET
UNIX_TIMESTAMP(), Datums- und Zeitfunktionen
UNKNOWN
testen auf, Vergleichsoperatoren
UNLOCK TABLES, LOCK TABLES und UNLOCK TABLES
Unterabfrage, Syntax von Unterabfragen
Unterabfragen, Syntax von Unterabfragen
Unterauswahl, Syntax von Unterabfragen
Unterdrückung
Vorgabewerte, Constraints auf ungültigen Daten
Unterscheidung der Groß-/Kleinschreibung
Bezeichner, Groß-/Kleinschreibung in Namen
in String-Vergleichen, String-Vergleichsfunktionen
Namen, Groß-/Kleinschreibung in Namen
Unterstützung
für Betriebssysteme, Betriebssysteme, die von MySQL unterstützt werden
UNTIL, REPEAT-Anweisung
UPDATE, UPDATE
UpdateXML(), XML-Funktionen
Upgrade, MySQL aktualisieren (Upgrade/Downgrade)
andere Architektur, Upgrade auf eine andere Architektur
auf 5.1, Upgrade von MySQL 5.0
UPPER(), String-Funktionen
uptime, mysqladmin — Client für die Verwaltung eines MySQL Servers
URLs für den Download von MySQL, Woher man MySQL bekommt
USE, USE
USE INDEX, SELECT, JOIN
USE KEY, SELECT, JOIN
user
Optionen für mysql, mysql Optionen
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
user (Tabelle)
sortieren, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
USER (Umgebungsvariable), Verbinden mit dem MySQL-Server
USER environment variable, Umgebungsvariablen
USER(), Informationsfunktionen
USER_PRIVILEGES
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA USER_PRIVILEGES
UTC_DATE(), Datums- und Zeitfunktionen
UTC_TIME(), Datums- und Zeitfunktionen
UTC_TIMESTAMP(), Datums- und Zeitfunktionen
UTF-8, Zeichensatz-Unterstützung
UUID(), Verschiedene Funktionen

V

VALUES(), Verschiedene Funktionen
VARBINARY (Datentyp), Überblick über String-Typen, Die BINARY- und VARBINARY-Typen
VARCHAR
Größe, Speicherbedarf von Spaltentypen
VARCHAR (Datentyp), Überblick über String-Typen, String-Typen
VARCHARACTER (Datentyp), Überblick über String-Typen
Variablen
Benutzervariablen, Benutzerdefinierte Variablen
mysqld, Serverparameter feineinstellen
Servervariablen, Server-Systemvariablen, SHOW VARIABLES
Statusvariablen, Server-Statusvariablen, SHOW STATUS
Systemvariablen, Server-Systemvariablen, Verwendung von Server-Systemvariablen, SHOW VARIABLES
VARIANCE(), Funktionen zur Benutzung in GROUP BY-Klauseln
VAR_POP(), Funktionen zur Benutzung in GROUP BY-Klauseln
VAR_SAMP(), Funktionen zur Benutzung in GROUP BY-Klauseln
Verarbeitung
Argumente, Verarbeitung von Argumenten
Verbessern
Leistung, Replikation: häufig gestellte Fragen
Verbindung
Abbruch, Kommunikationsfehler/abgebrochene Verbindung
Fernverbindung mit SSH, Verbinden mit einem entfernten MySQL-Server von Windows mit SSH aus
mit dem Server, Verbindung zum Server herstellen und trennen, Verbinden mit dem MySQL-Server
verifizieren, Zugriffskontrolle, Phase 1: Verbindungsüberprüfung
Verbindungstrennung
vom Server, Verbindung zum Server herstellen und trennen
verbose
Optionen für mysql, mysql Optionen
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
Optionen für perror, perror — Erklärung der Fehlercodes
Vergleichen
Muster, Übereinstimmende Suchmuster
Vergleichsoperatoren, Vergleichsoperatoren
Verknüpfen
Geschwindigkeit, Wie Kompilieren und Linken die Geschwindigkeit von MySQL beeinflusst
Verknüpfungen
symbolische, Symbolische Verknüpfungen
Verlinken, Clientprogramme bauen
Fehler, Probleme beim Linken mit der MySQL-Clientbibliothek
Verringern
Datenumfang, Wie Sie Ihre Daten so klein wie möglich bekommen
Verschachtelte Abfragen, Syntax von Unterabfragen
Verschlüsselungsfunktionen, Verschlüsselungs- und Kompressionsfunktionen
Version
aktuelle, Woher man MySQL bekommt
auswählen, Welche MySQL-Version Sie benutzen sollten
version
Optionen für mysql, mysql Optionen
Optionen für mysqld_multi, mysqld_multi — Verwalten mehrerer MySQL-Server
Optionen für perror, perror — Erklärung der Fehlercodes
VERSION(), Informationsfunktionen
vertical
Optionen für mysql, mysql Optionen
Verwenden mehrerer Festplatten zum Starten von Daten, Daten unter Windows auf verschiedene Platten aufteilen
Verzeichnisstruktur
standardmäßige, Installationslayouts
Views, Sichten (Views), Views, CREATE VIEW
aktualisierbare, Sichten (Views)
veränderbare, CREATE VIEW
VIEWS
INFORMATION_SCHEMA-Tabelle, Die Tabelle INFORMATION_SCHEMA VIEWS
Virtueller Speicher
Probleme bei der Kompilierung, Probleme beim Kompilieren?
Vision, MyODBC mit SunSystems Vision verwenden
Visual Objects, Visual Objects
Volle Festplatte, Wie MySQL mit vollen Festplatten umgeht
Volltextsuche, MySQL-Volltextsuche
Stoppwortliste, MySQL-Volltextsuche feineinstellen
Vorgabewerte, MySQL: konzeptionelle Einschränkungen, Vorgabewerte von Datentypen, CREATE TABLE, INSERT
BLOB- und TEXT-Spalten, Die Spaltentypen BLOB und TEXT
explizite, Vorgabewerte von Datentypen
implizite, Vorgabewerte von Datentypen
Unterdrückung, Constraints auf ungültigen Daten