Как я могу хранить и индексировать список в реляционной базе данных? - PullRequest
2 голосов
/ 17 декабря 2011

Я работаю над созданием базы данных (SQLite) для хранения информации о каждом запуске написанного мной сценария Mathematica. Сценарий принимает несколько входных параметров, поэтому в моей БД есть таблица со столбцом для каждого параметра (среди других столбцов).

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

Ограничения, указанные в комментариях:

  • Не существует явной верхней границы длины списка, но на практике она составляет от 1 до 50.
  • Количество отдельных списков будет небольшим, порядка 10.
  • У меня фактически есть 3 списка параметров. Для двух из них значения в списке являются неотрицательными числами с плавающей запятой двойной точности; для третьего значения - это пары таких чисел.
  • Дубликатов нет. (Точнее, комплектов , поэтому дубликатов нет, порядок не имеет значения)
  • Я могу легко организовать сортировку элементов списка.

Например: предположим, что мой стол настроен так

CREATE TABLE jobs (id INTEGER PRIMARY KEY, param1 REAL, param2_id INTEGER);
CREATE TABLE param2 (param2_id INTEGER PRIMARY KEY, value REAL);

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

param1 = 4;
param2 = {.1, .3, .5};
runTheCalculation[param1, param2]

Предполагая, что это самый первый запуск скрипта, он вставит в БД следующее содержимое:

jobs:   id      param1     param2_id
         1       4.0        1

param2: param2_id   value
         1           0.1
         1           0.3
         1           0.5

Пока все хорошо. Допустим, я снова запускаю скрипт с другим параметром,

param1 = 2;
param2 = {.1, .3, .5};
runTheCalculation[]

В простой реализации это приведет к базе данных, содержащей это:

jobs:   id      param1     param2_id
         1       4.0        1
         2       2.0        2

param2: param2_id   value
         1           0.1
         1           0.3
         1           0.5
         2           0.1
         2           0.3
         2           0.5

Но я бы хотел, чтобы он мог найти тот факт, что список {.1, .3, .5} уже находится в базе данных, чтобы после второго запуска БД содержала это вместо:

jobs:   id      param1     param2_id
         1       4.0        1
         2       2.0        1

param2: param2_id   value
         1           0.1
         1           0.3
         1           0.5

Какой запрос можно использовать, чтобы определить, что список {.1, .3, .5} уже существует в таблице param2?

Я не против создания дополнительных таблиц при необходимости. Или, если есть какая-то модель, кроме использования соединительной таблицы, которая имеет больше смысла, это тоже хорошо.

Ответы [ 3 ]

1 голос
/ 17 декабря 2011

Вы спрашиваете: Как я могу посмотреть, есть ли какой-либо данный список уже в базе данных?

Обычный способ - использовать индекс, и индексы всегда ориентированы на строки. Таким образом, стандартное проектирование базы данных предполагает, что вам нужно каким-то образом собрать весь список (нормализованный) в ряд.

Поскольку вы находитесь на SQLLite, у вас не так много вариантов:

http://www.sqlite.org/datatype3.html

Я рекомендую ТЕКСТ! Вы также можете индексировать BLOB, и BLOB сэкономит некоторое пространство, но, вероятно, TEXT будет работать просто отлично, а TEXT обычно намного удобнее для отладки и работы. Попробуйте придумать какой-нибудь канонический формат String для своих списков, который вы можете анализировать / генерировать, и всегда ВСТАВЛЯЙТЕ / ВЫБИРАЙТЕ это из базы данных согласованным способом (например, согласованное округление, предварительная сортировка, удаление дубликатов, конечные и ведущие нули всегда в соответствии), и с вами все будет в порядке.

Предупреждение: это не требующий особых усилий подход, и, возможно, даже "неправильный путь", но если он выполнит свою работу ...

1 голос
/ 17 декабря 2011

Если список короткий, а количество списков относительно невелико, вы можете просто упорядочить списки в TBL_Lists и посмотреть, совпадают ли ваши. Это довольно неэффективно, поскольку будет перечислять все сохраненные списки для сравнения с вашим одним сохраненным списком.

Другим способом, и, на мой взгляд, лучше всего было бы хешировать список и сохранять его хэш в TBL_List_Hashes

Для хеширования списка потребуется его перечисление один раз.

Пример алгоритма хеширования может состоять в том, чтобы построить строку из всех отсортированных числовых значений с равномерным заполнением, а затем запустить любой метод хеширования для объединенной строки.

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

Так что, если в вашем хэш-алгоритме есть коллизии, вы добавляете затраты на перечисление (и запрос) для каждого ошибочного совпадения.

РЕДАКТИРОВАТЬ:
Вот соответствующий ответ для .net
.net 3.5 Список Равенство и GetHashCode

EDIT2:
И если вы не зависите от порядка при сопоставлении, просто стандартизируйте порядок списка перед хэшированием
GetHashCode для класса с объектом списка

0 голосов
/ 17 декабря 2011

В общем, не используйте списки, если у вас нет очень необычного набора требований и достаточного практического опыта, чтобы предвидеть последствия.

Отношение «многие ко многим», содержащееся в соединительной таблице с соответствующими индексами, будет работать так же хорошо и будет намного проще в использовании. Это также более гибкий.

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