Составные первичные ключи и поле уникальный идентификатор объекта


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

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

может ли кто - нибудь предложить мнения или добавить больше глубины к этой теме?

15 69

15 ответов:

Большинство часто используемых движков (MS SQL Server, Oracle, DB2, MySQL и др.) не будет испытывать заметных проблем с использованием суррогатной ключевой системы. Некоторые из них могут даже испытывать повышение производительности от использования суррогата, но проблемы с производительностью сильно зависят от платформы.

аргументы в пользу естественного ключи (сингулярные или составные) обычно включают в себя следующее:

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

2) они устраняют необходимость определенных соединений. например, если у вас есть клиенты с кодами клиентов и счета-фактуры с номерами счетов-фактур (оба из которых являются" естественными " ключами), и вы хотите получить все номера счетов-фактур для определенного кода клиента, вы можете просто использовать "SELECT InvoiceNumber FROM Invoice WHERE CustomerCode = 'XYZ123'". В классическом подходе суррогатного ключа SQL будет выглядеть примерно так:"SELECT Invoice.InvoiceNumber FROM Invoice INNER JOIN Customer ON Invoice.CustomerID = Customer.CustomerID WHERE Customer.CustomerCode = 'XYZ123'".

3) они способствуют более универсально применимого подхода к моделированию данных. С естественными ключами, такую же конструкцию можно использовать в большинстве неизменно между различные механизмы SQL. Многие суррогатные ключевые подходы используют специальные методы SQL engine для генерации ключей, что требует большей специализации модели данных для реализации на разных платформах.

аргументы для суррогатных ключей, как правило, вращаются вокруг проблем, специфичных для SQL engine:

1) они позволяют легче изменять атрибуты при изменении бизнес-требований / правил. это потому, что они позволяют атрибутам данных быть изолированы в один стол. Это в первую очередь проблема для SQL-движков, которые не эффективно реализуют стандартные конструкции SQL, такие как Домены. Когда атрибут определяется оператором домена, изменения в атрибуте могут быть выполнены в масштабе всей схемы с помощью оператора ALTER DOMAIN. Различные механизмы SQL имеют различные характеристики производительности для изменения домена, а некоторые механизмы SQL вообще не реализуют Домены, поэтому разработчики моделей данных компенсируют эти ситуации, добавляя суррогатные ключи для улучшения возможность внесения изменений в атрибуты.

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

3) они работают лучше, чем естественные ключи. производительность больше всего зависит от механизма SQL. Одна и та же схема базы данных, реализованная на одном и том же оборудовании с использованием разных механизмов SQL, часто будет иметь резко отличающиеся характеристики производительности из-за механизмов хранения и извлечения данных SQL-движков. Некоторые SQL-движки близко приближаются к плоским файловым системам, где данные фактически хранятся избыточно, когда один и тот же атрибут, например код клиента, появляется в нескольких местах в схеме базы данных. Это избыточное хранилище с помощью механизма SQL может вызвать проблемы с производительностью, когда необходимо внести изменения в данные или схему. Другие механизмы SQL обеспечивают лучшее разделение между моделью данных и системой хранения/поиска, что позволяет быстрее изменять данные и схему.

4) суррогатные ключи работают лучше с определенным доступом к данным библиотеки и GUI-фреймворки. из-за однородной природы большинства конструкций суррогатных ключей (пример: все реляционные ключи являются целыми числами), библиотеки доступа к данным, ORMs и GUI-фреймворки могут работать с информацией без необходимости специальных знаний о данных. Естественные ключи, из-за их гетерогенной природы (различные типы данных, размер и т. д.), не работают с автоматической или полуавтоматической средств и библиотек. Для специализированных сценариев, таких как встроенные базы данных SQL, проектирование база данных с конкретным набором инструментов может быть приемлемой. В других сценариях базы данных-это корпоративные информационные ресурсы, к которым одновременно обращаются несколько платформ, приложений, систем отчетов и устройств, и поэтому они не функционируют так же хорошо, когда разрабатываются с акцентом на какую-либо конкретную библиотеку или фреймворк. Кроме того, базы данных, предназначенные для работы с конкретными наборами инструментов, становятся обузой, когда вводится следующий большой инструментарий.

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

есть несколько отличные ресурсы обсуждение достоинств каждого подхода:

http://www.google.com/search?q=natural + ключ + суррогат+ключ

http://www.agiledata.org/essays/keys.html

http://www.informationweek.com/news/software/bi/201806814

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

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

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

  • Если ключ не является постоянным, у вас есть проблема с будущим обновлением, которая может стать довольно сложной

  • Если ключ не бессмысленна, то он скорее всего изменится, т. е. не будет постоянной; см. выше

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

EDIT: есть дополнительная проблема, которая более практична, чем философская. Во многих случаях вы собираетесь найти определенную строку каким-то образом, а затем позже обновить ее или найти ее снова (или оба). С составными ключами есть больше данных для отслеживания и больше противопоказаний в предложении WHERE для повторного поиска или обновления (или удаления). Также возможно, что один из ключевых сегментов может измениться за это время!. С суррогатным ключом всегда есть только одно значение для сохранения (суррогатный идентификатор), и по определению он не может измениться, что значительно упрощает ситуацию.

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

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

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

использование полей' unique (object) ID ' упрощает соединения, но вы должны стремиться к тому, чтобы другой (возможно, составной) ключ все еще был уникальным-не ослабляйте ограничения not-null и поддерживайте ограничение unique.

