При работе с системой 1С часто возникает задача определить дату последней операции, связанной с конкретным договором. Это может быть необходимо для анализа взаиморасчетов, контроля сроков или формирования отчетов. Однако, при больших объемах данных, стандартные подходы могут приводить к низкой производительности запросов. В этой статье мы подробно разберем, как эффективно получить эту информацию, используя различные типы регистров и методы оптимизации.
Давайте вместе выясним причины возможного замедления и рассмотрим наиболее производительные решения, основанные на опыте коллег и рекомендациях по оптимизации.
Начнем с анализа того, почему некоторые подходы могут быть медленными, чтобы избежать этих ошибок в будущем.
Регистры бухгалтерии с субконто: Мы часто сталкиваемся с желанием получить данные из регистров бухгалтерии, таких как Хозрасчетный, поскольку они содержат множество информации. Однако, для работы с субконто в этих регистрах платформа вынуждена использовать виртуальные таблицы, например, ДвиженияССубконто. Эти виртуальные таблицы, хоть и удобны, являются одними из самых "тяжелых" и медленных, так как им приходится связывать проводки с субконто, которое хранится в отдельных таблицах. Если нет острой необходимости в бухгалтерских данных, мы настоятельно рекомендуем избегать их для поиска даты последней операции по договору.
Как отмечают специалисты, таблица движений регистра бухгалтерии сама по себе не содержит субконто, и для их получения всегда будет задействована виртуальная таблица, что неизбежно приводит к замедлению.
Неоптимизированные виртуальные таблицы регистров накопления: Хотя регистры накопления в целом более производительны, чем регистры бухгалтерии, некоторые виртуальные таблицы, особенно при неверном использовании, могут замедлять запросы. Например, для регистров накопления вида "Остатки" использование виртуальной таблицы "Обороты" для получения всех движений может оказаться неэффективным, так как платформа может строить запрос, перебирая все записи.
Теперь, когда мы понимаем, чего следует избегать, давайте перейдем к эффективным решениям.
Для большинства задач, связанных с датами операций по договорам, регистры накопления являются предпочтительным выбором. Рассмотрим подробнее несколько подходов.
Одним из наиболее производительных способов является прямой запрос к основной физической таблице движений регистра накопления. В отличие от виртуальных таблиц, которые могут выполнять сложную логику агрегации или связывания, физическая таблица содержит "сырые" записи движений, и обращение к ней зачастую быстрее.
Мы можем использовать такие регистры, как РасчетыСКлиентами или РасчетыСПоставщиками. Однако, стоит учесть, что в этих регистрах договор часто не является прямым измерением. Обычно он связан через справочник КлючиАналитикиУчетаПоПартнерам.
Давайте разберем по шагам, как это сделать:
Определяем нужный регистр накопления: В зависимости от задачи, это может быть РасчетыСКлиентами, РасчетыСПоставщиками или другой регистр, содержащий информацию о движениях по партнерам и договорам.
Связываем договор с ключом аналитики: Если договор не является прямым измерением регистра, нам потребуется связать его через Справочник.КлючиАналитикиУчетаПоПартнерам. Этот справочник содержит информацию о договорах, партнерах и других аналитиках.
Извлекаем дату регистратора: После связывания, мы можем получить поле Период или Дата из регистратора движения. Важно использовать именно Период регистра накопления, так как он точно соответствует дате движения.
Посмотрим на пример запроса, который использует этот подход для получения максимальной даты операции по договору:
ВЫБРАТЬ
МАКСИМУМ(РасчетыСКлиентами.Период) КАК ДатаПоследнейОперации,
РасчетыСКлиентами.Договор КАК Договор
ИЗ
РегистрНакопления.РасчетыСКлиентами КАК РасчетыСКлиентами
ГДЕ
РасчетыСКлиентами.Договор = &НужныйДоговор
СГРУППИРОВАТЬ ПО
РасчетыСКлиентами.Договор
Этот простой запрос вернет максимальную дату операции для указанного договора. Если нам нужна вся строка движения, мы можем использовать подзапрос:
ВЫБРАТЬ
Т1.Договор,
Т1.Регистратор,
Т1.Период КАК ДатаПоследнейОперации,
Т1.СуммаВзаиморасчетов
ИЗ
РегистрНакопления.РасчетыСКлиентами КАК Т1
ГДЕ
Т1.Договор = &НужныйДоговор
И Т1.Период = (
ВЫБРАТЬ
МАКСИМУМ(ВложенныйЗапрос.Период)
ИЗ
РегистрНакопления.РасчетыСКлиентами КАК ВложенныйЗапрос
ГДЕ
ВложенныйЗапрос.Договор = &НужныйДоговор
)
Этот подход, как показывает практика, отрабатывает за вполне разумные 10-20 секунд даже на больших объемах данных, что подтверждается опытом коллег.
Регистры сведений также предоставляют мощные инструменты для решения нашей задачи, особенно если они периодические.
Если информация о последней операции по договору хранится в периодическом регистре сведений (например, РеестрДокументов, если он периодический и содержит ссылку на договор), то наиболее эффективным способом получения актуальной даты является использование виртуальной таблицы СрезПоследних.
Виртуальная таблица СрезПоследних специально оптимизирована платформой 1С для получения последних значений ресурсов на определенный момент времени по каждому измерению. Платформа самостоятельно строит наиболее оптимальный запрос к физической таблице регистра сведений.
Посмотрим на пример:
ВЫБРАТЬ
СрезПоследних.Договор КАК Договор,
СрезПоследних.Период КАК ДатаПоследнейОперации,
СрезПоследних.Регистратор КАК ДокументОперации
ИЗ
РегистрСведений.РеестрДокументов.СрезПоследних(&МоментВремени, Договор = &НужныйДоговор) КАК СрезПоследних
Здесь &МоментВремени – это дата, на которую мы хотим получить срез. Если нужен самый последний срез на текущий момент, можно передать ТекущаяДата() или NULL.
Если текущие регистры не позволяют эффективно получить нужную информацию, или если эта операция выполняется очень часто и критична к производительности, мы можем рассмотреть создание отдельного периодического регистра сведений. Этот регистр будет хранить только дату последней операции по каждому договору.
Алгоритм действий:
Создаем новый периодический регистр сведений: Например, ДатаПоследнихОперацийПоДоговорам.
Определяем измерения: В качестве измерения указываем Договор (тип СправочникСсылка.ДоговорыКонтрагентов).
Определяем ресурсы: В качестве ресурса можно указать ДатаОперации (тип Дата).
Настраиваем периодичность: Устанавливаем периодичность "По позиции регистратора" или "По дате".
Записываем данные: При проведении документов, которые являются "операциями" по договору (например, реализации, поступления, оплаты), мы должны записывать в этот регистр сведений новую запись с датой документа.
При таком подходе получение даты последней операции будет максимально быстрым, так как регистр будет содержать только целевую информацию, и мы сможем использовать СрезПоследних.
Помимо выбора правильного регистра и метода, существуют общие правила оптимизации запросов, которые помогут нам добиться максимальной производительности.
Точность даты и функция КонецДня(): Мы должны помнить, что в 1С дата включает время с точностью до секунды. Если нам нужно получить данные за весь день, конечную дату периода следует приводить к концу дня с помощью функции КонецДня(). Иначе будет учтена только первая секунда указанной даты, что может привести к неполным данным.
Пример использования:
ГДЕ
Регистр.Период МЕЖДУ &НачалоПериода И КОНЕЦДНЯ(&КонецПериода)
Избегание "многоточечных" ссылок: В запросах, особенно в условиях ГДЕ или СОЕДИНЕНИЕ, не рекомендуется использовать "многоточечные" обращения к полям ссылочных типов (например, Регистратор.Дата, Договор.Владелец). Вместо этого следует выполнять явное соединение с таблицей документа-регистратора или справочника и использовать поля этой таблицы напрямую. Это значительно повышает производительность запросов, так как 1С не приходится выполнять неявные соединения.
Плохой пример:
ВЫБРАТЬ
Регистр.Регистратор.Дата
ИЗ
РегистрНакопления.РасчетыСКлиентами КАК Регистр
ГДЕ
Регистр.Регистратор.Договор = &Договор
Хороший пример:
ВЫБРАТЬ
ДокументРеализация.Дата
ИЗ
РегистрНакопления.РасчетыСКлиентами КАК Регистр
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК ДокументРеализация
ПО Регистр.Регистратор = ДокументРеализация.Ссылка
ГДЕ
Регистр.Договор = &Договор
Временные таблицы (ПОМЕСТИТЬ): Для сложных запросов с несколькими этапами обработки данных использование временных таблиц может значительно улучшить читаемость и производительность. Мы можем разбить сложную логику на более мелкие, оптимизированные шаги, каждый из которых формирует временную таблицу. Это позволяет платформе лучше оптимизировать выполнение запроса.
Пример использования:
ВЫБРАТЬ
Регистр.Договор,
МАКСИМУМ(Регистр.Период) КАК МаксПериод
ИЗ
РегистрНакопления.РасчетыСКлиентами КАК Регистр
ГДЕ
Регистр.Договор В (&СписокДоговоров)
СГРУППИРОВАТЬ ПО
Регистр.Договор
ПОМЕСТИТЬ ВТ_МаксимальныеДаты;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Договор.Ссылка,
ВТ_МаксимальныеДаты.МаксПериод
ИЗ
Справочник.ДоговорыКонтрагентов КАК Договор
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_МаксимальныеДаты КАК ВТ_МаксимальныеДаты
ПО Договор.Ссылка = ВТ_МаксимальныеДаты.Договор
Индексы: Эффективность запросов сильно зависит от соответствия условий запроса существующим индексам таблиц. Мы должны убедиться, что поля, по которым происходит отбор и соединение (например, ссылка на договор, период), проиндексированы. Платформа 1С автоматически создает индексы для измерений и некоторых реквизитов, но в некоторых случаях может потребоваться анализ и, возможно, ручное создание индексов (в рамках доработки конфигурации, если это допустимо).
Таким образом, для получения даты последней операции по договору мы рекомендуем в первую очередь рассмотреть использование регистров накопления с прямыми запросами к таблицам движений или оптимизированными запросами с МАКСИМУМ(Период). Также очень эффективны периодические регистры сведений с виртуальной таблицей СрезПоследних. При работе с любыми регистрами ключевым фактором является оптимизация запросов, включая правильную работу с датами, избегание неэффективных ссылок и использование временных таблиц.
Следуя этим рекомендациям, мы сможем добиться высокой производительности и точности при решении задачи получения даты последней операции по договору в 1С.
← К списку