Если идти всё прямо да прямо, далеко не уйдешь…
(Маленький принц, Антуан де Сент-Экзюпери)


Недавно ко мне обратился коллега с просьбой как-то помочь с Teradata. Eё сейчас активно внедряют и первым шагом этого внедрения является загрузка данных на ежедневной основе. Заливать приходится очень много и как можно быстрее. Меня попросили найти какие-нибудь альтернативные способы загрузки данных в Teradata, которые бы не сильно зависели от выделенных пользователю ресурсов. В процессе этой работы мне пришлось более близко познакомиться с .NET Data Provider for Teradata. Входе знакомства выяснились некоторые любопытные детали, знание которых, на мой взгляд, может быть очень полезным. Так как о Teradata знают не все, начну я с краткого её описания.


Что такое Teradata


С точки зрения программиста, который загружает и получает из неё данные:
Teradata — это большое хранилище данных работу с которыми пытаются оптимизировать с помощью программно-аппаратной архитектуры. В архитектуре основной упор делается на параллелизм.

Из википедии:
Teradata is a massively parallel processing system running a shared-nothing architecture. Its technology consists of hardware, software, database, and consulting. The system moves data to a data warehouse where it can be recalled and analyzed.

Загрузка данных в Teradata


Загрузку/Выгрузку больших объемов данных в Teradata предлагается делать с помощью
Teradata Load and Unload Utilities. Существуют на данный момент следующие утилиты:
  • Teradata TPump
  • Teradata FastLoad
  • Teradata MultiLoad
  • Teradata FastExport
  • BTEQ

У нас в компании пользуются в основном Teradata FastLoad. В качестве ETL используем продукт фирмы
Informatica.

Утилиты загрузки/выгрузки в Teradata в сравнении с DML требуют более глубокого погружения в теорию Teradata. В частности:
  • надо уметь их настраивать
  • знать принцип работы
  • учитывать их специфику и ограничения, которые они накладывают на таблицы в которые идёт запись
  • администратор Teradata может наложить ряд ограничений на их работу

Отсюда, способ записи данные с помощью DML команды Insert по прежнему актуален. DML более распространен, менее требователен к настройкам и поддерживается Teradata. Я решил проверить насколько эффективно можно использовать эту команду. В целях эксперимента был создан тестовый проект, целью которого было разобраться в принципах работы Terdata провайдера. Первым делом, я попробовал решить задачу в лоб – читать одну строчку из Oracle и затем вставлять её в Teradata, но этот способ оказался очень медленным. С целью найти виновного, я модернизировал программу – теперь она читала из Oracle, создавая под каждую строку поток, который вставлял данные в Teradata. По стремительно растущему количеству потоков, стало понятно, что основным виновником низкого быстродействия были Insert операции в Teradata. Поняв что вставка одной строки занимает много времени попробовал вставлять разом несколько строк, разделяя ‘;’ команды Insert. Скорость ощутимо возросла. Увеличивая количество строк, вставляемых за один раз я пришёл к Exception:

[.NET Data Provider for Teradata][100056] Total size of parameters is greater than the max Data parcel size.

Порывшись в исходниках я нашёл место, где возникало данное исключение:

if (bodyLength > this._maxParamRowSpace || bodyLength - num > this._sessionContext[WpSessionContext.SessionLimits.MaxDataParcelSize])
          throw UtlTrace.TraceException((Exception) new TdException("InvalidDataPclSize", new object[0]));

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

do
{
     numParamsInExec = _oneExec(ref com, numParamsInExec, ref err);
} while (err == Const.ERR_100056);

Таким образом, определяем максимальное количество операций Insert за один раз. Далее выполняем вставку данных пакетами, в случае возникновения Exception 100056, уменьшаем размер пакета. Данное решение существенно повысило скорость записи данных в Teradata, без использования специальных утилит. Отсюда, этот способ можно использовать в случае, если Вы ограниченны в ресурсах или же для записи сравнительно небольших объёмов данных в Teradata.

Комментарии (3)


  1. Geckelberryfinn
    02.12.2015 11:37

    Небольшой комментарий: если у вас в транзакции, допустим N операций insert, то довольно сложно будет потом отлавливать отвергнутую (rejected) строчку (или строчки). Так как транзакция отменится вся.
    Плюс Load utilites в том, что все режекты она может логировать.
    Я прав? Или у терадаты можно инсертить пакетами, невзирая на режекты?


    1. alex_29
      02.12.2015 12:01

      У Load utilites есть как плюсы так и минусы. Дело в том что обычный Insert сам по себе выполняется не очень быстро, по сравнению с пакетом, а размер пакета при этом ещё и лимитирован.


      1. alex_29
        02.12.2015 12:06

        С reject Вы правы, но reject виден в клиенте в момент вставки, где можно его обработать и сохранить куда-то. У Load utilites есть как плюсы так и минусы, в целом они очень даже не плохи. Другой вопрос, что им для работы нужны ресурсы дополнительные (utility slots например), иногда их нет. В этой ситуации можно это обойти с помощью DML. Но Insert сам по себе выполняется не очень быстро, по сравнению с пакетом, а размер пакета при этом ещё и лимитирован. Отсюда я выкрутился так, как описал в статье.