2009-08-20 2 views
2

Ich arbeite an einer Anwendung, die im Web bereitgestellt wird. Ein Teil der App sind Suchfunktionen, bei denen das Ergebnis in einer sortierten Liste dargestellt wird. Die Anwendung richtet sich an Benutzer in mehreren Ländern, die unterschiedliche Ländereinstellungen verwenden (= Sortierregeln). Ich muss eine Lösung finden, um für alle Benutzer richtig zu sortieren.Strategie für Gebietsschema empfindliche Sortierung mit Paginierung

Ich sortiere derzeit mit ORDER BY in meiner SQL-Abfrage, so dass die Sortierung nach dem für die Datenbank festgelegten Gebietsschema (oder LC_LOCATE) erfolgt. Diese Regeln sind für Benutzer mit einem anderen Gebietsschema als dem für die Datenbank festgelegten falsch.

Um das Problem weiter zu komplizieren, benutze ich Paginierung in der Anwendung, also wenn ich die Datenbank abfrage, frage ich nach den Zeilen 1 - 15, 16 - 30 usw., abhängig von der Seite, die ich brauche. Da die Sortierung jedoch falsch ist, enthält jede Seite Einträge, die falsch sortiert sind. Im schlimmsten Fall kann das gesamte Ergebnis für eine bestimmte Seite in Abhängigkeit von den Gebietsschema-/Sortierregeln des aktuellen Benutzers nicht in Ordnung sein.

Wenn ich in (Server-Seite) Code sortieren würde, muss ich alle Zeilen aus der Datenbank abrufen und dann sortieren. Dies führt zu einem enormen Leistungseinbruch bei der Datenmenge. Daher möchte ich das vermeiden.

Hat jemand eine Strategie (oder sogar eine technische Lösung), um dieses Problem anzugehen, was zu korrekt sortierten Listen führt, ohne den Leistungseinbruch beim Laden aller Daten in Kauf nehmen zu müssen?

Tech Details: Die Datenbank ist PostgreSQL 8.3, die Anwendung eine EJB3 App mit EJB QL für die Datenabfrage, die auf JBoss 4.5 läuft.

Antwort

0

Wie sind Sie mit PostgreSQL verbunden? Die documentation ist nicht vielversprechend:

Die Art einiger Gebietsschema Kategorien ist, dass ihr Wert für die Lebensdauer eines Datenbankclusters festgelegt werden muss. Das heißt, sobald initdb ausgeführt wurde, können Sie sie nicht mehr ändern. LC_COLLATE und LC_CTYPE sind diese Kategorien. Sie wirken sich auf die Sortierreihenfolge von Indizes aus, sodass sie beibehalten werden müssen oder dass Indizes für Textspalten beschädigt werden. PostgreSQL erzwingt dies, indem es die Werte von LC_COLLATE und LC_CTYPE aufzeichnet, die von initdb gesehen werden. Der Server übernimmt diese beiden Werte beim Start automatisch.

(Sortierungsregeln definieren, wie Text sortiert.)

Google wirft patch under discussion:

PostgreSQL derzeit nur eine Zusammenstellung zu einem Zeitpunkt unterstützt, als zu der Zeit durch die Variable LC_COLLATE fixiert Der Datenbankcluster wird initialisiert.

Ich bin mir nicht sicher, ob ich das außerhalb der Datenbank verwalten möchte, obwohl ich daran interessiert wäre, darüber zu lesen, wie es gemacht werden kann. (Wer einen guten technischen Überblick über die Probleme haben möchte, sollte Sorting Your Linguistic Data inside the Oracle Database auf der Oracle globalization site überprüfen.)

+0

PostgreSQL 8.4 (die aktuelle Version) unterstützt Gebietsschema Einstellungen pro Datenbank. Es ist alles andere als perfekt, aber es ist viel besser als 8.3. –

0

Ich weiß keine Möglichkeit, die Datenbank order by Reihenfolge zu wechseln. Daher muss man andere Lösungen in Betracht ziehen.

Wenn die Anzahl der Ergebnisse wirklich groß ist (Hunderttausende?), Habe ich keine Lösungen, außer dass nur die Anzahl der Ergebnisse angezeigt wird und der Benutzer eine genauere Anfrage stellt. Ansonsten könnte die Server-Seite, je nach den genauen Bedingungen, ....

Besonders die Verwendung eines Caches könnte die Dinge enorm verbessern. Die erste Anforderung an die Datenbank (unbegrenzt) wäre nicht so viel langsamer als bei einer Abfrage, die in der Anzahl der Ergebnisse begrenzt ist. Und die nachfolgenden Anfragen wären viel schneller. Paging und Neusortierung machen oft mehrere Anfragen, so dass der Cache gut funktioniert (sogar mit ein paar Minuten Dauer).

