Некоторые собранные мысли, идеи по поводу быстродействия системы Terrasoft CRM
Много чего я взял из тем на форуме и из ответов службы поддержки Террасофт, когда искал как ускорить работу CRM. Возможно, кому-то эта информация будет полезна.
На быстродействие системы может влиять довольно много параметров. В первую очередь сервер и клиентские места должны удовлетворять аппаратным и программным требованиям для использования программы Terrasoft. Они описаны в документе "Руководство администратора", который поставляется вместе с программой. Также быстродействие зависит от размера базы данных и количества активных подключений к серверу БД.Проверьте также, включено ли в Вашей базе данных кеширование (для этого необходимо установить значение 1 в колонке UseCache таблицы tbl_DatabaseInfo). Если включена данная опция, память под конкретный экземпляр объекта выделяется только один раз при его создании. При последующих обращениях эти объекты берутся из кеша.
Ещё одна возможная причина - реализация некоторого функционала при открытии раздела. Проверьте профайлером, не выполняются ли в это время запросы, напрямую не связанные с разделом, таблицей tbl_Service и напоминаниями. Очень может нагружать систему использование вызова Services.GetNewItemByUSI(...), особенно в циклах (в результате экземпляр объекта не подтягивается из кеша, а каждый раз создаётся новый экземпляр). Необходимо по возможности этого избегать, используя для получения экземпляров объекта функцию GetSingleItemByCode.
Від себе можу додати, я помітив, що продуктивність залежить від кількості активних (відкритих датасетів). Особливо коли вони знаходяться в режимі редагування. Террасофт рекомендує в деяких випадках вимикати реагування на події і після редагування записів вмикати(Dataset.DisableEvents()/Dataset.EnableEvents()).
Мені в одній із карточок реально вдалося підвищити швидкість відображення разів в 10 лише відключивши у відкритих датасетах (з яких дані лише беруться) режим редагування.Ще один фактор який мені порадили, по мінімуму прив'язувати таблиці до системи перевірки прав доступу. Можете перевірити на свойому клієнті під Адміністратором (мабуть блок "Адміністрування по записам" або "Групи таблиць" не активний) система завантажується і працює в 1,5 рази швидше.
Необходимо определиться, клиент тормозит или сервер. Я бы сначала посмотрел на запросы от клиента к серверу (профайлер от sql server).
Источник: Производительность системы
http://community.terrasoft.ua/forum/topic/5291
В этой записи в моем блоге я привожу пример как можно проанализировать время выполнения запросов и работы клиентской части CRM с помощью SQL Profiler:
Тема: Анализ быстродействия CRM с помощью SQL Profiler
http://community.terrasoft.ua/blogs/6030
Для увеличения быстродействия открытия окон, при их разработке необходимо учитывать следующее:
1. Минимизировать логику в обработчиках событий OnPrepare, OnShow.
2. Не загромождать окна лишними контролами.
3. Использовать минимальную вложенность контролов.
4. Группировать контролы в отдельные фреймы, в зависимости от их смыслового назначения. Использовать центрирование контролов в фреймах по правому либо по левому краю.
5. Уменьшить использование подсветки записей в реестре. Использование подсветки значительно замедляет работу системы.
6. Отображать минимальное количество колонок в реестре, остальные скрывать.Значительном шагом на пути улучшения быстродействия системы является ограничение записей, отображаемых в реестре записей каждого раздела. При уменьшении объема отображаемой информации снижается объем используемой
оперативной памяти компьютера, а также уменьшается нагрузка на сетевой трафик – что приводит к значительному улучшению в быстродействии программы.
Из личного примера: нужно было ускорить время открытия карточки редактирования задачи. После ранее внесенных изменений с моей стороны она открывалась секунд 5-6. Причину я нашел: подключал слишком громоздкие скрипты (например скрипт окна грида документов - wnd_DocumentsGridArea). Почистил подключаемые скрипты, перенес некоторые функции из подключенных скриптов в сам скрипт окна редактирования задачи. И как результат - окно начало открываться 1-2 секунды. Да, это была моя ошибка, но таким образом я узнал, что количество подключаемых скриптов тоже может влиять на быстродействие.
По этому поводу:
Чем больше используется подключенных скриптов, тем больше времени затрачивается на инициализацию, следовательно уменьшается быстродействие работы системы.Рекомендуется подключать только базовые скрипты. При наличии маленьких скриптов, лучше их не подключать, а включить прописанные в них функции непосредственно в код основного скрипта.
Также, избегайте зацикливания при подключении скриптов.
Как отключить скрипт из основного скрипта, таким образом исключив затраты на его инициализацию во время загрузки CRM, я описал в следующем посте:
Тема: Обращение к переменным и методам скрипта
http://community.terrasoft.ua/forum/topic/6036
По этому поводу я задал следующий вопрос в Службу поддержки Terrasoft:
Подскажите какие плюсы/минусы использования скриптов и их методов этими способами, как может это повлиять на быстродействие системы:
1. Подключать нужный скрипт в текущий скрипт и обращаться к функциям из подключенного скрипта напрямую, например:
ExportAccountToClient(AccountID);
Минус: это что всегда при инициализации основного скрипта инициализируется и подключенный скрипт, который может быть довольно ресурсоемким.
2. Вызывать метод скрипта через получение этого скрипта из кэша или из БД (если не закеширован). Например:
var scrGeneral1CUtils = Services.GetSingleItemByUSI('scr_General1CUtils');
scrGeneral1CUtils.ScriptControl.Run('ExportAccountToClient', AccountID);
Плюс: что мы избегаем обязательной инициализации дополнительных скриптов при инициализации основного скрипта.
Ответ был полезным для меня:
В общем, Вы описали один из методов оптимизации, который мы использовали при написании базовой конфигурации 3.3.2.
Из scr_Main было убрано явное и косвенное использование scr_UserReportCommon, в результате 3.3.2 стало запускаться почти в 2 раза быстрее, чем 3.3.1.Из минусов второго варианта на ум приходит только то что в главном скрипте нельзя будет прямо использовать глобальные переменные подчиненного скрипта. Но если вспомнить про инкапсуляцию данных, это становится весьма незначительным минусом.
Так же, при использовании второго подхода мы бы посоветовали локально кешировать (в главном скрипте сохранять в переменной полученный экземпляр подчиненного скрипта) сервис полученный через GetSingleItemByUSI, т.к. если вызвать GetSingleItemByUSI второй раз, то и во второй раз будет проведена
полная инициализация подчиненного скрипта (и возможно всех его uses тоже, этот вопрос требует исследования).Так же, для вызова методов подчиненного скрипта можно использовать не конструкцию вида:
scrGeneral1CUtils.ScriptControl.Run('ExportAccountToClient', AccountID);
а вот такой вариант:
scrGeneral1CUtils.ScriptControl.CodeObject.ExportAccountToClient(AccountID);
На сколько я знаю, сравнение этих методов не проводилось. Но исторически сложилось, что мы используем второй вариант.В целом, этот механизм стоит применять когда создается слабая связь 2 больших функционалов. Чтобы зависимый функционал инициализировался только когда нужно, а не когда инициализируется главный.
Из личного опыта:
Благодаря использованию конструкций кода, вместо подключения скриптов к главному скрипту (пример):
function GetIsOLAPControlIstalled_() {
if (!Assigned(Main.scrOLAPUtils)) {
Main.scrOLAPUtils = Services.GetSingleItemByUSI('scr_OLAPUtils');
}
return Main.scrOLAPUtils.ScriptControl.CodeObject.GetIsOLAPControlIstalled();
}
....
if ((WorkspaceUSI == 'wnd_OLAPWorkspace') &&
(!GetIsOLAPControlIstalled_())) {
....
- получилось ускорить время загрузки CRM с активным разделом "Контрагенты".
Показатели были получены при запуске на тестовом компьютере (процессор Intel Celeron 600 MHz, 256 Мб ОЗУ):
До:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
1.581 | 196.898 | 198.409
После:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
1.274 | 123.109 | 124.329
Итого общее время было уменьшено с приблизительно 3 мин. 20 сек до 2 мин. 4 сек., благодаря уменьшению времени на выполнение операций, выполняемых клиентской частью CRM.- ускорить время открытия карточки редактирования записи контрагента:
До:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
0.019 | 18.848 | 18.863
После:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
0.021 | 6.463 | 6.481
Итого общее время было уменьшено с приблизительно 19 сек до 6.5 сек.- ускорить время инициализации раздела "Задачи":
До:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
2.875 | 27.772 | 30.620
После:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
0.077 | 18.441 | 18.509
Итого общее время было уменьшено с приблизительно 28 сек до 18.5 сек.- ускорить время инициализации карточки редактирования задачи:
До:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
0.073 | 21.738 | 21.804
После:
Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
0.039 | 4.087 | 4.122
Итого общее время было уменьшено с приблизительно 22 сек до 4 сек.
Кому то будет полезна информация о процессе инициализации окон в разделе и в окне редактирования (последовательность, наиболее ресурсоемкие операции):
Процесс инициализации окон в разделе:
1. Десериализация – восстановление сохраненных объектов. Если раздел отображается впервые – происходит считывание данных из БД. Если раздел уже отображался – происходит считывание данных из Cache. В том случае, если системные характеристики компьютера достаточно низкие данная процедура будет происходит сравнительно медленно.
2. Инициализация групп, основного реестра, глобальных переменных, ссылок на наборы данных и открытие набора данных групп.
Отправной точкой для отображения данных является открытие набора данных групп с позиционированием на корневой группе (function OpenGroupsDataset()).
3. Вызов метода Show() для каждого элемента раздела.
4. Вызов метода Prepare() для каждого элемента раздела.
5. Фильтрация реестра записей.
6. Фильтрация текущего представления
7. Заполнение реестра данными
8. Refresh активной детали.Процесс инициализации карточки редактирования:
1. Десериализация.
2. Вызов метода Show() окна.
3. Вызов метода Prepare() окна.Наиболее ресурсоемкие операции –десериализация, прорисовка контролов, подтягивание данных.
С функциями, используемыми при инициализации Вы можете ознакомиться в SDK.
Как снизить время первоначального открытия разделов. Несколько видоизменил ответ от Раловец Ольги, добавив возврат в первоначально загружаемый раздел. Также внесены были замечания от других пользователей:
Пример реализации из проекта.
function wnd_MainOnShow(Window) {
Self.BeginUpdate();
var WspCodesArray = Main.UserSettingsWindow.Attributes('WorkspacesForCaching').split(' ');
for (var i in WspCodesArray) {
var WorkspaceWindowCode = WspCodesArray[i];
if (IsEmptyValue(WorkspaceWindowCode)) {
continue;
}
var WorkspaceWindow = GetWorkspaceByUSI(WorkspaceWindowCode);
wndWorkspace.Window = WorkspaceWindow;
var EditWindowUSI = '';
if (Assigned(WorkspaceWindow.ComponentsByName('wndGridData'))) {
EditWindowUSI =
WorkspaceWindow.ComponentsByName('wndGridData').Window.Attributes('EditWindowUSI');
}
if(IsEmptyValue(EditWindowUSI)) {
continue;
}
var Attrs = GetNewDictionary();
AddRequiredValuesToDictionary(Attrs, GUID_NULL, false, true);
var EditWindow = ShowEditWindowEx(EditWindowUSI, Attrs, System.EmptyValue, true, true);
EditWindow.Close();
}
Self.EndUpdate();
}В данном случае требовалось кэшировать при запуске системы разделы, отмеченные пользователем в настройках, и их карточки редактирования. Вместо строчки
var WspCodesArray = Main.UserSettingsWindow.Attributes('WorkspacesForCaching').split(' ');
можно явно указать нужные разделы, задав массив WspCodesArray, элементами которого являются коды главных окон этих разделов, например, 'wnd_ContactsWorkspace'. Если карточки редактирования Вас не интересуют, то все сведется к
function wnd_MainOnShow(Window) {
//предварительная инициализация разделов
Self.BeginUpdate();
var OriginalWorkspaceWindow = wndWorkspace.Window;
var WspCodesArray = new Array('wnd_AccountsWorkspace',
'wnd_ContactsWorkspace', 'wnd_TasksWorkspace',
'wnd_OpportunitiesWorkspace', 'wnd_ContractsWorkspace',
'wnd_DocumentsWorkspace', 'wnd_InvoicesWorkspace',
'wnd_MailWorkspace');
for (var i in WspCodesArray) {
var WorkspaceWindowCode = WspCodesArray[i];
if (IsEmptyValue(WorkspaceWindowCode)) {
continue;
}
var WorkspaceWindow = GetWorkspaceByUSI(WorkspaceWindowCode);
wndWorkspace.Window = WorkspaceWindow;
}
wndWorkspace.Window = OriginalWorkspaceWindow;
Self.EndUpdate();
}Данная функция описана в скрипте scr_Main. Проект был реализован на базе версии 3.2.1.
Источник: как ускорить первоначальное открытие разделов
http://community.terrasoft.ua/forum/topic/4285
Комментарий от партнера вендору: более чем ценная информация. для каждого из нас. не секрет, что темпы развития продуктов ТС опережают возможности документаторов и техподдержки ТС. Опережают они и наши возможности. Намного опережают. В ходе работы часто сталкиваемся с ситуацией когда надо перелопатить "единого слова ради тысячи тонн словесной руды" (форумы на Сообществе, документация к продуктам) и...все равно решения нет. Очень нужна публикация такого рода обобщенных наблюдений. в том числе от техподдержки ТС, когда вы, коллеги, отвечая по запросам, находите ответ или решение, не задокументированное ранее. Спасибо.
А еще ...
В базовой функции RefreshDetails все вставляют толпу if'ов и условия там идут вида: pgDetails.ActivePage.Name == pgMyDetail.Name
Для меня до сих пор, кстати, загадка зачем берут именно свойство объекта, а не строку )
это раз. а два - это ifы необходимо заменить на switch. В данном контексте switch работает быстрее. Конечно же это просто капля по сравнению со всем другим, но все-таки ;-)
Функция выводит список скриптов и функций, которые используются в указанном скрипте: перенес сюда.