Если СУБД не может эффективно обрабатывать уникальные целые числа, у нее большие проблемы. Однако использование как "уникального (объектного) идентификатора", так и другого ключа использует больше места (для индексов), чем просто другой ключ, и имеет два индекса для обновления при каждой операции вставки. Так что это не халява - но пока вы поддерживаете оригинальный ключ, то вы будете в порядке. Если вы устраните другой ключ, вы нарушите дизайн своей системы; весь ад в конечном итоге вырвется на свободу (и вы можете или не можете обнаружить, что ад вырвался на свободу).

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

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

каждый раз, когда я создаю таблицу, я терять время

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

мой ответ " нет " на все эти вопросы:

  1. у меня нет времени, чтобы потерять, пытаясь к определите "лучший первичный ключ", когда работа со списком людей.
  2. я не хочу вспоминать, что Первичный ключ моего "computer" таблица это строка длиной 64 символа (делает Windows принимает такое количество символов для имени компьютера?).
  3. я не хочу объяснять свой выбор другие разработчики, где один из них наконец-то скажет: "Да, чувак, но считайте, что вы должны управлять компьютеры в разных доменах? Позволяет ли эта строка из 64 символов вы в магазине доменное имя + the имя компьютера?".

так что я работаю в течение последних пяти лет с очень простым правилом: каждая таблица (давайте назовем ее 'myTable') имеет свое первое поле под названием'id_MyTable ' который имеет тип uniqueIdentifier. Даже если эта таблица поддерживает отношение "многие ко многим", например 'ComputerUser таблица, где сочетания 'id_Computer' и 'id_User 'формирует очень приемлемый первичный ключ, я предпочитаю создавать это'id_ComputerUser' поле является uniqueIdentifier, просто придерживаться к правилу.

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

Я не уверен, что мое правило-лучше один. Но это очень эффективный способ!

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

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

natural pk имеют свою мотивацию и сценарий использования и не являются плохой вещью (tm), они просто имеют тенденцию не ладить с ORM.

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

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

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

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

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

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

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

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

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

Это было почти наверняка нонсенсом, но, возможно, связано с проблемой конкуренции индексных блоков при назначении инкрементных чисел PK с высокой скоростью из разных сеансов. Если это так, то обратный ключевой индекс должен помочь, хотя и за счет большего размера индекса из-за изменения алгоритма разделения блоков. http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/schema.htm#sthref998

перейти на синтетический, особенно если это помогает более быстрому развитию с вашим набором инструментов.

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

формат внешних данных может меняться с течением времени. Например, вы можете подумать, что ISBN книги будет хорошим первичным ключом в таблице книг. В конце концов, ISBNs уникальны. Но поскольку эта конкретная книга пишется, издательская индустрия в Соединенных Штатах готовится к серьезным изменениям, поскольку дополнительные цифры добавляются ко всем номер ISBN. Если бы мы использовали ISBN в качестве первичного ключа в таблице книг, нам придется обновлять каждую строку, чтобы отразить это изменение. Но тогда у нас была бы другая проблема. В базе данных будут другие таблицы, которые ссылаются на строки в таблице книг через первичный ключ. Мы не можем изменить ключ в таблице книги, если мы сначала не пройдем и не обновим все эти ссылки. И это будет включать в себя удаление ограничений внешнего ключа, обновление таблиц, обновление таблицы книг и, наконец, восстановление ограничения. В общем, это что-то вроде боли. Проблемы исчезают, если мы используем наше собственное внутреннее значение в качестве первичного ключа. Никакая третья сторона не может прийти и произвольно сказать нам изменить нашу схему-мы контролируем наше собственное пространство ключей. И если что-то вроде ISBN действительно нужно изменить, оно может измениться, не затрагивая ни одной из существующих связей в базе данных. По сути, мы отделили вязание строк от внешнего представления данных в них строки.

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

@JeremyDWill

Спасибо за обеспечение столь необходимого баланса в дискуссии. В частности, спасибо за информацию о DOMAIN s.

Я на самом деле использую суррогатные ключи по всей системе ради согласованности, но там are компромиссы. Наиболее распространенной причиной для меня проклятия с использованием суррогатных ключей является то, что у меня есть таблица поиска с коротким списком канонических значений-я бы использовал меньше места, и все мои запросы были бы короче / проще / быстрее, если бы у меня был просто сделал значения PK вместо того, чтобы присоединяться к таблице.

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

что я, как правило, делают в эти дни, чтобы добавить "идентификатор rowid" собственность для каждой таблицы - это поле представляет собой идентификатор GUID, так и уникальными для каждой строки. Это не первичный ключ-это естественный ключ (если это возможно). Тем не менее, любые слои ORM, работающие верхняя часть этой базы данных может использовать RowID для идентификации своих производных объектов.

таким образом, вы могли бы иметь:

CREATE TABLE dbo.Invoice (
  CustomerId varchar(10),
  CustomerOrderNo varchar(10),
  InvoiceAmount money not null,
  Comments nvarchar(4000),
  RowId uniqueidentifier not null default(newid()),

  primary key(CustomerId, CustomerOrderNo)
)

Итак, ваш DBA счастлив, ваш архитектор ORM счастлив, и целостность вашей базы данных сохраняется!

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

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

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

но это не мешает кому-то от этого... таблица, использующая одно автоматически сгенерированное 32-битное целое число в качестве идентификатора, которое, как ожидается, будет хранить все транзакции на глобальном уровне для a конкретная компания быстрого питания, собирается потерпеть неудачу, как только он пытается вставить это 2,147,483,648-й сделки (и это вполне осуществимый сценарий).

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