Струни як первинні ключі в базі даних SQL


178

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

Відповіді:


191

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


11
не залежало б це від бази даних? Я думаю, що правильно індексований рядок не буде настільки повільнішим, якби взагалі з числа?
Райан Гілл

2
Я погоджуюся, що існує багато змінних. (У sqlserver) ми бачили реальні проблеми з використанням продуктивних рядків із довжиною в середньому та високому підлітковому віці та вище, навіть коли їх індексували. Придбайте, що ви праві, наприклад, є речі, які можна подолати.
kemiller2002

1
Досить справедливо. Я погодився б, що якщо рядок має сенс, саме це вам слід використовувати. Я б також сказав, що визначено час для полів GUID або UUID в базах даних, де поле для самовдосконалення не працюватиме.
Райан Гілл

7
Також майте на увазі, що часто існує різниця між CHAR і VARCHAR при порівнянні індексів
Том H

7
Кількість коментарів до цієї відповіді дає зрозуміти, наскільки вона неповна. Згадування індексації було б мінімально прийнятною відповіддю.
Педро Роло

74

Інша проблема використання Strings як первинного ключа полягає в тому, що тому, що індекс постійно вводиться в послідовний порядок, коли створюється новий ключ, який був би посередині порядку, індекс повинен бути повторно встановлений ... якщо ви використовуєте auto число ціле, новий ключ просто додається в кінці індексу.


2
Це може викликати "гарячі точки" для нових вставок. Доки ви належним чином керуєте своєю базою даних, у вас все одно має бути додаткового місця для вставок, а розбиття сторінок має бути рідкісним.
Том Х

20
тобто коли кластеризуються первинні ключі. їх можна створити і без кластеру.
Навчання

Упорядковано XID, що може допомогти, якщо ви просто використовуєте рядки
Xid

22

Вставки до таблиці, що має кластерний індекс, де вставка відбувається посередині послідовності, НЕ призводить до переписування індексу. Це не призводить до перезаписування сторінок, що містять дані. Якщо на сторінці є місце, куди буде йти рядок, він розміщується на цій сторінці. Одну сторінку буде переформатовано, щоб розмістити рядок у потрібному місці на сторінці. Коли сторінка заповнена, відбудеться розбиття сторінки, при цьому половина рядків на одній сторінці, а половина - на іншій. Потім сторінки повторно пов’язуються у пов'язаний список сторінок, що містять дані таблиць із кластерним індексом. Щонайбільше, ви закінчите писати 2 сторінки бази даних.


Гарне пояснення. Але чи справедливо це для всіх баз даних SQL? Я чув про проблеми продуктивності MySQL під час використання випадкового UUID в якості основного ключа.
hgoebl

13

Струни приєднуються повільніше, і в реальному житті вони дуже рідко бувають унікальними (навіть коли вони повинні бути). Єдина перевага полягає в тому, що вони можуть зменшити кількість приєднань, якщо ви приєднаєтесь до первинної таблиці лише для отримання імені. Однак рядки також часто можуть бути змінені, що створює проблему необхідності виправляти всі пов'язані записи, коли змінюється назва компанії або людина виходить заміж. Це може бути величезним враженням від продуктивності, і якщо всі таблиці, які повинні бути пов’язані якимось чином, не пов’язані між собою (це трапляється частіше, ніж ви думаєте), то у вас можуть бути і невідповідність даних. Ціле число, яке ніколи не зміниться протягом життя запису, є набагато безпечнішим вибором як з точки зору цілісності даних, так і з точки зору продуктивності. Натуральні ключі, як правило, не такі хороші для підтримки даних.

Я також хочу зазначити, що найкраще в обох світах - це використовувати ключ самовстановлення (або в деяких спеціалізованих випадках GUID) як ПК, а потім поставити унікальний індекс на природний ключ. Ви швидше приєднуєтесь, ви не отримуєте дублікатів записів, і вам не доведеться оновлювати мільйон дочірніх записів, оскільки змінено назву компанії.


26
Рядки, які є хорошими кандидатами в ПК, не мають дублікатів - інакше вони не були б хорошим кандидатом у ПК. Подумайте про коди ICD-9, коди країн, VIN #. Використання імені як прикладу проблеми з природними ключами є помилковим, оскільки вони ніколи не повинні бути кандидатами в першу чергу.
Том H

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 монотонних послідовностей наростаючого цілого числа досить легко виконати за допомогою префіксації або суфікса :)
Стів Шнепп

6

Не має значення, що ви використовуєте в якості основного ключа, якщо це УНІКАЛЬНО. Якщо ви турбуєтесь про швидкість або хороший дизайн бази даних, використовуйте int, якщо ви не плануєте реплікацію даних, то використовуйте GUID.

Якщо це база даних або якесь крихітне додаток, то кому це дійсно все одно. Я думаю, що причина, чому більшість з нас розробників ляпає по старому int або guide на передній панелі, полягає в тому, що проекти мають на шляху зростання до нас, і ви хочете залишити собі можливість рости.


5

Занадто багато змінних. Це залежить від розміру таблиці, індексів, характеру ключового домену рядка ...

Як правило , цілі числа будуть швидшими. Але чи буде різниця достатньо великою для догляду? Важко сказати.

Також яка ваша мотивація вибору струн? Числові клавіші автоматичного збільшення також часто набагато простіші . Це семантика? Зручність? Реплікація / відключені проблеми? Ваша відповідь тут може обмежити ваші варіанти. Це також враховує третій "гібридний" варіант, який ви забуваєте: Настанови.


це не має сенсу клотірм, що ви маєте на увазі?
HLGEM

@HLGEM: Якщо я розумію, що він пише, він має на увазі, як синхронізацію записів, створених на ноутбуці з основним db.
Joel Coehoorn

Я маю на увазі, що у мене є дві окремі бази даних з тими ж об'єктами, лише одна оновлюється рідше для цілей постійного зберігання. Якщо я запитую суб’єкт "Каліфорнія" в базі даних A, я хочу, щоб він був принципово таким же "Каліфорнія" в базі даних B.
mainstringargs

1
І це «як» синхронізація записів, створених на ноутбуці, в тому, що це та сама проблема: записи, створені в одному місці, не повинні суперечити записам, створеним в іншому. Одним з можливих варіантів рішення тут є Guid ключі.
Joel Coehoorn

5

Не турбуйтеся про ефективність, поки у вас не буде простий і надійний дизайн, який відповідає з предметом, який описують дані, і добре відповідає цільовому використанню даних. Потім, якщо виникають проблеми з продуктивністю, ви можете вирішити їх, налаштувавши систему.

У цьому випадку майже завжди краще перейти з рядком як природним первинним ключем, якщо ви можете довіряти цьому. Не хвилюйтесь, якщо це рядок, якщо рядок досить короткий, скажімо, про максимум 25 символів. Ви не заплатите велику ціну з точки зору продуктивності.

Чи завжди люди, що вводять дані, або автоматичні джерела даних забезпечують значення для передбачуваного природного ключа або іноді його не вистачає? Чи іноді неправильно у вхідних даних? Якщо так, то як виявляються та виправляються помилки?

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

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


3

Індекси означають безліч порівнянь.

Як правило, рядки довші, ніж цілі числа, і правила порівняння можуть застосовуватися для порівняння, тому порівняння рядків зазвичай є більш обчислювально завданням, ніж порівняння цілих чисел.

Однак іноді швидше використовувати рядок як основний ключ, ніж додаткове з'єднання з string to numerical idтаблицею.


2

Так, але якщо ви не плануєте мати мільйони рядків, не використовуючи рядок на основі клавіш, оскільки це повільніше, як правило, це "передчасна оптимізація". Зрештою, рядки зберігаються як великі числа, тоді як числові клавіші зазвичай зберігаються як менші числа.

Однак слід поглянути на те, якщо у вас є кластеризовані індекси на будь-якій клавіші і ви робите велику кількість вставок, які не є послідовними в індексі. Кожен написаний рядок призведе до повторного запису індексу. якщо ви робите пакетні вставки, це дійсно може сповільнити процес.


2

Дві причини використовувати цілі числа для стовпців ПК:

  1. Ми можемо встановити ідентичність для цілого поля, яке збільшується автоматично.

  2. Коли ми створюємо ПК, db створює індекс (кластер або не кластер), який сортує дані, перш ніж вони зберігаються в таблиці. Використовуючи ідентифікацію на ПК, оптимізатору не потрібно перевіряти порядок сортування перед збереженням запису. Це покращує продуктивність на великих столах.


1

Яка ваша причина наявності рядка в якості основного ключа?

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

Таким чином, якщо ви здійснюєте пошук за столом, вони повинні бути відносно швидкими, і всі ваші приєднання та звичайні перегляди не впливатимуть на їх швидкість.

Ви також можете контролювати кількість рядкового поля, яке індексується. Іншими словами, ви можете сказати "лише індексуйте перші 5 символів", якщо ви думаєте, що цього буде достатньо. Або якщо ваші дані можуть бути відносно схожими, ви можете проіндексувати все поле.


3
Я думаю, що поставити будь-яку розвідку в ключ - це попросити неприємностей. Чи залишаться вони унікальними? Чи розпочали вони всі номери рахунків з абревіатурою штату на початку лише до переходу клієнта. Оновіть поле - немає проблем - всі ті таблиці, пов’язані за номером рахунку - який безлад.
JeffO

1
Прикладом використання рядка як ПК може бути таблиця налаштувань. наприклад, settingNamePK, isUserEditable, isCustomerEditable і т. д. Тоді, якщо ви хочете змінити поведінку налаштування "UPDATE налаштування SET ... WHERE settingNamePK = 'dailyWorkObligation'" набагато приємніше, ніж використовувати ідентифікатори та зберігати десь зіставлення ідентифікаторів. Звичайно, у вас може бути ціле ПК і мати назву параметра як інший унікальний ключ.
MeatPopsicle

Оскільки основним ключем є ціле число з автоматичним збільшенням, чи не повинні вставки також впливати на їх швидкість?
Денніс

Для допитливих розробників Rails, ось як вказати довжину індексу . Зауважте, що SQLite не підтримує довжину індексу.
Денніс

1

З точки зору продуктивності - Так, рядок Yes (PK) уповільнить продуктивність порівняно з продуктивністю, досягнутою за допомогою цілого числа (PK), де PK ---> Первинний ключ.

З точки зору вимоги - Хоча це не є частиною вашого питання, я все ж хотів би зазначити. Коли ми обробляємо величезні дані в різних таблицях, ми зазвичай шукаємо ймовірний набір ключів, який можна встановити для певної таблиці. Це перш за все тому, що існує багато таблиць, і здебільшого кожна чи якась таблиця буде пов'язана з іншою через якесь відношення (концепція Зовнішнього ключа). Тому ми не завжди можемо вибрати ціле число в якості первинного ключа, а скористаємося комбінацією 3, 4 або 5 атрибутів як основного ключа для цих таблиць. І ці клавіші можна використовувати як зовнішній ключ, коли ми будемо співвідносити записи з якоюсь іншою таблицею. Це робить корисним зв'язок записів у різних таблицях, коли це потрібно.

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


0

Можливо, буде дуже велике непорозуміння, пов'язане з рядком у базі даних. Майже всі подумали, що представлення баз даних чисел більш компактне, ніж для рядків. Вони думають, що в db-s числа представлені як у пам'яті. АЛЕ це неправда. У більшості випадків представлення чисел ближче до рядка, як представлення, як для інших.

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


0

За замовчуванням ASPNetUserIds - це 128 рядків, а продуктивність просто чудова.

Якщо ключ ТАКЕ бути унікальним у таблиці, він повинен бути Ключем. Ось чому;

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

Інший варіант - це типовий int Key, але якщо рядок HAS бути унікальною, вам, ймовірно, потрібно буде додати індекс через запити non-stop, щоб перевірити чи перевірити його унікальність.

Отже, використовуючи ключ ідентичності int = Неправильні відносини БД, 1 ключ int (первинний), 1 інт індекс (первинний), ймовірно, унікальний рядок індекс, і вручну, щоб перевірити ту саму рядок, не існує (щось на зразок перевірки sql можливо ).

Для отримання кращої продуктивності за допомогою int над рядком для первинного ключа, коли рядок МАЄ бути унікальним, це повинно бути дуже дивною ситуацією. Я завжди вважав за краще використовувати рядкові клавіші. І як хороше правило, не денормалізовать базу даних , поки не потрібно к.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.