Чи марно створювати нову таблицю баз даних, а не використовувати тип даних enum?


38

Припустимо, у мене є 4 типи послуг, які я пропоную (навряд чи вони часто змінюються):

  • Тестування
  • Дизайн
  • Програмування
  • Інший

Припустимо, у мене є 60-80 реальних послуг, які належать до однієї з вищевказаних категорій. Наприклад, "послуга" може бути "Програма тестування з використанням техніки А", і вона має тип "Тестування".

Я хочу закодувати їх у базу даних. Я придумав кілька варіантів:

Варіант 0:

Використовуйте VARCHARбезпосередньо для кодування типу послуги безпосередньо у вигляді рядка

Варіант 1:

Використовуйте базу даних enum. Але, перерахування - це зло

Варіант 2:

використовувати дві таблиці:

service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);

Я навіть можу насолоджуватися референтною цілісністю:

ALTER service_line_item 
    ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);

Звучить добре, так?

Але мені все ж доводиться кодувати речі та мати справу з цілими числами, тобто під час заповнення таблиці. Або я повинен створити складне програмування або конструкції БД під час заселення або роботи з таблицею. А саме, ПРИЄДНАЙТЕСЯ, коли маєш справу з базою даних безпосередньо або створюєш нові об'єктно-орієнтовані об'єкти на стороні програмування, і переконайтесь, що я правильно ними керую.

Варіант 3:

Не використовуйте enum, не використовуйте дві таблиці, а просто використовуйте цілий стовпець

service_line_item (
    id,
    service_type INT,        -- use 0, 1, 2, 3 (for service types)
    description VARCHAR
);

Це як "фальшивий перелік", який вимагає більше накладних витрат на кодову сторону речей, наприклад, тобто знаючи це {2 == 'Programming'}та погоджуючись з цим.

Питання:

В даний час я реалізував його, використовуючи Варіант 2 , керуючись концепціями

  1. не використовувати enum (варіант 1)
  2. уникайте використання бази даних як електронної таблиці (варіант 0)

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

На "менш марнотратний спосіб" я дивлюся Option 3. ІТ легше і вимагає по суті однакових конструкцій коду для роботи (з незначними модифікаціями, але складність і структура в основному однакові, але з єдиною таблицею)

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

Якщо існує лише два типи (двійкові)

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

Я вирішив не створювати нову таблицю просто для зберігання значень {"Стандарт", "Виняток"}. Отже, мій стовпець просто містить {0, 1}, і назва мого стовпчика називається exception, і мій код робить переклад з {0, 1} => {STANDARD, EXCEPTION}(який я кодував як константи в мові програмування)

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

ОРМ

Щоб додати деякий контекст, прочитавши відповіді - я тільки що знову почав використовувати ORM (нещодавно), в моєму випадку Доктрина 2. Після визначення схеми БД через Анотації я хотів заповнити базу даних. Оскільки весь мій набір даних порівняно малий, я хотів спробувати використовувати конструктивні програми, щоб побачити, як це працює.

Я спочатку заповнював service_types, а потім service_line_items, оскільки існував список із фактичної електронної таблиці. Таким чином, такі як "стандарт / виняток" та "Тестування" - це всі рядки на електронній таблиці, і їх потрібно закодувати у належні типи, перш ніж зберігати їх у БД.

Я знайшов цю ТАКУ відповідь: Що ви використовуєте замість ENUM у doctrine2? , який запропонував не використовувати конструкцію enum DB, а використовувати INTполе та кодувати типи, використовуючи конструкцію 'const' мови програмування.

Але, як зазначено у вищезазначеному питанні, я можу уникати прямого використання цілих чисел та використовувати мовні конструкції - константи - після їх визначення ....

Але все ж .... як би ви не повернули, якщо я починаю з stringтипу, я повинен спершу перетворити його у належний тип, навіть коли використовую ORM.

Тож якщо скажіть $str = 'Testing';, мені все одно потрібно десь мати блок, який робить щось на кшталт:

switch($str):
{ 
    case 'Testing':  $type = MyEntity::TESTING; break;
    case 'Other':    $type = MyEntity::OTHER; break;
}

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

І саме це я мав на увазі частково, кажучи про такі речі, як "все-таки треба кодувати речі та мати справу з цілими числами". (Зрозуміло, зараз, після коментаря Окрамія, мені не доведеться мати справу з цілими числами, а мати справу з названими константами та деяким перетворенням на константи / з необхідності).


