Как перевести запрос sql в 1с

Обновлено: 04.07.2024

В одной из компаний где я когда-то работал, имелась собственная разработка на 1С 8.2 платформе.
Однажды мы пришли к понимаю что наша система работает не очень быстро. Оставалось понять в каком направлении двигаться, что бы оптимизировать работу системы. После долгих исследований и экспериментов, мы решили в серьез взяться за перенос некоторых операций на плечи СУБД, а именно на плечи MS SQL с помощью выполнения прямых запросов на стороне SQL Server, в обход сервера приложений 1С.

Тот случай был единственным где подобное решение было рациональным. Но те навыки что я получил в тот момент, с легкостью можно использовать для интеграций системы 1С с другими информационными системами.

Cтруктура базы данных 1С на уровне СУБД выглядит не совсем внятно.
Постараюсь описать что же из себя представляет эта структура. Описание будет не полное. Постараюсь описать лишь самое интересное и важное, из того что нужно понимать спускаясь на уровень СУБД.

Рассматриваем структуру хранения данных.

Каждый объект метаданных имеет определенный вид наименования таблиц. Например РегистрСведений начинается с "_InfoRg. ", далее идет номер (идентификатор/индекс) регистра. А вот таблички начинающиеся с _InfoRgChng это таблицы содержащие в себе регистрацию изменений в регистре. Перечислять в данной статье все префиксы я не буду. Это можно сделать с помощью средсв 1С. По мере необходимости.

Ещё интереснее у нас хранятся данные составных полей. Точнее те поля, которые могут примнимать разнотипные значения.
Допустим у нас есть поле. И оно может хранить в себе Строку, Дату, Число, ссылку на справочник клиентов, и ссылку на справочник сотрудников. В 1С мы видим одно единственное поле. На деле же такое поле в базе данных будет иметь ряд полей. Давайте рассмотрим этот пример. Предположим что индекс нашего поля - 8818.

Наименование поля Описание
_Fld8818_TYPE(binary(1)) В данном поле хранится тип значения, который хранится в текущей записи. Тип представляет из себя индекс. Целое число.
_Fld8818_N(Numeric(x)) Здесь будет храниться значение числа. Тип числа (разрядность и длинна равная x) будет зависеть от настроек в самом конфигураторе 1С
_Fld8818_T(datetime) В данном поле будет храниться значение типа Дата и Время
_Fld8818_S(nvarchar(1024)) В этом поле значение в виде строки. Причем длина строки зависит от настроек.
_Fld8818_RTRef(binary(4)) В данном поле, при условии что в записи хранится ссылка, будет указан тип ссылки. То есть, на какую таблицу ссылается ссылка, справочник это или документ, что за документ или справочник.
_Fld8818_RRRef(binary(16)) А это уже будет сама ссылка на конкретную запись, в конкретной таблице

Если с простыми типами данных все ясно, то тип ссылки не так прост.

Наверняка вы зададите вопрос: Как можно определить тип ссылки? То есть, что означает индекс хранящийся в поле _Fld8818_RTRef?
Если мы переведем этот индекс из шестнадцатеричной системы счисления в десятичную, и затем посмотрим на список таблиц базы данных, то обязательно найдем таблицу, в имени которой содержится данный индекс. То есть мы можем по этому индексу получить таблицу, в которой содержится элемент, на который ссылается ссылка в нашем поле.

Зная индекс, мы можем найти необходимую таблицу простым запросом:

Где 1950 — искомый индекс.

Получаем структуру хранения средствами платформы 1С.

Остается вопрос, как нам определить, как некоторая таблица в конфигурации 1С, именуется на уровне СУБД, а так же, соответствие полей на уровне СУБД и конфигурации?
В этом нам поможет встроенная функция поставляемая вместе с платформой:

Данная функция возвращает структуру в которой мы можем по имени объекта в МетаДанных, получить имя объекта в базе данных. Точно так же в структуре содержаться и все поля объектов, и их наименования в базе данных. Но здесь уже начинаются подводные грабли. Которых вроде как и нет, и в тоже время они есть.

Важный момент. При вызове метода, обязательно нужно передать во второй параметр значение «Истина». Что это означает? Этот параметр означает будет ли структура отображать данные в формате 1С: Предприятие, либо в формате СУБД. В чем же разница?

Допустим мы отображаем данные в формате 1С: Предприятие.
Например, если мы попытаемся с помощью этой структуры узнать как называется в базе данных поле «Клиент», то получим к примеру такое имя «Fld1234». Вроде бы все хорошо. Но если мы попытаемся написать запрос к MS SQL:

