Problème
Remarque: je me réfère aux séquences mathématiques , pas au mécanisme des séquences de PostgreSQL .
J'ai un tableau représentant des séquences d'entiers. La définition est:
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)
);
Mon objectif est de trouver des lignes en utilisant une sous-séquence donnée. C'est-à-dire, les lignes où le sequence
champ est une séquence qui contient la sous-séquence donnée (dans mon cas, la séquence est ordonnée).
Exemple
Supposons que le tableau contienne les données suivantes:
+----+-------+------------+-------------------------------+
| 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} |
+----+-------+------------+-------------------------------+
Donc, si la sous-séquence donnée est {12, 742, 225, 547}
, je veux trouver la ligne 2.
De même, si la sous-séquence donnée est {3, 17, 25, 377}
, je veux trouver la ligne 1 et la ligne 4.
Enfin, si la sous-séquence donnée l'est {12, 4, 3, 25, 377}
, aucune ligne n'est renvoyée.
Enquêtes
Premièrement, je ne suis pas complètement certain que représenter des séquences avec un type de données de tableau est sage. Bien que cela semble approprié à la situation; Je crains que cela rend la manipulation plus compliquée. Il vaut peut-être mieux représenter les séquences différemment, en utilisant un modèle de relations avec une autre table.
De la même manière, je pense à étendre les séquences à l'aide de la unnest
fonction tableau puis ajouter mes critères de recherche. Néanmoins, le nombre de termes dans la séquence étant variable, je ne vois pas comment faire cela.
Je sais qu'il est également possible de couper ma séquence en sous-séquence en utilisant la subarray
fonction de module intarray mais je ne vois pas en quoi cela me profite pour ma recherche.
Contraintes
Même si en ce moment mon modèle est encore en développement, la table est destinée à être composée de nombreuses séquences, entre 50 000 et 300 000 lignes. J'ai donc une forte contrainte de performance.
Dans mon exemple, j'ai utilisé des entiers relativement petits. En pratique, il est possible que ces nombres entiers deviennent beaucoup plus grands, jusqu'à déborder bigint
. Dans une telle situation, je pense que le mieux est de stocker les nombres sous forme de chaînes (car il n'est pas nécessaire d'effectuer ces séquences d'opérations mathématiques). Cependant, en optant pour cette solution, cela rend impossible l'utilisation du module intarray , mentionné ci-dessus.
bigint
vous devez les utilisernumeric
comme type pour les stocker. C'est beaucoup plus lent et prend beaucoup plus de place cependant.numeric
et non une chaîne (text
par exemple)? Je n'ai pas besoin d'effectuer d'opérations mathématiques sur mes séquences.text
, et vous empêche de stocker de fausses données non numériques. Cela dépend, si vous ne faites que des E / S, vous voudrez peut-être que le texte réduise le traitement des E / S.SELECT ARRAY[12, 4, 3, 17, 25, 377, 456, 25] @> ARRAY[12, 4, 3, 25, 377];
retournera true, car la commande n'est pas prise en compte par cet opérateur.Réponses:
Si vous recherchez des améliorations significatives des performances de la réponse de dnoeth , envisagez d'utiliser une fonction C native et de créer l'opérateur approprié.
Voici un exemple pour les tableaux int4. ( Une variante de tableau générique et le script SQL correspondant ).
Vous pouvez maintenant filtrer des lignes comme celle-ci.
J'ai mené une petite expérience pour découvrir à quel point cette solution est plus rapide.
Donc, c'est environ 16 fois plus rapide. Si cela ne suffit pas, vous pouvez ajouter la prise en charge des index GIN ou GiST, mais ce sera une tâche beaucoup plus difficile.
la source
numeric
pour représenter mes données car elles peuvent déborderbigint
. Il pourrait être judicieux de modifier votre réponse pour qu'elle corresponde aux contraintes de la question. Quoi qu'il en soit, je ferai une performance comparative que je posterai ici.numeric
ettext
et l'amélioration variait de 20 à 50 fois selon la longueur des tableaux.numeric
.bigint
.bigint
, il semble donc que je n'ai pas le choix. Mais si vous avez une idée, ça m'intéresse :).Vous pouvez facilement trouver la sous-séquence lorsque vous convertissez les tableaux en chaînes et remplacez les accolades par des virgules:
Faites de même pour le tableau que vous recherchez et ajoutez un début et une fin
%
:Maintenant, vous le comparez en utilisant
LIKE
:Éditer:
Fiddle travaille à nouveau.
Si les tableaux sont normalisés en une ligne par valeur, vous pouvez appliquer une logique basée sur un ensemble:
n
doit être séquentiel, pas de doublons, pas de lacunes. Rejoignez maintenant des valeurs communes et exploitez le fait que les séquences sont séquentielles :-)Enfin, comptez le nombre de lignes avec le même mannequin et vérifiez si c'est le bon numéro:
Essayez un index sur les séquences (val, id, n).
la source
TEXT
champ (varchar
c'est une mauvaise idée à mon avis, les séquences peuvent être longues, comme les nombres, donc la taille est plutôt imprévisible), pour éviter le cast; mais il n'est toujours pas possible d'utiliser des index pour améliorer les performances (en outre utiliser un champ string ne semble pas forcément judicieux, voir commentaire de @CraigRinger ci-dessus).25
existe deux foisid=4
, est-ce réellement possible? Combien de correspondances existent en moyenne / maximum pour une séquence recherchée?{1, 1, 1, 1, 12, 2, 2, 12, 12, 1, 1, 5, 4}
c'est tout à fait possible. Concernant le nombre de correspondances, les sous-séquences utilisées sont normalement censées limiter le nombre de résultats. Cependant, certaines séquences sont très similaires, et il peut parfois être intéressant d'utiliser une sous-séquence plus courte pour obtenir plus de résultats. J'estime que le nombre de correspondances pour la majorité des cas est compris entre 0 et 100. Avec toujours la possibilité qu'occasionnellement la correspondance de sous-séquences avec beaucoup de séquences soit courte ou très courante.