Пакетный запрос - передать результат одного запроса в ПАРАМЕТРЫ другого

1. DWZ2 13.05.22 01:17 Сейчас в теме
Есть два регистра сведений - один большой, 20 млн. записей, другой поменьше - всего 350 тысяч.

Требуется в запросе по первому регистру отфильтровать период (Период МЕЖДУ &ПериодМин И &ПериодМакс) по результатам значений запроса по второму регистру (МИНИМУМ(Период) и МАКСИМУМ(Период)).

Лично я вижу 2 варианта решения:

1. Разбить пакет запросов на 2 части и установить параметры вручную:

ВторойЗапрос.УстановитьПараметр("ПериодМин", ВыборкаИзПервогоЗапроса.ПериодМин);


2. Выгрузить первого запроса во временную таблицу с одной записью и поставить её слева в связи. Но 20 млн. записей это 20 млн. записей.

Может быть, есть метод лучше, который я не знаю?
По теме из базы знаний
Вознаграждение за ответ
Показать полностью
Найденные решения
4. spacecraft 13.05.22 05:58 Сейчас в теме +0.03 $m
(1) Из первого запроса пакета получить во временную таблицу МинПериод и МаксПериод. Всего одна запись.
Затем соединить эти записи с первой таблицей левым соединением.
Пример:
ВЫБРАТЬ
	МИНИМУМ(ВТ_Периоды.Период) КАК МинПериод,
	МАКСИМУМ(ВТ_Периоды.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_ГраницыПериодов
ИЗ
	ВТ_Периоды КАК ВТ_Периоды

;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ЦеныНоменклатуры.Период КАК Период,
	ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
	ЦеныНоменклатуры.ВидЦены КАК ВидЦены,
	ЦеныНоменклатуры.Цена КАК Цена
ИЗ
	ВТ_ГраницыПериодов КАК ВТ_ГраницыПериодов
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
		ПО ВТ_ГраницыПериодов.МинПериод <= ЦеныНоменклатуры.Период
			И ВТ_ГраницыПериодов.МаксПериод >= ЦеныНоменклатуры.Период
Показать

По производительности этот запрос (итоговый) будет аналогичен такому:
ВЫБРАТЬ
	ЦеныНоменклатуры.Период КАК Период,
	ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
	ЦеныНоменклатуры.ВидЦены КАК ВидЦены,
	ЦеныНоменклатуры.Цена КАК Цена
ИЗ
	РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
	
ГДЕ
	ЦеныНоменклатуры.Период МЕЖДУ &МинПериод И &МаксПериод
Показать
ImHunter; EVKash; +2 Ответить
5. Aleksandr_prof 198 13.05.22 07:10 Сейчас в теме +0.03 $m
(3) Вот тестовый пример, может быть это вам надо. Передаю результат одного запроса в виде таблицы в параметры другого запроса. Выполнен на УТ 11.4. Получаем цены услуг.
&НаСервере
Процедура Команда1НаСервере()
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Номенклатура.Ссылка КАК Номенклатура
		|ИЗ
		|	Справочник.Номенклатура КАК Номенклатура
		|ГДЕ
		|	Номенклатура.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Услуга)";
	
	ТаблицаТолькоУслуги = Запрос.Выполнить().Выгрузить();
		
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ВТ_Услуги.Номенклатура КАК Номенклатура
		|ПОМЕСТИТЬ ВТ_Услуги
		|ИЗ
		|	&ВТ_Услуги КАК ВТ_Услуги
		|;
		|
		|////////////////////////////////////////////////////////////­////////////////////
		|ВЫБРАТЬ
		|	ВТ_Услуги.Номенклатура КАК Номенклатура,
		|	ЦеныНоменклатуры.Цена КАК Цена
		|ИЗ
		|	ВТ_Услуги КАК ВТ_Услуги
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
		|		ПО ВТ_Услуги.Номенклатура = ЦеныНоменклатуры.Номенклатура";
	
	Запрос.УстановитьПараметр("ВТ_Услуги", ТаблицаТолькоУслуги);
	
	ТаблицаЦенУслуг = Запрос.Выполнить().Выгрузить();
		
КонецПроцедуры

&НаКлиенте
Процедура Команда1(Команда)
	Команда1НаСервере();
КонецПроцедуры
Показать

Есть важные нюансы:
1. Внешнюю таблицу обязательно нужно сразу помещать во временную.
2. При создании описания временной таблицы в конструкторе обязательно использовать & (амперсанд) перед именем таблицы.
3. Ну и, само собой, должны совпадать имена полей во внешней таблице и в описании.
15. ImHunter 330 14.05.22 10:56 Сейчас в теме +0.03 $m
(13) Прим так:

ВЫБРАТЬ
    МИНИМУМ(ВТ_Периоды.Период) КАК МинПериод,
    МАКСИМУМ(ВТ_Периоды.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_ГраницыПериодов
ИЗ
    ВТ_Периоды КАК ВТ_Периоды

;

////////////////////////////////////////////////////////////­­////////////////////
ВЫБРАТЬ
    ЦеныНоменклатуры.Период КАК Период,
    ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
    ЦеныНоменклатуры.ВидЦены КАК ВидЦены,
    ЦеныНоменклатуры.Цена КАК Цена
ИЗ
    ВТ_ГраницыПериодов КАК ВТ_ГраницыПериодов, 
    РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
Где ВТ_ГраницыПериодов.МинПериод <= ЦеныНоменклатуры.Период
            И ВТ_ГраницыПериодов.МаксПериод >= ЦеныНоменклатуры.Период
Показать
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
4. spacecraft 13.05.22 05:58 Сейчас в теме +0.03 $m
(1) Из первого запроса пакета получить во временную таблицу МинПериод и МаксПериод. Всего одна запись.
Затем соединить эти записи с первой таблицей левым соединением.
Пример:
ВЫБРАТЬ
	МИНИМУМ(ВТ_Периоды.Период) КАК МинПериод,
	МАКСИМУМ(ВТ_Периоды.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_ГраницыПериодов
ИЗ
	ВТ_Периоды КАК ВТ_Периоды

;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ЦеныНоменклатуры.Период КАК Период,
	ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
	ЦеныНоменклатуры.ВидЦены КАК ВидЦены,
	ЦеныНоменклатуры.Цена КАК Цена
ИЗ
	ВТ_ГраницыПериодов КАК ВТ_ГраницыПериодов
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
		ПО ВТ_ГраницыПериодов.МинПериод <= ЦеныНоменклатуры.Период
			И ВТ_ГраницыПериодов.МаксПериод >= ЦеныНоменклатуры.Период
Показать

По производительности этот запрос (итоговый) будет аналогичен такому:
ВЫБРАТЬ
	ЦеныНоменклатуры.Период КАК Период,
	ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
	ЦеныНоменклатуры.ВидЦены КАК ВидЦены,
	ЦеныНоменклатуры.Цена КАК Цена
ИЗ
	РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
	
ГДЕ
	ЦеныНоменклатуры.Период МЕЖДУ &МинПериод И &МаксПериод
Показать
ImHunter; EVKash; +2 Ответить
9. lmnlmn 69 13.05.22 11:45 Сейчас в теме
По производительности этот запрос (итоговый) будет аналогичен такому:


Видел подобные конструкции в типовых. Но гложут сомнения что по производительности аналогично. Есть что почитать на эту тему? Может исследовал уже кто?
10. spacecraft 13.05.22 12:33 Сейчас в теме
(9) достаточно посмотреть план выполнения запроса. Они почти идентичные.
Для первого запроса (в части итогового запроса):

NESTED OUTER LOOP
_INFORG35506 (T2) RANGE SCAN USING INDEX (_INFORG35506_1@) (2 fields)
WHERE
(T1._Q_001_F_000 <= T2.Период)
AND
(T1._Q_001_F_001 >= T2.Период)

Statistics: RecordsScanned = 1189, ParseTime = 0, ExecuteTime = 2, BuffersMemory = 95552, ResultRecords = 1188, RecordSize = 60

Для второго запроса:

_INFORG35506 (T1) RANGE SCAN USING INDEX (_INFORG35506_1@) (2 fields)
WHERE
(T1.Период >= 20150301000000)
AND
(T1.Период <= 20150304000000)

Statistics: RecordsScanned = 1188, ParseTime = 0, ExecuteTime = 2, BuffersMemory = 95552, ResultRecords = 1188, RecordSize = 60
7. ilnur75 13.05.22 08:31 Сейчас в теме
(1) а что на СКД не сделаете, соединение нескольких наборов данных с использованием списка параметров?
14. DWZ2 14.05.22 03:48 Сейчас в теме
(7) У меня не отчёт, а обработка - нужно по результатам запроса шарить по диску. Неохота возиться с компоновщиками. Плюс у меня и так 2 источника данных, а тут ещё, похоже, вложенная схема намечается.
8. starik-2005 3098 13.05.22 11:36 Сейчас в теме
(1)
2. Выгрузить первого запроса во временную таблицу с одной записью и поставить её слева в связи. Но 20 млн. записей это 20 млн. записей.
Вот разумная мысль, что 20 млн. записей во временной таблице - это не комильфо. И решается все наоборот - кладется во временную таблицу одна строчка с минимумом и максимумом из второго регистра (если нет больше никаких данных, кроме периода). Дальше обычная выборка из большого регистра, к ней присоединение (можно прям через запятую) этой одной строчки, в ГДЕ та же конструкция МЕЖДУ, в которой из этой одной строчки минимальная и максимальная дата. Все. Индекс на период обычно есть, так что будет достаточно оптимально.
11. DWZ2 13.05.22 17:23 Сейчас в теме
(8) Я так и делаю. Во временной таблице как раз одна запись.
2. PlatonStepan 38 13.05.22 02:55 Сейчас в теме
Если временные таблицы одного запроса нужно использовать в других, то используется МенеджерВременныхТаблиц.
Если в рамках одного пакета запроса, то используется связывание подготовленных таблиц.
3. DWZ2 13.05.22 03:49 Сейчас в теме
(2) Нет, тут пакет один. Вопрос как передать результат одного запроса в пакете в параметры другого.
5. Aleksandr_prof 198 13.05.22 07:10 Сейчас в теме +0.03 $m
(3) Вот тестовый пример, может быть это вам надо. Передаю результат одного запроса в виде таблицы в параметры другого запроса. Выполнен на УТ 11.4. Получаем цены услуг.
&НаСервере
Процедура Команда1НаСервере()
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Номенклатура.Ссылка КАК Номенклатура
		|ИЗ
		|	Справочник.Номенклатура КАК Номенклатура
		|ГДЕ
		|	Номенклатура.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Услуга)";
	
	ТаблицаТолькоУслуги = Запрос.Выполнить().Выгрузить();
		
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ВТ_Услуги.Номенклатура КАК Номенклатура
		|ПОМЕСТИТЬ ВТ_Услуги
		|ИЗ
		|	&ВТ_Услуги КАК ВТ_Услуги
		|;
		|
		|////////////////////////////////////////////////////////////­////////////////////
		|ВЫБРАТЬ
		|	ВТ_Услуги.Номенклатура КАК Номенклатура,
		|	ЦеныНоменклатуры.Цена КАК Цена
		|ИЗ
		|	ВТ_Услуги КАК ВТ_Услуги
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
		|		ПО ВТ_Услуги.Номенклатура = ЦеныНоменклатуры.Номенклатура";
	
	Запрос.УстановитьПараметр("ВТ_Услуги", ТаблицаТолькоУслуги);
	
	ТаблицаЦенУслуг = Запрос.Выполнить().Выгрузить();
		
КонецПроцедуры

&НаКлиенте
Процедура Команда1(Команда)
	Команда1НаСервере();
КонецПроцедуры
Показать

Есть важные нюансы:
1. Внешнюю таблицу обязательно нужно сразу помещать во временную.
2. При создании описания временной таблицы в конструкторе обязательно использовать & (амперсанд) перед именем таблицы.
3. Ну и, само собой, должны совпадать имена полей во внешней таблице и в описании.
6. DWZ2 13.05.22 07:30 Сейчас в теме
(5) Ну так это мой первый способ, только у меня таблица вырождается в одну-единственную строчку
12. ImHunter 330 13.05.22 18:52 Сейчас в теме
(9) В общем-то не без основания сомнения гложут. Но тут случай особый - во времянке всего только одна запись.

(1) Можно еще в другом варианте написать - сделать CROSS-соединение. И условие проверки периода вынести в WHERE.
13. DWZ2 13.05.22 21:30 Сейчас в теме
15. ImHunter 330 14.05.22 10:56 Сейчас в теме +0.03 $m
(13) Прим так:

ВЫБРАТЬ
    МИНИМУМ(ВТ_Периоды.Период) КАК МинПериод,
    МАКСИМУМ(ВТ_Периоды.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_ГраницыПериодов
ИЗ
    ВТ_Периоды КАК ВТ_Периоды

;

////////////////////////////////////////////////////////////­­////////////////////
ВЫБРАТЬ
    ЦеныНоменклатуры.Период КАК Период,
    ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
    ЦеныНоменклатуры.ВидЦены КАК ВидЦены,
    ЦеныНоменклатуры.Цена КАК Цена
ИЗ
    ВТ_ГраницыПериодов КАК ВТ_ГраницыПериодов, 
    РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
Где ВТ_ГраницыПериодов.МинПериод <= ЦеныНоменклатуры.Период
            И ВТ_ГраницыПериодов.МаксПериод >= ЦеныНоменклатуры.Период
Показать
16. DWZ2 15.05.22 11:48 Сейчас в теме
(15) Идея хороша, только рекомендуют вместо >= и <= использовать МЕЖДУ - так оптимизатор лучше понимает, что от него хотят.

Теперь вопрос знатокам MS SQL - как эффективнее - через левое соединение с временной таблицей из одно записи или через ГДЕ? Не будет ли full scan в случае с ГДЕ? Или надо смотреть конкретно?
17. spacecraft 15.05.22 12:00 Сейчас в теме
(16)
только рекомендуют вместо >= и <= использовать МЕЖДУ - так оптимизатор лучше понимает, что от него хотят.

См. (4) и (10). Получается абсолютно одинаковое условие в плане выполнения запроса.
Теперь вопрос знатокам MS SQL - как эффективнее - через левое соединение с временной таблицей из одно записи или через ГДЕ? Не будет ли full scan в случае с ГДЕ? Или надо смотреть конкретно?

То же самое. Абсолютно одинаково в данном случае.

Я даже больше скажу. Для запроса из (15) будет такой- же план выполнения запроса (с небольшими вариациями).
Оставьте свое сообщение

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