web-dev-qa-db-de.com

Was ist der Unterschied zwischen utf8_general_ci und utf8_unicode_ci?

Gibt es zwischen utf8_general_ci und utf8_unicode_ci Leistungsunterschiede?

972
KahWee Teng

Diese beiden Kollatierungen gelten beide für die UTF-8-Zeichenkodierung. Die Unterschiede bestehen darin, wie Text sortiert und verglichen wird.

Hinweis: Seit MySQL 5.5.3 sollten Sie utf8mb4 anstelle von utf8 verwenden. Sie beziehen sich beide auf die UTF-8-Codierung, aber der ältere utf8 hatte eine MySQL-spezifische Einschränkung, die die Verwendung von Zeichen mit einer Nummer über 0xFFFD verhinderte.

Wichtige Unterschiede

  • utf8mb4_unicode_ci basiert auf den offiziellen Unicode-Regeln für universelles 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 verwendet, um die Geschwindigkeit zu verbessern. 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 so gut wie zu vernachlässigen. Es wurde in einer Zeit entwickelt, in der Server einen winzigen Bruchteil der CPU-Leistung heutiger Computer hatten.

Hinweis: Es gibt jetzt eine aktualisierte Version von utf8mb4_unicode_ci mit dem Namen utf8mb4_0900_ai_ci - diese basiert auf Änderungen in Unicode Version 9.0 und ist anscheinend auch schneller. Es wird ein neues Benennungsschema eingeführt, bei dem 0900 die Unicode-Version ist und ai für akzentunempfindlich steht - wie beim vorherigen utf8mb4_unicode_ci werden Akzente in Buchstaben nicht als signifikant angesehen .

Vorteile von utf8mb4_unicode_ci gegenüber utf8mb4_general_ci

utf8mb4_unicode_ci, der die Unicode-Regeln zum Sortieren und Vergleichen verwendet, verwendet einen ziemlich komplexen Algorithmus für die korrekte Sortierung 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 sogenannten alphabetischen reihenfolge.

In Bezug auf lateinische (dh "europäische") Sprachen gibt es in MySQL keinen großen Unterschied zwischen der Unicode-Sortierung und der vereinfachten utf8mb4_general_ci-Sortierung, aber es gibt immer noch einige Unterschiede:

  • Beispielsweise sortiert die Unicode-Kollatierung "ß" wie "ss" und "Œ" wie "OE", wenn Benutzer diese Zeichen normalerweise verwenden möchten, während utf8mb4_general_ci sie als einzelne Zeichen sortiert (vermutlich wie "s" bzw. "e") ).

  • Einige Unicode-Zeichen werden als ignorierbar definiert. Dies bedeutet, dass sie nicht in die Sortierreihenfolge einbezogen werden und der Vergleich stattdessen zum nächsten Zeichen fortgesetzt werden soll. utf8mb4_unicode_ci handhabt diese ordnungsgemäß.

In nicht-lateinischen Sprachen, wie z. B. asiatischen Sprachen oder Sprachen mit unterschiedlichen Alphabeten, gibt es möglicherweise viele mehr Unterschiede zwischen der Unicode-Sortierung und der vereinfachten utf8mb4_general_ci-Sortierung. Die Eignung von utf8mb4_general_ci hängt stark von der verwendeten Sprache ab. Für einige Sprachen ist dies nicht ausreichend.

Was solltest du verwenden?

Es gibt mit ziemlicher Sicherheit keinen Grund mehr, utf8mb4_general_ci 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 eingeschränkt.

In der Vergangenheit wurde empfohlen, utf8mb4_general_ci zu verwenden, es sei denn, eine genaue Sortierung war wichtig genug, um die Leistungskosten zu rechtfertigen. Heute sind diese Leistungskosten so gut wie verschwunden, und die Entwickler nehmen die Internationalisierung ernst.

Es muss argumentiert werden, dass, wenn Geschwindigkeit für Sie wichtiger ist als Genauigkeit, Sie auch überhaupt keine Sortierung vornehmen können. Es ist trivial, einen Algorithmus schneller zu machen, wenn Sie keine Genauigkeit benötigen. utf8mb4_general_ci ist also ein 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, auch wenn Sie wissen, dass sie nur die englische Sprache unterstützt, möglicherweise noch mit den Namen von Personen umgehen muss. Diese können 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 zur Beruhigung bei, dass die sehr intelligenten Unicode-Mitarbeiter sehr hart daran gearbeitet haben, dass das Sortieren ordnungsgemäß funktioniert.

Was bedeuten die Teile

