В ходе довольно оживленного обсуждения в моей команде меня заставили задуматься о том, что большинству людей нравится в качестве первичных ключей. У нас были следующие группы:
- Int / BigInt, автоинкремент которых является достаточно хорошими первичными ключами.
- Должно быть не менее 3 столбцов, составляющих первичный ключ.
- Идентификатор, GUID и удобочитаемые идентификаторы строк следует рассматривать по-разному.
Какой лучший подход для ПК? Было бы здорово, если бы вы могли обосновать свое мнение. Есть ли лучший подход, чем описанный выше?
РЕДАКТИРОВАТЬ: у кого-нибудь есть простой образец / алгоритм для создания удобочитаемых идентификаторов для строк, которые хорошо масштабируются?
algorithm
database-design
relational-database
primary-key
ddl
Perpetualcoder
источник
источник
PK(NEWID(),NEWID(),NEWID())
;-)Ответы:
Если вы собираетесь выполнять синхронизацию между базами данных с периодически подключаемыми приложениями, вам следует использовать идентификаторы GUID для своих первичных ключей. Это своего рода боль при отладке, поэтому, кроме этого случая, я предпочитаю использовать целые числа этого автоинкремента.
Autoincrement Интс должно быть ваше по умолчанию, а не использовать их должно быть оправданы.
источник
CHAR(1)
бы достаточно логического или , например, forsex
. Излишне говорить, что работать с этим было кошмаром.Я не вижу ответа, который указывает (что я считаю) на действительно фундаментальный момент, а именно на то, что первичный ключ - это то, что гарантирует, что вы не получите две записи в таблице для одного и того же реального объекта (как смоделировано в базе данных). Это наблюдение помогает установить, какие варианты первичного ключа являются хорошими, а какие - плохими.
Например, в таблице названий и кодов штатов (США) либо имя, либо код могут быть первичным ключом - они составляют два разных ключа-кандидата, и один из них (обычно более короткий - код) выбирается в качестве основной ключ. В теории функциональных зависимостей (и зависимостей соединения - от 1NF до 5NF) решающее значение имеют ключи-кандидаты, а не первичный ключ.
В качестве контрпримера человеческие имена обычно являются плохим выбором в качестве первичного ключа. Есть много людей, которых зовут «Джон Смит» или другими подобными именами; даже с учетом отчества (помните: оно есть не у всех - например, у меня), есть много возможностей для дублирования. Следовательно, люди не используют имена в качестве первичных ключей. Они изобретают искусственные ключи, такие как номер социального страхования (SSN) или номер сотрудника, и используют их для обозначения человека.
Идеальный первичный ключ должен быть коротким, уникальным, запоминающимся и естественным. Из этих характеристик обязательна уникальность; остальным приходится сгибаться с учетом ограничений реальных данных.
Поэтому, когда дело доходит до определения первичного ключа данной таблицы, вы должны посмотреть, что эта таблица представляет. Какой набор или наборы значений столбцов в таблице однозначно идентифицируют каждую строку в таблице? Это ключи-кандидаты. Теперь, если каждый ключ-кандидат состоит из 4 или 5 столбцов, вы можете решить, что они слишком неуклюжие для создания хорошего первичного ключа (в первую очередь из-за краткости). В таких случаях вы можете ввести суррогатный ключ - искусственно созданное число. Очень часто (но не всегда) в качестве суррогатного ключа достаточно простого 32-битного целого числа. Затем вы назначаете этот суррогатный ключ первичным ключом.
Однако вы по- прежнему должны гарантировать, что другие ключи-кандидаты (поскольку суррогатный ключ также является ключом-кандидатом, а также выбранный первичный ключ) все поддерживаются как уникальный идентификатор - обычно путем наложения уникального ограничения на эти наборы столбцов.
Иногда людям сложно определить, что делает строку уникальной, но для этого должно быть что-то, потому что простое повторение части информации не делает ее более верной. И если вы не будете осторожны и получите две (или более) строки, предназначенные для хранения одной и той же информации, а затем вам нужно обновить информацию, существует опасность (особенно если вы используете курсоры), что вы обновите только одну строку а не каждую строку, поэтому строки не синхронизированы, и никто не знает, какая строка содержит правильную информацию.
В некоторых отношениях это довольно жесткая точка зрения.
У меня нет особых проблем с использованием GUID, когда они нужны, но они, как правило, большие (как в 16-64 байтах), и используются слишком часто. Очень часто достаточно хорошего 4-байтового значения. Использование GUID, где 4-байтового значения будет достаточно, приводит к бесполезной трате дискового пространства и замедляет даже индексированный доступ к данным, поскольку на каждую страницу индекса приходится меньше значений, поэтому индекс будет глубже, и для доступа к Информация.
источник
Это только религиозный вопрос, потому что люди ищут универсальный правильный ответ. Тот факт, что и ваша команда, и этот тред SO демонстрируют так много разногласий, должен указывать на то, что есть веские причины использовать все описанные вами решения в различных обстоятельствах.
state
(CA, TX, NY), вы также можете использоватьchar(2)
естественный ключ вместо int.id
суррогатный ключ без надобности, когда существует совершенно хороший составной ключ (это особенно верно в таблицах "многие ко многим"). Обязанность использования ключа из трех столбцов в каждой таблице - абсолютная чепуха.источник
Мне нравится блог "Программист баз данных" как источник такой информации.
3 столбца для первичного ключа? Я бы сказал, что столбцы должны иметь соответствующие уникальные ограничения в соответствии с требованиями бизнес-правил, но у меня все равно будет отдельный суррогатный ключ. Составные ключи означают, что бизнес-логика входит в ключ. Если логика изменится, вся ваша схема испорчена.
источник
Мне нравится мой уникальный.
источник
Немного не по теме, но я чувствую себя обязанным присоединиться к ...
Если ваш первичный ключ - это GUID, не делайте его кластеризованным индексом . Поскольку идентификаторы GUID не являются последовательными, данные будут переупорядочиваться на диске почти при каждой вставке. (Уф.) Если в качестве первичных ключей используются идентификаторы GUID, они должны быть некластеризованными индексами.
источник
Я всегда беру суррогатный ключ. Суррогатный ключ (обычно столбец идентификаторов, автоинкремент или GUID) - это ключ, в котором ключ отсутствует в самих данных. С другой стороны, естественный ключ - это тот, который сам по себе однозначно идентифицирует строку. Насколько я могу судить в жизни, настоящих естественных ключей почти не существует . Даже такие вещи, как SSN в Соединенных Штатах, не являются естественным ключом. Составные первичные ключи ждут катастрофы. Вы не можете редактировать какие-либо из этих данных (что является основным недостатком любого естественного ключа, составного или нет), но хуже то, что с составным ключом теперь вам нужно увековечить эти ключевые данные в каждой связанной таблице. Какая огромная трата.
Теперь для выбора суррогатного ключа я придерживаюсь столбцов идентификаторов (я работаю в основном в MS SQL Server). GUID являются слишком большими и Microsoft рекомендует против использования их в качестве ПК. Если у вас несколько серверов, все, что вам нужно сделать, это сделать приращение 10 или 20 или как вы думаете максимальное количество серверов, которое вам когда-либо понадобится для синхронизации / расширения, и просто добавьте начальное число для каждой таблицы на каждом последующем сервере. , и у вас никогда не будет конфликта данных.
Конечно, из-за приращения я делаю столбец идентификаторов BigInt (иначе известный как длинный [64 бита]).
Подсчитав немного, даже если вы сделаете приращение 100, в вашей таблице все равно останется 92 233 720 368 547 758 (> 92 квадриллионов) строк.
источник
Я считаю, что использование слова «первичный» во фразе «первичный ключ» в действительности вводит в заблуждение.
Во-первых, используйте определение, что «ключ» - это атрибут или набор атрибутов, которые должны быть уникальными в пределах таблицы,
Затем наличие любого ключа служит нескольким часто несовместимым целям.
Для увеличения количества запросов, которым необходимо быстро найти определенную запись / строку в таблице.
Для обеспечения согласованности данных за счет предотвращения вставки повторяющихся строк, представляющих один и тот же логический объект, в таблицу. (Его часто называют «естественным» ключом, и он должен состоять из атрибутов таблицы (сущности), которые относительно инвариантны.)
Ясно, что любой бессмысленный, неестественный ключ (например, GUID или автоматически сгенерированное целое число) совершенно не может удовлетворить # 4.
Но часто во многих (большинстве) таблиц совершенно естественный ключ, который может предоставить # 4, часто будет состоять из нескольких атрибутов и быть чрезмерно широким или настолько широким, что его использование для целей # 1, # 2 или # 3 приведет к неприемлемым последствия для производительности.
Ответ прост. Используйте оба. Используйте простой автоматически генерируемый интегральный ключ для всех соединений и FK в других дочерних таблицах, но убедитесь, что каждая таблица, которая требует согласованности данных (очень немногие таблицы не имеют), имеет альтернативный естественный уникальный ключ, который предотвратит вставку несовместимых строк данных. .. Кроме того, если у вас всегда есть и то, и другое, то все возражения против использования естественного ключа (что, если он изменится? Я должен изменить каждое место, где он упоминается как FK), становятся спорными, поскольку вы не используете его для этого. .. Вы используете его только в одной таблице, где это ПК, чтобы избежать противоречивых дублирующих данных ...
Что касается идентификаторов GUID, будьте очень осторожны при их использовании, так как использование идентификаторов в индексе может привести к фрагментации индекса. Наиболее распространенные алгоритмы, используемые для их создания, помещают "случайную" часть guid в наиболее значимые битовые позиции ... Это увеличивает требования к регулярной дефрагментации / переиндексированию индекса по мере добавления новых строк.
источник
Одна вещь, которую вы никогда не должны делать, - это использовать смарт-ключ. Это ключ, в котором информация о записи закодирована в самом ключе, и в конечном итоге он вас укусит.
Я работал в одном месте, где первичным ключом был идентификатор учетной записи, представляющий собой комбинацию букв и цифр. Я не помню каких-либо подробностей, но, например, те учетные записи, которые были одного типа, были бы в диапазоне 600, а другого типа, начинались с 400. Это было здорово, пока этот клиент не решил попросить оба виды работ. Или изменили тип выполняемой работы.
Другое место использовало место в дереве как первичный ключ для записей. Итак, были бы записи вроде следующего.
Конечно, первое, что хотели клиенты, - это способ перемещать элементы в дереве. Весь набор софта умер до того, как это произошло.
Пожалуйста, пожалуйста, пожалуйста, если вы пишете код, который мне когда-либо придется поддерживать, пожалуйста, не используйте смарт-ключ!
источник
Я поклонник автоинкремента в качестве первичного ключа. В глубине души я знаю, что это отговорка, но с ее помощью так легко сортировать данные по времени их добавления (ORDER BY ID DESC, f'r instance).
3 колонки звучат ужасно жестко для человеческого анализа.
И это компромисс - какая часть реляционных возможностей вам нужна, по сравнению с тем, чтобы ЭТА ТАБЛИЦА СПРАВА была понятна человеку, который ее опрашивает (по сравнению с хранимой процедурой или программным интерфейсом).
автоинкремент для нас, людей. :-(
источник
Как правило, это зависит от обстоятельств.
Лично мне нравятся целые числа автоинкремента.
Но я могу вам сказать одно: никогда не доверяйте данным из других источников как своему ключу. Клянусь, каждый раз, когда я это делаю, он возвращается, чтобы укусить меня. Что ж, больше никогда!
источник
Я этого не понимаю.
Вы говорите о «естественном ключе», например, о «имени и дате рождения»? Естественный ключ может быть идеальным, если он существует, но большинство кандидатов на естественный ключ либо не уникальны (несколько человек с одинаковым именем), либо не постоянны (кто-то может изменить свое имя).
Я предпочитаю Гида. Потенциальная проблема с автоинкрементом заключается в том, что значение (например, «идентификатор заказа») присваивается экземпляром базы данных (например, «базой данных продаж») ... что не будет полностью работать (вместо этого вам понадобятся составные ключи), если вам когда-либо понадобится объединить данные, созданные более чем одним экземпляром базы данных (например, из нескольких офисов продаж, каждый со своей собственной базой данных).
источник
RE GUID's
Следите за тем, будет ли это действительно ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО большая база данных, большая нагрузка и быстрый доступ.
На моей последней работе, когда у нас были базы данных от 100 до 500 миллионов записей, наши специалисты по базам данных категорически возражали против GUID и в пользу десятичного числа подходящего размера. Они посчитали, что (в Oracle) разница в размере внутренней памяти для строки Guid - против десятичного значения будет иметь очень заметную разницу при поиске. (Большие ключи = более глубокие деревья для пересечения)
Случайный характер идентификаторов GUID также значительно снижает коэффициент заполнения индексных страниц - это резко увеличивает разрыв и дисковый ввод-вывод.
источник
Колонки с автоматическим приращением. Я могу заставить свой код работать без проблем с SQL Server или Oracle, один из которых использует идентификацию, другой - последовательности через мой DAL, и я очень счастлив. Я согласен, GUID иногда необходимы, если вы выполняете репликацию или отправляете данные, чтобы получить их позже после обработки.
источник
Я всегда использовал суррогатный ключ - целое число с автоинкрементом, называемое id. Я вижу множество причин для этого, даже когда очевиден другой вариант:
... и нет разумной причины не:
разумные доводы против того, что я еще не придумал и не встретил, всегда приветствуются ...
источник
Это классическая «смотря по обстоятельствам». На каждый проект не существует одного правильного ответа. Мне нравятся разные вещи для разных ситуаций. Это зависит от того, использую ли я ORM и что он поддерживает. Это зависит от общей архитектуры (распределенной или нет и т. Д.). Просто выберите тот, который, по вашему мнению, подойдет, и переходите к спорам о табуляциях и пробелах.
источник
Я обычно использую вариант №1 или №3 в зависимости от размера, количества подключающихся людей и того, является ли это ситуацией с несколькими серверами баз данных или нет.
Вариант №2 не имеет для меня особого смысла. Если одной из трех недостаточно для идентификации уникальной записи, то возможно (без дополнительных махинаций) две записи будут отображаться с одинаковыми значениями во всех трех столбцах. Если вы хотите обеспечить уникальность любой комбинации из трех, просто добавьте для них индекс.
источник
Я использую только int или GUID с автоинкрементом. В 99% случаев я использую автоинкремент int. Это как раз то, что меня научили использовать, когда я впервые узнал о базах данных, и никогда не сталкивался с причинами, по которым их не использовать (хотя я знаю причины, по которым GUID было бы лучше).
Мне нравится автоматическое увеличение целых чисел, потому что это помогает с удобочитаемостью. Например, я могу сказать: «Взгляните на запись 129383», и кому-то довольно легко зайти и найти ее. С GUID это сделать практически невозможно.
источник
Если не считать основного определяющего ответа, то, что составляет хороший первичный ключ, остается в основном на усмотрение религии и споров о комнате для отдыха. Если у вас есть что-то, что есть и всегда будет однозначно сопоставляться с отдельной строкой, тогда оно будет отлично работать как первичный ключ. После этого есть и другие соображения:
Этот последний, вероятно, привлекает большинство людей к использованию таких вещей, как GUID или самоприращающиеся целочисленные столбцы, потому что полагаясь на такие вещи, как адреса, номера телефонов, имя / фамилия и т. Д., Просто не сокращайте его. Единственный инвариант о людях, о которых я могу думать, - это SSN, но я даже не уверен на 100% в том, что они останутся навсегда уникальными.
Надеюсь, это поможет добавить ясности ...
источник
Я подхожу к первичным ключам (и считаю, что это лучший вариант) - избегать использования «стандартного» подхода. Это означает, что вместо того, чтобы просто нажимать на автоматически увеличивающееся целое число и вызывать его, я смотрю на проблему и спрашиваю: «Есть ли столбец или группа столбцов, которые всегда будут уникальными и не будут меняться?» Если да, то я придерживаюсь этого подхода.
источник
Почти всегда целые числа.
У них есть и другие веские причины, помимо того, что они меньше / быстрее обрабатываются. Что бы вы предпочли записать - «404040» или «3463b5a2-a02b-4fd4-aa0f-1d3c0450026c»?
источник
Немного актуально, но кое-что, что я начал делать недавно, когда у меня есть небольшие классификационные таблицы (в основном те, которые будут представлять ENUM в коде), - это то, что я сделаю первичный ключ char (3) или char (4). Затем я делаю эти первичные ключи репрезентативными для значения поиска.
Например, у меня есть система котировок для наших внутренних торговых агентов. У нас есть «Категории затрат», в которых каждой строке котировок назначается одна из ... Итак, у меня есть таблица поиска типов под названием «tCostCategories», где первичный ключ - «MTL», «SVC», «TRV», «TAX», ODC. В других столбцах справочной таблицы хранятся дополнительные сведения, такие как обычные английские значения кодов, «Материал», «Услуги», «Путешествие», «Налоги», «Другие прямые расходы» и т. Д.
Это действительно приятно, потому что он не использует больше места, чем int, и когда вы смотрите на исходные данные, вам не нужно связывать таблицу поиска, чтобы узнать, какое значение, черт возьми,. Например, строка цитаты может выглядеть так:
1 Номер детали $ 40 MTL
2 Другой Номер детали $ 29,99 SVC
3 Номер детали2 $ 150 TRV
Гораздо проще использовать int для представления категорий, а затем связывать 1, 2, 3 во всех строках - у вас есть данные прямо перед вами, и на производительность, похоже, вообще не влияет (не то, что я ' действительно проверен.)
Что касается реального вопроса ... Мне нравятся уникальные идентификаторы RowGUID. Я не на 100% в этом вопросе, но разве все строки не имеют внутреннего RowGuid ?? Если это так, то использование RowGuid на самом деле займет меньше места, чем int (или что-то еще в этом отношении.) Все, что я знаю, это то, что если M $ достаточно для использования в GreatPlains, то для меня этого достаточно. (Я должен пригнуться ??)
источник
Еще одна причина, по которой я использую GUID - я использую иерархическую структуру данных. То есть у меня есть таблица «Компания» и таблица «Поставщик», для которых совпадают первичные ключи. Но у меня также есть таблица «Производитель», которая также «наследуется» от компании. Поля, общие для поставщиков и производителей, не отображаются в этих таблицах - они отображаются в компании. В этой настройке использование int намного более болезненно, чем Guids. По крайней мере, вы не можете использовать первичные ключи идентификации.
источник
Мне нравятся естественные ключи, когда я могу им доверять. Я готов заплатить небольшую цену за производительность, чтобы использовать ключи, понятные специалистам в данной области.
Для таблиц, описывающих сущности, должен быть простой естественный ключ, который идентифицирует отдельные экземпляры так же, как это делают люди из предметной области. Если предмет не имеет надежных идентификаторов для одной из сущностей, я прибегаю к суррогатному ключу.
Для таблиц, описывающих отношения, я использую составной ключ, где каждый компонент ссылается на сущность, которая участвует в взаимосвязи, и, следовательно, на строку в таблице сущностей. Опять же, снижение производительности при использовании составного ключа обычно минимально.
Как отмечали другие, термин «первичный ключ» немного вводит в заблуждение. В реляционной модели данных используется термин «ключи-кандидаты». Для одной таблицы может быть несколько ключей-кандидатов. По логике вещей, каждый так же хорош, как и другой. Выбор одного из них в качестве «основного» и создание всех ссылок с помощью этого ключа - это просто выбор, который может сделать дизайнер.
источник
Guids.period.
Если вам нужно масштабировать или назначить первичный ключ альтернативным способом, они станут вашим другом. Вы можете добавить индексы для всего остального.
обновить, чтобы уточнить мое заявление.
Я работал над множеством разных сайтов. От небольших отдельных серверов до крупных, поддерживаемых несколькими БД и веб-серверами. Конечно, были приложения, которые отлично справились бы с автоматическим увеличением целых чисел в качестве первичных ключей. Однако это не соответствует моей модели.
При использовании GUID вы можете сгенерировать идентификатор где угодно. Он может быть сгенерирован удаленным сервером, вашим веб-приложением, в самой базе данных или даже в нескольких базах данных в ситуации с несколькими мастерами.
С другой стороны, автоматически увеличиваемый INT может быть безопасно сгенерирован только в первичной базе данных. Опять же, это может быть нормально, если у вас есть приложение, которое будет тесно связано с этим одним резервным сервером БД, и масштабирование - это не то, что вас беспокоит.
Конечно, использование GUID означает, что вам нужно выполнять каждую ночь процессы переиндексации. Однако, если вы используете что-либо, кроме автоматически увеличиваемого INT, вы все равно должны это сделать. Черт возьми, даже с INT в качестве основного, вероятно, у вас есть другие индексы, которые необходимо регенерировать, чтобы справиться с фрагментацией. Следовательно, использование идентификаторов GUID точно не добавляет еще одной проблемы, потому что эти задачи необходимо выполнять независимо.
Если вы посмотрите на более крупные приложения, вы заметите кое-что важное: все они используют GUID в кодировке Base64 в качестве ключей. Причина этого проста: использование идентификаторов GUID позволяет легко масштабировать , тогда как при попытке масштабирования INT может возникнуть множество проблем, через которые нужно прыгнуть.
Наше последнее приложение переживает период тяжелых вставок, который длится около месяца. После этого 90% запросов выбираются для отчетности. Для увеличения емкости я могу подключить дополнительные серверы БД в течение этого большого периода вставки; а позже легко объединить их в единую базу данных для отчетности. Попытка сделать это с помощью INT была бы абсолютным кошмаром.
Откровенно говоря, каждый раз, когда вы кластеризуете базу данных или настраиваете репликацию, сервер БД в любом случае будет требовать, чтобы у вас были GUID в таблице. Итак, если вы думаете, что вашей системе может потребоваться рост, выберите ту, которая хороша.
источник
Это сложная тема, осознавали вы это или нет. Может подпадать под раздел этого FAQ по StackOverflow.
Какие вопросы мне здесь не задавать?
Избегайте вопросов, которые являются субъективными, аргументированными или требуют расширенного обсуждения. Это место для вопросов, на которые можно ответить!
Это обсуждается годами и будет продолжаться годами. Единственные намеки на консенсус, которые я видел, - это то, что ответы в некоторой степени предсказуемы в зависимости от того, спрашиваете ли вы специалиста по объектно-ориентированному программированию (GUID - единственный выход!), Разработчика моделирования данных (естественные ключи - единственный выход!), или ориентированный на производительность администратор базы данных (единственный выход - INT!).
источник