Как посмотреть запрос 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    186230    1037    403    

971

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

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    10020    dsdred    62    

111

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

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

23.06.2024    14245    bayselonarrend    21    

164

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

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

06.10.2023    26808    SeiOkami    48    

137

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

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

28.08.2023    18425    YA_418728146    8    

172

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

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

27.06.2023    34005    SeiOkami    33    

121
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. partizand 140 04.03.25 19:36 Сейчас в теме
А не проще добавить сбор планов запросов сразу в logcfg?
И получить готовый план сразу из ТЖ.
2. user593895_gurov-boris-spb 5 04.03.25 23:04 Сейчас в теме
(1) Да, спасибо за комментарий. План запросов можно собирать в технологическом журнале добавив в logcfg.xml тег <plansql />. Главное не делать этого на рабочих или общих тестовых серверах, т.к. в таком случае каждый запрос выборки будет выполняться дважды из-за особенностей взаимодействия платформы 1С и Postgres.
4. triviumfan 101 13.03.25 10:16 Сейчас в теме
(2) Даже если делать это в определенное время с указанием длительности (duration), чтобы найти только длительные запросы? Или это всё лишь уменьшит количество логов, но даст такую же нагрузку как и без доп фильтров?
5. user593895_gurov-boris-spb 5 22.03.25 15:06 Сейчас в теме
(4) Настройка <plansql /> в любом случае включает для всех запросов из 1С в PostgreSQL двойное выполнение на стороне СУБД. Поэтому включать ее на продуктивных серверах или общих тестовых серверах крайне не рекомендуется.
3. aShumakoff 156 05.03.25 09:13 Сейчас в теме
Смотрю платы с помощью модуля для постгрес auto_explain.
Также есть целая методика от вендора
https://its.1c.ru/db/metod8dev/content/6011/hdoc
6. pyrkin_vanya 498 29.03.25 07:37 Сейчас в теме
А можно ли как то собирать планы запросов для временных таблиц в постгресе через ТЖ? MS SQL это делает, а вот PG дает план только на пакетник выборки.
Оставьте свое сообщение