На даний момент мені поставлено завдання реалізувати схему зберігання для відносно великого обсягу даних. Дані будуть доступні насамперед для визначення поточного data point
значення, але я також повинен відстежувати останні шість місяців історії для тенденцій / аналізу даних.
Нещодавно було додано вимогу для відстеження значення min
/ max
/ sum
за минулу годину.
ПРИМІТКА: В ідеалі я хотів би розглянути варіант MongoDB, але мені потрібно продемонструвати, що я спочатку вичерпав параметри SQL-сервера.
Дані
Наступна таблиця представляє первинне джерело даних (найчастіше запитується). У таблиці буде приблизно п’ять мільйонів рядків. Зміни даних будуть переважно UPDATE
висловлюваннями з дуже випадковими INSERT
твердженнями після початкового завантаження даних. Я вирішив кластерувати дані, dataPointId
як ви завжди будете вибирати all values for a given data point
.
// Simplified Table
CREATE TABLE [dbo].[DataPointValue](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[minimum] [decimal](18, 0) NOT NULL,
[hourMinimum] [decimal](18, 0) NOT NULL,
[current] [decimal](18, 0) NOT NULL,
[currentTrend] [decimal](18, 0) NOT NULL,
[hourMaximum] [decimal](18, 0) NOT NULL,
[maximum] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointValue] PRIMARY KEY CLUSTERED ([dataPointId],[valueId])
)
Друга таблиця помітно більша - приблизно 3,1 мільярда рядків (що представляє дані за останні шість місяців). Дані, старші ніж шість місяців, будуть очищені; в іншому випадку суворо INSERT
твердження даних (~ 200 рядків / сек, 720 000 рядків / годину, 17 мільйонів рядків на тиждень).
// Simplified Table
CREATE TABLE [dbo].[DataPointValueHistory](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[value] [decimal](18, 0) NOT NULL,
[delta] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointHistory] PRIMARY KEY CLUSTERED ([dataPointId], [valueId], [timestamp])
)
Очікується, що ця таблиця збільшиться удвічі за розмірами, оскільки кількість відстежених значень точки даних зросте до 400 рядків / сек (тому досягнення ~ 10 мільярдів не підлягає сумніву).
Питання (-и) я задаю більше одного ... вони тісно пов'язані між собою).
На даний момент я використовую базу даних SQL-Server 2008 R2 Standard Edition. Я, швидше за все, зроблю справу для оновлення до Enterprise Edition, якщо зможете отримати бажаний рівень продуктивності за допомогою розділів таблиці (або MongoDB, якщо не вдасться досягти необхідних рівнів продуктивності за допомогою SQL-Server). Я хотів би ваш внесок щодо наступного:
1) Враховуючи, що мені потрібно обчислити min
, max
і sum
за минулу годину (як в now - 60 minutes
). Який найкращий підхід для відстеження останніх даних:
Зберігайте останні дані в пам'яті служби передачі даних. Випишіть обчислені хв / макс / середнє значення з кожним оновленням даних.
Запитуйте нещодавню історію з таблиці історії (впливає на наступне запитання?) Під час кожного оператора UPDATE. Запит може отримати доступ до останніх даних для значення точки даних, і слід сканувати лише останній мільйон записів чи так?
Збережіть недавню історію в самому рядку DataPointValue, щоб уникнути пошуку таблиці історії? Можливо, зберігається у вигляді обмеженого рядка та обробляється всередині облікового запису UPDATE?
Інший варіант, який я не розглядав?
2) Для DataPointValueHistory
, запити до даних, які завжди будуть, будуть dataPointId
або однією або кількома запитами valueId
. Запитані дані, як правило, припадають на останній день, тиждень або місяць, але в деяких випадках можуть бути цілі шість місяців.
В даний час я генерую вибірковий набір даних для експерименту з тим, чи має сенс кластеризувати даніPointId / valueId / timeStamp або timeStamp / dataPointId / valueId. Якщо хтось має досвід роботи з таблицею такого розміру і готовий запропонувати своє розуміння, це буде вдячно. Я схиляюся до останнього варіанту, щоб уникнути фрагментації індексу, але виконання запитів є критичним.
Кластер
DataPointValueHistory
по dataPointId -> valueId -> timeStampКластер
DataPointValueHistory
за часомStamp -> dataPointId -> valueId
3) Нарешті, як було сказано вище, я думаю, що буде сенс розділити DataPointValueHistory
таблицю. Будемо дуже вдячні за будь-які пропозиції щодо найкращого розподілу даних історії.
Якщо спочатку кластеризовано часовою міткою, я думаю, що дані слід розподілити за тижнями (всього 27 розділів). Найдавніша перегородка буде очищена після 27 тижня.
Якщо спочатку згруповано dataPointId, я думаю, що дані повинні бути розділені деяким модулем ідентифікатора?
Оскільки у мене дуже обмежений досвід роботи з розділеннями таблиць, ваш досвід буде вдячний.