Я должен добавить этот новый столбец к таблице клиентов или к отдельной новой таблице?

У меня есть таблица клиентов с информацией о наших клиентах (идентификатор, вход в систему, имя, информация о контактах, различные варианты, столбец TS, и так далее, ~15 столбцов, ~few сотни клиентов).

Теперь мы должны отправить every-day-updates нашим крупнейшим клиентам (<10% всех клиентов). И я должен сохранить метку времени последнего обновления, которые были отправлены клиенту, в поэтому следующий раз, когда я отправлю только новые обновления (я имею в виду обновления в строках порядка с TS, больше, чем сохраненный TS).

Если я добавлю новый столбец "LastUpdatesSentTS" к таблице клиентов, то, как я понимаю, это будет соответствовать правилам нормализации (в противном случае дайте ссылку, которая доказывает, что это повредит нормализацию).

Но, поскольку я также знаю с физической точки зрения проектирования баз данных, лучше составить новую таблицу с 2 столбцами [CustomerID, LastUpdatesSentTS], потому что только у меньше чем 10% клиентов будет это информацией TS сохраненный. Я подразумеваю, что, если я добавляю столбец к таблице клиентов - у большинства клиентов будет пустой указатель в том столбце. Кроме того, если я составлю отдельную новую таблицу, то возможно, будет лучше отбросить булев столбец "SendUpdates" из таблицы клиентов (потому что я буду в состоянии понять, каким клиентам нужны обновления, которые будут отправлены путем соединения таблицы клиентов с новой таблицей). Кроме того, в этом случае я боюсь, что через несколько лет у меня будет набор очень маленьких таблиц, когда все это могло быть в таблице клиентов (не повреждая нормализацию, как я понимаю).

В простых словах я вижу 2 возможных проекта таблицы:

1)

Table customers:  
[CustomerID, Name, ..., SendUpdates, LastUpdatesSentTS]

2)

Table customers:  
[CustomerID, Name, ...]  
Table customer_updates_sending:
[CustomerID, LastUpdatesSentTS]

Что Вы думаете?

18
задан nightcoder 12 February 2010 в 18:02
поделиться

6 ответов

Нет, необходимо использовать CGFloat.

-121--3977968-

При использовании stdbool.h определенного типа bool возникают проблемы, когда требуется переместить код из более нового компилятора, поддерживающего тип bool, в более старый компилятор. Это может произойти во встроенной среде программирования, когда вы переходите к новой архитектуре с компилятором Си на основе более старой версии спецификации.

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

-121--976080-

Я бы предложил сделать это в виде второй отдельной таблицы.

Причина в том, что, как вы предлагаете в вашем вопросе, только приблизительно 10% ваших клиентов нуждаются в этих «обновлениях», и поэтому приблизительно 90% записей из таблицы «клиентов» будут иметь поле, всегда содержащее значение NULL, если вы делаете это как дополнительное поле в той же таблице клиентов. Реализация этой функции в виде второй таблицы позволяет избежать этой проблемы.

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

В основном я мог бы спросить себя:

"Мог бы я, в любой момент в будущем, необходимо знать о клиенте история обновлений, а не только самая последняя? "

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

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

Даже если вы не заинтересованы в истории обновлений клиентов, я лично предпочитаю подход 2 таблицы, поскольку он, безусловно, позволяет вести исторические записи, и предлагает более продуманный подход (так как только некоторые записи из таблицы клиентов будут нуждаться в записях во второй таблице «обновлений»). Тем не менее, смотрите мой EDIT ниже для получения дополнительной информации. Если бы я знал, что история никогда не потребуется для этих данных, я бы внедрил как одно дополнительное поле в таблицу существующего клиента.

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

EDIT:

(В ответ на комментарии к моему ответу).

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

