Хранение значений множественного выбора в базе данных

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

UserLanguages
(
 UserID nvarchar(50),
 LookupLanguageID int
)

но сайт будет сильно загружен, и мы пытаемся устранить любые накладные расходы, где это возможно, поэтому, чтобы избежать соединений с основной таблицей участников при отображении результатов в пользовательском интерфейсе, я думал о том, чтобы хранить языки для пользователя в основной таблице, имея их через запятую, например "12,34,65"

Опять же, я не ищу их, поэтому мне не нужно делать полнотекстовый индекс для этого столбца.

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

Спасибо, Андрей


person Andrey    schedule 28.09.2009    source источник
comment
еще лучше, сохраните их все в одной строке xml и поместите в один столбец! ;-) просто шучу, не делайте этого!   -  person KM.    schedule 28.09.2009
comment
Я разговаривал с кем-то некоторое время назад, кто сделал именно это. он очень гордился тем, что он сделал. затем они попросили его предоставить отчеты   -  person Raj More    schedule 28.09.2009
comment
Хотя я определенно думаю, что вы должны нормализовать, как и все остальные, если вы этого не сделаете, я бы посоветовал вам сделать поле, в котором вы храните значения, разделенные запятыми, достаточно большим, чтобы вместить ВСЕ будущие возможные идентификаторы, которые вы хотите включить. Я работаю в отделе контроля качества и уже сталкивался с базой данных, которая использовала этот дизайн раньше, и она долгое время работала нормально. Но я предполагаю, что где-то за 10 с лишним лет никто не понял, что требования продолжали расти, пока поле не могло хранить все значения. Затем у вас есть кто-то вроде меня, который пытается выбрать все возможные идентификаторы и взорвать приложение.   -  person Michael Cheng    schedule 29.09.2009


Ответы (9)


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

То, что вы предлагаете, является классической преждевременной оптимизацией. Вы еще не знаете, будет ли это соединение узким местом, и поэтому вы не знаете, покупаете ли вы на самом деле какое-либо улучшение производительности. Подождите, пока вы не сможете профилировать вещь, и тогда вы узнаете, нужно ли оптимизировать эту часть.

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

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

person Jeremy Bourque    schedule 28.09.2009
comment
Ну, проблема в том, что существует около 30 таких множественных вариантов, и все они должны отображаться на одной странице профиля, что в конечном итоге означает запрос 30 таблиц для одного запроса. Это определенно будет узким местом, поэтому я пытаюсь понять, какие у меня есть варианты. - person Andrey; 28.09.2009
comment
30 запросов на странице профиля? Это никогда не должно быть проблемой с нагрузкой. Как часто, по вашему мнению, кто-то действительно загружает страницу своего профиля? Раз в минуту? Едва ли. Опять же, не делайте предварительную оптимизацию - person NotMe; 29.09.2009

Не надо.

  • Вы не ищете их сейчас
  • Данные бесполезны ни для чего, кроме этой одной ситуации
  • Отсутствие целостности данных (например, отсутствие FK)
  • Вам все еще нужно перейти на «английский, немецкий» и т. д. для отображения
  • «Дайте мне всех пользователей, говорящих на языке x» = НЕУДАЧА
  • Список на самом деле является проблемой презентации

Однако это ваша система, и я с нетерпением жду возможности ответить на неизбежные «помощные» вопросы позже...

person gbn    schedule 28.09.2009
comment
Собственно, дайте мне всех пользователей, говорящих на х, можно сделать: SELECT * FROM table WHERE ',' + языки + ',' LIKE',' + x + ','. Ужасная идея, но возможная. - person erikkallen; 29.09.2009
comment
Конечно: SELECT * FROM table WHERE ',' + языки + ',' LIKE '%,' + x + ',%' - person erikkallen; 29.09.2009
comment
@gbn Это мой вопрос на протяжении многих лет. Я использовал его в некоторых сценариях, и у меня есть таблица, в которой хранится идентификатор/имя, поэтому я объединяю идентификаторы с запятой и сохраняю в одном столбце. Я написал функцию, которая получает строку, разделенную запятыми, и возвращает таблицу с одним столбцом, и когда я хочу найти что-то в этой строке, используйте оператор IN из результата функции. это плохой способ? Еще одна важная проблема может заключаться в следующем: если я буду использовать дополнительную таблицу для хранения дополнительной информации, мне следует добавить более 40 таблиц к текущим примерно 200 таблицам в моей базе данных. Ваше мнение о добавлении таблиц уже есть? опишите, если можно. - person QMaster; 29.10.2014

Этот тип хранения почти ВСЕГДА преследовал меня. Во-первых, вы даже не в первой нормальной форме. Во-вторых, какой-нибудь менеджер обязательно вернется и скажет: «Эй, теперь, когда мы храним это, не могли бы вы написать мне отчет о…»

Я бы предложил использовать нормализованный дизайн. Поместите его в отдельную таблицу.

person Raj More    schedule 28.09.2009
comment
Ну, как я уже сказал, меня не волнуют отчеты, так как мы будем хранить все нормализованные данные в поисковой системе, и отчеты будут запрашивать их, а не базу данных. Список в БД будет только для двух вещей: пользовательский интерфейс и переиндексация поисковой системы в случае падения индекса. Я вижу, что вы указываете, как и другие, кто ответил, но я все еще испытываю искушение из-за производительности - person Andrey; 29.09.2009

Проблемы:

  1. Вы теряете возможность присоединиться (очевидно).
  2. Вы должны повторно анализировать список при каждой загрузке/отправке страницы. Что приводит к большему количеству кода на стороне клиента.
  3. Вы теряете все претензии на сохранение целостности базы данных. Только представьте, если вы решите УДАЛИТЬ язык позже... Какой sql будет исправлять все ваши пользовательские профили?
  4. Предполагая, что различные параметры вашего профиля хранятся в таблице поиска в БД, вам все равно придется выполнять «30 запросов» на страницу профиля. Если это не так, вам нужно развертывать код для каждого небольшого изменения. плохо, очень плохо.
  5. Основывать проектное решение на чем-то, что «не произойдет» — это абсолютный рецепт провала. Конечно, деловые люди сказали, что они никогда этого не сделают... Пока они не придумают причину, они обязательно должны это сделать. Сегодня. Который будет сразу после того, как вы закончите кодировать это.
  6. Как я уже говорил в комментарии, 30 запросов для малоиспользуемой страницы — это ничто. Не переживайте и определенно не оптимизируйте, если вы не уверены, что это необходимо. Угадайте, сколько запросов делает SO для своей страницы профиля?
person NotMe    schedule 28.09.2009

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

В качестве альтернативного решения: вы можете сохранить как одно целое число с битовой маской, например: 0 - нет выбора 1 - английский 2 - испанский 4 - немецкий 8 - французский 16 - русский --и т. д. степени 2

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

person WebMatrix    schedule 28.09.2009
comment
Я видел побитовые операции в базе данных, а не фанат. - person Gratzy; 28.09.2009
comment
Разве сохранение его как целого числа с битовой маской также не пытается хранить реляционные данные нереляционным способом? Не пытаюсь спорить, мне интересно, не упускаю ли я что-то. - person Gratzy; 28.09.2009
comment
@Gratzy, вы могли бы привести такой аргумент, это не ваш традиционный метод хранения реляционных данных, хотя он не так плох, как разделение запятыми. bitwize лучше всего работает в определенных ситуациях, когда вам нужно проверить несколько истинных условий (и я думаю, что это применимо к сценарию OP), я могу ошибаться - person WebMatrix; 28.09.2009

Преждевременная оптимизация — корень всех зол.

РЕДАКТИРОВАТЬ: Очевидно, контекст моего наблюдения был неправильно истолкован некоторыми - и, следовательно, отрицательные голоса. Поэтому я уточню.

Денормализация вашей модели, чтобы сделать вещи проще и/или "более производительными" - например, создание объединенных столбцов для представления бизнес-информации (как в случае OP) - это то, что я называю "преждевременной оптимизацией".

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

При проектировании базы данных разработчики (и администраторы баз данных) должны применять стандартные методы, такие как нормализация, чтобы их модель данных отражала собираемую и управляемую бизнес-информацию. Я не считаю, что правильное использование нормализации данных является «оптимизацией» — это необходимая практика. На мой взгляд, специалисты по моделированию данных всегда должны искать модели, которые можно было бы реструктурировать (как минимум) до третьей нормальной формы (3NF).

person LBushkin    schedule 28.09.2009
comment
-1, потому что это очень простое правило проектирования баз данных (1NF). - person Raj More; 29.09.2009

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

person MartW    schedule 28.09.2009

Вы, кажется, очень беспокоитесь о добавлении нескольких дополнительных соединений таблицы поиска. По моему опыту, время, необходимое для фактической передачи HTML-ответа и его рендеринга браузером, намного превышает несколько дополнительных объединений таблиц. Особенно, если вы используете индексы для своих первичных и внешних ключей (как и должно быть). Это похоже на то, что вы планируете многодневную поездку по пересеченной местности и беспокоитесь о 1 дополнительной 10-минутной остановке в туалете.

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

person Shane    schedule 28.09.2009

Нуууууууууууу!!!!!!!!

Как сказано очень хорошо в вышеупомянутых нескольких должностях.

Если вам нужна противоположная точка зрения на эту дискуссию, посмотрите на wordpress. Таблицы переполнены данными с разделителями, и это отличная и простая платформа.

person Jestep    schedule 28.09.2009