Странное потребление места на диске С










Решение проблемы постоянного роста папки %AppData%/Local/Temp.

Первым делом смотрим виновника в мониторе ресурсов:

Видим что им является один из процессов rphost с id 8484. (Remote Process HOST)

Далее, смотрим все сеансы этого рабочего процесса, где-то в последних столбцах таблицы ищем потребление диска:

Видим 6 сеансов на этом процессе:

Ага, вот и наш ненасытный сеанс, открытый фоновым заданием под пользователем Adm в 9:57. В колонке "Запись (Текущая)" значение достигло 138 гб! (пред. скрин). Кстати, с этого же времени висит ещё одно. Может они связаны.

Далее идем в консоль заданий и ищем что его породило:

Смотрим код первого:

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

Ок, не наш случай. Добавим проверку на существование файла и идём дальше. Код второго регламентного:

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

Когда в запросе выбирается реквизит типа хранилище значений с бинарными данными (поле ФайлДанных) — тогда в результирующую выборку попадает весь размер всех файлов одновременно!

В нашем случае это вызывает ошибку нехватки места на диске:

При выполнении метода Выполнить() данные запроса могут сбрасываться на диск, и вот почему:

http://its.1c.ru/db/v8std#content:-2145782922:1

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

Следует избегать формирования больших структур данных в памяти. Если объём данных, с которыми работает бизнес-логика, сам по себе ничем не ограничен, его нужно ограничивать искусственно, обрабатывая данные порциями и сохраняя результаты в базу или файлы.

2. При потенциально неограниченных выборках данных из ИБ следует получать данные из базы порциями фиксированного размера. 
Например, неправильно:

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование,
| Номенклатура.ВидНоменклатуры
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";

// Выгрузка всего справочника в таблицу значений 
Номенклатура = Запрос.Выполнить().Выгрузить(); 
Для каждого ПозицияНоменклатуры Из Номенклатура Цикл
// Обработка элемента справочника 
// …
КонецЦикла;

поскольку весь результат запроса сразу помещается в память, в таблицу значений.
Также неправильно:

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование,
| Номенклатура.ВидНоменклатуры
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";

РезультатЗапроса = Запрос.Выполнить();
// Обход результата запроса
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Обработка элемента выборки
// …
КонецЦикла;

поскольку и в этом случае при выполнении запроса его результат будет сначала считан в память целиком (*).

* Примечание. Если размер результата запроса превосходит размер имеющейся памяти, то данные будут записаны на диск, а затем считаны оттуда в процессе вызовов Выборка.Следующий().

Правильно ограничивать результат запроса искусственно:

ВсеОбработано = Ложь;
Пока Истина Цикл
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ ПЕРВЫЕ 1000
| Номенклатура.Ссылка,
| Номенклатура.Наименование,
| Номенклатура.ВидНоменклатуры
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| <условие выборки необработанных записей>";

РезультатЗапроса = Запрос.Выполнить();
ВсеОбработано = РезультатЗапроса.Пустой();
Если ВсеОбработано Тогда
Прервать;
КонецЕсли;

// Обход порции результата запроса
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Обработка элемента выборки
// …
КонецЦикла;

КонецЦикла;

Также правильно:

Выборка = Справочники.Номенклатура.Выбрать(…, Отбор);
Пока Выборка.Следующий() Цикл
// Обработка элемента выборки
// …
КонецЦикла;

поскольку в этом случае платформа 1С:Предприятие выполняет курсорный запрос.

Кроме того, число элементов выборки автоматически ограничивает платформа 1С:Предприятие в запросах динамических списков.

Таким образом, переписав код на получение значения хранилища через ключ записи, избавляемся от ошибки нехватки памяти:

 

Вывод: никогда не делайте неограниченную выборку полей типа ХранилищеЗначения, иначе забьёте память и диск!

 
 

 Динамическая же выборка считывает по 25 записей за раз

upd: insurgut +

