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

18.02.25

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

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

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

 

Структура статьи

  • Обсуждение проблемы
  • Демонстрация теории на простом примере
  • Анализ текущей ситуации
  • Исправление
    • Вариант 1
    • Вариант 2
    • Это еще не все, дополнительные действия
  • Заключение

 

1) Обсуждение проблемы

 

Во время очередного анализа проблем с производительностью мы обнаружили ряд длительных запросов. В процессе изучения выяснилось, что проблема связана с АРМ "РабочееМестоМенеджераПоДоставке" и динамическим списком на основной форме "ЗаданияНаПеревозкуВРаботе".

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

 

Рис. Изображение АРМ Доставка

 

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

Запрос выглядит вот так:

 
 Запрос динамического списка - задания на перевозку в работе

 

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ДокументЗаданиеНаПеревозку.Ссылка,
	ДокументЗаданиеНаПеревозку.ПометкаУдаления,
	ДокументЗаданиеНаПеревозку.Номер,
	ДокументЗаданиеНаПеревозку.Дата,
	ДокументЗаданиеНаПеревозку.Проведен,
	ВЫРАЗИТЬ(ДокументЗаданиеНаПеревозку.ДополнительнаяИнформация КАК СТРОКА(1000)) КАК ДополнительнаяИнформация,
	ДокументЗаданиеНаПеревозку.Статус,
	ВЫРАЗИТЬ(ДокументЗаданиеНаПеревозку.Комментарий КАК СТРОКА(1000)) КАК Комментарий,
	ДокументЗаданиеНаПеревозку.Ответственный,
	ДокументЗаданиеНаПеревозку.ДатаВремяРейсаПланС,
	ДокументЗаданиеНаПеревозку.ДатаВремяРейсаПланПо,
	ДокументЗаданиеНаПеревозку.ДатаВремяРейсаФактС,
	ДокументЗаданиеНаПеревозку.ДатаВремяРейсаФактПо,
	ДокументЗаданиеНаПеревозку.ТранспортноеСредство,
	ДокументЗаданиеНаПеревозку.КурьерЭкспедитор,
	ДокументЗаданиеНаПеревозку.Водитель,
	ДокументЗаданиеНаПеревозку.Склад,
	ДокументЗаданиеНаПеревозку.Вес,
	ДокументЗаданиеНаПеревозку.Объем,
	ДокументЗаданиеНаПеревозку.КоличествоПунктов,
	ДокументЗаданиеНаПеревозку.Приоритет,
	ДокументЗаданиеНаПеревозку.Операция,
	ВЫБОР
		КОГДА ДокументЗаданиеНаПеревозку.ЗаданиеВыполняет = ЗНАЧЕНИЕ(Перечисление.ТипыИсполнителейЗаданийНаПеревозку.НашаТранспортнаяСлужба)
			ТОГДА 1
		ИНАЧЕ 0
	КОНЕЦ КАК ЭтоНашаДоставка,
	ДокументЗаданиеНаПеревозку.ЗаданиеВыполняет
ИЗ
	Документ.ЗаданиеНаПеревозку КАК ДокументЗаданиеНаПеревозку
		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаданиеНаПеревозку.Маршрут КАК ЗаданиеНаПеревозкуМаршрут
		ПО (ЗаданиеНаПеревозкуМаршрут.Ссылка = ДокументЗаданиеНаПеревозку.Ссылка)
{ГДЕ
	ЗаданиеНаПеревозкуМаршрут.Зона.*}

 

 

В данном запросе меня смущает использование ключевого слова РАЗЛИЧНЫЕ. Зачем разработчики его добавили? Давайте разберемся.

Если внимательно изучить запрос и форму АРМ, можно заметить, что на форме реализован отбор по зоне. Однако поле "Зона" отсутствует в шапке документа "Задание на перевозку" — оно находится в табличной части "Маршрут". Именно поэтому разработчики добавили соединение с этой табличной частью.

