#c# #.net #data-warehouse #etl
#c# #.net #хранилище данных #etl
Вопрос:
Я написал процесс ETL, который выполняет процесс ETL. Процессу ETL необходимо обработать более 100 миллионов строк в целом за 2 года записей. Чтобы избежать проблемы нехватки памяти, мы сокращаем загрузку данных до каждых 7 дней. Для каждого процесса chank он загружает все необходимые справочные данные, затем процесс открывает sql-соединение и загружает исходные данные один за другим, преобразует их и записывает в хранилище данных.
Недостатком обработки данных с помощью chunk является то, что она медленная.
Этот процесс отлично работает для большинства таблиц, но есть одна таблица, с которой я все еще сталкиваюсь из-за нехватки памяти. Процесс загрузил слишком много справочных данных. Я хотел бы избежать сокращения объема данных до 3 дней, чтобы они имели достойную производительность.
Есть ли какие-либо другие стратегии, которые я могу использовать, чтобы избежать исключения OutOfMemoryException?
Например, локальная база данных, запишите справочные данные в файлы, запустите другой процесс .NET для хранения большего объема памяти в Windows, используйте хранимую процедуру CLR для выполнения ETL…
Среда: 32-разрядная ОС Windows 7. 4 ГБ оперативной памяти. SQL Server Standard Edition.
Единственное решение — использовать процедуру хранения и позволить SQL Server обрабатывать ETL. Однако я пытаюсь избежать этого, потому что программе также необходимо поддерживать Oracle. Другое улучшение производительности, которое я попробовал, — это добавление индексов для улучшения запросов на загрузку. Создайте пользовательский класс доступа к данным, чтобы загружать только необходимые столбцы, вместо загрузки всей строки в память.
Спасибо
Комментарии:
1. Одним из вариантов является создание кэша «справочных данных» фиксированного размера. Когда вашей программе нужны справочные данные, она ищет их в кэше. Если его там нет, он загружает его с вашего SQL server. Это работает эффективно, только если в ссылочных данных есть локальность.
Ответ №1:
Трудно сказать, не зная, как именно вы обрабатываете данные, но наивное решение, которое может быть реализовано в любом случае, — использовать 64-разрядную ОС и скомпилировать ваше приложение как 64-разрядное. В 32-битном режиме .ЧИСТАЯ куча вырастет только примерно до 1,5 ГБ, что может вас ограничивать.
Комментарии:
1. Наверняка! Безусловно, лучший способ сэкономить ваши деньги — перейти на 64-разрядную версию и, возможно, даже удвоить объем памяти. Стоимость попытки спроектировать решение для небольшого объема памяти намного выше, чем потратить несколько долларов на 8 или 16 ГБ оперативной памяти.
2. Я тестировал на 64-разрядной версии и уверен, что это решает проблему. К сожалению, ограничение касается компьютера клиента. Они работают только под управлением 32-разрядной ОС. Мне нужно будет поговорить с ИТ-отделом, чтобы узнать, возможно ли обновление до 64-разрядной ОС или нет.
Ответ №2:
Я знаю его старый пост, но для людей, ищущих лучшие моменты для написания операций с данными на языках программирования.
Я не уверен, рассматривали ли вы изучение того, как инструменты ETL выполняют свои операции загрузки данных, и повторяют подобную стратегию в вашем коде.
Одно из таких предложений — параллельные каналы передачи данных. Здесь каждый канал будет выполнять ETL для отдельных блоков на основе разделения данных из источника. Например, вы могли бы рассмотреть возможность параллельного запуска процессов для данных за разные недели. Это все равно не решит ваши проблемы с памятью в рамках одного процесса. Хотя может использоваться в случае, если вы достигнете предела с выделением памяти в куче в рамках одного процесса. Это также полезно для параллельного чтения данных с произвольным доступом. Хотя потребуется главный процесс для координации и завершения процесса как единой операции ETL.
Я предполагаю, что вы выполняете в своем преобразовании множество операций поиска, прежде чем окончательно записать свои данные в базу данных. Предполагая, что основная таблица транзакций огромна, а справочные данные малы. Вам нужно сосредоточиться на работе со структурой данных и alogirthm. Для этого ниже приведено несколько советов. Ознакомьтесь с характеристиками ваших данных, прежде чем выбирать, что лучше всего подходит при написании алгоритма.
Как правило, данные поиска (справочные данные) хранятся в кэше. Выберите простую структуру данных, которая эффективна для операций чтения и поиска (скажем, список массивов). Если возможно, отсортируйте этот массив по ключу, к которому вы присоединитесь, чтобы быть эффективным в вашем алгоритме поиска.
В ваших задачах преобразования существует другая стратегия для операций поиска. В мире баз данных вы можете вызвать это как операцию объединения.
Алгоритм объединения слиянием: идеально, когда исходный код уже отсортирован по ключу атрибута объединения. Ключевая идея алгоритма сортировки-слияния заключается в том, чтобы сначала отсортировать отношения по атрибуту join, чтобы чередующиеся линейные проверки обнаруживали эти наборы одновременно. Для примера кода,https://en.wikipedia.org/wiki/Sort-merge_join
Вложенное соединение: работает как вложенный цикл, где каждое значение индекса внешнего цикла принимается как предел (или начальная точка, или что-либо другое, что применимо) для индекса внутреннего цикла, и соответствующие действия выполняются над инструкциями, следующими за внутренним циклом. Итак, в принципе, если внешний цикл выполняется R раз, и для каждого такого выполнения внутренний цикл выполняется S раз, то общая стоимость или временная сложность вложенного цикла равна O (RS).
Соединения с вложенным циклом обеспечивают эффективный доступ, когда таблицы индексируются по столбцам объединения. Кроме того, во многих небольших транзакциях, таких как те, которые затрагивают только небольшой набор строк, индексные вложенные циклические соединения намного превосходят как объединения с сортировкой -слиянием, так и хэш-соединения
Я описываю только два метода, которые можно использовать в вашей операции поиска. Основная идея, которую следует помнить в ETL, заключается в поиске и извлечении кортежей (как установленных) для дальнейшей работы. Поиск будет основан на ключе, а результирующие ключи транзакции извлекут все записи (проекция). Воспользуйтесь этим и загрузите строки из файла за одну операцию чтения. Это скорее предложение на случай, если вам не нужны все записи для операций преобразования.
Другой очень дорогостоящей операцией является обратная запись в базу данных. Может наблюдаться тенденция обрабатывать извлечение, преобразование и загрузку по одной строке за раз. Подумайте об операциях, которые можно векторизовать, где вы можете выполнять это вместе с операцией структуры данных в массовом порядке. Например, операция lambada над многомерным вектором вместо того, чтобы перебирать каждую строку по очереди и выполнять преобразование и операции по всем столбцам для данной строки. Затем мы можем записать этот вектор в файл или базу данных. Это позволит избежать нехватки памяти.
Ответ №3:
Это был очень старый вопрос, и это скорее вопрос дизайна, и я уверен, что для него есть много решений, если я не вдамся в более конкретные детали.
В конечном счете, я написал хранимую процедуру SQL с использованием Merge для обработки процесса ETL для типа данных, обработка которого в приложении C # заняла слишком много времени. Кроме того, бизнес-требования были изменены таким образом, что мы отказались от поддержки Oracle и поддерживаем только 64-разрядный сервер, что снизило затраты на обслуживание и позволило избежать проблемы ETL с нехваткой памяти.
Кроме того, мы добавили много индексов всякий раз, когда видим возможность улучшить производительность запросов.
Вместо разбиения на фрагменты по диапазону дней процесс ETL также разбивает данные на количество (5000) и фиксирует при каждой транзакции, это уменьшило размер файла журнала транзакций, и в случае сбоя ETL процессу требуется откат только подмножества данных.
Наконец, мы внедрили кэши (ключ, значение), чтобы часто используемые данные в диапазоне дат ETL загружались в память, чтобы уменьшить количество запросов к базе данных.