Блог Александра Божко
Архивы
Рубрики
Поделись с другими!
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Боремся со скоростью!

В предыдущем посте я затронул проблему производительности приложения, использующего DevExpress компоненты. Здесь я расскажу о некоторых своих изысканиях в данном направлении.

Итак, имеем следующее…

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

К набору данных привязаны cxGrid, в котором активное представление TcxDBGridDBTableView и cxPivotGrid (еще один очень интересный компонент из набора DevExpress о котором обязательно стоит рассказать). При загрузке свыше тысячи записей наблюдается явственная протормозка.

Попробуем выяснить из-за чего именно. Ниже я приведу свой ход мысли. Возможно, в чем-то я не прав, поэтому надеюсь на вашу помощь в рассуждениях…

Я попытался вычислить количество миллисекунд, затрачиваемых на открытие DataSet’а и на загрузку данных в Grid’ы примерно так:

qry.DisableControls;
dtmStrt:= Now;

InitQry; //Здесь мы формируем зарос и открываем dataSet

speedList.Add(IntToStr(MilliSecondsBetween(dtmStrt,Now))+’ End InitQry’);
qry.EnableControls;
speedList.Add(IntToStr(MilliSecondsBetween(dtmStrt,Now))+’ EnableControls’);

speedList.Add(‘——->’+IntToStr(qry.RecordCount));

qry – это мой DataSet (TADOQuery, если быть конкретным);

speedList – это предварительно созданный TStringList, куда попадают:

  • количество миллисекунд, затраченных на формирование запроса и открытие DataSet;
  • количество миллисекунд, затраченных на выполнение операции qry.EnableControls;
  • количество записей в наборе данных;

InitQry – процедура в которой формируется запрос и открывается DataSet.

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

Что же получилось?

83 End InitQry
5060 EnableControls
——->1393

То есть, около 5 секунд на подключение 2-х гридов.

Сразу отмечу, что если не использовать метод DisableControls, то выходит 9 секунд.

Еще один любопытный факт. При повторном вызове кода (даже если мы перезапустили программу) получается примерно на секунду меньше (около 4 сек.). Если условия выборки меняются, а потом возвращаются на исходную – вновь около 5 секунд. Отсюда еще один вывод – работают какие-то механизмы кэширования (думаю это Windows старается).

Погрешность – порядка 20-30 миллисекунд при повторных тестированиях.

Проделав данную операцию, я увидел очевидное:

jackass

Гриды не отображаются одновременно. Они находятся на разных вкладках страничного переключателя и нет никакого смысла заполнять их одновременно.

Перед тем как засечь стартовое время делаем следующее:

PivotGrid.DataSource:= nil;

Получаем:

107 End InitQry

1705 EnableControls
——->1393

Впечатляет?

Опять же на первый взгляд – да, но не все так просто…

Меняем PivotGrid.DataSource:= nil;

на
cxDBGridDBTableView1.DataController.DataSource:= nil;

Получаем

98 End InitQry
1832 EnableControls
——->1393

А вот теперь – впечатляет…

Заметьте:

1832+1705 < 5060

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

Если же мы из футера грида убираем суммы, то порядка 100-150 миллисекунд мы сэкономим.

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

Возможно (и вероятнее всего), даже в DataSet все сразу не грузится… Тут зависит от реализации.

Но если с cxGrid все ясно, полный набор данных нужен только для подсчета сумм, то вот с PivotGrid - сложнее. Там все значения суммируются по группам. Очевидно, что грузится весь набор. Почему же тогда временные интервалы загрузки обоих гридов сопоставимы? Думаю, здесь дело в том, что в PivotGrid (по крайней мере у меня) не грузятся строковые данные, только числовые значения. Их обработка во внутреннем массиве грида происходит  быстрее.

В принципе, можно бы было произвести еще один эксперимент: разнести DataSet‘ы для гридов. Интересно бы было посмотреть увеличится -ли скорость загрузки PivotGrid если в dataSet’е не было бы “лишних” полей. Мой прогноз – нет. Именно в силу внутренней организации DataSet. Думаю “лишние данные” из БД не подгружаются. Хотя я могу и ошибаться…

Вопрос, который меня несколько смущеает:

