Таблиця замовлень електронної комерції. Зберегти ціни чи використовувати таблицю аудиту / історії?


13

Я розробляю свою першу схему електронної комерції. Я дещо читав цю тему і трохи розгублений щодо стосунків між a order_line_itemі aproduct

А productможна придбати. У ньому є різні деталі, але найголовніше unit_price.

У order_line_itemіноземного ключа є product_idкуплений, quantityпридбаний та unit_priceв той момент, коли клієнт придбав товар.

Більшість того, що я прочитав, говорить про те, що значення unit_priceon order_line_itemмає бути явно додане (тобто не посилатися через product_id). Має сенс, оскільки магазин може змінити ціну в майбутньому, що зіпсує звіти про замовлення, відстеження, цілісність тощо.

Те, що я не розумію, це чому безпосередньо зберігати unit_priceзначення на order_line_item?

Чи не було б краще створити таблицю аудиту / історії, яка документує unit_priceзміну product?

Коли order_line_itemстворюється, product_auditдодається зовнішній ключ таблиці, і звідти можна отримати ціну (за посиланням).

Мені здається, є багато позитивних при використанні цього підходу (менше дублювання даних, історія зміни цін тощо), так чому ж він частіше не використовується? Я не натрапив на приклад схеми електронної комерції, яка використовує такий підхід, я щось пропускаю?

UDPATE: Схоже, моє запитання стосується повільно мінливого виміру . Я все ще плутаюсь, хоча повільно змінюється параметр стосується сховища даних та OLAP. Тож чи можна застосувати типи повільних змін до моєї основної бази даних процесів бізнес-транзакцій (OLTP)? Цікаво, чи змішую я багато понять, дуже вдячний за деякі вказівки.


Я б насправді робив і те, і інше: зберігайте продажну ціну в порядку_лінії та зберігайте історію цін на продукцію. Тому що обидва служать різним цілям. Зберігання ціни продажу дозволить зробити запити на замовлення набагато простішими та швидшими. З іншого боку, ви можете отримати старі ціни навіть на продукти, які не продавались.
a_horse_with_no_name

Звичайно, спрощення запитів на замовлення не може бути єдиним драйвером, що зберігає остаточну ціну кожного разу. Зрештою, це реляційна база даних - запити не будуть набагато складнішими.
Gaz_Edge

3
Зберігання ціни продажу в рядку замовлення не є "нереляційним" (і я вважаю, що це нормалізується, так як ціни продажу - на мою думку, прямий атрибут рядка замовлення). Мистецтво використання реляційної бази даних полягає у знанні меж. Якщо ви керуєте магазином зі 100 продуктами та 5 замовленнями на день, зберігання та отримання старих цін не є проблемою. Якщо ви працюєте на ринку з мільйонами продуктів, тисячами дилерів і безліччю замовлень на хвилину, то запитувати, що історія буде проблемою.
a_horse_with_no_name

Де б ви зберігали ціни на історію? З того, що я читаю, мені знадобляться дві бази даних. Один для OLTP, один для OLAP. Історія йде в OLAP?
Gaz_Edge

Відповіді:


10

Як ви визначили, зберігання ціни на замовлення полегшує технічну реалізацію. Однак є ряд ділових причин, чому це може бути корисним.

Окрім веб-транзакцій, багато підприємств підтримують продаж через інші канали, наприклад:

  • По телефону
  • Агенти з продажу "в дорозі"
  • У фізичному місці (наприклад, магазин, офіс)

У цих випадках замовлення може бути введено в систему через деякий час після здійснення транзакції. За цих обставин може бути важко неможливо правильно визначити, який історичний облік цін слід використовувати - зберігання одиничної ціни безпосередньо на замовлення є єдино можливим варіантом.

Кілька каналів часто викликають ще одне завдання - різні ціни на той самий товар. Доплати за телефонні замовлення є загальними - і деякі клієнти можуть домовитись про знижку. Ви можете представляти всі можливі ціни на всі канали у вашій схемі товарів, але включення цього до таблиць замовлень може стати (дуже) складним.

У будь-якому місці, де домовленості дозволені, стає дуже важко пов'язати історію цін з узгодженою ціною замовлення (якщо тільки агенти мають дуже вузькі межі переговорів). Ціну потрібно зберігати під самим замовленням.

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

