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


11

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

"Чи буде сценарій, який виправдовує збереження даних в рядку (рядок) замість кількох рядків?"

Припустимо таблицю, яка називається, countryStatesде ми хочемо зберігати штати країни; Я використаю США для цього прикладу і не буду перераховувати всі Штати заради ліні.

Там ми мали б дві колонки; один дзвонив, Countryа другий дзвонив States. Як обговорювалося тут , і запропонований @ srutzky в відповідь , то PKбуде код визначається стандартом ISO 3166-1 альфа-3 .

Наш стіл виглядав би так:

+---------+-----------------------+-------------------------------------------------------+
| Country | States                | StateName                                             |
+---------+-----------------------+-------------------------------------------------------+
| USA     | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+

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

Ми зробили висновок, що ця модель не дуже корисна, але мені підозріло, що може бути спосіб зробити це корисним.

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


Тепер уявіть, що у вас є друга таблиця "продажів", в якій є дані про кожен продаж, який відбувся разом із кодом штату, в якому відбулася продаж. Як би ви написали запит, який генерує звіт зі стовпцями (StateName, TotalSalesAmount)? Важко, правда?
zgguy

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

Можливим сценарієм може бути зберігання змінних. Магазин a;b;c, використовувати передній кінець для розбору вашої рядки ви отримаєте те a, b, cі нести на виконання робити що - то з ними, може бути?. Відчуйте, що це може відповідати певній конкретній потребі таким чином ... По-друге, ні. Ви завжди можете зберігати ідентифікатори, приєднуйтесь до своїх таблиць і створюйте об'єднаний рядок, ніж можете надсилати вміст до ІП ...
Нельц

Для справедливості (мені щонайменше ;-), я запропонував використовувати двозначні коди країн :-) у цій іншій відповіді .
Соломон Руцький

2
Зауважте, що ніхто не має труднощів щодо збереження значення "Алабама" у стовпці, а не в окремій таблиці зі стовпцями ДЕРЖАВНІ, Н & С для "Ім'я ДЕРЖАВНОГО ДЕРЖАВНОГО має N-й символ С". Тому що або 1. ми не маємо наміру запитувати символи імен, або 2. ми не проти викликати функцію NTH_CHAR (N, S), повертаючи "N-й символ рядка S" у кожному рядку з іменем, якщо ми це робимо . (Vs JOIN та інші реляційні оператори, що виключають деякі такі рядки через додаткову таблицю.) Ditto для цілих чисел та NTH_DIGIT (N, I). Це завжди заклик судження щодо того, що в певній базі даних є атомарним.
філіпсі

Відповіді:


13

Для початку, поточний заголовок питання, що стосується "зберігання даних як рядок замість стовпців", трохи заплутаний. Якщо говорити про зберігання даних як рядків замість чогось іншого, це зазвичай стосується серіалізації всього до рядкового формату замість належного / сильного типу даних (наприклад, INTабо DATETIME). Але якщо запитати про збереження даних у вигляді декількох значень в одному полі на відміну від окремих рядків, це трохи інакше. І якщо бути справедливим, хоча об'єднання значень найлегше виконати за допомогою рядків, це також можна зробити INTі з BINARYтипами, також шляхом бітового маскування або аналогічного резервування певних позицій для різного значення. Оскільки друге тлумачення - це те, що насправді задають, на основі тексту Запитання, давайте розглянемо це.

Одним словом: Ні. Якщо ви зберігаєте фактичні точки даних, це принесе лише біль (з точки зору коду та продуктивності), оскільки це зайве ускладнення. Якщо це значення, яке коли-небудь зберігатиметься як єдиний блок, оновлюється як єдиний блок і ніколи не розбирається в базі даних, то це може бути нормально, оскільки це приблизно аналогічно збереженню зображення або PDF. В іншому випадку будь-яка спроба аналізу даних буде недійсною, використовуючи будь-які індекси (наприклад, використання LIKE '%something%', або CHARINDEX, або PATINDEX, або SUBSTRINGтощо).

Якщо вам потрібно зберігати окремі значення в одному полі одного рядка, тоді є більш відповідні засоби для цього: XML або JSON. Це розбірливі формати ( XML / JSON ) і XML можна навіть індексувати . Але в ідеалі ці дані зберігатимуться у правильно введених полях, щоб вони могли бути справді корисними.

І, будь ласка, не забувайте, що метою RDBMS є зберігання даних таким чином, щоб їх можна було отримати та маніпулювати якомога ефективніше, в межах обмежень, накладених на сумісність з ACID . Отримання об'єднаних значень досить погано через необхідність спочатку проаналізувати значення, і це не підлягає індексації. Але маніпулювання часто означає заміну всього блобу просто для оновлення його частини (припускаючи, що для використання REPLACEфункції не існує жодного шаблону ). Тип даних XML принаймні дозволяє використовувати XML DML для спрощених оновлень, хоча вони все ще не такі швидкі, як просте оновлення правильно модельованих даних.

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

А що робити, якщо вимоги бізнесу з часом змінюються, і вам потрібно відстежувати додаткові властивості цих елементів? Що стосується "штатів", що з столицями, чи населенням, чи порядком, чи ще чим? Зберігаючи належним чином як рядки, ви можете додати більше стовпців для додаткових властивостей. Звичайно, у вас може бути декілька рівнів даних, які можна проаналізувати, наприклад, |StateCode,Capital,Population |StateCode,Capital,Populate|...але, сподіваємось, хтось може побачити проблему, що росте експоненціально, поза контролем. Звичайно, саме ця проблема досить легко вирішується з форматами XML та JSON, і це їх цінність, як згадувалося вище. Але вам все одно знадобиться дуже вагомий привід для того, щоб використовувати будь-який з них як вихідний засіб моделювання, оскільки жоден з них не буде настільки ефективним, як використання дискретних полів в окремих рядках.


9

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

OutputType   OutputHeader
PersonalData Name|Address|City|State|Zip
JobInfo      Name|JobName|JobTitle

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

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


1

Я використовував це колись із досить невеликою таблицею, наприклад:

CREATE TABLE t1 (
  ID number,
  some_feature   varchar2(100),
  valid_channels  varchar2(100));

CREATE TABLE channel_def (
  channel varchar2(100));

А потім зберігайте значення CRM,SMS,SELF-CAREу valid_channel.

У всій таблиці є приблизно 10 записів. valid_channelмістить значення, які насправді повинні знаходитись у сполучній таблиці, яка зображує взаємозв'язок «багато-багато». Таблиця t1не буде використовуватися інтенсивно, тому ми просто вирішили піти цією дорогою. Деякі політики брали участь у цьому рішенні (див. Нижче).

Але взагалі я цього уникаю, це не 3NF.

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

SELECT * 
  FROM t1 
 INNER JOIN channel_def cd
    ON ','||t1.valid_channels||',' LIKE '%,'||cd.channel||',%';

Жахливо + на Oracle, він вимикає використання індексу через запуск '%,'.


Що було б повільніше: LIKEчи просте приєднання?
Human_AfterВсі

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

@Human_AfterAll LIKEбуде повільніше, особливо якщо дані правильно модельовані для використання TINYINTполя ПК у channel_def. Тоді потрібно лише порівняти один байт між двома таблицями. Тут він повинен проаналізувати рядок, символ за символом (принаймні, доки умова не буде виконана), і він робить нечутливий до регістру пошук (виходячи з наведеної таблиці, де не відображається використання _BIN2зіставлення). Це також недійсні індекси на SQL Server. Я вирішив це у своїй відповіді, сказавши, що для розбору не можна використовувати індекси. Я просто оновив свою відповідь, щоб зробити її зрозумілішою.
Соломон Руцький

1
@Human_AfterAll Я б сказав, що це рішення моделювання покладалося на брак досвіду та знань (а іноді і лінь). Ще одним додатком ПРИЄДНАЙТЕ є все, що зберігається, але те, що жертвується, - це можливість іноземного ключа, який би перешкоджав потраплянню неправдивих даних (навіть якщо це не відповідатиме LIKEклаузулу та не матиме дивних результатів, це все ще може спричинити інші проблеми або принаймні, зробити налагодження важче / довше). Це також ускладнює оновлення valid_channelsполя. Це не означає, що це не працює, просто немає вагомих причин для цього.
Соломон Руцький

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

1

Це було зроблено тут, на SE. Як пише Марк Гравелл :

... Після деякої думки та роздумів ми влаштувались на трубі (барі) з обмеженим природним поданням із провідними / задніми трубами, тому ".net c #" стає просто "| .net | c # |". У цьому є чесноти:

  • дуже простий для розбору
  • масове оновлення та видалення тегів можна зробити простою заміною (включаючи труби, щоб уникнути заміни середніх тегів)
  • ...

Цей "новий формат" був наступним кроком від "старого формату", який був дещо іншим і був вибраний для використання функції повнотекстового пошуку SQL Server, тому деякі переваги не мають значення, якщо ви робите це з нуля.

Вони, ймовірно, не повністю нормалізували річ як за кількістю роботи, так і з причин виконання.


0

Ну, однією з можливих головних переваг використання рядків та інших типів даних є надіслати їх із SQL Server на C #, C, C ++ (тощо), використовуючи SQLCLR, коли можливо потрібна сама продуктивність. Ви навіть можете створити перегляд або збережену процедуру для представлення реляційних даних нереляційно - як у вашому прикладі вище для цієї мети.

Дивіться цей приклад:

http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/

за Вікіпедією: SQL CLR або SQLCLR (SQL Common Language Runtime) - це технологія для розміщення механізму виконання загальної мови Microsoft .NET в системі SQL Server. SQLCLR дозволяє керувати кодом та керувати ним середовищем Microsoft SQL Server.


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

Посилання статті пояснює переваги із плюсами та мінусами. Крім того, я згадав про збереження даних у реляційному відношенні та для цілей CLR перетворення їх у нереляційні з видом або збереженою процедурою. Ваше запитання було: "Чи буде сценарій, який виправдовує збереження даних в рядку (рядок) замість кількох рядків?" І моя відповідь - так, хоча я віддаю перевагу перегляду або збереженій процедурі для цілей взаємодії з CLR.
Стінг

0

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

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

Якби вам довелося приєднатися до такого типу даних, це було б одним неприємним досвідом. Оновлення окремих елементів рядка також було б неприємним.

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