А точно-ли время отработки команды qry.EnableControls; это время загрузки данных во внутренний массив грида? Думаю – да. Цифры этому не противоречат, да и визуально видно, что грузится быстрей при раздельной загрузке гридов. Но если кто-то знает этот вопрос глубже – поправьте меня.

Как реально повысить скорость загрузки данных в гриды DevExpress?

А очень просто, как, вероятно и в любые другие гриды.

В каждый момент времени подключать к DataSet только те компоненты отображения данных, которые нам нужны.

Другие статьи серии:

Редизайн интерфейса приложения. #0
Редизайн интерфейса приложения. #1
Редизайн интерфейса приложения. #2
Редизайн интерфейса приложения. #3
Редизайн интерфейса приложения. #4
Редизайн интерфейса приложения. #5
Редизайн интерфейса приложения. #7
Редизайн интерфейса приложения. #8


Поделись с другими!
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

8 комментариев: Редизайн интерфейса приложения. #6

  • >В принципе, можно бы было произвести еще один эксперимент: разнести DataSet‘ы для гридов. Интересно бы было посмотреть увеличится -ли скорость загрузки PivotGrid если в dataSet’е не было бы “лишних” полей. Мой прогноз – нет. Именно в силу внутренней организации DataSet. Думаю “лишние данные” из БД не подгружаются. Хотя я могу и ошибаться…

    У меня как-то была похожая ситуация. Ну я разнёс и для PivotGrid я немного переписал SQL запрос сгруппировал по заданным измерениям, суммы просуммировал. У меня уменьшилось кол-во записей, и для PivotGrid облегчилось работа. Я там заметно выграл (особено на больших выборках), правда не подсчитывал как Вы.

    • Ну да. Это очевидно. Придется SQL переписывать…
      Проблема приложения в том, что запрос довольно активно переоткрывается в ходе работы. И выхода как этого избежать я пока не вижу…

  • Это не только к DevExpress компонентам применимо, но и к обычным DbGrid и JvDBGrid.
    Как известно самый быстрый код – тот что не выполняется.

  • >Ну я разнёс и для PivotGrid я немного переписал SQL
    Я извиняюсь, но не корректно написал, что суть исказилась.
    Я для cxGrid для PivotGrid сделал каждому по Квере соответственно по 1мес и 1чел у меня вышло что для cxGrid у меня ~38`000 для PivotGrid ~5`000 (тех же данных заранее сгрупиров. на сервере). Для первого ещё можно было бы поковырять (я не стал делать ибо общее время удовлетворило) настойки чтоб он всё на фечил, для 2-го это не прокатит.
    Для PivotGrid на порядок возрастала скорость работы кода поля перетаскиваешь.

    >Проблема приложения в том, что запрос довольно активно переоткрывается в ходе работы
    Если кверю вытащить в отдельный ДатаМодуль который создаётся 1 раз в начале. Открывать 1 раз, на опен проверять Активен ли нет.Если Активен то не пере открывать..

  • >чтоб он всё НЕ фечил

  • Тормозит обычно именно из-за того, что при первом открытии фетчатся все данные из БД. И в 95% влияют на это именно Db-контролы. По умолчанию, любой DbControl запрашивает у датасета только те записи, которые будут видны на экране (точнее, с первой записи по последнюю видную на экране).
    И TcxGrid, и TDbGridEh будут стараться зафетчить все записи в случае, если гриду зачем-то могут понадобится именно все записи. Обычно это происходит когда:
    1) у грида включен режим локальной сортировки или фильтрации
    2) используются автофильтры (если они заполняются при старте)
    3) у колонок грида добавлен Footer содержащий какие-то формулы (сумма записей, или количество записей).
    В старых версиях этих гридов было именно так.

    В остальных 5% виноват программист, который где-то в коде написал что-то в духе: Dataset.FetchAll или Dataset.Last (и то и другое потащит все записи с сервера).

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

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

    Конечно, всё зависит от реализации датасета. Но в 99% датасетов с которыми я работал, по умолчанию фетчились только необходимые записи.

  • Я прошу прошения. Не магу отображать данных не DBPivotGrid и не PivotGrid из какой свойстве подключит на DataSource ? помогите пожалуйста. или документация на русском языке нету ?

Оставить комментарий

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

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Продукты DevArt
Купить онлайн:



Читай русскоязычные Delphi блоги
Каталог блогов Blogdir.ru
Яндекс.Метрика