понедельник, 30 июля 2012 г.

QSqlQueryModel - просмотр базы данных с более 10000 записей

Стандартный QSqlQueryModel мало пригоден для просмотра больших баз данных. Модель устроена так, что изначально подгружает 256 записей, и по мере прокрутки таблицы вниз подгружает порциями еще по 256 записей. Всё это сильно лагает и на большой БД неюзабельно.
Можно использовать canFetchMore и fetchMore для загрузки всех данных, но это займет много времени и вдобавок все записи поместятся в память и выгрузка займет приличное время. В итоге - паузы при загрузке и выгрузке данных.
Но можно использовать курсоры БД, то есть QSqlQuery. Выполнение запроса на выборку (SELECT) занимает немного времени и в итоге у нас есть курсор QSqlQuery, который можно вертеть вперед (next()), назад (prevoius()) и в произвольное место (seek()).
Так как же организовать быструю табличную навигацию по БД?

Во-первых, из QTableView нужно выкинуть вертикальный скролл. То есть, задать политику - всегда выключен. Вместо выкинутого скролла ставим свой скроллбар и состыковываем с вьюхой через лэйаут.
Во-вторых, делаем запрос на количество записей в таблице БД (SELECT (COUNT(*)). Полученное значение присваиваем сколлбару (setMaximum()). Теперь смещение скролла будет означать переход на определенный номер записи. Связываем изменение значения скролла с смещением курсора QSqlQuery с помощью seek(). Начиная с этого значения считываем 30 записей и загружаем в QAbstractTableModel.
Таким образом, в таблице всегда будут только 30 записей, начиная с некоторого значения.
Скролл при этом не лагает, только иногда запаздывает за мышкой, но это не критично, и возможно, этого можно избежать обрабатывая не все изменения скролла. Например, если юзер зацепил ползунок и яростно тащит его вниз, то можно ему дать это сделать, а уже потом обновить данные в модели. Например, по таймауту - если за 100 мс не произошло изменений скролла - обновить модель. Как-то так.

Тестирование показало приемлемую навигацию с таким способом. Но, надо не забывать о других способах прокрутки данных: прокрутка колесика мышки - события вьюхи wheelEvent() надо перекидывать на скролл. Далее - возможна навигация с клавиатуры - Move Down, Up, PgDown, PgUp. Это тоже надо обрабатывать.

Выставить порядковые номера записей несложно - это значения скролла + 30.
Магическое число 30 выбрано эмпирически, можно в принципе использовать и 50. Просто есть взять 20, то таблица может быть не вся заполнена и останутся белые области снизу.

О том как вставить данные и обновить таблицу расскажу позже.


3 комментария:

  1. На всякий случай хочу отметить, что это не единственный вариант. Можно в модели определять случай выхода за пределы кеша при запросе данных методом QVariant data(QModelIndex..). Тогда никаких танцев по части View делать не нужно.

    ОтветитьУдалить
  2. Спасибо, друг. Эта статья мне реально помогла.

    ОтветитьУдалить
  3. Спасибо друг, статья очень погмогла.

    ОтветитьУдалить