2010-04-07 4 views
14

Wie kann eine spärliche Datenmatrix in PostgreSQL am besten dargestellt werden? Die beiden offensichtlichen Methoden, die ich sehen sind:Darstellen von spärlichen Daten in PostgreSQL

  1. Speichern von Daten in einem einzigen Tisch mit einer separaten Spalte für jede denkbare Funktion (möglicherweise Millionen), aber mit einem Standardwert von NULL für nicht genutzte Funktionen. Dies ist konzeptionell sehr einfach, aber ich weiß, dass dies bei den meisten RDMS-Implementierungen in der Regel sehr ineffizient ist, da die NULL-Werte üblicherweise einige Speicherplatz einnehmen. Allerdings habe ich einen Artikel gelesen (leider nicht gefunden), der behauptet, dass PG keine Daten für NULL-Werte aufnimmt, wodurch es besser für das Speichern von spärlichen Daten geeignet ist.

  2. Erstellen Sie separate "Zeilen" - und "Spalten" -Tabellen sowie eine Zwischentabelle, um sie zu verknüpfen und den Wert für die Spalte in dieser Zeile zu speichern. Ich glaube, dass dies die traditionellere RDMS-Lösung ist, aber es ist mehr Komplexität und Overhead damit verbunden.

Ich fand auch PostgreDynamic, was besser behauptet spärliche Daten zu unterstützen, aber ich will nicht meinen gesamten Datenbank-Server zu einem PG Gabel wechseln nur für diese Funktion.

Gibt es noch andere Lösungen? Welchen sollte ich benutzen?

Antwort

7

Einige Lösungen in den Sinn,

1) Ihre Funktionen in Gruppen trennen, die in der Regel zusammen gesetzt sind, erstellen Sie eine Tabelle für jede Gruppe mit einer Eins-zu-Eins-Fremdschlüsselbeziehung zu den wichtigsten Daten, nur Join auf Tabellen, die Sie bei der Abfrage benötigen

2) Verwenden Sie die EAV Anti-Muster, erstellen Sie eine 'Feature' Tabelle mit einem Fremdschlüsselfeld aus Ihrer primären Tabelle sowie eine Feldname und eine Wertespalte, und speichern Sie die Funktionen als Zeilen in dieser Tabelle statt als Attribute in Ihrer Primärtabelle

3) Ähnlich wie PostgreDynamic es tut Erstellen Sie eine Tabelle für jede 'Spalte' in Ihrer Primärtabelle (sie verwenden einen separaten Namespace für diese Tabellen) und erstellen Sie Funktionen, um den Zugriff auf diese Tabellen und das Aktualisieren der Daten in diesen Tabellen zu vereinfachen. 4) Erstellen Sie eine Spalte in Ihren Primärdaten mit XML oder VARCHAR, und speichern Sie ein strukturiertes Textformat, das Ihre Daten darstellt, erstellen Sie Indizes über die Daten mit funktionalen Indizes, schreiben Sie Funktionen, um die Daten zu aktualisieren (oder verwenden Sie die XML-Funktionen, wenn Sie sie verwenden dass Format)

5) verwenden, um die contrib/hstore Modul eine Spalte des Typs hstore zu erzeugen, die Schlüssel-Wert-Paare halten kann, und indexiert und

aktualisiert werden kann

6) Liv e mit vielen leeren Feldern

+0

Sie könnten auch ein 'Feature' TYPE AS Feature-Name VARCHAR, Feature-Wert VARCHAR (oder was immer der Wert sein soll) erstellen und ein FEATURES-Feld des Typs Feature [] zu Ihrer Primärtabelle hinzufügen. – MkV

+1

Warum nennst du EAV ein "Anti-Pattern"? Googeln zeigt, dass dies eine allgemeine Beschreibung von EAV ist (üblicherweise abschätzig verwendet), aber niemand scheint zu erklären, warum. Es scheint viele gültige Fälle zu geben, in denen Datenbanken spärliche Daten wie das medizinische Feld speichern müssen, wodurch EAV zu einem geeigneten "Muster" wird. – Cerin

+1

Es beseitigt alle Vorteile der Datenbank, Zeilen-Level-Einschränkungen und referenzielle Integrität und macht es schwierig, eine einzelne Zeile für eine einzelne Entität zurückzugeben. – MkV

2

Ein NULL-Wert belegt bei NULL keinen Platz. Es wird ein Bit in einer Bitmap im Tuple-Header aufnehmen, aber das wird unabhängig davon sein.

Allerdings kann das System nicht mit Millionen von Spalten, Zeitraum umgehen. Es gibt ein theoretisches Maximum von etwas mehr als tausend, IIRC, aber Sie wollen wirklich nicht so weit gehen.

Wenn Sie wirklich so viele brauchen, müssen Sie in einer einzigen Tabelle die EAV-Methode verwenden, was Sie im Grunde in (2) sagen.

