gifts2017

Кэширование в 1С или уменьшаем нагрузку на сервер

Опубликовал Евгений Стоянов (quick) в раздел Программирование - Практика программирования

О том как несложными алгоритмами можно уменьшить время отклика системы в целом.

Ничего нового не расскажу, но возможно кому-то поможет.

Ситуация

Пользователей > 100, конфигурация на базе 1С:Торговля+Склад. Загрузка на основном сервере ниже 80% практически не опускается в течении рабочего дня. После кэширования нагрузка стала держаться в среднем около 40%. Конечно сказок не бывает и "хорошие" отчеты быстро исправляют ситуацию.

Решение

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

Недостатки

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

Пример 1 Константы: 

Так как константы в процессе работы меняются не часто, то есть смысл их кэшировать.
ГлМодуль

Перем глКэшКонстант Экспорт; // Список значений констант

....

// получение константы если она есть то из кэша, иначе из базы
Функция глКонстанта(Имя) Экспорт
    Значение = глКэшКонстант.Получить(Имя);
    Если ПустоеЗначение(Значение) = 1 Тогда
        Значение = Константа.ПолучитьАтрибут(Имя);
        глКэшКонстант.Установить(Имя,Значение);
    КонецЕсли;
    Возврат Значение;
КонецФункции

глКэшКонстант = СоздатьОбъект("СписокЗначений");
глКэшКонстант.Установить("РежимОграниченияКолваОкон",Константа.РежимОграниченияКолваОкон);
глКэшКонстант.Установить("КэшироватьТочкиДоступа",Константа.КэшироватьТочкиДоступа);
глКэшКонстант.Установить("ДатаЗапретаРедактирования",Константа.ДатаЗапретаРедактирования);

В документах вместо Константа.ДатаЗапретаРедактирования использую глКонстанта("ДатаЗапретаРедактирования").

Пример 2 Внешние печатные формы:

В глобальном модуле есть функция
Функция глУстановкаКнопкиПечать(Конт, ВидОбъекта, ТаблицаПечФорм) Экспорт
При каждом открытии документа в ней выполняется поиск по папке PrnForm всех файлов *.efd, их считывание и формирование списка доступных печатных форм.

Добавляю в ГлМодуль

Перем глКэшПечатныхФорм Экспорт; // таблица списка печ. форм.

....

глКэшПечатныхФорм    = СоздатьОбъект("ТаблицаЗначений");
глКэшПечатныхФорм.НоваяКолонка("ВидДокумента","Строка");
глКэшПечатныхФорм.НоваяКолонка("Название","Строка",,,,30);
глКэшПечатныхФорм.НоваяКолонка("Файл","Строка",,,"Файл",10);
глКэшПечатныхФорм.НоваяКолонка("Кнопка","Строка",,,,10);
глКэшПечатныхФорм.НоваяКолонка("ФайлОписания","Строка");

В функции глУстановкаКнопкиПечать делаю проверку сначала в таблице и если ничего не найдено, то только тогда иду искать по файловой системе.

Функция глУстановкаКнопкиПечать(Конт, ВидОбъекта, ТаблицаПечФорм) Экспорт
    Перем Название, Кнопка;
    стр = 0;
    Если глКэшПечатныхФорм.НайтиЗначение(ВидОбъекта,стр,"ВидДокумента") = 1 Тогда
        Для Ном = 1 По глКэшПечатныхФорм.КоличествоСтрок() Цикл
            глКэшПечатныхФорм.ПолучитьСтрокуПоНомеру(Ном);
            Если (ВидОбъекта = глКэшПечатныхФорм.ВидДокумента) И (глКэшПечатныхФорм.Название <> "") Тогда
                ТаблицаПечФорм.НоваяСтрока();
                ТаблицаПечФорм.Название     = глКэшПечатныхФорм.Название;
                ТаблицаПечФорм.Кнопка       = глКэшПечатныхФорм.Кнопка;
                ТаблицаПечФорм.Файл         = глКэшПечатныхФорм.Файл;
                ТаблицаПечФорм.ФайлОписания = глКэшПечатныхФорм.ФайлОписания;
            КонецЕсли;
        КонецЦикла;
    Иначе
        // Дополним таблицу печатных форм внешними обработками из предопределенного
        // каталога ExtForms\PrnForms
        // одна запись нужна как флаг что эту запись уже искали
        глКэшПечатныхФорм.НоваяСтрока();
        глКэшПечатныхФорм.ВидДокумента = ВидОбъекта;
        глКэшПечатныхФорм.Название = "";

        Текст = СоздатьОбъект("Текст");
        ФайлОписания = ФС.НайтиПервыйФайл(глКаталогПечФорм+"*.efd");
        Пока ПустаяСтрока(ФайлОписания)=Цикл
            Текст.Открыть(глКаталогПечФорм+ФайлОписания);
            // Устанавливаем расширение
            Файл = Лев(ФайлОписания,СтрДлина(ФайлОписания) - 4) + "." + "ert";
            Если ФС.СуществуетФайл(глКаталогПечФорм + Файл) = 1 Тогда
                // Внешний файл, соответствующий файлу описания, найден.
            // Проверим, в нем что есть запись про текущий объект
                Если глНайтиВнешнююПечФорму(Текст, """" + ВидОбъекта + """", Название, Кнопка) = 1 Тогда
                    // Добавляем строку в список внешних файлов
                    ТаблицаПечФорм.НоваяСтрока();
                    ТаблицаПечФорм.Название     = Название;
                    ТаблицаПечФорм.Кнопка       = Кнопка;
                    ТаблицаПечФорм.Файл         = Файл;
                    ТаблицаПечФорм.ФайлОписания = (ФайлОписания);

                    глКэшПечатныхФорм.НоваяСтрока();
                    глКэшПечатныхФорм.ВидДокумента = ВидОбъекта;
                    глКэшПечатныхФорм.Название     = Название;
                    глКэшПечатныхФорм.Кнопка       = Кнопка;
                    глКэшПечатныхФорм.Файл         = Файл;
                    глКэшПечатныхФорм.ФайлОписания = (ФайлОписания);
                КонецЕсли;
            КонецЕсли;
            ФайлОписания = ФС.НайтиСледующийФайл();
        КонецЦикла;
    КонецЕсли;
    НомерСтроки = глПолучитьТекущуюПечФорму(ВидОбъекта, ТаблицаПечФорм);
    Если НомерСтроки = 0 Тогда
        ЗагловокКнПечать = "Печать";
    Иначе
        ЗагловокКнПечать = ТаблицаПечФорм.ПолучитьЗначение(НомерСтроки, "Кнопка");
    КонецЕсли;
    Конт.Форма.кнПечать.Заголовок(ЗагловокКнПечать);

    Возврат НомерСтроки;

КонецФункции // глУстановкаКнопкиПечать()

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Евгений Стоянов (quick) 22.01.10 14:53
Поскажите как нормально код оформить?
2. Евгений Мартыненков (JohnyDeath) 22.01.10 15:13
Не поверю, что кэшированием констант и путей к внешним. печ. формам ты добился двукратного снижения нагрузки на сервер.
3. Евгений (Berrimor) 22.01.10 15:31
Мысль логичная, но..... нужно оптимизировать кэшированием на каждом этапе (связано с ГЛОБАЛЬНЫМ перелопачиванием кода) так что мысль здравая, но ни чего нового не несущая, если это несущая модификацию кода модификация, а с теоретической точки зрения ВЫ ПРАВЫ ОДНОЗНАЧНО!
4. Asdam (Asdam) 22.01.10 15:51
Поскажите как нормально код оформить?

http://infostart.ru/public/19856/
5. Евгений Мартыненков (JohnyDeath) 22.01.10 16:07
6. Евгений Стоянов (quick) 22.01.10 17:25
Не поверю, что кэшированием констант и путей к внешним. печ. формам ты добился двукратного снижения нагрузки на сервер.

Сам до сих пор сомневаюсь :D, но эффект точно есть. У меня еще был закэширован один справочник опрашиваемый по нескольку раз при открытии форм и отвечающий за права доступа. В пример не вынес т.к. код идентичный. Он был самый "тяжелый".
7. Александр Крынецкий (echo77) 22.01.10 19:10
Загрузка на основном сервере ниже 80%

- эта цифра по какому показателю? Из каких показателей складывается?
8. Валентин Терёхин (Valet) 23.01.10 00:29
Только нагрузка наверняка никуда не делась, а переползла с сервера на клиента (плюс на клиенте и память занимаемая 1С подрастет).
И про использование справочников интересно. От запросов совсем отказаться?
9. Евгений Стоянов (quick) 23.01.10 23:32
Зачем полностью отказываться от запросов :) Всему свое место, просто есть данные, которые меняются редко или почти не меняются, а используются очень часто. Таблица констант кстати очень большая, т.к. в ней еще все периодические реквизиты хранятся. С другой стороны, все равно эти справочники будут постоянно занимать память (если они часто используются), почему бы их тогда просто в памяти не держать? :)
10. Сергей Карташев (Elisy) 27.01.10 07:01
Кэш на стороне клиента однозначно значительно помогает. Проблему вижу в том, что некоторые величины могут меняться, например, дата запрета редактирования. Кроме того кэширование, например, таблиц на стороне клиента приводит к затратам памяти. В 1С сложно организовать управление кешем. Как альтернативный вариант могу предложить класс Cache .Net из пространства имен System.Web.Caching. Он позволяет положить в кэш значение навсегда, на определенное время, на определенное время после последнего обращения. Таким образом частично снимает описанные мной проблемы.
11. Nik (nikakoy) 27.01.10 09:52
ТиС. Кешируются в таблицу курсы валют. Поскольку ГлПересчет(...) используется везде (и не по разу на одной форме!!!) при некоторых операциях скорость реально увеличивается на порядки...
12. Oleg (Rebel2007) 27.01.10 11:51
на этой странице вирус Trojan.tempi
13. Максим Шивирдинов (Ветер в поле) 27.01.10 12:01
Давно уже использую кэширование внешних печатных форм - давно заметил, что львиную долю времени открытия формы документа уходит на считывание файлов описаний внешних печ. форм. А когда в день открывается несколько тысяч документов, то это неплохо нагружает процессор. Но мой вариант оптимизации немного другой - при первом доступе к внешним формам я сразу заполняю глКэшПечатныхФорм по всем документам - все равно ведь приходится открывать все файлы.
14. Антон Рощин (wolfsoft) 27.01.10 14:45
15. Владимир Сумин (sumv1) 28.01.10 12:22
Идея отличная.
Её должны были в 1С на уровне платформы реализовать.
Тем более в 8-ке появились параметры сеанса - что-то подобное.

В приведенном примере с константами есть ошибка:
глКэшКонстант.Установить(Значение); - так мы потом не получим значение константы
а надо:
глКэшКонстант.Установить(Имя,Значение);

и периодическую константу не получишь методом: ПолучитьАтрибут()
её можно запомнить при входе

Может автор нас проверяет? ;)
16. ROM (ROM_1C) 29.01.10 12:39
Если нечиго делать - можна еще играться с кнопками, списками, и другим хламом, которое так или иначе повлеяет ли на производительность. ;)
А так идея хороша, но от того что кода станеть больше - никому не будет лучше :)
17. Алексей (Alav) 13.02.10 19:36
А если внешние печатные формы сделать на справочнике?. Т.е. реквизит видДокумента (отбор), Наименование, кнПечать, Путь? И этот справочник еще и за кэшировать с помощью Индексированной таблице (в виде дерева), где на первом уровне вид документа, а в тзПотомки соответственно список печатных форм?
18. Евгений Стоянов (quick) 14.02.10 01:46
А если внешние печатные формы сделать на справочнике?. Т.е. реквизит видДокумента (отбор), Наименование, кнПечать, Путь? И этот справочник еще и за кэшировать с помощью Индексированной таблице (в виде дерева), где на первом уровне вид документа, а в тзПотомки соответственно список печатных форм?

Можно и так, только придется еще справочник поддерживать в актуальном состоянии, а так при добавлении новой печ. формы достаточно перезайти в 1С.
19. Алексей (Alav) 14.02.10 09:28
А какая разница куда писать в efd или в справочник? ИМХО обработку не сложно поправить
20. Eugeneer (Eugeneer) 14.02.10 10:15
Привет Женек. как там наша база поживает :))))
нагрузка 80 процентов ?))) гыыы. Жека выбей у дира нормальный сервер, а то нашему серваку уже 6 лет от роду. Сейчас даже домашние компы мощнее.
21. Евгений Стоянов (quick) 15.02.10 18:05
Привет Жека :)) Еще живет, но свое отживает. По мелочи то там, то здесь подкручиваю... Занялся как видишь выносом "полезняшек" на всеобщее обозрение, что бы добро не пропало.
22. Александр Иванов (dwarkin) 19.03.10 10:00
Вопрос автору: а нагрузка снизится, если БД под SQLем крутится? Версия 1С Предприятия 7.7 SQL
23. Евгений Стоянов (quick) 19.03.10 23:09
Вопрос автору: а нагрузка снизится, если БД под SQLем крутится? Версия 1С Предприятия 7.7 SQL

Снизится за счет уменьшения кол-ва запросов. Но надо смотреть что оптимизировать. Мне помогло, кому может не помочь.
24. Александр Иванов (dwarkin) 20.03.10 09:22
(23) Вопрос как бы не праздный, сама же SQLка (2000 в моем случае) часто используемые данные пихает в свой собственный кэш, а это память. Вот и получается, SQL в кэш загрузила, да и мы еще их загрузили.
Будем попробовать....
25. Светлана Куприянова (Merlin12042009) 11.09.14 11:17