Комментарии 98
И индексы тоже не нужны! Да и БД! Даешь просто текстовые файлы!!! )))
Конечно нужны - это единственное, что бережет консистентность ваших данных в БД, а как известно из законов Мерфи - если что-то может случиться - это случиться.
Джуны/кот/комета/шальной скрипт/не сработавшая тразакция - на страже всего этого стоят эти ключи, чтобы случайно и далеко не обязательно, что напрямую через шастанье в БД не превратить ваши данные в желе.
В статье говорится, что ситуация, когда FK сработает — невозможна, либо около невозможна, а валидация в первую очередь должна быть на стороне бэкенда, а не БД.
FK от шального скрипта никак не защищают, вы все также можете проставить неправильный айдишник, просто он должен существовать. Либо вообще удалить данные
Защищаться от неправильных скриптов нужно через ограничение прав, а не FK
P.S. индексы, очевидно, нужны
Это просто еще одна ступень защиты (как и ограничение прав), естественно, а не серебрянная пуля, вы предлагаете ее отключить.
А часто бывает, что скрипт при разработке что-то делает, и права там не мешают.
Ну и есть еще плюшки от FK, например удаление цепочек.
Мне больше всего нравится в статье то что у вас с базой работает один backend. А по факту вообще говоря СУБД проектировались для конкурентного доступа и более того в СУБД может лазить далеко не один и тот же софт. По этому уповать на корректность архитектуры одного backend фикция. То что сейчас чаще всего это не используется. А из-за микросервисной архитектуры СУБД упрощается до максимум десяти таблиц, ну извините это никак не отменяет использование FK
Если отсутствие FK может превратить ваши данные в желе, то ваши архитекторы БД и не только зря получают зарплату.
Ни разу не сталкивались с ситуацией, когда надо что-то поправить уже каким либо способом накосясенное, а эти самые FK люто мешают?
Поэтому давно пришёл к мысли, что FK не только бесполезны, но и вредны.
Про индексы это же явное утрирование. Но есть ещё одна вещь из теории баз данных, которую тоже можно предать анафеме как и FK. Это нормальные формы. Они порой добавляют лютых тормозов путем создания узких мест, если слепо им следовать.
Ни разу не сталкивались с ситуацией, когда надо что-то поправить уже каким либо способом накосясенное, а эти самые FK люто мешают?
Сталкивался, не раз и не два. Никаких проблем не испытывал.
Мешают не FK, а то, что вы бросаетесь исправлять "с голой пяткой на танк", не спланировав корректировку с учётом имеющихся ограничений. Так что вина не на наличии ключей, а на вашем подходе к корректировке данных.
Вам не нужны внешние ключи
Так нужны или нет? Если вот не нужны, то покажите как вы с интернет магазином то решили вопрос.
FK не необходимы, их можно использовать, но если вы правильно проектирует бэкенд, то FK не дадут вам каких-либо преимуществ.
В правильно спроектированном бэкенде не будет ситуации, когда FK может триггернуться и выдать ошибку. Таким образом FK не дают нам каких-либо преимуществ.
С интернет-магазином все просто — в архитектуру заложена гарантия валидности связанных таблиц
А что будет гарантировать консистенцию данных? Только поверить на слово бэкенду? И почему сразу тут юзеров использовать? Кроме них не существует случаев, когда нужны FK? А при удалении данных пользователя зачем удалять самого пользователя? Удалите всю информацию о нём из его таблицы
FK не необходимы,
связанных таблиц
А как предлагаете связывать заказы и пользователей? Правильная архитектура это понятно, а наглядно то как? Только не пишите что хранить все в одной таблице или что заказы будут в файлах. Если можно пример.
Так и вижу, что мне приходит заказ с каким-то непонятным юзер_айди, или любым другим ФК, и я сначала пытаюсь найти в базе эту энтити по ФК, чтоб понять, существует ли она, и только потом сохраняю....
Т.е. вместо 1 запроса к бд, - сколько? пять? десять? а если таких полей у заказа штук 20?
Так вам в любом случае нужно сходить в БД, чтобы проверить, что юзер авторизован и имеет право сделать заказ
Если вы никак не верифицируете айдишники в системе, то злоумышленик может просто насоздавать заказов на чужих юзеров?
Вам же так и так нужно верифицировать, что инпут в систему корректен
у заказа помимо юзера может быть еще 100500 связей.
Да, безусловно, и их тоже нужно валидировать если вы не доверяете источнику!
Например, у заказа может быть shop_id и delivery_id. Если юзер отправляет запрос вида `POST /order {"shopId": ..., "deliveryId": ..., "cartItems": []}` вам же все равно нужно сходить в БД и проверить, что такой shop существует, что он может принимать заказы, что в нем есть указанные товары.
Вставить в БДшку поля без проверки можно только в случае, если мы доверяем отправителю, например, в приватной апишке между сервисами.
По умолчанию проверками существования при вставке как раз FK и будут заниматься — если магазина нет, будет ошибка. Вы же предлагаете все такие проверки делать вручную — т. е. написать перед INSERT столько SELECT, сколько у таблицы есть связей. Это как усложняет код на бэкенде, так и требует больше времени из-за большего количества запросов. А если мы добавим связь — теперь нам везде нужно прописать ещё по одному SELECT.
Вам не кажется, что цена проверки FK при вставке на стороне БД гораздо ниже, чем проверка, фактически, тех же FK на стороне бэкендов?
Согласен, ещё дополню, что важно иметь систему ошибок, позволяющую легко определить что именно пошло не так. Вместо голого HTTP 500 возвращать 422 с текстом "Такого магазина не существует (id=<id>)", и 500 связей таблиц в таком случае превращается в парсер ошибок и связь ошибки с конкретной таблицей, например в классе таблицы вашего ORM движка, или словарь с таблицами и текстом. При этом FK позволяют в принципе ничего не делать и получить информативную ошибку, но превратить ее во что то удобоваримое, в том числе для выведения в UI достаточно просто.
А в случае ОП когда всей валидацией занимается строго бэкенд, конечно такие валидационные ошибки появляются сами собой, если человек знает что делает, но это становится очень многословно. Фактически самым лучшим вариантом в мире где отсутствуют FK будет реализовать подобие FK на бэкенде, делать честные селекты или union для поиска всех требуемых связей, писать собственный мощный валидатор, перед тем как делать insert.
ОП кажется дальше пет проектов не ходил, или дальше проприетарного ПО уровня пет проекта.
Обман. По FK вы проверите только существование, вы не проверите "такой shop может принимать заказы, что в нем есть указанные товары" и тд и тп
Странная фраза... по-моему, очевидно, что далеко не все условия могут быть поставлены на контроль в рамках условий контроля целостности - ну хотя бы по причине ограничений, которые имеет CHECK. И по FK вы даже существования не проверите - вернее, сделаете это лишь косвенно. FK просто не позволяет создания противоречащих логике контроля записей.
Очень интересно как вы в таком случае будете на вызывающей стороне обрабатывать foreign key constraint error.
А ещё может быть soft delete
Валидацию юзера можно провести без тонны запросов к бд. Jwt токены в помощь
Отвратительный пример про персональные данные как ни посмотри. Равно как и тема ненужности FK.
Про бред по теме FK в комментариях уже вам прояснили, а на тему ПД будет пояснени ниже.
Если вы персональные данные планируете периодически удалять - то эта логика должна быть изначально реализована в вашем решении или доработки должны без проблем это позволять сделать не в смысле возможности удаления, а чтобы все остальное не сломать и не городить производные костыли по смежной причине.
А если вы это реализовали и теперь прекрасно обходиться можете без ПД, то правильный вопрос - а зачем тогда вы их собираете, если и без них все хорошо?
То есть реально ПД нужны исключительно тогда и в тех решениях, когда их не требуется удалять даже при наличии запроса от физического лица. Все остальное - это избыточные запросы ПД для ваших теневых маневров или от недостатка понимания как можно сделать иначе.
Если вы после удаления ПД позднее сможете однозначно определить какое лицо соответствует остаточным сущностям в вашей БД - значит у вас в модели данных есть поля, которые позволяют связать некоторое физическое лицо с какими-то объектами в вашей БД и фактически вы не смогли обезличить данные корректным образом.
То есть реально ПД нужны исключительно тогда и в тех решениях, когда их не требуется удалять даже при наличии запроса от физического лица.
Раскройте, пожалуйста, мысль не понял...
Если мы говорим про воображаемый интернет-магазин, то ПД нужны для авторизации (телефон) и отправки чека (почта).
После удаления аккаунта юзера, очевидно, эти ПД нам больше и не нужны, потому что юзер не будет авторизовываться и ему не будут отправляться чеки об покупках.
В БД останется только его айдишник, по нему не получится связать его с реальным человеком
ПД нужны исключительно тогда и в тех решениях, когда их не требуется удалять даже при наличии запроса от физического лица
Вот тут я не понял, вы предполагаете сценарий, в котором игнорируется запрос физлица на удаление его ПД? Это как минимум незаконно, не говоря уже об этической стороне. Или вы что-то другое имели ввиду?
3 года назад была статья
Мягкое удаление чаще всего не нужно
https://habr.com/ru/articles/677932/
Зачастую вместо delete используется подход, под названием soft delete
Там тоже есть минусы
Допустим, есть таблица статей и таблица дат, когда статьи менялись. В таблице дат внешний ключ - id статей. Такая структура БД нужна, чтобы можно было создавать виды для просмотра дат изменений конкретной(ых) статьи(ей). Как разработать БД иначе, чтобы не было FK, при условии, что надо хранить все даты изменений каждой статьи?
В статье акцент: как отсутствие FK уменьшает вероятность ошибок. Но у FK есть другие задачи.
Сама БДшка будет буквально такой же, что и при FK, просто без FK.
Разница будет только на стороне бекенда и только на операции удаления. Если вы не хотите использовать soft-delete, то на удаление статьи нужно будет сделать `delete from post_change where post_id = ?` (post_change - таблица дат). А после `delete from post where id = ?`.
В остальном архитектура будет такой же, как и с FK
Акцент у статьи я пытался чуть другим сделать — FK не уменьшает ошибки, FK не дает каких-либо гарантий, которые уже не были бы даны нормальным бэкендом.
"В таблице дат внешний ключ - id статей. Такая структура БД нужна, чтобы..." - FK никак не влияет на функциональность.
"создавать виды для просмотра дат изменений конкретной(ых) статьи(ей)" - как обычно SQL-запросом, FK тут не причем
"те гарантии, что дает FK, разработчик сам должен поддержать на стороне бэкенда. " - ахаха! При наличии ключа ошибочная операция обломится, а если всё доверить коду, данные поедут, и никто этого не заметит!
Мне одному кажется, что автор этого опуса решил поиздеваться над здравым смыслом? Ну, тогда продолжу:
1. на хрен Java, C, C++, Python и так далее - машина Тьюринга и достаточно
2. или для слабаков - brainfuck
И еще: давайте откажемся от использования в электрических сетях и проводках предохранителей. Будет же без них работать? Еще как! Правда, последствия от этого так себе, но принцип - главное.
FK появились не просто так. Они дают определенные гарантии. Важные гарантии. Рискну предложить почитать

