Почему ограничения применяются в базе данных, а не в коде?

21

Почему ограничение применяется в базе данных? Разве это не будет более гибким, чтобы поместить это в коде?

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

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

Текущие ограничения:

  1. Зарегистрированным лицом в системе может быть только Студент или Сотрудник.
  2. Личность лица требует уникальности социального номера, который, как мы предполагаем, у каждого человека есть только один уникальный (иначе говоря, достаточно хороший первичный ключ). (см. № 1)

Позже мы решим удалить число 1. Если однажды колледж решит, что Teacher( Employeeподтип) также может быть Student, посещая курсы в свободное время, гораздо сложнее изменить структуру базы данных, которая может иметь тысячи, миллионы, миллиарды, миллионы записей, а не просто изменение логики в коде: только та часть, которая не позволяла человеку быть зарегистрированным как студентом, так и сотрудником.

(Это очень невероятно, но сейчас я не могу думать ни о чем другом. Видимо это возможно).

Почему мы заботимся о бизнес-правилах в дизайне базы данных, а не в коде?

# 1: примечание 7 лет спустя, пример из реальной жизни:
я видел правительство, в котором из-за ошибки дублировались выданные SSN: несколько человек, один SSN. Те, кто разрабатывал исходную БД, определенно допустили ошибку, не применяя это ограничение уникальности в базе данных. (а позже ошибка в исходном приложении - несколько приложений, использующих общую базу данных и не согласных с тем, где поставить, проверить и применить ограничение? ...).
Эта ошибка будет продолжать существовать в системе и во всех разработанных системах, которые полагаются на базу данных этой исходной системы в течение многих лет. Читая ответы здесь, я научился применять все ограничения, как можно больше, мудро (не слепо) в базе данных, чтобы представить реальный физический мир настолько хорошо, насколько я могу.

hkoosha
источник
2
В основном мы заботимся о соблюдении бизнес-правил и о том, что лучше для этого.
ypercubeᵀᴹ
3
На самом деле вы представляете очень плохой пример того, для чего используются ограничения, поскольку гибкость ваших сущностей и расширяемость базы данных в основном определяются нормализацией. При этом ограничения являются окончательной гарантией от любых поврежденных данных, попадающих в базу данных, даже если приложение содержит ошибки, даже если разрабатывается новое приложение, даже если добавлен внешний API, даже если кто-то редактирует БД напрямую. Ограничения защищают базу данных, кроме того, бизнес-логика должна будет делать свои собственные вещи, прежде чем пытаться получить доступ к БД.
Niels Keurentjes
3
На самом деле, как аспирант, меня считают и студентом, и сотрудником, и учителем. Так что твой пример не совсем невероятен.
Уинстон Эверт
4
Вы никогда не должны основывать проект базы данных на объектах в вашем приложении. Вы могли бы придумать это как личность, а затем иметь соответствующую таблицу для определения роли людей. Тогда проблема не возникает, так как у вас есть реальная таблица для ролей, так что люди могут иметь несколько ролей. Если вы хотите, чтобы у вас был только один человек, то вы ограничите таблицу так, чтобы peopleID был уникальным. Когда вы хотите изменить это, удалите ограничение.
HLGEM
Объект <-> Реляционное отображение - это искусство.
Торбьерн Равн Андерсен

Ответы:

34

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

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

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

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

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

