Збереження проти обчислення сукупних значень


96

Чи є якісь вказівки чи правила, які визначають, коли потрібно зберігати сукупні значення та коли їх обчислювати під час руху?

Наприклад, припустимо, у мене є віджети, які користувачі можуть оцінювати (див. Схему нижче). Кожен раз, коли я показував віджет, я міг обчислити середню оцінку користувача з Ratingsтаблиці. Крім того, я міг би зберегти середню оцінку на Widgetстолі. Це позбавить мене від необхідності обчислювати рейтинг кожного разу, коли я показую віджет, але тоді мені доведеться перераховувати середню оцінку кожного разу, коли користувач оцінює віджет.

Ratings       Widgets
---------     -------
widget_id     widget_id
user_id       name              
rating        avg_rating  <--- The column in question

Відповіді:


58

Це залежить. Попереднє обчислення сукупних значень накладає велике навантаження на записи, їх виведення ускладнює читання

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

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

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


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

прихильне! збирався задати точне запитання, мені потрібно зберігати такі показники, як SMA, EMA, WMA, RSI і т. д., і вони включають важкі обчислення, я робив таблицю, в яку я в даний час оновлювався вручну, ці показники змінюються на 100% щоразу нові дані, яка хороша стратегія їх збереження, я знаю, що погляди повністю зірвуть базу даних, якщо всі почнуть запитувати погляди ліворуч і праворуч
PirateApp

11

Як часто вам потрібно обчислити / відобразити значення відносно того, як часто змінюються / оновлюються основні числа.

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

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


кожні 15 хв., 10 показників, які змінюються на 100% із 1000 рядків на метрику
PirateApp

1
@PirateApp і скільки разів його переглядають у середньому вікні 15 хвилин? Що ви також можете зробити, це згенерувати його за першим запитом у вікні 15 хв, а потім кешувати його для людей, які продовжують натискати, щоб перезавантажувати знову і знову
Джо

це буде на веб-сайті, тож я припускаю, що принаймні 10000 людей побачать його для початку, сайт не живе, тому не майте фактичних даних про поведінку користувачів
PirateApp,

1
Питання полягає в тому, скільки запитів щодо того, як часто він змінюється. Отже, якщо ви попередньо генеруєте щось, що буде бачити 10 000 разів до зміни базових даних, то так, попередньо генеруйте його. Якщо його переглядають лише один раз або рідше (тому що дані змінюються так швидко або тому, що сторінку рідко переглядаються), ви цього не зробите.
Джо

4

Використовуйте таблицю StaleWidgets як чергу з "недійсними" (для перерахунку) віджетами. Використовуйте інше потокове (асинхронне) завдання, яке може перерахувати ці значення. Період або момент перерахунку залежить від системних вимог:

  • просто читайте,
  • наприкінці місяця,
  • для деяких користувачів на початку дня
  • ...

1
Як вони потрапляють у чергову чергу?
jcolebrand

2
@jcolebrand .. про момент вставки / видалення рейтингу (таблиця рейтингів) для деякого віджета. У цей момент середнє значення таблиці Widgets стає недійсним, тому нам доведеться вставити в таблицю запису StaleWidgets, що містить лише один стовпець - widget_id. Використовуйте тригер або збережений прок, який вставляє запис у таблицю рейтингів або ваш варіант звичайно.
garik

2

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

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


2

Зокрема, для іншого випадку існує рішення, де вам не потрібно додавати всі оцінки та ділити їх на загальну, щоб знайти середню. Натомість у вас може бути інше поле, яке містить загальну кількість оглядів, тому кожен раз, коли ви додаєте рейтинг, ви обчислюєте нове середнє, використовуючи (avg_rating × total + new_rating) / total, це набагато швидше, ніж сукупність та зменшує читання дисків, оскільки ви не мають доступу до всіх значень рейтингу. Подібні рішення можуть застосовуватися і в інших випадках.

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

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