Дизайн базы данных инвентаризации

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

В прошлом я разрабатывал системы, которые тем или иным образом вели инвентаризацию предметов (неважно, какие предметы). Некоторые используют языки/БД, которые не поддерживают транзакции. В таких случаях я решил не сохранять количество товара в наличии в поле записи товара. Вместо этого количество в наличии рассчитывается как сумма полученных запасов — всего проданных запасов. Это привело к почти полному отсутствию расхождений в инвентаризации из-за программного обеспечения. Таблицы правильно проиндексированы, и производительность хорошая. Существует процесс архивирования на случай, если количество записей начнет влиять на производительность.

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

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

Спасибо


person nmarmol    schedule 13.11.2008    source источник
comment
Когда вы говорите, что предыдущие программисты здесь клянутся этим, вы имеете в виду, что они ругаются каждый раз, когда им приходится над этим работать?   -  person MusiGenesis    schedule 13.11.2008


Ответы (12)


Я видел оба подхода в своей нынешней компании и определенно склоняюсь к первому (расчет итогов на основе операций с акциями).

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

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

person Neil Aitken    schedule 13.11.2008
comment
+1 У меня была такая же дилемма, и теперь я думаю, что это лучший выбор - person INS; 10.11.2010
comment
@Neil - можете ли вы прокомментировать эффективность этого подхода. это кажется предпочтительным подходом, но если у вас есть сотни продуктов и тысячи транзакций, как и когда вы рассчитываете совокупные итоги. или вы просто храните совокупную сумму в другом месте, зная, что можете пересчитать, если это необходимо? - person Simon_Weaver; 14.07.2011
comment
@Simon Само собой разумеется, что это будет значительно менее эффективно, чем просто запрос одного поля. Я должен сказать, что я никогда не профилировал его с большим количеством продуктов. Было бы лучше попробовать это и посмотреть, какой удар по производительности вы получите в своем наборе данных. Затем решить, стоит ли где-то кэшировать количество. - person Neil Aitken; 14.07.2011
comment
Я провел тест — я разместил около 3 миллионов записей (с положительными и отрицательными корректировками запасов) по 2000 продуктам. Всего доли секунды потребовалось, чтобы подсчитать общую сумму всех строк, сгруппированных по SKU. Я должен сказать, что был совершенно поражен тем, как быстро это сработало, и для проекта, который я делаю, у меня определенно есть запасы роста на порядки, и мне не нужно будет беспокоиться об этом в ближайшее время. Очевидно, что если вы отображаете итоговые данные о запасах в реальном времени на веб-сайте, вы, вероятно, захотите их кэшировать, но даже по всем 2000 продуктам я могу почти мгновенно подсчитать общие суммы. - person Simon_Weaver; 19.07.2011
comment
@Simon_Weaver, приятно это слышать. Рад видеть, что этот метод имеет достойную производительность в вашей ситуации, так как это определенно мой предпочтительный метод управления запасами. - person Neil Aitken; 19.07.2011
comment
Банковские/бухгалтерские системы делают что-то подобное с транзакциями (дебет или кредит) часто как отдельные поля, но с тем же эффектом суммирования. В первую очередь по операционным причинам создается ежемесячный баланс (обычно существует процесс окончания месяца проверки), но это также метод, позволяющий сложить 12 месячных значений дельты, чтобы быстро сложить год вместо каждой транзакции в году. . Когда это делается в течение многих лет и миллионов учетных записей, выигрыш в производительности является реальным, а также позволяет исправить несколько месяцев назад, чтобы потребовать только пересчета закрытия этого месяца. - person ClearCrescendo; 02.05.2014
comment
Вы должны применить оба, 1 поле для количества и 1 таблицу для транзакции. Поле количества может пересчитываться при необходимости. Вам нужно это поле, потому что производительность. Когда конец месяца. мы должны переместить все числовые формы до месяца в новый месяц. Это моя система ERP работает. и хорошо работает - person Grey Wolf; 16.11.2015


Это зависит от того, системы инвентаризации — это гораздо больше, чем просто подсчет предметов. Например, для целей бухгалтерского учета вам может потребоваться знать учетную стоимость запасов на основе модели FIFO (First In First Out). Это нельзя рассчитать по простой формуле «сумма полученных запасов - общая сумма проданных запасов». Но их модель может легко вычислить это, потому что они изменяют учетную стоимость по ходу дела. Я не хочу вдаваться в подробности, потому что это не проблема программирования, но если они клянутся этим, возможно, вы не полностью поняли все их требования, которые они должны выполнить.

person lubos hasko    schedule 13.11.2008

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

  • количество элементов для суммирования относительно невелико
  • есть несколько или нет исключительных случаев для рассмотрения (возвраты, корректировки и т. д.)
  • количество предмета инвентаря не требуется очень часто

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

