Мы должны денормализовать базу данных для улучшения производительности?

У нас есть требование для хранения 500 измерений в секунду, происходя из нескольких устройств. Каждое измерение состоит из метки времени, типа количества и нескольких векторных значений. Прямо сейчас существует 8 векторных значений на измерение, и мы можем полагать, что это число является постоянным для потребностей нашего опытного проекта. Мы используем HNibernate. Тесты сделаны в SQLite (дб дискового файла, не в оперативной памяти), но производством, вероятно, будет 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 Vectors { get; private set; }
}

Векторные значения хранятся в отдельной таблице, так, чтобы каждый из них сослался на свое родительское измерение через внешний ключ.

Мы сделали несколько вещей гарантировать, что сгенерированный SQL (довольно) эффективен: мы используем Гуид. Расческа для генерации идентификаторов, мы сбрасываем приблизительно 500 объектов в единственной транзакции, размер пакета ADO.NET установлен на 100 (я думаю, что SQLIte не поддерживает пакетные обновления? Но это могло бы быть полезно позже).

Проблема

Прямо сейчас мы можем вставить 150-200 измерений в секунду (который не достаточно быстр, хотя это - SQLite, мы говорим о). Смотря на сгенерированный SQL, мы видим, что в единственной транзакции вставляем (как ожидалось):

  • 1 метка времени
  • 1 измерение
  • 8 векторных значений

что означает, что мы на самом деле делаем 10x, больше единственной таблицы вставляет: 1500-2000 в секунду.

Если мы поместили все (все 8 векторных значений и метка времени) в измерительную таблицу (добавляющий 9 специальных столбцов), кажется, что мы могли увеличить нашу скорость вставки до 10 раз.

Переключение на SQL-сервер улучшит производительность, но мы хотели бы знать, мог ли быть способ избежать ненужных затрат на производительность, связанных со способом, которым база данных организована прямо сейчас.

[Править]