Wenn jeder Eintrag nur relativ wenige Schlüssel hat, schlage ich vor, dass Sie sich die "hstore" contrib-Module ansehen, mit denen Sie diese Art von Daten sehr effizient als dritte Option speichern können. Es wurde in der kommenden 9.0-Version weiter verbessert. Wenn Sie also ein wenig von der Produktionsbereitstellung entfernt sind, sollten Sie sich diesen direkt ansehen. Aber es lohnt sich auch in 8.4. Und es unterstützt einige ziemlich effiziente indexbasierte Lookups. Definitiv einen Besuch wert.

10

ich Sie gehe davon sind von schwach besetzte Matrizen aus mathematischen Kontext zu denken: (schnelle Rechenoperation), nicht persistenten Speicher (niedrige Festplattennutzung http://en.wikipedia.org/wiki/Sparse_matrix (Die Speicherung beschriebenen Techniken gibt es für Speicher).)

Da man diese Matrizen normalerweise auf der Clientseite und nicht auf der Serverseite bearbeitet, ist ein SQL-ARRAY [] die beste Wahl!

Die Frage ist, wie man die Sparsity der Matrix ausnutzt? Hier die Ergebnisse einiger Untersuchungen.

Setup:

  • Postgres 8.4
  • Matrices w/400 * 400 Elemente in doppelter Genauigkeit (8 Bytes) -> 1.28MiB Rohgröße pro Matrix
  • 33% Nicht-Null-Elemente - -> 427kiB effektive Größe pro Matrix
  • gemittelt unter Verwendung von ~ 1000 verschiedene zufällig besiedelten Matrizes

Konkurrierende Methoden:

  • Verlass auf die automatischen Serverseite Kompression von Spalten mit SET STORAGE MAIN oder verlängert.
  • Nur die Nicht-Null-Elemente plus eine Bitmap (bit varying(xx)) speichern, die beschreibt, wo die Nicht-Null-Elemente in der Matrix zu finden sind. (Eine doppelte Genauigkeit ist 64 mal größer als ein Bit. In der Theorie (Overheads ignorierend) sollte diese Methode eine Verbesserung sein, wenn < = 98% nicht Null sind ;-).) Serverseitige Komprimierung ist aktiviert.
  • Ersetzen die Nullen in der Matrix mit Null. (Die RDBMS sind sehr effektiv beim Speichern von NULL-Werten.) Serverseitige Komprimierung ist aktiviert.

(Indizierung von Nicht-Null-Elemente einen zweiten Index-ARRAY [] ist nicht sehr vielversprechend und daher nicht geprüft werden.)

Ergebnisse:

  • Automatische Kompression
    • keine zusätzlichen Implementierungsanstrengungen
    • kein reduzierter Netzwerkverkehr
    • minimal Overhead Kompression
    • persistente Speicher = 39% des Ausgangsgröße
  • Bitmap
    • akzeptablen Implementierungsaufwand
    • Netzwerkverkehr leicht verringert; abhängig von sparsity
    • persistenten Speicher = 33,9% des Ausgangsgröße
  • ersetzen Nullen mit NULLs
    • einige Implementierungsaufwand (API wissen muss, wo und wie die NULL-Werte setzen in das ARRAY [] beim Erstellen der INSERT-Abfrage)
    • keine Änderung im Netzwerkverkehr
    • persistenter Speicher = 35% th e Rohgröße

Fazit: Mit dem erweiterten/MAIN Speicherparameter starten . Wenn Sie etwas Freizeit haben, untersuchen Sie Ihre Daten und verwenden Sie mein Test-Setup mit Ihrem Seltenheitswert. Aber der Effekt ist möglicherweise niedriger als erwartet.

Ich empfehle immer die Matrix-Serialisierung (z. B. Row-Dur-Reihenfolge) plus zwei ganzzahlige Spalten für die Matrix-Dimensionen NxM zu verwenden. Da die meisten APIs textuellen SQL verwenden, speichern Sie viel Netzwerkverkehr und Clientspeicher für verschachtelte "ARRAY [ARRAY [..], ARRAY [..], ARRAY [..], ARRAY [..], ..)" !!!

Tebas


CREATE TABLE _testschema.matrix_dense 
(
    matdata double precision[] 
); 
ALTER TABLE _testschema.matrix_dense ALTER COLUMN matdata SET STORAGE EXTERN; 


CREATE TABLE _testschema.matrix_sparse_autocompressed 
(
    matdata double precision[] 
); 

CREATE TABLE _testschema.matrix_sparse_bitmap 
(
    matdata double precision[] 
    bitmap bit varying(8000000) 
); 

Legen Sie die gleichen Matrizen in allen Tabellen. Die konkreten Daten hängen von der bestimmten Tabelle ab. Ändern Sie die Daten auf der Serverseite nicht aufgrund nicht verwendeter, aber zugewiesener Seiten. Oder mach einen VACUUM.

SELECT 
pg_total_relation_size('_testschema.matrix_dense') AS dense, 
pg_total_relation_size('_testschema.matrix_sparse_autocompressed') AS autocompressed, 
pg_total_relation_size('_testschema.matrix_sparse_bitmap') AS bitmap; 
2

Ich weiß, das ein alter Thread, aber MadLib liefert einen spärlichen Vektortyp für Postgres, zusammen mit mehreren maschinellen Lernens und der statistischen Methoden.