Каталог решений - Пакетная выборка данных

Пакетная выборка данных

Пакетная выборка данных

В наличии

Когда в методе вызываются несколько десятков запросов и хочется все это выполнить быстрее, мы используем обработку «Пакетная выборка данных» для выполнения множества запросов за одну sql команду.

Описание

Друзья, в обработке реализовано:

  •  Добавление и выполнение запросов в обычном / привилегированном режиме

В Заметках из Зазеркалья есть публикация, что платформа 8.5 начнет поддерживать пакетную обработку запросов. Теперь когда мы описываем пакетный запрос, есть шансы что это будет выполнено за 1 обращение к СУБД, а не как сейчас, 1 обращение на каждый пакет.

Но пока наши продуктивные базы не перешли на новую версию платформы, можно применить альтернативный подход — взять все пакеты с выборкой и соединить в 1 запрос через "ОБЪЕДИНИТЬ ВСЕ".

Чтобы реализовать данный подход в этом решении используется комбинация взаимодействия 2ух объектов / обработок:

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

Функция СсылкаСуществует(ПроверяемаяСсылка)

	// Проверили параметры, возможен возврат без выполнения запроса

	// Проверили параметры, модифицировали текст запроса

	// Создали / выполнили запрос

	// Обработали результат

	Возврат Результат;

КонецФункции

 — Обработка "Пакетная выборка данных". На входе принимает обработки "Дескриптор выбоки", объединяет их в коллеции и формирует единый запрос, а на выходе отдает результат общей выборки распределенный по дескрипторам выборки.

 

Рассмотрим подробнее реализацию на примере:

1.  Выполним инициализацию пакетной выборки данных с установкой контейнера вывода.

Контейнер вывода — это структура, соответствие или объект в свойства/реквизиты которых необходимо установить результат выполнения определенного дескриптора выборки. 

	// Определим контейнер вывода
	СвойстваИКоллекции = Новый Структура;

	// Инициализируем пакетную выборку
	ПакетнаяВыборкаДанных = Обработки.сп_ПакетнаяВыборкаДанных.Инициализировать();
	ПакетнаяВыборкаДанных.КонтейнерВыводаУстановить(СвойстваИКоллекции);

2. Добавим в пакет получение результата функции РаботаСФайламиСлужебный.ФайлРедактируетсяВОблаке.

Функция имеет следующий вид:

// РаботаСФайламиСлужебный
Функция ФайлРедактируетсяВОблаке(Файл)
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	СтатусыСинхронизацииФайловСОблачнымСервисом.Файл
		|ИЗ
		|	РегистрСведений.СтатусыСинхронизацииФайловСОблачнымСервисом КАК СтатусыСинхронизацииФайловСОблачнымСервисом
		|ГДЕ
		|	СтатусыСинхронизацииФайловСОблачнымСервисом.Файл = &Файл";
	
	Запрос.УстановитьПараметр("Файл", Файл);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		Возврат Истина;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

Чтобы иметь возможность использовать данную функцию в пакетной выборке её необходимо модифицировать. Добавим новый общий модуль "РаботаСФайламиСлужебныйПакетнаяВыборка" и выполним адаптацию функции под использование дескриптора выбоки.

// РаботаСФайламиСлужебный
Функция ФайлРедактируетсяВОблаке(Файл) Экспорт

	// Создадим дескриптор
	Дескриптор = РаботаСФайламиСлужебныйПакетнаяВыборка.ФайлРедактируетсяВОблаке_ДескрипторСоздать();

	// Заполним параметры
	Дескриптор.Параметры.Вставить("Файл", Файл);

	// Сформируем результат 
	Результат = Дескриптор.Исполнить();
	Возврат Результат;
	
КонецФункции

// РаботаСФайламиСлужебныйПакетнаяВыборка
Функция ФайлРедактируетсяВОблаке_ДескрипторСоздать() Экспорт

	//
	ЗапросТекст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	СтатусыСинхронизацииФайловСОблачнымСервисом.Файл КАК Файл
		|{ВЫБРАТЬ
		|	Файл}
		|ИЗ
		|	РегистрСведений.СтатусыСинхронизацииФайловСОблачнымСервисом КАК СтатусыСинхронизацииФайловСОблачнымСервисом
		|ГДЕ
		|	СтатусыСинхронизацииФайловСОблачнымСервисом.Файл = &Файл_ИдентификаторДескриптора";

	Запрос = Новый Запрос(ЗапросТекст);

	ДескрипторВыборки = Обработки.сп_ДескрипторВыборки.Инициализировать(Запрос);
	ДескрипторВыборки.ОбработчикПослеВыводаДанныхУстановить("ОбработчикПослеВыводаДанныхРезультатНеПустой");

	Возврат ДескрипторВыборки;

КонецФункции

 

Обратите внимание на изменение в тексте запроса, обязательно нужно:

а) Поля выборки добавить в поля построителя

б) Добавить постфикс "_ИдентификаторДескриптора" ко всем параметрам и временным таблицам

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