С SQLite в оперативной памяти я обхожу 350 объектов/секунда (3 500 единственных таблиц вставляют), которому я верю, почти так хорошо, как это добирается с NHibernate (занимающий этот пост для ссылки: http://ayende.com/Blog/archive/2009/08/22/nhibernate-perf-tricks.aspx).

Но я мог бы также переключиться на SQL-сервер и прекратить принимать вещи, правильно? Я обновлю свое сообщение, как только я тестирую его.

[Обновление]

Я переместился в SQL-сервер и сгладил свою иерархию, я протестировал его путем хранения 3 000 измерений/секунда в течение нескольких часов, и это, кажется, хорошо работает.

11
задан Groo 6 May 2010 в 17:29
поделиться

10 ответов

Лично я бы сказал, что нужно действовать: денормализовать, а затем создать ETL-процесс для приведения этих данных в более нормализованный формат для анализа/регулярного использования.

В принципе, идеальной ситуацией для вас может быть отдельная база данных (или даже просто отдельные таблицы в одной базе данных, если это необходимо), которая рассматривает получение данных как совершенно отдельный вопрос, а не как получение данных в формате, в котором вам нужно их обрабатывать.

Это не означает, что вам нужно выбросить сущности, которые вы создали вокруг вашей текущей структуры базы данных: просто вам нужно создать денормализованные таблицы и выполнить ETL для их обработки. Вы можете использовать SSIS (хотя он все еще довольно глючен и раздражителен) для периодического внесения данных в нормализованный набор таблиц, или даже приложение C# или другой процесс массовой загрузки.

EDIT: Это, конечно, при условии, что ваш анализ не должен выполняться в реальном времени: только сбор данных. Довольно часто люди не нуждаются (а иногда и предпочитают не нуждаться) в обновлении данных анализа в реальном времени. Это одна из тех вещей, которые хорошо звучат на бумаге, но на практике оказываются ненужными.

Если некоторым людям, которые анализируют эти данные, требуется доступ в реальном времени, то при желании можно создать инструментарий на основе "голых" денормализованных транзакционных данных: но довольно часто, когда вы действительно углубляетесь в требования, людям, выполняющим анализ, не нужно подлинное реальное время (а в некоторых случаях они предпочли бы иметь более статичный набор данных для работы!): и в этом случае периодический ETL будет работать вполне хорошо. Вам просто нужно встретиться с вашими целевыми пользователями и выяснить, что им действительно нужно.

10
ответ дан 3 December 2019 в 04:31
поделиться

Не просто денормализуйте. Создавайте для результатов, используя полезные шаблоны проектирования. Иногда полезный шаблон проектирования для повышения производительности дает дизайн, отличный от того, который вы получаете, следуя правилам нормализации.

Я не думаю, что денормализация поможет вашей ситуации. Почти все люди, которые выступают за денормализацию, говорят, что прирост производительности не достигается при хранении новых данных. Они приходят, когда вы извлекаете данные. Вам нужно будет решить, как это применимо к вашему делу.

Я могу вам многое сказать. Если вы в конечном итоге сохраните данные через несколько параллельных процессов, ваш дизайн приведет к серьезным узким местам и вполне может работать медленнее, чем нормализованный дизайн.

Но не верьте мне на слово. Экспериментируйте. Анализируйте. Учиться. Проспер.

1
ответ дан 3 December 2019 в 04:31
поделиться

Вы должны спросить себя: «Почему мы нормализуем?»

Есть три основные причины:

  1. Согласованность данных
  2. Скорость обновления
  3. Размер

Согласованность данных

Приятно иметь раскрывающиеся списки и все строки, которые означают одно и то же, с одинаковым FK, Правильно? Довольно очевидно. Это действительно важно для БД с несколькими «редакторами» данных. Но это ровно настолько, насколько хороши наши процессы. Допустим, это база данных полетов, и есть запись для национального аэропорта в Вашингтоне, округ Колумбия ... и некоторые добавляют НОВУЮ запись для национального аэропорта Рейгана в Вашингтоне, округ Колумбия ... FK будут там и будут использоваться в таблице детей, но выиграли не стоит многого ... Но это все равно хорошо ...

Скорость обновления

Что нам нужно было сделать, так это обновить строку для национального аэропорта с новым именем. Поскольку есть только одна родительская строка, это очень просто изменить. Если бы в моей полетной таблице был текст, я бы обновлял миллионы строк.

Размер

Если бы я сохранял «Национальный аэропорт Рейгана» на каждой записи, это заняло бы больше места, чем FK, скажем, 19. Раньше размер имел большое значение, но SAN делает его неактуальным.


Выводы

Итак, вы обеспокоены тем, что ваше приложение для сбора данных SOLO не может правильно хранить названия инструментов? Будет ли непротиворечивость данных проблемой?

Итак, как вы думаете, сколько раз вы будете менять название инструмента или точки данных? Я имею в виду, что растворенный O2 - это растворенный O2, а мутность - это мутность, верно? Но если вам действительно нужно было сделать массовое обновление, держу пари, у вас будет время простоя между запусками, чтобы сделать это. Так что это не проблема.

Хорошо, размер, конечно ... это много измерений; но, не делайте измерения «Растворенный кислород», DO2 в порядке ... насколько это больше, чем у некоторых FK, таких как «7»? Потратьте место, чтобы сэкономить время.

Не нормализируйте, потому что вы всегда мне сказали, что то, что делают хорошие дизайнеры баз данных. Знайте, зачем вы это делаете и почему вы выбираете то, что выбираете.

1
ответ дан 3 December 2019 в 04:31
поделиться

Используйте правильную СУБД и оборудование. Тестирование на другой платформе с другим оборудованием ничего не скажет о производительности.

Денормализация вряд ли повысит производительность записи, потому что по определению это означает, что вы создаете избыточные данные, и, следовательно, вы будете выполнять больше работы для каждой записи, а не меньше.

Приведенные вами цифры не являются исключительными для сценариев потоковой передачи данных и вполне достижимы при использовании подходящего оборудования, но я думаю, что nHibernate станет для вас основным ограничивающим фактором. Я думаю, что маловероятно, что nHib - разумный выбор для такого рода вещей.

Рассматривали ли вы использование некоторых технологий, которые обеспечивают специальную поддержку потоковых источников данных и CEP? Например: OSISoft PI, Microsoft StreamInsight и функция файлового потока SQL Server.

1
ответ дан 3 December 2019 в 04:31
поделиться

Ну, это зависит от того. Являются ли 8 значений вектора твердым и быстрым числом, которое никогда не изменится? Тогда денормализация в вашем случае может иметь смысл (но только тестирование на реальном оборудовании и базе данных, которые вы используете, покажет это). Если на следующей неделе может быть 9 измерений, не делайте этого.

Я бы сказал, что вам нужно сначала перейти на SQL сервер и оборудование, на котором вы будете работать, прежде чем пытаться решить, что делать.

После перехода запустите профилировщик. Вполне возможно, что nHibernate создает не самый лучший SQl для вашей вставки.

Тот факт, что у вас есть набор векторов, которые, вероятно, разделяются при вставке, может быть частью вашей проблемы производительности. Возможно, лучше иметь 8 отдельных переменных, чем набор, который приходится разделять.

Вы говорите о более чем 40 миллионах записей в день, это потребует серьезного оборудования и очень хорошо спроектированной базы данных. Также возможно, что реляционная база данных - не лучший выбор для этого (я не представляю, как вы хотите использовать такой объем данных). Как долго вы собираетесь хранить эти данные, размер здесь очень быстро выйдет из-под контроля.

Можно ли вместо этого выполнять массовую вставку записей в группе раз в минуту? Массовая вставка намного быстрее, чем вставка строка за строкой.

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

4
ответ дан 3 December 2019 в 04:31
поделиться

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

public class Measurement 
{ 
    public Guid ID { get; private set; } 
    public Device Device { get; private set; }
    public Sample[] { get; private set; }

    public DateTime FirstTimestamp { get; private set; } 
    public DateTime LastTimestamp { get; private set; } 
} 

public class Sample
{ 
    public DateTime Timestamp { get; private set; } 
    public VectorValue[] Vectors { get; private set; } 
}

Существуют различные способы хранения сложных типов (таких как список списков в данном случае) в одной записи. XML-столбцы и Типы, определяемые пользователем CLR , являются двумя примерами.

0
ответ дан 3 December 2019 в 04:31
поделиться

Сначала перейдите к целевой базе данных; производительность на основе SqlLite может не указывать на производительность на основе MsSql

Во-вторых, измерьте, где находится узкое место производительности; Навскидку, рискну предположить, что это диск и база данных в памяти будут работать намного лучше.

Затем денормализуйте, если необходимо, с помощью процесса ETL, как предложено выше.

Обработка потока событий гласит: « если ударишься по диску, ты мертв. »; -)

