Kann keine Umlaute in der DB speichern

Kann keine Umlaute in der DB speichern

am 08.06.2007 17:24:25 von Thomas Barth

Hallo,
ich kann machen was ich will, ich bekomme einfach keine Texte mit
Umlauten vollständig in die Datenbank. Ich habe eine csv-Datei, die ich
mit LOAD DATA einlese:

mysql -e "load data infile '/home/tbarth/workspace/tool/profiles.csv'
replace into table db.keywords fields terminated by ',' enclosed by '\''"

Texte werden vor dem Auftreten eines Umlautes einfach abgeschnitten.

z.B.: Frau mit kleinen Br

MySQL Version ist:
Server version: 5.0.40-log Gentoo Linux mysql-5.0.40


mysql> show variables;
| character_set_client | utf8|
| character_set_connection | utf8|
| character_set_database | utf8|
| character_set_filesystem | binary |
| character_set_results | utf8|
| character_set_server | utf8 |
| character_set_system | utf8
| character_sets_dir | /usr/share/mysql/charsets/|
| collation_connection | utf8_general_ci|
| collation_database | utf8_general_ci|
| collation_server | utf8_general_ci


Hat jemand vielleicht eine Idee, was da nicht stimmen könnte? Selbst
über PHP-Skripte bekomme ich die Texte nicht vollständig in die DB.

Gruß,
Thomas B

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 17:36:18 von Christian Kirsch

Am 08.06.2007 17:24 schrieb Thomas Barth:
> Hallo,
> ich kann machen was ich will, ich bekomme einfach keine Texte mit
> Umlauten vollständig in die Datenbank. Ich habe eine csv-Datei, die ich
> mit LOAD DATA einlese:
>
> mysql -e "load data infile '/home/tbarth/workspace/tool/profiles.csv'
> replace into table db.keywords fields terminated by ',' enclosed by '\''"
>
> Texte werden vor dem Auftreten eines Umlautes einfach abgeschnitten.
>
> z.B.: Frau mit kleinen Br
>

Und in welchem Encoding enthält deine CSV-Datei die Ümläute? Woher
*weißt* Du, dass die Texte "abgeschnitten" werden? (MaW: Womit guckst
Du sie Dir nach dem Import an?). Wie sieht Deine Tabellendefinition aus?

> MySQL Version ist:
> Server version: 5.0.40-log Gentoo Linux mysql-5.0.40
>
>
> mysql> show variables;
> | character_set_client | utf8|
> | character_set_connection | utf8|
> | character_set_database | utf8|
> | character_set_filesystem | binary |
> | character_set_results | utf8|
> | character_set_server | utf8 |
> | character_set_system | utf8
> | character_sets_dir | /usr/share/mysql/charsets/|
> | collation_connection | utf8_general_ci|
> | collation_database | utf8_general_ci|
> | collation_server | utf8_general_ci
>

Du hast also alles mögliche auf UTF-8 gestellt (ich frage jetzt mal
nicht, warum). Bist Du sicher, dass Deine CSV-Datei auch UTF-8 kodiert
ist?

>
> Hat jemand vielleicht eine Idee, was da nicht stimmen könnte? Selbst
> über PHP-Skripte bekomme ich die Texte nicht vollständig in die DB.
>

Was hat das jetzt mit PHP zu tun? Warum sollte eine weitere
Softwareschicht das Problem verschwinden lassen?

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 17:58:57 von Thomas Barth

