УТ 11 и RLS. Изменения режима при открытии формы

1. men47 16.08.19 13:04 Сейчас в теме
Всем привет! нужна помощь.

В компании включен RLS, но необходимо, чтобы поиск в подборе происходил достаточно быстро. Запрос вывода в динамический список, уже несколько раз изменялся, убирались лишние на текущий момент таблицы, теперь дошло и до RLS. Через сиквел мы видим, что при построении запроса поиска платформа подтягивает таблицы ограничении RLS'а. Нашли роль, которая осуществляет подстановку запроса, в УТ 11 это "ЧтениеОстатковДоступныхТоваров". Если мы коментим ограничение доступа у регистра накопления "СвободныеОстатки", то о чудо, при построения запроса поиска таблицы нету. Было принято решение добавить условие в ограничение доступа и через параметр сеанса включать/выключать данное ограничение. Т.е. при открытии/закрытии формы мы меняем параметр сеанса.

Создал параметр, добавил условие, добавил инициализацию при запуске, добавил код изменения параметр сеанса в подборе при открытии/закрытии формы. НО, ничего не поменялось, т.е. если мы меняем при запуске булево с ложь на истина, то да, таблица не добавляется. Если мы меняем при открытии/закрытии формы, нет. На мысль пришло то что необходимо при открытии/закрытии повторно инициализировать параметр сеанса. Так же нашел, что если мы отключаем RLS, то на лету (без перезахода) отключается подстановка таблицы. Посмотрел код при отключении/включении RLS, нашел, при изменении параметра, программа лезет в общий модуль "УправлениеДоступомСлужебный" в процедуру "УстановкаПараметровСеанса". Сделал обращение при открытии/закрытии формы по аналогии, добавил в эту процедуру свой параметр, прописал установку этого параметра так же как и остальные. И...... ничего не поменялось... Есть предложения куда еще можно заглянуть?

В роли прописано вот так:

#Если НЕ &ЛМ_НеИспользоватьRLS #Тогда 
#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда 
#ДляРегистра("ИдентификаторыОбъектовМетаданных.РегистрНакопленияСвободныеОстатки", "Склад", "", "", "", "") 
#Иначе 
#ПоЗначениям( "РегистрНакопления.СвободныеОстатки","Чтение","", 
"Склады","Склад", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","" ) 
#КонецЕсли 
#КонецЕсли 

в Общем модуле вот так: 

&Вместо("УстановкаПараметровСеанса") 
Процедура ЛМ_УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) 
     
    //на всякий случай скопировал весь модуль 
    //Если ИмяПараметра = "ЛМ_НеИспользоватьRLS" Тогда 
        ОграничениеЛМ_НеИспользоватьRLS = Константы.ЛМ_НеИспользоватьRLS.Получить(); 
        ПараметрыСеанса.ЛМ_НеИспользоватьRLS = ОграничениеЛМ_НеИспользоватьRLS; 
        УстановленныеПараметры.Добавить("ЛМ_НеИспользоватьRLS"); 
    //КонецЕсли; 
....... 


Обращение в эту процедуру вот так: 

Процедура ПриИзмененииЛМ_НеИспользоватьRLS(ОграничениеДоступаНаУровнеЗаписейВключено) Экспорт 
     
    УстановитьПривилегированныйРежим(Истина); 
     
    Константы.ЛМ_НеИспользоватьRLS.Установить(ОграничениеДоступаНаУровнеЗаписейВключено); 

    УстановленныеПараметры = Новый Массив; 
    УстановкаПараметровСеанса("", УстановленныеПараметры); 
     
КонецПроцедуры 
Показать


Из формы произвожу обращение:
&НаСервере 
Процедура ЛМ_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка) 
    НачатьТранзакцию(); 
     
    УстановитьПривилегированныйРежим(Истина); 
    УправлениеДоступомСлужебный.ПриИзмененииЛМ_НеИспользоватьRLS(Истина); 
    УстановитьПривилегированныйРежим(Ложь); 
    ЗафиксироватьТранзакцию(); 
КонецПроцедуры 
Показать


при закрытии на севере так же только параметр "Ложь"

p.s. отключить RLS не предлагать=)))
По теме из базы знаний
Найденные решения
26. men47 19.08.19 10:53 Сейчас в теме
(25) еще раз спасибо за помощь. Я реализовал через константу.

Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт
	//УстановитьПривилегированныйРежим(Истина); 
	Если ИмяПараметра = "ЛМ_ОтключениеRLS" Тогда
		
		ТекстИзКонстанты = Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Получить();
		Если СтрНайти(ТекстИзКонстанты, "" + Строка(ПользователиИнформационнойБазы.ТекущийПользователь()) + ";") = 0 Тогда
			ПараметрыСеанса.ЛМ_ОтключениеRLS = Ложь;
		Иначе
			ПараметрыСеанса.ЛМ_ОтключениеRLS = Истина;
		КонецЕсли;
		УстановленныеПараметры.Добавить("ЛМ_ОтключениеRLS");
	КонецЕсли;

	
