MySQL und MariaDB
Kernideen
- Serverdatenbank, sehr verbreitet in Webanwendungen und damit in vielen Datenquellen
- MariaDB ist aus MySQL hervorgegangen und weitgehend austauschbar
- Der Speicher-Engine entscheidet über Transaktionen und Fremdschlüssel
- Zeichensatz und Sortierung sind eine echte Fehlerquelle, nicht eine Formalie
- Analytisch schwächer als PostgreSQL, für den Lesezugriff aber unproblematisch
- In der Datenarbeit meist Quellsystem, nicht Zielsystem
Erklärung
Vorwissen: SQL. Der Zugriff aus R und Python steht unter Datenbankzugriff, die Einordnung gegenüber anderen Systemen in der Übersicht.
MySQL, MariaDB und was sie unterscheidet
MariaDB entstand als Abspaltung von MySQL und ist für den Lesezugriff praktisch identisch: dieselben Treiber, dieselben Abfragen, dieselben Werkzeuge. Für die Datenarbeit spielt der Unterschied selten eine Rolle; er wird erst beim Betrieb relevant, wo sich Funktionsumfang und Lizenzen unterscheiden.
Wichtiger als die Unterscheidung der beiden ist die Speicher-Engine. InnoDB ist heute der Standard und kann Transaktionen und Fremdschlüssel. Die ältere MyISAM kann beides nicht: Ein Fremdschlüssel wird dort ohne Fehlermeldung ignoriert, und ein abgebrochener Schreibvorgang hinterlässt einen halben Stand. In alten Beständen begegnet einem das gelegentlich, und man sieht es der Tabelle nicht an.
SELECT table_name, engine FROM information_schema.tables
WHERE table_schema = DATABASE();Zeichensatz und Sortierung
Die häufigste stille Fehlerquelle beim Lesen aus MySQL sind Umlaute, die als Fragezeichen oder als Buchstabensalat ankommen. Ursache ist ein Zeichensatz, der nicht durchgehend utf8mb4 ist. Historisch bedeutete utf8 in MySQL eine verkürzte Variante, die keine vier Byte langen Zeichen speichern konnte, also weder Emojis noch manche asiatische Schriftzeichen.
Die zweite Eigenheit ist die Sortierung, die auch die Vergleiche steuert. Bei den üblichen Voreinstellungen unterscheidet MySQL in WHERE nicht zwischen Gross- und Kleinschreibung, PostgreSQL dagegen schon. Eine Abfrage, die auf dem einen System das Erwartete liefert, kann auf dem anderen leer bleiben.
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';Eigenheiten, die beim Auswerten auffallen
- Datumsangaben mit Nullwerten: MySQL erlaubt
0000-00-00, was in R und Python zuNAbeziehungsweiseNaTwird oder den Treiber stört. In den Verbindungsoptionen lässt sich das Verhalten festlegen. GROUP BYmit nicht aggregierten Spalten: war lange erlaubt und lieferte einen beliebigen Wert der Gruppe. Neuere Versionen lehnen es ab, alte Abfragen brechen deshalb beim Umstieg.- Fensterfunktionen gibt es erst ab MySQL 8 und MariaDB 10.2; in älteren Beständen fehlen sie und werden durch Selbstverbindungen ersetzt.
LIMITohneORDER BYliefert keine definierte Auswahl, auch wenn es in der Praxis oft stabil aussieht.
Typische Aufgaben
Verbinden
con <- DBI::dbConnect(
RMariaDB::MariaDB(),
host = "db.example.org", port = 3306, dbname = "shop",
user = Sys.getenv("MYSQL_USER"), password = Sys.getenv("MYSQL_PASSWORD")
)
DBI::dbExecute(con, "SET NAMES utf8mb4")from sqlalchemy import create_engine
import os
motor = create_engine(
f"mysql+pymysql://{os.environ['MYSQL_USER']}:{os.environ['MYSQL_PASSWORD']}"
"@db.example.org:3306/shop?charset=utf8mb4"
)Der Zusatz zum Zeichensatz ist kein Detail: Ohne ihn kommen Umlaute je nach Servereinstellung falsch an, und zwar ohne Fehlermeldung.
Nachsehen, was es gibt
SHOW DATABASES;
SHOW TABLES;
DESCRIBE artikel;
SHOW CREATE TABLE artikel; -- inklusive Engine und ZeichensatzLesen und weiterverarbeiten
df <- DBI::dbGetQuery(con, "
SELECT a.bezeichnung, SUM(b.betrag) AS umsatz
FROM bestellung b JOIN artikel a ON a.artikel_id = b.artikel_id
WHERE b.datum >= ?
GROUP BY a.bezeichnung", params = list("2026-01-01"))df = pd.read_sql_query(
"""SELECT a.bezeichnung, SUM(b.betrag) AS umsatz
FROM bestellung b JOIN artikel a ON a.artikel_id = b.artikel_id
WHERE b.datum >= %(ab)s
GROUP BY a.bezeichnung""",
motor, params={"ab": "2026-01-01"})Eine langsame Abfrage untersuchen
EXPLAIN SELECT * FROM bestellung WHERE artikel_id = 3;
SHOW INDEX FROM bestellung;
CREATE INDEX idx_bestellung_artikel ON bestellung(artikel_id);Sicherung und Wiederherstellung
mysqldump -h host -u benutzer -p --single-transaction shop > sicherung.sql
mysql -h host -u benutzer -p shop < sicherung.sql--single-transaction sorgt bei InnoDB für einen konsistenten Stand, ohne die Tabellen zu sperren.
Aus einem Container heraus ausprobieren
docker run --name mariadb -e MARIADB_ROOT_PASSWORD=geheim -p 3306:3306 -d mariadb
docker exec -it mariadb mariadb -uroot -pgeheimSiehe auch Docker und Virtualisierung.
Verständnisfragen
Im Build dieser Website läuft kein MySQL-Server, deshalb sind die Beispiele hier Listings und es wird nichts gerechnet. Die SQL-Grundlagen selbst laufen echt unter SQL gegen SQLite.
Eine Abfrage WHERE bezeichnung = 'pneumatik' findet in MySQL Zeilen mit Pneumatik, in PostgreSQL nicht. Woran liegt das?
LOWER(bezeichnung) = 'pneumatik'.
Eine Tabelle wurde mit der Speicher-Engine MyISAM angelegt. Was fehlt gegenüber InnoDB?
Beim Auswerten einer MySQL-Quelle stehen in einer Textspalte Fragezeichen statt Umlauten. Was ist zu prüfen?
latin1 oder die Verbindung auf einem anderen Zeichensatz als die Daten, gehen Zeichen verloren, und zwar beim Schreiben unwiderruflich. Heute ist utf8mb4 die richtige Wahl.
Eine Auswertung soll aus einer MySQL-Quelle gelesen und dann analytisch weiterverarbeitet werden. Was spricht dafür, sie nicht vollständig in MySQL zu rechnen?