Christian Kirsch wrote:
> Am 08.06.2007 17:24 schrieb Thomas Barth:
>> Hallo,
>> ich kann machen was ich will, ich bekomme einfach keine Texte mit
>> Umlauten vollständig in die Datenbank. Ich habe eine csv-Datei, die ich
>> mit LOAD DATA einlese:
>>
>> mysql -e "load data infile '/home/tbarth/workspace/tool/profiles.csv'
>> replace into table db.keywords fields terminated by ',' enclosed by '\''"
>>
>> Texte werden vor dem Auftreten eines Umlautes einfach abgeschnitten.
>>
>> z.B.: Frau mit kleinen Br
>>
>
> Und in welchem Encoding enthält deine CSV-Datei die Ümläute? Woher
> *weißt* Du, dass die Texte "abgeschnitten" werden? (MaW: Womit guckst
> Du sie Dir nach dem Import an?). Wie sieht Deine Tabellendefinition aus?
>
>> MySQL Version ist:
>> Server version: 5.0.40-log Gentoo Linux mysql-5.0.40
>>
>>
>> mysql> show variables;
>> | character_set_client | utf8|
>> | character_set_connection | utf8|
>> | character_set_database | utf8|
>> | character_set_filesystem | binary |
>> | character_set_results | utf8|
>> | character_set_server | utf8 |
>> | character_set_system | utf8
>> | character_sets_dir | /usr/share/mysql/charsets/|
>> | collation_connection | utf8_general_ci|
>> | collation_database | utf8_general_ci|
>> | collation_server | utf8_general_ci
>>
>
> Du hast also alles mögliche auf UTF-8 gestellt (ich frage jetzt mal
> nicht, warum). Bist Du sicher, dass Deine CSV-Datei auch UTF-8 kodiert
> ist?
>

Davon bin ich ausgegangen, als ich eine xls-Datei unter Linux mit
OpenOffice als csv-Datei abgespeichert hatte. Dem war aber nicht so:

$ file sql/profiles.csv
sql/profiles.csv: ISO-8859 text, with very long lines

Mit "character set 'latin1'" bekomme ich die Texte nun vollständig in die DB

Warum man sein System auf UTF-8 stellt?

What UTF-8 Can Do for You
UTF-8 allows you to work in a standards-compliant and internationally
accepted multilingual environment, with a comparatively low data
redundancy. UTF-8 is the preferred way for transmitting non-ASCII
characters over the Internet, through Email, IRC or almost any other
medium. Despite this, many people regard UTF-8 in online communication
as abusive. It is always best to be aware of the attitude towards UTF-8
in a specific channel, mailing list or Usenet group before using
non-ASCII UTF-8.

(Quelle: http://www.gentoo.org/doc/en/utf-8.xml)


>>
>> Hat jemand vielleicht eine Idee, was da nicht stimmen könnte? Selbst
>> über PHP-Skripte bekomme ich die Texte nicht vollständig in die DB.
>>
>
> Was hat das jetzt mit PHP zu tun? Warum sollte eine weitere
> Softwareschicht das Problem verschwinden lassen?

Weil PHP eine sehr einfache Sprache ist, die einem viel Arbeit abnimmt.
Ich hatte angenommen, dass PHP mir vielleicht etwas abnimmt, wovon ich
nichts wußte :-)

Gruß,
Thomas

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 18:17:18 von Christian Kirsch

Am 08.06.2007 17:58 schrieb Thomas Barth:
> Christian Kirsch wrote:

>> Du hast also alles mögliche auf UTF-8 gestellt (ich frage jetzt mal
>> nicht, warum). Bist Du sicher, dass Deine CSV-Datei auch UTF-8 kodiert
>> ist?
>>
>
> Davon bin ich ausgegangen, als ich eine xls-Datei unter Linux mit
> OpenOffice als csv-Datei abgespeichert hatte. Dem war aber nicht so:
>
> $ file sql/profiles.csv
> sql/profiles.csv: ISO-8859 text, with very long lines
>

Nicht weiter verwunderlich - CSV ist viel älter als Unicode, und man
würde vermutlich viele Anwendungen sehr unglücklich machen, wenn man
plötzlich Unicode-Zeichen exportierte.


> Warum man sein System auf UTF-8 stellt?
>
> What UTF-8 Can Do for You
> UTF-8 allows you to work in a standards-compliant and internationally
> accepted multilingual environment, with a comparatively low data
> redundancy. UTF-8 is the preferred way for transmitting non-ASCII
> characters over the Internet, through Email, IRC or almost any other
> medium.