но, боюсь, не в коня корм
Господи, ну зачем писАть о том, в чём не разборался? Внешние ключи - это разновидность ограничения (CONSTRAINT), создаваемого в структуре базы данных. А не то, как вы пытаетесь их определять.
В реальности же FK это гарантия валидности родительского ключа.
Бред. Всё с точностью до наоборот - внешний ключ обеспечивает валидность значения дочерней записи.
Внешние ключи в принципе никак не влияют на ... связи между таблицами
Вот именно. А потому определению "Это ключевой элемент реляционных баз данных для установления связи между таблицами ..." место в мусорном ведре.
Иными словами — FK не дает дополнительных гарантий.
Угу. До тех пор, пока взаимодействие с данными ведётся только и исключительно через ограниченный набор валидированного программного обеспечения, и при этом гарантия возникновения нештатной ситуации (например, сбоя) равна нулю. Как и любая идеальная абстракция - не существует.
Начнем с того, что у любой сущности ID должен быть иммутабельным.
Давайте лучше начнём с того, что внешний ключ в принципе не обязан ссылаться именно на первичный ключ. А с учётом этой простой вещи весь пункт можно выбросить за ненадобностью.
И тэдэ, и тэпэ.
А чего только FK?
Я бы еще тогда пристально и неодобрительно посмотрел и на использование PK.
Совершенно понятно, что при правильной работе с БД там все записи будут и так уникальными!
ТС конечно ультанул и зря вкинул про "никогда не нужны", но немалая доля смысла в этом есть:
1) Добавляют ли FK накладных расходов? Добавляют. Следствие, убирая FK- экономия на ресурсах и времени транзакций.
2) Добавляют ли FK дедлоки? Да, такие сценарии присутствуют.
3) FK говорит "до свидания" при партициях. Получается если система большая, нужно учиться работать без FK.
4) Есть ли внешние ключи в распределенных системах ? Нет так как БД разные, и в целом нормально живут. Тогда почему в нераспределенных FK должны быть на всех связях, при этом вдруг становится неважным объем проекта и комманд. Почему команда оплат должна зашиваться связями с командой заказов. orderId или paymentId вполне могут быть не FK на стороне другого модуля и даже иметь неконсистентный Id, вопрос лишь как это обрабатывать при тех или иных сценариях.
5) Нужно ли абсолютно всегда поддерживать консистентность БД? Нет. Например вполне можно удалять статью, а какой то комментарий оставить мусорным, банально сбой в удалении мусора. При этом мусорный комментарий нам проблем не даст, а на FK мы сэкономим при вставках.
В общем как всегда - нет белого и черного, везде свои нюансы и подходы.
А можете развернуть мысль про проблемы с FK при партиционировании? Если дело в необходимости уникального индекса, то кажется в ряде СУБД (например Oracle, Postgresql Pro) присуствует возможность строить индексы уникальные внутри таблицы даже в случае если таблица партиционированная
Ну например у mysql нельзя ставить FK при партиционировании
https://dev.mysql.com/doc/refman/8.4/en/partitioning-limitations.html
Но вот у PG вроде да, можно сделать FK на партицированную таблицу, только надо будет уже сделать ссылки по 2 полям (чтобы ключ партицирования был в ключе )
Проблема в том что если таблица партицированная и на неë смотрит внешний ключ то не получится отсадить партицию в архив, нужно отключать внешний ключ. И там дальше каскад проблем. Не получится включить внешний ключ, т.к. родительских данных уже нет. И т.д.
Все кто ратует ЗА fk никогда не проектировали большие нагруженные системы, мое мнение.
Кажется что при архивировании данных в архив должен отправляться консистентный срез из всех зависимых таблиц (кроме справочников, но для них идея удаления обычно крайне спорная), а не просто кусок какой-то таблицы (иначе непонятно что с таким архивом делать). В чем проблема перенести сразу все зависимые данные в архив? В том что при пректировании забыли (или не знали) про настройки отложенной до коммита проверки консистентности? Кажется это не проблема FK.
Как выше уже заметили, бэкенд вовсе не обязательно может быть один. А значит что? А значит всё, приплыли.
Из этого же следует очевидное - ключи, структура БД, ограничения, и прочее - ЭТО И ЕСТЬ БЭКЕНД. И в нем всё что вы в своем личном велосипеде (зачеркнуто) бэкенде придумали уже есть.
И я даже знаю откуда это всё идёт... Из всех этих майскьюэль и прочих кастрированных БД, где ради скорости записи урезано было всё (времена были тяжелые). Потом конечно опомнились, но поздно, теперь всю консистентность данных на этих проектах приходится реализовывать самим, или мигрировать на БД с "встроенным" бэкендом.
Вводные автоматы у вас дома стоят? А зачем? Правильно спроектированная электрика не даст перегрузок или замыканий.
Тормоза в машине почему ещё не отключили? Правильно рассчитать скорость - и вы остановитесь у пункта назначения.
Возможно это будет новостью, но БД - это и есть бекэнд. За этим слоем уже ничего нет и, если возможно, как раз тут и нужно обеспечить валидность данных.
Но статья интересная :)
Прежде чем спорить о инструментах. Может вернемся к истокам проектирования любой системы: требованиям? И начинаются они не с выбора технологий, а с ответа на вопрос — что важнее: код или данные?
Если ваша система управляет критически важными данными, которые должны сохранять целостность и пережить множество циклов разработки, миграций и переписываний кода (например, финансовые транзакции, медкарты, документы), то ваш выбор — реляционная СУБД.
Реляционная СУБД — это инструмент, ядром философии которого являются ACID и гарантии целостности. Платя за такую систему, вы по умолчанию покупаете встроенные механизмы, обеспечивающие "C" (Consistency) и "D" (Durability). Сознательно отказываясь от FK, вы не "оптимизируете" систему — вы вручную выламываете из нее один из ключевых предохранителей, превращая бронированный сейф в картонную коробку.
С другой стороны, если ваша главная цель — скорость прототипирования и гибкость, а целостность данных на decades не является приоритетом, тогда вам действительно могут быть не нужны FK. Но тогда задайте себе честный вопрос: а ту ли СУБД вы вообще выбрали?
Использовать тяжелую реляционную систему с ее overhead, но при этом отключать ее основные защитные механизмы — это как купить промышленный фрезерный станок, чтобы забивать им гвозди.
Ваш идеальный бэкенд без FK — это не инженерное решение, а симптом. Симптом того, что вы, возможно, пытаетесь применить инструмент не по назначению. Может, вам нужна не PostgreSQL, а документная база или key-value хранилище? Начните с требований к данным — и выбор инструмента станет очевиден.
Эмм, нет. Вы делите на черное и белое. Или реляционная СУБД или нет, выбирай. А мне могут нравиться транзакции, но не нравится FK. Естественно я выберу реляционную СУБД, но использовать FK не буду.
Естественно я выберу реляционную СУБД, но использовать FK не буду.
То есть вы будете использовать РСУБД как транзакционную нереляционную СУБД. Ну да, она и так умеет.
dmitryez, вы абсолютно правы, выбор есть всегда.
Но некоторые выборы — это не выбор "между разными инструментами", а выбор "между использованием инструмента по назначению и созданием титанических костылей, имитирующих его работу".
потому что лучше джун удалит 1 запись из user, а не 1 запись из
userи все связанные изorder:)
А нечего при создании FK явно самому себе стрелять в ногу в виде доп опции:
... on delete cascadeи будут FK уберегать от таких кейсов сторожа консистентнось
А какая собственно разница, удалятся orders или нет? всё одно они останутся ни к чему не прислонённые. Более того, без специальной процедуры поиска таких "висячих строк" их и не обнаружишь... разве что детальные итоги перестанут биться и агрегированными - впрочем, это только обнаружит факт, но не сами записи.
Да и вернуть их будет тупо некуда.
Восстановить только записи users существенно проще
Да ладно... с какой такой радости проще-то?
Откуда вы возьмёте данные для восстановления записей? из последнего архива? так какая разница, восстанавливать записи одной таблицы или двух? Подготовительные работы займут настолько больше времени, что само восстановление в нём просто потеряется... Или будете откатываться по логу транзакций? ну так удаление по-любому есть один запрос и одна транзакция, так что восстановятся все удалённые записи из всех таблиц.
Забавно наблюдать, как статья начинается с классического «внешние ключи бесполезны», а заканчивается «ну, вообще FK можно использовать как дополнительную защиту». Чем громче заголовок, тем тише концовка.
Вы, конечно, вправе считать внешние ключи пережитком академического прошлого — особенно если вся практика ограничивается CRUD-приложениями, где один бэкенд и один разработчик «всё контролирует». Но, знаете, жизнь суровее лабораторных.
Жаль, не указали, где вы работаете. Не из любопытства, а чтобы я заранее знал, какими продуктами лучше не пользоваться: слишком страшно доверять системе, где консистентность данных держится исключительно на вере в идеальность бэкенда.
Да, если следовать сухой теории построения отношений в БД, то FK очень полезная штука.
Но лодка "красивой теории" разбивается о "быт" реализации конкретной СУБД и особенностей работы, с блокировками в частности, а также прямоты рук архитектора БД и разработчиков, особенно при реализации систем с высокой конкуренцией.
Использование FK (например в MS SQL) ведет к дэдлокам, и проблемам с производительностью БД, которые очень трудно диагностировать, постоянному сканированию индексов, даже при том что данные не менялись, накладным расходам на индексы и другим занятным штукам.
Примеры можете найти здесь:
https://sqlperformance.com/2014/06/sql-performance/the-snapshot-isolation-level
https://sqlserverfast.com/blog/hugo/2006/07/snapshot-isolation-a-threat-for-integrity-part-1/
https://sqlserverfast.com/blog/hugo/2006/07/snapshot-isolation-a-threat-for-integrity-part-2/
Незнаю насчет MS SQL, но рискну предположить (коль скоро это всетаки production-ready система), дедлоки появляются не от FK, а от того как эти FK конкретный разработчик спроектировал, иначе у вас классическое "ложки делают людей толстыми".
К сожалению, именно FK и связанные с ними механизмы в определенных ситуациях и ведут к дедлокам. Мы имеем ограниченные возможности влиять на поведение движка и оптимизатора, но и эти возможности (хинты) часто ведут к обратным результатам.
Проектируя систему, разработчик должен быть осведомлен об особенностях использования определенных подходов и решений в конкретном инструменте, как бы красиво и логично они не звучали в теории.
Очень правильная статья. По реакции на неë хорошо видно кто занимается проектированием и эксплуатацией больших высоконагруженных систем, а кто первый раз слышит про партиции и дедлоки.
Аналогичной темы про триггеры не хватает.
Видимо ваше предположение строиться на том, что вы предполагаете что высоконагруженные системы строяться только на MS SQL (т.к. дедлоки в контексте работы с партициями обсуждались только для этой СУБД). Кажется не самое обоснованное предположение. Или у вас есть данные по другим СУБД? (Postgresql? Oracle?)
Статья из области
"Тестирование не нужно. Ведь можно писать код без багов"
Т.е. вместо использования стандартных решений связей между таблицами в самой субд выносить эти связи в программный код backend ? Подобные решения уже видел. Там "страх и ужас" в данных.
Вы просто переносите с больной головы на здоровую. Вы не упрощаете, просто предлагаете перенести обязанности по гарантии целоности данных на бекэнд. Более того, а вы никогда не допускали ошибок? Может никогда не исправляли баги, которые были найдены пользователями? Тогда я не понимаю как вы можете гарантировать архитектурой бекэнда сохранность данных. Кроме этого тут выше вам уже писали, что FK, помимо этой, исполняет и ряд иных функций.
Извините за грубость автор прямо классический пример подхода схема данных не нужна Я все разрулю на бекенде
Помимо того что вы пропагандируете отказ от реляций, что по сути киллер фича реляционных баз.. вы так же предлагаете отказаться от встроенного механизма проверки консистентности, и реализовать его в application уровне. Предполагаю что с адом поддержки консиста данных и валидации в NoSQL вы не знакомы.
Автор молодец. Всех кто не принимает его теории отнес к душнилам =))
Если пишешь бэк один и всегда помнишь свои установленные правила, то как бы да - вперёд. Но если работает команда и кто-то внес ошибку, то база имеет ненулевой шанс превратиться в тыкву. Готовьте скрипты для латания дыр.
Внешние ключи, да и другие ограничения - последний бастион перед желающими загадить базу.
Всё, что вы пишете, на самом деле уже было в тёплые LAMPовые времена.
Тогда все сидели на MySQL, а MySQL не умела во внешние ключи, и приходилось всё делать на бэкенде.
Даже когда MySQL научилась во внешние ключи, многие всё ещё игнорировали эти возможности ровно из-за описанных в статье соображений — ради скорости.
Но даже тогда люди понимали, что жертвуют консистентностью ради производительности.
Сейчас же, кмк, если скорость — главный приоритет, проще взять NoSQL-решение.
Простой пример того, когда проверки на бэкенде не работают:
if (user_exists(user_id)) { // тут пользователь ещё существует
// тут процесс останавливается и другой процесс удаляет пользователя
create_order(user_id) // здесь создаётся заказ для пользователя, которого уже не существует
}Даже если вы используете soft delete, вы, скорее всего, всё равно не хотите, что бы заказы создавались для удалённых пользователей. Но, в случае с soft delete, вам только внешнего ключа уже не хватит, конечно.
А такие посты реально проходят модерацию?
Зашел напихать в панамку, а тут уже без меня справились)
Я почти ничего не понимаю в базах данных, но с такого тейка даже я выпал а осадок.
Можете кстати использовать пример ERP системы Dynamics AX или сейчас это Microsoft Dynamics 365 For Finance and Operations. Она основана на SQL Server и ключей FK в базе нет. Подозреваю что для первой версии системы это было довольно смелое архитектурное решение, но по факту оказалось что оно так и надо в типовом проекте. Но при этом есть логические валидации и внутреннаяя проверка целостности, которая может детектировать отсутсвующие ключи
Согласен со всем вышесказанным, при условии что разработчики пишут без ошибок, вендор всегда доступен для обратной связи, что никогда и не при каких обстоятельствах сопровождению не приходится решать какие-то вопросы минуя интерфейс, но реальность далека от этого. Так что господа разработки пишите внешние ключи где только можно, сопровождению логика работы приложения недоступна, а СУБД ещё кое как, а ситуации бывают разные.
Жёстко, конечно. Видно, что не так много опыта. Кроме очевидных вещей, которые умные люди подсветили выше. Есть ещё и не очень очевидная - это изучение системы новым человеком. Если у вас будет больше 30 сущностей без внешних ключей, а ещё если наименования ключевых полей в родительских и дочерних таблицах отличаются, то большой вам удачи в изучении. Можно, конечно, модель в коде посмотреть, но это уже будет строк 600-700. А по внешним ключам многие редакторы БД могут строить схемы, которые уже можно изучать и понимать. До 50 сущностей можно кататься на велосипеде как угодно. В моей практике было 1800 сущностей в большой системе. Пофантазируйте, как это выжило бы в вашей парадигме. Самую горькую усмешку вызвала фраза "в нормально спроектированном бэкенде"...
У вас с автором разный опыт. У вас 1800 сущностей с FK на 1 RPS. У автора шардированные кластера с микросервисами где нормальные FK просто не поддерживаются и не имеют смысла.
Как я понимаю FK поддерживаются, иначе эта статья не имела бы смысла (если нельзя использовать, то и обсуждать нечего). Я не отрицаю, что бывают случаи, когда от FK отказываются. Но это как отказываться от автоматической коробки передач в машине. Отказаться можно, но придется самому переключать передачи, жать сцепление. И микросервисы и шардирование сами по себе не отменяют FK. Всё зависит от стратегии хранения данных, требований к обеспечению целостности данных, или от типа системы по CAP теореме. Могут быть и nosql решения. Но тут же статья про реляционные БД, и FK это один из инструментов, достаточно сильный и удобный для своих целей.
TL:DR
Очевидно, при грамотной езде, ремни безопасности только замедляют процесс посадки и высадки водителя. В нормально обустроенном дорожном движении сложно представить себе ситуацию, когда они могут для чего-то пригодиться. А даже если такая ситуация и произойдёт, лучше гордым орлом покинуть транспортное средство через лобовое стекло, чем сгореть на привязи в искорёженном куске металла.
В идеальном мире где живут радужные пони fk действительно не нужны, как и в целом любые ключи и валидация данных. Не очень понятно правда почему вы поддержку этих ключей положили на бэкенд, у нас же есть ещё и фронт, и внешние системы, их же разработчики сами все провалидировали и прислали вам, думаю и на бэкенде такие проверки тоже лишние. А ещё у вас всегда есть конечный пользователь, он же очевидно проверит данные перед их вводом, так, что думаю подобные проверки в коде лишние совсем.
Fk в базе данных, это логика самого низкого уровня, она страхует нас от ошибок в логике более высокого уровня, которые на это уровне могут оставаться не обнаруженными очень длительное время, а так же связывает общими ограничениями разные части более высокоуровневой логики.
Простой пример. Разработчик Вася работал над заказами и сделал дополнительную точку их "генерции". В этой точке нет пользователя, они генерируется автоматом и разработчик Вася как хороший разработчик решил, что раз нет пользователя, значит нет, пишем null. А разработчик Петя, пять лет назад писали биллинг и в этом самом билинге использовал inner join к таблице пользователей, потому как там email куда биллинг нужно отправить. И это email давно в рамках системы не обязателен, есть эдо, но inner join остался и все тесты прошел. И вот теперь у вас есть заказы по которым нет биллинга. Удачи вам найти эту ошибку не через полгода, когда вам клиент сообщит, что платит как-то мало.
Да, куча систем обходится без fk, те же микросервисы и это их боль, на компенсацию которой приходится положить не мало усилий. Усили которые в монолитной системе не стоят фактически ничего.
Такое чувство, что я попал на олимпиаду "кто быстрее и дальше запустит в автора какаху". Немного грустно за русское комьюнити...
По сути, автор задал весьма полезный и безобидный вопрос "а что если?". Именно с такого вопроса и начинаются большие открытия.
Понятно, если мягко подытожить весь флейм, то ребята не рекомендуют отключать валидацию ценных связей. Есть несофтовые операции и форсмажоры, а также операции обслуживания БД, которым это крайне нужно.
Однако, вполне можно допустить целесообразность мягких связей в БД. Например, ключевые поля внутри JSONB структуры. Хотите, например некие properties или мета атрибуты таблицы, которые вы не хотите явно вносить в схему из-за динамической природы? Делайте JSONB поле и управляйте софтовым способом в своё удовольствие. Ни один ранимый эксперт не пострадает :)
Видите ли... автор как раз никакого "а что если" не задавал. Он сходу заявил, что только он - д'Артаньян, а потом (зачем-то) начал это маловменяемо обосновывать. И большинство того, которое "быстрее и дальше", прилетело в основном потому, что обоснование ну совсем не получилось.
Делайте JSONB поле и управляйте софтовым способом в своё удовольствие.
JSON-поля вполне себе индексируются. И даже, при соблюдении некоторых требований к формату данных (CHECK в помощь), вполне себе могут использоваться во внешних ключах.
Априори очень скандальный заголовок)
Однако идея не нова, например в ClickHouse нет внешних ключей, но поле с айдишником завести можешь.
Автор отчасти прав. Никаких изменений, нарушающих целостность, быть не должно. Вот в этих книгах изложено подробнее:
Искусство неизменяемой архитектуры.
Чисто функциональные структуры данных.
Дата-ориентированное программирование.
и др.
Хотя среднестатистического программиста вряд ли кто-то сможет выгнать из реляционного рая.
Никаких изменений, нарушающих целостность, быть не должно.
Угу. Ошибок в программах быть не должно. Обрывов сети и зависаний ОС/служб/программ быть не должно. Администраторов, работающих с данными напрямую, и хакеров, делающих с данными вообще что угодно, быть не должно. Чего там ещё быть не должно, а? Идеалист, аднака.
Тут возникло недопонимание. Ошибки, конечно, никто не отменял. Ошибки можно и в РСУБД наколбсить, даже с использованием внешних ключей.
Тут вопрос о том, какой инструмент из портфолио архитектора необходимо достать, чтобы решить ту или иную задачу. Если отталкиваться от видов данных, которые существуют в любой организации, а их выделяют пять:
Метаданные.
Мастерданные.
Операционно-учётные данные
Аналитические данные.
Слабоструктурированные или неструктурированные данные или контент.
то очевидно, что для управления каждым видом используется свой инструмент. РСУБД, в то время как они в первую очередь предназначены для управления операционно-учётными данными где катастрофически важен ACID, очень часто пытаются натянуть на работу с аналитическими данными. При небольших объёмах данных и необходимости построения real-time отчётности, это допускается. Т.н. ROLAP. И допускаются техники денормализации для повышения производительности.
Но современные реалии диктуют другие подходы: Data Lakehouse, Data Mesh и прочее. Я бы оставил внешние ключи в РСУБД. А для отчётов, которые требуют производительности, использовал специализированные решения. В конце концов CQRS никто не отменял )
Хочу вбить гвоздь в крышку всех уверовшавших в РСУБД. )
Какой уровень изолированности транзакций используется в прикладных решениях,, работающих с РСУБД, с которыми вам приходилось сталкиваться (я сейчас обращаюсь к гипотетическому оппоненту, никаких переходов на личности)? Тот уровень, который установлен по умолчанию в конкретной РСУБД? Не рассказывайте, пожалуйста, что при уровне Serializable ваше прикладное решение хоть как то ворочается в плане производительности и не встаёт колом. И зачем после этого рассказывать про консистентность и необходимость внешних ключей?
Далее... Какой RPO/RTO заложен в систему? Вы правда используете синхронную репликацию и тем самым гасите производительность и доступность системы в два раза? В любом другом случае у вас данные могут просто пропасть.
РСУБД очень плохо масштабируются горизонтально. Вообще никак. Это при том, что сами РСУБД никаких 100% ACID вам и не гарантируют: данные могут быть протухшими и даже неконсистентными.
Вот я пытаюсь сделать выборку, когда кто-то другой совершает транзакцию с данными, которые в мою выборку, логически, должны попасть. Но его транзакция завершается чуть позже моей. Я в этом случае получу неактуальные, но консистентные (возможно) данные. Никто Read uncommitted не выставляет как правило. Вопрос, возможно, каких-то миллисекунд. А кто выставил этот интервал в миллисекунды? Он актуален для бизнеса? Может если это будут секунды - это тоже всех устроит? Может мне надо изменения класть в высокопроизводительный брокер сообщений, а не в РСУБД, а там уже разберут кому куда надо. В конце концов по очередям брокера тоже можно запросы шарашить. Eventual Consistency. А чем она от не Eventual отличается? Да ничем. Временным интервалом.
Коллеги! Тема спорная, чисто для обсуждения. Как и сама статья выше. Буду благодарен за обратку )
Вот я пытаюсь сделать выборку, когда кто-то другой совершает транзакцию с данными, которые в мою выборку, логически, должны попасть.
То есть запрос 1) интерактивный 2) критичный по точке актуальности, по исходным данным.
Но его транзакция завершается чуть позже моей.
Могли бы в явной форме подождать завершения этой конкретной, заведомо известной и идентифицированной, влияющей транзакции. Но вы как-то игнорируете возможность и необходимость попадания в требуемую точку актуальности. Ну и кто виноват?
Я в этом случае получу неактуальные, но консистентные (возможно) данные.
На момент получения отображения результата, тем более на момент, когда они увидены и осознаны, они уже неактуальны - или с определённой долей вероятности, или гарантированно. В описанных условиях актуальных данных вообще - не существует.
Могли бы в явной форме подождать завершения этой конкретной, заведомо известной и идентифицированной, влияющей транзакции. Но вы как-то игнорируете возможность и необходимость попадания в требуемую точку актуальности. Ну и кто виноват?
Дак вот же! Вы говорите про Event Sourcing! Про те самые неизменяемые данные! Я могу попасть в любую точку реальности. Даже в точку "параллельной" реальности. Которая возникла, но по каким то причинам откатилась. Это как в Git. Гуляй себе по веткам репозиторя. Но только РСУБД для этого не предназначены.
В этом мире нет внешних ключей
Но его транзакция завершается чуть позже моей. Я в этом случае получу неактуальные, но консистентные (возможно) данные. Вопрос, возможно, каких-то миллисекунд.
Оно так и должно работать. Вы получите данные, консистентные на момент вашей транзакции. Нет никакой разницы, через несколько миллисекунд они поменялись или через несколько минут.
Может мне надо изменения класть в высокопроизводительный брокер сообщений, а не в РСУБД, а там уже разберут кому куда надо.
"РСУБД" это обычно и есть "куда надо".
Если не нужны внешние ключи, скорее всего не нужна реляционная СУБД. Есть же MongoDB, Cassandra и др. Они там нюансами отличаются, надо просто подобрать ту, которая лучше подойдёт под решение. Cassandra на вставку очень быстрая. Монга умеет какие-то джоины по минималкам. Но вы не любите внешние ключи поэтому вряд-ли Монга...
Возможно проблема не в СУБД. У вас есть ORM слой в прикладухе? Hibernate? SQLAlchemy? Если есть - очень сочувствую. Любой ORM превращает православный SQL в ООП месиво, которым невозможно управлять. Взять, и поверх очень красивого, одного из самых лучших декларативных языков программирования на планете, поставить ООП фасад...
А как же визуальное представление БД в GUI редакторах? Как без ключей они возможны?
Автор когда нибудь разрабатывал что-то, где в БД больше чем один десяток таблиц?
Есть системы, где в одной БД почти сотня связных таблиц, об архитектурной истине таких решений можно спорить, но всё же. Визуальные связи в реальном времени невероятно полезны.
Давайте попробуем в таком GUI редакторе открыть схему БД любой прикладной системы на базе платформы 1С:Предприятие. Там будет даже не десяток таблиц. Но что мы там увидим? А решения на базе 1С я бы просто так из рассмотрения не исключал. Это одна из лидирующих платформ на рынке.
Чем не устраивают решения класса Data Catalog? Та же OpenMetadata, например
Не, ну нормально так набросил.

Вам не нужны внешние ключи