Каков предпочтительный способ хранения пользовательских полей в базе данных SQL? - PullRequest
17 голосов
/ 19 января 2010

Мой друг строит продукт для использования различными независимыми медицинскими подразделениями.

В базе данных хранится обширная коллекция измерений, выполненных в разное время, таких как температура, кровяное давление и т. Д. *

Предположим, что они хранятся в таблице с именем exams и столбцами temperature, pressure и т. Д. (А также id, patient_id и timestamp).Большинство измерений хранятся как числа с плавающей точкой, но некоторые из них имеют другие типы (строки, целые числа ...)

Хотя многие из этих измерений обрабатываются их продуктом, необходимо разрешить различным медицинским единицам регистрироватьи обрабатывать другие пользовательские измерения.Очень удобный пользовательский интерфейс позволяет администратору редактировать эти таможенные поля, указывать их имя, тип, возможный диапазон значений и т. Д. *

Он не уверен, как хранить эти настраиваемые поля.

Он склоняется к отдельной таблице (скажем, стол custom_exam_data с такими полями, как exam_id, custom_field_id, float_value, string_value, ...)

Я беспокоюсь, что это будетсделать поиск более сложным и менее эффективным.

Я склоняюсь к непосредственному изменению таблицы экзаменов (избегая конфликтов имен столбцов с какой-либо схемой, такой как добавление префикса всех пользовательских полей с подчеркиванием или именование их custom_1,...)

Он беспокоится о динамическом изменении базы данных и наличии различных схем для каждого медицинского подразделения.

Надеемся, что некоторые люди, у которых больше опыта, могут взвесить этот вопрос.

Примечания:

  • он использует Ruby on Rails, но я думаю, что этот вопрос в значительной степени не зависит от фреймворка, за исключением того факта, что онищет решения только в базах данных SQL.

  • Я немного упростил задачу, поскольку настраиваемые поля должны быть доступны для нескольких таблиц, но я считаю, что это не влияет на направление, в котором они движутся.

  • (добавлено) Очень общий модуль отчетов должен будет искать, сортировать, генерировать статистику и т. Д. Этих данных, поэтому требуется, чтобы эти данные были сохранены в столбцах соответствующего типа

  • (добавлено) Введенные пользователем данные будут отфильтрованы как для стандартных полей, так и для пользовательских полей.Например, числа будут проверяться в заданном диапазоне (температура не может быть -12 или +444) и т. Д. Таким образом, преобразование в соответствующий тип SQL не является проблемой.

Ответы [ 10 ]

10 голосов
/ 19 января 2010

Мне приходилось сталкиваться с этой ситуацией много раз на протяжении многих лет, и я согласен с вашей первоначальной идеей прямого изменения таблиц БД и использования динамического SQL для генерации операторов.

Создание строковых столбцов UserAttribute или Key / Value на первый взгляд звучит привлекательно, но это приводит к эффекту внутренней платформы , когда вам в конечном итоге приходится заново реализовывать внешние ключи, типы данных, ограничения, транзакции проверка, сортировка, группировка, расчеты и др. внутри вашей РСУБД. Вы также можете просто использовать плоские файлы, а не SQL вообще.

SQL Server предоставляет INFORMATION_SCHEMA таблицы, которые позволяют создавать, запрашивать и изменять схемы таблиц во время выполнения. Здесь есть полная проверка типов, ограничения, транзакции, вычисления и все, что вам нужно, уже встроено, не изобретайте его заново.

7 голосов
/ 19 января 2010

Странно, что так много людей придумывают специальные решения для этого, когда есть хорошо документированный шаблон:

Модель атрибута-значения (EAV)

Две альтернативы - это XML и вложенные множества. XML проще в управлении, но в целом медленный. Вложенные наборы обычно требуют, чтобы какой-либо тип расширения собственной базы данных обходился без беспорядка, например, типы CLR в SQL Server 2005+. Они нарушают первую нормальную форму, но, тем не менее, являются наиболее быстродействующим решением.

5 голосов
/ 19 января 2010

Microsoft Dynamics CRM достигает этого, изменяя структуру базы данных каждый раз, когда вносятся изменения.Я думаю, что это неприятно.

Я бы сказал, что лучшим вариантом было бы рассмотреть таблицу атрибутов.Несмотря на то, что они часто осуждаются, это дает вам необходимую гибкость, и вы всегда можете создавать представления с использованием динамического SQL для повторного вывода данных.Просто убедитесь, что вы всегда используете ЛЕВЫЕ СОЕДИНЕНИЯ и ФК при создании этих представлений, чтобы оптимизатор запросов мог выполнять свою работу лучше.

1 голос
/ 19 января 2010

Определите две новые таблицы: custom_exam_schema и custom_exam_data.

custom_exam_data имеет столбец exam_id плюс дополнительный столбец для каждого настраиваемого атрибута.

custom_exam_schema будет иметь строку , чтобы описать, как интерпретировать каждый из столбцов таблицы custom_exam_data. Он будет иметь столбцы, такие как name, type, minValue, maxValue и т. Д.

Так, например, чтобы создать настраиваемое поле для отслеживания количества пальцев, которое есть у человека, вы должны добавить ('fingerCount', 'number', 0, 10) к custom_exam_schema, а затем добавить столбец с именем fingerCount в таблицу exam.

Кто-то может сказать, что плохо менять схему базы данных во время выполнения, но я бы сказал, что настройка этих настраиваемых полей является частью настройки и не будет происходить слишком часто. Тем не менее, этот метод позволяет вам обрабатывать изменения в любое время и не рискует возиться с вашими основными таблицами схем.

1 голос
/ 19 января 2010

Я не могу сказать вам лучший способ, но я могу рассказать вам, как Drupal достигает своего рода структуры без схемы, все еще используя стандартные СУБД, доступные сегодня.

Общая идея состоит в том, что есть таблица схемы со списком полей.Каждая строка на самом деле имеет только два столбца: «таблица»: столбец «Строка» и «столбец»: столбец «Строка».Для каждого из этих столбцов фактически определяется целая таблица, содержащая только идентификатор и фактические данные для этого столбца.

Хитрость в том, что когда вы работаете с данными, никогда не бывает более одного соединения вне таблицы связок, в которой перечислены все возможные столбцы, так что в итоге вы не теряете столько скорости, сколько вы могли бы подумать.Это также позволит вам расширяться гораздо дальше, чем несколько медицинских компаний, в отличие от префикса custom_, который вы предлагаете.

MySQL очень быстро возвращает данные строк для коротких строк с несколькими столбцами.Таким образом, эта схема заканчивается довольно быстро, обеспечивая вам большую гибкость.

Что касается поиска, я бы предложил индексировать содержимое страницы, а не содержимое базы данных.Используйте Solr для анализа отображаемых страниц и удержания ссылок на фактическую страницу вместо того, чтобы пытаться выполнить поиск в базе данных, используя умный SQL.

1 голос
/ 19 января 2010

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

Недостатком является то, что при переходе к фильтрации наборов результатов по некоторой метрике измерения вам все равно придется выполнять приведение, но по крайней мере механизм хранения и сохранения не вносит искажения.

1 голос
/ 19 января 2010

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

Таким образом, вы можетеиметь любые данные, работающие с базами данных любого типа.

1 голос
/ 19 января 2010

Я видел идею вашего друга в пакете коммерческого учета. Таблица была разделена на две части: первая содержала поля, определенные исключительно системой, а вторая содержала поля, такие как USER_STRING1, USER_STRING2, USER_FLOAT1 и т. Д. вставляется во второй). Каждая таблица, для которой нужны пользовательские поля, была разбита следующим образом.

0 голосов
/ 19 января 2010

Допустим, что в базе данных вашего друга должны храниться значения данных из нескольких источников, таких как демографические значения, диагностика, вмешательства, физиономические значения, значения для физиологических исследований, значения для госпитализации и т. Д.

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

Я бы предложил использовать другую таблицу, в которой были бы эти варианты, или вы просто использовали бы таблицу "Custom_field_choices", которая в какой-то момент точно такая же, но с другим именем.

Учитывая, что база данных:
- должен быть гибким
- что данные из нескольких таблиц могут быть добавлены и настроены
- что вы можете захотеть сохранить целостность основной структуры вашей базы данных для целей распределения и единообразия
- эти данные ДОЛЖНЫ иметь предел, а также сигналы тревоги и предупреждения
- эти данные должны иметь единицы (10 кг или 10 фунтов)?
- эти данные могут иметь выбор
- эти данные могут иметь разные права (от простого пользователя до администратора)
- что эти данные могут понадобиться для создания отчетов без изменения кода (автоматизация)
- что эти данные могут понадобиться для анализа перекрестных ссылок в системе без изменения кода

пользовательская таблица будет моим решением, модификация каждой таблицы будет слишком рискованной.

0 голосов
/ 19 января 2010

Я бы сохранил эти настраиваемые поля в таблице, где каждая запись (dataType, dataValue, dataUnit) будет использоваться в одной строке.Так что было бы отношение oneToMany из одного образца к данным.Вы также можете создать таблицу для записи всех типов катсом, которые вы бы использовали.Например:

create table DataType
(
id int primary key,
name varchar(100) not null unique
description text,
uri varchar(255) //<-- can be used for an ONTOLOGY
)


create table DataRecord
(
id int primary key,
sample_id int not null,//<-- reference to the sample
dataType_id int not null, //<-- references DataType
value varchar(100),//<-- the value as string
unit varchar(50)//<-- g, mg/ml, etc... but it could also be a link to a table describing the units just like DataType
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...