Перечислитель ADO службы SSIS ForEach - проблемы с производительностью - PullRequest
0 голосов
/ 08 января 2019

Это вопрос передового опыта / другого подхода к использованию цикла ADO Enumerator ForEach.

Мои данные - финансовые счета, поступающие из исходной системы в хранилище данных. Текущая структура данных представляет собой список финансовых транзакций, например.

+-----------------------+----------+-----------+------------+------+
|      AccountGUID      | Increase | Decrease  |    Date    | Tags |
+-----------------------+----------+-----------+------------+------+
| 00000-0000-0000-00000 |        0 |    100.00 | 01-01-2018 | Val1 |
| 00000-0000-0000-00000 |   200.00 |         0 | 03-01-2018 | Val3 |
| 00000-0000-0000-00000 |   400.00 |         0 | 06-01-2018 | Val1 |
| 00000-0000-0000-00000 |        0 |    170.00 | 08-01-2018 | Val1 |
| 00000-0000-0000-00002 |   200.00 |         0 | 04-01-2018 | Val1 |
| 00000-0000-0000-00002 |        0 |    100.00 | 09-01-2018 | Val1 |
+-----------------------+----------+-----------+------------+------+

Мой пакет служб SSIS, в настоящее время есть два цикла forEach

  1. Балансы за все время
  2. Остатки на конец месяца

Балансы за все время

Передает AccountGUID в цикл и выбирает все транзакции для этой учетной записи. Затем он упорядочивает их по дате, причем первая транзакция является первой, и присваивает ей порядковый номер.

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

Он завершает это, назначая последнюю запись с текущим флагом.

Все балансы по времени - рабочий процесс

->Get All Account ID's in Staging table
|-> Write all Account GUID's to object variable
|--> ADO Enumerator ForEach - Loop Account GUID List - Write GUID to variable
|---> (Data Flow) Select all transactions for Account GUID
|----> (Data Flow) Order all transactions by date and assign Sequence number
|-----> (Data Flow) Run each row through a script component transformation to calculate running totals for each record
|------> (Data Flow) Insert balance data into staging table 

Остатки на конец месяца

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

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

Вопрос / Вопрос

Все это в настоящее время работает нормально, но производительность ужасна.

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

Есть ли лучший способ сделать это, используя SQL-курсоры или другой удобный способ, которого я не видел?

1 Ответ

0 голосов
/ 10 января 2019

Хорошо, так что мне удалось ускорить выполнение пакета с 3 дней до 11 минут.

Я запустил профилировщик и стандартную статистику Windows во время выполнения циклов и обнаружил несколько интересных вещей.

Во-первых, во время выполнения пакетов практически не использовались HDD, CPU, RAM или сеть. Он сказал мне, что я вроде уже знал, что он работал не так быстро, как мог.

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

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

Исправление:

Теперь это было странное исправление, вам нужно зайти в свой менеджер соединений (нечетный бит), это должно быть экранное окно, а не правое окно менеджера проекта.

Если вы выберете ваше соединение, на которое ссылается цикл, в окне свойств справа (в любом случае, в моем макете) вы увидите опцию «RetainSameConnection», которая по умолчанию установлена ​​в false.

Установив значение true, я устранил задержку в 2 мс.

Вопросы:

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

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

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

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

Чтобы обойти это, я создал дубликат менеджера соединений (всего я создал три менеджера соединений для одной базы данных).

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

Вывод:

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

...