Нарешті, багато підприємств починають використовувати дуже динамічне ціноутворення. Для даного товару може бути не одна фіксована ціна - вона завжди розраховується під час виконання на основі таких факторів, як час доби, попит на товар тощо. У цих випадках ціна може не зберігатися в першу чергу щодо товару!


3

Я додам кілька практичних моментів, які я бачив.

  1. Продукти є тимчасовими.

    Те, що вони можуть означати сьогодні, може не збігатися з тим, що вони використовували для позначення року назад. Один і той же код (і, отже, product_id) може на різних етапах ставитися до різного варіанту / виду товару.

    Не всі розуміють усі занепокоєння під рукою; отже, користувач може змінити атрибути оригінального продукту замість того, щоб створити свіжий із власного невігластва. Дуже багато разів це могло статися через те, що в плані користувач (Гей! У мене може бути лише 100 ску, тож чому б не продовжувати змінювати старіші замість оновлення плану) Тож, бачте, у безлічі візків , продукт ніколи не буде означати одне й те саме.

  2. Різні ціни залежно від умов замовлення та доставки

    Як зазначав користувач @Chris, в різних сценаріях можуть застосовуватися різні ціни.

    У більшості візків ви знайдете щонайменше 3 різні поля, які зберігаються - ціна одиниці, сума знижки та ціна зі знижкою. У більш просунутих ви знайдете ще 2 - ціна одиниці з податком, ціна зі знижкою з податком. Ви можете знайти ще кілька полів для опису плати за спосіб доставки та додаткових платежів. Відсоток податку може змінюватись в залежності від штату, товару, країни, способу доставки тощо, і так само, як і інші керівники витрат. Аналогічно знижки можуть змінюватися залежно від географії, акцій, часу продажу тощо. Отже, є інформація, яку можна отримати лише на рівні замовлення, і ця об'єднана інформація не може бути сформована лише з даних у таблиці продуктів.

  3. Розділення проблем

    Багато кошиків реалізовані таким чином, щоб різні команди могли мати контроль над різними частинами даних. Хтось, хто керує системою замовлень, не завжди повинен знати, яка вся продукція є на складі, які там були ціни в різний момент часу, які є альтернативи для даного sku тощо. Збереження пов’язаних із продуктами даних разом із даними замовлення допомагає досягти роз'єднання проблем. Це може бути справедливим і на етапах розробки, якщо різні команди керують різними частинами системи.

  4. Легша масштабованість у кількох системах

    Багато разів система управління замовленнями, система управління правилами, система управління каталогами, система управління вмістом створюються / підтримуються як окремі власні системи. Це допомагає оптимізувати різні умови навантаження та генерувати спеціалізований інтелект для кожної системи. Тоді одна система не може бути притягнута до викупу через недоступність інформації з іншої системи.

  5. Швидший розвиток та час роботи

    Я тут використовував термін "час розробки", хоча використання "часу налагодження" було б більш доречним. Кожного разу, коли відбувається будь-яка нова розробка, буде швидше, якщо потрібні дані будуть доступні, не додаючи власних складностей, оскільки тоді будуть порівняно менші цикли налагодження.

    Уявіть, що вас попросили генерувати звіти за запитом на знижки, що пропонуються щоденно протягом даного місяця півроку назад. Якщо у вас є початкова ціна, знижена ціна в 1-2 таблицях разом із замовленням, деталями деталей замовлення, це майже вперед. Якщо ж вам доведеться перейти і отримати ціни з іншої таблиці, а потім застосувати знижки з іншої таблиці, а потім розібратися в деталях, і час розробки, і час роботи будуть вище.

Хороший дизайн повинен намагатися максимально оптимізувати майбутнє, як і теперішнє.


2

Це може закінчитися дорожче за зберігання, але я вважаю за краще зберігати всі релевантні деталі продажу разом із самою транзакцією, так що якщо з якої-небудь причини наш аудиторський слід буде порушений або адміністратор замінить безпеку на місці, деталі продаж на зразок: валюта, що використовується, ціна одиниці продукції, кількість, застосовувані податки та ін. Я зазвичай зберігаю це як XML, щоб він міг бути гнучким від продажу до продажу.