КонецПроцедуры
Показать




На форме:

&НаСервере
Процедура ЛМ_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
	
	УстановитьПривилегированныйРежим(Истина);
	Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Установить("" + Строка(ПользователиИнформационнойБазы.ТекущийПользователь()) + ";");
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

&НаСервере
Процедура ЛМ_ПриЗакрытииПослеНаСервере()
	
	УстановитьПривилегированныйРежим(Истина);
	ТекстИзКонстанты = Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Получить();
	ТекстИзКонстанты = СтрЗаменить(ТекстИзКонстанты, "" + Строка(ПользователиИнформационнойБазы.ТекущийПользователь()) + ";", "");
	Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Установить(ТекстИзКонстанты);
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры
Показать


Возможно не лучшее решение, но по времени выполнения это не сильно долго по сравнению с соединением таблиц в запросе.

По поводу Суриката, таблица "Номенклатуры" у нас достаточно большая (более 50к записей) так же происходит левое соединение с двумя таблицами ограничений, поэтому выполняется в 10 раз дольше. Чтобы этого не было, мы пытаемся минимизировать обращений запроса.
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
7. Сурикат 394 18.08.19 19:40 Сейчас в теме
(1) Вы бы план запроса проблемного показали или хотя бы сам запрос ... Там много настроек, которые влияют на итоговый запрос дин. списка.
Вы уверены, что проблема в RLS? Или вы имеете ввиду, что у вас при RLS есть скан таблицы вместо поиска по индексу?
2. VmvLer 16.08.19 13:31 Сейчас в теме
я не мучаю РЛС, а перехватываю создание форм в расширении и модифицирую запрос динамического списка по ряду условий - это проще, дешевле и понятнее чем охапка костылей.

примерно так же поступают в типовых в основной конфигурации.
3. men47 16.08.19 13:36 Сейчас в теме
(2) прошу прочитать еще раз начала основного текста. Запрос динамического списка и так сокращен на сколько можно. Дальше платформа производит подставление, т.к. при отладке если посмотреть на запрос динамического списка, то он такой же как мы его туда вогнали. Но если смотрим момент обращение в БД через SQL Server Profiler мы видим, что к основному запроса добавляется таблица ограничений, т.е. еще одна таблица из справочника и одна из регистра сведений.
4. VmvLer 16.08.19 13:42 Сейчас в теме
(3) тогда героически боритесь со способом обмана РЛС - я такой борьбы избегаю, очень дорого)
5. men47 16.08.19 13:59 Сейчас в теме
(4) пока приходится=) жду может кто еще сталкивался с данной проблемой...
6. dhurricane 16.08.19 22:16 Сейчас в теме
Вы как-то усложнили работу с параметром сеанса, возможно поэтому Ваш трюк и не удался: где-то что-то упустили. У меня получилось осуществить задуманное Вами с использованием параметра сеанса.

Вот какие есть замечания:

1) Вы некорректно инициализируете значение параметра сеанса. Нет необходимости копировать всю процедуру установки параметров сеанса целиком. Равно как и непосредственно вызывать ее. В конфигурации на базе БСП для этого в процедуре "ПриДобавленииОбработчиковУстановкиПараметровСеанса" общего модуля "ОбщегоНазначенияПереопределяемый" описывается собственный обработчик для своих параметров сеанса:
Обработчики.Вставить("ИмяПараметраСеанса", "МойОбщийМодуль.УстановкаПараметровСеанса");
Коли Вы используете расширения, добавьте данную процедуру в расширение с директивой &После и добавьте это описание обработчика. А затем в своем собственном модуле "МойОбщийМодуль" описываете свою процедуру "УстановкаПараметровСеанса" для инициализации собственных параметров сеанса:
Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт
	
	Если ИмяПараметра = "ИмяПараметраСеанса" Тогда
		ПараметрыСеанса.ИмяПараметраСеанса= Константы.МояКонстанта.Получить();
		УстановленныеПараметры.Добавить("ИмяПараметраСеанса");
	КонецЕсли;
	
КонецПроцедуры
Готово. При первом обращении к параметру сеанса будет вызвана данная процедура инициализации его значения. Подробнее об определении обработчиков установки параметров сеанса почитайте в описании к процедуре "ПриДобавленииОбработчиковУстановкиПараметровСеанса" модуля "ОбщегоНазначенияПереопределяемы" и на ИТС.

2) Некорректным мне кажется и присваивание нового значения параметру сеанса при открытии формы. Раз Вы используете значение константы для инициализации, то вместо непосредственного вызова процедуры "УстановкаПараметровСеанса" лучше просто очищать значение параметра сеанса:
Константы.МояКонстанта.Установить(Истина/Ложь);
ОчищаемыеПараметры = Новый Массив;
ОчищаемыеПараметры.Добавить("ИмяПараметраСеанса");
ПараметрыСеанса.Очистить(ОчищаемыеПараметры);
Больше ничего делать не нужно. При следующей попытки обращения к значению параметра сеанса он вновь будет инициализирован значением константы в обработчике, который я описал в п.1.