9
Що б ви не робили, не робіть №3. Психопат, який її підтримує, постійно повинен з'ясувати, що означають ці магічні числа. Якщо ви це зробите, то краще сподіваєтесь, що вони не знають, де ви живете. blog.codinghorror.com/coding-for-violent-psychopaths
RubberDuck

7
Мені подобається варіант 2. Якщо вам не подобається розповсюдження таблиць пошуку, використовуйте одну таблицю та додайте стовпець "тип пошуку". Але так, створення таблиці пошуку - це "стандартний" спосіб цього робити, оскільки він дозволяє робити цікаві речі, як легко заповнити спадне меню в інтерфейсі.
Роберт Харві

Не використовуйте тут "EDIT" у своїх публікаціях; ми не форум. Кожна публікація Exchange Stack вже містить детальну історію редагування , яку може переглядати кожен.
Роберт Харві

якщо я не можу використовувати EDIT, що мені використовувати?
Денніс

Просто відредагуйте публікацію і зробіть це природним, як я вже робив. Щоб переглянути зміни, перегляньте історію редагування.
Роберт Харві

Відповіді:


35

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

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

Усі інші варіанти, які ви описали, є ad hoc і хакі, включаючи MySQL enum, оскільки вони не є частиною стандарту SQL. (Крім того, то , що відстій з enumє реалізація MySQL, а не як така ідея. Я б не проти бачити його в один прекрасний день , як частина стандарту.)

Ваш остаточний варіант №3 із використанням простого цілого числа є особливо хитким. Ви отримуєте найгірше з усіх світів: немає референтної цілісності, ніяких названих значень, немає остаточного знання в базі даних того, що означає значення, просто довільних цілих чисел, кинутих всюди. За цим ознакою, ви можете також кинути використання констант у своєму коді та почати використовувати жорстко закодовані значення. circumference = radius * 6.28318530718;. Як про те, що?

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

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

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

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

  2. Замість використання цілого ідентифікатора для довідкової таблиці використовуйте стовпець CHAR (4) із 4-літерними абревіатурами. Отже, ідентифікатори ваших категорій стануть "TEST", "DSGN", "PROG", "OTHR". ( Звичайно, їх описи залишатимуться англійськими словами.) Це буде трохи повільніше, але, повірте, ніхто не помітить.

Нарешті, коли існує лише два типи, більшість людей просто використовують булеву колонку. Отже, цей стовпець "стандарт / виняток" буде реалізований як булевий і називатиметься "IsException".


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

Що з випадком, коли внаслідок цього дані повторюються, але не є зайвими (наприклад, аномалії оновлення / вставки / видалення не призведуть)? Наприклад, стать людини (навряд чи будуть вводити нові типи даних, ніколи не знадобиться змінювати ім’я статі тощо)
Адам Томпсон,

Це: тому що зрештою ви дізнаєтесь, що вам потрібно "середовище прийняття", і ваші незмінні суперечки потрібно змінити.
Пітер Б

3

Варіант 2 із константами або перерахунками на кінці програмування.
Хоча це дублює знання, порушуючи принцип Єдиного джерела правди, ви можете боротися з ним, використовуючи техніку Fail-fast . Коли ваша система завантажується, вона перевірить наявність значень enums або const у базі даних. Якщо ні, система повинна випустити помилку і відмовитись від завантаження. Виправити цю помилку, як правило, дешевше, ніж пізніше, коли може статися щось більш серйозне.


0

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

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

table service_type 
( id VARCHAR 
, name VARCHAR 
  primary key ( id ) 
);
table service_line_item 
( id 
, service_type VARCHAR 
, description VARCHAR
  foreign key ( service_type ) references service_type ( id )
);

select * from service_type ; 

+-------------+----------------+
| id          | name           |
+-------------+----------------+
| Testing     | Testen         |
| Design      | Design         | 
| Programming | Programmierung |
| Other       | Andere         |
+-------------+----------------+

або, для ваших французьких клієнтів ...

update services_types set name = 'Essai'         where id = 'Testing'; 
update services_types set name = 'Conception'    where id = 'Design'; 
update services_types set name = 'Programmation' where id = 'Programming'; 
update services_types set name = 'Autre'         where id = 'Other'; 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.