Хранение истории состояний в реляционной БД

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

Для решения этой задачи мы применяем 2 подхода, которые внутри нашей команды условно называются «горизонтальная запись» и «вертикальная запись».

Горизонтальная запись

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

Если статуса не было в истории, то в поле с датой должно быть null.

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

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

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

 

Вертикальная запись

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

В данном случае, если статуса не было в истории, то в таблице отсутствует соответствующая запись.

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

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

В свою очередь, чем больше join, тем дольше будет выполняться запрос. На небольшом объеме данных это не критично, но в какой-то момент это может стать проблемой.

Как обычно, какой подход использовать зависит от поставленной задачи. Дьявол кроется в деталях.

Вам также может понравиться...

Популярные посты