Существует ли реальная разница в производительности между первичными ключами INT и VARCHAR?

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

INT AUTO_INCREMENT соответствует условию "уникальное и неизменное по времени". Следовательно, предпочтение.

Ответ 3

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

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

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

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

Ответ 4

Абсолютно нет.

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

10 миллионов записей с PRIMARY KEY (уникальные и сгруппированные) имели ту же скорость и производительность (и стоимость поддерева) независимо от того, какой из трех я использовал.

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

Ответ 5

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

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

Ответ 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

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

Ответ 7

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

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

Ответ 8

Общие случаи, когда суррогат 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 нуждаются в дополнительном поиске; путем перемещения пары в PK, что предотвращается в одном направлении.
  • Вторичный индекс "покрывает", поэтому он не нуждается в дополнительном поиске.
  • Эта таблица меньше из-за избавления от id и одного индекса.

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

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

Слишком часто новичок нормализует country_code в 4-байтовый INT вместо использования "естественной" 2-байтовой, почти неизменной 2-байтовой строки. Быстрее, меньше, меньше JOINs, более читабельны.

Ответ 9

Эта статья посвящена Oracle, но она, вероятно, применима.

Ответ 10

Я столкнулся с той же дилеммой. Я сделал 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%. Тем не менее, к низкой производительности, но действуйте. Im работает в настройках и кластеризации MySQL.

Ответ 11

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

Ответ 12

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

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

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

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

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

Ответ 13

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

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

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

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

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