1345 Stimmen

Was ist der Unterschied zwischen utf8_general_ci und utf8_unicode_ci?

Zwischen utf8_general_ci y utf8_unicode_ci Gibt es Unterschiede in Bezug auf die Leistung?

3 Stimmen

9 Stimmen

Wenn Sie mögen utf8[mb4]_unicode_ci Sie Mai wie utf8[mb4]_unicode_520_ci noch mehr.

10 Stimmen

Ich weiß nicht, was ich davon halten soll - anstatt ihre Implementierung an den neuesten Unicode-Standard anzupassen, behalten sie die veraltete Version als Standard bei und die Leute müssen "520" hinzufügen, um die richtige Version zu verwenden. Und es ist nicht vorwärts- und rückwärtskompatibel, weil man die "520"-Version nicht auf älteren MySQL-Versionen verwenden kann. Warum konnten sie nicht einfach ihre bestehende Sortierung aktualisieren? Dasselbe gilt eigentlich für "mb4". Welcher Code hing wirklich von dem alten, eingeschränkten/veralteten Verhalten ab, um zu rechtfertigen, dass es als Standard beibehalten wird?

2043voto

thomasrutter Punkte 109036

Für diejenigen, die sich diese Frage erst im Jahr 2020 oder später stellen, gibt es neuere Optionen, die möglicherweise besser sind als ambos von diesen. Zum Beispiel, utf8_unicode_520_ci .

Alle diese Sortierungen gelten für die UTF-8-Zeichenkodierung. Die Unterschiede liegen darin, wie der Text sortiert und verglichen wird.

_unicode_ci y _general_ci sind zwei verschiedene Regelwerke für die Sortierung und den Vergleich von Text, wie wir es erwarten. Neuere Versionen von MySQL führen auch neue Sätze von Regeln ein, wie zum Beispiel _unicode_520_ci für äquivalente Regeln, die auf Unicode 5.2 basieren, oder die MySQL 8.x-spezifischen _0900_ai_ci für gleichwertige Regeln auf der Grundlage von Unicode 9.0 (und ohne gleichwertige _general_ci Variante). Diejenigen, die dies jetzt lesen, sollten wahrscheinlich eine dieser neueren Kollationen verwenden, anstatt entweder _unicode_ci o _general_ci . Die nachstehende Beschreibung dieser älteren Zusammenstellungen ist nur von Interesse.

MySQL stellt derzeit von einer älteren, mangelhaften UTF-8-Implementierung ab. Im Moment müssen Sie die utf8mb4 anstelle von utf8 für den Zeichencodierungsteil, um sicherzustellen, dass Sie die korrigierte Version erhalten. Die fehlerhafte Version bleibt aus Gründen der Abwärtskompatibilität erhalten, obwohl sie veraltet ist.

Wesentliche Unterschiede

  • utf8mb4_unicode_ci basiert auf den offiziellen Unicode-Regeln für universelle Sortierung und Vergleiche, die in einer Vielzahl von Sprachen präzise sortieren.

  • utf8mb4_general_ci ist ein vereinfachter Satz von Sortierregeln, der darauf abzielt, so gut wie möglich zu arbeiten und dabei viele Abkürzungen zu nehmen, um die Geschwindigkeit zu erhöhen. Es folgt nicht den Unicode-Regeln und wird in einigen Situationen zu unerwünschten Sortierungen oder Vergleichen führen, z. B. bei der Verwendung bestimmter Sprachen oder Zeichen.

    Auf modernen Servern ist diese Leistungssteigerung nahezu vernachlässigbar. Sie wurde in einer Zeit entwickelt, als Server nur einen winzigen Bruchteil der CPU-Leistung heutiger Computer hatten.

Vorteile von utf8mb4_unicode_ci en utf8mb4_general_ci

utf8mb4_unicode_ci die die Unicode-Regeln für die Sortierung und den Vergleich verwendet, verwendet einen ziemlich komplexen Algorithmus für die korrekte Sortierung in einer Vielzahl von Sprachen und bei der Verwendung einer großen Anzahl von Sonderzeichen. Diese Regeln müssen sprachspezifische Konventionen berücksichtigen; nicht jeder sortiert seine Zeichen in dem, was wir als "alphabetische Reihenfolge" bezeichnen würden.

