Строки как первичные ключи в базе данных SQL

178

Я не очень знаком с базами данных и теориями о том, как они работают. С точки зрения производительности (вставка / обновление / запрос) медленнее использовать строки для первичных ключей, чем целые числа?

mainstringargs
источник

Ответы:

192

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

kemiller2002
источник
11
не будет ли это зависеть от базы данных? Я думаю, что правильно проиндексированная строка не будет намного медленнее, если вообще из числа?
Райан Гилл
2
Я бы согласился, что есть много переменных для рассмотрения. (В sqlserver) мы сталкивались с реальными проблемами производительности при использовании строк с длинами от среднего до старшего и выше даже при индексации. Если вы правы, есть вещи, которые нужно преодолеть, например, это оборудование.
kemiller2002
1
Справедливо. Я согласен с тем, что если строка имеет смысл, это то, что вы должны использовать. Я также сказал бы, что в полях GUID или UUID определенно есть время, когда поле автоинкремента не будет работать.
Райан Гилл
7
Также имейте в виду, что при сравнении индексов часто существует большая разница между CHAR и VARCHAR
Том Х
7
Количество комментариев этого ответа дает понять, насколько он неполный. Упоминание индексации было бы минимально приемлемым ответом.
Педро Роло
75

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

Джефф Мартин
источник
2
Это может вызвать «горячие точки» для новых вставок. Если вы правильно управляете своей базой данных, у вас должно быть дополнительное пространство на страницах для вставок, и разбиение страниц должно быть редким.
Том Х
20
это когда первичные ключи кластеризованы. Вы можете создавать их и без кластеров.
Обучение
Заказываются XID, которые могут помочь, если вы просто используете строки
xid
22

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

Марк Томпсон
источник
Хорошее объяснение. Но верно ли это для всех баз данных SQL? Я слышал о проблемах производительности MySQL при использовании случайного UUID в качестве первичного ключа.
hgoebl
13

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

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

HLGEM
источник
26
Строки, которые являются хорошими кандидатами на PK, не имеют дубликатов, иначе они не будут хорошим кандидатом на PK. Подумайте о кодах ICD-9, кодах стран, VIN #. Использование имени в качестве примера проблемы с естественными ключами ошибочно, потому что они никогда не должны быть кандидатами в первую очередь.
Том Х
6
@Tom H: коды округа ISO меняются. [ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ] В ответ на связанный вопрос сказал [ stackoverflow.com/questions/925266/… ] «Для PRIMARY KEY убедитесь, что их уникальность находится под вашим контролем»
Стив Шнепп
4
@SteveSchnepp: да, и ISO является доверенным органом для управления этими изменениями. С другой стороны, когда вам нужно объединить свою монотонную последовательность приращения целочисленных значений с чужой, вы сами по себе;)
onedaywhen
1
Я согласен с тем, что имена не должны рассматриваться как ключевые, я только что видел их во времена, когда они были.
HLGEM
1
@onedaywhen слияние 2 монотонной последовательности возрастающего целого числа довольно легко сделать с помощью префикса или суффикса :)
Steve Schnepp
6

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

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

Аль Катавази
источник
5

Слишком много переменных. Это зависит от размера таблицы, индексов, характера строкового ключа домена ...

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

Кроме того, какова ваша мотивация для выбора строк? Цифровые автоинкрементные клавиши часто также намного проще . Это семантика? Удобство? Репликация / отключенные проблемы? Ваш ответ может ограничить ваши возможности. Это также напоминает о третьем «гибридном» варианте, который вы забыли: направляющие.

Джоэл Коухорн
источник
это не имеет никакого смысла, что ты имеешь в виду?
HLGEM
@HLGEM: Если я понимаю, что он пишет, он подразумевает синхронизацию записей, созданных на ноутбуке с основной базой данных.
Джоэл Коухорн
Я имею в виду, что у меня есть две отдельные базы данных с одинаковыми сущностями, только одна обновляется реже для целей постоянного хранения. Если я запрашиваю сущность «Калифорния» в базе данных А, я хочу, чтобы она была в основном той же «Калифорнией» в базе данных Б.
mainstringargs
1
И это похоже на синхронизацию записей, созданных на ноутбуке, в том, что проблема та же: записи, созданные в одном месте, не должны конфликтовать с записями, созданными в другом. Одним из возможных решений здесь являются ключи Guid.
Джоэл Коухорн
5

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

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

