php - utf8_encode - utf8mb4




Was ist die beste Sortierung fΓΌr MySQL mit PHP? (8)

Ich frage mich, ob es eine "beste" Wahl für die Sortierung in MySQL für eine allgemeine Website gibt, wo Sie nicht 100% sicher sind, was eingegeben wird? Ich verstehe, dass alle Kodierungen die selben sein sollten, wie MySQL, Apache, das HTML und alles innerhalb von PHP.

In der Vergangenheit habe ich festgelegt, dass PHP in "UTF-8" ausgeben soll, aber welche Sortierung passt zu MySQL? Ich denke, es ist einer der UTF-8, aber ich habe utf8_unicode_ci , utf8_general_ci und utf8_bin vorher verwendet.


Der Hauptunterschied liegt in der Sortiergenauigkeit (beim Vergleich von Zeichen in der Sprache) und der Leistung. Der einzige spezielle ist utf8_bin, der Zeichen im Binärformat vergleicht.

utf8_general_ci ist etwas schneller als utf8_unicode_ci , aber weniger genau (zum Sortieren). Die spezifische Sprache utf8 encoding (z. B. utf8_swedish_ci ) enthält zusätzliche Sprachregeln, die die Sortierung für diese Sprachen am genauesten machen. Die meiste Zeit benutze ich utf8_unicode_ci (ich bevorzuge Genauigkeit zu kleinen Leistungsverbesserungen), es sei denn, ich habe einen guten Grund, eine bestimmte Sprache zu bevorzugen.

Sie können mehr über spezifische Unicode-Zeichensätze im MySQL-Handbuch lesen - http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html


Die akzeptierte Antwort legt ziemlich definitiv nahe, utf8_unicode_ci zu verwenden, und während für neue Projekte das großartig ist, wollte ich meine aktuelle gegensätzliche Erfahrung nur für den Fall in Verbindung bringen, dass es irgendjemanden Zeit spart.

Da utf8_general_ci die Standardsortierung für Unicode in MySQL ist, müssen Sie utf8_unicode_ci an vielen Stellen angeben.

Zum Beispiel haben alle Client-Verbindungen nicht nur einen Standard-Zeichensatz (für mich sinnvoll), sondern auch eine Standard-Sortierung (dh die Sortierung wird immer auf utf8_general_ci für Unicode eingestellt).

Wenn Sie utf8_unicode_ci für Ihre Felder verwenden, müssen Ihre Skripts, die eine Verbindung zur Datenbank herstellen, wahrscheinlich explizit die gewünschte Sortierung angeben. Andernfalls können Abfragen, die Textzeichenfolgen verwenden, fehlschlagen, wenn Ihre Verbindung die Standardsortierung verwendet.

Das Ergebnis ist, dass Sie beim Konvertieren eines vorhandenen Systems mit einer beliebigen Größe in Unicode / utf8 möglicherweise gezwungen werden, utf8_general_ci zu verwenden, da MySQL Standardwerte verarbeitet.


Fügen Sie in Ihrer Datenbank-Upload-Datei die folgende Zeile vor jeder Zeile hinzu:

SET NAMES utf8;

Und dein Problem sollte gelöst werden.


Für UTF-8-Textinformationen sollten Sie utf8_general_ci weil ...

  • utf8_bin : vergleicht Zeichenfolgen mit dem Binärwert jedes Zeichens in der Zeichenfolge

  • utf8_general_ci : vergleicht Zeichenfolgen mit allgemeinen Sprachregeln und verwendet utf8_general_ci Groß- / Kleinschreibung

aka wird es die Suche und Indizierung der Daten schneller / effizienter / nützlicher machen.



Im Wesentlichen hängt es davon ab, wie Sie von einer Saite denken.

