Каковы компромиссы для увеличения идентификаторов и полнотекстовых ключей для конструкций внешнего ключа?

8

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

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

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

Table users
===========
userId int primary auto_increment
userName varchar unique

Table adressdata
==========
userId int references users.userId
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userId,adress_type))

Вот как я это делал и как я видел это в большинстве случаев.

Другой способ будет:

Table users
===========
userName varchar primary

Table adressdata
==========
userName varchar references users.userName
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userName,adress_type))

Здесь мы храним полное имя пользователя также в таблице адресных данных.

Для меня это имеет следующие преимущества:

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

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

Но также и недостатки:

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

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

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

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

  • Есть ли лучшие практики?

  • Есть ли плюсы / минусы, о которых я не думал, и эффект от которых может возникнуть в более поздний момент времени?

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

Джо Хопфгартнер
источник

Ответы:

3

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

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

Если вы хотите получить более глубокое понимание Великая дискуссия по первичным ключам - это отличная статья.

stivlo
источник
2

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

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

Я бы использовал естественные ключи только при двух условиях:

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

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

HLGEM
источник
1

В статье Википедии о суррогатном ключе есть несколько интересных фрагментов:

  • « Атрибуты, однозначно идентифицирующие сущность, могут измениться, что может сделать недействительной пригодность естественных составных ключей». Например, последующие ограничения на имена пользователей могут сделать недействительными существующие ключи при использовании естественного ключа, user nameтогда как это не повлияет на синтетический ключ.
  • « Суррогатные ключи не меняются, пока существует строка. » Таким образом, вам не нужно (вручную или автоматически) каскадно менять ключи в ссылочных таблицах.
  • « Значения сгенерированных суррогатных ключей не имеют отношения к реальному значению данных, хранящихся в строке». Это может затруднить аудит.

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


источник
Хороший ответ. Многие природные ключи имеют тенденцию к изменениям. Это делает их непригодными для ключей, на которые можно ссылаться как на внешний ключ. Есть много причин, по которым уместно изменить идентификатор пользователя.
BillThor
1

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

Я бы никогда не использовал естественный ключ для первичного ключа. Особенно если я использую MySQL / InnoDB. Я до сих пор не видел никакой пользы от использования естественного ключа, обычно я вижу влияние на производительность, если ничего. Я выделил «никогда, никогда» только потому, что естественные ключи использовали для повышения производительности моих проектов. Суррогат (целое число) всегда был лучшим выбором. Некоторые могут не согласиться, но мы живем в мире, где производительность играет определенную роль в теории.

Когда дело доходит до СОЕДИНЕНИЙ, я не пытаюсь избежать их любой ценой, но я стремлюсь оптимизировать их. Я стараюсь максимально злоупотреблять кластерным индексом InnoDB (первичным ключом). Если JOINs выполняются через PK, то они очень быстрые. Я также склонен избегать ФК, где они не имеют смысла. Честно говоря, меня не очень заботит целостность данных, когда речь идет о связывании пользователей и их адресной информации. Я бы применил это при связывании счетов с элементами для пользователей. Чрезмерное использование FKs - это излишнее убийство и кошмар, который нужно поддерживать после того, как вы на него ссылаетесь, думая, что это отличный дизайн - поддерживать отношения повсюду. В какой-то момент все должно измениться, и когда MySQL начинает постоянно жаловаться с ошибкой 150, вы просто хотите вернуться домой.

Вы также упомянули репликацию и избежание конфликтов из-за характера auto_increments. У меня был проект, где у нас было количество баз данных, хранящих информацию о продажах продуктов, количество баз данных было переменным. Каждый день базы данных копировались в одну «основную» базу данных, которую мы использовали для запуска отчетов. Я избежал коллизий PK, создав составной первичный ключ из части auto_increment и другой части INT, которая обозначала место, откуда пришла запись. Таким образом, я мог отследить, откуда взялись вещи, и ничего не потерял (продукты имели одинаковый идентификатор, изменился только идентификатор местоположения).

NB
источник