FrustratedWithFormsDesigner
источник
Таким образом, согласно этому ответу в коде должно применяться правило <человек может существовать только в таблице подтипов Студента или только в таблице подтипов Сотрудников>, а База данных имеет <подтип Студента / Сотрудника должен быть допустимым человек> ограничение. Я прав? (Это был пример книги). Благодарю.
hkoosha
2
@loolooyyyy: Да, я думаю, что это правильно. Если база данных применяет первое правило (то, что человек может быть только студентом или сотрудником), то описанная вами ситуация (в которой сотрудник хочет зарегистрироваться в классе) невозможна, потому что: человек не может быть и тем, и другим. даже возможно создать вторую «личную» запись, потому что они не могут делиться номерами социального страхования, которые предположительно выдаются третьей стороной (например, правительством). Конечно, эта чрезмерно ограничительная модель данных может работать в некоторых случаях ...
FrustratedWithFormsDesigner
2
@loolooyyyy: еще один способ использовать исходную модель данных и все же позволить учителям быть студентами, возможно, иметь другую таблицу, teachers_as_studentsкоторая называется другим подтипом Studentsи имеет новый внешний ключ, ссылающийся на Teachers, и сгенерированный системой первичный ключ вместо Social. Номер безопасности. Таким образом, «ученик» на самом деле является псевдонимом для учителя, поэтому учитель все еще может зарегистрироваться, чтобы посещать занятия. Трудно сказать наверняка, насколько хорошо это будет работать, не видя всей модели данных.
FrustratedWithFormsDesigner
2
Я понизил это. Нет времени, когда ограничение лучше всего применять только в приложении . Тон этого ответа взвешен неправильно.
Эван Кэрролл
3
@FrustratedWithFormsDesigner, безусловно, на самом деле это дочерний элемент плаката для ограничения внешнего ключа. Предположим, у вас есть три клиента разных версий / сборок точки доступа db, что вы будете делать, когда перестанете поставлять этот продукт красным цветом? Где вы собираетесь хранить список возможных цветовых комбинаций? Подсказка: у меня есть централизованное место для вас. И если вы создадите таблицу color_products, и colorвы, вероятно, сможете создавать дополнительные раскрывающиеся списки с большей легкостью - большинство IDE / загрузчиков схем поддерживают следующие fkeys.
Эван Кэрролл
35

Так как:

  1. Я хочу, чтобы на все данные в базе данных распространялись те же ограничения, а не только на новые данные, на которые распространяются ограничения в версии кода, которая выполняется сегодня.
  2. Я хочу декларативные ограничения, а не программные ограничения.
  3. Данные в базе данных часто превышают код, написанный для взаимодействия с ней сегодня. И эти данные, а не код, являются активом организации.
  4. Мой код становится намного проще, когда я знаю, что все данные подвергаются строгим ограничениям. Мне больше не нужно рассматривать особые случаи, которые я знаю, что база данных гарантирует невозможность.

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

Колин т Харт
источник
4
Полусвязанные с (1) и (3): ошибки в коде приложения могут быть исправлены, ошибки в ваших данных часто непоправимы.
Му слишком коротка
17

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

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

HLGEM
источник
17

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

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

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

Кстати, это не неизвестно разработчикам языка приложений. Прочтите раздел 3.10 «Уникальность» в руководствах по Ruby on Rails: проверки правильных записей и обратные вызовы

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

Дэвид Олдридж
источник
16

Преимущества ограничений, накладываемых базой данных:

Простота. Объявление ограничения значительно проще, чем объявление ограничения и написание кода, который обеспечит выполнение этого объявления.

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

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

Повторное использование - вы можете начать с одного приложения на одной платформе, но это может не произойти. Что если вам нужен доступ к данным из другой ОС, другого оборудования или из голосового интерфейса? Имея ограничения в базе данных, этот код никогда не должен быть переписан для новой платформы и никогда не должен быть отлажен для точности или профилирован для скорости.

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

Долговечность - Ваша платформа базы данных, скорее всего, переживет любое конкретное приложение.

Ли Риффель
источник
11

Почему ограничения применяются на сервере? Потому что вы не можете заставить плохих парней использовать ваш клиент.

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

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

Гринстоун Уолкер
источник
10