Мы в 80% случаев — получим ошибку. Почему? А потому что это лишь общий вид наименования поля. Но стоит знать о том что во первых любое имя поля начинается с нижнего подчеркивания. Казалось бы прибавим к наименованию поля символ "_" и делов то! Но нет. Далее ещё интересней. В зависимости от содержимого поля и его типа, поле имеет определенный постфикс в наименовании. Например RRef — это значит что в поле содержится ссылка. А если просто значение то этого постфикса нет. А помните составные типы данных? Там вообще может быть куча различных постфиксов, при этом полей начинающихся на "_Fld1234" будет гораздо больше чем одно. И как же нам обойти это?
Легко. Те кто знает MS SQL, сразу догадались что на помощь придет системное представление INFORMATION_SCHEMA.COLUMNS
С помощью этого представления мы можем отобрать информацию по наименованию таблицы, и по тому ключевому наименованию поля.
Пример запроса:

Данный запрос выдаст нам ряд полей, имена которых начинаются на "_Fld1234". Нам же останется эти данные обработать в нашей программе для использования в запросах к базе.

Но какие минусы у этого метода? Во первых для того что бы обратиться к базе, нам необходимо настроенное подключение к БД, через 1С. То есть дополнительные настройки. Но они нам в любом случае пригодятся, но представьте, у вас большой запрос. Нужно получить имена 20 полей. И каждый раз при этом обращаться к базе и искать там имена полей? Получать и использовать подключение? Это не очень оптимально. Плюс к тому полученные из базы данные, придется ещё как-то обрабатывать. Дополнительные действия. Да и словом - изобретение велосипеда.

Вот тут то нам и приходит на помощь функция

Когда значение параметра ИменаБазыДанных = Истина, то функция в результирующую структуру сразу передает всю необходимую информацию по объектам. Включая все физические поля Базы данных. Если поле составное, то в структуре будут видны все физические поля составного поля. Это значительно облегчает нашу работу.

Использование прямых запросов. Отборы. Соединения и обращения через точку.

Как же нам использовать отбор в прямых запросах? Как отобрать данные по конкретному документу? Или по конкретному значению?

Все довольно просто, но снова есть нюансы.

Поля формата Дата. По умолчанию при использовании MS SQL сервера, дата 1С в базу помещается с прибавлением к году 2000. То есть дата в системе 1С «01.01.2013» будет выглядеть как «01.01.4013». Но и это ещё не все. Для того что бы в запросе произвести сравнение даты и оно прошло корректно, нам необходимо дату конвертировать в определенный формат.
По умолчанию в базе данных MSSQL используется формат ymd. Это означает что в дате сперва указан год, месяц и затем число. А выглядит дата следующим образом: 4013-01-01. Для использования в условиях сравнения или для прочих манипуляций нам эту дату нужно обрамлять в опострофы, так же как и строки.

Для преобразования даты в формат SQL я написал для себя такую простенькую функцию:

Данная функция возвращает готовую дату, в нужном формате в виде строки, остается только подставить в текст запроса. Если у вас в MS SQL по каким то причинам установлен иной формат даты, можно на момент исполнения запроса его поменять. Делается это так:

Либо надо будет переделать представление даты в своем запросе.

Теперь нам нужно отобрать записи по определенному элементу справочника. Как это сделать?
Изначально, когда я не знал о существовании функции ЗначениеВСтрокуВнутр(), для своих нужно я написал пару функций, для получения ссылок на справочники и на документы. Выглядят они так:

Как видно в коде, мы строим простой запрос, и получаем из базы значение ID, которое храниться в базе данных. Объект — это у нас наименование справочника либо документа, а код — код элемента справочника или документа.
Функция master.dbo.fn_varbintohexstr() — позволяет преобразовать значение формата binary в строку.
Но использовать эту функцию — не обазательно.

Полученный ID имеет примерно такой вид: 0xa8ed00221591466911e17da9fd549878
В запросе мы его можем сравнивать как строку

Но в таком случае запрос будет отрабатывать дольше. Так как на преобразование в строку тоже нужно время.
Поэтому лучше сравнение делать таким образом:

Предыдущий вариант использовать можно, но на самом деле, имеется более универсальный и оптимальный способ получить ссылку. Он приведен в функции что показана ниже:

А давайте представим что нам нужно в запросе сделать внутреннее соединение. И сравнение должно происходить с полем через точку?
То есть, для сравнения нам необходимо проверять одно условие, что дата в основной таблице, равна дате, которая содержится в документе, ссылка на который содержится в присоединяемой таблице.
В 1С это будет выглядеть примерно так

Как же описать это с помощью MS SQL? В том месте запроса, где описываются соединения, компилятор запросов ещё не знает о том что в таблице регистра есть ссылка на регистратор, и что это в свою очередь есть документ, а у этого документа есть дата. Описать ещё одно соединение? Не поможет. Словом я пытался это сделать всяко. Но в итоге решение свелось к вложенному запросу. (если кто-то найдет реальную альтернативу, буду рад узнать ваш способ).

Выше приведенный фрагмент на чистом SQL будет выглядить так:

В запросе мы видим, что во вложенном запросе делаем выборку из таблицы документа, где ID документа равен ID который записан в поле нашей таблицы «Источник», и далее полученное значение _Date_Time сравниваем с датой из нашей таблицы. Все логично и просто. Думаю теперь мы понимаем, во что превращаются наши обращения к полям и объектам через точку, в запросах 1С, когда они транслируются на SQL запрос. И теперь становится понятно почему такие обращения затормаживают работу запросов.

Очень рекомендую вам поэксперементировать с различными запросами, используя инструмент SQL Server Profiler. С его помощью вы сможете увидеть, во что превращаются ваши запросы написанные на языке запросов 1С, пройдя трансляцию на сервере приложений 1С. Особенно интересно вам будет посмотреть что из себя представляют такие виртуальные таблицы как "СрезПоследних".

Тот пример который я описал выше, с внутренним соединеним, 1С сервер скорее всего реализует немного по другому. Но у него свои методы, с использованием переменных, значения которых заполняются серверов приложений перед выполнением запроса.
Ниже я приведу один пример.

Допустим у нас есть запрос в формате 1С:

Как мы видим, ситуация аналогичная, как я приводил выше, только соединение не внутреннее, а левое. Как же 1С Сервер приложений траслирует такой запрос?

Запрос на выходе из 1С Сервера приложений

С помощью SQL Server Profiler мы сможем это увидеть. На картинке выше, показан запрос сервера приложений. Как я и писал выше, мы видим что сервер приложений использует переменные, в которые заранее пишет соответствующие ID. Но нам при использовании прямых запросов, проще было использовать именно вложенный запрос, для нас это универсальное решение, так как не придется подставлять значения переменным.

Будет замечательно если вы самостоятельно изучите различные запросы в таком виде. Возможно это поможет вам оптимизировать ваши запросы.


Для решения каких задач нам могут понадобиться прямые запросы к базе данных?

Думаю данная возможность понадобиться при активной разработки своих собственных решений, либо при реструктуризации готовых решений. В тех случаях, когда в отладочных целях, либо ещё по каким-то причинам, нам придётся переносить большие объемы данных с одной таблицы в другую, либо разбивать данные на несколько таблиц.
Для интеграции 1С с другими, сторонними разработками. Например вывод данных из 1С в какую-нибудь стороннюю программу анализа продаж или что-то похожее.
Оптимизация массивных обработок данных. Когда нам необходимо обработать большое количество данных, при этом внося какие-то изменения, корректировки и т.п. Например копирование записей регистра сведений с изменением какого-либо поля средствами 1С, займет куда больше времени, чем выполнение операции T-SQL Update

Учимся получать доступ к СУБД из 1С.

Для работы с СУБД на прямую, в обход сервера приложений 1С, нам потребуется использовать COM объекты - ADO.
Первым делом нам понадобится строка подключения к базе данных. У нас даже есть возможность формировать эту строку через стандартный интерфейс Windows. Это значительно облегчает процесс подключения к БД.

Настройка подключения к Базе данных


Интерфейс настройки подключения к базе данных.

Давайте рассмотрим пример работы с ADO.

В данном фрагменте кода, мы создаем объект подключения к базе данных. А так же с помощью объекта DataLinks, получаем строку подключения к базе данных используя пользовательский интерфейс настройки этого самого подключения.

После того как мы получим строку подключения, нам скорее всего захочется отдельные её части разместить на форме, для того что бы пользователь мог исправлять отдельно взятые опции подключения. Следовательно строку необходимо распарсить. Я пока (на момент написания статьи) нашел лишь один способ это сделать, и привожу его ниже. Если кто-то подскажет более элегантный способ парсинга строк, будет здорово.

