Существует ли РЕАЛЬНАЯ разница в производительности между первичными ключами INT и VARCHAR?

174

Есть ли ощутимая разница в производительности между использованием INT и VARCHAR в качестве первичного ключа в MySQL? Я хотел бы использовать VARCHAR в качестве первичного ключа для списков ссылок (например, штаты США, коды стран), и коллега не будет указывать INT AUTO_INCREMENT в качестве первичного ключа для всех таблиц.

Мой аргумент, который подробно описан здесь , заключается в том, что разница в производительности между INT и VARCHAR незначительна, поскольку для каждой ссылки на внешний ключ INT требуется JOIN, чтобы понять смысл ссылки, ключ VARCHAR будет непосредственно представлять информацию.

Итак, есть ли у кого-нибудь опыт использования этого конкретного варианта использования и связанные с ним проблемы производительности?

Джейк МакГроу
источник
3
Я сделал сообщение с ответом «нет» с некоторыми подробностями тестов, которые я запускал ... но это был SQL Server, а не MySQL. Поэтому я удалил свой ответ.
Тимоти Хоури
17
@ Тимоти - ты не должен был его удалять. Я был в процессе голосования. Большинство серверов баз данных SQL имеют схожие планировщики запросов и схожие узкие места производительности.
Пол Томблин
9
@ Тимоти, пожалуйста, перепечатайте свои результаты.
Джейк МакГроу
2
Так много комментариев и ответов предполагают, что ключи используются для объединений. Они не. Ключи должны использоваться для согласованности данных - чтобы избежать дублирования строк (более одной строки, представляющей одну и ту же сущность). Любой столбец (или набор столбцов) может использоваться в объединении, и для гарантии того, что объединение равно один-к-ну или много столбцов, просто должны быть уникальными. Любой уникальный индекс гарантирует это, и он не должен быть значимым.
Чарльз Бретана

Ответы:

78

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

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

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

Другие люди отмечают, что на практике редко встречаются естественные ключи, которые никогда не меняются и не имеют дубликатов, поэтому суррогатные ключи обычно стоят того.

Билл Карвин
источник
3
И иногда, (imho, часто), оба лучше, суррогат для использования для ссылок FK в других таблицах и для объединений, и естественный ключ для обеспечения согласованности данных
Чарльз Бретана
@CharlesBretana Это интересно. Является ли использование естественного ключа для согласованности данных на стороне FK обычной практикой? Моей первой мыслью было, что дополнительное хранилище, которое потребуется для больших таблиц, может не оправдать себя. Любая информация приветствуется. К вашему сведению - у меня неплохой опыт программирования, но мой опыт работы с SQL ограничен в основном запросами SELECT
Роб
2
@CharlesBretana Когда я читаю «сохранить их обоих», я думаю, что «избыточность» и «не нормализовано», что равняется «Этот материал может испортиться» и «Я должен убедиться, что оба они изменены, если один из них когда-либо меняется». Если у вас есть избыточность, должна быть очень веская причина (например, совершенно неприемлемая производительность), потому что избыточность всегда может привести к тому, что ваши данные станут непоследовательными.
jpmc26
3
@ jpmc26, абсолютно НЕТ проблем избыточности или нормализации. Суррогатный ключ не имеет значимой связи со значениями в естественном ключе, поэтому его никогда не нужно менять. Что касается нормализации, о каких проблемах нормализации вы говорите? Нормализация применяется к значимым атрибутам отношения; числовое значение суррогатного ключа (собственно, само понятие суррогатного ключа) полностью выходит за рамки любой нормализации.
Чарльз Бретана
1
И чтобы ответить на ваш другой вопрос, в частности, о таблице состояний, если у вас есть суррогатный ключ в этой таблице со значениями, скажем, от 1 до 50, но вы НЕ поместили другой уникальный индекс или ключ в почтовый индекс штата, (и, на мой взгляд, также относительно названия штата), что может помешать кому-либо ввести две строки с разными значениями суррогатных ключей, но с одинаковым почтовым индексом и / или именем штата? Как бы клиентское приложение справилось с этим, если бы было две строки с «NJ», «New Jersey»? Natural Keys обеспечивает согласованность данных!
Чарльз Бретана
81

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

INT AUTO_INCREMENT соответствует условию «уникальность и неизменность во времени». Отсюда и предпочтение.

