Подтвердить что ты не робот

Три адреса клиентов в одной таблице или в отдельных таблицах?

В моем приложении у меня есть класс Customer и Address. Класс Customer имеет три экземпляра класса Address: customerAddress, deliveryAddress, invoiceAddress.

Каков наилучший способ отразить эту структуру в базе данных?

  • Прямым способом будет таблица клиентов и отдельная таблица адресов.
  • Более денормализованный способ - это просто таблица клиентов с столбцами для каждого адреса (пример для "street": customer_street, delivery_street, invoice_street)

Каковы ваши впечатления? Существуют ли какие-либо преимущества и недостатки этих подходов?

4b9b3361

Ответ 1

Если вы на 100% уверены, что клиент будет иметь только 3 адреса, которые вы описали, то это нормально:

CREATE TABLE Customer
(
    ID int not null IDENTITY(1,1) PRIMARY KEY,
    Name varchar(60) not null,
    customerAddress int not null
        CONSTRAINT FK_Address1_AddressID FOREIGN KEY References Address(ID),
    deliveryAddress int null
            CONSTRAINT FK_Address2_AddressID FOREIGN KEY References Address(ID),
    invoiceAddress int null
            CONSTRAINT FK_Address3_AddressID FOREIGN KEY References Address(ID),
    -- etc
)

CREATE TABLE Address
(
    ID int not null IDENTITY(1,1) PRIMARY KEY,
    Street varchar(120) not null
    -- etc
)

В противном случае я бы моделировал вот так:

CREATE TABLE Customer
(
    ID int not null IDENTITY(1,1) PRIMARY KEY,
    Name varchar(60) not null
    -- etc
)

CREATE TABLE Address
(
    ID int not null IDENTITY(1,1) PRIMARY KEY,
    CustomerID int not null
        CONSTRAINT FK_Customer_CustomerID FOREIGN KEY References Customer(ID),
    Street varchar(120) not null,
    AddressType int not null 
    -- etc
)

Ответ 2

Я бы пошел (как учит теория базы данных) для двух отдельных таблиц: Customer and Address.

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

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

Ответ 3

Я бы пошел с денормализованным. Это проще.

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

  • Создайте новую запись адреса.
  • Повторите запись клиента.

Если я верну его обратно, вам нужно проверить:

  • Имеется ли аналогичная запись адреса.
  • Повторите запись клиента.

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

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

Преимущества нормализованного

  • Меньше места.
  • Дублирующая логика вроде встроена (хотя, возможно, они не дублировались)?
  • Поддержка добавления новых полей адреса (kinda).

Преимущества денормализованного

  • Более быстрые запросы.
  • Меньше программирования.

Ответ 4

Перейдите с двумя таблицами, клиентом, адресом.

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

Теперь вы можете ссылаться на эти записи в таблице адресов. Например, когда заказ отправляется клиенту, идентификатор адреса, на который ссылается a по таблице заказов, может быть такой же, как в поле DeliveryAddressID в таблице клиентов.

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

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

Ответ 5

У меня есть это в Zen Cart (и, вероятно, osCommerce), в таблице заказов и задаются вопросом, почему они пошли именно так, даже если у них есть таблица адресов. Единственная причина, по которой я видел, которая действительна, предназначена для рекордных целей: даже если клиент меняет свои адреса, информация о заказе не должна меняться, она отражает данные во время заказа.

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

В целом, если вашему приложению не нужно вести историю, просто перейдите к двум разделенным таблицам.

Ответ 6

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

Скажем, у нас есть две альтернативные схемы в базе данных: 1) пользователь: user_id, имя пользователя, пароль

2) user: user_id, password_id  password: password_id, пароль

Является ли (2) "более нормированным", чем (1)? Нет

В этом случае OP, если: 1) мы рассматриваем адрес как атомную ценность, 2) приложение требует только трех типов адресов.

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

Ответ 7

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