Тонут в море нуль - PullRequest
       29

Тонут в море нуль

8 голосов
/ 01 июля 2010

Приложение, которое я унаследовал, отслеживает результаты лабораторных испытаний, выполненных на образцах материала. Данные хранятся в одной таблице (tblSampleData) с первичным ключом SampleID и 235 столбцами, представляющими потенциальные результаты теста. Проблема в том, что для выборки выполняется всего несколько тестов, поэтому каждая строка содержит более 200 нулей. На самом деле есть вторая похожая таблица (tblSampleData2) с еще 215 столбцами, в основном нулевыми, и первичный ключ SampleID. Две таблицы имеют отношение один к одному, и большинство идентификаторов SampleID содержат данные в обеих таблицах. Однако для каждого SampleID легко существует 400 пустых столбцов!

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

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

Ответы [ 10 ]

9 голосов
/ 01 июля 2010

Я видел статьи / статьи, которые указывают, что просто наличие в базе данных NULL нарушает первую нормальную форму.

Из того, что я понял из вашего описания базы данных, лучший дизайн может быть следующим:

Таблица образцов с полями, которые всегда связаны с образцом. Например,

Sample
------ 
SampleID 
SampleDate 
SampleSource

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

TestType
--------
TestTypeID
TestName
MaximumAllowedValue

Наконец, есть промежуточная таблица, которая представляет отношение «многие ко многим» между двумя приведенными выше таблицами и содержит результаты тестов.

TestResult
----------
SampleID
TestTypeID
TestResult

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

4 голосов
/ 01 июля 2010

Вы можете использовать хорошо известную модель Значение атрибута объекта (EAV). Описание того, когда целесообразно использовать EAV, вполне соответствует вашему варианту использования:

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

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

В вашем конкретном случае:

  • Сущность является образцом материала.
  • Атрибут является типом теста.
  • Значение является результатом теста для конкретного образца.

EAV имеет ряд серьезных недостатков и создает ряд трудностей, поэтому его следует применять только тогда, когда это необходимо. Вы не должны использовать его, если вам нужно вернуть все результаты теста для конкретного образца в одну строку.

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

1 голос
/ 01 июля 2010
  1. Возможно, вам даже не нужна СУБД для этих данных .Храните ваши данные в структурированных двоичных файлах или в таблице DBM / ISAM.

  2. Это не нормализовано.Обычно отсутствие нормализации является источником всех ваших проблем.Но в этом случае отсутствие нормализации не конец света, потому что эти данные «только для чтения» , есть только один ключ, и он не связан ни с чем другим.Так что аномалии обновления не должны беспокоить.Вам нужно только беспокоиться о том, что исходные данные непротиворечивы.

  3. Нет ничего слишком страшного со всеми этими NULL , если вы рассматриваете NULL как «специальное значение» с тем же значениемпо всему приложению. Данные не были собраны.Данные не доступны.Субъект отказался отвечать на вопрос.Данные являются выбросами.Данные ожидаютДанные известны как НЕИЗВЕСТНЫЕ.Субъект сказал, что они не знали ... и т.д., вы поняли идею.Разрешение NULL для без определенной причины без определенного значения ужасно неверно.

  4. Я говорю, нормализуй это.Либо определите специальные значения и создайте одну массивную таблицу.Или оставьте NULL для программистов на VB и PHP и правильно разделите ваши данные.Создайте VIEW, чтобы объединить резервные копии данных, если вам нужно поддерживать устаревший код.Из того, что вы описали, вы говорите о двух часах работы, чтобы исправить эту вещь.Это не такая плохая сделка.

1 голос
/ 01 июля 2010

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

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

1 голос
/ 01 июля 2010

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

1 голос
/ 01 июля 2010

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

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

0 голосов
/ 01 июля 2010

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

Вы можете достичь идеальной четвертой нормальной формы, адаптировав систему ключ-значение, как описано другими. Но вы можете существенно улучшить дизайн базы данных и при этом сохранить работоспособность (что сложно сделать при работе с системами ключ-значение без ORM), выполнив одно из следующих действий:

  1. Попытка обнаружить наибольшее количество измерений, необходимых для представления любого отдельного теста. Если тесты возвращают разные типы данных, вам необходимо обнаружить наибольшее количество значений каждого типа данных, возвращаемых самым большим тестом. Создайте таблицу только с этими столбцами, помеченными как Meas1, Meas2 и т. Д. Вместо 400 столбцов вам понадобится, может быть, 10. или 40. Затем создайте набор таблиц, которые описывают, что каждый столбец «означает» для каждого теста. Эта информация может использоваться для предоставления значимых подсказок и заголовков столбцов отчета в зависимости от типа сохраняемого теста. Это не устранит NULL полностью, но значительно уменьшит их, и, поскольку любой новый тест может «вписаться» в число указанных вами измерений, новый тест может быть добавлен как данные, а не как структурные изменения.

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

Надеюсь, это даст некоторые идеи для начала.

0 голосов
/ 01 июля 2010

EAV - это опция, но запросы убьют вас.

Можно ли перенести данные в NoSQL DB, например, MongoDB?Я считаю, что это будет самый эффективный и простой способ решения вашей проблемы.Поскольку вы упоминали, что в основном выполняете CRUD-запросы, NoSQL должен быть довольно эффективным.

0 голосов
/ 01 июля 2010

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

tblTest: testId, testDate tblResult: testId, machineId, channelId, Result

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

0 голосов
/ 01 июля 2010

Я бы пошел с 1 основной таблицей, где у вас будет 1 строка на выборку, она будет содержать все столбцы, которые должны быть в каждой выборке:

Sample
-------
SampleID  int auto increment PK
SampleComment
SampleDate
SampleOrigin
....

Я бы затем добавил одну таблицу длякаждый отдельный тест или «класс» аналогичных тестов и включает все столбцы, связанные с ними (используйте фактическое имя теста, а не XYZ):

TestMethod_XYZ
---------------
SampleID    int FK Sample.SampleID
MeltTemp
BurnTemp
TestPersonID
DateTested
...

TestMethod_ABC
---------------
SampleID    int FK Sample.SampleID
MinImpactForce
TestPersonID
DateTested
....

TestMethod_MNO
---------------
SampleID    int FK Sample.SampleID
ReactionYN
TimeToReact
ReactionType
TestPersonID
DateTested
...

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

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