Jürgen Herz
2006-01-24 12:50:48 UTC
Hallo,
mir liegt da ein Problem mit der Speicherung bzw. Interpretation von
Zeichen in MySQL im Magen.
Was ist zu tun damit Speicherung und Abfrage case sensitiv sind, u=u und
ü=ü, Multibyte-Zeichen auch als ein Zeichen angesehen werden und das
alles nicht auf Kosten der Performance geht?
Mit
`Titel` varchar(255) character set utf8 collate utf8_bin NOT NULL
default '',
bei DEFAULT CHARSET=utf8 - default Collation ist utf8_general_ci scheint
alles so zu funktionieren wie gewünscht.
Wobei für eine passable (ganz gefällt sie mir immer noch nicht) Sortierung
ORDER BY Titel COLLATE utf8_general_ci
nötig ist.
Aber ist das die beste Lösung?
Lange Erläuterung zum Problem:
Bis gestern hatte ich meine Textspalten wie diese hier
`Titel` varchar(255) character NOT NULL default '',
bei DEFAULT CHARSET=utf8 - default Collation ist utf8_general_ci.
Es gibt damit zwei Probleme:
1. Umlaute werden beim Einfügen übersehen. So darf nicht ein Datensatz
mit dem Unique Key 'Yürn' und eins 'Yurn' existieren. Für die Datenbank
ist anscheinend u=ü. Ebenso gibt die Abfrage SELECT Titel FROM Artikel
WHERE Titel = Yurn'; beide Sätze als Treffer aus.
2. Das Handling ist nicht case sensitiv - dabei sollte das, vor allem
für exotische Unicode-Zeichen, doch einfacher sein.
Um Abfragen doch case sensitiv zu machen, glaube ich irgendwo in der
MySQL-Doku gelesen zu haben, man solle
SELECT Titel FROM Artikel WHERE Titel COLLATE utf8_bin = 'Yurn';
nehmen. Und tatsächlich, das tut was es soll - nur ist ein SELECT damit
grauenhaft langsam (0,8 gegenüber 0,01 Sekunden) da lt. EXPLAIN der
Index nicht verwendet wird.
Jetzt steht in der MySQL-Doku (10.5.3. BINARY Operator), BINARY 'x' is
equivalent to 'x' COLLATE y, where y is the name of the binary collation
for the character set of 'x'. Müßte dann nicht
SELECT Titel FROM Artikel WHERE Titel COLLATE utf8_bin = 'Yurn';
gleich
SELECT Titel FROM Artikel WHERE Titel = BINARY 'Yurn';
sein, da ja utf8_bin die binary collation für utf8 sein sollte? Ist es
auch auf den ersten Blick vom Ergebnis her. Nur ist es fast so schnell
wie ohne Zusatz und es ist case sensitiv und u!=ü.
Leider gibt's doch ein Problem damit, denn
SELECT Titel FROM Artikel WHERE Titel LIKE BINARY 'Y_rn';
passt nur auf Yurn, nicht auf Yürn. Um das zu kriegen wird
SELECT Titel FROM Artikel WHERE Titel LIKE BINARY 'Y__rn';
(oder eben 'Y%rn') benötigt.
Wobei
SELECT Titel FROM Artikel WHERE Titel COLLATE utf8_bin LIKE 'Y_rn';
wahrscheinlich nur beide bringt weil da u und ü eben das Gleiche sind.
Grüße,
Jürgen
mir liegt da ein Problem mit der Speicherung bzw. Interpretation von
Zeichen in MySQL im Magen.
Was ist zu tun damit Speicherung und Abfrage case sensitiv sind, u=u und
ü=ü, Multibyte-Zeichen auch als ein Zeichen angesehen werden und das
alles nicht auf Kosten der Performance geht?
Mit
`Titel` varchar(255) character set utf8 collate utf8_bin NOT NULL
default '',
bei DEFAULT CHARSET=utf8 - default Collation ist utf8_general_ci scheint
alles so zu funktionieren wie gewünscht.
Wobei für eine passable (ganz gefällt sie mir immer noch nicht) Sortierung
ORDER BY Titel COLLATE utf8_general_ci
nötig ist.
Aber ist das die beste Lösung?
Lange Erläuterung zum Problem:
Bis gestern hatte ich meine Textspalten wie diese hier
`Titel` varchar(255) character NOT NULL default '',
bei DEFAULT CHARSET=utf8 - default Collation ist utf8_general_ci.
Es gibt damit zwei Probleme:
1. Umlaute werden beim Einfügen übersehen. So darf nicht ein Datensatz
mit dem Unique Key 'Yürn' und eins 'Yurn' existieren. Für die Datenbank
ist anscheinend u=ü. Ebenso gibt die Abfrage SELECT Titel FROM Artikel
WHERE Titel = Yurn'; beide Sätze als Treffer aus.
2. Das Handling ist nicht case sensitiv - dabei sollte das, vor allem
für exotische Unicode-Zeichen, doch einfacher sein.
Um Abfragen doch case sensitiv zu machen, glaube ich irgendwo in der
MySQL-Doku gelesen zu haben, man solle
SELECT Titel FROM Artikel WHERE Titel COLLATE utf8_bin = 'Yurn';
nehmen. Und tatsächlich, das tut was es soll - nur ist ein SELECT damit
grauenhaft langsam (0,8 gegenüber 0,01 Sekunden) da lt. EXPLAIN der
Index nicht verwendet wird.
Jetzt steht in der MySQL-Doku (10.5.3. BINARY Operator), BINARY 'x' is
equivalent to 'x' COLLATE y, where y is the name of the binary collation
for the character set of 'x'. Müßte dann nicht
SELECT Titel FROM Artikel WHERE Titel COLLATE utf8_bin = 'Yurn';
gleich
SELECT Titel FROM Artikel WHERE Titel = BINARY 'Yurn';
sein, da ja utf8_bin die binary collation für utf8 sein sollte? Ist es
auch auf den ersten Blick vom Ergebnis her. Nur ist es fast so schnell
wie ohne Zusatz und es ist case sensitiv und u!=ü.
Leider gibt's doch ein Problem damit, denn
SELECT Titel FROM Artikel WHERE Titel LIKE BINARY 'Y_rn';
passt nur auf Yurn, nicht auf Yürn. Um das zu kriegen wird
SELECT Titel FROM Artikel WHERE Titel LIKE BINARY 'Y__rn';
(oder eben 'Y%rn') benötigt.
Wobei
SELECT Titel FROM Artikel WHERE Titel COLLATE utf8_bin LIKE 'Y_rn';
wahrscheinlich nur beide bringt weil da u und ü eben das Gleiche sind.
Grüße,
Jürgen