Стив Маклеод
источник
25
Правда. В одной из моих самых больших баз данных есть записи по Югославии и Советскому Союзу. Я рад, что они не первичные ключи.
Пол Томблин
8
@ Стив, тогда почему ANSI SQL поддерживает синтаксис ON UPDATE CASCADE?
Билл Карвин
5
Неизменность не является обязательным требованием ключа. В любом случае суррогатные ключи иногда тоже меняются. Ничего плохого в смене ключей, если нужно.
nvogel
9
Павел, значит, вы изменили Советский Союз на Россию в своей базе данных? И делать вид, что СУ никогда не существует? А все ссылки на СУ сейчас указывают на Россию?
Дайний
6
@alga Я родился в SU, поэтому я знаю, что это такое.
Дайний,
52

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

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

Настройка была следующей:

  • Процессор Intel® Core ™ i7-7500U @ 2,70 ГГц × 4
  • 15.6 ГБ ОЗУ, из которых я гарантировал, что около 8 ГБ было свободно во время теста.
  • SSD-накопитель на 148,6 ГБ, с большим количеством свободного места.
  • Ubuntu 16.04 64-bit
  • MySQL Ver 14.14 Distrib 5.7.20, для Linux (x86_64)

Столы:

create table jan_int (data1 varchar(255), data2 int(10), myindex tinyint(4)) ENGINE=InnoDB;
create table jan_int_index (data1 varchar(255), data2 int(10), myindex tinyint(4), INDEX (myindex)) ENGINE=InnoDB;
create table jan_char (data1 varchar(255), data2 int(10), myindex char(6)) ENGINE=InnoDB;
create table jan_char_index (data1 varchar(255), data2 int(10), myindex char(6), INDEX (myindex)) ENGINE=InnoDB;
create table jan_varchar (data1 varchar(255), data2 int(10), myindex varchar(63)) ENGINE=InnoDB;
create table jan_varchar_index (data1 varchar(255), data2 int(10), myindex varchar(63), INDEX (myindex)) ENGINE=InnoDB;

Затем я заполнил 10 миллионов строк в каждой таблице сценарием PHP, суть которого такова:

$pdo = get_pdo();

$keys = [ 'alabam', 'massac', 'newyor', 'newham', 'delawa', 'califo', 'nevada', 'texas_', 'florid', 'ohio__' ];

for ($k = 0; $k < 10; $k++) {
    for ($j = 0; $j < 1000; $j++) {
        $val = '';
        for ($i = 0; $i < 1000; $i++) {
            $val .= '("' . generate_random_string() . '", ' . rand (0, 10000) . ', "' . ($keys[rand(0, 9)]) . '"),';
        }
        $val = rtrim($val, ',');
        $pdo->query('INSERT INTO jan_char VALUES ' . $val);
    }
    echo "\n" . ($k + 1) . ' millon(s) rows inserted.';
}

Для intтаблиц бит ($keys[rand(0, 9)])был заменен на just rand(0, 9), а для varcharтаблиц я использовал полные имена штатов США, не сокращая и не расширяя их до 6 символов.generate_random_string()генерирует случайную строку из 10 символов

Затем я побежал в MySQL:

  • SET SESSION query_cache_type=0;
  • Для jan_intтаблицы:
    • SELECT count(*) FROM jan_int WHERE myindex = 5;
    • SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
  • Для других таблиц, как и выше, с myindex = 'califo'для charтаблиц и myindex = 'california'для varcharтаблиц.

Время BENCHMARKзапроса на каждую таблицу:

  • январь: 21.30 сек
  • jan_int_index: 18,79 с
  • январь: 21,70 сек
  • jan_char_index: 18,85 с
  • январь: 21,76 сек
  • jan_varchar_index: 18,86 с

Что касается размеров таблиц и индексов, вот вывод show table status from janperformancetest;(с несколькими столбцами, которые не показаны):

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Name              | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Collation              |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| jan_int           | InnoDB |      10 | Dynamic    | 9739094 |             43 |   422510592 |               0 |            0 |   4194304 |           NULL | utf8mb4_unicode_520_ci |  
| jan_int_index     | InnoDB |      10 | Dynamic    | 9740329 |             43 |   420413440 |               0 |    132857856 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_char          | InnoDB |      10 | Dynamic    | 9726613 |             51 |   500170752 |               0 |            0 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_char_index    | InnoDB |      10 | Dynamic    | 9719059 |             52 |   513802240 |               0 |    202342400 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_varchar       | InnoDB |      10 | Dynamic    | 9722049 |             53 |   521142272 |               0 |            0 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_varchar_index | InnoDB |      10 | Dynamic    | 9738381 |             49 |   486539264 |               0 |    202375168 |   7340032 |           NULL | utf8mb4_unicode_520_ci | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

Мой вывод заключается в том, что для этого конкретного варианта использования нет разницы в производительности.

Ян Жаньковский
источник
Я знаю, что уже поздно, но мне было бы любопытно увидеть результаты, если бы вы выбрали менее идеальную строку для условия «где». «califo [rnia]» был идеальным, так как он мог отбрасывать несоответствия после сравнения первого символа, только нужно проверять дальнейшие совпадения; что-то вроде «newham» дало бы более интересные результаты, так как было бы новостью сравнивать больше символов, чтобы устранить все несоответствия. Кроме того, ограничение ваших целых чисел таким образом также складывает шансы против них, я бы дал им как минимум 26 значений.
Uueerdo
15
Удивительно, что в 10-летнем вопросе это только один из двух ответов, который не просто спекуляция и основывается на реальных критериях.
Адриан Бейкер
1
Но у ваших таблиц нет первичного ключа, который на самом деле в InnoDB представляет собой сортированную структуру данных. Скорость между целочисленной сортировкой и сортировкой строк должна быть разной.
Мелькор
1
@Melkor Честная точка зрения, которую я использую INDEXвместо PRIMARY KEY. Я не помню свои рассуждения - я, вероятно, предположил, что PRIMARY KEYэто просто INDEXограничение уникальности. Тем не менее, читая раздел о том, как вещи хранятся в InnoDB в federico-razzoli.com/primary-key-in-innodb , я думаю, что мои результаты по-прежнему применимы к первичным ключам, и отвечаю на вопрос о разнице в производительности поиска значений. Кроме того, ваш комментарий предлагает посмотреть на производительность алгоритмов сортировки , которые не относятся к исследуемому сценарию использования, который ищет значения в наборе.
Ян Янковский
1
Операция поиска также требует сравнения в поле первичного ключа (например, двоичный поиск), где int должен быть немного быстрее, чем varchar. Но, как показали ваши эксперименты, это не так очевидно (или, возможно, потому что у вас не было первичного ключа, поэтому все запросы были медленнее). Я думаю, что это то же самое при вставке и поиске.
Мелькор
38

Зависит от длины. Если varchar будет 20 символов, а int равно 4, то, если вы используете int, ваш индекс будет иметь ПЯТЬ раз больше страниц на страницу индексного пространства на диске ... Это означает, что обход Индекс потребует одну пятую от физического и / или логического чтения.

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

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

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

Чарльз Бретана
источник
Конечно? Arent большинство форматов данных на основе строк? Есть и другие данные, кроме ключей. Не является ли фактор 5 утопическим?
ManuelSchneid3r
1
@ manuelSchneid3r, что? утопично? Нет, фактор 5 не является «утопическим». Это просто 20, деленное на 4. И что означает «на основе строки формата данных»? Индексы не основаны на строках, они представляют собой сбалансированные древовидные структуры.
Чарльз Бретана
36

Точно нет.

Я сделал несколько ... несколько ... проверок производительности между INT, VARCHAR и CHAR.

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

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

Тимоти Хоури
источник
42
бессмысленно, не зная, как долго были varchars ... Если бы они имели ширину 100 байт, то гарантировали, что вы не получите такую ​​же производительность, как 4-байтовый int
Чарльз Бретана
6
Это также поможет узнать, какую базу данных вы используете и какую версию базы данных. Настройка производительности почти всегда работала и улучшалась от версии к версии.
Дейв Блэк,
VARCHAR определенно имеет значение для размера индекса. И индекс определяет, сколько может поместиться в памяти. И индексы в памяти намного, намного быстрее, чем те, которые нет. Возможно, для ваших 10-метровых строк у вас было 250 МБ памяти, доступной для этого индекса, и все было в порядке. Но если у вас есть 100-метровые ряды, вам будет не так хорошо в этой памяти.
Пол Дрэйпер,
9

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

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

Джоэл Коухорн
источник
2
Вы знаете наверняка, что это будет дорого? Или ты просто угадаешь?
Стив Маклеод
Конечно, это зависит от реализации rdbms, но из того, что я понимаю, большинство серверов сохраняют хэш фактического значения для целей индексации. Несмотря на это, и даже если это относительно короткий хэш (скажем, 10 байт), все равно лучше сравнить 2 10 байтовых хешей, чем 2 4 байтовых.
Джоэл Коухорн
НИКОГДА не используйте длинный (широкий) ключ для объединений ... Но если это лучшее представление о том, что является уникальным для строк в таблице, то лучше использовать уникальный ключ (или индекс - это то же самое) на таблица с использованием этих естественных ценностей. Ключи не для соединений, вы можете присоединиться к любому желанию вашего сердца. Есть ключи для обеспечения согласованности данных.
Чарльз Бретана
6

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

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

Недостатком использования суррогата является то, что вы можете разрешить изменение значения суррогата:

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

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

LeppyR64
источник
3

Распространенные случаи, когда суррогатная AUTO_INCREMENTболит

Распространенным шаблоном схемы является отображение «многие ко многим» :

CREATE TABLE map (
    id ... AUTO_INCREMENT,
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(id),
    UNIQUE(foo_id, bar_id),
    INDEX(bar_id) );

Производительность этого шаблона намного лучше, особенно при использовании InnoDB:

CREATE TABLE map (
    # No surrogate
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(foo_id, bar_id),
    INDEX      (bar_id, foo_id) );

Зачем?

  • Вторичные ключи InnoDB нуждаются в дополнительном поиске; переместив пару в ПК, этого можно избежать в одном направлении.
  • Вторичный индекс "покрытие", поэтому он не нуждается в дополнительном поиске.
  • Эта таблица меньше из-за избавления от idодного индекса.

Другой случай ( страна ):

country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii

Слишком часто новичок нормализует country_code в 4 байта INTвместо использования «естественной» 2-байтовой, почти неизменной 2-байтовой строки. Быстрее, меньше, меньше СОЕДИНЕНИЙ, более читабельно.

Рик Джеймс
источник
2

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

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

Герман Дж. Радтке III
источник
2

Я столкнулся с той же дилеммой. Я сделал DW (схему Созвездия) с 3 таблицами фактов: Дорожно-транспортные происшествия, Транспортные средства при авариях и Несчастные случаи при авариях. Данные включают все несчастные случаи, зарегистрированные в Великобритании с 1979 по 2012 год, и 60 таблиц измерений. Всего около 20 миллионов записей.

Связи таблиц фактов:

+----------+          +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1      * +----v----+
     1|                    |1
      |    +----------+    |
      +---<| Casualty |>---+
         * +----------+ *

RDMS: MySQL 5.6

По сути, индекс несчастных случаев - это varchar (цифры и буквы) с 15 цифрами. Я старался не иметь суррогатных ключей, как только индексы аварий никогда не изменятся. На компьютере i7 (8 ядер) DW стал слишком медленным для запроса после 12 миллионов записей загрузки в зависимости от размеров. После долгих переделок и добавления суррогатных ключей bigint я получил увеличение скорости в среднем на 20%. Тем не менее, к низкой производительности, но действительная попытка Я работаю в настройке MySQL и кластеризации.

Диего Дуарте
источник
1
Звучит так, будто вам нужно обратить внимание на разделы.
jcoffland
2

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

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

Дело в том, что процессор имеет дело с 4-байтовыми и 8-байтовыми целыми числами, естественно, в кремнии . Сравнение двух целых чисел ДЕЙСТВИТЕЛЬНО быстро - это происходит за один или два такта.

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

Мое общее правило - каждый первичный ключ должен быть автоинкрементным INT, особенно в OO-приложениях, использующих ORM (Hibernate, Datanucleus и т. Д.), Где есть много связей между объектами - они обычно всегда будут реализованы как простой FK и возможность для БД для их быстрого решения важен для отзывчивости вашего приложения.

Volksman
источник
0

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

Dexygen
источник
0

Как обычно, нет общих ответов. 'Это зависит!' и я не шучу Мое понимание исходного вопроса заключалось в том, что ключи в небольших таблицах - например, страна (целочисленный идентификатор или код char / varchar) - являются внешним ключом для потенциально огромной таблицы, такой как таблица адресов / контактов.

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

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

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

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

Винод
источник
0

Позвольте мне сказать «да», безусловно, есть разница, учитывая объем производительности (определение «из коробки»):

1- Использование суррогата int быстрее в приложении, потому что вам не нужно использовать ToUpper (), ToLower (), ToUpperInvarient () или ToLowerInvarient () в вашем коде или в вашем запросе, и эти 4 функции имеют разные показатели производительности. См. Правила производительности Microsoft по этому вопросу. (выполнение приложения)

2 - Использование суррогата int гарантирует, что ключ не изменится с течением времени. Даже коды стран могут измениться, см. Википедию, как коды ISO менялись со временем. Это займет много времени, чтобы изменить первичный ключ для поддеревьев. (производительность обслуживания данных)

3. Кажется, есть проблемы с решениями ORM, такими как NHibernate, когда PK / FK не int. (производительность разработчика)

Шади Намроути
источник