Erstens dient ci zum Sortieren und Vergleichen ohne Berücksichtigung der Groß-/Kleinschreibung . Dies bedeutet, dass es für Textdaten geeignet ist und die Groß- und Kleinschreibung nicht wichtig ist. Die anderen Sortierungstypen sind cs (Groß-/Kleinschreibung beachten) für Textdaten, bei denen die Groß-/Kleinschreibung wichtig ist, und bin, bei denen die Codierung Bit für Bit übereinstimmen muss, was für Felder geeignet ist, die sind wirklich codierte Binärdaten (einschließlich zum Beispiel Base64). Die Sortierung nach Groß- und Kleinschreibung führt zu seltsamen Ergebnissen, und der Vergleich nach Groß- und Kleinschreibung kann zu doppelten Werten führen, die sich nur in Groß- und Kleinschreibung unterscheiden. Daher sind Sortierungen nach Groß- und Kleinschreibung für Textdaten ungünstig und so weiter ist wahrscheinlich auch von Bedeutung, und eine binäre Sortierung könnte geeigneter sein.

Als nächstes bezieht sich unicode oder general auf die spezifischen Sortier- und Vergleichsregeln - insbesondere auf die Art und Weise, wie Text normalisiert oder verglichen wird. Es gibt viele verschiedene Regelsätze für die utf8mb4-Zeichencodierung, wobei unicode und general zwei sind, die versuchen, in allen möglichen Sprachen und nicht in einer bestimmten Sprache gut zu funktionieren. Die Unterschiede zwischen diesen beiden Regelwerken sind Gegenstand dieser Antwort. Beachten Sie, dass neuere Regelsätze 0900 für Unicode 9.0 und unicode_520 für Unicode 5.2 enthalten.

Und schließlich ist utf8mb4 natürlich die intern verwendete Zeichenkodierung. In dieser Antwort spreche ich nur von Unicode-basierten Codierungen.

1477
thomasrutter

Ich wollte wissen, was der Leistungsunterschied zwischen der Verwendung von utf8_general_ci und utf8_unicode_ci ist, fand jedoch keine im Internet aufgeführten 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 einfache SELECT, SELECT mit LIKE und Sortierung (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 obigen gespeicherten Prozeduren wird die Sortierung utf8_general_ci verwendet, aber natürlich habe ich während der Tests sowohl utf8_general_ci als auch utf8_unicode_ci verwendet.

Ich habe jede gespeicherte Prozedur fünfmal für jede Kollation aufgerufen (fünfmal für utf8_general_ci und fünfmal für utf8_unicode_ci) und dann die Durchschnittswerte berechnet.

Meine Ergebnisse sind:

benchmark_simple_select()

  • mit utf8_general_ci: 9.957 ms
  • mit utf8_unicode_ci: 10,271 ms

In diesem Benchmark ist die Verwendung von utf8_unicode_ci um 3,2% langsamer als utf8_general_ci.

benchmark_select_like()

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

In diesem Benchmark ist die Verwendung von utf8_unicode_ci um 12% langsamer als utf8_general_ci.

benchmark_order_by()

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

In diesem Benchmark ist die Verwendung von utf8_unicode_ci um 7,9% langsamer als utf8_general_ci.

149
nightcoder

Dieser Beitrag beschreibt es sehr schön.

Kurz gesagt: utf8_unicode_ci verwendet den in den Unicode-Standards definierten Unicode-Kollatierungsalgorithmus, wohingegen utf8_general_ci eine einfachere Sortierreihenfolge ist, die zu "weniger genauen" Sortierergebnissen führt.

36
Michael Madsen

Siehe das mysql-Handbuch, Abschnitt nicode Character Sets :

Operationen, die mit der _general_ci-Kollatierung ausgeführt werden, sind für jeden Unicode-Zeichensatz schneller als für die _unicode_ci-Kollatierung. Beispielsweise sind Vergleiche für die Sortierung 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 z. B. Erweiterungen unterstützt. Das heißt, wenn ein Zeichen mit Kombinationen anderer Zeichen verglichen wird. Zum Beispiel ist in Deutsch und einigen anderen Sprachen "ß" gleich "ss". utf8_unicode_ci unterstützt auch Kontraktionen und ignorierbare Zeichen. utf8_general_ci ist eine Legacy-Kollatierung, 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 Vergleichssatz (gemäß Standard) als utf_unicode_ci, der den gesamten Standard implementieren sollte . Die general_ci-Menge ist schneller, da weniger Berechnungen erforderlich sind.

8
Dana the Sane

In kurzen Worten:

Wenn Sie eine bessere Sortierreihenfolge benötigen, verwenden Sie utf8_unicode_ci (dies ist die bevorzugte Methode).

wenn Sie sich jedoch voll und ganz für Performance interessieren, verwenden Sie utf8_general_ci, aber Sie wissen, dass es ein wenig veraltet ist.

Die Leistungsunterschiede sind sehr gering.

5
simhumileco

Einige Details (PL)

Wie wir lesen können hier ( Peter Gulutzan ) gibt es einen Unterschied beim Sortieren/Vergleichen des polnischen Buchstabens "£" (L mit dem Strich - html esc: Ł) (Kleinbuchstabe: "ł" - 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 vor dem Buchstaben M. Keiner dieser Codes ist besser oder schlechter - es hängt von Ihren Bedürfnissen ab.

2