Das halte ich für eine blatante Lüge. UTF-8 ist möglicherweise dann
"the preferred way", wenn die älteren ISO-Kodierungen nicht ausreichen
für das, was man vorhat. Andererseits reichen sie eben für das meiste
aus.

Das Zitierte ist sehr hübsch, aber keine Erklärung dafür, warum *du*
es tust. UTF-8 ist sinnvoll, wenn man Daten aus mehreren Sprachräumen
gleichzeitig verarbeiten will: Deutsch/Griechisch, Thai/Hebräisch.
Sowas eben. Wenn man aber nur Daten aus dem westeuropäischen
Sprachraum hat, dann reicht Latin-1 aus. Und es ist genauso
"standards-compliant", allerdings ganz ohne "data redundancy". Axel
hat neulich erst darauf hingewiesen, dass MySQL bei UTF-8 bis zu
dreimal soviel Platz für Textfelder benötigt wie bei Latin-1.

>> Was hat das jetzt mit PHP zu tun? Warum sollte eine weitere
>> Softwareschicht das Problem verschwinden lassen?
>
> Weil PHP eine sehr einfache Sprache ist, die einem viel Arbeit abnimmt.

Oder macht. Ein Problem, das Du mit mysql hast, dürfte auch ein
PHP-Skript nicht lösen können.

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 20:34:18 von Daniel Maus

Christian Kirsch schrieb:
> "standards-compliant", allerdings ganz ohne "data redundancy". Axel
> hat neulich erst darauf hingewiesen, dass MySQL bei UTF-8 bis zu
> dreimal soviel Platz für Textfelder benötigt wie bei Latin-1.

Hi,

sorry, wenn ich hier einfach mal nachhake. Benötigt UTF-8 tatsächlich
(bis zu ) 3x soviel Platz? Ich dachte immer, daß die "gebräuchlichsten"
Zeichen auch mit 1 Byte kodiert wären. Die meisten Zeichen, die ich via
UTF-8 mit 2 oder 3 oder mehr Byte kodiert sind, dürfte ich z.B. mit
Latin-1 sowieso nicht darstellen können. Oder hab ich hier einen Denkfehler?

Bis denne
Daniel

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 20:58:47 von Christian Kirsch

Daniel Maus schrieb:
> Christian Kirsch schrieb:
>> "standards-compliant", allerdings ganz ohne "data redundancy". Axel
>> hat neulich erst darauf hingewiesen, dass MySQL bei UTF-8 bis zu
>> dreimal soviel Platz für Textfelder benötigt wie bei Latin-1.
>
> Hi,
>
> sorry, wenn ich hier einfach mal nachhake. Benötigt UTF-8 tatsächlich
> (bis zu ) 3x soviel Platz? Ich dachte immer, daß die "gebräuchlichsten"
> Zeichen auch mit 1 Byte kodiert wären. Die meisten Zeichen, die ich via
> UTF-8 mit 2 oder 3 oder mehr Byte kodiert sind, dürfte ich z.B. mit
> Latin-1 sowieso nicht darstellen können. Oder hab ich hier einen Denkfehler?

UTF-8 kodiert alle ASCII-Zeichen mit 1 Byte. Alle Nicht-ASCII-Werte (und
dazu gehören Latin-1, Latin-2, aber auch Chinesisch usw.) brauchen mehr
als 1 Byte. Latin-1 immer zwei, IIRC.

Es gibt genau 128 2-Byte-Zeichen in UTF-8, die Du mit Latin-1 darstellen
kannst, und 128 1-Byte-Zeichen (ok, es sind jeweils weniger, weil da
nicht-druckbares dabei ist).

