Гибридная "Index-like" структура btree - может ли PostgreSQL сделать это? - PullRequest
1 голос
/ 13 марта 2011

Я новичок в PostgreSQL. У меня очень необычное требование для гибридной базы данных, которую мне нужно построить. Из модулей, которые я видел, мне кажется , что возможно следующее.

Мне нужно иметь возможность добавлять ключ - [значения] в индекс без фактического добавления данных в таблицу. Проще говоря, мне нужно хранилище ключей [значений], в идеале, как btree (скорость поиска). Структура индекса идеальна. Возможно, другая структура сделает это.

Чтобы быть очень конкретным, я хочу сохранить что-то вроде:

KEY     [IDs]
Blue    10, 20, 23, 47
Green   5, 12, 40

Я не хочу затрат на хранение этих данных и их индексацию. Мне просто нужны данные, так сказать, «проиндексированные, но не сохраненные».

Не менее важна способность запрашивать эти структуры и получать данные (идентификаторы), а также иметь возможность выполнять ИНТЕРЕСЫ и т. Д. Для идентификаторов, а также IN, МЕЖДУ, = и т. Д. Для ключей.

Как вы, вероятно, можете догадаться, конечной целью является окончательный список идентификаторов, который затем будет отправлен клиенту и проверен по желанию.

EDIT

Чего я не хочу, так это записывать ключ для каждого значения. Используя приведенный выше пример, я не хочу хранить {Blue, 10}, {Blue, 20} и т. Д. Я хочу сохранить {Blue, [10, 20, 23, 47]}.

Если я сохраню это как традиционную таблицу, я не смогу обойти эту двойную проблему.

Глядя снова на Blue, [10, 20, 23, 47]}, технически это не более чем одно дерево, где идентификаторы (10, 20, 23, 47) помечены как значения, а родительский ключ «Синий» помечен как ключ.

Поскольку это несоответствие типов данных может быть грязным в одном дереве, я считаю, что идеальным решением является «[btrees] в btree», где «btree» - это ключ, а [btrees] - это btree для каждой группы значения ключа.

1 Ответ

3 голосов
/ 13 марта 2011

Если вы действительно настаиваете на том, чтобы делать это таким образом, вы можете сохранить значения в виде массива, а модуль intarray предоставляет операторы для манипулирования ими. То есть:

create table data(key text primary key, values int[] not null);
insert into data
  values('Blue', '{10,20,23,47}'),('Green','{5,12,40}'),('Red', '{5,10,28}');

с этим вы можете написать:

select unnest(values) from data where key = 'Blue'
  intersect
  select unnest(values) from data where key = 'Red';

В идеале вам нужна агрегатная функция для преобразования int [] в набор и вычисления пересечений и т. Д., Но, похоже, они не предоставляются.

Действительно, это просто немного более компактное хранилище более типичной структуры:

select key, unnest(values) as value from data;
  key  | value
-------+-------
 Blue  |    10
 Blue  |    20
 Blue  |    23
[...]

На самом деле, вы можете просто определить представление для вышеуказанного запроса.

Более нормализованный подход состоит в том, чтобы иметь две таблицы: одну для описания ключей, другую для связи их со значениями:

create table key_dimension(key_id serial primary key, key text not null unique);
insert into key_dimension(key) values('Blue'),('Green'),('Red');
create table key_value(key_id int not null references key_dimension(key_id), value int not null, primary key(key_id, value));
insert into key_value(key_id, value)
  select key_id, unnest(values) from key_dimension join data using (key);

и сейчас:

select value from key_value
  where key_id = (select key_id from key_dimension where key = 'Red')
intersect
select value from key_value
  where key_id = (select key_id from key_dimension where key = 'Blue')

Таким образом, любые запросы для выбора значений ключей должны выполняться только для набора ключей (key_dimension), а затем используется минимальный синтетический ключ (key_id) для преобразования их в фактические наборы значений данных (из key_value).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...