Problem
Hinweis: Ich beziehe mich auf die mathematischen Sequenzen , nicht auf den Sequenzmechanismus von PostgreSQL .
Ich habe eine Tabelle, die Folgen von ganzen Zahlen darstellt. Die Definition lautet:
CREATE TABLE sequences
(
id serial NOT NULL,
title character varying(255) NOT NULL,
date date NOT NULL,
sequence integer[] NOT NULL,
CONSTRAINT "PRIM_KEY_SEQUENCES" PRIMARY KEY (id)
);
Mein Ziel ist es, Zeilen mit einer bestimmten Teilsequenz zu finden. Das heißt, die Zeilen, in denen das sequence
Feld eine Sequenz ist, die die angegebene Teilsequenz enthält (in meinem Fall ist die Sequenz geordnet).
Beispiel
Angenommen, die Tabelle enthält folgende Daten:
+----+-------+------------+-------------------------------+
| id | title | date | sequence |
+----+-------+------------+-------------------------------+
| 1 | BG703 | 2004-12-24 | {1,3,17,25,377,424,242,1234} |
| 2 | BG256 | 2005-05-11 | {5,7,12,742,225,547,2142,223} |
| 3 | BD404 | 2004-10-13 | {3,4,12,5698,526} |
| 4 | BK956 | 2004-08-17 | {12,4,3,17,25,377,456,25} |
+----+-------+------------+-------------------------------+
Wenn also die gegebene Teilsequenz ist {12, 742, 225, 547}
, möchte ich die Zeile 2 finden.
In ähnlicher Weise {3, 17, 25, 377}
möchte ich , wenn die gegebene Teilsequenz ist , die Zeile 1 und die Zeile 4 finden.
Wenn die angegebene Teilsequenz lautet {12, 4, 3, 25, 377}
, werden keine Zeilen zurückgegeben.
Untersuchungen
Erstens bin ich mir nicht ganz sicher, ob es sinnvoll ist, Sequenzen mit einem Array-Datentyp darzustellen. Obwohl dies der Situation angemessen erscheint; Ich fürchte, es macht die Handhabung komplizierter. Vielleicht ist es besser, die Sequenzen anders darzustellen, indem Sie ein Beziehungsmodell mit einer anderen Tabelle verwenden.
Auf die gleiche Weise denke ich darüber nach, die Sequenzen mithilfe der unnest
Array-Funktion zu erweitern und dann meine Suchkriterien hinzuzufügen. Da die Anzahl der Begriffe in der Sequenz jedoch variabel ist, sehe ich nicht, wie das geht.
Ich weiß, dass es auch möglich ist, meine Sequenz mithilfe der subarray
Funktion des Intarray- Moduls in Teilsequenzen zu schneiden, aber ich sehe nicht, wie es mir bei meiner Suche zugute kommt.
Einschränkungen
Auch wenn sich mein Modell derzeit noch in der Entwicklung befindet, soll die Tabelle aus vielen Sequenzen zwischen 50.000 und 300.000 Zeilen bestehen. Ich habe also eine starke Leistungsbeschränkung.
In meinem Beispiel habe ich relativ kleine ganze Zahlen verwendet. In der Praxis ist es möglich, dass diese ganzen Zahlen bis zum Überlauf viel größer werden bigint
. In einer solchen Situation ist es meiner Meinung nach am besten, Zahlen als Zeichenfolgen zu speichern (da diese Sequenzen mathematischer Operationen nicht ausgeführt werden müssen). Wenn Sie sich jedoch für diese Lösung entscheiden, ist es unmöglich, das oben erwähnte Intarray- Modul zu verwenden .
bigint
, sollten Sie sienumeric
als Typ zum Speichern verwenden. Es ist viel langsamer und nimmt viel mehr Platz ein.numeric
und nicht eine Zeichenfolge (text
zum Beispiel)? Ich muss keine mathematischen Operationen an meinen Sequenzen ausführen.text
ist und Sie daran hindert, falsche nicht numerische Daten zu speichern. Abhängig davon, ob Sie nur E / A ausführen, möchten Sie möglicherweise, dass Text die E / A-Verarbeitung reduziert.SELECT ARRAY[12, 4, 3, 17, 25, 377, 456, 25] @> ARRAY[12, 4, 3, 25, 377];
Gibt true zurück, da die Reihenfolge von diesem Operator nicht berücksichtigt wird.Antworten:
Wenn Sie nach signifikanten Leistungsverbesserungen für die Antwort von dnoeth suchen , sollten Sie eine native C-Funktion verwenden und den entsprechenden Operator erstellen.
Hier ist ein Beispiel für int4-Arrays. ( Eine generische Array-Variante und das entsprechende SQL-Skript ).
Jetzt können Sie Zeilen wie diese filtern.
Ich habe ein kleines Experiment durchgeführt, um herauszufinden, wie viel schneller diese Lösung ist.
Es ist also ungefähr 16 mal schneller. Wenn dies nicht ausreicht, können Sie Unterstützung für GIN- oder GiST-Indizes hinzufügen. Dies ist jedoch eine viel schwierigere Aufgabe.
quelle
numeric
, um meine Daten darzustellen, da sie möglicherweise überlaufenbigint
. Es kann sinnvoll sein, Ihre Antwort so zu bearbeiten, dass sie den Einschränkungen der Frage entspricht. Wie auch immer, ich werde eine vergleichende Performance machen, die ich hier posten werde.numeric
und getestettext
und die Verbesserung lag je nach Länge der Arrays zwischen 20 und 50 Mal.numeric
.bigint
.bigint
, so dass ich anscheinend keine Wahl habe. Aber wenn Sie eine Idee haben, bin ich interessiert :).Sie können die Teilsequenz leicht finden, wenn Sie die Arrays in Zeichenfolgen umwandeln und die geschweiften Klammern durch Kommas ersetzen:
Machen Sie dasselbe für das Array, nach dem Sie suchen, und fügen Sie ein führendes und ein nachfolgendes hinzu
%
:Jetzt vergleichen Sie es mit
LIKE
:Bearbeiten:
Fiddle arbeitet wieder.
Wenn die Arrays in einer Zeile pro Wert normalisiert sind, können Sie eine satzbasierte Logik anwenden:
n
muss sequentiell sein, keine Duplikate, keine Lücken. Schließen Sie sich nun gemeinsamen Werten an und nutzen Sie die Tatsache, dass Sequenzen sequentiell sind :-)Zählen Sie abschließend die Anzahl der Zeilen mit demselben Dummy und prüfen Sie, ob es sich um die richtige Anzahl handelt:
Versuchen Sie einen Index für Sequenzen (val, id, n).
quelle
TEXT
Feld in Betracht zu ziehen (varchar
ist meiner Meinung nach eine schlechte Idee, Sequenzen können lang sein, da die Zahlen, so dass die Größe eher unvorhersehbar ist), um eine Umwandlung zu vermeiden. Es ist jedoch immer noch nicht möglich, Indizes zur Verbesserung der Leistung zu verwenden (außerdem scheint die Verwendung eines Zeichenfolgenfelds nicht unbedingt sinnvoll zu sein, siehe Kommentar von @CraigRinger oben).25
gibt es zweimal inid=4
, ist das tatsächlich möglich? Wie viele Übereinstimmungen gibt es im Durchschnitt / Maximum für eine gesuchte Sequenz?{1, 1, 1, 1, 12, 2, 2, 12, 12, 1, 1, 5, 4}
ist durchaus möglich. In Bezug auf die Anzahl der Übereinstimmungen wird normalerweise angenommen, dass die verwendeten Teilsequenzen die Anzahl der Ergebnisse begrenzen. Einige Sequenzen sind jedoch sehr ähnlich, und es kann manchmal interessant sein, eine kürzere Teilsequenz zu verwenden, um mehr Ergebnisse zu erzielen. Ich schätze, dass die Anzahl der Übereinstimmungen in den meisten Fällen zwischen 0 und 100 liegt. Es besteht immer die Möglichkeit, dass die Teilsequenz gelegentlich mit vielen Sequenzen übereinstimmt, wenn sie kurz oder sehr häufig ist.