Ускоряем расчет себестоимости в пару строчек кода. Проблемы производительности

22.12.25

База данных - HighLoad оптимизация

Можно существенно ускорить расчет себестоимости почти без программирования

В предыдущей статье "Проблемы производительности: Поля через несколько точек в условиях соединений" мы обсуждали, как соблюдение простых правил разработки ведёт к созданию быстрого и качественного кода. Сегодня мы разберём более злободневный реальный кейс, который наглядно показывает: писать «правильно» — не сложно, а результат оказывает колоссальное влияние на продуктивность и пользовательский опыт.

 

Структура технического разбора: от диагностики до решения

 

  1. Проблема:
    Расчёт себестоимости «висит» сутками. В логах — запросы на 11 000 секунд и дольше.
  2. Анализ:
    Неявное разименование в условиях соединения таблиц. 
  3. Решение:
    Меняем источник данных: вместо справочника используем специальный регистр сведений.
    Результат: 11 000 с → 2,5 с (ускорение в 4500 раз).
  4. Масштаб проблемы:
    В коде — десятки похожих мест с тем же полем. Риск повторения проблемы высок.
  5. Подарочный фикс от меня (5 мин, без правки кода):
    Используем новые возможности платформы

 

Поиск проблемы

 

Наш заказчик столкнулся с критической проблемой: процесс расчёта себестоимости в системе работал непредсказуемо долго. Пользователи запускали расчёт и не могли понять — он всё ещё выполняется или система «зависла». Ожидание занимало более суток, что делало функционал практически бесполезным.

 

 

Первым шагом мы обратились к мониторингу длительных операций в базе данных. Анализ выявил целый набор «узких мест» (см рис. ниже), но для наглядности мы сфокусируемся на показательном случае — достаточно длительном запросе, время выполнения которого превышало 11 000 секунд (более 3 часов!).

Что же могло заставить один запрос работать три часа? Давайте разберём его «по косточкам», увидим типичные ошибки и последовательно применим правила эффективной разработки, чтобы исправить ситуацию.

 

Рис. 1 Список длительных замеров

 

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

 

 
 Контекст проблемного запроса

 

