Як створити базу даних для визначених користувачем полів?


145

Мої вимоги:

  • Потрібно мати можливість динамічно додавати визначені користувачем поля будь-якого типу даних
  • Потрібно мати можливість швидко запитувати UDF
  • Потрібно вміти робити розрахунки для АДС на основі типу даних
  • Потрібно мати можливість сортувати UDF на основі типу даних

Інша інформація:

  • Я насамперед шукаю продуктивність
  • Є кілька мільйонів основних записів, до яких можуть бути додані дані UDF
  • Коли я востаннє перевіряв, у нашій базі даних було понад 50 мільйонів записів UDF
  • Більшу частину часу до АДС додається лише кілька тисяч головних записів, не всіх
  • UDF не приєднуються і не використовуються як ключі. Вони просто дані, які використовуються для запитів чи звітів

Параметри:

  1. Створіть велику таблицю за допомогою StringValue1, StringValue2 ... IntValue1, IntValue2, ... і т. Д. Я ненавиджу цю ідею, але буду розглядати її, якщо хтось може мені сказати, що вона краще, ніж інші ідеї і чому.

  2. Створіть динамічну таблицю, яка додасть новий стовпець за потребою. Мені також не подобається ця ідея, оскільки я вважаю, що ефективність буде повільною, якщо ви не індексуєте кожен стовпець.

  3. Створіть єдину таблицю, що містить UDFName, UDFDataType та Value. Коли додається новий UDF, генеруйте представлення, яке витягує саме ці дані та аналізує їх на будь-який тип вказаного типу. Елементи, які не відповідають критеріям розбору, повертають NULL.

  4. Створіть кілька таблиць UDF, по одній на тип даних. Таким чином, у нас були б таблиці для UDFStrings, UDFDates тощо. Можливо, зробили б те ж, що і №2, і автоматично генерують перегляд будь-коли, коли буде додано нове поле.

  5. XML DataTypes? Я не працював з ними раніше, але бачив їх згадування. Не впевнений, чи дадуть мені результати, які я хочу, особливо з продуктивністю.

  6. Щось ще?


