Створення вторинного первинного ключа в базі даних для деяких таблиць


22

До деяких моїх таблиць я хочу додати "second_primary_key", який буде uuid або якийсь випадковий довгий ключ. Мені це потрібно, тому що для деяких таблиць я не хочу виставляти цілі числа у своєму веб-додатку. Тобто, на сторінці "/ рахунків-фактур" у мене є список рахунків-фактур і посилання на "/ рахунки /: id", де: id - ціле число. Я не хочу, щоб користувач знав, скільки рахунків-фактур у моїй системі існує, тому замість "/ facs / 123" я хочу використовувати його "second_primary_key", щоб URL-адресою було "/ facs / N_8Zk241vNa"

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

Цікаво, чи це звичайна практика? Який найкращий спосіб здійснити це?

І як називається ця техніка врешті-решт, щоб я здійснив пошук на ній?


20
Чому б взагалі не позбутися цілого числа?
larsbe

4
На столі можна визначити стільки унікальних ключів / покажчиків, скільки вам подобається.
abuzittin gillifirca

2
Можливо, ви повинні назвати це вторинним ключем кандидата. "Первинний" пропонує лише одне.
Вальтер Мітті

4
"Другий первинний" - це оксиморон. У вас є первинний ключ, і ви можете мати вторинні ключі.
Зупиніть шкодити Моніці

7
@RobbieDee є вагомі причини того, що база даних не нормалізується повністю. А наявність кандидата чи вторинного ключа - це не зовсім копіювання даних.
Мачадо

Відповіді:


0

Ви можете додати стовпчик UUID, але насправді не потрібно (і не повинен). Це проблема ступеня презентації. Ви б не мріяли сказати, зберігаючи вартість валюти як 1,999 долара, так і 1999 рік.

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

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

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


48

Наявність "альтернативного первинного ключа" - це добре відома концепція реляційного моделювання баз даних, її називають "альтернативним ключем", а іноді також "вторинним ключем". Набір "потенційних первинних ключів" називається "ключами-кандидатами". Дивіться https://beginnersbook.com/2015/04/alternate-key-in-dbms/

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


11
Я також бачив терміни " Натуральний ключ" та " Сурогатний ключ", який використовується для опису цього сценарію.
DanK

2
@Dari: ви запитали "як називається ця техніка" - жирними літерами. І якщо розшифровка AES - можливо, на льоту - створює ключі того типу, який ви шукаєте, використовуйте його, це не суперечить моїй відповіді.
Док Браун

1
@Dari Оскільки це додає абсолютно непотрібні накладні витрати на ваш додаток
Lamak

1
@RobbieDee Ми вже зрозуміли, що вам не подобаються альтернативні ключі, але це не означає, що вони марні. Мені подобається підхід, спрямований на те, що він спрощує багато проблем.
Т. Сар - Відновлення Моніки

1
@RobbieDee Ми не використовуємо SQL Server. Ми використовуємо MySql. І це відбувається тому, що хтось створить щось на Prod, скажімо, з ідентифікатором 1234. На Dev, природно, ми створюємо набагато більше сутностей, ніж у prod. 1234 р. Давнє підприємство було вивезене на тестування. Коли нам потрібно випробувати об'єкт від prod, ми повинні перенести його назад до Dev - і його первинний ключ вже використовується. Міграція набагато простіша, якщо посилання на цю сутність базуються на керівних принципах. Але сплячий режим працює набагато краще, якщо первинний ключ є int або long, тому ми зберігаємо це. Мої чорти не ліниві чи неосвічені - вони приправлені.
corsiKa

9

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

Користувач може визначити за номером рахунка-фактури кількість клієнтів, які ви обслуговували, або скільки часу минуло до зміни стратегії нумерації рахунків-фактур.

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

Однак я б заблокував рахунок-фактуру за екраном входу користувача, тому не кожен може його вимагати. Потім у користувальницькому вході вони можуть використовувати методологію ajax для запиту своїх непогашених рахунків і т. Д. Це захищає ваші дані, приховує URL-адресу від ajax (зазвичай ніхто не може заважати дивитися деталі того, як будується запит ajax) , і ви керуєте способом відображення та пропонування даних.


7
Загальна стратегія, що застосовується в банківській справі (з чековими номерами) - не починати нарахування додаткового рахунку на 1, а на деяку більшу кількість саме з цієї причини.
DanK

Я думаю, саме тому id повинен бути додатковим первинним ключем, а не заміною старого первинного ключа.
Олександр

1
Я б не назвав це первинним ключем. Я б пішов на слизу, UUID як ім'я, але по суті це просто інше індексоване поле в таблиці. Цитата ідентифікатора, номер рахунку-фактури, Це поле, але не первинний ключ. Первинний ключ повинен бути унікальним і може використовуватися внутрішньо для реляційного відображення. Якщо поле в індексі, його можна швидко шукати за запитом де. userXveryY.where ('invoice_number', 'foobarbaz10'). get ();
Цалалака

1
Ви відповідаєте на технічне запитання аргументом, що він не потрібен через особливості США (потрібні послідовні номери рахунків-фактур, звіти в Торговій палаті). ІМО це не відповідає на питання.
RemcoGerlich

7

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

Він кодує ваш ідентифікатор бази даних у короткий хеш (подібний до URL-адреси відео YouTube), і вам не потрібно буде додавати до таблиці жодні вторинні ключі.


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

2
@ CrazyYoghurt True ... вони вирішили причину іменування його так, як це робили тут: hashids.org/#why-hashids
Ерік Кінг

3

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

Зберігання N_8Zk241vNaкоштує 12 байт на рядок у таблиці та ще більше в індексі. Це досить марно, що потрібно.

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

Зауважте, що з AES ви отримуєте 128-бітове ціле число, що означає 22 символи в base64, ймовірно, більше, ніж ви хочете. Шифр з розміром блоку 64, як DES або 3DES, дає вам 11 символів, як ви хочете.

Використовуйте різні клавіші для різних таблиць.

Якщо все, що вам потрібно, це приховувати розміри таблиць, ви можете використовувати загальну послідовність для всіх таблиць. Зауважте, що це може бути вузьким місцем, якщо в багатьох ваших таблицях є часті вставки. З чимось на кшталт Hibernate та Hi-Lo алгоритму ця проблема зникає.


Точно - зберігати це значення просто для того, щоб приховати інше, просто неправильно.
Роббі Ді

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

як я можу застосувати сюди Aes?
Дарі

@Dari Як можна застосувати AES до чого-небудь ? Не знаючи вашої мови, ніхто не може сказати. Зазвичай AES працює з a byte[], ви можете записати свої idв чотири чи вісім байтів, додати унікальний номер таблиці та шифрувати (вхід повинен бути рівно 16 байт). Якщо є варіанти на вибір, ЄЦБ має рацію.
maaartinus

@DanK Що? Ви стверджуєте, що AES є небезпечним? Не знаючи ключа, зловмисник не може зробити нічого кращого, ніж для збереженого атрибута. Нічого. +++ Я думаю, я не розумію ваш коментар.
maaartinus

0

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

Тому я пропоную розмістити його там, але мати його лише з індексом. Ви можете створити обробний компонент для запиту даних PK, а також інші унікальні стовпці. Під час обробки запиту на "/ facs / ..." просто перевірте параметр - якщо він є цілим числом, знайдіть ідентифікатор, інакше шукайте uuid. Або ви можете мати пошук uuid як резервний, коли пошук за допомогою ідентифікатора нічого не знайшов.

А щодо генерування деяких "випадкових" uuids: чому б не щось на кшталт "взяти ідентифікатор, додати CONSTANT, перетворити в шістнадцятковий". Неоднозначність ідентифікатора забезпечить унікальність uuid, шістнадцяткове число важче читати для нормальних смертних + додавання константи дозволить уникнути наявності uuid, як 00000001.


1
"Чому б не щось на кшталт" взяти ідентифікатор, додати CONSTANT, перетворити на шістнадцятковий "- тому що це досить легко зрозуміти - дайте мені URL-адресу, і я перегляну всі інші рахунки в системі. ІМО немає проблеми що це насправді вирішує, лише ті, що потенційно створює.
CompuChip

" Під час обробки запиту на" / рахунки / ... "просто перевірте параметр - якщо це ціле число, пошукайте ідентифікатор , інакше шукайте uuid " Вся суть (наскільки я розумію питання) полягає в тому, щоб запобігти пошуку когось за ідентифікатором ( /invoices/123, /invoices/124, ...), щоб ви шукали лише UUID з URL-адреси.
TripeHound

Також не всі шістнадцяткові цифри містять букви. Не можна завжди відрізняти ваші базові цілі числа та генеровані шістнадцяткові числа.
TRiG

@CompuChip, як я очікую, вас цікавлять комп’ютери :-), щоб ви розпізнали шістнадцятковий номер з першого погляду. Але Q було написано таким чином, щоб не показувати номер рахунка-фактури безпосередньо, щоб інші могли знати, скільки рахунків існує. Коли я показую якийсь шістнадцятковий номер своїй дружині, матері, сусідці, вони не дізнаються, що це за "дивний текст". Якщо в Q буде помічено питання щодо безпеки відповідно до номерів рахунків-фактур, то я запропонував би для цього певний складний метод хешування.
Jarda

@TripeHound він все ще може шукати по ідентифікатору внутрішньо або в межах якоїсь точки доступу з обмеженим доступом ...
Jarda

0

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

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

На моє розуміння, клавіші - це неявні індекси, і чим більше ви будете додавати індекси, тим повільнішими будуть вставки.


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

0

Інший підхід для вашого конкретного випадку використання полягає в тому, що замість зміни бази даних та програми ви можете просто створити власний маршрут до рахунків-фактур, щоб / / facs /: f (id), де f (id) - деяка функція ідентифікатора.

Спеціальний маршрут відповідає за подання запиту на правильну сторону сервера дій.


0

Це цілком прийнятна практика, яка також називається «альтернативний ключ» (АК). В основному АК - це ще один унікальний індекс або унікальне обмеження.

Ви навіть можете створювати обмеження для зовнішніх ключів на основі АК.

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


0

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

Оскільки питання стосується рахунків-фактур та номерів, можливо, варто вивчити, як бухгалтерська галузь очікує виглядати номери рахунків-фактур: http://smallbusiness.chron.com/assign-invoice-numbers-52422.html

Може здатися, що внутрішній ідентифікатор, який є первинним ключем, і інше унікальне поле з номером рахунка-фактури, який бачить додаток / клієнт, може здаватися безладним. Але це не так нечисто, коли, скажімо, за рік у дорозі, замовник хоче прийняти нову схему нумерації рахунків. У такому випадку ви не заважаєте внутрішній ідентифікатор та його відносини в інших таблицях, щоб перенумерувати всю кулю воску. Ви збережете свій внутрішній ідентифікатор таким, який є, і перенумеруєте номер, який не є внутрішнім рахунком-фактурою.

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


0

Дій.

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

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