В зависимости от характера «дополнительных» данных необходимо принять прагматичное решение о том, как они будут осуществляться. Аарон предполагает, что в случае поля даты «LastUpdate» наличие большого количества NULL в 90% таблицы клиентов не является плохой вещью, и я согласен с ним здесь в том, что, с точки зрения NULL , это не плохая вещь. Мое собственное предложение использовать 2 табличный подход было основано не столько на желании удалить NULL (хотя он и выполняет это), сколько на том, чтобы обеспечить сохранение истории дат «LastUpdate».

Конечно, если ведение истории полностью не требуется (и иметь в виду, что то, что не требуется сегодня, вполне может потребоваться завтра), то внедрение этой даты «LastUpdate» в качестве дополнительного поля в той же таблице «Customer» было бы хорошо. На самом деле, если бы между одним клиентом и одной датой «последнего обновления» существовала прямая связь «один к одному», разбить ее на 2 таблицы было бы неправильно. В этом случае я бы реализовал его как дополнительное поле в таблице клиентов, так как теперь это скалярное свойство этого клиента.

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

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

16
ответ дан 30 November 2019 в 08:21
поделиться

«Если сомневаетесь, сделайте простейшее, что может сработать» - Уорд Каннингем

Иногда я бы сказал «добавьте вторую таблицу», но в данном случае я не считаю это оправданным. Насколько я понимаю, нет необходимости вести историю значений этого атрибута. Стол маленький. И, в конечном итоге, у вас есть атрибут покупателя. Конечно, не все из них будут заселены, но для меня это второстепенное значение. Многие поля в большинстве случаев имеют значения NULL, но это не означает, что вы обязательно должны создать вторую таблицу для их хранения. Сделайте это как можно более простым (и максимально нормализованным), но не проще (или нормальным :-). Если бы это был я, я бы добавил эти поля в таблицу CUSTOMERS. YMMV.

Делитесь и наслаждайтесь.

7
ответ дан 30 November 2019 в 08:21
поделиться

Я бы выбрал вариант 2.

Мне не нравятся столбцы вроде SendUpdates . ИМО, лучше сохранить это при наличии строки в другой таблице.

SELECT * FROM customer_updates_sending;

проще и быстрее, чем

SELECT * FROM  customers WHERE SendUpdates = 1;

Дальнейшие мысли в ответ на комментарий:

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

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

Я не совсем понимаю, что вы имеете в виду «вам нужно изменить исходный запрос в каждой таблице». Таблица - это набор информации. Вы не сохраняете запросы в таблицах.

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

3
ответ дан 30 November 2019 в 08:21
поделиться

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

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

Об опасениях по поводу редкого использования столбца отметок времени обновления
(точка отключения, поскольку, вероятно, будет выбран подход с двумя таблицами, но в целом ...)
Тот факт, что только 10% записей была бы некоторая информация в столбце отметки времени, намеки на некоторую «расточительность», если бы мы выбрали вариант 1.На самом деле редкое использование этого столбца мало влияет на размер базы данных и производительность в целом. Например, если таблица легко включает столбец переменной длины, накладные расходы на размер фактически равны нулю; если это первый столбец, допускающий значение NULL или столбец переменной длины, будет взиматься налог минимального размера, но он не будет иметь большого значения. (Также в более поздних версиях SQL Server 2005, я думаю, можно использовать разреженный столбец, хотя это вряд ли стоит с базой данных размером в тысячу или даже десятки тысяч записей.)

В столбце "sendudpate"
Также неплохо удалить логический столбец sendupdate из основной таблицы, поместив всю информацию, относящуюся к обновлению, в связанную таблицу. Однако я предлагаю, чтобы тот факт, что клиент получает обновления, не должен подразумеваться для базового клиента, имеющего запись в связанной таблице. Вместо этого введите столбец «sendupdate» в соответствующем столбце, возможно, не как простое логическое значение, а как, например, частотный код (например, 0 = нет обновлений, 1 = обновлять ежедневно, 7 = обновлять еженедельно и т. Д.). Это не означает, что Я предлагаю, чтобы у всех клиентов была запись в связанной таблице, но чтобы тот факт, что у них есть такая запись, был необходимым, но недостаточным условием, например, позволяющим временно отключить обновления и т. Д. И т. Д.

