В моих базах данных у меня есть привычка иметь автоинкрементный первичный ключ целого числа с именем id
для каждой таблицы, которую я создаю, чтобы у меня был уникальный поиск для любой конкретной строки.
Это считается плохой идеей? Есть ли недостатки сделать это таким образом? Иногда у меня будет несколько индексов, например, id, profile_id, subscriptions
где id
находится уникальный идентификатор, profile_id
ссылки на id
сторонние Profile
таблицы и т. Д.
Или есть сценарии, когда вы не хотите добавлять такое поле?
t
, а ресурс 120 - одновременноt + 60
. Если вы видите оба этих идентификатора (100 и 120) в необсуждаемом виде, теперь вы знаете общее количество существующих активов, а также приблизительную скорость их создания. Это утечка информации. Это не чисто гипотетически.Ответы:
Это никогда не плохая идея иметь гарантированный уникальный идентификатор строки. Думаю, я не должен говорить никогда - но давайте согласимся с подавляющим большинством времени, это хорошая идея.
Теоретические потенциальные недостатки включают дополнительный индекс для обслуживания и дополнительное место для хранения. Это никогда не было достаточной причиной для меня, чтобы не использовать один.
источник
TableName.id
в отличие отTableName.TableName_id
, потому что что еще этоid
будет означать? Если у меня есть другое поле идентификатора в таблице, я добавлю к нему имя таблицы, если оно ссылается на какую-то другую таблицуWITHOUT ROWID
таблицы (с явнымиPRIMARY KEY
) в качестве оптимизации. Но в противном случаеINTEGER PRIMARY KEY
столбец является псевдонимом для rowid.Я не согласен со всеми ответами раньше. Существует множество причин, по которым плохая идея добавлять поле автоинкремента во все таблицы.
Если у вас есть таблица, в которой нет явных ключей, поле автоинкремента кажется хорошей идеей. В конце концов, вы не хотите
select * from blog where body = '[10000 character string]'
. Вы бы предпочлиselect * from blog where id = 42
. Я бы сказал, что в большинстве этих случаев вам действительно нужен уникальный идентификатор; не последовательный уникальный идентификатор. Вы, вероятно, хотите использовать универсально уникальный идентификатор вместо этого.В большинстве баз данных есть функции для генерации случайных уникальных идентификаторов (
uuid
в mysql, postgres.newid
В mssql). Они позволяют генерировать данные в несколько баз данных, на разных машинах, в любое время, без сетевого соединения между ними, и при этом объединять данные с нулевым конфликтом. Это позволяет упростить настройку нескольких серверов и даже центров обработки данных, например, с помощью микросервисов.Это также позволяет избежать угадывания злоумышленниками URL-адресов страниц, к которым у них не должно быть доступа. Если есть,
https://example.com/user/1263
то, вероятно,https://example.com/user/1262
также. Это может позволить автоматизировать эксплойт безопасности на странице профиля пользователя.Есть также много случаев, когда столбец uuid бесполезен или даже вреден. Допустим, у вас есть социальная сеть. Есть
users
стол иfriends
стол. Таблица друзей содержит два столбца идентификаторов пользователей и поле автоинкремента. Вы хотите3
дружить5
, поэтому вы вставляете3,5
в базу данных. База данных добавляет идентификатор автоинкремента и сохраняет1,3,5
. Почему-то пользователь3
снова нажимает кнопку «Добавить друга». Вы3,5
снова вставляете в базу данных, база данных добавляет идентификатор автоинкремента и вставляет2,3,5
. Но сейчас3
и5
дружим вдвойне! Это пустая трата места, и если подумать, то же самое относится и к столбцу автоинкремента. Все, что вам нужно, чтобы увидеть, еслиa
иb
друзья, чтобы выбрать для строки с этими двумя значениями. Вместе они являются уникальным идентификатором строки. (Вы, вероятно , хотите сделать написать некоторую логику , чтобы убедиться , что3,5
и5,3
являются дедуплицированными.)Есть все еще случаи, когда последовательные идентификаторы могут быть полезны, например, при создании сокращающего URL-адреса, но в основном (и даже с сокращающим URL-адресом) случайно генерируемый уникальный идентификатор - это то, что вы действительно хотите использовать вместо этого.
TL; DR: используйте UUID вместо автоинкремента, если у вас еще нет уникального способа идентификации каждой строки.
источник
Автоинструментальные ключи имеют в основном преимущества.
Но некоторые возможные недостатки могут быть:
Вот раздел статьи Википедии о недостатках суррогатных ключей.
источник
Просто чтобы быть противоположным, нет, вам не нужно всегда иметь числовой ПК AutoInc.
Если вы тщательно анализируете свои данные, вы часто идентифицируете естественные ключи в данных. Это часто тот случай, когда данные имеют внутреннее значение для бизнеса. Иногда PK - это артефакты древних систем, которые бизнес-пользователи используют в качестве второго языка для описания атрибутов своей системы. Например, я видел VIN-номера транспортных средств, используемые в качестве основного ключа таблицы «Автомобиль» в системе управления автопарком.
Как бы то ни было, если у вас уже есть уникальный идентификатор, используйте его. Не создавайте второй, бессмысленный первичный ключ; это расточительно и может привести к ошибкам.
Иногда вы можете использовать AutoInc PK для создания значимого для клиента значения, например, номера политик. Установка начального значения на что-то разумное и применение бизнес-правил о ведущих нулях и т. Д. Это, вероятно, подход «лучшее из обоих миров».
Если у вас есть небольшое количество значений, которые являются относительно статическими, используйте значения, которые имеют смысл для пользователя системы. Зачем использовать 1,2,3, если вы можете использовать L, C, H, где L, H и C представляют Life, Car и Home в контексте страхового «Типа полиса», или, возвращаясь к примеру VIN, как насчет использования «TO» для Тойоты? Все автомобили Toyata имеют VIN-код, начинающийся с буквы «TO». Пользователи должны помнить об этом меньше, снижают вероятность появления ошибок программирования и ошибок пользователя и даже могут быть полезным заменителем полного описания в управленческих отчетах, делая отчеты проще. писать и, возможно, быстрее генерировать.
Дальнейшее развитие этого вопроса, вероятно, является «слишком большим мостом», и я, как правило, не рекомендую его, но я включаю его для полноты, и вы можете найти для него хорошее применение. То есть используйте описание в качестве первичного ключа. Для быстро меняющихся данных это мерзость. Для очень статичных данных, которые сообщаются в All The Time , возможно, нет. Просто упомянув об этом, чтобы он сидел там как возможность.
Я действительно использую AutoInc PKs, я просто задействую свой мозг и сначала ищу лучшие альтернативы. Искусство проектирования баз данных делает что-то значимое, что можно быстро запросить. Слишком много соединений мешает этому.
РЕДАКТИРОВАТЬ Еще один важный случай, когда вам не нужен автоматически сгенерированный PK, - это случай таблиц, которые представляют пересечение двух других таблиц. Чтобы придерживаться аналогии с автомобилем, у автомобиля есть 0 ..n аксессуаров, каждый аксессуар можно найти на многих автомобилях. Таким образом, чтобы представить это, Вы создаете таблицу Car_Accessory, содержащую PK от Car и Accessory и другую соответствующую информацию о Дате ссылки и т. Д.
То, что вам (обычно) не нужно, - это AutoInc PK на этом столе - доступ к нему можно получить только через автомобиль «скажи мне, какие аксессуары есть на этом автомобиле» или из аксессуара «скажи им, какие автомобили имеют этот аксессуар»
источник
Don't create a second, meaningless primary key; it's wasteful and may cause errors.
Однако, если способ, которым вы устанавливаете уникальность для записи, представляет собой комбинацию из 6 столбцов, то объединение всех 6 всегда очень подвержено ошибкам. Естественно, у данных есть PK, но вам лучше использоватьid
столбец и уникальное ограничение для этих 6 столбцов.Многие таблицы уже имеют естественный уникальный идентификатор. Не добавляйте в эти таблицы еще один столбец уникальных идентификаторов (с автоинкрементом или иным образом). Вместо этого используйте естественный уникальный идентификатор. Если вы добавите еще один уникальный идентификатор, у вас по существу будет избыточность (дублирование или зависимость) в ваших данных. Это идет вразрез с принципами нормализации. Один уникальный идентификатор зависит от другого для точности. Это означает , что они должны быть идеально синхронизирована в любое время в любой системе , которая управляет этими строками. Это просто еще одна хрупкость в целостности ваших данных, которой вы на самом деле не хотите управлять и проверять в долгосрочной перспективе.
В настоящее время большинству таблиц действительно не требуется очень незначительное повышение производительности, которое может дать дополнительный столбец уникальных идентификаторов (а иногда это даже снижает производительность). Как правило в ИТ, избегайте избыточности, как чума! Сопротивляйтесь этому везде, где вам это предлагается. Это анафема. И прислушайся к цитате. Все должно быть максимально просто, но не проще. Не имейте двух уникальных идентификаторов, где одного будет достаточно, даже если естественный кажется менее аккуратным.
источник
В больших системах ID повышает согласованность, используйте его практически везде. В этом контексте отдельные первичные ключи НЕ рекомендуются, они стоят дорого в конце (прочитайте почему).
Каждое правило имеет исключение, поэтому вам может не понадобиться целочисленный идентификатор автоинкремента для промежуточных таблиц, используемых для экспорта / импорта, и для похожих односторонних таблиц или временных таблиц. Вы также предпочли бы идентификаторы GUID вместо идентификаторов в распределенных системах.
Многие ответы здесь предполагают, что существующий уникальный ключ должен быть взят. Ну даже если в нем 150 символов? Я так не думаю.
Теперь моя главная мысль:
Похоже, что противники целочисленного идентификатора автоинкремента говорят о небольших базах данных до 20 таблиц. Там они могут позволить себе индивидуальный подход к каждому столу.
НО, если у вас есть ERP с 400+ таблицами, иметь целочисленный идентификатор автоинкремента в любом месте (кроме случаев, упомянутых выше) просто имеет смысл. Вы не полагаетесь на другие уникальные поля, даже если они присутствуют и защищены для уникальности.
JOIN
таблицы, без необходимости проверять, какие ключи.В более крупных системах стоит игнорировать незначительные преимущества этих отдельных первичных ключей и в большинстве случаев последовательно использовать целочисленный идентификатор автоинкремента. Использование существующих уникальных полей в качестве первичных ключей, возможно, экономит несколько байтов на запись, но дополнительное хранилище или время индексации не представляют проблемы в современных механизмах баз данных. На самом деле вы теряете гораздо больше денег и ресурсов из-за потерянного времени разработчиков / разработчиков. Современное программное обеспечение должно быть оптимизировано по времени и усилиям программистов - какой подход с согласованными идентификаторами выполняет намного лучше.
источник
Это не хорошая практика для лишних конструкций. Т.е. не рекомендуется всегда иметь автоинкрементный первичный ключ, когда он не нужен.
Давайте посмотрим на пример, где он не нужен.
У вас есть таблица статей - она имеет первичный ключ int
id
и столбец varchar с именемtitle
.У вас также есть таблица, заполненная категориями статей -
id
int primary key, varcharname
.В одной строке таблицы «Статьи» есть
id
5 иtitle
«Как приготовить гуся с маслом». Вы хотите связать эту статью со следующими строками в вашей таблице категорий: «Мясо птицы» ( id : 20), «Гусь» ( id : 12), «Готовка» ( id : 2), «Масло» (id: 9) ,Теперь у вас есть 2 таблицы: статьи и категории. Как вы создаете отношения между ними?
Вы можете иметь таблицу с 3 столбцами: id (первичный ключ), article_id (внешний ключ), category_id (внешний ключ). Но теперь у вас есть что-то вроде:
Лучшее решение - иметь первичный ключ, состоящий из 2 столбцов.
Это может быть достигнуто путем:
Другая причина не использовать целочисленное значение с автоинкрементом состоит в том, что вы используете UUID для своего первичного ключа.
UUID по своему определению уникальны, что выполняет то же самое, что и использование уникальных целых чисел. У них также есть свои собственные дополнительные преимущества (и недостатки) по сравнению с целыми числами. Например, с UUID вы знаете, что уникальная строка, на которую вы ссылаетесь, указывает на конкретную запись данных; это полезно в тех случаях, когда у вас нет 1 центральной базы данных или когда приложения имеют возможность создавать записи данных в автономном режиме (а затем загружать их в базу данных позднее).
В конце концов, вам не нужно думать о первичных ключах как о вещи. Вы должны думать о них как о функции, которую они выполняют. Зачем вам нужны первичные ключи? Чтобы можно было однозначно идентифицировать определенные наборы данных из таблицы, используя поле, которое не будет изменено в будущем. Вам нужен определенный столбец, вызываемый
id
для этого, или вы можете основать эту уникальную идентификацию на других (неизменных) данных?источник
Конечно.
Прежде всего, существуют базы данных, у которых нет автоинкрементов (например, Oracle, который, конечно, не является одним из самых маленьких претендентов). Это должно быть первым признаком того, что не все любят или нуждаются в них.
Еще более важно, подумайте о том, что идентификатор фактически является - это первичный ключ для ваших данных. Если у вас есть таблица с другим первичным ключом, то вам не нужен идентификатор, и он не должен быть. Например, таблица
(EMPLOYEE_ID, TEAM_ID)
(где каждый сотрудник может быть в нескольких командах одновременно) имеет четко определенный первичный ключ, состоящий из этих двух идентификаторов. ДобавлениеID
столбца автоинкремента , который также является первичным ключом для этой таблицы, не имеет никакого смысла. Теперь вы таскаете 2 первичных ключа, и первое слово в «первичном ключе» должно дать вам подсказку, что у вас действительно должен быть только один.источник
Я обычно использую столбец «идентичность» (автоинкрементное целое число) при определении новых таблиц для «долгоживущих» данных (записи, которые я ожидаю вставить один раз и хранить бесконечно, даже если они в конечном итоге «логически удаляются» путем установки битового поля ).
Я могу подумать о нескольких ситуациях, когда вы не хотите их использовать, большинство из которых сводятся к сценариям, когда одна таблица в одном экземпляре БД не может быть официальным источником новых значений идентификаторов:
Как я уже упоминал, есть обходные пути, которые позволяют использовать столбцы идентификаторов в этих ситуациях, но в большинстве из них обновление целочисленного столбца идентификаторов до GUID проще и решает проблему более полно.
источник
ID, ID_M, ID_N
) из-за присоединения свойств к экземплярам отношения M: N.Автоинкрементный (идентификационный) первичный ключ является хорошей идеей, за исключением того, что он не имеет смысла вне контекста базы данных и непосредственных клиентов этой базы данных. Например, если вы перенесете и сохраните некоторые данные в другой базе данных, а затем продолжите записывать разные данные в обе таблицы базы данных, идентификаторы будут расходиться, т. Е. Данные с идентификатором 42 в одной базе данных не обязательно будут соответствовать данным. с идентификатором 42 в другом.
Учитывая это, если необходимо по-прежнему иметь возможность уникально идентифицировать строки вне базы данных (а это часто бывает), то для этой цели у вас должен быть другой ключ. Подойдет тщательно подобранный бизнес-ключ, но вы часто будете в положении большого количества столбцов, необходимых для обеспечения уникальности. Другой способ - использовать столбец Id в качестве кластеризованного первичного ключа с автоинкрементом и другой столбец уникального идентификатора (guid) в качестве некластеризованного уникального ключа для уникальной идентификации строки, где бы она ни находилась в мире. Причина, по которой у вас все еще есть автоинкрементный ключ в этом случае, заключается в том, что более эффективно кластеризовать и индексировать автоинкрементный ключ, чем делать то же самое для guid.
Одним из случаев, когда вам может не понадобиться автоинкрементный ключ, будет таблица «многие ко многим», где первичный ключ представляет собой соединение столбцов Id двух других таблиц (здесь у вас все еще может быть автоинкрементный ключ, но я не вижу смысла в этом).
Еще один вопрос - тип данных автоинкрементного ключа. Использование Int32 дает вам большой, но относительно ограниченный диапазон значений. Лично я часто использую столбцы bigint для идентификатора, чтобы практически никогда не беспокоиться об исчерпании значений.
источник
Поскольку другие люди приводят доводы в пользу увеличения первичного ключа, я сделаю один для GUID:
Изменить: Дублировать точку
источник
Как принцип хорошего дизайна, каждая таблица должна иметь надежный способ уникальной идентификации строки. Хотя для этого и нужен первичный ключ, он не всегда требует наличия первичного ключа. Добавление первичного ключа в каждую таблицу не является плохой практикой, поскольку обеспечивает уникальную идентификацию строки, но это может быть ненужным.
Чтобы поддерживать надежные отношения между строками двух или более таблиц, вы должны делать это через внешние ключи, следовательно, необходимы первичные ключи по крайней мере в некоторых таблицах. Добавление первичного ключа к каждой таблице облегчает расширение структуры базы данных, когда приходит время добавлять новые таблицы или связи к существующим данным. Планирование заранее - это всегда хорошо.
В качестве основного принципа (возможно, жесткого правила) значение первичного ключа никогда не должно меняться в течение всей жизни его ряда. Целесообразно предположить, что любые бизнес-данные в строке могут изменяться в течение срока службы, поэтому любые бизнес-данные будут плохим кандидатом на первичный ключ. Вот почему что-то абстрактное, например, автоинкрементное целое, часто является хорошей идеей. Однако, автоинкрементные целые числа имеют свои ограничения.
Если ваши данные будут иметь жизнь только в вашей базе данных, с автоматически возрастающими целыми числами все в порядке. Но, как уже упоминалось в других ответах, если вы когда-нибудь захотите, чтобы ваши данные передавались, синхронизировались или иным образом имели жизнь вне вашей базы данных, автоматически увеличиваемые целые числа создают плохие первичные ключи. Лучшим выбором будет guid (он же «универсально уникальный идентификатор»).
источник
В этом вопросе и во многих ответах упускается важный момент, согласно которому все естественные ключи для каждой таблицы находятся исключительно в логической схеме базы данных, а все суррогатные ключи для каждой таблицы находятся исключительно в физической схеме базы данных. другие ответы обсуждают исключительно относительные преимущества суррогатных ключей по сравнению с целочисленными по сравнению с GUID, не обсуждая причины и причины правильного использования суррогатных ключей.
Кстати: давайте не будем использовать плохо определенный и неточный термин первичный ключ . Это - артефакт моделей до-реляционных данных, которые сначала (неразумно) кооптировали в реляционную модель, а затем вернули обратно в физическую область различными поставщиками СУБД. Его использование служит только для того, чтобы запутать семантику.
Обратите внимание на реляционную модель, что для того, чтобы логическая схема базы данных находилась в первой нормальной форме , каждая таблица должна иметь видимый пользователем набор полей, известный как естественный ключ, который однозначно идентифицирует каждую строку таблицы. В большинстве случаев такой естественный ключ легко идентифицировать, но в некоторых случаях его необходимо создать, будь то поле прерывателя связи или иным образом. Однако такой созданный ключ всегда остается видимым для пользователя и, следовательно, всегда находится в логической схеме базы данных.
В отличие от этого, любой суррогатный ключ в таблице находится исключительно в физической схеме базы данных (и, следовательно, должен всегда быть абсолютно невидимым для пользователей базы данных как по соображениям безопасности, так и для поддержания целостности базы данных). Единственной причиной введения суррогатного ключа является решение проблем производительности при физическом обслуживании и использовании БД; будь то соединения, репликация, несколько аппаратных источников данных или другое.
Поскольку единственной причиной введения суррогатного ключа является производительность, давайте предположим, что мы хотим, чтобы он был эффективным. Если проблема производительности связана с объединениями, то мы обязательно хотим сделать наш суррогатный ключ настолько узким, насколько это возможно (не мешая аппаратному обеспечению, поэтому короткие целые числа и байты обычно отсутствуют). Производительность соединения зависит от минимальной высоты индекса, поэтому 4-байтовое целое число является естественным решением. Если ваша проблема производительности - скорость вставки, 4-байтовое целое число также может быть естественным решением (в зависимости от внутренних компонентов вашей RDBMS). Если ваша проблема производительности для таблицы связана с репликацией или несколькими источниками данных, чем какая-либо другая технология суррогатного ключа , может быть более подходящим может быть GUID или ключ из двух частей (идентификатор хоста + целое число). Я не являюсь фаворитом GUID, но они удобны.
Подводя итог, не всем таблицам потребуется суррогатный ключ (любого типа); их следует использовать только в тех случаях, когда это необходимо для работы рассматриваемой таблицы. Независимо от того, какую стандартную суррогатную технологию вы предпочитаете, тщательно продумайте фактические потребности стола, прежде чем делать выбор; Изменение суррогатного ключа выбора технологии для стола будет изнурительной работой. Запишите ключевые показатели эффективности для своей таблицы, чтобы ваши преемники поняли сделанный выбор.
Особые случаи
Если ваши бизнес-требования требуют последовательной нумерации транзакций для аудиторских (или других) целей, то это поле не является суррогатным ключом; это естественный ключ (с дополнительными требованиями). Из документации автоинкрементное целое число только генерирует суррогатные ключи , поэтому найдите другой механизм для его генерации. Очевидно, что потребуется какой-то вид монитора, и если вы используете свои транзакции с нескольких сайтов, то один сайт будет особенным , поскольку он назначен узлом-хостом для монитора.
Если ваша таблица никогда не будет содержать более ста строк, то высота индекса не имеет значения; каждый доступ будет при сканировании таблицы. Однако сравнение строк в длинных строках все равно будет намного дороже, чем сравнение 4-байтового целого числа, и дороже, чем сравнение GUID.
Таблица кодовых значений, кодируемых полем кода char (4), должна быть такой же производительной, как таблица с 4-байтовым целым числом. Хотя у меня нет доказательств этого, я часто использую это предположение, и у меня никогда не было причин его опровергать.
источник
Мало того, что это не очень хорошая практика, на самом деле это описано как анти-паттерн в книге SQL Antipatterns Билла Карвина.
Не каждая таблица нуждается в псевдоключе - первичном ключе с произвольным значением, а не в том, что имеет семантическое значение для модели - и нет причины всегда вызывать его
id
.источник
Это довольно универсально - в противном случае вам нужно будет проверить, что ключ на самом деле уникален. Это можно сделать, посмотрев на все остальные ключи ... что отнимает много времени. Наличие инкрементного ключа становится дорогим, так как номер вашей записи приближается к значению переполнения ключа.
Я обычно делаю указатели более очевидными именами полей, как
ref_{table}
или похожая идея.Если нет необходимости внешне указывать на запись, тогда вам не нужен идентификатор.
источник
unsigned int
для типа поля, в противном случае ограничение составляет половину этого числа.Я бы не сказал, что это всегда должно быть сделано. У меня здесь таблица без уникального ключа - и он не нужен. Это журнал аудита. Обновления никогда не будет, запросы будут возвращать все изменения в журнале, но это лучшее, что может быть разумно сделано, когда человеку требуется определить ошибочное изменение. (Если бы код мог это сделать, он бы вообще запретил!)
источник
Автоматический счетчик приращений для первичного ключа не очень хорошая идея. Это потому, что вам нужно вернуться в базу данных, чтобы найти следующий ключ и увеличить его на единицу, прежде чем вставлять свои данные.
При этом я обычно использую все, что база данных может предоставить для первичного ключа, а не как часть приложения.
Позволяя исходной базе данных предоставить ее вам, она может гарантировать, что ключ будет уникальным для того, что ему нужно.
Конечно, не все базы данных поддерживают это. В этом случае я обычно использую таблицу, в которой хранятся ключевые сегменты, и использую верхние и нижние диапазоны, которые управляются в приложении. Это наиболее эффективное решение, которое я нахожу, потому что вы получаете диапазон 10000 чисел и автоматически увеличиваете их в экземпляре приложения. Другой экземпляр приложения может подобрать другую группу чисел для работы. Вам нужен достаточно большой примитив первичного ключа, например, 64-битный.
UUID я не использую в качестве первичных ключей, потому что стоимость их создания и хранения намного выше, чем увеличение длинного значения на единицу. UUID все еще имеют дело с парадоксом дня рождения в том, что теоретически может возникнуть дубликат.
источник