Нормализация базы данных: использование отдельных таблиц для хранения одного поля

В настоящее время наша база данных настроена таким образом, что платежная транзакция записывает идентификатор типа платежа, а это связано с таблицей типа платежа (наличными, чеком, кредитом), которая содержит эти значения. Пример:

Платежная транзакция:

  • ID
  • Количество
  • Дата
  • Идентификатор типа платежа

Тип платежа:

  • ID
  • Тип оплаты (наличные, кредит)

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

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

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

Плюсы

  • Удаляет в основном ненужное соединение всякий раз, когда необходимо найти тип платежа.
  • Тип платежа для транзакции всегда будет точно отражать то, что было на момент регистрации транзакции. т. е. если я изменю запись «Наличные» в таблице типов платежей на «Кредит» (по какой-либо причине), все платежные транзакции, которые связаны с наличными, теперь будут связаны с кредитом.

Минусы

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

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


person ACobbs    schedule 11.03.2012    source источник


Ответы (2)


Я не согласен ни с одним из ваших аргументов за.

Удаляет в основном ненужное соединение всякий раз, когда необходимо найти тип платежа.

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

Тип платежа для транзакции всегда будет точно отражать то, что было на момент регистрации транзакции. т. е. если я изменю запись «Наличные» в таблице типов платежей на «Кредит» (по какой-либо причине), все платежные транзакции, которые связаны с наличными, теперь будут связаны с кредитом.

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

Любая реляционная база данных может обрабатывать JOIN и нормализованные таблицы. Боюсь, вы виновны в преждевременной оптимизации.

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

person duffymo    schedule 11.03.2012
comment
Я действительно говорю более конкретно о преимуществах, которые они предлагают разработчику/моему ленивому «я». Я знаю, что JOIN практически не повлияет на производительность, но гораздо приятнее написать запрос без этого JOIN, если это возможно. То же самое касается изменения типов платежей: у пользователя нет возможности сделать это, но нам довольно часто приходится менять типы платежей. Вместо того, чтобы полагаться на различные идентификаторы, я думаю, что гораздо лучше полагаться на статические «Наличные» или «Кредит», поскольку текстовое значение никогда не будет сильно меняться. - person ACobbs; 11.03.2012
comment
Никакой выгоды я не вижу. Я не согласен, что это лучше. Я бы поспорил с этим, но это ваша схема. - person duffymo; 11.03.2012
comment
Думаю, тогда я просто оставлю все как есть. Менять половину приложения каждый раз, когда меняется тип платежа, действительно неприятно, но я бы предпочел не отставать от лучших практик. Спасибо! - person ACobbs; 11.03.2012
comment
Как я уже сказал, я бы рекомендовал изменение типа платежа как отдельную транзакцию с собственной отметкой времени. Как вы сказали, вы хотите сохранить тип платежа, который был в день, когда был сделан оригинал, и когда произошло изменение. Вы не получите этого с UPDATE, если у вас нет триггера для его записи. - person duffymo; 11.03.2012

Если вы удалите таблицу PaymentType, вы замените проверку внешнего ключа ограничением CHECK таблицы:

PaymentType   CHAR(6) NOT NULL CHECK(PaymentType IN('Cash', 'Credit', 'Cheque')

Хорошо, вы пишете «чек» как «чек»; просто еще одно различие между английским и американским.

Теперь это значительно усложняет поиск возможных значений; вы должны проанализировать системный каталог, чтобы узнать. С отдельной таблицей вы можете изучить отдельную таблицу, чтобы узнать, что разрешено. Предположим, вы начинаете отслеживать «Дебет» отдельно от «Кредит»; вы добавляете строку в таблицу вместо изменения схемы таблицы. Предположим, вы решили, что вам нужно записывать, какие коды разрешены в будущих транзакциях (поэтому вариант «Наличные» перестает быть вариантом). Вы можете добавить столбец в таблицу «Тип платежа», чтобы указать, что этот код больше не действителен; гораздо сложнее сделать это с помощью простого ограничения CHECK.

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

Однако, если бы это был мой дизайн, я бы, вероятно, использовал код CHAR (1) или CHAR (2) в качестве идентификатора типа платежа, а не числовой столбец. Конечно, все три типа начинаются с «C», поэтому, возможно, вы должны использовать «A» для наличных денег, «H» для проверки и «R» для cRedit (и, возможно, «D» или «E» для дебета или дебета) с кодом CHAR(1); с CHAR(2) вы должны использовать 'CA', 'CH', 'CR' (и, возможно, 'DE'). Полное имя можно сохранить в таблице типов платежей для использования в отчетах. В этом случае преимущества невелики, но экономия 4 байтов на запись при достаточном количестве записей (достаточно большом количестве достаточно маленьких записей) может стать фактором ваших затрат на хранение. Конечно, накладные расходы на индекс также вступают в игру; если столбец в таблице «Платежная транзакция» должен быть проиндексирован, меньшее поле занимает меньше места в индексе.

person Jonathan Leffler    schedule 11.03.2012