Всегда ли люди, занимающиеся вводом данных, или автоматические источники данных предоставляют значение для предполагаемого естественного ключа или иногда не указываются? Это иногда неправильно во входных данных? Если да, то как ошибки обнаруживаются и исправляются?

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

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

Уолтер Митти
источник
3

Индексы подразумевают множество сравнений.

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

Иногда, однако, быстрее использовать строку в качестве первичного ключа, чем сделать дополнительное соединение с string to numerical idтаблицей.

Quassnoi
источник
2

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

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

Да, это Джейк.
источник
2

Две причины использовать целые числа для столбцов PK:

  1. Мы можем установить идентичность для целочисленного поля, которое увеличивается автоматически.

  2. Когда мы создаем PK, база данных создает индекс (Cluster или Non Cluster), который сортирует данные до их сохранения в таблице. Используя идентификатор на ПК, оптимизатору не нужно проверять порядок сортировки перед сохранением записи. Это улучшает производительность на больших столах.

Джатиндер Сингх
источник
1

Какова причина того, что строка является первичным ключом?

Я бы просто установил первичный ключ в поле целочисленного автоматического увеличения и поместил индекс в строковое поле.

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

Вы также можете контролировать количество строкового поля, которое индексируется. Другими словами, вы можете сказать «индексировать только первые 5 символов», если считаете, что этого будет достаточно. Или, если ваши данные могут быть относительно похожими, вы можете проиндексировать все поле.

Джон Бубриски
источник
3
Я думаю, что любой разум в ключе напрашивается на неприятности. Будут ли они оставаться уникальными? Начали ли они все номера счетов с аббревиатуры штата в начале только для перемещения клиента. Обновить поле - нет проблем - все эти таблицы связаны по номеру счета - что за беспорядок.
Джефф
1
Примером использования строки в качестве PK может быть таблица настроек. Например, settingNamePK, isUserEditable, isCustomerEditable и т. д. Затем, если вы хотите изменить поведение настройки «UPDATE setting SET ... WHERE settingNamePK = 'dailyWorkObligation'», это намного приятнее, чем необходимость использовать идентификаторы и хранить где-то отображение идентификаторов. Конечно, у вас может быть целое число PK и имя настройки в качестве еще одного уникального ключа.
MeatPopsicle
С первичным ключом, являющимся автоинкрементным целым числом, разве вставки не должны также быть затронуты в их скорости?
Деннис
Для любопытных разработчиков Rails, вот как указать длину индекса . Обратите внимание, что SQLite не поддерживает длину индекса.
Деннис
1

С точки зрения производительности - Да, строка (PK) замедлит производительность по сравнению с производительностью, достигнутой с помощью целого числа (PK), где PK ---> Первичный ключ.

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

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


источник
0

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

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

takacsot
источник
0

По умолчанию ASPNetUserIds 128 строк символов и производительность просто отличная.

Если ключ HAS быть уникальным в таблице , она должна быть ключом. Вот почему;

первичный строковый ключ = правильные связи с БД, 1 строковый ключ (первичный) и 1 строковый индекс (первичный).

Другим вариантом является типичный int Key, но если строка HAS должна быть уникальной, вам все равно, вероятно, потребуется добавить индекс из-за непрерывных запросов для проверки или проверки ее уникальности.

Таким образом, использование ключа идентификации int = Неверные отношения с БД, 1 ключ int (основной), 1 индекс int (основной), вероятно, уникальная строка Index, и необходимость вручную проверять ту же строку не существует (что-то вроде проверки sql может быть ).

Для того, чтобы получить более высокую производительность , используя Int над строкой для первичного ключа, когда строка ДОЛЖНА быть уникальным, он должен быть очень странная ситуация. Я всегда предпочитал использовать строковые ключи. И как хорошее правило, не денормализовать базу данных , пока не НУЖНО к.

JPoole
источник