Was die lateinischen (d.h. "europäischen") Sprachen betrifft, so gibt es keinen großen Unterschied zwischen der Unicode-Sortierung und der vereinfachten utf8mb4_general_ci Sortierung in MySQL, aber es gibt noch ein paar Unterschiede:

  • Zum Beispiel sortiert die Unicode-Sortierreihenfolge "ß" wie "ss" und "Œ" wie "OE", wie es die Benutzer dieser Zeichen normalerweise wünschen würden, während utf8mb4_general_ci sortiert sie als einzelne Zeichen (vermutlich wie "s" bzw. "e").

  • Einige Unicode-Zeichen sind als ignorierbar definiert, was bedeutet, dass sie in der Sortierreihenfolge nicht berücksichtigt werden und der Vergleich stattdessen mit dem nächsten Zeichen fortgesetzt werden sollte. utf8mb4_unicode_ci diese richtig behandelt.

In nicht-lateinischen Sprachen, wie z. B. asiatischen Sprachen oder Sprachen mit anderen Alphabeten, kann es eine Menge mehr Unterschiede zwischen der Unicode-Sortierung und der vereinfachten utf8mb4_general_ci Sortieren. Die Eignung von utf8mb4_general_ci wird stark von der verwendeten Sprache abhängen. Für einige Sprachen wird sie völlig unzureichend sein.

Was sollten Sie verwenden?

Es gibt mit Sicherheit keinen Grund, die utf8mb4_general_ci da wir den Punkt hinter uns gelassen haben, an dem die CPU-Geschwindigkeit so niedrig ist, dass der Leistungsunterschied von Bedeutung wäre. Ihre Datenbank wird mit ziemlicher Sicherheit durch andere Engpässe als diesen eingeschränkt.

In der Vergangenheit haben einige Leute empfohlen, die utf8mb4_general_ci Es sei denn, eine genaue Sortierung wäre wichtig genug, um die Kosten für die Leistung zu rechtfertigen. Heute sind diese Leistungskosten fast verschwunden, und die Entwickler nehmen die Internationalisierung ernster.

Man kann argumentieren, dass man, wenn einem Geschwindigkeit wichtiger ist als Genauigkeit, genauso gut gar nicht sortieren kann. Es ist trivial, einen Algorithmus schneller zu machen, wenn er nicht genau sein muss. So, utf8mb4_general_ci ist ein Kompromiss, der aus Geschwindigkeitsgründen wahrscheinlich nicht erforderlich und aus Gründen der Genauigkeit wahrscheinlich auch nicht geeignet ist.

Eine andere Sache, die ich hinzufügen möchte, ist, dass, selbst wenn Sie wissen, dass Ihre Anwendung nur die englische Sprache unterstützt, sie dennoch mit Namen von Personen umgehen muss, die oft Zeichen enthalten können, die in anderen Sprachen verwendet werden, in denen es genauso wichtig ist, korrekt zu sortieren. Die Verwendung der Unicode-Regeln für alles gibt Ihnen die Gewissheit, dass die klugen Unicode-Leute sehr hart daran gearbeitet haben, dass die Sortierung richtig funktioniert.

Was die Teile bedeuten

Erstens, ci ist für Groß- und Kleinschreibung wird nicht berücksichtigt Sortierung und Vergleich. Das bedeutet, dass es für Textdaten geeignet ist und die Groß- und Kleinschreibung keine Rolle spielt. 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 Fälle, in denen die Kodierung Bit für Bit übereinstimmen muss, was für Felder geeignet ist, die wirklich kodierte Binärdaten sind (einschließlich, zum Beispiel, Base64). Die Sortierung unter Berücksichtigung der Groß-/Kleinschreibung führt zu einigen seltsamen Ergebnissen und der Vergleich unter Berücksichtigung der Groß-/Kleinschreibung kann zu doppelten Werten führen, die sich nur in der Groß-/Kleinschreibung unterscheiden, so dass die Sortierung unter Berücksichtigung der Groß-/Kleinschreibung für Textdaten an Bedeutung verliert - wenn die Groß-/Kleinschreibung für Sie von Bedeutung ist, dann ist wahrscheinlich auch die ansonsten ignorierbare Interpunktion usw. von Bedeutung und eine binäre Sortierung könnte angemessener sein.

Nächste, unicode o general bezieht sich auf die spezifischen Sortier- und Vergleichsregeln - insbesondere auf die Art und Weise, wie der Text normalisiert oder verglichen wird. Es gibt viele verschiedene Regelsätze für die utf8mb4-Zeichenkodierung, mit unicode y general zwei, die versuchen, in allen möglichen Sprachen gut zu funktionieren und nicht nur in einer bestimmten Sprache. Die Unterschiede zwischen diesen beiden Regelwerken sind Gegenstand dieser Antwort. Beachten Sie, dass unicode verwendet Regeln aus Unicode 4.0. Neuere Versionen von MySQL und MariaDB fügen die Regelsätze unicode_520 mit Regeln aus Unicode 5.2, und MySQL 8.x fügt hinzu 0900 (ohne den "unicode_"-Teil) unter Verwendung der Regeln von Unicode 9.0.

Und zu guter Letzt, utf8mb4 ist natürlich die intern verwendete Zeichenkodierung. In dieser Antwort spreche ich nur über Unicode-basierte Kodierungen.

270 Stimmen

@KahWeeTeng Sie sollten nie, immer verwenden. utf8_general_ci : Es funktioniert einfach nicht. Es ist ein Rückfall in die schlechten alten Tage der ASCII-Stooopeeedity von vor fünfzig Jahren. Der Abgleich zwischen Groß- und Kleinschreibung in Unicode kann nicht ohne die Zuordnung der Groß- und Kleinschreibung im UCD durchgeführt werden. Zum Beispiel hat "" drei verschiedene Sigmas; oder die Kleinschreibung von "TSCHü" ist "tschü", aber die Großschreibung von "tschü" ist "TSCHÜSS". Man kann Recht haben oder schnell sein. Deshalb müssen Sie utf8_unicode_ci Denn wenn man sich nicht um die Korrektheit kümmert, dann ist es trivial, es unendlich schnell zu machen.

0 Stimmen

Ist die Base64-Kodierung nicht einfach als ASCII kodiert? Warum sollte der "bin"-Teil der Sortierung für Base64 relevant sein?

1 Stimmen

@BrianTristamWilliams die Sortierung bezieht sich darauf, wie der Textvergleich und die Sortierung funktionieren. "bin" als Sortierkriterium bedeutet, dass es sich um einen reinen Binärvergleich handelt: Es wird kein Versuch unternommen, sich an die Konventionen der Schriftsprache anzupassen, und der Vergleich erfolgt ausschließlich anhand der Datenbits.

215voto

nightcoder Punkte 12649

Ich wollte wissen, wie groß der Leistungsunterschied zwischen der Verwendung von utf8_general_ci y utf8_unicode_ci Da ich aber im Internet keine Benchmarks gefunden habe, habe ich beschlossen, 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 sie mit Zufallsdaten 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 einfache Benchmarks durchzuführen SELECT , SELECT con LIKE und Sortierung ( SELECT con ORDER BY ) :

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 obigen gespeicherten Prozeduren utf8_general_ci verwendet wird, aber natürlich habe ich bei den Tests beide utf8_general_ci y utf8_unicode_ci .

Ich habe jede gespeicherte Prozedur 5 Mal für jede Sortierung aufgerufen (5 Mal für utf8_general_ci und 5 Mal für utf8_unicode_ci ) und berechnete dann die Durchschnittswerte.

Meine Ergebnisse sind:

benchmark_simple_select()

  • mit utf8_general_ci : 9.957 ms
  • mit utf8_unicode_ci : 10.271 ms

Bei diesem Benchmark werden utf8_unicode_ci ist langsamer als utf8_general_ci um 3,2%.

benchmark_select_like()

  • mit utf8_general_ci : 11.441 ms
  • mit utf8_unicode_ci : 12.811 ms

Bei diesem Benchmark werden utf8_unicode_ci ist langsamer als utf8_general_ci um 12 %.

benchmark_order_by()

  • mit utf8_general_ci : 11.944 ms
  • mit utf8_unicode_ci : 12,887 ms

Bei diesem Benchmark werden utf8_unicode_ci ist langsamer als utf8_general_ci um 7,9 %.

24 Stimmen

Schöner Benchmark, danke für die Mitteilung. Ich erhalte vernünftigerweise ähnliche Zahlen (MySQL v5.6.12 unter Windows): 10%, 4%, 8%. Ich stimme zu: Der Leistungsgewinn von utf8_general_ci ist einfach zu gering, um sich zu lohnen.

12 Stimmen

1) Aber sollte dieser Benchmark nicht per Definition ähnliche Ergebnisse für die beiden Zusammenstellungen liefern? Ich meine CONV(FLOOR(RAND() * 99999999999999), 20, 36) erzeugt nur ASCII- und keine Unicode-Zeichen, die von den Algorithmen der Kollationen verarbeitet werden. 2) Description = 'test' COLLATE ... y Description LIKE 'test%' COLLATE ... nur eine einzige Zeichenkette ("test") zur Laufzeit verarbeiten, nicht wahr? 3) In realen Anwendungen würden die in der Bestellung verwendeten Spalten wahrscheinlich indiziert, und die Indizierungsgeschwindigkeit bei verschiedenen Sortierungen mit echtem Nicht-ASCII-Text könnte unterschiedlich sein.

2 Stimmen

@HalilÖzgür - Ihr Standpunkt ist teilweise falsch. Ich schätze, es geht nicht darum, dass der Codepoint-Wert außerhalb von ASCII liegt (was general_ci korrekt handhaben würde), sondern um spezifische Eigenschaften, wie die Behandlung von Umlauten, die als "Uml" geschrieben werden ea ute" oder ähnliche Spitzfindigkeiten.

59voto

Michael Madsen Punkte 52883

Diese Stelle beschreibt es sehr schön.

Kurz gesagt: utf8_unicode_ci verwendet den in den Unicode-Standards definierten Unicode Collation Algorithm, während utf8_general_ci ist eine einfachere Sortierreihenfolge, die zu "weniger genauen" Sortierergebnissen führt.

18 Stimmen

Wenn man sich nicht um die Korrektheit kümmert, dann ist es trivial, jeden Algorithmus unendlich schnell zu machen. Verwenden Sie einfach utf8_unicode_ci und so tun, als gäbe es den anderen nicht.

3 Stimmen

@tchrist, aber wenn Sie auf ein gewisses Gleichgewicht zwischen Korrektheit und Geschwindigkeit achten, utf8_general_ci kann für Sie sein

5 Stimmen

@tchrist Niemals ein Spieleprogrammierer werden ;)

14voto

Dana the Sane Punkte 14222

Siehe das mysql-Handbuch, Unicode-Zeichensätze Abschnitt:

Für jeden Unicode-Zeichensatz, Operationen, die mit der _general_ci collation durchgeführt werden, schneller als die für die _unicode_ci collation. Zum Beispiel sind Vergleiche für die utf8_general_ci-Kollation schneller, aber etwas weniger korrekt, als Vergleiche für utf8_unicode_ci. Der Grund dafür ist, dass utf8_unicode_ci Mappings unterstützt wie als Expansionen unterstützt; das heißt, wenn ein Zeichen verglichen wird als gleich zu Kombinationen von anderen Zeichen. Für Beispiel: Im Deutschen und einigen anderen Sprachen ist " gleich "ss". utf8_unicode_ci unterstützt auch Kontraktionen und ignorierbare Zeichen. utf8_general_ci ist eine Legacy-Kollation die keine Expansionen unterstützt, Kontraktionen oder ignorierbare Zeichen unterstützt. Sie kann nur eins-zu-eins Vergleiche zwischen Zeichen durchführen.

Zusammenfassend lässt sich also sagen, dass utf_general_ci eine kleinere und weniger korrekte (dem Standard entsprechende) Menge von Vergleichen verwendet als utf_unicode_ci, die sollte die gesamte Norm umzusetzen. Der Satz general_ci wird schneller sein, weil weniger Berechnungen durchgeführt werden müssen.

20 Stimmen

So etwas wie "etwas weniger korrekt" gibt es nicht. Korrektheit ist eine boolesche Eigenschaft; sie lässt keine Modifikatoren des Grades zu. Verwenden Sie einfach utf8_unicode_ci und so tun, als gäbe es die fehlerhafte, kaputte Version nicht.

2 Stimmen

Ich hatte Probleme, 5.6.15 dazu zu bringen, die collation_connection-Einstellung zu übernehmen, und es stellte sich heraus, dass man sie in der SET-Zeile wie 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci' übergeben muss. Der Dank für die Lösung geht an Mathias Bynens, hier ist seine sehr nützliche Anleitung: mathiasbynens.be/notes/mysql-utf8mb4

6 Stimmen

@tchrist Das Problem bei der Behauptung, Korrektheit sei boolesch, ist, dass Situationen, die nicht auf absolute Korrektheit angewiesen sind, nicht berücksichtigt werden. Ihr grundlegender Punkt ist nicht ungültig, und ich versuche auch nicht, die Vorteile von general_ci zu verteidigen, aber Ihre allgemeine Aussage über Korrektheit ist leicht zu widerlegen. Ich tue das täglich in meinem Beruf. Spaß beiseite, Stuart hat ein gutes Argument ici .

13voto

Kamil Kiełczewski Punkte 69048

Einige Details (PL)

Wie wir lesen können aquí ( Peter Gulutzan ) gibt es einen Unterschied beim Sortieren/Vergleichen von polnischen Buchstaben "" (L mit Strich - html esc: Ł ) (Kleinschreibung: "" - html esc: ł ) - haben wir 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

Brief in polnischer Sprache ist nach dem Buchstaben L und vor M . Keine dieser Kodierungen ist besser oder schlechter - es hängt von Ihren Bedürfnissen ab.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X