проблема
Примечание: я имею в виду математические последовательности , а не механизм последовательностей в PostgreSQL .
У меня есть таблица, представляющая последовательности целых чисел. Определение таково:
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)
);
Моя цель - найти строки, используя данную подпоследовательность. То есть строки, где sequence
поле представляет собой последовательность, которая содержит данную подпоследовательность (в моем случае последовательность упорядочена).
пример
Предположим, что таблица содержит следующие данные:
+----+-------+------------+-------------------------------+
| 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} |
+----+-------+------------+-------------------------------+
Поэтому, если данная подпоследовательность есть {12, 742, 225, 547}
, я хочу найти строку 2.
Точно так же, если данная подпоследовательность есть {3, 17, 25, 377}
, я хочу найти строку 1 и строку 4.
Наконец, если заданная подпоследовательность есть {12, 4, 3, 25, 377}
, то строки не возвращаются.
исследования
Во-первых, я не совсем уверен, что представлять последовательности с типом данных массива целесообразно. Хотя это похоже на ситуацию; Боюсь, это усложняет управление. Возможно, лучше представлять последовательности по-разному, используя модель отношений с другой таблицей.
Точно так же я думаю о расширении последовательностей с помощью unnest
функции массива, а затем добавляю критерии поиска. Тем не менее, количество членов в последовательности, являющейся переменной, я не вижу, как это сделать.
Я знаю, что также возможно вырезать мою последовательность в подпоследовательности, используя subarray
функцию модуля intarray, но я не понимаю, как это мне пригодится для моего поиска.
Ограничения
Даже если в данный момент моя модель все еще разрабатывается, предполагается, что таблица будет состоять из множества последовательностей, от 50 000 до 300 000 строк. Так что у меня сильное ограничение производительности.
В моем примере я использовал относительно маленькие целые числа. На практике, возможно, что эти целые числа становятся намного больше, вплоть до переполнения bigint
. В такой ситуации, я думаю, лучше всего хранить числа в виде строк (поскольку нет необходимости выполнять эти последовательности математических операций). Однако, выбирая это решение, это делает невозможным использование модуля intarray , упомянутого выше.
bigint
вы должны использовать ихnumeric
как тип для хранения. Это намного медленнее и занимает гораздо больше места, хотя.numeric
а не строку (text
например)? Мне не нужно выполнять математические операции над своими последовательностями.text
и не позволяет вам хранить поддельные нечисловые данные. Зависит от того, что если вы выполняете только ввод-вывод, вам может потребоваться, чтобы текст уменьшал объем обработки ввода-вывода.SELECT ARRAY[12, 4, 3, 17, 25, 377, 456, 25] @> ARRAY[12, 4, 3, 25, 377];
вернет true, потому что заказ не рассматривается этим оператором.Ответы:
Если вы ищете значительное улучшение производительности в ответе dnoeth , подумайте об использовании собственной C-функции и создании соответствующего оператора.
Вот пример для массивов int4. ( Общий вариант массива и соответствующий скрипт SQL ).
Теперь вы можете фильтровать строки, как это.
Я провел небольшой эксперимент, чтобы выяснить, насколько быстрее это решение.
Так что это примерно в 16 раз быстрее. Если этого недостаточно, вы можете добавить поддержку индексов GIN или GiST, но это будет гораздо более сложной задачей.
источник
numeric
для представления моих данных, потому что они могут переполнитьсяbigint
. Возможно, было бы хорошо отредактировать ваш ответ, чтобы он соответствовал ограничениям вопроса. Во всяком случае, я сделаю сравнительное представление, которое я опубликую здесь.numeric
иtext
улучшение варьировалось от 20 до 50 раз в зависимости от длины массивов.numeric
.bigint
.bigint
, поэтому, похоже, у меня нет выбора. Но если у вас есть идея, мне интересно :).Вы можете легко найти подпоследовательность, когда вы приводите массивы к строкам и заменяете фигурные скобки запятыми:
Сделайте то же самое для массива, который вы ищете, и добавьте ведущий и трейлинг
%
:Теперь вы сравниваете это, используя
LIKE
:Редактировать:
Скрипка снова работает.
Если массивы нормализованы в одну строку для каждого значения, вы можете применить логику на основе набора:
n
должен быть последовательным, без дубликатов, без пробелов. Теперь присоединяйтесь к общим значениям и используйте тот факт, что последовательности являются последовательными :-)Наконец, подсчитайте количество строк с одинаковой фиктивной переменной и проверьте, правильное ли это число:
Попробуйте указатель на последовательности (val, id, n).
источник
TEXT
поле (varchar
на мой взгляд, это плохая идея, последовательности могут быть длинными, так как числа, поэтому размер довольно непредсказуем), чтобы избежать приведения; но по-прежнему невозможно использовать индексы для улучшения производительности (более того, использование строкового поля не кажется разумным, см. комментарий @CraigRinger выше).25
существует дважды вid=4
, это на самом деле возможно? Сколько совпадений существует в среднем / максимальном для искомой последовательности?{1, 1, 1, 1, 12, 2, 2, 12, 12, 1, 1, 5, 4}
вполне возможно. Что касается количества совпадений, используемые подпоследовательности обычно считаются ограничивающими количество результатов. Однако некоторые последовательности очень похожи, и иногда может быть интересно использовать подпоследовательность, более короткую, чтобы получить больше результатов. Я предполагаю, что число совпадений для большинства случаев составляет от 0 до 100. Всегда существует вероятность того, что подпоследовательность иногда совпадает с большим количеством последовательностей, когда она короткая или очень распространенная.