GTT – global temporary tables, таблицы которые наполняются и очищаются в рамках ABAP-сессии (application session), но находятся при этом на уровне БД (то есть данные не передаются между Database и Application).
В ABAP-разработке их можно перевести как глобально сессионные таблицы или словарно-сессионные таблицы. Появляются Global Temporary Tables (GTT) с версии ABAP 7.50.
Что такое temporary tables?
В базах данных Temporary table – это объект на уровне базы данных, куда могут быть помещены данные после выборки из таблиц БД; при этом данные существуют в рамках сессии приложения и не передаются из базы на application, а остаются в базе. Это дает возможность применять SQL-операторы к «промежуточным» данным для вычислений и не делать дополнительные roundtrip между application и базой. В терминах ABAP-разработки temporary table можно рассматривать как альтернативу «промежуточным» внутренним таблицам или операторам UNION.
Temporary tables реализованы в различных базах: PostgreSQL, ORACLE, HANA ; также поддерживаются в 1С (ссылка здесь и здесь). Назначение их, по сути, одно и то же: в течение сессии сложить данные в таблицу, а по итогу сессии забрать данные и очистить таблицу.
GTT в ABAP представляет собой отдельную прозрачную таблицу, в которую складываются данные в рамках DB LUW и могут быть считаны только в рамках текущей сессии. На начало сессии и на завершение таблица должна быть пустая (очищена принудительной командой через ABAP, если нужно). Цель GTT – это дать возможность разделить сложную выборку на несколько шагов. За счет того, что данные хранятся в рамках одной сессии, то «закулисное администрирование» такой таблицы немного меньше. Можно сказать, что временная таблица работает почти как внутренняя таблица, но остаётся на стороне базы данных.
Демонстрационный пример в ABAP
Как правило, temporary table полезна, когда нужно получить данные из источников, которые имеют разное смысловое назначение, но сводятся к одной и той же структуре данных.
Пример: нужно получить список (MATNR) материалов, которые указаны в заказах на дату DATE1 и указаны в фактурах на дату фактурирования DATE1.
В SAP ERP (и как правило, в других системах тоже) заказы и фактуры находятся в разных таблицах, а также заголовок и позиция этих сущностей также находятся в разных таблицах (и даже не в одной ? ). В SAP ERP для заказов используются таблицы: VBAK, VBAP и др., а для фактур таблицы: VBRK, VBRP и др.. Однако для целей демонстрации (на стандарте экспериментировать не хорошо), я сделаю упрощённые аналогичные таблицы со структурой (рис.1 и табл.1).
Таблица |
Поле |
Комментарий |
ZTC8A016_ORDH |
VBELN |
Номер заказа, первичный ключ |
KUNNR |
Номер (id) партнера-заказчика |
|
ORDER_DATE |
Дата заказа |
|
CRDT |
Дата создания заказа |
|
| ||
ZTC8A016_ORDI
(позиции заказа, демо) |
VBELN |
Номер заказа, являются частью первичного ключа, связано внешним ключом с |
POSNR |
Номер позиции заказа, являются частью первичного ключа |
|
MATNR |
Номер материала (MATNR) |
|
| ||
ZTC8A016_INVH
(заголовок фактуры, демо) |
INV_NUM |
Номер фактуры, первичный ключ |
PAYER |
Номер (id) партнера-плательщика |
|
INVOICE_DATE |
Дата фактуры |
|
CRDT |
Дата создания фактуры |
|
| ||
ZTC8A016_INVI
(позиции фактуры, демо) |
INV_NUM |
Номер фактуры, является частью первичного ключа. Связано внешним ключом с ZTC8A016_INVH . INV_NUM |
INV_POSNR |
Номер позиции фактуры, является частью первичного ключа. |
|
MATNR |
Номер материала |
Данная структура является сильным упрощением реальной структуры (например, нет цен и других важнейших атрибутов сущностей), но для целей демонстрации GTT – пусть будет так. Главное, что хотелось подчеркнуть, что данные находятся в разных источниках: группа таблиц заказов и группа таблиц фактур. Наполним таблицы с помощью утилиты.
А теперь укажем, как может быть решена данная задача различными способами.
Способ1. Считываем данные из каждой таблицы (точнее join) и объединяем на стороне application server (этот способ классический и держится уже много десятилетий, поэтому не буду его приводить).
Способ2. Делаем UNION из двух JOIN и возвращаем результат. Одна из возможных реализаций этого способа приведена здесь.
Способ3. Создаём GT-таблицу. Извлекаем данные в неё из JOIN по заказам, при этом не возвращая ничего на application server; затем извлекаем данные из JOIN по фактурам, также ничего не возвращая. А третьим шагом – считываем данные из временной таблицы и очищаем её. Реализация доступна по ссылке.
Создание Global Temporary Table в SAP NetWeaver (GTT в ABAP)
Давайте рассмотрим по шагам, как создать Global Temporary Table в ABAP, и как использовать.
В ABAP-справке содержится описание GTT и пример содержится в программе (DEMO_GTT).
Создадим для нашего примера GTT через SE11; таблица создаётся как прозрачная таблица, но с указанием признака GTT (global temporary table).
Затем, как и в прозрачной таблице, указываем структуру таблицы.
Таблица 2 Структура GTT (Global Temporary Table) для демонстрации
Поле |
Тип |
Комментарий |
MANDT |
MANDT |
|
SRC_TYPE |
CHAR1 |
Ключевое поле, Содержит либо O – order, либо I – Invoice |
MATNR |
MATNR |
Материал |
Затем переходим по меню
Extras -> Change/Display Table Category
Технические параметры (тип таблицы, размер, буферизация, и т.д.) не ведутся для GTT.
Затем активируем таблицу и на этом создание GTT в словаре выполнено. Ограничения описаны в справке.
Использование и чтение данных из GTT в ABAP
Полная реализация этого способа тут.
GTT позволяет нам разделить чтение на части; поэтому мы можем использовать 2 метода по чтению, а именно: _fill_gtt_from_order и _fill_gtt_from_invoice. Таким образом, нам «удобнее» понимать, из каких шагов состит общая выборка. А также мы можем обращать внимание на переменную SY-DBCNT и, тем самым знать, сколько записей на каждом шаге было выбрано. Обращаю внимание, что мы не извлекаем данные во внутреннюю таблицу, а делаем INSERT во временную (в данном случае ZTC8A016_MAT_TMP, которую создали в предыдущем пункте).
METHOD _fill_gtt_from_order.
INSERT ztc8a016_mat_tmp FROM
(
SELECT DISTINCT
'O' AS src_type,
ordi~matnr AS matnr
FROM ztc8a016_ordi AS ordi
JOIN ztc8a016_ordh AS ordh ON ordi~vbeln EQ ordh~vbeln
WHERE ordh~order_date EQ @mv_trg_date
).
ENDMETHOD.
METHOD _fill_gtt_from_invoice.
INSERT ztc8a016_mat_tmp FROM
(
SELECT DISTINCT
'I' AS src_type,
invi~matnr AS matnr
FROM ztc8a016_invi AS invi
JOIN ztc8a016_invh AS invh ON invi~inv_num EQ invh~inv_num
WHERE invh~invoice_date EQ @mv_trg_date
).
ENDMETHOD.
Если там потребуется прочитать данные еще и из другого документа (например, поставок или закупочных документов), то существующие SELECT править уже не понадобиться, а нужно будет добавить метод, который заполняем temporary table. Таким образом, общая логика становится более наглядной и гибкой.
После того, как заполнение таблицы завершено, извлекаем нужные данные из временной таблицы. При этом мы можем применять «почти» любые ABAP SQL-операторы к этой таблице, включая агрегированные функции, JOIN, наложение условий через WHERE/HAVING и т.д. Однако, после того, как какие-либо данные добавлены в GTT не допускаются COMMIT (в том числе неявные / implicit).
_fill_gtt_from_order( ).
_fill_gtt_from_invoice( ).
""""""""" read
" допускается "почти" любой AbapSQL
SELECT DISTINCT matnr
FROM ztc8a016_mat_tmp
ORDER BY matnr DESCENDING
INTO TABLE @et_matnr_list
UP TO 3 ROWS.
IF mv_mode EQ '3'.
" из-за неудаленных данных - будетм RunTime Error (aka красный Dump)
" неявный коммит
MESSAGE i000(cl) WITH 'Runtime Error goes here'.
ENDIF.
""""""""" delete - MUST EXIST
DELETE FROM ztc8a016_mat_tmp.
MESSAGE i000(cl) WITH 'Почистили GTT в сессии'.
Полный пример доступен по ссылке на github.
Подробнее GTT описаны в справке.
Заключение
Основными преимуществами GTT (как в ABAP (SAP NetWeaver), так и в других базах) являются:
Возможность не передавать (не делать лишние database roundtrip) данные между базой и application (для данных более 50000 записей, это может иметь значение).
Разделить логику сбора данных на несколько шагов, что повысит удобочитаемость, а также расширяемость без риска «сломать существующее».
За счет «временности» накладные расходы на такую таблицу меньше, чем на обычную и работа с ней осуществляется немного быстрее.
На всякий случай обращу внимание, что GTT эффективно применимы не во всех возможных случаях, но эту возможность полезно знать.
mixsture
Очень похоже на реализацию временных таблиц в запросах 1с. В дополнение к перечисленным плюсам должно еще давать:
1) Отладку сложного запроса. Т.к. данные попадают во временные таблицы и если каждое действие записывать в свою временную таблицу, то можно увидеть все промежуточные результаты.
2) Более тонкую подстройку под индексы СУБД. Т.к. на каждом шаге хорошо видно, что используется в условиях, соединениях и группировках, то довольно просто договориться с планировщиком запросов о том, какой индекс будет использован. (относительно единого огромного запроса с вложенными подзапросами)
И характерные минусы этого решения:
Повышенная нагрузка на диски, где расположены временные таблицы.
Возможное отсутствие статистики у СУБД на эти таблицы, а значит неправильные принимаемые решения планировщиком запросов. (в постресПро, например, плагин для этого отдельный распространяют, чтобы статистику временных на лету вычислять)
rustabapclub Автор
Спасибо за комментарий!
Если дадите ссылочку на документацию по 1С, где описаны Temporary Tables - буду благодарен и добавлю её рядом с другими ссылками.
mixsture
Официальная документация
https://its.1c.ru/db/pubqlang/content/51/hdoc
(не распространяется бесплатно, но можно у них на 7 дней "тестовый" доступ оформить)