SQL Query минимизирует / кэширует в приложении C ++ - PullRequest
5 голосов
/ 01 августа 2011

Я пишу проект на C ++ / Qt , и он может подключаться к любой базе данных SQL , поддерживаемой QtSQL (http://doc.qt.nokia.com/latest/qtsql.html). Это включает в себя локальные и внешние .

Однако, когда рассматриваемая база данных является внешней, скорость запросов начинает становиться проблемой (медленный пользовательский интерфейс, ...). Причина : Каждый объект, который хранится в базе данных, загружается с отложенной загрузкой и, таким образом, будет выдавать запрос каждый раз, когда требуется атрибут. В среднем около 20 из этих объектов должны отображаться на экране, каждый из которых показывает около 5 атрибутов. Это означает, что для каждого экрана, который я показываю, выполняется около 100 запросов. Запросы выполняются довольно быстро на самом сервере базы данных, но накладные расходы на фактический запрос, выполняемый по сети, значительны (измеряются в секундах для всего экрана).

Я думал о нескольких способах решения проблемы, наиболее важными из них, по-моему, являются:

  1. Делать меньше запросов
  2. Ускорение запросов

Борьба (1)

  • Я мог бы найти какой-то способ отложить фактическую выборку атрибута (запустить транзакцию ), а затем, когда программист пишет endTransaction () , база данных пытается извлечь все за один раз (с SQL UNION или циклом ...). Это, вероятно, потребует внесения некоторых изменений в способ работы ленивых объектов, но если люди прокомментируют, что это достойное решение, я думаю, что оно может быть разработано элегантно. Если это решение ускоряет все достаточно, то сложная схема кэширования может даже не понадобиться, что избавляет от многих головных болей
  • Я мог бы попытаться предварительно загрузить данные атрибутов, выбрав их все в одном запросе для всех запрашиваемых объектов, фактически сделав их не ленивыми . Конечно, в этом случае мне придется беспокоиться об устаревших данных. Как бы я обнаружил устаревшие данные, не отправив хотя бы один запрос на внешнюю базу данных? ( Примечание: отправка запроса для проверки устаревших данных для каждой проверки атрибута обеспечит увеличение производительности в 0 раз в лучшем случае и снижение производительности в 2 раза в худшем случае, когда фактически обнаружится, что данные устарели )

Борьба (2)

Например, запросы можно было бы выполнять быстрее, если бы работающая локальная синхронизированная копия 1044 * работала. Однако на клиентских машинах у меня не так много возможностей для запуска, например, точно такого же типа базы данных, как на сервере. Таким образом, локальная копия будет, например, базой данных SQLite. Это также означало бы, что я не смогу использовать решение, специфичное для db-vendor. Какие у меня есть варианты? Что хорошо сработало для людей в подобных ситуациях?

Беспокойство

Мои основные заботы:

  • Устаревшие данные : существует множество возможных запросов, которые изменяют БД таким образом, что он запрещает действие, которое может показаться пользователю с устаревшими данными.
  • Ремонтопригодность : Насколько свободно я могу соединиться в этом новом слое? Очевидно, было бы предпочтительнее, если бы ему не нужно было знать все о моей внутренней ленивой объектной системе и о каждом объекте и возможном запросе

Последний вопрос

Что было бы хорошим способом минимизировать стоимость запроса? Хороший смысл, что-то вроде комбинации: поддерживаемый, простой в реализации, не слишком специфичный для приложения. Если все сводится к выбору любых 2, то пусть будет так. Мне бы хотелось услышать, как люди рассказывают о своем опыте и о том, что они сделали для его решения.

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

Предполагается, что была выполнена вся соответствующая настройка на стороне сервера (например, MySQLкэш, наилучшие возможные индексы, ...)

* Примечание: я проверил вопросы пользователей с похожими проблемами, которые не полностью удовлетворили мой вопрос: Предложение по схеме репликации длямой вариант использования? и Наилучшая практика для локального кэша базы данных? , например)

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

Примечание о "ленивом"

Небольшой пример того, как выглядит мой код (упрощенно, конечно):

QList<MyObject> myObjects = database->getObjects(20, 40); // fetch and construct object 20 to 40 from the db

// ...some time later

// screen filling time!
foreach (const MyObject& o, myObjects) {
    o->getInt("status", 0);  // == db request
    o->getString("comment", "no comment!"); // == db request
    // about 3 more of these
}

1 Ответ

2 голосов
/ 01 августа 2011

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

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

2) База данных меняется довольно часто.В этом случае «возможно» база данных SQL не подходит для ваших нужд.Возможно, вам потребуется динамическая база данных с более высокой производительностью, которая отправляет обновления, а не требует извлечения.Таким образом, ваше приложение получит уведомление при изменении базовых данных, и вы сможете быстро ответить.Однако, если это не сработает, вы можете придумать свой запрос, чтобы минимизировать количество вызовов библиотеки БД и ввода-вывода.Например, если вы выполняете последовательность select операторов, ваши результаты должны иметь все соответствующие данные в том порядке, в котором вы их запрашивали.Вы просто должны отслеживать, какие были соответствующие операторы select.В качестве альтернативы, если вы можете использовать более слабые критерии запроса, чтобы он возвращал более одной строки для вашего простого запроса, что также должно повысить производительность.

...