3) Ну и использование константы для хранения и инициализации значения Вашего параметра сеанса выглядит неудачным решением. Значение константы - одно на всю информационную базу. Фактически, пока один пользователь работает с формой подбора, все остальные пользователи также получают привилегированный режим для работы с таблицей свободных остатков. Я предлагаю, во-первых, отказаться от использования константы вовсе. Соответственно инициализировать параметр сеанса по умолчанию значением, запрещающим привилегированный режим с таблицей остатков. И во-вторых, в форме подбора как и раньше включить и выключать флаг, хранимый в параметре сеанса, непосредственным присваиванием нужного значения:
УстановитьПривилегированныйРежим(Истина);
ПараметрыСеанса.ИмяПараметраСеанса = Истина/Ложь;
8. men47 19.08.19 07:49 Сейчас в теме
(6) спасибо за ответ!

Я использовал константу по аналогии с включением/выключением RLS т к напрямую не получалось, т. е. При открытии формы, я производил обращение как вы написали в конце, параметр менялся все ок, но когда производился запрос к БД (смотрел через вьюер SQL), то таблицы все равно подставлялись. Если необходимо выслать примеры запросов БД, могу это сделать.

Я не мог понять, почему даже при открытой формы подбора, если включаешь/отключаешь RLS, то «налету» подставляется/убирается таблицы проверки.

Сегодня попробую как вы посоветовали, дальше отпишусь.
9. men47 19.08.19 08:37 Сейчас в теме
(6) нет. Не работает....

Пишу что я сейчас сделал. Я снес все. Заново добавил условие в правиле

#Если НЕ &ЛМ_ОтключениеRLS #Тогда
#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляРегистра("ИдентификаторыОбъектовМетаданных.РегистрНакопленияСвободныеОстатки", "Склад", "", "", "", "")
#Иначе
#ПоЗначениям( "РегистрНакопления.СвободныеОстатки","Чтение","",
"Склады","Склад", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","" )
#КонецЕсли
#КонецЕсли



Добавил:

&После("ПриДобавленииОбработчиковУстановкиПараметровСеанса")
Процедура ЛМ_ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики)
	
	Обработчики.Вставить("ЛМ_ОтключениеRLS", "ЛМ_ОбщийМодульСервер.УстановкаПараметровСеанса");
	
КонецПроцедуры


Добавил:

Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт
	
	Если ИмяПараметра = "ЛМ_ОтключениеRLS" Тогда
		ПараметрыСеанса.ЛМ_ОтключениеRLS = Ложь;
		УстановленныеПараметры.Добавить("ЛМ_ОтключениеRLS");
	КонецЕсли;
	
КонецПроцедуры


Добавил:

&НаСервере
Процедура ЛМ_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
	
	УстановитьПривилегированныйРежим(Истина);
	ПараметрыСеанса.ЛМ_ОтключениеRLS = Истина;
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры
Показать
...

И нет, не работает, т.е. в запросе все равно присутствуют таблицы...

