[ Вопрос дня ] Какая стратегия расчета данных используется платформой 1С для получения остатков из виртуальной таблицы остатков?

Доброго дня, коллеги!

Использование виртуальных таблиц в запросах – базовый навык специалиста 1С. В рамках курса Разработка и оптимизация запросов в 1С:Предприятие 8.3 виртуальные таблицы изучаются вдоль и поперек:)

Стратегия расчета остатков с использованием таблиц итогов на “будущую” дату и таблиц движений не всем слушателям кажется логичной, но с разработчиками 1С не поспоришь!

Вопрос

Добрый день! В курсе сказано, что платформа сначала получает текущие остатки регистра (остатки на текущую дату), которые хранятся в таблице итогов на дату 01.11.3999 00:00:00, затем корректирует эти остатки в соответствии с записями из таблицы движений за период с даты получения остатков по дату текущих остатков. Но это вроде же только один из возможных случаев, когда запрос СУБД будет сформирован таким образом. По большому счету это же, наверное, зависит от того, что на текущий момент имеется в таблице итогов, и на какую дату мы берем остатки.

Если взять пример из курса и поменять в нем только саму дату среза итогов на 05.03.2012. Разве оптимизатор не предпочтет выбрать итоги на 01.03.2012, а потом прибавить к ним выборку из таблицы движений за период с 01.03.2012 по 04.03.2012 23:59:59.

Ответ

Добрый день! Это достаточно логичное пожелание, которое часто встречается, но платформа так не поступает. Посмотрим при помощи консоли, какой запрос используется для получения остатков на 05.03.2012:

SELECT
T1.Fld82RRef,
T1.Fld83RRef,
T1.Fld84Balance_
FROM (SELECT
T2.Fld82RRef AS Fld82RRef,
T2.Fld83RRef AS Fld83RRef,
SUM(T2.Fld84Balance_) AS Fld84Balance_
FROM (SELECT
T3._Fld82RRef AS Fld82RRef,
T3._Fld83RRef AS Fld83RRef,
SUM(T3._Fld84) AS Fld84Balance_
FROM _AccumRgT85 T3
WHERE T3._Period = {ts '2012-04-01 00:00:00'} AND ((T3._Fld83RRef = 0xA9B000055D49B45E11DB8B8BEE7616E1)) AND (T3._Fld84 <> 0) AND (T3._Fld84 <> 0)
GROUP BY T3._Fld82RRef,
T3._Fld83RRef
HAVING (SUM(T3._Fld84)) <> 0
UNION ALL SELECT
T4._Fld82RRef AS Fld82RRef,
T4._Fld83RRef AS Fld83RRef,
CAST(SUM(CASE WHEN T4._RecordKind = 0 THEN -T4._Fld84 ELSE T4._Fld84 END) AS NUMERIC(22, 2)) AS Fld84Balance_
FROM _AccumRg81 T4
WHERE T4._Period >= {ts '2012-03-05 00:00:00'} AND T4._Period < {ts '2012-04-01 00:00:00'} AND T4._Active = TRUE AND ((T4._Fld83RRef = 0xA9B000055D49B45E11DB8B8BEE7616E1))
GROUP BY T4._Fld82RRef,
T4._Fld83RRef
HAVING (CAST(SUM(CASE WHEN T4._RecordKind = 0 THEN -T4._Fld84 ELSE T4._Fld84 END) AS NUMERIC(22, 2))) <> 0) T2
GROUP BY T2.Fld82RRef,
T2.Fld83RRef
HAVING (SUM(T2.Fld84Balance_)) <> 0) T1

Видно, что получаются итоги на 01.04.2012, а не на 01.03.2012.

Предполагаю, в общем случае сложно определить, что будет оптимальнее:

  • получить итоги на предыдущий месяц и скорректировать их по таблице движений
  • получить итоги на следующий месяц и скорректировать их по таблице движений

Поэтому платформа всегда получает итоги на “будущую” дату.

Теперь в запросе установим значение периода на 05.03.2019. Здесь уже платформа будет использовать актуальные (текущие) итоги, которые хранятся в базе на дату 01.11.3999:

SELECT
T1.Fld82RRef,
T1.Fld83RRef,
T1.Fld84Balance_
FROM (SELECT
T2.Fld82RRef AS Fld82RRef,
T2.Fld83RRef AS Fld83RRef,
SUM(T2.Fld84Balance_) AS Fld84Balance_
FROM (SELECT
T3._Fld82RRef AS Fld82RRef,
T3._Fld83RRef AS Fld83RRef,
SUM(T3._Fld84) AS Fld84Balance_
FROM _AccumRgT85 T3
WHERE T3._Period = {ts '3999-11-01 00:00:00'} AND ((T3._Fld83RRef = 0xA9B000055D49B45E11DB8B8BEE7616E1)) AND (T3._Fld84 <> 0) AND (T3._Fld84 <> 0)
GROUP BY T3._Fld82RRef,
T3._Fld83RRef
HAVING (SUM(T3._Fld84)) <> 0
UNION ALL SELECT
T4._Fld82RRef AS Fld82RRef,
T4._Fld83RRef AS Fld83RRef,
CAST(SUM(CASE WHEN T4._RecordKind = 0 THEN -T4._Fld84 ELSE T4._Fld84 END) AS NUMERIC(22, 2)) AS Fld84Balance_
FROM _AccumRg81 T4
WHERE T4._Period >= {ts '2019-03-05 00:00:00'} AND T4._Period < {ts '3999-11-01 00:00:00'} AND T4._Active = TRUE AND ((T4._Fld83RRef = 0xA9B000055D49B45E11DB8B8BEE7616E1))
GROUP BY T4._Fld82RRef,
T4._Fld83RRef
HAVING (CAST(SUM(CASE WHEN T4._RecordKind = 0 THEN -T4._Fld84 ELSE T4._Fld84 END) AS NUMERIC(22, 2))) <> 0) T2
GROUP BY T2.Fld82RRef,
T2.Fld83RRef
HAVING (SUM(T2.Fld84Balance_)) <> 0) T1

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

P.S.

Понимать, как работают запросы и уметь их строить - обязательный навык для всех, кто дорабатывает и внедряет 1С.

После курса Вы сможете:

  • Строить сложные запросы с несколькими источниками данных
  • Уверенно задействовать вложенные запросы и временные таблицы
  • Использовать встроенный язык для обработки результатов запроса
  • Учитывать особенности соединений и объединений нескольких таблиц.
  • Разрабатывать запросы на уровне задач Аттестации 1С:Специалист по платформе.
Программа, стоимость, условия и регистрация в группу: «Запросы в 1С 8.3, Базовый курс (с нуля до уровня Специалист по платформе)» Для всех, кто внедряет и дорабатывает 1С.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Вход на сайт

Зарегистрироваться

Подтверждение регистрации будет отправлено на указанный e-mail.

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

Восстановить доступ

E-mail или логин

Ссылка на создание нового пароля будет отправлена на указанный e-mail.