суррогат против естественного ключа: строгие цифры о различиях в производительности? - PullRequest
8 голосов
/ 04 августа 2009

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

ТАК 1

ТАК 2

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

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

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

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

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

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

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


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

  • PartNatural - таблица деталей, которая использует уникальный номер PartNumber в виде PK
  • PartSurrogate - таблица деталей, которая использует идентификатор (int, identity) в качестве PK и имеет уникальный индекс на PartNumber
  • Завод - ID (int, идентичность) как PK
  • Инженер - ID (int, identity) как PK

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

Ответы [ 2 ]

9 голосов
/ 04 августа 2009

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

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

3 голосов
/ 04 августа 2009

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

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

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

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

Сравнение VARCHAR s учитывает параметры сортировки, и они обычно длиннее целых, что делает их менее эффективными.

Сравнение набора из двух 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 секунды

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...