Теперь мы сохранили параметры подключения базы данных на форме, при желании можем их сохранить в базу данных.

Далее надо предусмотреть вариант, когда пользователь (чаще всего мы сами), изменит наименование базы данных или тайм аут прямо в форме обработки, минуя форму редактирования строки подключения. На такой случай создадим такую функцию, которая будет формировать строку подключения собирая данные из визуальных контролов формы. Выглядит она примерно так:

После выполнения данной функции нам станет ясно, можно ли работать дальше, или соединение с базой установить не удалось, и следовательно дальше что-либо делать с подключением — бесполезно. Кстати, для оптимизации функцию получения объекта ADODB.Connection можно разместить в общем модуле, в настройках которого выставлено «Повторное использование». Это позволит не создавать каждый раз новый объект подключения, а будет использоваться уже созданный объект. В теории это позволит сократить время вызова соединения, а так же совсем чуть-чуть сэкономит ресурсы системы.

Причем заметьте, что свойству ActiveConnection мы присваиваем ранее созданное подключение к базе. Теперь когда объект у нас создан, нам остается лишь воспользоваться им. Если нам необходимо просто выполнить запрос, который не вернет никаких результатов, то будет достаточно одной простой команды, которая показана ниже.

В рамках этой статьи не будем рассматривать, как правильно настроить профайлер. Считаем, что есть некоторый запрос, который очень долго выполняется. На его примере рассмотрим, как при помощи предлогаемой обработки найти его в коде конфигурации. Обработку разумеется нужно запускать из режима предприятия на той базе, запрос к которой отловил профайлер. Пусть выглядит он вот так.

SELECT
MIN ( CASE WHEN T2.SDBL_RLS_SIGNAL_ = 0x01 AND ISNULL ( T7.SDBL_RLS_SIGNAL_ , 0x01 ) = 0x01 THEN 0x01 ELSE 0x00 END ),
T1._Document367_IDRRef ,
T7.Date_Time_ ,
T7.Number_ ,
T7.Fld7948RRef ,
T7.Fld7949RRef ,
T7.Fld7950RRef ,
T7.Fld7956RRef ,
T7.Fld7954_ ,
T7.Fld7955RRef ,
CAST ( T7.Fld7951_ AS NVARCHAR ( 300 )),
T7.Fld7946_ ,
T7.Fld7947_ ,
T7.Fld7962RRef ,
T7.Fld17647RRef
FROM _Document367_VT7991 T1 WITH ( NOLOCK )
INNER JOIN (SELECT
CASE WHEN ( EXISTS (SELECT
@P1 AS Q_002_F_000_
FROM (SELECT DISTINCT
@P1 AS SDBL_RLS_SIGNAL_ ,
T5._Fld16928RRef AS Q_001_F_000RRef
FROM _InfoRg16925 T5 WITH ( NOLOCK )
INNER JOIN _InfoRg16833 T6 WITH ( NOLOCK )
ON (((( T5._Fld16926 = @P2 ) AND ( T6._Fld16834RRef = @P3 )) AND ( T6._Fld16835_TYPE = @P4 AND T6._Fld16835_RTRef = @P5 AND T6._Fld16835_RRRef = @P6 )) AND ( T6._Fld16837_TYPE = T5._Fld16927_TYPE AND T6._Fld16837_RTRef = T5._Fld16927_RTRef AND T6._Fld16837_RRRef = T5._Fld16927_RRRef ))) T4
WHERE 1 = 1 )) THEN @P1 ELSE @P7 END AS SDBL_RLS_SIGNAL_ ,
T3._IDRRef AS IDRRef
FROM _Document367 T3 WITH ( NOLOCK )) T2
ON T1._Document367_IDRRef = T2.IDRRef
LEFT OUTER JOIN (SELECT
CASE WHEN ( EXISTS (SELECT
@P1 AS Q_002_F_000_
FROM (SELECT DISTINCT
@P1 AS SDBL_RLS_SIGNAL_ ,
T10._Fld16928RRef AS Q_001_F_000RRef
FROM _InfoRg16925 T10 WITH ( NOLOCK )
INNER JOIN _InfoRg16833 T11 WITH ( NOLOCK )
ON (((( T10._Fld16926 = @P2 ) AND ( T11._Fld16834RRef = @P3 )) AND ( T11._Fld16835_TYPE = @P4 AND T11._Fld16835_RTRef = @P5 AND T11._Fld16835_RRRef = @P6 )) AND ( T11._Fld16837_TYPE = T10._Fld16927_TYPE AND T11._Fld16837_RTRef = T10._Fld16927_RTRef AND T11._Fld16837_RRRef = T10._Fld16927_RRRef ))) T9
WHERE 1 = 1 )) THEN @P1 ELSE @P7 END AS SDBL_RLS_SIGNAL_ ,
T8._IDRRef AS IDRRef ,
T8._Date_Time AS Date_Time_ ,
T8._Number AS Number_ ,
T8._Posted AS Posted_ ,
T8._Fld7946 AS Fld7946_ ,
T8._Fld7947 AS Fld7947_ ,
T8._Fld7948RRef AS Fld7948RRef ,
T8._Fld7949RRef AS Fld7949RRef ,
T8._Fld7950RRef AS Fld7950RRef ,
T8._Fld7951 AS Fld7951_ ,
T8._Fld7954 AS Fld7954_ ,
T8._Fld7955RRef AS Fld7955RRef ,
T8._Fld7956RRef AS Fld7956RRef ,
T8._Fld7962RRef AS Fld7962RRef ,
T8._Fld17647RRef AS Fld17647RRef
FROM _Document367 T8 WITH ( NOLOCK )
WHERE T8._Date_Time >= @P8 AND T8._Date_Time @P9 AND T8._Fld7948RRef = @P10 AND T8._Fld7956RRef = @P11 ) T7
ON T1._Document367_IDRRef = T7.IDRRef
WHERE T7.Posted_ = @P1 AND (( T7.Date_Time_ >= @P8 ) AND ( T7.Date_Time_ @P9 )) AND ( T7.Fld7948RRef = @P10 ) AND ( T7.Fld7956RRef = @P11 ) AND ( T1._Fld7994_TYPE = @P12 )
GROUP BY T1._Document367_IDRRef ,
T7.Date_Time_ ,
T7.Number_ ,
T7.Fld7948RRef ,
T7.Fld7949RRef ,
T7.Fld7950RRef ,
T7.Fld7956RRef ,
T7.Fld7954_ ,
T7.Fld7955RRef ,
CAST ( T7.Fld7951_ AS NVARCHAR ( 300 )),
T7.Fld7946_ ,
T7.Fld7947_ ,
T7.Fld7962RRef ,
T7.Fld17647RRef
ORDER BY 3 , 4

