Come scegliere una raccolta per database internazionale?


22

Sto progettando un database che memorizzerà i dati in diverse lingue (usando UTF-8), quindi penso che il modo migliore per visualizzare i risultati della query sia ordinarlo in base alla lingua dell'utente durante la query stessa ( perché ce ne sono più di uno modi corretti per farlo ), come segue:

SELECT a < b COLLATE "de_DE" FROM test1;

Supponendo che questo sia il modo corretto di lavorare con i dati internazionali, qual è la migliore raccolta per il database stesso? La documentazione di PostgreSQL dice :

Le regole di confronto C e POSIX specificano entrambe il comportamento "C tradizionale", in cui solo le lettere ASCII da "A" a "Z" vengono trattate come lettere e l'ordinamento viene eseguito rigorosamente in base ai valori dei byte del codice carattere.

Penso che questa sia la scelta migliore in questo caso, o sbaglio?

(Domanda bonus: è troppo lento per selezionare le regole di confronto nella query stessa?).


2
Il più grande punto dolente che soffrirai è che in un DB multilingue hai bisogno di molti indici, poiché gli indici sul testo raccoglibile sono specifici delle regole di confronto. Se si tende a cercare solo all'interno di una collazione / lingua particolare, è possibile utilizzare gli indici parziali per mantenere sotto controllo le dimensioni dell'indice.
Craig Ringer,

2
Quando si cita una fonte, aggiungere un collegamento.
Erwin Brandstetter,

Risposte:


27

La Craccolta è la scelta giusta.

Tutto è un po 'più veloce senza impostazioni locali. E poiché nessuna fascicolazione è corretta, creare il database senza fascicolazione, ovvero con C.

Potrebbe essere una seccatura dover fornire un confronto per molte operazioni. Tuttavia, non dovrebbe esserci una notevole differenza di velocità tra le regole di confronto predefinite e le regole di confronto ad hoc. Dopo tutto sono solo dati non ordinati e le regole di confronto vengono applicate durante l'ordinamento.

Tieni presente che Postgres si basa sulle impostazioni locali fornite dal sistema operativo sottostante, quindi devi avere locali generati per ogni locale da utilizzare. Più nella relativa risposta su SO qui e qui .

Tuttavia, come già accennato da @Craig , gli indici rappresentano il collo di bottiglia in questo scenario. Le regole di confronto dell'indice devono corrispondere alle regole di confronto dell'operatore applicato in molti casi che coinvolgono dati di carattere.

È possibile utilizzare l' COLLATEidentificatore negli indici per produrre indici corrispondenti. Gli indici parziali possono essere la scelta perfetta se si mescolano dati nella stessa tabella.

Ad esempio, una tabella con stringhe internazionali:

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

E sei principalmente interessato a una lingua alla volta:

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

Quindi creare indici parziali come:

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

Uno per ogni lingua di cui hai bisogno.

In realtà, l' eredità potrebbe essere un approccio superiore per una tabella come questa. Quindi puoi avere un indice semplice su ogni tabella ereditata contenente solo stringhe per una singola locale. Ovviamente devi essere a tuo agio con le regole speciali per le tabelle ereditate.


1
Usi la locale C (o 'non locale' per essere precisi) per impostazione predefinita per qualsiasi nuovo database?
Jack Douglas,

1
@JackDouglas: No, lo farei solo per casi speciali. In genere è molto più pratico lavorare con le impostazioni locali generalmente utilizzate sul posto.
Erwin Brandstetter,

13

Ti suggerisco di scegliere un confronto che fornisca l'ordinamento Unicode predefinito. In questo modo, otterrai risultati sani anche se non esegui l'override delle regole di confronto in ogni query. Sfortunatamente, la maggior parte dei sistemi operativi (tutti?) Non forniscono impostazioni locali che sono semplicemente denominate "Unicode predefinito" o qualcosa del genere, quindi dovrete indovinare e / o ricercare una buona scelta. Ad esempio, su Linux / glibc, le versioni locali de_DE.utf8 o en_US.utf8 passano semplicemente attraverso il comportamento predefinito, quindi entrambe sono buone scelte.

Non penso che usare la localizzazione C sia una buona idea, perché il comportamento predefinito dell'applicazione sarà inutile. E potresti non ottenere un comportamento corretto dalle operazioni di conversione dei casi.

(L'override delle regole di confronto in una query non ha molti costi. È solo un'operazione di analisi in tempo reale.)


Probabilmente meno dolore per avere un default sano ..
Erwin Brandstetter il

1
Attualmente sto usando es_CL.utf8 in un database di test, ma grazie alla tua risposta ho guardato un po 'di più e ho scoperto che utf8_unicode_ciè la strada da percorrere .
Tae,

0

Usiamo postgres in un contenitore docker, quindi abbiamo sempre ICU disponibile e usiamo und-x-icucome predefinito.

Questo è menzionato nel capitolo 23.2.2.2.2. Raccolte di ICU dei documenti di postres menzionati:

und-x-icu (per "non definito")
regole di confronto "root" ICU. Usa questo per ottenere un ordinamento ragionevole dal punto di vista linguistico.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.