Ich benutze immer utf8_bin wegen des von Guus hervorgehobenen Problems. Meiner Meinung nach ist eine Zeichenkette, was die Datenbank betrifft, immer noch nur eine Zeichenkette. Eine Zeichenfolge ist eine Anzahl von UTF-8-Zeichen. Ein Charakter hat eine binäre Darstellung, warum braucht er also die Sprache, die du benutzt? In der Regel werden Menschen Datenbanken für Systeme mit dem Umfang für mehrsprachige Websites erstellen. Das ist der Sinn von UTF-8 als Zeichensatz. Ich bin ein bisschen pure, aber ich denke, dass der Bug den leichten Vorteil, den man beim Indizieren bekommen kann, stark überwiegt. Alle sprachbezogenen Regeln sollten auf einer viel höheren Ebene als das DBMS durchgeführt werden.

In meinen Büchern sollte "Wert" niemals in einer Million Jahren "value" entsprechen.

Wenn ich ein Textfeld speichern und eine Suche ohne Berücksichtigung der Groß- / Kleinschreibung durchführen möchte, verwende ich MYSQL-String-Funktionen mit PHP-Funktionen wie LOWER () und der php-Funktion strtolower ().


Sortierfolgen beeinflussen, wie Daten sortiert werden und wie Zeichenfolgen miteinander verglichen werden. Das bedeutet, dass Sie die Kollatierung verwenden sollten, die die meisten Benutzer erwarten.

Beispiel aus der documentation :

utf8_general_ci auch für Deutsch und Französisch zufriedenstellend, außer dass "ß" gleich "s" ist und nicht "ss". Wenn dies für Ihre Anwendung akzeptabel ist, sollten Sie utf8_general_ci weil es schneller ist. Verwenden utf8_unicode_ci andernfalls utf8_unicode_ci da dies genauer ist.

Also - es hängt von Ihrer erwarteten Benutzerbasis ab und davon, wie viel Sie richtig sortieren müssen. Für eine englische Benutzerbasis sollte utf8_general_ci ausreichen, für andere Sprachen wie Schwedisch wurden spezielle utf8_general_ci erstellt.


Verwenden Sie am besten den Zeichensatz utf8mb4 mit der Sortierung utf8mb4_unicode_ci .

Der Zeichensatz utf8 unterstützt nur eine kleine Anzahl von UTF-8-Codepunkten, etwa 6% der möglichen Zeichen. utf8 unterstützt nur die Basic Multilingual Plane (BMP). Es gibt 16 andere Flugzeuge. Jede Ebene enthält 65.536 Zeichen. utf8mb4 unterstützt alle 17 Flugzeuge.

MySQL schneidet 4-Byte-UTF-8-Zeichen ab, was zu beschädigten Daten führt.

Der utf8mb4 Zeichensatz wurde am 2010-03-24 in MySQL 5.5.3 eingeführt.

Einige der erforderlichen Änderungen zur Verwendung des neuen Zeichensatzes sind nicht trivial:

  • Möglicherweise müssen in Ihrem Anwendungsdatenbankadapter Änderungen vorgenommen werden.
  • Es müssen Änderungen an my.cnf vorgenommen werden, einschließlich der Einstellung des Zeichensatzes, der Sortierung und dem Wechsel von innodb_file_format zu Barracuda
  • SQL CREATE-Anweisungen müssen möglicherweise ROW_FORMAT=DYNAMIC enthalten: ROW_FORMAT=DYNAMIC
    • DYNAMIC wird für Indizes für VARCHAR (192) und größer benötigt.

HINWEIS: Wenn Sie von Antelope zu Barracuda Antelope , müssen Sie möglicherweise den MySQL-Dienst mehrmals neu starten. innodb_file_format_max ändert sich erst, nachdem der MySQL-Dienst neu gestartet wurde: innodb_file_format = barracuda .

