Как посмотреть запрос 1С в PostgreSQL

04.03.25

База данных - Технологический журнал

Существуют различные методики и инструменты просмотра запроса 1С в PostgreSQL. В этой статье мы разберём подробнее метод анализа запроса 1С на стороне PostgreSQL с помощью технологического журнала платформы 1С и команд в терминале Ubuntu.

В отличие от 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"

Разберем каждую команду конвейера подробнее.

  1. sudo 
    выполнение команды от имени суперпользователя, которое поможет нам обойти проблемы права доступа на чтение логов;
  2. cat rphost_*/*.log
     получение всех логов из каталогов технологического журнала;
  3. awk '{if(match($0, "^[0-9][0-9]\:[0-9][0-9]\.[0-9]+\-")) printf "\n%s#line#", $0; else printf "%s#line#", $0;}' 
    преобразует многострочную запись события лога в одну строку. Запись лога технологического журнала 1С всегда начинается по одинаковому шаблону [минута]:[секунда].[микросекунда]. Но далее событие может записываться в многострочном режиме. Поэтому для дальнейшего поиска переменной «РезультатПросмотрЗапросаPostgreSQL»  преобразуем многострочные записи событий в одну строку без символа переноса. Символ переноса строки заменяем на #line#, чтобы после поиска вернуть все как было для удобочитаемости;
  4. grep 'РезультатПросмотрЗапросаPostgreSQL'
    построчный поиск среди всех логов событий, в которых присутствует текст «РезультатПросмотрЗапросаPostgreSQL»;
  5. 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 используете Вы?

PostgreSQL анализ запросов оптимизация запросов технологический журнал

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

15500 руб.

02.09.2020    177469    986    403    

941

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    11252    bayselonarrend    21    

162

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    26017    SeiOkami    48    

136

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    17417    YA_418728146    8    

170

Механизмы платформы 1С Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    31191    SeiOkami    33    

117

Запросы HighLoad оптимизация Программист Запросы Бесплатно (free)

Многие знают, что для ускорения работы запроса нужно «изучить план». При этом сам план обычно обескураживает: куча разноцветных иконок и стрелочек; ничего не понятно, но очень интересно! Аналитик производительности Александр Денисов на конференции Infostart Event 2021 Moscow Premiere рассказал, как выполняется план запроса и что нужно сделать, чтобы с его помощью находить проблемы производительности.

20.06.2023    33646    Филин    37    

119
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. partizand 140 04.03.25 19:36 Сейчас в теме
А не проще добавить сбор планов запросов сразу в logcfg?
И получить готовый план сразу из ТЖ.
2. user593895_gurov-boris-spb 1 04.03.25 23:04 Сейчас в теме
(1) Да, спасибо за комментарий. План запросов можно собирать в технологическом журнале добавив в logcfg.xml тег <plansql />. Главное не делать этого на рабочих или общих тестовых серверах, т.к. в таком случае каждый запрос выборки будет выполняться дважды из-за особенностей взаимодействия платформы 1С и Postgres.
3. aShumakoff 155 05.03.25 09:13 Сейчас в теме
Смотрю платы с помощью модуля для постгрес auto_explain.
Также есть целая методика от вендора
https://its.1c.ru/db/metod8dev/content/6011/hdoc
Оставьте свое сообщение