12 Comments

  1. w.r.

    Полная выборка справочника (регистра) — интересно, а зачем?

    Reply
  2. PerlAmutor

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

    Всегда интересно почитать про расследования.

    Я вот сейчас тоже веду два расследования. Пока безуспешно. Тех. журнал не помогает. Исключения, которые сыпятся в журнал зависят от данных в параметрах процедур, а ТЖ их не логирует никак, да еще и общие модули БСП. Пришлось ставить «ловушки» кодом, изменяя конфигурацию, посмотрю что именно попадается пользователю. Вторая — плавающая ошибка платформы, приводящая к краху всех клиентских сессий. Ошибка является следствием каких-то действий, но каких именно и кто был первым инициатором выяснить не удается. Исключение получается лавинообразным по всей системе.

    Reply
  3. user-z99999

    Запрос.Выполнить().Выгрузить();

    Запрос.Выполнить().Выбрать();

    В одном случает улетает результат в оперативную память, в другом — на диске во временную папку.

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

    Reply
  4. w.r.

    (2)

    Меня смущает здесь полная выборка, а потом уже наложение условия внутри

    ИнфоПрайсЛистов.ПрайсЛистБылУжеУспешноОбработан(ХэшФайла)

    Лучше соединить запрос этой функции с запросом с полной выборкой. Тогда сразу будет существенное сокращение результатов выборки

    Reply
  5. rpgshnik

    Это же всё ошибки доработок или разработчиков типовых поставок?)

    Reply
  6. insurgut
    Ага, вот и наш ненасытный сеанс, открытый фоновым заданием под пользователем Adm в 9:57.

    По какому принципу определили, что именно этот сеанс виноват?

    Затираем несуществующий путь, идём дальше.

    А разве не правильнее было переделать попытку (или добавить в коде попытки) условие на ФайлСуществует?

    И вот почему:

    Странно, выше говорится о проблеме выборки в запросе данных с типом ХранилищеЗначений, а в качестве объяснения непонятно к чему приводится пример с выборкой ссылок из справочника номенклатуры. Разбитие запроса на порции может и не решить конкретно в вашем случае проблемы с потреблением памяти. В результате проблема решается как положено, но к чему приведена информация о разбиении запроса на порции — не понятно.

    P.S. За труды в любом случае «+» 🙂

    Reply
  7. rozer

    off:

    Вспомним Душелова …

    RIP

    https://forum.mista.ru/topic.php?id=597601&page=2

    Reply
  8. KonstB

    (7) Прям в глаза бросилось 2019… как так подумал я

    RIP

    Reply
  9. gadmin

    (7)

    off:

    Я знал Васю лично, помним!(7)

    Reply
  10. logarifm

    (0) А еще есть такая штука как MS SQL Server и план запроса, где видно задействует-ли он для получения данных отличный оператор как

    Spool и если база Tempdb на этом же диске тогда вообще я не вижу никаких аномалий и странностей.

    Reply
  11. riposte

    Можно подключить файлопомойку террабайта на 2

    (из двух SATA-шников в R1, какого-нибудь тырпрайз уровня, которые заявляются как 247 с большой устойчивостью к вибрациям)

    и слинковать туда толстые temp через mklink /J

    Или целиком перенести туда профили.

    И износ системного харда уменьшим, и место уменьшаться перестанет так стремительно.

    Reply
  12. kuzyara

    (6)

    По какому принципу определили, что именно этот сеанс виноват?

    По объему записи/чтения диска

    А разве не правильнее было переделать попытку (или добавить в коде попытки) условие на ФайлСуществует?

    Да, действительно плохо, переделал.

    Странно, выше говорится о проблеме выборки в запросе данных с типом ХранилищеЗначений, а в качестве объяснения непонятно к чему приводится пример с выборкой ссылок из справочника номенклатуры.

    К сожалению это единственное место, где я смог найти упоминание о свопе результатов запроса на диск (

    Reply

Leave a Comment

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