Некоторые отличные ответы здесь и рискуют повторить другие мысли:

  • SSN не обязательно уникален. Черт, SSN даже не всегда известен, а в некоторых случаях он не существует (пока). SSN могут быть использованы повторно, и не у всех сотрудников или студентов может быть SSN. Это второстепенный вопрос, но он демонстрирует, что независимо от того, где вы применяете свои ограничения, вам необходимо достаточно тщательно понимать модель данных и область, чтобы принимать решения о бизнес-правилах.
  • Лично я предпочитаю, чтобы ограничения были как можно ближе к данным. Очень простая причина в том, что не все будут использовать код приложения для изменения данных в базе данных. Если вы применяете свои бизнес-правила на уровне приложения, и я запускаю UPDATEинструкцию непосредственно для базы данных, как ваше приложение предотвращает недопустимые изменения? Другая проблема с бизнес-правилами в приложении заключается в том, что перекомпиляция / повторное развертывание может быть затруднено, особенно для распределенных приложений, где возможно, что не все получат обновление одновременно. И, наконец, изменение бизнес-правил в приложении абсолютно ничего не делает с уже существующими данными, которые нарушают новые правила - если вы добавляете новое ограничение к данным, вам нужно исправить данные.
  • Вы можете обосновать несколько избыточных проверок на разных уровнях. Все это зависит от гибкости методологий развертывания, вероятности изменения и сложности синхронизации изменений бизнес-правил в базе данных и на других уровнях. Убедительным аргументом в пользу повторения проверок на уровне приложения является то, что вы потенциально можете предотвратить двустороннее обращение к базе данных только для того, чтобы не выполнить ограничение там (в зависимости от характера ограничения и от того, зависит ли оно от существующих данных). Но если бы мне пришлось выбирать один или другой, я бы положил его в базу данных по вышеуказанным причинам.

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

Аарон Бертран
источник
9
  1. База данных может эффективно проверять ограничения. Лучше, чем код.

  2. Ограничения целостности помогают базе данных находить эффективный план выполнения

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

ibre5041
источник
8

Краткий ответ ... для сохранения целостности данных (то есть точности и достоверности).

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

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

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

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

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

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

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

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

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

Кстати, это именно то, что должны делать программисты на COBOL, так как эти массивные базы данных часто создавались до того, как у нас были реляционные движки и ограничения. Даже если они перенесены в современную систему, такую ​​как IBM DB2, ограничения иногда не реализуются полностью, поскольку логика старых правил, воплощенная, возможно, в серии «пакетных» программ на языке COBOL, может быть настолько запутанной, что их непрактично преобразовывать. Вместо этого можно использовать автоматизированные инструменты для преобразования старого COBOL в более новую версию с интерфейсами для нового реляционного механизма и с небольшими изменениями, сохраняя целостность данных ... до тех пор, пока не будет написано новое приложение, которое слегка повреждает все, и компания поднимается скажем, в суде за взыскание с тысяч домовладельцев, которых у них не должно быть.

DocSalvager
источник
7

В дополнение к другим комментариям ...

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

gsiems
источник
5

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

Кроме того, триггеры с меньшей вероятностью будут переносимыми, так как они обычно пишутся на языках конкретного поставщика, таких как PL / SQL.

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

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

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

  1. База данных обеспечивает целостность среди разных клиентов. У вас могут быть разные клиенты на разных платформах для доступа к базе данных. Ограничения в базе данных не рискуют проблемами целостности при создании нового клиента. Это избавляет вас от необходимости проверять ваши ограничения в случае перезаписи или дополнительной точки доступа.
  2. База данных имеет DSL для построения ограничений: SQL DDL!
  3. База данных обеспечивает доступ к этим ограничениям в системных каталогах, поэтому надлежащий ORM или «загрузчик схемы» может прочитать эти ограничения и перенести их в ваше приложение. Например, если в вашей базе данных указано, что у вас есть varchar(5)тип, есть большая вероятность, что вы сможете найти схему, загружающую ORM для вашего конкретного языка, которая сопоставляет тип языка с типом схемы и собирает свое собственное ограничение на размер. DBIx for Perl is one such schema loader; вот еще один для Entity Framework . Возможности этих загрузчиков различны, но все, что они могут предоставить, является хорошим началом для обеспечения целостности приложения без использования базы данных.
Эван Кэрролл
источник