Когда мне следует использовать отношения один на один?


92

Извините за этот вопрос нуба, но есть ли реальная необходимость использовать взаимно-однозначные отношения с таблицами в вашей базе данных? Вы можете реализовать все необходимые поля внутри одной таблицы. Даже если данные становятся очень большими, вы можете перечислить имена столбцов, которые вам нужны, в SELECTоператоре вместо использования SELECT *. Когда вам действительно нужно это разделение?

Ответы:


105

1 до 0..1

  • «От 1 до 0..1» между суперклассами и подклассами используется как часть стратегии «все классы в отдельных таблицах» для реализации наследования .

  • От 1 до 0..1 можно представить в одной таблице с частью "0..1", покрытой полями, допускающими NULL. Однако, если отношение в основном «1 к 0» и только несколько строк «1 к 1», разделение части «0..1» в отдельную таблицу может сэкономить некоторые преимущества хранения (и производительности кеша). Некоторые базы данных экономнее хранят значения NULL, чем другие, поэтому «точка отсечения», когда эта стратегия становится жизнеспособной, может значительно варьироваться.

1 к 1

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

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

  • Триггеры также обычно привязаны к таблице. Хотя теоретически можно иметь только одну таблицу и триггер игнорировать «неправильную половину» строки, некоторые базы данных могут налагать дополнительные ограничения на то, что триггер может и не может делать, что может сделать это непрактичным. Например, Oracle не позволяет вам изменять изменяющуюся таблицу - имея отдельные таблицы, только одна из них может изменяться, поэтому вы все равно можете изменять другую из своего триггера.

  • Отдельные таблицы могут обеспечить более детальную безопасность.

В большинстве случаев эти соображения не имеют значения, поэтому в большинстве случаев вам следует рассмотреть возможность объединения таблиц «1 к 1» в единую таблицу.


20

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

Это может дать преимущества в будущем, если отдельные данные нужно будет также связать с каким-либо другим объектом.


19

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

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

Если в вашей таблице 20 атрибутов, и только 4 из них используются время от времени, имеет смысл разбить таблицу на 2 таблицы для проблем с производительностью.

В таких случаях нехорошо иметь все в одной таблице. К тому же, работать с таблицей из 45 столбцов непросто!


17

Мои 2 цента.

Я работаю в месте, где все мы разрабатываем большое приложение, и все представляет собой модуль. Например, у нас есть usersтаблица, и у нас есть модуль, который добавляет данные facebook для пользователя, другой модуль, который добавляет данные twitter для пользователя. Мы могли бы решить отключить один из этих модулей и удалить все его функции из нашего приложения. В этом случае каждый модуль добавляет свою собственную таблицу с отношениями 1: 1 к глобальной usersтаблице, например:

create table users ( id int primary key, ...);
create table users_fbdata ( id int primary key, ..., constraint users foreighn key ...)
create table users_twdata ( id int primary key, ..., constraint users foreighn key ...)

13

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

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

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

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


5

не очень часто.

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

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


5

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

Ниже приведена статья о нормализации.

http://support.microsoft.com/kb/283878


3

Как и на все вопросы, связанные с дизайном, ответ - «зависит от обстоятельств».

Есть несколько соображений:

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

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

  • Насколько вы уверены, что отношения будут 1: 1? Как указывает этот вопрос, все может быстро усложниться.


3

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


2

На практике я обычно сталкиваюсь с двумя общими видами отношений 1: 1:

  1. Отношения IS-A, также известные как отношения супертипа / подтипа. Это когда один вид сущности фактически является типом другой сущности (EntityA IS EntityB). Примеры:

    • Физическое лицо, с отдельными юридическими лицами для бухгалтера, инженера, продавца в рамках одной компании.
    • Сущность элемента с отдельными сущностями для Widget, RawMaterial, FinishedGood и т. Д.
    • Автомобиль с отдельными объектами для грузовика, седана и т. Д.

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

  2. "Хозяин" отношений. Это когда человек является уникальным начальником или менеджером или руководителем организационной единицы (отдела, компании и т. Д.). Когда для организационной единицы разрешен только один начальник, тогда существует отношение 1: 1 между физическим лицом, которое представляет начальника, и субъектом организационной единицы.


1
Мне нравится второй пример. У вас может быть сущность «Отдел» и сущность «Сотрудник». В одном отделе у вас много сотрудников, и сотрудник может работать только в одном отделе. Это 1: n. Сотрудник может быть руководителем отдела - только одного отдела, а в отделе есть только один руководитель. Таким образом, вы получаете две таблицы, связанные с двумя отношениями - 1: n и 1: 1.
cezar

2

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

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

Представьте, опять же, у вас есть customersпо одному addressадресу, но на этот раз иметь адрес необязательно. Конечно, вы можете реализовать это как NULLнабор столбцов с возможностью выбора, например ZIP,state,street. Но предположим, что, учитывая, что у вас есть адрес, состояние не является необязательным, а ZIP-файл. Как смоделировать это в одной таблице? Вы можете использовать ограничение для customerтаблицы, но гораздо проще разделить ее в другой таблице и сделать foreign_key NULLable. Таким образом, ваша модель гораздо более четко говорит, что сущность address является необязательной, и что ZIPэто необязательный атрибут этой сущности.


0

За время программирования я столкнулся с этим только в одной ситуации. Это когда между одними и теми же двумя объектами («Сущность A» и «Сущность B») существует отношение «1 ко многим» и «1 к 1».

Когда «Entity A» имеет несколько «Entity B», а «Entity B» имеет только 1 «Entity A», а «Entity A» имеет только 1 текущую «Entity B», а «Entity B» имеет только 1 «Entity A».

Например, у автомобиля может быть только один текущий водитель, а водитель может управлять только одним автомобилем за раз - поэтому соотношение между концепциями автомобиля и водителя будет 1 к 1. - Я позаимствовал этот пример из ответа @Steve Fenton

Если водитель может управлять несколькими машинами, но не одновременно. Таким образом, сущности «Автомобиль» и «Водитель» относятся к категории «один ко многим» или «многие ко многим». Но если нам нужно знать, кто является текущим драйвером, нам также понадобится соотношение 1 к 1.


0

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.