В отличие от Microsoft SQL Server (MS SQL) перехват и трассировка запроса из 1С в PostgreSQL выполняется не самым очевидным и удобным способом. В MS SQL используется встроенный инструмент Profiler, полного аналога которого, к сожалению, нет в PostgreSQL.
Вводные данные
Как правило, запрос из 1С на стороне системы управления базы данных (СУБД) просматривают по одной их причин ниже:
- необходимость его оптимизации;
- исправление ошибки на уровне СУБД;
- желание лучше вникнуть в механизмы работы платформы 1С.
Пусть перед нами стоит задача: выяснить, во что преобразуется запрос из 1С в базе данных PostgreSQL.
Расследование будем проводить в следующей среде:
- операционная система Ubuntu 22.04;
- платформа 1С «8.3.25.1286» (комьюнити лицензия);
- СУБД PostgreSQL 16.6 (официальная сборка от 1С).
Важно: все эксперименты и анализ взаимодействия платформы 1С и СУБД можно проводить только в тестовой зоне! В идеале на отдельном тестовом стенде.
Итак, у нас есть обработка, в которой при нажатии на кнопку выполняется код ниже.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НДСЗаписиКнигиПродажОбороты.Организация КАК Организация,
| НДСЗаписиКнигиПродажОбороты.СчетФактура КАК СчетФактура,
| НДСЗаписиКнигиПродажОбороты.ВидЦенности КАК ВидЦенности,
| НДСЗаписиКнигиПродажОбороты.СуммаБезНДСОборот КАК СуммаБезНДСОборот
|ПОМЕСТИТЬ ВТ_НДСЗаписиКнигиПродаж
|ИЗ
| РегистрНакопления.НДСЗаписиКнигиПродаж.Обороты(, , , Организация = &Организация) КАК НДСЗаписиКнигиПродажОбороты
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| СчетФактураВыданныйДокументыОснования.Ссылка КАК СчетФактура,
| СчетФактураВыданныйДокументыОснования.ДокументОснование КАК ДокументОснование
|ПОМЕСТИТЬ ВТ_ДокументыОснования
|ИЗ
| Документ.СчетФактураВыданный.ДокументыОснования КАК СчетФактураВыданныйДокументыОснования
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_НДСЗаписиКнигиПродаж.Организация КАК Организация,
| ВТ_НДСЗаписиКнигиПродаж.СуммаБезНДСОборот КАК СуммаБезНДСОборот,
| ВТ_НДСЗаписиКнигиПродаж.ВидЦенности КАК ВидЦенности,
| ЕСТЬNULL(ВТ_ДокументыОснования.ДокументОснование, НЕОПРЕДЕЛЕНО) КАК ДокументОснование
|ИЗ
| ВТ_НДСЗаписиКнигиПродаж КАК ВТ_НДСЗаписиКнигиПродаж
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДокументыОснования КАК ВТ_ДокументыОснования
| ПО ВТ_НДСЗаписиКнигиПродаж.СчетФактура = ВТ_ДокументыОснования.СчетФактура";
Запрос.УстановитьПараметр("Организация", Организация);
РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();
Обратите внимание, что результат запроса помещается в переменную «РезультатПросмотрЗапросаPostgreSQL». В дальнейшем нестандартное название переменной поможет нам для его поиска в технологическом журнале.
Настроим технологический журнал на логирование всех запросов к СУБД.
Технологический журнал – это встроенный инструмент 1С, который логирует большинство действий платформы 1С, в т.ч. взаимодействие с СУБД.
Настройка файла logcfg.xml для логирования запросов на стороне СУБД выглядит следующим образом.
<?xml version="1.0"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="/home/usr1cv8/log" history="4">
<event>
<eq property="Name" value="DBPOSTGRS"/>
</event>
<property name="all"/>
</log>
</config>
В Ubuntu для включения технологического журнала достаточно разместить файл настроек «logcfg.xml» в каталоге «/opt/1cv8/x86_64/8.3.25.1286/conf/logcfg.xml». После его размещения откроем обработку и нажмём кнопку «Выполнить запрос».
Выполненный запрос из 1С к СУБД попал в лог технологического журнала. Теперь можно посмотреть, во что преобразуется запрос 1С на стороне СУБД.
Для этого используем специальные команды в терминале Ubuntu. Т.к. в событии «DBPOSTGRES» логируется контекст кода из 1С, будем искать все упоминания переменной «РезультатПросмотрЗапросаPostgreSQL». Именно поэтому мы сделали название переменной уникальным. Полный набор команд поиска «РезультатПросмотрЗапросаPostgreSQL» в терминале выглядит следующим образом.
sudo cat rphost_*/*.log | awk '{if(match($0, "^[0-9][0-9]\:[0-9][0-9]\.[0-9]+\-")) printf "\n%s#line#", $0; else printf "%s#line#", $0;}' | grep 'РезультатПросмотрЗапросаPostgreSQL' | sed -e "s/#line#/\n/g"
Разберем каждую команду конвейера подробнее.
-
sudo
-
cat rphost_*/*.log
-
awk '{if(match($0, "^[0-9][0-9]\:[0-9][0-9]\.[0-9]+\-")) printf "\n%s#line#", $0; else printf "%s#line#", $0;}'
-
grep 'РезультатПросмотрЗапросаPostgreSQL'
-
sed -e "s/#line#/\n/g"
Переходим в каталог с логами технологического журнала и по правой кнопке мыши вызываем команду «Открыть в терминале».
Выполняем в терминале весь конвейр команд для поиска логов с переменной «РезультатПросмотрЗапросаPostgreSQL». Мы получили SQL команды, которые отправляла платформа 1С при выполнении запроса в обработке. Как видно по результату ниже, их намного больше чем один запрос в коде 1С.
Собираем запрос PostgreSQL
Наша задача из всех команд SQL, которые мы нашли в технологическом журнале, собрать полный текст запроса на уровне СУБД. Так как события в технологическом журнале упорядочены по дате выполнения пойдем сверху вниз.
30:03.623000-2999,DBPOSTGRS,3,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088, Sql='SELECT Creation,Modified,Attributes,DataSize,BinaryData FROM Config WHERE FileName = $1 ORDER BY PartNo', Prm="p_1: '32b77da9-151d-422f-9b6a-27d2f517f210'::mvarchar",RowsAffected=1,Result=PGRES_TUPLES_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Первый запрос - технический к таблице с конфигурацией 1С. Пропускаем. Смотрим дальше.
30:03.638000-8996,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql="SELECT
T1._Period,
T1._UseTotals,
T1._ActualPeriod,
T1._UseSplitter,
T1._MinPeriod,
T1._MinCalculatedPeriod
FROM _AccumRgOpt23707 T1
WHERE ((T1._Fld1000 = CAST(0 AS NUMERIC))) AND
(T1._RegID = '\\251}\\2672\\035\\025/B\\233j''\\322\\365\\027\\362\\020'::bytea AND T1._Fld1000 = CAST(0 AS NUMERIC))",RowsAffected=1,Result=PGRES_TUPLES_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Это служебный запрос, который получает настройки регистра накопления «НДСЗаписиКнигиПродаж». Для воспроизведения запроса в СУБД он нам не потребуется, т.к. запрос технический и выполняется платформой 1С для дальнейшей работы с виртуальной таблицей «РегистрНакопления.НДСЗаписиКнигиПродаж.Обороты(…)».
Продолжаем. Следующий запрос.
30:03.648000-7999,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql="SELECT
BOOL_AND(T1._AggMode),
BOOL_OR(T1._AggMode),
BOOL_AND(T1._EnableUse),
BOOL_OR(T1._EnableUse),
MIN(T1._DeltaPeriodic),
MAX(T1._DeltaPeriodic),
MIN(T1._BufferPeriodic),
MAX(T1._BufferPeriodic),
COUNT(*)
FROM _AccumRgAggOptK22804 T1
WHERE ((T1._Fld1000 = CAST(0 AS NUMERIC))) AND
(T1._RegID = '\\251}\\2672\\035\\025/B\\233j''\\322\\365\\027\\362\\020'::bytea AND T1._Fld1000 = CAST(0 AS NUMERIC))",RowsAffected=1,Result=PGRES_TUPLES_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Снова служебный запрос для виртуальной таблицы оборотов. Двигаемся дальше.
30:03.655000-3998,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql='drop table if exists tt11 cascade;create temporary table tt11
(_Q_000_F_000RRef bytea, _Q_000_F_001_TYPE bytea, _Q_000_F_001_RTRef bytea, _Q_000_F_001_RRRef bytea,
_Q_000_F_002RRef bytea, _Q_000_F_003 numeric(27, 2) ) without oids ',RowsAffected=0,Result=PGRES_COMMAND_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Вот первый запрос, который нас заинтересует. Создание временной таблицы. В отличии от языка запросов 1С в PostgreSQL создание временной таблицы выполняется заранее с описанием структуры полей. Копируем его себе в отдельный файлик в блокнот.
30:03.655001-4000,DBPOSTGRS,4,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Func=lookupTmpTable,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Вызов служебной функции «lookupTmpTable». Двигаемся дальше.
30:03.664000-8997,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql="INSERT INTO pg_temp.tt11 (_Q_000_F_000RRef, _Q_000_F_001_TYPE, _Q_000_F_001_RTRef, _Q_000_F_001_RRRef,
_Q_000_F_002RRef, _Q_000_F_003) SELECT
T1.Fld22777RRef,
T1.Fld22779_TYPE,
T1.Fld22779_RTRef,
T1.Fld22779_RRRef,
T1.Fld22780RRef,
T1.Fld22791Turnover_
FROM (SELECT
T2._Fld22777RRef AS Fld22777RRef,
T2._Fld22779_TYPE AS Fld22779_TYPE,
T2._Fld22779_RTRef AS Fld22779_RTRef,
T2._Fld22779_RRRef AS Fld22779_RRRef,
T2._Fld22780RRef AS Fld22780RRef,
SUM(T2._Fld22791) AS Fld22791Turnover_
FROM _AccumRgTn22801 T2
WHERE ((T2._Fld1000 = CAST(0 AS NUMERIC)))
AND (((T2._Fld22777RRef = '\\230-\\024\\332\\351\\261\\232H\\021\\345\\316X\\212''m\\266'::bytea))
AND (T2._Fld22791 <> CAST(0 AS NUMERIC)))
GROUP BY T2._Fld22777RRef,
T2._Fld22779_TYPE,
T2._Fld22779_RTRef,
T2._Fld22779_RRRef,
T2._Fld22780RRef
HAVING (SUM(T2._Fld22791)) <> CAST(0 AS NUMERIC)) T1",RowsAffected=27,Result=PGRES_COMMAND_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Наконец-то сам запрос к виртуальной таблице «РегистрНакопления.НДСЗаписиКнигиПродаж.Обороты(…)» и помещение его во временную таблицу «ВТ_НДСЗаписиКнигиПродаж». Копируем его тоже в блокнот. Продолжаем собирать запрос на стороне PostgreSQL.
30:03.664003-1,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql=ANALYZE pg_temp.tt11,RowsAffected=0,Result=PGRES_COMMAND_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Служебный запрос для сбора статистики временной таблицы. Тоже добавим его себе в итоговый запрос, чтобы учитывать особенности выполнения запросов в PostgreSQL через платформу 1С.
30:03.711000-999,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql='drop table if exists tt12 cascade;create temporary
table tt12 (_Q_001_F_000RRef bytea, _Q_001_F_001_TYPE bytea, _Q_001_F_001_RTRef bytea, _Q_001_F_001_RRRef bytea )
without oids ',RowsAffected=0,Result=PGRES_COMMAND_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Создание заготовки для второй временной таблицы «ВТ_ДокументыОснования». Добавляем в итоговый запрос.
30:03.720000-8997,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql='INSERT INTO pg_temp.tt12 (_Q_001_F_000RRef, _Q_001_F_001_TYPE, _Q_001_F_001_RTRef, _Q_001_F_001_RRRef) SELECT
T1._Document487_IDRRef,
T1._Fld15281_TYPE,
T1._Fld15281_RTRef,
T1._Fld15281_RRRef
FROM _Document487_VT15279 T1
WHERE (T1._Fld1000 = CAST(0 AS NUMERIC))',RowsAffected=1257,Result=PGRES_COMMAND_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Запрос второй временной таблицы «ВТ_ДокументыОснования». Копируем в итоговый.
30:03.725000-4998,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql=ANALYZE pg_temp.tt12,RowsAffected=0,Result=PGRES_COMMAND_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Служебный запрос для сбора статистики второй временной таблицы «ВТ_ДокументыОснования».
30:03.728000-999,DBPOSTGRS,5,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql="SELECT
T1._Q_000_F_000RRef,
T1._Q_000_F_003,
T1._Q_000_F_002RRef,
COALESCE(T2._Q_001_F_001_TYPE,'\\001'::bytea),
COALESCE(T2._Q_001_F_001_RTRef,'\\000\\000\\000\\000'::bytea),
COALESCE(T2._Q_001_F_001_RRRef,'\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000'::bytea)
FROM pg_temp.tt11 T1
LEFT OUTER JOIN pg_temp.tt12 T2
ON (T1._Q_000_F_001_TYPE = '\\010'::bytea AND T1._Q_000_F_001_RTRef = '\\000\\000\\001\\347'::bytea
AND T1._Q_000_F_001_RRRef = T2._Q_001_F_000RRef)",RowsAffected=27,Result=PGRES_TUPLES_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Финальный запрос выборки.
30:03.743000-999,DBPOSTGRS,4,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql="SELECT FASTTRUNCATE ('pg_temp.tt11')",RowsAffected=1,Result=PGRES_TUPLES_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
30:03.743004-1,DBPOSTGRS,4,level=DEBUG,process=rphost,p:processName=test,OSThread=5223,t:clientID=19,t:applicationName=1CV8C,t:computerName=ubuntu22-04,t:connectID=1,SessionID=19,Usr=АбрамовГС (директор),AppID=1CV8C,DBMS=DBPOSTGRS,DataBase=localhost\test,Trans=0,dbpid=5088,
Sql="SELECT FASTTRUNCATE ('pg_temp.tt12')",RowsAffected=1,Result=PGRES_TUPLES_OK,Context='Форма.Вызов : ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Модуль.ВыполнитьЗапросНаСервере
ВнешняяОбработка.ПросмотрЗапросаPostgreSQL.Форма.Форма.Форма : 43 : РезультатПросмотрЗапросаPostgreSQL = Запрос.Выполнить();'
Остаются только запросы очистки временных таблиц. Для наших целей анализа запроса они не понадобятся.
Полный собранный запрос 1С на стороне СУБД выглядит следующим образом.
drop table if exists tt2 cascade;create temporary table tt2 (_Q_000_F_000RRef bytea, _Q_000_F_001_TYPE bytea, _Q_000_F_001_RTRef bytea, _Q_000_F_001_RRRef bytea, _Q_000_F_002RRef bytea, _Q_000_F_003 numeric(27, 2) ) without oids;
INSERT INTO pg_temp.tt2 (_Q_000_F_000RRef, _Q_000_F_001_TYPE, _Q_000_F_001_RTRef, _Q_000_F_001_RRRef, _Q_000_F_002RRef, _Q_000_F_003) SELECT
T1.Fld22777RRef,
T1.Fld22779_TYPE,
T1.Fld22779_RTRef,
T1.Fld22779_RRRef,
T1.Fld22780RRef,
T1.Fld22791Turnover_
FROM (SELECT
T2._Fld22777RRef AS Fld22777RRef,
T2._Fld22779_TYPE AS Fld22779_TYPE,
T2._Fld22779_RTRef AS Fld22779_RTRef,
T2._Fld22779_RRRef AS Fld22779_RRRef,
T2._Fld22780RRef AS Fld22780RRef,
SUM(T2._Fld22791) AS Fld22791Turnover_
FROM _AccumRgTn22801 T2
WHERE ((T2._Fld1000 = CAST(0 AS NUMERIC))) AND (((T2._Fld22777RRef = '\\230-\\024\\332\\351\\261\\232H\\021\\345\\316X\\212''m\\266'::bytea)) AND (T2._Fld22791 <> CAST(0 AS NUMERIC)))
GROUP BY T2._Fld22777RRef,
T2._Fld22779_TYPE,
T2._Fld22779_RTRef,
T2._Fld22779_RRRef,
T2._Fld22780RRef
HAVING (SUM(T2._Fld22791)) <> CAST(0 AS NUMERIC)) T1;
ANALYZE pg_temp.tt2;
drop table if exists tt3 cascade;create temporary table tt3 (_Q_001_F_000RRef bytea, _Q_001_F_001_TYPE bytea, _Q_001_F_001_RTRef bytea, _Q_001_F_001_RRRef bytea ) without oids;
INSERT INTO pg_temp.tt3 (_Q_001_F_000RRef, _Q_001_F_001_TYPE, _Q_001_F_001_RTRef, _Q_001_F_001_RRRef) SELECT
T1._Document487_IDRRef,
T1._Fld15281_TYPE,
T1._Fld15281_RTRef,
T1._Fld15281_RRRef
FROM _Document487_VT15279 T1
WHERE (T1._Fld1000 = CAST(0 AS NUMERIC));
ANALYZE pg_temp.tt3;
SELECT
T1._Q_000_F_000RRef,
T1._Q_000_F_003,
T1._Q_000_F_002RRef,
COALESCE(T2._Q_001_F_001_TYPE,'\\001'::bytea),
COALESCE(T2._Q_001_F_001_RTRef,'\\000\\000\\000\\000'::bytea),
COALESCE(T2._Q_001_F_001_RRRef,'\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000'::bytea)
FROM pg_temp.tt2 T1
LEFT OUTER JOIN pg_temp.tt3 T2
ON (T1._Q_000_F_001_TYPE = '\\010'::bytea AND T1._Q_000_F_001_RTRef = '\\000\\000\\001\\347'::bytea AND T1._Q_000_F_001_RRRef = T2._Q_001_F_000RRef);
Казалось бы, что сейчас уже можно выполнить собранный запрос в PostgreSQL и проанализировать его план выполнения, но, увы, делать это еще пока рано.
Нюансы, нюансы и еще раз нюансы
Платформа 1С при установке соединения с СУБД PostgreSQL устанавливает специальные параметры, без которых запросы могут выполниться по-другому или даже привести к некорректному итоговому результату.
Установка параметров выполняется через конструкцию SET [параметр] = [значение]. Чтобы найти все ранее установленные параметры, можно использовать в терминале команду ниже.
sudo cat rphost_*/*.log | awk '{if(match($0, "^[0-9][0-9]\:[0-9][0-9]\.[0-9]+\-")) printf "\n%s#line#", $0; else printf "%s#line#", $0;}' | grep -i -o ',SQL=.set[^,]*,' | sort | uniq
Для платформы 8.3.25.1286 получили следующие параметры:
Уберем лишнее и добавим их в начало итогового запроса к PostgreSQL. Для получения плана запроса добавим EXPLAIN ANALYZE перед итоговой выборкой.
set client_encoding = 'utf8';
SET client_min_messages=error;
SET cpu_operator_cost = 0.001;
SET enable_mergejoin = off;
SET escape_string_warning = off;
SET lc_messages to 'en_US.UTF-8';
SET lock_timeout = 20000;
SET standard_conforming_strings = off;
drop table if exists tt2 cascade;create temporary table tt2 (_Q_000_F_000RRef bytea, _Q_000_F_001_TYPE bytea, _Q_000_F_001_RTRef bytea, _Q_000_F_001_RRRef bytea, _Q_000_F_002RRef bytea, _Q_000_F_003 numeric(27, 2) )
without oids;
INSERT INTO pg_temp.tt2 (_Q_000_F_000RRef, _Q_000_F_001_TYPE, _Q_000_F_001_RTRef, _Q_000_F_001_RRRef, _Q_000_F_002RRef, _Q_000_F_003) SELECT
T1.Fld22777RRef,
T1.Fld22779_TYPE,
T1.Fld22779_RTRef,
T1.Fld22779_RRRef,
T1.Fld22780RRef,
T1.Fld22791Turnover_
FROM (SELECT
T2._Fld22777RRef AS Fld22777RRef,
T2._Fld22779_TYPE AS Fld22779_TYPE,
T2._Fld22779_RTRef AS Fld22779_RTRef,
T2._Fld22779_RRRef AS Fld22779_RRRef,
T2._Fld22780RRef AS Fld22780RRef,
SUM(T2._Fld22791) AS Fld22791Turnover_
FROM _AccumRgTn22801 T2
WHERE ((T2._Fld1000 = CAST(0 AS NUMERIC))) AND (((T2._Fld22777RRef = '\\230-\\024\\332\\351\\261\\232H\\021\\345\\316X\\212''m\\266'::bytea)) AND (T2._Fld22791 <> CAST(0 AS NUMERIC)))
GROUP BY T2._Fld22777RRef,
T2._Fld22779_TYPE,
T2._Fld22779_RTRef,
T2._Fld22779_RRRef,
T2._Fld22780RRef
HAVING (SUM(T2._Fld22791)) <> CAST(0 AS NUMERIC)) T1;
ANALYZE pg_temp.tt2;
drop table if exists tt3 cascade;create temporary table tt3 (_Q_001_F_000RRef bytea, _Q_001_F_001_TYPE bytea, _Q_001_F_001_RTRef bytea, _Q_001_F_001_RRRef bytea ) without oids;
INSERT INTO pg_temp.tt3 (_Q_001_F_000RRef, _Q_001_F_001_TYPE, _Q_001_F_001_RTRef, _Q_001_F_001_RRRef) SELECT
T1._Document487_IDRRef,
T1._Fld15281_TYPE,
T1._Fld15281_RTRef,
T1._Fld15281_RRRef
FROM _Document487_VT15279 T1
WHERE (T1._Fld1000 = CAST(0 AS NUMERIC));
ANALYZE pg_temp.tt3;
EXPLAIN ANALYZE
SELECT
T1._Q_000_F_000RRef,
T1._Q_000_F_003,
T1._Q_000_F_002RRef,
COALESCE(T2._Q_001_F_001_TYPE,'\\001'::bytea),
COALESCE(T2._Q_001_F_001_RTRef,'\\000\\000\\000\\000'::bytea),
COALESCE(T2._Q_001_F_001_RRRef,'\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000'::bytea)
FROM pg_temp.tt2 T1
LEFT OUTER JOIN pg_temp.tt3 T2
ON (T1._Q_000_F_001_TYPE = '\\010'::bytea AND T1._Q_000_F_001_RTRef = '\\000\\000\\001\\347'::bytea AND T1._Q_000_F_001_RRRef = T2._Q_001_F_000RRef);
Важно: при первом выполнении запроса параметры не применяются к запросу ниже. Поэтому для их применения потребуется выполнить запрос повторно.
Перенесем полученный текст запроса в pg_admin и выполним его два раза для получения реального плана запроса как если бы запрос был выполнен из базы 1С.
План запроса получен.
А какие методы и инструменты для просмотра запроса 1С в PostgreSQL используете Вы?