Суррогатный ключ

Поделись знанием:
Перейти к: навигация, поиск
К:Википедия:Статьи без источников (тип: не указан)

Суррога́тный ключ — понятие теории реляционных баз данных.

Это дополнительное служебное поле, добавленное к уже имеющимся информационным полям таблицы, единственное предназначение которого — служить первичным ключом. Значение этого поля не образуется на основе каких-либо других данных из БД, а генерируется искусственно.





Пример

Пусть у нас есть две таблицы — «Люди» и «Квитанции». Человек идентифицируется четырьмя полями — фамилия, имя, отчество, дата рождения. В таблице «Квитанции» указано, кому именно она адресована.

person
name1  | name2 | name3    | birth_date | address
---------------------------------------------------------
Иванов | Иван  | Иванович | 1 янв 1971 | ул. Википедии, 1
bill
person_name1  | person_name2 | person_name3 | person_birth_date | date       | amount  | is_paid
------------------------------------------------------------------------------------------------
Иванов        | Иван         | Иванович     | 1 янв 1971        | 1 фев 2011 | 2000.00 | да
Иванов        | Иван         | Иванович     | 1 янв 1971        | 1 мар 2011 | 1000.00 | нет

Добавив к обеим таблицам техническое числовое поле (часто называемое «id»), получаем такую базу.

person                                                         
id    | name1  | name2 | name3    | birth_date | address
-----------------------------------------------------------------
12345 | Иванов | Иван  | Иванович | 1 янв 1971 | ул. Википедии, 1
bill
id    | person_id | date       | amount  | is_paid
--------------------------------------------------
56789 | 12345     | 1 фев 2011 | 2000.00 | да
67890 | 12345     | 1 мар 2011 | 1000.00 | нет

Теперь квитанции ссылаются не на «Иванова Ивана Ивановича, родившегося 1 января 1971 года», а на «человека № 12345».

Реализация

Как правило, суррогатный ключ — это просто числовое поле, в которое заносятся значения из возрастающей числовой последовательности. Это может делаться при помощи триггеров или последовательностей. В ряде СУБД (например, PostgreSQL, Sybase, MySQL[1] или SQL Server[2]) существует специальный тип данных для таких полей — числовое поле, в которое при добавлении записи в таблицу автоматически записывается уникальное для этой таблицы числовое значение — т. н. «автоинкремент» (англ. autoincrement) или serial в терминологии PostgreSQL. В последнее время появилась тенденция использования в качестве суррогатных первичных ключей значений UUID в той или иной форме.

Причины использования

Неизменность. Главное достоинство суррогатного ключа состоит в том, что он практически никогда не меняется, поскольку не несёт никакой информации из предметной области и, следовательно, в минимальной степени зависит от изменений, происходящих в ней. Для изменения суррогатного ключа обычно требуются экстраординарные обстоятельства (см. ниже причину «гибкость»).

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

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

Гибкость. Поскольку суррогатный ключ неинформативен, его можно свободно заменять. Допустим, сливаются две фирмы со сходной структурой БД; сотрудник идентифицируется сетевым логином. Чтобы в полученной БД ключ оставался уникальным, приходится добавлять в него дополнительное поле — «из какой фирмы пришёл». В случае с суррогатными ключами достаточно выдать сотрудникам одной из фирм новые ключи.

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

SELECT
  *
FROM
  person
  INNER JOIN 
  bill
    ON person.id = bill.person_id;

компактнее и быстрее, чем

SELECT
  * 
FROM
  person AS p
  INNER JOIN 
  bill AS b
    ON p.name1 = b.person_name1 AND 
       p.name2 = b.person_name2 AND 
       p.name3 = b.person_name3 AND 
       p.birth_date = b.person_birth_date;

Упрощение программирования. Некоторые программистские задачи можно отвязать от структуры БД, например, таким образом.

function getId($aTableName, $aFieldName, $aFieldValue)
{
  $sqFieldValue = mysql_real_escape_string($aFieldValue);
  $qry = <<<QQQ
SELECT id
FROM `$aTableName`
WHERE `$aFieldName`='$sqFieldValue';
QQQ;
  if (!($result = mysql_query($qry))) die(mysql_error());
  if (!($ar = mysql_fetch_array($result))) return null;
  return $ar[0];
}

Этот код на PHP, динамически типизированном языке, уже предполагает, что ключевое поле всего одно. На традиционных языках наподобие C++ или Java ключ должен быть не просто одним полем, а полем какого-то заранее известного типа. Поэтому реляционно-объектные отображения (ORM) рассчитывают на то, что ссылки на объект являются числами или GUID’ами.

Недостатки

Уязвимости генераторов ключей.[3] Например, по номерам ключей можно узнать, сколько записей появилось в БД за некоторый период.

Неинформативность. Усложняется ручная проверка БД, появляются INNER JOIN там, где без них можно обойтись. По этой причине в полях перечисляемого типа часто используют ключи в виде коротких строк.

athlete                                country
id | name1    | name2 | country_id     id  | name
---+----------+-------+-----------     ----+-------
A1 | Иванов   | Иван  | RUS            RUS | Россия
А2 | Петренко | Пётр  | UKR            UKR | Украина
A3 | Смит     | Джон  | USA            USA | США

Иногда данные по своей природе подлежат переносу из базы в базу (например, между локальной и централизованной БД, экспериментальным и рабочим вариантом). Принимая новые данные, СУБД должна сгенерировать для них свои суррогатные ключи.

Склоняет администратора пропустить нормализацию. Добавить суррогатные ключи проще, чем правильно, с учётом дублирования и соотношений «1:∞» разбить БД на таблицы и проставить уникальные индексы.

Вопросы оптимизации. СУБД приходится поддерживать два индекса, суррогатный и естественный. Как сказано выше, могут появляться INNER JOIN там, где они не нужны.

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

См. также

Напишите отзыв о статье "Суррогатный ключ"

Ссылки

  1. [www.mysql.ru/docs/man/example-AUTO_INCREMENT.html Справочное руководство по MySQL — Использование атрибута AUTO_INCREMENT]
  2. [msdn.microsoft.com/ru-ru/library/ms186775.aspx Электронная документация по SQL Server 2008 — IDENTITY (свойство)]
  3. [habrahabr.ru/post/228219/ Эти чертовы инкрементальные айдишники / Хабрахабр]

Отрывок, характеризующий Суррогатный ключ

– Мари проехала через Рязань, – сказала Наташа. Князь Андрей не заметил, что она называла его сестру Мари. А Наташа, при нем назвав ее так, в первый раз сама это заметила.
– Ну что же? – сказал он.
– Ей рассказывали, что Москва вся сгорела, совершенно, что будто бы…
Наташа остановилась: нельзя было говорить. Он, очевидно, делал усилия, чтобы слушать, и все таки не мог.
– Да, сгорела, говорят, – сказал он. – Это очень жалко, – и он стал смотреть вперед, пальцами рассеянно расправляя усы.
– А ты встретилась с графом Николаем, Мари? – сказал вдруг князь Андрей, видимо желая сделать им приятное. – Он писал сюда, что ты ему очень полюбилась, – продолжал он просто, спокойно, видимо не в силах понимать всего того сложного значения, которое имели его слова для живых людей. – Ежели бы ты его полюбила тоже, то было бы очень хорошо… чтобы вы женились, – прибавил он несколько скорее, как бы обрадованный словами, которые он долго искал и нашел наконец. Княжна Марья слышала его слова, но они не имели для нее никакого другого значения, кроме того, что они доказывали то, как страшно далек он был теперь от всего живого.
– Что обо мне говорить! – сказала она спокойно и взглянула на Наташу. Наташа, чувствуя на себе ее взгляд, не смотрела на нее. Опять все молчали.
– Andre, ты хоч… – вдруг сказала княжна Марья содрогнувшимся голосом, – ты хочешь видеть Николушку? Он все время вспоминал о тебе.
Князь Андрей чуть заметно улыбнулся в первый раз, но княжна Марья, так знавшая его лицо, с ужасом поняла, что это была улыбка не радости, не нежности к сыну, но тихой, кроткой насмешки над тем, что княжна Марья употребляла, по ее мнению, последнее средство для приведения его в чувства.
– Да, я очень рад Николушке. Он здоров?

