Стратегия, чтобы избежать OutOfMemoryException во время ETL в .NET - PullRequest
0 голосов
/ 28 апреля 2011

Я написал процесс ETL, который выполняет процесс ETL. Процесс ETL должен обработать более 100 миллионов записей или строк в целом для записей за 2 года. Чтобы избежать проблемы нехватки памяти, мы сокращаем загрузку данных каждые 7 дней. Для каждого процесса куска он загружает все необходимые справочные данные, затем процесс открывает соединение SQL и загружает исходные данные по одному, преобразует их и записывает в хранилище данных.

Недостаток обработки данных по частям - медленная.

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

Существуют ли другие стратегии, которые я могу использовать, чтобы избежать OutOfMemoryException?

Например, локальная база данных, запись справочных данных в файлы, порождение другого процесса .NET для хранения большего количества памяти в Windows, использование хранимой процедуры CLR для выполнения ETL ...

Среда: 32-битная ОС Windows 7. 4 ГБ ОЗУ. SQL Server Standard Edition.

Единственное решение - использовать процедуру хранения и позволить SQL Server обрабатывать ETL. Однако я стараюсь избегать этого, потому что программа должна поддерживать и Oracle. Другие улучшения производительности, которые я пробовал - это добавление индексов для улучшения загрузки запросов. Создайте собственный класс доступа к данным, чтобы загружать только необходимые столбцы, а не загружать всю строку в память.

Спасибо

Ответы [ 3 ]

1 голос
/ 30 октября 2018

Я знаю его старый пост, но для людей, которые ищут лучшие точки для написания операций с данными на языках программирования.

Я не уверен, рассмотрели ли вы, как инструменты ETL выполняют свои операции загрузки данных и воспроизводят похожую стратегию в вашем коде.

Одно из таких предложений - параллельные каналы передачи данных. Здесь каждый канал будет выполнять ETL для отдельных фрагментов на основе разделения данных из источника. Например, вы можете параллельно рассматривать процессы порождения для данных за разные недели. Это по-прежнему не решит проблемы с памятью в рамках одного процесса. Хотя может использоваться в случае, если вы достигнете предела с распределением памяти в куче в рамках одного процесса. Это также полезно для чтения данных параллельно с произвольным доступом. Хотя потребуется главный процесс для координации и завершения процесса как одной операции ETL.

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

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

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

Алгоритм слияния: Идеально, когда источник уже отсортирован по ключу атрибута соединения. Основная идея алгоритма сортировки-слияния состоит в том, чтобы сначала отсортировать отношения по атрибуту соединения, чтобы чередующиеся линейные сканы встретились с этими наборами одновременно. Для примера кода, https://en.wikipedia.org/wiki/Sort-merge_join

Nested Join: работает как вложенный цикл, где каждое значение индекса внешнего цикла берется в качестве предела (или начальной точки, или чего-либо другого) для индекса внутреннего цикла, и соответствующие действия выполняются над оператором (ами) после внутренний цикл Таким образом, в основном, если внешний цикл выполняет R раз и для каждого такого выполнения внутренний цикл выполняет S раз, то общая стоимость или временная сложность вложенного цикла составляет O (RS).

Соединения с вложенными циклами обеспечивают эффективный доступ, когда таблицы индексируются по столбцам соединения. Кроме того, во многих небольших транзакциях, таких как транзакции, затрагивающие только небольшой набор строк, вложенные в индекс петлевые соединения намного превосходят как соединения sort -merge, так и соединения хэшей

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

Другая очень дорогостоящая операция - обратная запись в базу данных. Может быть тенденция обрабатывать извлечение, преобразование и загрузку по одной строке за раз. Подумайте об операциях, которые можно векторизовать, где вы можете выполнить их вместе с операцией над структурой данных в натуральном выражении. Например, лямбада-операция над многомерным вектором, а не зацикливание каждой строки по одному и выполнение преобразования и операций по всем столбцам для данной строки. Затем мы можем записать этот вектор в файл или базу данных. Это позволит избежать давления памяти.

1 голос
/ 28 апреля 2011

Не зная, как именно вы обрабатываете данные, трудно сказать, но наивное решение, которое можно реализовать в любом случае, - это использовать 64-битную ОС и скомпилировать ваше приложение как 64-битное.В 32-битном режиме куча .NET увеличится только до 1,5 ГБ, что может ограничивать вас.

0 голосов
/ 01 ноября 2018

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

В конечном итоге я написал хранимую процедуру SQL, используя Merge для обработки процесса ETL для типа данных, который слишком долго обрабатывал продуманное приложение C #. Кроме того, бизнес-требования были изменены таким образом, что мы отказались от поддержки Oracle и поддерживаем только 64-битный сервер, что позволило снизить затраты на обслуживание и избежать проблем с ETL из-за недостатка памяти.

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...