Преобразование T-SQL запроса MSSQL в запрос 1С 8


Одним из традиционных способов определения узких мест работы информационной базы 1с 8 под MSSQL является отлов медленных запросов профайлером. Но видя "много букоф" на языке T-SQL, не так уж и просто понять, как найти запрос 1с, который их порождает. Особенно, если дополнительно используется механизм ограничения прав на уровне записей. В данной статье предлогается один из подходов упрощающих жизнь оптимизатору с использованием обработки, конвертирующей T-SQL запрос в запрос, похожий на язык запросов 1с 8.

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

T-SQL запрос:

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 КОНЕЦ),

T1.Документ.ПлатежноеПоручениеВходящее_Ссылка,
T7.Дата_,
T7.Номер_,
T7.Организация,
T7.СчетОрганизации,
T7.Контрагент,
T7.ВидОперации,
T7.СуммаДокумента,
T7.ВалютаДокумента,
ВЫРАЗИТЬ(T7.НазначениеПлатежа КАК СТРОКА(300)),
T7.ДатаВходящегоДокумента,
T7.НомерВходящегоДокумента,
T7.Ответственный,
T7.Автор
ИЗ Документ.ПлатежноеПоручениеВходящее.РасшифровкаПлатежа T1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
ВЫБОР КОГДА (СУЩЕСТВУЕТ(ВЫБРАТЬ
@P1 КАК Q_002_F_000_
ИЗ (ВЫБРАТЬ РАЗЛИЧНЫЕ
@P1 КАК SDBL_RLS_SIGNAL_,
T5.ГруппаДоступа КАК Q_001_F_000RRef
ИЗ РегистрСведений.ТаблицыГруппДоступа T5
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа T6
ПО ((((T5.Таблица = @P2) И (T6.ВидДоступа = @P3)) И (T6.ЗначениеДоступа = @P4 И T6.ЗначениеДоступа = @P5 И T6.ЗначениеДоступа = @P6)) И (T6.ГруппаДоступа = T5.Пользователь И T6.ГруппаДоступа = T5.Пользователь И T6.ГруппаДоступа = T5.Пользователь))) T4
ГДЕ 1=1)) ТОГДА @P1 ИНАЧЕ @P7 КОНЕЦ КАК SDBL_RLS_SIGNAL_,
T3._Ссылка КАК Ссылка
ИЗ Документ.ПлатежноеПоручениеВходящее T3 ) T2
ПО T1.Документ.ПлатежноеПоручениеВходящее_Ссылка = T2.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
ВЫБОР КОГДА (СУЩЕСТВУЕТ(ВЫБРАТЬ
@P1 КАК Q_002_F_000_
ИЗ (ВЫБРАТЬ РАЗЛИЧНЫЕ
@P1 КАК SDBL_RLS_SIGNAL_,
T10.ГруппаДоступа КАК Q_001_F_000RRef
ИЗ РегистрСведений.ТаблицыГруппДоступа T10
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа T11
ПО ((((T10.Таблица = @P2) И (T11.ВидДоступа = @P3)) И (T11.ЗначениеДоступа = @P4 И T11.ЗначениеДоступа = @P5 И T11.ЗначениеДоступа = @P6)) И (T11.ГруппаДоступа = T10.Пользователь И T11.ГруппаДоступа = T10.Пользователь И T11.ГруппаДоступа = T10.Пользователь))) T9
ГДЕ 1=1)) ТОГДА @P1 ИНАЧЕ @P7 КОНЕЦ КАК SDBL_RLS_SIGNAL_,
T8._Ссылка КАК Ссылка,
T8._Дата КАК Дата_,
T8._Номер КАК Номер_,
T8._Проведен КАК Проведен_,
T8.ДатаВходящегоДокумента КАК ДатаВходящегоДокумента,
T8.НомерВходящегоДокумента КАК НомерВходящегоДокумента,
T8._Организация КАК Организация,
T8._СчетОрганизации КАК СчетОрганизации,
T8._Контрагент КАК Контрагент,
T8.НазначениеПлатежа КАК НазначениеПлатежа,
T8.СуммаДокумента КАК СуммаДокумента,
T8._ВалютаДокумента КАК ВалютаДокумента,
T8._ВидОперации КАК ВидОперации,
T8._Ответственный КАК Ответственный,
T8._Автор КАК Автор
ИЗ Документ.ПлатежноеПоручениеВходящее T8
ГДЕ T8._Дата >= @P8 И T8._Дата @P9 И T8._Организация = @P10 И T8._ВидОперации = @P11) T7
ПО T1.Документ.ПлатежноеПоручениеВходящее_Ссылка = T7.Ссылка
ГДЕ T7.Проведен_ = @P1 И ((T7.Дата_ >= @P8) И (T7.Дата_ @P9)) И (T7.Организация = @P10) И (T7.ВидОперации = @P11) И (T1.Сделка = @P12)
СГРУППИРОВАТЬ ПО
T1.Документ.ПлатежноеПоручениеВходящее_Ссылка,
T7.Дата_,
T7.Номер_,
T7.Организация,
T7.СчетОрганизации,
T7.Контрагент,
T7.ВидОперации,
T7.СуммаДокумента,
T7.ВалютаДокумента,
ВЫРАЗИТЬ(T7.НазначениеПлатежа КАК СТРОКА(300)),
T7.ДатаВходящегоДокумента,
T7.НомерВходящегоДокумента,
T7.Ответственный,
T7.Автор
УПОРЯДОЧИТЬ ПО 3, 4

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

Получаем:

ВЫБРАТЬ
МИНИМУМ(ВЫБОР КОГДА T2.SDBL_RLS_SIGNAL_ = 1 И ISNULL(T7.SDBL_RLS_SIGNAL_,0x01) = 1 ТОГДА 1 ИНАЧЕ 0 КОНЕЦ),
T1.Документ.ПлатежноеПоручениеВходящее_Ссылка,
T7.Дата_,
T7.Номер_,
T7.Организация,
T7.СчетОрганизации,
T7.Контрагент,
T7.ВидОперации,
T7.СуммаДокумента,
T7.ВалютаДокумента,
ВЫРАЗИТЬ(T7.НазначениеПлатежа КАК СТРОКА(300)),
T7.ДатаВходящегоДокумента,
T7.НомерВходящегоДокумента,
T7.Ответственный,
T7.Автор
ИЗ Документ.ПлатежноеПоручениеВходящее.РасшифровкаПлатежа T1

ГДЕ T7.Проведен_ = @P1 И ((T7.Дата_ >= @P8) И (T7.Дата_ @P9)) И (T7.Организация = @P10) И (T7.ВидОперации = @P11) И (T1.Сделка = @P12)
СГРУППИРОВАТЬ ПО
T1.Документ.ПлатежноеПоручениеВходящее_Ссылка,
T7.Дата_,
T7.Номер_,
T7.Организация,
T7.СчетОрганизации,
T7.Контрагент,
T7.ВидОперации,
T7.СуммаДокумента,
T7.ВалютаДокумента,
ВЫРАЗИТЬ(T7.НазначениеПлатежа КАК СТРОКА(300)),
T7.ДатаВходящегоДокумента,
T7.НомерВходящегоДокумента,
T7.Ответственный,
T7.Автор
УПОРЯДОЧИТЬ ПО 3, 4

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

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

P.S. Это первая пробная версия. Так что пожелания и баг репорты приветствуются Smile

Файлы обработки:

-