Возможности обработки
1) Трассировка реально выполняемого запроса SQL по заданному тексту запроса 1С
2) Замена наименований таблиц SQL запроса терминами 1С (например, вместо _Reference185 будет Справочник.ПодразделенияОрганизаций)
3) Представление ссылок в 1С «формате» (например, вместо 0x9E80A570B3B742FB44770FC3B9C6ACCD будет "Подразделения" Перечисление.ВидыОбъектовДоступа)
4) Форматирование текста результирующего запроса с помощью интернет-сервиса «sqlformat.org»
Внешний вид обработки в обычных формах:
в управляемых формах:
в браузере:
Для чего можно использовать
Пример 1
В первую очередь обработка будет удобна для анализа RLS, чтобы получить реально выполняемый запрос базы данных со всеми ограничениями в удобочитаемом виде.
Пример: у нас есть запрос 1С из конфигурации УПП 1.3, который медленно выполняется под некоторыми пользователями, и мы хотим понять, какой запрос по факту выполняется и по возможности ускорить его.
Исходный запрос:
ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 100
СдельныйНаряд.Ссылка,
СдельныйНаряд.Проведен,
СдельныйНаряд.ПодразделениеОрганизации
ИЗ
Документ.СдельныйНаряд КАК СдельныйНаряд
Результат трансформации (все опции включены):
//exec sp_executesql N'
SELECT TOP 100 T1.Ссылка,
T1.Проведен,
T1.ПодразделениеОрганизации
FROM Документ.СдельныйНаряд T1
WHERE (1 В
(SELECT 1
FROM
(SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
LEFT OUTER JOIN
(SELECT DISTINCT T3.Ссылка AS Q_001_F_000RRef
FROM Справочник.ГруппыПользователей.ПользователиГруппы T3
WHERE (T3.Пользователь = &P1)) T2 ON 1=1
LEFT OUTER JOIN Справочник.Организации T4 ON (((T4.ГоловнаяОрганизация = T1.Организация)
AND (NOT (((T4.ГоловнаяОрганизация = &P2)))))
OR (T4.Ссылка = T1.Организация))
WHERE (NOT ((1 В
(SELECT 1.0 AS Q_001_F_000_
FROM РегистрСведений.НазначениеВидовОбъектовДоступа T5
WHERE (T5.ГруппаПользователей = T2.Q_001_F_000RRef)
AND (((T5.ВидОбъектаДоступа = &P3)
AND ((NOT ((1 В
(SELECT 1.0 AS Q_002_F_000_
FROM
(SELECT 1.0 AS Q_001_F_000_) T6
INNER JOIN РегистрСведений.НастройкиПравДоступаПользователей T7 ON ((((T7.ОбъектДоступа_TYPE = 0x08
AND T7.ОбъектДоступа_RTRef = 0x000000B5
AND T7.ОбъектДоступа = T1.Подразделение)
AND (T7.ВидОбъектаДоступа = &P4))
AND (T7.ОбластьДанных = &P5))
AND (T7.Пользователь = T5.ГруппаПользователей))))))))
OR (((T5.ВидОбъектаДоступа = &P6)
AND ((NOT ((1 В
(SELECT 1.0 AS Q_003_F_000_
FROM
(SELECT 1.0 AS Q_001_F_000_) T8
INNER JOIN РегистрСведений.НастройкиПравДоступаПользователей T9 ON ((((T9.ОбъектДоступа_TYPE = 0x08
AND T9.ОбъектДоступа_RTRef = 0x000000B6
AND T9.ОбъектДоступа = T1.ПодразделениеОрганизации)
AND (T9.ВидОбъектаДоступа = &P7))
AND (T9.ОбластьДанных = &P8))
AND (T9.Пользователь = T5.ГруппаПользователей))))))))
AND (NOT (((T5.ВидОбъектаДоступа = &P9))))))))))
AND (NOT ((T2.Q_001_F_000RRef IS NULL)))))
//',N'&P1 varbinary(16),&P2 varbinary(16),&P3 varbinary(16),&P4 varbinary(16),&P5 varbinary(16),&P6 varbinary(16),&P7 varbinary(16),&P8 varbinary(16),&P9 varbinary(16)'
//,0x94960050568E000111E1669B68D76556 // P1 = "Пупкин Василий Васильевич" Справочник.Пользователи
//,0x00000000000000000000000000000000 // P2 = НЕОПРЕДЕЛЕНО
//,0x9E80A570B3B742FB44770FC3B9C6ACCD // P3 = "Подразделения" Перечисление.ВидыОбъектовДоступа
//,0x9E80A570B3B742FB44770FC3B9C6ACCD // P4 = "Подразделения" Перечисление.ВидыОбъектовДоступа
//,0x00000000000000000000000000000000 // P5 = НЕОПРЕДЕЛЕНО
//,0x8C95AEE36D47C4BA4FDC1EECAB7AFA8D // P6 = "Подразделения организаций" Перечисление.ВидыОбъектовДоступа
//,0x8C95AEE36D47C4BA4FDC1EECAB7AFA8D // P7 = "Подразделения организаций" Перечисление.ВидыОбъектовДоступа
//,0x00000000000000000000000000000000 // P8 = НЕОПРЕДЕЛЕНО
//,0x9E80A570B3B742FB44770FC3B9C6ACCD // P9 = "Подразделения" Перечисление.ВидыОбъектовДоступа
Видно, что к исходному запросу добавляется громоздкое условие проверяющее доступ пользователя к данной таблице. Предположим, что в организации не используется управленческий учет, тогда проверку доступа RLS можно упростить, отключив контроль по подразделению и оставив контроль по подразделению организации (Операции->Константы->Настройка параметров доступа на уровне записей). Обратите внимание, что при включенном флажке «Результат в терминах 1С», текст запроса максимально приближен к тексту запроса, корректного для выполнения в консоли запроса 1С. Что мне не удалось сделать, так это убрать из текста запроса проверки типа для составных полей, так как для этого пришлось бы использовать полноценный парсер языка запросов SQL. Чтобы запрос был полностью рабочим для консоли запросов, придется руками убрать проверку на составной тип, если такой используется в запросе. В приведенном примере нужно заменить строки
T7.ОбъектДоступа_TYPE = 0x08
AND T7.ОбъектДоступа_RTRef = 0x000000B5
AND T7.ОбъектДоступа = T1.Подразделение на строку
на строку
AND T7.ОбъектДоступа = T1.Подразделение на строку
А также строки
T9.ОбъектДоступа_TYPE = 0x08
AND T9.ОбъектДоступа_RTRef = 0x000000B6
AND T9.ОбъектДоступа = T1.ПодразделениеОрганизации
На строку
T9.ОбъектДоступа = T1.ПодразделениеОрганизации
Тогда запрос будет полностью корректным для языка запросов 1с и его можно будет выполнить в консоли.
Дополнительный способ проверки результирующего запроса в SQL
Если при выполнении трансформации снять флажок «Результат в терминах 1С», то результирующий текст запроса будет корректным для языка T-SQL и его можно выполнить в SQL Server Management Studio или в консоли запросов, которая поддерживает выполнение прямых запросов SQL (например моя простенькая консоль SQL запросов). Для нашего примера со списком сдельных нарядов результат будет следующим:
Результат трансформации (снят флажок «Результат в терминах 1С»):
exec sp_executesql N'
SELECT TOP 100 T1._IDRRef,
T1._Posted,
T1._Fld15338RRef
FROM dbo._Document555 T1 WITH(NOLOCK)
WHERE (EXISTS
(SELECT 1
FROM
(SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
LEFT OUTER JOIN
(SELECT DISTINCT T3._Reference74_IDRRef AS Q_001_F_000RRef
FROM dbo._Reference74_VT1904 T3 WITH(NOLOCK)
WHERE (T3._Fld1906RRef = @P1)) T2 ON 1=1
LEFT OUTER JOIN dbo._Reference163 T4 WITH(NOLOCK) ON (((T4._Fld2784RRef = T1._Fld15330RRef)
AND (NOT (((T4._Fld2784RRef = @P2)))))
OR (T4._IDRRef = T1._Fld15330RRef))
WHERE (NOT ((EXISTS
(SELECT 1.0 AS Q_001_F_000_
FROM dbo._InfoRg18962 T5 WITH(NOLOCK)
WHERE (T5._Fld18963RRef = T2.Q_001_F_000RRef)
AND (((T5._Fld18964RRef = @P3)
AND ((NOT ((EXISTS
(SELECT 1.0 AS Q_002_F_000_
FROM
(SELECT 1.0 AS Q_001_F_000_) T6
INNER JOIN dbo._InfoRg19035 T7 WITH(NOLOCK) ON ((((T7._Fld19036_TYPE = 0x08
AND T7._Fld19036_RTRef = 0x000000B5
AND T7._Fld19036_RRRef = T1._Fld15336RRef)
AND (T7._Fld19037RRef = @P4))
AND (T7._Fld19038RRef = @P5))
AND (T7._Fld19039RRef = T5._Fld18963RRef))))))))
OR (((T5._Fld18964RRef = @P6)
AND ((NOT ((EXISTS
(SELECT 1.0 AS Q_003_F_000_
FROM
(SELECT 1.0 AS Q_001_F_000_) T8
INNER JOIN dbo._InfoRg19035 T9 WITH(NOLOCK) ON ((((T9._Fld19036_TYPE = 0x08
AND T9._Fld19036_RTRef = 0x000000B6
AND T9._Fld19036_RRRef = T1._Fld15338RRef)
AND (T9._Fld19037RRef = @P7))
AND (T9._Fld19038RRef = @P8))
AND (T9._Fld19039RRef = T5._Fld18963RRef))))))))
AND (NOT (((T5._Fld18964RRef = @P9))))))))))
AND (NOT ((T2.Q_001_F_000RRef IS NULL)))))
',N'@P1 varbinary(16),@P2 varbinary(16),@P3 varbinary(16),@P4 varbinary(16),@P5 varbinary(16),@P6 varbinary(16),@P7 varbinary(16),@P8 varbinary(16),@P9 varbinary(16)'
,0x94960050568E000111E1669B68D76556 -- P1 = "Пупкин Василий Васильевич" Справочник.Пользователи
,0x00000000000000000000000000000000 -- P2 = НЕОПРЕДЕЛЕНО
,0x9E80A570B3B742FB44770FC3B9C6ACCD -- P3 = "Подразделения" Перечисление.ВидыОбъектовДоступа
,0x9E80A570B3B742FB44770FC3B9C6ACCD -- P4 = "Подразделения" Перечисление.ВидыОбъектовДоступа
,0x00000000000000000000000000000000 -- P5 = НЕОПРЕДЕЛЕНО
,0x8C95AEE36D47C4BA4FDC1EECAB7AFA8D -- P6 = "Подразделения организаций" Перечисление.ВидыОбъектовДоступа
,0x8C95AEE36D47C4BA4FDC1EECAB7AFA8D -- P7 = "Подразделения организаций" Перечисление.ВидыОбъектовДоступа
,0x00000000000000000000000000000000 -- P8 = НЕОПРЕДЕЛЕНО
,0x9E80A570B3B742FB44770FC3B9C6ACCD -- P9 = "Подразделения" Перечисление.ВидыОбъектовДоступа
Теперь запрос представлен в исходном SQL виде с дополнительными комментариями к параметрам запроса с представлениями ссылок в 1с и его можно выполнить как обычный запрос на языке T-SQL.
Пример 2
Еще один способ использования обработки – в связке с технологическим журналом, без использования трассировки. Пример: в доработанной конфигурации Документооборот 1.4 под некоторыми пользователями очень медленно открывается список внутренних документов. Настраиваем тех. журнал на отлов событий DBMSSQL и смотрим запросы, которые генерировала платформа при открытии формы списка (для настройки и анализа тех. журнала удобно пользоваться инструментами разработчика, но для просмотра можно использовать и типовую обработку с ИТС ПросмотрТехнологическогоЖурнала.epf). Находим следующий запрос:
Исходный запрос из технологического журнала:
SELECT TOP 30
T1._IDRRef,
T1._Marked,
T1._Fld1609,
T1._Fld1584,
CASE WHEN (T1._Fld1584 <> {ts '2001-01-01 00:00:00'}) THEN T1._Fld1584 ELSE T1._Fld1585 END,
T1._Fld1579RRef,
T11.Fld1466_,
T1._Description,
CAST(T3.Fld5425_ AS NVARCHAR(1000)),
T1._Fld1602RRef,
T1._Fld1603RRef,
T1._Fld1606RRef,
T1._Fld1616RRef,
T1._Fld1586RRef,
T1._Fld1589RRef,
T1._Fld1601RRef,
T1._Fld1587,
T1._Code,
T1._Fld1600RRef,
T1._Fld1599RRef,
T1._Fld1613,
T1._Fld1578RRef,
T1._Fld1582,
T1._Fld1583,
T1._Fld1607RRef,
T3.Fld5426_,
CASE WHEN (T2._Fld5120 IS NULL OR (T2._Fld5120 = 0x00)) THEN 0.0 ELSE 1.0 END,
CASE WHEN T2._Fld5117 IS NULL THEN 0x00 WHEN T2._Fld5117 = 0x01 THEN 0x01 ELSE 0x00 END,
CASE WHEN (T2._Fld5128RRef = 0x978321BE0001E76642E10A917011A3D3) THEN CASE WHEN ((T2._Fld5129 = {ts '2001-01-01 00:00:00'}) OR (T2._Fld5129 >= {ts '4017-06-15 00:00:00'})) THEN 1.0 ELSE 3.0 END WHEN (T2._Fld5128RRef = 0x87C2940938835A28445ADC91DCBB0223) THEN 4.0 WHEN (T2._Fld5128RRef = 0xB951457BE98615BA44F94EED2FA871B9) THEN CASE WHEN ((T2._Fld5129 = {ts '2001-01-01 00:00:00'}) OR (T2._Fld5129 >= {ts '4017-06-15 00:00:00'})) THEN 5.0 WHEN ((T2._Fld5130 = {ts '2001-01-01 00:00:00'}) OR (T2._Fld5130 >= {ts '4017-06-15 00:00:00'})) THEN 8.0 ELSE 6.0 END WHEN (T2._Fld5128RRef = 0xA2188ED2B8E8907D44B84819A62CDFFB) THEN 7.0 WHEN (T2._Fld5128RRef = 0x97DE9D14E23C9F8644FF03E523B923B2) THEN CASE WHEN ((T2._Fld5129 = {ts '2001-01-01 00:00:00'}) OR (T2._Fld5129 >= {ts '4017-06-15 00:00:00'})) THEN 9.0 ELSE 10.0 END ELSE 0.0 END,
T1._Fld6655RRef,
CASE WHEN T1._PredefinedID > 0x00000000000000000000000000000000 THEN 0x01 ELSE 0x00 END,
T17._Fld2552,
T18._Fld2552,
CASE WHEN (T1._Fld1584 <> {ts '2001-01-01 00:00:00'}) THEN T1._Fld1584 ELSE T1._Fld1585 END,
T17._Fld2552,
T18._Fld2552
FROM dbo._Reference65 T1
LEFT OUTER JOIN dbo._InfoRg5114 T2
ON (0x08 = T2._Fld5115_TYPE AND 0x00000041 = T2._Fld5115_RTRef AND T1._IDRRef = T2._Fld5115_RRRef)
LEFT OUTER JOIN (SELECT
T4._Fld5421_TYPE AS Fld5421_TYPE,
T4._Fld5421_RTRef AS Fld5421_RTRef,
T4._Fld5421_RRRef AS Fld5421_RRRef,
T4._Fld5425 AS Fld5425_,
T4._Fld5426 AS Fld5426_,
T4._Fld5428 AS Fld5428_
FROM dbo._InfoRg5420 T4
WHERE (EXISTS(SELECT
1
FROM (SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
INNER JOIN dbo._InfoRg4869 T5
ON (T4._Fld5421_TYPE = T5._Fld4870_TYPE AND T4._Fld5421_RTRef = T5._Fld4870_RTRef AND T4._Fld5421_RRRef = T5._Fld4870_RRRef)
WHERE EXISTS(SELECT
0x01 AS Q_001_F_000_
FROM dbo._InfoRg5953 T6
LEFT OUTER JOIN dbo._InfoRg5601 T7
ON ((T6._Fld5955_TYPE = CASE WHEN T7._Fld5603RRef IS NOT NULL THEN 0x08 END AND T6._Fld5955_RTRef = CASE WHEN T7._Fld5603RRef IS NOT NULL THEN 0x00000075 END AND T6._Fld5955_RRRef = T7._Fld5603RRef) AND (0x08 = T7._Fld5602_TYPE AND 0x0000004F = T7._Fld5602_RTRef AND T5._Fld4872RRef = T7._Fld5602_RRRef))
LEFT OUTER JOIN dbo._InfoRg5601 T8
ON (((T8._Fld5603RRef = ?) AND (T6._Fld5955_TYPE = 0x08 AND T6._Fld5955_RTRef = 0x00000075)) AND (0x08 = T8._Fld5602_TYPE AND 0x0000004F = T8._Fld5602_RTRef AND T5._Fld4872RRef = T8._Fld5602_RRRef))
WHERE (T6._Fld5954RRef = ?) AND (T6._Fld5958 IN (?, ?)) AND (NOT (((T7._Fld5605 IS NULL AND T8._Fld5605 IS NULL)))))))) T3
ON (0x08 = T3.Fld5421_TYPE AND 0x00000041 = T3.Fld5421_RTRef AND T1._IDRRef = T3.Fld5421_RRRef)
LEFT OUTER JOIN (SELECT
T10._Fld5106_TYPE AS Q_001_F_000_TYPE,
T10._Fld5106_RTRef AS Q_001_F_000_RTRef,
T10._Fld5106_RRRef AS Q_001_F_000_RRRef
FROM dbo._InfoRg5105 T10
WHERE ((0x00 = 0x00) OR (CASE WHEN T10._Fld5107RRef IS NOT NULL THEN 1 END = 0)) AND ((0x00 = 0x00) OR CASE WHEN T10._Fld5107RRef IS NOT NULL THEN 1 END = 0)
GROUP BY T10._Fld5106_TYPE,
T10._Fld5106_RTRef,
T10._Fld5106_RRRef) T9
ON (0x08 = T9.Q_001_F_000_TYPE AND 0x00000041 = T9.Q_001_F_000_RTRef AND T1._IDRRef = T9.Q_001_F_000_RRRef)
LEFT OUTER JOIN (SELECT
T12._IDRRef AS IDRRef,
T12._Fld1457 AS Fld1457_,
T12._Fld1466 AS Fld1466_
FROM dbo._Reference54 T12
WHERE (EXISTS(SELECT
1
FROM (SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
INNER JOIN dbo._InfoRg4869 T13
ON (0x08 = T13._Fld4870_TYPE AND 0x00000036 = T13._Fld4870_RTRef AND T12._IDRRef = T13._Fld4870_RRRef)
WHERE EXISTS(SELECT
0x01 AS Q_001_F_000_
FROM dbo._InfoRg5953 T14
LEFT OUTER JOIN dbo._InfoRg5601 T15
ON ((T14._Fld5955_TYPE = CASE WHEN T15._Fld5603RRef IS NOT NULL THEN 0x08 END AND T14._Fld5955_RTRef = CASE WHEN T15._Fld5603RRef IS NOT NULL THEN 0x00000075 END AND T14._Fld5955_RRRef = T15._Fld5603RRef) AND (0x08 = T15._Fld5602_TYPE AND 0x0000004F = T15._Fld5602_RTRef AND T13._Fld4872RRef = T15._Fld5602_RRRef))
LEFT OUTER JOIN dbo._InfoRg5601 T16
ON (((T16._Fld5603RRef = ?) AND (T14._Fld5955_TYPE = 0x08 AND T14._Fld5955_RTRef = 0x00000075)) AND (0x08 = T16._Fld5602_TYPE AND 0x0000004F = T16._Fld5602_RTRef AND T13._Fld4872RRef = T16._Fld5602_RRRef))
WHERE (T14._Fld5954RRef = ?) AND (T14._Fld5958 IN (?, ?)) AND (NOT (((T15._Fld5605 IS NULL AND T16._Fld5605 IS NULL)))))))) T11
ON T1._Fld1579RRef = T11.IDRRef
LEFT OUTER JOIN dbo._Reference117 T17
ON T1._Fld1603RRef = T17._IDRRef
LEFT OUTER JOIN dbo._Reference117 T18
ON T1._Fld1616RRef = T18._IDRRef
WHERE ((EXISTS(SELECT
1
FROM (SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
INNER JOIN dbo._InfoRg4869 T19
ON (0x08 = T19._Fld4870_TYPE AND 0x00000041 = T19._Fld4870_RTRef AND T1._IDRRef = T19._Fld4870_RRRef)
WHERE EXISTS(SELECT
0x01 AS Q_001_F_000_
FROM dbo._InfoRg5953 T20
LEFT OUTER JOIN dbo._InfoRg5601 T21
ON ((T20._Fld5955_TYPE = CASE WHEN T21._Fld5603RRef IS NOT NULL THEN 0x08 END AND T20._Fld5955_RTRef = CASE WHEN T21._Fld5603RRef IS NOT NULL THEN 0x00000075 END AND T20._Fld5955_RRRef = T21._Fld5603RRef) AND (0x08 = T21._Fld5602_TYPE AND 0x0000004F = T21._Fld5602_RTRef AND T19._Fld4872RRef = T21._Fld5602_RRRef))
LEFT OUTER JOIN dbo._InfoRg5601 T22
ON (((T22._Fld5603RRef = ?) AND (T20._Fld5955_TYPE = 0x08 AND T20._Fld5955_RTRef = 0x00000075)) AND (0x08 = T22._Fld5602_TYPE AND 0x0000004F = T22._Fld5602_RTRef AND T19._Fld4872RRef = T22._Fld5602_RRRef))
WHERE (T20._Fld5954RRef = ?) AND (T20._Fld5958 IN (?, ?)) AND (NOT (((T21._Fld5605 IS NULL AND T22._Fld5605 IS NULL)))))))) AND ((((0x00 = 0x00) AND (0x00 = 0x00)) OR (NOT ((T9.Q_001_F_000_TYPE IS NULL AND T9.Q_001_F_000_RTRef IS NULL AND T9.Q_001_F_000_RRRef IS NULL)))) AND (T1._Marked = 0x00) AND ((CASE WHEN (T1._Fld1584 <> ?) THEN T1._Fld1584 ELSE T1._Fld1585 END > ?) OR ((CASE WHEN (T1._Fld1584 <> ?) THEN T1._Fld1584 ELSE T1._Fld1585 END = ?) AND (T1._IDRRef >= ?))))
ORDER BY (CASE WHEN (T1._Fld1584 <> {ts '2001-01-01 00:00:00'}) THEN T1._Fld1584 ELSE T1._Fld1585 END), (T1._IDRRef)
p_0: 0x00000000000000000000000000000000
p_1: 0x883100505681053811E51F9DBED35CAF
p_2: ''
p_3: 'ДокументыИФайлы'
p_4: 0x00000000000000000000000000000000
p_5: 0x883100505681053811E51F9DBED35CAF
p_6: ''
p_7: 'ДокументыИФайлы'
p_8: 0x00000000000000000000000000000000
p_9: 0x883100505681053811E51F9DBED35CAF
p_10: ''
p_11: 'ДокументыИФайлы'
p_12: 20010101000000
p_13: 40160829090726
p_14: 20010101000000
p_15: 40160829090726
p_16: 0x80EE005056A22A4A11E66D9F0447E6CF
Не очень удобно разбираться с таким запросом – нет форматирования, вместо параметров стоят вопросы и т.д., поэтому прогоняем его через трансформатор(все опции включены) и получаем такой вид:
Результат трансформации (все опции включены):
SELECT TOP 30 T1.Ссылка,
T1.ПометкаУдаления,
T1.РегистрационныйНомер,
T1.ДатаРегистрации,
CASE
WHEN (T1.ДатаРегистрации <> ДАТАВРЕМЯ(1,01,01,00,00,00)) THEN T1.ДатаРегистрации
ELSE T1.ДатаСоздания
END,
T1.ВидДокумента,
T11.Fld1466_,
T1.Наименование,
CAST(T3.Fld5425_ AS Строка(1000)),
T1.Папка,
T1.Подготовил,
T1.Подразделение,
T1.Утвердил,
T1.Дело,
T1.Зарегистрировал,
T1.Ответственный,
T1.Заголовок,
T1.Код,
T1.Организация,
T1.НоменклатураДел,
T1.Сумма,
T1.Валюта,
T1.ДатаНачалаДействия,
T1.ДатаОкончанияДействия,
T1.Проект,
T3.Fld5426_,
CASE
WHEN (T2.ЕстьФайлы IS NULL
OR (T2.ЕстьФайлы = ЛОЖЬ)) THEN 0.0
ELSE 1.0
END,
CASE
WHEN T2.ЕстьЗадачи IS NULL THEN ЛОЖЬ
WHEN T2.ЕстьЗадачи = ИСТИНА THEN ИСТИНА
ELSE ЛОЖЬ
END,
CASE
WHEN (T2.СостояниеКонтроля = &pp_17) THEN CASE
WHEN ((T2.СрокИсполнения = ДАТАВРЕМЯ(1,01,01,00,00,00))
OR (T2.СрокИсполнения >= ДАТАВРЕМЯ(2024,06,15,00,00,00))) THEN 1.0
ELSE 3.0
END
WHEN (T2.СостояниеКонтроля = &pp_18) THEN 4.0
WHEN (T2.СостояниеКонтроля = &pp_19) THEN CASE
WHEN ((T2.СрокИсполнения = ДАТАВРЕМЯ(1,01,01,00,00,00))
OR (T2.СрокИсполнения >= ДАТАВРЕМЯ(2024,06,15,00,00,00))) THEN 5.0
WHEN ((T2.СрокИсполненияОбщий = ДАТАВРЕМЯ(1,01,01,00,00,00))
OR (T2.СрокИсполненияОбщий >= ДАТАВРЕМЯ(2024,06,15,00,00,00))) THEN 8.0
ELSE 6.0
END
WHEN (T2.СостояниеКонтроля = &pp_20) THEN 7.0
WHEN (T2.СостояниеКонтроля = &pp_21) THEN CASE
WHEN ((T2.СрокИсполнения = ДАТАВРЕМЯ(1,01,01,00,00,00))
OR (T2.СрокИсполнения >= ДАТАВРЕМЯ(2024,06,15,00,00,00))) THEN 9.0
ELSE 10.0
END
ELSE 0.0
END,
T1.бит_Важность,
CASE
WHEN T1.ИмяПредопределенныхДанных > &pp_22 THEN ИСТИНА
ELSE ЛОЖЬ
END,
T17.Недействителен,
T18.Недействителен,
CASE
WHEN (T1.ДатаРегистрации <> ДАТАВРЕМЯ(1,01,01,00,00,00)) THEN T1.ДатаРегистрации
ELSE T1.ДатаСоздания
END,
T17.Недействителен,
T18.Недействителен
FROM Справочник.ВнутренниеДокументы T1
LEFT OUTER JOIN РегистрСведений.КешИнформацииОбОбъектах T2 ON ("0x08" = T2.Объект_TYPE
AND "0x00000041" = T2.Объект_RTRef
AND T1.Ссылка = T2.Объект)
LEFT OUTER JOIN
(SELECT T4.Документ_TYPE AS Fld5421_TYPE,
T4.Документ_RTRef AS Fld5421_RTRef,
T4.Документ AS Fld5421_RRRef,
T4.КорреспондентыДляСписков AS Fld5425_,
T4.ПредставлениеСостояния AS Fld5426_,
T4.СодержитОригинал AS Fld5428_
FROM РегистрСведений.ОбщиеРеквизитыДокументов T4
WHERE (ИСТИНА В
(SELECT 1
FROM
(SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
INNER JOIN РегистрСведений.ДескрипторыДоступаДляОбъектов T5 ON (T4.Документ_TYPE = T5.Объект_TYPE
AND T4.Документ_RTRef = T5.Объект_RTRef
AND T4.Документ = T5.Объект)
WHERE ИСТИНА В
(SELECT ИСТИНА AS Q_001_F_000_
FROM РегистрСведений.СоставСубъектовПравДоступа T6
LEFT OUTER JOIN РегистрСведений.ПраваПоДескрипторамДоступа T7 ON ((T6.Субъект_TYPE = CASE
WHEN T7.Пользователь IS NOT NULL THEN "0x08"
END
AND T6.Субъект_RTRef = CASE
WHEN T7.Пользователь IS NOT NULL THEN "0x00000075"
END
AND T6.Субъект = T7.Пользователь)
AND ("0x08" = T7.Дескриптор_TYPE
AND "0x0000004F" = T7.Дескриптор_RTRef
AND T5.Дескриптор = T7.Дескриптор))
LEFT OUTER JOIN РегистрСведений.ПраваПоДескрипторамДоступа T8 ON (((T8.Пользователь = &p_0)
AND (T6.Субъект_TYPE = "0x08"
AND T6.Субъект_RTRef = "0x00000075"))
AND ("0x08" = T8.Дескриптор_TYPE
AND "0x0000004F" = T8.Дескриптор_RTRef
AND T5.Дескриптор = T8.Дескриптор))
WHERE (T6.Пользователь = &p_1)
AND (T6.ИмяОбластиДелегирования IN (&p_2, &p_3))
AND (NOT (((T7.Изменение IS NULL
AND T8.Изменение IS NULL)))))))) T3 ON ("0x08" = T3.Fld5421_TYPE
AND "0x00000041" = T3.Fld5421_RTRef
AND T1.Ссылка = T3.Fld5421_RRRef)
LEFT OUTER JOIN
(SELECT T10.ОбъектДанных_TYPE AS Q_001_F_000_TYPE,
T10.ОбъектДанных_RTRef AS Q_001_F_000_RTRef,
T10.ОбъектДанных AS Q_001_F_000_RRRef
FROM РегистрСведений.КатегорииОбъектов T10
WHERE ((ЛОЖЬ = ЛОЖЬ)
OR (CASE
WHEN T10.КатегорияДанных IS NOT NULL THEN 1
END = 0))
AND ((ЛОЖЬ = ЛОЖЬ)
OR CASE
WHEN T10.КатегорияДанных IS NOT NULL THEN 1
END = 0)
GROUP BY T10.ОбъектДанных_TYPE,
T10.ОбъектДанных_RTRef,
T10.ОбъектДанных) T9 ON ("0x08" = T9.Q_001_F_000_TYPE
AND "0x00000041" = T9.Q_001_F_000_RTRef
AND T1.Ссылка = T9.Q_001_F_000_RRRef)
LEFT OUTER JOIN
(SELECT T12.Ссылка AS IDRRef,
T12.ОбязателенФайлОригинала AS Fld1457_,
T12.ЯвляетсяКомплектомДокументов AS Fld1466_
FROM Справочник.ВидыВнутреннихДокументов T12
WHERE (ИСТИНА В
(SELECT 1
FROM
(SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
INNER JOIN РегистрСведений.ДескрипторыДоступаДляОбъектов T13 ON ("0x08" = T13.Объект_TYPE
AND "0x00000036" = T13.Объект_RTRef
AND T12.Ссылка = T13.Объект)
WHERE ИСТИНА В
(SELECT ИСТИНА AS Q_001_F_000_
FROM РегистрСведений.СоставСубъектовПравДоступа T14
LEFT OUTER JOIN РегистрСведений.ПраваПоДескрипторамДоступа T15 ON ((T14.Субъект_TYPE = CASE
WHEN T15.Пользователь IS NOT NULL THEN "0x08"
END
AND T14.Субъект_RTRef = CASE
WHEN T15.Пользователь IS NOT NULL THEN "0x00000075"
END
AND T14.Субъект = T15.Пользователь)
AND ("0x08" = T15.Дескриптор_TYPE
AND "0x0000004F" = T15.Дескриптор_RTRef
AND T13.Дескриптор = T15.Дескриптор))
LEFT OUTER JOIN РегистрСведений.ПраваПоДескрипторамДоступа T16 ON (((T16.Пользователь = &p_4)
AND (T14.Субъект_TYPE = "0x08"
AND T14.Субъект_RTRef = "0x00000075"))
AND ("0x08" = T16.Дескриптор_TYPE
AND "0x0000004F" = T16.Дескриптор_RTRef
AND T13.Дескриптор = T16.Дескриптор))
WHERE (T14.Пользователь = &p_5)
AND (T14.ИмяОбластиДелегирования IN (&p_6, &p_7))
AND (NOT (((T15.Изменение IS NULL
AND T16.Изменение IS NULL)))))))) T11 ON T1.ВидДокумента = T11.IDRRef
LEFT OUTER JOIN Справочник.Пользователи T17 ON T1.Подготовил = T17.Ссылка
LEFT OUTER JOIN Справочник.Пользователи T18 ON T1.Утвердил = T18.Ссылка
WHERE ((ИСТИНА В
(SELECT 1
FROM
(SELECT 1 AS SDBL_DUMMY) SDBL_DUAL
INNER JOIN РегистрСведений.ДескрипторыДоступаДляОбъектов T19 ON ("0x08" = T19.Объект_TYPE
AND "0x00000041" = T19.Объект_RTRef
AND T1.Ссылка = T19.Объект)
WHERE ИСТИНА В
(SELECT ИСТИНА AS Q_001_F_000_
FROM РегистрСведений.СоставСубъектовПравДоступа T20
LEFT OUTER JOIN РегистрСведений.ПраваПоДескрипторамДоступа T21 ON ((T20.Субъект_TYPE = CASE
WHEN T21.Пользователь IS NOT NULL THEN "0x08"
END
AND T20.Субъект_RTRef = CASE
WHEN T21.Пользователь IS NOT NULL THEN "0x00000075"
END
AND T20.Субъект = T21.Пользователь)
AND ("0x08" = T21.Дескриптор_TYPE
AND "0x0000004F" = T21.Дескриптор_RTRef
AND T19.Дескриптор = T21.Дескриптор))
LEFT OUTER JOIN РегистрСведений.ПраваПоДескрипторамДоступа T22 ON (((T22.Пользователь = &p_8)
AND (T20.Субъект_TYPE = "0x08"
AND T20.Субъект_RTRef = "0x00000075"))
AND ("0x08" = T22.Дескриптор_TYPE
AND "0x0000004F" = T22.Дескриптор_RTRef
AND T19.Дескриптор = T22.Дескриптор))
WHERE (T20.Пользователь = &p_9)
AND (T20.ИмяОбластиДелегирования IN (&p_10, &p_11))
AND (NOT (((T21.Изменение IS NULL
AND T22.Изменение IS NULL))))))))
AND ((((ЛОЖЬ = ЛОЖЬ)
AND (ЛОЖЬ = ЛОЖЬ))
OR (NOT ((T9.Q_001_F_000_TYPE IS NULL
AND T9.Q_001_F_000_RTRef IS NULL
AND T9.Q_001_F_000_RRRef IS NULL))))
AND (T1.ПометкаУдаления = ЛОЖЬ)
AND ((CASE
WHEN (T1.ДатаРегистрации <> &p_12) THEN T1.ДатаРегистрации
ELSE T1.ДатаСоздания
END > &p_13)
OR ((CASE
WHEN (T1.ДатаРегистрации <> &p_14) THEN T1.ДатаРегистрации
ELSE T1.ДатаСоздания
END = &p_15)
AND (T1.Ссылка >= &p_16))))
ORDER BY (CASE
WHEN (T1.ДатаРегистрации <> ДАТАВРЕМЯ(1,01,01,00,00,00)) THEN T1.ДатаРегистрации
ELSE T1.ДатаСоздания
END), (T1.Ссылка)
// p_0: 0x00000000000000000000000000000000 НЕОПРЕДЕЛЕНО
// p_1: 0x883100505681053811E51F9DBED35CAF "Пупкин Василий Васильевич" Справочник.ФизическиеЛица
// p_2: ''
// p_3: 'ДокументыИФайлы'
// p_4: 0x00000000000000000000000000000000 НЕОПРЕДЕЛЕНО
// p_5: 0x883100505681053811E51F9DBED35CAF "Пупкин Василий Васильевич" Справочник.ФизическиеЛица
// p_6: ''
// p_7: 'ДокументыИФайлы'
// p_8: 0x00000000000000000000000000000000 НЕОПРЕДЕЛЕНО
// p_9: 0x883100505681053811E51F9DBED35CAF "Пупкин Василий Васильевич" Справочник.ФизическиеЛица
// p_10: ''
// p_11: 'ДокументыИФайлы'
// p_12: 20010101000000
// p_13: 40160829090726
// p_14: 20010101000000
// p_15: 40160829090726
// p_16: 0x80EE005056A22A4A11E66D9F0447E6CF "Дополнительное соглашение № 1 от 20.08.2024г.к договоур аренды от 15.09.2013г." Справочник.ВнутренниеДокументы
// pp_17: 0x978321BE0001E76642E10A917011A3D3 "На контроле" Перечисление.СостоянияКонтроля
// pp_18: 0x87C2940938835A28445ADC91DCBB0223 "Снят с контроля" Перечисление.СостоянияКонтроля
// pp_19: 0xB951457BE98615BA44F94EED2FA871B9 "На контроле несколько" Перечисление.СостоянияКонтроля
// pp_20: 0xA2188ED2B8E8907D44B84819A62CDFFB "Снят с контроля несколько" Перечисление.СостоянияКонтроля
// pp_21: 0x97DE9D14E23C9F8644FF03E523B923B2 "Смешанно несколько" Перечисление.СостоянияКонтроля
// pp_22: 0x00000000000000000000000000000000 НЕОПРЕДЕЛЕНО
Видно, что однотипные ограничения RLS применяются 3 раза при выполнении запроса динамического списка (это можно понять по характерным конструкциям WHERE EXISTS() или по использованию области доступа «ДокументыИФайлы») и это может быть причиной медленной работы списка документов. С проверкой на доступ к таблице T1 «Справочник.ВнутренниеДокументы» сделать ничего не получится, так как это основная таблица списка, а вот оставшиеся 2 проверки под вопросом. «РегистрСведений.ОбщиеРеквизитыДокументов» T4 используется для получения реквизитов «КорреспондентыДляСписков», «ПредставлениеСостояния», «СодержитОригинал», а таблица «Справочник.ВидыВнутреннихДокументов» T12 используется для получения реквизита «ВидДокумента.ЯвляетсяКомплектомДокументов». Таким образом, можно либо не использовать поля на форме, которые приводят к вызову дополнительных проверок на права доступа, либо убрать проверку RLS для вспомогательного регистра с данными, так как проверка уже выполняется в основной таблице и эффекта от дополнительных проверок в данном запросе нет.
Пример 3
Еще один вариант использования обработки – исследование фактического запроса SQL при обращении к виртуальным таблицам 1с. Меня давно интересовал вопрос, как интерпретируется запрос к виртуальным таблицам. Если с таблицей остатков и оборотов регистров накопления все достаточно очевидно, то, например, с регистрами бухгалтерии было бы интересно посмотреть на фактический запрос при указании разных параметров. Рассмотрим достаточно простой запрос обращения к движениям с субконто за указанный период
ВЫБРАТЬ
ХозрасчетныйДвиженияССубконто.СчетДт,
ХозрасчетныйДвиженияССубконто.СубконтоДт1,
ХозрасчетныйДвиженияССубконто.Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(ДАТАВРЕМЯ(2024, 5, 1), ДАТАВРЕМЯ(2024, 5, 31), Счет = &Счет, , ) КАК ХозрасчетныйДвиженияССубконто
Прогоняем запрос через трансформатор(все опции включены) и получаем такой вид:
Результат трансформации (все опции включены):
//exec sp_executesql N'
SELECT T1.Период,
T1._UseTotals,
T1._ActualPeriod,
T1._UseSplitter,
T1._MinPeriod
FROM dbo._AccRgOpt T1
WHERE T1._RegID = &P1
//',N'&P1 varbinary(8000)'
//,0x37016F671FA3D34495B9C95579A03D8A
//;
//exec sp_executesql N'
INSERT INTO #tt2 WITH(TABLOCK) (Регистратор,
Регистратор,
НомерСтроки)
SELECT T1.RecorderTRef,
T1.RecorderRRef,
T1.LineNo_
FROM
(SELECT T2.Регистратор AS RecorderTRef,
T2.Регистратор AS RecorderRRef,
T2.НомерСтроки AS LineNo_
FROM РегистрБухгалтерии.Хозрасчетный T2
WHERE ((T2.СчетДт = &P1))
AND T2.Период >= &P2
AND T2.Период <= &P3
UNION SELECT T3.Регистратор AS RecorderTRef,
T3.Регистратор AS RecorderRRef,
T3.НомерСтроки AS LineNo_
FROM РегистрБухгалтерии.Хозрасчетный T3
WHERE ((T3.СчетКт = &P4))
AND T3.Период >= &P5
AND T3.Период <= &P6) T1
//',N'&P1 varbinary(16),&P2 datetime2(3),&P3 datetime2(3),&P4 varbinary(16),&P5 datetime2(3),&P6 datetime2(3)'
//,0x00000000000000000000000000000000 // P1 = НЕОПРЕДЕЛЕНО
//,'4017-01-01 00:00:00'
//,'4017-01-31 00:00:00'
//,0x00000000000000000000000000000000 // P4 = НЕОПРЕДЕЛЕНО
//,'4017-01-01 00:00:00'
//,'4017-01-31 00:00:00'
//;
INSERT INTO #tt3 WITH(TABLOCK) (Регистратор,
Регистратор,
НомерСтроки)
SELECT T1.RecorderTRef,
T1.RecorderRRef,
T1.LineNo_
FROM
(SELECT TOP 1000 T2.Регистратор AS RecorderTRef,
T2.Регистратор AS RecorderRRef,
T2.НомерСтроки AS LineNo_
FROM #tt2 T2
ORDER BY T2.Регистратор,
T2.Регистратор,
T2.НомерСтроки) T1
//;
INSERT INTO #tt4 WITH(TABLOCK) (Регистратор,
Регистратор,
НомерСтроки,
СчетКт,
СчетДт,
Сумма)
SELECT T2.Регистратор,
T2.Регистратор,
T2.НомерСтроки,
T2.СчетКт,
T2.СчетДт,
T2.Сумма
FROM #tt3 T1
INNER JOIN РегистрБухгалтерии.Хозрасчетный T2 ON T1.Регистратор = T2.Регистратор
AND T1.Регистратор = T2.Регистратор
AND T1.НомерСтроки = T2.НомерСтроки
//;
//exec sp_executesql N'
INSERT INTO #tt5 WITH(TABLOCK) (Регистратор,
Регистратор,
НомерСтроки,
_KindRRef,
_Value_TYPE,
_Value_RTRef,
_Value_RRRef,
_Correspond,
_AccEdKindLineNo)
SELECT T2.Регистратор,
T2.Регистратор,
T2.НомерСтроки,
T2._KindRRef,
T2._Value_TYPE,
T2._Value_RTRef,
T2._Value_RRRef,
T2._Correspond,
T3.НомерСтроки
FROM #tt4 T1
INNER JOIN dbo._AccRgED1262 T2 ON T1.Регистратор = T2.Регистратор
AND T1.Регистратор = T2.Регистратор
AND T1.НомерСтроки = T2.НомерСтроки
INNER JOIN ПланСчетов.Хозрасчетный.ВидыСубконто T3 ON CASE
WHEN T2._Correspond = &P1 THEN T1.СчетДт
ELSE T1.СчетКт
END = T3.Ссылка
AND T2._KindRRef = T3.ВидСубконто
//',N'&P1 numeric(10)'
//,0
//;
//exec sp_executesql N'
INSERT INTO #tt1 WITH(TABLOCK) (СчетДт,
Сумма,
_ValueDt1_TYPE,
_ValueDt1_RTRef,
_ValueDt1_RRRef)
SELECT T1.СчетДт,
T1.Сумма,
T2._Value_TYPE,
T2._Value_RTRef,
T2._Value_RRRef
FROM #tt4 T1
LEFT OUTER JOIN #tt5 T2 ON T1.Регистратор = T2.Регистратор
AND T1.Регистратор = T2.Регистратор
AND T1.НомерСтроки = T2.НомерСтроки
AND T2._AccEdKindLineNo = &P1
AND T2._Correspond = &P2
//',N'&P1 numeric(10),&P2 numeric(10)'
//,1
//,0
//;
SELECT TOP 1 T1.Регистратор,
T1.Регистратор,
T1.НомерСтроки
FROM #tt3 T1
ORDER BY T1.Регистратор DESC,
T1.Регистратор DESC,
T1.НомерСтроки DESC
//;
//exec sp_executesql N'
INSERT INTO #tt3 WITH(TABLOCK) (Регистратор,
Регистратор,
НомерСтроки)
SELECT T1.RecorderTRef,
T1.RecorderRRef,
T1.LineNo_
FROM
(SELECT TOP 1000 T2.Регистратор AS RecorderTRef,
T2.Регистратор AS RecorderRRef,
T2.НомерСтроки AS LineNo_
FROM #tt2 T2
WHERE (T2.Регистратор > "0x000001AD"
OR T2.Регистратор = "0x000001AD"
AND T2.Регистратор > &P1)
OR T2.Регистратор = "0x000001AD"
AND T2.Регистратор = &P2
AND T2.НомерСтроки > &P3
ORDER BY T2.Регистратор,
T2.Регистратор,
T2.НомерСтроки) T1
//',N'&P1 varbinary(16),&P2 varbinary(16),&P3 numeric(10)'
//,0x94CB005056A15EB211E6E9D787E31C08 // P1 = "Операция (бухгалтерский и налоговый учет) AGR00000011 от 30.01.2024 12:00:00" Документ.ОперацияБух
//,0x94CB005056A15EB211E6E9D787E31C08 // P2 = "Операция (бухгалтерский и налоговый учет) AGR00000011 от 30.01.2024 12:00:00" Документ.ОперацияБух
//,1
//;
TRUNCATE TABLE #tt3
//;
SELECT T1.AccountDtRRef,
T1.ValueDt1_TYPE,
T1.ValueDt1_RTRef,
T1.ValueDt1_RRRef,
T1.Fld1237_
FROM
(SELECT T2.СчетДт AS AccountDtRRef,
T2.Сумма AS Fld1237_,
T2._ValueDt1_TYPE AS ValueDt1_TYPE,
T2._ValueDt1_RTRef AS ValueDt1_RTRef,
T2._ValueDt1_RRRef AS ValueDt1_RRRef
FROM #tt1 T2) T1
//;
TRUNCATE TABLE #tt1
//;
TRUNCATE TABLE #tt3
//;
TRUNCATE TABLE #tt2
//;
TRUNCATE TABLE #tt5
//;
TRUNCATE TABLE #tt4
//;
Получен интересный листинг, который показывает, что фактически происходит выполнение нескольких запросов с формированием временных таблиц. Рассмотрим эти запросы:
1) Выполняется запрос к системной таблице актуальности итогов для всех регистров с отбором по регистру. Это нужно для определения необходимости использования служебных таблиц с итогами и периода, на который эти итоги существуют (может есть и другие функции этого запроса, но мои знания ограничиваются только периодами в итогах — дополняйте в комментариях:))
2) Здесь формируется таблица #tt2, содержащая ссылки на регистраторов и номера строк всех записей из основной таблицы регистра бухгалтерии, которые удовлетворяют условиям, указанным в виртуальной таблице (в нашем случае происходит отбор по периоду и по счету). Запрос состоит из двух объединенных запросов, для выбора случаев когда указанный в параметрах счет проходит по дебету или по кредиту.
3) Формируется таблица #tt3, простым копированием первых 1000 записей из таблицы #tt2, упорядоченной по регистратору и номеру строки (порционная обработка данных таблицы)
4) Формируется таблица #tt4 с помощью соединения сформированной таблицы #tt3 с основной таблицей регистра бухгалтерии по регистратору и номеру строки, выбираются дополнительно поля СчетДт, СчетКт, Сумма.
5) Формируется таблица #tt5 с помощью соединения сформированной таблицы #tt4 с таблицей субконто регистра бухгалтерии из которой выбирается вид субконто, значение субконто, вид движения в дополнение к регистратору и номеру строки. Соединение с табличной частью плана счетов используется для определения номера субконто по счету дебета или кредита и по виду субконто.
6) Формируется таблица #tt1 левым соединением таблиц #tt4 и #tt5. Так как в запросе был выбран СубконтоДт1 из таблицы #tt5, то параметры соединения задаются соответственно: _AccEdKindLineNo — номер субконто 1, _Correspond — вид движения Дебет. СчетДт и Сумма берутся из таблицы #tt4.
7) Выбирается максимальный регистратор и номер строки, для отделения следующей порции данных
8) В таблицу #tt3 Выбирается следующая порция в 1000 записей из таблицы #tt2
9) Очистка таблицы #tt3. Здесь при необходимости происходит повторение выборки (шаги 4-9)
10) Окончательная выборка результатов из таблицы #tt1
Разобрав запрос, можно сделать вывод что производительность выборки из виртуальной таблицы ДвиженияССубконто полностью определяется объемами выбираемых данных и если не использовать отбор внутри виртуальной таблицы, то все записи физических таблиц будут прогоняться через временные таблицы порциями по 1000 записей, что очень медленно (даже продвинутая СУБД не сможет оптимизировать такой запрос).
Как настроить трассировку запроса из обработки
За трассировку запроса отвечает 2 поля:
Путь файла трассы — здесь указывается путь к папке, в которую будут сохраняться временные файлы трассировки и имя файла (например D:Временные файлыTraceTest). Имена файлов трассировки будут присваиваться автоматически, добавлением номера в конец имени (например TraceTest_54.trc)
Подключение SQL — строка подключения к базе данных (например «DRIVER={SQL Server};SERVER=PC_1C_003;UID=sa;PWD=123;DATABASE=Localbase»). Строку подключения можно проверить на работоспособность, нажав на кнопку «Проверить подключение».
Трассировка запускается только если исходный запрос написан на языке запросов 1с, поэтому если введен SQL запрос, то поля «Путь файла трассы» и «Подключние SQL» можно не заполнять.
Выводы
Данную обработку можно использовать в связке с технологическим журналом с помощью инструментов разработчика или типовой обработки, а также можно использовать без ТЖ, используя трассировку запроса, встроенную в обработку или запуская трассировку вручную. Для понимания фактически выполняемого SQL запроса, гораздо удобнее видеть наименования таблиц и полей в терминах 1с, видеть представление ссылок 1с и читать форматированный текст запроса с отступами и пробелами.
Форма обработки анализа ТЖ из инструментов разработчика:
Форма типовой обработки с ИТС для просмотра логов ТЖ:
Ссылки
Инструменты разработчика: //infostart.ru/public/15126/
Типовая обработка просмотра логов ТЖ: https://its.1c.ru/db/metod8dev#content:5896:hdoc
Простая консоль ADO запросов: //infostart.ru/public/343268/
Update 19.09.2024
— При обращении к сервису форматирования убрано использование объекта ЧтениеJSON, для совместимости с 8.2 и версиями ниже 8.3.6
неплохо
Ха! Неплохо ? Да это просто бомба!
Рекомендую тексты запросов в статье поместить в спойлеры.
подпишусь
(2) Спасибо за высокую оценку 🙂
(3) Да, портянки действительно большие, звучит разумно показывать по кнопке.
А че же про встроенный конвертор текста запроса в анализе техножурнала не упомянул? Там есть
— преобразование констант в ссылки
— перевод в термины метаданных
— форматирование
— список таблиц использованных в запросе
— переход в конструктор запроса
— переход в дерево запроса
О, по-моему, это крутейшая штука!
Вечер добрый!
Прекрасная вещь! Молодцы!
Спасибо!
(6)
А где оно расположено?
Помню сколько я мучился с сервисами онлайн-форматирования кода когда изучал исходные запросы виртуальных таблиц…
По-моему, в статье зря не упомянуто про типовую консоль запросов.
https://its.1c.ru/db/metod8dev/content/4500/hdoc
Именно с неё я и начинал изучение внутренностей бд.
Очень нужная вещь, автор молодец!
(9)
Флажок «Пересобрать текст»
Отличная вещь! Автор — молодец.
(2) у Вячеслава это, видимо, максимальное значение из диапазона оценок 🙂
(2) Бомба? Я вас умоляю, это баян. Просто акккуратно и хорошо сделано. И публикация грамотно оформлена.
Красиво сделано, аккуратно оформлено, толково рассказано. Собирался «вырастить» нечто подобное из своейhttp://infostart.ru/public/462714/ , но руки не дошли. Спасибо, на первый взгляд выглядит как серьёзная качественная работа.
(14) если только это не оценка ему самому )
только под 8.3 работает?
на платформе 8.2 — выдаёт ошибку!
{ВнешняяОбработка.ТрансформаторSQL1С.МодульОбъекта(26,22)}: Тип не определен (ЧтениеJSON)
ЧтениеJSON = Новый <<?>>ЧтениеJSON;
(18)
а что платформа 8.2 поддерживает JSON? Сами же видите где ошибка.
(18) выяснил, что формат JSON в 1С до версии 8.3.6 не реализованhttps://helpf.pro/faq82/view/1664.html
В принципе большой сложности нет — написать код разбора JSON ответа с форматированным запросом, тогда будет работать и на 8.2. Сделаю в след. версии. Пока можно не пользоваться галкой «Форматирование интернет-сервисом», остальное то будет работать.
(20) аффтар, удалось переделать для версии 8.2))) ??
(10) Николай, поделитесь плиз такой консолью, в типовой с сайта ИТС нет опции «показывать план выполнения запроса»
(21) доработка небольшая, в ближайшее время сделаю, раз есть потребность у сообщества. Просто я пока занялся доведением до ума своей консоли запросов, скоро выложу на ИС 🙂
(22), в обработке для 8.3 — есть.
Большая работа, спасибо.
PS надеюсь когда нибудь конструктор запроса научится выдавать и текст запроса в терминах СУБД
Автору спасибо за разработку — взял на заметку.
(25) Зачем?
(27) что бы видеть реальный запрос
А самое главное, — автор не собирается останавливаться на достигнутом :
//TODO
//1. Прикрутить план запросов SQL
//2. Выполнение запроса под определенным пользователем (под вопросом)
//3. Проверка на тонкий клиент 8.3.5 конструктор запроса + модальный вызов
//4. Сохранение/загрузка настроек в УФ
Очень ждем продолжения !!!
(29) вообще планы по развитию есть, но после обдумывания акценты сместились. В первую очередь хочу проработать 2 пункта:
1) таблица с параметрами запроса, как в консоли запросов. Это позволит выполнять некоторые запросы, которые нельзя выполнить сейчас из-за ограничений параметров, задаваемых текстом (например вирт. таблица регистра расчета для определения базы по регистру)
2) выполнение под другим пользователем. Тоже полезная функция, если надо проверить фактический запрос с учетом RLS для пользователя
Насчет плана запроса, есть задумки, но если делать, то надо делать полноценный вариант с графическим представлением и деревом плана запроса, а это довольно сложно. Разве что скопировать с согласия автора функционал из существующих на ИС обработок, работающих с планом запроса. В общем, с планом планом пока не определился точно, пишите пожелания 🙂
+++
Как раз собирался написать конвертер для нового ЦУП (который на УФ). Благодаря Вам эта муторная работа отменяется.
Добрый день!
Обработка классная!
Но, при обновлении платформы на 8.3.13.1644 перестала работать
(32) Это скорее всего проблемы с com-коннектором, а не с платформой, надо убедиться что он у вас работает сначала. Com-соединение используется в обработке чтобы определить ID запроса, по которому затем отбирается запрос SQL из трассировки.
Давайте в личку, попытаюсь помочь.
(33) В личку что-то не пишется, ругается на какуюто отложенную группу 🙁
Вот в чем «затык», но как исправить не понимаю:
{ВнешняяОбработка.ТрансформаторSQL1С.МодульОбъекта(350)}: Ошибка при вызове конструктора (COMОбъект)
Коннектор = Новый COMОбъект(«v»+версияКоннектора+».COMConnector»);
по причине:
-2147221005(0x800401F3): Недопустимая строка с указанием класса
(34) посмотрите эти статьи, думаю информация из них поможет:
http://1clenta.ru/pattern/186 //сначала пробуйте так
https://infostart.ru/public/400951/ //если не получится, то так
https://infostart.ru/public/276794/ //эта статья скорее всего уже перебор для вашего случая, но на всякий случай 🙂
(35) Поучительные статьи.
Все сделал именно так — под УФ не работает. Работает под неуправляемыми формами …
Странно как-то. Уже по сносил все и переустановил, но все равно под УФ УТ 11.4 не работает.
(36) Попробуй инструмент «Управление COM классами 1С» из набора «Инструменты разработчика». Он тебе покажет все варианты регистрации коннектора и позволит зарегистировать нужные.
(37) Тут глюк я думаю у 1С серьезный: та же конфа УТ 11.4, в режиме обычное приложение все отрабатывает на УРА! … А, в режиме управляемого ругается.
(38) Глюка в 1С тут уверяю нет. Но конечно, чтобы в этом убедиться, тебе потребуется потратить время.
Спасибо за обработку, не понял только почему не добавлена опция доверительного подключения к SQL. хотя дописать скачавшему в этом плане не проблема
(40) а что за доверительное подключение, какая от него польза? Можете ссылкой поделиться — почитаю на досуге
(41)
видимо слишком вычурно выразился. я имел ввиду виндовую аутентификацию по сути, просто если в рамках строки подключения через ADO прямой перевод именно такой » доверительное подключение)
код будет примерно такой для получения строки подключения в случае ADO
Показать
ну и еще раз спасибо за удобный инструмент и подробные инструкции
(42) аа, похоже понял о чем речь. Имеете ввиду возможность авторизации без логина и пароля, как в Management Studio через пункт «Windows Authentication»? Да, хорошая идея, спасибо
(43)
да, именно так
Выводит следующую ошибку
{ВнешняяОбработка.ТрансформаторSQL1С.МодульОбъекта(350)}: Ошибка при вызове конструктора (COMОбъект)
Коннектор = Новый COMОбъект(«v»+версияКоннектора+».COMConnector»);
по причине:
-2147221005(0x800401F3): Недопустимая строка с указанием класса
проблему уже обсуждали в комментарии (34), скорее всего у вас просто не установлена com-компонента для связи с сервером приложений 1С
(45) эта проблема уже обсуждалась в комментарии (34), скорее всего у вас не установлена com-компонента подключения к серверу приложений 1с