МИНИМУМ ( ВЫБОР КОГДА T2.SDBL_RLS_SIGNAL_ = 1 И ISNULL ( T7.SDBL_RLS_SIGNAL_ , 0x01 ) = 1 ТОГДА 1 ИНАЧЕ 0 КОНЕЦ ),

Осталось почистить ненужную информацию и строки, касающиесь RLS.

Теперь намного проще понять, какой запрос был отловлен профайлером. И код, где создается этот запрос можно искать, например, глобальным поиском по выборочным из запроса строкам.

Здесь параметры вида @P1 - это выражения, соответствующие некоторым параметрам запроса 1с. Иначе говоря, вместо них будет что-то вроде &МойПараметр.

ОФ

В первую очередь обработка будет удобна для анализа RLS, чтобы получить реально выполняемый запрос базы данных со всеми ограничениями в удобочитаемом виде.

Пример: у нас есть запрос 1С из конфигурации УПП 1.3, который медленно выполняется под некоторыми пользователями, и мы хотим понять, какой запрос по факту выполняется и по возможности ускорить его.

Видно, что к исходному запросу добавляется громоздкое условие проверяющее доступ пользователя к данной таблице. Предположим, что в организации не используется управленческий учет, тогда проверку доступа RLS можно упростить, отключив контроль по подразделению и оставив контроль по подразделению организации (Операции->Константы->Настройка параметров доступа на уровне записей). Обратите внимание, что при включенном флажке «Результат в терминах 1С», текст запроса максимально приближен к тексту запроса, корректного для выполнения в консоли запроса 1С. Что мне не удалось сделать, так это убрать из текста запроса проверки типа для составных полей, так как для этого пришлось бы использовать полноценный парсер языка запросов SQL. Чтобы запрос был полностью рабочим для консоли запросов, придется руками убрать проверку на составной тип, если такой используется в запросе. В приведенном примере нужно заменить строки

AND T7.ОбъектДоступа_RTRef = 0x000000B5

AND T7.ОбъектДоступа = T1.Подразделение на строку