Но здесь возникает проблема: после соединения с табличной частью высока вероятность появления дублей по ключевому полю "Ссылка". Это, в свою очередь, может привести к некорректной работе динамического списка. Чтобы избежать дублирования строк и обеспечить корректное функционирование списка, необходимо исключить дубли. Именно для этой цели и используется ключевое слово РАЗЛИЧНЫЕ.

На первый взгляд, в коде запроса явного отбора нет, но он добавляется динамически в процессе работы системы. 

 
 Код динамического добавления отбора по полю зона

 

	Если ЗонаГруппаИлиПустая Тогда
		ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(ЗаданияНаПеревозкуВРаботе,
			"Зона", Зона, ВидСравненияКомпоновкиДанных.ВИерархии,,ЗначениеЗаполнено(Зона));
	Иначе
		ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(ЗаданияНаПеревозкуВРаботе,
			"Зона", Зона, ВидСравненияКомпоновкиДанных.Равно,,Истина);
	КонецЕсли;

 

 

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

 

2) Демонстрация теории на простом примере

 

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

Одно из замечательных свойств динамического списка — это возможность получения данных небольшими порциями. Платформа 1С автоматически добавляет ограничение на количество записей при формировании SQL-запроса. Например, для MS SQL она добавляет TOP 45, а для PostgreSQL — LIMIT 45 (в динамических списках с динамическим считыванием). Если динамическое считывание отключено, то по умолчанию выбираются первые 1000 записей.

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

Рассмотрим это на примере. Предположим, в моей демонстрационной базе данных находится около 800 тысяч заказов клиентов. Я могу выполнить простой запрос.

 
 Простой запрос выбора данных

 

ВЫБРАТЬ 
	ЗаказКлиента.Ссылка КАК Ссылка,
	ЗаказКлиента.Номер КАК Номер,
	ЗаказКлиента.Дата КАК Дата
ИЗ
	Документ.ЗаказКлиента КАК ЗаказКлиента

 

 

В результате я получу на клиенте огромную таблицу данных, которая, по сути, мне не нужна. Сложно представить человека, который будет вручную просматривать все 800 тысяч записей. Скорее всего, вы воспользуетесь фильтром или отбором, чтобы найти нужную информацию. Именно поэтому использование таких «голых» запросов без ограничений в реальной практике не имеет смысла — это неэффективно и создает излишнюю нагрузку на систему.

План запроса: https://explain.tensor.ru/archive/explain/5aedc4e3813f6f6b13325321e3637163:0:2025-02-15#visio

 

 

План выполнения запроса выглядит достаточно просто. Мы видим, что данные выбираются из источника — таблицы заказов клиентов, причем выбираются все строки (см. rows). На первый взгляд, это может показаться быстрым, но в реальной жизни обычно на процесс выборки накладываются ограничения RLS (Row-Level Security — безопасность на уровне строк), что значительно увеличивает время выполнения запроса.

Об особенностях работы RLS и его влиянии на производительность я расскажу в отдельной статье, так что оставайтесь на связи!

Теперь, если я добавлю в запрос ограничение как в динамическом списке (например, ПЕРВЫЕ 45), то получу только небольшую порцию данных. В этом случае запрос будет выглядеть следующим образом:

 
 Запрос имитации динамического списка

 

ВЫБРАТЬ ПЕРВЫЕ 45
	ЗаказКлиента.Ссылка КАК Ссылка,
	ЗаказКлиента.Номер КАК Номер,
	ЗаказКлиента.Дата КАК Дата
ИЗ
	Документ.ЗаказКлиента КАК ЗаказКлиента

 

 

Такой запрос выполняется практически мгновенно. Теперь давайте взглянем на план выполнения этого запроса.

План запроса: https://explain.tensor.ru/archive/explain/e4a61626ee6f9a1b5b5ba7b038be558c:0:2025-02-15#visio

 

 

Как мы видим, из источника данных выбирается ровно 45 записей, что выполняется крайне быстро. По сравнению с предыдущим запросом, где выбирались все данные, разница в производительности составляет почти 3 000 раз. Выглядит это действительно впечатляюще.

Если говорить точнее, такой подход с использованием ключевого слова ПЕРВЫЕ работает следующим образом: система начинает выбирать записи из таблицы, и как только количество выбранных записей достигает установленного ограничения (в нашем случае — 45), выполнение запроса в СУБД завершается. Это позволяет значительно сократить время выполнения и снизить нагрузку на систему.

Теперь добавим ключевое слово РАЗЛИЧНЫЕ в исходный запрос. Не стоит искать в этом какого-то глубокого смысла — это просто шаг для нашего расследования.

 
 Добавили различные в запрос

 

ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 45
	ЗаказКлиента.Ссылка КАК Ссылка,
	ЗаказКлиента.Номер КАК Номер,
	ЗаказКлиента.Дата КАК Дата
ИЗ
	Документ.ЗаказКлиента КАК ЗаказКлиента

 

 

План запроса: https://explain.tensor.ru/archive/explain/f1a8d36ec88be5a94e0fd6019f83e792:0:2025-02-15#visio
 

 

Как мы видим, в результате выбирается 45 записей (операторы #1 и #3, см. rows), но при этом СУБД вынуждена прочитать всю таблицу заказов клиентов (оператор #2) чтобы найти различные. В итоге такой запрос выполняется даже дольше, чем первый вариант, — примерно в 3 раза, несмотря на то что мы получили всего 45 записей.

Почему это происходит? Чтобы наглядно объяснить, приведу пример. Представим, что у нас есть таблица с миллионом записей (или даже больше), и все записи в ней содержат всего три слова: «мяч», «лопата» и «собака».

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

 

 

Но нам не нужны дубли. Для этого мы должны использовать РАЗЛИЧНЫЕ. В результате получим не более трех уникальных значений: «мяч», «лопата» и «собака». На рисунке ниже показана схема работы ключевого слова РАЗЛИЧНЫЕ и то, как оно фильтрует дублирующиеся данные.

 

 

Мы можем сделать вывод, что при использовании ключевого слова РАЗЛИЧНЫЕ, даже несмотря на ограничение выборки (ПЕРВЫЕ), система все равно вынуждена просматривать всю исходную таблицу. Это происходит потому, что для определения уникальности значений необходимо проанализировать все данные.

Таким образом, эффективность использования ПЕРВЫХ теряется, так как СУБД все равно выполняет полное сканирование таблицы. Единственное, чего мы достигаем, — это уменьшение количества передаваемых записей на клиент, что лишь частично снижает нагрузку на канал передачи данных.

В некоторых случаях, когда вы используете ключевое слово РАЗЛИЧНЫЕ для получения уникальных записей, это может указывать на наличие проблемы — либо в самом запросе, либо в архитектуре приложения.

 

3) Анализ текущей проблемы

 

Продолжим разбор нашей проблемы. Исходя из вышесказанного, мы понимаем, что использование оператора РАЗЛИЧНЫЕ снижает эффективность работы динамического списка. Чтобы лучше понять масштаб проблемы, давайте посмотрим на время выполнения и план запроса. Эти данные понадобятся нам для сравнения с результатами оптимизации.

Для выполнения анализа воспользуемся консолью запросов. Чтобы приблизить условия к реальным, добавим в запрос ключевое слово ПЕРВЫЕ 45.

 
 Исходный запрос с добавлением первых 45

 

ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 45
	ДокументЗаданиеНаПеревозку.Ссылка,
	ДокументЗаданиеНаПеревозку.ПометкаУдаления,
	ДокументЗаданиеНаПеревозку.Номер,
	ДокументЗаданиеНаПеревозку.Дата,
	ДокументЗаданиеНаПеревозку.Статус
	
ИЗ
	Документ.ЗаданиеНаПеревозку КАК ДокументЗаданиеНаПеревозку
		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаданиеНаПеревозку.Маршрут КАК ЗаданиеНаПеревозкуМаршрут
		ПО (ЗаданиеНаПеревозкуМаршрут.Ссылка = ДокументЗаданиеНаПеревозку.Ссылка)
{ГДЕ
	ЗаданиеНаПеревозкуМаршрут.Зона.*}

 

 

 
 SQL представление

 

Время выполнения этого запроса на демонстрационной базе заняло около 5 с.

План запроса: https://explain.tensor.ru/archive/explain/320bd4aca448011918865a3310b77591:0:2025-02-12#visio

 

 

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

 

4) Исправления запроса

 

Нам необходимо исправить запрос. А именно — избавиться от ключевого слова РАЗЛИЧНЫЕ. Исходя из логики предыдущего запроса, нам нужно получить список заданий на перевозку, в которые входит выбранная зона. Другими словами, мы добавили РАЗЛИЧНЫЕ и соединение с табличной частью Маршруты только для того, чтобы реализовать возможность отбора по зоне.

Избавиться от РАЗЛИЧНЫЕ и при этом сохранить отбор можно несколькими способами. Что интересно, тексты запросов на языке 1С будут различаться, но их преобразование в SQL-текст окажется одинаковым.

 

Первый вариант

 

Мы удаляем соединение с табличной частью Маршруты, но добавляем в секцию ГДЕ отбор по условию, связанному с табличной частью через ссылку. Пример такого запроса приведен ниже.

 
 Исправленный запрос - вариант 1

 

ВЫБРАТЬ ПЕРВЫЕ 45
	ДокументЗаданиеНаПеревозку.Ссылка КАК Ссылка,
	ДокументЗаданиеНаПеревозку.Номер КАК Номер,
	ДокументЗаданиеНаПеревозку.Дата КАК Дата,
	ДокументЗаданиеНаПеревозку.Статус КАК Статус
ИЗ
	Документ.ЗаданиеНаПеревозку КАК ДокументЗаданиеНаПеревозку
ГДЕ
	ДокументЗаданиеНаПеревозку.Ссылка.Маршрут.Зона В(&Зона)

 

 

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

 

SELECT
T1.Ссылка,
T1.Номер,
T1.Дата,
T1.Статус
FROM Документ.ЗаданиеНаПеревозку T1
LEFT OUTER JOIN Документ.ЗаданиеНаПеревозку.Маршрут T2
ON ((T2.Ссылка = T1.Ссылка)) AND (T2.ОбластьДанныхОсновныеДанные = CAST(0 AS NUMERIC))
WHERE ((T1.ОбластьДанныхОсновныеДанные = CAST(0 AS NUMERIC))) AND ((T2.Зона IN ('\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000'::bytea))) LIMIT 45

 

 

План запроса: https://explain.tensor.ru/archive/explain/ff019c7079075007f0da4dbdf746bdda:0:2025-02-12#visio

 

 

Время выполнения запроса составило около 4 мс. Выбирается 45 записей, и план запроса выглядит достаточно оптимально. В итоге запрос выполняется в 1 000 раз быстрее. Но, это не единственное решение, есть еще один вариант. Его рассмотрим чуть ниже.

 

Второй вариант

 

Теперь рассмотрим второй вариант формирования отбора с использованием оператора EXISTS. Для этого нам нужно добавить нестандартный отбор, основанный на связи основной таблицы с таблицей Маршруты внутри оператора В. Пример такого запроса вы можете увидеть ниже.

 
 Исправленный запрос - вариант 2

 

ВЫБРАТЬ ПЕРВЫЕ 45
	ДокументЗаданиеНаПеревозку.Ссылка КАК Ссылка,
	ДокументЗаданиеНаПеревозку.Номер КАК Номер,
	ДокументЗаданиеНаПеревозку.Дата КАК Дата,
	ДокументЗаданиеНаПеревозку.Статус КАК Статус 
ИЗ
	Документ.ЗаданиеНаПеревозку КАК ДокументЗаданиеНаПеревозку
ГДЕ
	42 В
			(ВЫБРАТЬ ПЕРВЫЕ 1
				42
			ИЗ
				Документ.ЗаданиеНаПеревозку.Маршрут КАК ЗаданиеНаПеревозкуМаршрут
			ГДЕ
				ЗаданиеНаПеревозкуМаршрут.Ссылка = ДокументЗаданиеНаПеревозку.Ссылка
				И ЗаданиеНаПеревозкуМаршрут.Зона В (&Зона))

 

 

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

 

SELECT
T1.Ссылка,
T1.Номер,
T1.Дата,
T1.Статус
FROM Документ.ЗаданиеНаПеревозку T1
WHERE ((T1.ОбластьДанныхОсновныеДанные = CAST(0 AS NUMERIC))) AND (EXISTS(SELECT
CAST(42 AS NUMERIC) AS Q_002_F_000_
FROM Документ.ЗаданиеНаПеревозку.Маршрут T2
WHERE ((T2.ОбластьДанныхОсновныеДанные = CAST(0 AS NUMERIC))) AND ((T2.Ссылка = T1.Ссылка) AND (T2.Зона IN ('\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000'::bytea))))) LIMIT 45

 

 

Обратите внимание: несмотря на то что оба запроса на языке 1С выглядят по-разному, их преобразование в SQL-синтаксис оказывается одинаковым. Соответственно и планы запросов получились одинаковые.

План запроса: https://explain.tensor.ru/archive/explain/54de1f45f58d83a7a5f5835de1426def:0:2025-02-12#visio

 

Это еще не окончательное решение!

 

Мы должны проверить различные условия отборов, чтобы понять, как они влияют на запрос. Однако в результате мы можем столкнуться с неожиданным поведением. Например, если в качестве значения отбора выбрать что-то отличное от пустого, скажем, "Москва", то план выполнения запроса значительно изменится и станет таким:

https://explain.tensor.ru/archive/explain/f5360593bd779aa63b3975ad1bd22aad:0:2025-02-12#visio

 

 

Если сейчас мы сравним время выполнения неоптимизированного запроса с оптимизированными, то увидим, что существенного прироста производительности не наблюдается. В чем же причина?

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

В случае, когда значение зоны было пустым, планировщик запросов использовал в качестве источника данных кластерный индекс табличной части "Маршруты". Пустые значения составляли около 90% данных.

Во втором случае, когда я выбрал зону "Москва", документов с таким значением оказалось значительно меньше. В результате планировщик выбрал в качестве лидирующей таблицы "Маршруты". Однако поле "Зона" в этой таблице не проиндексировано, поэтому планировщик вынужден сначала сканировать всю таблицу (см. оператор #4) для отбора подходящих записей, и только потом выполнять соединение с другими таблицами. А это естественно не эффективно.

Внимание! Должна быть индексация по полям, которые находятся в отборах. Не обязательно для всех полей, а только для наиболее релевантных. Это отдельная большая тема, поэтому оставим за рамками этой статьи.

Нам нужно установить индексирование. Добавим индексацию на поле "Зона". После этого запрос начинает выполняться практически мгновенно.

План запроса: https://explain.tensor.ru/archive/explain/57a102297fba4dd0cfecdd68b359622b:0:2025-02-12#visio

 

 

Как мы видим, теперь используется индекс (см. оператор #3), и выборка данных выполняется наиболее оптимальным способом. В результате наш запрос стал выполняться практически в 75 000 раз быстрее.

Однако самое интересное заключается в том, что на практике запросы часто выполняются с учетом RLS (Row-Level Security), и в таких случаях добавление индекса становится еще более критичным. Конечно, степень улучшения производительности зависит от конкретных данных, которые хранятся в вашей базе.

Исходный запрос с учетом ограничений RLS – время выполнения 6,5 с
https://explain.tensor.ru/archive/explain/9d932e050003b374b1edcd148b2b9fc5:0:2025-02-15#visio

Оптимизированный запрос с RLS - время выполнения 1,4 мс
https://explain.tensor.ru/archive/explain/d5dc33888cc4b5fc72f83aeef5dcc431:0:2025-02-15#visio

 

5) Заключение

 

Использование ключевого слова РАЗЛИЧНЫЕ в динамических списках может быть полезным для устранения дубликатов, однако оно часто приводит к значительному снижению производительности. Основная проблема заключается в том, что для определения уникальности записей система вынуждена сканировать всю таблицу или её значительную часть, даже если в запросе указано ограничение на количество строк (например, ПЕРВЫЕ 45). Это сводит на нет преимущества динамической загрузки данных небольшими порциями.

Кроме того, использование РАЗЛИЧНЫЕ может указывать на проблемы в архитектуре запроса или данных. Однако бывают случаи, когда подобный подход действительно необходим для решения конкретной задачи. В таких ситуациях все же стоит тщательно пересмотреть своё решение и оценить, можно ли достичь цели более эффективным способом.

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

Думаю, Вам будет интересно ознакомиться с другими моими статьями по исправлению ошибок и повышению производительности - другие публикации.

 

P.S. К сожалению, складывается впечатление, что разработчики конфигурации не читают статьи на этом замечательном сайте и, судя по всему, вообще не интересуются проблемами высокопроизводительных систем. Я давно разочаровался в личном общении с поддержкой — кроме лишней и бессмысленной работы с моей стороны, это редко приводит к каким-то результатам.

С другой стороны, при каждой новой встрече с "замечательной" конфигурацией ERP выполнять одни и те же оптимизационные мероприятия уже порядком надоело.

См. также

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

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

24.06.2024    6297    ivanov660    12    

56

HighLoad оптимизация Программист Платформа 1С v8.3 Бесплатно (free)

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

06.06.2024    10875    Evg-Lylyk    61    

45

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

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

13.03.2024    5760    spyke    28    

51

HighLoad оптимизация Программист Платформа 1С v8.3 Бесплатно (free)

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

13.03.2024    8595    vasilev2015    20    

43

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист Платформа 1С v8.3 1C:Бухгалтерия Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

2 стартмани

15.02.2024    14014    276    ZAOSTG    87    

118

HighLoad оптимизация Системный администратор Программист Платформа 1С v8.3 1C:Бухгалтерия Абонемент ($m)

Принимать, хранить и анализировать показания счетчиков (метрики) в базе 1С? Почему бы нет? Но это решение быстро привело к проблемам с производительностью при попытках построить какую-то более-менее сложную аналитику. Переход на PostgresSQL только временно решил проблему, т.к. количество записей уже исчислялось десятками миллионов и что-то сложное вычислить на таких объемах за разумное время становилось все сложнее. Кое-что уже практически невозможно. А что будет с производительностью через пару лет - представить страшно. Надо что-то предпринимать! В этой статье поделюсь своим первым опытом применения СУБД Clickhouse от Яндекс. Как работает, что может, как на нее планирую (если планирую) переходить, сравнение скорости работы, оценка производительности через пару лет, пример работы из 1С. Все это приправлено текстами запросов, кодом, алгоритмами выполненных действий и преподнесено вам для ознакомления в этой статье.

1 стартмани

24.01.2024    6666    glassman    20    

42
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Xershi 1262 18.02.25 16:57 Сейчас в теме
Добрый день, так я что-то не понял вы не довольны что есть работа, за которую заплатят ещё раз?
А по поводу ТП обычно принимают проблемы к исправлению, вопрос только через сколько лет+)))
Но если не писать им так и исправлять не будут.
3. ivanov660 4685 18.02.25 19:08 Сейчас в теме
(1)
1. Ну, вот такой я какой есть. Хочется чего-то нового, новых ощущений)
2. У меня сохранилось в памяти одно из первых обращений - по поводу проблем производительности в УТ 11, когда они мне написали мне ответ через год. Писать не проблема, проблема пробиваться через стену недопонимания, в последнее время у меня не хватает терпения.
5. Xershi 1262 18.02.25 19:58 Сейчас в теме
(3) я тоже выловил баг. Он до сих пор жив. Мы же не на исходниках живем, а на закрытой платформе. Не всегда легко все поправить. А по поводу конфигурации. Я ошибку лет 6 ловлю. ТП, ответила не может на новой конфе воспроизвести. Так что это нормально.
2. Teplotrassamen 18.02.25 19:02 Сейчас в теме
Спасибо за статью, познавательно. Поставил бы плюс, но подписки нет(
Serg O.; ardn; ivanov660; +3 Ответить
4. ivanov660 4685 18.02.25 19:09 Сейчас в теме
(2) Не беда, за отзыв спасибо)
6. titanium2008 47 18.02.25 21:11 Сейчас в теме
Хорошая статья, плюсую.
ivanov660; Serg O.; +2 Ответить
7. gzharkoj 523 18.02.25 21:45 Сейчас в теме
Коррелированные подзапросы с точки зрения производительности в общем случае неэффективные и от них стоило бы избавится вовсе, особенно в динамическом списке, там по идее все должно быть максимально просто.
В данном случае список будет хорошо работать пока выборка по конкретной зоне доставки будет небольшой. Зон доставки вроде как должно быть не много и при большом количестве документов селективность будет ухудшаться, как отбор по организации или подразделению. "Повысить" селективность зоны доставки поможет выставление ограничения по периоду в списке, задействовав индекс по дате, но кто так делает из пользователей? =)
8. ivanov660 4685 18.02.25 22:06 Сейчас в теме
(7) Дам вам подсказку (по крайней мере мы так делаем). Вы всегда можете программно для каждого списка устанавливать принудительно период действия - скажем от текущей даты на три месяца назад. И не надо никого просить) Если же пользователь зачем-то хочет посмотреть все документы, то никто не мешает ему снять этот отбор.
9. gzharkoj 523 18.02.25 22:15 Сейчас в теме
(8) тогда стоит добавить, что надо еще и блокировать типовой поиск по дин списку по всем полям или ограничивать по полям, или выносить отборы по ключевым полями над формой, так тоже делаете?
10. ivanov660 4685 18.02.25 22:24 Сейчас в теме
(9) Да, делаем и такое - блокировка неподходящих полей для сортировки, отключение группировки, отключение поиска по всем полям, добавляем отдельные отборы по полям и некоторые другие мероприятия.
gzharkoj; +1 Ответить
11. PerlAmutor 157 19.02.25 07:09 Сейчас в теме
Коррелирующие подзапросы неплохая вещь, по сравнению с ЛЕВЫМ СОЕДИНЕНИЕМ помогают часто избежать Table Spool'ов. Бывают правда и обратные ситуации. Основной их минус в том, что в какой-то момент может прийти необходимость все-таки вытащить дополнительное поле из второй таблицы на форму, а тут тогда обратно к ЛЕВОМУ СОЕДИНЕНИЮ возвращаться приходится. Наверное главным правилом тут является - не превращать списки документов в Отчеты. У 1С плохо реализован механизм открытия форм с динамическими списками, плюс неявное добавление времени на обновление динамических списков при проведении документов. Все это должно быть в фоне, но на практике пользователь который проводит документ за 1 секунду вынужден ожидать обновление динамического списка еще 100 секунд, если там настроены свои неоптимальные отборы и порядки. В некоторых случаях в форму списка документов вообще войти нельзя, т.к. там запрос обновления стал выполняться часами.

P.S.: Разделяю боль по поводу общения с тех.поддержкой 1С. Когда у себя ошибку поправил за 5 секунд и решил поделиться исправлением с сообществом, а тех.поддержка "мурыжит" тебя бюрократией неделю отнимая твое время - не самый приятный опыт.
12. muskul 19.02.25 10:10 Сейчас в теме
P.S. К сожалению, складывается впечатление, что разработчики конфигурации не читают статьи на этом замечательном сайте и, судя по всему, вообще не интересуются проблемами высокопроизводительных систем. Я давно разочаровался в личном общении с поддержкой — кроме лишней и бессмысленной работы с моей стороны, это редко приводит к каким-то результатам.

С другой стороны, при каждой новой встрече с "замечательной" конфигурацией ERP выполнять одни и те же оптимизационные мероприятия уже порядком надоело.

Полностью поддерживаю, из серии вначале докажи что не верблюд
16. o.nikolaev 216 19.02.25 14:18 Сейчас в теме
(12) Разработчики конфигурации ERP не читали и никогда не будут читать "статьи на этом замечательном сайте". Т.к. у них на это тупо нет времени. И, да, они не особо интересуются "проблемами высокопроизводительных систем", что не означает что они - злобно хохоча - в запросах отчетов и динамических списков все делают "через точку". Нет, стандарты есть, их стараются соблюдать, есть АПК, есть Sonar, которые прокатываются по коммитам и автоматически вешают задачи исправления кодовой базы. Почему так? Все просто - они пристегнуты цепями к племетам помещены в тиски жесточайшего расписания выпуска релизов с новым функционалом и исправлением самых тяжелых ошибок. Дата выпуска - дедлайн в реальности, а не на словах. Попробуй только сорвать срок выпуска!

Все остальное - на откуп франчайзи. В чем недовольство то? Вам за это платят! Ваши семьи отлично живут на эти деньги, вы платите ипотеку и ездите в Тайланд или куда-то-там-не-важно.

Хочется сделать clean code? Не вопрос. Пишите свою ERP. Пусть будет open-erp. Наладьте процесс, сбор и обработку требований, периодическое встраивание БСП, тестирование, сборку и публикацию, службу поддержки. Как "не хотите"?

Порой мне кажется что все эти мрии про системы состоящие из clean code - это что-то из разряда геометрии Евклида. Красиво, чисто, приятно, но в жизни не встречается. Пора познакомиться с "геометрией жизни" - Лобачевского. Там где параллельные прямые все-таки пересекаются. А в реально действующих системах, работающих на огромном количестве оборудования - много, очень много ошибок. Что не мешает всему этому бесконечно сложному хаосу странным образом работать.
13. skeptik2105 19.02.25 11:40 Сейчас в теме
С практической точки зрения:

1. Выяснить, используют ли отбор по зонам доставки.
2. Если не используют - удаляем РАЗЛИЧНЫЕ и СОЕДИНЕНИЕ с ТЧ Маршрут
3. Если используют, добавляем ТЧ ЗоныДоставки, реализуем заполнением уникальными зонами из маршрута, переделываем соединение без РАЗЛИЧНЫЕ с ТЧ ЗоныДоставки
15. RustIG 1836 19.02.25 11:46 Сейчас в теме
(13) типовую форму АРМ можно оставить без изменения, но при этом создать свою отдельную обработку или форму АРМ, да выложить тут в виде расширения.
14. RustIG 1836 19.02.25 11:44 Сейчас в теме
(0) на закрытом форуме разработчиков 1С разместите ссылку на статью. думаю, что ваш коммент выделят "лампочкой" как весьма полезный. Да и охват читателей расширите.
В названии статьи слово "различные" желательно выделить в кавычки. А то не понятно как читать.
В целом, спасибо за исследование!
Оставьте свое сообщение