EDIT: Щоб розширити те, про що я коротко говорив вище, в коментарях, що додаються нижче, і те, що @a_horse_with_no_name торкнулося вище, надмірність даних транзакцій не тільки важлива, але й необхідна в масштабі.

Я припускаю, що ви будуєте за допомогою OOP, і тому ви, ймовірно, повинні мати об'єкт транзакції і або весь об'єкт продукту та / або ціновий об'єкт. На моєму особистому досвіді я вважаю за краще бути багатослівним у своїй історії, зберігання відносно привабливе.

Що ми зробили, це створити історію об’єктів, яку можна полегшити за допомогою наявного RDBMS або деякого аромату зберігання ключових значень NOSQL (а ще краще RDBMS, який дозволяє з'єднання типу NoSQL, наприклад обробник сокета або мемоша), і ми зберігаємо історію об'єктів Таким чином, із кожною деталлю та зміною ціни в одному місці легко та швидко можна придбати. Якщо ви серйозно, можете навіть використовувати DIFF, щоб заощадити на сховищі та зберігати зміни лише вперед, хоча у нього є власні застереження. Це повинно піклуватися про вашу історію, і перевага серіалізованих об'єктів полягає в тому, що ваша система зможе повернути їх назад як об’єкти, які вони зберігалися. Це піклується про історію.

Що стосується моєї пропозиції, зберігання реквізитів транзакцій, таких як податки, валюта та ін., А сама транзакція означає, що немає необхідності шукати ці деталі в іншому місці, ваш об’єкт транзакції буде відомий про його властивості, і ви, погляди, можете подбати про подання різні дані, як вважаєте за потрібне. Ви отримуєте швидкий доступ до знімка і отримуєте додаткову перевагу надмірних і перевірених записів.

Варто того, повірте!


це не має сенсу говорити, що ви не використовуєте його, оскільки його можна видалити. Ви можете змінити будь-які дані. Будь-яка стратегія повинна зберігати резервні копії
Gaz_Edge

@Gaz_Edge Вони не є взаємовиключними, ви все ще можете використовувати аудиторський слід та зберігати деталі з транзакціями, надмірність у цьому випадку виправдана. Ніколи не залишайте себе з даними цього важливого предмета жодної точки збою. У нашому випадку я використовую централізований об’єкт-магазин як механізм історії, а не намагаюся створити історію за типом об'єкта (наприклад, транзакцію чи продукт у цьому випадку). У мене буде як весь об'єкт транзакції в історії, але всі найважливіші деталі із самою записом. Це повністю осторонь предметів продукту в історії.
унциль

що робити, якщо я хотів запускати звіти про замовлення? Як, наприклад, скільки товару x було придбано? Або скільки замовлень понад y сума? Збереження XML означає, що ви втрачаєте можливість запиту даних, якщо я не помиляюся
Gaz_Edge

@Gaz_Edge Неправда, якщо ви говорите на MySQL, у вас є SELECT ExtractValue(field_name, '/x/path/');можливість фільтрувати такі речі, як усі транзакції у певній валюті або всі транзакції з певним мінімальним значенням податку чи будь-яким іншим. Звіти більшого масштабу можна робити з історії об’єктів. Для звітів з більшим масштабом ви можете налаштувати elasticsearchсервер / екземпляр, який має звіт про стиль BigData, і він легко розширюється на багато мільйонів документів +.
унциль

@Gaz_Edge Я також зазначу, що звіти, про які ви говорите (покупки за вартістю, продажі товару тощо), є загальними звітами, і вони повинні мати значення, що зберігаються у стовпчикових значеннях із записом транзакцій для швидшої обробки. Все, що важливо, але про це не обов'язково повідомляється часто, може перейти до XML. Дані знімків дійсно стосуються лише двох речей: 1. Проблема повільно змінюється розміру та 2. Валідація та порівняння, коли клієнт скаржиться, і вам потрібно швидко зрозуміти, хто прав. Це не для щоденного використання.
унциль

1

Моє голосування було б зберігати одиничну ціну на позиції та відстежувати історію цін на ваші товари в окремій таблиці. Моє виправдання цьому полягає в додатковій гнучкості.

Навіть якщо ваша структура цін є жорсткою та чітко визначеною та не допускає варіацій, про які згадував @Chris Saxon, вам комфортно, що це завжди буде так? Навіть якщо ви впевнені, навіщо малювати себе в кутку? Я думаю, що було б корисно зберігати це на деталі позиції, тому що я не можу придумати вагомих причин тримати її окремо.

Що стосується зберігання вашої історії ціноутворення, то тут зберігається певна цінність, щоб зберігати її окремо, оскільки в ціні товару можуть бути зміни, і ніхто їх не купував. Це, безумовно, буде корисною інформацією, щоб знати, чи зміна ціни неефективна. Як ви вже згадували, це сценарій класичного використання типу 2, який повільно змінює розмір, у сценарії сховища даних. Зазвичай будь-яка зміна ціни у вашій таблиці товарів буде зафіксована, і новий рядок буде доданий до таблиці вимірів із оновленою ціною та часовою маркою, щоб вказати, коли ця зміна відбулася. У попередньому рядку оновлена ​​дата закінчення вказуватиме, що це вже не ефективна ціна. Таким чином, одним із підходів було б відстеження подібних змін у сховищі даних.

Однак якщо ви не хочете займатися розробкою схеми сховища даних та процесом ETL одночасно з розробкою вашої бази даних електронної комерції OLTP, то ця історія, безумовно, може бути зафіксована в нашій базі даних електронної комерції. Це можна зробити так, як ви описали, створивши окрему таблицю product_audit, яка висить з таблиці продуктів і містить дати початку та кінця, коли діяла ця версія продукту. Це також можна зробити в самій таблиці продуктів, додавши в таблицю дати початку та кінця, щоб вказати, який продукт зараз активний. Однак, залежно від кількості товарів та кількості чи змін цін, які зазнає ваша компанія, це може зробити вашу таблицю товарів значно більшою, ніж планувалося, і згодом може викликати проблеми з виконанням запитів.

Нарешті, відокремлення вашої історії ціноутворення від фактичної одиничної ціни на позицію може, безумовно, дати інші аналітичні можливості побачити, коли товар продається за ціною, що була вище або нижче вказаної ціни на той момент.


дякую за відповідь. Я думаю, що стратегія, з якою я збираюся, полягає в розробці OLTP для книги. Мені реально подобається ідея мати сховище даних для звітності. Хоча це додає деяку додаткову роботу (створення нової схеми), схема може бути адаптована до OLAP. Начебто уникати сценарію, коли я намагаюся помістити квадратний кілочок у круглий отвір.
Gaz_Edge

@Gaz_Edge: Я в подібній ситуації з точки зору прийняття рішення щодо мого нового проекту. Чи можете ви, будь ласка, поділитися своїми думками щодо того, який дизайнерський підхід ви взяли на рік назад? Це спрацювало добре?
Абсолютний

@CoderAbsolute моє оригінальне рішення було дуже орієнтоване на «базу даних». Зараз моя програма зосереджена на сервісно-орієнтованій архітектурі. Зараз у мене є безліч малих роз'єднаних схем баз даних, а не одна щільно зв'язана. Необхідність 3N в одній масивній схемі відпала. Тому я просто додаю одиничну ціну безпосередньо до замовлення. Тримання історичних змін цін на продукцію тепер зникло, оскільки це не було вимогою бізнесу. Сподіваюся, що це допомагає.
Gaz_Edge

0

Я повністю згоден з основною ідеєю збереження інформації, що стосується порядку (контексту), разом. Лише незначна сторона зауважила, що така ситуація виникне лише тоді, коли ви розробляєте свою програму, орієнтовану на базу даних, і все обертається навколо великого товстого db. Якщо ви переключите свою точку зору, дивлячись на проблемну область з іншого кута, ви чітко помітите, що порядок - це зроблений знімок дуже особливої ​​події в життєвому циклі вашої програми. Якщо ви вирішуєте проблеми на основі контексту, то проблеми з базами даних стануть вторинними і складними, що всі бояться запитів і складання звітів будуть оброблятися бездоганно у доменній моделі.


Деякі невеликі приклади полегшили б зрозуміти вашу відповідь. Особливо такі пропозиції, як "замовлення, - це зроблений знімок дуже особливої ​​події в життєвому циклі вашої програми".
dezso
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.