Wie auch immer: Wenn Du in MySQL
bla CHAR(20)
für eine Latin-1-Spalte definierst, dann braucht MySQL 20 Byte dafür.
Klarerweise, denn ein Byte = 1 CHAR. Wenn Du dasselbe für UTF-8 machst,
dann ... tja, dann muss MySQL (und jedes andere Produkt)
- entweder den worst case annehmen und 3 Byte pro Zeichen allozieren
-> 60 Byte statt 20
- oder auf variable Recordlängen ausweichen, was der Performance nun
auch nicht unbedingt gut tut.

Mehr Möglichkeiten fallen mir nicht ein.

Axels Posting: <3h0dj4-nai.ln1@xl.homelinux.org>

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 21:46:05 von Thomas Barth

Christian Kirsch wrote:

> Wie auch immer: Wenn Du in MySQL
> bla CHAR(20)
> für eine Latin-1-Spalte definierst, dann braucht MySQL 20 Byte dafür.
> Klarerweise, denn ein Byte = 1 CHAR. Wenn Du dasselbe für UTF-8 machst,
> dann ... tja, dann muss MySQL (und jedes andere Produkt)
> - entweder den worst case annehmen und 3 Byte pro Zeichen allozieren
> -> 60 Byte statt 20

Bei den heutigen Speichervolumen völlig egal.

> - oder auf variable Recordlängen ausweichen, was der Performance nun
> auch nicht unbedingt gut tut.
>

Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
die Performance sogar gesteigert wird!

Gruß,
Thomas B

Re: Kann keine Umlaute in der DB speichern

am 08.06.2007 23:18:49 von Christoph Jeschke

Thomas Barth schrub:

> Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
> die Performance sogar gesteigert wird!

Magst Du uns auch noch erhellen, wieso Du dies vermutest?

--
Today is Prickle-Prickle, the 13rd day of Confusion in the YOLD 3173

Re: Kann keine Umlaute in der DB speichern

am 09.06.2007 00:38:45 von Christian Kirsch

Thomas Barth schrieb:
> Christian Kirsch wrote:
>
>> Wie auch immer: Wenn Du in MySQL
>> bla CHAR(20)
>> für eine Latin-1-Spalte definierst, dann braucht MySQL 20 Byte dafür.
>> Klarerweise, denn ein Byte = 1 CHAR. Wenn Du dasselbe für UTF-8 machst,
>> dann ... tja, dann muss MySQL (und jedes andere Produkt)
>> - entweder den worst case annehmen und 3 Byte pro Zeichen allozieren
>> -> 60 Byte statt 20
>
> Bei den heutigen Speichervolumen völlig egal.

Yep. Hau wech den Scheiß. Mag ja sein, dass Du einfach mal so dass
Dreifache an Platten- und Speicherplatz sowie Netz-Traffic verbrauchen
möchtest. Besonders pfiffig finde ich das jedenfalls nicht.

Hast Du eigentlich auch einen *Grund*, UTF-8 zu verwenden, oder
arbeitest Du einfach nur nach dem Motto "weil's geht"? Dann könntest Du
doch auch gleich die Volle Lotte machen und den ganzen Unicode-Raum
benutzen: Zeichen als 4-Byte-Integer speichern. Platz ist ja genug da, gell.

>
>> - oder auf variable Recordlängen ausweichen, was der Performance nun
>> auch nicht unbedingt gut tut.
>>
>
> Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
> die Performance sogar gesteigert wird!

Du meinst, variable Recordlängen könnten mehr Performance bringen als
feste? Dann solltest Du Dir dieses brillante Verfahren einfach
patentieren lassen.

Re: Kann keine Umlaute in der DB speichern

am 09.06.2007 10:31:10 von Thomas Rachel

Thomas Barth wrote:

> Christian Kirsch wrote:
>
>> Wie auch immer: Wenn Du in MySQL
>> bla CHAR(20)
>> für eine Latin-1-Spalte definierst, dann braucht MySQL 20 Byte dafür.
>> Klarerweise, denn ein Byte = 1 CHAR. Wenn Du dasselbe für UTF-8
>> machst, dann ... tja, dann muss MySQL (und jedes andere Produkt)
>> - entweder den worst case annehmen und 3 Byte pro Zeichen allozieren
>> -> 60 Byte statt 20
>
> Bei den heutigen Speichervolumen völlig egal.

