суррогатный против естественного ключа:точные цифры различий в производительности?

StackOverflow https://stackoverflow.com/questions/1229173

Вопрос

Существует здоровая дискуссия между суррогатными и естественными ключами:

ИТАК, пост 1

ИТАК, пост 2

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

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

1:Суррогатный ключ:В таблице есть поле ID, которое является PK (и идентификатором).Названия компаний должны быть уникальными в зависимости от штата, поэтому здесь существует ограничение уникальности.

2:Естественный ключ:Таблица использует CompanyName и State в качестве PK - удовлетворяет как PK, так и уникальности.

Допустим, что Company PK используется в 10 других таблицах.Моя гипотеза, не подкрепленная никакими цифрами, заключается в том, что подход с использованием суррогатного ключа был бы здесь намного быстрее.

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

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


Важное обновление:Я начал строить набор тестовых таблиц которые отвечают на этот вопрос.Это выглядит примерно так:

  • PartNatural - таблица частей, которая использует уникальный номер партнера в качестве PK
  • PartSurrogate - таблица частей, которая использует идентификатор (int, identity) в качестве PK и имеет уникальный индекс для PartNumber
  • Завод - ИДЕНТИФИКАТОР (int, identity) как PK
  • Инженер - идентификатор (int, identity) как PK

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

Это было полезно?

Решение

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

Большая часть шуток (в "дебатах" по этому вопросу) может быть вызвана тем, что является ложным предположением - что вы должны использовать Первичный Ключ для соединений и внешних ключей в других таблицах.ЭТО ЛОЖЬ.Вы можете использовать ЛЮБОЙ Клавиша в качестве целевого объекта для внешних ключей в других таблицах.Это может быть Первичный ключ, альтернативный ключ или любой уникальный индекс или уникальное ограничение.А что касается соединений, вы можете использовать вообще что угодно для условия соединения, это даже не обязательно должен быть ключ, или idex, или даже уникальный !!(хотя, если он не уникален, вы получите несколько строк в создаваемом им декартовом произведении).

Другие советы

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

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

Однако наиболее часто используемыми типами суррогатных ключей являются INTEGER и RAW(16) (или любой другой тип вашего RDBMS использует ли для GUID's),

Сравнение суррогатных целых чисел и натуральных целых чисел (например SSN) занимает точно такое же время.

Сравнивая VARCHARs make учитывают параметры сортировки, и они, как правило, длиннее целых чисел, что делает их менее эффективными.

Сравнение набора из двух INTEGER вероятно, также менее эффективно, чем сравнение одного INTEGER.

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

И вот цифры (в MySQL):

CREATE TABLE aint (id INT NOT NULL PRIMARY KEY, value VARCHAR(100));
CREATE TABLE adouble (id1 INT NOT NULL, id2 INT NOT NULL, value VARCHAR(100), PRIMARY KEY (id1, id2));
CREATE TABLE bint (id INT NOT NULL PRIMARY KEY, aid INT NOT NULL);
CREATE TABLE bdouble (id INT NOT NULL PRIMARY KEY, aid1 INT NOT NULL, aid2 INT NOT NULL);

INSERT
INTO    aint
SELECT  id, RPAD('', FLOOR(RAND(20090804) * 100), '*')
FROM    t_source;

INSERT
INTO    bint
SELECT  id, id
FROM    aint;

INSERT
INTO    adouble
SELECT  id, id, value
FROM    aint;

INSERT
INTO    bdouble
SELECT  id, id, id
FROM    aint;

SELECT  SUM(LENGTH(value))
FROM    bint b
JOIN    aint a
ON      a.id = b.aid;

SELECT  SUM(LENGTH(value))
FROM    bdouble b
JOIN    adouble a
ON      (a.id1, a.id2) = (b.aid1, b.aid2);

t_source это просто фиктивная таблица с 1,000,000 ряды.

aint и adouble, bint и bdouble содержат точно такие же данные, за исключением того, что aint имеет целое число в виде PRIMARY KEY, в то время как adouble имеет пару из двух одинаковых целых чисел.

На моем компьютере оба запроса выполняются в течение 14,5 секунд, + /- 0,1 секунды

Разница в производительности, если таковая имеется, находится в пределах диапазона колебаний.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top