Russian Qt Forum

Qt => Базы данных => Тема начата: JamS007 от Сентябрь 24, 2011, 10:54



Название: Кэширование данных, полученных с сервера
Отправлено: JamS007 от Сентябрь 24, 2011, 10:54
Здравствуйте, прошу помощи в решении следующей задачи:

Есть сервер, который напрямую связывается с сервером БД (postgres) и выполняет роль посредника между всеми клиентами и самой БД. Такой механизм выбран по нескольким причинам и уже на 90% реализован, поэтому от него отказываться нельзя.

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

У меня уже есть несколько идей по оптимизации этого процесса:
1. Передавать клиенту только то, что уместиться в регион видимости QTableView, а если ползунок прокрутки спуститься - передать еще порцию информации. Тут проблема в том, как отследить какая информация уже передана на клиент, а какая еще нет. ведь если хранить на сервере список с переданными полями, то он очень быстро скушает всю оп. память, а диск его кидать = затормозить сервер.

2. Все ранее принятые записи писать в кэш, и загружать данные в первую очередь из кэша, а уже потом обращаться к серверу. В этом случае проблема в том, чтобы синхронизировать информацию между несколькими клиентами, так как каждый клиент имеет право удалить или изменить запись, а все другие клиенты должны об этом "знать", чтобы обновить свой кэш.

Другие идеи также приветствоваться, спасибо.


Название: Re: Кэширование данных, полученных с сервера
Отправлено: asvil от Сентябрь 24, 2011, 11:10
А почему бы не предоставить пользователю фильтрацию запрашиваемых данных?


Название: Re: Кэширование данных, полученных с сервера
Отправлено: JamS007 от Сентябрь 24, 2011, 11:15
Эта возможность есть, но даже она в теории может давать на выходе много данных, которые тоже желательно кеэшировать или показывать не все.


Название: Re: Кэширование данных, полученных с сервера
Отправлено: demiurg от Сентябрь 24, 2011, 11:21
А что вам мешает на сервере с БД поставить APACH и запустить php скрипт. Сразу все проблемы отпадут... И на хост любой поставитьм можно... И клиенту не надо будет ставить какие то приложения... Всё из браузера посмотрит... 


Название: Re: Кэширование данных, полученных с сервера
Отправлено: JamS007 от Сентябрь 24, 2011, 11:26
demiurg, спасибо но данный вариант не подходит.


Название: Re: Кэширование данных, полученных с сервера
Отправлено: Rem Norton от Сентябрь 24, 2011, 12:11
Под описаную задачу подходит QSqlQueryModel. Она засасывает 256 строк сразу, остальные по факту прокрутки View. НО есть ограничение: если резалтсет forwardOnly(), то она ничего не отобразит. Наступал на эти грабли только когда пытался подружить QSqlQueryModel с MS SQL. У MS, если резалтсет надо получить из хранимой процедуры, то в QSqlQuery надо ставить forwardOnly = true, а в коде QSqlQueryModel четко прописано, что с такими курсорами она не работает.  Возможно у Postgres (не проверял, не уверен) есть подобное ограничение при получении резалтсета из хранимой процедуры.


Название: Re: Кэширование данных, полученных с сервера
Отправлено: JamS007 от Сентябрь 24, 2011, 14:07
Rem Norton, да, я знаю что QSqlQueryModel подходит под описанную задачу, но, для ее работы нужен адрес хоста с БД, а мы имеем только адрес промежуточного сервера.

Возможно, покопаю исходники QSqlQueryModel. Спасибо.


Название: Re: Кэширование данных, полученных с сервера
Отправлено: Rem Norton от Сентябрь 24, 2011, 19:19
Копать QSqlQueryModel не нужно. Если какая-то экзотика в подключении, то капать надо QSqlDriver. Все подключения только там, все остальное - надстройка.

Кстати QSqlDriver легко пишется самостоятельно при наличии документации на API нужной СУБД.


Название: Re: Кэширование данных, полученных с сервера
Отправлено: vlad-mal от Сентябрь 30, 2011, 16:24
Здравствуйте, прошу помощи в решении следующей задачи:

Есть сервер, который напрямую связывается с сервером БД (postgres) и выполняет роль посредника между всеми клиентами и самой БД. Такой механизм выбран по нескольким причинам и уже на 90% реализован, поэтому от него отказываться нельзя.

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

У меня уже есть несколько идей по оптимизации этого процесса:
1. Передавать клиенту только то, что уместиться в регион видимости QTableView, а если ползунок прокрутки спуститься - передать еще порцию информации. Тут проблема в том, как отследить какая информация уже передана на клиент, а какая еще нет. ведь если хранить на сервере список с переданными полями, то он очень быстро скушает всю оп. память, а диск его кидать = затормозить сервер.

2. Все ранее принятые записи писать в кэш, и загружать данные в первую очередь из кэша, а уже потом обращаться к серверу. В этом случае проблема в том, чтобы синхронизировать информацию между несколькими клиентами, так как каждый клиент имеет право удалить или изменить запись, а все другие клиенты должны об этом "знать", чтобы обновить свой кэш.

Другие идеи также приветствоваться, спасибо.
Совсем недавно решил подобную задачу, обычной двузвенкой. Основная идея:  клиенту информация передается только та, которая ему нужна (т.е., на которую он смотрит) :)

1. Клиент, желая отобразить набор записей в нужном порядке, загружает только набор идентификаторов этих записей, в том же порядке (если использовать 4-байтное целое, то получается быстро и не накладно: 4МБ для миллиона записей).
2. Данные отображаются в табличке (ну или в дереве) со множеством столбцов, состав которых клиент, естественно, знает.
3. Перед выполнением перерисовки (по любой причине - скроллинг, ресайзинг и проч.) таблички формируется список идентификаторов, которые должны быть показаны в обновляемой области (причем, не обязательно она совпадает с клиентской областью).
4. Для полученного списка идентификаторов выполняется проверка наличия значений полей (записей) в локальном кэше. Для тех, которых в локальном кэше нет, данные подгружаются в кэш одним запросом.
5. Далее, при выполнении перерисовки элементов (ячеек) таблички, последняя извлекает данные из кэша.
~~~~~~~~~~~~
Все операции выполняются по инициативе элемента отображения (таблички).

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

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

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