Bezogen auf ein Zeichen? Völlig richtig. Eine Benzinpreiserhöhung um 6
Cent ist auch egal. 6 Cent sind ja nicht viel. (Blödes Beispiel, ich
weiß.)

Ach, die Menge machts? Ja, stimmt. Eine Tabelle mit 10 Millionen
Einträgen und 5 Textfeldern zu je durchschnittlich 20 Zeichen - das
macht 10^9 Zeichen - also 3 GB zu 1 GB.


> Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
> die Performance sogar gesteigert wird!

Durch variable Recordlängen, bei der ein zusätzlicher Berechnungsschritt
notwendig ist?


Thomas
--
Das Fleisch war willig, aber das Gras war naß.

Re: Kann keine Umlaute in der DB speichern

am 10.06.2007 22:19:52 von Axel Schwenke

Daniel Maus wrote:
> Christian Kirsch schrieb:

>> "standards-compliant", allerdings ganz ohne "data redundancy". Axel
>> hat neulich erst darauf hingewiesen, dass MySQL bei UTF-8 bis zu
>> dreimal soviel Platz für Textfelder benötigt wie bei Latin-1.
>
> sorry, wenn ich hier einfach mal nachhake. Benötigt UTF-8 tatsächlich
> (bis zu ) 3x soviel Platz? Ich dachte immer, daß die "gebräuchlichsten"
> Zeichen auch mit 1 Byte kodiert wären. Die meisten Zeichen, die ich via
> UTF-8 mit 2 oder 3 oder mehr Byte kodiert sind, dürfte ich z.B. mit
> Latin-1 sowieso nicht darstellen können. Oder hab ich hier einen Denkfehler?

Die Hälfte der latin1-Zeichen (alle mit Codes > 127) werden in utf8 als
2-Byte Sequenzen dargestellt. Wenn alle Zeichen gleich häufig vorkommen,
wird utf8 also ca. den 1.5 fachen Platz brauchen im Vergleich zu latin1.
Bei realistischer Verteilung der Zeichen (etwa für deutsche Texte)
vermutlich eher das 1.05 fache.

Aber das ist nicht der Punkt.

Das gilt nämlich nur für dynamisch allozierte Datenstrukturen (etwa der
Buffer für eine VARCHAR() Spalte). MySQL verwendet aber aus Performance-
gründen so oft wie möglich statische Buffer (malloc() ist teuer). Da
dann eine Re-Allozierung nicht vorgesehen ist, muß MySQL den Buffer
pessimistisch dimensieren. Für utf8 heißt das 3 Byte pro Zeichen.
Das trifft dich z.B. für CHAR() Spalten direkt. Aber auch sort-Buffer
oder record-Buffer zum (De)Assemblieren eines Records (etwa für die
Ausführung eines UPDATE Statements) werden statisch alloziert.

Eine andere Stelle wo utf8 beißt, sind Limits. So kann z.B. MyISAM nur
Indexes bis max. 1000 Bytes. Du kannst also einen UNIQUE INDEX über 3x
VARCHAR(255) latin1 legen. Bei utf8 braucht aber schon eine VARCHAR(255)
Spalte pessimal 765 Bytes. Demnach erlaubt dir MySQL einen Index nur
über maximal 333 utf8-Zeichen.

Noch ein Problem mit utf8: bei einem latin1-String ist die Länge (in
Zeichen) gleich der Länge in Bytes. Bei utf8 ist das nicht so. Da muß
man tatsächlich die Sequenzen durchgehen, um die Länge heraus zu
bekommen. Man kann zwar abkürzen (man braucht nur die obersten 2 Bits
zu betrachten) - aber dann geht einem evtl. eine illegale Sequenz durch
die Lappen. Korrekterweise muß man jeden fremden utf8-String ohnehin
erst mal auf Konformität prüfen. Alles das kostet CPU-Zeit.