3
ответ дан 3 December 2019 в 04:31
поделиться

Думали ли вы об использовании SqlBulkCopy? Работает очень быстро. Я использовал его в производственной среде и достиг 10.000+ вставок в одну таблицу менее чем за секунду с машиной sql server 2005. Вам просто нужно подготовить DataTable (ы) для массовой вставки в ваше приложение. Вот образец.

        public static void SQLBulkCopyInsert(DataTable dtInsertRows, string destinationTableName, string[] columnMappings)
    {
        using (SqlBulkCopy sbc = new SqlBulkCopy(DBHelper.Secim2009DB.ConnectionString, SqlBulkCopyOptions.UseInternalTransaction))
        {                
            sbc.DestinationTableName = destinationTableName;
            // Number of records to be processed in one go
            sbc.BatchSize = 30000;
            // Map the Source Column from DataTabel to the Destination Columns in SQL Server 2005 Person Table

            foreach (string columnMapping in columnMappings)
            {
                sbc.ColumnMappings.Add(columnMapping, columnMapping);
            }

            // Number of records after which client has to be notified about its status
            sbc.NotifyAfter = dtInsertRows.Rows.Count;
            // Event that gets fired when NotifyAfter number of records are processed.
            sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(sbc_SqlRowsCopied);
            // Finally write to server
            sbc.WriteToServer(dtInsertRows);
            sbc.Close();
        }
    }

    public static void sbc_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
    {            

    }
2
ответ дан 3 December 2019 в 04:31
поделиться

«У нас есть требование хранить 500 измерений в секунду, поступающих с нескольких устройств».

Не используйте СУБД для хранения таких данных.

По каким причинам люди используют СУБД?

(a) Они могут наложить на вас ограничения на данные, которые вы пытаетесь зарегистрировать. Но у тебя их нет. Данные измерений такие, какие они есть, и их необходимо принять. Никаких ограничений.

(b) Они могут гарантировать согласованность и целостность ваших ценных бизнес-данных в случае (1) нарушения ограничений и (2) серьезных сбоев системы, таких как ошибки дискового ввода-вывода. Но поскольку у вас нет ограничений, (1) не применяется. А что касается (2), что вы будете делать со своими измерениями, если ошибка ввода-вывода диска не позволяет их записать? Ваши измерения теряются несмотря ни на что.

Итак, imo, у вас нет никаких причин использовать СУБД. Сохраните свою загрузку измерений в плоский файл и обработайте его по мере необходимости.

1
ответ дан 3 December 2019 в 04:31
поделиться

Вы можете рассмотреть другие альтернативы Базы данных. MSSQL предоставляет много функциональных возможностей, но это добавляет некоторые накладные расходы.

Отличный ресурс по высокопроизводительной обработке данных (как то, что вы пытаетесь сделать) находится на http://highscalability.com/

Одно из тематических исследований, которое они проводили - хранение статистики тысяч устройств в базе данных. Решение заключалось в использовании нескольких баз данных MYSQL и маршрутизации запроса на основе идентификатора устройства. В целом - сайт может предоставить отличные примеры. Возможно, вы сможете найти там возможное решение.

TImur

1
ответ дан 3 December 2019 в 04:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: