Заметки по SQL: Срез последних - аналог запроса

26.02.20

Разработка - Запросы

В статье описывается создание среза последних данных средствами классического языка запросов. Причем метод построения запроса был разработан еще во времена, когда автор работал с СУБД Oracle 9i и программировал на PL SQL. Основная идея заключается преобразовании запроса с подзапросом, в запрос без подзапроса (в примерах описывается преобразование до двух вложенных подзапросов). Запросы тестировались на реальных базах данных. Платформа - 1С:Предприятие 8.3 (8.3.10.2561).

1. Введение

Поскольку я занимаюсь сопровождением конфигурации - "Расчеты с населением за газ" (разработчик - ООО "АНТ-Консалт"), внедренной в 56 регионах России (цифра приблизительная), то все примеры будут основаны на данных именно этой конфигурации. Основу примеров составят запросы к регистру сведений "ПоказанияСчетчиков".

Вид запроса 1с для периодического, независимого регистра сведений с периодичностью "В пределах секунды",  который реально формируется в СУБД выглядит следующим образом:

ВЫБРАТЬ
	ВложенныйЗапрос.Оборудование КАК Оборудование,
	ВложенныйЗапрос.ПоследниеПоказанияПериод КАК ПоследниеПоказанияПериод,
	ПКУ_ПоказанияСчетчиков.Значение КАК ПоследниеПоказанияЗначение
ИЗ
	(ВЫБРАТЬ
		ПКУ_ПоказанияСчетчиков.Оборудование КАК Оборудование,
		МАКСИМУМ(ПКУ_ПоказанияСчетчиков.Период) КАК ПоследниеПоказанияПериод
	ИЗ
		РегистрСведений.ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков
	ГДЕ
		ПКУ_ПоказанияСчетчиков.Период <= &ДатаПоказаний
	
	СГРУППИРОВАТЬ ПО
		ПКУ_ПоказанияСчетчиков.Оборудование) КАК ВложенныйЗапрос
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков
		ПО ВложенныйЗапрос.Оборудование = ПКУ_ПоказанияСчетчиков.Оборудование
			И ВложенныйЗапрос.ПоследниеПоказанияПериод = ПКУ_ПоказанияСчетчиков.Период

Для простоты понимания пример приведен в синтаксисе языка запросов 1с, как реально это может выглядеть в profiler на MS SQL можно посмотреть в очень популярной статье на Инфостарте - "Регистры сведений 1С. Как это устроено.", раздел "3. Как работает СрезПоследних (СрезПервых) в запросе". 

А теперь преобразуем запрос с подзапросом в один запрос;

ВЫБРАТЬ
	ПКУ_ПоказанияСчетчиков.Значение КАК ПоследниеПоказанияЗначение,
	ПКУ_ПоказанияСчетчиков.Оборудование КАК Оборудование,
	ПКУ_ПоказанияСчетчиков.Период КАК Период
ИЗ
	РегистрСведений.ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков1
		ПО ПКУ_ПоказанияСчетчиков.Оборудование = ПКУ_ПоказанияСчетчиков1.Оборудование
ГДЕ
        ПКУ_ПоказанияСчетчиков1.Период <= &Период И
	ПКУ_ПоказанияСчетчиков.Период  <= &Период

СГРУППИРОВАТЬ ПО
	ПКУ_ПоказанияСчетчиков.Оборудование,
	ПКУ_ПоказанияСчетчиков.Значение,
	ПКУ_ПоказанияСчетчиков.Период

ИМЕЮЩИЕ
	МАКСИМУМ(ПКУ_ПоказанияСчетчиков1.Период) = ПКУ_ПоказанияСчетчиков.Период

Как видим нет ничего сверх естественного, все в рамках классического  SQL. Даже и пояснять особо ничего не нужно. Отмечу, что эта конструкция, будет являться базовой для построения запросов следующей публикации.

2. Работа с реальными данными.

Мы разобрали простейший пример, но не все так просто с реальными данными. В конфигурации для регистра сведений "ПоказанияСчетчиков" установлена периодичность "По позиции регистратора" , более того добавлен реквизит "ДатаРегистрацииИзменения". Спросим разработчиков, для чего введен этот реквизит, и услышим ответ, в конфигурации присутствуют данные, когда период и регистратор совпадают. А это значит, что запрос функция 1с :

ВЫБРАТЬ
	ПринятыеКУчетуПоказанияСрезПоследних.Период КАК Период,
	ПринятыеКУчетуПоказанияСрезПоследних.Оборудование КАК Оборудование,
	ПринятыеКУчетуПоказанияСрезПоследних.Значение КАК Значение
ИЗ
	РегистрСведений.ПринятыеКУчетуПоказания.СрезПоследних(, НЕ НеПриниматьКУчету) КАК ПринятыеКУчетуПоказанияСрезПоследних

работать будет не правильно.

Что же нам предлагают разработчики конфигурации - текст запроса:

ВЫБРАТЬ
	ПоказанияСчетчиков.Оборудование КАК Оборудование,
	ПоказанияСчетчиков.Значение КАК Значение,
	ПоказанияСчетчиков.ДатаРегистрацииИзменения КАК ДатаРегистрацииИзменения,
	ПоказанияСчетчиков.НеПриниматьКУчету КАК НеПриниматьКУчету,
	ПоказанияСчетчиков.Период КАК Период,
	ПоказанияСчетчиков.Регистратор КАК Регистратор
ПОМЕСТИТЬ втНач
ИЗ
	РегистрСведений.ПоказанияСчетчиков КАК ПоказанияСчетчиков
ГДЕ
	ПоказанияСчетчиков.Период <= &ДатаПоказаний

ИНДЕКСИРОВАТЬ ПО
	ПоказанияСчетчиков.Оборудование,
	ПоказанияСчетчиков.Период
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	втНач.Оборудование КАК Оборудование,
	втНач.Значение КАК Значение,
	втНач.Период КАК Период
ПОМЕСТИТЬ ПКУ_ПоказанияСчетчиков
ИЗ
	втНач КАК втНач
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
			втНач.Оборудование КАК Оборудование,
			МАКСИМУМ(втНач.Регистратор) КАК Регистратор,
			втНач.Период КАК Период,
			втНач.ДатаРегистрацииИзменения КАК ДатаРегистрацииИзменения
		ИЗ
			втНач КАК втНач
				ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
					втНач.Оборудование КАК Оборудование,
					втНач.Период КАК Период,
					МАКСИМУМ(втНач.ДатаРегистрацииИзменения) КАК ДатаРегистрацииИзменения
				ИЗ
					втНач КАК втНач
				
				СГРУППИРОВАТЬ ПО
					втНач.Оборудование,
					втНач.Период) КАК втДни2
				ПО втНач.Период = втДни2.Период
					И втНач.ДатаРегистрацииИзменения = втДни2.ДатаРегистрацииИзменения
					И втНач.Оборудование = втДни2.Оборудование
		
		СГРУППИРОВАТЬ ПО
			втНач.Оборудование,
			втНач.Период,
			втНач.ДатаРегистрацииИзменения) КАК втДни
		ПО втНач.Период = втДни.Период
			И втНач.ДатаРегистрацииИзменения = втДни.ДатаРегистрацииИзменения
			И втНач.Регистратор = втДни.Регистратор
			И втНач.Оборудование = втДни.Оборудование
ГДЕ
	НЕ втНач.НеПриниматьКУчету

ИНДЕКСИРОВАТЬ ПО
	втНач.Оборудование,
	втНач.Период
;

////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ втНач
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВложенныйЗапрос.Оборудование КАК Оборудование,
	ВложенныйЗапрос.ПоследниеПоказанияПериод КАК ПоследниеПоказанияПериод,
	ПКУ_ПоказанияСчетчиков.Значение КАК ПоследниеПоказанияЗначение
ИЗ
	(ВЫБРАТЬ
		ПКУ_ПоказанияСчетчиков.Оборудование КАК Оборудование,
		МАКСИМУМ(ПКУ_ПоказанияСчетчиков.Период) КАК ПоследниеПоказанияПериод
	ИЗ
		ПКУ_ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков
	
	СГРУППИРОВАТЬ ПО
		ПКУ_ПоказанияСчетчиков.Оборудование) КАК ВложенныйЗапрос
		ЛЕВОЕ СОЕДИНЕНИЕ ПКУ_ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков
		ПО ВложенныйЗапрос.Оборудование = ПКУ_ПоказанияСчетчиков.Оборудование
			И ВложенныйЗапрос.ПоследниеПоказанияПериод = ПКУ_ПоказанияСчетчиков.Период