(7)
Вот изначальный запрос:

				Результат="ВЫБРАТЬ
		|	СправочникНоменклатура.Ссылка КАК Ссылка,
		|СправочникНоменклатура.Синонимы КАК Синонимы,
		|СправочникНоменклатура.Марка КАК Бренд,
		|СправочникНоменклатура.ЛМ_АртикулыПоставщиков КАК АртикулыПоставщиков,
		|	СправочникНоменклатура.Артикул КАК Артикул,
		|	СправочникНоменклатура.Код КАК Код,
		|	СправочникНоменклатура.Наименование КАК Наименование,
		|	СправочникНоменклатура.Ссылка КАК Номенклатура,
		|	СправочникНоменклатура.Ссылка КАК ЭлементСписка,
		|	СправочникНоменклатура.ВидНоменклатуры КАК ВидНоменклатуры,
		|   СправочникНоменклатура.ЛМ_ЦеновыеКатегорииДляКраски КАК ЦеновыеКатегорииДляКраски,
		|	СправочникНоменклатура.ТипНоменклатуры КАК ТипНоменклатуры,
		|	СправочникНоменклатура.ЛМ_ЕдиницаИзмеренияДляПодбора КАК ЕдиницаИзмерения,
		|	СправочникНоменклатура.Качество КАК Качество,
		|	СправочникНоменклатура.ИспользованиеХарактеристик КАК ИспользованиеХарактеристик,
		|	&ВидыЦен КАК ВидЦены,
		|	ВЫРАЗИТЬ(ЕСТЬNULL(ЦеныНоменклатуры.Цена, 0) КАК ЧИСЛО(31,2)) КАК Цена,
		|	ВЫРАЗИТЬ(ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) КАК ЧИСЛО(15, 3)) КАК ВНаличииОстаток,
		|	ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) КАК ВНаличииВБазовыхЕдиницах,
		|	ВЫРАЗИТЬ(ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) - ЕСТЬNULL(СвободныеОстатки.ВРезервеПодЗаказОстаток, 0) -
		| ЕСТЬNULL(СвободныеОстатки.ВРезервеСоСкладаОстаток, 0) + ЕСТЬNULL(ОстаткиИзЗаказов.Количество, 0) 
		|КАК ЧИСЛО(15, 3)) КАК Доступно
		| ИЗ
		|	
		|	Справочник.Номенклатура КАК СправочникНоменклатура
		|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
		|			КОНЕЦПЕРИОДА(&Дата, День),
		|			ВидЦены = &ВидыЦен
		|				И Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)
		|			{(Номенклатура).* КАК Номенклатура}
		|		) КАК ЦеныНоменклатуры
		|	ПО (ЦеныНоменклатуры.Номенклатура = СправочникНоменклатура.Ссылка)
		|		И (ЦеныНоменклатуры.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка))
		|	И (ЦеныНоменклатуры.ВидЦены = &ВидыЦен)
		|	
		|	
		|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СвободныеОстатки.Остатки(
		|			, 
		|			Склад = &Склад
		|				И Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)
		|			{(Номенклатура).* КАК Номенклатура}
		|		) КАК СвободныеОстатки
		|	ПО (СвободныеОстатки.Склад = &Склад)
		|		И (СвободныеОстатки.Номенклатура = СправочникНоменклатура.Ссылка)
		|		И (СвободныеОстатки.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка))
		|
		|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДоступныеОстаткиПланируемыхПоступлений КАК ОстаткиИзЗаказов
		|		ПО (ОстаткиИзЗаказов.Склад = &Склад)
		|		И (ОстаткиИзЗаказов.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка))
		|		И (ОстаткиИзЗаказов.ДатаДоступности = ДАТАВРЕМЯ(1, 1, 1))
		|		И (ОстаткиИзЗаказов.Номенклатура = СправочникНоменклатура.Ссылка)
		|		И (ОстаткиИзЗаказов.Количество < 0)
		|
		| ГДЕ
		|	
		|	НЕ СправочникНоменклатура.ЭтоГруппа
		|
		|	
		|{ГДЕ
		|	(1 В
		|		(ВЫБРАТЬ ПЕРВЫЕ 1
		|			1
		|		ИЗ
		|			РегистрСведений.НоменклатураСегмента КАК Сегменты
		|		ГДЕ
		|			Сегменты.Номенклатура = СправочникНоменклатура.Ссылка
		|			И Сегменты.Сегмент = &СегментНоменклатуры))}";

Показать



Вот так выглядит данный запрос при поиске в SQL Server Profiler (прошу обратить внимание на "EXISTS", данные таблицы подставляются, если RLS включен)