Полученную функцию теперь можно использовать в пакетной выборке данных. Добавим её в контейнер вывода, с указанием адреса размещения результата — "РедактируетсяВОблаке".  

	// РедактируетсяВОблаке
	ДескрипторВыборки = РаботаСФайламиСлужебныйПакетнаяВыборка.ФайлРедактируетсяВОблаке_ДескрипторСоздать();
	ДескрипторВыборки.Параметры.Вставить("Файл", Файл);
	
	ПакетнаяВыборкаДанных.Добавить(ДескрипторВыборки, "РедактируетсяВОблаке");

3. Добавим в пакетную выборку поизвольный запрос

	// КоличествоВложений
	ЗапросТекст =
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(1) КАК КоличествоВложений
		|{ВЫБРАТЬ
		|	КоличествоВложений}
		|ИЗ
		|	Справочник.Файлы КАК Файлы
		|ГДЕ
		|	Файлы.ВладелецФайла = &ВладелецФайла_ИдентификаторДескриптора
		|	И НЕ Файлы.ПометкаУдаления";

	Запрос = Новый Запрос(ЗапросТекст);
	Запрос.УстановитьПараметр("ВладелецФайла", ВладелецФайла);

	ДескрипторВыборки = Обработки.сп_ДескрипторВыборки.Инициализировать(Запрос);
	ПакетнаяВыборкаДанных.Добавить(ДескрипторВыборки, "*");

В качестве адреса размещения результата указали "*" — это означает что все колонки последней строки выборки будут установлены в контейнер вывода. В нашем случае в стуктуру "СвойстваИКоллекции", будет добавлен новый ключ "КоличествоВложений" со значением из последней строки в колонке "КоличествоВложений".

 

4. Заключение

Весь код  пакетной выборки будет иметь следующий вид:

	//
	СвойстваИКоллекции = Новый Структура;

	// Инициализируем пакетную выборку
	ПакетнаяВыборкаДанных = Обработки.сп_ПакетнаяВыборкаДанных.Инициализировать();
	ПакетнаяВыборкаДанных.КонтейнерВыводаУстановить(СвойстваИКоллекции);

	// РедактируетсяВОблаке
	ДескрипторВыборки = сп_НесоответствияПакетнаяВыборка.ФайлРедактируетсяВОблаке_ДескрипторСоздать();
	ДескрипторВыборки.Параметры.Вставить("Файл", Файл);
	
	ПакетнаяВыборкаДанных.Добавить(ДескрипторВыборки, "РедактируетсяВОблаке");
	
	// КоличествоВложений
	ЗапросТекст =
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(1) КАК КоличествоВложений
		|{ВЫБРАТЬ
		|	КоличествоВложений}
		|ИЗ
		|	Справочник.Файлы КАК Файлы
		|ГДЕ
		|	Файлы.ВладелецФайла = &ВладелецФайла_ИдентификаторДескриптора
		|	И НЕ Файлы.ПометкаУдаления";

	Запрос = Новый Запрос(ЗапросТекст);
	Запрос.УстановитьПараметр("ВладелецФайла", ВладелецФайла);

	ДескрипторВыборки = Обработки.сп_ДескрипторВыборки.Инициализировать(Запрос);
	ПакетнаяВыборкаДанных.Добавить(ДескрипторВыборки, "*");
	
	// Выполним пакетную выборку данных и заполним контейнер вывода
	ПакетнаяВыборкаДанных.Исполнить()

Текст запроса, который будет выполнен:

	"ВЫБРАТЬ
	|	NULL КАК Поле0,
	|	NULL КАК ИдентификаторВыборки
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ ПЕРВЫЕ 1
	|	СтатусыСинхронизацииФайловСОблачнымСервисом.Файл,
	|	""0590fab2d98d4b3f870ee5c2accb3c73""
	|ИЗ
	|	РегистрСведений.СтатусыСинхронизацииФайловСОблачнымСервисом КАК СтатусыСинхронизацииФайловСОблачнымСервисом
	|ГДЕ
	|	СтатусыСинхронизацииФайловСОблачнымСервисом.Файл = &Файл_0590fab2d98d4b3f870ee5c2accb3c73
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	КОЛИЧЕСТВО(1),
	|	""2fc374c8272e46b58cf0d23b4df7b185""
	|ИЗ
	|	Справочник.Файлы КАК Файлы
	|ГДЕ
	|	Файлы.ВладелецФайла = &ВладелецФайла_2fc374c8272e46b58cf0d23b4df7b185
	|	И НЕ Файлы.ПометкаУдаления"

 

Что в итоге мы имеем:

1. Замеры времени выполнения показали -10%  на не нагруженной тестовой базе при выполнении пакетной выборки из 18 коротких запросов. В абсолютном значении — это 0,014 сек. 😉

2. Как минимум еще одна причина, по которой запрос уже давно пора обернуть в обработку и не обращаться к нему напрямую.

3. Отличный повод провести рефакторинг, еще -40% чисто исправили старые ошибки.

 

Как видите, все просто, данная разработка в помощь!

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

Проект и исходный код доступен на GitLab. 

 

 ——

Требования:

— Обработка предназначена для версии платформы >= 8.3.13, тестировалась на 8.3.27.1644

 

——

Ссылки:
— Проект в GitLab