Gibt es eine Obergrenze für eine array
Spalte?
Ich erhalte diesen Fehler beim Einfügen in das Array-Feld -
PG::Error: ERROR: index row size 3480 exceeds maximum 2712 for index "ix_data"
Hier ist meine Tabellendefinition -
create table test_array(id varchar(50), data text[]);
ALTER TABLE test_array ADD PRIMARY KEY (id);
CREATE INDEX ix_data ON test_array USING GIN (data);
Ich benötige einen Index für das Array-Feld, da ich einige Suchvorgänge darauf durchführe.
data
eine Liste von Tags enthält, wie in diesem verwandten Blog-Beitrag von Scott Snyder gezeigt ? In diesem Fall habe ich möglicherweise eine bessere Lösung für Sie.Antworten:
Das Problem
Hier ist ein sehr ähnlicher Fall, der auf pgsql.general diskutiert wird . Es geht um die Einschränkung in einem B-Tree-Index, aber es ist alles das Gleiche, da ein GIN-Index intern einen B-Tree-Index für Schlüssel verwendet und daher auf dieselbe Einschränkung für die Schlüsselgröße stößt (anstelle der Elementgröße in einem einfachen B-Tree) Index).
Ich zitiere das Handbuch zur Implementierung des GIN-Index :
In beiden Fällen ist mindestens ein Array-Element in Ihrer Spalte
data
zu groß, um indiziert zu werden. Wenn dies nur ein einzelner Freak-Wert oder eine Art Unfall ist, können Sie den Wert möglicherweise abschneiden und damit fertig werden.Für die folgende Demo gehe ich anders aus: viele Langtextwerte im Array.
Einfache Lösung
Sie können Elemente in Ihrem Array
data
durch entsprechende Hashwerte ersetzen . Und senden Sie Suchwerte über dieselbe Hash-Funktion. Natürlich möchten Sie Ihre Originale wahrscheinlich zusätzlich irgendwo aufbewahren. Damit kommen wir fast zu meiner zweiten Variante ...Erweiterte Lösung
Sie können eine Nachschlagetabelle für Array-Elemente mit einer
serial
Spalte als Ersatz-Primärschlüssel erstellen (praktisch eine radikale Art von Hash-Wert). Dies ist umso interessanter, wenn die beteiligten Elementwerte nicht eindeutig sind:Da wir nachschlagen möchten
elem
, fügen wir einen Index hinzu - diesmal jedoch einen Index für einen Ausdruck mit nur den ersten 10 Zeichen des Langtextes. Dies sollte in den meisten Fällen ausreichen, um eine Suche auf einen oder mehrere Treffer zu beschränken. Passen Sie die Größe an Ihre Datenverteilung an. Oder verwenden Sie eine komplexere Hash-Funktion.Ihre Spalte
data
wäre dann vom Typint[]
. Ich habe den Tisch in umbenanntdata
und das Unheil, dasvarchar(50)
Sie in Ihrem Beispiel hatten, beseitigt:Jedes Array-Element in
data
bezieht sich auf aelem.elem_id
. An diesem Punkt können Sie in Betracht ziehen, die Array-Spalte durch eine n: m-Tabelle zu ersetzen, wodurch Ihr Schema normalisiert wird und Postgres die erzwungene Integrität erzwingen kann. Indizierung und allgemeine Handhabung werden einfacher ...Aus Leistungsgründen kann die
int[]
Spalte in Kombination mit einem GIN-Index jedoch überlegen sein. Die Speichergröße ist viel kleiner. In diesem Fall benötigen wir den GIN-Index:Jetzt ist jeder Schlüssel des GIN-Index (= Array-Element) ein
integer
statt eines länglichentext
. Der Index wird um mehrere Größenordnungen kleiner sein, die Suche wird folglich viel schneller sein.Der Nachteil: Bevor Sie tatsächlich eine Suche durchführen können, müssen Sie die
elem_id
von der Tabelle nachschlagenelem
. Mit meinem neu eingeführten Funktionsindexelem_elem_left10_idx
wird auch dies viel schneller sein.Sie können alles in einer einfachen Abfrage erledigen :
Möglicherweise interessiert Sie die Erweiterung
intarray
, die zusätzliche Operatoren und Operatorklassen bereitstellt.Voll funktionsfähige Live-Demo auf sqlfiddle.
quelle
Der Fehler liegt beim Index
ix_data
, nicht beimtext[]
Feld. Die maximale Größe für eine Zeile in diesem bestimmten Indextyp ist auf2712
Bytes begrenzt. Wenn Sie Ihren Index löschen und die Einfügung erneut versuchen, sollte dies für Sie funktionieren. Wenn Sie ein größeres Feld indizieren müssen, sollten Sie sich die Volltext-Indizierungsfunktionen von Postgres ansehen.quelle
Ich habe dies in einer PostGIS-Geografiespalte erhalten. Das lag daran, dass ich den Index versehentlich falsch erstellt habe. Sie sollten den Parameter USING GIST einschließen, wenn Sie solche Indizes erstellen.
quelle