ОбщийМодуль.ЗакрытиеМесяцаСервер.Модуль : 4128 : Обработки.ОперацииЗакрытияМесяца.ВыполнитьРасчетЭтапов(ПараметрыЗапуска);
 Обработка.ОперацииЗакрытияМесяца.МодульМенеджера : 2285 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(
  ОбщийМодуль.ОбщегоНазначения.Модуль : 6119 : Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")";
: 1 : РасчетСебестоимостиКорректировкаСтоимости.Выполнить_РасчетПартийИСебестоимости(Параметры[0])
   ОбщийМодуль.РасчетСебестоимостиКорректировкаСтоимости.Модуль : 516 : РасчетСебестоимости.РассчитатьВсеВПопыткеИсключении(ПараметрыЗапуска);
    ОбщийМодуль.РасчетСебестоимости.Модуль : 600 : РассчитатьВсе(ПараметрыЗапуска, ПараметрыРасчета, ПараметрыОтладки);
     ОбщийМодуль.РасчетСебестоимости.Модуль : 335 : РасчетСебестоимостиПостатейныеЗатраты.РаспределениеДопРасходовМеждуПартиямиИТоварами(ПараметрыРасчета);
      ОбщийМодуль.РасчетСебестоимостиПостатейныеЗатраты.Модуль : 440 : ПолучитьДанныеДляДополнительныхРасходов(ПараметрыРасчета);
       ОбщийМодуль.РасчетСебестоимостиПостатейныеЗатраты.Модуль : 4627 : ТекстЗапросаДляРаспределенияДополнительныхРасходов(ПараметрыРасчета),
        ОбщийМодуль.РасчетСебестоимостиПрикладныеАлгоритмы.Модуль : 7224 : ВыполнитьЗапросСЗамеромДляПротокола(ПараметрыРасчета, Запрос,,,, Пояснение);
         ОбщийМодуль.РасчетСебестоимостиПрикладныеАлгоритмы.Модуль : 20025 : РезультатПодзапроса = Запрос.Выполнить();

 

 

Исходя из контекста, мы сфокусировались на модуле «РасчетСебестоимостиПрикладныеАлгоритмы». Но, вопреки ожиданиям, нужный запрос отсутствовал в этом модуле. 

Потребовался более глубокий поиск. Прорывом стало обнаружение в тексте SQL-запроса уникального ключа — строки "ШаблонТекстаПервичныеПриемникиПоЗаказам_1". Именно эта метка, встроенная разработчиками, позволила нам быстро идентифицировать проблемный запрос в конфигурации ЕРП.

 

 
 SQL текст запроса

 

INSERT INTO pg_temp.tt1070 (_Q_000_F_000, _Q_000_F_001RRef, _Q_000_F_002, _Q_000_F_003_TYPE, _Q_000_F_003_RRRef, _Q_000_F_004_TYPE, _Q_000_F_004_RRRef, _Q_000_F_005_TYPE, _Q_000_F_005_RRRef, _Q_000_F_006_TYPE, _Q_000_F_006_RRRef, _Q_000_F_007_TYPE, _Q_000_F_007_RTRef, _Q_000_F_007_RRRef, _Q_000_F_008_TYPE, _Q_000_F_008_RRRef, _Q_000_F_009_TYPE, _Q_000_F_009_RTRef, _Q_000_F_009_RRRef, _Q_000_F_010_TYPE, _Q_000_F_010_RRRef, _Q_000_F_011, _Q_000_F_012, _Q_000_F_013, _Q_000_F_014, _Q_000_F_015, _Q_000_F_016, _Q_000_F_017) SELECT
'ШаблонТекстаПервичныеПриемникиПоЗаказам_1'::mvarchar,
T1._Q_000_F_000RRef,
TRUE,
'\\010'::bytea,
T4._Fld40018RRef,
'\\010'::bytea,
T4._Fld40017RRef,
'\\010'::bytea,
T4._Fld40019RRef,
'\\010'::bytea,
T4._Fld40020RRef,
T4._Fld73358_TYPE,
T4._Fld73358_RTRef,
T4._Fld73358_RRRef,
'\\010'::bytea,
T4._Fld73359RRef,
T4._Fld73360_TYPE,
T4._Fld73360_RTRef,
T4._Fld73360_RRRef,
'\\010'::bytea,
T4._Fld73361RRef,
T4._Fld40021,
T4._Fld40022,
T4._Fld40023,
T4._Fld40026,
T4._Fld85790,
T4._Fld148272,
T4._Fld40026
FROM pg_temp.tt1056 T1
INNER JOIN pg_temp.tt1064 T2
ON ('\\010'::bytea = T2._Q_000_F_001_TYPE AND CASE WHEN T1._Q_000_F_000RRef IS NOT NULL THEN CAST(0 AS NUMERIC) END = T2._Q_000_F_001_N AND T1._Q_000_F_000RRef = T2._Q_000_F_001_RRRef) AND (T2._Q_000_F_000 = CAST(1 AS NUMERIC))
INNER JOIN pg_temp.tt1057 T3
ON (T1._Q_000_F_005_TYPE = T3._Q_000_F_001_TYPE AND T1._Q_000_F_005_RTRef = T3._Q_000_F_001_RTRef AND T1._Q_000_F_005_RRRef = T3._Q_000_F_001_RRRef)
INNER JOIN _AccumRg40016 T4
LEFT OUTER JOIN _Reference183 T5
ON (T4._Fld40017RRef = T5._IDRRef) AND (T5._Fld1585 = CAST(0 AS NUMERIC))
ON (T3._Q_000_F_000TRef = T4._RecorderTRef AND T3._Q_000_F_000RRef = T4._RecorderRRef) AND (T3._Q_000_F_003RRef = T5._Fld4910RRef) AND (T3._Q_000_F_004RRef = T5._Fld4911RRef) AND (T3._Q_000_F_005RRef = T5._Fld73709RRef) AND ('\\010'::bytea = T5._Fld4913_TYPE AND T3._Q_000_F_006TRef = T5._Fld4913_RTRef AND T3._Q_000_F_006RRef = T5._Fld4913_RRRef) AND (T4._RecordKind = CAST(0 AS NUMERIC)) AND (T4._Period < '2025-01-01 00:00:00'::timestamp) AND (T4._Fld40020RRef = T1._Q_000_F_001RRef)
INNER JOIN _InfoRg32601 T6
ON (T4._Fld40017RRef = T6._Fld32606RRef)
WHERE (((T4._Fld1585 = CAST(0 AS NUMERIC))) AND (T6._Fld1585 = CAST(0 AS NUMERIC))) AND (((T4._Fld40021 <> CAST(0 AS NUMERIC)) OR (T4._Fld73378RRef IN ('\\206\\337m\\254X\\304;bA\\210)\\226\\377YR,'::bytea, '\\271*\\304L\\007\\2627\\262E@`P(\\256l\\373'::bytea, '\\203hM<\\012]<\\302J\\201}{\\002W\\\\\\023'::bytea, '\\260\\352g\\005/\\262\\2270E7\\335\\311\\031-\\037\\252'::bytea, '\\267\\015mM4\\367\\302\\323M\\327K3Kng\\031'::bytea, '\\223\\303#V\\213\\322\\307\\025F\\317\\310@,Sim'::bytea))))
UNION ALL SELECT
'ШаблонТекстаПервичныеПриемникиПоЗаказам_2'::mvarchar,
T7._Q_000_F_000RRef,
FALSE,
T10._Q_001_F_004_TYPE,
T10._Q_001_F_004_RRRef,
T10._Q_001_F_003_TYPE,
T10._Q_001_F_003_RRRef,
T10._Q_001_F_005_TYPE,
T10._Q_001_F_005_RRRef,
T10._Q_001_F_006_TYPE,
T10._Q_001_F_006_RRRef,
T10._Q_001_F_007_TYPE,
T10._Q_001_F_007_RTRef,
T10._Q_001_F_007_RRRef,
T10._Q_001_F_008_TYPE,
T10._Q_001_F_008_RRRef,
T10._Q_001_F_009_TYPE,
T10._Q_001_F_009_RTRef,
T10._Q_001_F_009_RRRef,
T10._Q_001_F_010_TYPE,
T10._Q_001_F_010_RRRef,
T10._Q_001_F_011,
T10._Q_001_F_012,
T10._Q_001_F_013,
T10._Q_001_F_022,
T10._Q_001_F_030,
T10._Q_001_F_037,
T10._Q_001_F_022
FROM pg_temp.tt1056 T7
INNER JOIN pg_temp.tt1064 T8
ON ('\\010'::bytea = T8._Q_000_F_001_TYPE AND CASE WHEN T7._Q_000_F_000RRef IS NOT NULL THEN CAST(0 AS NUMERIC) END = T8._Q_000_F_001_N AND T7._Q_000_F_000RRef = T8._Q_000_F_001_RRRef) AND (T8._Q_000_F_000 = CAST(1 AS NUMERIC))
INNER JOIN pg_temp.tt1057 T9
ON (T7._Q_000_F_005_TYPE = T9._Q_000_F_001_TYPE AND T7._Q_000_F_005_RTRef = T9._Q_000_F_001_RTRef AND T7._Q_000_F_005_RRRef = T9._Q_000_F_001_RRRef)
INNER JOIN pg_temp.tt993 T10
LEFT OUTER JOIN _Reference183 T11
ON (T10._Q_001_F_003_TYPE = '\\010'::bytea AND '\\000\\000\\000\\267'::bytea = '\\000\\000\\000\\267'::bytea AND T10._Q_001_F_003_RRRef = T11._IDRRef) AND (T11._Fld1585 = CAST(0 AS NUMERIC))
ON ('\\010'::bytea = T10._Q_001_F_001_TYPE AND T9._Q_000_F_000TRef = T10._Q_001_F_001_RTRef AND T9._Q_000_F_000RRef = T10._Q_001_F_001_RRRef) AND (T9._Q_000_F_003RRef = (T11._Fld4910RRef)) AND (T9._Q_000_F_004RRef = (T11._Fld4911RRef)) AND (T9._Q_000_F_005RRef = (T11._Fld73709RRef)) AND ('\\010'::bytea = (T11._Fld4913_TYPE) AND T9._Q_000_F_006TRef = (T11._Fld4913_RTRef) AND T9._Q_000_F_006RRef = (T11._Fld4913_RRRef)) AND T10._Q_001_F_000 = TRUE AND (T10._Q_001_F_006_TYPE = '\\010'::bytea AND T10._Q_001_F_006_RRRef = T7._Q_000_F_001RRef)
INNER JOIN _InfoRg32601 T12
ON (T10._Q_001_F_003_TYPE = '\\010'::bytea AND T10._Q_001_F_003_RRRef = T12._Fld32606RRef)
WHERE ((T12._Fld1585 = CAST(0 AS NUMERIC))) AND ((NOT (((T10._Q_001_F_011 = CAST(0 AS NUMERIC))))))

 

 

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

В результате поиска мы локализовали проблемный запрос. Он находится в модуле "РасчетСебестоимостиПостатейныеЗатраты", в функции "ШаблонТекстаПервичныеПриемникиПоЗаказам". Проблема также воспроизводится в текущей стабильной версии платформы (ERP 2.5.22 LTS).

 

 
 Исходный 1С запрос

 

ВЫБРАТЬ
	"ШаблонТекстаПервичныеПриемникиПоЗаказам_1" КАК ЗапросИсточник,
	ДД.Ссылка КАК Регистратор,
	ИСТИНА КАК ЭтоПартияПрошлогоПериода,
	ИсточникБазы.РазделУчета КАК РазделУчета,
	ИсточникБазы.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры,
	ИсточникБазы.ВидЗапасов КАК ВидЗапасов,
	ИсточникБазы.Организация КАК Организация,
	ИсточникБазы.Партия КАК Партия,
	ИсточникБазы.АналитикаУчетаПартий КАК АналитикаУчетаПартий,
	ИсточникБазы.АналитикаФинансовогоУчета КАК АналитикаФинансовогоУчета,
	ИсточникБазы.ВидДеятельностиНДС КАК ВидДеятельностиНДС,
	ИсточникБазы.Количество КАК Количество,
	ИсточникБазы.Стоимость КАК Стоимость,
	ИсточникБазы.СтоимостьБезНДС КАК СтоимостьБезНДС,
	ИсточникБазы.СтоимостьРегл КАК СтоимостьРегл,
	ИсточникБазы.СтоимостьУпр КАК СтоимостьУпр,
	ИсточникБазы.СтоимостьНДД КАК СтоимостьНДД,
	ИсточникБазы.СтоимостьРегл КАК СтоимостьНУ
ПОМЕСТИТЬ ТаблицаДанных
ИЗ
	Регистраторы КАК ДД
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыОбъектовДополнительныхРасходов КАК Группа
		ПО ДД.Ссылка = Группа.Объект
			И (Группа.НомерГруппы = &НомерГруппы)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
		ПО ДД.АналитикаРасходов = АналитикиЗаказов.АналитикаРасходов
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров КАК ИсточникБазы
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = ИсточникБазы.АналитикаУчетаНоменклатуры.Номенклатура)
			И (АналитикиЗаказов.Характеристика = ИсточникБазы.АналитикаУчетаНоменклатуры.Характеристика)
			И (АналитикиЗаказов.Назначение = ИсточникБазы.АналитикаУчетаНоменклатуры.Назначение)
			И (АналитикиЗаказов.Склад = ИсточникБазы.АналитикаУчетаНоменклатуры.МестоХранения)
			И (ИсточникБазы.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход))
			И (ИсточникБазы.Период < &НачалоПериода)
			И (ИсточникБазы.Организация = ДД.Организация)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаОтбора
		ПО (ИсточникБазы.АналитикаУчетаНоменклатуры = АналитикаОтбора.КлючАналитики)
ГДЕ
	(ИсточникБазы.Количество <> 0
			ИЛИ ИсточникБазы.ТипЗаписи В (ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Партия), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Потребление), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.КорректировкаСтоимости), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.КорректировкаПриобретенияПрошлогоПериода), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Перемещение), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.ПеремещениеОбособленно)))
	И &УсловиеСоединения

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"ШаблонТекстаПервичныеПриемникиПоЗаказам_2",
	ДД.Ссылка,
	ЛОЖЬ,
	ИсточникБазы.РазделУчета,
	ИсточникБазы.АналитикаУчетаНоменклатуры,
	ИсточникБазы.ВидЗапасов,
	ИсточникБазы.Организация,
	ИсточникБазы.Партия,
	ИсточникБазы.АналитикаУчетаПартий,
	ИсточникБазы.АналитикаФинансовогоУчета,
	ИсточникБазы.ВидДеятельностиНДС,
	ИсточникБазы.Количество,
	ИсточникБазы.Стоимость,
	ИсточникБазы.СтоимостьБезНДС,
	ИсточникБазы.СтоимостьРегл,
	ИсточникБазы.СтоимостьУпр,
	ИсточникБазы.СтоимостьНДД,
	ИсточникБазы.СтоимостьРегл
ИЗ
	Регистраторы КАК ДД
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыОбъектовДополнительныхРасходов КАК Группа
		ПО ДД.Ссылка = Группа.Объект
			И (Группа.НомерГруппы = &НомерГруппы)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
		ПО ДД.АналитикаРасходов = АналитикиЗаказов.АналитикаРасходов
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТКэшРасчетныеОборотыСебестоимостьТоваров КАК ИсточникБазы
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = ИсточникБазы.АналитикаУчетаНоменклатуры.Номенклатура)
			И (АналитикиЗаказов.Характеристика = ИсточникБазы.АналитикаУчетаНоменклатуры.Характеристика)
			И (АналитикиЗаказов.Назначение = ИсточникБазы.АналитикаУчетаНоменклатуры.Назначение)
			И (АналитикиЗаказов.Склад = ИсточникБазы.АналитикаУчетаНоменклатуры.МестоХранения)
			И (ИсточникБазы.СлужебноеВидДвиженияПриход)
			И (ИсточникБазы.Организация = ДД.Организация)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаОтбора
		ПО (ИсточникБазы.АналитикаУчетаНоменклатуры = АналитикаОтбора.КлючАналитики)
ГДЕ
	НЕ ИсточникБазы.Количество = 0
	И &УсловиеСоединения

 

 

Анализ

 

План запроса представлен на рисунке ниже:

https://explain.tensor.ru/archive/explain/67a42a80c5a26abc3b57e549ce181a55:0:2025-12-09#visio

 

Рис. 2 Графическое представление проблемного запроса

 

Как видно на рисунке с планом выполнения, ключевой проблемой стал оператор доступа к таблице справочника «Ключи аналитики номенклатуры». Несмотря на использование индекса, доступ организован крайне неэффективно. Это наглядно демонстрирует статистика: серверу пришлось просмотреть и отбросить почти 12 миллиардов записей (логических чтений), чтобы в итоге вернуть лишь 24 тысячи строк. Такое чудовищное соотношение — явный признак того, что выбранный для поиска индекс плохо соответствует условиям отбора, то есть является слишком «слабым» (low selectivity).

Однако возникает закономерный вопрос: в исходном тексте запроса явного соединения с этой таблицей нет. Откуда она взялась в плане?

Ответ становится очевидным при детальном анализе условий запроса. В одном из соединений используется конструкция, критически влияющая на производительность — обращение к полю через  несколько точек:

 

 
 Плохое условие соединения

 

		...
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров КАК ИсточникБазы
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = ИсточникБазы.АналитикаУчетаНоменклатуры.Номенклатура)
			И (АналитикиЗаказов.Характеристика = ИсточникБазы.АналитикаУчетаНоменклатуры.Характеристика)
			И (АналитикиЗаказов.Назначение = ИсточникБазы.АналитикаУчетаНоменклатуры.Назначение)
			И (АналитикиЗаказов.Склад = ИсточникБазы.АналитикаУчетаНоменклатуры.МестоХранения)
			И (ИсточникБазы.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход))
		...

 

 

Когда в условии используется поле через точку, платформа 1С выполняет неявное разименование. Для реквизита «АналитикаУчетаНоменклатуры» это означает: чтобы получить значение для сравнения, система в фоне подключает таблицу справочника «КлючиАналитикиНоменклатуры» (тип поля прямо указывает на это).

Чтобы увидеть реальную структуру запроса, которую обрабатывает СУБД, необходимо выполнить разименование составного поля явно. Результат этого преобразования представлен ниже. Для наглядности мы присвоили добавленной таблице псевдоним «АналитикаЧерезТочку».

 

 
 Раскроем соединение через точку вручную

 

ВЫБРАТЬ
	"ШаблонТекстаПервичныеПриемникиПоЗаказам_1" КАК ЗапросИсточник,
	ДД.Ссылка КАК Регистратор,
	ИСТИНА КАК ЭтоПартияПрошлогоПериода,
	ИсточникБазы.РазделУчета КАК РазделУчета,
	ИсточникБазы.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры,
	ИсточникБазы.ВидЗапасов КАК ВидЗапасов,
	ИсточникБазы.Организация КАК Организация,
	ИсточникБазы.Партия КАК Партия,
	ИсточникБазы.АналитикаУчетаПартий КАК АналитикаУчетаПартий,
	ИсточникБазы.АналитикаФинансовогоУчета КАК АналитикаФинансовогоУчета,
	ИсточникБазы.ВидДеятельностиНДС КАК ВидДеятельностиНДС,
	ИсточникБазы.Количество КАК Количество,
	ИсточникБазы.Стоимость КАК Стоимость,
	ИсточникБазы.СтоимостьБезНДС КАК СтоимостьБезНДС,
	ИсточникБазы.СтоимостьРегл КАК СтоимостьРегл,
	ИсточникБазы.СтоимостьУпр КАК СтоимостьУпр,
	ИсточникБазы.СтоимостьНДД КАК СтоимостьНДД,
	ИсточникБазы.СтоимостьРегл КАК СтоимостьНУ
ПОМЕСТИТЬ ТаблицаДанных
ИЗ
	Регистраторы КАК ДД
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыОбъектовДополнительныхРасходов КАК Группа
		ПО ДД.Ссылка = Группа.Объект
			И (Группа.НомерГруппы = &НомерГруппы)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
		ПО ДД.АналитикаРасходов = АналитикиЗаказов.АналитикаРасходов
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров КАК ИсточникБазы
			ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК АналитикаЧерезТочку
			ПО (АналитикаЧерезТочку.Ссылка = ИсточникБазы.АналитикаУчетаНоменклатуры)
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = АналитикаЧерезТочку.Номенклатура)
			И (АналитикиЗаказов.Характеристика = АналитикаЧерезТочку.Характеристика)
			И (АналитикиЗаказов.Назначение = АналитикаЧерезТочку.Назначение)
			И (АналитикиЗаказов.Склад = АналитикаЧерезТочку.МестоХранения)
			И (ИсточникБазы.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход))
			И (ИсточникБазы.Период < &НачалоПериода)
			И (ИсточникБазы.Организация = ДД.Организация)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаОтбора
		ПО (ИсточникБазы.АналитикаУчетаНоменклатуры = АналитикаОтбора.КлючАналитики)
ГДЕ
	(ИсточникБазы.Количество <> 0
			ИЛИ ИсточникБазы.ТипЗаписи В (ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Партия), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Потребление), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.КорректировкаСтоимости), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.КорректировкаПриобретенияПрошлогоПериода), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Перемещение), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.ПеремещениеОбособленно)))
	И &УсловиеСоединения

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"ШаблонТекстаПервичныеПриемникиПоЗаказам_2",
	ДД.Ссылка,
	ЛОЖЬ,
	ИсточникБазы.РазделУчета,
	ИсточникБазы.АналитикаУчетаНоменклатуры,
	ИсточникБазы.ВидЗапасов,
	ИсточникБазы.Организация,
	ИсточникБазы.Партия,
	ИсточникБазы.АналитикаУчетаПартий,
	ИсточникБазы.АналитикаФинансовогоУчета,
	ИсточникБазы.ВидДеятельностиНДС,
	ИсточникБазы.Количество,
	ИсточникБазы.Стоимость,
	ИсточникБазы.СтоимостьБезНДС,
	ИсточникБазы.СтоимостьРегл,
	ИсточникБазы.СтоимостьУпр,
	ИсточникБазы.СтоимостьНДД,
	ИсточникБазы.СтоимостьРегл
ИЗ
	Регистраторы КАК ДД
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыОбъектовДополнительныхРасходов КАК Группа
		ПО ДД.Ссылка = Группа.Объект
			И (Группа.НомерГруппы = &НомерГруппы)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
		ПО ДД.АналитикаРасходов = АналитикиЗаказов.АналитикаРасходов
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТКэшРасчетныеОборотыСебестоимостьТоваров КАК ИсточникБазы
			ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК АналитикаЧерезТочку
			ПО (АналитикаЧерезТочку.Ссылка = ИсточникБазы.АналитикаУчетаНоменклатуры)
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = АналитикаЧерезТочку.Номенклатура)
			И (АналитикиЗаказов.Характеристика = АналитикаЧерезТочку.Характеристика)
			И (АналитикиЗаказов.Назначение = АналитикаЧерезТочку.Назначение)
			И (АналитикиЗаказов.Склад = АналитикаЧерезТочку.МестоХранения)
			И (ИсточникБазы.СлужебноеВидДвиженияПриход)
			И (ИсточникБазы.Организация = ДД.Организация)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаОтбора
		ПО (ИсточникБазы.АналитикаУчетаНоменклатуры = АналитикаОтбора.КлючАналитики)
ГДЕ
	НЕ ИсточникБазы.Количество = 0
	И &УсловиеСоединения

 

 

Замечание! Углубляясь в анализ, мы обнаружили ещё одну проблему. В ванильной конфигурации справочник «КлючиАналитикиНоменклатуры» не имеет индексов по своим реквизитам. Существующий в базе заказчика индекс — следствие локальной доработки, а не штатная возможность.

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

 

 

Решение

 

Итак, мы выяснили причину неэффективности. План выполнения показывает, что для доступа к справочнику «Ключи аналитики номенклатуры» используется индекс по полю «Назначение», который в данном контексте обладает низкой селективностью. Идеальным решением было бы создать более селективный составной индекс.

Однако здесь мы сталкиваемся с ограничением платформы 1С: для объектов типа «Справочник» можно создавать индексы, включающие только одно основное поле плюс системное поле «Ссылка» (см. документацию ИТС). Это архитектурное ограничение не позволяет нам просто добавить нужный индекс.

Что же делать? Вспоминаем о доступных инструментах.

В конфигурации существует объект, специально предназначенный для решения подобных задач — Регистр сведений «Аналитика учета номенклатуры». В отличие от справочников, для регистров сведений платформа позволяет создавать составные индексы, включающие множество полей. Более того, одна из ключевых задач этого регистра (как мы можем предположить) — как раз повышение эффективности запросов, связанных с аналитикой.

Таким образом, сама архитектура системы подсказывает нам решение: необходимо заменить обращение к справочнику на обращение к регистру сведений, сохранив при этом исходную логику запроса.

Эта замена выполняется буквально за несколько минут и не влечет потери функциональности.

 

 
 Оптимизированный запрос

 

ВЫБРАТЬ
	"ШаблонТекстаПервичныеПриемникиПоЗаказам_1" КАК ЗапросИсточник,
	ДД.Ссылка КАК Регистратор,
	ИСТИНА КАК ЭтоПартияПрошлогоПериода,
	ИсточникБазы.РазделУчета КАК РазделУчета,
	ИсточникБазы.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры,
	ИсточникБазы.ВидЗапасов КАК ВидЗапасов,
	ИсточникБазы.Организация КАК Организация,
	ИсточникБазы.Партия КАК Партия,
	ИсточникБазы.АналитикаУчетаПартий КАК АналитикаУчетаПартий,
	ИсточникБазы.АналитикаФинансовогоУчета КАК АналитикаФинансовогоУчета,
	ИсточникБазы.ВидДеятельностиНДС КАК ВидДеятельностиНДС,
	ИсточникБазы.Количество КАК Количество,
	ИсточникБазы.Стоимость КАК Стоимость,
	ИсточникБазы.СтоимостьБезНДС КАК СтоимостьБезНДС,
	ИсточникБазы.СтоимостьРегл КАК СтоимостьРегл,
	ИсточникБазы.СтоимостьУпр КАК СтоимостьУпр,
	ИсточникБазы.СтоимостьНДД КАК СтоимостьНДД,
	ИсточникБазы.СтоимостьРегл КАК СтоимостьНУ
ПОМЕСТИТЬ ТаблицаДанных
ИЗ
	Регистраторы КАК ДД
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыОбъектовДополнительныхРасходов КАК Группа
		ПО ДД.Ссылка = Группа.Объект
			И (Группа.НомерГруппы = &НомерГруппы)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
		ПО ДД.АналитикаРасходов = АналитикиЗаказов.АналитикаРасходов
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров КАК ИсточникБазы
			ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаЧерезТочку
			ПО (АналитикаЧерезТочку.КлючАналитики = ИсточникБазы.АналитикаУчетаНоменклатуры)
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = АналитикаЧерезТочку.Номенклатура)
			И (АналитикиЗаказов.Характеристика = АналитикаЧерезТочку.Характеристика)
			И (АналитикиЗаказов.Назначение = АналитикаЧерезТочку.Назначение)
			И (АналитикиЗаказов.Склад = АналитикаЧерезТочку.МестоХранения)
			И (ИсточникБазы.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход))
			И (ИсточникБазы.Период < &НачалоПериода)
			И (ИсточникБазы.Организация = ДД.Организация)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаОтбора
		ПО (ИсточникБазы.АналитикаУчетаНоменклатуры = АналитикаОтбора.КлючАналитики)
ГДЕ
	(ИсточникБазы.Количество <> 0
			ИЛИ ИсточникБазы.ТипЗаписи В (ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Партия), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Потребление), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.КорректировкаСтоимости), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.КорректировкаПриобретенияПрошлогоПериода), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.Перемещение), ЗНАЧЕНИЕ(Перечисление.ТипыЗаписейПартий.ПеремещениеОбособленно)))
	И &УсловиеСоединения

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	"ШаблонТекстаПервичныеПриемникиПоЗаказам_2",
	ДД.Ссылка,
	ЛОЖЬ,
	ИсточникБазы.РазделУчета,
	ИсточникБазы.АналитикаУчетаНоменклатуры,
	ИсточникБазы.ВидЗапасов,
	ИсточникБазы.Организация,
	ИсточникБазы.Партия,
	ИсточникБазы.АналитикаУчетаПартий,
	ИсточникБазы.АналитикаФинансовогоУчета,
	ИсточникБазы.ВидДеятельностиНДС,
	ИсточникБазы.Количество,
	ИсточникБазы.Стоимость,
	ИсточникБазы.СтоимостьБезНДС,
	ИсточникБазы.СтоимостьРегл,
	ИсточникБазы.СтоимостьУпр,
	ИсточникБазы.СтоимостьНДД,
	ИсточникБазы.СтоимостьРегл
ИЗ
	Регистраторы КАК ДД
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыОбъектовДополнительныхРасходов КАК Группа
		ПО ДД.Ссылка = Группа.Объект
			И (Группа.НомерГруппы = &НомерГруппы)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
		ПО ДД.АналитикаРасходов = АналитикиЗаказов.АналитикаРасходов
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТКэшРасчетныеОборотыСебестоимостьТоваров КАК ИсточникБазы
			ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаЧерезТочку
			ПО (АналитикаЧерезТочку.КлючАналитики = ИсточникБазы.АналитикаУчетаНоменклатуры)
		ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
			И (АналитикиЗаказов.Номенклатура = АналитикаЧерезТочку.Номенклатура)
			И (АналитикиЗаказов.Характеристика = АналитикаЧерезТочку.Характеристика)
			И (АналитикиЗаказов.Назначение = АналитикаЧерезТочку.Назначение)
			И (АналитикиЗаказов.Склад = АналитикаЧерезТочку.МестоХранения)
			И (ИсточникБазы.СлужебноеВидДвиженияПриход)
			И (ИсточникБазы.Организация = ДД.Организация)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АналитикаУчетаНоменклатуры КАК АналитикаОтбора
		ПО (ИсточникБазы.АналитикаУчетаНоменклатуры = АналитикаОтбора.КлючАналитики)
ГДЕ
	НЕ ИсточникБазы.Количество = 0
	И &УсловиеСоединения

 

 

После внесённых изменений мы перезапустили расчёт себестоимости и проанализировали новые планы выполнения запросов. Результат говорит сам за себя: время выполнения проблемного запроса сократилось с более 11 000 секунд до ~2,5 секунд.

https://explain.tensor.ru/archive/explain/517ee459870c4b9fc00a707ef31b5be0:0:2025-12-17#visio

 

Рис. 3 План запроса, который мы оптимизировали

 

Анализ нового плана выполнения показывает, что его структура осталась практически неизменной. Основное отличие — источник данных: вместо таблицы справочника «Ключи аналитики номенклатуры» теперь используется таблица регистра сведений «Аналитика учета номенклатуры». Все условия запроса теперь полностью покрываются составным индексом регистра, что исключает лишние операции фильтрации («отброшенные записи»). В результате этот оператор выполняется максимально эффективно.

 

Заключение

 

В результате проведённой оптимизации производительность запроса увеличилась примерно в 4500 раз (11 000 с / 2,5 с).

Этот случай наглядно показывает, что следование best practices — это не «лишняя сложность», а прямая экономия времени и ресурсов на этапе эксплуатации.

Для исправления не потребовалось сложных преобразований — достаточно было:

  • Явно выполнить разименование составного поля.
  • Выбрать более подходящий источник данных (регистр сведений вместо справочника).

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

 

Это еще не все!

 

Ради интереса мы выполнили поиск в модуле "РасчетСебестоимостиПостатейныеЗатраты" по фразе ".АналитикаУчетаНоменклатуры.". Результат показал не менее двух десятков таких вхождений.

Если использование такого поля в списках выборки (ВЫБРАТЬ) относительно безопасно, то его применение в условиях фильтрации (ГДЕ) и соединениях (СОЕДИНЕНИЕ) — это потенциальные точки проблем с производительности.

Яркий пример — функция "ТекстВыпущеннаяПродукция". Её запрос содержит идентичную проблему, и предложенная нами оптимизация (явное разименование и замена источника данных) гарантированно даст аналогичный эффект — сокращение времени выполнения с часов до секунд.

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

 

Возможности и компромиссы: как исправить всё «здесь и сейчас»?

 

Резонный вопрос: можно ли массово исправить все подобные места быстро, не прибегая к масштабному рефакторингу?

Ключ к решению — новые возможности платформы. Поскольку используемая версия ERP требует платформы 8.3.27 и выше, у нас появляется мощный инструмент: возможность создания произвольных индексов для справочников и других прикладных объектов. Доступно только для КОРП лицензий.

Это позволяет реализовать элегантный «костыль»: мы можем превратить справочник «Ключи аналитики номенклатуры» в подобие регистра сведений, снабдив его составными индексами, точно соответствующими нашим частым запросам.

Инструкция: добавление составного индекса в справочник (см. рис. 4)

  1. Откройте конфигуратор и найдите справочник «КлючиАналитикиНоменклатуры».
  2. Перейдите в его свойства и откройте форму «Дополнительные индексы».
  3. Создайте новый индекс. В перечень индексируемых полей добавьте поля, участвующие в условиях соединения:
    • Номенклатура
    • Характеристика
    • Назначение
    • МестоХранения
  4. Рекомендация: Для максимальной эффективности расположите поля в порядке убывания селективности. В большинстве сценариев оптимальным будет порядок: «Номенклатура, Характеристика, ...», так как отборы по этим полям встречаются чаще всего.

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

 

Рис. 4 Создание дополнительных индексов для справочника «Аналитика учета номенклатуры»

 

Более того, анализ показывает, что набор индексов в регистре сведений «Аналитика учета номенклатуры» немного избыточен. Мы можем создать точечные, более эффективные индексы прямо в справочнике, которые покроют все критические сценарии использования поля «АналитикаУчетаНоменклатуры» в условиях отбора.

Мы не поленились и выполнили тест расчета себестоимости с учетом дополнительных индексов и первоначальным запросом.

https://explain.tensor.ru/archive/explain/edb2d0e0dc8d67feff52a06279be5ed6:0:2025-12-21#visio

Время выполнения составило 3,9 с, что в сравнении с первоначальной ситуацией выглядит также великолепно.

Рис. 5 План запроса (используем дополнительные индексы)

Как видно на последнем плане выполнения, доступ к данным теперь осуществляется через индексную таблицу справочника «Ключи аналитики номенклатуры» и выполняется эффективно. Небольшое увеличение времени (по сравнению с вариантом, где был выполнен предыдущий оптимальный расчёт себестоимости) связано с изменением структуры плана запроса и состоянием данных (расчет себестоимости завершился успешно). Тем не менее, текущий вариант оптимизации полностью работоспособен и даёт приемлемый результат.

Плюсы индексации справочника:

  • Быстро: Не нужно менять код запросов, эффект мгновенный.
  • Локально: Все правки — только в структуре объекта.

Минус:

  • Это костыль. Правильнее использовать регистры сведений (в рамках текущей архитектуры).

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

 


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

Вступайте в нашу телеграмм-группу Инфостарт

См. также

HighLoad оптимизация Программист 1С 8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

Использование оператора «В» для полей или данных составного типа (например, Регистратор) может приводить к неочевидным проблемам.

10.11.2025    5746    ivanov660    48    

51

HighLoad оптимизация Программист 1С:Предприятие 8 1C:ERP Бесплатно (free)

Приведем примеры использования различных в динамических списках и посмотрим, почему это плохо.

18.02.2025    8420    ivanov660    39    

61

HighLoad оптимизация Технологический журнал Системный администратор Программист Бесплатно (free)

Обсудим поиск и разбор причин длительных серверных вызовов CALL, SCALL.

24.06.2024    10815    ivanov660    13    

64

HighLoad оптимизация Программист 1С:Предприятие 8 Бесплатно (free)

Метод очень медленно работает, когда параметр приемник содержит намного меньше свойств, чем источник.

06.06.2024    16853    Evg-Lylyk    73    

46

HighLoad оптимизация Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    8312    spyke    29    

54

HighLoad оптимизация Программист 1С:Предприятие 8 Бесплатно (free)

Оказывается, в типовых конфигурациях 1С есть, что улучшить!

13.03.2024    11665    vasilev2015    22    

47
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ildary 21 22.12.25 10:07 Сейчас в теме
Как всегда, материал прекрасно написан и весьма полезен!
Прошу Вас, продолжайте писать и радовать нас
sapervodichka; user1948730; shu_vol; G.Shatrov; ardn; ivanov660; +6 Ответить
2. ardn 731 22.12.25 11:04 Сейчас в теме
Отличная статья. Надо еще зарегистрировать ошибку, это же явно ошибка - соединяться со справочником, когда у нас есть специальный регистр.
zqzq; user1948730; shu_vol; G.Shatrov; +4 Ответить
4. ivanov660 4918 22.12.25 11:49 Сейчас в теме
(2) Я передал информацию в 1С, дальше зависит от них, примут они или нет
sapervodichka; user1948730; shard; ardn; +4 Ответить
3. G.Shatrov 152 22.12.25 11:32 Сейчас в теме
Владимир, спасибо большое за статью!
Хотел бы отметить, что использование Дополнительных индексов возможно при условии наличия КОРП лицензии
5. ivanov660 4918 22.12.25 12:00 Сейчас в теме
(3) Да, доступно только в корп, поправлю в статье
6. G.Shatrov 152 22.12.25 12:02 Сейчас в теме
(5) Спасибо!
Просто они то добавятся, и даже работать будет. А когда одновременно зайдет 10+ сеансов - поймают неприятную ошибку по лицензии.
7. ivanov660 4918 22.12.25 12:11 Сейчас в теме
(6) Может когда-нибудь 1С передаст в проф возможность создания составных индексов, это выглядит логично. К тому же некоторые вещи будут тормозить и при 10 пользователях, учитывая отсутствие следования best practices . Хотя с другой стороны у нас есть pgAdmin или аналоги.
8. ivanov660 4918 22.12.25 15:17 Сейчас в теме
(7)
Я тут подумал и пообщался с коллегами - зря этот функционал разработчики платформы исключили из нормальных инструментов разработки. Что в свою очередь бы позволило писать более быстро работающие конфигурации и упрощать код конфигураций. Иными словами поместить в коробочное решение каждой конфигурации - на примере справочников ключей аналитик и регистров аналитик. Т.е. , на мой взгляд, самим себе мешают разрабатывать тиражные решения.
А в таком варианте КОРП решений мало кто будет использовать подобный функционал, учитывая что до этого и так обходились.
zqzq; sapervodichka; pkorneenko; +3 Ответить
9. gybson 22.12.25 19:27 Сейчас в теме
Хорошо бы убрать кастомный индекс и посмотреть какой тогда будет использоваться и как.

Про "разыменование точки" какая точно в итоге с этим проблема то? Вы же сами пишете, что индексов не было, А когда добавил, так и через точку нормально заработало.

Все это здорово, но почему-то итог всегда один : "все оказалось даже и не так".
10. ivanov660 4918 22.12.25 19:37 Сейчас в теме
(9)
1. Никакой не будет использоваться, будет просто скан таблицы.
2. Все достаточно прозрачно
Viktor_Ermakov; +1 Ответить
11. gybson 22.12.25 21:03 Сейчас в теме
(10) Мне кажется вы слишком легко переиграли 1С. Какой-то тут подвох. Может быть по кластерному индексу будет быстрый поиск по номенклатура+характеристика, например.

У меня сейчас нет под рукой ERP и УТ, к сожалению. Но у вас то уже все настроено.
12. gybson 22.12.25 21:25 Сейчас в теме
(11) Пусть даже скан таблицы по фильтру, там же дальше он в схеме все-равно происходит.
15. ivanov660 4918 22.12.25 22:56 Сейчас в теме
(11)
1. Вы явно заблуждаетесь в особенностях работы операторов индексного сканирования и последовательного сканирования.
А также тому что из себя представляет кластерный индекс справочника. Специально привожу ссылку на ИТС https://its.1c.ru/db/metod8dev/content/1590/hdoc..
2. Если будет свободное время я попробую запустить, но сильно сомневаюсь что смогу дождаться результата. Какие-то запросы до изначальной оптимизации работали более суток, а стенд на большее время мне могут и не дать.
Viktor_Ermakov; +1 Ответить
16. gybson 22.12.25 23:39 Сейчас в теме
(15) Может сообщество поможет.

Вы кажется в прошлой статье уже сталкивались с назначением. А до того сталкивались с плохими индексами.

https://infostart.ru/1c/articles/2299790/?ysclid=mjhm5qsygn34900677

Как будто ходите по одним и тем же граблям по кругу.
20. ivanov660 4918 23.12.25 08:31 Сейчас в теме
(16)
1. В каждой своей статье я стараюсь привести уникальный случай ситуации, проблемы или оптимизации. Поэтому нет я не хожу по кругу и не заблудился в трех соснах. А то что поля иногда звучат одинаково, то это говорит о том что они наиболее часто востребованы в работе ЕРП.
2. Очень здорово видеть что вы пытаетесь разобраться в проблеме. Возможно вы этого еще не осознаете, но практически вся оптимизация строится вокруг индексов.
Viktor_Ermakov; +1 Ответить
18. a.doroshkevich 1366 23.12.25 02:51 Сейчас в теме
(11)
Добрый день
Кластерный индекс в postgresql это совсем не то что в MS sql.
Это просто индекс, он не включает в себя неиндексируеиые поля.
А кластерным называется потому что именно по нему будет произведена процедура cluster при ее запуске (что уже почти не используется на flash накопителях)
При этом в MS sql кластерный индекс вклбчает в себя как индексируемые так и неиндексируемые поля м поэтому там поиск по нему может быть эффективнее.

Применение доп индекса с доп полями или без это отличное решение, крайне безопасное, так как не требует изменение логики запросов ну и все остальные плюсы что описал автор статьи
22. gybson 23.12.25 09:43 Сейчас в теме
(18) ну вот индекс по назначению оказался опасным
и вопрос с точкой в запросе опять повис неловко
23. a.doroshkevich 1366 23.12.25 09:44 Сейчас в теме
(22)
ну вот индекс по назначению оказался опасным


чем?
27. gybson 23.12.25 13:14 Сейчас в теме
(23) данная статья об этом написана
сканирование по нему долгое (да и бесполезное)
28. a.doroshkevich 1366 23.12.25 13:20 Сейчас в теме
(27) стать ровно об обратном или мы читаем с вами разные статьи
Так как речь о доп индексе в корп платформе, а не о том который добавили в проф
29. gybson 23.12.25 15:28 Сейчас в теме
(28) вот самая первая схема запроса, там сканирование индекса очень долгое
одна из прошлых статей автора - индекс убил производительность

Соответственно первая и самая простая гипотеза - убрать вот этот самый индекс, которого ни у кого нет и который делает эту проблему уникальной, с которой никто больше не столкнулся и которую решать и не надо, достаточно не создавать.

Вот это все, что есть содержательного. Зачем опять эти "черезточки" в заголовок выносить, они и в прошлый раз были ни при чем. И в этот раз опять, стали переделывать соединение на явное и опять дело оказалось не в нем. Сумбур. По сути лучше бы из трех статей сделать одну и сразу обозначить постгр подробнее.

Ну давайте напишем статью как Бухгалтерия жрет память, долго будем чет искать и только в самом конце обозначим, что это их кретинский баннер на форме списка реализаций так себя ведет.
30. ivanov660 4918 23.12.25 16:02 Сейчас в теме
(29) Предлагаю вам почитать матчасть, прежде чем делать необоснованные заявления.

Возьмем рекомендации от компании 1С "Эффективные условия запросов"(
https://its.1c.ru/db/v8std/content/658/hdoc), которые они по идее должны соблюдать.

1. Условия запросов должны быть написаны оптимально с точки зрения производительности, чтобы исключить существенное увеличение длительности выполнения запросов при увеличении объема данных в таблицах.

...
Для условий в ПО ЛЕВОГО соединения следует индексировать поля в правой таблице.


Берем сам запрос и смотрим как тут получается:

ВНУТРЕННЕЕ СОЕДИНЕНИЕ АналитикиЗаказов КАК АналитикиЗаказов
...
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК АналитикаЧерезТочку
ПО (АналитикаЧерезТочку.Ссылка = ИсточникБазы.АналитикаУчетаНоменклатуры)
ПО (АналитикиЗаказов.РегистраторСебестоимости = ИсточникБазы.Регистратор)
И (АналитикиЗаказов.Номенклатура = АналитикаЧерезТочку.Номенклатура)
И (АналитикиЗаказов.Характеристика = АналитикаЧерезТочку.Характеристика)
И (АналитикиЗаказов.Назначение = АналитикаЧерезТочку.Назначение)
И (АналитикиЗаказов.Склад = АналитикаЧерезТочку.МестоХранения)
И (ИсточникБазы.СлужебноеВидДвиженияПриход)
И (ИсточникБазы.Организация = ДД.Организация)


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

И как раз когда разработчик в изначальном запросе строит условия соединения через точку, то как раз не прозрачно выглядит что с чем соединяется фактически.
13. gybson 22.12.25 21:37 Сейчас в теме
В результатах различное количество записей, 3266 и 3380, это я первый план и второй сравнил. Перепроверить бы.
14. ivanov660 4918 22.12.25 22:48 Сейчас в теме
(13) Я написал, что тесты запускались через некоторые интервалы, а не из нулевой системы. Поэтому ожидаемо что данные слегка будут отличаться.
17. gybson 22.12.25 23:39 Сейчас в теме
(14) 2 и 3 тесты совпадают
19. a.doroshkevich 1366 23.12.25 02:53 Сейчас в теме
Владимир, спасибо за расследование и за то что делишься результатами с сообществом, а не просто обладаешь тайным знаниями и приёмами кунг фу!
Viktor_Ermakov; ivanov660; +2 Ответить
21. ivanov660 4918 23.12.25 08:34 Сейчас в теме
(19)
1. Спасибо за отзыв.
2. Посмотрим будет ли это действительно полезно. О проблеме меня попросили написать сразу несколько коллег, надеюсь я буду услышан. Если эта статья позволит сдвинуть с мертвой точки подход в разработке тиражных решений в области оптимизации, то я действительно буду считать что не зря потратил время.
24. Viktor_Ermakov 394 23.12.25 09:46 Сейчас в теме
Время точно потрачено не зря.
Сдвинуть подход не получится в разработке тиражных решений.
Но какое то количество людей точно возьмет на заметку.
Спасибо!
25. Viktor_Ermakov 394 23.12.25 09:47 Сейчас в теме
Владимир, скажите а принскрины плана запроса, это из какого приложения?
Спасибо!
26. a.doroshkevich 1366 23.12.25 10:30 Сейчас в теме
(25)
Такое можно получить на сайте https://explain.tensor.ru/
ivanov660; +1 Ответить
Для отправки сообщения требуется регистрация/авторизация