Когда привели к князю Андрею Николушку, испуганно смотревшего на отца, но не плакавшего, потому что никто не плакал, князь Андрей поцеловал его и, очевидно, не знал, что говорить с ним.
Когда Николушку уводили, княжна Марья подошла еще раз к брату, поцеловала его и, не в силах удерживаться более, заплакала.
Он пристально посмотрел на нее.
– Ты об Николушке? – сказал он.
Княжна Марья, плача, утвердительно нагнула голову.
– Мари, ты знаешь Еван… – но он вдруг замолчал.
– Что ты говоришь?
– Ничего. Не надо плакать здесь, – сказал он, тем же холодным взглядом глядя на нее.

Когда княжна Марья заплакала, он понял, что она плакала о том, что Николушка останется без отца. С большим усилием над собой он постарался вернуться назад в жизнь и перенесся на их точку зрения.
«Да, им это должно казаться жалко! – подумал он. – А как это просто!»
«Птицы небесные ни сеют, ни жнут, но отец ваш питает их», – сказал он сам себе и хотел то же сказать княжне. «Но нет, они поймут это по своему, они не поймут! Этого они не могут понимать, что все эти чувства, которыми они дорожат, все наши, все эти мысли, которые кажутся нам так важны, что они – не нужны. Мы не можем понимать друг друга». – И он замолчал.

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


Князь Андрей не только знал, что он умрет, но он чувствовал, что он умирает, что он уже умер наполовину. Он испытывал сознание отчужденности от всего земного и радостной и странной легкости бытия. Он, не торопясь и не тревожась, ожидал того, что предстояло ему. То грозное, вечное, неведомое и далекое, присутствие которого он не переставал ощущать в продолжение всей своей жизни, теперь для него было близкое и – по той странной легкости бытия, которую он испытывал, – почти понятное и ощущаемое.
Прежде он боялся конца. Он два раза испытал это страшное мучительное чувство страха смерти, конца, и теперь уже не понимал его.
Первый раз он испытал это чувство тогда, когда граната волчком вертелась перед ним и он смотрел на жнивье, на кусты, на небо и знал, что перед ним была смерть. Когда он очнулся после раны и в душе его, мгновенно, как бы освобожденный от удерживавшего его гнета жизни, распустился этот цветок любви, вечной, свободной, не зависящей от этой жизни, он уже не боялся смерти и не думал о ней.
Чем больше он, в те часы страдальческого уединения и полубреда, которые он провел после своей раны, вдумывался в новое, открытое ему начало вечной любви, тем более он, сам не чувствуя того, отрекался от земной жизни. Всё, всех любить, всегда жертвовать собой для любви, значило никого не любить, значило не жить этою земною жизнию. И чем больше он проникался этим началом любви, тем больше он отрекался от жизни и тем совершеннее уничтожал ту страшную преграду, которая без любви стоит между жизнью и смертью. Когда он, это первое время, вспоминал о том, что ему надо было умереть, он говорил себе: ну что ж, тем лучше.
Но после той ночи в Мытищах, когда в полубреду перед ним явилась та, которую он желал, и когда он, прижав к своим губам ее руку, заплакал тихими, радостными слезами, любовь к одной женщине незаметно закралась в его сердце и опять привязала его к жизни. И радостные и тревожные мысли стали приходить ему. Вспоминая ту минуту на перевязочном пункте, когда он увидал Курагина, он теперь не мог возвратиться к тому чувству: его мучил вопрос о том, жив ли он? И он не смел спросить этого.

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