Gibt es zwischen utf8_general_ci
und utf8_unicode_ci
Leistungsunterschiede?
utf8[mb4]_unicode_ci
, Sie können gerne utf8[mb4]_unicode_520_ci
noch mehr.
utf8mb4_0900_ai_ci
.
Gibt es zwischen utf8_general_ci
und utf8_unicode_ci
Leistungsunterschiede?
utf8[mb4]_unicode_ci
, Sie können gerne utf8[mb4]_unicode_520_ci
noch mehr.
utf8mb4_0900_ai_ci
.
Antworten:
Diese beiden Kollatierungen gelten beide für die UTF-8-Zeichencodierung. Die Unterschiede bestehen darin, wie Text sortiert und verglichen wird.
Hinweis: In MySQL müssen Sie utf8mb4
eher als verwenden utf8
. Verwirrenderweise utf8
handelt es sich um eine fehlerhafte UTF-8-Implementierung aus frühen MySQL-Versionen, die nur aus Gründen der Abwärtskompatibilität erhalten bleibt. Die feste Version erhielt den Namen utf8mb4
.
Hinweis: Neuere Versionen von MySQL haben die Unicode-Sortierregeln aktualisiert, die unter Namen verfügbar sind, z. B. utf8mb4_0900_ai_ci
für äquivalente Regeln, die auf Unicode 9.0 basieren - und ohne äquivalente _general
Variante. Leute, die dies jetzt lesen, sollten wahrscheinlich eine dieser neueren Kollatierungen anstelle von entweder _unicode
oder verwenden _general
. Vieles von dem, was unten geschrieben steht, ist nicht mehr von großem Interesse, wenn Sie stattdessen eine der neueren Kollatierungen verwenden können.
Hauptunterschiede
utf8mb4_unicode_ci
basiert auf den offiziellen Unicode-Regeln für das universelle Sortieren und Vergleichen, die in einer Vielzahl von Sprachen genau sortiert werden.
utf8mb4_general_ci
ist ein vereinfachter Satz von Sortierregeln, der so gut wie möglich funktioniert und gleichzeitig viele Abkürzungen zur Verbesserung der Geschwindigkeit verwendet. Es folgt nicht den Unicode-Regeln und führt in einigen Situationen zu unerwünschten Sortierungen oder Vergleichen, z. B. bei der Verwendung bestimmter Sprachen oder Zeichen.
Auf modernen Servern ist diese Leistungssteigerung nahezu vernachlässigbar. Es wurde in einer Zeit entwickelt, in der Server einen winzigen Bruchteil der CPU-Leistung heutiger Computer hatten.
Vorteile von utf8mb4_unicode_ci
überutf8mb4_general_ci
utf8mb4_unicode_ci
, das die Unicode-Regeln zum Sortieren und Vergleichen verwendet, verwendet einen ziemlich komplexen Algorithmus zum korrekten Sortieren in einer Vielzahl von Sprachen und bei Verwendung einer Vielzahl von Sonderzeichen. Diese Regeln müssen sprachspezifische Konventionen berücksichtigen. Nicht jeder sortiert seine Zeichen in der von uns als "alphabetisch" bezeichneten Reihenfolge.
In Bezug auf lateinische (dh "europäische") Sprachen gibt es keinen großen Unterschied zwischen der Unicode-Sortierung und der vereinfachten utf8mb4_general_ci
Sortierung in MySQL, aber es gibt immer noch einige Unterschiede:
Beispielsweise sortiert die Unicode-Kollatierung "ß" wie "ss" und "Œ" wie "OE", wie Personen, die diese Zeichen verwenden, normalerweise möchten, während utf8mb4_general_ci
sie als einzelne Zeichen sortiert werden (vermutlich wie "s" bzw. "e"). .
Einige Unicode-Zeichen werden als ignorierbar definiert. Dies bedeutet, dass sie nicht für die Sortierreihenfolge berücksichtigt werden sollten und der Vergleich stattdessen zum nächsten Zeichen übergehen sollte. utf8mb4_unicode_ci
behandelt diese richtig.
In nicht-lateinischen Sprachen wie asiatischen Sprachen oder Sprachen mit unterschiedlichen Alphabeten kann es viel größere Unterschiede zwischen der Unicode-Sortierung und der vereinfachten utf8mb4_general_ci
Sortierung geben. Die Eignung von utf8mb4_general_ci
wird stark von der verwendeten Sprache abhängen. Für einige Sprachen ist dies völlig unzureichend.
Was solltest du verwenden?
Es gibt mit ziemlicher Sicherheit keinen Grund utf8mb4_general_ci
mehr, diese zu verwenden , da wir den Punkt hinter uns gelassen haben, an dem die CPU-Geschwindigkeit so niedrig ist, dass der Leistungsunterschied wichtig wäre. Ihre Datenbank wird mit ziemlicher Sicherheit durch andere Engpässe als diese eingeschränkt.
In der Vergangenheit wurde von einigen Personen empfohlen, diese zu verwenden, es sei utf8mb4_general_ci
denn, eine genaue Sortierung wäre wichtig genug, um die Leistungskosten zu rechtfertigen. Heute sind diese Leistungskosten so gut wie verschwunden, und Entwickler behandeln die Internationalisierung ernsthafter.
Es muss argumentiert werden, dass Sie, wenn Geschwindigkeit für Sie wichtiger ist als Genauigkeit, auch überhaupt keine Sortierung durchführen dürfen. Es ist trivial, einen Algorithmus schneller zu machen, wenn Sie ihn nicht benötigen, um genau zu sein. Es handelt sich also utf8mb4_general_ci
um einen Kompromiss, der aus Geschwindigkeitsgründen wahrscheinlich nicht benötigt wird und aus Genauigkeitsgründen wahrscheinlich auch nicht geeignet ist.
Eine andere Sache, die ich hinzufügen möchte, ist, dass Ihre Anwendung, selbst wenn Sie wissen, dass sie nur die englische Sprache unterstützt, möglicherweise immer noch mit den Namen von Personen umgehen muss, die häufig Zeichen enthalten, die in anderen Sprachen verwendet werden, in denen es genauso wichtig ist, richtig zu sortieren . Die Verwendung der Unicode-Regeln für alles trägt dazu bei, dass die sehr intelligenten Unicode-Mitarbeiter sehr hart daran gearbeitet haben, dass das Sortieren ordnungsgemäß funktioniert.
Was die Teile bedeuten
Erstens ci
dient das Sortieren und Vergleichen ohne Berücksichtigung der Groß- und Kleinschreibung . Dies bedeutet, dass es für Textdaten geeignet ist und die Groß- und Kleinschreibung nicht wichtig ist. Die anderen Arten der Sortierung sind cs
(Groß- und Kleinschreibung beachten) für Textdaten, bei denen die Groß- und Kleinschreibung wichtig ist, und bin
für die, bei denen die Codierung übereinstimmen muss, Bit für Bit, was für Felder geeignet ist, bei denen es sich tatsächlich um codierte Binärdaten handelt (einschließlich beispielsweise Base64). Die Sortierung nach Groß- und Kleinschreibung führt zu seltsamen Ergebnissen, und der Vergleich zwischen Groß- und Kleinschreibung kann dazu führen, dass doppelte Werte nur in Groß- und Kleinschreibung voneinander abweichen. Daher werden Sortierungen, bei denen zwischen Groß- und Kleinschreibung unterschieden wird, für Textdaten in Ungnade fallen und so weiter ist wahrscheinlich auch von Bedeutung, und eine binäre Kollatierung könnte geeigneter sein.
Weiter unicode
oder general
bezieht sich auf die spezifischen Sortier- und Vergleichsregeln - insbesondere auf die Art und Weise, wie Text normalisiert oder verglichen wird. Es gibt viele verschiedene Arten von Regeln für die utf8mb4 Zeichencodierung, mit unicode
und general
sind zwei dieser Versuch zu funktionieren gut in allen möglichen Sprachen statt einem spezifischen. Die Unterschiede zwischen diesen beiden Regelwerken sind Gegenstand dieser Antwort. Beachten Sie, dass unicode
Regeln aus Unicode 4.0 verwendet werden. Neuere Versionen von MySQL fügen die Regelsätze unicode_520
mithilfe von Regeln aus Unicode 5.2 und 0900
(Löschen des Teils "unicode_") mithilfe von Regeln aus Unicode 9.0 hinzu.
Und schließlich utf8mb4
wird natürlich die Zeichencodierung intern verwendet. In dieser Antwort spreche ich nur von Unicode-basierten Codierungen.
utf8_general_ci
: es funktioniert einfach nicht. Es ist ein Rückfall in die schlechten alten Zeiten der ASCII-Stooopeeedität vor fünfzig Jahren. Unicode-Matching ohne Berücksichtigung der Groß- und Kleinschreibung kann nicht ohne die Foldcase-Map von der UCD durchgeführt werden. Zum Beispiel hat "Σίσυφος" drei verschiedene Sigmen; oder wie der Kleinbuchstabe von "TSCHüẞ" "tschüβ" ist, aber der Großbuchstabe von "tschüβ" ist "TSCHÜSS". Sie können Recht haben oder Sie können schnell sein. Daher müssen Sie verwenden utf8_unicode_ci
, denn wenn Sie sich nicht um Korrektheit kümmern, ist es trivial, es unendlich schnell zu machen.
"か" == "が"
oder "ǽ" == "æ"
. Für die Sortierung ist dies sinnvoll, könnte aber überraschend sein, wenn Sie über Gleichungen auswählen oder mit eindeutigen Indizes arbeiten - bugs.mysql.com/bug.php?id=16526
utf8mb4
ist die einzig richtige Wahl . Mit utf8
Ihnen in einiger MySQL-only feststecken, 3-Byte - Variante von UTF - 8 , dass nur MySQL (und MariaDB) wissen , was mit zu tun. Der Rest der Welt verwendet UTF8, das bis zu 4 Bytes pro Zeichen enthalten kann . Die MySQL-Entwickler haben ihre Homebrew-Codierung falsch benannt. Um die utf8
Abwärtskompatibilität nicht zu beeinträchtigen , müssen sie sich jetzt auf die echte UTF8 als beziehen utf8mb4
.
Ich wollte wissen, was der Leistungsunterschied zwischen der Verwendung von utf8_general_ci
und utf8_unicode_ci
ist, fand jedoch keine im Internet aufgelisteten Benchmarks und habe mich daher entschlossen, selbst Benchmarks zu erstellen.
Ich habe eine sehr einfache Tabelle mit 500.000 Zeilen erstellt:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Dann habe ich es mit zufälligen Daten gefüllt, indem ich diese gespeicherte Prozedur ausgeführt habe:
CREATE PROCEDURE randomizer()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE random CHAR(20) ;
theloop: loop
SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
INSERT INTO test VALUES (i+1, random);
SET i=i+1;
IF i = 500000 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END
Dann habe ich die folgenden gespeicherten Prozeduren erstellt, um einfach SELECT
, SELECT
mit LIKE
und sortieren ( SELECT
mit ORDER BY
) zu vergleichen:
CREATE PROCEDURE benchmark_simple_select()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description = 'test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_select_like()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description LIKE '%test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_order_by()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
SET i = i + 1;
IF i = 10 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
In den oben gespeicherten Prozeduren wird die utf8_general_ci
Kollatierung verwendet, aber natürlich habe ich während der Tests sowohl utf8_general_ci
als auch verwendet utf8_unicode_ci
.
Ich habe jede gespeicherte Prozedur 5 Mal für jede Kollatierung aufgerufen (5 Mal für utf8_general_ci
und 5 Mal für utf8_unicode_ci
) und dann die Durchschnittswerte berechnet.
Meine Ergebnisse sind:
benchmark_simple_select()
utf8_general_ci
: 9.957 ms utf8_unicode_ci
: 10.271 ms In dieser Benchmark ist die Verwendung utf8_unicode_ci
langsamer als utf8_general_ci
um 3,2%.
benchmark_select_like()
utf8_general_ci
: 11.441 ms utf8_unicode_ci
: 12.811 ms In dieser Benchmark ist die Verwendung utf8_unicode_ci
langsamer als utf8_general_ci
um 12%.
benchmark_order_by()
utf8_general_ci
: 11.944 ms utf8_unicode_ci
: 12.887 ms In dieser Benchmark ist die Verwendung utf8_unicode_ci
langsamer als utf8_general_ci
um 7,9%.
utf8_general_ci
ist einfach zu gering, um ihn zu nutzen.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
generiert nur ASCII und keine Unicode-Zeichen, die von den Algorithmen der Kollatierungen verarbeitet werden sollen. 2) Description = 'test' COLLATE ...
und verarbeite Description LIKE 'test%' COLLATE ...
nur einen einzigen String ("Test") zur Laufzeit, nicht wahr? 3) In realen Apps werden die bei der Bestellung verwendeten Spalten wahrscheinlich indiziert, und die Indizierungsgeschwindigkeit für verschiedene Kollatierungen mit echtem Nicht-ASCII-Text kann unterschiedlich sein.
Dieser Beitrag beschreibt es sehr schön.
Kurz gesagt: utf8_unicode_ci verwendet den in den Unicode-Standards definierten Unicode-Kollatierungsalgorithmus, während utf8_general_ci eine einfachere Sortierreihenfolge ist, die zu "weniger genauen" Sortierergebnissen führt.
utf8_unicode_ci
und tun Sie so, als ob der andere nicht existiert.
utf8_general_ci
Siehe das MySQL-Handbuch, Abschnitt Unicode-Zeichensätze :
Für jeden Unicode-Zeichensatz sind Operationen, die mit der _general_ci-Kollatierung ausgeführt werden, schneller als die für die _unicode_ci-Kollatierung. Beispielsweise sind Vergleiche für die Kollatierung utf8_general_ci schneller, aber etwas weniger korrekt als Vergleiche für utf8_unicode_ci. Der Grund dafür ist, dass utf8_unicode_ci Zuordnungen wie Erweiterungen unterstützt. Das heißt, wenn ein Zeichen mit Kombinationen anderer Zeichen verglichen wird. In Deutsch und einigen anderen Sprachen ist „ß“ beispielsweise gleich „ss“. utf8_unicode_ci unterstützt auch Kontraktionen und ignorierbare Zeichen. utf8_general_ci ist eine Legacy-Sortierung, die keine Erweiterungen, Kontraktionen oder ignorierbaren Zeichen unterstützt. Es können nur Eins-zu-Eins-Vergleiche zwischen Zeichen durchgeführt werden.
Zusammenfassend verwendet utf_general_ci einen kleineren und weniger korrekten (gemäß dem Standard) Satz von Vergleichen als utf_unicode_ci, der den gesamten Standard implementieren sollte . Der Satz general_ci ist schneller, da weniger Berechnungen erforderlich sind.
utf8_unicode_ci
und tun Sie so, als ob die fehlerhafte Version des Buggys nicht existiert.
0
und 1
kein Bool. :) Das Auswählen von Geopunkten in einem Begrenzungsrahmen ist eine Annäherung an "Punkte in der Nähe", die nicht so gut ist wie das Berechnen des Abstands zwischen dem Punkt und dem Referenzpunkt und das Filtern danach. Aber beide sind eine Annäherung und in der Tat vollständige Richtigkeit ist meist nicht erreichbar. Siehe das Küstenparadoxon und IEEE 754
1/3
In kurzen Worten:
Wenn Sie eine bessere Sortierreihenfolge benötigen, verwenden Sie utf8_unicode_ci
(dies ist die bevorzugte Methode),
aber wenn Sie ganz an Leistung interessiert sind - verwenden Sie utf8_general_ci
, aber wissen Sie, dass es ein wenig veraltet ist.
Die Leistungsunterschiede sind sehr gering.
Wie wir hier lesen können ( Peter Gulutzan ), gibt es Unterschiede beim Sortieren / Vergleichen des polnischen Buchstabens "Ł" (L mit Strich - html esc :) Ł
(Kleinbuchstaben: "ł" - html esc :) ł
- wir haben folgende Annahme:
utf8_polish_ci Ł greater than L and less than M
utf8_unicode_ci Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci Ł greater than Z
In polnischer Sprache steht der Buchstabe Ł
nach dem Buchstaben L
und davor M
. Keine dieser Kodierungen ist besser oder schlechter - es hängt von Ihren Bedürfnissen ab.
Es gibt zwei große Unterschiede bei der Sortierung und der Zeichenübereinstimmung:
Sortierung :
utf8mb4_general_ci
Entfernt alle Akzente und sortiert nacheinander, was zu falschen Sortierergebnissen führen kann.utf8mb4_unicode_ci
sortiert genau.Zeichenübereinstimmung
Sie stimmen mit Charakteren unterschiedlich überein.
Zum Beispiel in utf8mb4_unicode_ci
dir i != ı
, aber utf8mb4_general_ci
darin gilt ı=i
.
Stellen Sie sich zum Beispiel vor, Sie haben eine Reihe mit name="Yılmaz"
. Dann
select id from users where name='Yilmaz';
würde die Zeile zurückgeben, wenn Kollokation ist utf8mb4_general_ci
, aber wenn es mit kollokiert ist , utf8mb4_unicode_ci
würde die Zeile nicht zurückgeben!
Auf der anderen Seite haben wir das a=ª
und ß=ss
in utf8mb4_unicode_ci
dem ist das nicht der Fall utf8mb4_general_ci
. So stellen Sie sich mit einer Reihe haben name="ªßi"
, dann
select id from users where name='assi';
würde die Zeile zurückgeben, wenn die Kollokation ist utf8mb4_unicode_ci
, würde aber keine Zeile zurückgeben, wenn die Kollokation auf gesetzt ist utf8mb4_general_ci
.
Eine vollständige Liste der Übereinstimmungen für jede Kollokation finden Sie hier .
Laut diesem Beitrag bietet MySQL 5.7 einen erheblich großen Leistungsvorteil, wenn utf8mb4_general_ci anstelle von utf8mb4_unicode_ci verwendet wird: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-Leistung /