Чому використання рядкових клавіш взагалі вважається поганою ідеєю?


24

Це мене клопоче вже деякий час. Здебільшого, коли мова йде про зберігання даних у таких структурах, як хештелі, програмісти, книги та статті, наполягають, що індексація елементів у зазначених структурах за значеннями String вважається поганою практикою. Але поки що я не знайшов жодного такого джерела, щоб також пояснити, ЧОМУ це вважається поганою практикою. Це залежить від мови програмування? За основу? Про реалізацію?

Візьміть два прості приклади, якщо це допомагає:

Таблиця, схожа на SQL, де рядки індексуються первинним ключем String.

Словник .NET, де ключами є рядки.


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

3
Зазвичай вам потрібні первинні ключі, які не змінюються протягом життя об'єкта / рядка. Так, наприклад, usernameяк основний ключ usersтаблиці, мабуть, не найкраща ідея, і ви віддаєте перевагу ідентифікатор автоматичного збільшення. Але usernameце рядок є лише випадковим, головне питання
змінне властивість

У базі даних подумайте, як би індексувати рядки на відміну від цілих чисел.

@CodesInChaos Я б хотів, щоб я пам'ятав, де я знайшов більшість справ, але поки що я можу вставити біт, який нагадав мені про проблему. Саме з слайд-шоу GDC від Valve обговорювали ігрові діалоги та зберігали факти про світ у парах <key = string, value = object>.

2
Струни добре. Тільки не «магічні» струни. Отже, використовуючи хеш-таблицю, переконайтеся, що у вас немає голих рядків у вашому коді. Ви повинні уникати великих текстових значень як ключів, оскільки вони не працюють добре, але в більшості реальних ситуацій короткий текстовий рядок такий же швидкий, як ціле число (вони не є масовими базами даних). Ви також можете використовувати альтернативні ключі, наприклад, первинний ключ - це номер, але є також "slug" або унікальна рядок, яка також є унікальною.
ipaul

Відповіді:


17

Це в основному стосується двох речей:

1) Швидкість пошуку (де, наприклад, цілі числа проходять набагато краще)

2) розмір індексів (де рядкові індекси вибухнуть)

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

PS Може не стосуватися вашого питання, але Посібники вважаються поганими і для ключів бази даних (16 байт Guid проти 4-байтових цілих чисел). На великих обсягах даних посібники сповільнюють пошук.


Не завжди - можливі додаткові GUID. Індекси все ще будуть більшими, але покарання при пошуку не буде майже таким же поганим.
Сам

7
Насправді вони прекрасні. Ви повинні подивитися на зв’язок між часом вводу-виводу диска часу та порівнянням значень у пам'яті. Оскільки час доступу до диска переповнює порівняння пам’яті, єдине, що дійсно має значення при аналізі продуктивності бази даних, це IO. Незалежно від того, чи є ключем GUID, рядок або ціле число, насправді не важливо. Розмір індексу впливає на кількість значень індексу на одній сторінці, але чи ключ є 4-байтним int (який може бути недостатньо великим і не може бути сформований клієнтом) або 16-байтне значення не викликає особливих проблем. У деяких базах даних розмір rowId може бути розміром 16 байт.
ipaul

9

Є ще одна проблема використання рядків як клавіш або, точніше, використання рядкових літералів як ключів, відміняючи чисті причини ефективності / ефективності. Друкарські помилки. Якщо ви використовуєте рядкові літерали як ключі в словнику, ви налаштовуєте себе на неприємний сюрприз, коли людина "ReceiverId"стає а "RecieverId". Налаштуйте константи для зберігання ключових значень та повторного використання їх щоразу, коли ви отримуєте доступ до словника.

Можна сказати, тривіально і очевидно, але надзвичайна кількість прикладів .NET коду в Інтернеті використовує рядкові літерали, що поширюють цю сумнівну практику. Тут особливо винним є ASP.NET з усіма сесіями, ViewStates та QueryParams, що розповсюджуються по всій кодовій базі.


Не банальний ІМХО. Я також бачив випадки, коли є ключі "1"та "1 "в одній таблиці.
pswg

Будьте ще кумедніші, коли ви кидаєте чутливість корпусу і в суміш. Побачені навантаження людей, включаючи мене, натрапляють прямо на це.
Тоні Хопкінсон

Навіть краще, ніж використовувати константи, принаймні, в C #, замість цього, використовується вирази. Таким чином ви можете генерувати свої рядки з назв методів / властивостей тощо, щоб ваші пошукові рядки стали типовими і безпечними для рефакторів.
GoatInTheMachine

4

Тут є багато компромісів. Насправді я часто використовую рядкові клавіші, але часто я включаю сурогатні вторинні ключі для приєднання (очевидно, це було б навпаки, якби я використовував MySQL). Є випадки, коли я цього не роблю.

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

З двох причин я зазвичай додаю сурогатні ключі:

  1. Не завжди зрозуміло, що таке природний ключ. Іноді їх доводиться змінювати. Зміна природного складеного ключа, коли він використовується для з'єднання та референтної цілісності, є складним та схильним до помилок.

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

У тих випадках, коли природний ключ є остаточним, одинарним стовпцем та текстом, я зазвичай приєднуюся до рядкового ключа. Моя причина для цього полягає в тому, що це часто уникає приєднань під час пошуку. Найбільш поширене використання - це надання належного дизайну db навколо випадку використання типів enum. У більшості випадків вони не потребують додаткового з'єднання для звичайних запитів. Отже, де це так, строкові клавіші як клавіші з'єднання мають ідеальний сенс.

Наприклад, у LedgerSMB ми зберігаємо категоризацію облікових записів. Вони ідентифікуються за допомогою рядкової посилання. Єдиний час, коли потрібна логіка - це збереження набору категоризацій, тому ми приєднуємось до рядкового ключа.

Щодо того, чому за замовчуванням будуть цілі клавіші, я не думаю, що це лише питання розміру індексу. Велике питання - управління ключами. Оскільки ключ довільний і ви можете мати справу з мільйонами записів, ви повинні мати спосіб створення унікальних рядків. Бувають випадки, коли люди використовують для цього UUID, але існує ненульовий шанс зіткнення UUID, і коли зберігаються мільярди записів, цей шанс стає достатньо високим, який можна насправді побачити, тоді як шанс зіткнення з інкремованими цілими типами дорівнює нулю за визначенням.


Це не нульове значення, якщо вам вдасться зробити цілий тип обгортання спиною до нуля. Для 32-розрядного типу, який не підписується, це лише 4G, що непомітно близьке до "мільярдів записів" ...
Donal Fellows

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

1

Існує ряд можливих проблем із використанням рядків як ключів, особливо якщо мова йде про таблиці, схожі на sql. Як згадував @bunny, індекси для ваших таблиць будуть більшими, але я думаю, що значно важливіше, що будь-які зовнішні ключові відносини до таблиці включатимуть таблиці BOTH, щоб вони містили рядок на відміну від ідентифікатора легшої ваги (цілого числа) . Якщо ви виявите, що існує ще більше таблиць із посиланнями на першу, рядкові клавіші будуть розповсюджені по всій вашій базі даних.


1

Сама по собі це не погана ідея, як правило, з 20/20 заднього огляду поганий дизайн-компроміс. Гнучкість та діапазон струн проти додаткових витрат та складності.

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


0

Ви якимось чином отримали неправильні дані з Hashtable.

Ви мали на увазі "Телефон дня" або "Вечірній телефон"?

або

Ви мали на увазі 1234567 чи 1234576?

Хоча цифри, напевно, ефективніші для машини , щоразу, коли справи йдуть не так (і вони роблять це), вам подобається, як ви і я, щоб мати сенс того, що трапилося, і, в той момент, заощадження кількох байтів пам’яті та кілька мікро (нано?) - секунди обробки втрачають ясність щоразу.


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

-1

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


2
Ця відповідь не додає нічого, про що вже не було сказано в інших відповідях, що говорить про це краще.
Martijn Pieters

-2

рядовий ключ матиме сенс, якщо мова йде про таблицю пошуку з приблизно 10-100 записами коротких рядків; пов'язані дані є більш читабельними + наприклад, відстеження змін (числовий / ідентифікатор і порівняння рядка, наприклад, "Адміністратор"); btw, база даних ASP.NET членства використовує рядкові ключі для AspNetRoles.

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