AND T7.ОбъектДоступа = T1.Подразделение на строку

AND T9.ОбъектДоступа_RTRef = 0x000000B6

AND T9.ОбъектДоступа = T1.ПодразделениеОрганизации

Тогда запрос будет полностью корректным для языка запросов 1с и его можно будет выполнить в консоли.

Дополнительный способ проверки результирующего запроса в SQL

Если при выполнении трансформации снять флажок «Результат в терминах 1С», то результирующий текст запроса будет корректным для языка T-SQL и его можно выполнить в SQL Server Management Studio или в консоли запросов, которая поддерживает выполнение прямых запросов SQL (например моя простенькая консоль SQL запросов). Для нашего примера со списком сдельных нарядов результат будет следующим:

Результат трансформации (снят флажок «Результат в терминах 1С»):

Теперь запрос представлен в исходном SQL виде с дополнительными комментариями к параметрам запроса с представлениями ссылок в 1с и его можно выполнить как обычный запрос на языке T-SQL.

Пример 2

Еще один способ использования обработки – в связке с технологическим журналом, без использования трассировки. Пример: в доработанной конфигурации Документооборот 1.4 под некоторыми пользователями очень медленно открывается список внутренних документов. Настраиваем тех. журнал на отлов событий DBMSSQL и смотрим запросы, которые генерировала платформа при открытии формы списка (для настройки и анализа тех. журнала удобно пользоваться инструментами разработчика, но для просмотра можно использовать и типовую обработку с ИТС ПросмотрТехнологическогоЖурнала.epf). Находим следующий запрос:

Не очень удобно разбираться с таким запросом – нет форматирования, вместо параметров стоят вопросы и т.д., поэтому прогоняем его через трансформатор(все опции включены) и получаем такой вид:

Видно, что однотипные ограничения RLS применяются 3 раза при выполнении запроса динамического списка (это можно понять по характерным конструкциям WHERE EXISTS() или по использованию области доступа «ДокументыИФайлы») и это может быть причиной медленной работы списка документов. С проверкой на доступ к таблице T1 «Справочник.ВнутренниеДокументы» сделать ничего не получится, так как это основная таблица списка, а вот оставшиеся 2 проверки под вопросом. «РегистрСведений.ОбщиеРеквизитыДокументов» T4 используется для получения реквизитов «КорреспондентыДляСписков», «ПредставлениеСостояния», «СодержитОригинал», а таблица «Справочник.ВидыВнутреннихДокументов» T12 используется для получения реквизита «ВидДокумента.ЯвляетсяКомплектомДокументов». Таким образом, можно либо не использовать поля на форме, которые приводят к вызову дополнительных проверок на права доступа, либо убрать проверку RLS для вспомогательного регистра с данными, так как проверка уже выполняется в основной таблице и эффекта от дополнительных проверок в данном запросе нет.

Пример 3

Еще один вариант использования обработки – исследование фактического запроса SQL при обращении к виртуальным таблицам 1с. Меня давно интересовал вопрос, как интерпретируется запрос к виртуальным таблицам. Если с таблицей остатков и оборотов регистров накопления все достаточно очевидно, то, например, с регистрами бухгалтерии было бы интересно посмотреть на фактический запрос при указании разных параметров. Рассмотрим достаточно простой запрос обращения к движениям с субконто за указанный период

Прогоняем запрос через трансформатор(все опции включены) и получаем такой вид:

Получен интересный листинг, который показывает, что фактически происходит выполнение нескольких запросов с формированием временных таблиц. Рассмотрим эти запросы:

1) Выполняется запрос к системной таблице актуальности итогов для всех регистров с отбором по регистру. Это нужно для определения необходимости использования служебных таблиц с итогами и периода, на который эти итоги существуют (может есть и другие функции этого запроса, но мои знания ограничиваются только периодами в итогах — дополняйте в комментариях:))

7) Выбирается максимальный регистратор и номер строки, для отделения следующей порции данных

Разобрав запрос, можно сделать вывод что производительность выборки из виртуальной таблицы ДвиженияССубконто полностью определяется объемами выбираемых данных и если не использовать отбор внутри виртуальной таблицы, то все записи физических таблиц будут прогоняться через временные таблицы порциями по 1000 записей, что очень медленно (даже продвинутая СУБД не сможет оптимизировать такой запрос).

Как настроить трассировку запроса из обработки

За трассировку запроса отвечает 2 поля:

Путь файла трассы — здесь указывается путь к папке, в которую будут сохраняться временные файлы трассировки и имя файла (например D:\Временные файлы\TraceTest). Имена файлов трассировки будут присваиваться автоматически, добавлением номера в конец имени (например TraceTest_54.trc)

Подключение SQL — строка подключения к базе данных (например «DRIVER=;SERVER=PC_1C_003;UID=sa;PWD=123;DATABASE=Localbase»). Строку подключения можно проверить на работоспособность, нажав на кнопку «Проверить подключение».

Трассировка запускается только если исходный запрос написан на языке запросов 1с, поэтому если введен SQL запрос, то поля «Путь файла трассы» и «Подключние SQL» можно не заполнять.

Выводы

Данную обработку можно использовать в связке с технологическим журналом с помощью инструментов разработчика или типовой обработки, а также можно использовать без ТЖ, используя трассировку запроса, встроенную в обработку или запуская трассировку вручную. Для понимания фактически выполняемого SQL запроса, гораздо удобнее видеть наименования таблиц и полей в терминах 1с, видеть представление ссылок 1с и читать форматированный текст запроса с отступами и пробелами.

Форма обработки анализа ТЖ из инструментов разработчика:

ИР

Форма типовой обработки с ИТС для просмотра логов ТЖ:

Типовая обработка

Ссылки

Update 19.09.2017

- При обращении к сервису форматирования убрано использование объекта ЧтениеJSON, для совместимости с 8.2 и версиями ниже 8.3.6

Затем создадим процедуру, которая будет вытаскивать данные. Процедура будет иметь два параметра: обязательный и необязательный. Обязательным будет дата, начиная с которой брать данные, а необязательным будет массив артикулов.

Процедура вытаскивает данные по параметрам во временную таблицу, выводит её и, после этого, дропает.

По ощущениям, работает быстрее чем просто запрос к внешнему источнику.

С SQL всё. Переходим к 1С

Подключение к SQL Сервер:

Установка параметров процедуры и её вызов:

Ну и заполнение ТЗ результатами вызова:

После этого с ТЗ уже делаем, что хотим.

Для примера выкладываю обработку и бэкап SQL базы.

Тестировалось на платформе 8.3.12.1685, 8.3.14.1944, 8.3.15.1747.

Использование хранимых процедур MS SQL Server в 1С Использование хранимых процедур MS SQL Server в 1С + гуманитарная помощь автору для совершенствования самообразования

Специальные предложения

Electronic Software Distribution

Интеграция 1С с системой Меркурий

Алкогольная декларация

Готовые переносы данных

54-ФЗ

Управление проектом на Инфостарте

Траектория обучения 1С-разработчика

Через внешние источники данных в связке с sql можно решить любую задачу. Зачем использовать такое решение совершенно не понятно (1)Если попробовать заджойнить две таблицы из внешнего источника - выйдет коллапс. Если всё-таки заставить это работать (это возможно) - будет намного медленней, чем если средствами самой СУБД (3) Вся логика отрабатывается в хранимой процедуре. Там джоинить можно что угодно. В 1С только финальный результат. Если нужно вернуть таблицу, то хранимая процедура возращает ID. Дальше SELECT по таблице уже в 1С, куда все написала процедура. Таблица в которую процедура должна написать результат подключается как внешний источник. Все идеально работает. (3) А почему не сделать вьюшку и обращаться именно к ней? (1) Попробуете сделать что нибудь масштабное через внешние источники данных - поймете :-) (6) Интеграцию любой степени сложности делал и не раз. И с хранимыми процедурами и с вьюшками и со скалярными функциями. Что угодно. Все идеально работает. Хранимые процедуры пишут в таблицу и возвращают ID. Эта таблица подключена к внешнему источнику и служит для "забрать результат". Что еще может быть проще ? (7) Попробуйте выгружать через внешние источники данных миллионы записей в MS SQL. (9) Если такие задачи возникают, то надо пересмотреть само приложение и подходы к работе с данными. Если надо что-то забирать из 1С, то тут лучше использовать ODATA. (11) миллиарды записей тоже ODATA? Интересно, как вы будете DWH строить с сотнями таблиц с контролем по ключам с инкрементальным обновлением. Внешние источники мертвы, к сожалению. (13) Просто не надо путать теплое с мягким. Внешние источники нужны именно для интеграции. Если требуется выгружать миллиарды записей, значит Вы ошиблись с софтом в принципе. Для реальных задач внешние источники очень полезный и простой инструмент. как вы будете DWH строить с сотнями таблиц с контролем по ключам с инкрементальным обновлением

