Стоит ли отходить от нормализации бд, чтобы улучшить производительность?
Смысл следующий, есть таблица payments - в которую записывается история денежного оборота.
Например:
- пользователь выводит средства: создается запись в таблице withdrawals и запись в payments
- пользователь переводит средства: создается запись в таблице transfers и запись в payments
- пользователь активирует аккаунт: создается запись в таблице activations и запись в payments
Тоесть любое изменение пользовательского счета фиксируется в payments, а так-же по необходимости в других таблицах.
В пользователя в кабинете есть кнопка: "История денежного оборота", куда он нажимает и попадает в таблицу, которая представлена списком его денежных операций. Все было хорошо до тех пор, пока не попросили выводить комментарий, что вообще произошло (тоесть какая система сняла или начислили средства).
Например:
30.09.2016, 15:00 Перевод средств Пользователю Вася
Все бы хорошо, но я не как не делаю связь между сущностями и историей денежного перевода. Тоесть у меня есть идентификаторы, что произошло type и system, например был подтвержденный перевод средств, а кто и или что его сделал мне было не важно.
Теперь собственно задача показать например логин того, кому были переведены средства. Это уже есть в таблице transfers и необходимо еще продублировать в payments.
У меня есть 2 варианта.
1) завести entity_id и хранить идентификатор на запись из нужной таблицы, а зная type и system уже делать манипуляции. - минус такого подхода в том, что если я вывожу 100 записей на экран, мне нужно постоянно их джоинить в некоторых случаях даже очень жирно джойнить. - еще 1 минус в том, что так как entity_id будет связываться с разными таблицами, в нее невозможно поставить индекс, что не гарантирует целостность.
2) создать текстовое поле data и засовывать туда просто логин ну и другую необходимую информацию. - минус такого подхода в том, что если пользователь поменяет логин (а такое конкретно у нас частое явление из-за перепродажи аккаунтов), то история уже будет показывать неверные данные.
Я прикинул следующее, я воспользуюсь обоими подходами, буду показывать данные из текстового поля, но с помощью entity_id по крону обходить историю денежного оборота и перепроверять данные пользователей например раз в день.
Что вы можете мне посоветовать или подсказать в данном вопросе ?
soulness: там повторение из-за того, что необходима в определенных случая модерация, а история денежного оборота это общий сток так сказать. Поэтому гдето 90%, что у меня там все нормализированно =)
Не прочёл весь текст вопроса, но с уверенностью могу сказать "ДА"! Любая реальная разработка - это баланс между строгостью и производительностью. Во всех статьях по нормализации, говорится что можно всё таки денормализировать базу для повышения производительности.
Порой для создания отчетов действительно проводят денормализацию с целью повышения производительности. Но в вашем случае мне кажется нужно смотреть в другую сторону - к примеру подумать об индексах или может сами запросы не оптимальны.
Индексы есть, как минимум их внешние ключи сами проставляют. Но но смотрите есть табилца сущности например перевод средств (так как перевод может быть на модерации нужна отдельная таблица), там реляция на пользователя, в котором в свою очередь реляция на профиль.
Получается чтобы вывести например 100 записей истории денежного оборота и показать ФИО тому, кому отправили средства нужно: джоин к сущности переводов, джоин к пользователю и джоин к профилю и так каждый раз. Тоесть вроде конечно удобно никаких проблем, но производительность уже заметно падает.
soulness: ну а что на счет прогресса ? Сегодня в базе 10 000 щаписей, завтра 100000, а после завтра 1000000, и сделать выборку 100 записей на страницу с джоинами учитывая что есть все индексы будет легко ? Я просто не знаю, не доходил до такого.
Можно завести ещё одну таблицу - список тех, кто поменял что-то совсем недавно и для него надо обновить вычисленное поле. Проходить только по ней. Сократит время обновления.
Или перевычислять это поле по факту изменений, но асинхронно, через очереди.
тут к сожалению стартаперский драйв, в стиле это нужно сделать на вчера, я пока не так хорошо знаю очереди (тот-же RebbitMQ), что бы его прилепить, настроить и организовать за 5 часов =(.
Изложен все довольно сумбурно. Денормализация имеет смысл, только тогда, когда профит от выигрыша в производительности выборки покрывает пенальти от объема хранения, скорости выборки и скорости вставки, а так же пенальти на поддержку данной системы.
Если мы говорим от денормализации для целей вывода информации пользователю, то чаще всего такая операция не оправдана, проще выполнить данную операцию на стороне пользователя.
В вашем случае, насколько я понял, таблица payments являеться технической, ее наличие само по себе уже денормализация( вы отдельно храните дубли данных, которые можно получить из других источников ), следовательно она зачем-то нужна. Если она нужна для ускорения технических операций( например предварительный пересчет суммы счета ), то ввод в нее доп.полей которые не нужны для данных операций это ошибка. Если цель ее существования быстрый вывод пользователю суммарной и сжатой информации по операциям, то нам в ней нужна вся информация которую одновременно хочет видеть пользователь без выполнения под запросов к целевым таблицам.
Проблема с entity_id вполне обходиться через последовательности. Найтивной реализации в MySQL нет, но есть различные велосипеды. Причем здесь индекс вообще не понятно, может быть вы имели ввиду внешний ключ.
Если создавать поле дата, то его можно сделать json или xml с произвольно структурой. Зачем его обновлять не очень понятно, это поле используется исключительно для ускорения вывода информации, и выводит информацию в таком виде в котором она была на момент операции.
было бы здорово, если бы не так печально. Когда есть несколько языков, когда логины могут меняться, и почти 90% всей инфы динамическая. Просто строчку "Вася привет, тебе начислено 10$" записать не получится, так как все кроме 10$ может меняться в зависимости от определенных условий.
nepster09: И пусть меняется, но на тот момент был Вася, а значит операция для Васи, значит Васю там и следует оставить. От того, что Вася теперь Петя, перевод не стал для Пети, Вася уже давно мог эти деньги вывести, а вопросы теперь будут к Пете, хотя он здесь вообще не пределах.
Вообще передача аккаунтов изначально говорит о проблемах в системе, аккаунт это идентификация определенного лица и передать его нельзя ну просто никак.
nApoBo3: я про смену логинов. Вы купили 10 аккаунтов вася1 - вася 10, потом продали 1 аккаунт мне, я не хочу быть васей 2, я меняю себе логин. А по васе 2 уже было не меньше 10 начислений. У всех в истории вася 2, а такого пользователя уже нет в проекте. =)
nepster09: Но начисления, то были Васе2. Дальше пользователь может открыть ссылку на Васю два( id пользователя то не сменился ) и видит, что теперь это Петя4, может посмотреть, что 2008-11 это был Леша 743, потом 2009-12 стал Вася 2, а 2015-09 стал Петя4.
В конце концов, вы можете выдать пользователю только id. Потом сделать под запрос по этим ид и показать пользователю имя.
Зачем вам вообще таблица payments?