В настоящее время мне поручено реализовать схему хранения для относительно большого объема данных. К данным в первую очередь будут обращаться, чтобы определить текущее data point
значение, но я также обязан отслеживать историю последних шести месяцев для анализа и анализа данных.
Недавнее требование было добавлено для отслеживания значения min
/ max
/ sum
за прошедший час.
ПРИМЕЧАНИЕ. В идеале я хотел бы рассмотреть вариант MongoDB, но мне нужно продемонстрировать, что я сначала исчерпал параметры SQL-Server.
Данные
В следующей таблице представлен основной источник данных (чаще всего запрашивается). Таблица будет иметь приблизительно пять миллионов строк. Изменения данных будут преимущественно 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-сервером). Я хотел бы, чтобы ваш вклад в следующее:
1) Учитывая , что мне нужно вычислить min
, max
и sum
за последний час (как в now - 60 minutes
). Каков наилучший подход для отслеживания последних данных:
Храните последние данные в памяти службы данных. Запишите вычисленные мин / макс / среднее с каждым обновлением данных.
Запросите недавнюю историю из таблицы истории (влияет на следующий вопрос?) Во время каждого оператора UPDATE. Запрос будет получать доступ к последним данным для значения точки данных и должен сканировать только последние миллионы записей или около того?
Сохранить недавнюю историю в самой строке DataPointValue, чтобы избежать поиска в таблице истории? Возможно, хранится в виде строки с разделителями и обрабатывается внутри процедуры UPDATE?
Другой вариант я не рассматривал?
2) Для DataPointValueHistory
запросов к данным всегда будет dataPointId
один или несколько запросов valueId
. Запрашиваемые данные обычно относятся к последнему дню, неделе или месяцу, но в некоторых случаях могут быть полными шестью месяцами.
В настоящее время я создаю пример набора данных, чтобы поэкспериментировать с тем, имеет ли смысл кластеризовать по dataPointId / valueId / timeStamp или timeStamp / dataPointId / valueId. Если кто-то имеет опыт работы с таблицей такого размера и желает предложить свое понимание, это будет оценено. Я склоняюсь к последнему варианту, чтобы избежать фрагментации индекса, но производительность запросов имеет решающее значение.
Кластер
DataPointValueHistory
по dataPointId -> valueId -> TIMESTAMPКластер
DataPointValueHistory
по timeStamp -> dataPointId -> valueId
3) Наконец, как уже упоминалось выше, я думаю, что будет иметь смысл разделить DataPointValueHistory
таблицу. Будем весьма благодарны за любые предложения о том, как лучше разделить исторические данные.
Если сначала кластеризовать по метке времени, я думаю, что данные должны быть разбиты по неделям (всего 27 секций). Самый старый раздел будет очищен после 27 недели.
Если сначала кластеризовать dataPointId, я думаю, что данные должны быть разделены по некоторому модулю идентификатора?
Поскольку у меня очень ограниченный опыт работы с разделами таблиц, ваш опыт был бы оценен.