Три адреса клиентов в одной таблице или в отдельных таблицах? - PullRequest
12 голосов
/ 22 ноября 2008

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

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

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

Каков ваш опыт с этим? Есть ли преимущества и недостатки этих подходов?

Ответы [ 7 ]

11 голосов
/ 22 ноября 2008

Если вы на 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
)
5 голосов
/ 22 ноября 2008

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

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

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

4 голосов
/ 22 ноября 2008

Перейти с 2 таблицами, Клиент, Адрес.

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

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

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

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

4 голосов
/ 22 ноября 2008

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

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

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

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

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

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

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

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

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

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

  • Ускоренные запросы.
  • Меньше программирования.
2 голосов
/ 24 ноября 2008

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

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

2) пользователь: user_id, password_id пароль: password_id, пароль

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

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

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

2 голосов
/ 22 ноября 2008

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

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

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

1 голос
/ 22 ноября 2008

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

...