Медленная прокрутка с QTableView на другом компьютере

#c #qt #optimization

#c #qt #оптимизация

Вопрос:

В настоящее время я разрабатываю приложение для просмотра базы данных, используя Qt и C . Базы данных находятся в нашей внутренней сети. Я работаю и компилирую на 32-битной версии Win7 с драйвером Qt 4.7.3 qodbc. Цель моего проекта — сделать эти данные доступными для наших пользователей, даже если они путешествуют, используя в этом случае VPN. Соединение происходит очень медленно (я имею в виду: ОЧЕНЬ медленно).

Итак, у меня есть QTableView, который я заполняю результатами 2k. Мне нужна только поддержка win7, и она хорошо работает на компьютерах нашей компании, которые находятся в сети. Но на некоторых компьютерах все происходит очень медленно, т.Е. Прокрутка на моем QTableView. Кажется, это происходит только при использовании VPN. Способ, который я использую для заполнения моего QTableView, — это просто выполнение setQuery(), поэтому мне интересно, выполняются ли какие-либо сетевые действия после выполнения запроса? Если да, в чем может быть проблема? Я не могу найти никакого ответа ни в Google, ни в Qt doc.

РЕДАКТИРОВАТЬ: проблема, похоже, исходит непосредственно из QSqlQuery. Я реализовал следующую модель в качестве пробной версии, чтобы избежать бесполезных запросов (да, это быстро и грязно) :

 class SqlAsyncModel : public QSqlQueryModel
{
public:
  explicit SqlAsyncModel(QObject *parent = 0) : QSqlQueryModel(parent)  {}
  SqlAsyncModel(QSqlQueryModelPrivate amp;dd, QObject *parent)
              : QSqlQueryModel(dd, parent)      {}

  void    queryChange()       { _currRow = 0; qu = this->query(); qu.last(); }
  virtual QVariant    data(const QModelIndex amp;index, int role = Qt::DisplayRole)
  {
      int r = index.row(); int c = index.column();
      if(!index.isValid() || role amp; ~Qt::DisplayRole || r < 0 || c < 0)
         return QVariant();
      while (_currRow < r)
         if (!nextValue())   goto ret;
      while (_currRow > r)
         if (prevValue())    goto ret;
  ret: return (qu.record().value(c));
  // Returns value or QVariant() if invalid QSqlRecord
  }
private:
  inline bool nextValue() { _currRow  ; return qu.next(); }
  inline bool prevValue() { _currRow--; return qu.previous(); }
  int         _currRow;
  QSqlQuery   qu;
 

Это по-прежнему приводит к тому же поведению.
Примечание: я также использую:

 while (mySqlAsyncModel->canFetchMore())
    mySqlAsyncModel->fetchMore();
 

Комментарии:

1. Попробуйте запустить Wireshark на проблемных компьютерах и посмотреть, какой сетевой трафик (если таковой имеется) отправляется / принимается во время прокрутки пользователем. Результаты могут быть информативными.

2. Спасибо за идею. После этого оказалось, что мой QTableView обновляет элементы при каждой прокрутке / появлении окна, что, очевидно, является источником проблемы. Кажется, что в QTableView нет способа установить что-то вроде таймера для обновления. Я иду взглянуть на другие виджеты…

3. Я думаю, что класс QTableView подходит, но вам может потребоваться заменить его другим подклассом QAbstractTableModel, который лучше подходит для ваших целей (вместо ванильного объекта QSqlQueryModel, который вы, вероятно, используете сейчас). Эта статья может представлять интерес: blog.wysota.eu.org/index.php/2006/12/26/remote-models

4. Также это может быть полезно: linuxjournal.com/article/9602

5. Интересные ссылки. Это заставляет меня углубляться в архитектуру MVC, и я узнал много вещей, о которых я не знал. Однако, похоже, это не совсем соответствует моим потребностям. Мой запрос по умолчанию извлекает 256 результатов с сервера (теперь я использую fetchMore()). Я получаю весь результат (используя fetchMore()) за 15-20 секунд, что приемлемо для моего клиента. Но во время прокрутки выполняются дополнительные запросы, и это настоящая проблема. Другая проблема, связанная с таким поведением (обновление в реальном времени), закрытие соединения с базой данных приводит к очистке модели.

Ответ №1:

Итак, проблема возникает из-за поведения QODBCResult. Я загрузил исходные тексты Qt и отредактировал драйвер odbc. Для тех, кто заинтересован в этом, вам нужно изменить поведение функций QODBCResult::data(int) и, по крайней мере, QODBCResult::fetch(int) (и, возможно, QODBCResult::fetchпревосходный / следующий / последний / первый, если вы действительно хотите что-то чистое).

Я лично добавляю буфер QList, где я сохраняю свои строки, когда они запрашиваются. Это почти то же поведение, что и Qt (поскольку он кэширует не все, а только запрошенные строки). Мое приложение занимает до 38-40 Мбайт памяти для 22 тыс. строк / 55 столбцов текста и плавает в кэше.

Комментарии:

1. Так почему это до сих пор не исправлено? Мне кажется, что простой кеш запрошенных строк уже должен быть реализован, поскольку это всего лишь вопрос качества предоставляемых артефактов. Например, у меня есть простой запрос, загружающий 50 строк по 5 столбцов, и каждое представление, связанное с этой моделью, адски отстает. Я должен реализовать свою собственную модель и кэшировать данные локально, но для 50 строк, почему я не могу использовать стандартную модель и покончить с этим, и знать, по крайней мере, что мои пользователи не будут жаловаться на низкую производительность всего с 50 строками.

2. Я думаю, это вопрос, который вам нужно будет задать на форумах / в списке рассылки Qt 😉

3. Похоже, проблема здесь в представлениях. С несколькими отладочными отпечатками, вставленными в модель, я мог видеть множество вызовов data функции-члена каждый раз, когда представление взаимодействует со всеми индексами, а не только с видимыми. В основном он проверяет наличие новых данных для различных ролей. Локальное кэширование данных в быстрой структуре данных уменьшает задержку, но вызовы функций по-прежнему выполняются так же часто, как и раньше, просто для возврата требуется меньше времени. Для реализации виртуализации необходимо внести дополнительные улучшения в представления.