XL

Re: Kann keine Umlaute in der DB speichern

am 11.06.2007 09:52:13 von Claus Reibenstein

Thomas Rachel schrieb:

> Thomas Barth wrote:
>
>> Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
>> die Performance sogar gesteigert wird!
>
> Durch variable Recordlängen, bei der ein zusätzlicher Berechnungsschritt
> notwendig ist?

Welcher "zusätzliche Berechnungsschritt"?

Eine variable Satzlänge kann durchaus Vorteile haben. Die Sätze belegen
dadurch i.d.R. weniger Platz, wodurch mehr Datensätze im Cacne gehalten
werden können. So verkehrt ist der Gedanke also nicht.

Ob es bei MySQL tatsächlich messbare Unterschiede gibt, lässt sich nur
durch Tests ermitteln. Hat von Euch schon mal jemand einen solchen Test
durchgeführt?

Gruß. Claus

Re: Kann keine Umlaute in der DB speichern

am 11.06.2007 09:54:59 von Christian Kirsch

Am 11.06.2007 09:52 schrieb Claus Reibenstein:
> Thomas Rachel schrieb:
>
>> Thomas Barth wrote:
>>
>>> Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
>>> die Performance sogar gesteigert wird!
>> Durch variable Recordlängen, bei der ein zusätzlicher Berechnungsschritt
>> notwendig ist?
>
> Welcher "zusätzliche Berechnungsschritt"?
>

Der für den Zugriff? Trivialerweise ist der Code für das
Lesen/Schreiben von Datensätzen mit fester Länge unkomplizierter und
läuft schneller als der für Datensätze mit variabler Länge.

Re: Kann keine Umlaute in der DB speichern

am 12.06.2007 08:23:34 von Axel Schwenke

Claus Reibenstein <4spammersonly@web.de> wrote:
> Thomas Rachel schrieb:
>> Thomas Barth wrote:
>>
>>> Gemessen hast du die Performance nicht! Ich kann mir vorstellen, dass
>>> die Performance sogar gesteigert wird!
>>
>> Durch variable Recordlängen, bei der ein zusätzlicher Berechnungsschritt
>> notwendig ist?
>
> Welcher "zusätzliche Berechnungsschritt"?

Tatsächlich ist es sogar ein Schritt weniger - zumindest wenn man
voraussetzt, daß über einen Index zugegriffen wird. Bei konstanter
Recordlänge speichert MySQL eine Record-Nummer im Index und findet
den Record im Datenfile an Position Record-Nr * konstante Record-
länge. Bei variablen Records steht im Index direkt die Position
im Datenfile. Allerdings kann man bei gleicher "Zeiger"-Länge mit
gleich langen Records mehr Daten addressieren.

(das stimmt so nur für MyISAM, bei InnoDB läuft das anders)

> Eine variable Satzlänge kann durchaus Vorteile haben. Die Sätze belegen
> dadurch i.d.R. weniger Platz, wodurch mehr Datensätze im Cacne gehalten
> werden können. So verkehrt ist der Gedanke also nicht.

So lange man nur liest, bringen variable Records keine Nachteile
(außer vielleicht, daß beim blockweisen Lesen keine konstante
Anzahl Records gelesen werden kann).

Die Probleme kommen beim Schreiben:
- bei einem UPDATE kann der Record länger werden, paßt also nicht
mehr an die alte Position. Es muß eine neue Position gefunden
werden und alle Indexe müssen angepaßt werden.
- nach DELETE (oder evtl. UPDATE) bleiben Lücken. Die müssen verwaltet
werden und es ist auch nicht gewährleistet, daß ein neuer Record in
eine beliebige Lücke paßt.

Langfristig führen variable-length Records zu fragmentierten Daten-
files. Der Vorteil des geringeren Platzverbrauchs wird dann ganz
schnell ad absurdum geführt.


XL