также обратите внимание, что если в вашей системе есть несоответствия, то в ней есть ошибки, которые следует отследить и устранить.

Я делал системы в обоих направлениях, и оба пути могут работать просто отлично, если вы не игнорируете ошибки!

person Steven A. Lowe    schedule 13.11.2008
comment
хм. возврат не является действительно исключительным, не так ли? если только вы не продаете скоропортящиеся товары или что-то еще, что нельзя перепродать. - person Simon_Weaver; 14.06.2011
comment
@Simon: одна из первых систем инвентаризации, которую я написал, была для магазина мороженого на заказ. Возвраты были не только исключительными, но и практически невозможными ;-) - person Steven A. Lowe; 14.06.2011

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

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

Если вы хотите увидеть, как работает большое приложение, взгляните на SugarCRM, хотя у них есть и модуль управления запасами. Я не уверен, как он хранит данные.

person Eric Goodwin    schedule 13.11.2008

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

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

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

person MusiGenesis    schedule 13.11.2008

Я бы выбрал первый путь, где

количество в наличии рассчитывается путем суммирования полученных запасов - общего количества проданных запасов

Правильный путь, имхо.

РЕДАКТИРОВАТЬ: я также хотел бы учитывать любые потери/повреждения запасов в системе, но я уверен, что вы это предусмотрели.

person Galwegian    schedule 13.11.2008

Раньше я работал над системами, решающими эту проблему. Я думаю, что идеальным решением является столбец с предварительным вычислением, который дает вам лучшее из обоих миров. Ваша сумма будет где-то полем, поэтому нет дорогостоящих поисков, но она не может рассинхронизироваться с остальными вашими данными (база данных поддерживает целостность). Я не помню, какие RDMS поддерживают предварительно вычисляемые столбцы, но если у вас нет транзакций, они тоже могут быть недоступны.

Вы потенциально можете подделать предварительно вычисленные столбцы (очень эффективно... я не вижу недостатков), используя триггеры. Однако вам, вероятно, понадобятся транзакции. ИМХО, сохранение целостности данных при такой контролируемой денормализации является единственным законным использованием триггера.

person rmeador    schedule 13.11.2008

Django-inventory больше ориентирован на основные средства, но может дать вам некоторые идеи.

IE: ItemTemplate (класс) -> ItemsOnHand (экземпляр)

ItemsOnHand можно связать с большим количеством ItemTemplates; Пример Требуется принтер и чернильные картриджи. Это также позволяет устанавливать точки повторного заказа для каждого ItemOnHand.

Каждый ItemsOnHand связан с InventoryTransactions, что позволяет легко проводить аудит. Чтобы избежать подсчета фактических товаров в наличии из тысяч инвентарных транзакций, используются контрольные точки, которые представляют собой просто баланс + дату. Чтобы рассчитать товары в наличии, запросите самую последнюю контрольную точку и начните добавлять или вычитать товары, чтобы найти текущий баланс товаров. Периодически определяйте новые контрольные точки.

person Roberto Rosario    schedule 03.10.2009

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

person JoeBloggs    schedule 13.11.2008

Не имеет одного или двух столбцов, то, что я имел в виду под «суммарный полученный инвентарь - общее количество проданного инвентаря», выглядит примерно так:

Select sum(quantity) as inventory_received from Inventory_entry
Select sum(quantity) as inventory_sold from Sales_items

потом

Qunatity_on_hand = inventory_received - inventory_sold

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

Также я хотел упомянуть, что, хотя это не вопрос «кодирования», он связан с алгоритмами и дизайном, которые, ИМХО, являются очень важными темами.

Спасибо всем за ваши ответы.

Нельсон Мармол

person nmarmol    schedule 13.11.2008
comment
Недостаток этого конкретного решения заключается в том, что производительность со временем будет становиться все хуже и хуже, так как вы должны постоянно вести учет всех когда-либо полученных или проданных запасов, чтобы получить правильное текущее количество! - person Steven A. Lowe; 13.11.2008

Мы решаем разные задачи, но наш подход к некоторым из них может быть вам интересен.

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

Чтобы применить это к инвентарю, у вас может быть 3 поля:

inventory_received
inventory_sold
estimated_on_hand

Затем вы можете запускать процесс (ежедневно?) в следующем порядке:

SELECT * 
FROM   Inventory
WHERE  estimated_on_hand != inventory_received - inventory_sold

Конечно, это зависит от того, просматривают ли пользователи это оповещение и что-то с этим делают.

Кроме того, у вас может быть функция для сброса инвентаря, либо путем обновления inventory_sold/received, либо, возможно, путем добавления другого поля «inventory_adjustment», которое может быть положительным или отрицательным.

... просто некоторые мысли. Надеюсь, это полезно.

person AJ.    schedule 13.11.2008