Разработка базы данных и использование нечисловых первичных ключей

В настоящее время я разрабатываю таблицы базы данных для приложения для управления клиентом и веб-сайтом. Мой вопрос касается использования первичных ключей в качестве функциональных частей таблицы (и не присваивания "идентификационных номеров" каждой таблице только потому, что).

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

--
-- website
--
CREATE TABLE IF NOT EXISTS `website` (
  `name` varchar(126) NOT NULL,
  `client_id` int(11) NOT NULL,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `notes` text NOT NULL,
  `website_status` varchar(26) NOT NULL,
  PRIMARY KEY  (`name`),
  KEY `client_id` (`client_id`),
  KEY `website_status` (`website_status`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- website_status
--
CREATE TABLE IF NOT EXISTS `website_status` (
  `name` varchar(26) NOT NULL,
  PRIMARY KEY  (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `website_status` (`name`) VALUES
('demo'),
('disabled'),
('live'),
('purchased'),
('transfered');

--
-- client
--
CREATE TABLE IF NOT EXISTS `client` (
  `id` int(11) NOT NULL auto_increment,
  `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `client_status` varchar(26) NOT NULL,
  `firstname` varchar(26) NOT NULL,
  `lastname` varchar(46) NOT NULL,
  `address` varchar(78) NOT NULL,
  `city` varchar(56) NOT NULL,
  `state` varchar(2) NOT NULL,
  `zip` int(11) NOT NULL,
  `country` varchar(3) NOT NULL,
  `phone` text NOT NULL,
  `email` varchar(78) NOT NULL,
  `notes` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `client_status` (`client_status`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- client_status
---
CREATE TABLE IF NOT EXISTS `client_status` (
  `name` varchar(26) NOT NULL,
  PRIMARY KEY  (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `client_status` (`name`) VALUES
('affiliate'),
('customer'),
('demo'),
('disabled'),
('reseller');

Как вы можете видеть, 3 из 4 таблиц используют свое "имя" в качестве первичного ключа. Я знаю, что они всегда будут уникальными. В 2 случаях (таблицы * _status) я в основном использую динамическую замену для ENUM, поскольку параметры состояния могут измениться в будущем, а для таблицы "веб-сайт" я знаю, что "имя" веб-сайта всегда будет быть уникальным.

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

Спасибо, что нашли время, чтобы прочитать это!

Ответ 1

Есть две причины, по которым я всегда добавлял идентификационный номер в таблицу поиска /ENUM:

  • Если вы ссылаетесь на одну таблицу столбцов с именем, то вам может быть лучше, если использовать ограничение
  • Что произойдет, если вы хотите переименовать одну из записей client_status? например если вы хотите изменить имя от "аффилированного лица" до "партнера", вам необходимо обновить таблицу клиентов, которая не должна быть необходимой. Идентификационный номер служит ссылкой, а имя - это описание.

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

EDIT: Как указано выше, у вас возникнут проблемы, если имя веб-сайта будет переименовано. Сделав это первичным ключом, вы сделаете это очень сложным, если не невозможным, для того, чтобы это было изменено позднее.

Ответ 2

При создании натуральных PRIMARY KEY, убедитесь, что их уникальность находится под вашим контролем.

Если вы абсолютно уверены, что никогда не будете иметь нарушения уникальности, тогда это ОК, чтобы использовать эти значения как PRIMARY KEY.

Так как website_status и client_status кажутся сгенерированными и используемыми вами и только вами, допустимо использовать их как PRIMARY KEY, хотя наличие длинного ключа может повлиять на производительность.

website имя, похоже, находится под контролем внешнего мира, поэтому я бы сделал его простым полем. Что делать, если они хотят переименовать их website?

Контрпримеры будут SSN и ZIP коды: это не вы, кто их генерирует, и нет гарантии, что они никогда не будут дублироваться.

Ответ 3

Кимберли Трипп имеет превосходную серию статей для блогов (GUIDs как ПЕРВИЧНЫЕ КЛЮЧИ и/или ключ кластеризации и дебаты по кластерному индексу продолжается) по вопросу создания кластеризованных индексов и выбора первичного ключа (связанные проблемы, но не всегда точно такие же). Она рекомендует кластерный индекс/первичный ключ:

  1. Уникальный (иначе бесполезный как ключ)
  2. Узкий (ключ используется во всех некластеризованных индексах и в отношениях внешнего ключа)
  3. Статический (вы не хотите менять все связанные записи)
  4. Всегда увеличивается (поэтому новые записи всегда добавляются в конец таблицы, и их не нужно вставлять в середину)

Использование "имени" в качестве ключа, хотя оно, кажется, удовлетворяет # 1, не удовлетворяет ЛЮБОМУ из трех других.

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

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

Ответ 4

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

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

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

например. если ваша таблица имеет 10 миллионов строк, 10 некластеризованных индексов, а ваш ключ кластеризации - 26 байт вместо 4 (для INT), тогда вы теряете 10 миллионов. на 10 на 22 байта на общую сумму 2,2 миллиарда байт (или на 2,2 ГБ) - это не арахис!

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

Марк

Ответ 5

"Если вы абсолютно уверены, что никогда не будете иметь нарушения уникальности, тогда это ОК, чтобы использовать эти значения как ОСНОВНЫЕ КЛЮЧИ".

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

Ответ 6

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

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

Ответ 7

Это просто кажется очень плохой идеей. Что делать, если вам нужно изменить значение перечисления? Идея состоит в том, чтобы создать реляционную базу данных, а не набор плоских файлов. На этом этапе, почему таблица client_status? Более того, если вы используете данные в приложении, используя такой тип, как GUID или INT, вы можете проверить тип и избежать плохих данных (в случае проверки типа). Таким образом, это еще одна из многих линий для сдерживания взлома.

Ответ 8

Я бы сказал, что база данных, которая устойчива к коррупции, даже если она работает немного медленнее, лучше, чем та, которая isn & rsquo; t.

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

Даже если это означает использование сложного ключа для обеспечения уникальности, я бы рекомендовал использовать осмысленный, естественный набор атрибутов в качестве первичного ключа, когда это возможно. Если вам все равно нужно записывать атрибуты, зачем добавлять еще один? Тем не менее, суррогатные ключи прекрасны, когда нет естественного, стабильного, сжатого, гарантированного к уникальному ключу (например, для людей).

Вы также можете рассмотреть возможность использования сжатия ключа индекса, если ваша СУБД поддерживает ее. Это может быть очень эффективным, особенно для индексов на составных ключах (думаю, trie структуры данных), и особенно если могут появляться наименее селективные атрибуты сначала в индексе.

Ответ 9

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

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

Ответ 10

Здесь нужно рассмотреть несколько пунктов, прежде чем принимать ключи в таблице

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

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

  • Цифровые клавиши делают db более простым понять (вы можете легко узнать строк, просто просматривая последнюю строку)

Ответ 11

Вы НИКОГДА не знаете, когда компания, на которую вы работаете, внезапно развивается, и вам приходится нанимать 5 разработчиков за ночь. Лучше всего использовать числовые (целочисленные) первичные ключи, поскольку всей команде будет намного проще работать с AND, и это повысит вашу производительность в случае роста базы данных. Если вам нужно разбить записи и разбить их на части, вы можете использовать первичный ключ. Если вы добавляете записи с отметкой даты и времени (как и в каждой таблице), и где-то в коде есть ошибка, которая неправильно обновляет это поле, единственный способ проверить, была ли запись введена в правильной последовательности, это проверить основной ключи. Вероятно, есть еще 10 причин TSQL или отладки для использования первичных ключей INT, не в последнюю очередь из которых пишется простой запрос для выбора последних 5 записей, введенных в таблицу.