У нас есть требование хранить 500 измерений в секунду, поступающих с нескольких устройств. Каждое измерение состоит из метки времени, типа количества и нескольких векторных значений. Прямо сейчас на измерение 8 значений вектора, и мы можем считать это число постоянным для потребностей нашего прототипа. Мы используем HNibernate. Тесты выполняются в SQLite (файл диска db, а не в памяти), но производство, вероятно, будет MsSQL.
Наш класс объектов измерения - это тот, который содержит одно измерение и выглядит следующим образом:
public class Measurement
{
public virtual Guid Id { get; private set; }
public virtual Device Device { get; private set; }
public virtual Timestamp Timestamp { get; private set; }
public virtual IList<VectorValue> Vectors { get; private set; }
}
Векторные значения хранятся в отдельной таблице, поэтому каждая из них ссылается на родительское измерение через внешний ключ.
Мы сделали несколько вещей, чтобы гарантировать, что сгенерированный SQL (разумно) эффективный: мы используем Guid.Comb для генерации идентификаторов, мы собираем около 500 элементов в одной транзакции, размер партии ADO.Net установлен на 100 (я думаю, что SQLIte не поддерживает пакетные обновления, но может быть полезно позже).
Проблема
Прямо сейчас мы можем вставить 150-200 измерений в секунду (что не достаточно быстро, хотя это SQLite, о котором мы говорим). Посмотрев на сгенерированный SQL, мы видим, что в одной транзакции мы вставляем (как и ожидалось):
- 1 временная метка
- 1 измерение
- 8 векторных значений
что означает, что мы на самом деле делаем 10-кратное число вставных таблиц: 1500-2000 в секунду.
Если мы поместили все (все 8 векторных значений и временную метку) в таблицу измерений (добавив 9 выделенных столбцов), кажется, что мы могли бы увеличить скорость вставки до 10 раз.
Переход на SQL-сервер повысит производительность, но мы хотели бы знать, есть ли способ избежать ненужных затрат на производительность, связанных с тем, как база данных организована прямо сейчас.
[изменить]
С встроенным SQLite я получаю около 350 наименований/сек (3500 одиночных табличных вставок), которые, я считаю, примерно так же хороши, как и у NHibernate (взяв этот пост для справки: http://ayende.com/Blog/archive/2009/08/22/nhibernate-perf-tricks.aspx).
Но я мог бы переключиться на SQL-сервер и перестать принимать на себя все, не так ли? Я обновляю свой пост, как только проверю его.
[Обновление]
Я перешел на SQL-сервер и сплющил свою иерархию, я протестировал его, сохранив 3000 измерений/сек в течение нескольких часов и, похоже, работает нормально.