exec sp_executesql N'SEL ECT
T29._IDRRef,
T29._Description
FR OM dbo._Reference270 T29
LEFT OUTER JOIN (SEL ECT
T33._Fld17496RRef AS Fld17496RRef,
T33._Fld17497RRef AS Fld17497RRef,
T33._Fld17495RRef AS Fld17495RRef
FR OM (SEL ECT
T32._Fld17495RRef AS Fld17495RRef,
T32._Fld17496RRef AS Fld17496RRef,
T32._Fld17497RRef AS Fld17497RRef,
MAX(T32._Period) AS MAXPERIOD_
FR OM dbo._InfoRg17494 T32
WHERE ((T32._Fld1354 = @P1)) AND (T32._Period <= @P2 AND (((T32._Fld17497RRef = @P3) AND (T32._Fld17496RRef = @P4))))
GROUP BY T32._Fld17495RRef,
T32._Fld17496RRef,
T32._Fld17497RRef) T31
INNER JOIN dbo._InfoRg17494 T33
ON T31.Fld17495RRef = T33._Fld17495RRef AND T31.Fld17496RRef = T33._Fld17496RRef AND T31.Fld17497RRef = T33._Fld17497RRef AND T31.MAXPERIOD_ = T33._Period
WHERE (T33._Fld1354 = @P5)) T30
ON (((T30.Fld17495RRef = T29._IDRRef) AND (T30.Fld17496RRef = @P6)) AND (T30.Fld17497RRef = @P7))
LEFT OUTER JOIN (SEL ECT
T35._Fld19334RRef AS Fld19334RRef,
T35._Fld19336RRef AS Fld19336RRef,
T35._Fld19335RRef AS Fld19335RRef,
T35._Fld19337 AS Fld19337Balance_,
T35._Fld19338 AS Fld19338Balance_,
T35._Fld19339 AS Fld19339Balance_
FR OM dbo._AccumRgT19341 T35
WHERE (((T35._Fld1354 = @P8)) AND (EXISTS(SEL ECT
0x01 AS Q_001_F_000_
FR OM dbo._Reference216 T36
INNER JOIN dbo._Reference175 T37
ON (((T36._Fld23442 = @P9) AND EXISTS(SEL ECT
0x01 AS Q_002_F_000_
FR OM dbo._InfoRg17048 T38
WHERE ((T38._Fld1354 = @P10)) AND ((T38._Fld17049_TYPE = 0x08 AND T38._Fld17049_RTRef = 0x000000D8 AND T38._Fld17049_RRRef = T36._IDRRef) AND (T38._Fld17050RRef = T37._IDRRef)))) AND 0x000000AF = 0x000000AF AND T37._IDRRef IN
(SELECT
T39._Reference175_IDRRef AS Q_003_F_000RRef
FR OM dbo._Reference175_VT22490 T39
INNER JOIN dbo._InfoRg16553 T40
ON ((T40._Fld16555_TYPE = 0x08 AND T40._Fld16555_RTRef = 0x00000139 AND T40._Fld16555_RRRef = @P11) AND (T40._Fld16554_TYPE = T39._Fld22492_TYPE AND T40._Fld16554_RTRef = T39._Fld22492_RTRef AND T40._Fld16554_RRRef = T39._Fld22492_RRRef))
WHERE ((T39._Fld1354 = @P12)) AND (T40._Fld1354 = @P13)))
WHERE ((T37._Fld1354 = @P14)) AND ((0x08 <> 0x01))))) AND (T35._Period = @P15 AND (((T35._Fld19336RRef = @P16) AND (T35._Fld19335RRef = @P17))) AND (T35._Fld19337 <> @P18 OR T35._Fld19338 <> @P19 OR T35._Fld19339 <> @P20) AND (T35._Fld19337 <> @P21 OR T35._Fld19338 <> @P22 OR T35._Fld19339 <> @P23))) T34
ON (((T34.Fld19336RRef = @P24) AND (T34.Fld19334RRef = T29._IDRRef)) AND (T34.Fld19335RRef = @P25))
LEFT OUTER JOIN dbo._InfoRg14493 T41
ON ((((((T41._Fld14496RRef = @P26) AND (T41._Fld14495RRef = @P27)) AND (T41._Fld14497 = @P28)) AND (T41._Fld14494RRef = T29._IDRRef)) AND (T41._Fld14498 < @P29))) AND (T41._Fld1354 = @P30)
WH ERE ((T29._Fld1354 = @P31)) AND ((T29._Folder) = 0x01 AND ((((((T29._Fld24341 LIKE @P32 ESCAPE ''/'') OR (T29._Fld33502 LIKE @P33 ESCAPE ''/'')) OR (T29._Fld33736 LIKE @P34 ESCAPE ''/'')) OR (T29._Description LIKE @P35 ESCAPE ''/'')) OR (T29._Fld33516 LIKE @P36 ESCAPE ''/'')) OR (T29._Fld33621 LIKE @P37 ESCAPE ''/'')) AND (T29._IDRRef IN (@P38, @P39)))',N'@P1 numeric(10),@P2 datetime2(3),@P3 varbinary(16),@P4 varbinary(16),@P5 numeric(10),@P6 varbinary(16),@P7 varbinary(16),@P8 numeric(10),@P9 nvarchar(4000),@P10 numeric(10),@P11 varbinary(16),@P12 numeric(10),@P13 numeric(10),@P14 numeric(10),@P15 datetime2(3),@P16 varbinary(16),@P17 varbinary(16),@P18 numeric(10),@P19 numeric(10),@P20 numeric(10),@P21 numeric(10),@P22 numeric(10),@P23 numeric(10),@P24 varbinary(16),@P25 varbinary(16),@P26 varbinary(16),@P27 varbinary(16),@P28 datetime2(3),@P29 numeric(10),@P30 numeric(10),@P31 numeric(10),@P32 nvarchar(4000),@P33 nvarchar(4000),@P34 nvarchar(4000),@P35 nvarchar(4000),@P36 nvarchar(4000),@P37 nvarchar(4000),@P38 varbinary(16),@P39 varbinary(16)',0,'4019-08-19 23:59:59',0x9107005056B17BE811E8FEC489DA96B7,0x00000000000000000000000000000000,0,0x00000000000000000000000000000000,0x9107005056B17BE811E8FEC489DA96B7,0,N'РегистрНакопления.СвободныеОстатки',0,0x911A005056B1CDF811E9B9BBD00727A3,0,0,0,'5999-11-01 00:00:00',0x00000000000000000000000000000000,0x00000000000000000000000000000000,0,0,0,0,0,0,0x00000000000000000000000000000000,0x00000000000000000000000000000000,0x00000000000000000000000000000000,0x00000000000000000000000000000000,'2001-01-01 00:00:00',0,0,0,N'%клей%',N'%клей%',N'%клей%',N'%клей%',N'%клей%',N'%клей%',0xB81F005056B6320D11E9503877CAF997,0xB840005056B6F8A211E956829351CA4D
Показать


Вот так выглядит данный запрос при поиске в SQL Server Profiler (прошу обратить внимание на "EXISTS", данные таблицы нету, т.к. RLS отключен):

exec sp_executesql N'SELECT
T17._IDRRef,
T17._Description
FR OM dbo._Reference270 T17
LEFT OUTER JOIN (SELECT
T21._Fld17496RRef AS Fld17496RRef,
T21._Fld17497RRef AS Fld17497RRef,
T21._Fld17495RRef AS Fld17495RRef
FR OM (SELECT
T20._Fld17495RRef AS Fld17495RRef,
T20._Fld17496RRef AS Fld17496RRef,
T20._Fld17497RRef AS Fld17497RRef,
MAX(T20._Period) AS MAXPERIOD_
FR OM dbo._InfoRg17494 T20
WH ERE ((T20._Fld1354 = @P1)) AND (T20._Period <= @P2 AND (((T20._Fld17497RRef = @P3) AND (T20._Fld17496RRef = @P4))))
GROUP BY T20._Fld17495RRef,
T20._Fld17496RRef,
T20._Fld17497RRef) T19
INNER JOIN dbo._InfoRg17494 T21
ON T19.Fld17495RRef = T21._Fld17495RRef AND T19.Fld17496RRef = T21._Fld17496RRef AND T19.Fld17497RRef = T21._Fld17497RRef AND T19.MAXPERIOD_ = T21._Period
WH ERE (T21._Fld1354 = @P5)) T18
ON (((T18.Fld17495RRef = T17._IDRRef) AND (T18.Fld17496RRef = @P6)) AND (T18.Fld17497RRef = @P7))
LEFT OUTER JOIN (SELECT
T23._Fld19334RRef AS Fld19334RRef,
T23._Fld19336RRef AS Fld19336RRef,
T23._Fld19335RRef AS Fld19335RRef,
T23._Fld19337 AS Fld19337Balance_,
T23._Fld19338 AS Fld19338Balance_,
T23._Fld19339 AS Fld19339Balance_
FR OM dbo._AccumRgT19341 T23
WH ERE ((T23._Fld1354 = @P8)) AND (T23._Period = @P9 AND (((T23._Fld19336RRef = @P10) AND (T23._Fld19335RRef = @P11))) AND (T23._Fld19337 <> @P12 OR T23._Fld19338 <> @P13 OR T23._Fld19339 <> @P14) AND (T23._Fld19337 <> @P15 OR T23._Fld19338 <> @P16 OR T23._Fld19339 <> @P17))) T22
ON (((T22.Fld19336RRef = @P18) AND (T22.Fld19334RRef = T17._IDRRef)) AND (T22.Fld19335RRef = @P19))
LEFT OUTER JOIN dbo._InfoRg14493 T24
ON ((((((T24._Fld14496RRef = @P20) AND (T24._Fld14495RRef = @P21)) AND (T24._Fld14497 = @P22)) AND (T24._Fld14494RRef = T17._IDRRef)) AND (T24._Fld14498 < @P23))) AND (T24._Fld1354 = @P24)
WH ERE ((T17._Fld1354 = @P25)) AND ((T17._Folder) = 0x01 AND ((((((T17._Fld24341 LIKE @P26 ESCAPE ''/'') OR (T17._Fld33502 LIKE @P27 ESCAPE ''/'')) OR (T17._Fld33736 LIKE @P28 ESCAPE ''/'')) OR (T17._Description LIKE @P29 ESCAPE ''/'')) OR (T17._Fld33516 LIKE @P30 ESCAPE ''/'')) OR (T17._Fld33621 LIKE @P31 ESCAPE ''/'')) AND (T17._IDRRef IN (@P32, @P33)))',N'@P1 numeric(10),@P2 datetime2(3),@P3 varbinary(16),@P4 varbinary(16),@P5 numeric(10),@P6 varbinary(16),@P7 varbinary(16),@P8 numeric(10),@P9 datetime2(3),@P10 varbinary(16),@P11 varbinary(16),@P12 numeric(10),@P13 numeric(10),@P14 numeric(10),@P15 numeric(10),@P16 numeric(10),@P17 numeric(10),@P18 varbinary(16),@P19 varbinary(16),@P20 varbinary(16),@P21 varbinary(16),@P22 datetime2(3),@P23 numeric(10),@P24 numeric(10),@P25 numeric(10),@P26 nvarchar(4000),@P27 nvarchar(4000),@P28 nvarchar(4000),@P29 nvarchar(4000),@P30 nvarchar(4000),@P31 nvarchar(4000),@P32 varbinary(16),@P33 varbinary(16)',0,'4019-08-19 23:59:59',0x9107005056B17BE811E8FEC489DA96B7,0x00000000000000000000000000000000,0,0x00000000000000000000000000000000,0x9107005056B17BE811E8FEC489DA96B7,0,'5999-11-01 00:00:00',0x00000000000000000000000000000000,0x00000000000000000000000000000000,0,0,0,0,0,0,0x00000000000000000000000000000000,0x00000000000000000000000000000000,0x00000000000000000000000000000000,0x00000000000000000000000000000000,'2001-01-01 00:00:00',0,0,0,N'%монтаж%',N'%монтаж%',N'%монтаж%',N'%монтаж%',N'%монтаж%',N'%монтаж%',0xB840005056B6F8A211E945E4FE1512D7,0xB81F005056B6320D11E959E0B9D51E7B
Показать
10. dhurricane 19.08.19 09:32 Сейчас в теме
(9) Еще один возможно глупый вопрос. А не может ли оказаться, что проверка прав выполняется не для регистра накопления "СвободныеОстатки", а для регистра сведений "ДоступныеОстаткиПланируемыхПоступлений"? Какие роли Вы исправляли? И проверяли ли, какие именно таблицы в используются в конечном SQL-запросе?
11. men47 19.08.19 09:39 Сейчас в теме
(10) Если закомментировать правила в указанной роли, то таблицы не добавляются => именно СвободныеОстатки=)))
13. men47 19.08.19 09:47 Сейчас в теме
(10) все оказалось сложнее, чем я думал....

Поясню. После добавления текста в поиск на форме Происходит вызов "УстановкаПараметровСеанса".... и параметр переопределяется. Так же в этом модуле нельзя проверить что зашито в параметр, даже после установки привилегированного режима мы не можем прочитать установленный ПараметрСеанс. Поэтому типовой код использует константу для получения данного параметра....

Пока мысля сделать константу и туда записывать пользователя как строка через разделитель и проверять при вызове "УстановкаПараметровСеанса"...
15. dhurricane 19.08.19 09:53 Сейчас в теме
(13) Интересно. Т.е. получается, что при создании на сервере не смотря на нашу инструкцию параметр сеанса не был инициализирован? И инициализируется он только при начале использования в РЛС? Очень неожиданно, но можно попробовать подстроиться: прежде, чем установить параметру сеанса значение при создании формы, попробуйте прочитать это значение. Т.о. будет инициирована инициализация параметра, а уже после этого Вы установите ему нужное значение.
17. men47 19.08.19 09:59 Сейчас в теме
(15) Форма "ПодборТоваровВДокументПродажи"

Как только я пишу текст в поиске он выпадает вот так (см. Рис). И если я пытаюсь проверить условием, выпадает ошибка.
Прикрепленные файлы:
18. men47 19.08.19 10:00 Сейчас в теме
(17) Сейчас ставлю Истина дефолтом, т.к. проверял запрос=)
19. dhurricane 19.08.19 10:01 Сейчас в теме
(17) Ну здесь то ошибка по понятным причинам. :) Вы пытаетесь прочитать значение параметра сеанса, но для этого системе нужно его инициализировать. А чтобы инициализировать, нужно выполнить тот самый код, который Вы прервали отладчиком.
20. men47 19.08.19 10:11 Сейчас в теме
(19) да, это я тоже понимаю, но получается, что необходим внешний источник, как константа, которая будет определять истина и ложь. Но просто булево константу я не могу поставить, т.к. распространится на всех... поэтому я и написал записывать пользователя как строка с разделителями, чтобы понимать кому включать, кому выключать.
23. dhurricane 19.08.19 10:25 Сейчас в теме
(20) Не согласен. Зачем внешний источник?

Попробовал воспроизвести Вашу ситуацию по Вашему же описанию из (9). Использовал демо-базу 11.4.6.188 на платформе 8.3.14.1779. Все изменения вносил непосредственно в конфигурацию, расширения не использовал. Во вложении отчет о сравнении, типовой и доработанной, чтобы видеть все мои изменения.

Профайлер не смотрел пока. Доработал роль немного иначе:
#Если НЕ &ЛМ_ОтключениеRLS #Тогда

Ограничение_включилось: что-то пошло не так

#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляРегистра("ИдентификаторыОбъектовМетаданных.РегистрНакопленияСвободныеОстатки", "Склад", "", "", "", "")
#Иначе
#ПоЗначениям( "РегистрНакопления.СвободныеОстатки","Чтение","",
"Склады","Склад", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","" )
#КонецЕсли

#Иначе

Ограничение_отключилось: все идет как надо

#КонецЕсли
Показать

Под пользователем с ограниченными правами открыл форму подбора и получил сообщение, какое и ожидал (см. рис.). Делаю вывод, что параметр сеанса отработал как следует.

Сейчас загляну в профайлер, посмотрю, что происходит там.
Прикрепленные файлы:
ОтчетОСравнении.mxl
24. men47 19.08.19 10:27 Сейчас в теме
(23) не совсем верно.

Переинициализация происходит в момент написания текста в поиске. Поиск у нас "Стандартный", а не "Расширенный"
25. dhurricane 19.08.19 10:45 Сейчас в теме
(24) Да, это я тупой Вас зря мучаю. :) Вероятнее всего поиск осуществляется фоновым заданием, для которого заного инициализируются параметры сеанса. Поэтому-то Ваш параметр и сбрасывается.

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

Не самое изящное решение, конечно. Но фоновое задание выполняется от того же пользователя, что его запустил, так что должно сработать. Если у Вас появится решение интереснее, расскажите. Возможно я еще столкнусь с подобной проблемой в жизни.

Ну и возможно стоит прислушаться к Сурикату и подумать, почему же запрос выполняется в 10 раз дольше. Мне кажется это нетипичная ситуация, но тут я некомпетентен давать советы.
26. men47 19.08.19 10:53 Сейчас в теме
(25) еще раз спасибо за помощь. Я реализовал через константу.

Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт
	//УстановитьПривилегированныйРежим(Истина); 
	Если ИмяПараметра = "ЛМ_ОтключениеRLS" Тогда
		
		ТекстИзКонстанты = Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Получить();
		Если СтрНайти(ТекстИзКонстанты, "" + Строка(ПользователиИнформационнойБазы.ТекущийПользователь()) + ";") = 0 Тогда
			ПараметрыСеанса.ЛМ_ОтключениеRLS = Ложь;
		Иначе
			ПараметрыСеанса.ЛМ_ОтключениеRLS = Истина;
		КонецЕсли;
		УстановленныеПараметры.Добавить("ЛМ_ОтключениеRLS");
	КонецЕсли;

	
КонецПроцедуры
Показать




На форме:

&НаСервере
Процедура ЛМ_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
	
	УстановитьПривилегированныйРежим(Истина);
	Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Установить("" + Строка(ПользователиИнформационнойБазы.ТекущийПользователь()) + ";");
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

&НаСервере
Процедура ЛМ_ПриЗакрытииПослеНаСервере()
	
	УстановитьПривилегированныйРежим(Истина);
	ТекстИзКонстанты = Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Получить();
	ТекстИзКонстанты = СтрЗаменить(ТекстИзКонстанты, "" + Строка(ПользователиИнформационнойБазы.ТекущийПользователь()) + ";", "");
	Константы.ЛМ_ПользователиКоторымОтключатьRLSНаВремя.Установить(ТекстИзКонстанты);
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры
Показать


Возможно не лучшее решение, но по времени выполнения это не сильно долго по сравнению с соединением таблиц в запросе.

По поводу Суриката, таблица "Номенклатуры" у нас достаточно большая (более 50к записей) так же происходит левое соединение с двумя таблицами ограничений, поэтому выполняется в 10 раз дольше. Чтобы этого не было, мы пытаемся минимизировать обращений запроса.
27. dhurricane 19.08.19 10:59 Сейчас в теме
(26) Позволю себе сделать замечание. :)

При установке константы во время создания формы Вы затираете ранее записанных пользователей.
28. men47 19.08.19 11:00 Сейчас в теме
(27) Упс... точно=) спасибо, сейчас изменю=)
29. dhurricane 19.08.19 11:01 Сейчас в теме
(28) Ну и предлагаю тогда использовать не представление пользователя, а его уникальный идентификатор для пущей надежности.
16. dhurricane 19.08.19 09:53 Сейчас в теме
(13) Уточните, пожалуйста, а с какой именно формой Вы работаете?
12. Сурикат 394 19.08.19 09:45 Сейчас в теме
(9)
А на плане запроса запрос к таблице в EXISTS занимает длительное время?

А что за параметр "&ОграничениеДоступаНаУровнеЗаписейУниверсально"? В последних типовых на старом RLS шаблон только ПоЗначениям
14. men47 19.08.19 09:50 Сейчас в теме
(12) да, достаточно длительно, в пятницу замеряли в профайлере, там разница была почти в 10 раз...

"А что за параметр "&ОграничениеДоступаНаУровнеЗаписейУниверсально"? В последних типовых на старом RLS шаблон только ПоЗначениям"


данный параметр это тоже ПараметрСеанса, который получает с константы установлен ли RLS или нет.
22. Сурикат 394 19.08.19 10:19 Сейчас в теме
(14)
достаточно длительно, в пятницу замеряли в профайлере, там разница была почти в 10 раз...

"А что за параметр "&ОграничениеДоступа

Т.е. это ваш собственный RLS?

Не, я не об этом. Судя по всему у вас MS SQL и вы можете посмотреть план запроса и определить почему есть разница.
21. men47 19.08.19 10:18 Сейчас в теме
dhurricane спасибо, большое за помощь!
30. triviumfan 93 20.08.19 20:15 Сейчас в теме
Такая тема и такое странное решение...
И какой профит в итоге? Как изменился поиск? Сколько номенклатуры?
Что-то не верится, что из-за какого-то rls с видом доступа по складам прям лаги наблюдаются.
31. MikhailDr 02.06.23 13:08 Сейчас в теме
Искал решение своей проблемы и набрел на эту тему. Мало ли вдруг кто-то другой прочитает.

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

Решил довольно просто - убрал инициализацию параметра при запуске программы. Теперь параметр инициализируется только при открытии формы и больше не слетает.
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот