Пары ключ / значение в таблице базы данных - PullRequest
11 голосов
/ 05 февраля 2009

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

Операции, которые мне нужно поддерживать:

  • Применение пары ключ / значение к группе элементов
  • Перечислить все активные в данный момент ключи
  • Определить все элементы, которые имеют значение для данного ключа
  • Определить все элементы, для которых значение, связанное с данным ключом, соответствует некоторым критериям.

Кажется, что самый простой способ сделать это - определить таблицу:

CREATE TABLE KeyValue (
  id    int,
  Key   varchar...,
  Value varchar...
);

Похоже, что я, вероятно, буду дублировать много данных в столбце «Ключ», потому что любой заданный ключ может быть определен для большого количества документов. Замена Key varchar целочисленным поиском в другой таблице, кажется, облегчает эту проблему (и делает его значительно более эффективным для перечисления всех активных ключей), но сталкивает меня с проблемой поддержания этой таблицы поиска (добавление в нее всякий раз, когда я хочу определить свойство и, возможно, удалить запись каждый раз, когда очищается ключ / значение).

Какой лучший способ сделать это?

Ответы [ 6 ]

29 голосов
/ 08 февраля 2009

Вы используете модель базы данных с именем Entity-Attribute-Value . Это распространенный способ хранения пар ключ / значение в реляционной базе данных, но он имеет ряд недостатков в отношении нормализации и эффективности базы данных.

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

Применение пары ключ / значение к группе элементов: Необходимо добавить одну строку для каждого элемента в группе.

INSERT INTO KeyValue (id, key, value) VALUES (101, 'color', 'green');
INSERT INTO KeyValue (id, key, value) VALUES (102, 'color', 'green');
INSERT INTO KeyValue (id, key, value) VALUES (103, 'color', 'green');

Вы также можете подготовить оператор INSERT с параметрами и выполнить несколько идентификаторов элементов в цикле или что-то еще.

Перечислите все текущие активные ключи:

SELECT DISTINCT Key FROM KeyValue;

Определить все элементы, которые имеют значение для данного ключа:

SELECT id FROM KeyValue WHERE Key = 'color';

Определить все элементы, для которых значение, связанное с данным ключом, соответствует некоторым критериям:

SELECT id FROM KeyValue WHERE Value = 'green';

Некоторые проблемы с Entity-Attribute-Value:

  • Нет способа убедиться, что ключи написаны одинаково для всех предметов
  • Нет способа сделать некоторые ключи обязательными для всех элементов (т.е. НЕ ПУСТО (NULL) в обычной схеме таблицы).
  • Все ключи должны использовать VARCHAR для значения; нельзя хранить разные типы данных для каждого ключа.
  • Нет способа использовать ссылочную целостность; невозможно создать FOREIGN KEY, который применяется к значениям некоторых ключей, а не других.

По сути, Entity-Attribute-Value не является нормализованным дизайном базы данных.

5 голосов
/ 06 февраля 2009

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

Если производительность является проблемой, то, вероятно, лучше использовать целочисленный ключ и отдельную таблицу (JOINS для целочисленных столбцов обычно быстрее, чем JOINS для столбцов переменной длины). Но первое правило оптимизации - это MEASURE FIRST - убедитесь, что ваш предположительно оптимизированный код действительно делает работу быстрее.

1 голос
/ 05 февраля 2009

Мне кажется, у вас есть пара вариантов дизайна.

Вариант 1: схема с двумя столами, на которую вы намекали в ответе

Keys (
 id int not null auto_increment
 key string/int
)
values (
 id int not null auto_increment
 key_id int
 value string/varchar/int
)

Вариант 2: возможно, как указал sambo99, вы можете изменить это:

keys (
 id int not null auto_increment
 key string/int
 hash_code int -- this would be computed by the inserting code, so that lookups would effectively have the id, and you can look them up directly
)

values (
 id int not null auto_increment -- this column might be nice since your hash_codes might colide, and this will make deletes/updates easier
 key_id int -- this column becomes optional
 hash_code int
 value string/varchar/int...
)

-

1 голос
/ 05 февраля 2009

Создание обновляемых представлений! . Также проверьте это для примера.

1 голос
/ 05 февраля 2009

Опция, которую стоит изучить, - это переваривание ключа с использованием SHA1 или MD5 перед вставкой его в таблицу.

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

0 голосов
/ 09 апреля 2018

Пара ключ-значение, как правило, не подходит для реляционных баз данных. Преимущества реляционных баз данных заключаются в ограничениях, валидации и структуре. Используя общую структуру ключ-значение в вашей таблице, вы теряете проверку и ограничения, которые делают реляционные базы данных хорошими. Если вам нужен гибкий дизайн пар «ключ-значение», вам лучше всего подойдет база данных NoSQL, такая как MongoDB или ее аналог.

Пара ключ-значение (например, базы данных NoSQL) работает лучше всего, когда базовые данные неструктурированы, непредсказуемы или часто меняются. Если у вас нет структурированных данных, у реляционной базы данных будет больше проблем, чем стоит, потому что вам нужно будет сделать много изменений схемы и / или перепрыгнуть через обручи, чтобы согласовать ваши данные с постоянно меняющейся структурой.

KVP / JSON / NoSql великолепен, потому что изменения в структуре данных не требуют полного рефакторинга модели данных. Добавление поля к вашему объекту данных - это просто вопрос добавления его к данным. Другая сторона медали в том, что в базе данных KVP / Nosql меньше ограничений и проверок, чем в реляционной базе данных, поэтому ваши данные могут запутаться.

Для реляционных моделей данных есть преимущества в производительности и экономии места. Нормализованные реляционные данные могут упростить понимание и проверку данных, поскольку существуют ключевые взаимосвязи таблиц и ограничения, которые могут вам помочь. Это облегчит поддержку и поддержку вашего приложения в долгосрочной перспективе. Другой подход заключается в использовании уровня абстракции данных в вашем коде, такого как Django или SQL Alchemy для Python, Entity Framework для .NET. Таким образом, когда ваш код изменится, ваша база данных изменится автоматически.

Один из худших паттернов, которые я когда-либо видел, - пытаться использовать его обоими способами Попытка поместить пару ключ-значение в реляционную базу данных часто приводит к катастрофе. Я бы порекомендовал использовать технологию, которая в первую очередь подходит вашим данным.

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