База данных: когда разбивать на отдельные таблицы? - PullRequest
6 голосов
/ 05 октября 2010

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

Я не могу решить, есть ли один стол:

[Sensor]
Id : PK
UpperLimit : FLOAT
UpperLimitAlertDelay : INT
LowerLimit : FLOAT
LowerLimitAlertDelay : INT
IsAnalog : BOOL

[SensorReading]
Id : PK
SensorId : FK
AnalogValue : FLOAT
IsOn : BOOL

ИЛИ разделить все это на отдельные таблицы:

[AnalogSensor]
Id : PK
UpperLimit : FLOAT
UpperLimitAlertDelay : INT
LowerLimit : FLOAT
LowerLimitAlertDelay : INT

[AnalogSensorReadings]
Id : PK
AnalogSensorId : FK
Value : FLOAT

[SwitchSensor]
Id : PK
OnTooLongAlertDelay : INT

[SwitchSensorReadings]
Id : PK
SwitchSensorId : FK
IsOn : BOOL

На данный момент у меня есть одна таблица, и я использую «UpperLimitAlertDelay» в качестве «OnTooLongAlertDelay», когда не использую его в качестве аналогового датчика.

В коде, который я различаю по булевому флагу в таблице Sensor, и создаю соответствующий объект (т. Е. AnalogSensor или SwitchSensor), но мне интересно, будет ли он более / более подходящим на уровне базы данных для его выделения.

Какое практическое правило вы бы использовали для такого рода решений? Это разные сущности на одном уровне, но на другом уровне можно сказать, что они оба просто сенсоры.

Это часто, когда я никогда не могу решить, какое направление выбрать при создании базы данных. Может быть, всякий раз, когда я использую bool, чтобы различить, какие поля означают / должны использоваться, это действительно должна быть отдельная таблица?

Общие мысли по этой теме или эта отдельная проблема приветствуются.

Спасибо!

РЕДАКТИРОВАТЬ: Дополнительная информация.

Датчики переключателя контролируют такие вещи, как открытая дверь, работает ли компрессор холодильника, включен ли прибор и т. Д.

Графики и отчеты могут быть созданы на любом датчике, поэтому они используются одинаково; это просто данные будут либо вкл / выкл или аналоговое значение в зависимости от типа.

Так что в основном к ним относятся одинаково.

В таблице показаний всегда одна строка для ОДНОГО считывания ОДНОГО датчика.

Пока мнения кажутся довольно субъективными - я полагаю, есть только плюсы и минусы в обоих направлениях.

Меняет ли информация выше чье-либо мнение?

Спасибо! Марк.

Ответы [ 7 ]

2 голосов
/ 05 октября 2010

Таблицы обычно разбиваются на логически отличные " вещи ", поэтому у вас нет одинаковых " вещей " дважды. Например, вы не хотели бы:

[SensorReadings]
Id : PK
UpperLimit : FLOAT
UpperLimitAlertDelay : INT
LowerLimit : FLOAT
LowerLimitAlertDelay : INT
IsAnalog : BOOL
AnalogValue : FLOAT
IsOn : BOOL

Поскольку вы смешиваете датчик и его показания в один ряд. Датчик - это вещь , отличная от показаний:

[Sensors]                      [SensorReadings]
Id                             Id
UpperLimit                     SensorID
UpperLimitAlertDelay           Reading
LowerLimit
LowerLimitAlertDelay
IsAnalog
Manufacturer
SerialNumber
LastInspectionDate
...

Единственное, чего бы я не хотел, так это разделить «датчики» на две таблицы. Датчик - это датчик, это то, чем он является. Как клиент - это клиент, или песня - это песня. У вас будет столик с песнями, а не столик с классическими песнями и еще один столик для всего остального. Если вы разделите датчики на две таблицы, вы можете предположить, что у вас будет два датчика с одинаковым ID. Датчики являются уникальными объектами, они должны находиться в одной таблице и иметь уникальный идентификатор. Тот факт, что датчик является аналоговым или цифровым, является свойством датчика.


Ваш вопрос уникален - ваши датчики могут иметь Показания в различных логических форматах; некоторые являются аналоговыми значениями с плавающей запятой, другие являются цифровыми логическими значениями. Вы боретесь с тем, как сохранить « показания » датчика, когда не все показания датчика соответствуют одному и тому же типу данных логического столбца (т.е. float vs bool). Все сводится к практичности и тому, что лучше для системы.

