Структура бази даних інвентаризації, коли елементи інвентаризації мають різні атрибути


10

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

ERD1

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

Зразок віджетів ERD

Ця структура буде чудово працювати, якби всі атрибути застосовні до предметів, які я зберігаю. Наприклад, якщо база даних зберігала лише мобільні телефони, атрибутами можуть бути такі речі, як сенсорний екран, трекпад, клавіатура, 4G, 3G ... будь-що. У цьому випадку всі вони стосуються телефонів. У моїй базі даних будуть такі атрибути, як ім’я хоста, тип схеми, номер телефону, які застосовуються лише до певних типів пристроїв.

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

Ось деякі інші теми, які я читаю. Вони дали мені гарне розуміння, але я не думаю, що вони реально застосовують:

/programming/9335548/how-to-structure-database-for-inventory-of-unlike-items

/programming/1249632/database-structure-for-items-with-varying-attributes

/programming/5559587/product-inventory-with-multiple-attributes

/programming/6613802/question-about-setting-up-inventory-database

/programming/514111/how-to-best-represent-items-with-variable-of-attributes-in-a-database

Відповіді:


6

Супертип / підтип

Як щодо того, щоб вивчити шаблон супертипу / підтипу? Загальні стовпці містяться в батьківській таблиці. Кожен окремий тип має свою власну таблицю з ідентифікатором батьківського власного ПК і містить унікальні стовпці, не спільні для всіх підтипів. Ви можете включити стовпчик типу в батьківські та дочірні таблиці, щоб переконатися, що кожен пристрій не може бути більше ніж один підтип. Зробіть ФК між дітьми та батьком на (ItemID, ItemTypeID). Ви можете використовувати FKs для таблиць супертипу або підтипу, щоб підтримувати потрібну цілісність в іншому місці. Наприклад, якщо дозволено ItemID будь-якого типу, створіть FK для батьківської таблиці. Якщо тільки на SubItemType1 можна посилатися, створіть FK до цієї таблиці. Я б не залишив TypeID від посилань на таблиці.

Іменування

Що стосується іменування, у вас є два варіанти, як я бачу (оскільки третій вибір просто "ІД" є на мою думку сильним антидіаграмою). Або викличте ключ підтипу ItemID таким, як він є у батьківській таблиці, або назвіть його ім'я підтипу, наприклад DoohickeyID. Після деякої думки та досвіду з цим я виступаю за те, щоб називати це DoohickeyID. Причиною цього є те, що, хоч може виникнути плутанина щодо таблиці підтипу, дійсно в маскуванні, що містить елементи (а не Doohickeys), це невеликий мінус порівняно з тим, коли ви створюєте FK до таблиці Doohickey, а назви стовпців не матч!

Для EAV чи не для EAV - Мій досвід роботи з базою даних EAV

Якщо EAV - це те, що ви справді повинні робити, то це вам потрібно зробити. Але що робити, якщо це було не те, що потрібно було робити?

Я створив базу даних EAV, яка використовується у бізнесі. Слава Богу, набір даних невеликий (хоча існує кілька десятків типів елементів), тому продуктивність непогана. Але було б погано, якби в базі даних було більше декількох тисяч елементів! Крім того, таблиці настільки ТРЕБОВІ для запиту. Цей досвід змусив мене по-справжньому прагнути уникати баз даних EAV в майбутньому, якщо це взагалі можливо.

Тепер у своїй базі даних я створив збережену процедуру, яка автоматично створює PIVOTed представлення для кожного підтипу, що існує. Я можу просто запит від AutoDoohickey. Мої метадані про підтипи містять стовпчик "ShortName", що містить об'єкт-ім'я, придатне для використання в іменах перегляду. Я навіть зробив перегляди оновленими! На жаль, ви не можете оновити їх під час з'єднання, але ви МОЖЕТЕ вставити до них уже існуючий рядок, який буде перетворений на UPDATE. На жаль, ви не можете оновити лише кілька стовпців, оскільки немає можливості вказати VIEW, які стовпці ви хочете оновити за допомогою процесу перетворення INSERT-UPDATE: значення NULL виглядає як "оновити цей стовпець до NULL", навіть якщо Ви хотіли вказати "Не оновлювати цю колонку взагалі".

Незважаючи на все це оздоблення, щоб зробити базу даних EAV простішою у використанні, я все одно не використовую ці погляди в найбільш звичайних запитах, тому що це ПОЗНАЧЕНО. Умови запиту не є присудком, який підштовхується до Valueтаблиці, тому перед фільтрацією він повинен створити проміжний набір результатів для всіх елементів типу цього перегляду. Ой. Тож у мене є багато, багато запитів з багатьма, багатьма приєднаннями, кожен з яких виходить, щоб отримати інше значення тощо. Вони працюють досить добре, але ой! Ось приклад. SP, який створює це (і його тригер оновлення), є одним з гігантських звірів, і я пишаюся цим, але це не те, що ви хочете коли-небудь намагатися підтримувати.

CREATE VIEW [dbo].[AutoModule]
AS
--This view is automatically generated by the stored procedure AutoViewCreate
SELECT
   ElementID,
   ElementTypeID,
   Convert(nvarchar(160), [3]) [FullName],
   Convert(nvarchar(1024), [435]) [Descr],
   Convert(nvarchar(255), [439]) [Comment],
   Convert(bit, [438]) [MissionCritical],
   Convert(int, [464]) [SupportGroup],
   Convert(int, [461]) [SupportHours],
   Convert(nvarchar(40), [4]) [Ver],
   Convert(bit, [28744]) [UsesJava],
   Convert(nvarchar(256), [28745]) [JavaVersions],
   Convert(bit, [28746]) [UsesIE],
   Convert(nvarchar(256), [28747]) [IEVersions],
   Convert(bit, [28748]) [UsesAcrobat],
   Convert(nvarchar(256), [28749]) [AcrobatVersions],
   Convert(bit, [28794]) [UsesDotNet],
   Convert(nvarchar(256), [28795]) [DotNetVersions],
   Convert(bit, [512]) [WebApplication],
   Convert(nvarchar(10), [433]) [IFAbbrev],
   Convert(int, [437]) [DataID],
   Convert(nvarchar(1000), [463]) [Notes],
   Convert(nvarchar(512), [523]) [DataDescription],
   Convert(nvarchar(256), [27991]) [SpecialNote],
   Convert(bit, [28932]) [Inactive],
   Convert(int, [29992]) [PatchTestedBy]
FROM (
   SELECT
      E.ElementID + 0 ElementID,
      E.ElementTypeID,
      V.AttrID,
      V.Value
   FROM
      dbo.Element E
      LEFT JOIN dbo.Value V ON E.ElementID = V.ElementID
   WHERE
      EXISTS (
         SELECT *
         FROM dbo.LayoutUsage L
         WHERE
            E.ElementTypeID = L.ElementTypeID
            AND L.AttrLayoutID = 7
      )
) X
PIVOT (
   Max(Value)
   FOR AttrID IN ([3], [435], [439], [438], [464], [461], [4], [28744], [28745], [28746], [28747], [28748], [28749], [28794], [28795], [512], [433], [437], [463], [523], [27991], [28932], [29992])
) P;

Ось ще один тип автоматично сформованого перегляду, створеного іншою збереженою процедурою із спеціальних метаданих, що допомагає знаходити зв’язки між елементами, які можуть мати між собою кілька шляхів (зокрема: Модуль-> Сервер, Модуль-> Кластер-> Сервер, Модуль-> СУБД- > Сервер, Модуль-> СУБД-> Кластер-> Сервер):

CREATE VIEW [dbo].[Link_Module_Server]
AS
-- This view is automatically generated by the stored procedure LinkViewCreate
SELECT
   ModuleID = A.ElementID,
   ServerID = B.ElementID
FROM
   Element A
   INNER JOIN Element B
      ON EXISTS (
         SELECT *
         FROM
            dbo.Element R1
         WHERE
            A.ElementID = R1.ElementID1
            AND B.ElementID = R1.ElementID2
            AND R1.ElementTypeID = 38
      ) OR EXISTS (
         SELECT *
         FROM
            dbo.Element R1
            INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
         WHERE
            A.ElementID = R1.ElementID1
            AND R1.ElementTypeID = 40
            AND B.ElementID = R2.ElementID2
            AND R2.ElementTypeID = 38
      ) OR EXISTS (
         SELECT *
         FROM
            dbo.Element R1
            INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
         WHERE
            A.ElementID = R1.ElementID1
            AND R1.ElementTypeID = 38
            AND B.ElementID = R2.ElementID2
            AND R2.ElementTypeID = 3122
      ) OR EXISTS (
         SELECT *
         FROM
            dbo.Element R1
            INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
            INNER JOIN dbo.Element C2 ON R2.ElementID2 = C2.ElementID
            INNER JOIN dbo.Element R3 ON R2.ElementID2 = R3.ElementID1
         WHERE
            A.ElementID = R1.ElementID1
            AND R1.ElementTypeID = 40
            AND C2.ElementTypeID = 3080
            AND R2.ElementTypeID = 38
            AND B.ElementID = R3.ElementID2
            AND R3.ElementTypeID = 3122
      )
WHERE
   A.ElementTypeID = 9
   AND B.ElementTypeID = 17

Гібридний підхід

Якщо у вас ОБ'ЄДНІ деякі динамічні аспекти бази даних EAV, ви можете розглянути можливість створення метаданих так, як якщо б ви мали таку базу даних, а натомість фактично використовували шаблон дизайну супертип / підтип. Так, вам доведеться створювати нові таблиці, додавати та видаляти та змінювати стовпці. Але при належній попередній обробці (як я це робив із автоматичними переглядами бази даних EAV), ви могли б мати справжні об’єкти, схожі на таблицю. Тільки вони не були б такими загальними, як у мене, і оптимізатор запитів міг би передбачити натискання на базові таблиці (читай: добре з ними). Було б просто одне з'єднання між таблицею супертипу та таблицею підтипу. Ваша програма може бути налаштована на зчитування метаданих, щоб виявити, що вона повинна робити (або в деяких випадках вона може використовувати автоматично сформовані представлення даних).

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

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

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

(Примітка. Так, ці погляди справді відформатовані таким чином, і PIVOT справді мають тригери оновлення. :) Якщо хтось справді зацікавлений у жахливих хворобливих деталях довгого та складного тригера UPDATE, дайте мені знати, і я опублікую зразок для вас.)

І ще одна ідея

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


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

Я створив базу даних EAV, яка використовується у бізнесі. Слава Богу, набір даних невеликий (хоча існує кілька десятків типів елементів), тому продуктивність непогана. Але це було б, якби в базі даних було більше декількох тисяч елементів. Цей досвід змусив мене по-справжньому прагнути уникати баз даних EAV в майбутньому, якщо це взагалі можливо, тому що вони настільки ЖИТТІ для запиту.
ЕрікЕ

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

Розглянувши схему EAV, я зрозумів, що значення атрибутів змушені ділити тип даних (у цьому випадку вся рядок). Крім того, запит про налаштування EAV буде справою. Супертип / підтип виглядає краще. Моє запитання зараз: чи певні таблиці дозволяють використовувати лише конкретні типи пристроїв. Чи підтверджую це, додаючи ідентифікатор класу пристрою (телефон, комп'ютер, маршрутизатор) у кожну таблицю і кладу обмеження для перевірки на це поле, або я виключаю це поле з таблиць підтипу і використовую тригер для кожної з них? Будь ласка, дивіться ERD3 для довідки.
TheSecretSquad

1
Для запитів даних EAV не рідкість побудувати масу даних реляційних таблиць для даних, які потрібно запитувати, а потім заповнити їх за допомогою певного сценарію. Запити працюватимуть швидше, але лише відносно даних, які ви вводите в datamart, і налаштування потребує неабиякого планування.
FrustratedWithFormsDesigner

6

У вашому випадку найкращим підходом є зміна моделі EAV (Entity-Attribute-Value). Є багато людей, які ухиляються від EAV, оскільки це в деякому сенсі не допомагає і багато часу зловживає. Однак EAV - це рішення, яке добре відповідає вашим конкретним вимогам.

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

Ось ескіз ERD:

ERD

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

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


Це схоже на те, що рекомендував ssmusoke. Я змінив свій ERD, використовуючи його рекомендацію, і, схоже, він відповідає вашому. Не соромтеся перевірити нову RD на веб- сайті http://www.dividegraphics.com/ERD2.jpg та надати будь-які відгуки.
TheSecretSquad

@reallythecrash - Ви праві, я пропоную той самий базовий підхід, що і ssmusoke, я просто прийняв іншу відповідь на свою відповідь, сподіваючись полегшити розуміння як структури моделі, так і обгрунтування використання EAV, багато людей (несправедливо) звинувачують як анти-модель.
Джоель Браун

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

@JoelBrown - яке програмне забезпечення ви використали для накреслення цієї діаграми?
Видар

@Vidar - я використав Visio з розмальовками ERD, які я створив, щоб використовувати візуальні конвенції Джеймса Мартіна та намальовані на замовленому шаблоном лінії, який є схематичним. Я вважаю, що це хороший інструмент, який можна використовувати для швидких / чорнових моделей даних. Якщо діаграма занадто формальна, це може змусити деяких людей подумати, що вона закінчена, тому щось схематичне допомагає заважати людям прискакувати до висновків про те, наскільки міцна / закінчена модель даних.
Джоель Браун

1
  1. Загальний підхід такий:

a) Модель підходу-значення атрибутів-значення для вирішення атрибутів різних пристроїв до типу пристрою. Кожен тип пристрою матиме список атрибутів, значення яких ви відстежуєте

b) Для кожного типу пристрою ви відстежуєте дані про інвентар за порядковим номером, який відповідає одному пристрою.

  1. Отже, ви отримаєте такі таблиці:

а) Атрибути - визначте атрибути для всіх пристроїв (все, що йде в цій таблиці) стовпців: id, ім'я, опис

б) Атрибути елемента - визначають дозволені атрибути для конкретного пристрою - itemid, attributeid

c) Визначення елемента - визначає елемент, наприклад, Black Berry Torch 4500, Iphone 4S, Iphone 3S тощо - id, ім'я, опис, categoryid (якщо ви хочете додати категорії, такі як мобільні телефони, комутатори тощо)

d) Пристрої - окремі пристрої - id, itemid, datadate, deaktiviated, serialnumber ... (в основному всі інші атрибути для пристрою)

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


Дякую за ваш внесок Це відповідає тому, що я шукаю, я просто не міг зрозуміти, як це зробити. Я змінив свій ERD, щоб відобразити ваші характеристики. Здається, що для введення всіх допустимих атрибутів для кожного типу пристрою потрібно більше роботи, але також виглядає так, що він пропонує максимальну гнучкість. Я збираюся зробити невеликий прототип, щоб побачити, чи працює він так, як я думаю, що буде. Знову дякую. Я завантажив ERD зі змінами, якщо ви хочете подивитися, і повідомте мені, чи я на правильному шляху. http://www.dividegraphics.com/ERD2.jpg
TheSecretSquad

Так, ви на правильному шляху.
Стівен Сенкомаго Мусоке

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

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

1
@ssmusoke: Погодився, але я хотів наголосити на цьому, оскільки я бачив, що люди не усвідомлюють важливість метаданих, і тоді їх реалізація EAV стає кошмаром.
FrustratedWithFormsDesigner
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.