Ich benutze EhCache als technische Lösung. Sortieren und Paging gehen zusammen, Sortieren und Paging. Die rohen Ergebnisse konnten im Cache gespeichert werden.

Um die Performance-Einbußen, einige Hinweise zu reduzieren:

  • Sie die Abfrage einmal für Ergebnismenge Größe, und warnt den Benutzer ausgeführt werden kann, wenn es zu viele Ergebnisse sind (fragen Sie entweder für eine langsame Abfrage bestätigt , oder fügen Sie einige Auswahlfelder hinzu)
  • nur die Spalten, die Sie benötigen,, lassen Sie alle anderen Spalten (in der Regel einige Daten werden nicht sofort für alle Ergebnisse angezeigt, sondern z. B. auf Maus verschieben angezeigt; diese Daten können faul angefordert werden , nur bei Bedarf, daher Reduzierung der für alle Ergebnisse angeforderten Spalten)
  • wenn Sie berechneten Werte haben, cachen die kleinere zwischen den Datenbankspalten und den berechneten Werten
  • wenn Sie wiederholt Werte in mehrere Ergebnisse haben, können Sie verlangen, dass Daten/Spalten getrennt (so abrufen Sie von der Datenbank einmal und cache sie nur einmal), rufen Sie nur einen Schlüssel (normalerweise, und Identifikation) in der Hauptanforderung ab.
1

Sind Sie bereit, ein kleines benutzerdefiniertes Postgres-Funktionsmodul in C zu entwickeln? (Wahrscheinlich nur ein paar Tage für einen erfahrenen C-Codierer.)

strxfrm() ist die Funktion, die die sprachabhängige Textzeichenfolge basierend auf der aktuellen LC_COLLATE-Einstellung (mehr oder weniger die aktuelle Sprache) in eine transformierte Zeichenfolge umwandelt richtige Sortierreihenfolge in dieser Sprache, wenn sie als binäre Bytefolge sortiert wird (z. B. strcmp()).

Wenn Sie dies für Postgres implementieren, sagen, es dauert eine Zeichenfolge und eine Sortierreihenfolge, dann können Sie von strxfrm (Textfeld, Collation_order) bestellen. Ich denke, dass Sie dann mehrere Funktionsindizes für Ihre Textspalte erstellen können (z. B. eine pro Sprache), indem Sie diese Funktion verwenden, um die Ergebnisse von strxfrm() zu speichern, damit das Optimierungsprogramm den Index verwendet.

Alternativ können Sie den Postgres-Entwicklern bei der Implementierung in Mainstream Postgres beitreten. Hier sind die Wiki-Seiten zu diesem Thema: Collation, ICU (das auch von Java verwendet wird, soweit ich weiß).


Alternativ kann, wie eine weniger anspruchsvolle Lösung, wenn die Dateneingabe nur über Java ist, könnten Sie diese strxfrm() Werte in Java berechnen (Java wird wahrscheinlich einen anderen Namen für dieses Konzept hat), wenn Sie die Daten in der die Datenbank und lassen Sie dann Postgres nach diesen vorberechneten Werten indexieren und sortieren.

0

Sie könnten diese Verpackung überprüfen: http://www.fi.muni.cz/~adelton/l10n/postgresql-nls-string/. Es wurde lange nicht mehr aktualisiert und funktioniert möglicherweise nicht mehr, aber es scheint ein vernünftiger Startpunkt zu sein, wenn Sie eine Funktion erstellen möchten, die dies für Sie tun kann.

0

Dieses Modul ist für Postgres 8.4.3 defekt. Ich reparierte es - Sie können feste Version von http://www.itreport.eu/__cw_files/.01/.17/.ee7844ba6716aa36b19abbd582a31701/nls_string.c herunterladen und Sie müssen es kompilieren und installieren es von Hand (wie in verwandten README und INSTALL von ursprünglichen Modul beschrieben), aber trotzdem Sortierung funktioniert nicht korrekt. Ich probierte es auf FreeBSD 8.0, LC_COLLATE ist cs_CZ.UTF-8

+0

Eigentlich sieht es wie UTF-8 + Postgres + Collation ist die schlechteste Kombination, die jemals existiert. Höchstwahrscheinlich müssen wir einen gewissen ICU-Patch auf Postgres selbst anwenden, da ein einfacher Test gezeigt hat, dass strcoll unter FreeBSD für cs_CZ.UTF-8 nicht korrekt funktioniert. –

+0

Die Lösung ist gefunden - für FreeBSD muss markieren Sie die ICU (ich wähle Version 4) - in diesem Fall wird Postgres interne Sortierung anstelle von FreeBSD gebrochen verwenden. nls_string für diesen Fall ist veraltet. Außerdem natürlich LC_COLLATE für DB einstellen. –