Я подхожу к проекту, где мне придется создать базу данных с моим боссом; мы очень маленький старт, поэтому рабочая среда глубоко личная.
Ранее он дал мне одну из баз данных компании, и она полностью противоречила тому, чему меня учили (и читали) в школе для RDBMS. Например, здесь есть целые базы данных, которые состоят из одной таблицы (для каждой независимой базы данных). Одна из этих таблиц имеет более 20 столбцов и для контекста, вот некоторые имена столбцов из одной таблицы:
lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngProductID | vrProductName
Дело в том, что там, где у него должны быть отдельные таблицы, в которых хранятся данные сущности (имя, размер, дата покупки и т. Д.), Он помещает их в одну большую таблицу для каждой базы данных.
Я хочу улучшить этот дизайн, но я не уверен, почему правильно нормализованная и сегментированная модель данных действительно улучшит этот продукт. Хотя я знаком с дизайном баз данных из колледжа и понимаю, как это сделать, я не уверен, почему это на самом деле улучшает базы данных.
Почему хорошая реляционная схема улучшает базу данных?
источник
He [the boss] had given me one of his databases before and it completely went against what I was taught (and read about) in school for RDBMS
<- Добро пожаловать в реальный мир!Ответы:
Обычно аргумент производительности является наиболее интуитивным. Вы особенно хотите указать, как трудно будет добавить хорошие индексы в некорректно нормализованную базу данных (примечание: существуют крайние случаи, когда денормализация может фактически повысить производительность, но когда вы оба неопытны с реляционными базами данных, вам, вероятно, будет нелегко увидеть эти случаи).
Другой аргумент - размер хранилища. Денормализованная таблица с большим количеством избыточностей потребует гораздо больше памяти. Это также влияет на производительность: чем больше у вас данных, тем медленнее будут ваши запросы.
Есть также аргумент, который немного сложнее понять, но на самом деле он важнее, потому что вы не можете решить его, добавив больше оборудования. Это проблема согласованности данных. Правильно нормализованная база данных сама позаботится о том, чтобы продукт с определенным идентификатором всегда имел одинаковое имя. Но в денормализованной базе данных такие несоответствия возможны, поэтому необходимо проявлять особую осторожность, чтобы избежать несоответствий, что потребует времени программирования, чтобы все исправить, и все равно приведет к ошибкам, которые обойдутся вам в удовлетворении клиента.
источник
Использование специального программного обеспечения для управления базами данных может быть значительно проще (извините, не устоял).
Если эта база данных заботится только о том, чтобы «регистрировать», какой продукт был продан, где, когда и кем, то вы можете расширить определение «OK database» настолько, чтобы охватить его. Если эти данные используются для чего - то еще, то они действительно довольно бедны.
Но ...
Приложение / запросы, использующие эти данные, отвечают медленно / медленно? Если нет, то настоящей проблемы не существует. Конечно, это выглядит и кажется уродливым, но если это сработает, вы не получите никаких «баллов», если предположить, что «могло бы быть» лучше.
Если вы можете найти определенные симптомы (например, проблемы), которые выглядят так, как будто они вызваны плохим моделированием данных, то создайте прототип лучшего решения. Возьмите копию одной из этих «баз данных», нормализуйте данные и посмотрите, работает ли ваше решение лучше. Если это значительно лучше (и я вполне ожидаю, что любые операции по обновлению этих данных будут значительно улучшены), тогда вернитесь к своему боссу и покажите им улучшение.
Вполне возможно воссоздать его «просмотр одной таблицы» данных с помощью… ну .. видов.
источник
Ответ: это не всегда улучшает базу данных. Вы должны знать, что то, чему вас, вероятно, учили, называется Третьей нормальной формой .
Другие формы действительны в некоторых ситуациях, что является ключом к ответу на ваш вопрос. Ваш пример выглядит как Первая нормальная форма , если это поможет вам лучше понять ее текущее состояние.
Правила 3NF устанавливают отношения между данными, которые «улучшают» базу данных:
Предотвращение попадания недопустимых данных в вашу систему (если отношение равно 1: 1, оно вызывает ошибку, несмотря на код, написанный поверх него). Если ваши данные согласованы в базе данных, это менее вероятно приведет к несоответствиям за пределами вашей базы данных.
Он обеспечивает способ проверки кода (например, отношение «многие к одному» является сигналом для ограничения свойств / поведения объекта). При написании кода для использования базы данных, иногда программисты замечают структуру данных как индикатор того, как должен работать их код. Или они могут предоставить полезную обратную связь, если база данных не соответствует их коду. (К сожалению, это больше похоже на желаемое за действительное)
Предоставьте правила, которые могут помочь вам уменьшить количество ошибок при создании базы данных, чтобы вы не создавали ее на основе произвольных требований, которые могут возникнуть в любое время в течение срока службы базы данных. Вместо этого вы систематически оцениваете информацию для достижения конкретных целей.
Правильные структуры базы данных приводят к повышению производительности благодаря соединению данных способами, которые минимизируют хранение данных, минимизируют обращения к хранилищу для извлечения данных, максимизируют ресурсы в памяти и / или минимизируют сортировку / манипулирование данными для конкретного набора данных, который у вас есть, по сравнению с запросом, которым вы являетесь выполняется против этого. Но «правильная» структура зависит от объема данных, характера данных, типа запроса, системных ресурсов и т. Д. Нормализация может ухудшить производительность (т. Е. Если вы загрузите все данные в виде 1 таблицы - объединение может замедлиться запрос). Обработка транзакций (OLTP) и бизнес-аналитика (хранилище данных) очень разные.
В небольшой компании с небольшими наборами данных вы можете обнаружить, что в этом нет ничего плохого. За исключением того, что если вы будете расти, позже будет сложно «исправить», потому что по мере того, как таблица становится большой, системы, которые ее используют, вероятно, будут работать медленнее.
Обычно вы хотите подчеркнуть быстрые транзакции по мере роста компании. Однако, если вы сейчас тратите время на этот проект, а не на другие вещи, которые могут понадобиться компании в срочном порядке, у вас может никогда не возникнуть такой проблемы, потому что ваша компания никогда не будет расти. Это «задача перед оптимизацией» - где можно провести свое драгоценное время прямо сейчас.
Удачи!
источник
WHERE
предложение. Конечно, они все еще могут пойти не так, но это менее вероятно в нормализованной ситуации, поскольку вам нужно сопоставить только одну строку с помощью первичного ключа.Существует множество причин, по которым использование одной большой «таблицы богов» плохо. Я попытаюсь проиллюстрировать проблемы с помощью примера базы данных. Предположим, вы пытаетесь смоделировать спортивные события. Скажем, вы хотите смоделировать игры и команды, играющие в эти игры. Конструкция с несколькими таблицами может выглядеть следующим образом (это очень упрощенно, поэтому не попадите в места, где можно применить больше нормализации):
и база данных одной таблицы будет выглядеть так
Во-первых, давайте посмотрим на создание индексов на этих таблицах. Если бы мне нужен был указатель на родной город для команды, я мог бы легко добавить его в
Teams
таблицу илиTeamsAndGames
таблицу. Помните, что всякий раз, когда вы создаете индекс, его нужно где-то хранить на диске и обновлять по мере добавления строк в таблицу. В случае сTeams
таблицей это довольно просто. Я положил в новую команду, база данных обновляет индекс. Но как насчетTeamsAndGames
? Ну, то же самое относится и кTeams
пример. Я добавляю команду, индекс обновляется. Но это также происходит, когда я добавляю игру! Даже если это поле будет нулевым для игры, индекс все равно должен быть обновлен и сохранен на диске для этой игры в любом случае. Для одного индекса это звучит не так уж плохо. Но когда вам нужно много индексов для множества сущностей, втиснутых в эту таблицу, вы тратите много места на хранение индексов и много процессорного времени, обновляя их для вещей, к которым они не применяются.Во-вторых, согласованность данных. В случае использования двух отдельных таблиц я могу использовать внешние ключи от
Games
таблицы кTeams
столу, чтобы определить, какие команды играют в игре. И при условии , я делаюHomeTeamId
иAwayTeamId
столбцы не обнуляемым, база данных будет гарантировать , что каждая игра , которую я поставил в есть 2 команды , и что существуют эти команды в моей базе данных. Но как насчет сценария с одним столом? Ну, поскольку в этой таблице есть несколько сущностей, эти столбцы должны быть обнуляемыми (вы можете сделать их не обнуляемыми и засунуть туда данные мусора, но это просто ужасная идея). Если эти столбцы обнуляются, база данных больше не может гарантировать, что при вставке игры в нее входят две команды.Но что, если вы решите просто пойти на это в любом случае? Вы устанавливаете внешние ключи так, чтобы эти поля указывали на другую сущность в той же таблице. Но теперь база данных просто удостоверится, что эти объекты существуют в таблице, а не что они имеют правильный тип. Вы можете очень легко установить
GameHomeTeamId
идентификатор другой игры, и база данных не будет жаловаться вообще. Если вы попробуете это в сценарии с несколькими таблицами, база данных будет соответствовать.Вы можете попытаться смягчить эти проблемы, сказав: «Ну, мы просто позаботимся о том, чтобы мы никогда не делали этого в коде». Если вы уверены в своей способности писать код без ошибок в первый раз и в своей способности учитывать каждую странную комбинацию вещей, которые может попробовать пользователь, продолжайте. Лично я не уверен в своей способности делать что-либо из этого, поэтому я позволю базе данных дать мне дополнительную сеть безопасности.
(Это становится еще хуже, если в вашем проекте вы копируете все релевантные данные между строками вместо использования внешних ключей. Любые несоответствия правописания / других данных будет трудно устранить. или если это было умышленно (потому что это два разных человека)?)
В-третьих, почти каждый столбец должен быть обнуляемым или заполняться скопированными или ненужными данными. Игра не нуждается в
TeamName
илиTeamHomeCity
. Так что либо каждая игра нуждается в каком-то заполнителе, либо она должна быть обнуляемой. И если он обнуляем, база данных с радостью возьмет игру безTeamName
. Также потребуется команда без имени, даже если ваша бизнес-логика говорит, что это никогда не должно произойти.Существует несколько других причин, по которым вам нужны отдельные таблицы (в том числе сохранение здравомыслия разработчика). Есть даже несколько причин, по которым таблица большего размера могла бы быть лучше (денормализация иногда улучшает производительность). Таких сценариев мало, и они далеки друг от друга (и обычно лучше всего их обрабатывать, когда у вас есть показатели производительности, чтобы показать, что это действительно проблема, а не отсутствующий индекс или что-то еще).
Наконец, разработайте что-нибудь, что будет легко поддерживать. То, что это «работает», не означает, что все в порядке. Попытка поддерживать таблицы богов (например, классы богов) - это кошмар. Вы просто настраиваете себя на боль позже.
источник
Цитата дня: « Теория и практика должны быть одинаковыми ... в теории »
Денормализованный стол
Ваша уникальная таблица хранения содержит избыточные данные и имеет одно преимущество: она делает отчеты по строкам очень простыми в коде и быстрыми для выполнения, потому что вам не нужно делать никаких объединений. Но это по высокой цене:
IngCompanyID
иvrCompanyName
). Обновление основных данных может потребовать обновления гораздо большего количества строк, чем в нормализованной схеме.Нормализованный стол
Указанные выше недостатки являются преимуществами для нормализованной схемы. Конечно, запросы могут быть немного более сложными для написания.
Короче говоря, нормализованная схема намного лучше выражает структуру и отношения между вашими данными. Я буду провокационным и скажу, что это такая же разница, как между дисциплиной, необходимой для использования набора заказанных офисных ящиков, и простотой использования мусорного ведра.
источник
Я думаю, что есть как минимум две части вашего вопроса:
1. Почему объекты разных типов не должны храниться в одной и той же таблице?
Наиболее важными ответами здесь являются читаемость кода и скорость. Буква A
SELECT name FROM companies WHERE id = ?
гораздо более удобочитаема, чем буква A,SELECT companyName FROM masterTable WHERE companyId = ?
и вы с меньшей вероятностью случайно запросите ерунду (например,SELECT companyName FROM masterTable WHERE employeeId = ?
это будет невозможно, если компании и сотрудники хранятся в разных таблицах). Что касается скорости, данные из таблицы базы данных извлекаются либо путем последовательного чтения полной таблицы, либо путем чтения из индекса. И то, и другое быстрее, если таблица / индекс содержит меньше данных, и это так, если данные хранятся в разных таблицах (и вам нужно только прочитать одну из таблиц / индексов).2. Почему объекты одного типа должны быть разделены на дочерние объекты, которые хранятся в разных таблицах?
Здесь причина в основном для предотвращения несоответствия данных. При использовании подхода единой таблицы для системы управления заказами вы можете сохранить имя клиента, адрес клиента и идентификатор продукта, заказанного клиентом, как единое целое. Если бы клиент заказал несколько продуктов, в вашей базе данных было бы несколько экземпляров имени и адреса клиента. В лучшем случае, вы просто получили дубликаты данных в вашей базе данных, что может немного замедлить их. Но хуже всего то, что кто-то (или какой-то код) допустил ошибку, когда данные были введены так, что компании в итоге получат разные адреса в вашей базе данных. Это само по себе достаточно плохо. Но если бы вы запросили адрес компании на основе ее названия (например,
SELECT companyAddress FROM orders WHERE companyName = ? LIMIT 1
) вы просто произвольно вернули бы один из двух адресов и даже не поняли бы, что было несоответствие. Но каждый раз, когда вы запускаете запрос, вы можете фактически получить другой адрес, в зависимости от того, как ваш запрос решается внутри СУБД. Это, вероятно, сломает ваше приложение где-то еще, и найти его причину будет очень сложно.При использовании многостолового подхода вы бы поняли, что существует функциональная зависимость от названия компании до адреса компании (если у компании может быть только один адрес), вы бы хранили кортеж (companyName, companyAddress) в одной таблице (например,
company
) и кортеж (productId, companyName) в другой таблице (напримерorder
).UNIQUE
Ограничение наcompany
столе может затем обеспечивать , что каждая компания имеет только один адрес в базе данных , так что никакого несоответствия адресов компании никогда не может возникнуть.Примечание: на практике по причинам производительности вы, вероятно, сгенерировали бы уникальный идентификатор компании для каждой компании и использовали бы его в качестве внешнего ключа вместо непосредственного использования companyName. Но общий подход остается прежним.
источник
TL; DR - Они проектируют базу данных, основываясь на том, как их учили в школе.
Я мог бы написать этот вопрос 10 лет назад. Мне потребовалось некоторое время, чтобы понять, почему мои предшественники создавали свои базы данных так, как они это делали. Вы работаете с кем-то, кто либо:
Я не подозреваю, что это № 1, так как у вас на самом деле есть идентификационные номера в вашей таблице, поэтому я буду считать № 2
После того, как я вышел из школы, я работал в магазине, который использовал AS / 400 (он же IBM i). Я обнаружил некоторые странные вещи в том, как они проектировали свои базы данных, и начал выступать за то, чтобы мы внесли изменения, чтобы следовать тому, как меня учили, как проектировать базы данных. (Я тогда был глуп)
Потребовался терпеливый программист старшего возраста, чтобы объяснить мне, почему все так было сделано. Они не изменили схему, потому что это привело бы к поломке программ, которые были старше меня. Буквально, исходный код для одной программы имел дату создания за год до моего рождения. В системе, над которой мы работали, их программы должны были реализовывать всю логику и операции, которые планировщик запросов вашей базы данных обрабатывает для вас. (Вы можете увидеть это, запустив EXPLAIN для одного из ваших запросов)
Он был в курсе техник, которые я пытался внедрить, но поддерживать работоспособность системы было важнее, чем вносить изменения, «потому что это противоречило тому, чему меня учили». Каждый новый проект, который каждый из нас начинал, наилучшим образом использовал реляционную модель, которую нам удавалось. К сожалению, другие программисты / консультанты того времени все еще проектировали свои базы данных так, как будто они работали с прежними ограничениями этой системы.
Некоторые примеры того, с чем я столкнулся, не соответствовало реляционной модели:
code1,code2, ..., code20
)Все причины, по которым мне были даны эти решения по проектированию, основывались на ограничениях системы, когда база данных создавалась впервые.
Даты - мне сказали, что для использования функции даты (какой месяц, день или день недели) для обработки даты понадобилось больше времени, чем для создания таблицы каждой возможной даты со всей этой информацией.
Последовательные столбцы одного типа - среда программирования, в которой они находились, позволяла программе создавать переменную массива в части строки. И это был более простой способ уменьшить количество операций чтения.
Столбцы CHAR длины NxM. Было проще поместить значения конфигурации в один столбец, чтобы уменьшить количество операций чтения файлов.
Плохо продуманный пример на С, эквивалентный для отражения среды программирования, которую они имели:
Согласно тому, что мне сказали, в то время это считалось лучшей практикой.
источник