Ну что ж, вполне себе работоспособный запрос . При чем вторая временная таблица "ПКУ_ПоказанияСчетчиков", очень напоминает нам аналог конструкции для регистра с периодичностью "По позиции регистратора" в СУБД, с той лишь разницей, что вместо периода используется реквизит "ДатаРегистрацииИзменения". Пример можно увидеть в уже вышеупомянутой статье - "Регистры сведений 1С. Как это устроено.", раздел "3. Как работает СрезПоследних (СрезПервых) в запросе".  Этот запрос был использован при разработке отчета в публикации "Реестр показаний по приборам учета за период с расчетом среднего потребления ресурса"

А теперь самое интересное. Преобразуем этот запрос, в запрос с одной виртуальной таблицей без подзапросов. Код запроса:

ВЫБРАТЬ
	втНач.Оборудование КАК Оборудование,
	втНач.Период КАК Период,
	втНач.Значение КАК Значение
ПОМЕСТИТЬ ПКУ_ПоказанияСчетчиков
ИЗ
	РегистрСведений.ПоказанияСчетчиков КАК втНач
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПоказанияСчетчиков КАК втНач1
		ПО втНач.Оборудование = втНач1.Оборудование
			И втНач.Период = втНач1.Период
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПоказанияСчетчиков КАК втНач2
		ПО втНач.Оборудование = втНач2.Оборудование
			И втНач.Период = втНач2.Период
ГДЕ
	НЕ втНач.НеПриниматьКУчету
	И втНач.Период <= &ДатаПоказаний

СГРУППИРОВАТЬ ПО
	втНач.Оборудование,
	втНач.Период,
	втНач.Регистратор,
	втНач.ДатаРегистрацииИзменения,
	втНач1.ДатаРегистрацииИзменения,
	втНач.Значение

ИМЕЮЩИЕ
	МАКСИМУМ(втНач2.ДатаРегистрацииИзменения) = втНач1.ДатаРегистрацииИзменения И
	МАКСИМУМ(втНач1.Регистратор) = втНач.Регистратор

ИНДЕКСИРОВАТЬ ПО
	Оборудование,
	Период
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ПКУ_ПоказанияСчетчиков.Оборудование КАК Оборудование,
	ПКУ_ПоказанияСчетчиков.Период КАК Период,
	ПКУ_ПоказанияСчетчиков.Значение КАК ПоследниеПоказанияЗначение
ИЗ
	ПКУ_ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПКУ_ПоказанияСчетчиков КАК ПКУ_ПоказанияСчетчиков1
		ПО ПКУ_ПоказанияСчетчиков.Оборудование = ПКУ_ПоказанияСчетчиков1.Оборудование

СГРУППИРОВАТЬ ПО
	ПКУ_ПоказанияСчетчиков.Оборудование,
	ПКУ_ПоказанияСчетчиков.Значение,
	ПКУ_ПоказанияСчетчиков.Период

ИМЕЮЩИЕ
	МАКСИМУМ(ПКУ_ПоказанияСчетчиков1.Период) = ПКУ_ПоказанияСчетчиков.Период

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

     Поскольку здесь сравниваются два запроса по реальным данным, уместно будет привести данные по их быстродействию. Так вот, первый запрос работает медленнее чем предложенный вариант приблизительно на 25% (обрабатывается 105 566 записей), при первом запуске в консоли запросов (не кешируемые запросы). Причем при повторном запуске (кешируемые запросы),  разность в скорости выполнения достигает порядка 50%, то есть предложенный вариант лучше кешируется, за счет отсутствия вложенных запросов. База данных расположена на MS SQL сервере.

    Таким образом получено реальное улучшение быстродействия запроса, в случае когда стандартными средствами 1с (виртуальными таблицами, срез последних) корректно решить задачу не не удалось.

3. Формализация результата

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

 
 
ВЫБРАТЬ
	втНач.ПолеОдин КАК ПолеОдин,
	втНач.ПолеДва КАК ПолеДва,
	втНач.Период КАК Период
ПОМЕСТИТЬ ВремТабл
ИЗ
	РегистрСведений.ДанныеРегистра КАК втНач
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеРегистра КАК втНач(1)
		ПО втНач.ПолеОдин = втНач(1).ПолеОдин
		 И втНач.ПолеДва = втНач(1).ПолеДва
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеРегистра КАК втНач(2)
		ПО  втНач(1).ПолеОдин = втНач(2).ПолеОдин
		  И втНач(1).ПолеДва = втНач(2).ПолеДва
		...............................................................
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеРегистра КАК втНач(N)
		ПО втНач(N-1).ПолеОдин = втНач(N).ПолеОдин
		 И втНач(N-1).ПолеДва = втНач(N).ПолеДва
			
ГДЕ
	втНач.Период <= &ДатаПолучения И
    втНач(1).Период <= &ДатаПолучения И
    ...
    втНач(N).Период <= &ДатаПолучения 

СГРУППИРОВАТЬ ПО
	втНач.ПолеОдин,
	втНач.ПолеДва,
	втНач.Период,
	втНач.ПериродическийРеквизит,
	втНач(1).ПериродическийРеквизит(1),
	...................................
	втНач(N-1).ПериродическийРеквизит(N)
	
ИМЕЮЩИЕ
	МАКСИМУМ(втНач(1).ПериродическийРеквизит(1)) = втНач.ПериродическийРеквизит
	МАКСИМУМ(втНач(2).ПериродическийРеквизит(2)) = втНач(1).ПериродическийРеквизит(1) И
	................................................................................
	МАКСИМУМ(втНач(N).ПериродическийРеквизит(N)) = втНач(N-1).ПериродическийРеквизит(N-1) 

 

 

 

См. также

SALE! 15%

Инструментарий разработчика Роли и права Запросы СКД Программист Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    159389    872    399    

861

Запросы Программист Бесплатно (free)

Увидел cheatsheet по SQL и захотелось нарисовать подобное, но про запросы.

18.10.2024    9869    sergey279    18    

64

Запросы Программист Платформа 1С v8.3 Запросы Конфигурации 1cv8 Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    5163    XilDen    36    

80

Запросы Программист Запросы Бесплатно (free)

Отлаживая взаимодействие с базой данных, мы регулярно сталкиваемся с зависающими или подозрительно долго выполняющимися обращениями, негативно влияющими на производительность. О том, как в PostgreSQL выявить подозрительные запросы, основываясь на доступной о них информации, расскажем в статье.

16.08.2024    7897    user1840182    5    

28

Математика и алгоритмы Запросы Программист Платформа 1С v8.3 Запросы Бесплатно (free)

Рассмотрим быстрый алгоритм поиска дублей с использованием hash функции по набору полей шапки и табличных частей.

08.07.2024    2393    ivanov660    9    

22

Запросы СКД Программист Стажер Система компоновки данных Россия Бесплатно (free)

Часто при разработке отчетов в СКД возникает ситуация, когда не совсем понятно, почему отчет выводит не те данные, которые нужны, либо не выводит вовсе. Возникает потребность увидеть конечный запрос, который формирует СКД. Как это сделать, рассмотрим в этой статье.

15.05.2024    8684    implecs_team    6    

47

Запросы Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Часто поступают задачи по произвольному распределению общих сумм. После распределения иногда пропадают копейки. Суть решения добавить АвтоНомерЗаписи() в ВТ распределения, и далее используя функции МАКСИМУМ или МИНИМУМ можем положить разницу копеек в первую или последнюю строку знаменателя распределения.

11.04.2024    3391    andrey_sag    10    

36
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Batman 165 16.01.19 12:25 Сейчас в теме
"...автор работал с СУБД Orakle 9i" - опечатка?
2. Fox-trot 163 16.01.19 12:40 Сейчас в теме
видимо настолько это давно было, что забыл как пишется
3. IVC_goal 226 16.01.19 13:33 Сейчас в теме
Виноват исправлю. А было это 9 лет назад
4. laby 23.01.19 10:35 Сейчас в теме
ничего не понятно, зачем куча вложенных запросов. В первом пункте ещё как-то понятно, а пункт два - это что-то с чем-то ...
conductor; +1 Ответить
5. IVC_goal 226 23.01.19 11:04 Сейчас в теме
(4) Первый вложенный запрос отбирает последние введенные показания по ДатаРегистрацииИзменения. Второй вложенный запрос отбирает последний документ регистрации для введенных показаний на ДатаРегистрацииИзменения. И последний запрос отбирает последний период, когда были введены показания.
6. ElKrab 26.02.20 10:16 Сейчас в теме
по п.1 и далее пришёл к выводу, что в блок ГДЕ необходимо добавить аналогичное условие для присоединяемой таблицы. Иначе не получить значения для предыдущего периода.

исходная таблица содержит 2 строки:

показатель: шаблон: начало действия:
c3c106df-8028-c5c5-1757-f46ac246dcf0 ОРВИ 2018-01-01
c3c106df-8028-c5c5-1757-f46ac246dcf0 ОРВИ04 2018-04-01

запрос:
sel ect
	т0.показатель_отчёта,
	т0.шаблон_поиска,
	т0.начало_действия
fr om
	public.map_шаблоны_показателей_отчётов т0
join public.map_шаблоны_показателей_отчётов т1 on
	т0.показатель_отчёта = т1.показатель_отчёта
where
	--т1.начало_действия <=  $период and 
	т0.начало_действия <= $период
group by
	т0.показатель_отчёта,
	т0.шаблон_поиска,
	т0.начало_действия
having
	max(т1.начало_действия) = т0.начало_действия
Показать


если $период = '2018-03-01', то результат запроса пустой,
если раскомментить второе условие, то результат даст ожидаемую строку
c3c106df-8028-c5c5-1757-f46ac246dcf0 ОРВИ 2018-01-01
7. IVC_goal 226 26.02.20 14:20 Сейчас в теме
(6) Вы правы это условие необходимо добавить,если вводится ограничение по дате
8. victor_k 95 28.12.20 02:14 Сейчас в теме
А так что не пойдет?
|//ВЫБРАТЬ
	|//	КадровыеПерем.Должность,
	|//	КадровыеПерем.Категория
	|//ИЗ
	|//	РегистрСведений.КадровыеПеремещения.СрезПоследних(&НаДату, 
	|//		Сотрудник = &Сотрудник 
	|//		И Магазин = &Магазин
	|//	) КАК КадровыеПерем
	|
	|ВЫБРАТЬ ПЕРВЫЕ 1
	|	КадровыеПерем.Должность,
	|	КадровыеПерем.Категория
	|ИЗ
	|	РегистрСведений.КадровыеПеремещения КАК КадровыеПерем
	|ГДЕ	
	|	КадровыеПерем.Период <= &НаДату
	|	И КадровыеПерем.Сотрудник = &Сотрудник 
	|	И КадровыеПерем.Магазин = &Магазин
	|УПОРЯДОЧИТЬ ПО
	|	КадровыеПерем.Период УБЫВ
Показать
9. IVC_goal 226 28.12.20 09:36 Сейчас в теме
(8)Конечно пойдет. Только надо сравнить, что пойдет быстрее
11. AlexO 135 01.07.21 23:21 Сейчас в теме
(9) так это понятно, что по дате нужно ограничить обе таблицы, раз уж их соединяем внутренним join.
А без этого неудивительно, что дает пустую таблицу.
12. AlexO 135 01.07.21 23:26 Сейчас в теме
(8) не пойдет. Вы получаете первую попавшуюся под руку запись, а не последнюю по дате.
Не говоря уже о том, что подобным запросом данные по всем сотрудникам вы получите разве что в цикле.
16. victor_k 95 04.07.21 16:48 Сейчас в теме
(12) не первую, а последнею по условию, прежде чем утверждать, тестировать надо... со вторым утверждение согласен...
10. AlexO 135 01.07.21 23:19 Сейчас в теме
(0)
ИМЕЮЩИЕ
	МАКСИМУМ(ПКУ_ПоказанияСчетчиков1.Период) = ПКУ_ПоказанияСчетчиков.Период

При прочих равных - такой код отберет только максимальные даты, например, внутри договора или адреса, напрочь игнорируя различие по оборудованию.
Т.е. имея по договору три различных оборудования с датами 01.10.2021, 01.10.2021 и 01.01.2020 - получим только два с максимальными датами 01.10.2021.

Таким образом получено реальное улучшение быстродействия запроса, в случае когда стандартными средствами 1с (виртуальными таблицами, срез последних) корректно решить задачу не не удалось.

СрезПоследних не отработает в двух случаях: когда нужен отбор по реквизитам регистра (СрезПоследних не поможет вообще никак), и если строки в регистре физически оказались перепутаны, и на оси времени строка со "старыми" данными оказалась ниже (позже) строки с последними данными.
Во всех остальных случаях о некорректности работы СрезПоследних речи не идет в принципе.
14. AlexO 135 01.07.21 23:52 Сейчас в теме
(10) дополнение:
и если строки в регистре физически оказались перепутаны, и на оси времени строка со "старыми" данными оказалась ниже (позже) строки с последними данными.
в этом случае СрезПоследних возвратит неправильные данные согласно и строго в рамках некорректного ввода.
13. AlexO 135 01.07.21 23:41 Сейчас в теме
(0)
Исходя из выше изложенного материала, можно предложить формализованную методику построения запроса получения среза последних данных

Нельзя.
Для СрезПоследних специально организуется соединение таблицы самой с собой, чтобы выбрать максимальный период - а не просто некие таблицы последовательно соединяются между собой.
Или у вас одна таблица - N-раз подряд соединяется сама с собой? Для чего вообще?
Да и очень сомнительно быстродействие такого бутерброда соединений более трех-четырех, у вас обрабатываемые данные растут в таком случае по геометрической прогрессии, какое уж тут "50% выигрыша скорости".
На данный момент самые быстрые запросы в 1С - это пакетные и временные таблицы. А ваш бутерброд уже после 8-9-го соединения встанет колом.
15. IVC_goal 226 02.07.21 05:15 Сейчас в теме
(13)
Да и очень сомнительно быстродействие такого бутерброда соединений более трех-четырех, у вас обрабатываемые данные растут в таком случае по геометрической прогрессии, какое уж тут "50% выигрыша скорости".
Великолепное, умозрительное предположение, которое можно рассматривать как гипотезу. Приведу такие жэ умозаключения, которые ни к чему не обязывают.
1. Скорость тестировалась не клиент серверной базе (MS SQL). Надеюсь вам известно, что там запросы переводятся в классический SQL код и СБД, оптимизирует запрос по своим алгоритмам.
Утверждение-
(13)
На данный момент самые быстрые запросы в 1С - это пакетные и временные таблицы.

может не работать
2. Приведенное сравнения быстродействия, основаны на работе с реальными базами, а не умозрительно-предположительно.
17. Said-We 19.04.23 17:54 Сейчас в теме
(1) А такой схематический запрос будет аналогом среза последних или нет? :-)
sel ect
    *
fr om
    (select
           row_number() over(partition by t.izmer1, t.izmer2...t.izmerN ORDER BY t.period DESC) as npp
          ,t.period

          ,t.izmer1
          ,t.izmer2
           ...
          ,t.izmerN

          ,t.resurs_rekvizit1
          ,t.resurs_rekvizit2
           ...
          ,t.resurs_rekvizitN
     fr om
           PC_name as t
     where
           t.period <= &ДатаХ AND
           условия внутри скобок среза на поля <t.izmer1, t.izmer2...t.izmerN> и на поля <t.resurs_rekvizit1, t.resurs_rekvizit2,...t.resurs_rekvizitN>
     ) as t
wh ere
     t.npp = 1
Показать
18. IVC_goal 226 20.04.23 14:59 Сейчас в теме
(17) Судя по тексту запроса вы используете аналитическую функцию нумерации строк по измерениям с убыванием по периоду. На выходе берется запись с номером 1, то есть последнее значение. Предварительный анализ показывает, что запрос работоспособный, но это утверждение нуждается в проверке. Запрос использует подзапрос, что делает невозможным построение индекса, это увеличивает время выполнения. Возможно лучше разбить запрос на два запроса.
Подобную нумерацию можно получить и не используя аналитическую функцию. Например как это сделано в статье Запрос, получающий изменения ресурса в регистрах сведений по датам изменения за период
19. Said-We 20.04.23 15:41 Сейчас в теме
(18)
Подобную нумерацию можно получить и не используя аналитическую функцию.

Можно, но это тормозные JOIN-ы. А если row_number() существует, то почему её не использовать? Тем более, если мы говорим не про 1С запросы, а про запросы, которые строит 1С к СУБД.
row_number() - достаточно шустрая функция даже с группировками (partition by).
Всего-то надо, либо допилить файловую 1С в части оконных функций, либо (и лучше ИМХО) отказаться от файловой в пользу бесплатного SQL сервера, например PsgSQL, так как его поддержка уже есть. Были же в 1С 77 версии на пять пользователей и т.д. Т.е. вопрос только в проверке лицензии и маркетинге.
С 2018 года даже SQLite умеет оконные функции, а этот сервер разрабатывает и поддерживает пол человека.

По поводу подзапросов.
Когда 1С переводит на язык запросов SQL к СУБД, то там есть позапросы? Джоины и группировки при расчете максимума есть?
20. IVC_goal 226 20.04.23 16:16 Сейчас в теме
(19) В статье Регистры сведений 1С. Как это устроено рассмотрены запросы формирующиеся 1С на стороне SQL Сервера
21. Said-We 20.04.23 16:20 Сейчас в теме
(20) Я это читал и не только это. Поэтому такой вопрос и задал. Это риторический вопрос.
Оставьте свое сообщение