От того, есть ли у них такая запись. Табличный подход "перерывов" и правила нормализации
Важно различать физический и логический проекты баз данных. Вполне возможно иметь физическую схему, которая не нарушает никаких правил нормализации, но не нормализуется логически.В очень широком смысле одна основная мантра нормализации - хранить только один тип Entity в таблице. Пока нет дублирования данных, можно поместить в одну и ту же таблицу в одну широкую запись информацию, фактически относящуюся к двум логическим объектам.
Проиллюстрировано с базой данных клиентов в вопросе, можно решить, что физические записи будут включать дату последнего обновления, отправленного данному клиенту. Справедливо, физически правило нормализации не нарушено ... Однако логически можно утверждать, что «административная информация о клиенте» (имя, адрес ...) и «информация об обновлении» (дата последнего отправленного обновления) - это две разные сущности, даже хотя, похоже, они находятся в отношениях 1-1 на данный момент .
Следовательно, состояние нормализации логической модели, где сущности эффективно определены, часто находится в глазах смотрящего, поскольку можно (иногда очень справедливо и разумно) утверждать те элементы данных, которые имеют отношение 1-1, принадлежат одному и тому же понятию (сущности).


Q: Что такое логическая и физическая нормализация? ... Разве правила нормализации не прямолинейны? Я попытался объяснить это выше.
«физическая нормализация» (или, вернее, нормальная форма физической схемы) рассматривает сам фактический состав таблиц и их взаимосвязи и применяет простые правила, чтобы узнать, какой нормальной форме удовлетворяет такая схема.
«логическая нормализация» (или, скорее, нормальная форма модели данных) рассматривает эффективные сущности, обнаруженные в системе.
Итак, чтобы предоставить еще один пример, при разработке простой базы данных о доме для продажи, можно решить сохранить единую концепцию «ДОМ» в единой таблице со столбцами типа «Адрес», «Кухонная_площадка», «Жилая_Комната_Площадь» и т. Д.И такая таблица будет «работать» и технически иметь определенную нормальную форму; это было бы несколько непрактично, предотвращать перечисление домов с двумя кухнями и т. д. В качестве альтернативы можно было бы увидеть дом как «Местоположение» (адрес и, возможно, другую информацию администратора) и «Комнаты» (тип, поверхность, информация о напольном покрытии ...), при этом каждая концепция (местоположение, комната) хранится в отдельной таблице, причем одно местоположение связано с несколькими комнатами.
Благодаря тому, что обе эти модели могут быть помещены в нормальную физическую схему, можно сказать, что первая модель денормализована (на логическом уровне) из-за того, что она не захватывает должным образом сущности эффективно присутствуют.


В: Я не понимаю, как вы предлагаете явно отмечать факт получения клиентом обновлений? A:

 SELECT whatever
 FROM Customers
 JOIN NotificationTable N on N.CustomerId = C.CustomerId
 WHERE N.notificationFrequency > 0

В приведенном выше примере
- JOIN фиксирует первое условие для уведомления клиента: в таблице уведомлений должна быть соответствующая запись.
- предикат WHERE N.notificationFrequency> 0 фиксирует очень явное условие - положительное значение столбца notificaionFrequency.

1
ответ дан 30 November 2019 в 08:21
поделиться

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

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

Я бы предпочел вариант 2, поскольку он кажется мне более интуитивным методом.

0
ответ дан 30 November 2019 в 08:21
поделиться

Мне нужен простой способ ежедневно записывать, какие обновления я отправляю. Это не еще одна таблица данных о «покупателях», а таблица дат, когда каждому покупателю было отправлено обновление. Вам зададут следующий вопрос: «Получал ли клиент« А »обновленную информацию в прошлый вторник?» Единственный ответ, который может дать решение с одной таблицей: «Я не знаю, но они получили это в пятницу». Может быть неприемлемо. Без истории вы не можете повторно отправить обновление, которое клиент не получил.

0
ответ дан 30 November 2019 в 08:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: