crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Работа с подготовленными запросами (QSqlQuery::prepare) (Firebird 2.1), оптимизация запросов, кэширование, транзакции
Steklova Olga
  опции профиля:
сообщение 3.2.2014, 19:23
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Всем привет :)
Пишу класс для работы с БД.
Написала метод класса, выполняющий подключение к БД.
Написала метод класса, выполняющий вставку записей в таблицу. В таком виде он работает.
QString DBFunctions::insertToDB()
{
    QString squery;
    QSqlQuery queryIns_T_BLOCK;
    squery = "INSERT INTO T_BLOCK (A, B, C) VALUES (:A, :B, :C)";
    if (!queryIns_T_BLOCK.prepare(squery))
        return "QUERY_PREP_ERR: " + QString("'%1' %2")
          .arg("INSERT INTO T_BLOCK").arg(queryIns_T_BLOCK.lastError().text());

    for (int i = 1; i <= 3; i++) {
        queryIns_T_BLOCK.bindValue(":A", 100 * i + 1); //тестовый вариант
        queryIns_T_BLOCK.bindValue(":B", 100 * i + 2);
        queryIns_T_BLOCK.bindValue(":C", 100 * i + 3);
        queryIns_T_BLOCK.exec();
        if (!queryIns_T_BLOCK.isActive())
            return "QUERY_EXEC_ERR: " + QString("'%1' %2")
              .arg("INSERT INTO T_BLOCK").arg(queryIns_T_BLOCK.lastError().text());
        }        

    return "";
}
Метод insertToDB() в процессе работы программы вызывается многократно.
В результате, каждый раз подготавливается один и тот же запрос.
Как сделать так, чтобы запрос подготавливался только один раз?
Я хотела вынести подготовку запроса в другой метод класса, который можно будет вызвать однократно.
Насколько я понимаю, для этого queryIns_T_BLOCK должно быть известно в обоих этих методах.
Еще не написав доп. метод, а только выполнив перенос описания QSqlQuery queryIns_T_BLOCK сюда
class DBFunctions
{
...
private:
    QSqlQuery queryIns_T_BLOCK;
};
у меня перестала работать подготовка запроса.
prepare стал выдавать ошибку Driver not loaded. Не понимаю, в чем дело.
Экземпляры класса QSqlQuery могут быть только локальными переменными?

Сообщение отредактировал Steklova Olga - 7.2.2014, 18:45
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Litkevich Yuriy
  опции профиля:
сообщение 4.2.2014, 19:50
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Steklova Olga @ 4.2.2014, 21:11) *
Где бы про это почитать?
у Хелен Бори есть
Цитата(Steklova Olga @ 4.2.2014, 21:11) *
А я и не думала, что надо учитывать такие вещи, мне только хотелось оптимизировать работу, чтобы не загружать БД разборкой одинаковых запросов.
вот собственно и не думай, оптимизирует сама СУБД, обрати внимание на примеры Qt - QSqlQuery всегда локальная переменная.

Применительно к Firebird.
Из Qt в Qt-драйвер БД отправляется срока prepare и пачка (массив) аргументов, этот драйвер прям как есть всё отправляет в Firebird, т.е. строка prepare и массив аргументов.
Firebird по строке prepare строит план запроса и сохраняет его, затем используя массив аргументов сам "биндит" их в план.

В большинстве случаев можно полагать, что сделав с двух разных машин и программ один и тот же prepare Firebird постарается воспользоватся уже подготовленным (с предыдущего события) планом запроса.

Firebird кэширует план запроса, в прочем MySQL тоже должен так делать. Собственно времени больше всего уходит именно на построение плана запроса.

Цитата(Steklova Olga @ 4.2.2014, 21:11) *
Лучше будет для оптимизации вообще все эти запросы делать с prepare? Или есть случаи, когда лучше их выполнить сразу, без подготовки, как q.exec(sQuery) ?
prepare полезно делать в ситуации, когда ты собираешься несколько наборов данных одинаковым запросом отправлять.

П.С.
Обрамить всю пачку prepare-bind в транзакцию - существенно увеличить скорость выполнения этой пачки (для любой БД), а для Firebird-а ещё и меньше мусорить, т.к. он версии состояний хранит.

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





Цитата(Steklova Olga @ 4.2.2014, 21:11) *
В процессе работы кэш запросов хранит текст запроса SELECT вместе с соответствующим результатом, который посылался клиенту.
Вот в Firebird я не помню чтоб результат запроса сколь-нибудь долго кэшировался, для заданной версии, может быть, но версий множество по-этому в общем котле вряд ли. А вот план кэшируется всегда для любого типа запроса
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.3.2024, 17:23