Вы можете сохранить все показания в столбце с плавающей запятой:

[SensorReadings]
Id  SensorID  Reading
==  ========  =======
 1   3728     120.2
 2   3728     120.3
 3     89         1
 4     89         0
 5   3728     120.2
 6     89         0

Но теперь вы должны знать, как интерпретировать значение с плавающей запятой 0, 1 как логическое on, off. Это сложно сделать? лично я так не думаю. Правда, он не в полной мере использует типы данных, доступные в ядре базы данных, но мне все равно. Вы собираетесь присоединиться к SensorReadings с Sensors, поэтому у вас будет столбец IsAnalog, чтобы помочь вам интерпретировать. Другими словами:

SELECT Id, SensorID, Reading, Sensors.IsAnalog
FROM SensorReadings sr
   INNER JOIN Sensors s ON sr.SensorID = s.SensorID

Довольно просто разобрать набор результатов:

Id  SensorID  Reading  IsAnalog
==  ========  =======  ========
 1   3728     120.2     false
 2   3728     120.3     false
 3     89         1      true
 4     89         0      true
 5   3728     120.2     false
 6     89         0      true

Вы можете даже создать вспомогательное представление (или просто запрос), которое декодирует чтение как AnalogReading и DigitalReading:

CREATE VIEW SimpleSensorReadings AS

SELECT Id, SensorID, Reading AS RawReading,
    CASE Sensors.IsAnalog
    WHEN 0 THEN Reading
    ELSE NULL
    END AS AnalogReading,

    CASE Sensors.IsAnalog
    WHEN 1 THEN CAST(Reading AS BOOL)
    ELSE NULL
    END AS DigitalReading,
    Sensors.IsAnalog
FROM SensorReadings sr
   INNER JOIN Sensors s ON sr.SensorID = s.SensorID

Это даст вам:

[SimpleSensorReadings]
Id  SensorID  RawReading  AnalogReading  DigitalReading  IsAnalog
==  ========  ==========  =============  ==============  ========
 1   3728        120.2         120.2                       true
 2   3728        120.3         120.3                       true
 3     89            1                       true         false
 4     89            0                      false         false
 5   3728        120.2         120.2                       true
 6     89            0                      false         false

Это зависит от того, кто имеет дело с результатами. Я легко могу представить код, сначала проверяющий столбец «IsAnalog», а затем считывающий AnalogReading или DigitalReading в зависимости от ситуации.


Вы могли бы сделать то, что вы изначально предложили; разделите их на несколько таблиц. Но теперь возникает проблема: как вы получаете доступ к данным? Мне кажется, если бы у меня была эта система показаний датчиков, в какой-то момент мне придется что-то с ними делать - показывать их пользователю. Теперь мне нужно прыгать через обручи, чтобы воссоединиться с данными:

SELECT ID, AnalogSensorID AS SensorID, 
   Value AS RawReading, Value AS AnalogReading, 
   true AS IsAnalog
FROM AnalogSensorReadings

UNION ALL 

SELECT ID, SwitchSensorID AS SensorID, 
   CAST(IsOn AS float) AS RawReading, null AS AnalogReading, IsOn AS DigitalReading,
   false AS IsAnalog

давая вам

Id  SensorID  RawReading  AnalogReading  DigitalReading  IsAnalog
==  ========  ==========  =============  ==============  ========
 1   3728        120.2         120.2                       true
 2   3728        120.3         120.3                       true
 1     89            1                       true         false
 2     89            0                      false         false
 3   3728        120.2         120.2                       true
 3     89            0                      false         false

Кроме того, "Id" также трудно декодировать, потому что два разных показания могут иметь один и тот же "ID". Чтение - это чтение, и оно должно быть уникальным.

Компромисс, который вы, вероятно, ищете, это то, что вы изначально имели.

[SensorReadings]
Id  SensorID  AnalogReading  DigitalReading
==  ========  =============  ==============
 1   3728        120.2         
 2   3728        120.3         
 3     89                       true
 4     89                      false
 5   3728        120.2         
 6     89                      false

Да, это оставляет вам множество (null) значений, но затраты на объединение таблиц - это практическая проблема, которая должна учитывать ваше проектное решение.


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

2 голосов
/ 14 декабря 2010

Является ли это тем же приложением / базой данных, что и ваш другой вопрос ?

В этом случае был получен ответ в этом Модель данных .

Если это не то же самое приложение / db, или если на этот вопрос не был дан адекватный ответ, пожалуйста, оставьте сообщение или комментарий.Например.Основываясь на предыдущей информации, я смоделировал ее так, чтобы таблица SensorType дифференцировала Sensor (аналоговый или логический) ... но мы могли бы:

  • дифференцировать ее на уровне датчика,

  • или преобразование Reading в подтипы: ReadingAnalog и ReadingSwitch.Это может немного облегчить работу программ, создающих графики и т. Д.

1 голос
/ 05 октября 2010

Вопрос: с точки зрения вашей системы, это одно и то же? Если это так, они принадлежат одной таблице. Если нет, то они принадлежат двум таблицам.

Обычно это просто. «Сотрудник» и «План страхования» - это разные вещи. «Сотрудник по имени Боб» и «Сотрудник по имени Салли» являются двумя примерами одного и того же.

Иногда это сложнее. «Грузовик» и «Лодка» - это разные вещи, или они просто подтипы «Транспортного средства»? Это зависит от точки зрения вашей системы. Если вы продаете их, они, вероятно, то же самое. Вам, наверное, все равно, что один плавает, а другой нет, вам просто важно, сколько они стоят и сколько у вас в наличии и тому подобное. То есть вы храните одни и те же данные о них и используете их в одних и тех же запросах. Но если ваша система управляет рыболовным флотом, а для Лодки вы заботитесь о таких вещах, как, например, члены экипажа, сколько им платят и сколько рыбы они поймали сегодня, а о Грузовике вы заботитесь о таких вещах, как, когда он появится на Стыковка, чтобы забрать сегодняшний улов и сколько вы должны заплатить компании-перевозчику за фунт, это, вероятно, две совершенно разные вещи.

Верные признаки того, что это одно и то же:

  • Они имеют одинаковые данные (конечно, не одинаковые значения, но одинаковые поля)
  • Запросы обычно будут применяться к обоим без каких-либо различий

Если это не так, возможно, это не одно и то же.

То есть, если вы обнаружите, что для типа 1 поле A будет иметь значение, а поле B всегда будет нулевым, в то время как для типа 2 поле A будет нулевым, а поле B будет иметь значение, тогда они не пройдут проверка данных.

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

В вашем примере вы не сказали нам, что вы собираетесь делать с данными, поэтому я не могу обсуждать тест запроса. Очевидно, у вас есть разные данные для двух типов датчиков - число против включения / выключения - так что сразу это голосование за две разные вещи. Но затем мы вернемся к тому, как это на самом деле имеет значение для вашей системы. Если для температурных зондов вы будете составлять графики температуры с течением времени или следить за тем, находятся ли они в определенных диапазонах, а для переключателей включения / выключения вы будете запускать процесс, когда он включается, и останавливать его, когда они выключаются, они, вероятно, будут двумя различными вещи. Если в обоих случаях вы будете создавать отчеты о значении - будь то число или включение / выключение - в любой момент времени, то они могут быть одним и тем же.

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

1 голос
/ 05 октября 2010

Как правило, вы хотите как можно меньше избыточности при проектировании базы данных. Посмотрите на Нормальные формы , что-либо ниже BCNF обычно трудно поддерживать. Некоторые приложения используют больше избыточности для достижения большей производительности при чтении, но жертвуют ясностью и производительностью записи для этого, например хранилища данных. Объединения могут быть медленными, но они лучше противоречивых данных, если одна и та же информация хранится дважды.

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

0 голосов
/ 06 октября 2010

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

Несколько изменений, которые я бы предложил:

  1. Разделите «UpperLimitAlertDelay» и «OnTooLongAlertDelay» на отдельные поля - насколько я понимаю, это разные значения, и поэтому (под 1NF) должны быть отдельными полями.
  2. Добавить поле даты и времени в таблицу чтения.
0 голосов
/ 05 октября 2010

Это довольно стандартное проектное решение, которое необходимо принять при выполнении объектно-реляционного отображения.

Первый вариант, который вы представляете, известен как таблица на иерархию, а второй - таблица на каждуюбетон класса.Существуют и другие варианты, такие как отображение абстрактных классов в их собственных таблицах.Некоторые платформы OR (например, hibernate) предоставляют готовый код для реализации некоторых из этих шаблонов.

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

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

0 голосов
/ 05 октября 2010

Предлагаю действовать согласно правилам нормализации .

В зависимости от ваших потребностей, вы можете выбрать базу данных no-sql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...