MySQL verwendet das alte Antelope InnoDB-Dateiformat. Barracuda unterstützt dynamische Zeilenformate, die Sie benötigen, wenn Sie nach dem Wechsel zum Zeichensatz die SQL-Fehler zum Erstellen von Indizes und Schlüsseln nicht mehr treffen wollen: utf8mb4

  • # 1709 - Indexspaltengröße zu groß. Die maximale Spaltengröße beträgt 767 Bytes.
  • # 1071 - Der angegebene Schlüssel war zu lang; Die maximale Schlüssellänge beträgt 767 Byte

Das folgende Szenario wurde in MySQL 5.6.17 getestet: Standardmäßig ist MySQL wie folgt konfiguriert:

SHOW VARIABLES;

innodb_large_prefix = OFF
innodb_file_format = Antelope

Stoppen Sie Ihren MySQL-Dienst und fügen Sie die Optionen zu Ihrer bestehenden my.cnf hinzu:

[client]
default-character-set= utf8mb4

[mysqld]
explicit_defaults_for_timestamp = true
innodb_large_prefix = true
innodb_file_format = barracuda
innodb_file_format_max = barracuda
innodb_file_per_table = true

# Character collation
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci

Beispiel SQL CREATE-Anweisung:

CREATE TABLE Contacts (
 id INT AUTO_INCREMENT NOT NULL,
 ownerId INT DEFAULT NULL,
 created timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 contact VARCHAR(640) NOT NULL,
 prefix VARCHAR(128) NOT NULL,
 first VARCHAR(128) NOT NULL,
 middle VARCHAR(128) NOT NULL,
 last VARCHAR(128) NOT NULL,
 suffix VARCHAR(128) NOT NULL,
 notes MEDIUMTEXT NOT NULL,
 INDEX IDX_CA367725E05EFD25 (ownerId),
 INDEX created (created),
 INDEX modified_idx (modified),
 INDEX contact_idx (contact),
 PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT=DYNAMIC;
  • Sie können den Fehler # 1709 für INDEX contact_idx (contact) wenn ROW_FORMAT=DYNAMIC aus der CREATE-Anweisung entfernt wird.

HINWEIS: Wenn Sie den Index so ROW_FORMAT=DYNAMIC , dass er auf die ersten 128 Zeichen eines contact entfällt die Verwendung von Barracuda mit ROW_FORMAT=DYNAMIC

INDEX contact_idx (contact(128)),

Beachten Sie auch: Wenn die Größe des Feldes VARCHAR(128) lautet, sind es keine 128 Bytes. Sie können 128, 4 Byte Zeichen oder 128, 1 Byte Zeichen verwenden.

Diese INSERT Anweisung sollte das 4-Byte-Zeichen "poo" in der 2 Zeile enthalten:

INSERT INTO `Contacts` (`id`, `ownerId`, `created`, `modified`, `contact`, `prefix`, `first`, `middle`, `last`, `suffix`, `notes`) VALUES
(1, NULL, '0000-00-00 00:00:00', '2014-08-25 03:00:36', '1234567890', '12345678901234567890', '1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678', '', ''),
(2, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', '', ''),
(3, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', 'πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', '123πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©πŸ’©', '', '');

Sie können den von der last Spalte belegten Speicherplatz sehen:

mysql> SELECT BIT_LENGTH(`last`), CHAR_LENGTH(`last`) FROM `Contacts`;
+--------------------+---------------------+
| BIT_LENGTH(`last`) | CHAR_LENGTH(`last`) |
+--------------------+---------------------+
|               1024 |                 128 | -- All characters are ASCII
|               4096 |                 128 | -- All characters are 4 bytes
|               4024 |                 128 | -- 3 characters are ASCII, 125 are 4 bytes
+--------------------+---------------------+

In Ihrem Datenbankadapter möchten Sie möglicherweise den Zeichensatz und die Sortierung für Ihre Verbindung festlegen:

SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'

In PHP wäre dies für: \PDO::MYSQL_ATTR_INIT_COMMAND

Verweise:





collation