Wie wähle ich eine Kollatierung für eine internationale Datenbank aus?


22

Ich entwerfe eine Datenbank, in der Daten in verschiedenen Sprachen gespeichert werden (unter Verwendung von UTF-8). Ich denke, die beste Möglichkeit, die Ergebnisse der Abfrage anzuzeigen, besteht darin, sie gemäß der Sprache des Benutzers während der Abfrage selbst zu ordnen ( da es mehr als eine gibt) richtige Art und Weise zu tun , dass ), wie folgt:

SELECT a < b COLLATE "de_DE" FROM test1;

Angenommen, dies ist die richtige Art und Weise, mit internationalen Daten zu arbeiten. Welches ist die beste Sortierung für die Datenbank selbst? In der PostgreSQL-Dokumentation heißt es :

Die Sortierungen C und POSIX geben das "traditionelle C" -Verhalten an, bei dem nur die ASCII-Buchstaben "A" bis "Z" als Buchstaben behandelt werden, und die Sortierung erfolgt streng nach Zeichencode-Bytewerten.

Ich denke, das ist die beste Wahl in diesem Fall, oder irre ich mich?

(Bonusfrage: Ist es zu langsam, die Sortierung in der Abfrage selbst auszuwählen?)


2
Die größte Schwierigkeit besteht darin, dass Sie in einer mehrsprachigen Datenbank viele Indizes benötigen, da die Indizes für kollatierbaren Text kollationsspezifisch sind. Wenn Sie dazu neigen, nur innerhalb einer bestimmten Kollatierung / Sprache zu suchen, können Sie Teilindizes verwenden, um die Indexgröße unter Kontrolle zu halten.
Craig Ringer

2
Fügen Sie beim Zitieren einer Quelle einen Link hinzu.
Erwin Brandstetter

Antworten:


27

Die CZusammenstellung ist die richtige Wahl.

Ohne Gebietsschema ist alles etwas schneller. Und da ohnehin keine Sortierung richtig ist, erstellen Sie die Datenbank ohne Sortierung, dh mit C.

Es kann schwierig sein, für viele Operationen eine Sammlung bereitzustellen. Es sollte jedoch keinen merklichen Geschwindigkeitsunterschied zwischen der Standardkollatierung und einer Ad-hoc-Kollatierung geben. Schließlich handelt es sich nur um unsortierte Daten, und beim Sortieren werden Sortierungsregeln angewendet.

Beachten Sie, dass Postgres auf den Gebietsschemaeinstellungen aufbaut, die vom zugrunde liegenden Betriebssystem bereitgestellt werden. Daher müssen für jedes zu verwendende Gebietsschema Gebietsschemas generiert werden. Mehr in verwandter Antwort auf SO hier und hier .

Wie @Craig bereits erwähnte , sind Indizes der Engpass in diesem Szenario. Die Kollatierung des Index muss in vielen Fällen mit der Kollatierung des angewendeten Operators übereinstimmen, bei denen es sich um Zeichendaten handelt.

Sie können den COLLATEBezeichner in Indizes verwenden, um übereinstimmende Indizes zu erstellen. Teilindizes sind möglicherweise die perfekte Wahl, wenn Sie Daten in derselben Tabelle mischen.

Zum Beispiel eine Tabelle mit internationalen Zeichenfolgen:

CREATE TABLE string (
   string_id serial
  ,lang_id   int NOT NULL
  ,string    text NOT NULL
);

Und Sie interessieren sich hauptsächlich für jeweils eine Sprache:

SELECT *
FROM   string
WHERE  lang_id = 5  -- 5 being German / Germany here
AND    string > 'foo' COLLATE "de_DE"
ORDER  BY string COLLATE "de_DE";

Dann erstelle Teilindizes wie:

CREATE INDEX string_string_lang_id_idx ON string (string COLLATE "de_DE")
WHERE lang_id = 5;

Eine für jede Sprache, die Sie benötigen.

Tatsächlich könnte die Vererbung für eine Tabelle wie diese ein überlegener Ansatz sein. Dann können Sie für jede geerbte Tabelle einen einfachen Index erstellen, der nur Zeichenfolgen für ein einzelnes Gebietsschema enthält. Natürlich müssen Sie mit den Sonderregeln für geerbte Tabellen vertraut sein.


1
Verwenden Sie für jede neue Datenbank standardmäßig das Gebietsschema C (oder genauer gesagt "Nicht-Gebietsschema")?
Jack Douglas

1
@JackDouglas: Nein, das würde ich nur für Sonderfälle machen. In der Regel ist es viel praktischer, mit dem allgemein verwendeten Gebietsschema vor Ort zu arbeiten.
Erwin Brandstetter

13

Ich schlage vor, dass Sie eine Sortierung auswählen, die die Standard-Unicode-Reihenfolge bietet. Auf diese Weise erhalten Sie vernünftige Ergebnisse, auch wenn Sie die Sortierung in jeder Abfrage nicht überschreiben. Leider bieten die meisten (alle?) Betriebssysteme kein Gebietsschema mit dem Namen "Standard-Unicode" oder ähnlichem an, sodass Sie eine gute Wahl treffen und / oder nachforschen müssen. Unter Linux / glibc durchlaufen die Gebietsschemas de_DE.utf8 oder en_US.utf8 einfach das Standardverhalten. Beide sind also eine gute Wahl.

Ich halte die Verwendung des Gebietsschemas C nicht für eine gute Idee, da das Standardverhalten Ihrer Anwendung dann unbrauchbar wird. Und bei Konvertierungsvorgängen für Groß- und Kleinschreibung tritt möglicherweise kein ordnungsgemäßes Verhalten auf.

(Das Überschreiben der Kollatierung in einer Abfrage ist nicht sehr aufwändig. Es handelt sich lediglich um eine Syntaxanalyse.)


Wahrscheinlich weniger Schmerzen, um eine gesunde Zahlungsunfähigkeit zu haben ..
Erwin Brandstetter

1
Momentan verwende ich es_CL.utf8 in einer Testdatenbank, aber dank Ihrer Antwort habe ich ein bisschen mehr nachgesehen und festgestellt, dass dies utf8_unicode_cider richtige Weg ist .
Tae

0

Wir verwenden Postgres in einem Docker-Container, daher haben wir immer die ICU zur Verfügung und verwenden sie und-x-icuals Standard.

Dies wird in Kapitel 23.2.2.2.2 erwähnt. ICU- Kollatierungen der postres docs erwähnen:

und-x-icu (für "undefiniert")
ICU "Root" -Kollatierung. Verwenden Sie diese Option, um eine vernünftige sprachunabhängige Sortierreihenfolge zu erhalten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.