Вы о чем . Пусть этим контролем занимается та система, в которой эти сотни таблиц созданы. Писать напрямую в эти таблицы из 1С никто не заставляет. Для этого и есть механизм вызова хранимых процедур, если это разумно при интеграции. Внешние источники очень удобны для загрузки данных в 1С. Во внешней системе делаем нужные вьюшки и подключаем их. В саму эту систему отправляем какие-либо подтверждения через вызов процедур. Если нужны выгрузки миллиардов записей, то задача решается совершенно другим способом.

(1) Если необходимо разрабатывать запрос с нуля, то возможно и выгоднее их использовать, но если требуется получить данные, которые уже можно выдрать с использованием хитрых хранимок - себе дороже. К тому же структура внешнего источника может дорабатываться. Использование хранимок позволяет переложить реализацию и контроль получения данных на тех, кто сопровождает внешнюю систему или как минимум получить консультацию, почему данные криво приходят.
Если не сложно - можете рассказать, как обновляете внешние источники (структуру) вкратце. В этом году пришлось много работать над интеграцией с ms sql server - показалось неудобно обновлять базу, после изменения внешнего источника (в расширение не пробовал переносить). (1) ограниченный взгляд, отрицание опыта человечества .
Берем данные из другой системы(oracle) используем при обработке и sql и pl-sql. (16) Что сказать то хотели ? Автор предложил корявый механизм работы с хранимыми процедурами. Через внешние источники данных в связке с sql можно решить любую задачу.

Однако далее в комментариях вы утверждаете что для любых задач, другие инструменты нужны :-)

Автор, а в чем смысл создавать таблицу?
Сначала создаешь таблицу, потом помещаешь туда выборку, потом получаешь все данные из этой таблицы, потом убиваешь таблицу.
Так ты возьми и просто получи данные из выборки.

Также непонятен смысл использования EXEC. Напиши сразу запрос выборки, зачем сначала формировать текст запроса в твоем ЭЛЕМЕНТАРНОМ примере, а потом его выполнять.

(5) Автор имеет ввиду, что хранимая процедура может делать что-то сложное и результат возвращать в табличном виде.
Есть только вариант вызывать функцию, которая вернет таблицу и это хорошо обыгрывается через внешние источники.
Но возможности функций в SQL значительно меньше, чем процедур.
В 1С через внешние источники нельзя вызвать процедуру с возвратом таблицы.
Вот это он хотел сказать. Просто самое решение очень корявое.

Использование хранимых процедур, как и любое подключение возможностей прямого доступа к данным - особая зона возможностей, на мой взгляд очень недооцененная.
Пример с хранимой процедурой из собственного опыта: была поставлена задача максимально быстрой синхронизации справочника "Номенклатура" в двух независимых базах (самостоятельные информационные системы разных организаций).
Самый быстрый вариант - в момент записи элемента в 1 базе, сразу-же создавать(изменять) соответствующий элемент в другой. Связь по ссылке. Т.к организации независимые и самостоятельные, раскрывать внутреннюю структуру и параметры подключения пользователей SQL с доступом к изменению данных - недопустимо. Кроме этого базы разделены территориально. В данном случае использование хранимой процедуры - идеальное решение, которое в описанном случае работает более 3х лет без единого сбоя.
Реализация:
1.В базе-приемнике создана хр. процедура, создающая(обновляющая) прямым запросом элемент номенклатуры по входным параметрам, переданным в процедуру. Возвращаемое значение - признак успешной загрузки;
2.В базе-приемнике создан пользователь, имеющий доступ только к хранимой процедуре;
3.В базе-источнике после записи нового(измененного) элемента выполняется прямое подключение к приемнику и запуск хр. процедуры с ключевыми параметрами записываемого элемента. Выполнение производится под пользователем с правами только к выполняемой процедуре, в запросе только имя процедуры и передаваемые параметры, структура данных скрыта, что и требуется по условиям задачи.

(12) а что будет, если в момент записи элемента справочника в одной базе будет недоступен канал связи между двумя базами?
Или такие риски не считаются?
Имхо, это решение - подходящее, но называть его идеальным - это слишком громко

И вообще, то, что создаете элементы в базе 1С прямыми запросами - это как-то не очень похвально, учитывая то, что для решения данной задачи имеются штатные механизмы
Использование костылей в данном примере - не обоснованно.

Читайте также: