UTF-8 und Emojis 😀😍👍
Was viele nicht wissen: utf8 in MySQL ist nicht das "wahre" UTF-8. Es ist nur ein Alias für utf8mb3 und kann daher nur bis zu drei Byte pro Zeichen speichern. Das führt zu Problemen mit Emojis und vielen Sonderzeichen, die bis zu vier Byte benötigen.
Inhaltsverzeichnis
Die UTF-8-Falle bei MySQL/MariaDB
Unicode, die Grundlage moderner Textkodierung, sollte eigentlich eine einfache Sache sein. Doch im Kontext von Datenbanken, insbesondere bei MySQL und MariaDB, kann die Wahl des richtigen Zeichensatzes zu Verwirrung führen. Häufig stösst man auf Begriffe wie utf8, utf8mb3 und utf8mb4.
In diesem Beitrag möchte ich klären, warum utf8 und utf8mb3 dasselbe sind und warum die ausschliessliche Verwendung von utf8mb4 unerlässlich ist. Ausserdem werfe ich einen genaueren Blick auf die Unterschiede zwischen den beiden gängigen Sortierregeln utf8mb4_general_ci und utf8mb4_unicode_ci.
Daten wurden nicht korrekt entschlüsselt
Kürzlich habe ich mich bei unserem Eigenprojekt onlyforme mit der verschlüsselten Speicherung von Tagebucheinträgen befasst. Ich konnte die Binärdaten problemlos verschlüsseln und in der Datenbank speichern. Die anschliessende Entschlüsselung beim Auslesen der Daten ist dann jedoch fehlgeschlagen. Nach längerer Suche konnte ich die Ursache auf den von mir gewählten Zeichensatz utf8 für die Datenbank-Verbindung eingrenzen.
Gelöst wurde das Problem nach langer Suche durch die einfache Ergänzung von utf8 mit mb4: https://github.com/Actra-AG/framework/commit/784bf61302362aa05c7ff07ee371c5dc9c26e681.
Der Unterschied zwischen utf8/utf8mb3 und utf8mb4
Der Unterschied zwischen utf8 (Alias zu utf8mb3) und utf8mb4 bei Zeichensätzen in MariaDB (und MySQl, da sie historisch eng verwandt sind) ist ein wichtiger Punkt, der oft zu Verwirrung und Datenverlust führen kann.
| Merkmal | utf8/utf8mb3 |
utf8mb4 |
|---|---|---|
| Max. Bytes pro Zeichen | 3 Bytes | 4 Bytes |
| Unicode-Abdeckung | BMP (Basic Multilingual Plane) | BMP, SMP (Supplementary Multilingual Plane) |
| Emojis/Sonderzeichen | Nicht unterstützt | Voll unterstützt |
| Bezeichnung | Historische, unvollständige UTF-8-Alias utf8mb3 |
Echte, vollständige UTF-8-Implementierung |
| Empfehlung | Nicht mehr verwenden | Immer verwenden für neue Projekte |
utf8/utf8mb3 - Die alte/unvollständige Implementierung in MariaDB/MySQL
utf8mb3 unterstützt nur Zeichen, die bis zu 3 Bytes pro Zeichen benötigen. Es deckt nur die Basic Multilingual Plane (BMP) von Unicode ab. Dies beinhaltet die meisten gängigen Zeichen für europäische Sprachen, viele asiatische Sprachen (aber nicht alle) und grundlegende Symbole. Es können keine Zeichen gespeichert werden, die mehr als 3 Bytes benötigen. Dies sind insbesondere Emojis, seltene chinesische, japanische oder koreanische (CJK) Zeichen, bestimmte mathematische Symbole, spezielle musikalische Noten und historische Schriften.
Beim Versuch, ein 4-Byte-Zeichen in einer Spalte mit utf8-Charset zu speichern, kann dies zu Fehlern (z.B. "Incorrect string value: ...") oder Datenverlust (das Zeichen wird stillschweigend abgeschnitten oder in ein Fragezeichen umgewandelt) führen.
Der Grund, warum MySQL/MariaDB dieses utf8 einführte, war, dass UTF-8 ursprünglich bis zu 4 Bytes pro Zeichen vorsah, aber zum Zeitpunkt der Implementierung die meisten verwendeten Zeichen nur bis zu 3 Bytes benötigten und man Speicherplatz sparen wollte. Die Bezeichnung utf8 ist daher irreführend, da es keine vollständige UTF8-Implementierung ist.
utf8mb4 - Die vollständige UTF-8-Implementierung
utf8mb4 unterstützt Zeichen, die bis zu 4 Bytes pro Zeichen benötigen. Es deckt den gesamten Unicode-Zeichensatz ab. Das bedeutet, es kann alle gültigen Unicode-Zeichen speichern, einschliesslich derer ausserhalb der BMP. utf8mb4 ist die echte und vollständige Implementierung des UTF-8-Standards in MariaDB/MYSQL. Es ist vollständig abwärtskompatibel mit utf8. Das heisst, alle Zeichen, die in utf8 gespeichert werden können, können auch in utf8mb4 gespeichert werden, und sie nehmen denselben Speicherplatz ein. Der zusätzliche Platzbedarf tritt nur auf, wenn tatsächlich 4-Byte-Zeichen gespeichert werden.
Warum ist utf8mb4 heute der Standard und die Empfehlung?
Emojis sind heutzutage allgegenwärtig in der Kommunikation und in Webanwendungen. Ohne utf8mb4 können sie nicht korrekt gespeichert werden. Für Anwendungen, die ein globales Publikum ansprechen und verschiedene Sprachen und Skripte unterstützen müssen, ist utf8mb4 unerlässlich. Da der Unicode-Standard ständig erweitert wird, stellt utf8mb4 sicher, dass die Datenbank auch zukünftige Zeichen verarbeiten kann. Der geringfügige Anstieg des Speicherplatzbedarfs für 4-Byte-Zeichen ist in der Regel vernachlässigbar im Vergleich zu den Vorteilen der vollständigen Unicode-Unterstützung.
Für alle neuen Projekte in MariaDB oder MySQL sollte immer utf8mb4 als Zeichensatz verwendet werden. Sowohl auf Datenbank-, Tablelen- als auch auf Spaltenebene (wenn sie nicht die Standardwerte nutzen). Auch die Anwendungen (PHP, etc.) sollten ebenfalls utf8mb4 als Verbindungs-Charset verwenden.
Bei älteren Projekten mit utf8/utf8mb3 sollte eine Migration zu utf8mb4 durchgeführt werden, um auch die Speicherung von Emojis und anderen 4-Byte-Zeichen zu ermöglichen.
Der feine Unterschied zwischen utf8mb4_general_ci vs. utf8mb4_unicode_ci
Nachdem wir nun wissen, dass utf8mb4 die richtige Wahl für unseren Zeichensatz ist, stellt sich die nächste Frage: Welches Collation (Sortierregel) sollen wir wählen? Die beiden gängigsten Optionen sind utf8mb4_general_ci vs. utf8mb4_unicode_ci. Obwohl sie auf den ersten Blick ähnliche Ergebnisse liefern, gibt es entscheidende Unterschiede in puncto Präzision und Performance.
| Collation | Vorteile | Nachteile |
|---|---|---|
utf8mb4_general_ci |
Ideal für Anwendungen, bei denen die Geschwindigkeit von Such- und Sortiervorgängen kritisch ist. Benötigt weniger Systemressourcen. | Kann bei bestimmten Sprachen zu falschen Sortierungen führen. So werden beispielsweise in der deutschen Sprache Umlaute (ä, ö, ü) oft wie ihre Grundzeichen (a, o, u) behandelt, was zu ungenauen Sortierungen führen kann. Auch bei manchen asiatischen oder osteuropäischen Sprachen ist die Sortierung nicht immer korrekt. Sie hält sich nicht vollständig an die strengen Regeln des Unicode Collation Algorithms (UCA). |
utf8mb4_unicode_ci |
Hält sich an die globalen Unicode-Standards, was eine sprachübergreifend korrekte Sortierung gewährleistet. Für die deutsche Sprache bedeutet dies, dass "ä" und "Ä" als "ae" sortiert werden, was in vielen Fällen dem gewünschten Verhalten entspricht. Deckt eine breitere Palette an Zeichen und deren Regeln ab. | Die komplexeren Vergleichsregeln können zu einer minimal geringeren Performance bei sehr grossen Datenmengen führen. Dieser Unterschied ist in den meisten Anwendungen jedoch vernachlässigbar. Benötigt etwas mehr Speicherplatz für Indizes. |
Was ist Collation?
Collation definiert die Regeln für den Vergleich und die Sortierung von Zeichen einer Zeichenfolge. Es legt fest, ob "A" und "a" als gleich gelten, wie Umlaute sortiert werden (ä, ö, ü) und wie Sonderzeichen behandelt werden. Das Suffix _ci in beiden Collation-Namen steht für case-insensitive, was bedeutet, dass bei Vergleichen Gross- und Kleinschreibung ignoriert wird.
utf8mb4_general_ci: Schnell, aber weniger genau
Die Collation utf8mb4_general_ci ist die ältere und einfachere der beiden. Sie ist in der Regel schneller und benötigt weniger Speicherplatz für die Indizierung. Der Grund dafür ist, dass sie einfache, binäre Regeln für den Zeichenvergleich verwendet und einige spezifische Sortierregeln, die in bestimmten Sprachen notwendig sind, weglässt.
Empfehlung: Deine Wahl der Collation
Für die meisten modernen Webanwendungen, die eine breite Sprachunterstützung benötigen und Wert auf korrekte Such- und Sortierergebnisse legen, ist utf8mb4_unicode_ci die klare Empfehlung. Der geringe Performance-Unterschied ist in den allermeisten Fällen nicht spürbar und die Vorteile der präzisen und korrekten Sortierung überwiegen bei weitem.
utf8mb4_general_ci sollte nur in spezifischen Nischen verwendet werden, wo maximale Geschwindigkeit absolut kritisch ist und die Einschränkung in der Sortierung bewusst in Kauf genommen werden kann. Andernfalls ist utf8mb4_unicode_ci die sichere und zukunftsträchtigere Wahl.
Kontaktieren Sie uns
Benötigen Sie Unterstützung bei der Programmierung in PHP? Gerne unterstützen wir Sie mit unserer individuellen Webentwicklung.
Kontaktieren Sie uns für eine unverbindliche Beratung!