7
Мартін Фаулер рекомендує 2 (схема, яку можна оновити
Ніл

Дивіться також питання StackOverflow про динамічні схеми бази даних .
FloverOwe

Відповіді:


49

Якщо продуктивність є головною проблемою, я б пішов з №6 ... таблицею на АДС (дійсно, це варіант №2). Ця відповідь спеціально з урахуванням даної ситуації та опису описаних моделей розподілу та доступу.

Плюси:

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

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

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

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

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

Мінуси:

  1. Це може створити багато таблиць. Прискорення розділення схеми та / або конвенції про іменування полегшило б це.

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

Інші міркування:

  1. Якщо є щось про характер даних, яке мало б сенс групувати АДС, це слід заохочувати. Таким чином, ці елементи даних можна об'єднати в єдину таблицю. Наприклад, скажімо, у вас є UDF за кольором, розміром та вартістю. Тенденція даних полягає в тому, що більшість екземплярів цих даних виглядає приблизно так

     'red', 'large', 45.03 

    а не

     NULL, 'medium', NULL

    У такому випадку ви не несете помітної швидкості покарання, комбінуючи 3 стовпця в 1 таблиці, оскільки мало значень буде NULL, і ви уникаєте робити ще 2 таблиці, що на 2 менших кількості приєднань потрібно, коли вам потрібно отримати доступ до всіх 3 стовпців .

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

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


1
Контрольні списки! Всередині жарт між мною та Філом, я сподіваюся, що це не суперечить правилам.
GunnerL3510

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

Я працюю з таблицею, яка датувала / переосмислювала UDF, я використовую цей метод, stackoverflow.com/a/123481/328968 , щоб отримати останні значення.
Пітер

22

Я написав про цю проблему багато . Найпоширенішим рішенням є антипатерн Entity-Attribute-Value, який схожий на те, що ви описуєте у своєму варіанті №3. Уникайте такого дизайну, як чума .

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

Ви можете прочитати цікаву статтю з 2009 року про це рішення тут: http://backchannel.org/blog/friendfeed-schemaless-mysql

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


1
Чи можете ви пояснити, чому я повинен уникати варіант №3? Я переглянув деякі ваші приклади, але вони насправді не такі, як я намагаюся зробити. Я просто хочу місце для зберігання додаткових даних, а не місце для зберігання всіх атрибутів.
Рейчел

2
Для початку, кому ви зробите атрибут NOT NULL? Як би ви зробили атрибут UNIQUE, не роблячи всіх атрибутів UNIQUE? Це продовжується звідти. Ви в остаточному підсумку пишете код програми для надання функцій, які RDBMS вже надає для вас, навіть до того, що вам потрібно буде написати якийсь клас відображення для простого вставлення запису логічної сутності та повернення її назад.
Білл Карвін

2
Коротка відповідь - «не змішувати дані та метадані». Створення стовпців varchar для fieldnameабо tablenameзберігання ідентифікаторів метаданих як рядків даних, і це є початком багатьох проблем. Також дивіться en.wikipedia.org/wiki/Inner-platform_effect
Білл Карвін

2
@Thomas: У перевернутому дизайні індексу ви можете використовувати стандартні рішення схем для типів даних і обмежень, таких як UNIQUE і FOREIGN KEY. Вони взагалі не працюють, коли ви використовуєте EAV. Я погоджуюсь, що інвертований індекс ділиться з EAV в тому, що він не є реляційним просто тому, що він підтримує різні атрибути на рядок, але це є компромісним питанням.
Білл Карвін

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

10

Я, швидше за все, створив би таблицю такої структури:

  • varchar Назва
  • varchar Тип
  • десяткова кількістьValue
  • varchar StringValue
  • date DateValue

Точні типи курсу залежать від ваших потреб (і, звичайно, від dbms, який ви використовуєте). Ви також можете використовувати поле NumberValue (десяткове) для int та booleans. Можливо, вам знадобляться й інші типи.

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

Можливо, ви хочете мати якусь інформацію про метадані. Отже, ви закінчуєте таке:

Таблиця UdfMetaData

  • int id
  • varchar Назва
  • varchar Тип

Таблиця MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • десяткова кількістьValue
  • varchar StringValue
  • date DateValue

Що б ви не робили, я не змінив би структуру таблиці динамічно. Це кошмар технічного обслуговування. Я б також не використовував XML-структури, вони занадто повільні.


Мені подобається ваша стратегія, і, можливо, вибирати її, але в 2017 році, чи виберете щось інше? як json
maztt

У нашому проекті ми реалізували власну структуру даних, яка серіалізує щось подібне до json. Він має інтерфейс, що зберігає тип, для читання та запису даних без кастингу та з великою інтеграцією мови програмування. Це справді чудово. У нього така ж проблема, як і всі подібні "документи" в базах даних. Важко запитувати специфічні значення, і він не може легко посилатися на дані за межами "документа". Залежно від використання, це навіть не є проблемою.
Стефан Штейнеггер

Крім цього, те, що я запропонував у 2011 році, - це ІМХО як і раніше справедливе рішення.
Стефан Штейнеггер

10

Це звучить як проблема, яка може бути краще вирішена нереляційним рішенням, як-от MongoDB або CouchDB.

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

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

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

Ви втрачаєте здатність ефективно керувати схемою. Чи вархар із 100 символів - це правильний тип поля "значення"? 200 символів? Чи замість цього повинен бути нварчар? Це може бути важким компромісом і закінчуватись тим, що ви повинні поставити штучні обмеження на динамічний характер вашого набору. Щось на кшталт "ви можете мати лише x визначені користувачем поля, і кожне може мати лише y символів.

З рішенням, орієнтованим на документи, як-от MongoDB або CouchDB, ви підтримуєте всі атрибути, пов’язані з користувачем, в межах одного кордону. Оскільки приєднання не є проблемою, життя щасливе, оскільки жодне з цих двох не вдається добре приєднатися, незважаючи на ажіотаж. Ваші користувачі можуть визначити стільки атрибутів, скільки вони хочуть (або ви дозволите) при довжині, яку не важко керувати, поки ви не досягнете приблизно 4 Мб.

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


6

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

Варіант 1

Цей підхід IMO дає вам схему, яка не знає, що означає схема, що є рецептом катастрофи та кошмаром для дизайнерів звітів. Тобто, ви повинні мати метадані, щоб знати, який стовпець зберігає які дані. Якщо ці метадані зіпсуються, вони можуть потенційно зібрати ваші дані. Крім того, це полегшує введення неправильних даних у неправильний стовпець. ("Що? String1 містить назву жіночих монастирів? Я думав, що це улюблені наркотики Чалі Шин.")

Варіант 3,4,5

ІМО, вимоги 2, 3 та 4 усувають будь-які зміни рівня EAV. Якщо вам потрібно запитати, сортувати або робити розрахунки за цими даними, то EAV - це мрія Ктулху, а також кошмар вашої команди розвитку та DBA. EAV's створить вузьке місце з точки зору продуктивності та не надасть вам цілісності даних, необхідної для швидкого отримання потрібної інформації. Запити швидко перетворяться на перехресні вузли Гордіа.

Варіант 2,6

Це дійсно залишає один вибір: зібрати технічні характеристики, а потім скласти схему.

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

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

Розріджені стовпці


5
  1. Створіть кілька таблиць UDF, по одній на тип даних. Таким чином, у нас були б таблиці для UDFStrings, UDFDates тощо. Можливо, зробили б те ж, що і №2, і автоматично генерують перегляд будь-коли, коли буде додано нове поле.

Згідно з моїм дослідженням, кілька таблиць на основі типу даних не допоможуть вам у роботі. Особливо, якщо у вас є об'ємні дані, як-от 20K або 25K-записи з 50+ UDF. Продуктивність була найгіршою.

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

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue

Це повинно бути правильним та обґрунтованим. Попередня відповідь Філа 2011 року вже не є гарною порадою сьогодні 2016.
Яп Кай Лун Леон

Чи можу я отримати простий приклад того, як зробити такий процес в sql.?
Нірой

Вибачте за пізню відповідь, але ви хочете, щоб структура бази даних була однаковою. Я не зрозумів тебе @Niroj. Чи можете ви поясніть, будь ласка, детально, як ви хочете.
Підрядник "Аміт"

4

Це проблемна ситуація, і жодне з рішень не видається «правильним». Однак варіант 1, мабуть, найкращий як з точки зору простоти, так і з точки зору продуктивності.

Це також рішення, яке використовується в деяких комерційних додатках підприємств.

EDIT

Ще один варіант, який доступний зараз, але не існував (або принаймні не дозрів), коли питання було оригінальним, - це використовувати поля json у БД.

багато реляційних БД тепер підтримують поля на основі json (які можуть включати динамічний список підполів) і дозволяють здійснювати запити по них

поступ

mysql


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

1300 різних UDF для однієї таблиці? чи кожен користувач має можливість додати UDF або лише якийсь користувач живлення?
Офір Йоктан

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

2

У мене був досвід або 1, 3 і 4, і всі вони закінчуються або безладним, і не зрозуміло, що це за дані, або насправді складне з якоюсь м'якою категоризацією, щоб розбити дані на динамічні типи записів.

Мені б сподобатися спробувати XML, ви повинні мати змогу застосувати схеми щодо вмісту xml, щоб перевірити введення даних тощо, що допоможе зберегти різницю наборів даних UDF. У нових версіях SQL-сервера ви можете проіндексувати поля XML, що повинно допомогти в продуктивності. (див. http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ), наприклад


Чесно кажучи, я взагалі не заглянув у XML. Основним недоліком цього є те, що я повинен був би дізнатися, як це працює і як робити запити проти нього, і я чув, що продуктивність може бути гіршою, ніж інші варіанти
Рейчел

1
Я б не використовував xml для цього: він може зробити цю роботу, і я реалізував щось подібне в xml в минулому, але продуктивність стала дуже поганою, оскільки структури даних зростали, а складність коду була великою.
Kell

2

Якщо ви використовуєте SQL Server, не оглядайте тип sqlvariant. Це досить швидко і повинно робити свою роботу. В інших базах даних може бути щось подібне.

Типи даних XML не так хороші з міркувань продуктивності. Якщо ви робите розрахунки на сервері, то вам постійно доведеться їх деріаріалізувати.

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


Дякую, я ще раз перегляну варіанти SQL. Моє найбільше занепокоєння - це продуктивність, і я не впевнений, як це впорається, особливо якщо ми говоримо про понад 50 мільйонів рядків
Рейчел

Щойно знайдені sql_varients не можна використовувати із пунктом LIKE ... це для мене величезний мінус. Звичайно, якщо я створити подання для кожного UDF, я можу привести його до відповідного типу даних на основі SQL_VARIANT_PROPERTY (значення, "BaseType") ... все-таки, здається, це погано для продуктивності
Rachel

Ви можете використовувати LIKE, але спочатку потрібно передати значення. LIKE працює лише на варшарах, тому вам доведеться передати sql_variant варчару. Поки ви знаєте, що є вашим UDF варчаром (наприклад, тому, що тип зберігається десь в іншому місці), ви можете відфільтрувати всі ваші рядки до варшарів, а потім відкинути і запустити свій запит LIKE: наприклад. виберіть * FROM MyTable, де variant_type = 'v' Cast (variant_value як varchar (max)) LIKE 'Blah%' Таким чином, ви не перетворюєте ints тощо на рядки, які б уповільнили вас.
Тім Роджерс

Мені потрібно провести кілька тестів, щоб побачити, наскільки ефективні показники, особливо з мільйонами рядків. Знаєте будь-які статті в Інтернеті про ефективність використання sql_varients? Особливо з кастингом і дуже великою кількістю записів?
Рейчел


1

У минулому я цим успішно керував, використовуючи жоден із цих варіантів (варіант 6? :)).

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

Візьміть документ як приклад: типовими полями будуть ім'я, тип, дата, автор тощо. Це буде міститись в основній таблиці. Тоді користувачі визначатимуть свої власні спеціальні типи документів із власними полями, такими як Contra_end_date, renewal_clause, bla bla bla bla. Для цього визначеного користувачем документа буде основна таблиця документів, таблиця xcontract, об'єднана в загальний первинний ключ (тому первинний ключ xcontracts також є іноземним для основного ключа основної таблиці). Тоді я б створив подання, щоб обернути ці дві таблиці. Продуктивність, коли запит був швидким. додаткові правила ведення бізнесу також можуть бути вбудовані в погляди. Це спрацювало дуже добре для мене.


1

У нашій базі даних працює програма SaaS (програмне забезпечення довідкової служби), де користувачі мають понад 7 к "користувацькі поля". Ми використовуємо комбінований підхід:

  1. (EntityID, FieldID, Value)таблиця для пошуку даних
  2. поле JSON у entitiesтаблиці, яке містить усі значення сутності, що використовуються для відображення даних. (таким чином вам не потрібен мільйон JOIN для отримання значень значень).

Ви також можете розділити №1, щоб мати "таблицю на тип даних", як пропонує ця відповідь , таким чином ви навіть можете індексувати свої UDF.

PS Пара слів, щоб захищати підхід "цінність-атрибут-цінність", який усі тримають. Ми використовували №1 без №2 протягом десятиліть, і це спрацювало чудово. Іноді це ділове рішення. У вас є час переписати додаток і переглянути дизайн db, або ви можете кинути пару доларів на хмарні сервери, які справді дешеві в ці дні? До речі, коли ми використовували підхід №1, наша БД містила мільйони сутностей, доступ до яких отримував 100 тисяч користувачів, а двоядерний сервер 16 ГБ - це чудово.


Привіт @Alex, я зіткнувся з подібною проблемою. Якщо я добре розумію, у вас є: 1) custom_fieldsтаблиця, що зберігає значення, такі як 1 => last_concert_year, 2 => band, 3 =>, musicа потім custom_fields_valuesтаблиця зі значеннями 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 , Metal Сподіваюся, приклад має сенс для вас і вибачте за форматування!
титами

@thitami не зовсім. Наслідуючи ваш приклад: у мене є bandsтаблиця з рядком, 1,'Iron Maiden'потім custom_fieldsрядками, 1,'concert_year' | 2,'music'потім custom_fields_valuesрядками1,1,'1977'|1,2,'metal'
Олексій

0

У коментарях я бачив, що ви говорите, що поля UDF повинні скидати імпортовані дані, які не відображаються належним чином користувачем.

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

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

Тепер я хотів би зробити варіант 4 (EDIT) із додаванням посилання на користувачів:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Тепер переконайтеся, що перегляньте, щоб оптимізувати ефективність та правильно встановити свої індекси. Цей рівень нормалізації робить слід БД меншим, але ваш додаток складнішим.


0

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

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

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

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

Для звітності ви можете PIVOTперетворити значення міток таблиці « Поля» у назви стовпців, а потім згорнути результати запитів із кожної таблиці типів даних у ці зведені стовпці.

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